diff --git a/README.md b/README.md index ff3bdaf..becd07a 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Supersonic supports any music server with a Subsonic (or OpenSubsonic) API, or J * [Jellyfin](https://jellyfin.org) * [Gonic](https://github.com/sentriz/gonic) * [LMS](https://github.com/epoupon/lms) +* [Nextcloud Music](https://apps.nextcloud.com/apps/music) * [Airsonic-Advanced](https://github.com/airsonic-advanced/airsonic-advanced) * [Ampache](https://ampache.org) * [Funkwhale](https://www.funkwhale.audio/) diff --git a/backend/mediaprovider/subsonic/trackiterator.go b/backend/mediaprovider/subsonic/trackiterator.go index 4d1b44d..8179bb4 100644 --- a/backend/mediaprovider/subsonic/trackiterator.go +++ b/backend/mediaprovider/subsonic/trackiterator.go @@ -12,7 +12,7 @@ func (s *subsonicMediaProvider) IterateTracks(searchQuery string) mediaprovider. return &allTracksIterator{ s: s, albumIter: s.IterateAlbums( - mediaprovider.AlbumSortArtistAZ, + mediaprovider.AlbumSortRecentlyAdded, mediaprovider.NewAlbumFilter(mediaprovider.AlbumFilterOptions{}), ), } diff --git a/res/translations/en.json b/res/translations/en.json index e095b42..08d9b69 100644 --- a/res/translations/en.json +++ b/res/translations/en.json @@ -224,5 +224,7 @@ "Set favorite": "Set favorite", "Unset favorite": "Unset favorite", "Remove from queue": "Remove from queue", - "Play song radio": "Play song radio" + "Play song radio": "Play song radio", + "to":"to", + "by":"by" } diff --git a/res/translations/it.json b/res/translations/it.json index 4f3aa63..6b444db 100644 --- a/res/translations/it.json +++ b/res/translations/it.json @@ -164,9 +164,9 @@ "Show info": "Mostra informazioni", "Show notification on track change": "Mostra notifica quando cambia la traccia", "Show year in album grid cards": "Mostra l'anno nella griglia degli album", - "Shuffle": "Mescola", - "Shuffle albums": "Mescola album", - "Shuffle tracks": "Mescola tracce", + "Shuffle": "Casuale", + "Shuffle albums": "Album casuali", + "Shuffle tracks": "Tracce casuali", "Similar artists": "Artisti simili", "Single": "Single", "Size": "Dimensione", @@ -216,5 +216,7 @@ "Set favorite": "Segna come preferito", "Unset favorite": "Rimuovi preferito", "Remove from queue": "Rimuovi dalla coda", - "Play song radio": "Avvia radio mix" + "Play song radio": "Avvia radio mix", + "to": "a", + "by": "by" } diff --git a/res/translations/pl.json b/res/translations/pl.json new file mode 100644 index 0000000..f926e03 --- /dev/null +++ b/res/translations/pl.json @@ -0,0 +1,222 @@ +{ + "A new version is available": "Nowa wersja jest dostępna", + "About": "O aplikacji", + "Add Server": "Dodaj serwer", + "Add to playlist": "Dodaj do playlisty", + "Add to queue": "Dodaj do odtwarzania", + "Album": "Album", + "album": "album", + "Album count": "Ilość albumów", + "Album Count": "Ilość Albumów", + "Album filters": "Filtry albumu", + "Album gain": "Album gain", + "Album info not available": "Informacje ablumu niedostępne", + "Album peak": "Album peak", + "Albums": "Albumy", + "albums": "albumy", + "All": "Wszystko", + "All Tracks": "Wszystkie ", + "Alt. URL": "Alt. URL", + "Are you sure you want to delete the server": "Czy jesteś pewny, że chcesz usunąć serwer", + "Artist": "Artysta", + "Artist (A-Z)": "Artyści (A-Z)", + "Artists": "Artyści", + "Artist biography not available.": "Biografia artysty niedostępna.", + "Audio device": "Urządzenie audio", + "Audio Drama": "Audio Drama", + "Audiobook": "Audiobook", + "Authentication failed": "Błąd autoryzacji", + "Auto": "Auto", + "Autoselect device": "Automatyczny wybór", + "Bit rate": "Bit rate", + "BPM": "BPM", + "Broadcast": "Broadcast", + "Cancel": "Anuluj", + "Check for Updates": "Sprawdź aktualizacje", + "Close": "Zamknij", + "Close to system tray": "Zamknij do zasobnika systemowego", + "Comment": "Komentarz", + "Compilation": "Compilation", + "Composer": "Composer", + "Configure your music server to add radio stations": "Skonfiguruj swój serwer muzyki aby dodać stacje radiowe", + "Confirm Delete Playlist": "Potwierdź usunięcie playlisty", + "Confirm Delete Server": "Potwierdź usunięcie serwera", + "Connect to Server": "Połącz z Serwerem", + "Connecting": "Łączenie", + "Connecting to": "Łączenie z", + "Content type": "Typ pliku", + "Could not reach server": "Nie można dosięgnąć serwera", + "Create new playlist": "Utwórz nową playlistę", + "day": "dzień", + "days": "dni", + "Delete Playlist": "Usuń playlistę", + "Demo": "Demo", + "Description": "Opis", + "Disable server transcoding": "Wyłącz transkodowanie serwera", + "Disc number": "Disc number", + "Discography": "Dyskografia", + "discs": "discs", + "DJ-Mix": "DJ-Mix", + "Download": "Pobierz", + "Download completed": "Pobieranie zakończone", + "Duration": "Czas trwania", + "Edit": "Edytuj", + "Edit Playlist": "Edytuj playlistę", + "Edit server": "Edytuj serwer", + "Enable system tray": "Włącz chowanie do zasobnika", + "Enabled": "Włączony", + "Enter": "Enter", + "EP": "EP", + "Equalizer": "Equalizer", + "Exclusive mode": "Tryb exclusive", + "Favorites": "Ulubione", + "Field Recording": "Field Recording", + "File path": "Ścieżka pliku", + "File size": "Wielkość pliku", + "Filter genres": "Filtruj gatunki", + "Frequently Played": "Często odtwarzane", + "General": "Ogólny", + "Genre": "Gatunek", + "Genres": "Gatunki", + "Github page": "Strona githuba", + "Go to release page": "Otwórz stronę z wersjami", + "Hide": "Ukryj", + "Home Page": "Strona domowa", + "hr": "hr", + "hrs": "hrs", + "Internet Radio Stations": "Internetowe Stacje Radiowe", + "Interview": "Wywiad", + "Is favorite": "Jest ulubione", + "Is not favorite": "Nie jest ulubione", + "Last played": "Ostatnio odtwarzane", + "Live": "Live", + "Locally": "Lokalnie", + "Log Out": "Wyloguj", + "Login to Server": "Login do Serwera", + "Lyrics": "Tekst piosenki", + "Lyrics not available": "Tekst piosenki nie jest dostępny", + "min": "min", + "minutes of track have been played": "minuty utworu odtworzono", + "Mixtape": "Mixtape", + "My Server": "Mój serwer", + "Name": "Nazwa", + "Name (A-Z)": "Nazwa (A-Z)", + "Next": "Następny", + "Nickname": "Nazwa serwera", + "No new version found": "Nie znaleziono nowych wersji", + "No radio stations available": "Brak dostępnych radio stacji", + "None": "Nic", + "none": "nic", + "none selected": "wybrano nic", + "OK": "OK", + "optional": "opcjonalne", + "or when": "lub kiedy", + "Password": "Hasło", + "Pause": "Pauza", + "Paused": "Wstrzymane", + "Peak Meter": "Licznik szczytowy", + "percent of track is played": "procent odtworzonej piosenki", + "Play": "Odtwórz", + "Play Artist Radio": "Odtwórz radio artysty", + "Play count": "Ilość odtworzeń", + "Play Discography": "Odtwórz Dyskografię", + "Play next": "Odtwórz następne", + "Play Queue": "Lista odtwarzania", + "Play random": "Odtwórz losowo", + "Playback": "Playback", + "Playing": "Odtwarza", + "Playlist": "Playlista", + "Playlists": "Playlisty", + "playlist by": "playlista przez", + "Plays": "Ilość odtworzeń", + "Prevent clipping": "Zapobiegnij przycicnaniu", + "Previous": "Poprzednie", + "Private": "Prywatna", + "Public": "Publiczne", + "Random": "Losowe", + "Rating": "Ocena", + "reissued": "odnowiony", + "Recently Added": "Ostatnio dodane", + "Recently Played": "Ostatnio odtwarzane", + "Related": "Powiązane", + "Remix": "Remix", + "Remove from playlist": "Usuń z playlisty", + "ReplayGain mode": "ReplayGain mode", + "ReplayGain preamp": "ReplayGain preamp", + "Restart required": "Wymagany restart", + "Save play queue on exit": "Zapisz kolejkę odtwarzania po zamknięciu", + "Saved at": "Zapisano w", + "Scrobble when": "Wyślij gdy", + "Search Everywhere": "Szukaj wszędzie", + "Search page": "Przeszukaj stronę", + "Search playlists or new playlist name": "Szukaj playlisty lub", + "sec": "sec", + "selected": "wybrano", + "Send playback statistics to server": "Wyślij statystyki playbacku do serwera", + "Server": "Serwer", + "Server Type": "Typ serwera", + "Server unreachable": "Server nieosiągalny", + "Set rating": "Ustaw ocenę", + "Settings": "Ustawienia", + "Share": "Udostępnij", + "Share content": "Share content", + "Show": "Pokaż", + "Show info": "Pokaż informacje", + "Show notification on track change": "Pokaż powiadomienie o zmianie ścieżki", + "Show year in album grid cards": "Pokaż rok w zakładce albumu", + "Shuffle": "Wymieszaj", + "Shuffle albums": "Wymieszaj album", + "Shuffle tracks": "Wymieszaj ścieżki", + "Similar artists": "Podobni artyści", + "Single": "Single", + "Size": "Wielkość", + "Skip duplicate tracks": "Pomiń zduplikowane ścieżki", + "Skip this version": "Pomiń tą wersję", + "Soundtrack": "Soundtrack", + "Spoken Word": "Spoken Word", + "Startup page": "Strona startowa", + "Stopped": "Wstrzymane", + "Support the project": "Wesprzyj projekt", + "Switch Servers": "Zmień serwer", + "Testing connection": "Testowanie połączenia", + "Theme": "Motyw", + "Time": "Czas", + "Title": "Tytuł", + "Title (A-Z)": "Tytuł (A-Z)", + "Top Tracks": "Top utworów", + "Total time": "Pełny czas", + "Track": "Utwór", + "track": "utwór", + "Track count": "Ilość utworów", + "Track gain": "Track gain", + "Track Info": "Informacje utworu", + "Track number": "Numer utworu", + "Track peak": "Track peak", + "tracks": "utwory", + "UI Scaling": "Skalowanie UI", + "URL": "URL", + "Use legacy authentication": "Użyj starsze uwierzytelnianie", + "Username": "Login", + "version": "wersja", + "Visualizations": "Wizualizacja", + "Volume": "Głośność", + "wrong URL": "Nieprawidłowy URL", + "wrong username/password": "Nieprawidłowy login/hasło", + "Year": "Rok", + "Year (ascending)": "Rok (rosnąco)", + "Year (descending)": "Rok (malejąco)", + "Year from": "Z roku", + "You are running the latest version of": "Korzystasz z najnowszej wersji", + "Quit": "Wyjdź", + "Rescan Library": "Przeszukaj ponownie bibliotekę", + "Search": "Szukaj", + "Owner": "Właściciel", + "To server": "Do serwera", + "Fav.": "Ulub.", + "Set favorite": "Ustaw ulubione", + "Unset favorite": "Usuń ulubione", + "Remove from queue": "Usuń z kolejki odtwarzania", + "Play song radio": "Odtwórz mix utworów", + "to":"do", + "by":"przez" +} diff --git a/res/translations/ro.json b/res/translations/ro.json new file mode 100644 index 0000000..be96f48 --- /dev/null +++ b/res/translations/ro.json @@ -0,0 +1,222 @@ +{ + "A new version is available": "O nouă versiune este disponibilă", + "About": "Despre", + "Add Server": "Adaugă server", + "Add to playlist": "Adaugă în playlist", + "Add to queue": "Adaugă în lista de redare", + "Album": "Album", + "album": "album", + "Album count": "Număr album", + "Album Count": "Număr album", + "Album filters": "Filtre album", + "Album gain": "Nivel volum album", + "Album info not available": "Informații despre album indisponibile", + "Album peak": "Vârf album", + "Albums": "Albume", + "albums": "albume", + "All": "Toate", + "All Tracks": "Toate melodiile", + "Alt. URL": "URL alt.", + "Are you sure you want to delete the server": "Ești sigur că vrei să ștergi serverul", + "Artist": "Artist", + "Artist (A-Z)": "Artist (A-Z)", + "Artists": "Artiști", + "Artist biography not available.": "Biografia artistului indisponibilă.", + "Audio device": "Dispozitiv audio", + "Audio Drama": "Dramă audio", + "Audiobook": "Audiobook", + "Authentication failed": "Autentificare eșuată", + "Auto": "Auto", + "Autoselect device": "Selectează automat dispozitiv", + "Bit rate": "Bit rate", + "BPM": "BPM", + "Broadcast": "Transmisiune", + "Cancel": "Anulează", + "Check for Updates": "Verifică actualizări", + "Close": "Închide", + "Close to system tray": "Închide în bara de sistem", + "Comment": "Comentariu", + "Compilation": "Compilație", + "Composer": "Compozitor", + "Configure your music server to add radio stations": "Configurează-ți serverul de muzică pentru a adăuga stații radio", + "Confirm Delete Playlist": "Confirmare ștergere playlist", + "Confirm Delete Server": "Confirmare ștergere server", + "Connect to Server": "Conectare la server", + "Connecting": "Conectare", + "Connecting to": "Conectare la", + "Content type": "Tip conținut", + "Could not reach server": "Serverul nu a putut fi contactat", + "Create new playlist": "Creează playlist nou", + "day": "zi", + "days": "zile", + "Delete Playlist": "Șterge playlist", + "Demo": "Demo", + "Description": "Descriere", + "Disable server transcoding": "Dezactivează transcodare pe server", + "Disc number": "Număr disc", + "Discography": "Discografie", + "discs": "discuri", + "DJ-Mix": "DJ-Mix", + "Download": "Descarcă", + "Download completed": "Descărcare completă", + "Duration": "Durată", + "Edit": "Editare", + "Edit Playlist": "Editează playlist", + "Edit server": "Editează server", + "Enable system tray": "Activare bara de sistem", + "Enabled": "Activat", + "Enter": "Enter", + "EP": "EP", + "Equalizer": "Egalizator", + "Exclusive mode": "Mod exclusiv", + "Favorites": "Favorite", + "Field Recording": "Înregistrare teren", + "File path": "Locație fișier", + "File size": "Mărime fișier", + "Filter genres": "Filtrează genuri", + "Frequently Played": "Redate frecvent", + "General": "General", + "Genre": "Gen", + "Genres": "Genuri", + "Github page": "Pagina Github", + "Go to release page": "Mergi la pagina de release-uri", + "Hide": "Ascunde", + "Home Page": "Pagina principală", + "hr": "oră", + "hrs": "ore", + "Internet Radio Stations": "Stații radio pe internet", + "Interview": "Interviu", + "Is favorite": "Este favorit", + "Is not favorite": "Nu este favorit", + "Last played": "Ultimul redat", + "Live": "Live", + "Locally": "Local", + "Log Out": "Deconectare", + "Login to Server": "Conectare la server", + "Lyrics": "Versuri", + "Lyrics not available": "Versuri indisponibile", + "min": "min", + "minutes of track have been played": "minute din melodie au fost redate", + "Mixtape": "Mixtape", + "My Server": "Serverul meu", + "Name": "Nume", + "Name (A-Z)": "Nume (A-Z)", + "Next": "Următorul", + "Nickname": "Supranume", + "No new version found": "Nicio versiune nouă", + "No radio stations available": "Nicio stație radio disponibilă", + "None": "Nimic", + "none": "nimic", + "none selected": "nimic selectat", + "OK": "OK", + "optional": "opțional", + "or when": "sau când", + "Password": "Parolă", + "Pause": "Pauză", + "Paused": "Oprit", + "Peak Meter": "Indicator de vârf", + "percent of track is played": "la sută din melodie a fost redat", + "Play": "Redare", + "Play Artist Radio": "Redă radio artist", + "Play count": "Număr redări", + "Play Discography": "Redă discografia", + "Play next": "Redă următorul", + "Play Queue": "Redă lista de redare", + "Play random": "Redă aleatoriu", + "Playback": "Playback", + "Playing": "Redare", + "Playlist": "Playlist", + "Playlists": "Playlist-uri", + "playlist by": "playlist de", + "Plays": "Redări", + "Prevent clipping": "Previne distorsiunea", + "Previous": "Anterior", + "Private": "Privat", + "Public": "Public", + "Random": "Aleatoriu", + "Rating": "Rating", + "reissued": "reeditat", + "Recently Added": "Adăugat recent", + "Recently Played": "Redat recent", + "Related": "Asociat", + "Remix": "Remix", + "Remove from playlist": "Șterge din playlist", + "ReplayGain mode": "Mod ReplayGain", + "ReplayGain preamp": "Preamplificare ReplayGain", + "Restart required": "Repornire necesară", + "Save play queue on exit": "Salvează listă de redare la ieșire", + "Saved at": "Salvat la", + "Scrobble when": "Scrobblare când", + "Search Everywhere": "Caută peste tot", + "Search page": "Pagină căutare", + "Search playlists or new playlist name": "Caută playlisturi sau nume de playlist nou", + "sec": "sec", + "selected": "selectat", + "Send playback statistics to server": "Trimite statistici de redare la server", + "Server": "Server", + "Server Type": "Tip server", + "Server unreachable": "Server indisponibil", + "Set rating": "Setează rating", + "Settings": "Setări", + "Share": "Partajează", + "Share content": "Partajează conținut", + "Show": "Arată", + "Show info": "Arată informații", + "Show notification on track change": "Arată notificare la schimbarea melodiei", + "Show year in album grid cards": "Arată anul în gridul de albume", + "Shuffle": "Amestecare", + "Shuffle albums": "Amestecă albume", + "Shuffle tracks": "Amestecă melodii", + "Similar artists": "Similar artists", + "Single": "Single", + "Size": "Mărime", + "Skip duplicate tracks": "Sari peste melodii duplicate", + "Skip this version": "Sari peste această versiune", + "Soundtrack": "Soundtrack", + "Spoken Word": "Cuvânt vorbit", + "Startup page": "Pagina de start", + "Stopped": "Oprit", + "Support the project": "Sprijină proiectul", + "Switch Servers": "Schimbă server-uri", + "Testing connection": "Testare conexiune", + "Theme": "Temă", + "Time": "Timp", + "Title": "Titlu", + "Title (A-Z)": "Titlu (A-Z)", + "Top Tracks": "Top melodii", + "Total time": "Timp total", + "Track": "Melodie", + "track": "melodie", + "Track count": "Număr melodii", + "Track gain": "Nivel volum melodie", + "Track Info": "Informații melodie", + "Track number": "Număr melodie", + "Track peak": "Vârf melodie", + "tracks": "melodii", + "UI Scaling": "Scalare interfață", + "URL": "URL", + "Use legacy authentication": "Folosește autentificarea de bază", + "Username": "Nume utilizator", + "version": "versiune", + "Visualizations": "Vizualizări", + "Volume": "Volum", + "wrong URL": "URL greșit", + "wrong username/password": "nume utilizator sau parolă greșite", + "Year": "An", + "Year (ascending)": "An (ascendent)", + "Year (descending)": "An (Descendent)", + "Year from": "An de la", + "You are running the latest version of": "Folosești ultima versiune de", + "Quit": "Ieșire", + "Rescan Library": "Rescanează librăria", + "Search": "Caută", + "Owner": "Deținător", + "To server": "Către server", + "Fav.": "Fav.", + "Set favorite": "Setează favorit", + "Unset favorite": "Șterge favorit", + "Remove from queue": "Șterge din lista de redare", + "Play song radio": "Redă melodie radio", + "to": "la", + "by": "de" +} diff --git a/ui/browsing/albumpage.go b/ui/browsing/albumpage.go index 01fcc69..6c14fdc 100644 --- a/ui/browsing/albumpage.go +++ b/ui/browsing/albumpage.go @@ -213,7 +213,7 @@ func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader { } a.releaseTypeLabel = widget.NewRichText( &widget.TextSegment{Text: lang.L("Album"), Style: util.BoldRichTextStyle}, - &widget.TextSegment{Text: " by", Style: widget.RichTextStyle{Inline: true}}, + &widget.TextSegment{Text: " " + lang.L("by"), Style: widget.RichTextStyle{Inline: true}}, ) a.artistLabel = widgets.NewMultiHyperlink() a.artistLabel.OnTapped = func(id string) { diff --git a/ui/controller/controller.go b/ui/controller/controller.go index 39e837b..f911a6d 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -708,7 +708,7 @@ func (c *Controller) createShareURL(id string) (*url.URL, error) { if err != nil { log.Printf("error creating share URL: %v", err) c.showError( - "Failed to share content. This commonly occurs when the server does not support sharing," + + "Failed to share content. This commonly occurs when the server does not support sharing, " + "or has the feature disabled.\nPlease check the server's settings and try again.", ) return nil, err diff --git a/ui/theme/theme.go b/ui/theme/theme.go index 1f27372..761ded4 100644 --- a/ui/theme/theme.go +++ b/ui/theme/theme.go @@ -205,11 +205,23 @@ func (m *MyTheme) Icon(name fyne.ThemeIconName) fyne.Resource { // Returns a map [themeFileName] -> displayName func (m *MyTheme) ListThemeFiles() map[string]string { - files, _ := filepath.Glob(m.themeFileDir + "/*.toml") + // Use filepath.Join to create a cross-platform file path + pattern := filepath.Join(m.themeFileDir, "/*.toml") + files, err := filepath.Glob(pattern) + if err != nil { + log.Printf("Failed to glob files: %v", err) + } + result := make(map[string]string) - for _, filepath := range files { - if themeFile, err := ReadThemeFile(filepath); err == nil { - result[path.Base(filepath)] = themeFile.SupersonicTheme.Name + for _, filePath := range files { + // Clean the path to avoid issues with slashes + cleanPath := filepath.Clean(filePath) + + // Now read the theme file, using the cleaned path + if themeFile, err := ReadThemeFile(cleanPath); err == nil { + result[filepath.Base(cleanPath)] = themeFile.SupersonicTheme.Name + } else { + log.Printf("Failed to load theme file: %s, error: %v", cleanPath, err) } } return result diff --git a/ui/widgets/albumfilterbutton.go b/ui/widgets/albumfilterbutton.go index 0549b8a..3562868 100644 --- a/ui/widgets/albumfilterbutton.go +++ b/ui/widgets/albumfilterbutton.go @@ -193,7 +193,7 @@ func NewAlbumFilterPopup(filter *AlbumFilterButton) *AlbumFilterPopup { title.TextStyle.Bold = true a.container = container.NewVBox( container.NewHBox(layout.NewSpacer(), title, layout.NewSpacer()), - container.NewHBox(widget.NewLabel(lang.L("Year from")), minYear, widget.NewLabel("to"), maxYear), + container.NewHBox(widget.NewLabel(lang.L("Year from")), minYear, widget.NewLabel(lang.L("to")), maxYear), container.NewHBox(a.isFavorite, a.isNotFavorite), a.genreFilter, )