Skip to content

Commit 8f8ead1

Browse files
committed
yodaluca23 has confirmed andrea Filice ban prs forever
1 parent 7ff2963 commit 8f8ead1

2 files changed

Lines changed: 97 additions & 60 deletions

File tree

Sources/EeveeSpotify/Lyrics/Models/LyricsSearchQuery.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Foundation
22

3-
struct LyricsSearchQuery {
3+
struct LyricsSearchQuery: Hashable {
44
var title: String
55
var primaryArtist: String
66
var spotifyTrackId: String

Sources/EeveeSpotify/Lyrics/Repositories/MusixmatchLyricsRepository.swift

Lines changed: 96 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,35 @@ import UIKit
33

44
class MusixmatchLyricsRepository: LyricsRepository {
55
private let apiUrl = "https://apic.musixmatch.com"
6-
6+
77
var selectedLanguage: String
8-
8+
99
static let shared = MusixmatchLyricsRepository(
1010
language: UserDefaults.lyricsOptions.musixmatchLanguage
1111
)
12-
12+
1313
private init(language: String) {
1414
selectedLanguage = language
1515
}
1616

17+
//
18+
19+
private class CachedLyrics {
20+
let dto: LyricsDto
21+
22+
init(dto: LyricsDto) {
23+
self.dto = dto
24+
}
25+
}
26+
27+
private let lyricsCache = NSCache<NSString, CachedLyrics>()
28+
29+
private func getCacheKey(for query: LyricsSearchQuery) -> String {
30+
return "\(query.hashValue)_\(selectedLanguage)"
31+
}
32+
33+
//
34+
1735
private func perform(
1836
_ path: String,
1937
query: [String: Any] = [:]
@@ -26,7 +44,7 @@ class MusixmatchLyricsRepository: LyricsRepository {
2644

2745
let queryString = finalQuery.queryString
2846
stringUrl += "?\(queryString)"
29-
47+
3048
let request = URLRequest(url: URL(string: stringUrl)!)
3149

3250
let semaphore = DispatchSemaphore(value: 0)
@@ -48,9 +66,9 @@ class MusixmatchLyricsRepository: LyricsRepository {
4866

4967
return data!
5068
}
51-
69+
5270
//
53-
71+
5472
private func getMacroCalls(_ data: Data) throws -> [String: Any] {
5573
guard
5674
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
@@ -62,41 +80,44 @@ class MusixmatchLyricsRepository: LyricsRepository {
6280
}
6381

6482
if let header = message["header"] as? [String: Any],
65-
header["status_code"] as? Int == 401 {
83+
header["status_code"] as? Int == 401
84+
{
6685
throw LyricsError.invalidMusixmatchToken
6786
}
68-
87+
6988
return macroCalls
7089
}
71-
90+
7291
private func getFirstSubtitle(_ subtitlesMessage: [String: Any]) throws -> [String: Any] {
73-
guard
92+
guard
7493
let subtitlesBody = subtitlesMessage["body"] as? [String: Any],
7594
let subtitleList = subtitlesBody["subtitle_list"] as? [[String: Any]],
7695
let firstSubtitle = subtitleList.first,
7796
let subtitle = firstSubtitle["subtitle"] as? [String: Any]
7897
else {
7998
throw LyricsError.decodingError
8099
}
81-
100+
82101
if let restricted = subtitle["restricted"] as? Bool, restricted {
83102
throw LyricsError.musixmatchRestricted
84103
}
85-
104+
86105
return subtitle
87106
}
88-
107+
89108
//
90-
91-
private func getTranslations(_ spotifyTrackId: String, selectedLanguage: String) throws -> [String: String] {
109+
110+
private func getTranslations(_ spotifyTrackId: String, selectedLanguage: String) throws
111+
-> [String: String]
112+
{
92113
let data = try perform(
93114
"/ws/1.1/crowd.track.translations.get",
94115
query: [
95116
"track_spotify_id": spotifyTrackId,
96-
"selected_language": selectedLanguage
117+
"selected_language": selectedLanguage,
97118
]
98119
)
99-
120+
100121
guard
101122
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
102123
let message = json["message"] as? [String: Any],
@@ -109,27 +130,34 @@ class MusixmatchLyricsRepository: LyricsRepository {
109130
let translations = translationsList.compactMap {
110131
$0["translation"] as? [String: Any]
111132
}
112-
133+
113134
return translations.reduce(into: [:]) { dictionary, translation in
114-
dictionary[translation["subtitle_matched_line"] as! String] = translation["description"] as? String
135+
dictionary[translation["subtitle_matched_line"] as! String] =
136+
translation["description"] as? String
115137
}
116138
}
117-
139+
118140
//
119-
141+
120142
func getLyrics(_ query: LyricsSearchQuery, options: LyricsOptions) throws -> LyricsDto {
143+
let cacheKey = getCacheKey(for: query)
144+
145+
if let cached = lyricsCache.object(forKey: cacheKey as NSString) {
146+
return cached.dto
147+
}
148+
121149
var musixmatchQuery = [
122150
"track_spotify_id": query.spotifyTrackId,
123151
"subtitle_format": "mxm",
124152
"q_track": query.title,
125-
"q_artist": query.primaryArtist
153+
"q_artist": query.primaryArtist,
126154
]
127-
155+
128156
if !selectedLanguage.isEmpty {
129157
musixmatchQuery["selected_language"] = selectedLanguage
130158
musixmatchQuery["part"] = "subtitle_translated"
131159
}
132-
160+
133161
let data = try perform(
134162
"/ws/1.1/macro.subtitles.get",
135163
query: musixmatchQuery
@@ -139,7 +167,7 @@ class MusixmatchLyricsRepository: LyricsRepository {
139167

140168
var romanized = false
141169
var translation: LyricsTranslationDto? = nil
142-
170+
143171
let macroCalls = try getMacroCalls(data)
144172

145173
if let trackSubtitlesGet = macroCalls["track.subtitles.get"] as? [String: Any],
@@ -149,55 +177,55 @@ class MusixmatchLyricsRepository: LyricsRepository {
149177
let subtitleBody = subtitle["subtitle_body"] as? String,
150178
let subtitles = try? JSONDecoder().decode(
151179
[MusixmatchSubtitle].self, from: subtitleBody.data(using: .utf8)!
152-
) {
153-
180+
)
181+
{
182+
154183
let romanizationLanguage = "r\(subtitleLanguage.prefix(1))"
155-
184+
156185
var lyricsLines = subtitles.dropLast().map { subtitle in
157186
LyricsLineDto(
158187
content: subtitle.text.lyricsNoteIfEmpty,
159188
offsetMs: Int(subtitle.time.total * 1000)
160189
)
161190
}
162-
191+
163192
lyricsLines.append(
164193
LyricsLineDto(
165194
content: "",
166195
offsetMs: Int(subtitles.last!.time.total * 1000)
167196
)
168197
)
169-
198+
170199
if selectedLanguage != subtitleLanguage,
171-
let subtitleTranslated = subtitle["subtitle_translated"] as? [String: Any],
172-
let subtitleTranslatedBody = subtitleTranslated["subtitle_body"] as? String,
173-
let subtitlesTranslated = try? JSONDecoder().decode(
200+
let subtitleTranslated = subtitle["subtitle_translated"] as? [String: Any],
201+
let subtitleTranslatedBody = subtitleTranslated["subtitle_body"] as? String,
202+
let subtitlesTranslated = try? JSONDecoder().decode(
174203
[MusixmatchSubtitle].self, from: subtitleTranslatedBody.data(using: .utf8)!
175-
)
204+
)
176205
{
177206
if selectedLanguage == romanizationLanguage {
178207
romanized = true
179-
208+
180209
for (index, subtitleTranslated) in subtitlesTranslated.enumerated() {
181210
if !subtitleTranslated.text.isEmpty {
182211
lyricsLines[index].content = subtitleTranslated.text
183212
}
184213
}
185-
}
186-
else {
214+
} else {
187215
translation = LyricsTranslationDto(
188216
languageCode: selectedLanguage,
189217
lines: subtitlesTranslated.map { $0.text }
190218
)
191219
}
192220
}
193-
221+
194222
if options.romanization && selectedLanguage != romanizationLanguage {
195223
if let translations = try? getTranslations(
196224
query.spotifyTrackId,
197225
selectedLanguage: romanizationLanguage
198226
) {
199227
romanized = true
200-
228+
201229
for (original, translation) in translations {
202230
for i in 0..<lyricsLines.count {
203231
if lyricsLines[i].content == original {
@@ -207,50 +235,59 @@ class MusixmatchLyricsRepository: LyricsRepository {
207235
}
208236
}
209237
}
210-
238+
211239
var romanization = LyricsRomanizationStatus.original
212-
240+
213241
if romanized {
214242
romanization = .romanized
215-
}
216-
else if subtitleLanguage.isCanBeRomanizedLanguage {
243+
} else if subtitleLanguage.isCanBeRomanizedLanguage {
217244
romanization = .canBeRomanized
218245
}
219-
220-
return LyricsDto(
246+
247+
let lyricsDto = LyricsDto(
221248
lines: lyricsLines,
222249
timeSynced: true,
223250
romanization: romanization,
224251
translation: translation
225252
)
253+
254+
lyricsCache.setObject(CachedLyrics(dto: lyricsDto), forKey: cacheKey as NSString)
255+
return lyricsDto
226256
}
227-
257+
228258
if let trackLyricsGet = macroCalls["track.lyrics.get"] as? [String: Any],
229-
let lyricsMessage = trackLyricsGet["message"] as? [String: Any],
230-
let lyricsHeader = lyricsMessage["header"] as? [String: Any],
231-
let lyricsStatusCode = lyricsHeader["status_code"] as? Int {
232-
259+
let lyricsMessage = trackLyricsGet["message"] as? [String: Any],
260+
let lyricsHeader = lyricsMessage["header"] as? [String: Any],
261+
let lyricsStatusCode = lyricsHeader["status_code"] as? Int
262+
{
263+
233264
if lyricsStatusCode == 404 {
234265
throw LyricsError.noSuchSong
235266
}
236-
267+
237268
if let lyricsBody = lyricsMessage["body"] as? [String: Any],
238-
let lyrics = lyricsBody["lyrics"] as? [String: Any],
239-
let lyricsLanguage = lyrics["lyrics_language"] as? String,
240-
let plainLyrics = lyrics["lyrics_body"] as? String {
241-
269+
let lyrics = lyricsBody["lyrics"] as? [String: Any],
270+
let lyricsLanguage = lyrics["lyrics_language"] as? String,
271+
let plainLyrics = lyrics["lyrics_body"] as? String
272+
{
273+
242274
if let restricted = lyrics["restricted"] as? Bool, restricted {
243275
throw LyricsError.musixmatchRestricted
244276
}
245-
246-
return LyricsDto(
247-
lines: plainLyrics
277+
278+
let lyricsDto = LyricsDto(
279+
lines:
280+
plainLyrics
248281
.components(separatedBy: "\n")
249282
.dropLast()
250283
.map { LyricsLineDto(content: $0.lyricsNoteIfEmpty) },
251284
timeSynced: false,
252-
romanization: lyricsLanguage.isCanBeRomanizedLanguage ? .canBeRomanized : .original
285+
romanization: lyricsLanguage.isCanBeRomanizedLanguage
286+
? .canBeRomanized : .original
253287
)
288+
289+
lyricsCache.setObject(CachedLyrics(dto: lyricsDto), forKey: cacheKey as NSString)
290+
return lyricsDto
254291
}
255292
}
256293

0 commit comments

Comments
 (0)