mirror of
https://github.com/whoeevee/EeveeSpotifyReborn.git
synced 2026-01-09 00:23:20 +01:00
what i've done so far
This commit is contained in:
1 parent
727fd664ef
commit
92e6cc7900
47 files changed
+298
-271
No files matched your search
@@ -4,9 +4,12 @@ import SwiftUI
|
||||
|
||||
struct DarkPopUps: HookGroup { }
|
||||
|
||||
private let popUpContainerViewController = EeveeSpotify.isOldSpotifyVersion
|
||||
? "SPTEncorePopUpContainer"
|
||||
: "EncoreConsumerMobile_Wrappers.PopUpPresentableContainer"
|
||||
private var popUpContainerViewController: String {
|
||||
switch EeveeSpotify.hookTarget {
|
||||
case .lastAvailableiOS14: return "SPTEncorePopUpContainer"
|
||||
default: return "EncoreConsumerMobile_Wrappers.PopUpPresentableContainer"
|
||||
}
|
||||
}
|
||||
|
||||
class EncoreLabelHook: ClassHook<UIView> {
|
||||
typealias Group = DarkPopUps
|
||||
|
||||
@@ -34,7 +34,7 @@ class SPTDataLoaderServiceHook: ClassHook<NSObject>, SpotifySessionDelegate {
|
||||
orig.URLSession(
|
||||
session,
|
||||
dataTask: task,
|
||||
didReceiveData: try getLyricsForCurrentTrack(
|
||||
didReceiveData: try getLyricsDataForCurrentTrack(
|
||||
originalLyrics: try? Lyrics(serializedBytes: buffer)
|
||||
)
|
||||
)
|
||||
@@ -94,7 +94,7 @@ class SPTDataLoaderServiceHook: ClassHook<NSObject>, SpotifySessionDelegate {
|
||||
)!
|
||||
|
||||
do {
|
||||
let lyricsData = try getLyricsForCurrentTrack()
|
||||
let lyricsData = try getLyricsDataForCurrentTrack()
|
||||
|
||||
orig.URLSession(
|
||||
session,
|
||||
@@ -109,9 +109,7 @@ class SPTDataLoaderServiceHook: ClassHook<NSObject>, SpotifySessionDelegate {
|
||||
return
|
||||
}
|
||||
catch {
|
||||
NSLog("[EeveeSpotify] Unable to load lyrics: \(error)")
|
||||
orig.URLSession(session, task: task, didCompleteWithError: error)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import Orion
|
||||
import UIKit
|
||||
|
||||
class HookedInstances {
|
||||
static var productState: SPTCoreProductState?
|
||||
static var currentTrack: SPTPlayerTrack?
|
||||
static var nowPlayingMetaBackgroundModel: SPTNowPlayingMetadataBackgroundViewModel?
|
||||
}
|
||||
|
||||
class SPTNowPlayingModelHook: ClassHook<NSObject> {
|
||||
static let targetName = "SPTNowPlayingModel"
|
||||
|
||||
func currentTrack() -> SPTPlayerTrack? {
|
||||
if let track = orig.currentTrack() {
|
||||
HookedInstances.currentTrack = track
|
||||
return track
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
class SPTNowPlayingMetadataBackgroundViewModelHook: ClassHook<NSObject> {
|
||||
static let targetName = "SPTNowPlayingMetadataBackgroundViewModel"
|
||||
|
||||
func color() -> UIColor {
|
||||
HookedInstances.nowPlayingMetaBackgroundModel = Dynamic.convert(
|
||||
target,
|
||||
to: SPTNowPlayingMetadataBackgroundViewModel.self
|
||||
)
|
||||
return orig.color()
|
||||
}
|
||||
}
|
||||
|
||||
class SPTCoreProductStateInstanceHook: ClassHook<NSObject> {
|
||||
static let targetName = "SPTCoreProductState"
|
||||
|
||||
func stringForKey(_ key: String) -> NSString {
|
||||
HookedInstances.productState = Dynamic.convert(
|
||||
target,
|
||||
to: SPTCoreProductState.self
|
||||
)
|
||||
return orig.stringForKey(key)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import Orion
|
||||
import UIKit
|
||||
|
||||
class SPTPlayerTrackHook: ClassHook<NSObject> {
|
||||
typealias Group = LyricsGroup
|
||||
static let targetName = "SPTPlayerTrack"
|
||||
|
||||
func metadata() -> [String:String] {
|
||||
func metadata() -> [String: String] {
|
||||
var meta = orig.metadata()
|
||||
|
||||
meta["has_lyrics"] = "true"
|
||||
@@ -14,14 +15,33 @@ class SPTPlayerTrackHook: ClassHook<NSObject> {
|
||||
|
||||
class LyricsScrollProviderHook: ClassHook<NSObject> {
|
||||
typealias Group = LyricsGroup
|
||||
|
||||
static var targetName: String {
|
||||
return EeveeSpotify.isOldSpotifyVersion
|
||||
? "Lyrics_CoreImpl.ScrollProvider"
|
||||
: "Lyrics_NPVCommunicatorImpl.ScrollProvider"
|
||||
}
|
||||
static var targetName = HookTargetNameHelper.lyricsScrollProvider
|
||||
|
||||
func isEnabledForTrack(_ track: SPTPlayerTrack) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class NowPlayingScrollViewControllerHook: ClassHook<NSObject> {
|
||||
typealias Group = LyricsGroup
|
||||
static var targetName = "NowPlaying_ScrollImpl.NowPlayingScrollViewController"
|
||||
|
||||
func nowPlayingScrollViewModelWithDidLoadComponentsFor(
|
||||
_ track: SPTPlayerTrack,
|
||||
withDifferentProviders: Bool,
|
||||
scrollEnabledValueChanged: Bool
|
||||
) -> NowPlayingScrollViewController {
|
||||
var controller = orig.nowPlayingScrollViewModelWithDidLoadComponentsFor(
|
||||
track,
|
||||
withDifferentProviders: withDifferentProviders,
|
||||
scrollEnabledValueChanged: scrollEnabledValueChanged
|
||||
)
|
||||
|
||||
if !scrollEnabledValueChanged {
|
||||
controller.scrollEnabled = true
|
||||
controller.nowPlayingScrollViewModelDidChangeScrollEnabledValue()
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import Orion
|
||||
import UIKit
|
||||
|
||||
class LyricsFullscreenViewControllerHook: ClassHook<UIViewController> {
|
||||
typealias Group = LyricsGroup
|
||||
|
||||
static var targetName: String {
|
||||
switch EeveeSpotify.hookTarget {
|
||||
case .lastAvailableiOS14: return "Lyrics_CoreImpl.FullscreenViewController"
|
||||
default: return "Lyrics_FullscreenPageImpl.FullscreenViewController"
|
||||
}
|
||||
}
|
||||
|
||||
func viewDidLoad() {
|
||||
orig.viewDidLoad()
|
||||
|
||||
if UserDefaults.lyricsSource == .musixmatch
|
||||
&& lyricsState.fallbackError == nil
|
||||
&& !lyricsState.wasRomanized
|
||||
&& !lyricsState.isEmpty {
|
||||
return
|
||||
}
|
||||
|
||||
let headerView = Ivars<UIView>(target.view).headerView
|
||||
|
||||
if let reportButton = headerView.subviews(matching: "EncoreButton")[1] as? UIButton {
|
||||
reportButton.isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import Orion
|
||||
import UIKit
|
||||
|
||||
class LyricsOnlyViewControllerHook: ClassHook<UIViewController> {
|
||||
typealias Group = LyricsGroup
|
||||
|
||||
static var targetName: String {
|
||||
switch EeveeSpotify.hookTarget {
|
||||
case .lastAvailableiOS14: return "Lyrics_CoreImpl.LyricsOnlyViewController"
|
||||
default: return "Lyrics_NPVCommunicatorImpl.LyricsOnlyViewController"
|
||||
}
|
||||
}
|
||||
|
||||
func viewDidLoad() {
|
||||
orig.viewDidLoad()
|
||||
|
||||
guard
|
||||
let lyricsHeaderViewController = target.parent?.children.first
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let lyricsLabel = WindowHelper.shared.findFirstSubview(
|
||||
"SPTEncoreLabel",
|
||||
in: lyricsHeaderViewController.view
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
||||
let encoreLabel = Dynamic.convert(lyricsLabel, to: SPTEncoreLabel.self)
|
||||
|
||||
var text = [
|
||||
encoreLabel.text().firstObject
|
||||
]
|
||||
|
||||
let attributes = Dynamic.SPTEncoreAttributes
|
||||
.alloc(interface: SPTEncoreAttributes.self)
|
||||
.`init`({ attributes in
|
||||
attributes.setForegroundColor(.white.withAlphaComponent(0.5))
|
||||
})
|
||||
|
||||
let typeStyle = type(
|
||||
of: Dynamic[
|
||||
dynamicMember: EeveeSpotify.hookTarget == .lastAvailableiOS14
|
||||
? "SPTEncoreTypeStyle"
|
||||
: "SPTEncoreTextStyle"
|
||||
].alloc(interface: SPTEncoreTypeStyle.self)
|
||||
).bodyMediumBold()
|
||||
|
||||
//
|
||||
|
||||
if UserDefaults.lyricsOptions.showFallbackReasons,
|
||||
let description = lyricsState.fallbackError?.description
|
||||
{
|
||||
let attributedString = Dynamic.SPTEncoreAttributedString.alloc(
|
||||
interface: SPTEncoreAttributedString.self
|
||||
)
|
||||
|
||||
text.append(
|
||||
EeveeSpotify.hookTarget == .lastAvailableiOS14
|
||||
? attributedString.initWithString(
|
||||
"\n\("fallback_attribute".localized): \(description)",
|
||||
typeStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
: attributedString.initWithString(
|
||||
"\n\("fallback_attribute".localized): \(description)",
|
||||
textStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if lyricsState.wasRomanized {
|
||||
let attributedString = Dynamic.SPTEncoreAttributedString.alloc(
|
||||
interface: SPTEncoreAttributedString.self
|
||||
)
|
||||
|
||||
text.append(
|
||||
EeveeSpotify.hookTarget == .lastAvailableiOS14
|
||||
? attributedString.initWithString(
|
||||
"\n\("romanized_attribute".localized)",
|
||||
typeStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
: attributedString.initWithString(
|
||||
"\n\("romanized_attribute".localized)",
|
||||
textStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if EeveeSpotify.hookTarget == .lastAvailableiOS14 {
|
||||
encoreLabel.setNumberOfLines(text.count)
|
||||
}
|
||||
|
||||
encoreLabel.setText(text as NSArray)
|
||||
}
|
||||
}
|
||||
@@ -5,163 +5,24 @@ import SwiftUI
|
||||
|
||||
struct LyricsGroup: HookGroup { }
|
||||
|
||||
//
|
||||
var lyricsState = LyricsLoadingState()
|
||||
|
||||
class LyricsFullscreenViewControllerHook: ClassHook<UIViewController> {
|
||||
typealias Group = LyricsGroup
|
||||
|
||||
static var targetName: String {
|
||||
return EeveeSpotify.isOldSpotifyVersion
|
||||
? "Lyrics_CoreImpl.FullscreenViewController"
|
||||
: "Lyrics_FullscreenPageImpl.FullscreenViewController"
|
||||
}
|
||||
|
||||
func viewDidLoad() {
|
||||
orig.viewDidLoad()
|
||||
|
||||
if UserDefaults.lyricsSource == .musixmatch
|
||||
&& lastLyricsState.fallbackError == nil
|
||||
&& !lastLyricsState.wasRomanized
|
||||
&& !lastLyricsState.areEmpty {
|
||||
return
|
||||
}
|
||||
|
||||
let headerView = Ivars<UIView>(target.view).headerView
|
||||
|
||||
if let reportButton = headerView.subviews(matching: "EncoreButton")[1] as? UIButton {
|
||||
reportButton.isEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
private var preloadedLyrics: Lyrics? = nil
|
||||
private var lastLyricsState = LyricsLoadingState()
|
||||
|
||||
private var hasShownRestrictedPopUp = false
|
||||
private var hasShownUnauthorizedPopUp = false
|
||||
|
||||
//
|
||||
|
||||
class LyricsOnlyViewControllerHook: ClassHook<UIViewController> {
|
||||
typealias Group = LyricsGroup
|
||||
|
||||
static var targetName: String {
|
||||
return EeveeSpotify.isOldSpotifyVersion
|
||||
? "Lyrics_CoreImpl.LyricsOnlyViewController"
|
||||
: "Lyrics_NPVCommunicatorImpl.LyricsOnlyViewController"
|
||||
}
|
||||
|
||||
func viewDidLoad() {
|
||||
orig.viewDidLoad()
|
||||
|
||||
guard
|
||||
let lyricsHeaderViewController = target.parent?.children.first
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
guard let lyricsLabel = WindowHelper.shared.findFirstSubview(
|
||||
"SPTEncoreLabel",
|
||||
in: lyricsHeaderViewController.view
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
let encoreLabel = Dynamic.convert(lyricsLabel, to: SPTEncoreLabel.self)
|
||||
|
||||
var text = [
|
||||
encoreLabel.text().firstObject
|
||||
]
|
||||
|
||||
let attributes = Dynamic.SPTEncoreAttributes
|
||||
.alloc(interface: SPTEncoreAttributes.self)
|
||||
.`init`({ attributes in
|
||||
attributes.setForegroundColor(.white.withAlphaComponent(0.5))
|
||||
})
|
||||
|
||||
let typeStyle = type(
|
||||
of: Dynamic[
|
||||
dynamicMember: EeveeSpotify.isOldSpotifyVersion
|
||||
? "SPTEncoreTypeStyle"
|
||||
: "SPTEncoreTextStyle"
|
||||
].alloc(interface: SPTEncoreTypeStyle.self)
|
||||
).bodyMediumBold()
|
||||
|
||||
//
|
||||
|
||||
if UserDefaults.lyricsOptions.showFallbackReasons,
|
||||
let description = lastLyricsState.fallbackError?.description
|
||||
{
|
||||
let attributedString = Dynamic.SPTEncoreAttributedString.alloc(
|
||||
interface: SPTEncoreAttributedString.self
|
||||
)
|
||||
|
||||
text.append(
|
||||
EeveeSpotify.isOldSpotifyVersion
|
||||
? attributedString.initWithString(
|
||||
"\n\("fallback_attribute".localized): \(description)",
|
||||
typeStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
: attributedString.initWithString(
|
||||
"\n\("fallback_attribute".localized): \(description)",
|
||||
textStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if lastLyricsState.wasRomanized {
|
||||
let attributedString = Dynamic.SPTEncoreAttributedString.alloc(
|
||||
interface: SPTEncoreAttributedString.self
|
||||
)
|
||||
|
||||
text.append(
|
||||
EeveeSpotify.isOldSpotifyVersion
|
||||
? attributedString.initWithString(
|
||||
"\n\("romanized_attribute".localized)",
|
||||
typeStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
: attributedString.initWithString(
|
||||
"\n\("romanized_attribute".localized)",
|
||||
textStyle: typeStyle,
|
||||
attributes: attributes
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if EeveeSpotify.isOldSpotifyVersion {
|
||||
encoreLabel.setNumberOfLines(text.count)
|
||||
}
|
||||
|
||||
encoreLabel.setText(text as NSArray)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
var hasShownRestrictedPopUp = false
|
||||
var hasShownUnauthorizedPopUp = false
|
||||
|
||||
private let geniusLyricsRepository = GeniusLyricsRepository()
|
||||
private let petitLyricsRepository = PetitLyricsRepository()
|
||||
|
||||
//
|
||||
|
||||
private func loadLyricsForCurrentTrack() throws {
|
||||
guard let track = HookedInstances.currentTrack else {
|
||||
private func loadCustomLyricsForCurrentTrack() throws -> Lyrics {
|
||||
guard let track = nowPlayingScrollViewController?.loadedTrack else {
|
||||
throw LyricsError.noCurrentTrack
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
let searchQuery = LyricsSearchQuery(
|
||||
title: track.trackTitle(),
|
||||
primaryArtist: EeveeSpotify.isOldSpotifyVersion
|
||||
primaryArtist: EeveeSpotify.hookTarget == .lastAvailableiOS14
|
||||
? track.artistTitle()
|
||||
: track.artistName(),
|
||||
spotifyTrackId: track.URI().spt_trackIdentifier()
|
||||
@@ -185,20 +46,17 @@ private func loadLyricsForCurrentTrack() throws {
|
||||
case .notReplaced:
|
||||
throw LyricsError.invalidSource
|
||||
}
|
||||
|
||||
|
||||
let lyricsDto: LyricsDto
|
||||
|
||||
//
|
||||
|
||||
lastLyricsState = LyricsLoadingState()
|
||||
lyricsState = LyricsLoadingState()
|
||||
|
||||
do {
|
||||
lyricsDto = try repository.getLyrics(searchQuery, options: options)
|
||||
}
|
||||
catch let error {
|
||||
if let error = error as? LyricsError {
|
||||
lastLyricsState.fallbackError = error
|
||||
lyricsState.fallbackError = error
|
||||
|
||||
switch error {
|
||||
|
||||
@@ -229,50 +87,39 @@ private func loadLyricsForCurrentTrack() throws {
|
||||
}
|
||||
}
|
||||
else {
|
||||
lastLyricsState.fallbackError = .unknownError
|
||||
lyricsState.fallbackError = .unknownError
|
||||
}
|
||||
|
||||
if source == .genius || !UserDefaults.lyricsOptions.geniusFallback {
|
||||
throw error
|
||||
}
|
||||
|
||||
NSLog("[EeveeSpotify] Unable to load lyrics from \(source): \(error), trying Genius as fallback")
|
||||
|
||||
source = .genius
|
||||
repository = GeniusLyricsRepository()
|
||||
|
||||
lyricsDto = try repository.getLyrics(searchQuery, options: options)
|
||||
}
|
||||
|
||||
lastLyricsState.areEmpty = lyricsDto.lines.isEmpty
|
||||
lyricsState.isEmpty = lyricsDto.lines.isEmpty
|
||||
|
||||
lastLyricsState.wasRomanized = lyricsDto.romanization == .romanized
|
||||
lyricsState.wasRomanized = lyricsDto.romanization == .romanized
|
||||
|| (lyricsDto.romanization == .canBeRomanized && UserDefaults.lyricsOptions.romanization)
|
||||
|
||||
lastLyricsState.loadedSuccessfully = true
|
||||
lyricsState.loadedSuccessfully = true
|
||||
|
||||
let lyrics = Lyrics.with {
|
||||
$0.data = lyricsDto.toLyricsData(source: source.description)
|
||||
$0.data = lyricsDto.toSpotifyLyricsData(source: source.description)
|
||||
}
|
||||
|
||||
preloadedLyrics = lyrics
|
||||
return lyrics
|
||||
}
|
||||
|
||||
func getLyricsForCurrentTrack(originalLyrics: Lyrics? = nil) throws -> Data {
|
||||
guard let track = HookedInstances.currentTrack else {
|
||||
func getLyricsDataForCurrentTrack(originalLyrics: Lyrics? = nil) throws -> Data {
|
||||
guard let track = nowPlayingScrollViewController?.loadedTrack else {
|
||||
throw LyricsError.noCurrentTrack
|
||||
}
|
||||
|
||||
var lyrics = preloadedLyrics
|
||||
|
||||
if lyrics == nil {
|
||||
try loadLyricsForCurrentTrack()
|
||||
lyrics = preloadedLyrics
|
||||
}
|
||||
|
||||
guard var lyrics = lyrics else {
|
||||
throw LyricsError.unknownError
|
||||
}
|
||||
var lyrics = try loadCustomLyricsForCurrentTrack()
|
||||
|
||||
let lyricsColorsSettings = UserDefaults.lyricsColors
|
||||
|
||||
@@ -280,30 +127,36 @@ func getLyricsForCurrentTrack(originalLyrics: Lyrics? = nil) throws -> Data {
|
||||
lyrics.colors = originalLyrics.colors
|
||||
}
|
||||
else {
|
||||
var color: Color?
|
||||
let extractedColor = switch EeveeSpotify.hookTarget {
|
||||
case .lastAvailableiOS14:
|
||||
track.extractedColorHex()
|
||||
default:
|
||||
track.metadata()["extracted_color"]
|
||||
}
|
||||
|
||||
let extractedColor = EeveeSpotify.isOldSpotifyVersion
|
||||
? track.extractedColorHex()
|
||||
: track.metadata()["extracted_color"]
|
||||
var color: Color
|
||||
|
||||
if let extractedColor = extractedColor {
|
||||
if lyricsColorsSettings.useStaticColor {
|
||||
color = Color(hex: lyricsColorsSettings.staticColor)
|
||||
}
|
||||
else if let extractedColor = extractedColor {
|
||||
color = Color(hex: extractedColor)
|
||||
.normalized(lyricsColorsSettings.normalizationFactor)
|
||||
}
|
||||
else if let uiColor = HookedInstances.nowPlayingMetaBackgroundModel?.color() {
|
||||
else if let uiColor = nowPlayingScrollViewController?.backgroundViewController.color() {
|
||||
color = Color(uiColor)
|
||||
.normalized(lyricsColorsSettings.normalizationFactor)
|
||||
}
|
||||
else {
|
||||
color = Color.gray
|
||||
}
|
||||
|
||||
color = color?.normalized(lyricsColorsSettings.normalizationFactor)
|
||||
|
||||
lyrics.colors = LyricsColors.with {
|
||||
$0.backgroundColor = lyricsColorsSettings.useStaticColor
|
||||
? Color(hex: lyricsColorsSettings.staticColor).uInt32
|
||||
: color?.uInt32 ?? Color.gray.uInt32
|
||||
$0.backgroundColor = color.uInt32
|
||||
$0.lineColor = Color.black.uInt32
|
||||
$0.activeLineColor = Color.white.uInt32
|
||||
}
|
||||
}
|
||||
|
||||
preloadedLyrics = nil
|
||||
return try lyrics.serializedBytes()
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import Orion
|
||||
|
||||
extension NowPlayingScrollViewController {
|
||||
private var nowPlayingScrollViewModel: NSObject {
|
||||
get {
|
||||
Ivars<NSObject>(self).scrollViewModel
|
||||
}
|
||||
}
|
||||
|
||||
var scrollEnabled: Bool {
|
||||
get {
|
||||
Ivars<Bool>(nowPlayingScrollViewModel).scrollEnabled
|
||||
}
|
||||
set {
|
||||
Ivars<Bool>(nowPlayingScrollViewModel).scrollEnabled = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var loadedTrack: SPTPlayerTrack {
|
||||
get {
|
||||
Ivars<SPTPlayerTrack>(nowPlayingScrollViewModel).loadedTrack
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var backgroundViewController: SPTNowPlayingBackgroundViewController {
|
||||
get {
|
||||
Ivars<SPTNowPlayingBackgroundViewController>(self).backgroundViewController
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import UIKit
|
||||
|
||||
@objc protocol SPTNowPlayingBackgroundViewController {
|
||||
func color() -> UIColor
|
||||
}
|
||||
@@ -6,7 +6,7 @@ struct LyricsDto {
|
||||
var romanization: LyricsRomanizationStatus
|
||||
var translation: LyricsTranslationDto?
|
||||
|
||||
func toLyricsData(source: String) -> LyricsData {
|
||||
func toSpotifyLyricsData(source: String) -> LyricsData {
|
||||
var lyricsData = LyricsData.with {
|
||||
$0.timeSynchronized = timeSynced
|
||||
$0.restriction = .unrestricted
|
||||
|
||||
@@ -2,7 +2,7 @@ import Foundation
|
||||
|
||||
struct LyricsLoadingState {
|
||||
var wasRomanized = false
|
||||
var areEmpty = false
|
||||
var isEmpty = false
|
||||
var fallbackError: LyricsError? = nil
|
||||
var loadedSuccessfully = false
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import Orion
|
||||
import UIKit
|
||||
|
||||
var nowPlayingScrollViewController: NowPlayingScrollViewController?
|
||||
|
||||
class NowPlayingScrollViewControllerInstanceHook: ClassHook<UIViewController> {
|
||||
typealias Group = LyricsGroup
|
||||
static let targetName = "NowPlaying_ScrollImpl.NowPlayingScrollViewController"
|
||||
|
||||
func nowPlayingScrollViewModelWithDidMoveToRelativeTrack(
|
||||
_ track: SPTPlayerTrack,
|
||||
withDifferentProviders: Bool,
|
||||
scrollEnabledValueChanged: Bool
|
||||
) -> NowPlayingScrollViewController {
|
||||
nowPlayingScrollViewController = orig.nowPlayingScrollViewModelWithDidMoveToRelativeTrack(
|
||||
track,
|
||||
withDifferentProviders: withDifferentProviders,
|
||||
scrollEnabledValueChanged: scrollEnabledValueChanged
|
||||
)
|
||||
|
||||
return nowPlayingScrollViewController!
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
@objc protocol SPTCoreProductState {
|
||||
func stringForKey(_ key: String) -> String
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import UIKit
|
||||
|
||||
@objc protocol SPTNowPlayingMetadataBackgroundViewModel {
|
||||
func color() -> UIColor
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
@objc protocol SPTPlayerTrack {
|
||||
func setMetadata(_ metadata: [String:String])
|
||||
func metadata() -> [String:String]
|
||||
func extractedColorHex() -> String?
|
||||
func trackTitle() -> String
|
||||
func artistTitle() -> String
|
||||
func artistName() -> String
|
||||
func URI() -> SPTURL
|
||||
}
|
||||
@@ -10,9 +10,10 @@ private func showHavePremiumPopUp() {
|
||||
|
||||
class SpotifySessionDelegateBootstrapHook: ClassHook<NSObject>, SpotifySessionDelegate {
|
||||
static var targetName: String {
|
||||
EeveeSpotify.isOldSpotifyVersion
|
||||
? "SPTCoreURLSessionDataDelegate"
|
||||
: "SPTDataLoaderService"
|
||||
switch EeveeSpotify.hookTarget {
|
||||
case .lastAvailableiOS14: return "SPTCoreURLSessionDataDelegate"
|
||||
default: return "SPTDataLoaderService"
|
||||
}
|
||||
}
|
||||
|
||||
func URLSession(
|
||||
|
||||
@@ -2,6 +2,8 @@ import Orion
|
||||
import Intents
|
||||
|
||||
class INMediaItemHook: ClassHook<INMediaItem> {
|
||||
typealias Group = PremiumPatchingGroup
|
||||
|
||||
func identifier() -> String {
|
||||
var identifier = orig.identifier()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class SPTFreeTierArtistHubRemoteURLResolverHook: ClassHook<NSObject> {
|
||||
onDemandSet: Any,
|
||||
onDemandTrialService: Any,
|
||||
trackRowsEnabled: Bool,
|
||||
productState: SPTCoreProductState
|
||||
productState: NSObject
|
||||
) -> Target {
|
||||
return orig.initWithViewURI(
|
||||
uri,
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,11 @@
|
||||
import UIKit
|
||||
import Orion
|
||||
|
||||
struct HookTargetNameHelper {
|
||||
static var lyricsScrollProvider: String {
|
||||
switch EeveeSpotify.hookTarget {
|
||||
case .lastAvailableiOS14: return "Lyrics_CoreImpl.ScrollProvider"
|
||||
default: return "Lyrics_NPVCommunicatorImpl.ScrollProvider"
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-1
@@ -2,7 +2,6 @@ import SwiftUI
|
||||
import UIKit
|
||||
|
||||
extension UIColor {
|
||||
|
||||
func mix(with target: UIColor, amount: CGFloat) -> Self {
|
||||
var r1: CGFloat = 0, g1: CGFloat = 0, b1: CGFloat = 0, a1: CGFloat = 0
|
||||
var r2: CGFloat = 0, g2: CGFloat = 0, b2: CGFloat = 0, a2: CGFloat = 0
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,5 @@
|
||||
enum VersionHookTarget {
|
||||
case latest
|
||||
case lastAvailableiOS15
|
||||
case lastAvailableiOS14
|
||||
}
|
||||
@@ -12,8 +12,19 @@ struct PremiumPatchingGroup: HookGroup { }
|
||||
|
||||
struct EeveeSpotify: Tweak {
|
||||
static let version = "5.9.9"
|
||||
static let isOldSpotifyVersion =
|
||||
NSClassFromString("Lyrics_NPVCommunicatorImpl.LyricsOnlyViewController") == nil
|
||||
|
||||
static var hookTarget: VersionHookTarget {
|
||||
let version = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
|
||||
|
||||
switch version {
|
||||
case "9.0.48":
|
||||
return .lastAvailableiOS15
|
||||
case "8.9.8":
|
||||
return .lastAvailableiOS14
|
||||
default:
|
||||
return .latest
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
if UserDefaults.darkPopUps {
|
||||
|
||||
Reference in new issue
Block a user