From cdda152c68e5e32020bedd9f64eef7753453e34b Mon Sep 17 00:00:00 2001 From: DynamycSound Date: Mon, 20 Jul 2026 11:56:51 +0000 Subject: [PATCH] Hotfix v1.6.3: wrong-singer veto, smooth lyrics auto-scroll, MusicResync rename - Reject provider hits whose artist agrees with none of the file's artist guesses (raw tag or parsed filename) unless the runtime matches exactly. Closes the v1.6.2 hole where a short generic title (Rari, BMW, A Ti, Automatic) saved lyrics of a completely different song via artist-less title-only views, across search, plain fallback and last-resort rescue. - REJECT-tier hits no longer drive the early-stop or provider-best logic. - Synced lyrics player now glides continuously to keep the active line just above centre instead of window-jumping, and lands directly on far seeks. - All user-facing SongSync texts renamed to MusicResync (incl. the [by:] tag in generated .lrc files) in every locale; original-project credit kept. - Version 1.6.3 (163) + release notes; 8 new regression tests. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QADiJzVyNycc1w28sirc1a --- RELEASE_NOTES.md | 29 ++-- app/build.gradle.kts | 4 +- .../java/pl/lambada/songsync/MainActivity.kt | 2 +- .../lyrics_providers/SmartLyricsMatcher.kt | 57 +++++++- .../lyrics_providers/others/LRCLibAPI.kt | 2 +- .../player/SyncedLyricsPlayerScreen.kt | 35 +++-- app/src/main/res/values-ar/strings.xml | 8 +- app/src/main/res/values-cs/strings.xml | 10 +- app/src/main/res/values-de/strings.xml | 10 +- app/src/main/res/values-es/strings.xml | 14 +- app/src/main/res/values-et/strings.xml | 10 +- app/src/main/res/values-fa/strings.xml | 10 +- app/src/main/res/values-fil/strings.xml | 8 +- app/src/main/res/values-fr/strings.xml | 10 +- app/src/main/res/values-in/strings.xml | 10 +- app/src/main/res/values-it/strings.xml | 10 +- app/src/main/res/values-ja/strings.xml | 10 +- app/src/main/res/values-ko/strings.xml | 8 +- app/src/main/res/values-nl/strings.xml | 6 +- app/src/main/res/values-pl/strings.xml | 10 +- app/src/main/res/values-pt-rBR/strings.xml | 14 +- app/src/main/res/values-pt/strings.xml | 10 +- app/src/main/res/values-ro/strings.xml | 12 +- app/src/main/res/values-ru/strings.xml | 10 +- app/src/main/res/values-tr/strings.xml | 14 +- app/src/main/res/values-vi/strings.xml | 8 +- app/src/main/res/values-zh-rCN/strings.xml | 10 +- app/src/main/res/values-zh-rTW/strings.xml | 10 +- app/src/main/res/values/strings.xml | 12 +- .../songsync/matching/WrongSingerVetoTest.kt | 130 ++++++++++++++++++ 30 files changed, 333 insertions(+), 160 deletions(-) create mode 100644 app/src/test/java/pl/lambada/songsync/matching/WrongSingerVetoTest.kt diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 588676a..c42814d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,27 +1,14 @@ -## MusicResync v1.6.2 +## MusicResync v1.6.3 — hotfix -### Batch matching now finds what single-song search finds (fixes reports of "it works when I open the song, but not in batch") -The batch downloader was missing two things the single-song screen already had, which made it fail on songs like **Ariana Grande - Focus** (artist tag `Unknown`), **D-Devils - 6th Gate**, and **Tyler, The Creator - Tamale**: +### Fixed: wrong lyrics saved for songs with short, generic titles +v1.6.2's looser matching (which judges hits against the parsed filename, not just the raw tags) opened a precision hole: a song whose title matches some unrelated track exactly — "PETROV - RARI" getting the German "Rari" by lil doggo, "Numero - BMW" getting "BMW" by Cecilio G., "UKIC X PETROV - A TI?" getting "A Ti" by Dyango, "QuESt - Automatic" getting a Japanese "Automatic (Live)" — could ride in on the title alone, because the artist-less view of the track had nothing left to object to the wrong singer. -- **Every provider hit is now also scored against the parsed filename/title view of the track, not just the raw tags.** A junk tag like title `"Ariana Grande - Focus"` / artist `"Unknown"` used to make the scorer reject the correct hit outright (it saw a weak title match and a "disagreeing" artist); it's now also compared against the cleaned `Focus` / `Ariana Grande` reading, which matches. A safety guard still requires an exact runtime match before an artist-less reading can carry a result to auto-accept, so a same-titled song by the wrong artist still can't sneak through. -- **Batch now runs the same last-resort rescue** (canonicalizing a messy name via iTunes/Deezer, then re-querying) that only the single-song screen had before — this was the actual reason a song could be found by opening it manually but not during a batch run. Rescues are still validated against duration/title evidence and are always saved as "review", never silently auto-accepted. -- Placeholder artist tags (`Unknown`, `Various Artists`, ``, …) are now treated as missing information instead of as evidence that contradicts a correct match. -- Filenames with a `(feat. ...)` clause followed by junk (e.g. `Biba - Harli Kvin (feat. AV47) [Official Audio] _420(MP3_320K).mp3`) are now parsed correctly, and trailing junk numbers left over from ripper suffixes are stripped for an extra fallback query. -- Rescued matches whose album art visually matches your file's embedded cover get a small confidence boost — a *different* cover is never held against a match, since re-releases and singles legitimately use different art. +New **wrong-singer veto**: whenever your file gives the matcher *any* artist guess (from the tags or the parsed filename) and a provider's result names an artist that agrees with **none** of those guesses, the result is rejected — across the normal search, the plain-lyrics fallback, and the last-resort rescue. An exact runtime match still overrides a disagreeing artist (that trust is what makes junk-tagged rips matchable at all), and a result with no artist at all is unaffected. A provider artist written in a different script (e.g. CJK vs. a Latin filename) now counts as disagreeing too. -### Fast mode (new, opt-in) -A new toggle in Settings races only the two fastest providers with a short timeout for single-song search — quicker answers at a small cost to thoroughness. Off by default; the full search remains the default everywhere. +### Fixed: lyrics player not following the song / janky scrolling +The synced-lyrics player (the adjust-timing screen) only scrolled once the highlighted line left a visibility window, which looked like the list wasn't following the song at all — and then it lurched a whole screen at a time. It now glides continuously: each new line smoothly eases the list so the active line settles just above centre, Samsung-Music style. Seeks and taps on the progress bar still jump straight to the right spot. -### Fixed: lyrics preview showing wrong state / stuck loading (#11) -The synced-lyrics player and the batch "tap to view lyrics" preview only ever checked for a sidecar `.lrc` file, so a song with lyrics *embedded in the audio tags* looked like it had none — the player said "no lyrics found" and the batch preview spun forever. Both now also check embedded lyrics and always resolve to a real result. - -### Removed redundant menu options (#12) -The home screen's three-dot menu now only has Settings — "batch download" already has its own button, and the lyrics-provider order lives in Settings, so the duplicate entries are gone. - -### More honest provider status -In the single-song screen's provider dropdown, a provider that found usable lyrics but simply wasn't the best match is now shown as "found lyrics" instead of a red X. Only providers that were actually queried can now be marked as having failed — ones skipped by an early match stay "not tried yet". - -### Polish -Saving lyrics (.lrc or embedded) now has a proper success animation instead of an instant text swap. +### Renamed leftovers +All user-facing "SongSync" texts now say **MusicResync** — including the `[by:]` tag written into generated .lrc files, the settings/about texts, and the welcome screen (all languages). The credit to the original SongSync project by Lambada10 remains, as it should. Install over your existing app — it's signed with the same key, so it upgrades in place. diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 96990a2..7058a6e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,8 +15,8 @@ android { minSdk = 21 //noinspection OldTargetApi targetSdk = 35 - versionCode = 162 - versionName = "1.6.2" + versionCode = 163 + versionName = "1.6.3" vectorDrawables { useSupportLibrary = true diff --git a/app/src/main/java/pl/lambada/songsync/MainActivity.kt b/app/src/main/java/pl/lambada/songsync/MainActivity.kt index 626a99a..58deb9f 100644 --- a/app/src/main/java/pl/lambada/songsync/MainActivity.kt +++ b/app/src/main/java/pl/lambada/songsync/MainActivity.kt @@ -33,7 +33,7 @@ import pl.lambada.songsync.util.dataStore import java.io.File /** - * The main activity of the SongSync app. + * The main activity of the MusicResync app. */ class MainActivity : ComponentActivity() { private val lyricsProviderService = LyricsProviderService() diff --git a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/SmartLyricsMatcher.kt b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/SmartLyricsMatcher.kt index 9ccc034..3162e5e 100644 --- a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/SmartLyricsMatcher.kt +++ b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/SmartLyricsMatcher.kt @@ -19,6 +19,7 @@ import pl.lambada.songsync.util.matching.MatchStrategy import pl.lambada.songsync.util.matching.MatchTier import pl.lambada.songsync.util.matching.ProviderResult import pl.lambada.songsync.util.matching.QueryCandidate +import pl.lambada.songsync.util.matching.TextMatch import pl.lambada.songsync.util.networking.withRetry private const val TAG = "MusicResync" @@ -140,7 +141,9 @@ class SmartLyricsMatcher( val key = "${hit.provider}|${hit.result.title}|${hit.result.artist}|${hit.result.durationSec}" val existing = hits[key] if (existing == null || hit.confidence.score > existing.confidence.score) hits[key] = hit - if (hit.confidence.score > best) { + // REJECT-tier hits (e.g. wrong-singer vetoes) keep their raw score for the manual UI but must + // never drive the early stop — a vetoed 90% "match" isn't a reason to cancel other providers. + if (hit.tier != MatchTier.REJECT && hit.confidence.score > best) { best = hit.confidence.score log(" [${provider.displayName}] ${hit.strategy.label} -> ${hit.result.title} - ${hit.result.artist} (${hit.confidence.percent()}%${if (hit.confidence.durationMatched) ", duration✓" else ""})") } @@ -170,6 +173,7 @@ class SmartLyricsMatcher( ): List { val providerHits = LinkedHashMap() var providerBest = 0.0 + val artistGuesses = artistGuessesFor(local, candidates) for (cand in candidates) { val query = cand.asSearchString() if (query.isBlank()) continue @@ -180,11 +184,14 @@ class SmartLyricsMatcher( Providers.LYRICSPLUS, Providers.BETTERLYRICS -> searchDirect(provider, local, cand, config, log) else -> searchGeneric(provider, local, cand, config, log) } - for (hit in found) { + for (raw in found) { + val hit = if (wrongSingerVetoed(artistGuesses, raw.result.artist, raw.confidence)) + raw.copy(confidence = raw.confidence.copy(tier = MatchTier.REJECT)) + else raw val key = "${hit.provider}|${hit.result.title}|${hit.result.artist}|${hit.result.durationSec}" val existing = providerHits[key] if (existing == null || hit.confidence.score > existing.confidence.score) providerHits[key] = hit - if (hit.confidence.score > providerBest) providerBest = hit.confidence.score + if (hit.tier != MatchTier.REJECT && hit.confidence.score > providerBest) providerBest = hit.confidence.score } if (providerBest >= ConfidenceScorer.AUTO_ACCEPT_THRESHOLD) break delay(config.requestDelayMs) @@ -208,6 +215,7 @@ class SmartLyricsMatcher( ): PlainHit? = withTimeoutOrNull(config.providerTimeoutMs) { // Same hard time budget as a regular provider (issue #9): this fallback runs after a failed search, so // letting its retries stack would just re-create the long wait we removed. + val artistGuesses = artistGuessesFor(local, candidates) for (cand in candidates) { val query = cand.asSearchString() if (query.isBlank()) continue @@ -222,7 +230,7 @@ class SmartLyricsMatcher( Triple(pr, scoreFor(local, pr, cand), r.plainLyrics!!) } .sortedByDescending { it.second.score } - .firstOrNull { it.second.tier != MatchTier.REJECT } + .firstOrNull { it.second.tier != MatchTier.REJECT && !wrongSingerVetoed(artistGuesses, it.first.artist, it.second) } if (best != null) { log(" [plain fallback] ${best.first.title} - ${best.first.artist} (${best.second.percent()}%)") @@ -416,7 +424,7 @@ class SmartLyricsMatcher( val key = "${hit.provider}|${hit.result.title}|${hit.result.artist}|${hit.result.durationSec}" val existing = hits[key] if (existing == null || hit.confidence.score > existing.confidence.score) hits[key] = hit - if (hit.confidence.score >= ConfidenceScorer.AUTO_ACCEPT_THRESHOLD) break + if (hit.tier != MatchTier.REJECT && hit.confidence.score >= ConfidenceScorer.AUTO_ACCEPT_THRESHOLD) break } return hits.values.sortedByDescending { it.confidence.score } } @@ -502,6 +510,40 @@ internal fun scoreHitAgainstViews(local: LocalTrack, pr: ProviderResult, cand: Q else best } +/** + * Every usable artist guess for the local file: the raw tag (when not junk-filtered away) plus each parsed + * candidate's artist. This is what the wrong-singer veto compares a provider's artist against. + */ +internal fun artistGuessesFor(local: LocalTrack, candidates: List): List = + (listOfNotNull(local.artist) + candidates.mapNotNull { it.artist }) + .filter { it.isNotBlank() } + .distinct() + +/** + * The wrong-singer veto (v1.6.3 hotfix). Scoring hits against artist-less views of the local track (added in + * v1.6.2 for junk-tag files) opened a hole: a short generic title ("Rari", "BMW", "A Ti", "Automatic") matches + * some unrelated song exactly, and with no artist on the winning view nothing was left to veto the wrong singer + * — so batch runs saved lyrics of a completely different track. This closes the hole from the outside: when the + * file gives us artist guesses ([artistGuessesFor]) and the provider names an artist that agrees with NONE of + * them, the hit is vetoed. Two escapes keep the v1.6.2 recall wins intact: + * - an exact runtime match still overrides a disagreeing artist (the same trust the scorer itself applies); + * - a provider with no artist at all is not vetoed (nothing to disagree with). + * A provider artist in a different script (normalizes to nothing comparable) counts as disagreeing — it cannot + * be the same name our Latin guess spells, and the duration escape still saves genuine cross-script matches. + */ +internal fun wrongSingerVetoed( + artistGuesses: List, + resultArtist: String?, + conf: ConfidenceBreakdown, +): Boolean { + if (conf.durationMatched) return false + if (resultArtist.isNullOrBlank()) return false + val guesses = artistGuesses.filter { TextMatch.normalizeForCompare(it).isNotEmpty() } + if (guesses.isEmpty()) return false + if (TextMatch.normalizeForCompare(resultArtist).isEmpty()) return true + return guesses.maxOf { TextMatch.similarity(it, resultArtist) } < 0.50 +} + /** A raw rescued lyrics candidate (a canonicalized provider result + its lyrics) awaiting confidence validation. */ data class RescueCandidate( val result: ProviderResult, @@ -539,6 +581,7 @@ data class RescueCandidate( fun selectBestRescue(localViews: List, candidates: List): SmartLyricsMatcher.LastResortHit? { val durationView = localViews.firstOrNull { it.durationSec != null && it.durationSec > 0 } val localHasDuration = durationView?.durationSec != null + val artistGuesses = localViews.mapNotNull { it.artist }.filter { it.isNotBlank() }.distinct() data class Scored(val c: RescueCandidate, val synced: Boolean, val conf: ConfidenceBreakdown, val ranking: Double) @@ -559,6 +602,10 @@ fun selectBestRescue(localViews: List, candidates: List "All of My Problems Always Involve Me" while still allowing a // rescue through when the best cleaned candidate title really matches or the duration is exact. if (!conf.durationMatched && conf.title < 0.55) return@mapNotNull null + // Wrong-singer veto: the max-over-views confidence above may have come from an artist-less view, which + // cannot object to a different singer with the same generic title ("Rari" by someone else entirely). + // When any local view supplies an artist and the rescue's artist agrees with none of them, drop it. + if (wrongSingerVetoed(artistGuesses, c.result.artist, conf)) return@mapNotNull null // Album-art agreement is additive-only: it lifts the ranking of a candidate whose cover matches the // local file's embedded art, but a mismatch never pushes a candidate below the acceptance gates above. diff --git a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/LRCLibAPI.kt b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/LRCLibAPI.kt index 1545be7..ed4db2f 100644 --- a/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/LRCLibAPI.kt +++ b/app/src/main/java/pl/lambada/songsync/data/remote/lyrics_providers/others/LRCLibAPI.kt @@ -15,7 +15,7 @@ import java.nio.charset.StandardCharsets class LRCLibAPI { private val baseURL = "https://lrclib.net/api/" - private val userAgent = "MusicResync v1.0 (https://github.com/Lambada10/SongSync)" + private val userAgent = "MusicResync (https://github.com/DynamycSound/MusicResync)" /** * MusicResync: returns the *full* list of search hits (each already carries duration, album and synced diff --git a/app/src/main/java/pl/lambada/songsync/ui/screens/player/SyncedLyricsPlayerScreen.kt b/app/src/main/java/pl/lambada/songsync/ui/screens/player/SyncedLyricsPlayerScreen.kt index 89e21a2..97aae6e 100644 --- a/app/src/main/java/pl/lambada/songsync/ui/screens/player/SyncedLyricsPlayerScreen.kt +++ b/app/src/main/java/pl/lambada/songsync/ui/screens/player/SyncedLyricsPlayerScreen.kt @@ -2,8 +2,11 @@ package pl.lambada.songsync.ui.screens.player import android.media.MediaPlayer import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -88,7 +91,6 @@ import pl.lambada.songsync.util.matching.LyricState import pl.lambada.songsync.util.showToast import pl.lambada.songsync.util.toCrlf import java.io.File -import kotlin.math.abs import kotlin.math.max import kotlin.math.roundToInt @@ -312,20 +314,27 @@ fun SyncedLyricsPlayerScreen( else lines.indexOfLast { it.timeMs <= positionMs + offsetMs.roundToInt() }.coerceAtLeast(0) } } - // Word/line-dense lyrics were stuttering because we launched a new animateScrollToItem on *every* highlight - // change. Keep the current line within a comfortable window and only scroll when it leaves that window; - // small shifts jump immediately (no competing animations), while larger jumps still animate. - LaunchedEffect(currentIndex) { + // Karaoke-style follow: every highlight change glides the list so the active line settles just above + // centre. animateScrollBy restarts smoothly from wherever the list currently is (a new line simply + // retargets the glide), giving one continuous crawl that visibly tracks the song. The old logic only + // scrolled once the line left a visibility window, which read as "the player isn't following the song" + // and then lurched a whole window at a time. + LaunchedEffect(currentIndex, lyricsLoaded) { if (lines.isEmpty()) return@LaunchedEffect - val visible = listState.layoutInfo.visibleItemsInfo.size.coerceAtLeast(1) - val first = listState.firstVisibleItemIndex - val lowerBound = first + 1 - val upperBound = first + visible - 3 - if (currentIndex in lowerBound..upperBound) return@LaunchedEffect - val target = (currentIndex - 3).coerceAtLeast(0) runCatching { - if (abs(target - first) <= 2) listState.scrollToItem(target) - else listState.animateScrollToItem(target) + val info = listState.layoutInfo + val item = info.visibleItemsInfo.firstOrNull { it.index == currentIndex } + if (item != null) { + // Glide the line's centre to an anchor ~38% down the viewport (slightly above centre). + val viewport = info.viewportEndOffset - info.viewportStartOffset + val anchor = info.viewportStartOffset + viewport * 0.38f + val delta = item.offset + item.size / 2f - anchor + listState.animateScrollBy(delta, tween(durationMillis = 600, easing = FastOutSlowInEasing)) + } else { + // Line is far off-screen (seek, tapped the bar, opened mid-song): land near the anchor + // directly; subsequent lines glide from there. + listState.animateScrollToItem((currentIndex - 2).coerceAtLeast(0)) + } } } diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index d63aabe..d349918 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -21,8 +21,8 @@ يمكنك البحث أيضاً عن أغانٍ محدَّدة لتحصل على كلماتها (وتحفظها في التنزيلات). إصدار التطبيق: %1$s سپوتيفاي للمطورين - عن سونغ‌سينك (SongSync) - يستخدم سونغ‌سينك (SongSync) واجهة سپوتيفاي‌ليرِكس (SpotifyLyrics) البرمجية للوصول لكلمات الأغاني. تجد المزيد حولها على صفحة غِت‌هَب (GitHub) الخاصة بهم. + عن سونغ‌سينك (MusicResync) + يستخدم سونغ‌سينك (MusicResync) واجهة سپوتيفاي‌ليرِكس (SpotifyLyrics) البرمجية للوصول لكلمات الأغاني. تجد المزيد حولها على صفحة غِت‌هَب (GitHub) الخاصة بهم. اِعرِض في غِت‌هَب المساهمون وجدتَ خطأً ما؟ عندكَ اقتراح؟ تريد المساهمة؟ لا تتردد بتواصلكَ معي في مجموعتي على تِلِغرام. @@ -93,8 +93,8 @@ تُنزَّل الكلمات لا تغلق البرنامج، فقد تحتاج العملية وقتاً. ليس هناك اتصال بالانترنت أو أن الخادم مُعطَّل - سونغ‌سينك (SongSync) تطبيق يمكّنكَ من تنزيل كلمات الأغاني المُزَمَّنة (ملفات lrc.) لمكتبة الموسيقى المحلية الخاصة بكَ. - سونغ‌سينك (SongSync) مشروع مفتوح المصدر. تجد شفرة المصدر على غِت‌هَب. + سونغ‌سينك (MusicResync) تطبيق يمكّنكَ من تنزيل كلمات الأغاني المُزَمَّنة (ملفات lrc.) لمكتبة الموسيقى المحلية الخاصة بكَ. + سونغ‌سينك (MusicResync) مشروع مفتوح المصدر. تجد شفرة المصدر على غِت‌هَب. تحقَّق من اتصالك وحاول مرةً أخرى. نُسِخَت الكلمات إلى الحافظة اعكس التحديد diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 5872d09..b234353 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -14,7 +14,7 @@ Žádné výsledky Zkuste to prosím zvova později Uložit .lrc soubor - O SongSync + O MusicResync Zdrojový kód Podpora Zavřít aplikaci @@ -56,7 +56,7 @@ Datum změny Pomožte nám přeložit tuto aplikaci do vašeho jazyka! Otevřít Weblate - Vítej v SongSync! + Vítej v MusicResync! Verze aplikace: %1$s Potřebujete přístup ke internetu pro používání této aplikace. Přístup odepřen @@ -72,7 +72,7 @@ Úspěch: %1$d Selhalo: %1$d Limit možných požadavků Spotify API dosažen - SongSync je aplikace, která umožňuje stahování synchronizovaného textu (.lrc soubory) pro vaší muziku. + MusicResync je aplikace, která umožňuje stahování synchronizovaného textu (.lrc soubory) pro vaší muziku. Seznam změn:\n%1$s Poskytovatel textů Vyberte poskytovatel textů níže @@ -105,7 +105,7 @@ Použito pro ukázování průběhu stažení ve notifikaci od Přijmout - SongSync je open-source projekt. Můžete najít zdrojový kód na GitHubu. + MusicResync je open-source projekt. Můžete najít zdrojový kód na GitHubu. Zhlédnout na GitHubu Našli jste chybu? Máte nápad? Chcete přispět? Neváhejte mě kontaktovat ve moji Telegram skupině. Filtry @@ -118,7 +118,7 @@ Zádný přístup ke internetu nebo server nereaguje na požadavky Můžete také hledat pro dané písně a získat její text (a uložit ho do stažených). Spotify pro Vývojáře - SongSync používá SpotifyLyrics API ke získání textů pro písně. Můžete zjistit více informací o SpotifyLyrics API na jejich GitHub stránkách. + MusicResync používá SpotifyLyrics API ke získání textů pro písně. Můžete zjistit více informací o SpotifyLyrics API na jejich GitHub stránkách. Můžete také vytvořit problém/issue na GitHubu (odkaz nahoře). Táto aplikace potřebuje přístup k uložišti pro skenování vaší hudební knihovnu a ukládání textů. Jestli jste připojen, asi Spotify nereaguje. Zkuste to prosím později znovu. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 966fa72..89cabdf 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -23,14 +23,14 @@ Keine Ergebnisse Keine Internetverbindung oder Server ist down Unbekannt - SongSync ist eine App, die dich synchronisierte Lyrics-Dateien (.lrc) für deine lokale Musikbibliothek herunterladen lässt. + MusicResync ist eine App, die dich synchronisierte Lyrics-Dateien (.lrc) für deine lokale Musikbibliothek herunterladen lässt. Du kannst auch nach spezifischen Songs suchen, um ihren Liedtext zu erhalten (und sie in Downloads zu speichern). App-Version: %1$s Spotify für Entwickler - Über SongSync - SongSync nutzt die SpotifyLyrics API, um Liedtexte zu erhalten. Du kannst weitere Informationen auf der GitHub-Seite von SpotifyLyrics erhalten. + Über MusicResync + MusicResync nutzt die SpotifyLyrics API, um Liedtexte zu erhalten. Du kannst weitere Informationen auf der GitHub-Seite von SpotifyLyrics erhalten. Auf GitHub ansehen - SongSync ist ein Open-Source-Projekt. Du kannst den Quellcode auf GitHub finden. + MusicResync ist ein Open-Source-Projekt. Du kannst den Quellcode auf GitHub finden. Beitragende Hast du einen Fehler gefunden? Oder einen Verbesserungsvorschlag? Du kannst mich in meiner Telegram-Gruppe kontaktieren. Telegram-Gruppe @@ -158,7 +158,7 @@ Benachrichtigungen anzeigen (optional) Wird verwendet, um die Download Fortschritt Benachrichtigung anzuzeigen Fortsetzen - Willkommen bei SongSync! + Willkommen bei MusicResync! Um loszulegen, erlaube bitte die folgenden Berechtigungen: Aktuell abgespieltes Lied Benachrichtigungszugriff (optional) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 325cf9e..fe3a623 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,6 +1,6 @@ - SongSync + MusicResync Descargar letras en lote Obtener letras Intentar de nuevo @@ -24,16 +24,16 @@ Sin resultados No hay conexión a internet o el servidor está caído Desconocido - Generado usando SongSync - SongSync es una aplicación que te permite descargar letras sincronizadas (.lrc) para tu biblioteca de música local. + Generado usando MusicResync + MusicResync es una aplicación que te permite descargar letras sincronizadas (.lrc) para tu biblioteca de música local. También puedes buscar canciones específicas para obtener sus letras (y guardarlas en descargas). Versión de la aplicación: %1$s Spotify para Desarrolladores API de SpotifyLyrics - Acerca de SongSync - SongSync utiliza la API de SpotifyLyrics para obtener letras de canciones. Puedes encontrar más información sobre la API de SpotifyLyrics en su página de GitHub. + Acerca de MusicResync + MusicResync utiliza la API de SpotifyLyrics para obtener letras de canciones. Puedes encontrar más información sobre la API de SpotifyLyrics en su página de GitHub. Ver en GitHub - SongSync es un proyecto de código abierto. Puedes encontrar el código fuente en GitHub. + MusicResync es un proyecto de código abierto. Puedes encontrar el código fuente en GitHub. Colaboradores GitHub Telegram @@ -160,7 +160,7 @@ Mostrar notificación (Opcional) Usado para mostrar la notificación de progreso de descarga Continuar - ¡Bienvenido a SongSync! + ¡Bienvenido a MusicResync! Para comenzar, por favor otorga los siguientes permisos: Canción en reproducción Acceso a notificaciones (Opcional) diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index b87e952..d11f29e 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -24,14 +24,14 @@ Tulemusi pole Nutiseadmel puudub internetiühendus või server ei tööta Teadmata - SongSync võimaldab sul oma kohaliku muusikakogu jaoks allalaadida sünkroniseeritud laulusõnu (.lrc failidena). + MusicResync võimaldab sul oma kohaliku muusikakogu jaoks allalaadida sünkroniseeritud laulusõnu (.lrc failidena). Võid ka konkreetsete laulude sõnu otsida (ja neid salvestada allalaadimiste kausta). Rakenduse versioon: %1$s Spotify arendajate jaoks - Rakenduse teave: SongSync - SongSync kasutab laulusõnade leidmiseks SpotifyLyrics API liidestust. Lisateavet SpotifyLyrics API kohta leiad nende GitHubi lehelt. + Rakenduse teave: MusicResync + MusicResync kasutab laulusõnade leidmiseks SpotifyLyrics API liidestust. Lisateavet SpotifyLyrics API kohta leiad nende GitHubi lehelt. Vaata GitHubis - SongSync on avatud lähtekoodil põhinev arendusprojekt. Rakenduse lähtekoodi leiad GitHubist. + MusicResync on avatud lähtekoodil põhinev arendusprojekt. Rakenduse lähtekoodi leiad GitHubist. Kaasautorid Telegrami grupp Võid ka lisada veateate GitHubis (link on ülal). @@ -153,7 +153,7 @@ Ligipääs kõikidele failidele See on vajalik lrc-failide salvestamiseks lugude kaustadesse ilma, et peaks iga kord failivalijat avama Jätka - Tere tulemast kasutama SongSynci! + Tere tulemast kasutama MusicResynci! Alustamiseks palun luba järgnevad õigused: Hetkel esitamisel lugu Ligipääs teavitustele (valikuline) diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 1489b71..e2a3491 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -27,9 +27,9 @@ پیشرفت: %1$d/%2$d (%3$d%%) نگارش برنامه: %1$s ‏Spotify برای توسعه‌دهنده‌ها - دربارۀ SongSync + دربارۀ MusicResync دیدن در گیت‌هاب - ‏SongSync یک پروژۀ متن‌باز است. شما می‌توانید کد منبع را در گیت‌هاب پیدا کنید. + ‏MusicResync یک پروژۀ متن‌باز است. شما می‌توانید کد منبع را در گیت‌هاب پیدا کنید. مشارکت‌کننده‌ها همچنین می‌توانید در گیت‌هاب یک issue ایجاد کنید (پیوند بالا). کد منبع @@ -128,9 +128,9 @@ بدون ترانه: %1$d تلاش دوباره بله - ‏SongSync برنامه‌ای است که به شما امکان می‌دهد ترانه‌های همگام شده (پرونده‌های ‎.lrc‏) را برای کتابخانۀ موسیقی محلی‌تان بارگیری کنید. + ‏MusicResync برنامه‌ای است که به شما امکان می‌دهد ترانه‌های همگام شده (پرونده‌های ‎.lrc‏) را برای کتابخانۀ موسیقی محلی‌تان بارگیری کنید. همچنین می‌توانید برای آهنگ‌های به‌خصوص جست‌وجو کنید تا ترانه‌های آن‌ها را دریافت کنید (و آن‌ها را در بارگیری‌ها ذخیره کنید). - ‏SongSync از SpotifyLyrics API استفاده می‌کند تا ترانه‌ها را برای آهنگ‌های شما دریافت کند. شما می‌توانید اطلاعات بیشتری دربارۀ SpotifyLyrics API در صفحۀ گیت‌هاب آن‌ها پیدا کنید. + ‏MusicResync از SpotifyLyrics API استفاده می‌کند تا ترانه‌ها را برای آهنگ‌های شما دریافت کند. شما می‌توانید اطلاعات بیشتری دربارۀ SpotifyLyrics API در صفحۀ گیت‌هاب آن‌ها پیدا کنید. مشکلی پیدا کردید؟ پیشنهادی دارید؟ می‌خواهید مشارکت کنید؟ با خیال راحت می‌توانید با من در گروه تلگرام ارتباط برقرار کنید. این برنامه به دسترسی محل ذخیره برای پوییدن کتابخانۀ موسیقی شما و ذخیرۀ ترانه‌ها نیاز دارد. ویرایش @@ -153,7 +153,7 @@ نمایش اعلان (اختیاری) برای نمایش اعلان پیشرفت بارگیری استفاده شده ادامه - به SongSync خوش‌آمدید! + به MusicResync خوش‌آمدید! برای شروع، لطفا اجازۀ دسترسی‌های زیر را بدهید: آهنگ در حال پخش دسترسی اعلان (اختیاری) diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index 6a0ee22..4c1df4c 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -27,9 +27,9 @@ unknown Bersyon ng app: %1$s Spotify Para sa Developers - Tungkol sa SongSync + Tungkol sa MusicResync Tingnan sa GitHub - Ang SongSync ay isang open-source na proyekto. Maaari mong mahanap ang source code nito sa GitHub. + Ang MusicResync ay isang open-source na proyekto. Maaari mong mahanap ang source code nito sa GitHub. Mga Nag-ambag Source code Suporta @@ -74,9 +74,9 @@ Pakiusap, huwag isara ang app, maaaring magtagal ito Nalimitahan na ang Spotify API rate Walang resulta - Ang SongSync ay isang app na pwede mong downloadan ng synced lyrics (.lrc files) para sa local music library. + Ang MusicResync ay isang app na pwede mong downloadan ng synced lyrics (.lrc files) para sa local music library. Maaari ka ring maghanap ng mga tiyak na kanta upang makuha ang kanilang mga liriko (at i-save ang mga ito sa mga downloads) - Ang SongSync ay gumagamit ng SpotifyLyrics API para makakuha ng liriko sa kanta, maari ka pang makahanap ng iba pang impormasyon tungkol sa SpotifyLyrics API sa GitHub Page + Ang MusicResync ay gumagamit ng SpotifyLyrics API para makakuha ng liriko sa kanta, maari ka pang makahanap ng iba pang impormasyon tungkol sa SpotifyLyrics API sa GitHub Page Nakatagpo ng bug? May suggestion? Nais makipag-ambag? Huwag mag-atubiling makipag-ugnayan sa akin sa aking Telegram group. Telegram Group Maaari ka ring lumikha ng isyu sa GitHub (link sa itaas). diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 2eaeeae..ddfe886 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -10,7 +10,7 @@ Limite de l\'API Spotify atteinte Vous avez trouvé un bug ? Vous avez une suggestion ? Vous voulez contribuer ? N\'hésitez pas à me contacter sur mon groupe Telegram. Recherche - SongSync est une application qui vous permet de télécharger des paroles synchronisées (fichiers .lrc) pour votre bibliothèque musicale locale. + MusicResync est une application qui vous permet de télécharger des paroles synchronisées (fichiers .lrc) pour votre bibliothèque musicale locale. Durée Ok Obtenez des paroles non synchronisées @@ -35,9 +35,9 @@ Vous pouvez également rechercher des chansons spécifiques pour obtenir leurs paroles (et les enregistrer en les téléchargeants). Version de l\'application : %1$s Spotify pour les développeurs - À propos de SongSync + À propos de MusicResync Voir sur GitHub - SongSync est un projet open source. Vous pouvez trouver le code source sur GitHub. + MusicResync est un projet open source. Vous pouvez trouver le code source sur GitHub. Contributeurs Groupe Telegram Vous pouvez également créer un problème sur GitHub (lien ci-dessus). @@ -135,7 +135,7 @@ par Erreur Oui - SongSync utilise l\'API SpotifyLyrics pour obtenir les paroles des chansons. Vous trouverez plus d\'informations sur l\'API SpotifyLyrics sur leur page GitHub. + MusicResync utilise l\'API SpotifyLyrics pour obtenir les paroles des chansons. Vous trouverez plus d\'informations sur l\'API SpotifyLyrics sur leur page GitHub. Année Inclure les paroles traduites lors de l\'obtention des paroles de chansons auprès du fournisseur NetEase Vous utilisez la dernière version @@ -154,7 +154,7 @@ Afficher les notifications (facultatif) Utilisé pour afficher une notification de progression du téléchargement Continuer - Bienvenue sur SongSync ! + Bienvenue sur MusicResync ! Pour commencer, veuillez accorder les autorisations suivantes : Chanson en cours de lecture Accès aux notifications (facultatif) diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 3c4625d..f5b0746 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -17,12 +17,12 @@ Coba lagi nanti Simpan berkas .lrc Tidak ada hasil - SongSync adalah aplikasi yang memungkinkan Anda untuk mengunduh lirik yang tersinkron (berkas .lrc) bagi pustaka musik lokal milik Anda. + MusicResync adalah aplikasi yang memungkinkan Anda untuk mengunduh lirik yang tersinkron (berkas .lrc) bagi pustaka musik lokal milik Anda. Versi aplikasi: %1$s Spotify untuk Para Pengembang - Tentang SongSync + Tentang MusicResync Lihat di GitHub - SongSync adalah sebuah proyek sumber terbuka. Anda bisa menemukan kode sumbernya di GitHub. + MusicResync adalah sebuah proyek sumber terbuka. Anda bisa menemukan kode sumbernya di GitHub. Para Kontributor Menemukan bug\? Punya saran\? Ingin berkontribusi\? Jangan segan untuk menghubungi kami di grup Telegram. Grup Telegram @@ -69,7 +69,7 @@ Mohon jangan menutup aplikasi, proses ini mungkin memakan waktu yang cukup lama Tidak ada koneksi internet atau server sedang tidak aktif Anda juga bisa mencari lagu spesifik untuk bisa memperoleh liriknya (dan menyimpannya ke unduhan). - SongSync menggunakan API SpotifyLyrics untuk memperoleh lirik bagi lagu. Anda bisa menemukan informasi selengkapnya tentang API SpotifyLyrics di halaman GitHub mereka. + MusicResync menggunakan API SpotifyLyrics untuk memperoleh lirik bagi lagu. Anda bisa menemukan informasi selengkapnya tentang API SpotifyLyrics di halaman GitHub mereka. Kontributor Aplikasi ini membutuhkan akses penyimpanan untuk memindai pustaka musik Anda dan menyimpan lirik. Anda memerlukan koneksi internet untuk menggunakan aplikasi ini. @@ -154,7 +154,7 @@ Tampilkan notifikasi (Opsional) Digunakan untuk menampilkan notifikasi kemajuan pengunduhan Lanjut - Selamat datang di SongSync! + Selamat datang di MusicResync! Untuk memulai, mohon izinkan perizinan berikut: Lagu yang sedang diputar Akses notifikasi (Opsional) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 0ddd2a5..d34fae5 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -21,14 +21,14 @@ Nessun risultato Nessuna connessione internet o il server é malfunzionante Sconosciuto - SongSync è un\'app che ti consente di scaricare testi sincronizzati (file .lrc) per la tua libreria musicale locale. + MusicResync è un\'app che ti consente di scaricare testi sincronizzati (file .lrc) per la tua libreria musicale locale. Puoi anche cercare canzoni specifiche per ottenerne i testi (e salvarli nei download). Versione dell\'app: %1$s Spotify per sviluppatori - A proposito di SongSync + A proposito di MusicResync Visualizza su GitHub - SongSync è un progetto open source. Puoi trovare il codice sorgente su GitHub. - SongSync usa SpotifyLyrics API per ottenere i testi delle canzoni. Puoi trovare maggiori informazioni su SpotifyLyrics API sulla loro pagina GitHub. + MusicResync è un progetto open source. Puoi trovare il codice sorgente su GitHub. + MusicResync usa SpotifyLyrics API per ottenere i testi delle canzoni. Puoi trovare maggiori informazioni su SpotifyLyrics API sulla loro pagina GitHub. Collaboratori Codice sorgente Hai trovato un bug? Hai un suggerimento? Vuoi contribuire? Sentiti libero di contattarmi sul mio gruppo Telegram. @@ -145,7 +145,7 @@ da Utilizzato per mostrare la notifica di progresso del doenload Continua - Benvenuto su SongSync! + Benvenuto su MusicResync! Per iniziare, concedi le seguenti autorizzazioni: Accesso alle notifiche (Opzionale) Canzone in riproduzione diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 4353759..cd302c9 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -19,12 +19,12 @@ .lrc ファイルを保存 結果なし 不明 - SongSync は同期可能な歌詞ファイル (.lrc ファイル) をローカルに保存するアプリです。 + MusicResync は同期可能な歌詞ファイル (.lrc ファイル) をローカルに保存するアプリです。 アプリのバージョン: %1$s Spotify for Developers - SongSync について + MusicResync について GitHub を表示 - SongSync は、オープンソースプロジェクトです。ソースコードは GitHub にあります。 + MusicResync は、オープンソースプロジェクトです。ソースコードは GitHub にあります。 貢献者 Telegram グループ ソースコード @@ -80,7 +80,7 @@ アプリを閉じずにしばらくお待ちください インターネットが未接続またはサーバーがダウンしています 特定の曲名を入力するだけでも歌詞を取得できます (ダウンロードして保存も可能)。 - SongSync は SpotifyLyrics API を使用して歌詞を取得します。SpotifyLyrics API の詳細については、GitHub ページをご確認ください。 + MusicResync は SpotifyLyrics API を使用して歌詞を取得します。SpotifyLyrics API の詳細については、GitHub ページをご確認ください。 バグを見つけましたか?それとも提案や貢献をしたいですか?お気軽に Telegram グループまでご連絡ください。 GitHub (上記リンク) で Issue を作成する事もできます。 このアプリは、音楽ライブラリをスキャンして歌詞を保存するためにストレージアクセスの許可が必要です。 @@ -149,7 +149,7 @@ ダークモードが有効化されている場合にピュアブラックテーマを使用します すべてのファイルにアクセス 続行 - SongSync にようこそ! + MusicResync にようこそ! 通知を表示 (オプション) ファイルピッカーを毎回開かずに曲のディレクトリに lrc ファイルを保存するために必要です ダウンロードの進捗通知を表示するために使用します diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 377f0fb..0d8748c 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -23,14 +23,14 @@ 결과 없음 인터넷 연결이 없거나 서버가 다운되었습니다 알 수 없음 - SongSync는 로컬 음악 라이브러리를 위한 동기화된 가사(.lrc 파일)를 다운로드할 수 있게 해주는 앱입니다. + MusicResync는 로컬 음악 라이브러리를 위한 동기화된 가사(.lrc 파일)를 다운로드할 수 있게 해주는 앱입니다. 특정 곡을 검색하여 가사를 가져오고 다운로드 폴더에 저장할 수도 있습니다. 앱 버전: %1$s Spotify 개발자용 - SongSync 정보 - SongSync는 곡의 가사를 가져오기 위해 SpotifyLyrics API를 사용합니다. SpotifyLyrics API에 대한 자세한 정보는 GitHub 페이지에서 확인할 수 있습니다. + MusicResync 정보 + MusicResync는 곡의 가사를 가져오기 위해 SpotifyLyrics API를 사용합니다. SpotifyLyrics API에 대한 자세한 정보는 GitHub 페이지에서 확인할 수 있습니다. GitHub에서 보기 - SongSync는 오픈 소스 프로젝트입니다. 소스 코드는 GitHub에서 확인할 수 있습니다. + MusicResync는 오픈 소스 프로젝트입니다. 소스 코드는 GitHub에서 확인할 수 있습니다. 기여자 버그를 찾으셨나요? 제안이 있으신가요? 기여하고 싶으신가요? 제 텔레그램 그룹으로 자유롭게 연락하세요. 텔레그램 그룹 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index e29b2d4..557da59 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -27,10 +27,10 @@ Je kan ook naar specifieke nummers zoeken om hun songteksten te krijgen (en ze op te slaan in je downloads). App versie: %1$s Spotify voor ontwikkelaars - Over SongSync - SongSync gebruikt de SpotifyLyrics API om songteksten te krijgen. Je kan meer info over de SpotifyLyrics API vinden op hun GitHub pagina. + Over MusicResync + MusicResync gebruikt de SpotifyLyrics API om songteksten te krijgen. Je kan meer info over de SpotifyLyrics API vinden op hun GitHub pagina. Bekijk op GitHub - SongSync is een open-source project. Je kan de scripts/code vinden op GitHub. + MusicResync is een open-source project. Je kan de scripts/code vinden op GitHub. Bijdragers Heb je een bug gevonden? Heb je een suggestie? Wil je helpen? Je kan me contacteren op mijn Telegramgroep. Telegramgroep diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index acbabfa..cf98183 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -23,11 +23,11 @@ Brak wyników Brak połączenia z internetem, lub serwer jest niedostępny Nieznany - SongSync to aplikacja, która pozwala na pobieranie zsynchronizowanych tekstów (pliki .lrc) do użytku w lokalnej bibliotece muzycznej. + MusicResync to aplikacja, która pozwala na pobieranie zsynchronizowanych tekstów (pliki .lrc) do użytku w lokalnej bibliotece muzycznej. Możesz również wyszukiwać konkretne utwory, aby pobrać ich teksty (oraz zapisać w katalogu). Wersja aplikacji: %1$s Spotify dla deweloperów - O SongSync + O MusicResync Kopiuj tekst do schowka Utwór lokalny Utwór z chmury @@ -90,7 +90,7 @@ Pokaż powiadomienie (Opcjonalne) Pokaż powiadomienie postępu pobierania Kontynuuj - Witaj w SongSync! + Witaj w MusicResync! Aby rozpocząć, proszę, zezwól na wymagane uprawnienia: Teraz odtwarzany utwór Dostęp do powiadomień (Opcjonalne) @@ -103,9 +103,9 @@ %1$d utworów %1$d utworów - SongSync używa SpotifyLyrics API, żeby pobierać teksty utworów. Aby dowiedzieć się więcej o SpotifyLyrics API odwiedź stronę na GitHub\'ie. + MusicResync używa SpotifyLyrics API, żeby pobierać teksty utworów. Aby dowiedzieć się więcej o SpotifyLyrics API odwiedź stronę na GitHub\'ie. Odwiedź stronę na GitHub\'ie - SongSync to projekt otwartoźródłowy. Możesz zobaczyć jego kod na GitHub\'ie. + MusicResync to projekt otwartoźródłowy. Możesz zobaczyć jego kod na GitHub\'ie. Współtwórcy Znalazłeś błąd? Masz sugestię? Chcesz współtworzyć? Zapraszam do kontaktu na grupie Telegram. Grupa Telegram diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 223a41d..8171760 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1,6 +1,6 @@ - SongSync + MusicResync Baixar letras em lote Obter letras Tentar novamente @@ -24,16 +24,16 @@ Nenhum resultado Sem conexão com a internet ou o servidor está fora do ar Desconhecido - Gerado usando SongSync - SongSync é um aplicativo que permite baixar letras sincronizadas (.lrc) para sua biblioteca de músicas local. + Gerado usando MusicResync + MusicResync é um aplicativo que permite baixar letras sincronizadas (.lrc) para sua biblioteca de músicas local. Você também pode pesquisar músicas específicas para obter suas letras (e salvá-las nos downloads). Versão do aplicativo: %1$s Spotify para Desenvolvedores SpotifyLyrics API - Sobre o SongSync - O SongSync usa a API do SpotifyLyrics para obter letras de músicas. Você pode encontrar mais informações sobre a API do SpotifyLyrics na página do GitHub. + Sobre o MusicResync + O MusicResync usa a API do SpotifyLyrics para obter letras de músicas. Você pode encontrar mais informações sobre a API do SpotifyLyrics na página do GitHub. Ver no GitHub - SongSync é um projeto de código aberto. Você pode encontrar o código-fonte no GitHub. + MusicResync é um projeto de código aberto. Você pode encontrar o código-fonte no GitHub. Contribuidores GitHub Telegram @@ -160,7 +160,7 @@ Mostrar notificação (opcional) Usado para mostrar notificação de progresso do download Continuar - Bem-vindo ao SongSync! + Bem-vindo ao MusicResync! Para começar, conceda as seguintes permissões: Música tocando agora Acesso à notificação (opcional) diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 3ae34b5..a3b5a16 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -21,10 +21,10 @@ Também pode pesquisar músicas específicas para obter as suas letras (e gravá-las nas descargas). Versão do aplicativo: %1$s Spotify para Desenvolvedores - Sobre o SongSync - O SongSync usa a API do SpotifyLyrics para obter as letras das músicas. Você pode encontrar mais informações sobre a API do SpotifyLyrics em sua página do GitHub. + Sobre o MusicResync + O MusicResync usa a API do SpotifyLyrics para obter as letras das músicas. Você pode encontrar mais informações sobre a API do SpotifyLyrics em sua página do GitHub. Veja no GitHub - SongSync é um projeto de código aberto. Você pode encontrar o código-fonte no GitHub. + MusicResync é um projeto de código aberto. Você pode encontrar o código-fonte no GitHub. Colaboradores Grupo Telegram Você também pode relatar um problema no GitHub (Link acima). @@ -83,7 +83,7 @@ Progresso: %1$d/%2$d (%3$d%%) Sucesso: %1$d, Sem letras: %2$d, Falhou: %3$d Desconhecido - SongSync é uma aplicação que permite descarregar letras sincronizadas (ficheiros .lrc) para a sua Biblioteca de Música Local. + MusicResync é uma aplicação que permite descarregar letras sincronizadas (ficheiros .lrc) para a sua Biblioteca de Música Local. Encontrou um bug\? Tem uma sugestão\? Quer contribuir\? Se sinta à vontade para entrar em contato comigo no meu grupo do Telegram. Desenvolvedores Este aplicativo requer acesso ao armazenamento para escanear sua Biblioteca de Músicas e salvar as letras. @@ -156,7 +156,7 @@ Mostrar notificação (opcional) Usado para mostrar notificação de progresso da descarga Continuar - Bem-vindo ao SongSync! + Bem-vindo ao MusicResync! Para começar, conceda as seguintes permissões: Música tocando agora Acesso à notificação (opcional) diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 44a0cb6..9878a34 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -1,6 +1,6 @@ - SongSync + MusicResync Descărcare lot de versuri Obținere versuri Încercați din nou @@ -24,16 +24,16 @@ Fără rezultate Fără conexiune la internet sau server-ul este jos Necunoscut - Generat cu SongSync - SongSync este o aplicație care vă permite descărcarea versurilor sincronizate (fișiere .lrc) pentru biblioteca dvs. de muzică locală. + Generat cu MusicResync + MusicResync este o aplicație care vă permite descărcarea versurilor sincronizate (fișiere .lrc) pentru biblioteca dvs. de muzică locală. De asemenea, puteți căuta anumite melodii pentru a le obține versurile (și să le salvați în descărcări). Versiunea aplicației: %1$s Spotify pentru Developeri SpotifyLyrics API - Despre SongSync - SongSync utilizează API-ul SpotifyLyrics ca să obțină versuri pentru melodii. Puteți găsi mai multe informații despre API-ul SpotifyLyrics pe pagina lor de GitHub. + Despre MusicResync + MusicResync utilizează API-ul SpotifyLyrics ca să obțină versuri pentru melodii. Puteți găsi mai multe informații despre API-ul SpotifyLyrics pe pagina lor de GitHub. Vizualizare pe GitHub - SongSync este un proiect open-source. Puteți găsi sursa codului pe GitHub. + MusicResync este un proiect open-source. Puteți găsi sursa codului pe GitHub. Contribuitori GitHub Telegram diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0208444..2b50434 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -23,14 +23,14 @@ Нет результатов Нет подключения к Интернету или сервер недоступен Неизвестно - SongSync - это приложение, которое позволяет загружать синхронизированные тексты песен (.lrc файлы) для вашей локальной музыкальной библиотеки. + MusicResync - это приложение, которое позволяет загружать синхронизированные тексты песен (.lrc файлы) для вашей локальной музыкальной библиотеки. Вы также можете искать конкретные песни, чтобы получить их тексты (и сохранить их в загрузки). Версия приложения: %1$s Spotify для разработчиков - О SongSync - SongSync использует API SpotifyLyrics для получения текстов песен. Вы можете найти дополнительную информацию о API SpotifyLyrics на их странице GitHub. + О MusicResync + MusicResync использует API SpotifyLyrics для получения текстов песен. Вы можете найти дополнительную информацию о API SpotifyLyrics на их странице GitHub. Просмотреть на GitHub - SongSync - это проект с открытым исходным кодом. Вы можете найти исходный код на GitHub. + MusicResync - это проект с открытым исходным кодом. Вы можете найти исходный код на GitHub. Авторы Нашли ошибку? Есть предложение? Хотите внести свой вклад? Не стесняйтесь связаться со мной в моей группе Telegram. Группа Telegram @@ -155,7 +155,7 @@ Показывать уведомления (необязательно) Применяется для отображения уведомления о процессе загрузки Продолжить - Добро пожаловать в SongSync! + Добро пожаловать в MusicResync! Для начала работы, пожалуйста, выдайте эти разрешения: Текущая песня Доступ к уведомлениям (необязательно) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index dab348f..ee86a7c 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,6 +1,6 @@ - SongSync + MusicResync Toplu şarkı sözü indir Şarkı sözlerini al Tekrar dene @@ -24,16 +24,16 @@ Sonuç yok İnternet bağlantısı yok veya sunucu kapalı Bilinmeyen - Generated using SongSync - SongSync, yerel müzik kütüphaneniz için senkronize şarkı sözleri (.lrc dosyaları) indirmenizi sağlayan bir uygulamadır. + Generated using MusicResync + MusicResync, yerel müzik kütüphaneniz için senkronize şarkı sözleri (.lrc dosyaları) indirmenizi sağlayan bir uygulamadır. Ayrıca belirli şarkıları arayarak şarkı sözlerini alabilir (ve bunları indirmelere kaydedebilirsiniz). Uygulama sürümü: %1$s Geliştiriciler için Spotify SpotifyLyrics API - SongSync Hakkında - SongSync, şarkı sözlerini almak için SpotifyLyrics API’sini kullanır. SpotifyLyrics API hakkında daha fazla bilgiyi GitHub sayfasında bulabilirsiniz. + MusicResync Hakkında + MusicResync, şarkı sözlerini almak için SpotifyLyrics API’sini kullanır. SpotifyLyrics API hakkında daha fazla bilgiyi GitHub sayfasında bulabilirsiniz. GitHub’da Görüntüle - SongSync bir açık kaynak projesidir. Kaynak kodunu GitHub’da bulabilirsiniz. + MusicResync bir açık kaynak projesidir. Kaynak kodunu GitHub’da bulabilirsiniz. Katkıda Bulunanlar GitHub Telegram @@ -160,7 +160,7 @@ Bildirim göster (İsteğe bağlı) İndirme ilerleme bildirimini göstermek için kullanılır Devam et - SongSync’e Hoş Geldiniz! + MusicResync’e Hoş Geldiniz! Başlamak için lütfen aşağıdaki izinleri verin: Şu anda çalan şarkı Bildirim erişimi (İsteğe bağlı) diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index c4de679..67bda58 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -14,9 +14,9 @@ Không xác định Phiên bản ứng dụng: %1$s Spotify dành cho Nhà phát triển - Về SongSync + Về MusicResync Xem trên GitHub - SongSync là một dự án mã nguồn mở. Bạn có thể tìm mã nguồn trên GitHub. + MusicResync là một dự án mã nguồn mở. Bạn có thể tìm mã nguồn trên GitHub. Những người đóng góp Tìm thấy lỗi\? Có gợi ý\? Muốn đóng góp\? Đừng ngại và hãy liên hệ với tôi trên nhóm Telegram. Mã nguồn @@ -71,9 +71,9 @@ Thành công: %1$d, Không có lời: %2$d, Thất bại: %3$d Tải xuống thành công Không có kết nối mạng hoặc máy chủ đã bị sập - SongSync là một ứng dụng giúp bạn tải xuống lời bài hát (tệp .lrc) cho thư viện nhạc của bạn. + MusicResync là một ứng dụng giúp bạn tải xuống lời bài hát (tệp .lrc) cho thư viện nhạc của bạn. Bạn cũng có thể tìm kiếm một bài hát cụ thể để lấy lời bài hát (và lưu nó lại). - SongSync sử dụng API SpotifyLyrics để lấy lời của bài hát. Bạn có thể tìm hiểu thêm thông tin về API SpotifyLyrics trên trang GitHub của họ. + MusicResync sử dụng API SpotifyLyrics để lấy lời của bài hát. Bạn có thể tìm hiểu thêm thông tin về API SpotifyLyrics trên trang GitHub của họ. Nhóm Telegram Bạn cũng có thể tạo một issue trên GitHub (liên kết ở trên). Quyền truy cập bị từ chối diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 9bc608e..c547bd4 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -18,12 +18,12 @@ 保存 .lrc 文件 没有结果 未知 - SongSync 是一款能够为你的本地曲库下载同步歌词 (.lrc 文件) 的应用。 + MusicResync 是一款能够为你的本地曲库下载同步歌词 (.lrc 文件) 的应用。 应用版本: %1$s 面向开发者的 Spotify - 关于 SongSync + 关于 MusicResync 在 Github 上查看 - SongSync 是开源项目。你可以在 GitHub 上找到源代码。 + MusicResync 是开源项目。你可以在 GitHub 上找到源代码。 贡献者 主开发者 关闭应用 @@ -70,7 +70,7 @@ 开发者 权限被拒绝 本应用需要储存权限才能扫描你的音乐库和保存歌词。 - SongSync 使用 SpotifyLyrics API 来获取歌曲信息。你可以在 SpotifyLyrics 的GitHub主页上找到有关 SpotifyLyrics API 的更多信息。 + MusicResync 使用 SpotifyLyrics API 来获取歌曲信息。你可以在 SpotifyLyrics 的GitHub主页上找到有关 SpotifyLyrics API 的更多信息。 出现了 bug\? 有什么建议\? 想要贡献代码\? 欢迎加入猫猫的 Telegram Group来联系 lambada 猫猫。 如果你已经连接到网络了,那么 Spotify 的服务器可能正在维护。请稍候再试。 搜索 @@ -144,7 +144,7 @@ 用于显示下载进度通知 继续 如果不想每次都打开文件选择器将歌词文件保存在歌曲目录中,那么必须授予该权限 - 欢迎来到 SongSync! + 欢迎来到 MusicResync! 要开始使用,请授予以下权限: 正在播放歌曲 通知权限(可选) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index ee7ef3c..0b0921e 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -8,7 +8,7 @@ 找不到同步歌詞時,切換從Musixmatch取得未同步歌詞。 存取所有檔案 繼續 - 歡迎來到SongSync! + 歡迎來到MusicResync! 首先,請授予以下權限: 現在播放的歌曲 存取通知權限(可選) @@ -28,12 +28,12 @@ 請稍後再試 沒有網路連線或伺服器已關閉 未知 - SongSync這個應用程式可讓您下載本地音樂的同步歌詞(.lrc 檔案)。 + MusicResync這個應用程式可讓您下載本地音樂的同步歌詞(.lrc 檔案)。 應用程式版本:%1$s - 關於SongSync - SongSync 使用 SpotifyLyrics API 取得歌曲的歌詞。 您可以在 SpotifyLyrics API 的 GitHub 頁面上找到有關 SpotifyLyrics API 的更多資訊。 + 關於MusicResync + MusicResync 使用 SpotifyLyrics API 取得歌曲的歌詞。 您可以在 SpotifyLyrics API 的 GitHub 頁面上找到有關 SpotifyLyrics API 的更多資訊。 在Github上查看 - SongSync是開源項目。你可以在Github上找到源代碼。 + MusicResync是開源項目。你可以在Github上找到源代碼。 貢獻者 Telegram群組 源代碼 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c61d64c..2cb9b3e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -62,16 +62,16 @@ No results No internet connection or server is down Unknown - Generated using SongSync - SongSync is an app that lets you to download synced lyrics (.lrc files) for your local music library. + Generated using MusicResync + MusicResync is an app that lets you to download synced lyrics (.lrc files) for your local music library. You can also search for specific songs to get their lyrics (and save them to downloads). App version: %1$s Spotify for Developers SpotifyLyrics API - About SongSync - SongSync uses SpotifyLyrics API to get lyrics for songs. You can find more information about SpotifyLyrics API on their GitHub page. + About MusicResync + MusicResync uses SpotifyLyrics API to get lyrics for songs. You can find more information about SpotifyLyrics API on their GitHub page. View on GitHub - SongSync is an open-source project. You can find the source code on GitHub. + MusicResync is an open-source project. You can find the source code on GitHub. Contributors GitHub Telegram @@ -200,7 +200,7 @@ Show notification (Optional) Used to show download progress notification Continue - Welcome to SongSync! + Welcome to MusicResync! To get started, please grant the following permissions: Now playing song Notification access (Optional) diff --git a/app/src/test/java/pl/lambada/songsync/matching/WrongSingerVetoTest.kt b/app/src/test/java/pl/lambada/songsync/matching/WrongSingerVetoTest.kt new file mode 100644 index 0000000..c9773c2 --- /dev/null +++ b/app/src/test/java/pl/lambada/songsync/matching/WrongSingerVetoTest.kt @@ -0,0 +1,130 @@ +package pl.lambada.songsync.matching + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import pl.lambada.songsync.data.remote.lyrics_providers.RescueCandidate +import pl.lambada.songsync.data.remote.lyrics_providers.artistGuessesFor +import pl.lambada.songsync.data.remote.lyrics_providers.scoreHitAgainstViews +import pl.lambada.songsync.data.remote.lyrics_providers.selectBestRescue +import pl.lambada.songsync.data.remote.lyrics_providers.wrongSingerVetoed +import pl.lambada.songsync.util.matching.ConfidenceBreakdown +import pl.lambada.songsync.util.matching.FilenameParser +import pl.lambada.songsync.util.matching.LocalTrack +import pl.lambada.songsync.util.matching.MatchTier +import pl.lambada.songsync.util.matching.ProviderResult + +/** + * v1.6.3 hotfix regressions: songs with a short generic title were saving lyrics of a completely different + * track by a different artist ("PETROV - RARI" -> "Rari" by lil doggo, "Numero - BMW" -> "BMW" by Cecilio G., + * "UKIC X PETROV - A TI?" -> "A Ti" by Dyango, "QuESt - Automatic" -> "Automatic (Live)" by 宇多田ヒカル). + * All rode in on artist-less views of the local track, which cannot object to a wrong singer. The wrong-singer + * veto rejects such hits whenever the file gives us any artist guess that the provider's artist disagrees with, + * keeping the exact-duration escape the scorer has always trusted. + */ +class WrongSingerVetoTest { + + private val someLrc = "[00:01.00] la la la" + + private fun conf(durationMatched: Boolean) = ConfidenceBreakdown( + score = 0.9, title = 1.0, artist = 0.0, duration = 0.5, album = 0.0, + tier = MatchTier.REVIEW, durationMatched = durationMatched, + ) + + @Test + fun `Petrov - Rari rescue by lil doggo is vetoed`() { + val views = listOf( + LocalTrack("PETROV - RARI (OFFICIAL VIDEO)", null, 195.0), + LocalTrack("RARI", "PETROV", 195.0), + LocalTrack("Rari", null, 195.0), + ) + val wrong = RescueCandidate( + ProviderResult("Rari", "lil doggo", 190.0, null, true), someLrc, null, null, + ) + assertNull(selectBestRescue(views, listOf(wrong))) + } + + @Test + fun `Petrov - Rari rescue by the right artist still passes`() { + val views = listOf( + LocalTrack("PETROV - RARI (OFFICIAL VIDEO)", null, 195.0), + LocalTrack("RARI", "PETROV", 195.0), + LocalTrack("Rari", null, 195.0), + ) + val right = RescueCandidate( + ProviderResult("Rari", "PETROV", 190.0, null, true), someLrc, null, null, + ) + val hit = selectBestRescue(views, listOf(right)) + assertNotNull(hit) + assertEquals("PETROV", hit!!.artist) + } + + @Test + fun `Numero - BMW rescue by Cecilio G is vetoed`() { + val views = listOf( + LocalTrack("Numero - BMW", null, 200.0), + LocalTrack("BMW", "Numero", 200.0), + LocalTrack("BMW", null, 200.0), + ) + val wrong = RescueCandidate( + ProviderResult("BMW", "Cecilio G., Anti", 205.0, null, true), someLrc, null, null, + ) + assertNull(selectBestRescue(views, listOf(wrong))) + } + + @Test + fun `exact runtime match still overrides a disagreeing artist`() { + // The scorer has always trusted an exact duration over a disagreeing artist (that trust is what makes + // junk-artist rips like "xope87" matchable at all) — the veto must keep that escape. + val views = listOf(LocalTrack("RARI", "PETROV", 195.0)) + val sameLength = RescueCandidate( + ProviderResult("Rari", "lil doggo", 195.5, null, true), someLrc, null, null, + ) + assertNotNull(selectBestRescue(views, listOf(sameLength))) + } + + @Test + fun `A Ti by a different singer is vetoed in the main search path`() { + // The raw title view ("UKIC X PETROV - A TI? ..." contains the phrase "A Ti") scored this REVIEW-grade + // even though we clearly knew the artists; the veto is applied on top of scoreHitAgainstViews. + val local = LocalTrack("UKIC X PETROV - A TI? (Prod.by Papapedro)", null, 180.0) + val candidates = FilenameParser.candidates("UKIC X PETROV - A TI? (Prod.by Papapedro)", "Unknown", null) + val guesses = artistGuessesFor(local, candidates) + assertTrue("expected artist guesses from the parsed title", guesses.isNotEmpty()) + + val wrong = ProviderResult("A Ti", "Dyango", 174.0, null, true) + val survives = candidates.any { cand -> + val c = scoreHitAgainstViews(local, wrong, cand) + c.tier != MatchTier.REJECT && !wrongSingerVetoed(guesses, wrong.artist, c) + } + assertFalse("wrong-singer hit survived the veto", survives) + } + + @Test + fun `cross-script provider artist counts as disagreeing`() { + // "QuESt - Automatic" matched "Automatic (Live)" by 宇多田ヒカル: the CJK name normalizes to nothing our + // Latin guess could ever equal, so it must count as a disagreement (duration escape still applies). + assertTrue(wrongSingerVetoed(listOf("QuESt"), "宇多田ヒカル", conf(durationMatched = false))) + assertFalse(wrongSingerVetoed(listOf("QuESt"), "宇多田ヒカル", conf(durationMatched = true))) + } + + @Test + fun `veto stays out of the way when it cannot judge`() { + // No artist from the provider, or no guesses from the file: nothing to disagree with. + assertFalse(wrongSingerVetoed(listOf("PETROV"), null, conf(durationMatched = false))) + assertFalse(wrongSingerVetoed(listOf("PETROV"), " ", conf(durationMatched = false))) + assertFalse(wrongSingerVetoed(emptyList(), "lil doggo", conf(durationMatched = false))) + // A guess that normalizes to nothing comparable (pure symbols) is not usable evidence either. + assertFalse(wrongSingerVetoed(listOf("???"), "lil doggo", conf(durationMatched = false))) + } + + @Test + fun `featured-artist orderings are not false positives`() { + // Provider lists the collab differently than the filename: max similarity across guesses must clear it. + val guesses = listOf("Prti Bee Gee ft. Ajs Nigrutin", "Prti Bee Gee", "Ajs Nigrutin") + assertFalse(wrongSingerVetoed(guesses, "Ajs Nigrutin, Prti Bee Gee", conf(durationMatched = false))) + } +}