diff --git a/app.go b/app.go
index 2e31cb3..ddf4b25 100644
--- a/app.go
+++ b/app.go
@@ -510,15 +510,15 @@ func (a *App) DownloadTrack(req DownloadRequest) (DownloadResponse, error) {
backend.CompleteDownloadItem(itemID, filename, 0)
}
- go func(fPath, track, artist, album, sID, cover, format string) {
+ go func(fPath, track, artist, album, sID, cover, format, source string) {
+ time.Sleep(2 * time.Second)
+
quality := "Unknown"
- durationStr := "--:--"
+ durationStr := "0:00"
meta, err := backend.GetTrackMetadata(fPath)
- if err == nil && meta != nil {
- if meta.BitsPerSample > 0 {
- quality = fmt.Sprintf("%d-bit/%.1fkHz", meta.BitsPerSample, float64(meta.SampleRate)/1000.0)
- } else if meta.Bitrate > 0 {
+ if err == nil {
+ if meta.Bitrate > 0 {
quality = fmt.Sprintf("%dkbps/%.1fkHz", meta.Bitrate/1000, float64(meta.SampleRate)/1000.0)
} else if meta.SampleRate > 0 {
quality = fmt.Sprintf("%.1fkHz", float64(meta.SampleRate)/1000.0)
@@ -539,6 +539,7 @@ func (a *App) DownloadTrack(req DownloadRequest) (DownloadResponse, error) {
Quality: quality,
Format: strings.ToUpper(format),
Path: fPath,
+ Source: source,
}
if item.Format == "" || item.Format == "LOSSLESS" {
@@ -554,7 +555,7 @@ func (a *App) DownloadTrack(req DownloadRequest) (DownloadResponse, error) {
}
backend.AddHistoryItem(item, "SpotiFLAC")
- }(filename, req.TrackName, req.ArtistName, req.AlbumName, req.SpotifyID, req.CoverURL, req.AudioFormat)
+ }(filename, req.TrackName, req.ArtistName, req.AlbumName, req.SpotifyID, req.CoverURL, req.AudioFormat, req.Service)
}
return DownloadResponse{
diff --git a/backend/history.go b/backend/history.go
index 11b6856..754db43 100644
--- a/backend/history.go
+++ b/backend/history.go
@@ -22,6 +22,7 @@ type HistoryItem struct {
Quality string `json:"quality"`
Format string `json:"format"`
Path string `json:"path"`
+ Source string `json:"source"`
Timestamp int64 `json:"timestamp"`
}
diff --git a/backend/spotfetch.go b/backend/spotfetch.go
index c584d94..4ca171c 100644
--- a/backend/spotfetch.go
+++ b/backend/spotfetch.go
@@ -555,7 +555,7 @@ func FilterTrack(data map[string]interface{}, separator string, albumFetchData .
copyrightData := getMap(albumData, "copyright")
if len(copyrightData) > 0 {
copyrightItems := getSlice(copyrightData, "items")
- if copyrightItems != nil {
+ if len(copyrightItems) > 0 {
for _, item := range copyrightItems {
itemMap, ok := item.(map[string]interface{})
if !ok {
@@ -574,7 +574,7 @@ func FilterTrack(data map[string]interface{}, separator string, albumFetchData .
if len(tracksData) > 0 {
discNumbers := make(map[int]bool)
trackItems := getSlice(tracksData, "items")
- if trackItems != nil {
+ if len(trackItems) > 0 {
for _, item := range trackItems {
itemMap, ok := item.(map[string]interface{})
if !ok {
@@ -656,7 +656,7 @@ func FilterTrack(data map[string]interface{}, separator string, albumFetchData .
albumArtistsString := ""
albumLabel := ""
- if albumFetchDataMap != nil && len(albumFetchDataMap) > 0 {
+ if len(albumFetchDataMap) > 0 {
albumUnionData := getMap(getMap(albumFetchDataMap, "data"), "albumUnion")
if len(albumUnionData) > 0 {
albumArtists := extractArtists(getMap(albumUnionData, "artists"))
@@ -957,21 +957,9 @@ func FilterPlaylist(data map[string]interface{}, separator string) map[string]in
avatarData := getMap(ownerData, "avatar")
if len(avatarData) > 0 {
sources := getSlice(avatarData, "sources")
- if sources != nil {
- for _, source := range sources {
- sourceMap, ok := source.(map[string]interface{})
- if !ok {
- continue
- }
- if getFloat64(sourceMap, "width") == 300 {
- avatarURL = getString(sourceMap, "url")
- break
- }
- }
- if avatarURL == nil && len(sources) > 0 {
- if firstSource, ok := sources[0].(map[string]interface{}); ok {
- avatarURL = getString(firstSource, "url")
- }
+ if len(sources) > 0 {
+ if firstSource, ok := sources[0].(map[string]interface{}); ok {
+ avatarURL = getString(firstSource, "url")
}
}
}
@@ -1291,7 +1279,7 @@ func extractDiscographyItems(itemsData map[string]interface{}) []map[string]inte
}
func stripHTMLTags(s string) string {
- re := regexp.MustCompile(`<[^>]*>`)
+ re := regexp.MustCompile(`(?s)<[^>]*>`)
return re.ReplaceAllString(s, "")
}
diff --git a/frontend/src/components/HistoryPage.tsx b/frontend/src/components/HistoryPage.tsx
index 9f34b4c..a5c488c 100644
--- a/frontend/src/components/HistoryPage.tsx
+++ b/frontend/src/components/HistoryPage.tsx
@@ -9,6 +9,7 @@ import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, Pagi
import { GetDownloadHistory, ClearDownloadHistory, GetPreviewURL, GetFetchHistory, DeleteDownloadHistoryItem, DeleteFetchHistoryItem, ClearFetchHistoryByType } from "../../wailsjs/go/main/App";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { openExternal } from "@/lib/utils";
+import { TidalIcon, QobuzIcon, AmazonIcon } from "./PlatformIcons";
const formatDate = (timestamp: number) => {
const date = new Date(timestamp * 1000);
const year = date.getFullYear();
@@ -30,6 +31,7 @@ interface DownloadHistoryItem {
quality: string;
format: string;
path: string;
+ source: string;
timestamp: number;
}
interface FetchHistoryItem {
@@ -62,10 +64,35 @@ export function HistoryPage({ onHistorySelect }: HistoryPageProps) {
const [fetchSearchQuery, setFetchSearchQuery] = useState("");
const [fetchCurrentPage, setFetchCurrentPage] = useState(1);
const ITEMS_PER_PAGE = 50;
+ const getTrackLink = (spotifyId: string) => {
+ if (spotifyId?.startsWith("tidal_"))
+ return { url: `https://listen.tidal.com/track/${spotifyId.replace("tidal_", "")}`, label: "Open in Tidal" };
+ if (spotifyId?.startsWith("qobuz_"))
+ return { url: `https://www.qobuz.com/track/${spotifyId.replace("qobuz_", "")}`, label: "Open in Qobuz" };
+ if (spotifyId?.startsWith("amazon_"))
+ return { url: `https://music.amazon.com/tracks/${spotifyId.replace("amazon_", "")}`, label: "Open in Amazon Music" };
+ if (spotifyId?.startsWith("deezer_"))
+ return { url: `https://www.deezer.com/track/${spotifyId.replace("deezer_", "")}`, label: "Open in Deezer" };
+ return { url: `https://open.spotify.com/track/${spotifyId}`, label: "Open in Spotify" };
+ };
+ const getSourceIcon = (source: string) => {
+ const s = source?.toLowerCase() || "";
+ if (s.includes("tidal"))
+ return