mirror of
https://github.com/whoeevee/EeveeSpotifyReborn.git
synced 2026-01-09 00:23:20 +01:00
fallback reasons
This commit is contained in:
@@ -28,7 +28,64 @@ class EncoreButtonHook: ClassHook<UIButton> {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private var lastLyricsError: LyricsError? = nil
|
||||
|
||||
private var hasShownRestrictedPopUp = false
|
||||
private var hasShownUnauthorizedPopUp = false
|
||||
|
||||
//
|
||||
|
||||
class LyricsOnlyViewControllerHook: ClassHook<UIViewController> {
|
||||
|
||||
static let targetName = "Lyrics_NPVCommunicatorImpl.LyricsOnlyViewController"
|
||||
|
||||
func viewDidLoad() {
|
||||
|
||||
orig.viewDidLoad()
|
||||
|
||||
if !UserDefaults.fallbackReasons {
|
||||
return
|
||||
}
|
||||
|
||||
guard
|
||||
let lyricsHeaderViewController = target.parent?.children.first,
|
||||
let lyricsLabel = lyricsHeaderViewController.view.subviews.first
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
let encoreLabel = Dynamic.convert(lyricsLabel, to: SPTEncoreLabel.self)
|
||||
|
||||
let attributedString = Dynamic.convert(
|
||||
encoreLabel.text().firstObject as AnyObject,
|
||||
to: SPTEncoreAttributedString.self
|
||||
)
|
||||
|
||||
var text = [attributedString]
|
||||
|
||||
if let description = lastLyricsError?.description {
|
||||
|
||||
let attributes = Dynamic.SPTEncoreAttributes
|
||||
.alloc(interface: SPTEncoreAttributes.self)
|
||||
.`init`({ attributes in
|
||||
attributes.setForegroundColor(.white.withAlphaComponent(0.5))
|
||||
})
|
||||
|
||||
text.append(
|
||||
Dynamic.SPTEncoreAttributedString.alloc(interface: SPTEncoreAttributedString.self)
|
||||
.initWithString(
|
||||
"\nFallback: \(description)",
|
||||
typeStyle: attributedString.typeStyle(),
|
||||
attributes: attributes
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
encoreLabel.setText(text as NSArray)
|
||||
}
|
||||
}
|
||||
|
||||
func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
|
||||
|
||||
@@ -47,20 +104,28 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
|
||||
spotifyTrackId: track.URI().spt_trackIdentifier(),
|
||||
source: source
|
||||
)
|
||||
|
||||
lastLyricsError = nil
|
||||
}
|
||||
|
||||
catch let error as LyricsError {
|
||||
|
||||
lastLyricsError = error
|
||||
|
||||
switch error {
|
||||
|
||||
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. If you use an iPad, you should get the token from the Musixmatch app for iPad.",
|
||||
buttonText: "OK"
|
||||
)
|
||||
break
|
||||
if !hasShownUnauthorizedPopUp {
|
||||
|
||||
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. If you use an iPad, you should get the token from the Musixmatch app for iPad.",
|
||||
buttonText: "OK"
|
||||
)
|
||||
|
||||
hasShownUnauthorizedPopUp.toggle()
|
||||
}
|
||||
|
||||
case .MusixmatchRestricted:
|
||||
|
||||
@@ -75,8 +140,6 @@ func getCurrentTrackLyricsData(originalLyrics: Lyrics? = nil) throws -> Data {
|
||||
hasShownRestrictedPopUp.toggle()
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -68,42 +68,57 @@ struct MusixmatchLyricsDataSource {
|
||||
else {
|
||||
throw LyricsError.DecodingError
|
||||
}
|
||||
|
||||
if let header = message["header"] as? [String: Any],
|
||||
header["status_code"] as? Int == 401 {
|
||||
|
||||
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],
|
||||
let subtitlesBody = subtitlesMessage["body"] as? [String: Any],
|
||||
let subtitlesList = subtitlesBody["subtitle_list"] as? [Any],
|
||||
let firstSubtitle = subtitlesList.first as? [String: Any],
|
||||
let subtitle = firstSubtitle["subtitle"] as? [String: Any] {
|
||||
|
||||
if let restricted = subtitle["restricted"] as? Bool, restricted {
|
||||
throw LyricsError.MusixmatchRestricted
|
||||
let subtitlesMessage = trackSubtitlesGet["message"] as? [String: Any],
|
||||
let subtitlesHeader = subtitlesMessage["header"] as? [String: Any],
|
||||
let subtitlesStatusCode = subtitlesHeader["status_code"] as? Int {
|
||||
|
||||
if subtitlesStatusCode == 404 {
|
||||
throw LyricsError.NoSuchSong
|
||||
}
|
||||
|
||||
if let subtitleBody = subtitle["subtitle_body"] as? String {
|
||||
return PlainLyrics(content: subtitleBody, timeSynced: true)
|
||||
if let subtitlesBody = subtitlesMessage["body"] as? [String: Any],
|
||||
let subtitleList = subtitlesBody["subtitle_list"] as? [[String: Any]],
|
||||
let firstSubtitle = subtitleList.first,
|
||||
let subtitle = firstSubtitle["subtitle"] as? [String: Any] {
|
||||
|
||||
if let restricted = subtitle["restricted"] as? Bool, restricted {
|
||||
throw LyricsError.MusixmatchRestricted
|
||||
}
|
||||
|
||||
if let subtitleBody = subtitle["subtitle_body"] as? String {
|
||||
return PlainLyrics(content: subtitleBody, timeSynced: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard
|
||||
let trackLyricsGet = macroCalls["track.lyrics.get"] as? [String: Any],
|
||||
let lyricsMessage = trackLyricsGet["message"] as? [String: Any],
|
||||
let lyricsBody = lyricsMessage["body"] as? [String: Any],
|
||||
let lyrics = lyricsBody["lyrics"] as? [String: Any],
|
||||
let plainLyrics = lyrics["lyrics_body"] as? String
|
||||
else {
|
||||
throw LyricsError.DecodingError
|
||||
}
|
||||
|
||||
if let restricted = lyrics["restricted"] as? Bool, restricted {
|
||||
throw LyricsError.MusixmatchRestricted
|
||||
if let trackLyricsGet = macroCalls["track.lyrics.get"] as? [String: Any],
|
||||
let lyricsMessage = trackLyricsGet["message"] as? [String: Any],
|
||||
let lyricsHeader = lyricsMessage["header"] as? [String: Any],
|
||||
let lyricsStatusCode = lyricsHeader["status_code"] as? Int {
|
||||
|
||||
if lyricsStatusCode == 404 {
|
||||
throw LyricsError.NoSuchSong
|
||||
}
|
||||
|
||||
if let lyricsBody = lyricsMessage["body"] as? [String: Any],
|
||||
let lyrics = lyricsBody["lyrics"] as? [String: Any],
|
||||
let plainLyrics = lyrics["lyrics_body"] as? String {
|
||||
|
||||
if let restricted = lyrics["restricted"] as? Bool, restricted {
|
||||
throw LyricsError.MusixmatchRestricted
|
||||
}
|
||||
|
||||
return PlainLyrics(content: plainLyrics, timeSynced: false)
|
||||
}
|
||||
}
|
||||
|
||||
return PlainLyrics(content: plainLyrics, timeSynced: false)
|
||||
throw LyricsError.DecodingError
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import Foundation
|
||||
|
||||
enum LyricsError: Error {
|
||||
enum LyricsError: Error, CustomStringConvertible {
|
||||
case NoCurrentTrack
|
||||
case MusixmatchRestricted
|
||||
case InvalidMusixmatchToken
|
||||
case DecodingError
|
||||
case NoSuchSong
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .NoSuchSong: "No Song Found"
|
||||
case .MusixmatchRestricted: "Restricted"
|
||||
case .InvalidMusixmatchToken: "Unauthorized"
|
||||
case .DecodingError: "Decoding Error"
|
||||
case .NoCurrentTrack: "No Track Instance"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ extension UserDefaults {
|
||||
private static let lyricsSourceKey = "lyricsSource"
|
||||
private static let musixmatchTokenKey = "musixmatchToken"
|
||||
private static let geniusFallbackKey = "geniusFallback"
|
||||
private static let fallbackReasonsKey = "fallbackReasons"
|
||||
private static let darkPopUpsKey = "darkPopUps"
|
||||
private static let patchTypeKey = "patchType"
|
||||
private static let overwriteConfigurationKey = "overwriteConfiguration"
|
||||
@@ -42,6 +43,15 @@ extension UserDefaults {
|
||||
defaults.set(fallback, forKey: geniusFallbackKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var fallbackReasons: Bool {
|
||||
get {
|
||||
defaults.object(forKey: fallbackReasonsKey) as? Bool ?? true
|
||||
}
|
||||
set (reasons) {
|
||||
defaults.set(reasons, forKey: fallbackReasonsKey)
|
||||
}
|
||||
}
|
||||
|
||||
static var darkPopUps: Bool {
|
||||
get {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
@objc protocol SPTEncoreAttributedString {
|
||||
func initWithString(_ string: String, typeStyle: Any, attributes: Any) -> SPTEncoreAttributedString
|
||||
func text() -> String
|
||||
func typeStyle() -> Any
|
||||
func attributes() -> SPTEncoreAttributes
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import UIKit
|
||||
|
||||
@objc protocol SPTEncoreAttributes {
|
||||
func `init`(_: (SPTEncoreAttributes) -> Void) -> SPTEncoreAttributes
|
||||
func foregroundColor() -> UIColor
|
||||
func setForegroundColor(_ color: UIColor)
|
||||
}
|
||||
6
Sources/EeveeSpotify/Models/Headers/SPTEncoreLabel.swift
Normal file
6
Sources/EeveeSpotify/Models/Headers/SPTEncoreLabel.swift
Normal file
@@ -0,0 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
@objc protocol SPTEncoreLabel {
|
||||
func text() -> NSArray
|
||||
func setText(_ text: NSArray)
|
||||
}
|
||||
@@ -9,4 +9,4 @@ import Foundation
|
||||
@objc enum ClickState: Int {
|
||||
case primary
|
||||
case secondary
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ import Foundation
|
||||
static func shared() -> SPTEncorePopUpPresenter
|
||||
func presentPopUp(_ popUp: SPTEncorePopUpDialog)
|
||||
func dismissPopupWithAnimate(_ animate: Bool, clearQueue: Bool, completion: Any?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +116,14 @@ If the tweak is unable to find a song or process the lyrics, you'll see a "Could
|
||||
set: { UserDefaults.geniusFallback = $0 }
|
||||
)
|
||||
)
|
||||
|
||||
Toggle(
|
||||
"Show Fallback Reasons",
|
||||
isOn: Binding<Bool>(
|
||||
get: { UserDefaults.fallbackReasons },
|
||||
set: { UserDefaults.fallbackReasons = $0 }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user