feat: added debug mode and optimized logging

This commit is contained in:
2025-10-26 23:48:35 +05:30
parent 14fed76c1e
commit 9150fc22f7
8 changed files with 101 additions and 19 deletions

View File

@@ -88,6 +88,10 @@ export default function App({ children }: { children: React.ReactNode }) {
const USE_CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
const CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.custom_commands);
const FILENAME_TEMPLATE = useSettingsPageStatesStore(state => state.settings.filename_template);
const DEBUG_MODE = useSettingsPageStatesStore(state => state.settings.debug_mode);
const LOG_VERBOSE = useSettingsPageStatesStore(state => state.settings.log_verbose);
const LOG_WARNING = useSettingsPageStatesStore(state => state.settings.log_warning);
const LOG_PROGRESS = useSettingsPageStatesStore(state => state.settings.log_progress);
const isErrored = useDownloaderPageStatesStore((state) => state.isErrored);
const isErrorExpected = useDownloaderPageStatesStore((state) => state.isErrorExpected);
@@ -295,7 +299,6 @@ export default function App({ children }: { children: React.ReactNode }) {
'--format',
selectedFormat,
'--no-mtime',
'--no-warnings',
'--retries',
MAX_RETRIES.toString(),
];
@@ -304,6 +307,14 @@ export default function App({ children }: { children: React.ReactNode }) {
args.push('--ffmpeg-location', '/Applications/NeoDLP.app/Contents/MacOS');
}
if (!DEBUG_MODE || (DEBUG_MODE && !LOG_WARNING)) {
args.push('--no-warnings');
}
if (DEBUG_MODE && LOG_VERBOSE) {
args.push('--verbose');
}
if (selectedSubtitles) {
args.push('--embed-subs', '--sub-lang', selectedSubtitles);
}
@@ -462,7 +473,7 @@ export default function App({ children }: { children: React.ReactNode }) {
command.stdout.on('data', line => {
if (line.startsWith('status:') || line.startsWith('[#')) {
console.log(line);
LOG.info(`YT-DLP Download ${downloadId}`, line);
if (DEBUG_MODE && LOG_PROGRESS) LOG.progress(`YT-DLP Download ${downloadId}`, line);
const currentProgress = parseProgressLine(line);
const state: DownloadState = {
download_id: downloadId,
@@ -653,6 +664,7 @@ export default function App({ children }: { children: React.ReactNode }) {
if (!ongoingDownloads || ongoingDownloads && ongoingDownloads?.length < MAX_PARALLEL_DOWNLOADS) {
LOG.info('NEODLP', `Starting yt-dlp download with args: ${args.join(' ')}`);
if(!DEBUG_MODE || (DEBUG_MODE && !LOG_PROGRESS)) LOG.warning('NEODLP', `Progress logs are hidden. Enable 'Debug Mode > Log Progress' in Settings to unhide.`);
const child = await command.spawn();
processPid = child.pid;
return Promise.resolve();

View File

@@ -41,7 +41,7 @@ export default function Navbar() {
<p className="text-sm text-muted-foreground">NO LOGS TO SHOW!</p>
) : (
logs.slice().reverse().map((log, index) => (
<div key={index} className={`flex flex-col ${log.level === 'error' ? 'text-red-500' : log.level === 'warning' ? 'text-amber-500' : log.level === 'debug' ? 'text-sky-500' : 'text-foreground'}`}>
<div key={index} className={`flex flex-col ${log.level === 'error' ? 'text-red-500' : log.level === 'warning' ? 'text-amber-500' : log.level === 'debug' ? 'text-sky-500' : log.level === 'progress' ? 'text-emerald-500' : 'text-foreground'}`}>
<p className="text-xs"><strong>{new Date(log.timestamp).toLocaleTimeString()}</strong> [{log.level.toUpperCase()}] <em>{log.context}</em> :</p>
<p className="text-xs font-mono break-all">{log.message}</p>
</div>

View File

@@ -18,9 +18,12 @@ export function useLogger() {
debug: (context: string, message: string) => {
addLog({ timestamp: Date.now(), level: 'debug', context, message });
},
progress: (context: string, message: string) => {
addLog({ timestamp: Date.now(), level: 'progress', context, message });
},
getLogs: () => logs,
clearLogs,
};
return logger;
}
}

View File

@@ -6,7 +6,7 @@ import { Progress } from "@/components/ui/progress";
import { Separator } from "@/components/ui/separator";
import { toast } from "sonner";
import { useAppContext } from "@/providers/appContextProvider";
import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useDownloadStatesStore, useLibraryPageStatesStore } from "@/services/store";
import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useDownloadStatesStore, useLibraryPageStatesStore, useSettingsPageStatesStore } from "@/services/store";
import { formatBitrate, formatCodec, formatDurationString, formatFileSize, formatSecToTimeString, formatSpeed } from "@/utils";
import { AudioLines, Clock, File, FileAudio2, FileQuestion, FileVideo2, FolderInput, ListVideo, Loader2, Music, Pause, Play, Search, Square, Trash2, Video, X } from "lucide-react";
import { invoke } from "@tauri-apps/api/core";
@@ -34,6 +34,8 @@ export default function LibraryPage() {
const setIsCancelingDownload = useDownloadActionStatesStore(state => state.setIsCancelingDownload);
const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked);
const debugMode = useSettingsPageStatesStore(state => state.settings.debug_mode);
const { pauseDownload, resumeDownload, cancelDownload } = useAppContext()
const queryClient = useQueryClient();
@@ -379,7 +381,7 @@ export default function LibraryPage() {
</div>
)}
<div className="text-xs text-muted-foreground">{ state.download_status && (
`${state.download_status === 'downloading' && state.status === 'finished' ? 'Processing' : state.download_status.charAt(0).toUpperCase() + state.download_status.slice(1)} ${state.download_id ? `• ID: ${state.download_id.toUpperCase()}` : ""} ${state.download_status === 'downloading' && state.status !== 'finished' && state.speed ? `• Speed: ${formatSpeed(state.speed)}` : ""} ${state.download_status === 'downloading' && state.eta ? `• ETA: ${formatSecToTimeString(state.eta)}` : ""}`
`${state.download_status === 'downloading' && state.status === 'finished' ? 'Processing' : state.download_status.charAt(0).toUpperCase() + state.download_status.slice(1)} ${debugMode && state.download_id ? `• ID: ${state.download_id.toUpperCase()}` : ""} ${state.download_status === 'downloading' && state.status !== 'finished' && state.speed ? `• Speed: ${formatSpeed(state.speed)}` : ""} ${state.download_status === 'downloading' && state.eta ? `• ETA: ${formatSecToTimeString(state.eta)}` : ""}`
)}</div>
</div>
<div className="w-full flex items-center gap-2 mt-2">

View File

@@ -7,7 +7,7 @@ import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import { ArrowDownToLine, ArrowRight, BrushCleaning, Cookie, EthernetPort, ExternalLink, FileVideo, Folder, FolderOpen, Info, Loader2, LucideIcon, Monitor, Moon, Radio, RotateCcw, RotateCw, ShieldMinus, SquareTerminal, Sun, Terminal, Trash, TriangleAlert, WandSparkles, Wifi, Wrench } from "lucide-react";
import { ArrowDownToLine, ArrowRight, BrushCleaning, Bug, Cookie, EthernetPort, ExternalLink, FileVideo, Folder, FolderOpen, Info, Loader2, LucideIcon, Monitor, Moon, Radio, RotateCcw, RotateCw, ShieldMinus, SquareTerminal, Sun, Terminal, Trash, TriangleAlert, WandSparkles, Wifi, Wrench } from "lucide-react";
import { cn } from "@/lib/utils";
import { useEffect } from "react";
import { useTheme } from "@/providers/themeProvider";
@@ -123,6 +123,10 @@ export default function SettingsPage() {
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
const filenameTemplate = useSettingsPageStatesStore(state => state.settings.filename_template);
const debugMode = useSettingsPageStatesStore(state => state.settings.debug_mode);
const logVerbose = useSettingsPageStatesStore(state => state.settings.log_verbose);
const logWarning = useSettingsPageStatesStore(state => state.settings.log_warning);
const logProgress = useSettingsPageStatesStore(state => state.settings.log_progress);
const websocketPort = useSettingsPageStatesStore(state => state.settings.websocket_port);
const isChangingWebSocketPort = useSettingsPageStatesStore(state => state.isChangingWebSocketPort);
@@ -525,9 +529,14 @@ export default function SettingsPage() {
value="commands"
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
><SquareTerminal className="size-4" /> Commands</TabsTrigger>
<TabsTrigger
key="debug"
value="debug"
className="data-[state=active]:bg-primary data-[state=active]:text-primary-foreground justify-start px-3 py-1.5 gap-2"
><Bug className="size-4" /> Debug</TabsTrigger>
</TabsList>
<div className="min-h-full flex flex-col max-w-[55%] w-full border-l border-border pl-4">
<TabsContent key="general" value="general" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="general" value="general" className="flex flex-col gap-4 min-h-[385px]">
<div className="max-parallel-downloads">
<h3 className="font-semibold">Max Parallel Downloads</h3>
<p className="text-xs text-muted-foreground mb-3">Set maximum number of allowed parallel downloads</p>
@@ -583,7 +592,7 @@ export default function SettingsPage() {
/>
</div>
</TabsContent>
<TabsContent key="appearance" value="appearance" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="appearance" value="appearance" className="flex flex-col gap-4 min-h-[385px]">
<div className="app-theme">
<h3 className="font-semibold">Theme</h3>
<p className="text-xs text-muted-foreground mb-3">Choose app interface theme</p>
@@ -606,7 +615,7 @@ export default function SettingsPage() {
</div>
</div>
</TabsContent>
<TabsContent key="folders" value="folders" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="folders" value="folders" className="flex flex-col gap-4 min-h-[385px]">
<div className="download-dir">
<h3 className="font-semibold">Download Folder</h3>
<p className="text-xs text-muted-foreground mb-3">Set default download folder (directory)</p>
@@ -696,7 +705,7 @@ export default function SettingsPage() {
</Form>
</div>
</TabsContent>
<TabsContent key="formats" value="formats" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="formats" value="formats" className="flex flex-col gap-4 min-h-[385px]">
<div className="video-format">
<h3 className="font-semibold">Video Format</h3>
<p className="text-xs text-muted-foreground mb-3">Choose in which format the final video file will be saved</p>
@@ -764,7 +773,7 @@ export default function SettingsPage() {
/>
</div>
</TabsContent>
<TabsContent key="metadata" value="metadata" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="metadata" value="metadata" className="flex flex-col gap-4 min-h-[385px]">
<div className="embed-video-metadata">
<h3 className="font-semibold">Embed Metadata</h3>
<p className="text-xs text-muted-foreground mb-3">Wheather to embed metadata in video/audio files (info, chapters)</p>
@@ -798,7 +807,7 @@ export default function SettingsPage() {
/>
</div>
</TabsContent>
<TabsContent key="network" value="network" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="network" value="network" className="flex flex-col gap-4 min-h-[385px]">
<div className="proxy">
<h3 className="font-semibold">Proxy</h3>
<p className="text-xs text-muted-foreground mb-3">Use proxy for downloads, Unblocks blocked sites in your region (download speed may affect, some sites may not work)</p>
@@ -893,7 +902,7 @@ export default function SettingsPage() {
onCheckedChange={(checked) => saveSettingsKey('use_force_internet_protocol', checked)}
disabled={useCustomCommands}
/>
<Label htmlFor="use-force-internet-protocol">Force</Label>
<Label htmlFor="use-force-internet-protocol">Force IPV</Label>
</div>
<RadioGroup
orientation="horizontal"
@@ -914,7 +923,7 @@ export default function SettingsPage() {
<Label className="text-xs text-muted-foreground">(Forced: {forceInternetProtocol === "ipv4" ? 'IPv4' : 'IPv6'}, Status: {useForceInternetProtocol && !useCustomCommands ? 'Enabled' : 'Disabled'})</Label>
</div>
</TabsContent>
<TabsContent key="cookies" value="cookies" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="cookies" value="cookies" className="flex flex-col gap-4 min-h-[385px]">
<div className="cookies">
<h3 className="font-semibold">Cookies</h3>
<p className="text-xs text-muted-foreground mb-3">Use cookies to access exclusive/private (login-protected) contents from sites (use wisely, over-use can even block/ban your account)</p>
@@ -1003,7 +1012,7 @@ export default function SettingsPage() {
<Label className="text-xs text-muted-foreground">(Configured: {importCookiesFrom === "browser" ? 'Yes' : cookiesFile ? 'Yes' : 'No'}, From: {importCookiesFrom === "browser" ? 'Browser' : 'Text'}, Status: {useCookies && !useCustomCommands ? 'Enabled' : 'Disabled'})</Label>
</div>
</TabsContent>
<TabsContent key="sponsorblock" value="sponsorblock" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="sponsorblock" value="sponsorblock" className="flex flex-col gap-4 min-h-[385px]">
<div className="sponsorblock">
<h3 className="font-semibold">Sponsor Block</h3>
<p className="text-xs text-muted-foreground mb-3">Use sponsorblock to remove/mark unwanted segments in videos (sponsorships, intros, outros, etc.)</p>
@@ -1127,7 +1136,7 @@ export default function SettingsPage() {
<Label className="text-xs text-muted-foreground">(Configured: {sponsorblockMode === "remove" && sponsorblockRemove === "custom" && sponsorblockRemoveCategories.length <= 0 ? 'No' : sponsorblockMode === "mark" && sponsorblockMark === "custom" && sponsorblockMarkCategories.length <= 0 ? 'No' : 'Yes'}, Mode: {sponsorblockMode === "remove" ? 'Remove' : 'Mark'}, Status: {useSponsorblock && !useCustomCommands ? 'Enabled' : 'Disabled'})</Label>
</div>
</TabsContent>
<TabsContent key="commands" value="commands" className="flex flex-col gap-4 min-h-[350px]">
<TabsContent key="commands" value="commands" className="flex flex-col gap-4 min-h-[385px]">
<div className="custom-commands">
<h3 className="font-semibold">Custom Commands</h3>
<p className="text-xs text-muted-foreground mb-3"> Run custom yt-dlp commands for your downloads</p>
@@ -1229,6 +1238,50 @@ export default function SettingsPage() {
</div>
</div>
</TabsContent>
<TabsContent key="debug" value="debug" className="flex flex-col gap-4 min-h-[385px]">
<div className="debug-mode">
<h3 className="font-semibold">Debug Mode</h3>
<p className="text-xs text-muted-foreground mb-3">Enable debug mode for troubleshooting issues (get debug logs, download ids, and more)</p>
<div className="flex items-center space-x-2 mb-4">
<Switch
id="debug-mode"
checked={debugMode}
onCheckedChange={(checked) => saveSettingsKey('debug_mode', checked)}
/>
<Label htmlFor="debug-mode">Enable Debug Mode</Label>
</div>
<div className="flex flex-col gap-2 mt-5">
<Label className="text-xs mb-1">Logging Options</Label>
<div className="flex items-center space-x-2 mb-1">
<Switch
id="log-verbose"
checked={logVerbose}
onCheckedChange={(checked) => saveSettingsKey('log_verbose', checked)}
disabled={!debugMode}
/>
<Label htmlFor="log-verbose">Verbose Logging</Label>
</div>
<div className="flex items-center space-x-2 mb-1">
<Switch
id="log-warning"
checked={logWarning}
onCheckedChange={(checked) => saveSettingsKey('log_warning', checked)}
disabled={!debugMode}
/>
<Label htmlFor="log-warning">Log Warnings</Label>
</div>
<div className="flex items-center space-x-2 mb-1">
<Switch
id="log-progress"
checked={logProgress}
onCheckedChange={(checked) => saveSettingsKey('log_progress', checked)}
disabled={!debugMode}
/>
<Label htmlFor="log-progress">Log Progress</Label>
</div>
</div>
</div>
</TabsContent>
</div>
</Tabs>
</TabsContent>

View File

@@ -180,6 +180,10 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
use_custom_commands: false,
custom_commands: [],
filename_template: '%(title)s_%(resolution|unknown)s',
debug_mode: false,
log_verbose: true,
log_warning: true,
log_progress: false,
// extension settings
websocket_port: 53511
},
@@ -241,6 +245,10 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
use_custom_commands: false,
custom_commands: [],
filename_template: '%(title)s_%(resolution|unknown)s',
debug_mode: false,
log_verbose: true,
log_warning: true,
log_progress: false,
// extension settings
websocket_port: 53511
},

View File

@@ -1,6 +1,6 @@
export interface Log {
timestamp: number;
level: 'info' | 'warning' | 'error' | 'debug';
level: 'info' | 'warning' | 'error' | 'debug' | 'progress';
context: string;
message: string;
}
}

View File

@@ -44,6 +44,10 @@ export interface Settings {
use_custom_commands: boolean;
custom_commands: CustomCommand[];
filename_template: string;
debug_mode: boolean;
log_verbose: boolean;
log_warning: boolean;
log_progress: boolean;
// extension settings
websocket_port: number;
}