1*50245d53Smaotoumaoimport RNFS, { copyFile, exists, readDir, readFile, stat, unlink, writeFile } from "react-native-fs"; 2*50245d53Smaotoumaoimport CryptoJs from "crypto-js"; 3*50245d53Smaotoumaoimport dayjs from "dayjs"; 4*50245d53Smaotoumaoimport axios from "axios"; 5*50245d53Smaotoumaoimport bigInt from "big-integer"; 6*50245d53Smaotoumaoimport qs from "qs"; 7*50245d53Smaotoumaoimport * as webdav from "webdav"; 8*50245d53Smaotoumaoimport { InteractionManager, ToastAndroid } from "react-native"; 9*50245d53Smaotoumaoimport pathConst from "@/constants/pathConst"; 10*50245d53Smaotoumaoimport { compare, satisfies } from "compare-versions"; 11*50245d53Smaotoumaoimport DeviceInfo from "react-native-device-info"; 12*50245d53Smaotoumaoimport deviceInfoModule from "react-native-device-info"; 13*50245d53Smaotoumaoimport StateMapper from "@/utils/stateMapper"; 14*50245d53Smaotoumaoimport MediaExtra from "./mediaExtra"; 15*50245d53Smaotoumaoimport { nanoid } from "nanoid"; 16*50245d53Smaotoumaoimport { devLog, errorLog, trace } from "../utils/log"; 17*50245d53Smaotoumaoimport { getInternalData, InternalDataType, isSameMediaItem, resetMediaItem } from "@/utils/mediaItem"; 187993f90eS猫头猫import { 197993f90eS猫头猫 CacheControl, 20e08d37a3S猫头猫 emptyFunction, 217993f90eS猫头猫 internalSerializeKey, 227993f90eS猫头猫 localPluginHash, 23*50245d53Smaotoumao localPluginPlatform 24*50245d53Smaotoumao} from "@/constants/commonConst"; 25*50245d53Smaotoumaoimport delay from "@/utils/delay"; 26*50245d53Smaotoumaoimport * as cheerio from "cheerio"; 27*50245d53Smaotoumaoimport he from "he"; 28*50245d53Smaotoumaoimport Network from "./network"; 29*50245d53Smaotoumaoimport LocalMusicSheet from "./localMusicSheet"; 30*50245d53Smaotoumaoimport Mp3Util from "@/native/mp3Util"; 31*50245d53Smaotoumaoimport { PluginMeta } from "./pluginMeta"; 32*50245d53Smaotoumaoimport { useEffect, useState } from "react"; 33*50245d53Smaotoumaoimport { addFileScheme, getFileName } from "@/utils/fileUtils"; 34*50245d53Smaotoumaoimport { URL } from "react-native-url-polyfill"; 35*50245d53Smaotoumaoimport Base64 from "@/utils/base64"; 36*50245d53Smaotoumaoimport MediaCache from "./mediaCache"; 37*50245d53Smaotoumaoimport { produce } from "immer"; 38*50245d53Smaotoumaoimport objectPath from "object-path"; 39*50245d53Smaotoumaoimport notImplementedFunction from "@/utils/notImplementedFunction.ts"; 40*50245d53Smaotoumaoimport { readAsStringAsync } from "expo-file-system"; 41927dbe93S猫头猫 4261aca335S猫头猫axios.defaults.timeout = 2000; 43927dbe93S猫头猫 44927dbe93S猫头猫const sha256 = CryptoJs.SHA256; 45927dbe93S猫头猫 46cfa0fc07S猫头猫export enum PluginStateCode { 47927dbe93S猫头猫 /** 版本不匹配 */ 48927dbe93S猫头猫 VersionNotMatch = 'VERSION NOT MATCH', 49927dbe93S猫头猫 /** 无法解析 */ 50927dbe93S猫头猫 CannotParse = 'CANNOT PARSE', 51927dbe93S猫头猫} 52927dbe93S猫头猫 5333d52955Smaotoumaoconst deprecatedCookieManager = { 5433d52955Smaotoumao get: notImplementedFunction, 5533d52955Smaotoumao set: notImplementedFunction, 5633d52955Smaotoumao flush: notImplementedFunction, 5733d52955Smaotoumao}; 5833d52955Smaotoumao 599c34d637S猫头猫const packages: Record<string, any> = { 609c34d637S猫头猫 cheerio, 619c34d637S猫头猫 'crypto-js': CryptoJs, 629c34d637S猫头猫 axios, 639c34d637S猫头猫 dayjs, 649c34d637S猫头猫 'big-integer': bigInt, 659c34d637S猫头猫 qs, 669c34d637S猫头猫 he, 6733d52955Smaotoumao '@react-native-cookies/cookies': deprecatedCookieManager, 6828ccceb7S猫头猫 webdav, 699c34d637S猫头猫}; 709c34d637S猫头猫 71b43683eaS猫头猫const _require = (packageName: string) => { 72b43683eaS猫头猫 let pkg = packages[packageName]; 73b43683eaS猫头猫 pkg.default = pkg; 74b43683eaS猫头猫 return pkg; 75b43683eaS猫头猫}; 769c34d637S猫头猫 7753f8cd8eS猫头猫const _consoleBind = function ( 7853f8cd8eS猫头猫 method: 'log' | 'error' | 'info' | 'warn', 7953f8cd8eS猫头猫 ...args: any 8053f8cd8eS猫头猫) { 8153f8cd8eS猫头猫 const fn = console[method]; 8253f8cd8eS猫头猫 if (fn) { 8353f8cd8eS猫头猫 fn(...args); 8453f8cd8eS猫头猫 devLog(method, ...args); 8553f8cd8eS猫头猫 } 8653f8cd8eS猫头猫}; 8753f8cd8eS猫头猫 8853f8cd8eS猫头猫const _console = { 8953f8cd8eS猫头猫 log: _consoleBind.bind(null, 'log'), 9053f8cd8eS猫头猫 warn: _consoleBind.bind(null, 'warn'), 9153f8cd8eS猫头猫 info: _consoleBind.bind(null, 'info'), 9253f8cd8eS猫头猫 error: _consoleBind.bind(null, 'error'), 9353f8cd8eS猫头猫}; 9453f8cd8eS猫头猫 95ab012f7fSmaotoumaoconst appVersion = deviceInfoModule.getVersion(); 96ab012f7fSmaotoumao 97a7b42a4cS猫头猫function formatAuthUrl(url: string) { 98a7b42a4cS猫头猫 const urlObj = new URL(url); 99a7b42a4cS猫头猫 100a7b42a4cS猫头猫 try { 101a7b42a4cS猫头猫 if (urlObj.username && urlObj.password) { 102a7b42a4cS猫头猫 const auth = `Basic ${Base64.btoa( 103a7b42a4cS猫头猫 `${decodeURIComponent(urlObj.username)}:${decodeURIComponent( 104a7b42a4cS猫头猫 urlObj.password, 105a7b42a4cS猫头猫 )}`, 106a7b42a4cS猫头猫 )}`; 107a7b42a4cS猫头猫 urlObj.username = ''; 108a7b42a4cS猫头猫 urlObj.password = ''; 109a7b42a4cS猫头猫 110a7b42a4cS猫头猫 return { 111a7b42a4cS猫头猫 url: urlObj.toString(), 112a7b42a4cS猫头猫 auth, 113a7b42a4cS猫头猫 }; 114a7b42a4cS猫头猫 } 115a7b42a4cS猫头猫 } catch (e) { 116a7b42a4cS猫头猫 return { 117a7b42a4cS猫头猫 url, 118a7b42a4cS猫头猫 }; 119a7b42a4cS猫头猫 } 120a7b42a4cS猫头猫 return { 121a7b42a4cS猫头猫 url, 122a7b42a4cS猫头猫 }; 123a7b42a4cS猫头猫} 124a7b42a4cS猫头猫 125d5bfeb7eS猫头猫//#region 插件类 126927dbe93S猫头猫export class Plugin { 127927dbe93S猫头猫 /** 插件名 */ 128927dbe93S猫头猫 public name: string; 129927dbe93S猫头猫 /** 插件的hash,作为唯一id */ 130927dbe93S猫头猫 public hash: string; 131927dbe93S猫头猫 /** 插件状态:激活、关闭、错误 */ 132927dbe93S猫头猫 public state: 'enabled' | 'disabled' | 'error'; 133927dbe93S猫头猫 /** 插件状态信息 */ 134927dbe93S猫头猫 public stateCode?: PluginStateCode; 135927dbe93S猫头猫 /** 插件的实例 */ 136927dbe93S猫头猫 public instance: IPlugin.IPluginInstance; 137927dbe93S猫头猫 /** 插件路径 */ 138927dbe93S猫头猫 public path: string; 139927dbe93S猫头猫 /** 插件方法 */ 140927dbe93S猫头猫 public methods: PluginMethods; 141927dbe93S猫头猫 14274d0cf81S猫头猫 constructor( 14374d0cf81S猫头猫 funcCode: string | (() => IPlugin.IPluginInstance), 14474d0cf81S猫头猫 pluginPath: string, 14574d0cf81S猫头猫 ) { 146927dbe93S猫头猫 this.state = 'enabled'; 147927dbe93S猫头猫 let _instance: IPlugin.IPluginInstance; 1483b3d6357S猫头猫 const _module: any = {exports: {}}; 149927dbe93S猫头猫 try { 15074d0cf81S猫头猫 if (typeof funcCode === 'string') { 151e0caf342S猫头猫 // 插件的环境变量 152e0caf342S猫头猫 const env = { 153e0caf342S猫头猫 getUserVariables: () => { 154e0caf342S猫头猫 return ( 155e0caf342S猫头猫 PluginMeta.getPluginMeta(this)?.userVariables ?? {} 156e0caf342S猫头猫 ); 157e0caf342S猫头猫 }, 158ab012f7fSmaotoumao appVersion, 159e3fa9b3cS猫头猫 os: 'android', 160ab012f7fSmaotoumao lang: 'zh-CN' 161e0caf342S猫头猫 }; 162ab012f7fSmaotoumao const _process = { 163ab012f7fSmaotoumao platform: 'android', 164ab012f7fSmaotoumao version: appVersion, 165ab012f7fSmaotoumao env, 166ab012f7fSmaotoumao } 167e0caf342S猫头猫 1684060c00aS猫头猫 // eslint-disable-next-line no-new-func 169927dbe93S猫头猫 _instance = Function(` 170927dbe93S猫头猫 'use strict'; 171ab012f7fSmaotoumao return function(require, __musicfree_require, module, exports, console, env, URL, process) { 1729c34d637S猫头猫 ${funcCode} 173927dbe93S猫头猫 } 174e0caf342S猫头猫 `)()( 175e0caf342S猫头猫 _require, 176e0caf342S猫头猫 _require, 177e0caf342S猫头猫 _module, 178e0caf342S猫头猫 _module.exports, 179e0caf342S猫头猫 _console, 180e0caf342S猫头猫 env, 18191eb8fa8S猫头猫 URL, 182ab012f7fSmaotoumao _process 183e0caf342S猫头猫 ); 1843b3d6357S猫头猫 if (_module.exports.default) { 1853b3d6357S猫头猫 _instance = _module.exports 1863b3d6357S猫头猫 .default as IPlugin.IPluginInstance; 1873b3d6357S猫头猫 } else { 1889c34d637S猫头猫 _instance = _module.exports as IPlugin.IPluginInstance; 1893b3d6357S猫头猫 } 19074d0cf81S猫头猫 } else { 19174d0cf81S猫头猫 _instance = funcCode(); 19274d0cf81S猫头猫 } 193c2b3a262S猫头猫 // 插件初始化后的一些操作 19495297592S猫头猫 if (Array.isArray(_instance.userVariables)) { 19595297592S猫头猫 _instance.userVariables = _instance.userVariables.filter( 19695297592S猫头猫 it => it?.key, 19795297592S猫头猫 ); 19895297592S猫头猫 } 199927dbe93S猫头猫 this.checkValid(_instance); 200927dbe93S猫头猫 } catch (e: any) { 201b43683eaS猫头猫 console.log(e); 202927dbe93S猫头猫 this.state = 'error'; 203927dbe93S猫头猫 this.stateCode = PluginStateCode.CannotParse; 204927dbe93S猫头猫 if (e?.stateCode) { 205927dbe93S猫头猫 this.stateCode = e.stateCode; 206927dbe93S猫头猫 } 207927dbe93S猫头猫 errorLog(`${pluginPath}插件无法解析 `, { 208927dbe93S猫头猫 stateCode: this.stateCode, 209927dbe93S猫头猫 message: e?.message, 210927dbe93S猫头猫 stack: e?.stack, 211927dbe93S猫头猫 }); 212927dbe93S猫头猫 _instance = e?.instance ?? { 213927dbe93S猫头猫 _path: '', 214927dbe93S猫头猫 platform: '', 215927dbe93S猫头猫 appVersion: '', 21620e6a092S猫头猫 async getMediaSource() { 217927dbe93S猫头猫 return null; 218927dbe93S猫头猫 }, 219927dbe93S猫头猫 async search() { 220927dbe93S猫头猫 return {}; 221927dbe93S猫头猫 }, 222927dbe93S猫头猫 async getAlbumInfo() { 223927dbe93S猫头猫 return null; 224927dbe93S猫头猫 }, 225927dbe93S猫头猫 }; 226927dbe93S猫头猫 } 227927dbe93S猫头猫 this.instance = _instance; 228927dbe93S猫头猫 this.path = pluginPath; 229927dbe93S猫头猫 this.name = _instance.platform; 230ab8941d9S猫头猫 if ( 231ab8941d9S猫头猫 this.instance.platform === '' || 232ab8941d9S猫头猫 this.instance.platform === undefined 233ab8941d9S猫头猫 ) { 234927dbe93S猫头猫 this.hash = ''; 235927dbe93S猫头猫 } else { 23674d0cf81S猫头猫 if (typeof funcCode === 'string') { 237927dbe93S猫头猫 this.hash = sha256(funcCode).toString(); 23874d0cf81S猫头猫 } else { 23974d0cf81S猫头猫 this.hash = sha256(funcCode.toString()).toString(); 24074d0cf81S猫头猫 } 241927dbe93S猫头猫 } 242927dbe93S猫头猫 243927dbe93S猫头猫 // 放在最后 244927dbe93S猫头猫 this.methods = new PluginMethods(this); 245927dbe93S猫头猫 } 246927dbe93S猫头猫 247927dbe93S猫头猫 private checkValid(_instance: IPlugin.IPluginInstance) { 248927dbe93S猫头猫 /** 版本号校验 */ 249927dbe93S猫头猫 if ( 250927dbe93S猫头猫 _instance.appVersion && 251927dbe93S猫头猫 !satisfies(DeviceInfo.getVersion(), _instance.appVersion) 252927dbe93S猫头猫 ) { 253927dbe93S猫头猫 throw { 254927dbe93S猫头猫 instance: _instance, 255927dbe93S猫头猫 stateCode: PluginStateCode.VersionNotMatch, 256927dbe93S猫头猫 }; 257927dbe93S猫头猫 } 258927dbe93S猫头猫 return true; 259927dbe93S猫头猫 } 260927dbe93S猫头猫} 26142a9f3e6Smaotoumao 262d5bfeb7eS猫头猫//#endregion 263927dbe93S猫头猫 264d5bfeb7eS猫头猫//#region 基于插件类封装的方法,供给APP侧直接调用 265927dbe93S猫头猫/** 有缓存等信息 */ 266927dbe93S猫头猫class PluginMethods implements IPlugin.IPluginInstanceMethods { 267927dbe93S猫头猫 private plugin; 26842a9f3e6Smaotoumao 269927dbe93S猫头猫 constructor(plugin: Plugin) { 270927dbe93S猫头猫 this.plugin = plugin; 271927dbe93S猫头猫 } 27242a9f3e6Smaotoumao 273927dbe93S猫头猫 /** 搜索 */ 274927dbe93S猫头猫 async search<T extends ICommon.SupportMediaType>( 275927dbe93S猫头猫 query: string, 276927dbe93S猫头猫 page: number, 277927dbe93S猫头猫 type: T, 278927dbe93S猫头猫 ): Promise<IPlugin.ISearchResult<T>> { 279927dbe93S猫头猫 if (!this.plugin.instance.search) { 280927dbe93S猫头猫 return { 281927dbe93S猫头猫 isEnd: true, 282927dbe93S猫头猫 data: [], 283927dbe93S猫头猫 }; 284927dbe93S猫头猫 } 285927dbe93S猫头猫 2864060c00aS猫头猫 const result = 2874060c00aS猫头猫 (await this.plugin.instance.search(query, page, type)) ?? {}; 288927dbe93S猫头猫 if (Array.isArray(result.data)) { 289927dbe93S猫头猫 result.data.forEach(_ => { 290927dbe93S猫头猫 resetMediaItem(_, this.plugin.name); 291927dbe93S猫头猫 }); 292927dbe93S猫头猫 return { 293927dbe93S猫头猫 isEnd: result.isEnd ?? true, 294927dbe93S猫头猫 data: result.data, 295927dbe93S猫头猫 }; 296927dbe93S猫头猫 } 297927dbe93S猫头猫 return { 298927dbe93S猫头猫 isEnd: true, 299927dbe93S猫头猫 data: [], 300927dbe93S猫头猫 }; 301927dbe93S猫头猫 } 302927dbe93S猫头猫 303927dbe93S猫头猫 /** 获取真实源 */ 30420e6a092S猫头猫 async getMediaSource( 305927dbe93S猫头猫 musicItem: IMusic.IMusicItemBase, 306abaede57S猫头猫 quality: IMusic.IQualityKey = 'standard', 307927dbe93S猫头猫 retryCount = 1, 308dc160d50S猫头猫 notUpdateCache = false, 309192ae2b0S猫头猫 ): Promise<IPlugin.IMediaSourceResult | null> { 310927dbe93S猫头猫 // 1. 本地搜索 其实直接读mediameta就好了 31143eb30bfS猫头猫 const mediaExtra = MediaExtra.get(musicItem); 312927dbe93S猫头猫 const localPath = 31343eb30bfS猫头猫 mediaExtra?.localPath || 31443eb30bfS猫头猫 getInternalData<string>(musicItem, InternalDataType.LOCALPATH) || 3150e4173cdS猫头猫 getInternalData<string>( 3160e4173cdS猫头猫 LocalMusicSheet.isLocalMusic(musicItem), 3170e4173cdS猫头猫 InternalDataType.LOCALPATH, 3180e4173cdS猫头猫 ); 31942a9f3e6Smaotoumao if (localPath && (await exists(localPath))) { 3200e4173cdS猫头猫 trace('本地播放', localPath); 32143eb30bfS猫头猫 if (mediaExtra && mediaExtra.localPath !== localPath) { 32243eb30bfS猫头猫 // 修正一下本地数据 32343eb30bfS猫头猫 MediaExtra.update(musicItem, { 32443eb30bfS猫头猫 localPath, 32543eb30bfS猫头猫 }); 32643eb30bfS猫头猫 } 327927dbe93S猫头猫 return { 32811908939S猫头猫 url: addFileScheme(localPath), 329927dbe93S猫头猫 }; 33043eb30bfS猫头猫 } else if (mediaExtra?.localPath) { 33143eb30bfS猫头猫 MediaExtra.update(musicItem, { 33243eb30bfS猫头猫 localPath: undefined, 33343eb30bfS猫头猫 }); 334927dbe93S猫头猫 } 335a84a85c5S猫头猫 3367993f90eS猫头猫 if (musicItem.platform === localPluginPlatform) { 337f5935920S猫头猫 throw new Error('本地音乐不存在'); 338f5935920S猫头猫 } 339927dbe93S猫头猫 // 2. 缓存播放 34043eb30bfS猫头猫 const mediaCache = MediaCache.getMediaCache( 34143eb30bfS猫头猫 musicItem, 34243eb30bfS猫头猫 ) as IMusic.IMusicItem | null; 343985f8e75S猫头猫 const pluginCacheControl = 344985f8e75S猫头猫 this.plugin.instance.cacheControl ?? 'no-cache'; 345cfa0fc07S猫头猫 if ( 346cfa0fc07S猫头猫 mediaCache && 34743eb30bfS猫头猫 mediaCache?.source?.[quality]?.url && 34848f4b873S猫头猫 (pluginCacheControl === CacheControl.Cache || 34948f4b873S猫头猫 (pluginCacheControl === CacheControl.NoCache && 350ef714860S猫头猫 Network.isOffline())) 351cfa0fc07S猫头猫 ) { 3525276aef9S猫头猫 trace('播放', '缓存播放'); 35343eb30bfS猫头猫 const qualityInfo = mediaCache.source[quality]; 354927dbe93S猫头猫 return { 35543eb30bfS猫头猫 url: qualityInfo!.url, 356927dbe93S猫头猫 headers: mediaCache.headers, 3574060c00aS猫头猫 userAgent: 3584060c00aS猫头猫 mediaCache.userAgent ?? mediaCache.headers?.['user-agent'], 359927dbe93S猫头猫 }; 360927dbe93S猫头猫 } 361927dbe93S猫头猫 // 3. 插件解析 36220e6a092S猫头猫 if (!this.plugin.instance.getMediaSource) { 363a7b42a4cS猫头猫 const {url, auth} = formatAuthUrl( 364a7b42a4cS猫头猫 musicItem?.qualities?.[quality]?.url ?? musicItem.url, 365a7b42a4cS猫头猫 ); 366a7b42a4cS猫头猫 return { 367a7b42a4cS猫头猫 url: url, 368a7b42a4cS猫头猫 headers: auth 369a7b42a4cS猫头猫 ? { 370a7b42a4cS猫头猫 Authorization: auth, 371a7b42a4cS猫头猫 } 372a7b42a4cS猫头猫 : undefined, 373a7b42a4cS猫头猫 }; 374927dbe93S猫头猫 } 375927dbe93S猫头猫 try { 376abaede57S猫头猫 const {url, headers} = (await this.plugin.instance.getMediaSource( 377abaede57S猫头猫 musicItem, 378abaede57S猫头猫 quality, 379abaede57S猫头猫 )) ?? {url: musicItem?.qualities?.[quality]?.url}; 380927dbe93S猫头猫 if (!url) { 381a28eac61S猫头猫 throw new Error('NOT RETRY'); 382927dbe93S猫头猫 } 3835276aef9S猫头猫 trace('播放', '插件播放'); 384927dbe93S猫头猫 const result = { 385927dbe93S猫头猫 url, 386927dbe93S猫头猫 headers, 387927dbe93S猫头猫 userAgent: headers?.['user-agent'], 388cfa0fc07S猫头猫 } as IPlugin.IMediaSourceResult; 389a7b42a4cS猫头猫 const authFormattedResult = formatAuthUrl(result.url!); 390a7b42a4cS猫头猫 if (authFormattedResult.auth) { 391a7b42a4cS猫头猫 result.url = authFormattedResult.url; 392a7b42a4cS猫头猫 result.headers = { 393a7b42a4cS猫头猫 ...(result.headers ?? {}), 394a7b42a4cS猫头猫 Authorization: authFormattedResult.auth, 395a7b42a4cS猫头猫 }; 396a7b42a4cS猫头猫 } 397927dbe93S猫头猫 398dc160d50S猫头猫 if ( 399dc160d50S猫头猫 pluginCacheControl !== CacheControl.NoStore && 400dc160d50S猫头猫 !notUpdateCache 401dc160d50S猫头猫 ) { 40243eb30bfS猫头猫 // 更新缓存 40343eb30bfS猫头猫 const cacheSource = { 40443eb30bfS猫头猫 headers: result.headers, 40543eb30bfS猫头猫 userAgent: result.userAgent, 40643eb30bfS猫头猫 url, 40743eb30bfS猫头猫 }; 40843eb30bfS猫头猫 let realMusicItem = { 40943eb30bfS猫头猫 ...musicItem, 41043eb30bfS猫头猫 ...(mediaCache || {}), 41143eb30bfS猫头猫 }; 41243eb30bfS猫头猫 realMusicItem.source = { 41343eb30bfS猫头猫 ...(realMusicItem.source || {}), 41443eb30bfS猫头猫 [quality]: cacheSource, 41543eb30bfS猫头猫 }; 41643eb30bfS猫头猫 41743eb30bfS猫头猫 MediaCache.setMediaCache(realMusicItem); 418752ffc5aS猫头猫 } 419927dbe93S猫头猫 return result; 420927dbe93S猫头猫 } catch (e: any) { 421a28eac61S猫头猫 if (retryCount > 0 && e?.message !== 'NOT RETRY') { 422927dbe93S猫头猫 await delay(150); 423abaede57S猫头猫 return this.getMediaSource(musicItem, quality, --retryCount); 424927dbe93S猫头猫 } 425927dbe93S猫头猫 errorLog('获取真实源失败', e?.message); 426ea6d708fS猫头猫 devLog('error', '获取真实源失败', e, e?.message); 427192ae2b0S猫头猫 return null; 428927dbe93S猫头猫 } 429927dbe93S猫头猫 } 430927dbe93S猫头猫 431927dbe93S猫头猫 /** 获取音乐详情 */ 432927dbe93S猫头猫 async getMusicInfo( 433927dbe93S猫头猫 musicItem: ICommon.IMediaBase, 43474d0cf81S猫头猫 ): Promise<Partial<IMusic.IMusicItem> | null> { 435927dbe93S猫头猫 if (!this.plugin.instance.getMusicInfo) { 436d704daedS猫头猫 return null; 437927dbe93S猫头猫 } 43874d0cf81S猫头猫 try { 439927dbe93S猫头猫 return ( 440927dbe93S猫头猫 this.plugin.instance.getMusicInfo( 4417993f90eS猫头猫 resetMediaItem(musicItem, undefined, true), 442d704daedS猫头猫 ) ?? null 443927dbe93S猫头猫 ); 444ea6d708fS猫头猫 } catch (e: any) { 445ea6d708fS猫头猫 devLog('error', '获取音乐详情失败', e, e?.message); 446d704daedS猫头猫 return null; 44774d0cf81S猫头猫 } 448927dbe93S猫头猫 } 449927dbe93S猫头猫 4507e883dbbS猫头猫 /** 4517e883dbbS猫头猫 * 4527e883dbbS猫头猫 * getLyric(musicItem) => { 4537e883dbbS猫头猫 * lyric: string; 4547e883dbbS猫头猫 * trans: string; 4557e883dbbS猫头猫 * } 4567e883dbbS猫头猫 * 4577e883dbbS猫头猫 */ 458927dbe93S猫头猫 /** 获取歌词 */ 459927dbe93S猫头猫 async getLyric( 46043eb30bfS猫头猫 originalMusicItem: IMusic.IMusicItemBase, 461927dbe93S猫头猫 ): Promise<ILyric.ILyricSource | null> { 46243eb30bfS猫头猫 // 1.额外存储的meta信息(关联歌词) 4635589cdf3S猫头猫 const meta = MediaExtra.get(originalMusicItem); 46443eb30bfS猫头猫 let musicItem: IMusic.IMusicItem; 465927dbe93S猫头猫 if (meta && meta.associatedLrc) { 46643eb30bfS猫头猫 musicItem = meta.associatedLrc as IMusic.IMusicItem; 46743eb30bfS猫头猫 } else { 46843eb30bfS猫头猫 musicItem = originalMusicItem as IMusic.IMusicItem; 469927dbe93S猫头猫 } 47043eb30bfS猫头猫 47143eb30bfS猫头猫 const musicItemCache = MediaCache.getMediaCache( 4727a91f04fS猫头猫 musicItem, 47343eb30bfS猫头猫 ) as IMusic.IMusicItemCache | null; 47443eb30bfS猫头猫 47543eb30bfS猫头猫 /** 原始歌词文本 */ 4767e883dbbS猫头猫 let rawLrc: string | null = musicItem.rawLrc || null; 4777e883dbbS猫头猫 let translation: string | null = null; 47843eb30bfS猫头猫 47926f32636S猫头猫 // 2. 本地手动设置的歌词 48026f32636S猫头猫 const platformHash = CryptoJs.MD5(musicItem.platform).toString( 48126f32636S猫头猫 CryptoJs.enc.Hex, 48226f32636S猫头猫 ); 48326f32636S猫头猫 const idHash = CryptoJs.MD5(musicItem.id).toString(CryptoJs.enc.Hex); 48426f32636S猫头猫 if ( 48526f32636S猫头猫 await RNFS.exists( 48626f32636S猫头猫 pathConst.localLrcPath + platformHash + '/' + idHash + '.lrc', 48726f32636S猫头猫 ) 48826f32636S猫头猫 ) { 48926f32636S猫头猫 rawLrc = await RNFS.readFile( 49026f32636S猫头猫 pathConst.localLrcPath + platformHash + '/' + idHash + '.lrc', 49126f32636S猫头猫 'utf8', 49226f32636S猫头猫 ); 49326f32636S猫头猫 49426f32636S猫头猫 if ( 49526f32636S猫头猫 await RNFS.exists( 49626f32636S猫头猫 pathConst.localLrcPath + 49726f32636S猫头猫 platformHash + 49826f32636S猫头猫 '/' + 49926f32636S猫头猫 idHash + 50026f32636S猫头猫 '.tran.lrc', 50126f32636S猫头猫 ) 50226f32636S猫头猫 ) { 50326f32636S猫头猫 translation = 50426f32636S猫头猫 (await RNFS.readFile( 50526f32636S猫头猫 pathConst.localLrcPath + 50626f32636S猫头猫 platformHash + 50726f32636S猫头猫 '/' + 50826f32636S猫头猫 idHash + 50926f32636S猫头猫 '.tran.lrc', 51026f32636S猫头猫 'utf8', 51126f32636S猫头猫 )) || null; 51226f32636S猫头猫 } 51326f32636S猫头猫 51426f32636S猫头猫 return { 51526f32636S猫头猫 rawLrc, 51626f32636S猫头猫 translation: translation || undefined, // TODO: 这里写的不好 51726f32636S猫头猫 }; 51826f32636S猫头猫 } 51926f32636S猫头猫 52043eb30bfS猫头猫 // 2. 缓存歌词 / 对象上本身的歌词 52143eb30bfS猫头猫 if (musicItemCache?.lyric) { 52243eb30bfS猫头猫 // 缓存的远程结果 52343eb30bfS猫头猫 let cacheLyric: ILyric.ILyricSource | null = 52443eb30bfS猫头猫 musicItemCache.lyric || null; 52543eb30bfS猫头猫 // 缓存的本地结果 52643eb30bfS猫头猫 let localLyric: ILyric.ILyricSource | null = 52743eb30bfS猫头猫 musicItemCache.$localLyric || null; 52843eb30bfS猫头猫 5297e883dbbS猫头猫 // 优先用缓存的结果 5307e883dbbS猫头猫 if (cacheLyric.rawLrc || cacheLyric.translation) { 53143eb30bfS猫头猫 return { 5327e883dbbS猫头猫 rawLrc: cacheLyric.rawLrc, 5337e883dbbS猫头猫 translation: cacheLyric.translation, 53443eb30bfS猫头猫 }; 53543eb30bfS猫头猫 } 53643eb30bfS猫头猫 5377e883dbbS猫头猫 // 本地其实是缓存的路径 5387e883dbbS猫头猫 if (localLyric) { 5397e883dbbS猫头猫 let needRefetch = false; 5407e883dbbS猫头猫 if (localLyric.rawLrc && (await exists(localLyric.rawLrc))) { 5417e883dbbS猫头猫 rawLrc = await readFile(localLyric.rawLrc, 'utf8'); 5427e883dbbS猫头猫 } else if (localLyric.rawLrc) { 5437e883dbbS猫头猫 needRefetch = true; 5447e883dbbS猫头猫 } 5457e883dbbS猫头猫 if ( 5467e883dbbS猫头猫 localLyric.translation && 5477e883dbbS猫头猫 (await exists(localLyric.translation)) 5487e883dbbS猫头猫 ) { 5497e883dbbS猫头猫 translation = await readFile( 5507e883dbbS猫头猫 localLyric.translation, 5517e883dbbS猫头猫 'utf8', 5527e883dbbS猫头猫 ); 5537e883dbbS猫头猫 } else if (localLyric.translation) { 5547e883dbbS猫头猫 needRefetch = true; 55543eb30bfS猫头猫 } 55643eb30bfS猫头猫 5577e883dbbS猫头猫 if (!needRefetch && (rawLrc || translation)) { 55843eb30bfS猫头猫 return { 5597e883dbbS猫头猫 rawLrc: rawLrc || undefined, 5607e883dbbS猫头猫 translation: translation || undefined, 56143eb30bfS猫头猫 }; 56243eb30bfS猫头猫 } 56343eb30bfS猫头猫 } 56443eb30bfS猫头猫 } 56543eb30bfS猫头猫 56643eb30bfS猫头猫 // 3. 无缓存歌词/无自带歌词/无本地歌词 56743eb30bfS猫头猫 let lrcSource: ILyric.ILyricSource | null; 56843eb30bfS猫头猫 if (isSameMediaItem(originalMusicItem, musicItem)) { 56943eb30bfS猫头猫 lrcSource = 57043eb30bfS猫头猫 (await this.plugin.instance 5717e883dbbS猫头猫 ?.getLyric?.(resetMediaItem(musicItem, undefined, true)) 57243eb30bfS猫头猫 ?.catch(() => null)) || null; 57343eb30bfS猫头猫 } else { 57443eb30bfS猫头猫 lrcSource = 57543eb30bfS猫头猫 (await PluginManager.getByMedia(musicItem) 57643eb30bfS猫头猫 ?.instance?.getLyric?.( 57743eb30bfS猫头猫 resetMediaItem(musicItem, undefined, true), 57843eb30bfS猫头猫 ) 57943eb30bfS猫头猫 ?.catch(() => null)) || null; 58043eb30bfS猫头猫 } 58143eb30bfS猫头猫 58243eb30bfS猫头猫 if (lrcSource) { 5837e883dbbS猫头猫 rawLrc = lrcSource?.rawLrc || rawLrc; 5847e883dbbS猫头猫 translation = lrcSource?.translation || null; 58543eb30bfS猫头猫 5867e883dbbS猫头猫 const deprecatedLrcUrl = lrcSource?.lrc || musicItem.lrc; 58743eb30bfS猫头猫 5887e883dbbS猫头猫 // 本地的文件名 5897e883dbbS猫头猫 let filename: string | undefined = `${ 5907e883dbbS猫头猫 pathConst.lrcCachePath 5917e883dbbS猫头猫 }${nanoid()}.lrc`; 5927e883dbbS猫头猫 let filenameTrans: string | undefined = `${ 5937e883dbbS猫头猫 pathConst.lrcCachePath 5947e883dbbS猫头猫 }${nanoid()}.lrc`; 59543eb30bfS猫头猫 5967e883dbbS猫头猫 // 旧版本兼容 5977e883dbbS猫头猫 if (!(rawLrc || translation)) { 5987e883dbbS猫头猫 if (deprecatedLrcUrl) { 59943eb30bfS猫头猫 rawLrc = ( 6007e883dbbS猫头猫 await axios 6017e883dbbS猫头猫 .get(deprecatedLrcUrl, {timeout: 3000}) 6027e883dbbS猫头猫 .catch(() => null) 60343eb30bfS猫头猫 )?.data; 6047e883dbbS猫头猫 } else if (musicItem.rawLrc) { 6057e883dbbS猫头猫 rawLrc = musicItem.rawLrc; 6067e883dbbS猫头猫 } 60743eb30bfS猫头猫 } 60843eb30bfS猫头猫 60943eb30bfS猫头猫 if (rawLrc) { 61043eb30bfS猫头猫 await writeFile(filename, rawLrc, 'utf8'); 61143eb30bfS猫头猫 } else { 6127e883dbbS猫头猫 filename = undefined; 6137e883dbbS猫头猫 } 6147e883dbbS猫头猫 if (translation) { 6157e883dbbS猫头猫 await writeFile(filenameTrans, translation, 'utf8'); 6167e883dbbS猫头猫 } else { 6177e883dbbS猫头猫 filenameTrans = undefined; 6187a91f04fS猫头猫 } 6197a91f04fS猫头猫 6207e883dbbS猫头猫 if (rawLrc || translation) { 6217e883dbbS猫头猫 MediaCache.setMediaCache( 6227e883dbbS猫头猫 produce(musicItemCache || musicItem, draft => { 6237e883dbbS猫头猫 musicItemCache?.$localLyric?.rawLrc; 6247e883dbbS猫头猫 objectPath.set(draft, '$localLyric.rawLrc', filename); 62543eb30bfS猫头猫 objectPath.set( 62643eb30bfS猫头猫 draft, 6277e883dbbS猫头猫 '$localLyric.translation', 6287e883dbbS猫头猫 filenameTrans, 62943eb30bfS猫头猫 ); 63043eb30bfS猫头猫 return draft; 63143eb30bfS猫头猫 }), 63243eb30bfS猫头猫 ); 633927dbe93S猫头猫 return { 6347e883dbbS猫头猫 rawLrc: rawLrc || undefined, 6357e883dbbS猫头猫 translation: translation || undefined, 636927dbe93S猫头猫 }; 637927dbe93S猫头猫 } 638927dbe93S猫头猫 } 63943eb30bfS猫头猫 6403a6f67b1S猫头猫 // 6. 如果是本地文件 64143eb30bfS猫头猫 const isDownloaded = LocalMusicSheet.isLocalMusic(originalMusicItem); 64243eb30bfS猫头猫 if ( 64343eb30bfS猫头猫 originalMusicItem.platform !== localPluginPlatform && 64443eb30bfS猫头猫 isDownloaded 64543eb30bfS猫头猫 ) { 6467e883dbbS猫头猫 const res = await localFilePlugin.instance!.getLyric!(isDownloaded); 64743eb30bfS猫头猫 64843eb30bfS猫头猫 console.log('本地文件歌词'); 64943eb30bfS猫头猫 6503a6f67b1S猫头猫 if (res) { 6513a6f67b1S猫头猫 return res; 6523a6f67b1S猫头猫 } 6533a6f67b1S猫头猫 } 654ea6d708fS猫头猫 devLog('warn', '无歌词'); 655927dbe93S猫头猫 656927dbe93S猫头猫 return null; 657927dbe93S猫头猫 } 658927dbe93S猫头猫 659927dbe93S猫头猫 /** 获取歌词文本 */ 660927dbe93S猫头猫 async getLyricText( 661927dbe93S猫头猫 musicItem: IMusic.IMusicItem, 662927dbe93S猫头猫 ): Promise<string | undefined> { 6637e883dbbS猫头猫 return (await this.getLyric(musicItem))?.rawLrc; 664927dbe93S猫头猫 } 665927dbe93S猫头猫 666927dbe93S猫头猫 /** 获取专辑信息 */ 667927dbe93S猫头猫 async getAlbumInfo( 668927dbe93S猫头猫 albumItem: IAlbum.IAlbumItemBase, 669f9afcc0dS猫头猫 page: number = 1, 670f9afcc0dS猫头猫 ): Promise<IPlugin.IAlbumInfoResult | null> { 671927dbe93S猫头猫 if (!this.plugin.instance.getAlbumInfo) { 672f9afcc0dS猫头猫 return { 673f9afcc0dS猫头猫 albumItem, 674f2a4767cS猫头猫 musicList: (albumItem?.musicList ?? []).map( 675f2a4767cS猫头猫 resetMediaItem, 676f2a4767cS猫头猫 this.plugin.name, 677f2a4767cS猫头猫 true, 678f2a4767cS猫头猫 ), 679f9afcc0dS猫头猫 isEnd: true, 680f9afcc0dS猫头猫 }; 681927dbe93S猫头猫 } 682927dbe93S猫头猫 try { 683927dbe93S猫头猫 const result = await this.plugin.instance.getAlbumInfo( 684927dbe93S猫头猫 resetMediaItem(albumItem, undefined, true), 685f9afcc0dS猫头猫 page, 686927dbe93S猫头猫 ); 6875276aef9S猫头猫 if (!result) { 6885276aef9S猫头猫 throw new Error(); 6895276aef9S猫头猫 } 690927dbe93S猫头猫 result?.musicList?.forEach(_ => { 691927dbe93S猫头猫 resetMediaItem(_, this.plugin.name); 69296744680S猫头猫 _.album = albumItem.title; 693927dbe93S猫头猫 }); 6945276aef9S猫头猫 695f9afcc0dS猫头猫 if (page <= 1) { 696f9afcc0dS猫头猫 // 合并信息 697f9afcc0dS猫头猫 return { 698f9afcc0dS猫头猫 albumItem: {...albumItem, ...(result?.albumItem ?? {})}, 699f9afcc0dS猫头猫 isEnd: result.isEnd === false ? false : true, 700f9afcc0dS猫头猫 musicList: result.musicList, 701f9afcc0dS猫头猫 }; 702f9afcc0dS猫头猫 } else { 703f9afcc0dS猫头猫 return { 704f9afcc0dS猫头猫 isEnd: result.isEnd === false ? false : true, 705f9afcc0dS猫头猫 musicList: result.musicList, 706f9afcc0dS猫头猫 }; 707f9afcc0dS猫头猫 } 7084394410dS猫头猫 } catch (e: any) { 7094394410dS猫头猫 trace('获取专辑信息失败', e?.message); 710ea6d708fS猫头猫 devLog('error', '获取专辑信息失败', e, e?.message); 711ea6d708fS猫头猫 712f9afcc0dS猫头猫 return null; 713927dbe93S猫头猫 } 714927dbe93S猫头猫 } 715927dbe93S猫头猫 7165830c002S猫头猫 /** 获取歌单信息 */ 7175830c002S猫头猫 async getMusicSheetInfo( 7185830c002S猫头猫 sheetItem: IMusic.IMusicSheetItem, 7195830c002S猫头猫 page: number = 1, 7205830c002S猫头猫 ): Promise<IPlugin.ISheetInfoResult | null> { 7215281926bS猫头猫 if (!this.plugin.instance.getMusicSheetInfo) { 7225830c002S猫头猫 return { 7235830c002S猫头猫 sheetItem, 7245830c002S猫头猫 musicList: sheetItem?.musicList ?? [], 7255830c002S猫头猫 isEnd: true, 7265830c002S猫头猫 }; 7275830c002S猫头猫 } 7285830c002S猫头猫 try { 7295830c002S猫头猫 const result = await this.plugin.instance?.getMusicSheetInfo?.( 7305830c002S猫头猫 resetMediaItem(sheetItem, undefined, true), 7315830c002S猫头猫 page, 7325830c002S猫头猫 ); 7335830c002S猫头猫 if (!result) { 7345830c002S猫头猫 throw new Error(); 7355830c002S猫头猫 } 7365830c002S猫头猫 result?.musicList?.forEach(_ => { 7375830c002S猫头猫 resetMediaItem(_, this.plugin.name); 7385830c002S猫头猫 }); 7395830c002S猫头猫 7405830c002S猫头猫 if (page <= 1) { 7415830c002S猫头猫 // 合并信息 7425830c002S猫头猫 return { 7435830c002S猫头猫 sheetItem: {...sheetItem, ...(result?.sheetItem ?? {})}, 7445830c002S猫头猫 isEnd: result.isEnd === false ? false : true, 7455830c002S猫头猫 musicList: result.musicList, 7465830c002S猫头猫 }; 7475830c002S猫头猫 } else { 7485830c002S猫头猫 return { 7495830c002S猫头猫 isEnd: result.isEnd === false ? false : true, 7505830c002S猫头猫 musicList: result.musicList, 7515830c002S猫头猫 }; 7525830c002S猫头猫 } 7535830c002S猫头猫 } catch (e: any) { 7545830c002S猫头猫 trace('获取歌单信息失败', e, e?.message); 7555830c002S猫头猫 devLog('error', '获取歌单信息失败', e, e?.message); 7565830c002S猫头猫 7575830c002S猫头猫 return null; 7585830c002S猫头猫 } 7595830c002S猫头猫 } 7605830c002S猫头猫 761927dbe93S猫头猫 /** 查询作者信息 */ 762efb9da24S猫头猫 async getArtistWorks<T extends IArtist.ArtistMediaType>( 763927dbe93S猫头猫 artistItem: IArtist.IArtistItem, 764927dbe93S猫头猫 page: number, 765927dbe93S猫头猫 type: T, 766927dbe93S猫头猫 ): Promise<IPlugin.ISearchResult<T>> { 767efb9da24S猫头猫 if (!this.plugin.instance.getArtistWorks) { 768927dbe93S猫头猫 return { 769927dbe93S猫头猫 isEnd: true, 770927dbe93S猫头猫 data: [], 771927dbe93S猫头猫 }; 772927dbe93S猫头猫 } 773927dbe93S猫头猫 try { 774efb9da24S猫头猫 const result = await this.plugin.instance.getArtistWorks( 775927dbe93S猫头猫 artistItem, 776927dbe93S猫头猫 page, 777927dbe93S猫头猫 type, 778927dbe93S猫头猫 ); 779927dbe93S猫头猫 if (!result.data) { 780927dbe93S猫头猫 return { 781927dbe93S猫头猫 isEnd: true, 782927dbe93S猫头猫 data: [], 783927dbe93S猫头猫 }; 784927dbe93S猫头猫 } 785927dbe93S猫头猫 result.data?.forEach(_ => resetMediaItem(_, this.plugin.name)); 786927dbe93S猫头猫 return { 787927dbe93S猫头猫 isEnd: result.isEnd ?? true, 788927dbe93S猫头猫 data: result.data, 789927dbe93S猫头猫 }; 7904394410dS猫头猫 } catch (e: any) { 7914394410dS猫头猫 trace('查询作者信息失败', e?.message); 792ea6d708fS猫头猫 devLog('error', '查询作者信息失败', e, e?.message); 793ea6d708fS猫头猫 794927dbe93S猫头猫 throw e; 795927dbe93S猫头猫 } 796927dbe93S猫头猫 } 79708380090S猫头猫 79808380090S猫头猫 /** 导入歌单 */ 79908380090S猫头猫 async importMusicSheet(urlLike: string): Promise<IMusic.IMusicItem[]> { 80008380090S猫头猫 try { 80108380090S猫头猫 const result = 80208380090S猫头猫 (await this.plugin.instance?.importMusicSheet?.(urlLike)) ?? []; 80308380090S猫头猫 result.forEach(_ => resetMediaItem(_, this.plugin.name)); 80408380090S猫头猫 return result; 805ea6d708fS猫头猫 } catch (e: any) { 8060e4173cdS猫头猫 console.log(e); 807ea6d708fS猫头猫 devLog('error', '导入歌单失败', e, e?.message); 808ea6d708fS猫头猫 80908380090S猫头猫 return []; 81008380090S猫头猫 } 81108380090S猫头猫 } 81242a9f3e6Smaotoumao 8134d9d3c4cS猫头猫 /** 导入单曲 */ 8144d9d3c4cS猫头猫 async importMusicItem(urlLike: string): Promise<IMusic.IMusicItem | null> { 8154d9d3c4cS猫头猫 try { 8164d9d3c4cS猫头猫 const result = await this.plugin.instance?.importMusicItem?.( 8174d9d3c4cS猫头猫 urlLike, 8184d9d3c4cS猫头猫 ); 8194d9d3c4cS猫头猫 if (!result) { 8204d9d3c4cS猫头猫 throw new Error(); 8214d9d3c4cS猫头猫 } 8224d9d3c4cS猫头猫 resetMediaItem(result, this.plugin.name); 8234d9d3c4cS猫头猫 return result; 824ea6d708fS猫头猫 } catch (e: any) { 825ea6d708fS猫头猫 devLog('error', '导入单曲失败', e, e?.message); 826ea6d708fS猫头猫 8274d9d3c4cS猫头猫 return null; 8284d9d3c4cS猫头猫 } 8294d9d3c4cS猫头猫 } 83042a9f3e6Smaotoumao 831d52aa40eS猫头猫 /** 获取榜单 */ 83292b6c95aS猫头猫 async getTopLists(): Promise<IMusic.IMusicSheetGroupItem[]> { 833d52aa40eS猫头猫 try { 834d52aa40eS猫头猫 const result = await this.plugin.instance?.getTopLists?.(); 835d52aa40eS猫头猫 if (!result) { 836d52aa40eS猫头猫 throw new Error(); 837d52aa40eS猫头猫 } 838d52aa40eS猫头猫 return result; 839d52aa40eS猫头猫 } catch (e: any) { 840d52aa40eS猫头猫 devLog('error', '获取榜单失败', e, e?.message); 841d52aa40eS猫头猫 return []; 842d52aa40eS猫头猫 } 843d52aa40eS猫头猫 } 84442a9f3e6Smaotoumao 845d52aa40eS猫头猫 /** 获取榜单详情 */ 846d52aa40eS猫头猫 async getTopListDetail( 84792b6c95aS猫头猫 topListItem: IMusic.IMusicSheetItemBase, 848956ee1b7S猫头猫 page: number, 849956ee1b7S猫头猫 ): Promise<IPlugin.ITopListInfoResult> { 850d52aa40eS猫头猫 try { 851d52aa40eS猫头猫 const result = await this.plugin.instance?.getTopListDetail?.( 852d52aa40eS猫头猫 topListItem, 853956ee1b7S猫头猫 page, 854d52aa40eS猫头猫 ); 855d52aa40eS猫头猫 if (!result) { 856d52aa40eS猫头猫 throw new Error(); 857d52aa40eS猫头猫 } 858d384662fS猫头猫 if (result.musicList) { 859d384662fS猫头猫 result.musicList.forEach(_ => 860d384662fS猫头猫 resetMediaItem(_, this.plugin.name), 861d384662fS猫头猫 ); 862d384662fS猫头猫 } 863956ee1b7S猫头猫 if (result.isEnd !== false) { 864956ee1b7S猫头猫 result.isEnd = true; 865956ee1b7S猫头猫 } 866d52aa40eS猫头猫 return result; 867d52aa40eS猫头猫 } catch (e: any) { 868d52aa40eS猫头猫 devLog('error', '获取榜单详情失败', e, e?.message); 869d52aa40eS猫头猫 return { 870956ee1b7S猫头猫 isEnd: true, 871956ee1b7S猫头猫 topListItem: topListItem as IMusic.IMusicSheetItem, 872d52aa40eS猫头猫 musicList: [], 873d52aa40eS猫头猫 }; 874d52aa40eS猫头猫 } 875d52aa40eS猫头猫 } 876ceb900cdS猫头猫 8775830c002S猫头猫 /** 获取推荐歌单的tag */ 878ceb900cdS猫头猫 async getRecommendSheetTags(): Promise<IPlugin.IGetRecommendSheetTagsResult> { 879ceb900cdS猫头猫 try { 880ceb900cdS猫头猫 const result = 881ceb900cdS猫头猫 await this.plugin.instance?.getRecommendSheetTags?.(); 882ceb900cdS猫头猫 if (!result) { 883ceb900cdS猫头猫 throw new Error(); 884ceb900cdS猫头猫 } 885ceb900cdS猫头猫 return result; 886ceb900cdS猫头猫 } catch (e: any) { 887ceb900cdS猫头猫 devLog('error', '获取推荐歌单失败', e, e?.message); 888ceb900cdS猫头猫 return { 889ceb900cdS猫头猫 data: [], 890ceb900cdS猫头猫 }; 891ceb900cdS猫头猫 } 892ceb900cdS猫头猫 } 89342a9f3e6Smaotoumao 8945830c002S猫头猫 /** 获取某个tag的推荐歌单 */ 895ceb900cdS猫头猫 async getRecommendSheetsByTag( 896ceb900cdS猫头猫 tagItem: ICommon.IUnique, 897ceb900cdS猫头猫 page?: number, 898ceb900cdS猫头猫 ): Promise<ICommon.PaginationResponse<IMusic.IMusicSheetItemBase>> { 899ceb900cdS猫头猫 try { 900ceb900cdS猫头猫 const result = 901ceb900cdS猫头猫 await this.plugin.instance?.getRecommendSheetsByTag?.( 902ceb900cdS猫头猫 tagItem, 903ceb900cdS猫头猫 page ?? 1, 904ceb900cdS猫头猫 ); 905ceb900cdS猫头猫 if (!result) { 906ceb900cdS猫头猫 throw new Error(); 907ceb900cdS猫头猫 } 908ceb900cdS猫头猫 if (result.isEnd !== false) { 909ceb900cdS猫头猫 result.isEnd = true; 910ceb900cdS猫头猫 } 911ceb900cdS猫头猫 if (!result.data) { 912ceb900cdS猫头猫 result.data = []; 913ceb900cdS猫头猫 } 914ceb900cdS猫头猫 result.data.forEach(item => resetMediaItem(item, this.plugin.name)); 915ceb900cdS猫头猫 916ceb900cdS猫头猫 return result; 917ceb900cdS猫头猫 } catch (e: any) { 918ceb900cdS猫头猫 devLog('error', '获取推荐歌单详情失败', e, e?.message); 919ceb900cdS猫头猫 return { 920ceb900cdS猫头猫 isEnd: true, 921ceb900cdS猫头猫 data: [], 922ceb900cdS猫头猫 }; 923ceb900cdS猫头猫 } 924ceb900cdS猫头猫 } 925da2a2959S猫头猫 926da2a2959S猫头猫 async getMusicComments( 927da2a2959S猫头猫 musicItem: IMusic.IMusicItem, 928da2a2959S猫头猫 ): Promise<ICommon.PaginationResponse<IMedia.IComment>> { 929da2a2959S猫头猫 const result = await this.plugin.instance?.getMusicComments?.( 930da2a2959S猫头猫 musicItem, 931da2a2959S猫头猫 ); 932da2a2959S猫头猫 if (!result) { 933da2a2959S猫头猫 throw new Error(); 934da2a2959S猫头猫 } 935da2a2959S猫头猫 if (result.isEnd !== false) { 936da2a2959S猫头猫 result.isEnd = true; 937da2a2959S猫头猫 } 938da2a2959S猫头猫 if (!result.data) { 939da2a2959S猫头猫 result.data = []; 940da2a2959S猫头猫 } 941da2a2959S猫头猫 942da2a2959S猫头猫 return result; 943da2a2959S猫头猫 } 9447fb90110S猫头猫 9457fb90110S猫头猫 async migrateFromOtherPlugin( 9467fb90110S猫头猫 mediaItem: ICommon.IMediaBase, 9477fb90110S猫头猫 fromPlatform: string, 9487fb90110S猫头猫 ): Promise<{isOk: boolean; data?: ICommon.IMediaBase}> { 9497fb90110S猫头猫 try { 9507fb90110S猫头猫 const result = await this.plugin.instance?.migrateFromOtherPlugin( 9517fb90110S猫头猫 mediaItem, 9527fb90110S猫头猫 fromPlatform, 9537fb90110S猫头猫 ); 9547fb90110S猫头猫 9557fb90110S猫头猫 if ( 9567fb90110S猫头猫 result.isOk && 9577fb90110S猫头猫 result.data?.id && 9587fb90110S猫头猫 result.data?.platform === this.plugin.platform 9597fb90110S猫头猫 ) { 9607fb90110S猫头猫 return { 9617fb90110S猫头猫 isOk: result.isOk, 9627fb90110S猫头猫 data: result.data, 9637fb90110S猫头猫 }; 9647fb90110S猫头猫 } 9657fb90110S猫头猫 return { 9667fb90110S猫头猫 isOk: false, 9677fb90110S猫头猫 }; 9687fb90110S猫头猫 } catch { 9697fb90110S猫头猫 return { 9707fb90110S猫头猫 isOk: false, 9717fb90110S猫头猫 }; 9727fb90110S猫头猫 } 9737fb90110S猫头猫 } 974927dbe93S猫头猫} 97533d52955Smaotoumao 976d5bfeb7eS猫头猫//#endregion 9771a5528a0S猫头猫 978927dbe93S猫头猫let plugins: Array<Plugin> = []; 979927dbe93S猫头猫const pluginStateMapper = new StateMapper(() => plugins); 98074d0cf81S猫头猫 981d5bfeb7eS猫头猫//#region 本地音乐插件 98274d0cf81S猫头猫/** 本地插件 */ 98374d0cf81S猫头猫const localFilePlugin = new Plugin(function () { 9840e4173cdS猫头猫 return { 985d5bfeb7eS猫头猫 platform: localPluginPlatform, 98674d0cf81S猫头猫 _path: '', 98774d0cf81S猫头猫 async getMusicInfo(musicBase) { 98874d0cf81S猫头猫 const localPath = getInternalData<string>( 98974d0cf81S猫头猫 musicBase, 99074d0cf81S猫头猫 InternalDataType.LOCALPATH, 9910e4173cdS猫头猫 ); 99274d0cf81S猫头猫 if (localPath) { 99374d0cf81S猫头猫 const coverImg = await Mp3Util.getMediaCoverImg(localPath); 99474d0cf81S猫头猫 return { 99574d0cf81S猫头猫 artwork: coverImg, 99674d0cf81S猫头猫 }; 99774d0cf81S猫头猫 } 99874d0cf81S猫头猫 return null; 99974d0cf81S猫头猫 }, 10007993f90eS猫头猫 async getLyric(musicBase) { 10017993f90eS猫头猫 const localPath = getInternalData<string>( 10027993f90eS猫头猫 musicBase, 10037993f90eS猫头猫 InternalDataType.LOCALPATH, 10047993f90eS猫头猫 ); 10053a6f67b1S猫头猫 let rawLrc: string | null = null; 10067993f90eS猫头猫 if (localPath) { 10073a6f67b1S猫头猫 // 读取内嵌歌词 10083a6f67b1S猫头猫 try { 10093a6f67b1S猫头猫 rawLrc = await Mp3Util.getLyric(localPath); 10103a6f67b1S猫头猫 } catch (e) { 1011a84a85c5S猫头猫 console.log('读取内嵌歌词失败', e); 10127993f90eS猫头猫 } 10133a6f67b1S猫头猫 if (!rawLrc) { 10143a6f67b1S猫头猫 // 读取配置歌词 10153a6f67b1S猫头猫 const lastDot = localPath.lastIndexOf('.'); 10163a6f67b1S猫头猫 const lrcPath = localPath.slice(0, lastDot) + '.lrc'; 10173a6f67b1S猫头猫 10183a6f67b1S猫头猫 try { 10193a6f67b1S猫头猫 if (await exists(lrcPath)) { 10203a6f67b1S猫头猫 rawLrc = await readFile(lrcPath, 'utf8'); 10213a6f67b1S猫头猫 } 10223a6f67b1S猫头猫 } catch {} 10233a6f67b1S猫头猫 } 10243a6f67b1S猫头猫 } 10253a6f67b1S猫头猫 10263a6f67b1S猫头猫 return rawLrc 10273a6f67b1S猫头猫 ? { 10283a6f67b1S猫头猫 rawLrc, 10293a6f67b1S猫头猫 } 10303a6f67b1S猫头猫 : null; 10317993f90eS猫头猫 }, 1032a84a85c5S猫头猫 async importMusicItem(urlLike) { 1033a84a85c5S猫头猫 let meta: any = {}; 103442a9f3e6Smaotoumao let id: string; 103542a9f3e6Smaotoumao 1036a84a85c5S猫头猫 try { 1037a84a85c5S猫头猫 meta = await Mp3Util.getBasicMeta(urlLike); 103842a9f3e6Smaotoumao const fileStat = await stat(urlLike); 103942a9f3e6Smaotoumao id = 104042a9f3e6Smaotoumao CryptoJs.MD5(fileStat.originalFilepath).toString( 104142a9f3e6Smaotoumao CryptoJs.enc.Hex, 104242a9f3e6Smaotoumao ) || nanoid(); 104342a9f3e6Smaotoumao } catch { 10445353b473S猫头猫 id = nanoid(); 10455353b473S猫头猫 } 104642a9f3e6Smaotoumao 1047a84a85c5S猫头猫 return { 1048a84a85c5S猫头猫 id: id, 1049a84a85c5S猫头猫 platform: '本地', 1050a84a85c5S猫头猫 title: meta?.title ?? getFileName(urlLike), 1051a84a85c5S猫头猫 artist: meta?.artist ?? '未知歌手', 10525353b473S猫头猫 duration: parseInt(meta?.duration ?? '0', 10) / 1000, 1053a84a85c5S猫头猫 album: meta?.album ?? '未知专辑', 1054a84a85c5S猫头猫 artwork: '', 1055a84a85c5S猫头猫 [internalSerializeKey]: { 1056a84a85c5S猫头猫 localPath: urlLike, 1057a84a85c5S猫头猫 }, 1058a84a85c5S猫头猫 }; 1059a84a85c5S猫头猫 }, 106011908939S猫头猫 async getMediaSource(musicItem, quality) { 106111908939S猫头猫 if (quality === 'standard') { 106211908939S猫头猫 return { 106311908939S猫头猫 url: addFileScheme(musicItem.$?.localPath || musicItem.url), 106411908939S猫头猫 }; 106511908939S猫头猫 } 106611908939S猫头猫 return null; 106711908939S猫头猫 }, 106874d0cf81S猫头猫 }; 106974d0cf81S猫头猫}, ''); 10707993f90eS猫头猫localFilePlugin.hash = localPluginHash; 1071927dbe93S猫头猫 1072d5bfeb7eS猫头猫//#endregion 1073d5bfeb7eS猫头猫 1074927dbe93S猫头猫async function setup() { 1075927dbe93S猫头猫 const _plugins: Array<Plugin> = []; 1076927dbe93S猫头猫 try { 1077927dbe93S猫头猫 // 加载插件 1078927dbe93S猫头猫 const pluginsPaths = await readDir(pathConst.pluginPath); 1079927dbe93S猫头猫 for (let i = 0; i < pluginsPaths.length; ++i) { 1080927dbe93S猫头猫 const _pluginUrl = pluginsPaths[i]; 10811e263108S猫头猫 trace('初始化插件', _pluginUrl); 10821e263108S猫头猫 if ( 10831e263108S猫头猫 _pluginUrl.isFile() && 10841e263108S猫头猫 (_pluginUrl.name?.endsWith?.('.js') || 10851e263108S猫头猫 _pluginUrl.path?.endsWith?.('.js')) 10861e263108S猫头猫 ) { 1087927dbe93S猫头猫 const funcCode = await readFile(_pluginUrl.path, 'utf8'); 1088927dbe93S猫头猫 const plugin = new Plugin(funcCode, _pluginUrl.path); 10894060c00aS猫头猫 const _pluginIndex = _plugins.findIndex( 10904060c00aS猫头猫 p => p.hash === plugin.hash, 10914060c00aS猫头猫 ); 1092927dbe93S猫头猫 if (_pluginIndex !== -1) { 1093927dbe93S猫头猫 // 重复插件,直接忽略 10940c266394S猫头猫 continue; 1095927dbe93S猫头猫 } 1096927dbe93S猫头猫 plugin.hash !== '' && _plugins.push(plugin); 1097927dbe93S猫头猫 } 1098927dbe93S猫头猫 } 1099927dbe93S猫头猫 1100927dbe93S猫头猫 plugins = _plugins; 1101e08d37a3S猫头猫 /** 初始化meta信息 */ 1102c2b3a262S猫头猫 await PluginMeta.setupMeta(plugins.map(_ => _.name)); 1103c2b3a262S猫头猫 /** 查看一下是否有禁用的标记 */ 1104c2b3a262S猫头猫 const allMeta = PluginMeta.getPluginMetaAll() ?? {}; 1105c2b3a262S猫头猫 for (let plugin of plugins) { 1106c2b3a262S猫头猫 if (allMeta[plugin.name]?.enabled === false) { 1107c2b3a262S猫头猫 plugin.state = 'disabled'; 1108c2b3a262S猫头猫 } 1109c2b3a262S猫头猫 } 1110c2b3a262S猫头猫 pluginStateMapper.notify(); 1111927dbe93S猫头猫 } catch (e: any) { 11124060c00aS猫头猫 ToastAndroid.show( 11134060c00aS猫头猫 `插件初始化失败:${e?.message ?? e}`, 11144060c00aS猫头猫 ToastAndroid.LONG, 11154060c00aS猫头猫 ); 11161a5528a0S猫头猫 errorLog('插件初始化失败', e?.message); 1117927dbe93S猫头猫 throw e; 1118927dbe93S猫头猫 } 1119927dbe93S猫头猫} 1120927dbe93S猫头猫 1121e36e2599S猫头猫interface IInstallPluginConfig { 1122e36e2599S猫头猫 notCheckVersion?: boolean; 1123e36e2599S猫头猫} 1124e36e2599S猫头猫 1125*50245d53Smaotoumao// 从本地文件安装插件 1126*50245d53Smaotoumaoasync function installPluginFromLocalFile( 1127e36e2599S猫头猫 pluginPath: string, 1128*50245d53Smaotoumao config?: IInstallPluginConfig & { 1129*50245d53Smaotoumao useExpoFs?: boolean 1130*50245d53Smaotoumao }, 1131e36e2599S猫头猫) { 1132*50245d53Smaotoumao let funcCode: string; 1133*50245d53Smaotoumao if (config?.useExpoFs) { 1134*50245d53Smaotoumao funcCode = await readAsStringAsync(pluginPath); 1135*50245d53Smaotoumao } else { 1136*50245d53Smaotoumao funcCode = await readFile(pluginPath, 'utf8'); 1137*50245d53Smaotoumao } 1138e36e2599S猫头猫 1139e36e2599S猫头猫 if (funcCode) { 1140927dbe93S猫头猫 const plugin = new Plugin(funcCode, pluginPath); 1141927dbe93S猫头猫 const _pluginIndex = plugins.findIndex(p => p.hash === plugin.hash); 1142927dbe93S猫头猫 if (_pluginIndex !== -1) { 1143e36e2599S猫头猫 // 静默忽略 1144e36e2599S猫头猫 return plugin; 1145927dbe93S猫头猫 } 1146e36e2599S猫头猫 const oldVersionPlugin = plugins.find(p => p.name === plugin.name); 1147e36e2599S猫头猫 if (oldVersionPlugin && !config?.notCheckVersion) { 1148e36e2599S猫头猫 if ( 1149e36e2599S猫头猫 compare( 1150e36e2599S猫头猫 oldVersionPlugin.instance.version ?? '', 1151e36e2599S猫头猫 plugin.instance.version ?? '', 1152e36e2599S猫头猫 '>', 1153e36e2599S猫头猫 ) 1154e36e2599S猫头猫 ) { 1155e36e2599S猫头猫 throw new Error('已安装更新版本的插件'); 1156e36e2599S猫头猫 } 1157e36e2599S猫头猫 } 1158e36e2599S猫头猫 1159927dbe93S猫头猫 if (plugin.hash !== '') { 1160927dbe93S猫头猫 const fn = nanoid(); 1161e36e2599S猫头猫 if (oldVersionPlugin) { 1162e36e2599S猫头猫 plugins = plugins.filter(_ => _.hash !== oldVersionPlugin.hash); 1163e36e2599S猫头猫 try { 1164e36e2599S猫头猫 await unlink(oldVersionPlugin.path); 1165e36e2599S猫头猫 } catch {} 1166e36e2599S猫头猫 } 1167927dbe93S猫头猫 const _pluginPath = `${pathConst.pluginPath}${fn}.js`; 1168927dbe93S猫头猫 await copyFile(pluginPath, _pluginPath); 1169927dbe93S猫头猫 plugin.path = _pluginPath; 1170927dbe93S猫头猫 plugins = plugins.concat(plugin); 1171927dbe93S猫头猫 pluginStateMapper.notify(); 1172a84a85c5S猫头猫 return plugin; 1173927dbe93S猫头猫 } 1174e36e2599S猫头猫 throw new Error('插件无法解析!'); 1175927dbe93S猫头猫 } 1176e36e2599S猫头猫 throw new Error('插件无法识别!'); 1177c2b3a262S猫头猫} 1178c2b3a262S猫头猫 1179ee781061S猫头猫const reqHeaders = { 1180ee781061S猫头猫 'Cache-Control': 'no-cache', 1181ee781061S猫头猫 Pragma: 'no-cache', 1182ee781061S猫头猫 Expires: '0', 1183ee781061S猫头猫}; 1184ee781061S猫头猫 1185c2b3a262S猫头猫async function installPluginFromUrl( 1186c2b3a262S猫头猫 url: string, 1187c2b3a262S猫头猫 config?: IInstallPluginConfig, 1188c2b3a262S猫头猫) { 118958992c6bS猫头猫 try { 1190ee781061S猫头猫 const funcCode = ( 1191ee781061S猫头猫 await axios.get(url, { 1192ee781061S猫头猫 headers: reqHeaders, 1193ee781061S猫头猫 }) 1194ee781061S猫头猫 ).data; 119558992c6bS猫头猫 if (funcCode) { 119658992c6bS猫头猫 const plugin = new Plugin(funcCode, ''); 119758992c6bS猫头猫 const _pluginIndex = plugins.findIndex(p => p.hash === plugin.hash); 119858992c6bS猫头猫 if (_pluginIndex !== -1) { 11998b7ddca8S猫头猫 // 静默忽略 12008b7ddca8S猫头猫 return; 120158992c6bS猫头猫 } 120225c1bd29S猫头猫 const oldVersionPlugin = plugins.find(p => p.name === plugin.name); 1203c2b3a262S猫头猫 if (oldVersionPlugin && !config?.notCheckVersion) { 120425c1bd29S猫头猫 if ( 120525c1bd29S猫头猫 compare( 120625c1bd29S猫头猫 oldVersionPlugin.instance.version ?? '', 120725c1bd29S猫头猫 plugin.instance.version ?? '', 120825c1bd29S猫头猫 '>', 120925c1bd29S猫头猫 ) 121025c1bd29S猫头猫 ) { 121125c1bd29S猫头猫 throw new Error('已安装更新版本的插件'); 121225c1bd29S猫头猫 } 121325c1bd29S猫头猫 } 121425c1bd29S猫头猫 121558992c6bS猫头猫 if (plugin.hash !== '') { 121658992c6bS猫头猫 const fn = nanoid(); 121758992c6bS猫头猫 const _pluginPath = `${pathConst.pluginPath}${fn}.js`; 121858992c6bS猫头猫 await writeFile(_pluginPath, funcCode, 'utf8'); 121958992c6bS猫头猫 plugin.path = _pluginPath; 122058992c6bS猫头猫 plugins = plugins.concat(plugin); 122125c1bd29S猫头猫 if (oldVersionPlugin) { 122225c1bd29S猫头猫 plugins = plugins.filter( 122325c1bd29S猫头猫 _ => _.hash !== oldVersionPlugin.hash, 122425c1bd29S猫头猫 ); 122525c1bd29S猫头猫 try { 122625c1bd29S猫头猫 await unlink(oldVersionPlugin.path); 122725c1bd29S猫头猫 } catch {} 122825c1bd29S猫头猫 } 122958992c6bS猫头猫 pluginStateMapper.notify(); 123058992c6bS猫头猫 return; 123158992c6bS猫头猫 } 123274acbfc0S猫头猫 throw new Error('插件无法解析!'); 123358992c6bS猫头猫 } 123425c1bd29S猫头猫 } catch (e: any) { 1235ea6d708fS猫头猫 devLog('error', 'URL安装插件失败', e, e?.message); 123658992c6bS猫头猫 errorLog('URL安装插件失败', e); 123725c1bd29S猫头猫 throw new Error(e?.message ?? ''); 123858992c6bS猫头猫 } 123958992c6bS猫头猫} 124058992c6bS猫头猫 1241927dbe93S猫头猫/** 卸载插件 */ 1242927dbe93S猫头猫async function uninstallPlugin(hash: string) { 1243927dbe93S猫头猫 const targetIndex = plugins.findIndex(_ => _.hash === hash); 1244927dbe93S猫头猫 if (targetIndex !== -1) { 1245927dbe93S猫头猫 try { 124624e5e74aS猫头猫 const pluginName = plugins[targetIndex].name; 1247927dbe93S猫头猫 await unlink(plugins[targetIndex].path); 1248927dbe93S猫头猫 plugins = plugins.filter(_ => _.hash !== hash); 1249927dbe93S猫头猫 pluginStateMapper.notify(); 125043eb30bfS猫头猫 // 防止其他重名 125124e5e74aS猫头猫 if (plugins.every(_ => _.name !== pluginName)) { 12525589cdf3S猫头猫 MediaExtra.removeAll(pluginName); 125324e5e74aS猫头猫 } 1254927dbe93S猫头猫 } catch {} 1255927dbe93S猫头猫 } 1256927dbe93S猫头猫} 1257927dbe93S猫头猫 125808882a77S猫头猫async function uninstallAllPlugins() { 125908882a77S猫头猫 await Promise.all( 126008882a77S猫头猫 plugins.map(async plugin => { 126108882a77S猫头猫 try { 126208882a77S猫头猫 const pluginName = plugin.name; 126308882a77S猫头猫 await unlink(plugin.path); 12645589cdf3S猫头猫 MediaExtra.removeAll(pluginName); 126508882a77S猫头猫 } catch (e) {} 126608882a77S猫头猫 }), 126708882a77S猫头猫 ); 126808882a77S猫头猫 plugins = []; 126908882a77S猫头猫 pluginStateMapper.notify(); 1270e08d37a3S猫头猫 1271e08d37a3S猫头猫 /** 清除空余文件,异步做就可以了 */ 1272e08d37a3S猫头猫 readDir(pathConst.pluginPath) 1273e08d37a3S猫头猫 .then(fns => { 1274e08d37a3S猫头猫 fns.forEach(fn => { 1275e08d37a3S猫头猫 unlink(fn.path).catch(emptyFunction); 1276e08d37a3S猫头猫 }); 1277e08d37a3S猫头猫 }) 1278e08d37a3S猫头猫 .catch(emptyFunction); 127908882a77S猫头猫} 128008882a77S猫头猫 128125c1bd29S猫头猫async function updatePlugin(plugin: Plugin) { 128225c1bd29S猫头猫 const updateUrl = plugin.instance.srcUrl; 128325c1bd29S猫头猫 if (!updateUrl) { 128425c1bd29S猫头猫 throw new Error('没有更新源'); 128525c1bd29S猫头猫 } 128625c1bd29S猫头猫 try { 128725c1bd29S猫头猫 await installPluginFromUrl(updateUrl); 128825c1bd29S猫头猫 } catch (e: any) { 128925c1bd29S猫头猫 if (e.message === '插件已安装') { 129025c1bd29S猫头猫 throw new Error('当前已是最新版本'); 129125c1bd29S猫头猫 } else { 129225c1bd29S猫头猫 throw e; 129325c1bd29S猫头猫 } 129425c1bd29S猫头猫 } 129525c1bd29S猫头猫} 129625c1bd29S猫头猫 1297927dbe93S猫头猫function getByMedia(mediaItem: ICommon.IMediaBase) { 12982c595535S猫头猫 return getByName(mediaItem?.platform); 1299927dbe93S猫头猫} 1300927dbe93S猫头猫 1301927dbe93S猫头猫function getByHash(hash: string) { 13027993f90eS猫头猫 return hash === localPluginHash 13037993f90eS猫头猫 ? localFilePlugin 13047993f90eS猫头猫 : plugins.find(_ => _.hash === hash); 1305927dbe93S猫头猫} 1306927dbe93S猫头猫 1307927dbe93S猫头猫function getByName(name: string) { 13087993f90eS猫头猫 return name === localPluginPlatform 13090e4173cdS猫头猫 ? localFilePlugin 13100e4173cdS猫头猫 : plugins.find(_ => _.name === name); 1311927dbe93S猫头猫} 1312927dbe93S猫头猫 1313927dbe93S猫头猫function getValidPlugins() { 1314927dbe93S猫头猫 return plugins.filter(_ => _.state === 'enabled'); 1315927dbe93S猫头猫} 1316927dbe93S猫头猫 13172b80a429S猫头猫function getSearchablePlugins(supportedSearchType?: ICommon.SupportMediaType) { 13182b80a429S猫头猫 return plugins.filter( 13192b80a429S猫头猫 _ => 13202b80a429S猫头猫 _.state === 'enabled' && 13212b80a429S猫头猫 _.instance.search && 132239ac60f7S猫头猫 (supportedSearchType && _.instance.supportedSearchType 132339ac60f7S猫头猫 ? _.instance.supportedSearchType.includes(supportedSearchType) 13242b80a429S猫头猫 : true), 13252b80a429S猫头猫 ); 1326efb9da24S猫头猫} 1327efb9da24S猫头猫 13282b80a429S猫头猫function getSortedSearchablePlugins( 13292b80a429S猫头猫 supportedSearchType?: ICommon.SupportMediaType, 13302b80a429S猫头猫) { 13312b80a429S猫头猫 return getSearchablePlugins(supportedSearchType).sort((a, b) => 1332e08d37a3S猫头猫 (PluginMeta.getPluginMeta(a).order ?? Infinity) - 1333e08d37a3S猫头猫 (PluginMeta.getPluginMeta(b).order ?? Infinity) < 1334e08d37a3S猫头猫 0 1335e08d37a3S猫头猫 ? -1 1336e08d37a3S猫头猫 : 1, 1337e08d37a3S猫头猫 ); 1338e08d37a3S猫头猫} 1339e08d37a3S猫头猫 134015feccc1S猫头猫function getTopListsablePlugins() { 134115feccc1S猫头猫 return plugins.filter(_ => _.state === 'enabled' && _.instance.getTopLists); 134215feccc1S猫头猫} 134315feccc1S猫头猫 134415feccc1S猫头猫function getSortedTopListsablePlugins() { 134515feccc1S猫头猫 return getTopListsablePlugins().sort((a, b) => 134615feccc1S猫头猫 (PluginMeta.getPluginMeta(a).order ?? Infinity) - 134715feccc1S猫头猫 (PluginMeta.getPluginMeta(b).order ?? Infinity) < 134815feccc1S猫头猫 0 134915feccc1S猫头猫 ? -1 135015feccc1S猫头猫 : 1, 135115feccc1S猫头猫 ); 135215feccc1S猫头猫} 135315feccc1S猫头猫 1354ceb900cdS猫头猫function getRecommendSheetablePlugins() { 1355ceb900cdS猫头猫 return plugins.filter( 1356ceb900cdS猫头猫 _ => _.state === 'enabled' && _.instance.getRecommendSheetsByTag, 1357ceb900cdS猫头猫 ); 1358ceb900cdS猫头猫} 1359ceb900cdS猫头猫 1360ceb900cdS猫头猫function getSortedRecommendSheetablePlugins() { 1361ceb900cdS猫头猫 return getRecommendSheetablePlugins().sort((a, b) => 1362ceb900cdS猫头猫 (PluginMeta.getPluginMeta(a).order ?? Infinity) - 1363ceb900cdS猫头猫 (PluginMeta.getPluginMeta(b).order ?? Infinity) < 1364ceb900cdS猫头猫 0 1365ceb900cdS猫头猫 ? -1 1366ceb900cdS猫头猫 : 1, 1367ceb900cdS猫头猫 ); 1368ceb900cdS猫头猫} 1369ceb900cdS猫头猫 1370e08d37a3S猫头猫function useSortedPlugins() { 1371e08d37a3S猫头猫 const _plugins = pluginStateMapper.useMappedState(); 1372e08d37a3S猫头猫 const _pluginMetaAll = PluginMeta.usePluginMetaAll(); 1373e08d37a3S猫头猫 137434588741S猫头猫 const [sortedPlugins, setSortedPlugins] = useState( 137534588741S猫头猫 [..._plugins].sort((a, b) => 1376e08d37a3S猫头猫 (_pluginMetaAll[a.name]?.order ?? Infinity) - 1377e08d37a3S猫头猫 (_pluginMetaAll[b.name]?.order ?? Infinity) < 1378e08d37a3S猫头猫 0 1379e08d37a3S猫头猫 ? -1 1380e08d37a3S猫头猫 : 1, 138134588741S猫头猫 ), 1382e08d37a3S猫头猫 ); 138334588741S猫头猫 138434588741S猫头猫 useEffect(() => { 1385d4cd40d8S猫头猫 InteractionManager.runAfterInteractions(() => { 138634588741S猫头猫 setSortedPlugins( 138734588741S猫头猫 [..._plugins].sort((a, b) => 138834588741S猫头猫 (_pluginMetaAll[a.name]?.order ?? Infinity) - 138934588741S猫头猫 (_pluginMetaAll[b.name]?.order ?? Infinity) < 139034588741S猫头猫 0 139134588741S猫头猫 ? -1 139234588741S猫头猫 : 1, 139334588741S猫头猫 ), 139434588741S猫头猫 ); 1395d4cd40d8S猫头猫 }); 139634588741S猫头猫 }, [_plugins, _pluginMetaAll]); 139734588741S猫头猫 139834588741S猫头猫 return sortedPlugins; 1399e08d37a3S猫头猫} 1400e08d37a3S猫头猫 1401c2b3a262S猫头猫async function setPluginEnabled(plugin: Plugin, enabled?: boolean) { 1402c2b3a262S猫头猫 const target = plugins.find(it => it.hash === plugin.hash); 1403c2b3a262S猫头猫 if (target) { 1404c2b3a262S猫头猫 target.state = enabled ? 'enabled' : 'disabled'; 1405c2b3a262S猫头猫 plugins = [...plugins]; 1406c2b3a262S猫头猫 pluginStateMapper.notify(); 1407c2b3a262S猫头猫 PluginMeta.setPluginMetaProp(plugin, 'enabled', enabled); 1408c2b3a262S猫头猫 } 1409c2b3a262S猫头猫} 1410c2b3a262S猫头猫 1411927dbe93S猫头猫const PluginManager = { 1412927dbe93S猫头猫 setup, 1413*50245d53Smaotoumao installPluginFromLocalFile, 141458992c6bS猫头猫 installPluginFromUrl, 141525c1bd29S猫头猫 updatePlugin, 1416927dbe93S猫头猫 uninstallPlugin, 1417927dbe93S猫头猫 getByMedia, 1418927dbe93S猫头猫 getByHash, 1419927dbe93S猫头猫 getByName, 1420927dbe93S猫头猫 getValidPlugins, 1421efb9da24S猫头猫 getSearchablePlugins, 1422e08d37a3S猫头猫 getSortedSearchablePlugins, 142315feccc1S猫头猫 getTopListsablePlugins, 1424ceb900cdS猫头猫 getSortedRecommendSheetablePlugins, 142515feccc1S猫头猫 getSortedTopListsablePlugins, 14265276aef9S猫头猫 usePlugins: pluginStateMapper.useMappedState, 1427e08d37a3S猫头猫 useSortedPlugins, 142808882a77S猫头猫 uninstallAllPlugins, 1429c2b3a262S猫头猫 setPluginEnabled, 14305276aef9S猫头猫}; 1431927dbe93S猫头猫 1432927dbe93S猫头猫export default PluginManager; 1433