mirror of
https://github.com/whoeevee/EeveeSpotifyReborn.git
synced 2026-01-09 00:23:20 +01:00
Genius Lyrics (I so like it)
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusApi {
|
||||
|
||||
private static let apiUrl = "https://api.genius.com"
|
||||
|
||||
private static func perform(
|
||||
_ path: String,
|
||||
query: [String:Any] = [:]
|
||||
) throws -> GeniusDataResponse? {
|
||||
|
||||
var stringUrl = "\(apiUrl)\(path)"
|
||||
|
||||
if !query.isEmpty {
|
||||
|
||||
let queryString = query.queryString.addingPercentEncoding(
|
||||
withAllowedCharacters: .urlHostAllowed
|
||||
)!
|
||||
|
||||
stringUrl += "?\(queryString)"
|
||||
}
|
||||
|
||||
var request = URLRequest(url: URL(string: stringUrl)!)
|
||||
request.addValue("6.19.1", forHTTPHeaderField: "X-Genius-iOS-Version")
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
var data: Data?
|
||||
|
||||
let task = URLSession.shared.dataTask(with: request) { response, _, _ in
|
||||
data = response
|
||||
semaphore.signal()
|
||||
}
|
||||
|
||||
task.resume()
|
||||
semaphore.wait()
|
||||
|
||||
let rootResponse = try JSONDecoder().decode(GeniusRootResponse.self, from: data!)
|
||||
return rootResponse.response
|
||||
}
|
||||
|
||||
static func search(_ query: String) throws -> [GeniusHit] {
|
||||
|
||||
let data = try perform("/search", query: ["q": query])
|
||||
|
||||
guard case .hits(let hitsResponse) = data else {
|
||||
throw GeniusLyricsError.DecodingError
|
||||
}
|
||||
|
||||
return hitsResponse.hits
|
||||
}
|
||||
|
||||
static func getSongInfo(_ songId: Int) throws -> GeniusSong {
|
||||
|
||||
let data = try perform("/songs/\(songId)", query: ["text_format": "plain"])
|
||||
|
||||
guard case .song(let songResponse) = data else {
|
||||
throw GeniusLyricsError.DecodingError
|
||||
}
|
||||
|
||||
return songResponse.song
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import Orion
|
||||
import SwiftUI
|
||||
|
||||
class SPTPlayerTrackHook: ClassHook<NSObject> {
|
||||
|
||||
static let targetName = "SPTPlayerTrack"
|
||||
|
||||
func setMetadata(_ metadata: [String:String]) {
|
||||
var meta = metadata
|
||||
|
||||
meta["has_lyrics"] = "true"
|
||||
orig.setMetadata(meta)
|
||||
}
|
||||
}
|
||||
|
||||
class EncoreButtonHook: ClassHook<UIButton> {
|
||||
|
||||
static let targetName = "_TtC12EncoreMobileP33_6EF3A3C098E69FB1E331877B69ACBF8512EncoreButton"
|
||||
|
||||
func intrinsicContentSize() -> CGSize {
|
||||
|
||||
if target.accessibilityIdentifier == "Components.UI.LyricsHeader.ReportButton" {
|
||||
target.isEnabled = false
|
||||
}
|
||||
|
||||
return orig.intrinsicContentSize()
|
||||
}
|
||||
}
|
||||
|
||||
func getCurrentTrackLyricsData() throws -> Data {
|
||||
|
||||
let track = HookedInstances.currentTrack!
|
||||
|
||||
let title = track.trackTitle()
|
||||
.removeMatches("\\(.*\\)")
|
||||
.prefix(30)
|
||||
|
||||
let artist = track.artistTitle()
|
||||
|
||||
let geniusHits = try GeniusApi.search("\(title) \(artist)")
|
||||
|
||||
guard let geniusSong = (
|
||||
geniusHits.first(
|
||||
where: { $0.result.title.containsInsensitive(title) }
|
||||
) ?? geniusHits.first
|
||||
)?.result else {
|
||||
throw GeniusLyricsError.NoSuchSong
|
||||
}
|
||||
|
||||
let geniusSongInfo = try GeniusApi.getSongInfo(geniusSong.id)
|
||||
|
||||
var geniusLyrics = geniusSongInfo.lyrics.plain
|
||||
.components(separatedBy: "\n")
|
||||
.map { $0.trimmingCharacters(in: .whitespaces) }
|
||||
|
||||
geniusLyrics.removeAll { $0.matches("\\[.*\\]") }
|
||||
|
||||
geniusLyrics = Array(
|
||||
geniusLyrics
|
||||
.drop(while: { $0.isEmpty })
|
||||
.dropLast(while: { $0.isEmpty })
|
||||
)
|
||||
|
||||
let lyrics = Lyrics.with {
|
||||
$0.colors = LyricsColors.with {
|
||||
$0.backgroundColor = Color(hex: track.extractedColorHex()).uInt32
|
||||
$0.lineColor = Color.black.uInt32
|
||||
$0.activeLineColor = Color.white.uInt32
|
||||
}
|
||||
$0.data = LyricsData.with {
|
||||
$0.timeSynchronized = false
|
||||
$0.restriction = .unrestricted
|
||||
$0.providedBy = "Genius (EeveeSpotify)"
|
||||
$0.lines = geniusLyrics.map { line in
|
||||
LyricsLine.with { $0.content = line }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return try lyrics.serializedData()
|
||||
}
|
||||
|
||||
class SPTDataLoaderServiceHook: ClassHook<NSObject> {
|
||||
|
||||
static let targetName = "SPTDataLoaderService"
|
||||
|
||||
func URLSession(
|
||||
_ session: URLSession,
|
||||
dataTask task: URLSessionDataTask,
|
||||
didReceiveResponse response: HTTPURLResponse,
|
||||
completionHandler handler: Any
|
||||
) {
|
||||
let url = response.url!
|
||||
|
||||
if url.isLyrics, response.statusCode != 200 {
|
||||
|
||||
let okResponse = HTTPURLResponse(
|
||||
url: url,
|
||||
statusCode: 200,
|
||||
httpVersion: "2.0",
|
||||
headerFields: [:]
|
||||
)!
|
||||
|
||||
do {
|
||||
|
||||
let lyricsData = try getCurrentTrackLyricsData()
|
||||
|
||||
orig.URLSession(
|
||||
session,
|
||||
dataTask: task,
|
||||
didReceiveResponse: okResponse,
|
||||
completionHandler: handler
|
||||
)
|
||||
|
||||
orig.URLSession(
|
||||
session,
|
||||
dataTask: task,
|
||||
didReceiveData: lyricsData
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
catch {
|
||||
NSLog("[EeveeSpotify] Unable to load lyrics: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
orig.URLSession(
|
||||
session,
|
||||
dataTask: task,
|
||||
didReceiveResponse: response,
|
||||
completionHandler: handler
|
||||
)
|
||||
}
|
||||
|
||||
func URLSession(
|
||||
_ session: URLSession,
|
||||
dataTask task: URLSessionDataTask,
|
||||
didReceiveData data: Data
|
||||
) {
|
||||
let request = task.currentRequest!
|
||||
let url = request.url!
|
||||
|
||||
if url.isLyrics {
|
||||
|
||||
do {
|
||||
orig.URLSession(
|
||||
session,
|
||||
dataTask: task,
|
||||
didReceiveData: try getCurrentTrackLyricsData()
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
catch {
|
||||
NSLog("[EeveeSpotify] Unable to load lyrics: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
orig.URLSession(session, dataTask: task, didReceiveData: data)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,22 @@ import Orion
|
||||
|
||||
class HookedInstances {
|
||||
static var productState: SPTCoreProductState?
|
||||
static var currentTrack: SPTPlayerTrack?
|
||||
}
|
||||
|
||||
class SPTNowPlayingContentLayerViewModelHook: ClassHook<NSObject> {
|
||||
|
||||
static let targetName = "SPTNowPlayingContentLayerViewModel"
|
||||
|
||||
func currentTrack() -> SPTPlayerTrack? {
|
||||
|
||||
if let track = orig.currentTrack() {
|
||||
HookedInstances.currentTrack = track
|
||||
return track
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
class SPTCoreProductStateInstanceHook: ClassHook<NSObject> {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import Foundation
|
||||
|
||||
extension Collection {
|
||||
func dropLast(while predicate: (Element) throws -> Bool) rethrows -> SubSequence {
|
||||
guard let index = try indices.reversed().first(where: { try !predicate(self[$0]) }) else {
|
||||
return self[startIndex..<startIndex]
|
||||
}
|
||||
return self[...index]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
extension Color {
|
||||
|
||||
init(hex: String) {
|
||||
|
||||
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
||||
var int: UInt64 = 0
|
||||
Scanner(string: hex).scanHexInt64(&int)
|
||||
let a, r, g, b: UInt64
|
||||
switch hex.count {
|
||||
case 3:
|
||||
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
|
||||
case 6:
|
||||
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
|
||||
case 8:
|
||||
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
|
||||
default:
|
||||
(a, r, g, b) = (1, 1, 1, 0)
|
||||
}
|
||||
|
||||
self.init(
|
||||
.sRGB,
|
||||
red: Double(r) / 255,
|
||||
green: Double(g) / 255,
|
||||
blue: Double(b) / 255,
|
||||
opacity: Double(a) / 255
|
||||
)
|
||||
}
|
||||
|
||||
var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
|
||||
|
||||
typealias NativeColor = UIColor
|
||||
|
||||
var r: CGFloat = 0
|
||||
var g: CGFloat = 0
|
||||
var b: CGFloat = 0
|
||||
var a: CGFloat = 0
|
||||
|
||||
guard NativeColor(self).getRed(&r, green: &g, blue: &b, alpha: &a) else {
|
||||
return (0, 0, 0, 0)
|
||||
}
|
||||
|
||||
return (r, g, b, a)
|
||||
}
|
||||
|
||||
var uInt32: UInt32 {
|
||||
UInt32(components.alpha * 255) << 24
|
||||
| UInt32(components.red * 255) << 16
|
||||
| UInt32(components.green * 255) << 8
|
||||
| UInt32(components.blue * 255)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
extension Dictionary {
|
||||
var queryString: String {
|
||||
return self
|
||||
.compactMap({ (key, value) -> String in
|
||||
return "\(key)=\(value)"
|
||||
})
|
||||
.joined(separator: "&")
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,32 @@
|
||||
import Foundation
|
||||
|
||||
extension String {
|
||||
|
||||
|
||||
static func ~= (lhs: String, rhs: String) -> Bool {
|
||||
guard let regex = try? NSRegularExpression(pattern: rhs) else { return false }
|
||||
let range = NSRange(location: 0, length: lhs.utf16.count)
|
||||
return regex.firstMatch(in: lhs, options: [], range: range) != nil
|
||||
}
|
||||
|
||||
var range: NSRange {
|
||||
NSRange(self.startIndex..., in: self)
|
||||
}
|
||||
|
||||
func containsInsensitive<S: StringProtocol>(_ s: S) -> Bool {
|
||||
self.range(of: s, options: .caseInsensitive) != nil
|
||||
}
|
||||
|
||||
func matches(_ pattern: String) -> Bool {
|
||||
try! NSRegularExpression(pattern: pattern)
|
||||
.firstMatch(in: self, range: self.range) != nil
|
||||
}
|
||||
|
||||
func removeMatches(_ pattern: String) -> String {
|
||||
try! NSRegularExpression(pattern: pattern)
|
||||
.stringByReplacingMatches(
|
||||
in: self,
|
||||
range: self.range,
|
||||
withTemplate: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
extension URL {
|
||||
var isLyrics: Bool {
|
||||
self.path.contains("color-lyrics/v2")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import Foundation
|
||||
|
||||
enum GeniusDataResponse: Decodable {
|
||||
case hits(GeniusHitsResponse)
|
||||
case song(GeniusSongResponse)
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.singleValueContainer()
|
||||
|
||||
if let hits = try? container.decode(GeniusHitsResponse.self) {
|
||||
self = .hits(hits)
|
||||
}
|
||||
else if let song = try? container.decode(GeniusSongResponse.self) {
|
||||
self = .song(song)
|
||||
}
|
||||
else {
|
||||
throw DecodingError.typeMismatch(
|
||||
GeniusDataResponse.self,
|
||||
DecodingError.Context(
|
||||
codingPath: decoder.codingPath,
|
||||
debugDescription: "Invalid data format"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusHit: Decodable {
|
||||
var result: GeniusHitResult
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusHitResult: Decodable {
|
||||
var id: Int
|
||||
var title: String
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusHitsResponse: Decodable {
|
||||
var hits: [GeniusHit]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusLyrics: Decodable {
|
||||
var plain: String
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusRootResponse : Decodable {
|
||||
var response: GeniusDataResponse?
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusSong: Decodable {
|
||||
var lyrics: GeniusLyrics
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import Foundation
|
||||
|
||||
struct GeniusSongResponse: Decodable {
|
||||
var song: GeniusSong
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
enum GeniusLyricsError: Swift.Error {
|
||||
case DecodingError
|
||||
case NoSuchSong
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
@objc protocol SPTPlayerTrack {
|
||||
func setMetadata(_ metadata: [String:String])
|
||||
func extractedColorHex() -> String
|
||||
func trackTitle() -> String
|
||||
func artistTitle() -> String
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
// DO NOT EDIT.
|
||||
// swift-format-ignore-file
|
||||
//
|
||||
// Generated by the Swift generator plugin for the protocol buffer compiler.
|
||||
// Source: lyrics.proto
|
||||
//
|
||||
// For information on using the generated types, please see the documentation:
|
||||
// https://github.com/apple/swift-protobuf/
|
||||
|
||||
import Foundation
|
||||
import SwiftProtobuf
|
||||
|
||||
// If the compiler emits an error on this type, it is because this file
|
||||
// was generated by a version of the `protoc` Swift plug-in that is
|
||||
// incompatible with the version of SwiftProtobuf to which you are linking.
|
||||
// Please ensure that you are building against the same version of the API
|
||||
// that was used to generate this file.
|
||||
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
|
||||
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
|
||||
typealias Version = _2
|
||||
}
|
||||
|
||||
enum LyricsRestriction: SwiftProtobuf.Enum {
|
||||
typealias RawValue = Int
|
||||
case unrestricted // = 0
|
||||
case showLyrics // = 1
|
||||
case showLyricsMonthlyLimit // = 2
|
||||
case monthlyLimitReached // = 3
|
||||
case UNRECOGNIZED(Int)
|
||||
|
||||
init() {
|
||||
self = .unrestricted
|
||||
}
|
||||
|
||||
init?(rawValue: Int) {
|
||||
switch rawValue {
|
||||
case 0: self = .unrestricted
|
||||
case 1: self = .showLyrics
|
||||
case 2: self = .showLyricsMonthlyLimit
|
||||
case 3: self = .monthlyLimitReached
|
||||
default: self = .UNRECOGNIZED(rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
var rawValue: Int {
|
||||
switch self {
|
||||
case .unrestricted: return 0
|
||||
case .showLyrics: return 1
|
||||
case .showLyricsMonthlyLimit: return 2
|
||||
case .monthlyLimitReached: return 3
|
||||
case .UNRECOGNIZED(let i): return i
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
|
||||
extension LyricsRestriction: CaseIterable {
|
||||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static let allCases: [LyricsRestriction] = [
|
||||
.unrestricted,
|
||||
.showLyrics,
|
||||
.showLyricsMonthlyLimit,
|
||||
.monthlyLimitReached,
|
||||
]
|
||||
}
|
||||
|
||||
#endif // swift(>=4.2)
|
||||
|
||||
struct LyricsLine {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var offsetMs: Int32 = 0
|
||||
|
||||
var content: String = String()
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct LyricsColors {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var backgroundColor: UInt32 = 0
|
||||
|
||||
var lineColor: UInt32 = 0
|
||||
|
||||
var activeLineColor: UInt32 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct LyricsData {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var timeSynchronized: Bool = false
|
||||
|
||||
var lines: [LyricsLine] = []
|
||||
|
||||
var providedBy: String = String()
|
||||
|
||||
var restriction: LyricsRestriction = .unrestricted
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct Lyrics {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
var data: LyricsData {
|
||||
get {return _data ?? LyricsData()}
|
||||
set {_data = newValue}
|
||||
}
|
||||
/// Returns true if `data` has been explicitly set.
|
||||
var hasData: Bool {return self._data != nil}
|
||||
/// Clears the value of `data`. Subsequent reads from it will return its default value.
|
||||
mutating func clearData() {self._data = nil}
|
||||
|
||||
var colors: LyricsColors {
|
||||
get {return _colors ?? LyricsColors()}
|
||||
set {_colors = newValue}
|
||||
}
|
||||
/// Returns true if `colors` has been explicitly set.
|
||||
var hasColors: Bool {return self._colors != nil}
|
||||
/// Clears the value of `colors`. Subsequent reads from it will return its default value.
|
||||
mutating func clearColors() {self._colors = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
||||
fileprivate var _data: LyricsData? = nil
|
||||
fileprivate var _colors: LyricsColors? = nil
|
||||
}
|
||||
|
||||
#if swift(>=5.5) && canImport(_Concurrency)
|
||||
extension LyricsRestriction: @unchecked Sendable {}
|
||||
extension LyricsLine: @unchecked Sendable {}
|
||||
extension LyricsColors: @unchecked Sendable {}
|
||||
extension LyricsData: @unchecked Sendable {}
|
||||
extension Lyrics: @unchecked Sendable {}
|
||||
#endif // swift(>=5.5) && canImport(_Concurrency)
|
||||
|
||||
// MARK: - Code below here is support for the SwiftProtobuf runtime.
|
||||
|
||||
extension LyricsRestriction: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "UNRESTRICTED"),
|
||||
1: .same(proto: "SHOW_LYRICS"),
|
||||
2: .same(proto: "SHOW_LYRICS_MONTHLY_LIMIT"),
|
||||
3: .same(proto: "MONTHLY_LIMIT_REACHED"),
|
||||
]
|
||||
}
|
||||
|
||||
extension LyricsLine: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "LyricsLine"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "offsetMs"),
|
||||
2: .same(proto: "content"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularInt32Field(value: &self.offsetMs) }()
|
||||
case 2: try { try decoder.decodeSingularStringField(value: &self.content) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.offsetMs != 0 {
|
||||
try visitor.visitSingularInt32Field(value: self.offsetMs, fieldNumber: 1)
|
||||
}
|
||||
if !self.content.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.content, fieldNumber: 2)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: LyricsLine, rhs: LyricsLine) -> Bool {
|
||||
if lhs.offsetMs != rhs.offsetMs {return false}
|
||||
if lhs.content != rhs.content {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension LyricsColors: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "LyricsColors"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "backgroundColor"),
|
||||
2: .same(proto: "lineColor"),
|
||||
3: .same(proto: "activeLineColor"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularUInt32Field(value: &self.backgroundColor) }()
|
||||
case 2: try { try decoder.decodeSingularUInt32Field(value: &self.lineColor) }()
|
||||
case 3: try { try decoder.decodeSingularUInt32Field(value: &self.activeLineColor) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.backgroundColor != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.backgroundColor, fieldNumber: 1)
|
||||
}
|
||||
if self.lineColor != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.lineColor, fieldNumber: 2)
|
||||
}
|
||||
if self.activeLineColor != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.activeLineColor, fieldNumber: 3)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: LyricsColors, rhs: LyricsColors) -> Bool {
|
||||
if lhs.backgroundColor != rhs.backgroundColor {return false}
|
||||
if lhs.lineColor != rhs.lineColor {return false}
|
||||
if lhs.activeLineColor != rhs.activeLineColor {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension LyricsData: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "LyricsData"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "timeSynchronized"),
|
||||
2: .same(proto: "lines"),
|
||||
5: .same(proto: "providedBy"),
|
||||
14: .same(proto: "restriction"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularBoolField(value: &self.timeSynchronized) }()
|
||||
case 2: try { try decoder.decodeRepeatedMessageField(value: &self.lines) }()
|
||||
case 5: try { try decoder.decodeSingularStringField(value: &self.providedBy) }()
|
||||
case 14: try { try decoder.decodeSingularEnumField(value: &self.restriction) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.timeSynchronized != false {
|
||||
try visitor.visitSingularBoolField(value: self.timeSynchronized, fieldNumber: 1)
|
||||
}
|
||||
if !self.lines.isEmpty {
|
||||
try visitor.visitRepeatedMessageField(value: self.lines, fieldNumber: 2)
|
||||
}
|
||||
if !self.providedBy.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.providedBy, fieldNumber: 5)
|
||||
}
|
||||
if self.restriction != .unrestricted {
|
||||
try visitor.visitSingularEnumField(value: self.restriction, fieldNumber: 14)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: LyricsData, rhs: LyricsData) -> Bool {
|
||||
if lhs.timeSynchronized != rhs.timeSynchronized {return false}
|
||||
if lhs.lines != rhs.lines {return false}
|
||||
if lhs.providedBy != rhs.providedBy {return false}
|
||||
if lhs.restriction != rhs.restriction {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Lyrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = "Lyrics"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "data"),
|
||||
2: .same(proto: "colors"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularMessageField(value: &self._data) }()
|
||||
case 2: try { try decoder.decodeSingularMessageField(value: &self._colors) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
try { if let v = self._data {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
|
||||
} }()
|
||||
try { if let v = self._colors {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Lyrics, rhs: Lyrics) -> Bool {
|
||||
if lhs._data != rhs._data {return false}
|
||||
if lhs._colors != rhs._colors {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user