Files
aris-old/IrisCompanion/iris/Spotify/SpotifyModels.swift
christophergyman 11ee893367 Add Spotify integration with toggleable music source
- Add OAuth 2.0 PKCE authentication for Spotify Web API
- Create SpotifyNowPlayingMonitor for polling current track
- Add Settings tab with music source toggle (Apple Music/Spotify)
- Store tokens securely in Keychain
- Display current track on Glass as NOW_PLAYING card

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 20:27:37 +00:00

92 lines
1.9 KiB
Swift

//
// SpotifyModels.swift
// iris
//
// Codable models for Spotify Web API responses.
//
import Foundation
struct SpotifyTokens: Codable {
let accessToken: String
let refreshToken: String
let expiresAt: Date
enum CodingKeys: String, CodingKey {
case accessToken = "access_token"
case refreshToken = "refresh_token"
case expiresAt = "expires_at"
}
var isExpired: Bool {
Date() >= expiresAt
}
var expiresWithinMinutes: Bool {
Date().addingTimeInterval(5 * 60) >= expiresAt
}
}
struct SpotifyTokenResponse: Codable {
let accessToken: String
let tokenType: String
let expiresIn: Int
let refreshToken: String?
let scope: String?
enum CodingKeys: String, CodingKey {
case accessToken = "access_token"
case tokenType = "token_type"
case expiresIn = "expires_in"
case refreshToken = "refresh_token"
case scope
}
}
struct SpotifyPlaybackState: Codable {
let isPlaying: Bool
let progressMs: Int?
let item: SpotifyTrack?
enum CodingKeys: String, CodingKey {
case isPlaying = "is_playing"
case progressMs = "progress_ms"
case item
}
}
struct SpotifyTrack: Codable {
let id: String
let name: String
let artists: [SpotifyArtist]
let album: SpotifyAlbum
let durationMs: Int
enum CodingKeys: String, CodingKey {
case id, name, artists, album
case durationMs = "duration_ms"
}
}
struct SpotifyArtist: Codable {
let id: String
let name: String
}
struct SpotifyAlbum: Codable {
let id: String
let name: String
}
enum MusicSource: String, CaseIterable, Codable {
case appleMusic = "apple_music"
case spotify = "spotify"
var displayName: String {
switch self {
case .appleMusic: return "Apple Music"
case .spotify: return "Spotify"
}
}
}