api -> subsonic
This commit is contained in:
parent
e9bfd056c8
commit
19dd3b13e2
7 changed files with 37 additions and 38 deletions
|
@ -1,5 +1,3 @@
|
||||||
Subsonic public_api;
|
|
||||||
|
|
||||||
public class Audrey.Application : Adw.Application {
|
public class Audrey.Application : Adw.Application {
|
||||||
public Application () {
|
public Application () {
|
||||||
Object (
|
Object (
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
audrey_sources = [
|
audrey_sources = [
|
||||||
'api.vala',
|
|
||||||
'application.vala',
|
'application.vala',
|
||||||
'globalconf.vala',
|
'globalconf.vala',
|
||||||
'main.vala',
|
'main.vala',
|
||||||
'mpris.vala',
|
'mpris.vala',
|
||||||
'playbin.vala',
|
'playbin.vala',
|
||||||
|
'subsonic.vala',
|
||||||
'ui/play_queue.vala',
|
'ui/play_queue.vala',
|
||||||
'ui/setup.vala',
|
'ui/setup.vala',
|
||||||
'ui/window.vala',
|
'ui/window.vala',
|
||||||
|
|
|
@ -25,14 +25,14 @@ class Playbin : GLib.Object {
|
||||||
|
|
||||||
public PlaybinState state { get; private set; default = PlaybinState.STOPPED; }
|
public PlaybinState state { get; private set; default = PlaybinState.STOPPED; }
|
||||||
|
|
||||||
public Song? current_song { get; private set; default = null; }
|
public Subsonic.Song? current_song { get; private set; default = null; }
|
||||||
|
|
||||||
// true if a timer should update the position property
|
// true if a timer should update the position property
|
||||||
private bool update_position = false;
|
private bool update_position = false;
|
||||||
public int64 position { get; private set; default = 0; }
|
public int64 position { get; private set; default = 0; }
|
||||||
public int64 duration { get; private set; default = 1; } // if 0, the seekbar vanishes
|
public int64 duration { get; private set; default = 1; } // if 0, the seekbar vanishes
|
||||||
|
|
||||||
public Subsonic api { get; set; default = null; }
|
public Subsonic.Client api { get; set; default = null; }
|
||||||
|
|
||||||
// sent when a new song starts playing
|
// sent when a new song starts playing
|
||||||
// continues: whether the track is a gapless continuation
|
// continues: whether the track is a gapless continuation
|
||||||
|
@ -109,7 +109,7 @@ class Playbin : GLib.Object {
|
||||||
// we're in luck, about-to-finish hasn't been triggered yet
|
// we're in luck, about-to-finish hasn't been triggered yet
|
||||||
// we can get away with replacing it
|
// we can get away with replacing it
|
||||||
if (this.current_position+1 < play_queue.get_n_items ()) {
|
if (this.current_position+1 < play_queue.get_n_items ()) {
|
||||||
Song song = (Song) play_queue.get_item (this.current_position+1);
|
var song = (Subsonic.Song) play_queue.get_item (this.current_position+1);
|
||||||
this.next_uri.push (this.api.stream_uri (song.id));
|
this.next_uri.push (this.api.stream_uri (song.id));
|
||||||
} else {
|
} else {
|
||||||
this.next_uri.push ("");
|
this.next_uri.push ("");
|
||||||
|
@ -182,7 +182,7 @@ class Playbin : GLib.Object {
|
||||||
this.next_gapless = true;
|
this.next_gapless = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var now_playing = (Song) play_queue.get_item (this.current_position);
|
var now_playing = (Subsonic.Song) play_queue.get_item (this.current_position);
|
||||||
if (this.api.stream_uri (now_playing.id) == (string) this.playbin.current_uri) {
|
if (this.api.stream_uri (now_playing.id) == (string) this.playbin.current_uri) {
|
||||||
if (continues) {
|
if (continues) {
|
||||||
this.current_song = now_playing;
|
this.current_song = now_playing;
|
||||||
|
@ -190,7 +190,7 @@ class Playbin : GLib.Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.current_position+1 < play_queue.get_n_items ()) {
|
if (this.current_position+1 < play_queue.get_n_items ()) {
|
||||||
Song song = (Song) play_queue.get_item (this.current_position+1);
|
var song = (Subsonic.Song) play_queue.get_item (this.current_position+1);
|
||||||
this.next_uri.push (this.api.stream_uri (song.id));
|
this.next_uri.push (this.api.stream_uri (song.id));
|
||||||
} else {
|
} else {
|
||||||
this.next_uri.push ("");
|
this.next_uri.push ("");
|
||||||
|
@ -230,7 +230,7 @@ class Playbin : GLib.Object {
|
||||||
|
|
||||||
this.current_position = position;
|
this.current_position = position;
|
||||||
this.playbin.set_state (Gst.State.READY);
|
this.playbin.set_state (Gst.State.READY);
|
||||||
var song = (Song) this.play_queue.get_item (position);
|
var song = (Subsonic.Song) this.play_queue.get_item (position);
|
||||||
this.playbin.uri = this.api.stream_uri (song.id);
|
this.playbin.uri = this.api.stream_uri (song.id);
|
||||||
this.playbin.set_state (Gst.State.PLAYING);
|
this.playbin.set_state (Gst.State.PLAYING);
|
||||||
this.next_gapless = false;
|
this.next_gapless = false;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
errordomain SubsonicError {
|
public errordomain Subsonic.Error {
|
||||||
BAD_AUTHN,
|
BAD_AUTHN,
|
||||||
ERROR,
|
ERROR,
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void SongCallback (Song song);
|
public delegate void Subsonic.SongCallback (Song song);
|
||||||
|
|
||||||
public class Artist : Object, Json.Serializable {
|
public class Subsonic.Artist : Object {
|
||||||
public string index;
|
public string index;
|
||||||
public string id;
|
public string id;
|
||||||
public string name { get; private set; }
|
public string name { get; private set; }
|
||||||
|
@ -38,7 +38,7 @@ public class Artist : Object, Json.Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Album : Object {
|
public class Subsonic.Album : Object {
|
||||||
public string id;
|
public string id;
|
||||||
public string name;
|
public string name;
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ public class Album : Object {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Song : Object {
|
public class Subsonic.Song : Object {
|
||||||
public string id { get; private set; }
|
public string id { get; private set; }
|
||||||
public string title { get; private set; }
|
public string title { get; private set; }
|
||||||
public string album { get; private set; }
|
public string album { get; private set; }
|
||||||
|
@ -89,7 +89,7 @@ public class Song : Object {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct API.PlayQueue {
|
public struct Subsonic.PlayQueue {
|
||||||
public string current;
|
public string current;
|
||||||
public int64 position;
|
public int64 position;
|
||||||
public DateTime changed;
|
public DateTime changed;
|
||||||
|
@ -128,7 +128,7 @@ public struct API.PlayQueue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Subsonic : Object {
|
public class Subsonic.Client : Object {
|
||||||
public ListStore artist_list;
|
public ListStore artist_list;
|
||||||
public ListStore album_list;
|
public ListStore album_list;
|
||||||
public ListStore song_list;
|
public ListStore song_list;
|
||||||
|
@ -137,7 +137,7 @@ public class Subsonic : Object {
|
||||||
private string url;
|
private string url;
|
||||||
private string parameters;
|
private string parameters;
|
||||||
|
|
||||||
public Subsonic.with_token (string url, string username, string token, string salt) {
|
public Client.with_token (string url, string username, string token, string salt) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.parameters = @"u=$(Uri.escape_string(username))&t=$(Uri.escape_string(token))&s=$(Uri.escape_string(salt))&v=1.16.1&c=eu.callcc.audrey";
|
this.parameters = @"u=$(Uri.escape_string(username))&t=$(Uri.escape_string(token))&s=$(Uri.escape_string(salt))&v=1.16.1&c=eu.callcc.audrey";
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ public class Subsonic : Object {
|
||||||
this.song_list = new ListStore (typeof (Song));
|
this.song_list = new ListStore (typeof (Song));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unwrap_response (Json.Reader reader) throws Error {
|
private void unwrap_response (Json.Reader reader) throws GLib.Error {
|
||||||
reader.read_member ("subsonic-response");
|
reader.read_member ("subsonic-response");
|
||||||
|
|
||||||
reader.read_member ("status");
|
reader.read_member ("status");
|
||||||
|
@ -157,15 +157,15 @@ public class Subsonic : Object {
|
||||||
reader.end_member ();
|
reader.end_member ();
|
||||||
reader.read_member ("error");
|
reader.read_member ("error");
|
||||||
reader.read_member ("message");
|
reader.read_member ("message");
|
||||||
throw new SubsonicError.ERROR (reader.get_string_value () ?? "???");
|
throw new Subsonic.Error.ERROR (reader.get_string_value () ?? "???");
|
||||||
}
|
}
|
||||||
reader.end_member();
|
reader.end_member();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ping () throws Error {
|
public async void ping () throws GLib.Error {
|
||||||
var msg = new Soup.Message ("GET", @"$(this.url)/rest/ping?f=json&$(this.parameters)");
|
var msg = new Soup.Message ("GET", @"$(this.url)/rest/ping?f=json&$(this.parameters)");
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
throw new SubsonicError.BAD_AUTHN ("Bad message");
|
throw new Subsonic.Error.BAD_AUTHN ("Bad message");
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = yield this.session.send_and_read_async (msg, Priority.DEFAULT, null);
|
var bytes = yield this.session.send_and_read_async (msg, Priority.DEFAULT, null);
|
||||||
|
@ -178,7 +178,7 @@ public class Subsonic : Object {
|
||||||
this.unwrap_response (reader);
|
this.unwrap_response (reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void scrobble (string id) throws Error {
|
public async void scrobble (string id) throws GLib.Error {
|
||||||
var msg = new Soup.Message ("GET", @"$(this.url)/rest/scrobble?id=$(Uri.escape_string (id))&f=json&$(this.parameters)");
|
var msg = new Soup.Message ("GET", @"$(this.url)/rest/scrobble?id=$(Uri.escape_string (id))&f=json&$(this.parameters)");
|
||||||
assert (msg != null);
|
assert (msg != null);
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ public class Subsonic : Object {
|
||||||
this.unwrap_response (reader);
|
this.unwrap_response (reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void get_random_songs (string? parameters, SongCallback callback) throws Error {
|
public async void get_random_songs (string? parameters, SongCallback callback) throws GLib.Error {
|
||||||
string str_parameters;
|
string str_parameters;
|
||||||
if (parameters == null) {
|
if (parameters == null) {
|
||||||
str_parameters = "";
|
str_parameters = "";
|
||||||
|
@ -232,7 +232,7 @@ public class Subsonic : Object {
|
||||||
return @"$(this.url)/rest/getCoverArt?id=$(Uri.escape_string(id))&$(this.parameters)";
|
return @"$(this.url)/rest/getCoverArt?id=$(Uri.escape_string(id))&$(this.parameters)";
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Gdk.Pixbuf cover_art (string id, Cancellable cancellable) throws Error {
|
public async Gdk.Pixbuf cover_art (string id, Cancellable cancellable) throws GLib.Error {
|
||||||
var msg = new Soup.Message("GET", this.cover_art_uri (id));
|
var msg = new Soup.Message("GET", this.cover_art_uri (id));
|
||||||
assert (msg != null);
|
assert (msg != null);
|
||||||
|
|
|
@ -34,8 +34,8 @@ template $UiPlayQueue: Adw.NavigationPage {
|
||||||
template ColumnViewCell {
|
template ColumnViewCell {
|
||||||
child: Label {
|
child: Label {
|
||||||
halign: start;
|
halign: start;
|
||||||
label: bind template.item as <$Song>.title;
|
label: bind template.item as <$SubsonicSong>.title;
|
||||||
tooltip-text: bind template.item as <$Song>.title;
|
tooltip-text: bind template.item as <$SubsonicSong>.title;
|
||||||
ellipsize: end;
|
ellipsize: end;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,8 @@ template $UiPlayQueue: Adw.NavigationPage {
|
||||||
template ColumnViewCell {
|
template ColumnViewCell {
|
||||||
child: Label {
|
child: Label {
|
||||||
halign: start;
|
halign: start;
|
||||||
label: bind template.item as <$Song>.artist;
|
label: bind template.item as <$SubsonicSong>.artist;
|
||||||
tooltip-text: bind template.item as <$Song>.artist;
|
tooltip-text: bind template.item as <$SubsonicSong>.artist;
|
||||||
ellipsize: end;
|
ellipsize: end;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class Ui.Setup : Adw.PreferencesDialog {
|
||||||
public string token;
|
public string token;
|
||||||
public string salt;
|
public string salt;
|
||||||
|
|
||||||
public signal void connected (Subsonic api);
|
public signal void connected (Subsonic.Client api);
|
||||||
|
|
||||||
private static Secret.Schema secret_schema = new Secret.Schema (
|
private static Secret.Schema secret_schema = new Secret.Schema (
|
||||||
"eu.callcc.audrey",
|
"eu.callcc.audrey",
|
||||||
|
@ -49,7 +49,7 @@ public class Ui.Setup : Adw.PreferencesDialog {
|
||||||
|
|
||||||
string new_token, new_salt;
|
string new_token, new_salt;
|
||||||
salt_password (this.password, out new_token, out new_salt);
|
salt_password (this.password, out new_token, out new_salt);
|
||||||
var api = new Subsonic.with_token (
|
var api = new Subsonic.Client.with_token (
|
||||||
this.server_url,
|
this.server_url,
|
||||||
this.username,
|
this.username,
|
||||||
new_token,
|
new_token,
|
||||||
|
|
|
@ -8,6 +8,8 @@ class Ui.Window : Adw.ApplicationWindow {
|
||||||
[GtkChild] public unowned Adw.ButtonRow shuffle_all_tracks;
|
[GtkChild] public unowned Adw.ButtonRow shuffle_all_tracks;
|
||||||
|
|
||||||
private Setup setup;
|
private Setup setup;
|
||||||
|
|
||||||
|
private Subsonic.Client api;
|
||||||
|
|
||||||
public int64 position { get; private set; }
|
public int64 position { get; private set; }
|
||||||
|
|
||||||
|
@ -25,7 +27,7 @@ class Ui.Window : Adw.ApplicationWindow {
|
||||||
public Gdk.Paintable playing_cover_art { get; set; }
|
public Gdk.Paintable playing_cover_art { get; set; }
|
||||||
|
|
||||||
public Playbin playbin { get; private set; default = new Playbin (); }
|
public Playbin playbin { get; private set; default = new Playbin (); }
|
||||||
public ListStore play_queue_store { get; private set; default = new ListStore (typeof (Song)); }
|
public ListStore play_queue_store { get; private set; default = new ListStore (typeof (Subsonic.Song)); }
|
||||||
|
|
||||||
public Window (Gtk.Application app) {
|
public Window (Gtk.Application app) {
|
||||||
Object (application: app);
|
Object (application: app);
|
||||||
|
@ -56,6 +58,7 @@ class Ui.Window : Adw.ApplicationWindow {
|
||||||
this.setup = new Setup ();
|
this.setup = new Setup ();
|
||||||
|
|
||||||
this.setup.connected.connect ((api) => {
|
this.setup.connected.connect ((api) => {
|
||||||
|
this.api = api;
|
||||||
this.playbin.api = api;
|
this.playbin.api = api;
|
||||||
|
|
||||||
this.playbin.now_playing.connect ((continues) => {
|
this.playbin.now_playing.connect ((continues) => {
|
||||||
|
@ -70,8 +73,6 @@ class Ui.Window : Adw.ApplicationWindow {
|
||||||
this.playbin.select_track (position);
|
this.playbin.select_track (position);
|
||||||
});
|
});
|
||||||
|
|
||||||
public_api = api;
|
|
||||||
|
|
||||||
this.shuffle_all_tracks.sensitive = true;
|
this.shuffle_all_tracks.sensitive = true;
|
||||||
this.shuffle_all_tracks.activated.connect (() => {
|
this.shuffle_all_tracks.activated.connect (() => {
|
||||||
this.shuffle_all_tracks.sensitive = false;
|
this.shuffle_all_tracks.sensitive = false;
|
||||||
|
@ -105,9 +106,9 @@ class Ui.Window : Adw.ApplicationWindow {
|
||||||
this.cover_art_loading = true;
|
this.cover_art_loading = true;
|
||||||
|
|
||||||
string song_id = playbin.current_song.id;
|
string song_id = playbin.current_song.id;
|
||||||
public_api.cover_art.begin (song_id, this.cancel_loading_art, (obj, res) => {
|
this.api.cover_art.begin (song_id, this.cancel_loading_art, (obj, res) => {
|
||||||
try {
|
try {
|
||||||
this.playing_cover_art = Gdk.Texture.for_pixbuf (public_api.cover_art.end (res));
|
this.playing_cover_art = Gdk.Texture.for_pixbuf (this.api.cover_art.end (res));
|
||||||
this.cover_art_loading = false;
|
this.cover_art_loading = false;
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
if (!(e is IOError.CANCELLED)) {
|
if (!(e is IOError.CANCELLED)) {
|
||||||
|
@ -215,15 +216,15 @@ class Ui.Window : Adw.ApplicationWindow {
|
||||||
this.seek_impl (new_position);
|
this.seek_impl (new_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
[GtkCallback] private string song_title (Song? song) {
|
[GtkCallback] private string song_title (Subsonic.Song? song) {
|
||||||
return song == null ? "" : song.title;
|
return song == null ? "" : song.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
[GtkCallback] private string song_artist (Song? song) {
|
[GtkCallback] private string song_artist (Subsonic.Song? song) {
|
||||||
return song == null ? "" : song.artist;
|
return song == null ? "" : song.artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
[GtkCallback] private string song_album (Song? song) {
|
[GtkCallback] private string song_album (Subsonic.Song? song) {
|
||||||
return song == null ? "" : song.album;
|
return song == null ? "" : song.album;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue