From c85af59b2137cccfe5a7ed3eb5c61f4f0c12072d Mon Sep 17 00:00:00 2001 From: memorydream <34763046+memorydream@users.noreply.github.com> Date: Thu, 28 Apr 2022 14:45:00 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20bilibili=E9=9F=B3=E6=BA=90=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=92=AD=E6=94=BE=E7=9A=84=E9=97=AE=E9=A2=98=20(#1573?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/electron/ipcMain.js | 6 ++-- src/utils/Player.js | 60 ++++++++++++++++++++++-------------- src/utils/base64.js | 67 +++++++++++++++++++++++++++++++++++++++++ src/views/settings.vue | 17 ----------- 4 files changed, 107 insertions(+), 43 deletions(-) create mode 100644 src/utils/base64.js diff --git a/src/electron/ipcMain.js b/src/electron/ipcMain.js index a64847e..0075301 100644 --- a/src/electron/ipcMain.js +++ b/src/electron/ipcMain.js @@ -88,10 +88,10 @@ function toBuffer(data) { } /** - * Get the file URI from bilivideo. + * Get the file base64 data from bilivideo. * * @param {string} url The URL to fetch. - * @returns {Promise} The file URI. + * @returns {Promise} The file base64 data. */ async function getBiliVideoFile(url) { const axios = await import('axios').then(m => m.default); @@ -106,7 +106,7 @@ async function getBiliVideoFile(url) { const buffer = toBuffer(response.data); const encodedData = buffer.toString('base64'); - return `data:application/octet-stream;base64,${encodedData}`; + return encodedData; } /** diff --git a/src/utils/Player.js b/src/utils/Player.js index 2394d30..0274dac 100644 --- a/src/utils/Player.js +++ b/src/utils/Player.js @@ -10,6 +10,7 @@ import { cacheTrackSource, getTrackSource } from '@/utils/db'; import { isCreateMpris, isCreateTray } from '@/utils/platform'; import { Howl, Howler } from 'howler'; import shuffle from 'lodash/shuffle'; +import { decode as base642Buffer } from '@/utils/base64'; const PLAY_PAUSE_FADE_DURATION = 200; @@ -329,25 +330,27 @@ export default class { } this.setOutputDevice(); } + _getAudioSourceBlobURL(data) { + // Create a new object URL. + const source = URL.createObjectURL(new Blob([data])); + + // Clean up the previous object URLs since we've created a new one. + // Revoke object URLs can release the memory taken by a Blob, + // which occupied a large proportion of memory. + for (const url in this.createdBlobRecords) { + URL.revokeObjectURL(url); + } + + // Then, we replace the createBlobRecords with new one with + // our newly created object URL. + this.createdBlobRecords = [source]; + + return source; + } _getAudioSourceFromCache(id) { return getTrackSource(id).then(t => { if (!t) return null; - - // Create a new object URL. - const source = URL.createObjectURL(new Blob([t.source])); - - // Clean up the previous object URLs since we've created a new one. - // Revoke object URLs can release the memory taken by a Blob, - // which occupied a large proportion of memory. - for (const url in this.createdBlobRecords) { - URL.revokeObjectURL(url); - } - - // Then, we replace the createBlobRecords with new one with - // our newly created object URL. - this.createdBlobRecords = [source]; - - return source; + return this._getAudioSourceBlobURL(t.source); }); } _getAudioSourceFromNetease(track) { @@ -416,15 +419,26 @@ export default class { ); if (store.state.settings.automaticallyCacheSongs && retrieveSongInfo?.url) { - cacheTrackSource( - track, - retrieveSongInfo.url, - 128000, - `unm:${retrieveSongInfo.source}` - ); + // 对于来自 bilibili 的音源 + // retrieveSongInfo.url 是音频数据的base64编码 + // 其他音源为实际url + const url = + retrieveSongInfo.source === 'bilibili' + ? `data:application/octet-stream;base64,${retrieveSongInfo.url}` + : retrieveSongInfo.url; + cacheTrackSource(track, url, 128000, `unm:${retrieveSongInfo.source}`); } - return retrieveSongInfo?.url; + if (!retrieveSongInfo) { + return null; + } + + if (retrieveSongInfo.source !== 'bilibili') { + return retrieveSongInfo.url; + } + + const buffer = base642Buffer(retrieveSongInfo.url); + return this._getAudioSourceBlobURL(buffer); } _getAudioSource(track) { return this._getAudioSourceFromCache(String(track.id)) diff --git a/src/utils/base64.js b/src/utils/base64.js new file mode 100644 index 0000000..99ac23c --- /dev/null +++ b/src/utils/base64.js @@ -0,0 +1,67 @@ +// https://github.com/niklasvh/base64-arraybuffer/blob/master/src/index.ts +// Copyright (c) 2012 Niklas von Hertzen Licensed under the MIT license. + +const chars = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +// Use a lookup table to find the index. +const lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256); +for (let i = 0; i < chars.length; i++) { + lookup[chars.charCodeAt(i)] = i; +} + +export const encode = arraybuffer => { + let bytes = new Uint8Array(arraybuffer), + i, + len = bytes.length, + base64 = ''; + + for (i = 0; i < len; i += 3) { + base64 += chars[bytes[i] >> 2]; + base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; + base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; + base64 += chars[bytes[i + 2] & 63]; + } + + if (len % 3 === 2) { + base64 = base64.substring(0, base64.length - 1) + '='; + } else if (len % 3 === 1) { + base64 = base64.substring(0, base64.length - 2) + '=='; + } + + return base64; +}; + +export const decode = base64 => { + let bufferLength = base64.length * 0.75, + len = base64.length, + i, + p = 0, + encoded1, + encoded2, + encoded3, + encoded4; + + if (base64[base64.length - 1] === '=') { + bufferLength--; + if (base64[base64.length - 2] === '=') { + bufferLength--; + } + } + + const arraybuffer = new ArrayBuffer(bufferLength), + bytes = new Uint8Array(arraybuffer); + + for (i = 0; i < len; i += 4) { + encoded1 = lookup[base64.charCodeAt(i)]; + encoded2 = lookup[base64.charCodeAt(i + 1)]; + encoded3 = lookup[base64.charCodeAt(i + 2)]; + encoded4 = lookup[base64.charCodeAt(i + 3)]; + + bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); + bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); + bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); + } + + return arraybuffer; +}; diff --git a/src/views/settings.vue b/src/views/settings.vue index 6bb9e7e..f96c847 100644 --- a/src/views/settings.vue +++ b/src/views/settings.vue @@ -301,23 +301,6 @@ -
-
-
请求用代理服务器 (Proxy)
-
- 请求如 YouTube 音源服务时要使用的代理服务器。
- 留空则不进行相关设置。 -
-
-
- -
-
-
Joox 引擎的 Cookie