feat: expand platform adapters and preview tooling

This commit is contained in:
2026-05-13 19:40:43 +08:00
parent b81ead700d
commit 7a286fd619
44 changed files with 4370 additions and 115 deletions
+1151
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -20,6 +20,7 @@
"@vitejs/plugin-vue": "^5.2.3",
"typescript": "^5.7.3",
"vite": "^6.2.0",
"vite-plugin-vue-devtools": "^8.1.2",
"vue-tsc": "^2.2.0"
}
}
+5
View File
@@ -1,6 +1,7 @@
import axios from "axios";
import { ElNotification } from "element-plus";
import { markBackendAvailable, markBackendUnavailable } from "@/composables/useBackendStatus";
import { isNoBackendPreviewMode } from "@/utils/devPreview";
export const apiBaseUrl = import.meta.env.VITE_API_BASE_URL ?? "/api";
@@ -134,6 +135,10 @@ export function getApiErrorMessage(error: unknown, fallback = "请求失败,
}
function notifyBackendUnavailable(message: string) {
if (isNoBackendPreviewMode) {
return;
}
const now = Date.now();
if (now - lastBackendUnavailableNotificationAt < backendUnavailableNotificationIntervalMs) {
return;
+3
View File
@@ -5,5 +5,8 @@ import "element-plus/dist/index.css";
import App from "./App.vue";
import router from "./router";
import "./styles/main.css";
import { ensurePreviewSession } from "./utils/devPreview";
ensurePreviewSession();
createApp(App).use(createPinia()).use(router).use(ElementPlus).mount("#app");
+67 -7
View File
@@ -441,9 +441,7 @@ export interface SystemSettings {
enableAutoUpload: boolean;
deleteLocalFilesAfterUpload: boolean;
uploadTarget: number;
douyinProxy: PlatformProxySettings;
bilibiliProxy: PlatformProxySettings;
huyaProxy: PlatformProxySettings;
platformRequestSettings: Record<string, PlatformRequestSettings>;
webDavUpload: WebDavUploadSettings;
s3Upload: S3UploadSettings;
enableEventScripts: boolean;
@@ -482,9 +480,6 @@ export interface SystemSettings {
notifyWebhookOnLiveStarted: boolean;
notifyWebhookOnException: boolean;
webhookBodyTemplate: string;
douyinUserAgent: string;
douyinReferer: string;
douyinCookie: string;
}
export interface PlatformProxySettings {
@@ -492,6 +487,63 @@ export interface PlatformProxySettings {
proxyUrl: string;
}
export interface PlatformRequestSettings {
proxy: PlatformProxySettings;
userAgent: string;
referer: string;
cookie: string;
}
export interface PlatformOption {
key: string;
value: number;
label: string;
}
export const platformOptionList: PlatformOption[] = [
{ key: "douyin", value: 1, label: "Douyin" },
{ key: "bilibili", value: 2, label: "Bilibili" },
{ key: "huya", value: 3, label: "Huya" },
{ key: "douyu", value: 4, label: "Douyu" },
{ key: "kuaishou", value: 5, label: "Kuaishou" },
{ key: "tiktok", value: 6, label: "TikTok" },
{ key: "xiaohongshu", value: 7, label: "Xiaohongshu" },
{ key: "youtube", value: 8, label: "YouTube" },
{ key: "twitch", value: 9, label: "Twitch" },
{ key: "pandatv", value: 10, label: "PandaTV" },
{ key: "migu", value: 11, label: "Migu" }
];
export function createDefaultPlatformRequestSettingsMap(): Record<string, PlatformRequestSettings> {
const userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0";
const referers: Record<string, string> = {
douyin: "https://live.douyin.com/",
bilibili: "https://live.bilibili.com/",
huya: "https://www.huya.com/",
douyu: "https://www.douyu.com/",
kuaishou: "https://live.kuaishou.com/",
tiktok: "https://www.tiktok.com/",
xiaohongshu: "https://www.xiaohongshu.com/",
youtube: "https://www.youtube.com/",
twitch: "https://www.twitch.tv/",
pandatv: "https://www.pandalive.co.kr/",
migu: "https://www.miguvideo.com/"
};
return platformOptionList.reduce<Record<string, PlatformRequestSettings>>((accumulator, platform) => {
accumulator[platform.key] = {
proxy: {
enabled: false,
proxyUrl: ""
},
userAgent,
referer: referers[platform.key] ?? "",
cookie: ""
};
return accumulator;
}, {});
}
export interface WebDavUploadSettings {
endpoint: string;
basePath: string;
@@ -701,7 +753,15 @@ export const platformLabelMap: Record<number, string> = {
0: "未知",
1: "Douyin",
2: "Bilibili",
3: "Huya"
3: "Huya",
4: "Douyu",
5: "Kuaishou",
6: "TikTok",
7: "Xiaohongshu",
8: "YouTube",
9: "Twitch",
10: "PandaTV",
11: "Migu"
};
export const uploadTargetLabelMap: Record<number, string> = {
+42
View File
@@ -0,0 +1,42 @@
import type { AuthenticatedUser } from "@/types";
const TOKEN_STORAGE_KEY = "live-recorder-token";
const USER_STORAGE_KEY = "live-recorder-user";
const PREVIEW_TOKEN = "dev-preview-token";
const previewUser: AuthenticatedUser = {
userId: "dev-preview",
username: "preview",
displayName: "UI Preview",
token: PREVIEW_TOKEN,
expiresAt: "2099-12-31T23:59:59.000Z"
};
export const isNoBackendPreviewMode = import.meta.env.DEV && import.meta.env.VITE_PREVIEW_NO_BACKEND === "1";
function hasUsablePreviewUser(value: string | null) {
if (!value) {
return false;
}
try {
const parsed = JSON.parse(value) as Partial<AuthenticatedUser>;
return Boolean(parsed.userId && parsed.username && parsed.displayName);
} catch {
return false;
}
}
export function ensurePreviewSession() {
if (!isNoBackendPreviewMode || typeof window === "undefined") {
return;
}
if (!localStorage.getItem(TOKEN_STORAGE_KEY)) {
localStorage.setItem(TOKEN_STORAGE_KEY, PREVIEW_TOKEN);
}
if (!hasUsablePreviewUser(localStorage.getItem(USER_STORAGE_KEY))) {
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(previewUser));
}
}
+7 -3
View File
@@ -1,9 +1,13 @@
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import VueDevTools from "vite-plugin-vue-devtools";
import path from "node:path";
export default defineConfig({
plugins: [vue()],
export default defineConfig(({ command }) => ({
plugins: [
...(command === "serve" ? [VueDevTools()] : []),
vue()
],
resolve: {
alias: {
"@": path.resolve(__dirname, "src")
@@ -42,4 +46,4 @@ export default defineConfig({
}
}
}
});
}));