-
-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
let spinitron = {submit=()} | ||
|
||
# Submit a track to the spinitron track system | ||
# and return the raw response. | ||
# @category Interaction | ||
# @flag extra | ||
# @param ~api_key API key | ||
def spinitron.submit.raw( | ||
~host="https://spinitron.com/api", | ||
~api_key, | ||
~live=true, | ||
~start=null(), | ||
~duration=null(), | ||
~artist, | ||
~release=null(), | ||
~label=null(), | ||
~genre=null(), | ||
~song, | ||
~composer=null(), | ||
~isrc=null() | ||
) = | ||
params = [("song", song), ("artist", artist)] | ||
|
||
def fold_optional_string_params(params, param) = | ||
let (label, param) = param | ||
if | ||
null.defined(param) | ||
then | ||
[(label, null.get(param)), ...params] | ||
else | ||
params | ||
end | ||
end | ||
|
||
params = | ||
list.fold( | ||
fold_optional_string_params, | ||
params, | ||
[ | ||
("live", null.map(string, (live : bool?))), | ||
("start", start), | ||
("duration", null.map(string, (duration : int?))), | ||
("release", release), | ||
("label", label), | ||
("genre", genre), | ||
("composer", composer), | ||
("isrc", isrc) | ||
] | ||
) | ||
|
||
def encode_param(param) = | ||
let (label, param) = param | ||
"#{label}=#{url.encode(param)}" | ||
end | ||
|
||
params = string.concat(separator="&", list.map(encode_param, params)) | ||
|
||
http.post( | ||
data=params, | ||
headers= | ||
[ | ||
("Accept", "application/json"), | ||
("Content-Type", "application/x-www-form-urlencoded"), | ||
( | ||
"Authorization", | ||
"Bearer #{(api_key : string)}" | ||
) | ||
], | ||
"#{host}/spins" | ||
) | ||
end | ||
|
||
# Submit a track to the spinitron track system | ||
# and return the parsed response | ||
# @category Interaction | ||
# @flag extra | ||
# @param ~api_key API key | ||
def replaces spinitron.submit(%argsof(spinitron.submit.raw)) = | ||
resp = spinitron.submit.raw(%argsof(spinitron.submit.raw)) | ||
|
||
if | ||
resp.status_code == 201 | ||
then | ||
let json.parse (resp : | ||
{ | ||
id: int, | ||
playlist_id: int, | ||
"start" as spin_start: string, | ||
"end" as spin_end: string?, | ||
duration: int?, | ||
timezone: string?, | ||
image: string?, | ||
classical: bool, | ||
artist: string, | ||
"artist-custom" as artist_custom: string?, | ||
composer: string?, | ||
release: string?, | ||
"release-custom" as release_custom: string?, | ||
va: bool, | ||
label: string?, | ||
"label-custom" as label_custom: string?, | ||
released: int?, | ||
medium: string?, | ||
genre: string?, | ||
song: string, | ||
note: string?, | ||
request: bool, | ||
local: bool, | ||
new: bool, | ||
work: string?, | ||
conductor: string?, | ||
performers: string?, | ||
ensemble: string?, | ||
"catalog-number" as catalog_number: string?, | ||
isrc: string?, | ||
upc: string?, | ||
iswc: string?, | ||
"_links" as links: {self: {href: string}?, playlist: {href: string}?}? | ||
} | ||
) = resp | ||
|
||
resp | ||
elsif | ||
resp.status_code == 422 | ||
then | ||
let json.parse (errors : [{field: string, message: string}]) = resp | ||
|
||
errors = | ||
list.map( | ||
fun (p) -> | ||
begin | ||
let {field, message} = p | ||
"#{field}: #{message}" | ||
end, | ||
errors | ||
) | ||
|
||
errors = | ||
string.concat( | ||
separator= | ||
", ", | ||
errors | ||
) | ||
|
||
error.raise( | ||
error.raise( | ||
error.http, | ||
"Invalid fields: #{errors}" | ||
) | ||
) | ||
else | ||
let json.parse ({name, message, code, status, type} : | ||
{name: string, message: string, code: int, status: int, type: string?} | ||
) = resp | ||
|
||
type = type ?? "undefined" | ||
|
||
error.raise( | ||
error.raise( | ||
error.http, | ||
"#{name}: #{message} (code: #{code}, status: #{status}, type: #{type})" | ||
) | ||
) | ||
end | ||
end | ||
|
||
# Submit a spin using the given metadata to the spinitron track system | ||
# and return the parsed response. `artist` and `song` (or `title`) must | ||
# be present either as metadata or as optional argument. | ||
# @category Interaction | ||
# @flag extra | ||
# @param m Metadata to submit. Overrides optional arguments when present. | ||
# @param ~api_key API key | ||
def spinitron.submit.metadata( | ||
%argsof(spinitron.submit[!artist,!song]), | ||
~artist=null(), | ||
~song=null(), | ||
m | ||
) = | ||
def conv_opt_arg(convert, label, default) = | ||
list.assoc.mem(label, m) ? convert(m[label]) : default | ||
end | ||
|
||
opt_arg = | ||
fun (label, default) -> conv_opt_arg(fun (x) -> null(x), label, default) | ||
|
||
live = conv_opt_arg(bool_of_string, "live", live) | ||
start = opt_arg("start", start) | ||
duration = conv_opt_arg(int_of_string, "duration", duration) | ||
artist = opt_arg("artist", artist) | ||
release = opt_arg("release", release) | ||
label = opt_arg("label", label) | ||
genre = opt_arg("genre", genre) | ||
song = opt_arg("title", song) | ||
song = opt_arg("song", song) | ||
composer = opt_arg("composer", composer) | ||
isrc = opt_arg("isrc", isrc) | ||
|
||
if | ||
artist == null() or song == null() | ||
then | ||
error.raise( | ||
error.invalid, | ||
"Both \"artist\" and \"song\" (or \"title\" metadata) must be provided!" | ||
) | ||
end | ||
|
||
artist = null.get(artist) | ||
song = null.get(song) | ||
|
||
spinitron.submit(%argsof(spinitron.submit)) | ||
end | ||
|
||
# Specialized version of `source.on_metadata` that submits spins using | ||
# the source's metadata to the spinitron track system. `artist` and `song` | ||
# (or `title`) must be present either as metadata or as optional argument. | ||
# @category Interaction | ||
# @flag extra | ||
# @param m Metadata to submit. Overrides optional arguments when present. | ||
# @param ~api_key API key | ||
def spinitron.submit.on_metadata( | ||
~id=null(), | ||
%argsof(spinitron.submit.metadata), | ||
s | ||
) = | ||
def on_metadata(m) = | ||
if | ||
m["title"] == "" and m["song"] == "" | ||
then | ||
log.important( | ||
label=source.id(s), | ||
"Field \"song\" or \"title\" missing, skipping metadata spinitron \ | ||
submission." | ||
) | ||
elsif | ||
m["artist"] == "" | ||
then | ||
log.important( | ||
label=source.id(s), | ||
"Field \"artist\" missing, skipping metadata spinitron submission." | ||
) | ||
else | ||
try | ||
ignore(spinitron.submit.metadata(%argsof(spinitron.submit.metadata), m)) | ||
log.info( | ||
label=source.id(s), | ||
"Successfully submitted spin from metadata" | ||
) | ||
catch err do | ||
log.important( | ||
label=source.id(s), | ||
"Error while submitting spin from metadata: #{err}" | ||
) | ||
end | ||
end | ||
end | ||
|
||
source.on_metadata(id=id, s, on_metadata) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters