Skip to content

Commit

Permalink
better URLSession intercepts/fix #182, lyrics colors options
Browse files Browse the repository at this point in the history
  • Loading branch information
whoeevee committed Jun 10, 2024
1 parent b2411b3 commit a71253a
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 230 deletions.
123 changes: 64 additions & 59 deletions Sources/EeveeSpotify/DataLoaderServiceHooks.x.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,71 @@ class SPTDataLoaderServiceHook: ClassHook<NSObject> {

static let targetName = "SPTDataLoaderService"

// orion:new
func shouldModify(_ url: URL) -> Bool {
let isModifyingCustomizeResponse = UserDefaults.patchType == .requests
return url.isLyrics || (url.isCustomize && isModifyingCustomizeResponse)
}

func URLSession(
_ session: URLSession,
task: URLSessionDataTask,
didCompleteWithError error: Error?
) {
if let url = task.currentRequest?.url {
if url.isLyrics || (UserDefaults.patchType == .requests && url.isCustomize) {
return
guard
let request = task.currentRequest,
let url = request.url
else {
return
}

if error == nil && shouldModify(url) {

if let buffer = URLSessionHelper.shared.obtainData(for: url) {

if url.isLyrics {

do {
orig.URLSession(
session,
dataTask: task,
didReceiveData: try getCurrentTrackLyricsData(
originalLyrics: try? Lyrics(serializedData: buffer)
)
)

orig.URLSession(session, task: task, didCompleteWithError: nil)
}
catch {
orig.URLSession(session, task: task, didCompleteWithError: error)
}

return
}

do {
var customizeMessage = try CustomizeMessage(serializedData: buffer)
modifyRemoteConfiguration(&customizeMessage.response)

orig.URLSession(
session,
dataTask: task,
didReceiveData: try customizeMessage.serializedData()
)

orig.URLSession(session, task: task, didCompleteWithError: nil)

NSLog("[EeveeSpotify] Modified customize data")
return
}
catch {
NSLog("[EeveeSpotify] Unable to modify customize data: \(error)")
}
}
}

orig.URLSession(session, task: task, didCompleteWithError: error)

}

func URLSession(
Expand All @@ -25,7 +79,7 @@ class SPTDataLoaderServiceHook: ClassHook<NSObject> {
completionHandler handler: Any
) {
let url = response.url!

if url.isLyrics, response.statusCode != 200 {

let okResponse = HTTPURLResponse(
Expand All @@ -34,17 +88,17 @@ class SPTDataLoaderServiceHook: ClassHook<NSObject> {
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)
orig.URLSession(session, task: task, didCompleteWithError: nil)

Expand Down Expand Up @@ -73,63 +127,14 @@ class SPTDataLoaderServiceHook: ClassHook<NSObject> {
) {
guard
let request = task.currentRequest,
let response = task.response,
let url = request.url
else {
return
}

if url.isLyrics {

do {
orig.URLSession(
session,
dataTask: task,
didReceiveData: try getCurrentTrackLyricsData(
originalLyrics: try? Lyrics(serializedData: data)
)
)

orig.URLSession(session, task: task, didCompleteWithError: nil)
return
}
catch {
NSLog("[EeveeSpotify] Unable to load lyrics: \(error)")
orig.URLSession(session, task: task, didCompleteWithError: error)

return
}
}

if url.isCustomize && UserDefaults.patchType == .requests {

do {
guard let buffer = OfflineHelper.appendDataAndReturnIfFull(
data,
response: response
) else {
return
}

OfflineHelper.dataBuffer = Data()

var customizeMessage = try CustomizeMessage(serializedData: buffer)
modifyRemoteConfiguration(&customizeMessage.response)

orig.URLSession(
session,
dataTask: task,
didReceiveData: try customizeMessage.serializedData()
)

orig.URLSession(session, task: task, didCompleteWithError: nil)

NSLog("[EeveeSpotify] Modified customize data")
return
}
catch {
NSLog("[EeveeSpotify] Unable to modify customize data: \(error)")
}
if shouldModify(url) {
URLSessionHelper.shared.setOrAppend(data, for: url)
return
}

orig.URLSession(session, dataTask: task, didReceiveData: data)
Expand Down
23 changes: 23 additions & 0 deletions Sources/EeveeSpotify/Helpers/URLSessionHelper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import UIKit

class URLSessionHelper {

static let shared = URLSessionHelper()

private var requestsMap: [URL:Data]

private init() {
self.requestsMap = [:]
}

func setOrAppend(_ data: Data, for url: URL) {
var loadedData = requestsMap[url] ?? Data()
loadedData.append(data)

requestsMap[url] = loadedData
}

func obtainData(for url: URL) -> Data? {
return requestsMap.removeValue(forKey: url)
}
}
51 changes: 33 additions & 18 deletions Sources/EeveeSpotify/Lyrics/CustomLyrics.x.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ class SPTPlayerTrackHook: ClassHook<NSObject> {

static let targetName = "SPTPlayerTrack"

func setMetadata(_ metadata: [String:String]) {
var meta = metadata

func metadata() -> [String:String] {
var meta = orig.metadata()
meta["has_lyrics"] = "true"
orig.setMetadata(meta)
return meta
}
}

Expand All @@ -29,24 +29,24 @@ class EncoreButtonHook: ClassHook<UIButton> {
}

func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {

guard let track = HookedInstances.currentTrack else {
throw LyricsError.NoCurrentTrack
}

var source = UserDefaults.lyricsSource

let plainLyrics: PlainLyrics?

do {
plainLyrics = try LyricsRepository.getLyrics(
title: track.trackTitle(),
artist: track.artistTitle(),
title: track.trackTitle(),
artist: track.artistTitle(),
spotifyTrackId: track.URI().spt_trackIdentifier(),
source: source
)
}

catch let error as LyricsError {

switch error {
Expand All @@ -67,10 +67,10 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
if source == .genius || !UserDefaults.geniusFallback {
throw error
}

NSLog("[EeveeSpotify] Unable to load lyrics from \(source): \(error), trying Genius as fallback")
source = .genius

plainLyrics = try LyricsRepository.getLyrics(
title: track.trackTitle(),
artist: track.artistTitle(),
Expand All @@ -80,13 +80,28 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
}

let lyrics = try Lyrics.with {
$0.colors = originalLyrics?.colors ?? LyricsColors.with {
$0.backgroundColor = Color(hex: track.extractedColorHex()).normalized.uInt32
$0.lineColor = Color.black.uInt32
$0.activeLineColor = Color.white.uInt32
}
$0.colors = getLyricsColors()
$0.data = try LyricsHelper.composeLyricsData(plainLyrics!, source: source)
}

return try lyrics.serializedData()

func getLyricsColors() -> LyricsColors {

let lyricsColorsSettings = UserDefaults.lyricsColors

if lyricsColorsSettings.displayOriginalColors, let originalLyrics = originalLyrics {
return originalLyrics.colors
}

return LyricsColors.with {
$0.backgroundColor = lyricsColorsSettings.useStaticColor
? Color(hex: lyricsColorsSettings.staticColor).uInt32
: Color(hex: track.extractedColorHex())
.normalized(lyricsColorsSettings.normalizationFactor)
.uInt32
$0.lineColor = Color.black.uInt32
$0.activeLineColor = Color.white.uInt32
}
}
}
4 changes: 0 additions & 4 deletions Sources/EeveeSpotify/Lyrics/Helpers/LyricsHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,6 @@ class LyricsHelper {
captures[name] = String(line[substringRange])
}
}

if captures.count != 3 {
return nil
}

let minute = Int(captures["minute"]!)!
let seconds = Float(captures["seconds"]!)!
Expand Down
8 changes: 8 additions & 0 deletions Sources/EeveeSpotify/Lyrics/Models/LyricsColorsSettings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Foundation

struct LyricsColorsSettings: Codable, Equatable {
var displayOriginalColors: Bool
var useStaticColor: Bool
var staticColor: String
var normalizationFactor: CGFloat
}
17 changes: 13 additions & 4 deletions Sources/EeveeSpotify/Models/Extensions/Color+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,19 @@ extension Color {
) / 1000
}

var normalized: Color {
brightness < 0.5
? self.lighter(by: 0.5 - brightness)
: self.darker(by: brightness - 0.5)
func normalized(_ by: CGFloat) -> Color {
brightness < 0.5
? self.lighter(by: max(by - brightness, 0))
: self.darker(by: max(brightness - by, 0))
}

var hexString: String {
String(
format: "%02X%02X%02X",
Int(components.red * 255),
Int(components.green * 255),
Int(components.blue * 255)
)
}

var uInt32: UInt32 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extension UserDefaults {
private static let darkPopUpsKey = "darkPopUps"
private static let patchTypeKey = "patchType"
private static let overwriteConfigurationKey = "overwriteConfiguration"
private static let lyricsColorsKey = "lyricsColors"

static var lyricsSource: LyricsSource {
get {
Expand Down Expand Up @@ -72,4 +73,22 @@ extension UserDefaults {
defaults.set(overwriteConfiguration, forKey: overwriteConfigurationKey)
}
}

static var lyricsColors: LyricsColorsSettings {
get {
if let data = defaults.object(forKey: lyricsColorsKey) as? Data {
return try! JSONDecoder().decode(LyricsColorsSettings.self, from: data)
}

return LyricsColorsSettings(
displayOriginalColors: true,
useStaticColor: false,
staticColor: "",
normalizationFactor: 0.5
)
}
set (lyricsColors) {
defaults.set(try! JSONEncoder().encode(lyricsColors), forKey: lyricsColorsKey)
}
}
}
Loading

0 comments on commit a71253a

Please sign in to comment.