@ -1,129 +1,170 @@
interface getItemsArgs {
interface getItemsArgs {
limit : number ,
limit : number ;
period : string ,
period : string ;
page : number ,
page : number ;
artist_id? : number ,
artist_id? : number ;
album_id? : number ,
album_id? : number ;
track_id? : number
track_id? : number ;
}
}
interface getActivityArgs {
interface getActivityArgs {
step : string
step : string ;
range : number
range : number ;
month : number
month : number ;
year : number
year : number ;
artist_id : number
artist_id : number ;
album_id : number
album_id : number ;
track_id : number
track_id : number ;
}
}
function getLastListens ( args : getItemsArgs ) : Promise < PaginatedResponse < Listen > > {
function getLastListens (
return fetch ( ` /apis/web/v1/listens?period= ${ args . period } &limit= ${ args . limit } &artist_id= ${ args . artist_id } &album_id= ${ args . album_id } &track_id= ${ args . track_id } &page= ${ args . page } ` ) . then ( r = > r . json ( ) as Promise < PaginatedResponse < Listen > > )
args : getItemsArgs
) : Promise < PaginatedResponse < Listen > > {
return fetch (
` /apis/web/v1/listens?period= ${ args . period } &limit= ${ args . limit } &artist_id= ${ args . artist_id } &album_id= ${ args . album_id } &track_id= ${ args . track_id } &page= ${ args . page } `
) . then ( ( r ) = > r . json ( ) as Promise < PaginatedResponse < Listen > > ) ;
}
}
function getTopTracks ( args : getItemsArgs ) : Promise < PaginatedResponse < Track > > {
function getTopTracks ( args : getItemsArgs ) : Promise < PaginatedResponse < Track > > {
if ( args . artist_id ) {
if ( args . artist_id ) {
return fetch ( ` /apis/web/v1/top-tracks?period= ${ args . period } &limit= ${ args . limit } &artist_id= ${ args . artist_id } &page= ${ args . page } ` ) . then ( r = > r . json ( ) as Promise < PaginatedResponse < Track > > )
return fetch (
` /apis/web/v1/top-tracks?period= ${ args . period } &limit= ${ args . limit } &artist_id= ${ args . artist_id } &page= ${ args . page } `
) . then ( ( r ) = > r . json ( ) as Promise < PaginatedResponse < Track > > ) ;
} else if ( args . album_id ) {
} else if ( args . album_id ) {
return fetch ( ` /apis/web/v1/top-tracks?period= ${ args . period } &limit= ${ args . limit } &album_id= ${ args . album_id } &page= ${ args . page } ` ) . then ( r = > r . json ( ) as Promise < PaginatedResponse < Track > > )
return fetch (
` /apis/web/v1/top-tracks?period= ${ args . period } &limit= ${ args . limit } &album_id= ${ args . album_id } &page= ${ args . page } `
) . then ( ( r ) = > r . json ( ) as Promise < PaginatedResponse < Track > > ) ;
} else {
} else {
return fetch ( ` /apis/web/v1/top-tracks?period= ${ args . period } &limit= ${ args . limit } &page= ${ args . page } ` ) . then ( r = > r . json ( ) as Promise < PaginatedResponse < Track > > )
return fetch (
` /apis/web/v1/top-tracks?period= ${ args . period } &limit= ${ args . limit } &page= ${ args . page } `
) . then ( ( r ) = > r . json ( ) as Promise < PaginatedResponse < Track > > ) ;
}
}
}
}
function getTopAlbums ( args : getItemsArgs ) : Promise < PaginatedResponse < Album > > {
function getTopAlbums ( args : getItemsArgs ) : Promise < PaginatedResponse < Album > > {
const baseUri = ` /apis/web/v1/top-albums?period= ${ args . period } &limit= ${ args . limit } &page= ${ args . page } `
const baseUri = ` /apis/web/v1/top-albums?period= ${ args . period } &limit= ${ args . limit } &page= ${ args . page } ` ;
if ( args . artist_id ) {
if ( args . artist_id ) {
return fetch ( baseUri + ` &artist_id= ${ args . artist_id } ` ) . then ( r = > r . json ( ) as Promise < PaginatedResponse < Album > > )
return fetch ( baseUri + ` &artist_id= ${ args . artist_id } ` ) . then (
( r ) = > r . json ( ) as Promise < PaginatedResponse < Album > >
) ;
} else {
} else {
return fetch ( baseUri ) . then ( r = > r . json ( ) as Promise < PaginatedResponse < Album > > )
return fetch ( baseUri ) . then (
( r ) = > r . json ( ) as Promise < PaginatedResponse < Album > >
) ;
}
}
}
}
function getTopArtists ( args : getItemsArgs ) : Promise < PaginatedResponse < Artist > > {
function getTopArtists ( args : getItemsArgs ) : Promise < PaginatedResponse < Artist > > {
const baseUri = ` /apis/web/v1/top-artists?period= ${ args . period } &limit= ${ args . limit } &page= ${ args . page } `
const baseUri = ` /apis/web/v1/top-artists?period= ${ args . period } &limit= ${ args . limit } &page= ${ args . page } ` ;
return fetch ( baseUri ) . then ( r = > r . json ( ) as Promise < PaginatedResponse < Artist > > )
return fetch ( baseUri ) . then (
( r ) = > r . json ( ) as Promise < PaginatedResponse < Artist > >
) ;
}
}
function getActivity ( args : getActivityArgs ) : Promise < ListenActivityItem [ ] > {
function getActivity ( args : getActivityArgs ) : Promise < ListenActivityItem [ ] > {
return fetch ( ` /apis/web/v1/listen-activity?step= ${ args . step } &range= ${ args . range } &month= ${ args . month } &year= ${ args . year } &album_id= ${ args . album_id } &artist_id= ${ args . artist_id } &track_id= ${ args . track_id } ` ) . then ( r = > r . json ( ) as Promise < ListenActivityItem [ ] > )
return fetch (
` /apis/web/v1/listen-activity?step= ${ args . step } &range= ${ args . range } &month= ${ args . month } &year= ${ args . year } &album_id= ${ args . album_id } &artist_id= ${ args . artist_id } &track_id= ${ args . track_id } `
) . then ( ( r ) = > r . json ( ) as Promise < ListenActivityItem [ ] > ) ;
}
}
function getStats ( period : string ) : Promise < Stats > {
function getStats ( period : string ) : Promise < Stats > {
return fetch ( ` /apis/web/v1/stats?period= ${ period } ` ) . then ( r = > r . json ( ) as Promise < Stats > )
return fetch ( ` /apis/web/v1/stats?period= ${ period } ` ) . then (
( r ) = > r . json ( ) as Promise < Stats >
) ;
}
}
function search ( q : string ) : Promise < SearchResponse > {
function search ( q : string ) : Promise < SearchResponse > {
q = encodeURIComponent ( q )
q = encodeURIComponent ( q ) ;
return fetch ( ` /apis/web/v1/search?q= ${ q } ` ) . then ( r = > r . json ( ) as Promise < SearchResponse > )
return fetch ( ` /apis/web/v1/search?q= ${ q } ` ) . then (
( r ) = > r . json ( ) as Promise < SearchResponse >
) ;
}
}
function imageUrl ( id : string , size : string ) {
function imageUrl ( id : string , size : string ) {
if ( ! id ) {
if ( ! id ) {
id = 'default'
id = "default" ;
}
}
return ` /images/ ${ size } / ${ id } `
return ` /images/ ${ size } / ${ id } ` ;
}
}
function replaceImage ( form : FormData ) : Promise < Response > {
function replaceImage ( form : FormData ) : Promise < Response > {
return fetch ( ` /apis/web/v1/replace-image ` , {
return fetch ( ` /apis/web/v1/replace-image ` , {
method : "POST" ,
method : "POST" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function mergeTracks ( from : number , to : number ) : Promise < Response > {
function mergeTracks ( from : number , to : number ) : Promise < Response > {
return fetch ( ` /apis/web/v1/merge/tracks?from_id= ${ from } &to_id= ${ to } ` , {
return fetch ( ` /apis/web/v1/merge/tracks?from_id= ${ from } &to_id= ${ to } ` , {
method : "POST" ,
method : "POST" ,
} )
} ) ;
}
}
function mergeAlbums ( from : number , to : number , replaceImage : boolean ) : Promise < Response > {
function mergeAlbums (
return fetch ( ` /apis/web/v1/merge/albums?from_id= ${ from } &to_id= ${ to } &replace_image= ${ replaceImage } ` , {
from : number ,
to : number ,
replaceImage : boolean
) : Promise < Response > {
return fetch (
` /apis/web/v1/merge/albums?from_id= ${ from } &to_id= ${ to } &replace_image= ${ replaceImage } ` ,
{
method : "POST" ,
method : "POST" ,
} )
}
}
) ;
function mergeArtists ( from : number , to : number , replaceImage : boolean ) : Promise < Response > {
}
return fetch ( ` /apis/web/v1/merge/artists?from_id= ${ from } &to_id= ${ to } &replace_image= ${ replaceImage } ` , {
function mergeArtists (
from : number ,
to : number ,
replaceImage : boolean
) : Promise < Response > {
return fetch (
` /apis/web/v1/merge/artists?from_id= ${ from } &to_id= ${ to } &replace_image= ${ replaceImage } ` ,
{
method : "POST" ,
method : "POST" ,
} )
}
}
) ;
function login ( username : string , password : string , remember : boolean ) : Promise < Response > {
}
const form = new URLSearchParams
function login (
form . append ( 'username' , username )
username : string ,
form . append ( 'password' , password )
password : string ,
form . append ( 'remember_me' , String ( remember ) )
remember : boolean
) : Promise < Response > {
const form = new URLSearchParams ( ) ;
form . append ( "username" , username ) ;
form . append ( "password" , password ) ;
form . append ( "remember_me" , String ( remember ) ) ;
return fetch ( ` /apis/web/v1/login ` , {
return fetch ( ` /apis/web/v1/login ` , {
method : "POST" ,
method : "POST" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function logout ( ) : Promise < Response > {
function logout ( ) : Promise < Response > {
return fetch ( ` /apis/web/v1/logout ` , {
return fetch ( ` /apis/web/v1/logout ` , {
method : "POST" ,
method : "POST" ,
} )
} ) ;
}
}
function getCfg ( ) : Promise < Config > {
function getCfg ( ) : Promise < Config > {
return fetch ( ` /apis/web/v1/config ` ) . then ( r = > r . json ( ) as Promise < Config > )
return fetch ( ` /apis/web/v1/config ` ) . then ( ( r ) = > r . json ( ) as Promise < Config > ) ;
}
}
function submitListen ( id : string , ts : Date ) : Promise < Response > {
function submitListen ( id : string , ts : Date ) : Promise < Response > {
const form = new URLSearchParams
const form = new URLSearchParams ( ) ;
form . append ( "track_id" , id )
form . append ( "track_id" , id ) ;
const ms = new Date ( ts ) . getTime ( )
const ms = new Date ( ts ) . getTime ( ) ;
const unix = Math . floor ( ms / 1000 ) ;
const unix = Math . floor ( ms / 1000 ) ;
form . append ( "unix" , unix . toString ( ) )
form . append ( "unix" , unix . toString ( ) ) ;
return fetch ( ` /apis/web/v1/listen ` , {
return fetch ( ` /apis/web/v1/listen ` , {
method : "POST" ,
method : "POST" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function getApiKeys ( ) : Promise < ApiKey [ ] > {
function getApiKeys ( ) : Promise < ApiKey [ ] > {
return fetch ( ` /apis/web/v1/user/apikeys ` ) . then ( ( r ) = > r . json ( ) as Promise < ApiKey [ ] > )
return fetch ( ` /apis/web/v1/user/apikeys ` ) . then (
( r ) = > r . json ( ) as Promise < ApiKey [ ] >
) ;
}
}
const createApiKey = async ( label : string ) : Promise < ApiKey > = > {
const createApiKey = async ( label : string ) : Promise < ApiKey > = > {
const form = new URLSearchParams
const form = new URLSearchParams ( ) ;
form . append ( 'label' , label )
form . append ( "label" , label ) ;
const r = await fetch ( ` /apis/web/v1/user/apikeys ` , {
const r = await fetch ( ` /apis/web/v1/user/apikeys ` , {
method : "POST" ,
method : "POST" ,
body : form ,
body : form ,
@ -132,7 +173,7 @@ const createApiKey = async (label: string): Promise<ApiKey> => {
let errorMessage = ` error: ${ r . status } ` ;
let errorMessage = ` error: ${ r . status } ` ;
try {
try {
const errorData : ApiError = await r . json ( ) ;
const errorData : ApiError = await r . json ( ) ;
if ( errorData && typeof errorData . error === 'string' ) {
if ( errorData && typeof errorData . error === "string" ) {
errorMessage = errorData . error ;
errorMessage = errorData . error ;
}
}
} catch ( e ) {
} catch ( e ) {
@ -145,75 +186,94 @@ const createApiKey = async (label: string): Promise<ApiKey> => {
} ;
} ;
function deleteApiKey ( id : number ) : Promise < Response > {
function deleteApiKey ( id : number ) : Promise < Response > {
return fetch ( ` /apis/web/v1/user/apikeys?id= ${ id } ` , {
return fetch ( ` /apis/web/v1/user/apikeys?id= ${ id } ` , {
method : "DELETE"
method : "DELETE" ,
} )
} ) ;
}
}
function updateApiKeyLabel ( id : number , label : string ) : Promise < Response > {
function updateApiKeyLabel ( id : number , label : string ) : Promise < Response > {
const form = new URLSearchParams
const form = new URLSearchParams ( ) ;
form . append ( 'id' , String ( id ) )
form . append ( "id" , String ( id ) ) ;
form . append ( 'label' , label )
form . append ( "label" , label ) ;
return fetch ( ` /apis/web/v1/user/apikeys ` , {
return fetch ( ` /apis/web/v1/user/apikeys ` , {
method : "PATCH" ,
method : "PATCH" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function deleteItem ( itemType : string , id : number ) : Promise < Response > {
function deleteItem ( itemType : string , id : number ) : Promise < Response > {
return fetch ( ` /apis/web/v1/ ${ itemType } ?id= ${ id } ` , {
return fetch ( ` /apis/web/v1/ ${ itemType } ?id= ${ id } ` , {
method : "DELETE"
method : "DELETE" ,
} )
} ) ;
}
}
function updateUser ( username : string , password : string ) {
function updateUser ( username : string , password : string ) {
const form = new URLSearchParams
const form = new URLSearchParams ( ) ;
form . append ( 'username' , username )
form . append ( "username" , username ) ;
form . append ( 'password' , password )
form . append ( "password" , password ) ;
return fetch ( ` /apis/web/v1/user ` , {
return fetch ( ` /apis/web/v1/user ` , {
method : "PATCH" ,
method : "PATCH" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function getAliases ( type : string , id : number ) : Promise < Alias [ ] > {
function getAliases ( type : string , id : number ) : Promise < Alias [ ] > {
return fetch ( ` /apis/web/v1/aliases? ${ type } _id= ${ id } ` ) . then ( r = > r . json ( ) as Promise < Alias [ ] > )
return fetch ( ` /apis/web/v1/aliases? ${ type } _id= ${ id } ` ) . then (
( r ) = > r . json ( ) as Promise < Alias [ ] >
) ;
}
}
function createAlias ( type : string , id : number , alias : string ) : Promise < Response > {
function createAlias (
const form = new URLSearchParams
type : string ,
form . append ( ` ${ type } _id ` , String ( id ) )
id : number ,
form . append ( 'alias' , alias )
alias : string
) : Promise < Response > {
const form = new URLSearchParams ( ) ;
form . append ( ` ${ type } _id ` , String ( id ) ) ;
form . append ( "alias" , alias ) ;
return fetch ( ` /apis/web/v1/aliases ` , {
return fetch ( ` /apis/web/v1/aliases ` , {
method : 'POST' ,
method : "POST" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function deleteAlias ( type : string , id : number , alias : string ) : Promise < Response > {
function deleteAlias (
const form = new URLSearchParams
type : string ,
form . append ( ` ${ type } _id ` , String ( id ) )
id : number ,
form . append ( 'alias' , alias )
alias : string
) : Promise < Response > {
const form = new URLSearchParams ( ) ;
form . append ( ` ${ type } _id ` , String ( id ) ) ;
form . append ( "alias" , alias ) ;
return fetch ( ` /apis/web/v1/aliases/delete ` , {
return fetch ( ` /apis/web/v1/aliases/delete ` , {
method : "POST" ,
method : "POST" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function setPrimaryAlias ( type : string , id : number , alias : string ) : Promise < Response > {
function setPrimaryAlias (
const form = new URLSearchParams
type : string ,
form . append ( ` ${ type } _id ` , String ( id ) )
id : number ,
form . append ( 'alias' , alias )
alias : string
) : Promise < Response > {
const form = new URLSearchParams ( ) ;
form . append ( ` ${ type } _id ` , String ( id ) ) ;
form . append ( "alias" , alias ) ;
return fetch ( ` /apis/web/v1/aliases/primary ` , {
return fetch ( ` /apis/web/v1/aliases/primary ` , {
method : "POST" ,
method : "POST" ,
body : form ,
body : form ,
} )
} ) ;
}
}
function getAlbum ( id : number ) : Promise < Album > {
function getAlbum ( id : number ) : Promise < Album > {
return fetch ( ` /apis/web/v1/album?id= ${ id } ` ) . then ( r = > r . json ( ) as Promise < Album > )
return fetch ( ` /apis/web/v1/album?id= ${ id } ` ) . then (
( r ) = > r . json ( ) as Promise < Album >
) ;
}
}
function deleteListen ( listen : Listen ) : Promise < Response > {
function deleteListen ( listen : Listen ) : Promise < Response > {
const ms = new Date ( listen . time ) . getTime ( )
const ms = new Date ( listen . time ) . getTime ( ) ;
const unix = Math . floor ( ms / 1000 ) ;
const unix = Math . floor ( ms / 1000 ) ;
return fetch ( ` /apis/web/v1/listen?track_id= ${ listen . track . id } &unix= ${ unix } ` , {
return fetch ( ` /apis/web/v1/listen?track_id= ${ listen . track . id } &unix= ${ unix } ` , {
method : "DELETE"
method : "DELETE" ,
} )
} ) ;
}
}
function getExport() {
function getExport() { }
function getNowPlaying ( ) : Promise < NowPlaying > {
return fetch ( "/apis/web/v1/now-playing" ) . then ( ( r ) = > r . json ( ) ) ;
}
}
export {
export {
@ -246,94 +306,99 @@ export {
getAlbum ,
getAlbum ,
getExport ,
getExport ,
submitListen ,
submitListen ,
}
getNowPlaying ,
} ;
type Track = {
type Track = {
id : number
id : number ;
title : string
title : string ;
artists : SimpleArtists [ ]
artists : SimpleArtists [ ] ;
listen_count : number
listen_count : number ;
image : string
image : string ;
album_id : number
album_id : number ;
musicbrainz_id : string
musicbrainz_id : string ;
time_listened : number
time_listened : number ;
first_listen : number
first_listen : number ;
}
} ;
type Artist = {
type Artist = {
id : number
id : number ;
name : string
name : string ;
image : string ,
image : string ;
aliases : string [ ]
aliases : string [ ] ;
listen_count : number
listen_count : number ;
musicbrainz_id : string
musicbrainz_id : string ;
time_listened : number
time_listened : number ;
first_listen : number
first_listen : number ;
is_primary : boolean
is_primary : boolean ;
}
} ;
type Album = {
type Album = {
id : number ,
id : number ;
title : string
title : string ;
image : string
image : string ;
listen_count : number
listen_count : number ;
is_various_artists : boolean
is_various_artists : boolean ;
artists : SimpleArtists [ ]
artists : SimpleArtists [ ] ;
musicbrainz_id : string
musicbrainz_id : string ;
time_listened : number
time_listened : number ;
first_listen : number
first_listen : number ;
}
} ;
type Alias = {
type Alias = {
id : number
id : number ;
alias : string
alias : string ;
source : string
source : string ;
is_primary : boolean
is_primary : boolean ;
}
} ;
type Listen = {
type Listen = {
time : string ,
time : string ;
track : Track ,
track : Track ;
}
} ;
type PaginatedResponse < T > = {
type PaginatedResponse < T > = {
items : T [ ] ,
items : T [ ] ;
total_record_count : number ,
total_record_count : number ;
has_next_page : boolean ,
has_next_page : boolean ;
current_page : number ,
current_page : number ;
items_per_page : number ,
items_per_page : number ;
}
} ;
type ListenActivityItem = {
type ListenActivityItem = {
start_time : Date ,
start_time : Date ;
listens : number
listens : number ;
}
} ;
type SimpleArtists = {
type SimpleArtists = {
name : string
name : string ;
id : number
id : number ;
}
} ;
type Stats = {
type Stats = {
listen_count : number
listen_count : number ;
track_count : number
track_count : number ;
album_count : number
album_count : number ;
artist_count : number
artist_count : number ;
minutes_listened : number
minutes_listened : number ;
}
} ;
type SearchResponse = {
type SearchResponse = {
albums : Album [ ]
albums : Album [ ] ;
artists : Artist [ ]
artists : Artist [ ] ;
tracks : Track [ ]
tracks : Track [ ] ;
}
} ;
type User = {
type User = {
id : number
id : number ;
username : string
username : string ;
role : 'user' | 'admin'
role : "user" | "admin" ;
}
} ;
type ApiKey = {
type ApiKey = {
id : number
id : number ;
key : string
key : string ;
label : string
label : string ;
created_at : Date
created_at : Date ;
}
} ;
type ApiError = {
type ApiError = {
error : string
error : string ;
}
} ;
type Config = {
type Config = {
default_theme : string
default_theme : string ;
}
} ;
type NowPlaying = {
currently_playing : boolean ;
track : Track ;
} ;
export type {
export type {
getItemsArgs ,
getItemsArgs ,
@ -349,5 +414,6 @@ export type {
Alias ,
Alias ,
ApiKey ,
ApiKey ,
ApiError ,
ApiError ,
Config
Config ,
}
NowPlaying ,
} ;