Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ type DownloadRequest struct {
UseSingleGenre bool `json:"use_single_genre,omitempty"`
EmbedGenre bool `json:"embed_genre,omitempty"`
Separator string `json:"separator,omitempty"`
IsExplicit bool `json:"is_explicit,omitempty"`
}

type DownloadResponse struct {
Expand Down Expand Up @@ -501,6 +502,8 @@ func (a *App) DownloadTrack(req DownloadRequest) (DownloadResponse, error) {
req.AudioFormat = "LOSSLESS"
}

req.TrackName = backend.ApplyExplicitTitleSuffix(req.TrackName, req.IsExplicit)

var err error
var filename string

Expand Down Expand Up @@ -1804,6 +1807,7 @@ type CheckFileExistenceRequest struct {
IncludeTrackNumber bool `json:"include_track_number,omitempty"`
AudioFormat string `json:"audio_format,omitempty"`
RelativePath string `json:"relative_path,omitempty"`
IsExplicit bool `json:"is_explicit,omitempty"`
}

type CheckFileExistenceResult struct {
Expand Down Expand Up @@ -1947,7 +1951,7 @@ func (a *App) CheckFilesExistence(outputDir string, rootDir string, tracks []Che
}

expectedFilenameBase := backend.BuildExpectedFilename(
t.TrackName,
backend.ApplyExplicitTitleSuffix(t.TrackName, t.IsExplicit),
t.ArtistName,
t.AlbumName,
t.AlbumArtist,
Expand Down
10 changes: 10 additions & 0 deletions backend/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ func GetRedownloadWithSuffixSetting() bool {
return enabled
}

func GetAppendExplicitTagSetting() bool {
settings, err := LoadConfigSettings()
if err != nil || settings == nil {
return false
}

enabled, _ := settings["appendExplicitTag"].(bool)
return enabled
}

func GetCustomTidalAPISetting() string {
settings, err := LoadConfigSettings()
if err != nil || settings == nil {
Expand Down
15 changes: 15 additions & 0 deletions backend/filename.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ import (
"unicode/utf8"
)

const explicitTitleSuffix = "πŸ…΄"

func ApplyExplicitTitleSuffix(title string, isExplicit bool) string {
if !isExplicit || title == "" {
return title
}
if !GetAppendExplicitTagSetting() {
return title
}
if strings.HasSuffix(strings.TrimSpace(title), explicitTitleSuffix) {
return title
}
return strings.TrimRight(title, " ") + " " + explicitTitleSuffix
}

func buildFormattedFilenameBase(trackName, artistName, albumName, albumArtist, releaseDate, filenameFormat, playlistName, playlistOwner, isrc string, includeTrackNumber bool, position, discNumber int, useAlbumTrackNumber bool) string {
safeTitle := SanitizeFilename(trackName)
safeArtist := SanitizeFilename(artistName)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/AlbumInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ interface AlbumInfoProps {
onSortChange: (value: string) => void;
onToggleTrack: (id: string) => void;
onToggleSelectAll: (tracks: TrackMetadata[]) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string, isExplicit?: boolean) => void;
onDownloadLyrics?: (spotifyId: string, name: string, artists: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
onDownloadCover?: (coverUrl: string, trackName: string, artistName: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, trackId?: string, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
onCheckAvailability?: (spotifyId: string) => void;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ArtistInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ interface ArtistInfoProps {
onSortChange: (value: string) => void;
onToggleTrack: (id: string) => void;
onToggleSelectAll: (tracks: TrackMetadata[]) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string, isExplicit?: boolean) => void;
onDownloadLyrics?: (spotifyId: string, name: string, artists: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
onDownloadCover?: (coverUrl: string, trackName: string, artistName: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, trackId?: string, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
onCheckAvailability?: (spotifyId: string) => void;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/PlaylistInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ interface PlaylistInfoProps {
onSortChange: (value: string) => void;
onToggleTrack: (id: string) => void;
onToggleSelectAll: (tracks: TrackMetadata[]) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string, isExplicit?: boolean) => void;
onDownloadLyrics?: (spotifyId: string, name: string, artists: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
onDownloadCover?: (coverUrl: string, trackName: string, artistName: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, trackId?: string, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
onCheckAvailability?: (spotifyId: string) => void;
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/components/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,16 @@ export function SettingsPage({ onUnsavedChangesChange, onResetRequest, }: Settin
</Label>
</div>

<div className="flex items-center gap-3">
<Switch id="append-explicit-tag" checked={tempSettings.appendExplicitTag} onCheckedChange={(checked) => setTempSettings((prev) => ({
...prev,
appendExplicitTag: checked,
}))}/>
<Label htmlFor="append-explicit-tag" className="text-sm cursor-pointer font-normal">
Append πŸ…΄ to explicit track titles
</Label>
</div>


</div>

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/TrackList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface TrackListProps {
downloadingCoverTrack?: string | null;
onToggleTrack: (id: string) => void;
onToggleSelectAll: (tracks: TrackMetadata[]) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string) => void;
onDownloadTrack: (id: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, durationMs?: number, position?: number, albumArtist?: string, releaseDate?: string, coverUrl?: string, spotifyTrackNumber?: number, spotifyDiscNumber?: number, spotifyTotalTracks?: number, spotifyTotalDiscs?: number, copyright?: string, publisher?: string, isExplicit?: boolean) => void;
onDownloadLyrics?: (spotifyId: string, name: string, artists: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
onCheckAvailability?: (spotifyId: string) => void;
onDownloadCover?: (coverUrl: string, trackName: string, artistName: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number, trackId?: string, albumArtist?: string, releaseDate?: string, discNumber?: number) => void;
Expand Down Expand Up @@ -289,7 +289,7 @@ export function TrackList({ tracks, searchQuery, sortBy, selectedTracks, downloa
<div className="flex items-center justify-center gap-1">
{track.spotify_id && (<Tooltip>
<TooltipTrigger asChild>
<Button onClick={() => onDownloadTrack(track.spotify_id!, track.name, track.artists, track.album_name, track.spotify_id, folderName, track.duration_ms, startIndex + index + 1, track.album_artist, track.release_date, track.images, track.track_number, track.disc_number, track.total_tracks, track.total_discs, track.copyright, track.publisher)} size="icon" disabled={isDownloading || downloadingTrack === track.spotify_id}>
<Button onClick={() => onDownloadTrack(track.spotify_id!, track.name, track.artists, track.album_name, track.spotify_id, folderName, track.duration_ms, startIndex + index + 1, track.album_artist, track.release_date, track.images, track.track_number, track.disc_number, track.total_tracks, track.total_discs, track.copyright, track.publisher, track.is_explicit)} size="icon" disabled={isDownloading || downloadingTrack === track.spotify_id}>
{downloadingTrack === track.spotify_id ? (<Spinner />) : skippedTracks.has(track.spotify_id) ? (<FileCheck className="h-4 w-4"/>) : downloadedTracks.has(track.spotify_id) ? (<CheckCircle className="h-4 w-4"/>) : failedTracks.has(track.spotify_id) ? (<XCircle className="h-4 w-4"/>) : (<Download className="h-4 w-4"/>)}
</Button>
</TooltipTrigger>
Expand Down
Loading