mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Wraps accounts.spotify.com login in a WKWebView so users can sign in without opening the browser inspector to copy the sp_dc cookie. The sheet uses a non-persistent data store, observes the cookie store, and hands the captured value to the existing SpotifyAuthManager.validate flow on a match. Spotify's anti-bot blocks the WebView path for some accounts, so this sits alongside (not replaces) the manual paste field, with an "Open in Browser" escape hatch in the sheet toolbar. Signed-off-by: Jis G Jacob <studiokeys@blissroms.org>
129 lines
5.1 KiB
Swift
129 lines
5.1 KiB
Swift
/*
|
|
* Atoll (DynamicIsland)
|
|
* Copyright (C) 2024-2026 Atoll Contributors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import AppKit
|
|
import Defaults
|
|
import SwiftUI
|
|
|
|
struct SpotifyAuthSettingsSection: View {
|
|
@Default(.spotifySPDCCookie) private var spotifySPDCCookie
|
|
@ObservedObject private var spotifyAuthManager = SpotifyAuthManager.shared
|
|
@State private var showingLoginSheet = false
|
|
|
|
private var hasCookie: Bool {
|
|
!SpotifyAuthManager.sanitizeCookie(spotifySPDCCookie).isEmpty
|
|
}
|
|
|
|
var body: some View {
|
|
Section {
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
Text("Sign in to Spotify to capture the `sp_dc` cookie automatically, or paste it in below.")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
|
|
Button {
|
|
showingLoginSheet = true
|
|
} label: {
|
|
Label("Sign in with Spotify", systemImage: "person.crop.circle.badge.checkmark")
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
|
|
TextField("sp_dc cookie", text: $spotifySPDCCookie, axis: .vertical)
|
|
.textFieldStyle(.roundedBorder)
|
|
.font(.caption.monospaced())
|
|
.lineLimit(2...4)
|
|
.textSelection(.enabled)
|
|
}
|
|
|
|
HStack(spacing: 10) {
|
|
Circle()
|
|
.fill(spotifyAuthManager.isAuthenticated ? Color.green : (hasCookie ? Color.orange : Color.secondary))
|
|
.frame(width: 8, height: 8)
|
|
|
|
Text(spotifyAuthManager.sessionStatusText)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
|
|
if let authErrorMessage = spotifyAuthManager.authErrorMessage, !authErrorMessage.isEmpty {
|
|
Text(authErrorMessage)
|
|
.font(.caption)
|
|
.foregroundStyle(.red)
|
|
}
|
|
|
|
HStack {
|
|
Button("Paste from Clipboard") {
|
|
pasteCookieFromClipboard()
|
|
}
|
|
|
|
Button(spotifyAuthManager.isAuthorizing ? "Validating..." : "Validate Cookie") {
|
|
spotifySPDCCookie = SpotifyAuthManager.sanitizeCookie(spotifySPDCCookie)
|
|
Task {
|
|
await spotifyAuthManager.validateSession()
|
|
}
|
|
}
|
|
.disabled(!hasCookie || spotifyAuthManager.isAuthorizing)
|
|
|
|
Button("Clear") {
|
|
spotifySPDCCookie = ""
|
|
spotifyAuthManager.clearSession()
|
|
}
|
|
.disabled(!hasCookie && !spotifyAuthManager.isAuthenticated)
|
|
}
|
|
|
|
DisclosureGroup("Get the cookie manually") {
|
|
VStack(alignment: .leading, spacing: 6) {
|
|
Text("1. Open Spotify in a browser and log in")
|
|
.font(.caption)
|
|
Text("2. Developer Tools -> Application/Storage -> Cookies -> https://open.spotify.com")
|
|
.font(.caption)
|
|
Text("3. Copy the value of `sp_dc` and paste it here")
|
|
.font(.caption)
|
|
|
|
HStack(spacing: 12) {
|
|
Link("Open Spotify Web Player", destination: URL(string: "https://open.spotify.com")!)
|
|
Link("Method source", destination: URL(string: "https://github.com/Paxsenix0/Spotify-Canvas-API")!)
|
|
}
|
|
.font(.caption)
|
|
}
|
|
.padding(.top, 4)
|
|
}
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
} header: {
|
|
Text("Spotify Canvas Session")
|
|
} footer: {
|
|
Text("Atoll uses the local `sp_dc` cookie only to request Spotify's internal web-player token and fetch the matching Canvas for the current track.")
|
|
.foregroundStyle(.secondary)
|
|
.font(.caption)
|
|
}
|
|
.sheet(isPresented: $showingLoginSheet) {
|
|
SpotifyLoginSheet { capturedValue in
|
|
let sanitized = SpotifyAuthManager.sanitizeCookie(capturedValue)
|
|
spotifySPDCCookie = sanitized
|
|
Task {
|
|
await spotifyAuthManager.validateSession()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func pasteCookieFromClipboard() {
|
|
guard let clipboardText = NSPasteboard.general.string(forType: .string) else { return }
|
|
spotifySPDCCookie = SpotifyAuthManager.sanitizeCookie(clipboardText)
|
|
}
|
|
}
|