From c233289b82eb97df2965f742c890cbd67b12ef6b Mon Sep 17 00:00:00 2001 From: eevee Date: Thu, 18 Jul 2024 13:52:18 +0300 Subject: [PATCH] romanized lyrics for all sources --- .../EeveeSpotify/Lyrics/CustomLyrics.x.swift | 3 ++- .../EeveeSpotify/Lyrics/Models/LyricsDto.swift | 17 ++++++++++++----- .../Models/LyricsRomanizationStatus.swift | 7 +++++++ .../Repositories/GeniusLyricsRepository.swift | 14 ++++++++++++-- .../Repositories/LrclibLyricsRepository.swift | 6 ++++-- .../MusixmatchLyricsRepository.swift | 14 ++++++++++++-- .../Repositories/PetitLyricsRepository.swift | 8 ++++++-- .../Models/Extensions/String+Extension.swift | 12 ++++++++++++ .../Sections/EeveeLyricsSettingsView.swift | 14 ++++++-------- 9 files changed, 73 insertions(+), 22 deletions(-) create mode 100644 Sources/EeveeSpotify/Lyrics/Models/LyricsRomanizationStatus.swift diff --git a/Sources/EeveeSpotify/Lyrics/CustomLyrics.x.swift b/Sources/EeveeSpotify/Lyrics/CustomLyrics.x.swift index e60500f2..360d10f7 100644 --- a/Sources/EeveeSpotify/Lyrics/CustomLyrics.x.swift +++ b/Sources/EeveeSpotify/Lyrics/CustomLyrics.x.swift @@ -213,7 +213,8 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data { lyricsDto = try repository.getLyrics(searchQuery, options: options) } - lastLyricsWasRomanized = lyricsDto.romanized + lastLyricsWasRomanized = lyricsDto.romanization == .romanized + || (lyricsDto.romanization == .canBeRomanized && UserDefaults.lyricsOptions.romanization) lastLyricsAreEmpty = lyricsDto.lines.isEmpty let lyrics = Lyrics.with { diff --git a/Sources/EeveeSpotify/Lyrics/Models/LyricsDto.swift b/Sources/EeveeSpotify/Lyrics/Models/LyricsDto.swift index f0276b06..861e9cc7 100644 --- a/Sources/EeveeSpotify/Lyrics/Models/LyricsDto.swift +++ b/Sources/EeveeSpotify/Lyrics/Models/LyricsDto.swift @@ -3,7 +3,7 @@ import Foundation struct LyricsDto { var lines: [LyricsLineDto] var timeSynced: Bool - var romanized: Bool = false + var romanization: LyricsRomanizationStatus var translation: LyricsTranslationDto? func toLyricsData(source: String) -> LyricsData { @@ -13,8 +13,10 @@ struct LyricsDto { $0.providedBy = "\(source) (EeveeSpotify)" } - lyricsData.lines = lines.isEmpty - ? [ + let shouldRomanize = UserDefaults.lyricsOptions.romanization + + if lines.isEmpty { + lyricsData.lines = [ LyricsLine.with { $0.content = "This song is instrumental." }, @@ -25,12 +27,17 @@ struct LyricsDto { $0.content = "" } ] - : lines.map { line in + } + else { + lyricsData.lines = lines.map { line in LyricsLine.with { - $0.content = line.content + $0.content = (shouldRomanize && romanization == .canBeRomanized) + ? line.content.applyingTransform(.toLatin, reverse: false)! + : line.content $0.offsetMs = Int32(line.offsetMs ?? 0) } } + } if let translation = translation { lyricsData.translation = LyricsTranslation.with { diff --git a/Sources/EeveeSpotify/Lyrics/Models/LyricsRomanizationStatus.swift b/Sources/EeveeSpotify/Lyrics/Models/LyricsRomanizationStatus.swift new file mode 100644 index 00000000..e3912d1e --- /dev/null +++ b/Sources/EeveeSpotify/Lyrics/Models/LyricsRomanizationStatus.swift @@ -0,0 +1,7 @@ +import Foundation + +enum LyricsRomanizationStatus { + case romanized + case canBeRomanized + case original +} diff --git a/Sources/EeveeSpotify/Lyrics/Repositories/GeniusLyricsRepository.swift b/Sources/EeveeSpotify/Lyrics/Repositories/GeniusLyricsRepository.swift index d5529fe4..77fc1bf0 100644 --- a/Sources/EeveeSpotify/Lyrics/Repositories/GeniusLyricsRepository.swift +++ b/Sources/EeveeSpotify/Lyrics/Repositories/GeniusLyricsRepository.swift @@ -145,12 +145,22 @@ struct GeniusLyricsRepository: LyricsRepository { ) let songInfo = try getSongInfo(song.id) - let plainLines = songInfo.lyrics.plain.components(separatedBy: "\n") + let plainLyrics = songInfo.lyrics.plain + let plainLines = plainLyrics.components(separatedBy: "\n") + + var romanization = LyricsRomanizationStatus.original + + if hasFoundRomanizedLyrics { + romanization = .romanized + } + else if plainLyrics.canBeRomanized { + romanization = .canBeRomanized + } return LyricsDto( lines: mapLyricsLines(plainLines).map { line in LyricsLineDto(content: line) }, timeSynced: false, - romanized: hasFoundRomanizedLyrics + romanization: romanization ) } } diff --git a/Sources/EeveeSpotify/Lyrics/Repositories/LrclibLyricsRepository.swift b/Sources/EeveeSpotify/Lyrics/Repositories/LrclibLyricsRepository.swift index 571eb215..6719e125 100644 --- a/Sources/EeveeSpotify/Lyrics/Repositories/LrclibLyricsRepository.swift +++ b/Sources/EeveeSpotify/Lyrics/Repositories/LrclibLyricsRepository.swift @@ -105,7 +105,8 @@ struct LrcLibLyricsRepository: LyricsRepository { lines: mapSyncedLyricsLines( syncedLyrics.components(separatedBy: "\n").dropLast() ), - timeSynced: true + timeSynced: true, + romanization: syncedLyrics.canBeRomanized ? .canBeRomanized : .original ) } @@ -118,7 +119,8 @@ struct LrcLibLyricsRepository: LyricsRepository { .components(separatedBy: "\n") .dropLast() .map { content in LyricsLineDto(content: content) }, - timeSynced: false + timeSynced: false, + romanization: plainLyrics.canBeRomanized ? .canBeRomanized : .original ) } } diff --git a/Sources/EeveeSpotify/Lyrics/Repositories/MusixmatchLyricsRepository.swift b/Sources/EeveeSpotify/Lyrics/Repositories/MusixmatchLyricsRepository.swift index 85b48172..866bb23b 100644 --- a/Sources/EeveeSpotify/Lyrics/Repositories/MusixmatchLyricsRepository.swift +++ b/Sources/EeveeSpotify/Lyrics/Repositories/MusixmatchLyricsRepository.swift @@ -228,10 +228,19 @@ class MusixmatchLyricsRepository: LyricsRepository { } } + var romanization = LyricsRomanizationStatus.original + + if romanized { + romanization = .romanized + } + else if lyricsLines.map({ $0.content }).joined().canBeRomanized { + romanization = .canBeRomanized + } + return LyricsDto( lines: lyricsLines, timeSynced: true, - romanized: romanized, + romanization: romanization, translation: translation ) } @@ -258,7 +267,8 @@ class MusixmatchLyricsRepository: LyricsRepository { .components(separatedBy: "\n") .dropLast() .map { LyricsLineDto(content: $0.lyricsNoteIfEmpty) }, - timeSynced: false + timeSynced: false, + romanization: plainLyrics.canBeRomanized ? .canBeRomanized : .original ) } } diff --git a/Sources/EeveeSpotify/Lyrics/Repositories/PetitLyricsRepository.swift b/Sources/EeveeSpotify/Lyrics/Repositories/PetitLyricsRepository.swift index 0c1996f6..824f410b 100644 --- a/Sources/EeveeSpotify/Lyrics/Repositories/PetitLyricsRepository.swift +++ b/Sources/EeveeSpotify/Lyrics/Repositories/PetitLyricsRepository.swift @@ -115,7 +115,10 @@ struct PetitLyricsRepository: LyricsRepository { offsetMs: $0.words.first!.starttime ) }, - timeSynced: true + timeSynced: true, + romanization: lyrics.lines.map { $0.linestring }.joined().canBeRomanized + ? .canBeRomanized + : .original ) case .plain: @@ -125,7 +128,8 @@ struct PetitLyricsRepository: LyricsRepository { lines: stringLyrics .components(separatedBy: "\n") .map { LyricsLineDto(content: $0) }, - timeSynced: false + timeSynced: false, + romanization: stringLyrics.canBeRomanized ? .canBeRomanized : .original ) default: diff --git a/Sources/EeveeSpotify/Models/Extensions/String+Extension.swift b/Sources/EeveeSpotify/Models/Extensions/String+Extension.swift index 88572b98..fa4e40c0 100644 --- a/Sources/EeveeSpotify/Models/Extensions/String+Extension.swift +++ b/Sources/EeveeSpotify/Models/Extensions/String+Extension.swift @@ -1,4 +1,5 @@ import Foundation +import NaturalLanguage extension String { @@ -45,6 +46,17 @@ extension String { ) } + var canBeRomanized: Bool { + let languageRecognizer = NLLanguageRecognizer() + languageRecognizer.processString(self) + + if let code = languageRecognizer.dominantLanguage?.rawValue { + return ["ja", "ko"].contains(code) || code.contains("zh") + } + + return false + } + var hexadecimal: Data? { var data = Data(capacity: count / 2) diff --git a/Sources/EeveeSpotify/Settings/Views/Sections/EeveeLyricsSettingsView.swift b/Sources/EeveeSpotify/Settings/Views/Sections/EeveeLyricsSettingsView.swift index 7410e567..0c2a4d17 100644 --- a/Sources/EeveeSpotify/Settings/Views/Sections/EeveeLyricsSettingsView.swift +++ b/Sources/EeveeSpotify/Settings/Views/Sections/EeveeLyricsSettingsView.swift @@ -37,13 +37,11 @@ struct EeveeLyricsSettingsView: View { // - if [.genius, .musixmatch].contains(lyricsSource) || geniusFallback { - Section(footer: Text("Load romanized lyrics from Musixmatch or Genius.")) { - Toggle( - "Romanized Lyrics", - isOn: $lyricsOptions.romanization - ) - } + Section(footer: Text("Display romanized lyrics for Japanese, Korean, and Chinese.")) { + Toggle( + "Romanized Lyrics", + isOn: $lyricsOptions.romanization + ) } if lyricsSource == .musixmatch { @@ -64,7 +62,7 @@ struct EeveeLyricsSettingsView: View { .foregroundColor(.gray) } } footer: { - Text("You can enter a 2-letter Musixmatch language code and see translated lyrics on Musixmatch if they are available. It overrides Romanized Lyrics.") + Text("You can enter a 2-letter Musixmatch language code and see translated lyrics on Musixmatch if they are available.") } }