Merge pull request #434 from cloudflypeng/refactor/background-api

Refactor messageListeners and add utils module to simply use api
This commit is contained in:
Hakadao
2024-03-29 23:25:58 +08:00
committed by GitHub
4 changed files with 244 additions and 133 deletions

View File

@@ -1,57 +1,66 @@
import browser from 'webextension-polyfill'
import type { APIMAP, _FETCH } from '../utils'
import { AHS } from '../utils'
const API_ANIME: APIMAP = {
getPopularAnimeList: {
url: 'https://api.bilibili.com/pgc/web/rank/list',
_fetch: {
method: 'get',
},
params: {
season_type: 1,
day: 3,
},
afterHandle: AHS.J_D,
},
getAnimeWatchList: {
url: 'https://api.bilibili.com/x/space/bangumi/follow/list',
_fetch: {
method: 'get',
},
params: {
pn: 1,
ps: 15,
type: 1,
follow_status: 0,
vmid: '',
},
afterHandle: AHS.J_D,
},
getRecommendAnimeList: {
url: 'https://api.bilibili.com/pgc/page/web/v3/feed',
_fetch: {
method: 'get',
},
params: {
coursor: '',
name: 'anime',
},
afterHandle: AHS.J_D,
},
getAnimeTimeTable: {
url: 'https://api.bilibili.com/pgc/web/timeline',
_fetch: {
method: 'get',
},
params: {
types: 1,
before: 6,
after: 6,
},
afterHandle: AHS.J_D,
},
getAnimeDetail: {
url: 'https://api.bilibili.com/pgc/view/web/season',
_fetch: {
method: 'get',
},
params: {
ep_id: '234406',
},
afterHandle: AHS.J_D,
},
function handleMessage(message: any) {
// get popular anime list
if (message.contentScriptQuery === 'getPopularAnimeList') {
const url
= 'https://api.bilibili.com/pgc/web/rank/list?season_type=1&day=3'
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/36e250090800793b41b223b55eefdcbb9391b53e/user/space.md#%E6%9F%A5%E8%AF%A2%E7%94%A8%E6%88%B7%E8%BF%BD%E7%95%AA%E8%BF%BD%E5%89%A7%E6%98%8E%E7%BB%86
else if (message.contentScriptQuery === 'getAnimeWatchList') {
const url = `https://api.bilibili.com/x/space/bangumi/follow/list?type=1&follow_status=0&pn=${message.pn}&ps=${message.ps}&vmid=${message.vmid}`
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
else if (message.contentScriptQuery === 'getRecommendAnimeList') {
const url = `https://api.bilibili.com/pgc/page/web/v3/feed?name=anime&coursor=${
message.coursor ?? ''
}`
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/bangumi/timeline.md#%E7%95%AA%E5%89%A7%E6%88%96%E5%BD%B1%E8%A7%86%E6%97%B6%E9%97%B4%E7%BA%BF
else if (message.contentScriptQuery === 'getAnimeTimeTable') {
const url
= 'https://api.bilibili.com/pgc/web/timeline?types=1&before=6&after=6'
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
else if (message.contentScriptQuery === 'getAnimeDetail') {
const url = 'https://api.bilibili.com/pgc/view/web/season?ep_id=234406'
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
// TODO: https://api.bilibili.com/pgc/season/index/condition?season_type=1&type=1
}
function handleConnect() {
browser.runtime.onMessage.removeListener(handleMessage)
browser.runtime.onMessage.addListener(handleMessage)
}
export function setupAnimeMsgLstnr() {
browser.runtime.onConnect.removeListener(handleConnect)
browser.runtime.onConnect.addListener(handleConnect)
}
export default API_ANIME

View File

@@ -1,81 +1,74 @@
import browser from 'webextension-polyfill'
import type { APIMAP, _FETCH } from '../utils'
import { AHS } from '../utils'
function handleMessage(message: any) {
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/history&toview/history.md#%E8%8E%B7%E5%8F%96%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95%E5%88%97%E8%A1%A8_web%E7%AB%AF
if (message.contentScriptQuery === 'getHistoryList') {
const url = `https://api.bilibili.com/x/web-interface/history/cursor?ps=20&type=${message.type}&view_at=${message.viewAt}`
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
else if (message.contentScriptQuery === 'searchHistoryList') {
const url = `https://api.bilibili.com/x/web-goblin/history/search?pn=${message.pn}&keyword=${message.keyword}&business=all`
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/history&toview/history.md#%E5%88%A0%E9%99%A4%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95
else if (message.contentScriptQuery === 'deleteHistoryItem') {
const url = 'https://api.bilibili.com/x/v2/history/delete'
return fetch(url, {
method: 'POST',
const API_HISTORY: APIMAP = {
getHistoryList: {
url: 'https://api.bilibili.com/x/web-interface/history/cursor',
_fetch: {
method: 'get',
},
params: {
ps: 20,
type: '',
view_at: '',
},
afterHandle: AHS.J_D,
},
searchHistoryList: {
url: 'https://api.bilibili.com/x/web-goblin/history/search',
_fetch: {
method: 'get',
},
params: {
pn: 1,
keyword: '',
business: 'all',
},
afterHandle: AHS.J_D,
},
deleteHistoryItem: {
url: 'https://api.bilibili.com/x/v2/history/delete',
_fetch: {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
body: new URLSearchParams({
kid: message.kid,
csrf: message.csrf,
}),
})
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/history&toview/history.md#%E6%B8%85%E7%A9%BA%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95
else if (message.contentScriptQuery === 'clearAllHistory') {
const url = 'https://api.bilibili.com/x/v2/history/clear'
return fetch(url, {
method: 'POST',
body: new URLSearchParams({
csrf: message.csrf,
}),
})
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/history&toview/history.md#%E6%9F%A5%E8%AF%A2%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95%E5%81%9C%E7%94%A8%E7%8A%B6%E6%80%81
else if (message.contentScriptQuery === 'getHistoryPauseStatus') {
const url = 'https://api.bilibili.com/x/v2/history/shadow'
return fetch(url)
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/history&toview/history.md#%E5%81%9C%E7%94%A8%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95
else if (message.contentScriptQuery === 'setHistoryPauseStatus') {
const url = 'https://api.bilibili.com/x/v2/history/shadow/set'
return fetch(url, {
method: 'POST',
body: new URLSearchParams({
switch: message.switch,
csrf: message.csrf,
}),
})
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error))
}
},
params: {
kid: '',
csrf: '',
},
afterHandle: AHS.J_D,
},
clearAllHistory: {
url: 'https://api.bilibili.com/x/v2/history/clear',
_fetch: {
method: 'post',
},
params: {
csrf: '',
},
afterHandle: AHS.J_D,
},
getHistoryPauseStatus: {
url: 'https://api.bilibili.com/x/v2/history/shadow',
_fetch: {
method: 'get',
},
params: {},
afterHandle: AHS.J_D,
},
setHistoryPauseStatus: {
url: 'https://api.bilibili.com/x/v2/history/shadow/set',
_fetch: {
method: 'post',
},
params: {
switch: '',
csrf: '',
},
afterHandle: AHS.J_D,
},
}
function handleConnect() {
browser.runtime.onMessage.removeListener(handleMessage)
browser.runtime.onMessage.addListener(handleMessage)
}
export function setupHistoryMsgLstnr() {
browser.runtime.onConnect.removeListener(handleConnect)
browser.runtime.onConnect.addListener(handleConnect)
}
export default API_HISTORY

View File

@@ -1,11 +1,13 @@
import { setupAnimeMsgLstnr } from './anime'
import browser from 'webextension-polyfill'
import { apiListenerFactory } from '../utils'
import API_ANIME from './anime'
import { setupAuthMsgLstnr } from './auth'
import { setupVideoMsgLstnr } from './video'
import { setupUserMsgLstnr } from './user'
import { setupSearchMsgLstnr } from './search'
import { setupNotificationMsgLstnr } from './notification'
import { setupMomentMsgLstnr } from './moment'
import { setupHistoryMsgLstnr } from './history'
import API_HISTORY from './history'
import { setupFavoriteMsgLstnr } from './favorite'
import { setupWatchLaterMsgLstnr } from './watchLater'
import { setupRankingMsgLstnr } from './ranking'
@@ -17,9 +19,16 @@ export function setupAllMsgLstnrs() {
setupSearchMsgLstnr()
setupNotificationMsgLstnr()
setupMomentMsgLstnr()
setupHistoryMsgLstnr()
setupFavoriteMsgLstnr()
setupAnimeMsgLstnr()
setupWatchLaterMsgLstnr()
setupRankingMsgLstnr()
// 上面的会全部删除, 每个文件只保留定义API 的对象, 在这里进行mixin
// 然后整个开始监听
const FullAPI = Object.assign({}, API_ANIME, API_HISTORY)
const handleMessage = apiListenerFactory(FullAPI)
browser.runtime.onMessage.removeListener(handleMessage)
browser.runtime.onMessage.addListener(handleMessage)
}

100
src/background/utils.ts Normal file
View File

@@ -0,0 +1,100 @@
// 对于fetch的常见后处理
// 1. 直接返回data
// 2. json化后返回data
type FetchAfterHandler = ((data: Response) => Promise<any>) | ((data: any) => any)
function toJsonHandler(data: Response): Promise<any> {
return data.json()
}
function toData(data: Promise<any>): Promise<any> {
return data
}
// if need sendResponse, use this
function sendResponseHandler(sendResponse: any) {
return (data: any) => sendResponse(data)
}
// 定义后处理流
const AHS: {
J_D: FetchAfterHandler[]
J_S: FetchAfterHandler[]
} = {
J_D: [toJsonHandler, toData],
J_S: [toJsonHandler, sendResponseHandler],
}
interface Message {
contentScriptQuery: string
[key: string]: any
}
interface _FETCH {
method: string
headers?: {
[key: string]: any
}
body?: any
}
interface API {
url: string
_fetch: _FETCH
params: {
[key: string]: any
}
afterHandle: ((response: Response) => Response | Promise<Response>)[]
}
interface APIMAP {
[key: string]: API
}
// 工厂函数API_LISTENER_FACTORY
function apiListenerFactory(API_MAP: APIMAP) {
return (message: Message) => {
if (API_MAP[message?.contentScriptQuery]) {
try {
let { contentScriptQuery, ...rest } = message
rest = rest || {}
const { _fetch, url, params, afterHandle } = API_MAP[contentScriptQuery] as API
const { method, headers, body } = _fetch as _FETCH
const targetParams = Object.assign({}, params, rest)
let targetUrl = url
let targetBody = Object.assign({}, body)
if (method === 'get') {
const urlParams = new URLSearchParams()
for (const key in targetParams)
urlParams.append(key, targetParams[key])
targetUrl += `?${urlParams.toString()}`
}
else {
targetBody = JSON.stringify(targetParams)
}
// get cant take body
const fetchOpt = method === 'get' ? { method, headers } : { method, headers, body: targetBody }
let baseFunc = fetch(targetUrl, fetchOpt)
afterHandle.forEach(func => baseFunc = baseFunc.then(func))
baseFunc.catch(console.error)
return baseFunc
}
catch (e) {
console.error(e)
}
}
}
}
export {
FetchAfterHandler,
toJsonHandler,
toData,
sendResponseHandler,
AHS,
Message,
_FETCH,
API,
APIMAP,
apiListenerFactory,
}