Files
gitlab-instance-0a899031_do…/web-console/lib/youtubeConfigUtils.ts
2026-03-29 01:17:00 -05:00

137 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 对齐 d2yexeapp electron `youtubeConfigUtils.ts` 的浏览器侧解析(无 OAuth */
export function parseYoutubeStreamKeySuffix(iniOrKeyLine: string): string {
for (const line of iniOrKeyLine.split(/\r?\n/)) {
const t = line.trim();
if (t.startsWith("#") || !t) continue;
const m = t.match(/^(?:key|stream_key)\s*=\s*(.+)$/i);
if (m) {
const v = m[1].trim().split(/[#;]/)[0].trim();
if (v && !v.toLowerCase().startsWith("rtmp")) return v.length > 8 ? v.slice(-8) : v;
if (v.includes("live2/")) {
const parts = v.split("/");
const last = parts[parts.length - 1] || "";
return last.length > 8 ? last.slice(-8) : last;
}
}
}
const one = iniOrKeyLine.trim();
if (one && !one.includes("\n") && !one.toLowerCase().startsWith("rtmp"))
return one.length > 8 ? one.slice(-8) : one;
return "";
}
export function extractDouyinLiveUrls(urlIni: string): string[] {
const out: string[] = [];
for (const line of urlIni.split(/\r?\n/)) {
const t = line.trim();
if (!t || t.startsWith("#")) continue;
if (!/douyin\.com|v\.douyin\.com/i.test(t)) continue;
const full = t.match(/(https?:\/\/live\.douyin\.com\/[a-zA-Z0-9_-]+)/i);
if (full) {
out.push(full[1].replace(/^http:\/\//i, "https://"));
continue;
}
const rel = t.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);
if (rel) {
out.push(`https://live.douyin.com/${rel[1]}`);
continue;
}
const n = t.match(/(\d{8,})/);
if (n) out.push(`https://live.douyin.com/${n[1]}`);
}
return Array.from(new Set(out)).slice(0, 16);
}
/** 从进程日志中解析「当前」抖音房间号(取文本中最后一次出现的 live.douyin.com/xxx */
export function extractDouyinCurrentRoomFromLog(logText: string): string | null {
if (!logText) return null;
let last: string | null = null;
for (const line of logText.split(/\r?\n/)) {
const m = line.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);
if (m) last = m[1];
const m2 = line.match(/https?:\/\/[^/\s]*douyin\.com\/(\d{8,})/i);
if (m2) last = m2[1];
}
return last;
}
/** URL_config 文本中提取抖音房间线索(与 d2y electron 一致) */
export function extractDouyinRoomHints(urlIni: string): string[] {
const out: string[] = [];
for (const line of urlIni.split(/\r?\n/)) {
const t = line.trim();
if (!t || t.startsWith("#")) continue;
if (!/douyin\.com|v\.douyin\.com/i.test(t)) continue;
const m = t.match(/live\.douyin\.com\/([a-zA-Z0-9_-]+)/i);
if (m) {
out.push(m[1]);
continue;
}
const n = t.match(/(\d{8,})/);
out.push(n ? n[1] : t.slice(0, 96));
}
return Array.from(new Set(out)).slice(0, 12);
}
export type YoutubeIniFields = {
key: string;
rtmps: boolean;
bitrate: string;
fastAudio: boolean;
};
export function parseYoutubeIniFields(content: string): YoutubeIniFields {
let key = "";
let rtmps = true;
let bitrate = "";
let fastAudio = false;
const lines = content.split(/\r?\n/);
let inYoutube = false;
for (const line of lines) {
const t = line.trim();
if (/^\[youtube\]/i.test(t)) {
inYoutube = true;
continue;
}
if (/^\[/.test(t)) {
inYoutube = false;
continue;
}
if (!inYoutube) continue;
if (!t || t.startsWith("#") || t.startsWith(";")) continue;
const eq = t.indexOf("=");
if (eq < 0) continue;
const k = t.slice(0, eq).trim().toLowerCase();
const v = t
.slice(eq + 1)
.trim()
.split(/[#;]/)[0]
.trim();
if (k === "key" || k === "stream_key") key = v;
else if (k === "rtmps") rtmps = !/^(0|false|否)/i.test(v);
else if (k === "bitrate") bitrate = v;
else if (k === "fast_audio") fastAudio = /^(1|true|yes|是|开|on)/i.test(v);
}
return { key, rtmps, bitrate, fastAudio };
}
export function buildYoutubeIniFromFields(f: YoutubeIniFields): string {
const bitrateLine = f.bitrate.trim()
? `bitrate = ${f.bitrate.trim()}`
: "# bitrate = 4000";
return `[youtube]
# YouTube 推流 key工作室 → 直播 → 串流密钥)
key = ${f.key.trim()}
# 使用 RTMPS填 否 则 RTMP
rtmps = ${f.rtmps ? "是" : "否"}
# 视频比特率 kbps可选
${bitrateLine}
# 轻量音频链,减轻 CPU1 / 是
fast_audio = ${f.fastAudio ? "1" : "0"}
`;
}