feat: Add proxy only for YouTube setting

This commit is contained in:
Peifan Li
2025-12-12 13:05:25 -05:00
parent 846c7ec728
commit 3ff2e5c7cd
11 changed files with 83 additions and 38 deletions

View File

@@ -3,9 +3,9 @@ import { Request, Response } from "express";
import fs from "fs-extra";
import path from "path";
import {
COLLECTIONS_DATA_PATH,
STATUS_DATA_PATH,
VIDEOS_DATA_PATH,
COLLECTIONS_DATA_PATH,
STATUS_DATA_PATH,
VIDEOS_DATA_PATH,
} from "../config/paths";
import downloadManager from "../services/downloadManager";
import * as storageService from "../services/storageService";
@@ -28,6 +28,7 @@ interface Settings {
itemsPerPage?: number;
ytDlpConfig?: string;
showYoutubeSearch?: boolean;
proxyOnlyYoutube?: boolean;
}
const defaultSettings: Settings = {

View File

@@ -4,21 +4,21 @@ import path from "path";
import { IMAGES_DIR, SUBTITLES_DIR, VIDEOS_DIR } from "../../config/paths";
import { bccToVtt } from "../../utils/bccToVtt";
import {
calculateDownloadedSize,
formatBytes,
isCancellationError,
isDownloadActive,
parseSize,
calculateDownloadedSize,
formatBytes,
isCancellationError,
isDownloadActive,
parseSize,
} from "../../utils/downloadUtils";
import {
extractBilibiliVideoId,
formatVideoFilename,
extractBilibiliVideoId,
formatVideoFilename,
} from "../../utils/helpers";
import {
executeYtDlpJson,
executeYtDlpSpawn,
getNetworkConfigFromUserConfig,
getUserYtDlpConfig,
executeYtDlpJson,
executeYtDlpSpawn,
getNetworkConfigFromUserConfig,
getUserYtDlpConfig,
} from "../../utils/ytDlpUtils";
import * as storageService from "../storageService";
import { Collection, Video } from "../storageService";
@@ -126,7 +126,7 @@ export class BilibiliDownloader {
console.log("Extracted mid:", mid);
// Get user config for network options (cookies, proxy, etc.)
const userConfig = getUserYtDlpConfig();
const userConfig = getUserYtDlpConfig(spaceUrl);
const networkConfig = getNetworkConfigFromUserConfig(userConfig);
// Use yt-dlp to get the latest video from the user's space
@@ -212,11 +212,11 @@ export class BilibiliDownloader {
thumbnailUrl: string;
}> {
try {
// Get user config for network options
const userConfig = getUserYtDlpConfig();
const networkConfig = getNetworkConfigFromUserConfig(userConfig);
const videoUrl = `https://www.bilibili.com/video/${videoId}`;
// Get user config for network options
const userConfig = getUserYtDlpConfig(videoUrl);
const networkConfig = getNetworkConfigFromUserConfig(userConfig);
const info = await executeYtDlpJson(videoUrl, {
...networkConfig,
noWarnings: true,
@@ -282,7 +282,7 @@ export class BilibiliDownloader {
console.log("Downloading Bilibili video using yt-dlp to:", tempDir);
// Get user's yt-dlp configuration for network settings
const userConfig = getUserYtDlpConfig();
const userConfig = getUserYtDlpConfig(url);
const networkConfig = getNetworkConfigFromUserConfig(userConfig);
// Get video info first (with network config)

View File

@@ -3,19 +3,19 @@ import fs from "fs-extra";
import path from "path";
import { IMAGES_DIR, SUBTITLES_DIR, VIDEOS_DIR } from "../../config/paths";
import {
calculateDownloadedSize,
cleanupPartialVideoFiles,
cleanupSubtitleFiles,
isCancellationError,
isDownloadActive,
parseSize,
calculateDownloadedSize,
cleanupPartialVideoFiles,
cleanupSubtitleFiles,
isCancellationError,
isDownloadActive,
parseSize,
} from "../../utils/downloadUtils";
import { formatVideoFilename } from "../../utils/helpers";
import {
executeYtDlpJson,
executeYtDlpSpawn,
getNetworkConfigFromUserConfig,
getUserYtDlpConfig,
executeYtDlpJson,
executeYtDlpSpawn,
getNetworkConfigFromUserConfig,
getUserYtDlpConfig,
} from "../../utils/ytDlpUtils";
import * as storageService from "../storageService";
import { Video } from "../storageService";
@@ -130,7 +130,7 @@ export class YtDlpDownloader {
}> {
try {
// Get user config for network options
const userConfig = getUserYtDlpConfig();
const userConfig = getUserYtDlpConfig(url);
const networkConfig = getNetworkConfigFromUserConfig(userConfig);
const info = await executeYtDlpJson(url, {
@@ -165,7 +165,7 @@ export class YtDlpDownloader {
console.log("Fetching latest video for channel:", channelUrl);
// Get user config for network options
const userConfig = getUserYtDlpConfig();
const userConfig = getUserYtDlpConfig(channelUrl);
const networkConfig = getNetworkConfigFromUserConfig(userConfig);
// Append /videos to channel URL to ensure we get videos and not the channel tab
@@ -315,7 +315,7 @@ export class YtDlpDownloader {
}
// Get user's yt-dlp configuration
const userConfig = getUserYtDlpConfig();
const userConfig = getUserYtDlpConfig(videoUrl);
// Default format based on user config or fallback
let defaultFormat =

View File

@@ -305,13 +305,30 @@ export function parseYtDlpConfig(configText: string): Record<string, any> {
/**
* Get user's yt-dlp configuration from settings
* @param url - Optional URL to contextually filter settings (e.g. proxy only for YouTube)
*/
export function getUserYtDlpConfig(): Record<string, any> {
export function getUserYtDlpConfig(url?: string): Record<string, any> {
try {
const settings = storageService.getSettings();
if (settings.ytDlpConfig) {
const parsedConfig = parseYtDlpConfig(settings.ytDlpConfig);
const configText = settings.ytDlpConfig;
const proxyOnlyYoutube = settings.proxyOnlyYoutube === true;
if (configText) {
const parsedConfig = parseYtDlpConfig(configText);
console.log("Parsed user yt-dlp config:", parsedConfig);
// If proxy is restricted to YouTube only, and we have a non-YouTube URL
if (proxyOnlyYoutube && url) {
const isYoutube = url.includes("youtube.com") || url.includes("youtu.be");
if (!isYoutube) {
console.log("Proxy restricted to YouTube only. Removing proxy settings for:", url);
// Remove proxy-related settings
delete parsedConfig.proxy;
// Also remove potentially related network options if they are usually proxy-specific?
// sticking to just 'proxy' as per request and standard usage.
}
}
return parsedConfig;
}
} catch (error) {

View File

@@ -2,7 +2,9 @@ import {
Box,
Button,
Collapse,
FormControlLabel,
Link,
Switch,
TextField,
Typography
} from '@mui/material';
@@ -11,7 +13,9 @@ import { useLanguage } from '../../contexts/LanguageContext';
interface YtDlpSettingsProps {
config: string;
proxyOnlyYoutube?: boolean;
onChange: (config: string) => void;
onProxyOnlyYoutubeChange?: (checked: boolean) => void;
}
// Default yt-dlp configuration
@@ -206,7 +210,7 @@ const DEFAULT_CONFIG = `# yt-dlp Configuration File
`;
const YtDlpSettings: React.FC<YtDlpSettingsProps> = ({ config, onChange }) => {
const YtDlpSettings: React.FC<YtDlpSettingsProps> = ({ config, proxyOnlyYoutube = false, onChange, onProxyOnlyYoutubeChange }) => {
const { t } = useLanguage();
const [isExpanded, setIsExpanded] = useState(false);
const [localConfig, setLocalConfig] = useState(config || DEFAULT_CONFIG);
@@ -264,6 +268,21 @@ const YtDlpSettings: React.FC<YtDlpSettingsProps> = ({ config, onChange }) => {
<Collapse in={isExpanded}>
<Box sx={{ mt: 2 }}>
{/* Proxy Toggle */}
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
<FormControlLabel
control={
<Switch
checked={proxyOnlyYoutube}
onChange={(e) => onProxyOnlyYoutubeChange && onProxyOnlyYoutubeChange(e.target.checked)}
color="primary"
/>
}
label={t('proxyOnlyApplyToYoutube') || "Proxy only apply to Youtube"}
/>
</Box>
<TextField
fullWidth
multiline

View File

@@ -52,7 +52,8 @@ const SettingsPage: React.FC = () => {
cloudDrivePath: '',
itemsPerPage: 12,
ytDlpConfig: '',
showYoutubeSearch: true
showYoutubeSearch: true,
proxyOnlyYoutube: false
});
const [message, setMessage] = useState<{ text: string; type: 'success' | 'error' | 'warning' | 'info' } | null>(null);
const debouncedSettings = useDebounce(settings, 1000);
@@ -413,7 +414,9 @@ const SettingsPage: React.FC = () => {
<Grid size={12}>
<YtDlpSettings
config={settings.ytDlpConfig || ''}
proxyOnlyYoutube={settings.proxyOnlyYoutube || false}
onChange={(config) => handleChange('ytDlpConfig', config)}
onProxyOnlyYoutubeChange={(checked) => handleChange('proxyOnlyYoutube', checked)}
/>
</Grid>

View File

@@ -73,4 +73,5 @@ export interface Settings {
itemsPerPage?: number;
ytDlpConfig?: string;
showYoutubeSearch?: boolean;
proxyOnlyYoutube?: boolean;
}

View File

@@ -454,4 +454,5 @@ export const en = {
hide: "Hide",
reset: "Reset",
more: "More",
proxyOnlyApplyToYoutube: 'Proxy only apply to Youtube',
};

View File

@@ -453,4 +453,5 @@ export const ja = {
hide: "隠す",
reset: "リセット",
more: "もっと見る",
proxyOnlyApplyToYoutube: 'Proxy only apply to Youtube',
};

View File

@@ -447,4 +447,5 @@ export const ko = {
hide: "숨기기",
reset: "초기화",
more: "더 보기",
proxyOnlyApplyToYoutube: 'Proxy only apply to Youtube',
};

View File

@@ -443,4 +443,5 @@ export const zh = {
hide: "隐藏",
reset: "重置",
more: "更多",
proxyOnlyApplyToYoutube: '代理仅应用于 Youtube',
};