Skip to content

Commit

Permalink
升级到ManifestV3
Browse files Browse the repository at this point in the history
  • Loading branch information
kscript committed Sep 16, 2024
1 parent 5a5871f commit 3cd5ebb
Show file tree
Hide file tree
Showing 9 changed files with 1,313 additions and 1,230 deletions.
2,220 changes: 1,150 additions & 1,070 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "markdown-downloader",
"version": "1.0.8",
"version": "2.0.0",
"description": "markdown文章下载",
"main": "dist/index.js",
"scripts": {
Expand Down Expand Up @@ -45,6 +45,7 @@
"mathjax": "^3.2.2",
"md5": "^2.3.0",
"path-browserify": "^1.0.1",
"qs": "^6.13.0",
"webpack": "^5.63.0",
"webpack-cli": "^4.9.1",
"webpack-merge": "^5.8.0"
Expand Down
79 changes: 24 additions & 55 deletions src/background.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,30 @@
import { ajax, blob2array } from './request'
import { configs } from './websites'
import downloadZip from './download'

const getHeaders = (xhr, responseHeaders) => {
const headers = {}
if (Array.isArray(responseHeaders)) {
responseHeaders.map(item => {
headers[item] = xhr.getResponseHeader(item)
})
}
return headers
}

const sendCallback = (sendResponse, responseHeaders) => {
return {
sendSuccess (message, xhr) {
sendResponse([null, message, getHeaders(xhr, responseHeaders), xhr])
},
sendError (error, xhr) {
sendResponse([error, null, getHeaders(xhr, responseHeaders), xhr])
}
}
}

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const { type, responseHeaders } = message
const { url, data, dataType, callback } = message
const { fileName, files, options = {} } = message
const { sendSuccess, sendError } = sendCallback(sendResponse, responseHeaders)
if (/(get|post)/i.test(type)) {
ajax({
url,
method: type,
data,
dataType,
success (data, xhr) {
if (/text|blob/i.test(dataType)) {
sendSuccess(data, xhr)
} else {
const obj = dataType === 'text' ? data : JSON.parse(data)
const result = /^json$/i.test(dataType) ? {
callback: noop(callback),
data: obj
} : data
if (typeof callback === 'string' && callback) {
sendSuccess(result, xhr)
} else {
sendSuccess(obj, xhr)
}
}
},
error (error, xhr) {
sendError(error, xhr)
const { type } = message
const { url, data, dataType } = message
if (/(get|post)/i.test(type)) {
ajax({
url,
method: type,
data,
dataType,
success: async (data) => {
if (/blob/i.test(dataType)) {
sendResponse([null, {
data: await blob2array(data),
mimeType: data.type
}])
} else {
sendResponse([null, data])
}
})
} else if (type === 'download') {
downloadZip(fileName, files, options)
}
},
error (error) {
sendResponse([error, null])
}
})
}
return true
})

Expand All @@ -71,7 +40,7 @@ const sendMessage = (message, onsuccess) => {
})
}

chrome.browserAction.onClicked.addListener((tab) => {
chrome.action.onClicked.addListener((tab) => {
const { host } = new URL(tab.url)
const matched = configs.some(({ website, hosts }) => {
if (
Expand Down
85 changes: 2 additions & 83 deletions src/download.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,8 @@
import md5 from 'md5'
import JSZip from 'jszip'
import FileSaver from 'jszip/vendor/FileSaver'
import { getLocalOptions } from './utils'

const defaultOptions = {
partLimit: 1e3,
requestLimit: 5,
retry: 3
}

const options = Object.assign({}, defaultOptions)

export const mergeOptions = (newOptions) => {
return Object.assign(options, defaultOptions, newOptions instanceof Object ? newOptions : {})
}
export const mergeLocalOptions = async () => {
return Object.assign(mergeOptions(await getLocalOptions()))
}

export const noop = (func, defaultFunc) => {
return typeof func === 'function' ? func : typeof defaultFunc === 'function' ? defaultFunc : () => {}
}

export const ajax = async (options) => {
const config = await mergeLocalOptions()
const core = (retry = 3) => {
const xhr = new XMLHttpRequest()
const errorCB = (err) => {
if (retry--) {
setTimeout(() => {
core(retry - 1)
}, 3e3)
} else {
console.log(err)
noop(options.error)(err, xhr)
}
}
options.method = options.method || 'get'
xhr.responseType = options.dataType || 'json'
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status === 200) {
try {
noop(options.success)(xhr.response, xhr)
} catch (err) {
errorCB(err)
}
} else {
errorCB(new Error('network error'))
}
}
}
xhr.error = errorCB
if (/post/i.test(options.method)) {
xhr.open(options.method, options.url, options.async !== false)
xhr.setRequestHeader('Content-type', /json/i.test(options.dataType) ? 'application/json' : 'application/x-www-form-urlencoded')
xhr.send(options.data)
} else {
xhr.open(options.method, options.url, options.async !== false)
xhr.send()
}
}
core(config.retry)
}

export const fetchBlobFile = (file) =>{
return new Promise((resolve, reject) => {
if (file.content) {
resolve(new Blob([file.content], {type : file.type || 'text/plain'}))
} else {
ajax({
url: file.downloadUrl,
type: 'get',
data: '',
dataType: 'blob',
success: (blob) => {
resolve(blob)
},
error: () => {
resolve(new Blob([file.downloadUrl], {type : 'text/plain'}))
}
})
}
})
}
import { options, mergeLocalOptions } from './options'
import { fetchBlobFile } from './request'

export const partTask = (items, handler, limit) => {
let index = 0
Expand Down
14 changes: 11 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { websites } from './websites'
import {
isExtension,
sendMessage,
getLocalOptions
sendMessage
} from './utils'
import downloadZip from './download'
import { downloadMarkdown } from './markdown'
import { getLocalOptions } from './options'

const extract = async (options, customOptions, hook) => {
const localOptions = await getLocalOptions()
const data = await downloadMarkdown(options, Object.assign(customOptions, {
localOptions
}), hook)
data && sendMessage(data)
if (data) {
if (data.type === 'download') {
const { fileName, files, options = {} } = data
downloadZip(fileName, files, options)
} else {
sendMessage(data)
}
}
return data
}

Expand Down
31 changes: 22 additions & 9 deletions src/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"manifest_version": 2,
"manifest_version": 3,
"name": "markdown文档下载",
"version": "1.0",
"description": "",
Expand All @@ -9,11 +9,9 @@
"128": "icon.png"
},
"background": {
"scripts": [
"background.js"
]
"service_worker": "background.js"
},
"browser_action": {
"action": {
"default_icon": "icon.png"
},
"options_page": "option.html",
Expand All @@ -32,13 +30,28 @@
"contextMenus",
"tabs",
"notifications",
"webRequest",
"webRequestBlocking",
"storage",
"webRequest",
"webNavigation",
"scripting"
],
"host_permissions": [
"http://*/*",
"https://*/*"
],
"externally_connectable": {
"matches": [
"http://*/*",
"https://*/*"
]
},
"web_accessible_resources": [
"inject.js"
]
{
"resources": ["inject.js"],
"matches": ["http://*/*", "https://*/*"]
}
],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}
28 changes: 28 additions & 0 deletions src/options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const defaultOptions = {
partLimit: 1e3,
requestLimit: 5,
retry: 3
}

export const options = Object.assign({}, defaultOptions)

export const getLocalOptions = () => {
return new Promise((resolve) => {
chrome.storage.local.get('localOptions', ({ localOptions }) => {
resolve(localOptions instanceof Object ? localOptions : {})
})
})
}
export const mergeOptions = (newOptions) => {
return Object.assign(options, defaultOptions, newOptions instanceof Object ? newOptions : {})
}
export const mergeLocalOptions = async () => {
return Object.assign(mergeOptions(await getLocalOptions()))
}

export default {
options,
getLocalOptions,
mergeOptions,
mergeLocalOptions
}
72 changes: 72 additions & 0 deletions src/request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import qs from 'qs'
import { mergeLocalOptions } from './options'
const noop = (func, defaultFunc) => {
return typeof func === 'function' ? func : typeof defaultFunc === 'function' ? defaultFunc : () => {}
}
export const blob2array = (blob) => {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = () => {
resolve(Array.from(new Uint8Array(reader.result)))
}
reader.onerror = reject
reader.readAsArrayBuffer(blob)
})
}
export const array2blob = (array, mimeType = '') => {
return new Blob([new Uint8Array(array)], { type: mimeType });
}

export const fetchBlobFile = (file) => {
return new Promise((resolve) => {
if (file.content) {
resolve(new Blob([file.content], {type : file.type || 'text/plain'}))
} else {
chrome.runtime.sendMessage({ type: 'get', url: file.downloadUrl, dataType: 'blob' }, ([error, message]) => {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return;
}
if (error) {
resolve(new Blob([file.downloadUrl], {type : 'text/plain'}))
} else {
resolve(array2blob(message.data, message.mimeType || 'text/plain'))
}
})
}
})
}

export const ajax = async (options) => {
const config = await mergeLocalOptions()
const core = (retry = 3) => {
const errorCB = (err) => {
if (retry-- > 0) {
setTimeout(() => {
core(retry - 1)
}, 3e3)
} else {
noop(options.error)(err)
}
}
const { method = 'get', data, dataType, headers, success } = options
const fetchOptions = {
method,
headers: headers instanceof Object ? headers : {}
}
if (/get/i.test(method)) {
options.url += (/\?/.test(options.url) ? '&' : '?') + qs.stringify(data)
} else {
fetchOptions.body = JSON.stringify(data)
}
fetch(options.url, Object.assign(fetchOptions)).then(res => {
return res[dataType] ? res[dataType]() : res.text()
}).then(success).catch(errorCB)
}
core(config.retry)
}

export default {
ajax,
fetchBlobFile
}
Loading

0 comments on commit 3cd5ebb

Please sign in to comment.