Skip to content

Commit

Permalink
wip: 新增视频采集站远程配置,支持从远程仓库加载
Browse files Browse the repository at this point in the history
  • Loading branch information
renxia committed Jun 28, 2023
1 parent e0aefc7 commit 2a2a18a
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 23 deletions.
8 changes: 4 additions & 4 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ function getOptions() {
async function VideoSerachAndDL(keyword: string, options: { url?: string[] }, baseOpts: POptions): Promise<void> {
const vs = new VideoSearch();
await vs.updateOptions({ api: options.url || [] });
let apiUrl = vs.api[0];
const apis = vs.api;
let apiUrl = apis[0];

if (!options.url && vs.api.length > 0) {
await prompt<{ k: string }>({
type: 'select',
name: 'k',
message: '请选择 API 站点',
choices: vs.api.map(d => ({ name: d, message: d })) as never,

choices: apis.map(d => ({ name: d.url, message: d.desc })) as never,
validate: value => value.length >= 1,
}).then(v => (apiUrl = v.k));
}).then(v => (apiUrl = vs.apiMap.get(v.k)));
}

await prompt<{ k: string }>({
Expand Down
11 changes: 11 additions & 0 deletions src/lib/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ import { homedir } from 'node:os';
export interface M3u8StorConfig extends VSOptions {
/** 播放地址缓存 */
api?: string[];
remoteConfig?: {
updateTime?: number;
data?: {
apiSites: {
url: string;
desc?: string;
enable?: 0 | 1 | boolean;
remote?: boolean;
}[];
};
};
}

export const stor = LiteStorage.getInstance<M3u8StorConfig>({ uuid: 'm3u8dl', filepath: resolve(homedir(), '.liteStorage/m3u8dl.json') });
76 changes: 57 additions & 19 deletions src/lib/video-search.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Request } from '@lzwme/fe-utils';
import { VideoListResult, VideoSearchResult } from '../types';
import { stor } from './storage';
import { stor, type M3u8StorConfig } from './storage';

const req = new Request(null, {
'content-type': 'application/json; charset=UTF-8',
Expand All @@ -9,39 +9,49 @@ const req = new Request(null, {
export interface VSOptions {
/** 播放地址缓存 */
api?: string[];
force?: boolean;
}

export class VideoSearch {
public apiMap = new Map<string, M3u8StorConfig['remoteConfig']['data']['apiSites'][0]>();
public get api() {
return this.options.api;
return [...this.apiMap.values()];
}
constructor(protected options: VSOptions = {}) {
if (!options.api?.length) options.api = [];
if (process.env.VAPI) options.api.push(...process.env.VAPI.split('$$$'));
this.updateOptions(options).then(() => {
if (!this.api.length) throw Error('没有可用站点,请添加或指定');
if (!this.apiMap.size) throw Error('没有可用站点,请添加或指定');
});
}
async updateOptions(options: VSOptions) {
const cache = stor.get();
if (Array.isArray(cache.api)) this.options.api.push(...cache.api);
const apis = [...(cache.api || []), ...options.api];

await this.formatUrl(apis);

if (options.api?.length) {
this.options.api.unshift(...options.api);
this.options.api = await this.formatUrl(this.options.api);
stor.set({ api: this.options.api });
stor.set({ api: [...(cache.api || []), ...options.api] });
}

(cache.api || []).forEach(url => {
this.apiMap.set(url, { url, desc: url });
});

await this.updateApiFromRemote(options.force);

return this;
}
async search(wd: string, api = this.api[0]) {
let { data } = await req.get<VideoSearchResult>(api, { wd }, null, { rejectUnauthorized: false });
let { data } = await req.get<VideoSearchResult>(api.url, { wd }, null, { rejectUnauthorized: false });

if (typeof data == 'string') data = JSON.parse(data) as VideoSearchResult;

return data;
}
async getVideoList(ids: number | string | (number | string)[], api = this.api[0]) {
let { data } = await req.get<VideoListResult>(
api,
api.url,
{
ac: 'videolist',
ids: Array.isArray(ids) ? ids.join(',') : ids,
Expand All @@ -54,22 +64,15 @@ export class VideoSearch {

return data;
}
async formatUrl(url: string | string[]) {
private formatUrl(url: string | string[]) {
const urls: string[] = [];
if (!url) return urls;
if (typeof url === 'string') url = [url];

for (let u of url) {
u = String(u || '').trim();
if (!u) continue;
if (u.endsWith('.json')) {
const { data } = await req.get<Record<string, string>>(u, null, null, { rejectUnauthorized: false });
if (Array.isArray(data)) {
urls.push(...(await this.formatUrl(data as string[])));
} else {
urls.push(...Object.values(data));
}
} else if (u.startsWith('http')) {

if (u.startsWith('http')) {
if (u.endsWith('provide/')) u += 'vod/';
if (u.endsWith('provide/vod')) u += '/';
urls.push(u.replace('/at/xml/', '/'));
Expand All @@ -78,6 +81,41 @@ export class VideoSearch {

return [...new Set(urls)];
}
async updateApiFromRemote(force = false) {
const cache = stor.get();
let needReadFromRemote = true;

if (!force && cache.remoteConfig?.updateTime) {
needReadFromRemote = Date.now() - cache.remoteConfig.updateTime > 1 * 60 * 60 * 1000;
}

if (needReadFromRemote) {
const url = 'https://ghproxy.com/raw.githubusercontent.com/lzwme/m3u8-dl/main/test/remote-config.json';
const { data } = await req.get<M3u8StorConfig['remoteConfig']['data']>(
url,
null,
{ 'content-type': 'application/json' },
{ rejectUnauthorized: false }
);

if (Array.isArray(data.apiSites)) {
cache.remoteConfig = {
updateTime: Date.now(),
data,
};
stor.save();
}
}

if (Array.isArray(cache.remoteConfig?.data?.apiSites)) {
cache.remoteConfig.data.apiSites.forEach(item => {
if (item.enable === 0 || item.enable === false) return;
item.url = this.formatUrl(item.url)[0];
item.remote = true;
this.apiMap.set(item.url, item);
});
}
}
}

// const v = new VideoSearch({ api: ['https://api.xinlangapi.com/xinlangapi.php/provide/vod/'] });
Expand Down
19 changes: 19 additions & 0 deletions test/remote-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"apiSites": [
{
"url": "https://jyzyapi.com/provide/vod/",
"desc": "金鹰",
"enable": 1
},
{
"url": "https://jyzy1.com/provide/vod/",
"desc": "金鹰备用1",
"enable": 0
},
{
"url": "https://api.xinlangapi.com/xinlangapi.php/provide/vod/",
"desc": "新浪API",
"enable": 1
}
]
}

0 comments on commit 2a2a18a

Please sign in to comment.