progress
This commit is contained in:
parent
c5161b9c01
commit
c25df9d61b
5 changed files with 76 additions and 19 deletions
|
@ -1,7 +1,7 @@
|
||||||
project('wavelet', ['c', 'vala'],
|
project('wavelet', ['c', 'vala'],
|
||||||
version: '0.1.0',
|
version: '0.1.0',
|
||||||
meson_version: '>= 1.0.0',
|
meson_version: '>= 1.0.0',
|
||||||
default_options: [ 'warning_level=2', 'werror=false', ],
|
default_options: [ 'warning_level=none', 'werror=false', ],
|
||||||
)
|
)
|
||||||
|
|
||||||
i18n = import('i18n')
|
i18n = import('i18n')
|
||||||
|
|
27
src/api.vala
27
src/api.vala
|
@ -164,7 +164,7 @@ public class Wavelet.Subsonic : Object {
|
||||||
|
|
||||||
public Subsonic.with_password (string url, string username, string password) {
|
public Subsonic.with_password (string url, string username, string password) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.parameters = @"u=$(Uri.escape_string(username))&p=$(Uri.escape_string(password))&v=1.16.1&c=eu.callcc.Wavelet&f=json";
|
this.parameters = @"u=$(Uri.escape_string(username))&p=$(Uri.escape_string(password))&v=1.16.1&c=eu.callcc.Wavelet";
|
||||||
|
|
||||||
this.session = new Soup.Session ();
|
this.session = new Soup.Session ();
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ public class Wavelet.Subsonic : Object {
|
||||||
|
|
||||||
public Subsonic.with_token (string url, string username, string token, string salt) {
|
public Subsonic.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.Wavelet&f=json";
|
this.parameters = @"u=$(Uri.escape_string(username))&t=$(Uri.escape_string(token))&s=$(Uri.escape_string(salt))&v=1.16.1&c=eu.callcc.Wavelet";
|
||||||
|
|
||||||
this.session = new Soup.Session ();
|
this.session = new Soup.Session ();
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ public class Wavelet.Subsonic : Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ping () throws Error {
|
public async void ping () throws Error {
|
||||||
var msg = new Soup.Message ("GET", @"$(this.url)/rest/ping?$(this.parameters)");
|
var msg = new Soup.Message ("GET", @"$(this.url)/rest/ping?f=json&$(this.parameters)");
|
||||||
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);
|
||||||
assert (msg.get_status () == Soup.Status.OK);
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ public class Wavelet.Subsonic : Object {
|
||||||
this.remaining_artists = 0;
|
this.remaining_artists = 0;
|
||||||
this.remaining_albums = 0;
|
this.remaining_albums = 0;
|
||||||
|
|
||||||
var msg = new Soup.Message ("GET", @"$(this.url)/rest/getArtists?$(this.parameters)");
|
var msg = new Soup.Message ("GET", @"$(this.url)/rest/getArtists?f=json&$(this.parameters)");
|
||||||
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);
|
||||||
|
|
||||||
var parser = new Json.Parser ();
|
var parser = new Json.Parser ();
|
||||||
|
@ -264,7 +264,7 @@ public class Wavelet.Subsonic : Object {
|
||||||
|
|
||||||
private async void reload_artist (string artist_id) throws Error {
|
private async void reload_artist (string artist_id) throws Error {
|
||||||
try {
|
try {
|
||||||
var msg = new Soup.Message ("GET", @"$(this.url)/rest/getArtist?id=$(artist_id)&$(this.parameters)");
|
var msg = new Soup.Message ("GET", @"$(this.url)/rest/getArtist?id=$(artist_id)&f=json&$(this.parameters)");
|
||||||
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);
|
||||||
assert (msg.get_status () == Soup.Status.OK);
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ public class Wavelet.Subsonic : Object {
|
||||||
|
|
||||||
private async void reload_album (string album_id) throws Error {
|
private async void reload_album (string album_id) throws Error {
|
||||||
try {
|
try {
|
||||||
var msg = new Soup.Message ("GET", @"$(this.url)/rest/getAlbum?id=$(album_id)&$(this.parameters)");
|
var msg = new Soup.Message ("GET", @"$(this.url)/rest/getAlbum?id=$(album_id)&f=json&$(this.parameters)");
|
||||||
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);
|
||||||
assert (msg.get_status () == Soup.Status.OK);
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
|
||||||
|
@ -340,7 +340,7 @@ public class Wavelet.Subsonic : Object {
|
||||||
str_parameters = @"$parameters&";
|
str_parameters = @"$parameters&";
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = new Soup.Message("GET", @"$(this.url)/rest/getRandomSongs?$(str_parameters)size=500&$(this.parameters)");
|
var msg = new Soup.Message("GET", @"$(this.url)/rest/getRandomSongs?$(str_parameters)size=500&f=json&$(this.parameters)");
|
||||||
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);
|
||||||
assert (msg.get_status () == Soup.Status.OK);
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
|
||||||
|
@ -363,6 +363,17 @@ public class Wavelet.Subsonic : Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
public string stream_uri (string id) {
|
public string stream_uri (string id) {
|
||||||
return @"$(this.url)/rest/stream?id=$(id)&$(this.parameters)";
|
return @"$(this.url)/rest/stream?id=$(Uri.escape_string(id))&$(this.parameters)";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string cover_art_uri (string id, int size) {
|
||||||
|
return @"$(this.url)/rest/getCoverArt?id=$(Uri.escape_string(id))&$(size)&$(this.parameters)";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Gdk.Pixbuf cover_art (string id, int size, Cancellable cancellable) throws Error {
|
||||||
|
var msg = new Soup.Message("GET", this.cover_art_uri (id, size));
|
||||||
|
var stream = yield this.session.send_async (msg, Priority.DEFAULT, cancellable);
|
||||||
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
return yield new Gdk.Pixbuf.from_stream_async (stream, cancellable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
Sqlite.Database config_db;
|
Sqlite.Database config_db;
|
||||||
Gst.Element playbin;
|
Gst.Element playbin;
|
||||||
|
Wavelet.Subsonic public_api;
|
||||||
|
|
||||||
public class Wavelet.Application : Adw.Application {
|
public class Wavelet.Application : Adw.Application {
|
||||||
public Application () {
|
public Application () {
|
||||||
|
@ -96,16 +97,16 @@ public class Wavelet.Application : Adw.Application {
|
||||||
win.play_position.sensitive = true;
|
win.play_position.sensitive = true;
|
||||||
|
|
||||||
int64 duration_ns;
|
int64 duration_ns;
|
||||||
assert(playbin.query_duration (Gst.Format.TIME, out duration_ns));
|
if (playbin.query_duration (Gst.Format.TIME, out duration_ns)) {
|
||||||
print("%lld\n", duration_ns);
|
win.play_position_ms = 0;
|
||||||
|
win.play_duration_ms = (int) (duration_ns / 1000000);
|
||||||
win.play_position_ms = 0;
|
} else {
|
||||||
win.play_duration_ms = (int) (duration_ns / 1000000);
|
warning ("could not query playbin duration after ASYNC_DONE");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
print ("%s\n", message.type.to_string ());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -114,6 +115,8 @@ public class Wavelet.Application : Adw.Application {
|
||||||
var next_queue = new AsyncQueue<string?> ();
|
var next_queue = new AsyncQueue<string?> ();
|
||||||
|
|
||||||
win.setup.connected.connect ((api) => {
|
win.setup.connected.connect ((api) => {
|
||||||
|
public_api = api;
|
||||||
|
|
||||||
win.artist_list.model = api.artist_list;
|
win.artist_list.model = api.artist_list;
|
||||||
win.song_list.model = api.song_list;
|
win.song_list.model = api.song_list;
|
||||||
|
|
||||||
|
@ -130,7 +133,11 @@ public class Wavelet.Application : Adw.Application {
|
||||||
api.get_random_songs.begin (null, (song) => {
|
api.get_random_songs.begin (null, (song) => {
|
||||||
win.play_queue.queue (song);
|
win.play_queue.queue (song);
|
||||||
}, (obj, res) => {
|
}, (obj, res) => {
|
||||||
api.get_random_songs.end (res);
|
try {
|
||||||
|
api.get_random_songs.end (res);
|
||||||
|
} catch (Error e) {
|
||||||
|
error ("could not get random songs: %s", e.message);
|
||||||
|
}
|
||||||
win.shuffle_all_tracks.sensitive = true;
|
win.shuffle_all_tracks.sensitive = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -105,9 +105,18 @@ template $WaveletWindow: Adw.ApplicationWindow {
|
||||||
"toolbar",
|
"toolbar",
|
||||||
]
|
]
|
||||||
|
|
||||||
Image {
|
Overlay {
|
||||||
height-request: 100;
|
[overlay] Adw.Spinner {
|
||||||
width-request: 100;
|
halign: center;
|
||||||
|
valign: center;
|
||||||
|
width-request: 20;
|
||||||
|
height-request: 20;
|
||||||
|
visible: bind template.cover_art_loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
Picture {
|
||||||
|
paintable: bind template.playing_cover_art;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box {
|
Box {
|
||||||
|
|
|
@ -43,12 +43,42 @@ public class Wavelet.Window : Adw.ApplicationWindow {
|
||||||
|
|
||||||
public Song? song { get; set; default = null; }
|
public Song? song { get; set; default = null; }
|
||||||
|
|
||||||
|
private Cancellable cancel_loading_art;
|
||||||
|
public bool cover_art_loading { get; set; default = false; }
|
||||||
|
public Gdk.Paintable playing_cover_art { get; set; }
|
||||||
|
|
||||||
public Window (Gtk.Application app) {
|
public Window (Gtk.Application app) {
|
||||||
Object (application: app);
|
Object (application: app);
|
||||||
}
|
}
|
||||||
|
|
||||||
construct {
|
construct {
|
||||||
this.sidebar.select_row (this.sidebar.get_row_at_index (0));
|
this.sidebar.select_row (this.sidebar.get_row_at_index (0));
|
||||||
|
|
||||||
|
this.notify["song"].connect (() => {
|
||||||
|
if (this.cancel_loading_art != null) {
|
||||||
|
this.cancel_loading_art.cancel ();
|
||||||
|
}
|
||||||
|
this.cancel_loading_art = new Cancellable ();
|
||||||
|
|
||||||
|
this.playing_cover_art = Gdk.Paintable.empty (100, 100);
|
||||||
|
if (this.song != null) {
|
||||||
|
this.cover_art_loading = true;
|
||||||
|
|
||||||
|
string song_id = this.song.id;
|
||||||
|
public_api.cover_art.begin (song_id, 100, this.cancel_loading_art, (obj, res) => {
|
||||||
|
try {
|
||||||
|
this.playing_cover_art = Gdk.Texture.for_pixbuf (public_api.cover_art.end (res));
|
||||||
|
this.cover_art_loading = false;
|
||||||
|
} catch (Error e) {
|
||||||
|
if (!(e is IOError.CANCELLED)) {
|
||||||
|
warning ("could not load cover for %s: %s", song_id, e.message);
|
||||||
|
this.cover_art_loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.set("song", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void show_mute () {
|
public void show_mute () {
|
||||||
|
|
Loading…
Reference in a new issue