.link resolver
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetDefaultMusicPath() string {
|
func GetDefaultMusicPath() string {
|
||||||
@@ -67,3 +68,34 @@ func GetSpotFetchAPISettings() (bool, string) {
|
|||||||
|
|
||||||
return true, apiURL
|
return true, apiURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetLinkResolverSetting() string {
|
||||||
|
settings, err := LoadConfigSettings()
|
||||||
|
if err != nil || settings == nil {
|
||||||
|
return linkResolverProviderSongstats
|
||||||
|
}
|
||||||
|
|
||||||
|
resolver, _ := settings["linkResolver"].(string)
|
||||||
|
switch strings.TrimSpace(strings.ToLower(resolver)) {
|
||||||
|
case "songlink", linkResolverProviderDeezerSongLink:
|
||||||
|
return linkResolverProviderDeezerSongLink
|
||||||
|
case "", "songstats":
|
||||||
|
return linkResolverProviderSongstats
|
||||||
|
default:
|
||||||
|
return linkResolverProviderSongstats
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLinkResolverAllowFallback() bool {
|
||||||
|
settings, err := LoadConfigSettings()
|
||||||
|
if err != nil || settings == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
allowFallback, ok := settings["allowResolverFallback"].(bool)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return allowFallback
|
||||||
|
}
|
||||||
|
|||||||
+27
-14
@@ -30,32 +30,23 @@ func (s *SongLinkClient) resolveSpotifyTrackLinks(spotifyTrackID string, region
|
|||||||
}
|
}
|
||||||
|
|
||||||
if links.ISRC != "" {
|
if links.ISRC != "" {
|
||||||
resolvers := prioritizeProviders("link_resolver", []string{
|
resolvers := orderedLinkResolvers()
|
||||||
linkResolverProviderSongstats,
|
|
||||||
linkResolverProviderDeezerSongLink,
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, resolver := range resolvers {
|
for _, resolver := range resolvers {
|
||||||
switch resolver {
|
switch resolver {
|
||||||
case linkResolverProviderSongstats:
|
case linkResolverProviderSongstats:
|
||||||
addedData, songstatsErr := s.resolveLinksViaSongstats(links)
|
addedData, songstatsErr := s.resolveLinksViaSongstats(links)
|
||||||
if addedData {
|
|
||||||
recordProviderSuccess("link_resolver", linkResolverProviderSongstats)
|
|
||||||
} else if songstatsErr != nil {
|
|
||||||
recordProviderFailure("link_resolver", linkResolverProviderSongstats)
|
|
||||||
}
|
|
||||||
if songstatsErr != nil {
|
if songstatsErr != nil {
|
||||||
attempts = append(attempts, fmt.Sprintf("songstats: %v", songstatsErr))
|
attempts = append(attempts, fmt.Sprintf("songstats: %v", songstatsErr))
|
||||||
|
} else if addedData {
|
||||||
|
fmt.Println("Using Songstats as configured link resolver")
|
||||||
}
|
}
|
||||||
case linkResolverProviderDeezerSongLink:
|
case linkResolverProviderDeezerSongLink:
|
||||||
addedData, deezerSongLinkErr := s.resolveLinksViaDeezerSongLink(links, region)
|
addedData, deezerSongLinkErr := s.resolveLinksViaDeezerSongLink(links, region)
|
||||||
if addedData {
|
|
||||||
recordProviderSuccess("link_resolver", linkResolverProviderDeezerSongLink)
|
|
||||||
} else if deezerSongLinkErr != nil {
|
|
||||||
recordProviderFailure("link_resolver", linkResolverProviderDeezerSongLink)
|
|
||||||
}
|
|
||||||
if deezerSongLinkErr != nil {
|
if deezerSongLinkErr != nil {
|
||||||
attempts = append(attempts, fmt.Sprintf("deezer-songlink: %v", deezerSongLinkErr))
|
attempts = append(attempts, fmt.Sprintf("deezer-songlink: %v", deezerSongLinkErr))
|
||||||
|
} else if addedData {
|
||||||
|
fmt.Println("Using Songlink as configured link resolver")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +67,28 @@ func (s *SongLinkClient) resolveSpotifyTrackLinks(spotifyTrackID string, region
|
|||||||
return links, errors.New(strings.Join(attempts, " | "))
|
return links, errors.New(strings.Join(attempts, " | "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func orderedLinkResolvers() []string {
|
||||||
|
preferred := GetLinkResolverSetting()
|
||||||
|
if !GetLinkResolverAllowFallback() {
|
||||||
|
if preferred == linkResolverProviderDeezerSongLink {
|
||||||
|
return []string{linkResolverProviderDeezerSongLink}
|
||||||
|
}
|
||||||
|
return []string{linkResolverProviderSongstats}
|
||||||
|
}
|
||||||
|
|
||||||
|
if preferred == linkResolverProviderDeezerSongLink {
|
||||||
|
return []string{
|
||||||
|
linkResolverProviderDeezerSongLink,
|
||||||
|
linkResolverProviderSongstats,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{
|
||||||
|
linkResolverProviderSongstats,
|
||||||
|
linkResolverProviderDeezerSongLink,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SongLinkClient) resolveLinksViaSongstats(links *resolvedTrackLinks) (bool, error) {
|
func (s *SongLinkClient) resolveLinksViaSongstats(links *resolvedTrackLinks) (bool, error) {
|
||||||
if links == nil || links.ISRC == "" {
|
if links == nil || links.ISRC == "" {
|
||||||
return false, fmt.Errorf("ISRC is required for Songstats resolver")
|
return false, fmt.Errorf("ISRC is required for Songstats resolver")
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -14,6 +14,8 @@ import { SelectFolder, OpenConfigFolder } from "../../wailsjs/go/main/App";
|
|||||||
import { toastWithSound as toast } from "@/lib/toast-with-sound";
|
import { toastWithSound as toast } from "@/lib/toast-with-sound";
|
||||||
import { ApiStatusTab } from "./ApiStatusTab";
|
import { ApiStatusTab } from "./ApiStatusTab";
|
||||||
import { AmazonIcon, QobuzIcon, TidalIcon } from "./PlatformIcons";
|
import { AmazonIcon, QobuzIcon, TidalIcon } from "./PlatformIcons";
|
||||||
|
import songlinkIcon from "@/assets/icons/songlink.ico";
|
||||||
|
import songstatsIcon from "@/assets/icons/songstats.png";
|
||||||
interface SettingsPageProps {
|
interface SettingsPageProps {
|
||||||
onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void;
|
onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void;
|
||||||
onResetRequest?: (resetFn: () => void) => void;
|
onResetRequest?: (resetFn: () => void) => void;
|
||||||
@@ -230,6 +232,44 @@ export function SettingsPage({ onUnsavedChangesChange, onResetRequest, }: Settin
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="link-resolver">Link Resolver</Label>
|
||||||
|
<div className="flex items-center gap-3 flex-wrap">
|
||||||
|
<Select value={tempSettings.linkResolver} onValueChange={(value: "songstats" | "songlink") => setTempSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
linkResolver: value,
|
||||||
|
}))}>
|
||||||
|
<SelectTrigger id="link-resolver" className="h-9 w-fit min-w-[140px]">
|
||||||
|
<SelectValue placeholder="Select a link resolver"/>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="songstats">
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<img src={songstatsIcon} alt="Songstats" className="h-4 w-4 shrink-0 rounded-[3px] object-contain" loading="lazy" />
|
||||||
|
Songstats
|
||||||
|
</span>
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="songlink">
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<img src={songlinkIcon} alt="Songlink" className="h-4 w-4 shrink-0 rounded-[3px] object-contain" loading="lazy" />
|
||||||
|
Songlink
|
||||||
|
</span>
|
||||||
|
</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<Switch id="allow-link-resolver-fallback" checked={tempSettings.allowResolverFallback} onCheckedChange={(checked) => setTempSettings((prev) => ({
|
||||||
|
...prev,
|
||||||
|
allowResolverFallback: checked,
|
||||||
|
}))}/>
|
||||||
|
<Label htmlFor="allow-link-resolver-fallback" className="text-sm font-normal cursor-pointer">
|
||||||
|
Allow Fallback
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="downloader">Source</Label>
|
<Label htmlFor="downloader">Source</Label>
|
||||||
<div className="flex gap-2 flex-wrap">
|
<div className="flex gap-2 flex-wrap">
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ export type FilenamePreset = "title" | "title-artist" | "artist-title" | "track-
|
|||||||
export interface Settings {
|
export interface Settings {
|
||||||
downloadPath: string;
|
downloadPath: string;
|
||||||
downloader: "auto" | "tidal" | "qobuz" | "amazon";
|
downloader: "auto" | "tidal" | "qobuz" | "amazon";
|
||||||
|
linkResolver: "songstats" | "songlink";
|
||||||
|
allowResolverFallback: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
themeMode: "auto" | "light" | "dark";
|
themeMode: "auto" | "light" | "dark";
|
||||||
fontFamily: FontFamily;
|
fontFamily: FontFamily;
|
||||||
@@ -93,6 +95,8 @@ function detectOS(): "Windows" | "linux/MacOS" {
|
|||||||
export const DEFAULT_SETTINGS: Settings = {
|
export const DEFAULT_SETTINGS: Settings = {
|
||||||
downloadPath: "",
|
downloadPath: "",
|
||||||
downloader: "auto",
|
downloader: "auto",
|
||||||
|
linkResolver: "songstats",
|
||||||
|
allowResolverFallback: true,
|
||||||
theme: "yellow",
|
theme: "yellow",
|
||||||
themeMode: "auto",
|
themeMode: "auto",
|
||||||
fontFamily: "google-sans",
|
fontFamily: "google-sans",
|
||||||
@@ -225,6 +229,12 @@ function getSettingsFromLocalStorage(): Settings {
|
|||||||
if (!('allowFallback' in parsed)) {
|
if (!('allowFallback' in parsed)) {
|
||||||
parsed.allowFallback = true;
|
parsed.allowFallback = true;
|
||||||
}
|
}
|
||||||
|
if (!('linkResolver' in parsed)) {
|
||||||
|
parsed.linkResolver = "songstats";
|
||||||
|
}
|
||||||
|
if (!('allowResolverFallback' in parsed)) {
|
||||||
|
parsed.allowResolverFallback = true;
|
||||||
|
}
|
||||||
if (!('separator' in parsed)) {
|
if (!('separator' in parsed)) {
|
||||||
parsed.separator = "semicolon";
|
parsed.separator = "semicolon";
|
||||||
}
|
}
|
||||||
@@ -304,6 +314,12 @@ export async function loadSettings(): Promise<Settings> {
|
|||||||
if (!('allowFallback' in parsed)) {
|
if (!('allowFallback' in parsed)) {
|
||||||
parsed.allowFallback = true;
|
parsed.allowFallback = true;
|
||||||
}
|
}
|
||||||
|
if (!('linkResolver' in parsed)) {
|
||||||
|
parsed.linkResolver = "songstats";
|
||||||
|
}
|
||||||
|
if (!('allowResolverFallback' in parsed)) {
|
||||||
|
parsed.allowResolverFallback = true;
|
||||||
|
}
|
||||||
if (!('createPlaylistFolder' in parsed)) {
|
if (!('createPlaylistFolder' in parsed)) {
|
||||||
parsed.createPlaylistFolder = true;
|
parsed.createPlaylistFolder = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user