|
| 1 | +import Regex |
| 2 | +import CXShim |
| 3 | +import Foundation |
| 4 | +import LyricsCore |
| 5 | +import CXExtensions |
| 6 | + |
| 7 | +struct SpotifyAccessToken: Codable { |
| 8 | + let accessToken: String |
| 9 | + let accessTokenExpirationTimestampMs: TimeInterval |
| 10 | + let isAnonymous: Bool |
| 11 | +} |
| 12 | + |
| 13 | +struct SpotifyResponse: Codable { |
| 14 | + struct Tracks: Codable { |
| 15 | + struct Item: Codable { |
| 16 | + let type: String |
| 17 | + let id: String |
| 18 | + } |
| 19 | + |
| 20 | + let items: [Item] |
| 21 | + } |
| 22 | + |
| 23 | + let tracks: Tracks |
| 24 | +} |
| 25 | + |
| 26 | +extension LyricsProviders { |
| 27 | + final class Spotify: _LyricsProvider { |
| 28 | + typealias LyricsToken = SpotifyResponse.Tracks.Item |
| 29 | + |
| 30 | + let accessToken: String |
| 31 | + let fakeSpotifyUserAgentconfig = URLSessionConfiguration.default |
| 32 | + let fakeSpotifyUserAgentSession: URLSession |
| 33 | + init(accessToken: String) { |
| 34 | + self.accessToken = accessToken |
| 35 | + fakeSpotifyUserAgentconfig.httpAdditionalHeaders = ["User-Agent": "Spotify/121000760 Win32/0 (PC laptop)"] |
| 36 | + fakeSpotifyUserAgentSession = URLSession(configuration: fakeSpotifyUserAgentconfig) |
| 37 | + } |
| 38 | + } |
| 39 | +} |
| 40 | + |
| 41 | +extension LyricsProviders.Spotify { |
| 42 | + static var service: LyricsProviders.Service? = .spotify |
| 43 | + |
| 44 | + func lyricsSearchPublisher(request: LyricsSearchRequest) -> AnyPublisher<LyricsToken, Never> { |
| 45 | + let url: URL |
| 46 | + switch request.searchTerm { |
| 47 | + case let .keyword(string): |
| 48 | + url = URL(string: "https://api.spotify.com/v1/search?q=track:\(string)+&type=track&limit=10")! |
| 49 | + case let .info(title, artist): |
| 50 | + url = URL(string: "https://api.spotify.com/v1/search?q=track:\(title)+artist:\(artist)+&type=track&limit=10")! |
| 51 | + } |
| 52 | + |
| 53 | + var req = URLRequest(url: url) |
| 54 | + req.addValue("WebPlayer", forHTTPHeaderField: "app-platform") |
| 55 | + req.addValue("Bearer \(accessToken)", forHTTPHeaderField: "authorization") |
| 56 | + return sharedURLSession.cx.dataTaskPublisher(for: req) |
| 57 | + .map(\.data) |
| 58 | + .decode(type: SpotifyResponse.self, decoder: JSONDecoder().cx) |
| 59 | + .map(\.tracks.items) |
| 60 | + .replaceError(with: []) |
| 61 | + .flatMap(Publishers.Sequence.init) |
| 62 | + .map { $0 as LyricsToken } |
| 63 | + .eraseToAnyPublisher() |
| 64 | + } |
| 65 | + |
| 66 | + func lyricsFetchPublisher(token: LyricsToken) -> AnyPublisher<Lyrics, Never> { |
| 67 | +// let url = URL(string: "https://spclient.wg.spotify.com/color-lyrics/v2/track/\(token.id)?format=json&vocalRemoval=false")! |
| 68 | +// var request = URLRequest(url: url) |
| 69 | +// request.addValue("WebPlayer", forHTTPHeaderField: "app-platform") |
| 70 | +// request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "authorization") |
| 71 | +// |
| 72 | +// return fakeSpotifyUserAgentSession.dataTaskPublisher(for: request) |
| 73 | +// .map { |
| 74 | +// |
| 75 | +// } |
| 76 | +// .ignoreOutput() |
| 77 | +// .eraseToAnyPublisher() |
| 78 | +// |
| 79 | +// let songObject = try decoder.decode(SongObjectParent.self, from: urlResponseAndData.0) |
| 80 | +// print("downloaded from internet successfully \(trackID) \(trackName)") |
| 81 | +// saveCoreData() |
| 82 | +// let lyricsArray = zip(songObject.lyrics.lyricsTimestamps, songObject.lyrics.lyricsWords).map { LyricLine(startTime: $0, words: $1) } |
| 83 | + fatalError() |
| 84 | + } |
| 85 | +} |
0 commit comments