Musixmatch Invalid Token Alert, better token input, Overwrite Configuration Option

This commit is contained in:
eevee
2024-06-05 01:17:16 +03:00
parent e258ebc35b
commit 3c5509ea53
12 changed files with 145 additions and 48 deletions
@@ -47,23 +47,36 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
)
}
catch {
if source != .genius && UserDefaults.geniusFallback {
catch let error as LyricsError {
switch 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(),
spotifyTrackId: track.URI().spt_trackIdentifier(),
source: source
case .InvalidMusixmatchToken:
PopUpHelper.showPopUp(
delayed: false,
message: "The tweak is unable to load lyrics from Musixmatch due to Unauthorized error. Please check or update your Musixmatch token.",
buttonText: "OK"
)
break
default:
break
}
else {
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(),
spotifyTrackId: track.URI().spt_trackIdentifier(),
source: source
)
}
let lyrics = try Lyrics.with {
@@ -65,6 +65,11 @@ struct MusixmatchLyricsDataSource {
else {
throw LyricsError.DecodingError
}
if let header = message["header"] as? [String: Any],
header["status_code"] as? Int == 401 {
throw LyricsError.InvalidMusixmatchToken
}
if let trackSubtitlesGet = macroCalls["track.subtitles.get"] as? [String: Any],
let subtitlesMessage = trackSubtitlesGet["message"] as? [String: Any],
@@ -2,6 +2,7 @@ import Foundation
enum LyricsError: Swift.Error {
case NoCurrentTrack
case InvalidMusixmatchToken
case DecodingError
case NoSuchSong
}
}
@@ -44,4 +44,19 @@ extension String {
withTemplate: ""
)
}
var hexadecimal: Data? {
var data = Data(capacity: count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, range: NSRange(startIndex..., in: self)) { match, _, _ in
let byteString = (self as NSString).substring(with: match!.range)
let num = UInt8(byteString, radix: 16)!
data.append(num)
}
guard data.count > 0 else { return nil }
return data
}
}
@@ -9,6 +9,7 @@ extension UserDefaults {
private static let geniusFallbackKey = "geniusFallback"
private static let darkPopUpsKey = "darkPopUps"
private static let patchTypeKey = "patchType"
private static let overwriteConfigurationKey = "overwriteConfiguration"
static var lyricsSource: LyricsSource {
get {
@@ -62,4 +63,13 @@ extension UserDefaults {
defaults.set(patchType.rawValue, forKey: patchTypeKey)
}
}
static var overwriteConfiguration: Bool {
get {
defaults.bool(forKey: overwriteConfigurationKey)
}
set (overwriteConfiguration) {
defaults.set(overwriteConfiguration, forKey: overwriteConfigurationKey)
}
}
}
@@ -1,6 +1,11 @@
import Foundation
func modifyRemoteConfiguration(_ configuration: inout UcsResponse) {
if UserDefaults.overwriteConfiguration {
configuration.resolve.configuration = try! BundleHelper.shared.resolveConfiguration()
}
modifyAttributes(&configuration.attributes.accountAttributes)
}
@@ -62,6 +62,19 @@ class SPTCoreURLSessionDataDelegateHook: ClassHook<NSObject> {
var bootstrapMessage = try BootstrapMessage(serializedData: buffer)
if UserDefaults.patchType == .notSet {
if bootstrapMessage.attributes["type"]?.stringValue == "premium" {
UserDefaults.patchType = .disabled
showHavePremiumPopUp()
}
else {
UserDefaults.patchType = .requests
}
NSLog("[EeveeSpotify] Fetched bootstrap, \(UserDefaults.patchType) was set")
}
if UserDefaults.patchType == .requests {
modifyRemoteConfiguration(&bootstrapMessage.ucsResponse)
@@ -75,21 +88,6 @@ class SPTCoreURLSessionDataDelegateHook: ClassHook<NSObject> {
NSLog("[EeveeSpotify] Modified bootstrap data")
}
else {
if UserDefaults.patchType == .notSet {
if bootstrapMessage.attributes["type"]?.stringValue == "premium" {
UserDefaults.patchType = .disabled
showHavePremiumPopUp()
}
else {
UserDefaults.patchType = .offlineBnk
showOfflineBnkMethodSetPopUp()
}
NSLog("[EeveeSpotify] Fetched bootstrap, \(UserDefaults.patchType) was set")
}
orig.URLSession(session, dataTask: task, didReceiveData: buffer)
}
@@ -26,4 +26,15 @@ class BundleHelper {
)!
)
}
func resolveConfiguration() throws -> ResolveConfiguration {
return try ResolveConfiguration(
serializedData: try Data(
contentsOf: self.bundle.url(
forResource: "resolveconfiguration",
withExtension: "bnk"
)!
)
)
}
}
@@ -2,7 +2,7 @@ import SwiftUI
extension EeveeSettingsView {
@ViewBuilder func PremiumSection() -> some View {
@ViewBuilder func PremiumSections() -> some View {
Section(footer: patchType == .disabled ? nil : Text("""
You can select the Premium patching method you prefer. App restart is required after changing.
@@ -17,7 +17,7 @@ If you have an active Premium subscription, you can turn on Do Not Patch Premium
"Do Not Patch Premium",
isOn: Binding<Bool>(
get: { patchType == .disabled },
set: { patchType = $0 ? .disabled : .offlineBnk }
set: { patchType = $0 ? .disabled : .requests }
)
)
@@ -31,5 +31,16 @@ If you have an active Premium subscription, you can turn on Do Not Patch Premium
}
}
}
if patchType == .requests {
Section(
footer: Text("Replace remote configuration with the dumped Premium one. It might fix some issues, such as appearing ads, but it's not guaranteed.")
) {
Toggle(
"Overwrite Configuration",
isOn: $overwriteConfiguration
)
}
}
}
}
@@ -6,6 +6,20 @@ struct EeveeSettingsView: View {
@State var musixmatchToken = UserDefaults.musixmatchToken
@State var patchType = UserDefaults.patchType
@State var lyricsSource = UserDefaults.lyricsSource
@State var overwriteConfiguration = UserDefaults.overwriteConfiguration
private func getMusixmatchToken(_ input: String) -> String? {
if let match = input.firstMatch("\\[UserToken\\]: ([a-f0-9]+)"),
let tokenRange = Range(match.range(at: 1), in: input) {
return String(input[tokenRange])
}
else if input ~= "^[a-f0-9]+$" {
return input
}
return nil
}
private func showMusixmatchTokenAlert(_ oldSource: LyricsSource) {
@@ -25,16 +39,8 @@ struct EeveeSettingsView: View {
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in
let text = alert.textFields!.first!.text!
let token: String
if let match = text.firstMatch("\\[UserToken\\]: ([a-f0-9]+)"),
let tokenRange = Range(match.range(at: 1), in: text) {
token = String(text[tokenRange])
}
else if text ~= "^[a-f0-9]+$" {
token = text
}
else {
guard let token = getMusixmatchToken(text) else {
lyricsSource = oldSource
return
}
@@ -50,7 +56,7 @@ struct EeveeSettingsView: View {
List {
PremiumSection()
PremiumSections()
LyricsSections()
@@ -73,14 +79,26 @@ struct EeveeSettingsView: View {
}
}
}
.padding(.bottom, 45)
.listStyle(GroupedListStyle())
.padding(.bottom, 60)
.ignoresSafeArea(.keyboard)
.animation(.default, value: lyricsSource)
.animation(.default, value: patchType)
.onChange(of: musixmatchToken) { token in
UserDefaults.musixmatchToken = token
.onChange(of: musixmatchToken) { input in
if input.isEmpty { return }
if let token = getMusixmatchToken(input) {
UserDefaults.musixmatchToken = token
self.musixmatchToken = token
}
else {
self.musixmatchToken = ""
}
}
.onChange(of: lyricsSource) { [lyricsSource] newSource in
@@ -104,8 +122,18 @@ struct EeveeSettingsView: View {
NSLog("Unable to reset offline.bnk: \(error)")
}
}
.listStyle(GroupedListStyle())
.onChange(of: overwriteConfiguration) { overwriteConfiguration in
UserDefaults.overwriteConfiguration = overwriteConfiguration
do {
try OfflineHelper.resetOfflineBnk()
}
catch {
NSLog("Unable to reset offline.bnk: \(error)")
}
}
.onAppear {
UIView.appearance(
@@ -30,7 +30,7 @@ If the tweak is unable to find a song or process the lyrics, you'll see a "Could
Text("Musixmatch User Token")
TextField("Enter User Token", text: $musixmatchToken)
TextField("Enter User Token or Paste Debug Info", text: $musixmatchToken)
.foregroundColor(.gray)
}
.frame(maxWidth: .infinity, alignment: .leading)