Skip to content

Commit

Permalink
fix: improve lyrics fetching and query encoding for special characters (
Browse files Browse the repository at this point in the history
#594)

* chore: gitignore .vscode

* fix(lrclib): use 'get' API, return empty lines when instrumental

* build: add workflow_dispatch trigger

* fix: encode query strings with stricter character set
  • Loading branch information
Mapleshade20 authored Dec 30, 2024
1 parent ba407d7 commit 85a002b
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 27 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches: [ "swift" ]
pull_request:
branches: [ "swift" ]
workflow_dispatch:

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ xcuserdata/
.theos/
packages/
.DS_Store
.vscode/
1 change: 1 addition & 0 deletions Sources/EeveeSpotify/Lyrics/Models/Lrclib/LrclibSong.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ struct LrclibSong: Decodable {
var name: String
var plainLyrics: String?
var syncedLyrics: String?
var instrumental: Bool
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ struct GeniusLyricsRepository: LyricsRepository {
var stringUrl = "\(apiUrl)\(path)"

if !query.isEmpty {
let queryString = query.queryString.addingPercentEncoding(
withAllowedCharacters: .urlHostAllowed
)!
let queryString = query.queryString

stringUrl += "?\(queryString)"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ struct LrcLibLyricsRepository: LyricsRepository {
var stringUrl = "\(apiUrl)\(path)"

if !query.isEmpty {
let queryString = query.queryString.addingPercentEncoding(
withAllowedCharacters: .urlHostAllowed
)!
let queryString = query.queryString

stringUrl += "?\(queryString)"
}
Expand All @@ -49,23 +47,18 @@ struct LrcLibLyricsRepository: LyricsRepository {
return data!
}

private func searchSong(_ query: String) throws -> [LrclibSong] {
let data = try perform("/search", query: ["q": query])
return try JSONDecoder().decode([LrclibSong].self, from: data)
}

//

private func mostRelevantSong(songs: [LrclibSong], strippedTitle: String) -> LrclibSong? {
return songs.first(
where: { $0.name.containsInsensitive(strippedTitle) }
) ?? songs.first
private func getSong(trackName: String, artistName: String) throws -> LrclibSong {
let data: Data = try perform("/get", query: [
"track_name": trackName,
"artist_name": artistName
])
return try JSONDecoder().decode(LrclibSong.self, from: data)
}

private func mapSyncedLyricsLines(_ lines: [String]) -> [LyricsLineDto] {
return lines.compactMap { line in
guard let match = line.firstMatch(
"\\[(?<minute>\\d*):(?<seconds>\\d*\\.?\\d*)\\] ?(?<content>.*)"
"\\[(?<minute>\\d*):(?<seconds>\\d+\\.\\d+|\\d+)\\] ?(?<content>.*)"
) else {
return nil
}
Expand Down Expand Up @@ -93,13 +86,27 @@ struct LrcLibLyricsRepository: LyricsRepository {
}

func getLyrics(_ query: LyricsSearchQuery, options: LyricsOptions) throws -> LyricsDto {
let strippedTitle = query.title.strippedTrackTitle
let songs = try searchSong("\(strippedTitle) \(query.primaryArtist)")

guard let song = mostRelevantSong(songs: songs, strippedTitle: strippedTitle) else {
throw LyricsError.noSuchSong
let song: LrclibSong

do {
song = try getSong(trackName: query.title, artistName: query.primaryArtist)
} catch {
let strippedTitle = query.title.strippedTrackTitle
do {
song = try getSong(trackName: strippedTitle, artistName: query.primaryArtist)
} catch {
throw LyricsError.noSuchSong
}
}


if song.instrumental {
return LyricsDto(
lines: [],
timeSynced: false,
romanization: .original
)
}

if let syncedLyrics = song.syncedLyrics {
let lines = Array(syncedLyrics.components(separatedBy: "\n").dropLast())
return LyricsDto(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Foundation

extension CharacterSet {
static var urlQueryAllowedStrict: CharacterSet {
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: "/?@&=+$")
return allowed
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import Foundation
extension Dictionary {
var queryString: String {
return self
.compactMap({ (key, value) -> String in
return "\(key)=\(value)"
.compactMap({ (key, value) -> String? in
guard let keyString = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowedStrict),
let valueString = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowedStrict) else {
return nil
}
return "\(keyString)=\(valueString)"
})
.joined(separator: "&")
.joined(separator: "&")
}
}

0 comments on commit 85a002b

Please sign in to comment.