Compare commits
No commits in common. "e85e606ba995063f5a863309c4a777131500e009" and "371c966be86baa79747ed122de5a2d34edb906dd" have entirely different histories.
e85e606ba9
...
371c966be8
17 changed files with 1927 additions and 72 deletions
11
meson.build
11
meson.build
|
@ -1,6 +1,6 @@
|
||||||
project(
|
project(
|
||||||
'audrey',
|
'audrey',
|
||||||
'c',
|
['c', 'vala'],
|
||||||
version: '0.1.0', # AUDREY_VERSION
|
version: '0.1.0', # AUDREY_VERSION
|
||||||
meson_version: '>= 1.0.0',
|
meson_version: '>= 1.0.0',
|
||||||
default_options: ['warning_level=0', 'werror=false'],
|
default_options: ['warning_level=0', 'werror=false'],
|
||||||
|
@ -10,6 +10,7 @@ i18n = import('i18n')
|
||||||
gnome = import('gnome')
|
gnome = import('gnome')
|
||||||
fs = import('fs')
|
fs = import('fs')
|
||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
|
valac = meson.get_compiler('vala')
|
||||||
|
|
||||||
srcdir = meson.project_source_root() / 'src'
|
srcdir = meson.project_source_root() / 'src'
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ config_h.set_quoted('GETTEXT_PACKAGE', 'audrey')
|
||||||
config_h.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir'))
|
config_h.set_quoted('LOCALEDIR', get_option('prefix') / get_option('localedir'))
|
||||||
configure_file(output: 'config.h', configuration: config_h)
|
configure_file(output: 'config.h', configuration: config_h)
|
||||||
|
|
||||||
|
config_dep = valac.find_library('config', dirs: srcdir)
|
||||||
config_inc = include_directories('.')
|
config_inc = include_directories('.')
|
||||||
|
|
||||||
add_project_arguments(
|
add_project_arguments(
|
||||||
|
@ -52,12 +54,17 @@ endif
|
||||||
cargo = find_program('cargo')
|
cargo = find_program('cargo')
|
||||||
cargo_env = environment()
|
cargo_env = environment()
|
||||||
cargo_env.set('MESON_BUILD_ROOT', meson.project_build_root())
|
cargo_env.set('MESON_BUILD_ROOT', meson.project_build_root())
|
||||||
|
cargo_env.append(
|
||||||
|
'RUSTFLAGS',
|
||||||
|
'-L ' + fs.parent(audrey_c.full_path()),
|
||||||
|
separator: ' ',
|
||||||
|
)
|
||||||
|
|
||||||
custom_target(
|
custom_target(
|
||||||
'cargo-build',
|
'cargo-build',
|
||||||
build_by_default: true,
|
build_by_default: true,
|
||||||
build_always_stale: true,
|
build_always_stale: true,
|
||||||
depends: blueprints,
|
depends: [audrey_c, blueprints],
|
||||||
input: config_rs,
|
input: config_rs,
|
||||||
console: true,
|
console: true,
|
||||||
# means nothing (always stale and uncopied), we can't cp since env: drops the /bin/sh wrapper
|
# means nothing (always stale and uncopied), we can't cp since env: drops the /bin/sh wrapper
|
||||||
|
|
|
@ -22,3 +22,10 @@ blueprints = custom_target(
|
||||||
'@INPUT@',
|
'@INPUT@',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
removeme = gnome.compile_resources(
|
||||||
|
'audrey-resources',
|
||||||
|
'audrey.gresource.xml',
|
||||||
|
c_name: 'audrey',
|
||||||
|
dependencies: blueprints,
|
||||||
|
)
|
||||||
|
|
6
src/config.vapi
Normal file
6
src/config.vapi
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")]
|
||||||
|
namespace Audrey.Config {
|
||||||
|
public const string GETTEXT_PACKAGE;
|
||||||
|
public const string LOCALEDIR;
|
||||||
|
public const string PACKAGE_VERSION;
|
||||||
|
}
|
3
src/globalconf.vala
Normal file
3
src/globalconf.vala
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
namespace Audrey.Const {
|
||||||
|
public const string user_agent = "audrey/linux";
|
||||||
|
}
|
11
src/main.rs
11
src/main.rs
|
@ -16,8 +16,8 @@ pub use playbin_song::Song as PlaybinSong;
|
||||||
|
|
||||||
pub mod subsonic;
|
pub mod subsonic;
|
||||||
|
|
||||||
pub mod playbin;
|
pub mod playbin2;
|
||||||
pub type Playbin = playbin::Playbin<PlaybinSong>;
|
pub type Playbin = playbin2::Playbin<PlaybinSong>;
|
||||||
|
|
||||||
mod signal;
|
mod signal;
|
||||||
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
pub use signal::{Signal, SignalEmitter, SignalHandler};
|
||||||
|
@ -28,6 +28,13 @@ use gtk::{gio, glib};
|
||||||
|
|
||||||
pub mod mpv;
|
pub mod mpv;
|
||||||
|
|
||||||
|
#[link(name = "audrey")]
|
||||||
|
#[link(name = "gcrypt")]
|
||||||
|
#[link(name = "json-glib-1.0")]
|
||||||
|
#[link(name = "secret-1")]
|
||||||
|
#[link(name = "soup-3.0")]
|
||||||
|
extern "C" {}
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
fn main() -> glib::ExitCode {
|
||||||
gio::resources_register_include!("audrey.gresource").expect("could not register resources");
|
gio::resources_register_include!("audrey.gresource").expect("could not register resources");
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,40 @@
|
||||||
|
audrey_sources = [
|
||||||
|
'globalconf.vala',
|
||||||
|
'playbin.vala',
|
||||||
|
'rust.vapi',
|
||||||
|
'subsonic.vala',
|
||||||
|
]
|
||||||
|
|
||||||
|
audrey_deps = [
|
||||||
|
dependency('gtk4', version: '>= 4.16'),
|
||||||
|
dependency('json-glib-1.0', version: '>= 1.10'),
|
||||||
|
dependency('libadwaita-1', version: '>= 1.6'),
|
||||||
|
dependency('libgcrypt', version: '>= 1.11'),
|
||||||
|
dependency('libsecret-1', version: '>= 0.21'),
|
||||||
|
dependency('libsoup-3.0', version: '>= 3.6'),
|
||||||
|
dependency('mpv', version: '>= 2.3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
audrey_sources += removeme
|
||||||
|
|
||||||
config_rs = configure_file(
|
config_rs = configure_file(
|
||||||
output: 'meson_config.rs',
|
output: 'meson_config.rs',
|
||||||
input: 'meson_config.rs.in',
|
input: 'meson_config.rs.in',
|
||||||
configuration: config_h,
|
configuration: config_h,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
audrey_c = static_library(
|
||||||
|
'audrey',
|
||||||
|
audrey_sources,
|
||||||
|
dependencies: audrey_deps,
|
||||||
|
include_directories: config_inc,
|
||||||
|
install: true,
|
||||||
|
vala_args: [
|
||||||
|
'--vapidir',
|
||||||
|
meson.current_source_dir() / 'vapi',
|
||||||
|
'--gresources',
|
||||||
|
meson.project_source_root() / 'resources/audrey.gresource.xml',
|
||||||
|
],
|
||||||
|
vala_header: 'audrey.h',
|
||||||
|
vala_gir: 'audrey-0.gir',
|
||||||
|
)
|
||||||
|
|
430
src/playbin.vala
Normal file
430
src/playbin.vala
Normal file
|
@ -0,0 +1,430 @@
|
||||||
|
public enum Audrey.PlaybinState {
|
||||||
|
STOPPED,
|
||||||
|
PAUSED,
|
||||||
|
PLAYING,
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct Audrey.CommandCallback {
|
||||||
|
unowned SourceFunc callback;
|
||||||
|
int error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Audrey.PlaybinSong : Object {
|
||||||
|
private static int64 next_counter = 0;
|
||||||
|
public int64 counter { get; private set; }
|
||||||
|
|
||||||
|
public string id { get; set; }
|
||||||
|
public string title { get; set; }
|
||||||
|
public string artist { get; set; }
|
||||||
|
public string album { get; set; }
|
||||||
|
public string? genre { get; set; }
|
||||||
|
public int64 duration { get; set; }
|
||||||
|
public int64 track { get; set; }
|
||||||
|
public int64 play_count { get; set; }
|
||||||
|
|
||||||
|
public string cover_art_url { get; set; }
|
||||||
|
public string stream_url { get; set; }
|
||||||
|
|
||||||
|
construct {
|
||||||
|
this.counter = next_counter;
|
||||||
|
next_counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaybinSong (Subsonic.Client api, Subsonic.Song song) {
|
||||||
|
this.id = song.id;
|
||||||
|
this.title = song.title;
|
||||||
|
this.artist = song.artist;
|
||||||
|
this.album = song.album;
|
||||||
|
this.genre = song.genre;
|
||||||
|
this.duration = song.duration;
|
||||||
|
this.track = song.track;
|
||||||
|
this.play_count = song.play_count;
|
||||||
|
|
||||||
|
this.cover_art_url = api.cover_art_uri(this.id);
|
||||||
|
this.stream_url = api.stream_uri(this.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Audrey.Playbin : GLib.Object {
|
||||||
|
private Mpv.Handle mpv = new Mpv.Handle ();
|
||||||
|
private int _volume = 100;
|
||||||
|
private bool _mute = false;
|
||||||
|
private ListStore _play_queue = new ListStore (typeof (PlaybinSong));
|
||||||
|
|
||||||
|
// try to prevent wait_event to be called twice
|
||||||
|
private bool is_handling_event = false;
|
||||||
|
|
||||||
|
public PlaybinState state { get; private set; default = PlaybinState.STOPPED; }
|
||||||
|
|
||||||
|
public int volume {
|
||||||
|
get { return _volume; }
|
||||||
|
set {
|
||||||
|
var ret = mpv.set_property_int64 ("volume", value);
|
||||||
|
if (ret >= 0) {
|
||||||
|
_volume = value;
|
||||||
|
} else {
|
||||||
|
warning ("failed to set volume to %d: %s", value, ret.to_string ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool mute {
|
||||||
|
get { return _mute; }
|
||||||
|
set {
|
||||||
|
var ret = mpv.set_property_flag ("mute", value);
|
||||||
|
if (ret >= 0) {
|
||||||
|
_mute = value;
|
||||||
|
} else {
|
||||||
|
warning ("failed to set mute status: %s", ret.to_string ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// invariant: negative iff stopped, otherwise < play queue length
|
||||||
|
public int play_queue_position { get; private set; default = -1; }
|
||||||
|
|
||||||
|
// signalled when a new track is current
|
||||||
|
public signal void new_track (PlaybinSong song);
|
||||||
|
// signalled when the last track is over
|
||||||
|
public signal void stopped ();
|
||||||
|
// signalled when the position changes discontinuously
|
||||||
|
public signal void seeked (double position);
|
||||||
|
|
||||||
|
// these are mostly synced with mpv
|
||||||
|
public double position { get; private set; default = 0.0; }
|
||||||
|
public double duration { get; private set; default = 0.0; }
|
||||||
|
|
||||||
|
public weak Subsonic.Client api { get; set; default = null; }
|
||||||
|
|
||||||
|
public ListModel play_queue { get { return this._play_queue; } }
|
||||||
|
public uint play_queue_length { get; private set; default = 0; }
|
||||||
|
|
||||||
|
private async Mpv.Error mpv_command_async (string[] args) {
|
||||||
|
CommandCallback cc = {};
|
||||||
|
|
||||||
|
this.mpv.command_async ((uint64) &cc, args);
|
||||||
|
|
||||||
|
cc.callback = this.mpv_command_async.callback;
|
||||||
|
yield;
|
||||||
|
return cc.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Playbin () {
|
||||||
|
assert (this.mpv.initialize () >= 0);
|
||||||
|
assert (this.mpv.set_property_string ("audio-client-name", "audrey") >= 0);
|
||||||
|
assert (this.mpv.set_property_string ("user-agent", Audrey.Const.user_agent) >= 0);
|
||||||
|
assert (this.mpv.set_property_string ("video", "no") >= 0);
|
||||||
|
assert (this.mpv.set_property_string ("prefetch-playlist", "yes") >= 0);
|
||||||
|
assert (this.mpv.set_property_string ("gapless-audio", "yes") >= 0);
|
||||||
|
assert (this.mpv.observe_property (0, "time-pos", Mpv.Format.DOUBLE) >= 0);
|
||||||
|
assert (this.mpv.observe_property (1, "duration", Mpv.Format.DOUBLE) >= 0);
|
||||||
|
assert (this.mpv.observe_property (2, "playlist-pos", Mpv.Format.INT64) >= 0);
|
||||||
|
assert (this.mpv.observe_property (3, "pause", Mpv.Format.FLAG) >= 0);
|
||||||
|
|
||||||
|
this.mpv.wakeup_callback = () => {
|
||||||
|
Idle.add (() => {
|
||||||
|
if (this.is_handling_event) {
|
||||||
|
warning ("main thread mpv wakeup callback called twice");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.is_handling_event = true;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
var event = this.mpv.wait_event (0.0);
|
||||||
|
if (event.event_id == Mpv.EventId.NONE) break;
|
||||||
|
|
||||||
|
switch (event.event_id) {
|
||||||
|
case Mpv.EventId.PROPERTY_CHANGE:
|
||||||
|
var data = event.parse_property ();
|
||||||
|
switch (event.reply_userdata) {
|
||||||
|
case 0:
|
||||||
|
assert (data.name == "time-pos");
|
||||||
|
if (data.format == Mpv.Format.NONE) {
|
||||||
|
this.position = 0.0;
|
||||||
|
} else {
|
||||||
|
this.position = data.parse_double ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
assert (data.name == "duration");
|
||||||
|
if (data.format == Mpv.Format.NONE) {
|
||||||
|
// this.duration = 0.0; i think this prevents the fallback below from working
|
||||||
|
} else {
|
||||||
|
this.duration = data.parse_double ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// here as a sanity check
|
||||||
|
// should always match our own play_queu_position/state
|
||||||
|
assert (data.name == "playlist-pos");
|
||||||
|
int64 playlist_pos = data.parse_int64 ();
|
||||||
|
if (playlist_pos < 0) {
|
||||||
|
if (this.state != PlaybinState.STOPPED) {
|
||||||
|
error ("mpv has no current playlist entry, but we think it's index %d", this.play_queue_position);
|
||||||
|
}
|
||||||
|
assert (this.play_queue_position < 0);
|
||||||
|
} else {
|
||||||
|
if (this.state == PlaybinState.STOPPED) {
|
||||||
|
error ("mpv is at playlist entry %d, but we're stopped", (int) playlist_pos);
|
||||||
|
}
|
||||||
|
if (this.play_queue_position != (int) playlist_pos) {
|
||||||
|
error ("mpv is at playlist entry %d, but we think it's %d", (int) playlist_pos, this.play_queue_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// also here as a sanity check
|
||||||
|
// should always match our own state
|
||||||
|
assert (data.name == "pause");
|
||||||
|
bool pause = data.parse_flag ();
|
||||||
|
if (pause && this.state != PlaybinState.PAUSED) {
|
||||||
|
error (@"mpv is paused, but we are @(this.state)");
|
||||||
|
}
|
||||||
|
if (!pause && this.state == PlaybinState.PAUSED) {
|
||||||
|
error ("mpv is not paused, but we are paused");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert (false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mpv.EventId.START_FILE:
|
||||||
|
debug ("START_FILE received");
|
||||||
|
|
||||||
|
// estimate duration from api data
|
||||||
|
// while mpv doesn't know it
|
||||||
|
var song = (PlaybinSong) this._play_queue.get_item (this.play_queue_position);
|
||||||
|
this.duration = song.duration;
|
||||||
|
|
||||||
|
this.new_track (song);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mpv.EventId.END_FILE:
|
||||||
|
var data = event.parse_end_file ();
|
||||||
|
debug (@"END_FILE received (reason: $(data.reason))");
|
||||||
|
|
||||||
|
if (data.error < 0) {
|
||||||
|
warning ("playback of track aborted: %s", data.error.to_string ());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.reason == Mpv.EndFileReason.EOF) {
|
||||||
|
// assume this is a proper transition
|
||||||
|
this.play_queue_position += 1;
|
||||||
|
|
||||||
|
if (this.play_queue_position == this._play_queue.get_n_items ()) {
|
||||||
|
// reached the end (?)
|
||||||
|
this.state = PlaybinState.STOPPED;
|
||||||
|
this.play_queue_position = -1;
|
||||||
|
this.stopped ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mpv.EventId.COMMAND_REPLY:
|
||||||
|
unowned CommandCallback *cc = (CommandCallback *) event.reply_userdata;
|
||||||
|
cc.error = event.error;
|
||||||
|
cc.callback ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// ignore by default
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.is_handling_event = false;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void seek (double position) {
|
||||||
|
var rc = this.mpv.command ({"seek", position.to_string (), "absolute"});
|
||||||
|
if (rc < 0) {
|
||||||
|
warning (@"could not seek to $position: $rc");
|
||||||
|
} else {
|
||||||
|
this.position = position;
|
||||||
|
this.seeked (position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// manually changes which track in the play queue to play
|
||||||
|
public void select_track (uint position)
|
||||||
|
requires (position < this.play_queue.get_n_items ())
|
||||||
|
{
|
||||||
|
assert (this.mpv.command ({"playlist-play-index", position.to_string ()}) >= 0);
|
||||||
|
this.play_queue_position = (int) position;
|
||||||
|
this.state = PlaybinState.PLAYING;
|
||||||
|
this.play (); // make sure mpv actually starts playing the track
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pause () {
|
||||||
|
assert (this.state != PlaybinState.STOPPED);
|
||||||
|
this.state = PlaybinState.PAUSED;
|
||||||
|
debug ("setting state to paused");
|
||||||
|
// TODO: abstract away this handling around mpv api a bit for auto debug printing
|
||||||
|
var ret = this.mpv.set_property_flag("pause", true);
|
||||||
|
if (ret != 0) {
|
||||||
|
debug (@"failed to set state to paused ($(ret)): $(ret.to_string())");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play () {
|
||||||
|
if (this.state == PlaybinState.STOPPED) {
|
||||||
|
// allow only when playlist is not empty
|
||||||
|
// and start from the top
|
||||||
|
assert (this._play_queue.get_n_items () > 0);
|
||||||
|
this.select_track (0);
|
||||||
|
} else {
|
||||||
|
this.state = PlaybinState.PLAYING;
|
||||||
|
debug ("setting state to playing");
|
||||||
|
var ret = this.mpv.set_property_flag("pause", false);
|
||||||
|
if (ret != 0) {
|
||||||
|
debug (@"failed to set state to playing ($(ret)): $(ret.to_string())");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void go_to_next_track ()
|
||||||
|
requires (this.state != PlaybinState.STOPPED)
|
||||||
|
{
|
||||||
|
if (this.play_queue_position+1 < this._play_queue.get_n_items ()) {
|
||||||
|
this.play_queue_position += 1;
|
||||||
|
assert (this.mpv.command ({"playlist-next-playlist"}) >= 0);
|
||||||
|
} else {
|
||||||
|
warning ("tried to skip forward at end of play queue, ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void go_to_prev_track ()
|
||||||
|
requires (this.state != PlaybinState.STOPPED)
|
||||||
|
{
|
||||||
|
if (this.play_queue_position > 0) {
|
||||||
|
this.play_queue_position -= 1;
|
||||||
|
assert (this.mpv.command ({"playlist-prev-playlist"}) >= 0);
|
||||||
|
} else {
|
||||||
|
warning ("tried to skip to prev track at start of play queue, ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove_track (uint position)
|
||||||
|
requires (position < this._play_queue.get_n_items ())
|
||||||
|
{
|
||||||
|
assert (this.mpv.command({"playlist-remove", position.to_string ()}) >= 0);
|
||||||
|
this._play_queue.remove (position);
|
||||||
|
this.play_queue_length -= 1;
|
||||||
|
if (this.play_queue_position > position) this.play_queue_position -= 1;
|
||||||
|
if (this.play_queue_position == this._play_queue.get_n_items ()) {
|
||||||
|
// we just killed the last track
|
||||||
|
this.state = PlaybinState.STOPPED;
|
||||||
|
this.play_queue_position = -1;
|
||||||
|
this.stopped ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear () {
|
||||||
|
assert (this.mpv.command({"playlist-clear"}) >= 0);
|
||||||
|
if (this.state != PlaybinState.STOPPED) {
|
||||||
|
assert (this.mpv.command({"playlist-remove", "current"}) >= 0);
|
||||||
|
}
|
||||||
|
this.state = PlaybinState.STOPPED;
|
||||||
|
this._play_queue.remove_all ();
|
||||||
|
this.play_queue_length = 0;
|
||||||
|
this.play_queue_position = -1;
|
||||||
|
|
||||||
|
this.stopped ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void append_track (Subsonic.Song song) {
|
||||||
|
var pb_song = new PlaybinSong (this.api, song);
|
||||||
|
assert (this.mpv.command ({
|
||||||
|
"loadfile",
|
||||||
|
pb_song.stream_url,
|
||||||
|
"append",
|
||||||
|
}) >= 0);
|
||||||
|
this._play_queue.append (pb_song);
|
||||||
|
this.play_queue_length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void append_track_async (Subsonic.Song song) {
|
||||||
|
var pb_song = new PlaybinSong (this.api, song);
|
||||||
|
var err = yield this.mpv_command_async ({
|
||||||
|
"loadfile",
|
||||||
|
pb_song.stream_url,
|
||||||
|
"append",
|
||||||
|
});
|
||||||
|
assert (err >= 0);
|
||||||
|
|
||||||
|
this._play_queue.append (pb_song);
|
||||||
|
this.play_queue_length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move_track (uint from, uint to)
|
||||||
|
requires (from < this._play_queue.get_n_items ())
|
||||||
|
requires (to < this._play_queue.get_n_items ())
|
||||||
|
{
|
||||||
|
debug (@"moving track $from to $to");
|
||||||
|
|
||||||
|
if (from < to) {
|
||||||
|
// why offset to? because if the playlist is 01234,
|
||||||
|
// mpv takes "move 1 to 3" to mean 02134, not 02314
|
||||||
|
// that is, the target is a "gap", not a playlist entry
|
||||||
|
// from -> 0 1 2 3 4 5
|
||||||
|
// to -> 0 1 2 3 4 5 6
|
||||||
|
assert(this.mpv.command({
|
||||||
|
"playlist-move",
|
||||||
|
from.to_string (),
|
||||||
|
(to+1).to_string (),
|
||||||
|
}) >= 0);
|
||||||
|
|
||||||
|
// F0123T -> 0123TF
|
||||||
|
var additions = new Object[to-from+1];
|
||||||
|
for (uint i = from+1; i < to; i += 1) {
|
||||||
|
additions[i-from-1] = this._play_queue.get_item (i);
|
||||||
|
}
|
||||||
|
additions[to-from-1] = this._play_queue.get_item (to);
|
||||||
|
additions[to-from] = this._play_queue.get_item (from);
|
||||||
|
this._play_queue.splice(from, to-from+1, additions);
|
||||||
|
|
||||||
|
if (this.play_queue_position == (int) from) this.play_queue_position = (int) to;
|
||||||
|
else if (this.play_queue_position > (int) from && this.play_queue_position <= (int) to) this.play_queue_position -= 1;
|
||||||
|
} else if (from > to) {
|
||||||
|
assert(this.mpv.command({
|
||||||
|
"playlist-move",
|
||||||
|
from.to_string (),
|
||||||
|
to.to_string (),
|
||||||
|
}) >= 0);
|
||||||
|
|
||||||
|
// T0123F -> FT0123
|
||||||
|
var additions = new Object[from-to+1];
|
||||||
|
additions[0] = this._play_queue.get_item (from);
|
||||||
|
for (uint i = to; i < from; i += 1) {
|
||||||
|
additions[i-to+1] = this._play_queue.get_item (i);
|
||||||
|
}
|
||||||
|
this._play_queue.splice (to, from-to+1, additions);
|
||||||
|
|
||||||
|
if (this.play_queue_position == (int) from) this.play_queue_position = (int) to;
|
||||||
|
else if (this.play_queue_position >= (int) to && this.play_queue_position < (int) from) this.play_queue_position += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop () {
|
||||||
|
debug ("stopping playback");
|
||||||
|
// don't clear the playlist, just in case (less state changes to sync)
|
||||||
|
assert(this.mpv.command({"stop", "keep-playlist"}) >= 0);
|
||||||
|
this.state = PlaybinState.STOPPED;
|
||||||
|
this.play_queue_position = -1;
|
||||||
|
this.stopped ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Playbin () {
|
||||||
|
debug ("destroying playbin");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,81 +1,100 @@
|
||||||
mod imp {
|
pub mod ffi {
|
||||||
use adw::prelude::*;
|
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use gtk::subclass::prelude::*;
|
use std::ffi::c_char;
|
||||||
use std::cell::{Cell, RefCell};
|
|
||||||
|
|
||||||
static NEXT_COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
#[repr(C)]
|
||||||
|
pub struct AudreyPlaybinSong {
|
||||||
#[derive(glib::Properties, Default)]
|
_data: [u8; 0],
|
||||||
#[properties(wrapper_type = super::Song)]
|
|
||||||
pub struct Song {
|
|
||||||
#[property(get, set)]
|
|
||||||
counter: Cell<u64>,
|
|
||||||
|
|
||||||
#[property(get, set)]
|
|
||||||
id: RefCell<String>,
|
|
||||||
#[property(get, set)]
|
|
||||||
title: RefCell<String>,
|
|
||||||
#[property(get, set)]
|
|
||||||
artist: RefCell<String>,
|
|
||||||
#[property(get, set)]
|
|
||||||
album: RefCell<String>,
|
|
||||||
#[property(get, set)]
|
|
||||||
genre: RefCell<Option<String>>,
|
|
||||||
#[property(get, set)]
|
|
||||||
duration: Cell<i64>,
|
|
||||||
#[property(get, set)]
|
|
||||||
track: Cell<i64>,
|
|
||||||
|
|
||||||
#[property(get, set)]
|
|
||||||
cover_art_url: RefCell<String>,
|
|
||||||
#[property(get, set)]
|
|
||||||
stream_url: RefCell<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[repr(C)]
|
||||||
impl ObjectSubclass for Song {
|
pub struct AudreyPlaybinSongClass {
|
||||||
const NAME: &'static str = "AudreyPlaybinSong";
|
_data: [u8; 0],
|
||||||
type Type = super::Song;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::derived_properties]
|
extern "C" {
|
||||||
impl ObjectImpl for Song {
|
pub fn audrey_playbin_song_get_type() -> glib::ffi::GType;
|
||||||
fn constructed(&self) {
|
pub fn audrey_playbin_song_get_counter(self_: *mut AudreyPlaybinSong) -> i64;
|
||||||
self.parent_constructed();
|
pub fn audrey_playbin_song_get_id(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
||||||
|
pub fn audrey_playbin_song_get_title(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
||||||
|
pub fn audrey_playbin_song_get_artist(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
||||||
|
pub fn audrey_playbin_song_get_album(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
||||||
|
pub fn audrey_playbin_song_get_duration(self_: *mut AudreyPlaybinSong) -> i64;
|
||||||
|
|
||||||
self.obj()
|
pub fn audrey_playbin_song_get_cover_art_url(
|
||||||
.set_counter(NEXT_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed));
|
self_: *mut AudreyPlaybinSong,
|
||||||
}
|
) -> *const c_char;
|
||||||
|
pub fn audrey_playbin_song_get_stream_url(self_: *mut AudreyPlaybinSong) -> *const c_char;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::subsonic;
|
use glib::translate::{from_glib_none, ToGlibPtr};
|
||||||
use glib::Object;
|
use glib::GString;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct Song(ObjectSubclass<imp::Song>);
|
pub struct Song(Object<ffi::AudreyPlaybinSong, ffi::AudreyPlaybinSongClass>);
|
||||||
|
|
||||||
|
match fn {
|
||||||
|
type_ => || ffi::audrey_playbin_song_get_type(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Song {
|
impl Song {
|
||||||
pub fn from_child(api: &subsonic::Client, song: &subsonic::schema::Child) -> Self {
|
pub fn counter(&self) -> i64 {
|
||||||
Object::builder()
|
unsafe { ffi::audrey_playbin_song_get_counter(self.to_glib_none().0) }
|
||||||
.property("id", &song.id)
|
}
|
||||||
.property("title", &song.title)
|
|
||||||
.property("artist", &song.artist)
|
pub fn id(&self) -> GString {
|
||||||
.property("album", &song.album)
|
unsafe { from_glib_none(ffi::audrey_playbin_song_get_id(self.to_glib_none().0)) }
|
||||||
.property("genre", &song.genre)
|
}
|
||||||
.property("duration", song.duration as i64)
|
|
||||||
//.property("track", song.track)
|
pub fn title(&self) -> GString {
|
||||||
.property("cover-art-url", api.cover_art_url(&song.id).as_str())
|
unsafe { from_glib_none(ffi::audrey_playbin_song_get_title(self.to_glib_none().0)) }
|
||||||
.property("stream-url", api.stream_url(&song.id).as_str())
|
}
|
||||||
|
|
||||||
|
pub fn artist(&self) -> GString {
|
||||||
|
unsafe { from_glib_none(ffi::audrey_playbin_song_get_artist(self.to_glib_none().0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn album(&self) -> GString {
|
||||||
|
unsafe { from_glib_none(ffi::audrey_playbin_song_get_album(self.to_glib_none().0)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn duration(&self) -> i64 {
|
||||||
|
unsafe { ffi::audrey_playbin_song_get_duration(self.to_glib_none().0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cover_art_url(&self) -> url::Url {
|
||||||
|
let url: String = unsafe {
|
||||||
|
from_glib_none(ffi::audrey_playbin_song_get_cover_art_url(
|
||||||
|
self.to_glib_none().0,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
url::Url::parse(&url).expect("invalid url from vala side")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stream_url(&self) -> url::Url {
|
||||||
|
let url: String = unsafe {
|
||||||
|
from_glib_none(ffi::audrey_playbin_song_get_stream_url(
|
||||||
|
self.to_glib_none().0,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
url::Url::parse(&url).expect("invalid url from vala side")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_child(
|
||||||
|
api: &crate::subsonic::Client,
|
||||||
|
child: &crate::subsonic::schema::Child,
|
||||||
|
) -> Self {
|
||||||
|
glib::Object::builder()
|
||||||
|
.property("id", &child.id)
|
||||||
|
.property("title", &child.title)
|
||||||
|
.property("artist", &child.artist)
|
||||||
|
.property("album", &child.album)
|
||||||
|
.property("duration", child.duration as i64)
|
||||||
|
.property("cover-art-url", api.cover_art_url(&child.id).as_str())
|
||||||
|
.property("stream-url", api.stream_url(&child.id).as_str())
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::playbin::PlaybinEntry for Song {
|
|
||||||
fn url(&self) -> url::Url {
|
|
||||||
url::Url::parse(&self.stream_url()).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
31
src/rust.h
Normal file
31
src/rust.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
// ui::playbar
|
||||||
|
typedef void AudreyUiPlaybar;
|
||||||
|
|
||||||
|
// ui::play_queue::Song
|
||||||
|
typedef void AudreyUiPlayQueueSong;
|
||||||
|
#define AUDREY_UI_TYPE_PLAY_QUEUE_SONG (audrey_ui_play_queue_song_get_type ())
|
||||||
|
GType audrey_ui_play_queue_song_get_type(void);
|
||||||
|
AudreyUiPlayQueueSong *audrey_ui_play_queue_song_new(void *playbin);
|
||||||
|
void audrey_ui_play_queue_song_set_draggable(AudreyUiPlayQueueSong *self, gboolean draggable);
|
||||||
|
void audrey_ui_play_queue_song_set_show_position(AudreyUiPlayQueueSong *self, gboolean show_position);
|
||||||
|
void audrey_ui_play_queue_song_set_show_artist(AudreyUiPlayQueueSong *self, gboolean show_artist);
|
||||||
|
void audrey_ui_play_queue_song_set_show_cover(AudreyUiPlayQueueSong *self, gboolean show_cover);
|
||||||
|
void audrey_ui_play_queue_song_bind(AudreyUiPlayQueueSong *self, guint position, void *song);
|
||||||
|
void audrey_ui_play_queue_song_unbind(AudreyUiPlayQueueSong *self);
|
||||||
|
|
||||||
|
// ui::PlayQueue
|
||||||
|
typedef void AudreyUiPlayQueue;
|
||||||
|
|
||||||
|
// Mpris
|
||||||
|
typedef void AudreyMpris;
|
||||||
|
AudreyMpris *audrey_mpris_new(void *window);
|
||||||
|
guint audrey_mpris_register_object(AudreyMpris *self, GDBusConnection *conn, const gchar *object_path, GError **error);
|
||||||
|
|
||||||
|
// ui::Setup
|
||||||
|
typedef void AudreyUiSetup;
|
||||||
|
AudreyUiSetup *audrey_ui_setup_new();
|
||||||
|
void audrey_ui_setup_load(AudreyUiSetup *self);
|
62
src/rust.vapi
Normal file
62
src/rust.vapi
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
[CCode (cheader_filename = "rust.h")]
|
||||||
|
namespace Audrey {
|
||||||
|
|
||||||
|
public class Ui.Playbar : Adw.Bin {
|
||||||
|
public PlaybinSong? song { get; set; }
|
||||||
|
public Gdk.Paintable? playing_cover_art { get; set; }
|
||||||
|
public weak Playbin playbin { get; set; }
|
||||||
|
public bool show_cover_art { get; set; /*default = true;*/ }
|
||||||
|
public int volume { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Ui.PlayQueueSong : Gtk.Box {
|
||||||
|
public bool draggable { get; set; }
|
||||||
|
public bool show_position { get; set; }
|
||||||
|
public bool show_artist { get; set; }
|
||||||
|
public bool show_cover { get; set; }
|
||||||
|
public bool current { get; set; }
|
||||||
|
public uint displayed_position { get; set; }
|
||||||
|
public PlaybinSong song { get; set; }
|
||||||
|
|
||||||
|
public PlayQueueSong (Playbin playbin);
|
||||||
|
public void bind (uint position, PlaybinSong song);
|
||||||
|
public void unbind ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Ui.PlayQueue : Adw.Bin {
|
||||||
|
public Playbin playbin { get; set; }
|
||||||
|
public bool can_clear_all { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Ui.Setup : Adw.PreferencesDialog {
|
||||||
|
public string status { get; }
|
||||||
|
public bool authn_can_edit { get; }
|
||||||
|
public bool authn_can_validate { get; }
|
||||||
|
public string server_url { get; set; }
|
||||||
|
public string username { get; set; }
|
||||||
|
public string password { get; set; }
|
||||||
|
|
||||||
|
public signal void connected (Subsonic.Client api);
|
||||||
|
|
||||||
|
public Setup ();
|
||||||
|
public void load ();
|
||||||
|
public void save ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Ui.Window : Adw.ApplicationWindow {
|
||||||
|
public int volume { get; set; }
|
||||||
|
public bool mute { get; set; }
|
||||||
|
|
||||||
|
public PlaybinSong? song { get; }
|
||||||
|
public Gdk.Paintable? playing_cover_art { get; set; }
|
||||||
|
|
||||||
|
public bool cover_art_loading { get; set; }
|
||||||
|
|
||||||
|
public Playbin playbin { get; }
|
||||||
|
|
||||||
|
public Window (Gtk.Application app);
|
||||||
|
|
||||||
|
public bool can_click_shuffle_all { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
236
src/subsonic.vala
Normal file
236
src/subsonic.vala
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
public errordomain Audrey.Subsonic.Error {
|
||||||
|
BAD_AUTHN,
|
||||||
|
ERROR,
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void Audrey.Subsonic.SongCallback (Song song);
|
||||||
|
|
||||||
|
public class Audrey.Subsonic.Artist : Object {
|
||||||
|
public string index;
|
||||||
|
public string id;
|
||||||
|
public string name { get; private set; }
|
||||||
|
public string? cover_art;
|
||||||
|
public string? artist_image_url;
|
||||||
|
public int64 album_count;
|
||||||
|
|
||||||
|
public Artist (string index, Json.Reader reader) {
|
||||||
|
this.index = index;
|
||||||
|
|
||||||
|
reader.read_member ("id");
|
||||||
|
this.id = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("name");
|
||||||
|
this.name = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("coverArt");
|
||||||
|
this.cover_art = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("artistImageUrl");
|
||||||
|
this.artist_image_url = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("albumCount");
|
||||||
|
this.album_count = reader.get_int_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Audrey.Subsonic.Album : Object {
|
||||||
|
public string id;
|
||||||
|
public string name;
|
||||||
|
|
||||||
|
public Album (Json.Reader reader) {
|
||||||
|
reader.read_member ("id");
|
||||||
|
this.id = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("name");
|
||||||
|
this.name = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Audrey.Subsonic.Song {
|
||||||
|
public string id;
|
||||||
|
public string title;
|
||||||
|
public string album;
|
||||||
|
public string artist;
|
||||||
|
public int64 track;
|
||||||
|
public int64 year;
|
||||||
|
public DateTime? starred; // TODO
|
||||||
|
public int64 duration;
|
||||||
|
public int64 play_count;
|
||||||
|
public string? genre;
|
||||||
|
public string cover_art;
|
||||||
|
|
||||||
|
public Song (Json.Reader reader) {
|
||||||
|
reader.read_member ("id");
|
||||||
|
this.id = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("title");
|
||||||
|
this.title = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("album");
|
||||||
|
this.album = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("artist");
|
||||||
|
this.artist = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("track");
|
||||||
|
this.track = reader.get_int_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("year");
|
||||||
|
this.year = reader.get_int_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("duration");
|
||||||
|
this.duration = reader.get_int_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("playCount");
|
||||||
|
this.play_count = reader.get_int_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("genre");
|
||||||
|
this.genre = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
|
||||||
|
reader.read_member ("coverArt");
|
||||||
|
this.cover_art = reader.get_string_value ();
|
||||||
|
reader.end_member ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Audrey.Subsonic.Client : Object {
|
||||||
|
private Soup.Session session;
|
||||||
|
private string url;
|
||||||
|
private string parameters;
|
||||||
|
|
||||||
|
public Client.with_token (string url, string username, string token, string salt) {
|
||||||
|
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.session = new Soup.Session ();
|
||||||
|
this.session.user_agent = Audrey.Const.user_agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unwrap_response (Json.Reader reader) throws GLib.Error {
|
||||||
|
reader.read_member ("subsonic-response");
|
||||||
|
|
||||||
|
reader.read_member ("status");
|
||||||
|
if (reader.get_string_value () != "ok") {
|
||||||
|
reader.end_member ();
|
||||||
|
reader.read_member ("error");
|
||||||
|
reader.read_member ("message");
|
||||||
|
throw new Subsonic.Error.ERROR (reader.get_string_value () ?? "???");
|
||||||
|
}
|
||||||
|
reader.end_member();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ping () throws GLib.Error {
|
||||||
|
var msg = new Soup.Message ("GET", @"$(this.url)/rest/ping?f=json&$(this.parameters)");
|
||||||
|
if (msg == null) {
|
||||||
|
throw new Subsonic.Error.BAD_AUTHN ("Bad message");
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = yield this.session.send_and_read_async (msg, Priority.DEFAULT, null);
|
||||||
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
|
||||||
|
var parser = new Json.Parser ();
|
||||||
|
parser.load_from_data ((string) bytes.get_data ());
|
||||||
|
|
||||||
|
var reader = new Json.Reader (parser.get_root ());
|
||||||
|
this.unwrap_response (reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)");
|
||||||
|
assert (msg != null);
|
||||||
|
|
||||||
|
var bytes = yield this.session.send_and_read_async (msg, Priority.DEFAULT, null);
|
||||||
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
|
||||||
|
var parser = new Json.Parser ();
|
||||||
|
parser.load_from_data ((string) bytes.get_data ());
|
||||||
|
|
||||||
|
var reader = new Json.Reader (parser.get_root ());
|
||||||
|
this.unwrap_response (reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void get_random_songs (string? parameters, SongCallback callback) throws GLib.Error {
|
||||||
|
string str_parameters;
|
||||||
|
if (parameters == null) {
|
||||||
|
str_parameters = "";
|
||||||
|
} else {
|
||||||
|
str_parameters = @"$parameters&";
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = new Soup.Message("GET", @"$(this.url)/rest/getRandomSongs?$(str_parameters)size=500&f=json&$(this.parameters)");
|
||||||
|
assert (msg != null);
|
||||||
|
|
||||||
|
var bytes = yield this.session.send_and_read_async (msg, Priority.DEFAULT, null);
|
||||||
|
assert (msg.get_status () == Soup.Status.OK);
|
||||||
|
|
||||||
|
var parser = new Json.Parser ();
|
||||||
|
parser.load_from_data ((string) bytes.get_data ());
|
||||||
|
|
||||||
|
var reader = new Json.Reader (parser.get_root ());
|
||||||
|
this.unwrap_response (reader);
|
||||||
|
|
||||||
|
reader.read_member ("randomSongs");
|
||||||
|
reader.read_member ("song");
|
||||||
|
|
||||||
|
for (int i = 0; i < reader.count_elements (); i += 1) {
|
||||||
|
reader.read_element (i);
|
||||||
|
callback (Song (reader));
|
||||||
|
reader.end_element ();
|
||||||
|
|
||||||
|
Idle.add (this.get_random_songs.callback);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (reader.get_error () == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string stream_uri (string id) {
|
||||||
|
return @"$(this.url)/rest/stream?id=$(Uri.escape_string(id))&$(this.parameters)";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string cover_art_uri (string id, int size = -1) {
|
||||||
|
if (size >= 0) {
|
||||||
|
return @"$(this.url)/rest/getCoverArt?id=$(Uri.escape_string(id))&$(this.parameters)";
|
||||||
|
} else {
|
||||||
|
return @"$(this.url)/rest/getCoverArt?size=$size&id=$(Uri.escape_string(id))&$(this.parameters)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Gdk.Pixbuf cover_art (
|
||||||
|
string id,
|
||||||
|
int size = -1,
|
||||||
|
int priority = Priority.DEFAULT,
|
||||||
|
Cancellable? cancellable = null
|
||||||
|
)
|
||||||
|
throws GLib.Error
|
||||||
|
{
|
||||||
|
var msg = new Soup.Message("GET", this.cover_art_uri (id, size));
|
||||||
|
assert (msg != null);
|
||||||
|
|
||||||
|
var stream = yield this.session.send_async (msg, priority, cancellable);
|
||||||
|
if (msg.get_status () != Soup.Status.OK) {
|
||||||
|
warning ("could not load cover art for %s: %s", id, Soup.Status.get_phrase (msg.get_status ()));
|
||||||
|
}
|
||||||
|
return yield new Gdk.Pixbuf.from_stream_async (stream, cancellable);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Client () {
|
||||||
|
debug ("destroying subsonic client");
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ pub struct Child {
|
||||||
pub starred: Option<chrono::DateTime<chrono::offset::Utc>>, // TODO: check which is best
|
pub starred: Option<chrono::DateTime<chrono::offset::Utc>>, // TODO: check which is best
|
||||||
// applicable
|
// applicable
|
||||||
pub duration: u64,
|
pub duration: u64,
|
||||||
//pub play_count: Option<u32>,
|
pub play_count: Option<u32>,
|
||||||
pub genre: Option<String>,
|
pub genre: Option<String>,
|
||||||
pub cover_art: String,
|
pub cover_art: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,23 +54,23 @@ mod imp {
|
||||||
#[gtk::template_callbacks]
|
#[gtk::template_callbacks]
|
||||||
impl Playbar {
|
impl Playbar {
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn song_title(&self, song: Option<&PlaybinSong>) -> Option<String> {
|
fn song_title(&self, song: Option<&PlaybinSong>) -> Option<GString> {
|
||||||
song.map(|song| song.title())
|
song.map(|song| song.title())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn song_artist(&self, song: Option<&PlaybinSong>) -> Option<String> {
|
fn song_artist(&self, song: Option<&PlaybinSong>) -> Option<GString> {
|
||||||
song.map(|song| song.artist())
|
song.map(|song| song.artist())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn song_album(&self, song: Option<&PlaybinSong>) -> Option<String> {
|
fn song_album(&self, song: Option<&PlaybinSong>) -> Option<GString> {
|
||||||
song.map(|song| song.album())
|
song.map(|song| song.album())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn format_timestamp(&self, s: f64) -> String {
|
fn format_timestamp(&self, s: f64) -> GString {
|
||||||
format!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60)
|
gformat!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
|
@ -7,6 +7,12 @@ mod imp {
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
impl crate::playbin2::PlaybinEntry for PlaybinSong {
|
||||||
|
fn url(&self) -> url::Url {
|
||||||
|
self.stream_url()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||||
#[template(resource = "/eu/callcc/audrey/window.ui")]
|
#[template(resource = "/eu/callcc/audrey/window.ui")]
|
||||||
#[properties(wrapper_type = super::Window)]
|
#[properties(wrapper_type = super::Window)]
|
||||||
|
|
829
src/vapi/libgcrypt.vapi
Normal file
829
src/vapi/libgcrypt.vapi
Normal file
|
@ -0,0 +1,829 @@
|
||||||
|
/* gcrypt.vapi
|
||||||
|
*
|
||||||
|
* Copyright:
|
||||||
|
* 2008 Jiqing Qiang
|
||||||
|
* 2008, 2010, 2012-2013 Evan Nemerson
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Author:
|
||||||
|
* Jiqing Qiang <jiqing.qiang@gmail.com>
|
||||||
|
* Evan Nemerson <evan@coeus-group.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
[CCode (cheader_filename = "gcrypt.h", lower_case_cprefix = "gcry_")]
|
||||||
|
namespace GCrypt {
|
||||||
|
[CCode (cname = "gpg_err_source_t", cprefix = "GPG_ERR_SOURCE_")]
|
||||||
|
public enum ErrorSource {
|
||||||
|
UNKNOWN,
|
||||||
|
GCRYPT,
|
||||||
|
GPG,
|
||||||
|
GPGSM,
|
||||||
|
GPGAGENT,
|
||||||
|
PINENTRY,
|
||||||
|
SCD,
|
||||||
|
GPGME,
|
||||||
|
KEYBOX,
|
||||||
|
KSBA,
|
||||||
|
DIRMNGR,
|
||||||
|
GSTI,
|
||||||
|
ANY,
|
||||||
|
USER_1,
|
||||||
|
USER_2,
|
||||||
|
USER_3,
|
||||||
|
USER_4,
|
||||||
|
|
||||||
|
/* This is one more than the largest allowed entry. */
|
||||||
|
DIM
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "gpg_err_code_t", cprefix = "GPG_ERR_")]
|
||||||
|
public enum ErrorCode {
|
||||||
|
NO_ERROR,
|
||||||
|
GENERAL,
|
||||||
|
UNKNOWN_PACKET,
|
||||||
|
UNKNOWN_VERSION,
|
||||||
|
PUBKEY_ALGO,
|
||||||
|
DIGEST_ALGO,
|
||||||
|
BAD_PUBKEY,
|
||||||
|
BAD_SECKEY,
|
||||||
|
BAD_SIGNATURE,
|
||||||
|
NO_PUBKEY,
|
||||||
|
CHECKSUM,
|
||||||
|
BAD_PASSPHRASE,
|
||||||
|
CIPHER_ALGO,
|
||||||
|
KEYRING_OPEN,
|
||||||
|
INV_PACKET,
|
||||||
|
INV_ARMOR,
|
||||||
|
NO_USER_ID,
|
||||||
|
NO_SECKEY,
|
||||||
|
WRONG_SECKEY,
|
||||||
|
BAD_KEY,
|
||||||
|
COMPR_ALGO,
|
||||||
|
NO_PRIME,
|
||||||
|
NO_ENCODING_METHOD,
|
||||||
|
NO_ENCRYPTION_SCHEME,
|
||||||
|
NO_SIGNATURE_SCHEME,
|
||||||
|
INV_ATTR,
|
||||||
|
NO_VALUE,
|
||||||
|
NOT_FOUND,
|
||||||
|
VALUE_NOT_FOUND,
|
||||||
|
SYNTAX,
|
||||||
|
BAD_MPI,
|
||||||
|
INV_PASSPHRASE,
|
||||||
|
SIG_CLASS,
|
||||||
|
RESOURCE_LIMIT,
|
||||||
|
INV_KEYRING,
|
||||||
|
TRUSTDB,
|
||||||
|
BAD_CERT,
|
||||||
|
INV_USER_ID,
|
||||||
|
UNEXPECTED,
|
||||||
|
TIME_CONFLICT,
|
||||||
|
KEYSERVER,
|
||||||
|
WRONG_PUBKEY_ALGO,
|
||||||
|
TRIBUTE_TO_D_A,
|
||||||
|
WEAK_KEY,
|
||||||
|
INV_KEYLEN,
|
||||||
|
INV_ARG,
|
||||||
|
BAD_URI,
|
||||||
|
INV_URI,
|
||||||
|
NETWORK,
|
||||||
|
UNKNOWN_HOST,
|
||||||
|
SELFTEST_FAILED,
|
||||||
|
NOT_ENCRYPTED,
|
||||||
|
NOT_PROCESSED,
|
||||||
|
UNUSABLE_PUBKEY,
|
||||||
|
UNUSABLE_SECKEY,
|
||||||
|
INV_VALUE,
|
||||||
|
BAD_CERT_CHAIN,
|
||||||
|
MISSING_CERT,
|
||||||
|
NO_DATA,
|
||||||
|
BUG,
|
||||||
|
NOT_SUPPORTED,
|
||||||
|
INV_OP,
|
||||||
|
TIMEOUT,
|
||||||
|
INTERNAL,
|
||||||
|
EOF_GCRYPT,
|
||||||
|
INV_OBJ,
|
||||||
|
TOO_SHORT,
|
||||||
|
TOO_LARGE,
|
||||||
|
NO_OBJ,
|
||||||
|
NOT_IMPLEMENTED,
|
||||||
|
CONFLICT,
|
||||||
|
INV_CIPHER_MODE,
|
||||||
|
INV_FLAG,
|
||||||
|
INV_HANDLE,
|
||||||
|
TRUNCATED,
|
||||||
|
INCOMPLETE_LINE,
|
||||||
|
INV_RESPONSE,
|
||||||
|
NO_AGENT,
|
||||||
|
AGENT,
|
||||||
|
INV_DATA,
|
||||||
|
ASSUAN_SERVER_FAULT,
|
||||||
|
ASSUAN,
|
||||||
|
INV_SESSION_KEY,
|
||||||
|
INV_SEXP,
|
||||||
|
UNSUPPORTED_ALGORITHM,
|
||||||
|
NO_PIN_ENTRY,
|
||||||
|
PIN_ENTRY,
|
||||||
|
BAD_PIN,
|
||||||
|
INV_NAME,
|
||||||
|
BAD_DATA,
|
||||||
|
INV_PARAMETER,
|
||||||
|
WRONG_CARD,
|
||||||
|
NO_DIRMNGR,
|
||||||
|
DIRMNGR,
|
||||||
|
CERT_REVOKED,
|
||||||
|
NO_CRL_KNOWN,
|
||||||
|
CRL_TOO_OLD,
|
||||||
|
LINE_TOO_LONG,
|
||||||
|
NOT_TRUSTED,
|
||||||
|
CANCELED,
|
||||||
|
BAD_CA_CERT,
|
||||||
|
CERT_EXPIRED,
|
||||||
|
CERT_TOO_YOUNG,
|
||||||
|
UNSUPPORTED_CERT,
|
||||||
|
UNKNOWN_SEXP,
|
||||||
|
UNSUPPORTED_PROTECTION,
|
||||||
|
CORRUPTED_PROTECTION,
|
||||||
|
AMBIGUOUS_NAME,
|
||||||
|
CARD,
|
||||||
|
CARD_RESET,
|
||||||
|
CARD_REMOVED,
|
||||||
|
INV_CARD,
|
||||||
|
CARD_NOT_PRESENT,
|
||||||
|
NO_PKCS15_APP,
|
||||||
|
NOT_CONFIRMED,
|
||||||
|
CONFIGURATION,
|
||||||
|
NO_POLICY_MATCH,
|
||||||
|
INV_INDEX,
|
||||||
|
INV_ID,
|
||||||
|
NO_SCDAEMON,
|
||||||
|
SCDAEMON,
|
||||||
|
UNSUPPORTED_PROTOCOL,
|
||||||
|
BAD_PIN_METHOD,
|
||||||
|
CARD_NOT_INITIALIZED,
|
||||||
|
UNSUPPORTED_OPERATION,
|
||||||
|
WRONG_KEY_USAGE,
|
||||||
|
NOTHING_FOUND,
|
||||||
|
WRONG_BLOB_TYPE,
|
||||||
|
MISSING_VALUE,
|
||||||
|
HARDWARE,
|
||||||
|
PIN_BLOCKED,
|
||||||
|
USE_CONDITIONS,
|
||||||
|
PIN_NOT_SYNCED,
|
||||||
|
INV_CRL,
|
||||||
|
BAD_BER,
|
||||||
|
INV_BER,
|
||||||
|
ELEMENT_NOT_FOUND,
|
||||||
|
IDENTIFIER_NOT_FOUND,
|
||||||
|
INV_TAG,
|
||||||
|
INV_LENGTH,
|
||||||
|
INV_KEYINFO,
|
||||||
|
UNEXPECTED_TAG,
|
||||||
|
NOT_DER_ENCODED,
|
||||||
|
NO_CMS_OBJ,
|
||||||
|
INV_CMS_OBJ,
|
||||||
|
UNKNOWN_CMS_OBJ,
|
||||||
|
UNSUPPORTED_CMS_OBJ,
|
||||||
|
UNSUPPORTED_ENCODING,
|
||||||
|
UNSUPPORTED_CMS_VERSION,
|
||||||
|
UNKNOWN_ALGORITHM,
|
||||||
|
INV_ENGINE,
|
||||||
|
PUBKEY_NOT_TRUSTED,
|
||||||
|
DECRYPT_FAILED,
|
||||||
|
KEY_EXPIRED,
|
||||||
|
SIG_EXPIRED,
|
||||||
|
ENCODING_PROBLEM,
|
||||||
|
INV_STATE,
|
||||||
|
DUP_VALUE,
|
||||||
|
MISSING_ACTION,
|
||||||
|
MODULE_NOT_FOUND,
|
||||||
|
INV_OID_STRING,
|
||||||
|
INV_TIME,
|
||||||
|
INV_CRL_OBJ,
|
||||||
|
UNSUPPORTED_CRL_VERSION,
|
||||||
|
INV_CERT_OBJ,
|
||||||
|
UNKNOWN_NAME,
|
||||||
|
LOCALE_PROBLEM,
|
||||||
|
NOT_LOCKED,
|
||||||
|
PROTOCOL_VIOLATION,
|
||||||
|
INV_MAC,
|
||||||
|
INV_REQUEST,
|
||||||
|
UNKNOWN_EXTN,
|
||||||
|
UNKNOWN_CRIT_EXTN,
|
||||||
|
LOCKED,
|
||||||
|
UNKNOWN_OPTION,
|
||||||
|
UNKNOWN_COMMAND,
|
||||||
|
BUFFER_TOO_SHORT,
|
||||||
|
SEXP_INV_LEN_SPEC,
|
||||||
|
SEXP_STRING_TOO_LONG,
|
||||||
|
SEXP_UNMATCHED_PAREN,
|
||||||
|
SEXP_NOT_CANONICAL,
|
||||||
|
SEXP_BAD_CHARACTER,
|
||||||
|
SEXP_BAD_QUOTATION,
|
||||||
|
SEXP_ZERO_PREFIX,
|
||||||
|
SEXP_NESTED_DH,
|
||||||
|
SEXP_UNMATCHED_DH,
|
||||||
|
SEXP_UNEXPECTED_PUNC,
|
||||||
|
SEXP_BAD_HEX_CHAR,
|
||||||
|
SEXP_ODD_HEX_NUMBERS,
|
||||||
|
SEXP_BAD_OCT_CHAR,
|
||||||
|
ASS_GENERAL,
|
||||||
|
ASS_ACCEPT_FAILED,
|
||||||
|
ASS_CONNECT_FAILED,
|
||||||
|
ASS_INV_RESPONSE,
|
||||||
|
ASS_INV_VALUE,
|
||||||
|
ASS_INCOMPLETE_LINE,
|
||||||
|
ASS_LINE_TOO_LONG,
|
||||||
|
ASS_NESTED_COMMANDS,
|
||||||
|
ASS_NO_DATA_CB,
|
||||||
|
ASS_NO_INQUIRE_CB,
|
||||||
|
ASS_NOT_A_SERVER,
|
||||||
|
ASS_NOT_A_CLIENT,
|
||||||
|
ASS_SERVER_START,
|
||||||
|
ASS_READ_ERROR,
|
||||||
|
ASS_WRITE_ERROR,
|
||||||
|
ASS_TOO_MUCH_DATA,
|
||||||
|
ASS_UNEXPECTED_CMD,
|
||||||
|
ASS_UNKNOWN_CMD,
|
||||||
|
ASS_SYNTAX,
|
||||||
|
ASS_CANCELED,
|
||||||
|
ASS_NO_INPUT,
|
||||||
|
ASS_NO_OUTPUT,
|
||||||
|
ASS_PARAMETER,
|
||||||
|
ASS_UNKNOWN_INQUIRE,
|
||||||
|
USER_1,
|
||||||
|
USER_2,
|
||||||
|
USER_3,
|
||||||
|
USER_4,
|
||||||
|
USER_5,
|
||||||
|
USER_6,
|
||||||
|
USER_7,
|
||||||
|
USER_8,
|
||||||
|
USER_9,
|
||||||
|
USER_10,
|
||||||
|
USER_11,
|
||||||
|
USER_12,
|
||||||
|
USER_13,
|
||||||
|
USER_14,
|
||||||
|
USER_15,
|
||||||
|
USER_16,
|
||||||
|
MISSING_ERRNO,
|
||||||
|
UNKNOWN_ERRNO,
|
||||||
|
EOF,
|
||||||
|
|
||||||
|
E2BIG,
|
||||||
|
EACCES,
|
||||||
|
EADDRINUSE,
|
||||||
|
EADDRNOTAVAIL,
|
||||||
|
EADV,
|
||||||
|
EAFNOSUPPORT,
|
||||||
|
EAGAIN,
|
||||||
|
EALREADY,
|
||||||
|
EAUTH,
|
||||||
|
EBACKGROUND,
|
||||||
|
EBADE,
|
||||||
|
EBADF,
|
||||||
|
EBADFD,
|
||||||
|
EBADMSG,
|
||||||
|
EBADR,
|
||||||
|
EBADRPC,
|
||||||
|
EBADRQC,
|
||||||
|
EBADSLT,
|
||||||
|
EBFONT,
|
||||||
|
EBUSY,
|
||||||
|
ECANCELED,
|
||||||
|
ECHILD,
|
||||||
|
ECHRNG,
|
||||||
|
ECOMM,
|
||||||
|
ECONNABORTED,
|
||||||
|
ECONNREFUSED,
|
||||||
|
ECONNRESET,
|
||||||
|
ED,
|
||||||
|
EDEADLK,
|
||||||
|
EDEADLOCK,
|
||||||
|
EDESTADDRREQ,
|
||||||
|
EDIED,
|
||||||
|
EDOM,
|
||||||
|
EDOTDOT,
|
||||||
|
EDQUOT,
|
||||||
|
EEXIST,
|
||||||
|
EFAULT,
|
||||||
|
EFBIG,
|
||||||
|
EFTYPE,
|
||||||
|
EGRATUITOUS,
|
||||||
|
EGREGIOUS,
|
||||||
|
EHOSTDOWN,
|
||||||
|
EHOSTUNREACH,
|
||||||
|
EIDRM,
|
||||||
|
EIEIO,
|
||||||
|
EILSEQ,
|
||||||
|
EINPROGRESS,
|
||||||
|
EINTR,
|
||||||
|
EINVAL,
|
||||||
|
EIO,
|
||||||
|
EISCONN,
|
||||||
|
EISDIR,
|
||||||
|
EISNAM,
|
||||||
|
EL2HLT,
|
||||||
|
EL2NSYNC,
|
||||||
|
EL3HLT,
|
||||||
|
EL3RST,
|
||||||
|
ELIBACC,
|
||||||
|
ELIBBAD,
|
||||||
|
ELIBEXEC,
|
||||||
|
ELIBMAX,
|
||||||
|
ELIBSCN,
|
||||||
|
ELNRNG,
|
||||||
|
ELOOP,
|
||||||
|
EMEDIUMTYPE,
|
||||||
|
EMFILE,
|
||||||
|
EMLINK,
|
||||||
|
EMSGSIZE,
|
||||||
|
EMULTIHOP,
|
||||||
|
ENAMETOOLONG,
|
||||||
|
ENAVAIL,
|
||||||
|
ENEEDAUTH,
|
||||||
|
ENETDOWN,
|
||||||
|
ENETRESET,
|
||||||
|
ENETUNREACH,
|
||||||
|
ENFILE,
|
||||||
|
ENOANO,
|
||||||
|
ENOBUFS,
|
||||||
|
ENOCSI,
|
||||||
|
ENODATA,
|
||||||
|
ENODEV,
|
||||||
|
ENOENT,
|
||||||
|
ENOEXEC,
|
||||||
|
ENOLCK,
|
||||||
|
ENOLINK,
|
||||||
|
ENOMEDIUM,
|
||||||
|
ENOMEM,
|
||||||
|
ENOMSG,
|
||||||
|
ENONET,
|
||||||
|
ENOPKG,
|
||||||
|
ENOPROTOOPT,
|
||||||
|
ENOSPC,
|
||||||
|
ENOSR,
|
||||||
|
ENOSTR,
|
||||||
|
ENOSYS,
|
||||||
|
ENOTBLK,
|
||||||
|
ENOTCONN,
|
||||||
|
ENOTDIR,
|
||||||
|
ENOTEMPTY,
|
||||||
|
ENOTNAM,
|
||||||
|
ENOTSOCK,
|
||||||
|
ENOTSUP,
|
||||||
|
ENOTTY,
|
||||||
|
ENOTUNIQ,
|
||||||
|
ENXIO,
|
||||||
|
EOPNOTSUPP,
|
||||||
|
EOVERFLOW,
|
||||||
|
EPERM,
|
||||||
|
EPFNOSUPPORT,
|
||||||
|
EPIPE,
|
||||||
|
EPROCLIM,
|
||||||
|
EPROCUNAVAIL,
|
||||||
|
EPROGMISMATCH,
|
||||||
|
EPROGUNAVAIL,
|
||||||
|
EPROTO,
|
||||||
|
EPROTONOSUPPORT,
|
||||||
|
EPROTOTYPE,
|
||||||
|
ERANGE,
|
||||||
|
EREMCHG,
|
||||||
|
EREMOTE,
|
||||||
|
EREMOTEIO,
|
||||||
|
ERESTART,
|
||||||
|
EROFS,
|
||||||
|
ERPCMISMATCH,
|
||||||
|
ESHUTDOWN,
|
||||||
|
ESOCKTNOSUPPORT,
|
||||||
|
ESPIPE,
|
||||||
|
ESRCH,
|
||||||
|
ESRMNT,
|
||||||
|
ESTALE,
|
||||||
|
ESTRPIPE,
|
||||||
|
ETIME,
|
||||||
|
ETIMEDOUT,
|
||||||
|
ETOOMANYREFS,
|
||||||
|
ETXTBSY,
|
||||||
|
EUCLEAN,
|
||||||
|
EUNATCH,
|
||||||
|
EUSERS,
|
||||||
|
EWOULDBLOCK,
|
||||||
|
EXDEV,
|
||||||
|
EXFULL,
|
||||||
|
|
||||||
|
/* This is one more than the largest allowed entry. */
|
||||||
|
CODE_DIM
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_error_t", cprefix = "gpg_err_")]
|
||||||
|
public struct Error : uint {
|
||||||
|
[CCode (cname = "gcry_err_make")]
|
||||||
|
public Error (ErrorSource source, ErrorCode code);
|
||||||
|
[CCode (cname = "gcry_err_make_from_errno")]
|
||||||
|
public Error.from_errno (ErrorSource source, int err);
|
||||||
|
public ErrorCode code ();
|
||||||
|
public ErrorSource source ();
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_strerror")]
|
||||||
|
public unowned string to_string ();
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_strsource")]
|
||||||
|
public unowned string source_to_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "enum gcry_ctl_cmds", cprefix = "GCRYCTL_")]
|
||||||
|
public enum ControlCommand {
|
||||||
|
SET_KEY,
|
||||||
|
SET_IV,
|
||||||
|
CFB_SYNC,
|
||||||
|
RESET,
|
||||||
|
FINALIZE,
|
||||||
|
GET_KEYLEN,
|
||||||
|
GET_BLKLEN,
|
||||||
|
TEST_ALGO,
|
||||||
|
IS_SECURE,
|
||||||
|
GET_ASNOID,
|
||||||
|
ENABLE_ALGO,
|
||||||
|
DISABLE_ALGO,
|
||||||
|
DUMP_RANDOM_STATS,
|
||||||
|
DUMP_SECMEM_STATS,
|
||||||
|
GET_ALGO_NPKEY,
|
||||||
|
GET_ALGO_NSKEY,
|
||||||
|
GET_ALGO_NSIGN,
|
||||||
|
GET_ALGO_NENCR,
|
||||||
|
SET_VERBOSITY,
|
||||||
|
SET_DEBUG_FLAGS,
|
||||||
|
CLEAR_DEBUG_FLAGS,
|
||||||
|
USE_SECURE_RNDPOOL,
|
||||||
|
DUMP_MEMORY_STATS,
|
||||||
|
INIT_SECMEM,
|
||||||
|
TERM_SECMEM,
|
||||||
|
DISABLE_SECMEM_WARN,
|
||||||
|
SUSPEND_SECMEM_WARN,
|
||||||
|
RESUME_SECMEM_WARN,
|
||||||
|
DROP_PRIVS,
|
||||||
|
ENABLE_M_GUARD,
|
||||||
|
START_DUMP,
|
||||||
|
STOP_DUMP,
|
||||||
|
GET_ALGO_USAGE,
|
||||||
|
IS_ALGO_ENABLED,
|
||||||
|
DISABLE_INTERNAL_LOCKING,
|
||||||
|
DISABLE_SECMEM,
|
||||||
|
INITIALIZATION_FINISHED,
|
||||||
|
INITIALIZATION_FINISHED_P,
|
||||||
|
ANY_INITIALIZATION_P,
|
||||||
|
SET_CBC_CTS,
|
||||||
|
SET_CBC_MAC,
|
||||||
|
SET_CTR,
|
||||||
|
ENABLE_QUICK_RANDOM,
|
||||||
|
SET_RANDOM_SEED_FILE,
|
||||||
|
UPDATE_RANDOM_SEED_FILE,
|
||||||
|
SET_THREAD_CBS,
|
||||||
|
FAST_POLL
|
||||||
|
}
|
||||||
|
public Error control (ControlCommand cmd, ...);
|
||||||
|
|
||||||
|
namespace Cipher {
|
||||||
|
[CCode (cname = "enum gcry_cipher_algos", cprefix = "GCRY_CIPHER_")]
|
||||||
|
public enum Algorithm {
|
||||||
|
NONE,
|
||||||
|
IDEA,
|
||||||
|
3DES,
|
||||||
|
CAST5,
|
||||||
|
BLOWFISH,
|
||||||
|
SAFER_SK128,
|
||||||
|
DES_SK,
|
||||||
|
AES,
|
||||||
|
AES128,
|
||||||
|
RIJNDAEL,
|
||||||
|
RIJNDAEL128,
|
||||||
|
AES192,
|
||||||
|
RIJNDAEL192,
|
||||||
|
AES256,
|
||||||
|
RIJNDAEL256,
|
||||||
|
TWOFISH,
|
||||||
|
TWOFISH128,
|
||||||
|
ARCFOUR,
|
||||||
|
DES,
|
||||||
|
SERPENT128,
|
||||||
|
SERPENT192,
|
||||||
|
SERPENT256,
|
||||||
|
RFC2268_40,
|
||||||
|
RFC2268_128,
|
||||||
|
SEED,
|
||||||
|
CAMELLIA128,
|
||||||
|
CAMELLIA192,
|
||||||
|
CAMELLIA256,
|
||||||
|
SALSA20,
|
||||||
|
SALSA20R12,
|
||||||
|
GOST28147,
|
||||||
|
CHACHA20;
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_cipher_algo_info")]
|
||||||
|
public Error info (ControlCommand what, [CCode (array_length_type = "size_t")] ref uchar[] buffer);
|
||||||
|
[CCode (cname = "gcry_cipher_algo_name")]
|
||||||
|
public unowned string to_string ();
|
||||||
|
[CCode (cname = "gcry_cipher_map_name")]
|
||||||
|
public static Algorithm from_string (string name);
|
||||||
|
[CCode (cname = "gcry_cipher_map_oid")]
|
||||||
|
public static Algorithm from_oid (string oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "enum gcry_cipher_modes", cprefix = "GCRY_CIPHER_MODE_")]
|
||||||
|
public enum Mode {
|
||||||
|
NONE, /* No mode specified */
|
||||||
|
ECB, /* Electronic Codebook */
|
||||||
|
CFB, /* Cipher Feedback */
|
||||||
|
CFB8, /* Cipher Feedback */
|
||||||
|
CBC, /* Cipher Block Chaining */
|
||||||
|
STREAM, /* Used with stream ciphers */
|
||||||
|
OFB, /* Output Feedback */
|
||||||
|
CTR, /* Counter */
|
||||||
|
AESWRAP,
|
||||||
|
CCM, /* Counter with CBC-MAC */
|
||||||
|
GCM, /* Galois/Counter Mode */
|
||||||
|
POLY1305,
|
||||||
|
OCB
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "enum gcry_cipher_flags", cprefix = "GCRY_CIPHER_")]
|
||||||
|
public enum Flag {
|
||||||
|
SECURE, /* Allocate in secure memory. */
|
||||||
|
ENABLE_SYNC, /* Enable CFB sync mode. */
|
||||||
|
CBC_CTS, /* Enable CBC cipher text stealing (CTS). */
|
||||||
|
CBC_MAC /* Enable CBC message auth. code (MAC). */
|
||||||
|
}
|
||||||
|
[Compact]
|
||||||
|
[CCode (cname = "struct gcry_cipher_handle", lower_case_cprefix = "gcry_cipher_", free_function = "gcry_cipher_close")]
|
||||||
|
public class Cipher {
|
||||||
|
public static Error open (out Cipher cipher, Algorithm algo, Mode mode, Flag flags);
|
||||||
|
public void close ();
|
||||||
|
[CCode (cname = "gcry_cipher_ctl")]
|
||||||
|
public Error control (ControlCommand cmd, [CCode (array_length_type = "size_t")] uchar[] buffer);
|
||||||
|
public Error info (ControlCommand what, [CCode (array_length_type = "size_t")] ref uchar[] buffer);
|
||||||
|
|
||||||
|
public Error encrypt (uchar[] out_buffer, uchar[] in_buffer);
|
||||||
|
public Error decrypt (uchar[] out_buffer, uchar[] in_buffer);
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_cipher_setkey")]
|
||||||
|
public Error set_key (uchar[] key_data);
|
||||||
|
[CCode (cname = "gcry_cipher_setiv")]
|
||||||
|
public Error set_iv (uchar[] iv_data);
|
||||||
|
[CCode (cname = "gcry_cipher_setctr")]
|
||||||
|
public Error set_counter_vector (uchar[] counter_vector);
|
||||||
|
public Error reset ();
|
||||||
|
public Error sync ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Compact, CCode (cname = "struct gcry_md_handle", cprefix = "gcry_md_", free_function = "gcry_md_close")]
|
||||||
|
public class Hash {
|
||||||
|
[CCode (cname = "enum gcry_md_algos", cprefix = "GCRY_MD_")]
|
||||||
|
public enum Algorithm {
|
||||||
|
NONE,
|
||||||
|
SHA1,
|
||||||
|
RMD160,
|
||||||
|
MD5,
|
||||||
|
MD4,
|
||||||
|
MD2,
|
||||||
|
TIGER,
|
||||||
|
TIGER1,
|
||||||
|
TIGER2,
|
||||||
|
HAVAL,
|
||||||
|
SHA224,
|
||||||
|
SHA256,
|
||||||
|
SHA384,
|
||||||
|
SHA512,
|
||||||
|
SHA3_224,
|
||||||
|
SHA3_256,
|
||||||
|
SHA3_384,
|
||||||
|
SHA3_512,
|
||||||
|
SHAKE128,
|
||||||
|
SHAKE256,
|
||||||
|
CRC32,
|
||||||
|
CRC32_RFC1510,
|
||||||
|
CRC24_RFC2440,
|
||||||
|
WHIRLPOOL,
|
||||||
|
GOSTR3411_94,
|
||||||
|
STRIBOG256,
|
||||||
|
STRIBOG512;
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_md_get_algo_dlen")]
|
||||||
|
public size_t get_digest_length ();
|
||||||
|
[CCode (cname = "gcry_md_algo_info")]
|
||||||
|
public Error info (ControlCommand what, [CCode (array_length_type = "size_t")] ref uchar[] buffer);
|
||||||
|
[CCode (cname = "gcry_md_algo_name")]
|
||||||
|
public unowned string to_string ();
|
||||||
|
[CCode (cname = "gcry_md_map_name")]
|
||||||
|
public static Algorithm from_string (string name);
|
||||||
|
[CCode (cname = "gcry_md_test_algo")]
|
||||||
|
public Error is_available ();
|
||||||
|
[CCode (cname = "gcry_md_get_asnoid")]
|
||||||
|
public Error get_oid ([CCode (array_length_type = "size_t")] ref uchar[] buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "enum gcry_md_flags", cprefix = "GCRY_MD_FLAG_")]
|
||||||
|
public enum Flag {
|
||||||
|
SECURE,
|
||||||
|
HMAC,
|
||||||
|
BUGEMU1
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Error open (out Hash hash, Algorithm algo, Flag flag);
|
||||||
|
public void close ();
|
||||||
|
public Error enable (Algorithm algo);
|
||||||
|
[CCode (instance_pos = -1)]
|
||||||
|
public Error copy (out Hash dst);
|
||||||
|
public void reset ();
|
||||||
|
[CCode (cname = "gcry_md_ctl")]
|
||||||
|
public Error control (ControlCommand cmd, [CCode (array_length_type = "size_t")] uchar[] buffer);
|
||||||
|
public void write (uchar[] buffer);
|
||||||
|
[CCode (array_length = false)]
|
||||||
|
public unowned uchar[] read (Algorithm algo);
|
||||||
|
public static void hash_buffer (Algorithm algo, [CCode (array_length = false)] uchar[] digest, uchar[] buffer);
|
||||||
|
public Algorithm get_algo ();
|
||||||
|
public bool is_enabled (Algorithm algo);
|
||||||
|
public bool is_secure ();
|
||||||
|
public Error info (ControlCommand what, [CCode (array_length_type = "size_t")] ref uchar[] buffer);
|
||||||
|
[CCode (cname = "gcry_md_setkey")]
|
||||||
|
public Error set_key (uchar[] key_data);
|
||||||
|
public void putc (char c);
|
||||||
|
public void final ();
|
||||||
|
public static Error list (ref Algorithm[] algos);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Random {
|
||||||
|
[CCode (cname = "gcry_random_level_t")]
|
||||||
|
public enum Level {
|
||||||
|
[CCode (cname = "GCRY_WEAK_RANDOM")]
|
||||||
|
WEAK,
|
||||||
|
[CCode (cname = "GCRY_STRONG_RANDOM")]
|
||||||
|
STRONG,
|
||||||
|
[CCode (cname = "GCRY_VERY_STRONG_RANDOM")]
|
||||||
|
VERY_STRONG
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_randomize")]
|
||||||
|
public static void randomize (uchar[] buffer, Level level = Level.VERY_STRONG);
|
||||||
|
[CCode (cname = "gcry_fast_random_poll")]
|
||||||
|
public static Error poll ();
|
||||||
|
[CCode (cname = "gcry_random_bytes", array_length = false)]
|
||||||
|
public static uchar[] random_bytes (size_t nbytes, Level level = Level.VERY_STRONG);
|
||||||
|
[CCode (cname = "gcry_random_bytes_secure", array_length = false)]
|
||||||
|
public static uchar[] random_bytes_secure (size_t nbytes, Level level = Level.VERY_STRONG);
|
||||||
|
[CCode (cname = "gcry_create_nonce")]
|
||||||
|
public static void nonce (uchar[] buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Compact, CCode (cname = "struct gcry_mpi", cprefix = "gcry_mpi_", free_function = "gcry_mpi_release")]
|
||||||
|
public class MPI {
|
||||||
|
[CCode (cname = "enum gcry_mpi_format", cprefix = "GCRYMPI_FMT_")]
|
||||||
|
public enum Format {
|
||||||
|
NONE,
|
||||||
|
STD,
|
||||||
|
PGP,
|
||||||
|
SSH,
|
||||||
|
HEX,
|
||||||
|
USG
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "enum gcry_mpi_flag", cprefix = "GCRYMPI_FLAG_")]
|
||||||
|
public enum Flag {
|
||||||
|
SECURE,
|
||||||
|
OPAQUE
|
||||||
|
}
|
||||||
|
|
||||||
|
public MPI (uint nbits);
|
||||||
|
[CCode (cname = "gcry_mpi_snew")]
|
||||||
|
public MPI.secure (uint nbits);
|
||||||
|
public MPI copy ();
|
||||||
|
public void set (MPI u);
|
||||||
|
public void set_ui (ulong u);
|
||||||
|
public void swap (MPI b);
|
||||||
|
public int cmp (MPI v);
|
||||||
|
public int cmp_ui (ulong v);
|
||||||
|
|
||||||
|
public static Error scan (out MPI ret, MPI.Format format, [CCode (array_length = false)] uchar[] buffer, size_t buflen, out size_t nscanned);
|
||||||
|
[CCode (instance_pos = -1)]
|
||||||
|
public Error print (MPI.Format format, [CCode (array_length = false)] uchar[] buffer, size_t buflen, out size_t nwritter);
|
||||||
|
[CCode (instance_pos = -1)]
|
||||||
|
public Error aprint (MPI.Format format, [CCode (array_length_type = "size_t")] out uchar[] buffer);
|
||||||
|
|
||||||
|
public void add (MPI u, MPI v);
|
||||||
|
public void add_ui (MPI u, ulong v);
|
||||||
|
public void addm (MPI u, MPI v, MPI m);
|
||||||
|
public void sub (MPI u, MPI v);
|
||||||
|
public void sub_ui (MPI u, ulong v);
|
||||||
|
public void subm (MPI u, MPI v, MPI m);
|
||||||
|
public void mul (MPI u, MPI v);
|
||||||
|
public void mul_ui (MPI u, ulong v);
|
||||||
|
public void mulm (MPI u, MPI v, MPI m);
|
||||||
|
public void mul_2exp (MPI u, ulong cnt);
|
||||||
|
public void div (MPI r, MPI dividend, MPI divisor, int round);
|
||||||
|
public void mod (MPI dividend, MPI divisor);
|
||||||
|
public void powm (MPI b, MPI e, MPI m);
|
||||||
|
public int gcd (MPI a, MPI b);
|
||||||
|
public int invm (MPI a, MPI m);
|
||||||
|
|
||||||
|
public uint get_nbits ();
|
||||||
|
public int test_bit (uint n);
|
||||||
|
public void set_bit (uint n);
|
||||||
|
public void clear_bit (uint n);
|
||||||
|
public void set_highbit (uint n);
|
||||||
|
public void clear_highbit (uint n);
|
||||||
|
public void rshift (MPI a, uint n);
|
||||||
|
public void lshift (MPI a, uint n);
|
||||||
|
|
||||||
|
public void set_flag (MPI.Flag flag);
|
||||||
|
public void clear_flag (MPI.Flag flag);
|
||||||
|
public int get_flag (MPI.Flag flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Compact, CCode (cname = "struct gcry_sexp", free_function = "gcry_sexp_release")]
|
||||||
|
public class SExp {
|
||||||
|
[CCode (cname = "int", cprefix = "GCRYSEXP_FMT_")]
|
||||||
|
public enum Format {
|
||||||
|
DEFAULT,
|
||||||
|
CANON,
|
||||||
|
BASE64,
|
||||||
|
ADVANCED
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Error @new (out SExp retsexp, void * buffer, size_t length, int autodetect);
|
||||||
|
public static Error create (out SExp retsexp, void * buffer, size_t length, int autodetect, GLib.DestroyNotify free_function);
|
||||||
|
public static Error sscan (out SExp retsexp, out size_t erroff, char[] buffer);
|
||||||
|
public static Error build (out SExp retsexp, out size_t erroff, string format, ...);
|
||||||
|
public size_t sprint (Format mode, char[] buffer);
|
||||||
|
public static size_t canon_len (uchar[] buffer, out size_t erroff, out int errcode);
|
||||||
|
public SExp find_token (string token, size_t token_length = 0);
|
||||||
|
public int length ();
|
||||||
|
public SExp? nth (int number);
|
||||||
|
public SExp? car ();
|
||||||
|
public SExp? cdr ();
|
||||||
|
[CCode (array_length_type = "size_t")]
|
||||||
|
public unowned char[] nth_data (int number);
|
||||||
|
public gcry_string nth_string (int number);
|
||||||
|
public MPI nth_mpi (int number, MPI.Format mpifmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "char", free_function = "gcry_free")]
|
||||||
|
public class gcry_string : string { }
|
||||||
|
|
||||||
|
[CCode (lower_case_cprefix = "gcry_pk_")]
|
||||||
|
namespace PublicKey {
|
||||||
|
[CCode (cname = "enum gcry_pk_algos")]
|
||||||
|
public enum Algorithm {
|
||||||
|
RSA,
|
||||||
|
ELG_E,
|
||||||
|
DSA,
|
||||||
|
ELG,
|
||||||
|
ECDSA;
|
||||||
|
|
||||||
|
[CCode (cname = "gcry_pk_algo_name")]
|
||||||
|
public unowned string to_string ();
|
||||||
|
[CCode (cname = "gcry_pk_map_name")]
|
||||||
|
public static Algorithm map_name (string name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Error encrypt (out SExp ciphertext, SExp data, SExp pkey);
|
||||||
|
public static Error decrypt (out SExp plaintext, SExp data, SExp skey);
|
||||||
|
public static Error sign (out SExp signature, SExp data, SExp skey);
|
||||||
|
public static Error verify (SExp signature, SExp data, SExp pkey);
|
||||||
|
public static Error testkey (SExp key);
|
||||||
|
public static Error genkey (out SExp r_key, SExp s_params);
|
||||||
|
public static uint get_nbits (SExp key);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (lower_case_cprefix = "gcry_kdf_")]
|
||||||
|
namespace KeyDerivation {
|
||||||
|
[CCode (cname = "enum gcry_kdf_algos", cprefix = "GCRY_KDF_", has_type_id = false)]
|
||||||
|
public enum Algorithm {
|
||||||
|
NONE,
|
||||||
|
SIMPLE_S2K,
|
||||||
|
SALTED_S2K,
|
||||||
|
ITERSALTED_S2K,
|
||||||
|
PBKDF1,
|
||||||
|
PBKDF2,
|
||||||
|
SCRYPT
|
||||||
|
}
|
||||||
|
|
||||||
|
public GCrypt.Error derive ([CCode (type = "const void*", array_length_type = "size_t")] uint8[] passphrasse, GCrypt.KeyDerivation.Algorithm algo, GCrypt.Hash.Algorithm subalgo, [CCode (type = "const void*", array_length_type = "size_t")] uint8[] salt, ulong iterations, [CCode (type = "void*", array_length_type = "size_t", array_length_pos = 5.5)] uint8[] keybuffer);
|
||||||
|
}
|
||||||
|
}
|
177
src/vapi/mpv.vapi
Normal file
177
src/vapi/mpv.vapi
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
[CCode (cheader_filename = "mpv/client.h")]
|
||||||
|
namespace Mpv {
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_error", cprefix = "MPV_ERROR_", has_type_id = false)]
|
||||||
|
public enum Error {
|
||||||
|
SUCCESS,
|
||||||
|
EVENT_QUEUE_FULL,
|
||||||
|
NOMEM,
|
||||||
|
UNINITIALIZED,
|
||||||
|
INVALID_PARAMETER,
|
||||||
|
OPTION_NOT_FOUND,
|
||||||
|
OPTION_FORMAT,
|
||||||
|
OPTION_ERROR,
|
||||||
|
PROPERTY_NOT_FOUND,
|
||||||
|
PROPERTY_FORMAT,
|
||||||
|
PROPERTY_UNAVAILABLE,
|
||||||
|
PROPERTY_ERROR,
|
||||||
|
COMMAND,
|
||||||
|
LOADING_FAILED,
|
||||||
|
AO_INIT_FAILED,
|
||||||
|
VO_INIT_FAILED,
|
||||||
|
NOTHING_TO_PLAY,
|
||||||
|
UNKNOWN_FORMAT,
|
||||||
|
UNSUPPORTED,
|
||||||
|
NOT_IMPLEMENTED,
|
||||||
|
GENERIC;
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_error_string")]
|
||||||
|
public unowned string to_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void WakeupCallback ();
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_handle", free_function = "mpv_terminate_destroy")]
|
||||||
|
[Compact]
|
||||||
|
public class Handle {
|
||||||
|
[CCode (cname = "mpv_create")]
|
||||||
|
public Handle ();
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_initialize")]
|
||||||
|
public Error initialize ();
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_wait_event")]
|
||||||
|
public unowned Event? wait_event (double timeout);
|
||||||
|
|
||||||
|
public WakeupCallback wakeup_callback {
|
||||||
|
[CCode (cname = "mpv_set_wakeup_callback")] set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_set_property")]
|
||||||
|
private Error set_property (string name, Format format, void *data);
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_set_property_string")]
|
||||||
|
public Error set_property_string (string name, string value);
|
||||||
|
|
||||||
|
public Error set_property_int64 (string name, int64 value) {
|
||||||
|
return this.set_property (name, Format.INT64, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Error set_property_flag (string name, bool value) {
|
||||||
|
int flag = value ? 1 : 0;
|
||||||
|
return this.set_property (name, Format.FLAG, &flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_command")]
|
||||||
|
public Error command ([CCode (array_length = false)] string[] args);
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_command_async")]
|
||||||
|
public Error command_async (uint64 reply_userdata, [CCode (array_length = false)] string[] args);
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_observe_property")]
|
||||||
|
public Error observe_property (uint64 reply_userdata, string name, Format format);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_format", cprefix = "MPV_FORMAT_", has_type_id = false)]
|
||||||
|
public enum Format {
|
||||||
|
NONE,
|
||||||
|
STRING,
|
||||||
|
OSD_STRING,
|
||||||
|
FLAG,
|
||||||
|
INT64,
|
||||||
|
DOUBLE,
|
||||||
|
NODE,
|
||||||
|
NODE_ARRAY,
|
||||||
|
NODE_MAP,
|
||||||
|
BYTE_ARRAY,
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_event_id", cprefix = "MPV_EVENT_", has_type_id = false)]
|
||||||
|
public enum EventId {
|
||||||
|
NONE,
|
||||||
|
SHUTDOWN,
|
||||||
|
LOG_MESSAGE,
|
||||||
|
GET_PROPERTY_REPLY,
|
||||||
|
SET_PROPERTY_REPLY,
|
||||||
|
COMMAND_REPLY,
|
||||||
|
START_FILE,
|
||||||
|
END_FILE,
|
||||||
|
FILE_LOADED,
|
||||||
|
CLIENT_MESSAGE,
|
||||||
|
VIDEO_RECONFIG,
|
||||||
|
AUDIO_RECONFIG,
|
||||||
|
SEEK,
|
||||||
|
PLAYBACK_RESTART,
|
||||||
|
PROPERTY_CHANGE,
|
||||||
|
QUEUE_OVERFLOW,
|
||||||
|
HOOK;
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_event_name")]
|
||||||
|
public unowned string to_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_event", destroy_function = "", has_type_id = false, has_copy_function = false)]
|
||||||
|
public struct Event {
|
||||||
|
EventId event_id;
|
||||||
|
Error error;
|
||||||
|
uint64 reply_userdata;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
public unowned EventProperty? parse_property ()
|
||||||
|
requires (event_id == EventId.PROPERTY_CHANGE)
|
||||||
|
requires (error >= 0)
|
||||||
|
{
|
||||||
|
return (EventProperty?) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public unowned EventEndFile? parse_end_file ()
|
||||||
|
requires (event_id == EventId.END_FILE)
|
||||||
|
requires (error >= 0)
|
||||||
|
{
|
||||||
|
return (EventEndFile?) data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_event_property", destroy_function = "", has_type_id = false, has_copy_function = false)]
|
||||||
|
public struct EventProperty {
|
||||||
|
unowned string name;
|
||||||
|
Format format;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
public int64 parse_int64 ()
|
||||||
|
requires (format == Format.INT64)
|
||||||
|
{
|
||||||
|
return * (int64 *) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double parse_double ()
|
||||||
|
requires (format == Format.DOUBLE)
|
||||||
|
{
|
||||||
|
return * (double *) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool parse_flag ()
|
||||||
|
requires (format == Format.FLAG)
|
||||||
|
{
|
||||||
|
return (* (int *) data) == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_event_end_file", destroy_function = "", has_type_id = false, has_copy_function = false)]
|
||||||
|
public struct EventEndFile {
|
||||||
|
EndFileReason reason;
|
||||||
|
Error error;
|
||||||
|
int64 playlist_entry_id;
|
||||||
|
int playlist_insert_num_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "mpv_end_file_reason", cprefix = "MPV_END_FILE_REASON_", has_type_id = false)]
|
||||||
|
public enum EndFileReason {
|
||||||
|
EOF,
|
||||||
|
STOP,
|
||||||
|
QUIT,
|
||||||
|
ERROR,
|
||||||
|
REDIRECT,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue