mirror of
https://github.com/neosubhamoy/neodlp.git
synced 2025-12-20 03:09:33 +05:30
feat: added square crop thumbnail config
This commit is contained in:
686
package-lock.json
generated
686
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@@ -39,9 +39,9 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.10",
|
"@radix-ui/react-toggle": "^1.1.10",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.11",
|
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
"@tanstack/react-query": "^5.90.8",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"@tanstack/react-query-devtools": "^5.90.2",
|
"@tanstack/react-query-devtools": "^5.91.1",
|
||||||
"@tauri-apps/api": "^2.9.0",
|
"@tauri-apps/api": "^2.9.1",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
|
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
|
||||||
"@tauri-apps/plugin-dialog": "^2.4.2",
|
"@tauri-apps/plugin-dialog": "^2.4.2",
|
||||||
"@tauri-apps/plugin-fs": "^2.4.4",
|
"@tauri-apps/plugin-fs": "^2.4.4",
|
||||||
@@ -57,36 +57,36 @@
|
|||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"es-toolkit": "^1.41.0",
|
"es-toolkit": "^1.43.0",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^0.553.0",
|
"lucide-react": "^0.561.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.3",
|
||||||
"react-day-picker": "^9.11.1",
|
"react-day-picker": "^9.12.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.3",
|
||||||
"react-hook-form": "^7.66.0",
|
"react-hook-form": "^7.68.0",
|
||||||
"react-resizable-panels": "^3.0.6",
|
"react-resizable-panels": "^3.0.6",
|
||||||
"react-router-dom": "^7.9.5",
|
"react-router-dom": "^7.10.1",
|
||||||
"recharts": "^3.4.1",
|
"recharts": "^3.6.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.4.0",
|
||||||
"ulid": "^3.0.1",
|
"ulid": "^3.0.2",
|
||||||
"vaul": "^1.1.2",
|
"vaul": "^1.1.2",
|
||||||
"zod": "^4.1.12",
|
"zod": "^4.2.0",
|
||||||
"zustand": "^5.0.8"
|
"zustand": "^5.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.18",
|
||||||
"@tailwindcss/vite": "^4.1.17",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@tauri-apps/cli": "^2.9.4",
|
"@tauri-apps/cli": "^2.9.6",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^25.0.2",
|
||||||
"@types/react": "^19.2.3",
|
"@types/react": "^19.2.7",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^5.1.1",
|
"@vitejs/plugin-react": "^5.1.2",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"tailwindcss": "^4.1.17",
|
"tailwindcss": "^4.1.18",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.9.3",
|
||||||
"vite": "^7.2.2"
|
"vite": "^7.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
688
src-tauri/Cargo.lock
generated
688
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -151,8 +151,83 @@ pub fn get_migrations() -> Vec<Migration> {
|
|||||||
},
|
},
|
||||||
Migration {
|
Migration {
|
||||||
version: 3,
|
version: 3,
|
||||||
description: "add_performance_indexes",
|
description: "add_more_columns_and_indexes_to_downloads",
|
||||||
sql: "
|
sql: "
|
||||||
|
-- Create temporary table with all new columns
|
||||||
|
CREATE TABLE downloads_temp (
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
download_id TEXT UNIQUE NOT NULL,
|
||||||
|
download_status TEXT NOT NULL,
|
||||||
|
video_id TEXT NOT NULL,
|
||||||
|
format_id TEXT NOT NULL,
|
||||||
|
subtitle_id TEXT,
|
||||||
|
queue_index INTEGER,
|
||||||
|
playlist_id TEXT,
|
||||||
|
playlist_index INTEGER,
|
||||||
|
resolution TEXT,
|
||||||
|
ext TEXT,
|
||||||
|
abr REAL,
|
||||||
|
vbr REAL,
|
||||||
|
acodec TEXT,
|
||||||
|
vcodec TEXT,
|
||||||
|
dynamic_range TEXT,
|
||||||
|
process_id INTEGER,
|
||||||
|
status TEXT,
|
||||||
|
progress REAL,
|
||||||
|
total INTEGER,
|
||||||
|
downloaded INTEGER,
|
||||||
|
speed REAL,
|
||||||
|
eta INTEGER,
|
||||||
|
filepath TEXT,
|
||||||
|
filetype TEXT,
|
||||||
|
filesize INTEGER,
|
||||||
|
output_format TEXT,
|
||||||
|
embed_metadata INTEGER NOT NULL DEFAULT 0,
|
||||||
|
embed_thumbnail INTEGER NOT NULL DEFAULT 0,
|
||||||
|
square_crop_thumbnail INTEGER NOT NULL DEFAULT 0,
|
||||||
|
sponsorblock_remove TEXT,
|
||||||
|
sponsorblock_mark TEXT,
|
||||||
|
use_aria2 INTEGER NOT NULL DEFAULT 0,
|
||||||
|
custom_command TEXT,
|
||||||
|
queue_config TEXT,
|
||||||
|
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (video_id) REFERENCES video_info (video_id),
|
||||||
|
FOREIGN KEY (playlist_id) REFERENCES playlist_info (playlist_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Copy all data from original table to temporary table with default values for new columns
|
||||||
|
INSERT INTO downloads_temp SELECT
|
||||||
|
id, download_id, download_status, video_id, format_id, subtitle_id,
|
||||||
|
queue_index, playlist_id, playlist_index, resolution, ext, abr, vbr,
|
||||||
|
acodec, vcodec, dynamic_range, process_id, status, progress, total,
|
||||||
|
downloaded, speed, eta, filepath, filetype, filesize,
|
||||||
|
output_format,
|
||||||
|
embed_metadata,
|
||||||
|
embed_thumbnail,
|
||||||
|
0, -- square_crop_thumbnail
|
||||||
|
sponsorblock_remove, sponsorblock_mark, use_aria2,
|
||||||
|
custom_command, queue_config, created_at, updated_at
|
||||||
|
FROM downloads;
|
||||||
|
|
||||||
|
-- Remove existing triggers
|
||||||
|
DROP TRIGGER IF EXISTS update_downloads_updated_at;
|
||||||
|
|
||||||
|
-- Drop the original table
|
||||||
|
DROP TABLE downloads;
|
||||||
|
|
||||||
|
-- Rename temporary table to original name
|
||||||
|
ALTER TABLE downloads_temp RENAME TO downloads;
|
||||||
|
|
||||||
|
-- Create trigger for updating updated_at timestamp
|
||||||
|
CREATE TRIGGER IF NOT EXISTS update_downloads_updated_at
|
||||||
|
AFTER UPDATE ON downloads
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE downloads SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Add indexes to improve query performance
|
||||||
CREATE INDEX IF NOT EXISTS idx_downloads_video_id ON downloads(video_id);
|
CREATE INDEX IF NOT EXISTS idx_downloads_video_id ON downloads(video_id);
|
||||||
CREATE INDEX IF NOT EXISTS idx_downloads_playlist_id ON downloads(playlist_id);
|
CREATE INDEX IF NOT EXISTS idx_downloads_playlist_id ON downloads(playlist_id);
|
||||||
CREATE INDEX IF NOT EXISTS idx_downloads_status_updated ON downloads(download_status, updated_at DESC);
|
CREATE INDEX IF NOT EXISTS idx_downloads_status_updated ON downloads(download_status, updated_at DESC);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
|
|||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
|
|
||||||
interface DownloadConfigDialogProps {
|
interface DownloadConfigDialogProps {
|
||||||
selectedFormatFileType: "video+audio" | "video" | "audio" | "unknown";
|
selectedFormatFileType: "video+audio" | "video" | "audio" | "unknown";
|
||||||
@@ -221,6 +222,15 @@ function DownloadConfigDialog({ selectedFormatFileType }: DownloadConfigDialogPr
|
|||||||
disabled={useCustomCommands}
|
disabled={useCustomCommands}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="embed-thumbnail">Embed Thumbnail</Label>
|
<Label htmlFor="embed-thumbnail">Embed Thumbnail</Label>
|
||||||
|
<div className="flex items-center gap-3 ml-4">
|
||||||
|
<Checkbox
|
||||||
|
id="square-crop-thumbnail"
|
||||||
|
checked={downloadConfiguration.square_crop_thumbnail !== null ? downloadConfiguration.square_crop_thumbnail : false}
|
||||||
|
onCheckedChange={(checked) => setDownloadConfigurationKey('square_crop_thumbnail', checked)}
|
||||||
|
disabled={useCustomCommands || !(downloadConfiguration.embed_thumbnail !== null ? downloadConfiguration.embed_thumbnail : (selectedFormatFileType && (selectedFormatFileType === 'video' || selectedFormatFileType === 'video+audio')) || activeDownloadModeTab === 'combine' ? embedVideoThumbnail : selectedFormatFileType && selectedFormatFileType === 'audio' ? embedAudioThumbnail : false)}
|
||||||
|
/>
|
||||||
|
<Label htmlFor="square-crop-thumbnail">Square Crop</Label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|||||||
@@ -19,16 +19,13 @@ interface SelectivePlaylistDownloadProps {
|
|||||||
videoOnlyFormats: VideoFormat[] | undefined;
|
videoOnlyFormats: VideoFormat[] | undefined;
|
||||||
combinedFormats: VideoFormat[] | undefined;
|
combinedFormats: VideoFormat[] | undefined;
|
||||||
qualityPresetFormats: VideoFormat[] | undefined;
|
qualityPresetFormats: VideoFormat[] | undefined;
|
||||||
allFilteredFormats: VideoFormat[];
|
|
||||||
subtitleLanguages: { code: string; lang: string }[];
|
subtitleLanguages: { code: string; lang: string }[];
|
||||||
selectedFormat: VideoFormat | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CombinedPlaylistDownloadProps {
|
interface CombinedPlaylistDownloadProps {
|
||||||
audioOnlyFormats: VideoFormat[] | undefined;
|
audioOnlyFormats: VideoFormat[] | undefined;
|
||||||
videoOnlyFormats: VideoFormat[] | undefined;
|
videoOnlyFormats: VideoFormat[] | undefined;
|
||||||
subtitleLanguages: { code: string; lang: string }[];
|
subtitleLanguages: { code: string; lang: string }[];
|
||||||
selectedFormat: VideoFormat | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PlaylistDownloaderProps {
|
interface PlaylistDownloaderProps {
|
||||||
@@ -37,9 +34,7 @@ interface PlaylistDownloaderProps {
|
|||||||
videoOnlyFormats: VideoFormat[] | undefined;
|
videoOnlyFormats: VideoFormat[] | undefined;
|
||||||
combinedFormats: VideoFormat[] | undefined;
|
combinedFormats: VideoFormat[] | undefined;
|
||||||
qualityPresetFormats: VideoFormat[] | undefined;
|
qualityPresetFormats: VideoFormat[] | undefined;
|
||||||
allFilteredFormats: VideoFormat[];
|
|
||||||
subtitleLanguages: { code: string; lang: string }[];
|
subtitleLanguages: { code: string; lang: string }[];
|
||||||
selectedFormat: VideoFormat | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function PlaylistPreviewSelection({ videoMetadata }: PlaylistPreviewSelectionProps) {
|
function PlaylistPreviewSelection({ videoMetadata }: PlaylistPreviewSelectionProps) {
|
||||||
@@ -104,12 +99,13 @@ function PlaylistPreviewSelection({ videoMetadata }: PlaylistPreviewSelectionPro
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectivePlaylistDownload({ videoMetadata, audioOnlyFormats, videoOnlyFormats, combinedFormats, qualityPresetFormats, allFilteredFormats, subtitleLanguages, selectedFormat }: SelectivePlaylistDownloadProps) {
|
function SelectivePlaylistDownload({ videoMetadata, audioOnlyFormats, videoOnlyFormats, combinedFormats, qualityPresetFormats, subtitleLanguages }: SelectivePlaylistDownloadProps) {
|
||||||
const selectedDownloadFormat = useDownloaderPageStatesStore((state) => state.selectedDownloadFormat);
|
const selectedDownloadFormat = useDownloaderPageStatesStore((state) => state.selectedDownloadFormat);
|
||||||
const selectedSubtitles = useDownloaderPageStatesStore((state) => state.selectedSubtitles);
|
const selectedSubtitles = useDownloaderPageStatesStore((state) => state.selectedSubtitles);
|
||||||
const selectedPlaylistVideoIndex = useDownloaderPageStatesStore((state) => state.selectedPlaylistVideoIndex);
|
const selectedPlaylistVideoIndex = useDownloaderPageStatesStore((state) => state.selectedPlaylistVideoIndex);
|
||||||
const setSelectedDownloadFormat = useDownloaderPageStatesStore((state) => state.setSelectedDownloadFormat);
|
const setSelectedDownloadFormat = useDownloaderPageStatesStore((state) => state.setSelectedDownloadFormat);
|
||||||
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
||||||
|
const resetDownloadConfiguration = useDownloaderPageStatesStore((state) => state.resetDownloadConfiguration);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
||||||
@@ -120,7 +116,7 @@ function SelectivePlaylistDownload({ videoMetadata, audioOnlyFormats, videoOnlyF
|
|||||||
className="flex flex-col items-start gap-2 mb-2"
|
className="flex flex-col items-start gap-2 mb-2"
|
||||||
value={selectedSubtitles}
|
value={selectedSubtitles}
|
||||||
onValueChange={(value) => setSelectedSubtitles(value)}
|
onValueChange={(value) => setSelectedSubtitles(value)}
|
||||||
disabled={selectedFormat?.ext !== 'mp4' && selectedFormat?.ext !== 'mkv' && selectedFormat?.ext !== 'webm'}
|
// disabled={selectedFormat?.ext !== 'mp4' && selectedFormat?.ext !== 'mkv' && selectedFormat?.ext !== 'webm'}
|
||||||
>
|
>
|
||||||
<p className="text-xs">Subtitle Languages</p>
|
<p className="text-xs">Subtitle Languages</p>
|
||||||
<div className="flex gap-2 flex-wrap items-center">
|
<div className="flex gap-2 flex-wrap items-center">
|
||||||
@@ -141,10 +137,11 @@ function SelectivePlaylistDownload({ videoMetadata, audioOnlyFormats, videoOnlyF
|
|||||||
value={selectedDownloadFormat}
|
value={selectedDownloadFormat}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSelectedDownloadFormat(value);
|
setSelectedDownloadFormat(value);
|
||||||
const currentlySelectedFormat = value === 'best' ? videoMetadata?.entries[Number(value) - 1].requested_downloads[0] : allFilteredFormats.find((format) => format.format_id === value);
|
// const currentlySelectedFormat = value === 'best' ? videoMetadata?.entries[Number(value) - 1].requested_downloads[0] : allFilteredFormats.find((format) => format.format_id === value);
|
||||||
if (currentlySelectedFormat?.ext !== 'mp4' && currentlySelectedFormat?.ext !== 'mkv' && currentlySelectedFormat?.ext !== 'webm') {
|
// if (currentlySelectedFormat?.ext !== 'mp4' && currentlySelectedFormat?.ext !== 'mkv' && currentlySelectedFormat?.ext !== 'webm') {
|
||||||
setSelectedSubtitles([]);
|
// setSelectedSubtitles([]);
|
||||||
}
|
// }
|
||||||
|
resetDownloadConfiguration();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p className="text-xs">Suggested</p>
|
<p className="text-xs">Suggested</p>
|
||||||
@@ -217,13 +214,14 @@ function SelectivePlaylistDownload({ videoMetadata, audioOnlyFormats, videoOnlyF
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CombinedPlaylistDownload({ audioOnlyFormats, videoOnlyFormats, subtitleLanguages, selectedFormat }: CombinedPlaylistDownloadProps) {
|
function CombinedPlaylistDownload({ audioOnlyFormats, videoOnlyFormats, subtitleLanguages }: CombinedPlaylistDownloadProps) {
|
||||||
const selectedCombinableVideoFormat = useDownloaderPageStatesStore((state) => state.selectedCombinableVideoFormat);
|
const selectedCombinableVideoFormat = useDownloaderPageStatesStore((state) => state.selectedCombinableVideoFormat);
|
||||||
const selectedCombinableAudioFormat = useDownloaderPageStatesStore((state) => state.selectedCombinableAudioFormat);
|
const selectedCombinableAudioFormat = useDownloaderPageStatesStore((state) => state.selectedCombinableAudioFormat);
|
||||||
const selectedSubtitles = useDownloaderPageStatesStore((state) => state.selectedSubtitles);
|
const selectedSubtitles = useDownloaderPageStatesStore((state) => state.selectedSubtitles);
|
||||||
const setSelectedCombinableVideoFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableVideoFormat);
|
const setSelectedCombinableVideoFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableVideoFormat);
|
||||||
const setSelectedCombinableAudioFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableAudioFormat);
|
const setSelectedCombinableAudioFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableAudioFormat);
|
||||||
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
||||||
|
const resetDownloadConfiguration = useDownloaderPageStatesStore((state) => state.resetDownloadConfiguration);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
||||||
@@ -234,7 +232,6 @@ function CombinedPlaylistDownload({ audioOnlyFormats, videoOnlyFormats, subtitle
|
|||||||
className="flex flex-col items-start gap-2 mb-2"
|
className="flex flex-col items-start gap-2 mb-2"
|
||||||
value={selectedSubtitles}
|
value={selectedSubtitles}
|
||||||
onValueChange={(value) => setSelectedSubtitles(value)}
|
onValueChange={(value) => setSelectedSubtitles(value)}
|
||||||
disabled={selectedFormat?.ext !== 'mp4' && selectedFormat?.ext !== 'mkv' && selectedFormat?.ext !== 'webm'}
|
|
||||||
>
|
>
|
||||||
<p className="text-xs">Subtitle Languages</p>
|
<p className="text-xs">Subtitle Languages</p>
|
||||||
<div className="flex gap-2 flex-wrap items-center">
|
<div className="flex gap-2 flex-wrap items-center">
|
||||||
@@ -256,6 +253,7 @@ function CombinedPlaylistDownload({ audioOnlyFormats, videoOnlyFormats, subtitle
|
|||||||
value={selectedCombinableAudioFormat}
|
value={selectedCombinableAudioFormat}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSelectedCombinableAudioFormat(value);
|
setSelectedCombinableAudioFormat(value);
|
||||||
|
resetDownloadConfiguration();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{videoOnlyFormats && videoOnlyFormats.length > 0 && audioOnlyFormats && audioOnlyFormats.length > 0 && (
|
{videoOnlyFormats && videoOnlyFormats.length > 0 && audioOnlyFormats && audioOnlyFormats.length > 0 && (
|
||||||
@@ -277,6 +275,7 @@ function CombinedPlaylistDownload({ audioOnlyFormats, videoOnlyFormats, subtitle
|
|||||||
value={selectedCombinableVideoFormat}
|
value={selectedCombinableVideoFormat}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSelectedCombinableVideoFormat(value);
|
setSelectedCombinableVideoFormat(value);
|
||||||
|
resetDownloadConfiguration();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{audioOnlyFormats && audioOnlyFormats.length > 0 && videoOnlyFormats && videoOnlyFormats.length > 0 && (
|
{audioOnlyFormats && audioOnlyFormats.length > 0 && videoOnlyFormats && videoOnlyFormats.length > 0 && (
|
||||||
@@ -308,11 +307,12 @@ function CombinedPlaylistDownload({ audioOnlyFormats, videoOnlyFormats, subtitle
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PlaylistDownloader({ videoMetadata, audioOnlyFormats, videoOnlyFormats, combinedFormats, qualityPresetFormats, allFilteredFormats, subtitleLanguages, selectedFormat }: PlaylistDownloaderProps) {
|
export function PlaylistDownloader({ videoMetadata, audioOnlyFormats, videoOnlyFormats, combinedFormats, qualityPresetFormats, subtitleLanguages }: PlaylistDownloaderProps) {
|
||||||
const activeDownloadModeTab = useDownloaderPageStatesStore((state) => state.activeDownloadModeTab);
|
const activeDownloadModeTab = useDownloaderPageStatesStore((state) => state.activeDownloadModeTab);
|
||||||
const setActiveDownloadModeTab = useDownloaderPageStatesStore((state) => state.setActiveDownloadModeTab);
|
const setActiveDownloadModeTab = useDownloaderPageStatesStore((state) => state.setActiveDownloadModeTab);
|
||||||
const playlistPanelSizes = useDownloaderPageStatesStore((state) => state.playlistPanelSizes);
|
const playlistPanelSizes = useDownloaderPageStatesStore((state) => state.playlistPanelSizes);
|
||||||
const setPlaylistPanelSizes = useDownloaderPageStatesStore((state) => state.setPlaylistPanelSizes);
|
const setPlaylistPanelSizes = useDownloaderPageStatesStore((state) => state.setPlaylistPanelSizes);
|
||||||
|
const resetDownloadConfiguration = useDownloaderPageStatesStore((state) => state.resetDownloadConfiguration);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
@@ -334,7 +334,10 @@ export function PlaylistDownloader({ videoMetadata, audioOnlyFormats, videoOnlyF
|
|||||||
<Tabs
|
<Tabs
|
||||||
className=""
|
className=""
|
||||||
value={activeDownloadModeTab}
|
value={activeDownloadModeTab}
|
||||||
onValueChange={(tab) => setActiveDownloadModeTab(tab)}
|
onValueChange={(tab) => {
|
||||||
|
setActiveDownloadModeTab(tab);
|
||||||
|
resetDownloadConfiguration();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h3 className="text-sm flex items-center gap-2">
|
<h3 className="text-sm flex items-center gap-2">
|
||||||
@@ -353,9 +356,7 @@ export function PlaylistDownloader({ videoMetadata, audioOnlyFormats, videoOnlyF
|
|||||||
videoOnlyFormats={videoOnlyFormats}
|
videoOnlyFormats={videoOnlyFormats}
|
||||||
combinedFormats={combinedFormats}
|
combinedFormats={combinedFormats}
|
||||||
qualityPresetFormats={qualityPresetFormats}
|
qualityPresetFormats={qualityPresetFormats}
|
||||||
allFilteredFormats={allFilteredFormats}
|
|
||||||
subtitleLanguages={subtitleLanguages}
|
subtitleLanguages={subtitleLanguages}
|
||||||
selectedFormat={selectedFormat}
|
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="combine">
|
<TabsContent value="combine">
|
||||||
@@ -363,7 +364,6 @@ export function PlaylistDownloader({ videoMetadata, audioOnlyFormats, videoOnlyF
|
|||||||
audioOnlyFormats={audioOnlyFormats}
|
audioOnlyFormats={audioOnlyFormats}
|
||||||
videoOnlyFormats={videoOnlyFormats}
|
videoOnlyFormats={videoOnlyFormats}
|
||||||
subtitleLanguages={subtitleLanguages}
|
subtitleLanguages={subtitleLanguages}
|
||||||
selectedFormat={selectedFormat}
|
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ function SelectiveVideoDownload({ videoMetadata, audioOnlyFormats, videoOnlyForm
|
|||||||
const selectedSubtitles = useDownloaderPageStatesStore((state) => state.selectedSubtitles);
|
const selectedSubtitles = useDownloaderPageStatesStore((state) => state.selectedSubtitles);
|
||||||
const setSelectedDownloadFormat = useDownloaderPageStatesStore((state) => state.setSelectedDownloadFormat);
|
const setSelectedDownloadFormat = useDownloaderPageStatesStore((state) => state.setSelectedDownloadFormat);
|
||||||
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
||||||
const setDownloadConfigurationKey = useDownloaderPageStatesStore((state) => state.setDownloadConfigurationKey);
|
const resetDownloadConfiguration = useDownloaderPageStatesStore((state) => state.resetDownloadConfiguration);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
||||||
@@ -133,10 +133,7 @@ function SelectiveVideoDownload({ videoMetadata, audioOnlyFormats, videoOnlyForm
|
|||||||
// if (currentlySelectedFormat?.ext !== 'mp4' && currentlySelectedFormat?.ext !== 'mkv' && currentlySelectedFormat?.ext !== 'webm') {
|
// if (currentlySelectedFormat?.ext !== 'mp4' && currentlySelectedFormat?.ext !== 'mkv' && currentlySelectedFormat?.ext !== 'webm') {
|
||||||
// setSelectedSubtitles([]);
|
// setSelectedSubtitles([]);
|
||||||
// }
|
// }
|
||||||
setDownloadConfigurationKey('output_format', null);
|
resetDownloadConfiguration();
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
|
||||||
setDownloadConfigurationKey('sponsorblock', null);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p className="text-xs">Suggested</p>
|
<p className="text-xs">Suggested</p>
|
||||||
@@ -216,7 +213,7 @@ function CombinedVideoDownload({ audioOnlyFormats, videoOnlyFormats, subtitleLan
|
|||||||
const setSelectedCombinableVideoFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableVideoFormat);
|
const setSelectedCombinableVideoFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableVideoFormat);
|
||||||
const setSelectedCombinableAudioFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableAudioFormat);
|
const setSelectedCombinableAudioFormat = useDownloaderPageStatesStore((state) => state.setSelectedCombinableAudioFormat);
|
||||||
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
const setSelectedSubtitles = useDownloaderPageStatesStore((state) => state.setSelectedSubtitles);
|
||||||
const setDownloadConfigurationKey = useDownloaderPageStatesStore((state) => state.setDownloadConfigurationKey);
|
const resetDownloadConfiguration = useDownloaderPageStatesStore((state) => state.resetDownloadConfiguration);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
<div className="flex flex-col overflow-y-scroll max-h-[50vh] xl:max-h-[60vh] no-scrollbar">
|
||||||
@@ -248,10 +245,7 @@ function CombinedVideoDownload({ audioOnlyFormats, videoOnlyFormats, subtitleLan
|
|||||||
value={selectedCombinableAudioFormat}
|
value={selectedCombinableAudioFormat}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSelectedCombinableAudioFormat(value);
|
setSelectedCombinableAudioFormat(value);
|
||||||
setDownloadConfigurationKey('output_format', null);
|
resetDownloadConfiguration();
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
|
||||||
setDownloadConfigurationKey('sponsorblock', null);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{videoOnlyFormats && videoOnlyFormats.length > 0 && audioOnlyFormats && audioOnlyFormats.length > 0 && (
|
{videoOnlyFormats && videoOnlyFormats.length > 0 && audioOnlyFormats && audioOnlyFormats.length > 0 && (
|
||||||
@@ -273,10 +267,7 @@ function CombinedVideoDownload({ audioOnlyFormats, videoOnlyFormats, subtitleLan
|
|||||||
value={selectedCombinableVideoFormat}
|
value={selectedCombinableVideoFormat}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setSelectedCombinableVideoFormat(value);
|
setSelectedCombinableVideoFormat(value);
|
||||||
setDownloadConfigurationKey('output_format', null);
|
resetDownloadConfiguration();
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
|
||||||
setDownloadConfigurationKey('sponsorblock', null);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{audioOnlyFormats && audioOnlyFormats.length > 0 && videoOnlyFormats && videoOnlyFormats.length > 0 && (
|
{audioOnlyFormats && audioOnlyFormats.length > 0 && videoOnlyFormats && videoOnlyFormats.length > 0 && (
|
||||||
@@ -311,7 +302,7 @@ function CombinedVideoDownload({ audioOnlyFormats, videoOnlyFormats, subtitleLan
|
|||||||
export function VideoDownloader({ videoMetadata, audioOnlyFormats, videoOnlyFormats, combinedFormats, qualityPresetFormats, subtitleLanguages }: VideoDownloaderProps) {
|
export function VideoDownloader({ videoMetadata, audioOnlyFormats, videoOnlyFormats, combinedFormats, qualityPresetFormats, subtitleLanguages }: VideoDownloaderProps) {
|
||||||
const activeDownloadModeTab = useDownloaderPageStatesStore((state) => state.activeDownloadModeTab);
|
const activeDownloadModeTab = useDownloaderPageStatesStore((state) => state.activeDownloadModeTab);
|
||||||
const setActiveDownloadModeTab = useDownloaderPageStatesStore((state) => state.setActiveDownloadModeTab);
|
const setActiveDownloadModeTab = useDownloaderPageStatesStore((state) => state.setActiveDownloadModeTab);
|
||||||
const setDownloadConfigurationKey = useDownloaderPageStatesStore((state) => state.setDownloadConfigurationKey);
|
const resetDownloadConfiguration = useDownloaderPageStatesStore((state) => state.resetDownloadConfiguration);
|
||||||
const videoPanelSizes = useDownloaderPageStatesStore((state) => state.videoPanelSizes);
|
const videoPanelSizes = useDownloaderPageStatesStore((state) => state.videoPanelSizes);
|
||||||
const setVideoPanelSizes = useDownloaderPageStatesStore((state) => state.setVideoPanelSizes);
|
const setVideoPanelSizes = useDownloaderPageStatesStore((state) => state.setVideoPanelSizes);
|
||||||
|
|
||||||
@@ -336,11 +327,8 @@ export function VideoDownloader({ videoMetadata, audioOnlyFormats, videoOnlyForm
|
|||||||
className=""
|
className=""
|
||||||
value={activeDownloadModeTab}
|
value={activeDownloadModeTab}
|
||||||
onValueChange={(tab) => {
|
onValueChange={(tab) => {
|
||||||
setActiveDownloadModeTab(tab)
|
setActiveDownloadModeTab(tab);
|
||||||
setDownloadConfigurationKey('output_format', null);
|
resetDownloadConfiguration();
|
||||||
setDownloadConfigurationKey('embed_metadata', null);
|
|
||||||
setDownloadConfigurationKey('embed_thumbnail', null);
|
|
||||||
setDownloadConfigurationKey('sponsorblock', null);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|||||||
@@ -1295,9 +1295,9 @@ function AppInfoSettings() {
|
|||||||
{ key: 'directories', name: 'Directories', desc: 'A Rust library for platform-specific standard locations', url: 'https://crates.io/crates/directories', license: 'MIT, Apache-2.0', licenseUrl: 'https://codeberg.org/dirs/directories-rs/src/branch/main/LICENSE-APACHE' },
|
{ key: 'directories', name: 'Directories', desc: 'A Rust library for platform-specific standard locations', url: 'https://crates.io/crates/directories', license: 'MIT, Apache-2.0', licenseUrl: 'https://codeberg.org/dirs/directories-rs/src/branch/main/LICENSE-APACHE' },
|
||||||
];
|
];
|
||||||
|
|
||||||
function DependencyItem(dep: { key: string, name: string; desc: string; url: string; license: string; licenseUrl: string }) {
|
function DependencyItem(dep: { name: string; desc: string; url: string; license: string; licenseUrl: string }) {
|
||||||
return (
|
return (
|
||||||
<div key={dep.key} className="p-4 border border-border rounded-md flex items-center justify-between gap-4">
|
<div className="p-4 border border-border rounded-md flex items-center justify-between gap-4">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<h4 className="font-semibold flex items-center gap-2">
|
<h4 className="font-semibold flex items-center gap-2">
|
||||||
<a href={dep.url} target="_blank" className="hover:underline">
|
<a href={dep.url} target="_blank" className="hover:underline">
|
||||||
@@ -1379,7 +1379,7 @@ function AppInfoSettings() {
|
|||||||
<span className="flex items-center gap-4 flex-wrap">
|
<span className="flex items-center gap-4 flex-wrap">
|
||||||
<Button className="px-4" variant="outline" size="sm" asChild>
|
<Button className="px-4" variant="outline" size="sm" asChild>
|
||||||
<a href={'mailto:' + config.appSupportEmail + '?subject=[BUG]%20Title%20Here&body=Describe%20The%20Bug%20Here.%20Follow%20this%20issue%20template%3A%20https%3A%2F%2Fgithub.com%2Fneosubhamoy%2Fneodlp%2Fissues%2Fnew%3Ftemplate%3Dbug_report.md'} target="_blank" >
|
<a href={'mailto:' + config.appSupportEmail + '?subject=[BUG]%20Title%20Here&body=Describe%20The%20Bug%20Here.%20Follow%20this%20issue%20template%3A%20https%3A%2F%2Fgithub.com%2Fneosubhamoy%2Fneodlp%2Fissues%2Fnew%3Ftemplate%3Dbug_report.md'} target="_blank" >
|
||||||
<Mail className="size-4" /> Write an Email
|
<Mail className="size-4" /> Write Us an Email
|
||||||
</a>
|
</a>
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="px-4" size="sm" asChild>
|
<Button className="px-4" size="sm" asChild>
|
||||||
@@ -1415,16 +1415,16 @@ function AppInfoSettings() {
|
|||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex flex-col gap-4 max-h-[45vh] overflow-y-auto">
|
<div className="flex flex-col gap-4 max-h-[45vh] overflow-y-auto">
|
||||||
<h4 className="text-sm font-semibold">External Binaries</h4>
|
<h4 className="text-sm font-semibold">External Binaries</h4>
|
||||||
{binDepsList.map((dep) => (
|
{binDepsList.map(({key, ...dep}) => (
|
||||||
<DependencyItem {...dep} />
|
<DependencyItem key={key} {...dep} />
|
||||||
))}
|
))}
|
||||||
<h4 className="text-sm font-semibold">Languages, Frameworks & Tooling</h4>
|
<h4 className="text-sm font-semibold">Languages, Frameworks & Tooling</h4>
|
||||||
{langDepsList.map((dep) => (
|
{langDepsList.map(({key, ...dep}) => (
|
||||||
<DependencyItem {...dep} />
|
<DependencyItem key={key} {...dep} />
|
||||||
))}
|
))}
|
||||||
<h4 className="text-sm font-semibold">Notable Libraries</h4>
|
<h4 className="text-sm font-semibold">Notable Libraries</h4>
|
||||||
{libDepsList.map((dep) => (
|
{libDepsList.map(({key, ...dep}) => (
|
||||||
<DependencyItem {...dep} />
|
<DependencyItem key={key} {...dep} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -1,28 +1,31 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
||||||
import { Check } from "lucide-react"
|
import { CheckIcon } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const Checkbox = React.forwardRef<
|
function Checkbox({
|
||||||
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
className,
|
||||||
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
...props
|
||||||
>(({ className, ...props }, ref) => (
|
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
||||||
<CheckboxPrimitive.Root
|
return (
|
||||||
ref={ref}
|
<CheckboxPrimitive.Root
|
||||||
className={cn(
|
data-slot="checkbox"
|
||||||
"grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
className={cn(
|
||||||
className
|
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
)}
|
className
|
||||||
{...props}
|
)}
|
||||||
>
|
{...props}
|
||||||
<CheckboxPrimitive.Indicator
|
|
||||||
className={cn("grid place-content-center text-current")}
|
|
||||||
>
|
>
|
||||||
<Check className="h-4 w-4" />
|
<CheckboxPrimitive.Indicator
|
||||||
</CheckboxPrimitive.Indicator>
|
data-slot="checkbox-indicator"
|
||||||
</CheckboxPrimitive.Root>
|
className="grid place-content-center text-current transition-none"
|
||||||
))
|
>
|
||||||
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
<CheckIcon className="size-3.5" />
|
||||||
|
</CheckboxPrimitive.Indicator>
|
||||||
|
</CheckboxPrimitive.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export { Checkbox }
|
export { Checkbox }
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +1,44 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
|
||||||
import { Circle } from "lucide-react"
|
import { CircleIcon } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const RadioGroup = React.forwardRef<
|
function RadioGroup({
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
className,
|
||||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
...props
|
||||||
>(({ className, ...props }, ref) => {
|
}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
|
||||||
return (
|
return (
|
||||||
<RadioGroupPrimitive.Root
|
<RadioGroupPrimitive.Root
|
||||||
className={cn("grid gap-2", className)}
|
data-slot="radio-group"
|
||||||
|
className={cn("grid gap-3", className)}
|
||||||
{...props}
|
{...props}
|
||||||
ref={ref}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
|
||||||
|
|
||||||
const RadioGroupItem = React.forwardRef<
|
function RadioGroupItem({
|
||||||
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
className,
|
||||||
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
...props
|
||||||
>(({ className, ...props }, ref) => {
|
}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
|
||||||
return (
|
return (
|
||||||
<RadioGroupPrimitive.Item
|
<RadioGroupPrimitive.Item
|
||||||
ref={ref}
|
data-slot="radio-group-item"
|
||||||
className={cn(
|
className={cn(
|
||||||
"aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
<RadioGroupPrimitive.Indicator
|
||||||
<Circle className="h-3.5 w-3.5 fill-primary" />
|
data-slot="radio-group-indicator"
|
||||||
|
className="relative flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
|
||||||
</RadioGroupPrimitive.Indicator>
|
</RadioGroupPrimitive.Indicator>
|
||||||
</RadioGroupPrimitive.Item>
|
</RadioGroupPrimitive.Item>
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
|
||||||
|
|
||||||
export { RadioGroup, RadioGroupItem }
|
export { RadioGroup, RadioGroupItem }
|
||||||
|
|
||||||
|
|||||||
@@ -340,14 +340,14 @@ export default function useDownloader() {
|
|||||||
}
|
}
|
||||||
// Handle audio only
|
// Handle audio only
|
||||||
else if (fileType === 'audio' && (AUDIO_FORMAT !== 'auto' || format)) {
|
else if (fileType === 'audio' && (AUDIO_FORMAT !== 'auto' || format)) {
|
||||||
args.push('--extract-audio', '--audio-format', format || AUDIO_FORMAT);
|
args.push('--extract-audio', '--audio-format', format || AUDIO_FORMAT, '--audio-quality', '0');
|
||||||
}
|
}
|
||||||
// Handle unknown filetype
|
// Handle unknown filetype
|
||||||
else if (fileType === 'unknown' && format) {
|
else if (fileType === 'unknown' && format) {
|
||||||
if (['mkv', 'mp4', 'webm'].includes(format)) {
|
if (['mkv', 'mp4', 'webm'].includes(format)) {
|
||||||
args.push(recodeOrRemux, formatToUse);
|
args.push(recodeOrRemux, formatToUse);
|
||||||
} else if (['mp3', 'm4a', 'opus'].includes(format)) {
|
} else if (['mp3', 'm4a', 'opus'].includes(format)) {
|
||||||
args.push('--extract-audio', '--audio-format', format);
|
args.push('--extract-audio', '--audio-format', format, '--audio-quality', '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,6 +365,7 @@ export default function useDownloader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let embedThumbnail = 0;
|
let embedThumbnail = 0;
|
||||||
|
let squareCropThumbnail = 0;
|
||||||
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || EMBED_VIDEO_THUMBNAIL || EMBED_AUDIO_THUMBNAIL)) {
|
if ((!USE_CUSTOM_COMMANDS && !resumeState?.custom_command) && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || EMBED_VIDEO_THUMBNAIL || EMBED_AUDIO_THUMBNAIL)) {
|
||||||
const shouldEmbedThumbForVideo = (fileType === 'video+audio' || fileType === 'video') && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || (EMBED_VIDEO_THUMBNAIL && downloadConfig.embed_thumbnail === null));
|
const shouldEmbedThumbForVideo = (fileType === 'video+audio' || fileType === 'video') && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || (EMBED_VIDEO_THUMBNAIL && downloadConfig.embed_thumbnail === null));
|
||||||
const shouldEmbedThumbForAudio = fileType === 'audio' && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || (EMBED_AUDIO_THUMBNAIL && downloadConfig.embed_thumbnail === null));
|
const shouldEmbedThumbForAudio = fileType === 'audio' && (downloadConfig.embed_thumbnail || resumeState?.embed_thumbnail || (EMBED_AUDIO_THUMBNAIL && downloadConfig.embed_thumbnail === null));
|
||||||
@@ -372,7 +373,12 @@ export default function useDownloader() {
|
|||||||
|
|
||||||
if (shouldEmbedThumbForUnknown || shouldEmbedThumbForVideo || shouldEmbedThumbForAudio) {
|
if (shouldEmbedThumbForUnknown || shouldEmbedThumbForVideo || shouldEmbedThumbForAudio) {
|
||||||
embedThumbnail = 1;
|
embedThumbnail = 1;
|
||||||
args.push('--embed-thumbnail');
|
args.push('--embed-thumbnail', '--convert-thumbnail', 'jpg');
|
||||||
|
|
||||||
|
if (downloadConfig.square_crop_thumbnail || resumeState?.square_crop_thumbnail) {
|
||||||
|
squareCropThumbnail = 1;
|
||||||
|
args.push('--postprocessor-args', 'ThumbnailsConvertor+FFmpeg_o:-c:v mjpeg -qmin 1 -qscale:v 1 -vf crop="\'min(iw,ih)\':\'min(iw,ih)\'"');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,6 +509,7 @@ export default function useDownloader() {
|
|||||||
output_format: outputFormat,
|
output_format: outputFormat,
|
||||||
embed_metadata: embedMetadata,
|
embed_metadata: embedMetadata,
|
||||||
embed_thumbnail: embedThumbnail,
|
embed_thumbnail: embedThumbnail,
|
||||||
|
square_crop_thumbnail: squareCropThumbnail,
|
||||||
sponsorblock_remove: sponsorblockRemove,
|
sponsorblock_remove: sponsorblockRemove,
|
||||||
sponsorblock_mark: sponsorblockMark,
|
sponsorblock_mark: sponsorblockMark,
|
||||||
use_aria2: useAria2,
|
use_aria2: useAria2,
|
||||||
@@ -630,6 +637,7 @@ export default function useDownloader() {
|
|||||||
output_format: resumeState?.output_format || null,
|
output_format: resumeState?.output_format || null,
|
||||||
embed_metadata: resumeState?.embed_metadata || 0,
|
embed_metadata: resumeState?.embed_metadata || 0,
|
||||||
embed_thumbnail: resumeState?.embed_thumbnail || 0,
|
embed_thumbnail: resumeState?.embed_thumbnail || 0,
|
||||||
|
square_crop_thumbnail: resumeState?.square_crop_thumbnail || 0,
|
||||||
sponsorblock_remove: resumeState?.sponsorblock_remove || null,
|
sponsorblock_remove: resumeState?.sponsorblock_remove || null,
|
||||||
sponsorblock_mark: resumeState?.sponsorblock_mark || null,
|
sponsorblock_mark: resumeState?.sponsorblock_mark || null,
|
||||||
use_aria2: resumeState?.use_aria2 || 0,
|
use_aria2: resumeState?.use_aria2 || 0,
|
||||||
|
|||||||
@@ -347,10 +347,8 @@ export default function DownloaderPage() {
|
|||||||
audioOnlyFormats={audioOnlyFormats}
|
audioOnlyFormats={audioOnlyFormats}
|
||||||
videoOnlyFormats={videoOnlyFormats}
|
videoOnlyFormats={videoOnlyFormats}
|
||||||
combinedFormats={combinedFormats}
|
combinedFormats={combinedFormats}
|
||||||
allFilteredFormats={allFilteredFormats}
|
|
||||||
qualityPresetFormats={qualityPresetFormats}
|
qualityPresetFormats={qualityPresetFormats}
|
||||||
subtitleLanguages={subtitleLanguages}
|
subtitleLanguages={subtitleLanguages}
|
||||||
selectedFormat={selectedFormat}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!isMetadataLoading && videoMetadata && selectedDownloadFormat && (
|
{!isMetadataLoading && videoMetadata && selectedDownloadFormat && (
|
||||||
|
|||||||
@@ -101,12 +101,13 @@ export const saveDownloadState = async (downloadState: DownloadState) => {
|
|||||||
output_format,
|
output_format,
|
||||||
embed_metadata,
|
embed_metadata,
|
||||||
embed_thumbnail,
|
embed_thumbnail,
|
||||||
|
square_crop_thumbnail,
|
||||||
sponsorblock_remove,
|
sponsorblock_remove,
|
||||||
sponsorblock_mark,
|
sponsorblock_mark,
|
||||||
use_aria2,
|
use_aria2,
|
||||||
custom_command,
|
custom_command,
|
||||||
queue_config
|
queue_config
|
||||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33)
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34)
|
||||||
ON CONFLICT(download_id) DO UPDATE SET
|
ON CONFLICT(download_id) DO UPDATE SET
|
||||||
download_status = $2,
|
download_status = $2,
|
||||||
video_id = $3,
|
video_id = $3,
|
||||||
@@ -135,11 +136,12 @@ export const saveDownloadState = async (downloadState: DownloadState) => {
|
|||||||
output_format = $26,
|
output_format = $26,
|
||||||
embed_metadata = $27,
|
embed_metadata = $27,
|
||||||
embed_thumbnail = $28,
|
embed_thumbnail = $28,
|
||||||
sponsorblock_remove = $29,
|
square_crop_thumbnail = $29,
|
||||||
sponsorblock_mark = $30,
|
sponsorblock_remove = $30,
|
||||||
use_aria2 = $31,
|
sponsorblock_mark = $31,
|
||||||
custom_command = $32,
|
use_aria2 = $32,
|
||||||
queue_config = $33`,
|
custom_command = $33,
|
||||||
|
queue_config = $34`,
|
||||||
[
|
[
|
||||||
downloadState.download_id,
|
downloadState.download_id,
|
||||||
downloadState.download_status,
|
downloadState.download_status,
|
||||||
@@ -169,6 +171,7 @@ export const saveDownloadState = async (downloadState: DownloadState) => {
|
|||||||
downloadState.output_format,
|
downloadState.output_format,
|
||||||
downloadState.embed_metadata,
|
downloadState.embed_metadata,
|
||||||
downloadState.embed_thumbnail,
|
downloadState.embed_thumbnail,
|
||||||
|
downloadState.square_crop_thumbnail,
|
||||||
downloadState.sponsorblock_remove,
|
downloadState.sponsorblock_remove,
|
||||||
downloadState.sponsorblock_mark,
|
downloadState.sponsorblock_mark,
|
||||||
downloadState.use_aria2,
|
downloadState.use_aria2,
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export const useDownloaderPageStatesStore = create<DownloaderPageStatesStore>((s
|
|||||||
output_format: null,
|
output_format: null,
|
||||||
embed_metadata: null,
|
embed_metadata: null,
|
||||||
embed_thumbnail: null,
|
embed_thumbnail: null,
|
||||||
|
square_crop_thumbnail: null,
|
||||||
sponsorblock: null,
|
sponsorblock: null,
|
||||||
custom_command: null
|
custom_command: null
|
||||||
},
|
},
|
||||||
@@ -86,6 +87,7 @@ export const useDownloaderPageStatesStore = create<DownloaderPageStatesStore>((s
|
|||||||
output_format: null,
|
output_format: null,
|
||||||
embed_metadata: null,
|
embed_metadata: null,
|
||||||
embed_thumbnail: null,
|
embed_thumbnail: null,
|
||||||
|
square_crop_thumbnail: null,
|
||||||
sponsorblock: null,
|
sponsorblock: null,
|
||||||
custom_command: null
|
custom_command: null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export interface DownloadState {
|
|||||||
output_format: string | null;
|
output_format: string | null;
|
||||||
embed_metadata: number;
|
embed_metadata: number;
|
||||||
embed_thumbnail: number;
|
embed_thumbnail: number;
|
||||||
|
square_crop_thumbnail: number;
|
||||||
sponsorblock_remove: string | null;
|
sponsorblock_remove: string | null;
|
||||||
sponsorblock_mark: string | null;
|
sponsorblock_mark: string | null;
|
||||||
use_aria2: number;
|
use_aria2: number;
|
||||||
@@ -78,6 +79,7 @@ export interface Download {
|
|||||||
output_format: string | null;
|
output_format: string | null;
|
||||||
embed_metadata: number;
|
embed_metadata: number;
|
||||||
embed_thumbnail: number;
|
embed_thumbnail: number;
|
||||||
|
square_crop_thumbnail: number;
|
||||||
sponsorblock_remove: string | null;
|
sponsorblock_remove: string | null;
|
||||||
sponsorblock_mark: string | null;
|
sponsorblock_mark: string | null;
|
||||||
use_aria2: number;
|
use_aria2: number;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export interface DownloadConfiguration {
|
|||||||
output_format: string | null;
|
output_format: string | null;
|
||||||
embed_metadata: boolean | null;
|
embed_metadata: boolean | null;
|
||||||
embed_thumbnail: boolean | null;
|
embed_thumbnail: boolean | null;
|
||||||
|
square_crop_thumbnail: boolean | null;
|
||||||
sponsorblock: string | null;
|
sponsorblock: string | null;
|
||||||
custom_command: string | null;
|
custom_command: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user