romanized genius lyrics

This commit is contained in:
eevee
2024-07-05 10:11:54 +03:00
parent f79ee3d51d
commit 5a242bf849
12 changed files with 88 additions and 63 deletions
@@ -127,6 +127,7 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
spotifyTrackId: track.URI().spt_trackIdentifier()
)
let options = UserDefaults.lyricsOptions
var source = UserDefaults.lyricsSource
var repository: LyricsRepository = switch source {
@@ -140,7 +141,7 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
//
do {
lyricsDto = try repository.getLyrics(searchQuery)
lyricsDto = try repository.getLyrics(searchQuery, options: options)
lastLyricsError = nil
}
@@ -189,7 +190,7 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
source = .genius
repository = GeniusLyricsRepository()
lyricsDto = try repository.getLyrics(searchQuery)
lyricsDto = try repository.getLyrics(searchQuery, options: options)
}
let lyrics = Lyrics.with {
@@ -3,4 +3,5 @@ import Foundation
struct GeniusHitResult: Decodable {
var id: Int
var title: String
var artistNames: String
}
@@ -0,0 +1,5 @@
import Foundation
struct LyricsOptions: Codable, Equatable {
var geniusRomanizations: Bool
}
@@ -1,5 +1,5 @@
import Foundation
protocol LyricsRepository {
func getLyrics(_ query: LyricsSearchQuery) throws -> LyricsDto
func getLyrics(_ query: LyricsSearchQuery, options: LyricsOptions) throws -> LyricsDto
}
@@ -1,6 +1,8 @@
import Foundation
struct GeniusLyricsRepository: LyricsRepository {
private let jsonDecoder: JSONDecoder
private let apiUrl = "https://api.genius.com"
private let session: URLSession
@@ -13,6 +15,9 @@ struct GeniusLyricsRepository: LyricsRepository {
]
session = URLSession(configuration: configuration)
jsonDecoder = JSONDecoder()
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
}
private func perform(
@@ -48,7 +53,7 @@ struct GeniusLyricsRepository: LyricsRepository {
throw error
}
let rootResponse = try JSONDecoder().decode(GeniusRootResponse.self, from: data!)
let rootResponse = try jsonDecoder.decode(GeniusRootResponse.self, from: data!)
return rootResponse.response
}
@@ -79,12 +84,28 @@ struct GeniusLyricsRepository: LyricsRepository {
//
private func mostRelevantHitResult(hits: [GeniusHit], strippedTitle: String) -> GeniusHitResult? {
return (
hits.first(
where: { $0.result.title.containsInsensitive(strippedTitle) }
) ?? hits.first
)?.result
private func mostRelevantHitResult(
hits: [GeniusHit],
strippedTitle: String,
romanized: Bool
) -> GeniusHitResult {
let results = hits.map { $0.result }
let matchingByTitle = results.filter(
{ $0.title.containsInsensitive(strippedTitle) }
)
if matchingByTitle.isEmpty {
return results.first!
}
if romanized, let romanizedSong = matchingByTitle.first(
where: { $0.artistNames == "Genius Romanizations" }
) {
return romanizedSong
}
return matchingByTitle.first!
}
private func mapLyricsLines(_ rawLines: [String]) -> [String] {
@@ -102,36 +123,20 @@ struct GeniusLyricsRepository: LyricsRepository {
return lines
}
func getLyrics(_ query: LyricsSearchQuery) throws -> LyricsDto {
func getLyrics(_ query: LyricsSearchQuery, options: LyricsOptions) throws -> LyricsDto {
let strippedTitle = query.title.strippedTrackTitle
var queries = [
"\(strippedTitle) \(query.primaryArtist)"
]
if UserDefaults.romanizedLyrics {
queries = [
"\(strippedTitle) \(query.primaryArtist) (Romanized)",
"\(strippedTitle) \(query.primaryArtist)"
]
}
var hits: [GeniusHit] = []
let hits = try searchSong("\(strippedTitle) \(query.primaryArtist)")
for searchQuery in queries {
do {
hits = try searchSong(searchQuery)
if !hits.isEmpty {
break
}
} catch {
// Continue to the next query if the current one fails
}
}
guard !hits.isEmpty,
let song = mostRelevantHitResult(hits: hits, strippedTitle: strippedTitle) else {
guard !hits.isEmpty else {
throw LyricsError.NoSuchSong
}
let song = mostRelevantHitResult(
hits: hits,
strippedTitle: strippedTitle,
romanized: options.geniusRomanizations
)
let songInfo = try getSongInfo(song.id)
let plainLines = songInfo.lyrics.plain.components(separatedBy: "\n")
@@ -92,7 +92,7 @@ struct LrcLibLyricsRepository: LyricsRepository {
}
}
func getLyrics(_ query: LyricsSearchQuery) throws -> LyricsDto {
func getLyrics(_ query: LyricsSearchQuery, options: LyricsOptions) throws -> LyricsDto {
let strippedTitle = query.title.strippedTrackTitle
let songs = try searchSong("\(strippedTitle) \(query.primaryArtist)")
@@ -46,7 +46,7 @@ struct MusixmatchLyricsRepository: LyricsRepository {
return data!
}
func getLyrics(_ query: LyricsSearchQuery) throws -> LyricsDto {
func getLyrics(_ query: LyricsSearchQuery, options: LyricsOptions) throws -> LyricsDto {
let data = try perform(
"/ws/1.1/macro.subtitles.get",
@@ -7,12 +7,12 @@ extension UserDefaults {
private static let lyricsSourceKey = "lyricsSource"
private static let musixmatchTokenKey = "musixmatchToken"
private static let geniusFallbackKey = "geniusFallback"
private static let romanizedLyricsKey = "romanizedLyrics"
private static let fallbackReasonsKey = "fallbackReasons"
private static let darkPopUpsKey = "darkPopUps"
private static let patchTypeKey = "patchType"
private static let overwriteConfigurationKey = "overwriteConfiguration"
private static let lyricsColorsKey = "lyricsColors"
private static let lyricsOptionsKey = "lyricsOptions"
static var lyricsSource: LyricsSource {
get {
@@ -45,12 +45,16 @@ extension UserDefaults {
}
}
static var romanizedLyrics: Bool {
static var lyricsOptions: LyricsOptions {
get {
defaults.object(forKey: romanizedLyricsKey) as? Bool ?? false
if let data = defaults.object(forKey: lyricsOptionsKey) as? Data {
return try! JSONDecoder().decode(LyricsOptions.self, from: data)
}
return LyricsOptions(geniusRomanizations: false)
}
set (romanized) {
defaults.set(romanized, forKey: romanizedLyricsKey)
set (lyricsOptions) {
defaults.set(try! JSONEncoder().encode(lyricsOptions), forKey: lyricsOptionsKey)
}
}
@@ -45,8 +45,8 @@ You can set a static color or a normalization factor based on the extracted trac
}
}
.onChange(of: lyricsColors) { newLyricsColors in
UserDefaults.lyricsColors = newLyricsColors
.onChange(of: lyricsColors) { lyricsColors in
UserDefaults.lyricsColors = lyricsColors
}
}
}
@@ -8,7 +8,9 @@ struct EeveeSettingsView: View {
@State var overwriteConfiguration = UserDefaults.overwriteConfiguration
@State var lyricsSource = UserDefaults.lyricsSource
@State var geniusFallback = UserDefaults.geniusFallback
@State var lyricsColors = UserDefaults.lyricsColors
@State var lyricsOptions = UserDefaults.lyricsOptions
@State var latestVersion = ""
@@ -19,7 +21,8 @@ struct EeveeSettingsView: View {
PremiumSections()
LyricsSections()
LyricsSourceSection()
LyricsOptionsSection()
LyricsColorsSection()
@@ -51,9 +54,9 @@ struct EeveeSettingsView: View {
}
.listStyle(GroupedListStyle())
.ignoresSafeArea(.keyboard)
.animation(.default, value: lyricsSource)
.animation(.default, value: geniusFallback)
.animation(.default, value: patchType)
.animation(.default, value: lyricsColors)
.animation(.default, value: latestVersion)
@@ -0,0 +1,17 @@
import SwiftUI
extension EeveeSettingsView {
@ViewBuilder func LyricsOptionsSection() -> some View {
if lyricsSource == .genius || geniusFallback {
Section {
Toggle(
"Romanized Genius Lyrics",
isOn: $lyricsOptions.geniusRomanizations
)
}
.onChange(of: lyricsOptions) { lyricsOptions in
UserDefaults.lyricsOptions = lyricsOptions
}
}
}
}
@@ -47,7 +47,7 @@ extension EeveeSettingsView {
}
@ViewBuilder func LyricsSections() -> some View {
@ViewBuilder func LyricsSourceSection() -> some View {
Section(footer: Text("""
You can select the lyrics source you prefer.
@@ -105,16 +105,8 @@ If the tweak is unable to find a song or process the lyrics, you'll see a "Could
UserDefaults.lyricsSource = newSource
}
if lyricsSource == .genius {
Section {
Toggle(
"Use Romanized (Romaji) Lyrics when Available",
isOn: Binding<Bool>(
get: { UserDefaults.romanizedLyrics },
set: { UserDefaults.romanizedLyrics = $0 }
)
)
}
.onChange(of: geniusFallback) { geniusFallback in
UserDefaults.geniusFallback = geniusFallback
}
if lyricsSource != .genius {
@@ -123,10 +115,7 @@ If the tweak is unable to find a song or process the lyrics, you'll see a "Could
) {
Toggle(
"Genius Fallback",
isOn: Binding<Bool>(
get: { UserDefaults.geniusFallback },
set: { UserDefaults.geniusFallback = $0 }
)
isOn: $geniusFallback
)
Toggle(