unity-lens-music-6.9.0+14.04.20151120.2/ 0000755 0000153 0000161 00000000000 12623574331 017444 5 ustar pbuser pbgroup 0000000 0000000 unity-lens-music-6.9.0+14.04.20151120.2/src/ 0000755 0000153 0000161 00000000000 12623574331 020233 5 ustar pbuser pbgroup 0000000 0000000 unity-lens-music-6.9.0+14.04.20151120.2/src/ubuntuone-webservices.vala 0000644 0000153 0000161 00000033350 12623574234 025451 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Alejandro J. Cura
*
*/
using Soup;
using Ubuntuone.Constants;
[DBus (name = "com.ubuntuone.CredentialsManagement")]
interface CredentialsManagement : GLib.Object {
public signal void credentials_found (HashTable info);
public signal void credentials_not_found ();
public signal void credentials_error (HashTable error_dict);
[DBus (name = "find_credentials")]
public abstract void find_credentials () throws Error;
}
namespace Ubuntuone.Webservice
{
public errordomain PurchaseError
{
MISSING_CREDENTIALS_ERROR,
PURCHASE_ERROR,
WRONG_PASSWORD_ERROR,
UNSPECIFIED_ERROR
}
public class PurchaseService : GLib.Object
{
internal Soup.SessionAsync http_session;
Soup.SessionAsync http_session_sso;
CredentialsManagement credentials_management;
public string nickname { get; private set; default = null; }
public string email { get; private set; default = null; }
public string selected_payment_method { get; internal set; default = null; }
public string consumer_key { get; private set; default = null; }
public string token { get; private set; default = null; }
public string open_url { get; private set; default = null; }
internal HashTable _ubuntuone_credentials = null;
construct {
http_session = build_http_session ();
http_session_sso = build_http_session ();
credentials_management = build_credentials_management ();
}
internal Soup.SessionAsync build_http_session ()
{
var session = new Soup.SessionAsync ();
session.user_agent = "%s/%s (libsoup)".printf("UbuntuOneMusicstoreLens", "1.0");
return session;
}
public bool got_credentials () {
return _ubuntuone_credentials != null;
}
internal virtual CredentialsManagement build_credentials_management ()
{
try {
return Bus.get_proxy_sync (BusType.SESSION, "com.ubuntuone.Credentials",
"/credentials", DBusProxyFlags.DO_NOT_AUTO_START);
} catch (IOError e) {
error ("Can't connect to DBus: %s", e.message);
}
}
public bool ready_to_purchase {
get { return selected_payment_method != null; }
}
internal Json.Object parse_json (string json_string) throws GLib.Error
{
var parser = new Json.Parser();
parser.load_from_data(json_string, -1);
return parser.get_root().get_object();
}
internal void parse_account_json (string json_string) throws GLib.Error
{
var root_object = parse_json (json_string);
nickname = root_object.get_string_member("nickname");
email = root_object.get_string_member("email");
}
internal void parse_payment_method_json (string json_string) throws GLib.Error, PurchaseError
{
var root_object = parse_json (json_string);
if (root_object.has_member ("selected_payment_method")) {
selected_payment_method = root_object.get_string_member("selected_payment_method");
} else {
open_url = root_object.get_string_member ("open_url");
var error_message = root_object.get_string_member ("error_message");
throw new PurchaseError.PURCHASE_ERROR (error_message);
}
}
internal void parse_authentication_json (string json_string) throws GLib.Error
{
var root_object = parse_json (json_string);
consumer_key = root_object.get_string_member ("consumer_key");
token = root_object.get_string_member ("token");
}
internal string parse_purchase_json (string json_string) throws GLib.Error
{
var root_object = parse_json (json_string);
if (root_object.has_member ("open_url")) {
return root_object.get_string_member("open_url");
} else {
return "";
}
}
internal virtual async void fetch_credentials () throws PurchaseError
{
PurchaseError error = null;
ulong found_handler = credentials_management.credentials_found.connect ((credentials) => {
_ubuntuone_credentials = credentials;
debug ("got credentials");
fetch_credentials.callback ();
});
ulong not_found_handler = credentials_management.credentials_not_found.connect (() => {
error = new PurchaseError.MISSING_CREDENTIALS_ERROR ("No Ubuntu One tokens.");
debug ("not found handler");
fetch_credentials.callback ();
});
ulong error_handler = credentials_management.credentials_error.connect ((error_dict) => {
error = new PurchaseError.MISSING_CREDENTIALS_ERROR ("Can't get Ubuntu One tokens.");
debug ("error handler");
fetch_credentials.callback ();
});
try {
credentials_management.find_credentials ();
yield;
} catch (Error e) {
error = new PurchaseError.MISSING_CREDENTIALS_ERROR ("Can't get Ubuntu One tokens: %s", e.message);
}
credentials_management.disconnect (found_handler);
credentials_management.disconnect (not_found_handler);
credentials_management.disconnect (error_handler);
if (error != null) {
debug ("Can't get Ubuntu One tokens: %s", error.message);
throw error;
}
}
string oauth_sign (string uri)
{
return OAuth.sign_url2(uri, null,
OAuth.Method.PLAINTEXT, "GET",
_ubuntuone_credentials["consumer_key"],
_ubuntuone_credentials["consumer_secret"],
_ubuntuone_credentials["token"],
_ubuntuone_credentials["token_secret"]);
}
internal virtual async PurchaseError call_api (string method, string uri, out string response)
{
PurchaseError error = null;
var signed_uri = oauth_sign (uri);
var message = new Soup.Message (method, signed_uri);
http_session.queue_message (message, (session, message) => {
if (message.status_code != Soup.KnownStatusCode.OK) {
debug ("Web request failed: HTTP %u %s - %s",
message.status_code, message.reason_phrase, uri);
error = new PurchaseError.PURCHASE_ERROR (message.reason_phrase);
}
call_api.callback ();
});
yield;
message.response_body.flatten ();
response = (string) message.response_body.data;
return error;
}
internal virtual async void fetch_account () throws PurchaseError
{
string response;
PurchaseError error = yield call_api ("GET", account_uri(), out response);
if (error != null) {
debug ("Error while fetching U1 account: %s.", error.message);
throw error;
}
try {
parse_account_json (response);
debug ("got account");
} catch (GLib.Error e) {
debug ("Error while parsing U1 account: %s.", e.message);
throw new PurchaseError.PURCHASE_ERROR (e.message);
}
}
internal virtual void fetch_payment_method (string purchase_sku) throws PurchaseError
{
var uri = payment_method_uri().printf (purchase_sku);
var message = send_signed_webservice_call ("GET", uri);
if (message.status_code != Soup.KnownStatusCode.OK) {
debug ("Purchase request failed: HTTP %u", message.status_code);
debug ("Reason: %s", message.reason_phrase);
try {
message.response_body.flatten ();
debug ("body: ------\n%s\n------\n", (string) message.response_body.data);
} catch (Error e) {
}
throw new PurchaseError.PURCHASE_ERROR ("Retrieve payment method failed: %s".printf (message.reason_phrase));
}
try {
message.response_body.flatten ();
var result = (string) message.response_body.data;
parse_payment_method_json (result);
} catch (GLib.Error e) {
throw new PurchaseError.PURCHASE_ERROR (e.message);
}
}
public virtual async void fetch_account_info () throws PurchaseError
{
yield fetch_credentials ();
yield fetch_account ();
}
public virtual void fetch_payment_info (string purchase_sku) throws PurchaseError
{
fetch_payment_method (purchase_sku);
}
internal virtual void _do_sso_webcall (Soup.Message message, string password)
{
var handler = http_session_sso.authenticate.connect ((session, message, auth, retrying) => {
if (!retrying) {
auth.authenticate (email, password);
}
});
http_session_sso.send_message (message);
http_session_sso.disconnect (handler);
}
internal virtual string authenticated_sso_webcall (string method, string uri, string operation, string password)
throws PurchaseError
{
var message = new Soup.Message (method, uri);
message.set_request ("application/x-www-form-urlencoded", Soup.MemoryUse.COPY, operation.data);
_do_sso_webcall (message, password);
if (message.status_code != Soup.KnownStatusCode.OK) {
debug ("Authentication request failed: HTTP %u", message.status_code);
debug ("Reason: %s", message.reason_phrase);
if (message.status_code == Soup.KnownStatusCode.UNAUTHORIZED) {
throw new PurchaseError.WRONG_PASSWORD_ERROR ("Wrong password");
}
try {
message.response_body.flatten ();
debug ("body: ------\n%s\n------\n", (string) message.response_body.data);
} catch (Error e) {
}
throw new PurchaseError.PURCHASE_ERROR (message.reason_phrase);
}
message.response_body.flatten ();
return (string) message.response_body.data;
}
internal virtual string get_purchase_token (string password) throws PurchaseError
{
var result = authenticated_sso_webcall ("POST", authentication_uri(), AUTHENTICATE_PARAMS, password);
try {
parse_authentication_json (result);
} catch (GLib.Error e) {
throw new PurchaseError.PURCHASE_ERROR (e.message);
}
return "%s:%s".printf (consumer_key, token);
}
internal virtual Soup.Message send_signed_webservice_call (string method, string uri)
{
var signed_uri = oauth_sign (uri);
var message = new Soup.Message (method, signed_uri);
http_session.send_message (message);
return message;
}
internal virtual void purchase_with_default_payment (string album_id, string purchase_token) throws PurchaseError
{
var uri = purchase_with_default_payment_uri().printf (album_id, purchase_token);
var message = send_signed_webservice_call ("GET", uri);
if (message.status_code != Soup.KnownStatusCode.OK) {
debug ("Purchase request failed: HTTP %u", message.status_code);
debug ("Reason: %s", message.reason_phrase);
try {
message.response_body.flatten ();
debug ("body: ------\n%s\n------\n", (string) message.response_body.data);
} catch (Error e) {
}
throw new PurchaseError.PURCHASE_ERROR ("Purchase failed: %s".printf (message.reason_phrase));
}
try {
message.response_body.flatten ();
var result = (string) message.response_body.data;
var open_url = parse_purchase_json (result);
if (open_url != "") {
throw new PurchaseError.PURCHASE_ERROR (open_url);
}
} catch (GLib.Error e) {
throw new PurchaseError.PURCHASE_ERROR (e.message);
}
}
public void purchase (string album_id, string password) throws PurchaseError
{
var purchase_token = get_purchase_token (password);
debug ("purchasing...");
purchase_with_default_payment (album_id, purchase_token);
debug ("purchase completed.");
}
}
}
unity-lens-music-6.9.0+14.04.20151120.2/src/dash-proxy.vala 0000644 0000153 0000161 00000002650 12623574234 023203 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Pawel Stolowski
*/
namespace PreviewPlayer {
static const string DASH_DBUS_NAME = "com.canonical.Unity";
static const string DASH_DBUS_PATH = "/com/canonical/Unity/Dash";
[DBus (name = "com.canonical.Unity.Dash")]
public interface DashInterface: GLib.Object
{
public abstract async void hide_dash () throws Error;
}
public class DashProxy: GLib.Object
{
public async void connect_to () throws Error
{
_dash_interface = Bus.get_proxy_sync (BusType.SESSION, DASH_DBUS_NAME, DASH_DBUS_PATH);
}
public async void hide_dash () throws Error
{
if (_dash_interface == null)
{
yield connect_to ();
}
yield _dash_interface.hide_dash ();
}
private DashInterface _dash_interface;
}
}
unity-lens-music-6.9.0+14.04.20151120.2/src/filter-parser-genre.vala 0000644 0000153 0000161 00000002644 12623574234 024765 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Alex Launi
*
*/
using GLib;
namespace Unity.MusicLens {
public class GenreFilterParser : FilterParser
{
public GenreFilterParser (CheckOptionFilterCompact filter)
{
base (filter);
map = new Genre ();
}
public override string parse ()
{
return "";
}
protected override string id { get { return "genre"; } }
protected Genre map { get; private set; }
protected List get_all_selected_genres ()
{
unowned List options = (filter as CheckOptionFilterCompact).options;
var active = new List ();
foreach (FilterOption option in options)
{
if (option.active)
active.append (option);
}
return active;
}
}
}
unity-lens-music-6.9.0+14.04.20151120.2/src/player.vala 0000644 0000153 0000161 00000027112 12623574234 022401 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Pawel Stolowski
*/
using Gst;
using Gst.PbUtils;
namespace PreviewPlayer
{
errordomain PreviewPlayerError
{
GST_INIT_FAILED
}
public class PreviewPlayer
{
// Track states; keep in sync with libunity - TrackState enum
private enum TrackState
{
STOPPED,
PLAYING,
PAUSED
}
private static uint GST_NETWORK_TIMEOUT_SECS = 10; //gstreamer network timeout (in seconds)
private static uint64 GST_STATE_QUERY_TIMEOUT = 1000000;
// gstreamer - playbin plugin flags; run 'gst-inspect1.0 playbin' for more flags & description
private static int GST_PLAYBIN_AUDIO = 0x02;
private static int GST_PLAYBIN_SOFT_VOLUME = 0x10;
private Gst.Pipeline gst_pipeline;
private Gst.Element gst_playbin;
private Gst.Element gst_sink;
private Gst.Bus gst_bus;
private uint timer_id;
private string uri;
private bool error;
private bool update_registry = false;
public signal void progress (string uri, uint32 state, double value);
public PreviewPlayer () throws PreviewPlayerError
{
timer_id = 0;
init_gst ();
}
internal void init_gst () throws PreviewPlayerError
{
gst_pipeline = new Gst.Pipeline ("preview-player-pipeline");
gst_playbin = Gst.ElementFactory.make ("playbin", "playbin");
gst_sink = Gst.ElementFactory.make ("pulsesink", "sink");
if (gst_sink == null)
{
gst_sink = Gst.ElementFactory.make ("alsasink", "sink");
if (gst_sink == null)
{
throw new PreviewPlayerError.GST_INIT_FAILED ("Can't create backend sink");
}
}
gst_playbin.set_property ("audio-sink", gst_sink);
gst_playbin.set_property ("flags", GST_PLAYBIN_AUDIO | GST_PLAYBIN_SOFT_VOLUME);
gst_playbin.notify["source"].connect (playbin_setup);
gst_pipeline.add (gst_playbin);
gst_bus = gst_pipeline.get_bus ();
gst_bus.add_watch (GLib.Priority.DEFAULT, gst_bus_message_cb);
}
internal void playbin_setup (GLib.Object source, GLib.ParamSpec spec)
{
GLib.Value source_element = GLib.Value (GLib.Type.from_name("GstElement"));
gst_playbin.get_property ("source", ref source_element);
Gst.Element obj = (Gst.Element)source_element.get_object();
// playbin use different source plugins (e.g. FileSrc), timeout is only valid for http source
if (obj.get_class ().get_type ().name () == "GstSoupHTTPSrc")
{
obj.set_property ("timeout", GST_NETWORK_TIMEOUT_SECS);
}
}
internal bool gst_bus_message_cb (Gst.Bus bus, Gst.Message message)
{
switch (message.type)
{
case Gst.MessageType.EOS:
gst_pipeline.set_state (Gst.State.READY);
progress (uri, TrackState.PLAYING, 1.0f);
break;
case Gst.MessageType.ERROR:
gst_pipeline.set_state (Gst.State.READY);
error = true;
break;
case Gst.MessageType.ELEMENT:
if (Gst.PbUtils.is_missing_plugin_message (message))
{
handle_missing_plugin.begin (message);
}
break;
default:
// there are more meesages gstreamer may send over bus, but we're not interested in them
break;
}
return true;
}
private async void handle_missing_plugin (Gst.Message message)
{
var detail = Gst.PbUtils.missing_plugin_message_get_installer_detail (message);
var descr = Gst.PbUtils.missing_plugin_message_get_description (message);
warning ("Missing plugin: '%s': %s\n", descr, detail);
string[] details = {detail};
var status = Gst.PbUtils.install_plugins_async (details, null, codec_install_finished);
if (status == Gst.PbUtils.InstallPluginsReturn.STARTED_OK)
{
var dash_proxy = new DashProxy ();
try
{
yield dash_proxy.hide_dash ();
}
catch (Error e)
{
warning ("Failed to hide dash: %s", e.message);
}
}
else
{
warning ("Failed to start codec installation");
}
}
private void codec_install_finished (Gst.PbUtils.InstallPluginsReturn result)
{
debug ("Codec install returned: %d\n", result);
if (result == Gst.PbUtils.InstallPluginsReturn.SUCCESS)
{
/* In theory we should get here after codec installation successfully finished and then calling Gst.update_registry() would
pick the changes. It turns out we get SUCCESS before apt actually finishes installation... As a workaround set a flag
and postpone registry update till next call to play(). Note that this may result in another codec installation popup for same codec
if user requests playback again before installation ends.
*/
update_registry = true;
}
}
private void remove_progress_cb ()
{
if (timer_id > 0)
{
GLib.Source.remove(timer_id);
timer_id = 0;
}
}
private bool progress_report_cb ()
{
Gst.State current_state;
Gst.State pending_state;
var status = gst_pipeline.get_state (out current_state, out pending_state, GST_STATE_QUERY_TIMEOUT);
if (status != Gst.StateChangeReturn.FAILURE)
{
if (current_state == Gst.State.PLAYING || pending_state == Gst.State.PLAYING)
{
progress (uri, TrackState.PLAYING, gst_progress ());
return true;
}
if (current_state == Gst.State.PAUSED || pending_state == Gst.State.PAUSED)
{
return true;
}
// FIXME: set TrackState.ERROR if error=true (and STOPPED if false) when we have ERROR state supported by libunity & unity core
progress (uri, TrackState.STOPPED, 0.0f);
}
return false;
}
private double gst_progress ()
{
int64 pos;
int64 dur;
var fmt = Gst.Format.TIME;
if (gst_pipeline.query_position (fmt, out pos))
{
if (gst_pipeline.query_duration (fmt, out dur))
{
if (dur > 0)
{
return pos / (double)dur;
}
}
}
return 0.0f;
}
private bool is_playing ()
{
Gst.State current_state;
Gst.State pending_state;
var status = gst_pipeline.get_state (out current_state, out pending_state, GST_STATE_QUERY_TIMEOUT);
return status != Gst.StateChangeReturn.FAILURE && (current_state == Gst.State.PLAYING || pending_state == Gst.State.PLAYING);
}
public void play (string uri)
{
if (update_registry)
{
update_registry = false;
debug ("Updating gstreamer plugin registry\n");
Gst.update_registry ();
debug ("Finished gstreamer plugin registry update\n");
}
// resume playback for same uri
if (uri == this.uri)
{
Gst.State current_state;
Gst.State pending_state;
var status = gst_pipeline.get_state (out current_state, out pending_state, GST_STATE_QUERY_TIMEOUT);
if (status != Gst.StateChangeReturn.FAILURE)
{
if (current_state == Gst.State.PAUSED || pending_state == Gst.State.PAUSED)
{
gst_pipeline.set_state (Gst.State.PLAYING);
progress (uri, TrackState.PLAYING, gst_progress ());
return;
}
}
}
// start new playback
remove_progress_cb ();
error = false;
this.uri = uri;
gst_pipeline.set_state (Gst.State.NULL);
gst_playbin.set_property ("uri", uri);
gst_pipeline.set_state (Gst.State.PLAYING);
timer_id = GLib.Timeout.add_seconds (1, progress_report_cb);
progress_report_cb();
}
public void stop ()
{
Gst.State current_state;
Gst.State pending_state;
var status = gst_pipeline.get_state (out current_state, out pending_state, GST_STATE_QUERY_TIMEOUT);
if (status != Gst.StateChangeReturn.FAILURE)
{
if (current_state == Gst.State.PAUSED || current_state == Gst.State.PLAYING ||
pending_state == Gst.State.PAUSED || pending_state == Gst.State.PLAYING)
{
gst_pipeline.set_state (Gst.State.READY);
progress (uri, TrackState.STOPPED, 0.0f);
}
}
}
public void pause ()
{
if (is_playing())
{
gst_pipeline.set_state (Gst.State.PAUSED);
progress (uri, TrackState.PAUSED, gst_progress ());
}
}
public void resume ()
{
Gst.State current_state;
Gst.State pending_state;
var status = gst_pipeline.get_state (out current_state, out pending_state, GST_STATE_QUERY_TIMEOUT);
if (status != Gst.StateChangeReturn.FAILURE)
{
if (current_state == Gst.State.PAUSED || pending_state == Gst.State.PAUSED)
{
gst_pipeline.set_state (Gst.State.PLAYING);
progress (uri, TrackState.PLAYING, gst_progress ());
}
}
}
public void pause_resume()
{
Gst.State current_state;
Gst.State pending_state;
var status = gst_pipeline.get_state (out current_state, out pending_state, GST_STATE_QUERY_TIMEOUT);
if (status != Gst.StateChangeReturn.FAILURE)
{
TrackState track_state = TrackState.STOPPED;
Gst.State gst_state = Gst.State.NULL;
if (current_state == Gst.State.PLAYING || pending_state == Gst.State.PLAYING)
{
track_state = TrackState.PAUSED;
gst_state = Gst.State.PAUSED;
gst_pipeline.set_state (Gst.State.PAUSED);
}
else if (current_state == Gst.State.PAUSED || pending_state == Gst.State.PAUSED)
{
track_state = TrackState.PLAYING;
gst_state = Gst.State.PLAYING;
}
if (gst_state != Gst.State.NULL)
{
gst_pipeline.set_state (gst_state);
progress (uri, track_state, gst_progress ());
}
}
}
public HashTable get_video_file_props (string uri)
{
var props = new HashTable (str_hash, str_equal);
try
{
var discoverer = new Gst.PbUtils.Discoverer (2 * 1000000000); //2 seconds
var discoverer_info = discoverer.discover_uri (uri);
var video_streams = discoverer_info.get_video_streams ();
// note: the container may have multiple video and audio streams, we just get properties of the first one
if (video_streams != null && video_streams.length () > 0)
{
var vstream = video_streams.nth_data (0) as Gst.PbUtils.DiscovererVideoInfo;
props.insert ("width", new GLib.Variant.uint32 (vstream.get_width ()));
props.insert ("height", new GLib.Variant.uint32 (vstream.get_height ()));
props.insert ("codec", new GLib.Variant.string (Gst.PbUtils.get_codec_description (vstream.get_caps ())));
}
}
catch (GLib.Error e)
{
warning ("Failed to get video file properties for '%s': '%s'\n", uri, e.message);
}
return props;
}
}
}
unity-lens-music-6.9.0+14.04.20151120.2/src/musicstore-filter-parser-genre.vala 0000644 0000153 0000161 00000002610 12623574234 027151 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Alex Launi
*
*/
using GLib;
namespace Unity.MusicLens {
public class MusicStoreGenreFilterParser : GenreFilterParser, MusicStoreFilterParser
{
public MusicStoreGenreFilterParser (GenreFilterParser parser)
{
base (parser.filter as CheckOptionFilterCompact);
}
public override string parse ()
{
StringBuilder builder = new StringBuilder ("&genres=");
foreach (FilterOption genre in get_all_selected_genres ()) {
string id = genre.id;
if (genre.id == null)
continue;
foreach (string alt in map.get_genre_synonyms (id))
{
builder.append_printf ("%s,", alt);
}
}
// cut off hanging ','
builder.truncate (builder.len - 1);
return builder.str;
}
}
}
unity-lens-music-6.9.0+14.04.20151120.2/src/player-service.vala 0000644 0000153 0000161 00000004256 12623574234 024043 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Pawel Stolowski
*/
namespace PreviewPlayer
{
[DBus (name = "com.canonical.Unity.Lens.Music.PreviewPlayer")]
public class PreviewPlayerService : Object
{
private PreviewPlayer player;
private bool released;
public PreviewPlayerService (PreviewPlayer preview_player)
{
released = false;
player = preview_player;
player.progress.connect (on_progress_change);
}
private void on_progress_change (string uri, uint32 state, double value)
{
progress (uri, state, value);
}
public void play (string uri)
{
if (released)
{
released = false;
var app = GLib.Application.get_default ();
app.hold ();
}
player.play (uri);
}
public void pause ()
{
player.pause ();
}
public void resume ()
{
player.resume ();
}
public void pause_resume ()
{
player.pause_resume ();
}
public void stop ()
{
player.stop ();
}
public void close ()
{
if (released)
return;
released = true;
player.stop ();
var app = GLib.Application.get_default ();
app.release ();
}
public HashTable video_properties (string uri)
{
if (released)
{
released = false;
var app = GLib.Application.get_default ();
app.hold ();
}
return player.get_video_file_props (uri);
}
public signal void progress (string uri, uint32 state, double value);
}
} unity-lens-music-6.9.0+14.04.20151120.2/src/banshee-filter-parser.vala 0000644 0000153 0000161 00000001435 12623574234 025267 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Alex Launi
*
*/
using GLib;
namespace Unity.MusicLens {
public interface BansheeFilterParser : FilterParser
{
}
}
unity-lens-music-6.9.0+14.04.20151120.2/src/main.vala 0000644 0000153 0000161 00000007237 12623574234 022037 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Mikkel Kamstrup Erlandsen
* Alex Launi
*
*/
using GLib;
using Config;
namespace Unity.MusicLens {
static Application? app = null;
static Daemon? daemon = null;
static const string BUS_NAME = "com.canonical.Unity.Scope.Music";
/* Check if a given well known DBus is owned.
* WARNING: This does sync IO! */
public static bool dbus_name_has_owner (string name)
{
try {
bool has_owner;
DBusConnection bus = Bus.get_sync (BusType.SESSION);
Variant result = bus.call_sync ("org.freedesktop.DBus",
"/org/freedesktop/dbus",
"org.freedesktop.DBus",
"NameHasOwner",
new Variant ("(s)", name),
new VariantType ("(b)"),
DBusCallFlags.NO_AUTO_START,
-1);
result.get ("(b)", out has_owner);
return has_owner;
} catch (Error e) {
warning ("Unable to decide whether '%s' is running: %s", name, e.message);
}
return false;
}
public static int main (string[] args)
{
GLib.Environment.set_prgname ("unity-music-daemon");
/* Sort up locale to get translations but also sorting and
* punctuation right */
GLib.Intl.textdomain (Config.PACKAGE);
GLib.Intl.bindtextdomain (Config.PACKAGE, Config.LOCALEDIR);
GLib.Intl.bind_textdomain_codeset (Config.PACKAGE, "UTF-8");
GLib.Intl.setlocale(GLib.LocaleCategory.ALL, "");
/* Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=640714
* GApplication.register() call owns our DBus name in a sync manner
* making it race against GDBus' worker thread to export our
* objects on the bus before/after owning our name and receiving
* method calls on our objects (which may not yet be up!)*/
if (dbus_name_has_owner (BUS_NAME))
{
print ("Another instance of the Unity Music Daemon " +
"already appears to be running.\nBailing out.\n");
return 2;
}
/* Now register our DBus objects *before* acquiring the name!
* See above for reasons */
daemon = new Daemon ();
/* Use GApplication directly for single instance app functionality */
app = new Application (BUS_NAME, ApplicationFlags.IS_SERVICE);
try {
app.register ();
} catch (Error e) {
/* FIXME: We get this error if another daemon is already running,
* but it uses a generic error so we can't detect this reliably... */
print ("Failed to start music daemon: %s\n", e.message);
return 1;
}
if (app.get_is_remote ())
{
print ("Another instance of the Unity Music Daemon " +
"already appears to be running.\nBailing out.\n");
return 2;
}
/* Hold()ing the app makes sure the GApplication doesn't exit */
app.hold();
return app.run ();
}
} /* namespace */
unity-lens-music-6.9.0+14.04.20151120.2/src/tdb.deps 0000644 0000153 0000161 00000000006 12623574234 021657 0 ustar pbuser pbgroup 0000000 0000000 posix
unity-lens-music-6.9.0+14.04.20151120.2/src/oauth.vapi 0000644 0000153 0000161 00000001056 12623574234 022240 0 ustar pbuser pbgroup 0000000 0000000 /* Minimal vapi for OAuth */
[CCode (cheader_filename="oauth.h")]
namespace OAuth {
[CCode (cheader_filename="oauth.h", cprefix="OA_")]
public enum Method {
HMAC,
RSA,
PLAINTEXT
}
[CCode (cheader_filename="oauth.h", cprefix="oauth_")]
public string sign_url2(string url, out string postargs,
OAuth.Method method,
string? http_method,
string c_key, string c_secret,
string t_key, string t_secret);
}
unity-lens-music-6.9.0+14.04.20151120.2/src/rhythmbox-collection.vala 0000644 0000153 0000161 00000104665 12623574240 025270 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by David Calle
* Michal Hruby
*
*/
using Dee;
using Gee;
namespace Unity.MusicLens
{
const string UNITY_ICON_PATH = Config.PKGDATADIR + "/icons";
const string ALBUM_MISSING_ICON_PATH = UNITY_ICON_PATH + "/album_missing.png";
const string ALBUM_MISSING_PREVIEW_ICON_PATH = UNITY_ICON_PATH + "/album_missing_preview.png";
private enum Columns
{
TYPE,
URI,
TITLE,
ARTIST,
ALBUM,
ARTWORK,
MIMETYPE,
GENRE,
ALBUM_ARTIST,
TRACK_NUMBER,
YEAR,
PLAY_COUNT,
DURATION,
N_COLUMNS
}
class RhythmboxCollection : Object
{
const string UNKNOWN_ALBUM = _("Unknown");
SequenceModel all_tracks;
ModelTag album_art_tag;
FilterModel tracks_by_play_count;
HashTable> album_to_tracks_map;
TDB.Database album_art_tdb;
FileMonitor tdb_monitor;
int current_album_art_tag;
HashTable variant_store;
HashTable int_variant_store;
Variant row_buffer[13];
Analyzer analyzer;
Index? index;
ICUTermFilter ascii_filter;
string media_art_dir;
public class XmlParser: Object
{
const MarkupParser parser =
{
start_tag,
end_tag,
process_text,
null,
null
};
// contains genre maps
Genre genre = new Genre ();
MarkupParseContext context;
bool is_rhythmdb_xml = false;
construct
{
context = new MarkupParseContext (parser, 0, this, null);
}
public bool parse (string content, size_t len) throws MarkupError
{
return context.parse (content, (ssize_t) len);
}
bool processing_track;
Track current_track;
int current_data = -1;
private void start_tag (MarkupParseContext context, string name,
[CCode (array_length = false, array_null_terminated = true)] string[] attr_names, [CCode (array_length = false, array_null_terminated = true)] string[] attr_values)
throws MarkupError
{
if (!processing_track)
{
switch (name)
{
case "rhythmdb": is_rhythmdb_xml = true; break;
case "entry":
string accepted_element_name = null;
for (int i = 0; attr_names[i] != null; i++)
{
if (attr_names[i] == "type" && (attr_values[i] == "song"
/*|| attr_values[i] == "iradio"*/)) // disable radio stations
accepted_element_name = attr_values[i];
}
if (accepted_element_name == null) return;
processing_track = true;
current_track = new Track ();
current_track.type_track = accepted_element_name == "song" ?
TrackType.SONG : TrackType.RADIO;
break;
}
}
else
{
switch (name)
{
case "location": current_data = Columns.URI; break;
case "title": current_data = Columns.TITLE; break;
case "duration": current_data = Columns.DURATION; break;
case "artist": current_data = Columns.ARTIST; break;
case "album": current_data = Columns.ALBUM; break;
case "genre": current_data = Columns.GENRE; break;
case "track-number": current_data = Columns.TRACK_NUMBER; break;
case "play-count": current_data = Columns.PLAY_COUNT; break;
case "date": current_data = Columns.YEAR; break;
case "media-type": current_data = Columns.MIMETYPE; break;
case "album-artist": current_data = Columns.ALBUM_ARTIST; break;
default: current_data = -1; break;
}
}
}
public signal void track_info_ready (Track track);
private void end_tag (MarkupParseContext content, string name)
throws MarkupError
{
switch (name)
{
case "location":
case "title":
case "duration":
case "artist":
case "album":
case "genre":
case "track-number":
case "play-count":
case "date":
case "media-type":
case "album-artist":
if (current_data >= 0) current_data = -1;
break;
case "hidden":
if (processing_track) processing_track = false;
break;
case "entry":
if (processing_track && current_track != null)
{
track_info_ready (current_track);
}
processing_track = false;
break;
}
}
private void process_text (MarkupParseContext context,
string text, size_t text_len)
throws MarkupError
{
if (!processing_track || current_data < 0) return;
switch (current_data)
{
case Columns.URI: current_track.uri = text; break;
case Columns.TITLE: current_track.title = text; break;
case Columns.ARTIST: current_track.artist = text; break;
case Columns.ALBUM: current_track.album = text; break;
case Columns.ALBUM_ARTIST:
current_track.album_artist = text;
break;
case Columns.GENRE:
current_track.genre = genre.get_id_for_genre (text.down ());
break;
case Columns.MIMETYPE:
current_track.mime_type = text;
break;
case Columns.YEAR:
current_track.year = int.parse (text) / 365;
break;
case Columns.PLAY_COUNT:
current_track.play_count = int.parse (text);
break;
case Columns.TRACK_NUMBER:
current_track.track_number = int.parse (text);
break;
case Columns.DURATION:
current_track.duration = int.parse (text);
break;
}
}
}
construct
{
static_assert (13 == Columns.N_COLUMNS); // sync with row_buffer size
media_art_dir = Path.build_filename (
Environment.get_user_cache_dir (), "media-art");
variant_store = new HashTable (str_hash,
str_equal);
int_variant_store = new HashTable (direct_hash,
direct_equal);
all_tracks = new SequenceModel ();
// the columns correspond to the Columns enum
all_tracks.set_schema ("i", "s", "s", "s", "s", "s", "s",
"s", "s", "i", "i", "i", "i");
assert (all_tracks.get_schema ().length == Columns.N_COLUMNS);
album_art_tag = new ModelTag (all_tracks);
album_to_tracks_map =
new HashTable> (str_hash,
str_equal);
var filter = Dee.Filter.new_sort ((row1, row2) =>
{
int a = row1[Columns.PLAY_COUNT].get_int32 ();
int b = row2[Columns.PLAY_COUNT].get_int32 ();
return b - a; // higher play count first
});
tracks_by_play_count = new FilterModel (all_tracks, filter);
ascii_filter = new ICUTermFilter.ascii_folder ();
analyzer = new TextAnalyzer ();
analyzer.add_term_filter ((terms_in, terms_out) =>
{
foreach (unowned string term in terms_in)
{
var folded = ascii_filter.apply (term);
terms_out.add_term (term);
if (folded != term) terms_out.add_term (folded);
}
});
initialize_index ();
}
private void initialize_index ()
{
var reader = ModelReader.new ((model, iter) =>
{
var s ="%s\n%s\n%s".printf (model.get_string (iter, Columns.TITLE),
model.get_string (iter, Columns.ARTIST),
model.get_string (iter, Columns.ALBUM));
return s;
});
index = new TreeIndex (all_tracks, analyzer, reader);
}
private string? check_album_art_tdb (string artist, string album)
{
if (album_art_tdb == null) return null;
uint8 null_helper[1] = { 0 };
ByteArray byte_arr = new ByteArray ();
byte_arr.append ("album".data);
byte_arr.append (null_helper);
byte_arr.append (album.data);
byte_arr.append (null_helper);
byte_arr.append ("artist".data);
byte_arr.append (null_helper);
byte_arr.append (artist.data);
byte_arr.append (null_helper);
TDB.Data key = TDB.NULL_DATA;
key.data = byte_arr.data;
var val = album_art_tdb.fetch (key);
if (val.data != null)
{
Variant v = Variant.new_from_data (new VariantType ("a{sv}"), val.data, false);
var file_variant = v.lookup_value ("file", VariantType.STRING);
if (file_variant != null)
{
return file_variant.get_string ();
}
}
return null;
}
private string? get_albumart (Track track)
{
string filename;
var artist = track.album_artist ?? track.artist;
var album = track.album;
var artist_norm = artist.normalize (-1, NormalizeMode.NFKD);
var album_norm = album.normalize (-1, NormalizeMode.NFKD);
filename = check_album_art_tdb (artist, album);
if (filename != null)
{
filename = Path.build_filename (Environment.get_user_cache_dir (),
"rhythmbox", "album-art",
filename);
if (FileUtils.test (filename, FileTest.EXISTS)) return filename;
}
var artist_md5 = Checksum.compute_for_string (ChecksumType.MD5,
artist_norm);
var album_md5 = Checksum.compute_for_string (ChecksumType.MD5,
album_norm);
filename = Path.build_filename (media_art_dir,
"album-%s-%s".printf (artist_md5, album_md5));
if (FileUtils.test (filename, FileTest.EXISTS)) return filename;
var combined = "%s\t%s".printf (artist, album).normalize (-1, NormalizeMode.NFKD);
filename = Path.build_filename (media_art_dir,
"album-%s.jpg".printf (Checksum.compute_for_string (
ChecksumType.MD5, combined)));
if (FileUtils.test (filename, FileTest.EXISTS)) return filename;
if (track.uri.has_prefix ("file://"))
{
// Try Nautilus thumbnails
try
{
File artwork_file = File.new_for_uri (track.uri);
var info = artwork_file.query_info (FileAttribute.THUMBNAIL_PATH, 0, null);
var thumbnail_path = info.get_attribute_string (FileAttribute.THUMBNAIL_PATH);
if (thumbnail_path != null) return thumbnail_path;
} catch {}
}
// Try covers folder
string artwork = Path.build_filename (
Environment.get_user_cache_dir (), "rhythmbox", "covers",
"%s - %s.jpg".printf (track.artist, track.album));
if (FileUtils.test (artwork, FileTest.EXISTS)) return artwork;
return null;
}
public SList get_album_tracks (string album_key)
{
SList results = new SList ();
var iter_arr = album_to_tracks_map[album_key];
if (iter_arr != null)
{
for (int i = iter_arr.length - 1; i >= 0; i--)
{
results.prepend (all_tracks.get_string (iter_arr[i], Columns.URI));
}
}
return results;
}
private Track get_track (ModelIter iter)
{
Track track = new Track();
track.uri = all_tracks.get_string (iter, Columns.URI);
track.title = all_tracks.get_string (iter, Columns.TITLE);
track.artist = all_tracks.get_string (iter, Columns.ARTIST);
track.album = all_tracks.get_string (iter, Columns.ALBUM);
track.artwork_path = all_tracks.get_string (iter, Columns.ARTWORK);
track.mime_type = all_tracks.get_string (iter, Columns.MIMETYPE);
track.genre = all_tracks.get_string (iter, Columns.GENRE);
track.album_artist = all_tracks.get_string (iter, Columns.ALBUM_ARTIST);
track.track_number = all_tracks.get_int32 (iter, Columns.TRACK_NUMBER);
track.year = all_tracks.get_int32 (iter, Columns.YEAR);
track.play_count = all_tracks.get_int32 (iter, Columns.PLAY_COUNT);
track.duration = all_tracks.get_int32 (iter, Columns.DURATION);
return track;
}
public Track? get_album_track (string uri)
{
var iter = all_tracks.get_first_iter ();
var end_iter = all_tracks.get_last_iter ();
// FIXME: linear search, change to insert_sorted / find_sorted
while (iter != end_iter)
{
if (all_tracks.get_string (iter, Columns.URI) == uri) {
return get_track (iter);
}
iter = all_tracks.next (iter);
}
return null;
}
public SList