@@ -5,7 +5,7 @@ struct MusixmatchLyricsRepository: LyricsRepository {
55 private let apiUrl = " https://apic.musixmatch.com "
66
77 private func perform(
8- _ path: String ,
8+ _ path: String ,
99 query: [ String : Any ] = [ : ]
1010 ) throws -> Data {
1111
@@ -49,7 +49,7 @@ struct MusixmatchLyricsRepository: LyricsRepository {
4949 func getLyrics( _ query: LyricsSearchQuery , options: LyricsOptions ) throws -> LyricsDto {
5050
5151 let data = try perform (
52- " /ws/1.1/macro.subtitles.get " ,
52+ " /ws/1.1/macro.subtitles.get " ,
5353 query: [
5454 " track_spotify_id " : query. spotifyTrackId,
5555 " subtitle_format " : " mxm " ,
@@ -59,7 +59,7 @@ struct MusixmatchLyricsRepository: LyricsRepository {
5959
6060 // 😭😭😭
6161
62- guard
62+ guard
6363 let json = try ? JSONSerialization . jsonObject ( with: data, options: [ ] ) as? [ String : Any ] ,
6464 let message = json [ " message " ] as? [ String : Any ] ,
6565 let body = message [ " body " ] as? [ String : Any ] ,
@@ -68,7 +68,7 @@ struct MusixmatchLyricsRepository: LyricsRepository {
6868 throw LyricsError . DecodingError
6969 }
7070
71- if let header = message [ " header " ] as? [ String : Any ] ,
71+ if let header = message [ " header " ] as? [ String : Any ] ,
7272 header [ " status_code " ] as? Int == 401 {
7373 throw LyricsError . InvalidMusixmatchToken
7474 }
@@ -100,15 +100,83 @@ struct MusixmatchLyricsRepository: LyricsRepository {
100100 throw LyricsError . DecodingError
101101 }
102102
103- return LyricsDto (
104- lines: subtitles. map { subtitle in
105- LyricsLineDto (
106- content: subtitle. text. lyricsNoteIfEmpty,
107- offsetMs: Int ( subtitle. time. total * 1000 )
103+ if !UserDefaults. lyricsOptions. musixmatchRomanizations {
104+ return LyricsDto (
105+ lines: subtitles. map { subtitle in
106+ LyricsLineDto (
107+ content: subtitle. text. lyricsNoteIfEmpty,
108+ offsetMs: Int ( subtitle. time. total * 1000 )
109+ )
110+ } ,
111+ timeSynced: true
112+ )
113+ } else {
114+ do {
115+ let subtitleLang = subtitle [ " subtitle_language " ] as? String ?? " "
116+ let romajiLang = " r \( subtitleLang. prefix ( 1 ) ) "
117+
118+ let romajiData = try perform (
119+ " /ws/1.1/crowd.track.translations.get " ,
120+ query: [
121+ " track_spotify_id " : query. spotifyTrackId,
122+ " selected_language " : romajiLang
123+ ]
108124 )
109- } ,
110- timeSynced: true
111- )
125+
126+ guard
127+ let romajiJson = try ? JSONSerialization . jsonObject ( with: romajiData, options: [ ] ) as? [ String : Any ] ,
128+ let romajiMessage = romajiJson [ " message " ] as? [ String : Any ] ,
129+ let romajiBody = romajiMessage [ " body " ] as? [ String : Any ] ,
130+ let translationsList = romajiBody [ " translations_list " ] as? [ [ String : Any ] ]
131+ else {
132+ throw LyricsError . DecodingError
133+ }
134+
135+ var translationDict : [ String : String ] = [ : ]
136+
137+ for translation in translationsList {
138+ if let translationInfo = translation [ " translation " ] as? [ String : Any ] ,
139+ let translationMatch = translationInfo [ " subtitle_matched_line " ] as? String ,
140+ let translationString = translationInfo [ " description " ] as? String {
141+ if translationMatch != translationString {
142+ translationDict [ translationMatch] = translationString
143+ }
144+
145+ }
146+ }
147+
148+ let modifiedSubtitles = subtitles. map { subtitle in
149+ var modifiedText = subtitle. text
150+ for (translationMatch, translationString) in translationDict {
151+ modifiedText = modifiedText. replacingOccurrences ( of: translationMatch, with: translationString)
152+ }
153+ return MusixmatchSubtitle (
154+ text: modifiedText,
155+ time: subtitle. time
156+ )
157+ }
158+
159+ return LyricsDto (
160+ lines: modifiedSubtitles. map { subtitle in
161+ LyricsLineDto (
162+ content: subtitle. text. lyricsNoteIfEmpty,
163+ offsetMs: Int ( subtitle. time. total * 1000 )
164+ )
165+ } ,
166+ timeSynced: true
167+ )
168+ } catch {
169+ return LyricsDto (
170+ lines: subtitles. map { subtitle in
171+ LyricsLineDto (
172+ content: subtitle. text. lyricsNoteIfEmpty,
173+ offsetMs: Int ( subtitle. time. total * 1000 )
174+ )
175+ } ,
176+ timeSynced: true
177+ )
178+ }
179+ }
112180 }
113181 }
114182 }
@@ -130,13 +198,74 @@ struct MusixmatchLyricsRepository: LyricsRepository {
130198 throw LyricsError . MusixmatchRestricted
131199 }
132200
133- return LyricsDto (
134- lines: plainLyrics
135- . components ( separatedBy: " \n " )
136- . dropLast ( )
137- . map { LyricsLineDto ( content: $0. lyricsNoteIfEmpty) } ,
138- timeSynced: false
139- )
201+ if ( !UserDefaults. lyricsOptions. musixmatchRomanizations) {
202+ return LyricsDto (
203+ lines: plainLyrics
204+ . components ( separatedBy: " \n " )
205+ . dropLast ( )
206+ . map { LyricsLineDto ( content: $0. lyricsNoteIfEmpty) } ,
207+ timeSynced: false
208+ )
209+ } else {
210+ do {
211+ let subtitleLang = lyrics [ " lyrics_language " ] as? String ?? " "
212+ let romajiLang = " r \( subtitleLang. prefix ( 1 ) ) "
213+
214+ let romajiData = try perform (
215+ " /ws/1.1/crowd.track.translations.get " ,
216+ query: [
217+ " track_spotify_id " : query. spotifyTrackId,
218+ " selected_language " : romajiLang
219+ ]
220+ )
221+
222+ guard
223+ let romajiJson = try ? JSONSerialization . jsonObject ( with: romajiData, options: [ ] ) as? [ String : Any ] ,
224+ let romajiMessage = romajiJson [ " message " ] as? [ String : Any ] ,
225+ let romajiBody = romajiMessage [ " body " ] as? [ String : Any ] ,
226+ let translationsList = romajiBody [ " translations_list " ] as? [ [ String : Any ] ]
227+ else {
228+ throw LyricsError . DecodingError
229+ }
230+
231+ var translationDict : [ String : String ] = [ : ]
232+
233+ for translation in translationsList {
234+ if let translationInfo = translation [ " translation " ] as? [ String : Any ] ,
235+ let translationMatch = translationInfo [ " matched_line " ] as? String ,
236+ let translationString = translationInfo [ " description " ] as? String {
237+ if translationMatch != translationString {
238+ translationDict [ translationMatch] = translationString
239+ }
240+
241+ }
242+ }
243+
244+ let modifiedLyrics = plainLyrics
245+ . components ( separatedBy: " \n " )
246+ . dropLast ( )
247+ . map { line in
248+ var modifiedLine = line
249+ for (translationMatch, translationString) in translationDict {
250+ modifiedLine = modifiedLine. replacingOccurrences ( of: translationMatch, with: translationString)
251+ }
252+ return modifiedLine
253+ }
254+
255+ return LyricsDto (
256+ lines: modifiedLyrics. map { LyricsLineDto ( content: $0. lyricsNoteIfEmpty) } ,
257+ timeSynced: false
258+ )
259+ } catch {
260+ return LyricsDto (
261+ lines: plainLyrics
262+ . components ( separatedBy: " \n " )
263+ . dropLast ( )
264+ . map { LyricsLineDto ( content: $0. lyricsNoteIfEmpty) } ,
265+ timeSynced: false
266+ )
267+ }
268+ }
140269 }
141270 }
142271
0 commit comments