From aa5bc1b1f0370b99db76e2ad364af00715f8b58a Mon Sep 17 00:00:00 2001 From: aiden Date: Sun, 18 Dec 2022 20:07:04 +0800 Subject: [PATCH 1/5] add import-series --- .../components/utils/import-series/index.ts | 18 +++ .../components/utils/import-series/logic.ts | 122 ++++++++++++++++++ .../utils/import-series/progress.vue | 102 +++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 registry/lib/components/utils/import-series/index.ts create mode 100644 registry/lib/components/utils/import-series/logic.ts create mode 100644 registry/lib/components/utils/import-series/progress.vue diff --git a/registry/lib/components/utils/import-series/index.ts b/registry/lib/components/utils/import-series/index.ts new file mode 100644 index 000000000..9c08291f3 --- /dev/null +++ b/registry/lib/components/utils/import-series/index.ts @@ -0,0 +1,18 @@ +import { defineComponentMetadata } from '@/components/define' +import { realEntry } from './logic' + +export const component = defineComponentMetadata({ + name: 'importSeries', + author: { + name: 'aiden', + link: 'https://github.com/swhoro', + }, + displayName: '批量导入合集', + tags: [componentsTags.utils], + entry: realEntry, + enabledByDefault: true, + description: { + 'zh-CN': '在合集页面制作一个批量导入按钮,可以新增所有合集内视频至同名收藏夹', + }, + urlInclude: [/^https:\/\/space\.bilibili\.com\/\d+\/channel\/seriesdetail/], +}) diff --git a/registry/lib/components/utils/import-series/logic.ts b/registry/lib/components/utils/import-series/logic.ts new file mode 100644 index 000000000..94fb4b846 --- /dev/null +++ b/registry/lib/components/utils/import-series/logic.ts @@ -0,0 +1,122 @@ +import progress from './progress.vue' +import { mountVueComponent } from '@/core/utils' + +export const realEntry = async () => { + // 模仿python中的time.sleep + const sleep = timeout => + new Promise(resolve => { + setTimeout(resolve, timeout) + }) + + const url = new URL(window.location.href) + // 合集id + const sid = url.searchParams.get('sid') + // 合集作者 + const uid = url.pathname.split('/')[1] + // 合集名 + let series_name = '' + while (true) { + series_name = document.getElementsByClassName('item cur')[0].innerHTML + if (series_name !== '') { + break + } else { + await sleep(500) + } + } + + const get_cookie = name => { + const cookies = document.cookie.split(';') + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].split('=') + cookie[0] = cookie[0].trim() + if (cookie[0] === name) { + return cookie[1] + } + } + return '' + } + // 当前登录用户 我 的验证信息 + const csrf = get_cookie('bili_jct') + + // add a button + const page_head = document.getElementsByClassName('page-head')[0] + const rel = page_head.children[1] + const button = document.createElement('a') + // 什么离谱class名,play打错了可还行 + button.className = 'paly-all-btn' + button.textContent = '一键收藏' + button.style.cssText = ` + right: 6rem; + display: block; + text-align: center; + width: 65px; + ` + page_head.insertBefore(button, rel) + + button.onclick = async () => { + // 获取合集所有视频 + const series_videos = ( + await fetch( + `https://api.bilibili.com/x/series/archives?mid=${uid}&series_id=${sid}&only_normal=true&sort=desc&pn=1&ps=99999`, + ).then(r => r.json()) + ).data.archives + + let fav_id = 0 + // 创建收藏夹,获取新收藏夹id + while (true) { + const response = await fetch('https://api.bilibili.com/x/v3/fav/folder/add', { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: `title=${series_name}&csrf=${csrf}&privacy=0`, + }).then(r => r.json()) + + if (response.code === 0) { + fav_id = response.data.id + break + } else { + await sleep(2000) + } + } + + // 挂载弹出框 + const mount_point = document.createElement('div') + document.getElementsByTagName('body')[0].appendChild(mount_point) + type progressSetting = Vue & { + isDisabled: boolean + all: number + handled: number + } + const p: progressSetting = mountVueComponent(progress, mount_point) + p.all = series_videos.length + + for (let i = 0; i < series_videos.length; i++) { + // 添加每一个视频至收藏夹 + while (true) { + // 做个延迟,防止太快而遭服务器拒绝 + await sleep(500) + const response = await fetch('https://api.bilibili.com/x/v3/fav/resource/deal', { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: `rid=${series_videos[i].aid}&add_media_ids=${fav_id}&type=2&csrf=${csrf}`, + }).then(r => r.json()) + + if (response.code === 0) { + // 如果请求成功,更新progress组件 + p.handled = i + 1 + break + } else { + // 如果请求失败,等待2s后重试 + await sleep(2000) + } + } + } + // 添加收藏夹任务完成,更改按钮为可点击 + p.isDisabled = false + } +} diff --git a/registry/lib/components/utils/import-series/progress.vue b/registry/lib/components/utils/import-series/progress.vue new file mode 100644 index 000000000..eda806d6c --- /dev/null +++ b/registry/lib/components/utils/import-series/progress.vue @@ -0,0 +1,102 @@ + + + + + From 172efb861b51c29e5702d21d77ce759b6e6b6c01 Mon Sep 17 00:00:00 2001 From: aiden Date: Mon, 19 Dec 2022 00:56:22 +0800 Subject: [PATCH 2/5] fix --- .../components/utils/import-series/index.ts | 1 - .../components/utils/import-series/logic.ts | 75 +++++++------------ 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/registry/lib/components/utils/import-series/index.ts b/registry/lib/components/utils/import-series/index.ts index 9c08291f3..bb0307668 100644 --- a/registry/lib/components/utils/import-series/index.ts +++ b/registry/lib/components/utils/import-series/index.ts @@ -10,7 +10,6 @@ export const component = defineComponentMetadata({ displayName: '批量导入合集', tags: [componentsTags.utils], entry: realEntry, - enabledByDefault: true, description: { 'zh-CN': '在合集页面制作一个批量导入按钮,可以新增所有合集内视频至同名收藏夹', }, diff --git a/registry/lib/components/utils/import-series/logic.ts b/registry/lib/components/utils/import-series/logic.ts index 94fb4b846..cbf9c6456 100644 --- a/registry/lib/components/utils/import-series/logic.ts +++ b/registry/lib/components/utils/import-series/logic.ts @@ -1,46 +1,29 @@ -import progress from './progress.vue' -import { mountVueComponent } from '@/core/utils' +import Progress from './Progress.vue' +import { mountVueComponent, getCsrf, delay } from '@/core/utils' +import { sq } from '@/core/spin-query' export const realEntry = async () => { - // 模仿python中的time.sleep - const sleep = timeout => - new Promise(resolve => { - setTimeout(resolve, timeout) - }) - const url = new URL(window.location.href) // 合集id const sid = url.searchParams.get('sid') // 合集作者 const uid = url.pathname.split('/')[1] // 合集名 - let series_name = '' - while (true) { - series_name = document.getElementsByClassName('item cur')[0].innerHTML - if (series_name !== '') { - break - } else { - await sleep(500) - } - } + let seriesName = '' + seriesName = await sq( + () => document.getElementsByClassName('item cur')[0].innerHTML, + t => t !== '', + { + queryInterval: 500, + }, + ) - const get_cookie = name => { - const cookies = document.cookie.split(';') - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i].split('=') - cookie[0] = cookie[0].trim() - if (cookie[0] === name) { - return cookie[1] - } - } - return '' - } // 当前登录用户 我 的验证信息 - const csrf = get_cookie('bili_jct') + const csrf = getCsrf() // add a button - const page_head = document.getElementsByClassName('page-head')[0] - const rel = page_head.children[1] + const pageHead = document.getElementsByClassName('page-head')[0] + const rel = pageHead.children[1] const button = document.createElement('a') // 什么离谱class名,play打错了可还行 button.className = 'paly-all-btn' @@ -51,17 +34,17 @@ export const realEntry = async () => { text-align: center; width: 65px; ` - page_head.insertBefore(button, rel) + pageHead.insertBefore(button, rel) button.onclick = async () => { // 获取合集所有视频 - const series_videos = ( + const seriesVideos = ( await fetch( `https://api.bilibili.com/x/series/archives?mid=${uid}&series_id=${sid}&only_normal=true&sort=desc&pn=1&ps=99999`, ).then(r => r.json()) ).data.archives - let fav_id = 0 + let favId = 0 // 创建收藏夹,获取新收藏夹id while (true) { const response = await fetch('https://api.bilibili.com/x/v3/fav/folder/add', { @@ -70,40 +53,40 @@ export const realEntry = async () => { headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, - body: `title=${series_name}&csrf=${csrf}&privacy=0`, + body: `title=${seriesName}&csrf=${csrf}&privacy=0`, }).then(r => r.json()) if (response.code === 0) { - fav_id = response.data.id + favId = response.data.id break } else { - await sleep(2000) + await delay(2000) } } // 挂载弹出框 - const mount_point = document.createElement('div') - document.getElementsByTagName('body')[0].appendChild(mount_point) - type progressSetting = Vue & { + const mountPoint = document.createElement('div') + document.getElementsByTagName('body')[0].appendChild(mountPoint) + type ProgressSetting = Vue & { isDisabled: boolean all: number handled: number } - const p: progressSetting = mountVueComponent(progress, mount_point) - p.all = series_videos.length + const p: ProgressSetting = mountVueComponent(Progress, mountPoint) + p.all = seriesVideos.length - for (let i = 0; i < series_videos.length; i++) { + for (let i = 0; i < seriesVideos.length; i++) { // 添加每一个视频至收藏夹 while (true) { // 做个延迟,防止太快而遭服务器拒绝 - await sleep(500) + await delay(500) const response = await fetch('https://api.bilibili.com/x/v3/fav/resource/deal', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, - body: `rid=${series_videos[i].aid}&add_media_ids=${fav_id}&type=2&csrf=${csrf}`, + body: `rid=${seriesVideos[i].aid}&add_media_ids=${favId}&type=2&csrf=${csrf}`, }).then(r => r.json()) if (response.code === 0) { @@ -112,7 +95,7 @@ export const realEntry = async () => { break } else { // 如果请求失败,等待2s后重试 - await sleep(2000) + await delay(2000) } } } From 9c75c40a52f9144d21d543e215c9a5829445c727 Mon Sep 17 00:00:00 2001 From: aiden Date: Mon, 19 Dec 2022 14:48:36 +0800 Subject: [PATCH 3/5] add support for collection, add transition, fix bugs --- .../components/utils/import-series/index.ts | 2 +- .../components/utils/import-series/logic.ts | 206 +++++++++++------- .../utils/import-series/progress.vue | 37 +++- 3 files changed, 158 insertions(+), 87 deletions(-) diff --git a/registry/lib/components/utils/import-series/index.ts b/registry/lib/components/utils/import-series/index.ts index bb0307668..2b106a043 100644 --- a/registry/lib/components/utils/import-series/index.ts +++ b/registry/lib/components/utils/import-series/index.ts @@ -13,5 +13,5 @@ export const component = defineComponentMetadata({ description: { 'zh-CN': '在合集页面制作一个批量导入按钮,可以新增所有合集内视频至同名收藏夹', }, - urlInclude: [/^https:\/\/space\.bilibili\.com\/\d+\/channel\/seriesdetail/], + urlInclude: [/^https:\/\/space\.bilibili\.com\//], }) diff --git a/registry/lib/components/utils/import-series/logic.ts b/registry/lib/components/utils/import-series/logic.ts index cbf9c6456..694242946 100644 --- a/registry/lib/components/utils/import-series/logic.ts +++ b/registry/lib/components/utils/import-series/logic.ts @@ -1,23 +1,132 @@ import Progress from './Progress.vue' import { mountVueComponent, getCsrf, delay } from '@/core/utils' import { sq } from '@/core/spin-query' +import { urlChange } from '@/core/observer' +import { Toast } from '@/core/toast' + +const addSeries = async (sid, uid, csrf) => { + // 获取合集所有视频 + const seriesVideos = ( + await fetch( + `https://api.bilibili.com/x/series/archives?mid=${uid}&series_id=${sid}&only_normal=true&sort=desc&pn=1&ps=99999`, + ).then(r => r.json()) + ).data.archives -export const realEntry = async () => { - const url = new URL(window.location.href) - // 合集id - const sid = url.searchParams.get('sid') - // 合集作者 - const uid = url.pathname.split('/')[1] // 合集名 - let seriesName = '' - seriesName = await sq( + const seriesName = await sq( () => document.getElementsByClassName('item cur')[0].innerHTML, t => t !== '', - { - queryInterval: 500, - }, ) + // 挂载弹出框 + const mountPoint = document.createElement('div') + document.getElementsByTagName('body')[0].appendChild(mountPoint) + type ProgressSetting = Vue & { + isDisabled: boolean + all: number + handled: number + } + const p: ProgressSetting = mountVueComponent(Progress, mountPoint) + p.all = seriesVideos.length + + // 创建收藏夹,获取新收藏夹id + let favId = 0 + while (true) { + const response = await fetch('https://api.bilibili.com/x/v3/fav/folder/add', { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: `title=${seriesName}&csrf=${csrf}&privacy=0`, + }).then(r => r.json()) + + if (response.code === 0) { + favId = response.data.id + break + } else { + await delay(2000) + } + } + + // 添加每一个视频至收藏夹 + for (let i = 0; i < seriesVideos.length; i++) { + // 做个延迟,防止太快而遭服务器拒绝 + await delay(500) + while (true) { + const response = await fetch('https://api.bilibili.com/x/v3/fav/resource/deal', { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: `rid=${seriesVideos[i].aid}&add_media_ids=${favId}&type=2&csrf=${csrf}`, + }).then(r => r.json()) + + if (response.code === 0) { + // 如果请求成功,更新progress组件 + p.handled = i + 1 + break + } else { + // 如果请求失败,等待2s后重试 + await delay(2000) + } + } + } + + // 添加收藏夹任务完成,更改按钮为可点击 + p.isDisabled = false +} + +const addCollection = async (sid, csrf) => { + while (true) { + const response = await fetch('https://api.bilibili.com/x/v3/fav/season/fav', { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: `platform=web&season_id=${sid}&csrf=${csrf}`, + }).then(r => r.json()) + + if (response.code === 0) { + Toast.success('成功', '导入合集', 2000) + break + } else { + await delay(2000) + } + } +} + +const addButton = () => { + enum PageType { + Collection, + Series, + } + + const url = new URL(window.location.href) + let pageType: PageType + + // series 或 collection 的 id + let sid + if (url.pathname.includes('seriesdetail')) { + // series id + console.log('aiden: series') + sid = url.searchParams.get('sid') + pageType = PageType.Series + } else if (url.pathname.includes('collectiondetail')) { + // collection id + console.log('aiden: collection') + sid = url.searchParams.get('sid') + pageType = PageType.Collection + } else { + console.log('aiden: none') + return + } + + // 合集作者 + const uid = url.pathname.split('/')[1] + // 当前登录用户 我 的验证信息 const csrf = getCsrf() @@ -33,73 +142,20 @@ export const realEntry = async () => { display: block; text-align: center; width: 65px; - ` + ` pageHead.insertBefore(button, rel) button.onclick = async () => { - // 获取合集所有视频 - const seriesVideos = ( - await fetch( - `https://api.bilibili.com/x/series/archives?mid=${uid}&series_id=${sid}&only_normal=true&sort=desc&pn=1&ps=99999`, - ).then(r => r.json()) - ).data.archives - - let favId = 0 - // 创建收藏夹,获取新收藏夹id - while (true) { - const response = await fetch('https://api.bilibili.com/x/v3/fav/folder/add', { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: `title=${seriesName}&csrf=${csrf}&privacy=0`, - }).then(r => r.json()) - - if (response.code === 0) { - favId = response.data.id - break - } else { - await delay(2000) - } + if (pageType === PageType.Series) { + await addSeries(sid, uid, csrf) + } else { + await addCollection(sid, csrf) } - - // 挂载弹出框 - const mountPoint = document.createElement('div') - document.getElementsByTagName('body')[0].appendChild(mountPoint) - type ProgressSetting = Vue & { - isDisabled: boolean - all: number - handled: number - } - const p: ProgressSetting = mountVueComponent(Progress, mountPoint) - p.all = seriesVideos.length - - for (let i = 0; i < seriesVideos.length; i++) { - // 添加每一个视频至收藏夹 - while (true) { - // 做个延迟,防止太快而遭服务器拒绝 - await delay(500) - const response = await fetch('https://api.bilibili.com/x/v3/fav/resource/deal', { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: `rid=${seriesVideos[i].aid}&add_media_ids=${favId}&type=2&csrf=${csrf}`, - }).then(r => r.json()) - - if (response.code === 0) { - // 如果请求成功,更新progress组件 - p.handled = i + 1 - break - } else { - // 如果请求失败,等待2s后重试 - await delay(2000) - } - } - } - // 添加收藏夹任务完成,更改按钮为可点击 - p.isDisabled = false } } + +export const realEntry = async () => { + urlChange(() => { + addButton() + }) +} diff --git a/registry/lib/components/utils/import-series/progress.vue b/registry/lib/components/utils/import-series/progress.vue index eda806d6c..01c216f23 100644 --- a/registry/lib/components/utils/import-series/progress.vue +++ b/registry/lib/components/utils/import-series/progress.vue @@ -1,11 +1,9 @@