playlist endpoint
This commit is contained in:
parent
4893de0d28
commit
7a3d74dc87
11 changed files with 111 additions and 663 deletions
|
@ -32,11 +32,11 @@ after configuring, it's just as easy as running `npm run build` and running the
|
||||||
|
|
||||||
a system module is provided for your convenience, and the main output is `nixosModules.default`
|
a system module is provided for your convenience, and the main output is `nixosModules.default`
|
||||||
|
|
||||||
after importing this module, the option `services.amdl` will show up, which is documented in [`flake.nix`](./flake.nix) somewhat well. everything under the `config` tree follows the `config.toml` well, along with everything under the `env` tree. defaults are provided for everything that isn't the private keys and client ids inside of the env section. make sure to set those!!
|
after importing this module, the option `services.amdl` will show up, which is documented in [`flake.nix`](./flake.nix) somewhat well. everything under the `config` tree follows the `config.toml` well, along with everything under the `env` tree. defaults are provided for everything that isn't the ITUA inside of the env section. make sure to set those!!
|
||||||
|
|
||||||
## limitations / the formats
|
## limitations / the formats
|
||||||
|
|
||||||
currently you can only get basic widevine ones, everything related to playready and fairplay encryption methods are not supported, sorry!! someday i will get this working, at least for playready. it's just that no one has written a library yet but has for python (yuck!!)
|
currently you can only get basic widevine ones, everything related to playready and fairplay encryption methods are not supported, sorry!! someday i will get this working, at least for playready. it's just that no one has written a library yet but has for python (yuck!!) lossless audio is unfortunately out of the question currently. it will be a while till someone breaks fairplay drm
|
||||||
|
|
||||||
guaranteed formats to work include:
|
guaranteed formats to work include:
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 769 B |
|
@ -1,6 +1,6 @@
|
||||||
import axios, { type AxiosInstance } from "axios";
|
import axios, { type AxiosInstance } from "axios";
|
||||||
import { ampApiUrl, appleMusicHomepageUrl, licenseApiUrl, webplaybackApiUrl } from "../constants/urls.js";
|
import { ampApiUrl, appleMusicHomepageUrl, licenseApiUrl, webplaybackApiUrl } from "../constants/urls.js";
|
||||||
import type { GetSongResponse, SearchResponse } from "./types/responses.js";
|
import type { GetPlaylistResponse, GetSongResponse, SearchResponse } from "./types/responses.js";
|
||||||
import type { AlbumAttributesExtensionTypes, AnyAttributesExtensionTypes, SongAttributesExtensionTypes } from "./types/extensions.js";
|
import type { AlbumAttributesExtensionTypes, AnyAttributesExtensionTypes, SongAttributesExtensionTypes } from "./types/extensions.js";
|
||||||
import { getToken } from "./token.js";
|
import { getToken } from "./token.js";
|
||||||
import { config, env } from "../config.js";
|
import { config, env } from "../config.js";
|
||||||
|
@ -50,9 +50,29 @@ export default class AppleMusicApi {
|
||||||
})).data;
|
})).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make it so you can get more than the first 100 tracks
|
||||||
|
// you can't since it's entirely undocumented
|
||||||
|
// and the "trivial" way simply throws a 400, which is awesome
|
||||||
|
async getPlaylist<
|
||||||
|
T extends SongAttributesExtensionTypes = [],
|
||||||
|
U extends RelationshipTypes<T> = ["tracks"]
|
||||||
|
> (
|
||||||
|
id: string,
|
||||||
|
extend: T = [] as never as T,
|
||||||
|
relationships: U = ["tracks"] as U
|
||||||
|
): Promise<GetPlaylistResponse<T, U>> {
|
||||||
|
return (await this.http.get<GetPlaylistResponse<T, U>>(`/v1/catalog/${this.storefront}/playlists/${id}`, {
|
||||||
|
params: {
|
||||||
|
extend: extend.join(","),
|
||||||
|
include: relationships.join(",")
|
||||||
|
}
|
||||||
|
})).data;
|
||||||
|
}
|
||||||
|
|
||||||
async getSong<
|
async getSong<
|
||||||
// TODO: possibly make this any, and use the addScopingParameters function?
|
// TODO: possibly make this any, and use the addScopingParameters function?
|
||||||
// would be a bit cleaner, almost everywhere, use above in `getAlbum` perchancibly
|
// would be a bit cleaner, almost everywhere, use above in `getAlbum` perchancibly
|
||||||
|
// and `getPlaylst`.... maybe just rewrite the whole thing at this point,, scoping parameters are my OPP
|
||||||
T extends SongAttributesExtensionTypes = ["extendedAssetUrls"],
|
T extends SongAttributesExtensionTypes = ["extendedAssetUrls"],
|
||||||
U extends RelationshipTypes<T> = ["albums"]
|
U extends RelationshipTypes<T> = ["albums"]
|
||||||
> (
|
> (
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { Artwork, EditorialNotes, PlayParameters, Preview } from "./extras.js";
|
import type { Artwork, DescriptionAttribute, EditorialNotes, PlayParameters, Preview } from "./extras.js";
|
||||||
import type {
|
import type {
|
||||||
AlbumAttributesExtensionMap, AlbumAttributesExtensionTypes,
|
AlbumAttributesExtensionMap, AlbumAttributesExtensionTypes,
|
||||||
|
PlaylistAttributesExtensionMap, PlaylistAttributesExtensionTypes,
|
||||||
SongAttributesExtensionMap, SongAttributesExtensionTypes
|
SongAttributesExtensionMap, SongAttributesExtensionTypes
|
||||||
} from "./extensions.js";
|
} from "./extensions.js";
|
||||||
|
|
||||||
|
@ -27,6 +28,21 @@ export type AlbumAttributes<
|
||||||
}
|
}
|
||||||
& Pick<AlbumAttributesExtensionMap, T[number]>
|
& Pick<AlbumAttributesExtensionMap, T[number]>
|
||||||
|
|
||||||
|
export type PlaylistAttributes<
|
||||||
|
T extends PlaylistAttributesExtensionTypes,
|
||||||
|
> = {
|
||||||
|
artwork?: Artwork
|
||||||
|
curatorName: string
|
||||||
|
description?: DescriptionAttribute,
|
||||||
|
isChart: boolean,
|
||||||
|
lastModifiedDate?: string
|
||||||
|
name: string
|
||||||
|
playlistType: string
|
||||||
|
playParams?: PlayParameters
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
& Pick<PlaylistAttributesExtensionMap, T[number]>
|
||||||
|
|
||||||
export type SongAttributes<
|
export type SongAttributes<
|
||||||
T extends SongAttributesExtensionTypes,
|
T extends SongAttributesExtensionTypes,
|
||||||
> = {
|
> = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export type AnyAttributesExtensionType = AlbumAttributesExtensionType | SongAttributesExtensionType;
|
export type AnyAttributesExtensionType = AlbumAttributesExtensionType | PlaylistAttributesExtensionType | SongAttributesExtensionType;
|
||||||
export type AnyAttributesExtensionTypes = AnyAttributesExtensionType[];
|
export type AnyAttributesExtensionTypes = AnyAttributesExtensionType[];
|
||||||
|
|
||||||
export type AlbumAttributesExtensionType = keyof AlbumAttributesExtensionMap;
|
export type AlbumAttributesExtensionType = keyof AlbumAttributesExtensionMap;
|
||||||
|
@ -8,6 +8,12 @@ export type AlbumAttributesExtensionMap = {
|
||||||
audioVariants?: string[]
|
audioVariants?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PlaylistAttributesExtensionType = keyof PlaylistAttributesExtensionMap;
|
||||||
|
export type PlaylistAttributesExtensionTypes = PlaylistAttributesExtensionType[];
|
||||||
|
export type PlaylistAttributesExtensionMap = {
|
||||||
|
trackTypes: string[]
|
||||||
|
}
|
||||||
|
|
||||||
export type SongAttributesExtensionType = keyof SongAttributesExtensionMap;
|
export type SongAttributesExtensionType = keyof SongAttributesExtensionMap;
|
||||||
export type SongAttributesExtensionTypes = SongAttributesExtensionType[];
|
export type SongAttributesExtensionTypes = SongAttributesExtensionType[];
|
||||||
export type SongAttributesExtensionMap = {
|
export type SongAttributesExtensionMap = {
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
// https://developer.apple.com/documentation/applemusicapi/descriptionattribute
|
||||||
|
export interface DescriptionAttribute {
|
||||||
|
short?: string
|
||||||
|
standard: string
|
||||||
|
}
|
||||||
|
|
||||||
// https://developer.apple.com/documentation/applemusicapi/artwork
|
// https://developer.apple.com/documentation/applemusicapi/artwork
|
||||||
export interface Artwork {
|
export interface Artwork {
|
||||||
bgColor?: string
|
bgColor?: string
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// you will shit yourself if you don't read this:
|
// you will shit yourself if you don't read this:
|
||||||
// required reading: https://developer.apple.com/documentation/applemusicapi/handling-resource-representation-and-relationships
|
// required reading: https://developer.apple.com/documentation/applemusicapi/handling-resource-representation-and-relationships
|
||||||
|
|
||||||
import type { AlbumAttributes, SongAttributes } from "./attributes.js";
|
import type { AlbumAttributes, PlaylistAttributes, SongAttributes } from "./attributes.js";
|
||||||
import type { AlbumAttributesExtensionTypes, AnyAttributesExtensionTypes, SongAttributesExtensionTypes } from "./extensions.js";
|
import type { AlbumAttributesExtensionTypes, AnyAttributesExtensionTypes, PlaylistAttributesExtensionTypes, SongAttributesExtensionTypes } from "./extensions.js";
|
||||||
|
|
||||||
// TODO: have something like this for every resource
|
// TODO: have something like this for every resource
|
||||||
export type Relationship<T> = {
|
export type Relationship<T> = {
|
||||||
|
@ -11,7 +11,7 @@ export type Relationship<T> = {
|
||||||
data: {
|
data: {
|
||||||
// TODO: there is extra types here (id, type, etc) i just can't cba to add them lol
|
// TODO: there is extra types here (id, type, etc) i just can't cba to add them lol
|
||||||
// probably not important ! ahahahah
|
// probably not important ! ahahahah
|
||||||
// seems to be the same basic "resource" pattern i'm starting to notice (id(?), href, type, meta, etc)
|
// seems to be the same basic "resource" pattern i'm starting to notice (id(?), href, type, meta (not included), etc)
|
||||||
attributes: T
|
attributes: T
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,8 @@ export type RelationshipType<T extends AnyAttributesExtensionTypes> = keyof Rela
|
||||||
export type RelationshipTypes<T extends AnyAttributesExtensionTypes> = RelationshipType<T>[];
|
export type RelationshipTypes<T extends AnyAttributesExtensionTypes> = RelationshipType<T>[];
|
||||||
export type RelationshipTypeMap<T extends AnyAttributesExtensionTypes> = {
|
export type RelationshipTypeMap<T extends AnyAttributesExtensionTypes> = {
|
||||||
albums: AlbumAttributes<Extract<T, AlbumAttributesExtensionTypes>>,
|
albums: AlbumAttributes<Extract<T, AlbumAttributesExtensionTypes>>,
|
||||||
tracks: SongAttributes<Extract<T, SongAttributesExtensionTypes>> // TODO: tracks can also be music videos, uh oh.
|
// TODO: from what i can tell, playlists can NOT be used as a relationship type? kept in case
|
||||||
|
playlists: PlaylistAttributes<Extract<T, PlaylistAttributesExtensionTypes>>,
|
||||||
|
// TODO: tracks can also be music videos, uh oh.
|
||||||
|
tracks: SongAttributes<Extract<T, SongAttributesExtensionTypes>>
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,27 @@ export interface GetAlbumResponse<
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://developer.apple.com/documentation/applemusicapi/get-a-catalog-playlist
|
||||||
|
export interface GetPlaylistResponse<
|
||||||
|
T extends SongAttributesExtensionTypes,
|
||||||
|
U extends RelationshipTypes<T>
|
||||||
|
> {
|
||||||
|
// https://developer.apple.com/documentation/applemusicapi/playlists
|
||||||
|
data: {
|
||||||
|
id: string
|
||||||
|
type: "playlists"
|
||||||
|
href: string
|
||||||
|
// https://developer.apple.com/documentation/applemusicapi/playlists/attributes-data.dictionary
|
||||||
|
attributes: SongAttributes<T>
|
||||||
|
// https://developer.apple.com/documentation/applemusicapi/playlists/relationships-data.dictionary
|
||||||
|
relationships: {
|
||||||
|
[K in U[number]]: Relationship<
|
||||||
|
K extends RelationshipType<T> ? RelationshipTypeMap<T>[K] : never
|
||||||
|
>
|
||||||
|
}
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
// https://developer.apple.com/documentation/applemusicapi/get-a-catalog-song
|
// https://developer.apple.com/documentation/applemusicapi/get-a-catalog-song
|
||||||
export interface GetSongResponse<
|
export interface GetSongResponse<
|
||||||
T extends SongAttributesExtensionTypes,
|
T extends SongAttributesExtensionTypes,
|
||||||
|
|
|
@ -1,654 +0,0 @@
|
||||||
// thank u goat
|
|
||||||
// https://gist.github.com/BrychanOdlum/2208578ba151d1d7c4edeeda15b4e9b1
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
"name": "Algeria",
|
|
||||||
"code": "DZ",
|
|
||||||
"storefrontId": 143563
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Angola",
|
|
||||||
"code": "AO",
|
|
||||||
"storefrontId": 143564
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Anguilla",
|
|
||||||
"code": "AI",
|
|
||||||
"storefrontId": 143538
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Antigua & Barbuda",
|
|
||||||
"code": "AG",
|
|
||||||
"storefrontId": 143540
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Argentina",
|
|
||||||
"code": "AR",
|
|
||||||
"storefrontId": 143505
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Armenia",
|
|
||||||
"code": "AM",
|
|
||||||
"storefrontId": 143524
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Australia",
|
|
||||||
"code": "AU",
|
|
||||||
"storefrontId": 143460
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Austria",
|
|
||||||
"code": "AT",
|
|
||||||
"storefrontId": 143445
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Azerbaijan",
|
|
||||||
"code": "AZ",
|
|
||||||
"storefrontId": 143568
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Bahrain",
|
|
||||||
"code": "BH",
|
|
||||||
"storefrontId": 143559
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Bangladesh",
|
|
||||||
"code": "BD",
|
|
||||||
"storefrontId": 143490
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Barbados",
|
|
||||||
"code": "BB",
|
|
||||||
"storefrontId": 143541
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Belarus",
|
|
||||||
"code": "BY",
|
|
||||||
"storefrontId": 143565
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Belgium",
|
|
||||||
"code": "BE",
|
|
||||||
"storefrontId": 143446
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Belize",
|
|
||||||
"code": "BZ",
|
|
||||||
"storefrontId": 143555
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Bermuda",
|
|
||||||
"code": "BM",
|
|
||||||
"storefrontId": 143542
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Bolivia",
|
|
||||||
"code": "BO",
|
|
||||||
"storefrontId": 143556
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Botswana",
|
|
||||||
"code": "BW",
|
|
||||||
"storefrontId": 143525
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Brazil",
|
|
||||||
"code": "BR",
|
|
||||||
"storefrontId": 143503
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "British Virgin Islands",
|
|
||||||
"code": "VG",
|
|
||||||
"storefrontId": 143543
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Brunei",
|
|
||||||
"code": "BN",
|
|
||||||
"storefrontId": 143560
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Bulgaria",
|
|
||||||
"code": "BG",
|
|
||||||
"storefrontId": 143526
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Canada",
|
|
||||||
"code": "CA",
|
|
||||||
"storefrontId": 143455
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Cayman Islands",
|
|
||||||
"code": "KY",
|
|
||||||
"storefrontId": 143544
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Chile",
|
|
||||||
"code": "CL",
|
|
||||||
"storefrontId": 143483
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "China",
|
|
||||||
"code": "CN",
|
|
||||||
"storefrontId": 143465
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Colombia",
|
|
||||||
"code": "CO",
|
|
||||||
"storefrontId": 143501
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Costa Rica",
|
|
||||||
"code": "CR",
|
|
||||||
"storefrontId": 143495
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Cote D’Ivoire",
|
|
||||||
"code": "CI",
|
|
||||||
"storefrontId": 143527
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Croatia",
|
|
||||||
"code": "HR",
|
|
||||||
"storefrontId": 143494
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Cyprus",
|
|
||||||
"code": "CY",
|
|
||||||
"storefrontId": 143557
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Czech Republic",
|
|
||||||
"code": "CZ",
|
|
||||||
"storefrontId": 143489
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Denmark",
|
|
||||||
"code": "DK",
|
|
||||||
"storefrontId": 143458
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Dominica",
|
|
||||||
"code": "DM",
|
|
||||||
"storefrontId": 143545
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Dominican Rep.",
|
|
||||||
"code": "DO",
|
|
||||||
"storefrontId": 143508
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ecuador",
|
|
||||||
"code": "EC",
|
|
||||||
"storefrontId": 143509
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Egypt",
|
|
||||||
"code": "EG",
|
|
||||||
"storefrontId": 143516
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "El Salvador",
|
|
||||||
"code": "SV",
|
|
||||||
"storefrontId": 143506
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Estonia",
|
|
||||||
"code": "EE",
|
|
||||||
"storefrontId": 143518
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Finland",
|
|
||||||
"code": "FI",
|
|
||||||
"storefrontId": 143447
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "France",
|
|
||||||
"code": "FR",
|
|
||||||
"storefrontId": 143442
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Germany",
|
|
||||||
"code": "DE",
|
|
||||||
"storefrontId": 143443
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ghana",
|
|
||||||
"code": "GH",
|
|
||||||
"storefrontId": 143573
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Greece",
|
|
||||||
"code": "GR",
|
|
||||||
"storefrontId": 143448
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Grenada",
|
|
||||||
"code": "GD",
|
|
||||||
"storefrontId": 143546
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Guatemala",
|
|
||||||
"code": "GT",
|
|
||||||
"storefrontId": 143504
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Guyana",
|
|
||||||
"code": "GY",
|
|
||||||
"storefrontId": 143553
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Honduras",
|
|
||||||
"code": "HN",
|
|
||||||
"storefrontId": 143510
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Hong Kong",
|
|
||||||
"code": "HK",
|
|
||||||
"storefrontId": 143463
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Hungary",
|
|
||||||
"code": "HU",
|
|
||||||
"storefrontId": 143482
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Iceland",
|
|
||||||
"code": "IS",
|
|
||||||
"storefrontId": 143558
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "India",
|
|
||||||
"code": "IN",
|
|
||||||
"storefrontId": 143467
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Indonesia",
|
|
||||||
"code": "ID",
|
|
||||||
"storefrontId": 143476
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ireland",
|
|
||||||
"code": "IE",
|
|
||||||
"storefrontId": 143449
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Israel",
|
|
||||||
"code": "IL",
|
|
||||||
"storefrontId": 143491
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Italy",
|
|
||||||
"code": "IT",
|
|
||||||
"storefrontId": 143450
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jamaica",
|
|
||||||
"code": "JM",
|
|
||||||
"storefrontId": 143511
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Japan",
|
|
||||||
"code": "JP",
|
|
||||||
"storefrontId": 143462
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Jordan",
|
|
||||||
"code": "JO",
|
|
||||||
"storefrontId": 143528
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Kazakstan",
|
|
||||||
"code": "KZ",
|
|
||||||
"storefrontId": 143517
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Kenya",
|
|
||||||
"code": "KE",
|
|
||||||
"storefrontId": 143529
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Korea, Republic Of",
|
|
||||||
"code": "KR",
|
|
||||||
"storefrontId": 143466
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Kuwait",
|
|
||||||
"code": "KW",
|
|
||||||
"storefrontId": 143493
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Latvia",
|
|
||||||
"code": "LV",
|
|
||||||
"storefrontId": 143519
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Lebanon",
|
|
||||||
"code": "LB",
|
|
||||||
"storefrontId": 143497
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Liechtenstein",
|
|
||||||
"code": "LI",
|
|
||||||
"storefrontId": 143522
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Lithuania",
|
|
||||||
"code": "LT",
|
|
||||||
"storefrontId": 143520
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Luxembourg",
|
|
||||||
"code": "LU",
|
|
||||||
"storefrontId": 143451
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Macau",
|
|
||||||
"code": "MO",
|
|
||||||
"storefrontId": 143515
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Macedonia",
|
|
||||||
"code": "MK",
|
|
||||||
"storefrontId": 143530
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Madagascar",
|
|
||||||
"code": "MG",
|
|
||||||
"storefrontId": 143531
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Malaysia",
|
|
||||||
"code": "MY",
|
|
||||||
"storefrontId": 143473
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Maldives",
|
|
||||||
"code": "MV",
|
|
||||||
"storefrontId": 143488
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mali",
|
|
||||||
"code": "ML",
|
|
||||||
"storefrontId": 143532
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Malta",
|
|
||||||
"code": "MT",
|
|
||||||
"storefrontId": 143521
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mauritius",
|
|
||||||
"code": "MU",
|
|
||||||
"storefrontId": 143533
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mexico",
|
|
||||||
"code": "MX",
|
|
||||||
"storefrontId": 143468
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Moldova, Republic Of",
|
|
||||||
"code": "MD",
|
|
||||||
"storefrontId": 143523
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Montserrat",
|
|
||||||
"code": "MS",
|
|
||||||
"storefrontId": 143547
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Nepal",
|
|
||||||
"code": "NP",
|
|
||||||
"storefrontId": 143484
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Netherlands",
|
|
||||||
"code": "NL",
|
|
||||||
"storefrontId": 143452
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "New Zealand",
|
|
||||||
"code": "NZ",
|
|
||||||
"storefrontId": 143461
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Nicaragua",
|
|
||||||
"code": "NI",
|
|
||||||
"storefrontId": 143512
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Niger",
|
|
||||||
"code": "NE",
|
|
||||||
"storefrontId": 143534
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Nigeria",
|
|
||||||
"code": "NG",
|
|
||||||
"storefrontId": 143561
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Norway",
|
|
||||||
"code": "NO",
|
|
||||||
"storefrontId": 143457
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Oman",
|
|
||||||
"code": "OM",
|
|
||||||
"storefrontId": 143562
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Pakistan",
|
|
||||||
"code": "PK",
|
|
||||||
"storefrontId": 143477
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Panama",
|
|
||||||
"code": "PA",
|
|
||||||
"storefrontId": 143485
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Paraguay",
|
|
||||||
"code": "PY",
|
|
||||||
"storefrontId": 143513
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Peru",
|
|
||||||
"code": "PE",
|
|
||||||
"storefrontId": 143507
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Philippines",
|
|
||||||
"code": "PH",
|
|
||||||
"storefrontId": 143474
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Poland",
|
|
||||||
"code": "PL",
|
|
||||||
"storefrontId": 143478
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Portugal",
|
|
||||||
"code": "PT",
|
|
||||||
"storefrontId": 143453
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Qatar",
|
|
||||||
"code": "QA",
|
|
||||||
"storefrontId": 143498
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Romania",
|
|
||||||
"code": "RO",
|
|
||||||
"storefrontId": 143487
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Russia",
|
|
||||||
"code": "RU",
|
|
||||||
"storefrontId": 143469
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Saudi Arabia",
|
|
||||||
"code": "SA",
|
|
||||||
"storefrontId": 143479
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Senegal",
|
|
||||||
"code": "SN",
|
|
||||||
"storefrontId": 143535
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Serbia",
|
|
||||||
"code": "RS",
|
|
||||||
"storefrontId": 143500
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Singapore",
|
|
||||||
"code": "SG",
|
|
||||||
"storefrontId": 143464
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Slovakia",
|
|
||||||
"code": "SK",
|
|
||||||
"storefrontId": 143496
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Slovenia",
|
|
||||||
"code": "SI",
|
|
||||||
"storefrontId": 143499
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "South Africa",
|
|
||||||
"code": "ZA",
|
|
||||||
"storefrontId": 143472
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Spain",
|
|
||||||
"code": "ES",
|
|
||||||
"storefrontId": 143454
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Sri Lanka",
|
|
||||||
"code": "LK",
|
|
||||||
"storefrontId": 143486
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "St. Kitts & Nevis",
|
|
||||||
"code": "KN",
|
|
||||||
"storefrontId": 143548
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "St. Lucia",
|
|
||||||
"code": "LC",
|
|
||||||
"storefrontId": 143549
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "St. Vincent & The Grenadines",
|
|
||||||
"code": "VC",
|
|
||||||
"storefrontId": 143550
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Suriname",
|
|
||||||
"code": "SR",
|
|
||||||
"storefrontId": 143554
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Sweden",
|
|
||||||
"code": "SE",
|
|
||||||
"storefrontId": 143456
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Switzerland",
|
|
||||||
"code": "CH",
|
|
||||||
"storefrontId": 143459
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Taiwan",
|
|
||||||
"code": "TW",
|
|
||||||
"storefrontId": 143470
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Tanzania",
|
|
||||||
"code": "TZ",
|
|
||||||
"storefrontId": 143572
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Thailand",
|
|
||||||
"code": "TH",
|
|
||||||
"storefrontId": 143475
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "The Bahamas",
|
|
||||||
"code": "BS",
|
|
||||||
"storefrontId": 143539
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Trinidad & Tobago",
|
|
||||||
"code": "TT",
|
|
||||||
"storefrontId": 143551
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Tunisia",
|
|
||||||
"code": "TN",
|
|
||||||
"storefrontId": 143536
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Turkey",
|
|
||||||
"code": "TR",
|
|
||||||
"storefrontId": 143480
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Turks & Caicos",
|
|
||||||
"code": "TC",
|
|
||||||
"storefrontId": 143552
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Uganda",
|
|
||||||
"code": "UG",
|
|
||||||
"storefrontId": 143537
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "UK",
|
|
||||||
"code": "GB",
|
|
||||||
"storefrontId": 143444
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ukraine",
|
|
||||||
"code": "UA",
|
|
||||||
"storefrontId": 143492
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "United Arab Emirates",
|
|
||||||
"code": "AE",
|
|
||||||
"storefrontId": 143481
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Uruguay",
|
|
||||||
"code": "UY",
|
|
||||||
"storefrontId": 143514
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "USA",
|
|
||||||
"code": "US",
|
|
||||||
"storefrontId": 143441
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Uzbekistan",
|
|
||||||
"code": "UZ",
|
|
||||||
"storefrontId": 143566
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Venezuela",
|
|
||||||
"code": "VE",
|
|
||||||
"storefrontId": 143502
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Vietnam",
|
|
||||||
"code": "VN",
|
|
||||||
"storefrontId": 143471
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Yemen",
|
|
||||||
"code": "YE",
|
|
||||||
"storefrontId": 143571
|
|
||||||
}
|
|
||||||
];
|
|
28
src/web/endpoints/back/getPlaylistMetadata.ts
Normal file
28
src/web/endpoints/back/getPlaylistMetadata.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { appleMusicApi } from "../../../appleMusicApi/index.js";
|
||||||
|
import express from "express";
|
||||||
|
import { validate } from "../../validate.js";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
query: z.object({
|
||||||
|
id: z.string()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// see comments in `getTrackMetadata.ts`
|
||||||
|
// awawawawawa
|
||||||
|
router.get("/getPlaylistMetadata", async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const { id } = (await validate(req, schema)).query;
|
||||||
|
|
||||||
|
const trackMetadata = await appleMusicApi.getPlaylist(id);
|
||||||
|
|
||||||
|
res.json(trackMetadata);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
|
@ -7,9 +7,11 @@ export const front = [
|
||||||
|
|
||||||
import backDownload from "./back/download.js";
|
import backDownload from "./back/download.js";
|
||||||
import getAlbumMetadata from "./back/getAlbumMetadata.js";
|
import getAlbumMetadata from "./back/getAlbumMetadata.js";
|
||||||
|
import getPlaylistMetadata from "./back/getPlaylistMetadata.js";
|
||||||
import getTrackMetadata from "./back/getTrackMetadata.js";
|
import getTrackMetadata from "./back/getTrackMetadata.js";
|
||||||
export const back = [
|
export const back = [
|
||||||
backDownload,
|
backDownload,
|
||||||
getAlbumMetadata,
|
getAlbumMetadata,
|
||||||
|
getPlaylistMetadata,
|
||||||
getTrackMetadata
|
getTrackMetadata
|
||||||
];
|
];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue