mirror of
https://github.com/whoeevee/EeveeSpotifyReborn.git
synced 2026-01-09 00:23:20 +01:00
romanized genius lyrics
This commit is contained in:
@@ -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)
|
||||
|
||||
+17
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-15
@@ -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(
|
||||
Reference in New Issue
Block a user