Skip to content
Snippets Groups Projects
SpotifyScript.ts 91.2 KiB
Newer Older
//#region constants
    type AlbumResponse,
    type AlbumTracksResponse,
    type ArtistDetails,
    type ArtistMetadataResponse,
    type ContentType,
    type EpisodeMetadataResponse,
    type FileManifestResponse,
    type GetLicenseResponse,
    type LyricsResponse,
    type PlaylistContent,
    type PlaylistContentResponse,
    type PlaylistResponse,
    type PlaylistType,
    type ShowMetadataResponse,
    type Settings,
    type SongMetadataResponse,
    type State,
    type TrackMetadataResponse,
    type Tracks,
    type TranscriptResponse,
    type ProfileAttributesResponse,
    type ChannelType,
    type BrowsePageResponse,
    type GenrePlaylistSection,
    type ChannelTypeCapabilities,
    type FilterGroupIDs,
    type SectionItemAlbum,
    type SectionItemPlaylist,
    type BrowseSectionResponse,
    type Section,
    type BookChaptersResponse,
    type PodcastEpisodesResponse,
    type UserPlaylistsResponse,
    type DiscographyResponse,
    type HomeResponse,
    type HomePlaylistSection,
    type SectionItemEpisode,
    type WhatsNewResponse,
    type WhatsNewSection,
const CONTENT_REGEX = /^https:\/\/open\.spotify\.com\/(track|episode)\/([a-zA-Z0-9]*)($|\/)/
const PLAYLIST_REGEX = /^https:\/\/open\.spotify\.com\/(album|playlist)\/([a-zA-Z0-9]*)($|\/)/
const CHANNEL_REGEX = /^https:\/\/open\.spotify\.com\/(show|artist|user|genre|section|content-feed)\/(section|)([a-zA-Z0-9]*)($|\/)/
const SONG_URL_PREFIX = "https://open.spotify.com/track/" as const
const EPISODE_URL_PREFIX = "https://open.spotify.com/episode/" as const
const SHOW_URL_PREFIX = "https://open.spotify.com/show/" as const
const ARTIST_URL_PREFIX = "https://open.spotify.com/artist/" as const
const USER_URL_PREFIX = "https://open.spotify.com/user/" as const
const ALBUM_URL_PREFIX = "https://open.spotify.com/album/" as const
const PAGE_URL_PREFIX = "https://open.spotify.com/genre/" as const
const SECTION_URL_PREFIX = "https://open.spotify.com/section/" as const
const PLAYLIST_URL_PREFIX = "https://open.spotify.com/playlist/" as const
const QUERY_URL = "https://api-partner.spotify.com/pathfinder/v1/query" as const
const IMAGE_URL_PREFIX = "https://i.scdn.co/image/" as const

const PLATFORM = "Spotify" as const
// const USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0" as const

const HARDCODED_ZERO = 0 as const
const HARDCODED_EMPTY_STRING = "" as const

const local_http = http
// const local_utility = utility

// set missing constants
Type.Order.Chronological = "Latest releases"
Type.Order.Views = "Most played"
Type.Order.Favorites = "Most favorited"

Type.Feed.Playlists = "PLAYLISTS"
Type.Feed.Albums = "ALBUMS"


//#region source methods
source.enable = enable
source.disable = disable
source.saveState = saveState
source.getHome = getHome

// source.searchSuggestions = searchSuggestions
// source.getSearchCapabilities = getSearchCapabilities
// source.search = search

// source.searchChannels = searchChannels
source.isChannelUrl = isChannelUrl
source.getChannel = getChannel
source.getChannelCapabilities = getChannelCapabilities
source.getChannelContents = getChannelContents
// source.getSearchChannelContentsCapabilities = getSearchChannelContentsCapabilities
// source.searchChannelContents = searchChannelContents

source.isContentDetailsUrl = isContentDetailsUrl
source.getContentDetails = getContentDetails

source.isPlaylistUrl = isPlaylistUrl
// source.searchPlaylists = searchPlaylists
source.getPlaylist = getPlaylist

// source.getUserSubscriptions = getUserSubscriptions
// source.getUserPlaylists = getUserPlaylists

/*
if (IS_TESTING) {
    const assert_source: SpotifySource = {
        enable,
        disable,
        saveState,
        getHome,
        searchSuggestions,
        search,
        getSearchCapabilities,
        isContentDetailsUrl,
        getContentDetails,
        isChannelUrl,
        getChannel,
        getChannelContents,
        getChannelCapabilities,
        searchChannelContents,
        getSearchChannelContentsCapabilities,
        searchChannels,
        getComments,
        getSubComments,
        isPlaylistUrl,
        getPlaylist,
        searchPlaylists,
        getLiveChatWindow,
        getUserPlaylists,
        getUserSubscriptions
    }
    if (source.enable === undefined) { assert_never(source.enable) }
    if (source.disable === undefined) { assert_never(source.disable) }
    if (source.saveState === undefined) { assert_never(source.saveState) }
    if (source.getHome === undefined) { assert_never(source.getHome) }
    if (source.searchSuggestions === undefined) { assert_never(source.searchSuggestions) }
    if (source.search === undefined) { assert_never(source.search) }
    if (source.getSearchCapabilities === undefined) { assert_never(source.getSearchCapabilities) }
    if (source.isContentDetailsUrl === undefined) { assert_never(source.isContentDetailsUrl) }
    if (source.getContentDetails === undefined) { assert_never(source.getContentDetails) }
    if (source.isChannelUrl === undefined) { assert_never(source.isChannelUrl) }
    if (source.getChannel === undefined) { assert_never(source.getChannel) }
    if (source.getChannelContents === undefined) { assert_never(source.getChannelContents) }
    if (source.getChannelCapabilities === undefined) { assert_never(source.getChannelCapabilities) }
    if (source.searchChannelContents === undefined) { assert_never(source.searchChannelContents) }
    if (source.getSearchChannelContentsCapabilities === undefined) { assert_never(source.getSearchChannelContentsCapabilities) }
    if (source.searchChannels === undefined) { assert_never(source.searchChannels) }
    if (source.getComments === undefined) { assert_never(source.getComments) }
    if (source.getSubComments === undefined) { assert_never(source.getSubComments) }
    if (source.isPlaylistUrl === undefined) { assert_never(source.isPlaylistUrl) }
    if (source.getPlaylist === undefined) { assert_never(source.getPlaylist) }
    if (source.searchPlaylists === undefined) { assert_never(source.searchPlaylists) }
    if (source.getLiveChatWindow === undefined) { assert_never(source.getLiveChatWindow) }
    if (source.getUserPlaylists === undefined) { assert_never(source.getUserPlaylists) }
    if (source.getUserSubscriptions === undefined) { assert_never(source.getUserSubscriptions) }
    if (IS_TESTING) {
        log(assert_source)
    }
}
*/
//#region enable
function enable(conf: SourceConfig, settings: Settings, savedState: string | null) {
    if (IS_TESTING) {
        log("IS_TESTING true")
        log("logging configuration")
        log(conf)
        log("logging settings")
        log(settings)
        log("logging savedState")
        log(savedState)
    }
    if (savedState !== null) {
        const state: State = JSON.parse(savedState)
        local_state = state
        // the token stored in state might be old
        check_and_update_token()
        const { token_response, user_data } = download_bearer_token()
        const bearer_token = token_response.accessToken

        // download license uri and get logged in user
        const get_license_url_url = "https://gue1-spclient.spotify.com/melody/v1/license_url?keysystem=com.widevine.alpha&sdk_name=harmony&sdk_version=4.41.0"
        const profile_attributes_url = "https://api-partner.spotify.com/pathfinder/v1/query?operationName=profileAttributes&variables=%7B%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%2253bcb064f6cd18c23f752bc324a791194d20df612d8e1239c735144ab0399ced%22%7D%7D"
        const responses = local_http
            .batch()
            .GET(
                get_license_url_url,
                { Authorization: `Bearer ${bearer_token}` },
                false
            )
            .GET(
                profile_attributes_url,
                { Authorization: `Bearer ${bearer_token}` },
Loading
Loading full blame...