Files
SubMusic/source/AmpacheProvider.mc
memen45 46d3554ff4 Added initial podcast implementation (backend only)
added podcast methods for AmpacheAPI, AmpacheProvider
added podcast methods for SubsonicAPI, SubsonicProvider
added PodcastStore class
2020-11-03 15:59:00 +01:00

403 lines
9.1 KiB
MonkeyC

class AmpacheProvider {
private var d_api;
// request variables needed to repeat the request if necessary
private var d_action = null;
private var d_params = {
"limit" => 20, // defines the number of songs in single response
"offset" => 0, // defines the offset for the last request
};
private var d_encoding; // encoding parameter needed for stream
private var d_response; // construct full response
private var d_callback;
private var d_fallback;
enum {
AMPACHE_ACTION_PLAYLIST,
AMPACHE_ACTION_PLAYLISTS,
AMPACHE_ACTION_PLAYLIST_SONGS,
AMPACHE_ACTION_STREAM,
AMPACHE_ACTION_PODCASTS,
AMPACHE_ACTION_PODCAST,
AMPACHE_ACTION_PODCAST_EPISODES,
}
function initialize(settings) {
d_api = new AmpacheAPI(settings, self.method(:onError), self.method(:onFailed));
}
function onSettingsChanged(settings) {
d_api.update(settings);
}
// functions:
// - getAllPlaylists - returns array of all playlists available for Ampache user
// - getPlaylist - returns an array of one playlist object with id
// - getPlaylistSongs - returns an array of songs on the playlist with id
// - getRefId - returns a refId for a song by id (this downloads the song)
//
// - getPodcasts
// - getPodcast
// - getPodcastEpisodes
//
// to be added in the future:
// - getUpdatedPlaylists - returns array of all playlists updated since Moment
/**
* getAllPlaylists
*
* returns array of all playlists available for Ampache user
*/
function getAllPlaylists(callback) {
d_callback = callback;
// create empty array as initial response
d_response = [];
d_params = {
"limit" => 20,
"offset" => 0,
};
d_action = AMPACHE_ACTION_PLAYLISTS;
do_();
}
/**
* getPlaylist
*
* returns an array of one playlist object for id
*/
function getPlaylist(id, callback) {
d_callback = callback;
// create empty array as initial response
d_response = [];
d_params = {
"filter" => id,
};
d_action = AMPACHE_ACTION_PLAYLIST;
do_();
}
/**
* getPlaylistSongs
*
* returns an array of songs on the playlist with id
*/
function getPlaylistSongs(id, callback) {
d_callback = callback;
// create empty response
d_response = [];
d_params = {
"filter" => id,
"limit" => 20,
"offset" => 0,
};
d_action = AMPACHE_ACTION_PLAYLIST_SONGS;
do_();
}
/**
* getRefId
*
* returns a refId for a song by id (this downloads the song)
*/
function getRefId(id, mime, callback) {
d_callback = callback;
d_encoding = mimeToEncoding(mime);
var format = "mp3";
if (d_encoding == Media.ENCODING_INVALID) {
// default to mp3 transcoding
d_encoding = Media.ENCODING_MP3;
} else {
// if mime is supported, request raw
format = "raw";
}
var type = "song";
d_params = {
"id" => id,
"type" => type,
"format" => format,
};
d_action = AMPACHE_ACTION_STREAM;
do_();
}
function getPodcasts(callback) {
d_callback = callback;
// create empty response
d_response = [];
d_params = {
"limit" => 20,
"offset" => 0,
};
d_action = AMPACHE_ACTION_PODCASTS;
do_();
}
function getPodcast(id, callback) {
d_callback = callback;
d_params = {
"filter" => id,
};
d_action = AMPACHE_ACTION_PODCAST;
do_();
}
function getPodcastEpisodes(id, callback) {
d_callback = callback;
// create empty response
d_response = [];
d_params = {
"filter" => id,
"limit" => 20,
"offset" => 0,
};
d_action = AMPACHE_ACTION_PODCAST_EPISODES;
do_();
}
// handlers
function on_do_playlist(response) {
// append the standard playlist objects to the array
for (var idx = 0; idx < response.size(); ++idx) {
var playlist = response[idx];
var items = playlist["items"];
if (items == null) {
items = 0;
}
d_response.add(new Playlist({
"id" => playlist["id"],
"name" => playlist["name"],
"songCount" => items.toNumber(),
"remote" => true,
}));
}
d_action = null;
d_callback.invoke(d_response);
}
function on_do_playlists(response) {
// append the standard playlist objects to the array
for (var idx = 0; idx < response.size(); ++idx) {
var playlist = response[idx];
var items = playlist["items"];
if (items == null) {
items = 0;
}
d_response.add(new Playlist({
"id" => playlist["id"],
"name" => playlist["name"],
"songCount" => items.toNumber(),
"remote" => true,
}));
}
// if less than limit, no more requests required
if (response.size() < d_params["limit"]) {
d_action = null;
d_callback.invoke(d_response);
return;
}
d_params["offset"] += d_params["limit"]; // increase offset
do_();
}
function on_do_playlist_songs(response) {
// append the standard song objects to the array
for (var idx = 0; idx < response.size(); ++idx) {
var song = response[idx];
// new way of storing songs
var time = song["time"];
if (time == null) {
time = 0;
}
d_response.add(new Song({
"id" => song["id"],
"time" => time.toNumber(),
"mime" => song["mime"],
}));
}
if (response.size() < d_params["limit"]) {
d_action = null;
d_callback.invoke(d_response);
return;
}
d_params["offset"] += d_params["limit"]; // increase offset
do_();
}
function on_do_stream(refId) {
d_action = null;
d_callback.invoke(refId);
}
function on_do_podcasts(response) {
// append the standard podcast objects to the array
for (var idx = 0; idx < response.size(); ++idx) {
var playlist = response[idx];
var items = playlist["items"];
if (items == null) {
items = 0;
}
d_response.add(new Playlist({
"id" => playlist["id"],
"name" => playlist["name"],
"songCount" => items.toNumber(),
"remote" => true,
}));
}
// if less than limit, no more requests required
if (response.size() < d_params["limit"]) {
d_action = null;
d_callback.invoke(d_response);
return;
}
d_params["offset"] += d_params["limit"]; // increase offset
do_();
}
function on_do_podcast_episodes(response) {
// append the standard song objects to the array
for (var idx = 0; idx < response.size(); ++idx) {
var song = response[idx];
// new way of storing songs
var time = song["time"];
if (time == null) {
time = 0;
}
d_response.add(new Song({
"id" => song["id"],
"time" => time.toNumber(),
"mime" => song["mime"],
}));
}
if (response.size() < d_params["limit"]) {
d_action = null;
d_callback.invoke(d_response);
return;
}
d_params["offset"] += d_params["limit"]; // increase offset
do_();
}
function do_() {
// check if session still valid
if (!d_api.session(null)) {
d_api.handshake(self.method(:do_));
return;
}
if (d_action == AMPACHE_ACTION_PLAYLIST) {
d_api.playlist(self.method(:on_do_playlist), d_params);
return;
}
if (d_action == AMPACHE_ACTION_PLAYLISTS) {
d_api.playlists(self.method(:on_do_playlists), d_params);
return;
}
if (d_action == AMPACHE_ACTION_PLAYLIST_SONGS) {
d_api.playlist_songs(self.method(:on_do_playlist_songs), d_params);
return;
}
if (d_action == AMPACHE_ACTION_STREAM) {
d_api.stream(self.method(:on_do_stream), d_params, d_encoding);
return;
}
if (d_action == AMPACHE_ACTION_PODCASTS) {
d_api.podcasts(self.method(:on_do_podcasts), d_params);
return;
}
if (d_action == AMPACHE_ACTION_PODCAST) {
d_api.podcast(self.method(:on_do_podcast), d_params);
return;
}
if (d_action == AMPACHE_ACTION_PODCAST_EPISODES) {
d_api.podcast_episodes(self.method(:on_do_podcast_episodes), d_params);
return;
}
// no valid action defined
}
function onError(code, message) {
System.println("AmpacheProvider::onError( code: " + code + " message: " + message + " )");
// if session expired, reset
if (code == 401) {
d_api.deleteSession();
do_();
return;
}
// end current request
d_action = null;
d_fallback.invoke(code, message);
}
function onFailed(responseCode, data) {
// too large and response can be limited? Half the response
if ((responseCode == Communications.NETWORK_RESPONSE_TOO_LARGE)
&& (d_params["limit"] > 1)) {
d_params["limit"] = (d_params["limit"] / 2).toNumber(); // half the response
System.println("AmpacheProvider limit was lowered to " + d_params["limit"]);
do_(); // retry the request
return;
}
// end current request
d_action = null;
d_fallback.invoke(responseCode, data);
}
function setFallback(fallback) {
d_fallback = fallback;
}
function mimeToEncoding(mime) {
// mime should be a string
if (!(mime instanceof Lang.String)) {
return Media.ENCODING_INVALID;
}
// check docs: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers
if (mime.equals("audio/mpeg")) {
return Media.ENCODING_MP3;
}
if (mime.equals("audio/mp4")) {
return Media.ENCODING_M4A;
}
if (mime.equals("audio/aac")) {
return Media.ENCODING_ADTS;
}
if (mime.equals("audio/wave")
|| mime.equals("audio/wav")
|| mime.equals("audio/x-wav")
|| mime.equals("audio/x-pn-wav")) {
return Media.ENCODING_WAV;
}
// known mime types, but not supported by the sdk
if (mime.equals("audio/x-flac")) {
return Media.ENCODING_INVALID;
}
// mime type not defined
return Media.ENCODING_INVALID;
}
}