Skip to content

Commit 374df5c

Browse files
committed
Will support LRCLIB
1 parent 1e75962 commit 374df5c

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import Foundation
2+
3+
struct LRCLIBRepsonse: Decodable {
4+
struct LyricLine: Decodable, Hashable {
5+
let startTimeMS: TimeInterval
6+
let words: String
7+
let id = UUID()
8+
9+
enum CodingKeys: String, CodingKey {
10+
case startTimeMS = "startTimeMs"
11+
case words
12+
}
13+
14+
init(from decoder: Decoder) throws {
15+
let container = try decoder.container(keyedBy: CodingKeys.self)
16+
self.startTimeMS = try TimeInterval(container.decode(String.self, forKey: .startTimeMS))!
17+
self.words = try container.decode(String.self, forKey: .words)
18+
}
19+
20+
init(startTime: TimeInterval, words: String) {
21+
self.startTimeMS = startTime
22+
self.words = words
23+
}
24+
}
25+
26+
let id: Int
27+
let name, trackName, artistName, albumName: String
28+
let duration: Int
29+
let instrumental: Bool
30+
let plainLyrics, syncedLyrics: String
31+
let lyrics: [LyricLine]
32+
33+
enum CodingKeys: CodingKey {
34+
case id
35+
case name
36+
case trackName
37+
case artistName
38+
case albumName
39+
case duration
40+
case instrumental
41+
case plainLyrics
42+
case syncedLyrics
43+
// case lyrics
44+
}
45+
46+
static func decodeLyrics(input: String) -> [LyricLine] {
47+
var lyricsArray: [LyricLine] = []
48+
let lines = input.components(separatedBy: "\n")
49+
50+
for line in lines {
51+
// Use regex to match the timestamp and the lyrics
52+
let regex = try! NSRegularExpression(pattern: #"\[(\d{2}:\d{2}\.\d{2})\]\s*(.*)"#)
53+
let matches = regex.matches(in: line, range: NSRange(line.startIndex ..< line.endIndex, in: line))
54+
55+
for match in matches {
56+
if let timestampRange = Range(match.range(at: 1), in: line),
57+
let lyricsRange = Range(match.range(at: 2), in: line) {
58+
let timestamp = String(line[timestampRange])
59+
let lyrics = String(line[lyricsRange])
60+
lyricsArray.append(LyricLine(startTime: timestamp.convertToTimeInterval(), words: lyrics))
61+
}
62+
}
63+
}
64+
65+
return lyricsArray
66+
}
67+
68+
init(from decoder: any Decoder) throws {
69+
let container = try decoder.container(keyedBy: CodingKeys.self)
70+
self.id = try container.decode(Int.self, forKey: .id)
71+
self.name = try container.decode(String.self, forKey: .name)
72+
self.trackName = try container.decode(String.self, forKey: .trackName)
73+
self.artistName = try container.decode(String.self, forKey: .artistName)
74+
self.albumName = try container.decode(String.self, forKey: .albumName)
75+
self.duration = try container.decode(Int.self, forKey: .duration)
76+
self.instrumental = try container.decode(Bool.self, forKey: .instrumental)
77+
if instrumental {
78+
self.plainLyrics = ""
79+
self.syncedLyrics = ""
80+
self.lyrics = []
81+
} else {
82+
self.plainLyrics = try container.decode(String.self, forKey: .plainLyrics)
83+
self.syncedLyrics = try container.decode(String.self, forKey: .syncedLyrics)
84+
self.lyrics = Self.decodeLyrics(input: syncedLyrics)
85+
}
86+
}
87+
}
88+
89+
extension String {
90+
fileprivate func convertToTimeInterval() -> TimeInterval {
91+
guard self != "" else {
92+
return 0
93+
}
94+
95+
var interval: Double = 0
96+
97+
let parts = self.components(separatedBy: ":")
98+
for (index, part) in parts.reversed().enumerated() {
99+
interval += (Double(part) ?? 0) * pow(Double(60), Double(index))
100+
}
101+
102+
return interval * 1000 // Convert seconds to milliseconds
103+
}
104+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import Foundation

Sources/LyricsService/Provider/Service.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ extension LyricsProviders {
1717
case kugou = "Kugou"
1818
case gecimi = "Gecimi"
1919
case syair = "Syair"
20+
case lrclib = "LRCLIB"
2021
}
2122
}
2223

0 commit comments

Comments
 (0)