.redownlaod with suffix, isrc variable
This commit is contained in:
@@ -36,6 +36,7 @@ interface FileMetadata {
|
||||
track_number: number;
|
||||
disc_number: number;
|
||||
year: string;
|
||||
isrc?: string;
|
||||
}
|
||||
type TabType = "track" | "lyric" | "cover";
|
||||
const FORMAT_PRESETS: Record<string, {
|
||||
@@ -549,7 +550,7 @@ export function FileManagerPage() {
|
||||
<Info className="h-3.5 w-3.5 text-muted-foreground cursor-help"/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">
|
||||
<p className="text-xs whitespace-nowrap">Variables: {"{title}"}, {"{artist}"}, {"{album}"}, {"{album_artist}"}, {"{track}"}, {"{disc}"}, {"{year}"}, {"{date}"}</p>
|
||||
<p className="text-xs whitespace-nowrap">Variables: {"{title}"}, {"{artist}"}, {"{album}"}, {"{album_artist}"}, {"{track}"}, {"{disc}"}, {"{year}"}, {"{date}"}, {"{isrc}"}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@@ -571,7 +572,7 @@ export function FileManagerPage() {
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Preview: <span className="font-mono">{renameFormat.replace(/\{title\}/g, "All The Stars").replace(/\{artist\}/g, "Kendrick Lamar, SZA").replace(/\{album\}/g, "Black Panther").replace(/\{album_artist\}/g, "Kendrick Lamar").replace(/\{track\}/g, "01").replace(/\{disc\}/g, "1").replace(/\{year\}/g, "2018").replace(/\{date\}/g, "2018-02-09")}.flac</span>
|
||||
Preview: <span className="font-mono">{renameFormat.replace(/\{title\}/g, "All The Stars").replace(/\{artist\}/g, "Kendrick Lamar, SZA").replace(/\{album\}/g, "Black Panther").replace(/\{album_artist\}/g, "Kendrick Lamar").replace(/\{track\}/g, "01").replace(/\{disc\}/g, "1").replace(/\{year\}/g, "2018").replace(/\{date\}/g, "2018-02-09").replace(/\{isrc\}/g, "USUM71801234")}.flac</span>
|
||||
</p>
|
||||
</div>)}
|
||||
|
||||
@@ -660,6 +661,7 @@ export function FileManagerPage() {
|
||||
<div className="grid grid-cols-[100px_1fr] gap-2 text-sm"><span className="text-muted-foreground">Track</span><span>{metadataInfo.track_number || "-"}</span></div>
|
||||
<div className="grid grid-cols-[100px_1fr] gap-2 text-sm"><span className="text-muted-foreground">Disc</span><span>{metadataInfo.disc_number || "-"}</span></div>
|
||||
<div className="grid grid-cols-[100px_1fr] gap-2 text-sm"><span className="text-muted-foreground">Year</span><span>{metadataInfo.year ? metadataInfo.year.substring(0, 4) : "-"}</span></div>
|
||||
<div className="grid grid-cols-[100px_1fr] gap-2 text-sm"><span className="text-muted-foreground">ISRC</span><span>{metadataInfo.isrc || "-"}</span></div>
|
||||
</div>) : (<div className="text-center py-4 text-muted-foreground">No metadata available</div>)}
|
||||
<DialogFooter><Button onClick={() => setShowMetadata(false)}>Close</Button></DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@@ -568,7 +568,8 @@ export function SettingsPage({ onUnsavedChangesChange, onResetRequest, }: Settin
|
||||
.replace(/\{track\}/g, "01")
|
||||
.replace(/\{disc\}/g, "1")
|
||||
.replace(/\{year\}/g, "2018")
|
||||
.replace(/\{date\}/g, "2018-02-09")}
|
||||
.replace(/\{date\}/g, "2018-02-09")
|
||||
.replace(/\{isrc\}/g, "USUM71801234")}
|
||||
/
|
||||
</span>
|
||||
</p>)}
|
||||
@@ -614,6 +615,16 @@ export function SettingsPage({ onUnsavedChangesChange, onResetRequest, }: Settin
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<Switch id="redownload-with-suffix" checked={tempSettings.redownloadWithSuffix} onCheckedChange={(checked) => setTempSettings((prev) => ({
|
||||
...prev,
|
||||
redownloadWithSuffix: checked,
|
||||
}))}/>
|
||||
<Label htmlFor="redownload-with-suffix" className="text-sm cursor-pointer font-normal">
|
||||
Redownload With Suffix
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -686,7 +697,8 @@ export function SettingsPage({ onUnsavedChangesChange, onResetRequest, }: Settin
|
||||
.replace(/\{track\}/g, "01")
|
||||
.replace(/\{disc\}/g, "1")
|
||||
.replace(/\{year\}/g, "2018")
|
||||
.replace(/\{date\}/g, "2018-02-09")}
|
||||
.replace(/\{date\}/g, "2018-02-09")
|
||||
.replace(/\{isrc\}/g, "USUM71801234")}
|
||||
.flac
|
||||
</span>
|
||||
</p>)}
|
||||
|
||||
@@ -12,6 +12,7 @@ interface CheckFileExistenceRequest {
|
||||
album_name?: string;
|
||||
album_artist?: string;
|
||||
release_date?: string;
|
||||
isrc?: string;
|
||||
track_number?: number;
|
||||
disc_number?: number;
|
||||
position?: number;
|
||||
@@ -31,6 +32,24 @@ interface FileExistenceResult {
|
||||
const CheckFilesExistence = (outputDir: string, rootDir: string, tracks: CheckFileExistenceRequest[]): Promise<FileExistenceResult[]> => (window as any)["go"]["main"]["App"]["CheckFilesExistence"](outputDir, rootDir, tracks);
|
||||
const SkipDownloadItem = (itemID: string, filePath: string): Promise<void> => (window as any)["go"]["main"]["App"]["SkipDownloadItem"](itemID, filePath);
|
||||
const CreateM3U8File = (playlistName: string, outputDir: string, filePaths: string[]): Promise<void> => (window as any)["go"]["main"]["App"]["CreateM3U8File"](playlistName, outputDir, filePaths);
|
||||
const GetTrackISRC = (spotifyId: string): Promise<string> => (window as any)["go"]["main"]["App"]["GetTrackISRC"](spotifyId);
|
||||
|
||||
async function resolveTemplateISRC(settings: { folderTemplate?: string; filenameTemplate?: string }, spotifyId?: string): Promise<string> {
|
||||
if (!spotifyId) {
|
||||
return "";
|
||||
}
|
||||
const folderTemplate = settings.folderTemplate || "";
|
||||
const filenameTemplate = settings.filenameTemplate || "";
|
||||
if (!folderTemplate.includes("{isrc}") && !filenameTemplate.includes("{isrc}")) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return await GetTrackISRC(spotifyId);
|
||||
}
|
||||
catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
export function useDownload(region: string) {
|
||||
const [downloadProgress, setDownloadProgress] = useState<number>(0);
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
@@ -81,11 +100,13 @@ export function useDownload(region: string) {
|
||||
const displayAlbumArtist = settings.useFirstArtistOnly && albumArtist
|
||||
? getFirstArtist(albumArtist)
|
||||
: albumArtist;
|
||||
const resolvedTemplateISRC = await resolveTemplateISRC(settings, spotifyId || id);
|
||||
const templateData: TemplateData = {
|
||||
artist: displayArtist?.replace(/\//g, placeholder),
|
||||
album: albumName?.replace(/\//g, placeholder),
|
||||
album_artist: displayAlbumArtist?.replace(/\//g, placeholder) || displayArtist?.replace(/\//g, placeholder),
|
||||
title: trackName?.replace(/\//g, placeholder),
|
||||
isrc: resolvedTemplateISRC?.replace(/\//g, placeholder),
|
||||
track: trackNumberForTemplate,
|
||||
year: yearValue,
|
||||
date: releaseDate,
|
||||
@@ -117,6 +138,7 @@ export function useDownload(region: string) {
|
||||
album_name: albumName,
|
||||
album_artist: displayAlbumArtist,
|
||||
release_date: finalReleaseDate || releaseDate,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
track_number: finalTrackNumber || spotifyTrackNumber || 0,
|
||||
disc_number: spotifyDiscNumber || 0,
|
||||
position: trackNumberForTemplate,
|
||||
@@ -193,6 +215,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_first_artist_only: settings.useFirstArtistOnly,
|
||||
@@ -240,6 +263,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_single_genre: settings.useSingleGenre,
|
||||
@@ -286,6 +310,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_single_genre: settings.useSingleGenre,
|
||||
@@ -350,6 +375,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_single_genre: settings.useSingleGenre,
|
||||
@@ -395,11 +421,13 @@ export function useDownload(region: string) {
|
||||
const displayAlbumArtist = settings.useFirstArtistOnly && albumArtist
|
||||
? getFirstArtist(albumArtist)
|
||||
: albumArtist;
|
||||
const resolvedTemplateISRC = await resolveTemplateISRC(settings, spotifyId);
|
||||
const templateData: TemplateData = {
|
||||
artist: displayArtist?.replace(/\//g, placeholder),
|
||||
album: albumName?.replace(/\//g, placeholder),
|
||||
album_artist: displayAlbumArtist?.replace(/\//g, placeholder) || displayArtist?.replace(/\//g, placeholder),
|
||||
title: trackName?.replace(/\//g, placeholder),
|
||||
isrc: resolvedTemplateISRC?.replace(/\//g, placeholder),
|
||||
track: trackNumberForTemplate,
|
||||
year: yearValue,
|
||||
date: releaseDate,
|
||||
@@ -468,6 +496,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_first_artist_only: settings.useFirstArtistOnly,
|
||||
@@ -515,6 +544,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_first_artist_only: settings.useFirstArtistOnly,
|
||||
@@ -563,6 +593,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_first_artist_only: settings.useFirstArtistOnly,
|
||||
@@ -624,6 +655,7 @@ export function useDownload(region: string) {
|
||||
spotify_disc_number: spotifyDiscNumber,
|
||||
spotify_total_tracks: spotifyTotalTracks,
|
||||
spotify_total_discs: spotifyTotalDiscs,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
copyright: copyright,
|
||||
publisher: publisher,
|
||||
use_first_artist_only: settings.useFirstArtistOnly,
|
||||
|
||||
@@ -5,6 +5,24 @@ import { toastWithSound as toast } from "@/lib/toast-with-sound";
|
||||
import { joinPath, sanitizePath, getFirstArtist } from "@/lib/utils";
|
||||
import { logger } from "@/lib/logger";
|
||||
import type { TrackMetadata } from "@/types/api";
|
||||
const GetTrackISRC = (spotifyId: string): Promise<string> => (window as any)["go"]["main"]["App"]["GetTrackISRC"](spotifyId);
|
||||
|
||||
async function resolveTemplateISRC(settings: { folderTemplate?: string; filenameTemplate?: string }, spotifyId?: string): Promise<string> {
|
||||
if (!spotifyId) {
|
||||
return "";
|
||||
}
|
||||
const folderTemplate = settings.folderTemplate || "";
|
||||
const filenameTemplate = settings.filenameTemplate || "";
|
||||
if (!folderTemplate.includes("{isrc}") && !filenameTemplate.includes("{isrc}")) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return await GetTrackISRC(spotifyId);
|
||||
}
|
||||
catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
export function useLyrics() {
|
||||
const [downloadingLyricsTrack, setDownloadingLyricsTrack] = useState<string | null>(null);
|
||||
const [downloadedLyrics, setDownloadedLyrics] = useState<Set<string>>(new Set());
|
||||
@@ -28,11 +46,13 @@ export function useLyrics() {
|
||||
const yearValue = releaseDate?.substring(0, 4);
|
||||
const displayArtist = settings.useFirstArtistOnly && artistName ? getFirstArtist(artistName) : artistName;
|
||||
const displayAlbumArtist = settings.useFirstArtistOnly && albumArtist ? getFirstArtist(albumArtist) : albumArtist;
|
||||
const resolvedTemplateISRC = await resolveTemplateISRC(settings, spotifyId);
|
||||
const templateData: TemplateData = {
|
||||
artist: displayArtist?.replace(/\//g, placeholder),
|
||||
album: albumName?.replace(/\//g, placeholder),
|
||||
album_artist: displayAlbumArtist?.replace(/\//g, placeholder) || displayArtist?.replace(/\//g, placeholder),
|
||||
title: trackName?.replace(/\//g, placeholder),
|
||||
isrc: resolvedTemplateISRC?.replace(/\//g, placeholder),
|
||||
track: position,
|
||||
year: yearValue,
|
||||
date: releaseDate,
|
||||
@@ -61,6 +81,7 @@ export function useLyrics() {
|
||||
album_name: albumName,
|
||||
album_artist: displayAlbumArtist,
|
||||
release_date: releaseDate,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
output_dir: outputDir,
|
||||
filename_format: settings.filenameTemplate || "{title}",
|
||||
track_number: settings.trackNumber,
|
||||
@@ -129,11 +150,13 @@ export function useLyrics() {
|
||||
const yearValue = track.release_date?.substring(0, 4);
|
||||
const displayArtist = settings.useFirstArtistOnly && track.artists ? getFirstArtist(track.artists) : track.artists;
|
||||
const displayAlbumArtist = settings.useFirstArtistOnly && track.album_artist ? getFirstArtist(track.album_artist) : track.album_artist;
|
||||
const resolvedTemplateISRC = await resolveTemplateISRC(settings, id);
|
||||
const templateData: TemplateData = {
|
||||
artist: displayArtist?.replace(/\//g, placeholder),
|
||||
album: track.album_name?.replace(/\//g, placeholder),
|
||||
album_artist: displayAlbumArtist?.replace(/\//g, placeholder) || displayArtist?.replace(/\//g, placeholder),
|
||||
title: track.name?.replace(/\//g, placeholder),
|
||||
isrc: resolvedTemplateISRC?.replace(/\//g, placeholder),
|
||||
track: trackPosition,
|
||||
year: yearValue,
|
||||
date: track.release_date,
|
||||
@@ -161,6 +184,7 @@ export function useLyrics() {
|
||||
album_name: track.album_name,
|
||||
album_artist: displayAlbumArtist,
|
||||
release_date: track.release_date,
|
||||
isrc: resolvedTemplateISRC || undefined,
|
||||
output_dir: outputDir,
|
||||
filename_format: settings.filenameTemplate || "{title}",
|
||||
track_number: settings.trackNumber,
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface Settings {
|
||||
useFirstArtistOnly: boolean;
|
||||
useSingleGenre: boolean;
|
||||
embedGenre: boolean;
|
||||
redownloadWithSuffix: boolean;
|
||||
separator: "comma" | "semicolon";
|
||||
}
|
||||
export const FOLDER_PRESETS: Record<FolderPreset, {
|
||||
@@ -85,6 +86,7 @@ export const TEMPLATE_VARIABLES = [
|
||||
{ key: "{disc}", description: "Disc number", example: "1" },
|
||||
{ key: "{year}", description: "Release year", example: "2014" },
|
||||
{ key: "{date}", description: "Release date (YYYY-MM-DD)", example: "2014-10-27" },
|
||||
{ key: "{isrc}", description: "Track ISRC", example: "USUM71412345" },
|
||||
];
|
||||
function detectOS(): "Windows" | "linux/MacOS" {
|
||||
const platform = window.navigator.platform.toLowerCase();
|
||||
@@ -124,6 +126,7 @@ export const DEFAULT_SETTINGS: Settings = {
|
||||
useFirstArtistOnly: false,
|
||||
useSingleGenre: false,
|
||||
embedGenre: true,
|
||||
redownloadWithSuffix: false,
|
||||
separator: "semicolon"
|
||||
};
|
||||
export const FONT_OPTIONS: {
|
||||
@@ -243,6 +246,9 @@ function getSettingsFromLocalStorage(): Settings {
|
||||
if (!('separator' in parsed)) {
|
||||
parsed.separator = "semicolon";
|
||||
}
|
||||
if (!('redownloadWithSuffix' in parsed)) {
|
||||
parsed.redownloadWithSuffix = false;
|
||||
}
|
||||
return { ...DEFAULT_SETTINGS, ...parsed };
|
||||
}
|
||||
}
|
||||
@@ -346,6 +352,9 @@ export async function loadSettings(): Promise<Settings> {
|
||||
if (!('separator' in parsed)) {
|
||||
parsed.separator = "semicolon";
|
||||
}
|
||||
if (!('redownloadWithSuffix' in parsed)) {
|
||||
parsed.redownloadWithSuffix = false;
|
||||
}
|
||||
cachedSettings = { ...DEFAULT_SETTINGS, ...parsed };
|
||||
return cachedSettings!;
|
||||
}
|
||||
@@ -368,6 +377,7 @@ export interface TemplateData {
|
||||
album?: string;
|
||||
album_artist?: string;
|
||||
title?: string;
|
||||
isrc?: string;
|
||||
track?: number;
|
||||
disc?: number;
|
||||
year?: string;
|
||||
@@ -382,6 +392,7 @@ export function parseTemplate(template: string, data: TemplateData): string {
|
||||
result = result.replace(/\{artist\}/g, data.artist || "Unknown Artist");
|
||||
result = result.replace(/\{album\}/g, data.album || "Unknown Album");
|
||||
result = result.replace(/\{album_artist\}/g, data.album_artist || data.artist || "Unknown Artist");
|
||||
result = result.replace(/\{isrc\}/g, data.isrc || "");
|
||||
result = result.replace(/\{track\}/g, data.track ? String(data.track).padStart(2, "0") : "00");
|
||||
result = result.replace(/\{disc\}/g, data.disc ? String(data.disc) : "1");
|
||||
result = result.replace(/\{year\}/g, data.year || "0000");
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface TrackMetadata {
|
||||
artist_id?: string;
|
||||
artist_url?: string;
|
||||
artists_data?: ArtistSimple[];
|
||||
isrc?: string;
|
||||
copyright?: string;
|
||||
publisher?: string;
|
||||
plays?: string;
|
||||
@@ -134,6 +135,7 @@ export interface DownloadRequest {
|
||||
spotify_disc_number?: number;
|
||||
spotify_total_tracks?: number;
|
||||
spotify_total_discs?: number;
|
||||
isrc?: string;
|
||||
copyright?: string;
|
||||
publisher?: string;
|
||||
spotify_url?: string;
|
||||
@@ -190,6 +192,7 @@ export interface LyricsDownloadRequest {
|
||||
album_name?: string;
|
||||
album_artist?: string;
|
||||
release_date?: string;
|
||||
isrc?: string;
|
||||
output_dir?: string;
|
||||
filename_format?: string;
|
||||
track_number?: boolean;
|
||||
@@ -278,4 +281,5 @@ export interface AudioMetadata {
|
||||
track_number: number;
|
||||
disc_number: number;
|
||||
year: string;
|
||||
isrc?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user