GithubHelp home page GithubHelp logo

swiftyspot's Introduction

SwiftySpot - Swift Spotify API Library

Swift Package Manager compatible Platform

Spotify API swift implementation

Content

Introduction

The library provides an interface for interacting with the Spotify API

macOS 10.13+ and iOS 11.0+ are supported by the module. Other platforms (watchOS 4.0+, tvOS 11.0+, Windows, Linux, Android) have experimental support

For work with Spotify API need:

  • Active session (client token). Usually the token has a validity period of 14 days. The token is provided when the client passes the challenge. After expiration must be regenerated
  • Authorization: access and refresh tokens. Usually the access token has a validity period of 2 hours. After expiration can be regenerated by refresh token, if exists, or by signing in
  • Access point host (for some endpoints). Can be retrieved with active session

Setup

Swift Package Manager

SwiftySpot is available with SPM

  • Package sources
.package(url: "https://github.com/mIwr/SwiftySpot.git", .from(from: "0.5.3"))
  • Precompiled XCFramework (macOS, iOS, iOS Simulator, watchOS, tvOS): make your own Swift package and import it to the target project
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "MySwiftySpot",
    platforms: [
        .macOS(.v10_13), .iOS(.v11), .tvOS(.v11), .watchOS(.v4)
    ],
    products: [
        .library(name: "SwiftySpot", targets: ["SwiftySpot"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.25.0")
    ],
    targets: [
        .binaryTarget(
            name: "SwiftySpot",
            dependencies: [.product(name: "SwiftProtobuf", package: "swift-protobuf")],
            url: "https://github.com/mIwr/SwiftySpot/releases/download/0.5.3/SwiftySpot.xcframework.zip",
            checksum: "9e7f4e9e78362e7b2ffc9e358e37c9b1abbadfbfde57ea1ae2a4dc28717294fb"
        ),
    ]
)

CocoaPods

SwiftySpot is available with CocoaPods. To install a module, just add to the Podfile:

  • iOS
platform :ios, '11.0'
...
pod 'SwiftySpot'
  • macOS
platform :osx, '10.13'
...
pod 'SwiftySpot'
  • tvOS
platform :tvos, '11.0'
...
pod 'SwiftySpot'
  • watchOS
platform :watchos, '4.0'
...
pod 'SwiftySpot'

Getting started

You can interact with the API through SPClient instance.

Client has 3 states:

  1. Client without session and authorization. The first launch, for example
  2. Client with session and without authorization
  3. Client with session and authorization, including state without access token, but with refresh credential

SPClient manages the session itself: Initializes (client session) or refreshes (client session and auth token) if needed

Client initialization. State 1

import SwiftySpot

let device = SPDevice(os: "osName", osVer: "osVersion", osVerNum: 1, cpuAbi: "32", manufacturer: "brand", model: "model", deviceId: "{8 bytes hex string}")

let client = SPClient(device: device)

Available API method - Authorize with credentials. Client token will be generated automatically before auth process

Client initialization. State 2

import SwiftySpot

let device = SPDevice(os: "osName", osVer: "os version", osVerNum: {os number}, cpuAbi: "32", manufacturer: "brand", model: "model", deviceId: "{8 bytes hex string}")

let clToken = "..."
let clExpires = 3600
let clRefresh = 4800
let clCreateTs = 0

let client = SPClient(device: device, clToken: clToken, clTokenExpires: clExpires, clTokenRefreshAfter: clRefresh, clTokenCreateTsUTC: clCreated)

Available API method - Authorize with credentials

Client initialization. State 3

import SwiftySpot

let device = SPDevice(os: "osName", osVer: "os version", osVerNum: {osNumber}, cpuAbi: "32", manufacturer: "brand", model: "model", deviceId: "{8 bytes hex string}")

let clToken = "..."
let clExpires = 3600
let clRefresh = 4800
let clCreateTs = 0

let authToken = "..."
let authExpires = 7200
let authCreateTs = 0
let username = "..."
let storedCredential = Data()

let client = SPClient(device: device, clToken: clToken, clTokenExpires: clExpires, clTokenRefreshAfter: clRefresh, clTokenCreateTsUTC: clCreated, authToken: authToken, authExpiresInS: authExpires, username: username, storedCred: storedCredential, authTokenCreateTsUTC: authCreateTs)

All API methods are available

Managing metadata

Library has built-in metadata manager. It caches on RAM all artist, album and track metadata, which are requested by API. The manager is initialized with empty storage by default during API client init. You are able to init the manager with start metadata

Metadata provider tips

Metadata from manager can be provided in 3 ways:

  1. Through manager instance search methods: searchTrack(-s), searchArtist(-s), searchAlbum(-s):
let trackNavUri = "spotify:track:123"
let track: SPMetadataTrack? = client.tracksMetaStorage.find(uri: trackNavUri)
  1. Through manager instance properties, which return all available data:
let allAlbumsMeta: [SPMetadataAlbum] = client.albumsMetaStorage.items
  1. Through NotificationCenter update events
Notification.Name Name key Payload type Description
SPArtistMetaUpdate SPArtistMetaUpdate SPMetadataArtist API client received artist meta
SPAlbumMetaUpdate SPAlbumMetaUpdate SPMetadataAlbum API client received album meta
SPPlaylistMetaUpdate SPPlaylistMetaUpdate SPPlaylist API client received playlist meta
SPTrackMetaUpdate SPTrackMetaUpdate SPMetadataTrack API client received track meta
SPLyricsUpdate SPLyricsUpdate SPLyrics API client received lyrics info

Library has notification extension, which provides methods for parsing payload object to API instances:

//notification: Notification
let artistParseRes: (Bool, SPMetadataArtist?) = notifcation.tryParseArtistMetaUpdate()
let albumParseRes: (Bool, SPMetadataAlbum?) = notifcation.tryParseAlbumMetaUpdate()
let plylistParseRes: (Bool, SPPlaylist?) = notifcation.tryParsePlaylistMetaUpdate()
let trackParseRes: (Bool, SPMetadataTrack?) = notifcation.tryParseTrackMetaUpdate()
let lyricsParseRes: (Bool, SPLyrics?) = notifcation.tryParseLyricsUpdate()

The first variable in pair (Bool) is parse status. 'True' value means that the notification has correct name and payload object type

Managing like/dislike collections

Library has built-in like/dislike collection managers. It caches on RAM artist and track likes/dislikes, which are processed by API. The managers are initialized with empty storage by default during API client init. You are able to init the manager with start collection

Also managers save current collection state, which includes:

  • Sync token (Collection update ID)
  • Next page token

Like/Dislike provider tips

Like/Dislike info from manager can be provided 3 ways:

  1. Through manager instance find method
let trackNavUri = "spotify:track:123
let collectionItem: SPCollectionItem? = client.likedTracksStorage.find(uri: trackNavUri)
  1. Through manager instance property, which return all available data ordered by add timestamp:
let allAlbumsMeta: [SPCollectionItem] = client.likedAlbumsStorage.orderedItems
  1. Through NotificationCenter update events
Notification.Name Name key Payload type Description
SPArtistLikeUpdate SPArtistLikeUpdate SPCollectionItem Fires on Like/Dislike op, get collection or update collection by delta API requests
SPArtistDislikeUpdate SPArtistDislikeUpdate SPCollectionItem Fires on Like/Dislike op, get collection or update collection by delta API requests
SPAlbumLikeUpdate SPAlbumLikeUpdate SPCollectionItem Fires on Like/Dislike op, get collection or update collection by delta API requests
SPAlbumDislikeUpdate SPAlbumDislikeUpdate SPCollectionItem Fires on Like/Dislike op, get collection or update collection by delta API requests
SPTrackLikeUpdate SPTrackLikeUpdate SPCollectionItem Fires on Like/Dislike op, get collection or update collection by delta API requests
SPTrackDislikeUpdate SPTrackDislikeUpdate SPCollectionItem Fires on Like/Dislike op, get collection or update collection by delta API requests

Library has notification extension, which provides methods for parsing payload object to API instances:

//notification: Notification
var parseRes: (Bool, SPCollectionItem?) = notifcation.tryParseArtistLikeUpdate()
parseRes = notifcation.tryParseArtistDislikeUpdate()
parseRes = notifcation.tryParseAlbumLikeUpdate()
parseRes = notifcation.tryParseAlbumDislikeUpdate()
parseRes = notifcation.tryParseTrackLikeUpdate()
parseRes = notifcation.tryParseTrackDislikeUpdate()

The first variable in pair (Bool) is parse status. 'True' value means that the notification has correct name and payload object type

Usage examples

Start landing (Dac request)

Spotify Dac object contains screen design info and payload data with playlists. SPClient extracts playlists from response and pushes them to completion handler.

client.getLandingData { result in
    guard let landing = try? result.get() else {return}
    //processing playlists...
}

Get metadata

let uri = SPNavigateUriUtil.generateTrackUri(id: TestConstants.trackId)
client.getTracksDetails(trackUris: [uri]) { result in
    guard let meta = try? result.get() else {return}
    //processing tracks full info...
}

Track metadata also contains codecs download info, which can be used to retrieve direct download link

Track download info

Although each spotify track has many codec variants for download (ogg, mp3, mp4, flac and others), only OGG files can be downloaded (Free - 96, 160 kbps, Premium - 320 kbps)

let fileIdHex = "..."//From track audio file metadata
client.getDownloadInfo(hexFileId: fileIdHex) { result in
    guard let di = try? result.get() else {return}
    //processing track direct download links...
}

App example

An application for iOS (14.0+, SwiftUI) was created for this API. It implements a working minimum: Playlists from dac, displaying playlist tracks, the ability to like or dislike them, display the 'my collection' tracks and search tracks Its source code is publicy available.

swiftyspot's People

Stargazers

Velka avatar ringsaturn avatar Virgil Clyne avatar  avatar

Watchers

 avatar

swiftyspot's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.