mirror of
https://github.com/neosubhamoy/neodlp.git
synced 2025-12-19 22:32:58 +05:30
feat: added filename template option in settings
This commit is contained in:
@@ -87,6 +87,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const FORCE_INTERNET_PROTOCOL = useSettingsPageStatesStore(state => state.settings.force_internet_protocol);
|
const FORCE_INTERNET_PROTOCOL = useSettingsPageStatesStore(state => state.settings.force_internet_protocol);
|
||||||
const USE_CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
const USE_CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
||||||
const CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
const CUSTOM_COMMANDS = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
||||||
|
const FILENAME_TEMPLATE = useSettingsPageStatesStore(state => state.settings.filename_template);
|
||||||
|
|
||||||
const isErrored = useDownloaderPageStatesStore((state) => state.isErrored);
|
const isErrored = useDownloaderPageStatesStore((state) => state.isErrored);
|
||||||
const isErrorExpected = useDownloaderPageStatesStore((state) => state.isErrorExpected);
|
const isErrorExpected = useDownloaderPageStatesStore((state) => state.isErrorExpected);
|
||||||
@@ -124,7 +125,7 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const fetchVideoMetadata = async (url: string, formatId?: string, playlistIndex?: string, selectedSubtitles?: string | null, resumeState?: DownloadState, downloadConfig?: DownloadConfiguration): Promise<RawVideoInfo | null> => {
|
const fetchVideoMetadata = async (url: string, formatId?: string, playlistIndex?: string, selectedSubtitles?: string | null, resumeState?: DownloadState, downloadConfig?: DownloadConfiguration): Promise<RawVideoInfo | null> => {
|
||||||
try {
|
try {
|
||||||
const args = [url, '--dump-single-json', '--no-warnings'];
|
const args = [url, '--dump-single-json', '--no-warnings'];
|
||||||
if (formatId) args.push('-f', formatId);
|
if (formatId) args.push('--format', formatId);
|
||||||
if (selectedSubtitles) args.push('--embed-subs', '--sub-lang', selectedSubtitles);
|
if (selectedSubtitles) args.push('--embed-subs', '--sub-lang', selectedSubtitles);
|
||||||
if (playlistIndex) args.push('--playlist-items', playlistIndex);
|
if (playlistIndex) args.push('--playlist-items', playlistIndex);
|
||||||
if (PREFER_VIDEO_OVER_PLAYLIST && !playlistIndex) args.push('--no-playlist');
|
if (PREFER_VIDEO_OVER_PLAYLIST && !playlistIndex) args.push('--no-playlist');
|
||||||
@@ -285,12 +286,12 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
'--paths',
|
'--paths',
|
||||||
`home:${downloadDirPath}`,
|
`home:${downloadDirPath}`,
|
||||||
'--output',
|
'--output',
|
||||||
`%(title)s_%(resolution|unknown)s[${downloadId}].%(ext)s`,
|
`${FILENAME_TEMPLATE}[${downloadId}].%(ext)s`,
|
||||||
'--windows-filenames',
|
'--windows-filenames',
|
||||||
'--restrict-filenames',
|
'--restrict-filenames',
|
||||||
'--exec',
|
'--exec',
|
||||||
'after_move:echo Finalpath: {}',
|
'after_move:echo Finalpath: {}',
|
||||||
'-f',
|
'--format',
|
||||||
selectedFormat,
|
selectedFormat,
|
||||||
'--no-mtime',
|
'--no-mtime',
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ const addCustomCommandSchema = z.object({
|
|||||||
args: z.string().min(1, { message: "Arguments are required" }),
|
args: z.string().min(1, { message: "Arguments are required" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const filenameTemplateShcema = z.object({
|
||||||
|
template: z.string().min(1, { message: "Filename Template is required" }),
|
||||||
|
});
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const { setTheme } = useTheme();
|
const { setTheme } = useTheme();
|
||||||
|
|
||||||
@@ -118,6 +122,7 @@ export default function SettingsPage() {
|
|||||||
const forceInternetProtocol = useSettingsPageStatesStore(state => state.settings.force_internet_protocol);
|
const forceInternetProtocol = useSettingsPageStatesStore(state => state.settings.force_internet_protocol);
|
||||||
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
const useCustomCommands = useSettingsPageStatesStore(state => state.settings.use_custom_commands);
|
||||||
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
const customCommands = useSettingsPageStatesStore(state => state.settings.custom_commands);
|
||||||
|
const filenameTemplate = useSettingsPageStatesStore(state => state.settings.filename_template);
|
||||||
|
|
||||||
const websocketPort = useSettingsPageStatesStore(state => state.settings.websocket_port);
|
const websocketPort = useSettingsPageStatesStore(state => state.settings.websocket_port);
|
||||||
const isChangingWebSocketPort = useSettingsPageStatesStore(state => state.isChangingWebSocketPort);
|
const isChangingWebSocketPort = useSettingsPageStatesStore(state => state.isChangingWebSocketPort);
|
||||||
@@ -297,6 +302,30 @@ export default function SettingsPage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filenameTemplateForm = useForm<z.infer<typeof filenameTemplateShcema>>({
|
||||||
|
resolver: zodResolver(filenameTemplateShcema),
|
||||||
|
defaultValues: {
|
||||||
|
template: filenameTemplate,
|
||||||
|
},
|
||||||
|
mode: "onChange",
|
||||||
|
});
|
||||||
|
const watchedFilenameTemplate = filenameTemplateForm.watch("template");
|
||||||
|
const { errors: filenameTemplateFormErrors } = filenameTemplateForm.formState;
|
||||||
|
|
||||||
|
function handleFilenameTemplateSubmit(values: z.infer<typeof filenameTemplateShcema>) {
|
||||||
|
try {
|
||||||
|
saveSettingsKey('filename_template', values.template);
|
||||||
|
toast.success("Filename Template updated", {
|
||||||
|
description: `Filename Template changed to ${values.template}`,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error changing filename template:", error);
|
||||||
|
toast.error("Failed to change filename template", {
|
||||||
|
description: "An error occurred while trying to change the filename template. Please try again.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface Config {
|
interface Config {
|
||||||
port: number;
|
port: number;
|
||||||
}
|
}
|
||||||
@@ -372,7 +401,14 @@ export default function SettingsPage() {
|
|||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||||
<AlertDialogAction onClick={
|
<AlertDialogAction onClick={
|
||||||
() => resetSettings()
|
() => {
|
||||||
|
resetSettings()
|
||||||
|
proxyUrlForm.reset();
|
||||||
|
rateLimitForm.reset();
|
||||||
|
addCustomCommandForm.reset();
|
||||||
|
filenameTemplateForm.reset();
|
||||||
|
websocketPortForm.reset();
|
||||||
|
}
|
||||||
}>Reset</AlertDialogAction>
|
}>Reset</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
@@ -629,6 +665,36 @@ export default function SettingsPage() {
|
|||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="filename-template">
|
||||||
|
<h3 className="font-semibold">Filename Template</h3>
|
||||||
|
<p className="text-xs text-muted-foreground mb-3">Set the template for naming downloaded files (download id and file extension will be auto-appended at the end, changing template may cause paused downloads to re-start from begining)</p>
|
||||||
|
<Form {...filenameTemplateForm}>
|
||||||
|
<form onSubmit={filenameTemplateForm.handleSubmit(handleFilenameTemplateSubmit)} className="flex gap-4 w-full" autoComplete="off">
|
||||||
|
<FormField
|
||||||
|
control={filenameTemplateForm.control}
|
||||||
|
name="template"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="w-full">
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
className="focus-visible:ring-0"
|
||||||
|
placeholder="Enter filename template"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
disabled={!watchedFilenameTemplate || watchedFilenameTemplate === filenameTemplate || Object.keys(filenameTemplateFormErrors).length > 0}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
</TabsContent>
|
</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-[350px]">
|
||||||
<div className="video-format">
|
<div className="video-format">
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
|
|||||||
force_internet_protocol: 'ipv4',
|
force_internet_protocol: 'ipv4',
|
||||||
use_custom_commands: false,
|
use_custom_commands: false,
|
||||||
custom_commands: [],
|
custom_commands: [],
|
||||||
|
filename_template: '%(title)s_%(resolution|unknown)s',
|
||||||
// extension settings
|
// extension settings
|
||||||
websocket_port: 53511
|
websocket_port: 53511
|
||||||
},
|
},
|
||||||
@@ -239,6 +240,7 @@ export const useSettingsPageStatesStore = create<SettingsPageStatesStore>((set)
|
|||||||
force_internet_protocol: 'ipv4',
|
force_internet_protocol: 'ipv4',
|
||||||
use_custom_commands: false,
|
use_custom_commands: false,
|
||||||
custom_commands: [],
|
custom_commands: [],
|
||||||
|
filename_template: '%(title)s_%(resolution|unknown)s',
|
||||||
// extension settings
|
// extension settings
|
||||||
websocket_port: 53511
|
websocket_port: 53511
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export interface Settings {
|
|||||||
force_internet_protocol: string;
|
force_internet_protocol: string;
|
||||||
use_custom_commands: boolean;
|
use_custom_commands: boolean;
|
||||||
custom_commands: CustomCommand[];
|
custom_commands: CustomCommand[];
|
||||||
|
filename_template: string;
|
||||||
// extension settings
|
// extension settings
|
||||||
websocket_port: number;
|
websocket_port: number;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user