diff options
author | Jens Georg <mail@jensge.org> | 2020-05-07 00:49:22 +0200 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2020-07-05 15:31:52 +0200 |
commit | 234603ff447de98bd8e640b984db877535af399e (patch) | |
tree | 1b85f0771aeec48a32c88f17dec94399720edd82 | |
parent | 79f75e90e6f608539082f144c22b07160737ca75 (diff) | |
download | rygel-234603ff447de98bd8e640b984db877535af399e.tar.gz |
tracker3: Add plugin to support tracker3
Mainly just copy the tracker plugin and change the sparql connection.
35 files changed, 3120 insertions, 1 deletions
diff --git a/meson_options.txt b/meson_options.txt index bd61fb60..cb604c4e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,7 @@ option('uninstalled', type: 'boolean', value: 'false', description: 'Run Rygel from build directory only') option('api-docs', type: 'boolean', value: 'false', description: 'Build the API documentation') option('systemd-user-units-dir', type : 'string', value : 'auto', description : 'Where to install the systemd user unit (use special values "auto" or "none", or pass a path') -option('plugins', type : 'array', choices : ['external', 'gst-launch', 'lms', 'media-export', 'mpris', 'playbin', 'ruih', 'tracker']) +option('plugins', type : 'array', choices : ['external', 'gst-launch', 'lms', 'media-export', 'mpris', 'playbin', 'ruih', 'tracker', 'tracker3']) option('engines', type : 'array', choices : ['simple', 'gstreamer']) option('examples', type : 'boolean', value : 'true') option('tests', type : 'boolean', value : 'true') diff --git a/src/plugins/tracker3/meson.build b/src/plugins/tracker3/meson.build new file mode 100644 index 00000000..b43359a6 --- /dev/null +++ b/src/plugins/tracker3/meson.build @@ -0,0 +1,49 @@ +configure_file(input : 'tracker3.plugin.in', + output : 'tracker3.plugin', + configuration : plugin_config, + install_dir : rygel_plugindir) + +rygel_tracker_sources = [ + 'rygel-tracker-root-container.vala', + 'rygel-tracker-category-container.vala', + 'rygel-tracker-music.vala', + 'rygel-tracker-videos.vala', + 'rygel-tracker-pictures.vala', + 'rygel-tracker-metadata-values.vala', + 'rygel-tracker-metadata-container.vala', + 'rygel-tracker-metadata-multivalues.vala', + 'rygel-tracker-tags.vala', + 'rygel-tracker-years.vala', + 'rygel-tracker-titles.vala', + 'rygel-tracker-albums.vala', + 'rygel-tracker-artists.vala', + 'rygel-tracker-genre.vala', + 'rygel-tracker-new.vala', + 'rygel-tracker-search-container.vala', + 'rygel-tracker-category-all-container.vala', + 'rygel-tracker-upnp-property-map.vala', + 'rygel-tracker-query.vala', + 'rygel-tracker-selection-query.vala', + 'rygel-tracker-deletion-query.vala', + 'rygel-tracker-insertion-query.vala', + 'rygel-tracker-cleanup-query.vala', + 'rygel-tracker-query-triplet.vala', + 'rygel-tracker-query-triplets.vala', + 'rygel-tracker-item-factory.vala', + 'rygel-tracker-video-item-factory.vala', + 'rygel-tracker-music-item-factory.vala', + 'rygel-tracker-picture-item-factory.vala', + 'rygel-tracker-plugin.vala', + 'rygel-tracker-plugin-factory.vala', + 'rygel-tracker-interfaces.vala'] + +shared_module('rygel-tracker3', + rygel_tracker_sources, + dependencies : [ + common_deps, + dependency('tracker-sparql-3.0'), + build_config, rygel_core, rygel_server + ], + c_args : ['-DG_LOG_DOMAIN="RygelTracker3"'], + install : true, + install_dir : rygel_plugindir) diff --git a/src/plugins/tracker3/rygel-tracker-albums.vala b/src/plugins/tracker3/rygel-tracker-albums.vala new file mode 100644 index 00000000..2bc63d33 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-albums.vala @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009,2010 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +/** + * Container listing Music albums as containers. + */ +public class Rygel.Tracker.Albums : MetadataValues { + public Albums (Music parent) { + base (parent.id + "Albums", + parent, + _("Albums"), + parent.item_factory, + "upnp:album", + MediaContainer.MUSIC_ALBUM); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-artists.vala b/src/plugins/tracker3/rygel-tracker-artists.vala new file mode 100644 index 00000000..38e37eb6 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-artists.vala @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009,2010 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +/** + * Container listing artists as containers. + */ +public class Rygel.Tracker.Artists : MetadataValues { + public Artists (Music parent) { + base (parent.id + "Artists", + parent, + _("Artists"), + parent.item_factory, + "upnp:artist", + MediaContainer.MUSIC_ARTIST); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-category-all-container.vala b/src/plugins/tracker3/rygel-tracker-category-all-container.vala new file mode 100644 index 00000000..64ab3aa7 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-category-all-container.vala @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008-2012 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * A search container that contains all the items in a category. + */ +public class Rygel.Tracker.CategoryAllContainer : SearchContainer, + WritableContainer, + SearchableContainer { + /* class-wide constants */ + private const string TRACKER_SERVICE = "org.freedesktop.Tracker1"; + private const string RESOURCES_PATH = "/org/freedesktop/Tracker1/Resources"; + + public ArrayList<string> create_classes { get; set; } + public ArrayList<string> search_classes { get; set; } + + private Sparql.Connection resources; + + public CategoryAllContainer (CategoryContainer parent) { + base ("All" + parent.id, parent, "All", parent.item_factory); + + this.create_classes = new ArrayList<string> (); + this.create_classes.add (item_factory.upnp_class); + this.search_classes = new ArrayList<string> (); + + try { + this.resources = Sparql.Connection.bus_new ("org.freedesktop.Tracker3.Miner.Files", null); + } catch (Error io_error) { + critical (_("Failed to create a Tracker connection: %s"), + io_error.message); + } + + if (item_factory.upload_dir != null) { + try { + var uri = Filename.to_uri (item_factory.upload_dir, null); + this.add_uri (uri); + } catch (ConvertError error) { + warning (_("Failed to construct URI for folder “%s”: %s"), + item_factory.upload_dir, + error.message); + } + } + + try { + var connection = Bus.get_sync (BusType.SESSION); + connection.signal_subscribe (TRACKER_SERVICE, + TRACKER_SERVICE + ".Resources", + "GraphUpdated", + RESOURCES_PATH, + this.item_factory.category_iri, + DBusSignalFlags.NONE, + this.on_graph_updated); + } catch (Error error) { + critical (_("Could not subscribe to Tracker signals: %s"), + error.message); + } + + var cleanup_query = new CleanupQuery (this.item_factory.category); + cleanup_query.execute.begin (this.resources); + } + + public async void add_item (MediaFileItem item, Cancellable? cancellable) + throws Error { + var urn = yield this.create_entry_in_store (item); + + item.id = this.create_child_id_for_urn (urn); + item.parent = this; + } + + public async void add_container (MediaContainer container, + Cancellable? cancellable) throws Error { + throw new WritableContainerError.NOT_IMPLEMENTED (_("Not supported")); + } + + public async void remove_item (string id, Cancellable? cancellable) + throws Error { + string parent_id; + + var urn = this.get_item_info (id, out parent_id); + + yield this.remove_entry_from_store (urn); + } + + public async void remove_container (string id, Cancellable? cancellable) + throws Error { + throw new WritableContainerError.NOT_IMPLEMENTED ("Not supported"); + } + + public async MediaObjects? search (SearchExpression? expression, + uint offset, + uint max_count, + string sort_criteria, + Cancellable? cancellable, + out uint total_matches) + throws Error { + return yield this.simple_search (expression, + offset, + max_count, + sort_criteria, + cancellable, + out total_matches); + } + + private void on_graph_updated (DBusConnection connection, + string? sender, + string object_path, + string interface_name, + string signal_path, + Variant parameters) { + this.get_children_count.begin (); + } + + private async string create_entry_in_store (MediaFileItem item) + throws Error { + var category = this.item_factory.category; + var query = new InsertionQuery (item, category); + + yield query.execute (this.resources); + + return query.id; + } + + private async void remove_entry_from_store (string id) throws Error { + var query = new DeletionQuery (id); + + yield query.execute (this.resources); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-category-container.vala b/src/plugins/tracker3/rygel-tracker-category-container.vala new file mode 100644 index 00000000..351df188 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-category-container.vala @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * Container listing content hierarchy for a specific category. + */ +public abstract class Rygel.Tracker.CategoryContainer : Rygel.SimpleContainer { + public ItemFactory item_factory; + + private CategoryAllContainer all_container; + + protected CategoryContainer (string id, + MediaContainer parent, + string title, + ItemFactory item_factory) { + base (id, parent, title); + + this.item_factory = item_factory; + + this.all_container = new CategoryAllContainer (this); + + this.add_child_container (this.all_container); + this.add_child_container (new Tags (this, item_factory)); + this.add_child_container (new Titles (this, this.item_factory)); + this.add_child_container (new New (this, this.item_factory)); + ulong signal_id = 0; + + signal_id = this.all_container.container_updated.connect( () => { + // ingore first update + this.all_container.container_updated.connect + (this.on_all_container_updated); + this.all_container.disconnect (signal_id); + }); + } + + public void add_create_class (string create_class) { + this.all_container.create_classes.add (create_class); + } + + private void trigger_child_update (MediaObjects children) { + foreach (var container in children) { + if (container == this.all_container || + container == null) { + continue; + } + + if (container is MetadataValues) { + ((MetadataValues) container).fetch_metadata_values.begin (); + } else if (container is SearchContainer) { + ((SearchContainer) container).get_children_count.begin (); + } + } + } + + private void on_all_container_updated (MediaContainer other) { + if (other != this.all_container) { + // otherwise we'd do a recursive update + return; + } + + this.trigger_child_update (this.get_all_children ()); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-cleanup-query.vala b/src/plugins/tracker3/rygel-tracker-cleanup-query.vala new file mode 100644 index 00000000..73c92ac7 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-cleanup-query.vala @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011-2012 Nokia Corporation. + * + * Author: Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Represents Tracker SPARQL Deletion query + */ +public class Rygel.Tracker.CleanupQuery : Query { + private string category; + + public CleanupQuery (string category) { + var triplets = new QueryTriplets (); + triplets.add (new QueryTriplet ("?r", "a", "rdfs:Resource")); + + base (triplets); + + this.category = category; + } + + public override async void execute (Sparql.Connection resources) + throws Error, + IOError, + Sparql.Error, + DBusError { + var str = this.to_string (); + + debug ("Executing SPARQL query: %s", str); + + yield resources.update_async (str); + } + + public override string to_string () { + StringBuilder result = new StringBuilder (); + + result.append ("DELETE {"); + result.append (base.to_string ()); + result.append ("} WHERE {"); + result.append_printf ("?r a nie:DataObject, %s . ", this.category); + result.append (" ?r nie:generator \"rygel\". "); + result.append ("FILTER(NOT EXISTS { ?r "); + result.append ("a nfo:FileDataObject. })}"); + + return result.str; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-deletion-query.vala b/src/plugins/tracker3/rygel-tracker-deletion-query.vala new file mode 100644 index 00000000..537acc4d --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-deletion-query.vala @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010-2012 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Represents Tracker SPARQL Deletion query + */ +public class Rygel.Tracker.DeletionQuery : Query { + private string id; + + public DeletionQuery (string id) { + var triplets = new QueryTriplets (); + triplets.add (new QueryTriplet ("<" + id + ">", "a", "rdfs:Resource")); + + base (triplets); + + this.id = id; + } + + public override async void execute (Sparql.Connection resources) + throws Error, + IOError, + Sparql.Error, + DBusError { + var str = this.to_string (); + + debug ("Executing SPARQL query: %s", str); + + yield resources.update_async (str); + + debug ("Deleted item '%s' from Tracker store", this.id); + } + + public override string to_string () { + return "DELETE { " + base.to_string () + " }"; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-genre.vala b/src/plugins/tracker3/rygel-tracker-genre.vala new file mode 100644 index 00000000..47c90cc0 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-genre.vala @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009,2010 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +/** + * Container listing music genres as containers. + */ +public class Rygel.Tracker.Genre : MetadataValues { + public Genre (Music parent) { + base (parent.id + "Genre", + parent, + _("Genre"), + parent.item_factory, + "upnp:genre", + MediaContainer.MUSIC_GENRE); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-insertion-query.vala b/src/plugins/tracker3/rygel-tracker-insertion-query.vala new file mode 100644 index 00000000..e062d058 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-insertion-query.vala @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2010-2012 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Represents Tracker SPARQL Insertion query + */ +public class Rygel.Tracker.InsertionQuery : Query { + private const string TEMP_ID = "x"; + private const string QUERY_ID = "_:" + TEMP_ID; + + private const string MINER_SERVICE = "org.freedesktop.Tracker1.Miner.Files.Index"; + private const string MINER_PATH = "/org/freedesktop/Tracker1/Miner/Files/Index"; + + // We need to add the size in the miner's graph so that the miner will + // update it and correct a (possibly wrong) size we got via CreateItem + // (DLNA requirement 7.3.128.7) + // FIXME: Use constant from libtracker-miner once we port to + // libtracker-sparql + private const string MINER_GRAPH = + "urn:uuid:472ed0cc-40ff-4e37-9c0c-062d78656540"; + + private const string RESOURCE_ID_QUERY_TEMPLATE = + "SELECT ?resource WHERE { ?resource a nie:DataObject; nie:url '%s' }"; + + private const string RESOURCE_NOT_BOUND_TEMPLATE = + "OPTIONAL { ?resource a nie:DataObject; nie:url '%s' } " + + "FILTER (!bound(?resource))"; + + public string id; + + private string uri; + + public InsertionQuery (MediaFileItem item, string category) { + var type = "nie:DataObject"; + var file = File.new_for_uri (item.get_primary_uri ()); + + if (!file.is_native ()) { + type = "nfo:RemoteDataObject"; + } + + var triplets = new QueryTriplets (); + triplets.add (new QueryTriplet (QUERY_ID, "a", category)); + triplets.add (new QueryTriplet (QUERY_ID, "a", type)); + triplets.add (new QueryTriplet (QUERY_ID, "nmm:uPnPShared", "true")); + triplets.add (new QueryTriplet (QUERY_ID, "tracker:available", "true")); + triplets.add (new QueryTriplet (QUERY_ID, + "nie:generator", + "\"rygel\"")); + + triplets.add (new QueryTriplet (QUERY_ID, + "nie:title", + "\"" + item.title + "\"")); + + triplets.add (new QueryTriplet.with_graph + (MINER_GRAPH, + QUERY_ID, + "nie:mimeType", + "\"" + item.mime_type + "\"")); + var dlna_profile = ""; + if (item.dlna_profile != null) { + dlna_profile = item.dlna_profile; + } + + triplets.add (new QueryTriplet.with_graph + (MINER_GRAPH, + QUERY_ID, + "nmm:dlnaProfile", + "\"" + dlna_profile + "\"")); + + triplets.add (new QueryTriplet (QUERY_ID, + "nie:url", + "\"" + item.get_primary_uri () + "\"")); + string date; + if (item.date == null) { + var now = new GLib.DateTime.now_utc (); + date = "%sZ".printf (now.format ("%Y-%m-%dT%H:%M:%S")); + } else { + // Rygel core makes sure that this is a valid ISO8601 date. + date = item.date; + } + triplets.add (new QueryTriplet (QUERY_ID, + "nie:contentCreated", + "\"" + date + "\"")); + + if (item.size > 0) { + triplets.add (new QueryTriplet.with_graph + (MINER_GRAPH, + QUERY_ID, + "nie:byteSize", + "\"" + item.size.to_string () + "\"")); + } + + base (triplets); + + this.uri = item.get_primary_uri (); + } + + public override async void execute (Sparql.Connection resources) + throws Error, + IOError, + Sparql.Error, + DBusError { + var str = this.to_string (); + + debug ("Executing SPARQL query: %s", str); + + Variant v = yield resources.update_blank_async (str); + VariantIter iter1, iter2, iter3; + string key = null; + + iter1 = v.iterator (); + while (iter1.next ("aa{ss}", out iter2)) { + while (iter2.next ("a{ss}", out iter3)) { + while (iter3.next ("{ss}", out key, out this.id)) { + break; + } + } + } + + // Item already existed + if (this.id == null) { + var cursor = yield resources.query_async + (this.get_resource_id_query ()); + + try { + while (cursor.next ()) { + this.id = cursor.get_string (0); + break; + } + } catch (Error error) { + } + } else { + var file = File.new_for_uri (this.uri); + if (file.is_native () && + file.query_exists ()) { + MinerFilesIndexIface miner = Bus.get_proxy_sync + (BusType.SESSION, + MINER_SERVICE, + MINER_PATH, + DBusProxyFlags.DO_NOT_LOAD_PROPERTIES); + miner.index_file.begin (this.uri); + } + } + + debug ("Created item in Tracker store with ID '%s'", this.id); + } + + public override string to_string () { + var query = "INSERT { " + base.to_string () + " }"; + query += "WHERE {" + RESOURCE_NOT_BOUND_TEMPLATE.printf (this.uri) + + "}"; + + return query; + } + + private string get_resource_id_query () { + return RESOURCE_ID_QUERY_TEMPLATE.printf (this.uri); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-interfaces.vala b/src/plugins/tracker3/rygel-tracker-interfaces.vala new file mode 100644 index 00000000..e4b21a0b --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-interfaces.vala @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +public struct Event { + int graph_id; + int subject_id; + int pred_id; + int object_id; +} + +[DBus (name = "org.freedesktop.Tracker1.Statistics")] +public interface Rygel.Tracker.StatsIface : DBusProxy { + public abstract string[,] get () throws IOError, DBusError; +} + +[DBus (name = "org.freedesktop.Tracker1.Resources")] +public interface Rygel.Tracker.ResourcesIface: DBusProxy { + public abstract async string[,] sparql_query (string query) + throws IOError, DBusError; + public abstract async void sparql_update (string query) + throws IOError, DBusError; + public abstract async HashTable<string,string>[,] sparql_update_blank + (string query) + throws IOError, DBusError; +} + +[DBus (name = "org.freedesktop.Tracker1.Miner.Files.Index")] +public interface Rygel.Tracker.MinerFilesIndexIface: DBusProxy { + public abstract async void index_file (string uri) + throws IOError, DBusError; +} diff --git a/src/plugins/tracker3/rygel-tracker-item-factory.vala b/src/plugins/tracker3/rygel-tracker-item-factory.vala new file mode 100644 index 00000000..5c069f80 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-item-factory.vala @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008-2012 Nokia Corporation. + * Copyright (C) 2010 MediaNet Inh. + * Copyright (C) 2012 Intel Corporation. + * Copyright (C) 2013 Cable Television Laboratories, Inc. + * + * Authors: Zeeshan Ali <zeenix@gmail.com> + * Sunil Mohan Adapa <sunil@medhas.org> + * Jens Georg <jensg@openismus.com> + * Doug Galligan <doug@sentosatech.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using GUPnP; +using Tracker; + +/** + * Abstract Tracker item factory. + */ +public abstract class Rygel.Tracker.ItemFactory { + protected enum Metadata { + TRACKER_ID, + URL, + PLACE_HOLDER, + FILE_NAME, + TITLE, + DLNA_PROFILE, + MIME, + SIZE, + DATE, + + LAST_KEY + } + + public string category; + public string category_iri; + public string upnp_class; + public string? upload_dir; + + public ArrayList<string> properties; + + protected ItemFactory (string category, + string category_iri, + string upnp_class, + string? upload_dir) { + this.category = category; + this.category_iri = category_iri; + this.upnp_class = upnp_class; + this.upload_dir = upload_dir; + + message ("Using %s as upload directory for %s", + upload_dir == null ? "none" : upload_dir, + upnp_class); + + this.properties = new ArrayList<string> (); + + // These must be the same order as enum Metadata + this.properties.add ("res"); + this.properties.add ("place_holder"); + this.properties.add ("fileName"); + this.properties.add ("dc:title"); + this.properties.add ("dlnaProfile"); + this.properties.add ("mimeType"); + this.properties.add ("res@size"); + this.properties.add ("date"); + } + + public abstract MediaFileItem create (string id, + string uri, + SearchContainer parent, + Sparql.Cursor metadata) + throws GLib.Error; + + protected void set_ref_id (MediaFileItem item, string prefix) { + if (item.id.has_prefix (prefix)) { + return; + } + + var split_id = item.id.split (","); + if (split_id.length != 2) { + return; + } + + item.ref_id = prefix + "," + split_id[1]; + } + + protected virtual void set_metadata (MediaFileItem item, + string uri, + Sparql.Cursor metadata) + throws GLib.Error { + if (metadata.is_bound (Metadata.TITLE)) { + item.title = metadata.get_string (Metadata.TITLE); + } else { + /* If title wasn't provided, use filename instead */ + item.title = metadata.get_string (Metadata.FILE_NAME); + } + + if (metadata.is_bound (Metadata.SIZE)) { + item.size = metadata.get_integer (Metadata.SIZE); + } else { + // If its in tracker store and size is unknown, it most probably + // means the size is 0 (i-e a place-holder empty item that we + // created). + item.size = 0; + } + + item.place_holder = metadata.get_boolean (Metadata.PLACE_HOLDER); + + if (metadata.is_bound (Metadata.DATE)) { + item.date = metadata.get_string (Metadata.DATE); + } + + if (metadata.is_bound (Metadata.DLNA_PROFILE)) { + item.dlna_profile = metadata.get_string (Metadata.DLNA_PROFILE); + } + + if (metadata.is_bound (Metadata.MIME)) { + item.mime_type = metadata.get_string (Metadata.MIME); + } + + item.add_uri (uri); + } + + protected virtual void add_resources (MediaFileItem item) + throws GLib.Error { + item.add_engine_resources.begin (); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-metadata-container.vala b/src/plugins/tracker3/rygel-tracker-metadata-container.vala new file mode 100644 index 00000000..1637fef3 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-metadata-container.vala @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using GUPnP; +using Gee; +using Tracker; + +/** + * Base class for containers listing possible values of a particular Tracker + * metadata key. + */ +public abstract class Rygel.Tracker.MetadataContainer : Rygel.SimpleContainer { + /* class-wide constants */ + private const string TRACKER_SERVICE = "org.freedesktop.Tracker1"; + private const string RESOURCES_PATH = "/org/freedesktop/Tracker1/Resources"; + + protected ItemFactory item_factory; + private bool update_in_progress = false; + + private string child_class; + + private Sparql.Connection resources; + protected QueryTriplets triplets; + + protected MetadataContainer (string id, + MediaContainer parent, + string title, + ItemFactory item_factory, + string? child_class = null) { + base (id, parent, title); + + this.item_factory = item_factory; + this.child_class = child_class; + + try { + this.resources = Sparql.Connection.bus_new ("org.freedesktop.Tracker3.Miner.Files", null); + } catch (Error error) { + critical (_("Failed to create Tracker connection: %s"), + error.message); + + return; + } + } + + internal async void fetch_metadata_values () { + if (this.update_in_progress) { + return; + } + + this.update_in_progress = true; + // First thing, clear the existing hierarchy, if any + this.clear (); + + var query = this.create_query (); + + try { + yield query.execute (this.resources); + + /* Iterate through all the values */ + while (query.result.next ()) { + if (!query.result.is_bound (0)) { + continue; + } + + var value = query.result.get_string (0); + + if (value == "") { + continue; + } + + var title = this.create_title_for_value (value); + if (title == null) { + continue; + } + + var id = this.create_id_for_title (title); + if (id == null || !this.is_child_id_unique (id)) { + continue; + } + + var container = this.create_container (id, title, value); + + if (this.child_class != null) { + container.upnp_class = child_class; + } + + this.add_child_container (container); + } + } catch (Error error) { + critical (_("Error getting all values for “%s”: %s"), + this.id, + error.message); + this.update_in_progress = false; + + return; + } + + this.updated (); + this.update_in_progress = false; + } + + protected abstract SelectionQuery create_query (); + protected abstract SearchContainer create_container (string id, + string title, + string value); + + public override async MediaObject? find_object (string id, + Cancellable? cancellable) + throws GLib.Error { + if (this.is_our_child (id)) { + return yield base.find_object (id, cancellable); + } else { + return null; + } + } + + protected virtual string? create_id_for_title (string title) { + return this.id + ":" + Uri.escape_string (title, "", true); + } + + protected virtual string? create_title_for_value (string value) { + return value; + } + + protected virtual string create_filter (string variable, string value) { + return variable + " = \"" + Query.escape_string (value) + "\""; + } + + private bool is_our_child (string id) { + return id.has_prefix (this.id + ":"); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-metadata-multivalues.vala b/src/plugins/tracker3/rygel-tracker-metadata-multivalues.vala new file mode 100644 index 00000000..a5d94716 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-metadata-multivalues.vala @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008-2012 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * Jens Georg <jensg@openismus.com> + * Jens Georg <mail@jensge.org> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using GUPnP; +using Gee; + +/** + * Container listing possible values of a particuler Tracker metadata key. + * This class is used for multivalue properties such as nao:Tag (via + * nao:hasTag) + */ +public abstract class Rygel.Tracker.MetadataMultiValues : MetadataContainer { + public string[] key_chain; + + protected MetadataMultiValues (string id, + MediaContainer parent, + string title, + ItemFactory item_factory, + string[] key_chain, + string? child_class = null) { + base (id, parent, title, item_factory, child_class); + + this.key_chain = key_chain; + + this.fetch_metadata_values.begin (); + } + + protected override SelectionQuery create_query () { + this.triplets = new QueryTriplets (); + + this.triplets.add (new QueryTriplet (SelectionQuery.ITEM_VARIABLE, + "a", + this.item_factory.category)); + + // All variables used in the query + var num_keys = this.key_chain.length - 1; + var variables = new string[num_keys]; + for (int i = 0; i < num_keys; i++) { + variables[i] = "?" + key_chain[i].replace (":", "_"); + + string subject; + if (i == 0) { + subject = SelectionQuery.ITEM_VARIABLE; + } else { + subject = variables[i - 1]; + } + + this.triplets.add (new QueryTriplet (subject, + this.key_chain[i], + variables[i])); + } + + // Variables to select from query + var selected = new ArrayList<string> (); + // Last variable is the only thing we are interested in the result + var last_variable = variables[num_keys - 1]; + selected.add ("DISTINCT " + last_variable); + + return new SelectionQuery (selected, triplets, null, last_variable); + } + + protected override SearchContainer create_container (string id, + string title, + string value) { + + // The child container can use the same triplets we used in our + // query. + var child_triplets = new QueryTriplets.clone (triplets); + + // However we constrain the object of our last triplet. + var filters = new ArrayList<string> (); + var filter = this.create_filter (child_triplets.last ().obj, value); + filters.add (filter); + + return new SearchContainer (id, + this, + title, + this.item_factory, + child_triplets, + filters); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-metadata-values.vala b/src/plugins/tracker3/rygel-tracker-metadata-values.vala new file mode 100644 index 00000000..e9fd1606 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-metadata-values.vala @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008-2012 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using GUPnP; +using Gee; +using Tracker; + +/** + * Container listing possible values of a particuler Tracker metadata key. + * The key needs to be single-valued. + */ +public abstract class Rygel.Tracker.MetadataValues : MetadataContainer { + private string property; + + protected MetadataValues (string id, + MediaContainer parent, + string title, + ItemFactory item_factory, + string property, + string? child_class = null) { + base (id, parent, title, item_factory, child_class); + + this.property = property; + + this.triplets = new QueryTriplets (); + + this.triplets.add (new QueryTriplet (SelectionQuery.ITEM_VARIABLE, + "a", + this.item_factory.category)); + this.fetch_metadata_values.begin (); + } + + protected override SelectionQuery create_query () { + var property_map = UPnPPropertyMap.get_property_map (); + var selected = new ArrayList<string> (); + selected.add ("DISTINCT " + + property_map[this.property] + + " AS ?x"); + + return new SelectionQuery (selected, triplets, null, "?x"); + } + + protected override SearchContainer create_container (string id, + string title, + string value) { + // The child container can use the same triplets we used in our + // query. + var child_triplets = new QueryTriplets.clone (this.triplets); + + // However we constrain the object of our last triplet. + var filters = new ArrayList<string> (); + var property_map = UPnPPropertyMap.get_property_map (); + var property = property_map[this.property]; + var filter = this.create_filter (property, value); + filters.add (filter); + + var child = new SearchContainer (id, + this, + title, + this.item_factory, + child_triplets, + filters); + if (this.property == "upnp:album") { + child.sort_criteria = MediaContainer.ALBUM_SORT_CRITERIA; + } + + return child; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-music-item-factory.vala b/src/plugins/tracker3/rygel-tracker-music-item-factory.vala new file mode 100644 index 00000000..9a273999 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-music-item-factory.vala @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008-2012 Nokia Corporation. + * Copyright (C) 2010 MediaNet Inh. + * + * Authors: Zeeshan Ali <zeenix@gmail.com> + * Sunil Mohan Adapa <sunil@medhas.org> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Tracker music item factory. + */ +public class Rygel.Tracker.MusicItemFactory : ItemFactory { + private enum MusicMetadata { + DURATION = Metadata.LAST_KEY, + AUDIO_ALBUM, + AUDIO_ARTIST, + AUDIO_TRACK_NUM, + AUDIO_GENRE, + SAMPLE_RATE, + CHANNELS, + BITS_PER_SAMPLE, + BITRATE, + + LAST_KEY + } + + private const string CATEGORY = "nmm:MusicPiece"; + private const string CATEGORY_IRI = "http://www.tracker-project.org/" + + "temp/nmm#MusicPiece"; + + public MusicItemFactory () { + var upload_folder = Environment.get_user_special_dir + (UserDirectory.MUSIC); + try { + var config = MetaConfig.get_default (); + upload_folder = config.get_music_upload_folder (); + } catch (Error error) {}; + + base (CATEGORY, CATEGORY_IRI, MusicItem.UPNP_CLASS, upload_folder); + + // These must be the same order as enum MusicMetadata + this.properties.add ("res@duration"); + this.properties.add ("upnp:album"); + this.properties.add ("upnp:artist"); + this.properties.add ("upnp:originalTrackNumber"); + this.properties.add ("upnp:genre"); + this.properties.add ("sampleRate"); + this.properties.add ("upnp:nrAudioChannels"); + this.properties.add ("upnp:bitsPerSample"); + this.properties.add ("upnp:bitrate"); + } + + public override MediaFileItem create (string id, + string uri, + SearchContainer parent, + Sparql.Cursor metadata) + throws GLib.Error { + var item = new MusicItem (id, parent, ""); + + this.set_metadata (item, uri, metadata); + + return item; + } + + protected override void set_metadata (MediaFileItem item, + string uri, + Sparql.Cursor metadata) + throws GLib.Error { + base.set_metadata (item, uri, metadata); + + this.set_ref_id (item, "AllMusic"); + + var music = item as MusicItem; + + if (metadata.is_bound (MusicMetadata.DURATION) && + metadata.get_string (MusicMetadata.DURATION) != "0") { + music.duration = (long) metadata.get_integer + (MusicMetadata.DURATION); + } + + if (metadata.is_bound (MusicMetadata.SAMPLE_RATE)) { + music.sample_freq = (int) metadata.get_integer + (MusicMetadata.SAMPLE_RATE); + } + + if (metadata.is_bound (MusicMetadata.CHANNELS)) { + music.channels = (int) metadata.get_integer + (MusicMetadata.CHANNELS); + } + + if (metadata.is_bound (MusicMetadata.BITS_PER_SAMPLE)) { + music.bits_per_sample = (int) metadata.get_integer + (MusicMetadata.BITS_PER_SAMPLE); + } + + if (metadata.is_bound (MusicMetadata.BITRATE)) { + music.bitrate = (int) metadata.get_integer + (MusicMetadata.BITRATE) / 8; + } + + if (metadata.is_bound (MusicMetadata.AUDIO_TRACK_NUM)) { + music.track_number = (int) metadata.get_integer + (MusicMetadata.AUDIO_TRACK_NUM); + } + + if (metadata.is_bound (MusicMetadata.AUDIO_ARTIST)) { + music.artist = metadata.get_string (MusicMetadata.AUDIO_ARTIST); + } + + if (metadata.is_bound (MusicMetadata.AUDIO_ALBUM)) { + music.album = metadata.get_string (MusicMetadata.AUDIO_ALBUM); + } + + if (metadata.is_bound (MusicMetadata.AUDIO_GENRE)) { + music.genre = metadata.get_string (MusicMetadata.AUDIO_GENRE); + } + + music.lookup_album_art (); + + base.add_resources(music); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-music.vala b/src/plugins/tracker3/rygel-tracker-music.vala new file mode 100644 index 00000000..dc81cf00 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-music.vala @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * Container listing Music content hierarchy. + */ +public class Rygel.Tracker.Music : CategoryContainer { + public Music (string id, MediaContainer parent, string title) { + base (id, parent, title, new MusicItemFactory ()); + + this.add_child_container (new Artists (this)); + this.add_child_container (new Albums (this)); + this.add_child_container (new Genre (this)); + this.search_classes.add (AudioItem.UPNP_CLASS); + this.search_classes.add (MusicItem.UPNP_CLASS); + this.add_create_class (AudioItem.UPNP_CLASS); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-new.vala b/src/plugins/tracker3/rygel-tracker-new.vala new file mode 100644 index 00000000..efabcc86 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-new.vala @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>. + * Copyright (C) 2008,2010 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * A container listing all newly (<3 days) added items. + */ +public class Rygel.Tracker.New : Rygel.Tracker.SearchContainer { + private const string ADDED_PREDICATE = "tracker:added"; + private const string ADDED_VARIABLE = "?added"; + private const long THREE_DAYS_AS_SEC = 259200; + + public New (MediaContainer parent, ItemFactory item_factory) { + var triplets = new QueryTriplets (); + + triplets.add (new QueryTriplet (SelectionQuery.ITEM_VARIABLE, + "a", + item_factory.category)); + triplets.add (new QueryTriplet (SelectionQuery.ITEM_VARIABLE, + ADDED_PREDICATE, + ADDED_VARIABLE)); + + var now = new DateTime.now_utc (); + now.add_days (-3); + var three_days_ago = "%sZ".printf (now.format ("%Y-%m-%dT%H:%M:%S")); + + var filters = new ArrayList<string> (); + filters.add (ADDED_VARIABLE + " > \"" + three_days_ago + "\""); + + base (parent.id + "New", + parent, + "New", + item_factory, + triplets, + filters); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-picture-item-factory.vala b/src/plugins/tracker3/rygel-tracker-picture-item-factory.vala new file mode 100644 index 00000000..e937fc2d --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-picture-item-factory.vala @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008 Nokia Corporation. + * Copyright (C) 2010 MediaNet Inh. + * + * Authors: Zeeshan Ali <zeenix@gmail.com> + * Sunil Mohan Adapa <sunil@medhas.org> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Tracker picture item factory. + */ +public class Rygel.Tracker.PictureItemFactory : ItemFactory { + private enum PictureMetadata { + HEIGHT = Metadata.LAST_KEY, + WIDTH, + + LAST_KEY + } + + private const string CATEGORY = "nmm:Photo"; + private const string CATEGORY_IRI = "http://www.tracker-project.org/" + + "temp/nmm#Photo"; + + public PictureItemFactory () { + var upload_folder = Environment.get_user_special_dir + (UserDirectory.PICTURES); + try { + var config = MetaConfig.get_default (); + upload_folder = config.get_picture_upload_folder (); + } catch (Error error) {}; + + base (CATEGORY, CATEGORY_IRI, PhotoItem.UPNP_CLASS, upload_folder); + + // These must be in the same order as enum PictureMetadata + this.properties.add ("height"); + this.properties.add ("width"); + } + + public override MediaFileItem create (string id, + string uri, + SearchContainer parent, + Sparql.Cursor metadata) + throws GLib.Error { + var item = new PhotoItem (id, parent, ""); + + this.set_metadata (item, uri, metadata); + + return item; + } + + protected override void set_metadata (MediaFileItem item, + string uri, + Sparql.Cursor metadata) + throws GLib.Error { + base.set_metadata (item, uri, metadata); + + this.set_ref_id (item, "AllPictures"); + + var photo = item as PhotoItem; + + if (metadata.is_bound (PictureMetadata.WIDTH)) { + photo.width = (int) metadata.get_integer (PictureMetadata.WIDTH); + } + + if (metadata.is_bound (PictureMetadata.HEIGHT)) { + photo.height = (int) metadata.get_integer (PictureMetadata.HEIGHT); + } + + base.add_resources(photo); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-pictures.vala b/src/plugins/tracker3/rygel-tracker-pictures.vala new file mode 100644 index 00000000..78c2c1f5 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-pictures.vala @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * Container listing Pictures content hierarchy. + */ +public class Rygel.Tracker.Pictures : CategoryContainer { + public Pictures (string id, MediaContainer parent, string title) { + base (id, parent, title, new PictureItemFactory ()); + + this.add_child_container (new Years (this, this.item_factory)); + this.search_classes.add (ImageItem.UPNP_CLASS); + this.add_create_class (ImageItem.UPNP_CLASS); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-plugin-factory.vala b/src/plugins/tracker3/rygel-tracker-plugin-factory.vala new file mode 100644 index 00000000..e7c74c92 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-plugin-factory.vala @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>. + * Copyright (C) 2009-2012 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Rygel; +using Gee; + +private Rygel.Tracker.PluginFactory plugin_factory; + +public void module_init (PluginLoader loader) { + try { + plugin_factory = new Rygel.Tracker.PluginFactory (loader); + } catch (Error err) { + warning (_("Failed to start Tracker service: %s. Plugin disabled."), + err.message); + } +} + +public class Rygel.Tracker.PluginFactory { + private const string TRACKER_SERVICE = "org.freedesktop.Tracker1"; + private const string STATISTICS_OBJECT = + "/org/freedesktop/Tracker1/Statistics"; + + StatsIface stats; + PluginLoader loader; + + public PluginFactory (PluginLoader loader) throws IOError, DBusError { + this.stats = Bus.get_proxy_sync (BusType.SESSION, + TRACKER_SERVICE, + STATISTICS_OBJECT, + DBusProxyFlags.DO_NOT_LOAD_PROPERTIES); + this.loader = loader; + + this.stats.get (); + + this.loader.add_plugin (new Tracker.Plugin ()); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-plugin.vala b/src/plugins/tracker3/rygel-tracker-plugin.vala new file mode 100644 index 00000000..d01cb528 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-plugin.vala @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +public class Rygel.Tracker.Plugin : Rygel.MediaServerPlugin { + public const string NAME = "Tracker"; + + private static RootContainer root; + + public Plugin () { + if (root == null) { + // translators: @REALNAME@ is substituted for user's real name and it doesn't need translation. + root = new RootContainer (_("@REALNAME@’s media")); + } + + base (root, Plugin.NAME, null, PluginCapabilities.UPLOAD); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-query-triplet.vala b/src/plugins/tracker3/rygel-tracker-query-triplet.vala new file mode 100644 index 00000000..870dfe7d --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-query-triplet.vala @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * Represents SPARQL Triplet + */ +public class Rygel.Tracker.QueryTriplet { + public string graph; + public string subject; + public string predicate; + public string obj; + + public QueryTriplet next; + + public QueryTriplet (string subject, string predicate, string obj) { + this.graph = null; + this.subject = subject; + this.predicate = predicate; + this.obj = obj; + } + + public QueryTriplet.with_graph (string graph, + string subject, + string predicate, + string object) { + this.graph = graph; + this.subject = subject; + this.predicate = predicate; + this.obj = object; + } + + public QueryTriplet.chain (string subject, + string predicate, + QueryTriplet next) { + this.subject = subject; + this.predicate = predicate; + this.next = next; + } + + public QueryTriplet.clone (QueryTriplet triplet) { + this.graph = triplet.graph; + this.subject = triplet.subject; + this.predicate = triplet.predicate; + + if (triplet.next != null) { + this.next = triplet.next; + } else { + this.obj = triplet.obj; + } + } + + public static bool equal_func (QueryTriplet a, QueryTriplet b) { + bool chain_equal; + + if (a.next != null && b.next != null) { + chain_equal = equal_func (a.next, b.next); + } else { + chain_equal = a.next == b.next; + } + + return a.graph == b.graph && + a.subject == b.subject && + a.obj == b.obj && + a.predicate == b.predicate && + chain_equal; + } + + public string to_string (bool include_subject = true) { + string str = ""; + + if (include_subject) { + str += " " + subject; + } + + str += " " + predicate; + + if (this.next != null) { + str += " [ " + this.next.to_string () + " ] "; + } else { + str += " " + this.obj; + } + + return str; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-query-triplets.vala b/src/plugins/tracker3/rygel-tracker-query-triplets.vala new file mode 100644 index 00000000..92a39de7 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-query-triplets.vala @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2008 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * Represents a list of SPARQL Triplet + */ +public class Rygel.Tracker.QueryTriplets : ArrayList<QueryTriplet> { + public QueryTriplets () { + base ((EqualDataFunc<QueryTriplet>) QueryTriplet.equal_func); + } + + public QueryTriplets.clone (QueryTriplets triplets) { + base ((EqualDataFunc<QueryTriplet>) QueryTriplet.equal_func); + + foreach (var triplet in triplets) { + this.add (new QueryTriplet.clone (triplet)); + } + } + + public string serialize () { + string str = ""; + var include_subject = true; + + for (int i = 0; i < this.size; i++) { + if (this[i].graph != null && include_subject) { + str += "GRAPH <%s> {".printf (this[i].graph); + } + + str += this[i].to_string (include_subject); + + if (i < this.size - 1) { + include_subject = this[i].subject != this[i + 1].subject || + this.check_graph_change (i); + + if (include_subject) { + str += " . "; + // close the graph if we change the subject + if (this[i].graph != null) { + str += "} "; + } + } else { + str += " ; "; + } + } else { + // need to explicitly close the graph for the last triplet + if (this[i].graph != null) { + str += " . } "; + } + } + } + + return str; + } + + public override bool add (QueryTriplet triplet) { + if (!this.contains (triplet)) { + return base.add (triplet); + } + + return false; + } + + private bool check_graph_change (int i) { + return (this[i].graph == null && this[i + 1].graph != null) || + (this[i].graph != null && this[i + 1].graph == null) || + (this[i].graph != this[i + 1].graph); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-query.vala b/src/plugins/tracker3/rygel-tracker-query.vala new file mode 100644 index 00000000..8aa7ea08 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-query.vala @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008-2012 Nokia Corporation. + * + * Authors: Zeeshan Ali <zeenix@gmail.com> + * Ivan Frade <ivan.frade@nokia.com> + * Jens Georg <jensg@openismus.com> + * Luis de Bethencourt <luisbg@collabora.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Represents Tracker SPARQL query + */ +public abstract class Rygel.Tracker.Query { + public QueryTriplets triplets; + + protected Query (QueryTriplets triplets) { + this.triplets = triplets; + } + + public abstract async void execute (Sparql.Connection resources) + throws Error, + IOError, + Sparql.Error, + DBusError; + + // Deriving classes should override this method and complete it by + // adding the first part of the query + public virtual string to_string () { + return this.triplets.serialize (); + } + + /** + * Convenience function to combine Query.escape_string and + * Regex.escape_string in one function call + * + * @param literal A string to escape + * + * @return A newly allocated string with the sparql-escaped regex-escaped + * version of literal. The returned string should be freed with g_free() + * when no longer needed. + */ + public static string escape_regex (string literal) { + return escape_string (Regex.escape_string (literal)); + } + + /** + * tracker_sparql_escape_string: Escapes a string so that it can be + * used in a SPARQL query. Copied from Tracker project. + * + * @param literal A string to escape + * + * @return A newly-allocated string with the escaped version of + * literal. The returned string should be freed with g_free() when no + * longer needed. + */ + public static string escape_string (string literal) { + StringBuilder str = new StringBuilder (); + char *p = literal; + + while (*p != '\0') { + size_t len = Posix.strcspn ((string) p, "\t\n\r\b\f\"\\"); + str.append_len ((string) p, (long) len); + p += len; + + switch (*p) { + case '\t': + str.append ("\\t"); + break; + case '\n': + str.append ("\\n"); + break; + case '\r': + str.append ("\\r"); + break; + case '\b': + str.append ("\\b"); + break; + case '\f': + str.append ("\\f"); + break; + case '"': + str.append ("\\\""); + break; + case '\\': + str.append ("\\\\"); + break; + default: + continue; + } + + p++; + } + + return str.str; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-root-container.vala b/src/plugins/tracker3/rygel-tracker-root-container.vala new file mode 100644 index 00000000..88a7d3af --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-root-container.vala @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>. + * Copyright (C) 2008 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using GUPnP; +using Gee; + +/** + * Represents the root container for Tracker media content hierarchy. + */ +public class Rygel.Tracker.RootContainer : Rygel.SimpleContainer { + public RootContainer (string title) { + base.root (title); + + if (this.get_bool_config_without_error ("share-music")) { + this.add_child_container (new Music ("Music", this, "Music")); + } + + if (this.get_bool_config_without_error ("share-videos")) { + this.add_child_container (new Videos ("Videos", this, "Videos")); + } + + if (this.get_bool_config_without_error ("share-pictures")) { + this.add_child_container (new Pictures ("Pictures", + this, + "Pictures")); + } + } + + private bool get_bool_config_without_error (string key) { + var value = true; + var config = MetaConfig.get_default (); + + try { + value = config.get_bool ("Tracker", key); + } catch (GLib.Error error) {} + + return value; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-search-container.vala b/src/plugins/tracker3/rygel-tracker-search-container.vala new file mode 100644 index 00000000..4310e090 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-search-container.vala @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008-2012 Nokia Corporation. + * Copyright (C) 2010 MediaNet Inh. + * + * Authors: Zeeshan Ali <zeenix@gmail.com> + * Sunil Mohan Adapa <sunil@medhas.org> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using GUPnP; +using Gee; +using Tracker; + +/** + * A container listing a Tracker search result. + */ +public class Rygel.Tracker.SearchContainer : SimpleContainer { + /* class-wide constants */ + private const string MODIFIED_PROPERTY = "nfo:fileLastModified"; + + public SelectionQuery query; + public ItemFactory item_factory; + + private Sparql.Connection resources; + + private static HashMap<string, uint> update_id_hash; + + public SearchContainer (string id, + MediaContainer parent, + string title, + ItemFactory item_factory, + QueryTriplets? triplets = null, + ArrayList<string>? filters = null) { + base (id, parent, title); + + if (unlikely (update_id_hash == null)) { + update_id_hash = new HashMap<string, uint> (); + } + + if (update_id_hash.has_key (this.id)) { + this.update_id = update_id_hash[this.id]; + } + + this.container_updated.connect ( (container, origin) => { + if (origin == this) { + update_id_hash[this.id] = this.update_id; + } + }); + + this.item_factory = item_factory; + + var variables = new ArrayList<string> (); + variables.add (SelectionQuery.ITEM_VARIABLE); + + QueryTriplets our_triplets; + if (triplets != null) { + our_triplets = triplets; + } else { + our_triplets = new QueryTriplets (); + } + + our_triplets.add (new QueryTriplet + (SelectionQuery.ITEM_VARIABLE, + "a", + item_factory.category)); + + var property_map = UPnPPropertyMap.get_property_map (); + foreach (var property in this.item_factory.properties) { + variables.add (property_map[property]); + } + + var order_by = MODIFIED_PROPERTY + + "(" + + SelectionQuery.ITEM_VARIABLE + + ")"; + + this.query = new SelectionQuery (variables, + our_triplets, + filters, + order_by); + + try { + this.resources = Sparql.Connection.bus_new ("org.freedesktop.Tracker3.Miner.Files", null); + + this.get_children_count.begin (); + } catch (Error error) { + critical (_("Failed to get Tracker connection: %s"), error.message); + } + } + + public override async MediaObjects? get_children (uint offset, + uint max_count, + string sort_criteria, + Cancellable? cancellable) + throws GLib.Error { + var expression = new RelationalExpression (); + expression.op = SearchCriteriaOp.EQ; + expression.operand1 = "@parentID"; + expression.operand2 = this.id; + + uint total_matches; + + return yield this.execute_query (expression, + sort_criteria, + offset, + max_count, + cancellable, + out total_matches); + } + + public async MediaObjects? execute_query (SearchExpression? expression, + string sort_criteria, + uint offset, + uint max_count, + Cancellable? cancellable, + out uint total_matches) + throws GLib.Error { + var results = new MediaObjects (); + + var query = this.create_query (expression as RelationalExpression, + (int) offset, + (int) max_count, + sort_criteria); + + if (query != null) { + yield query.execute (this.resources); + + /* Iterate through all items */ + while (yield query.result.next_async ()) { + var id = query.result.get_string (0); + id = this.create_child_id_for_urn (id); + var uri = query.result.get_string (1); + + var item = this.item_factory.create (id, + uri, + this, + query.result); + results.add (item); + } + } + + total_matches = results.size; + + return results; + } + + public override async MediaObject? find_object (string id, + Cancellable? cancellable) + throws GLib.Error { + if (!this.is_our_child (id)) { + return null; + } + + var expression = new RelationalExpression (); + expression.op = SearchCriteriaOp.EQ; + expression.operand1 = "@id"; + expression.operand2 = id; + + uint total_matches; + var results = yield this.execute_query (expression, + "", + 0, + 1, + cancellable, + out total_matches); + if (results.size > 0) { + return results[0]; + } else { + return null; + } + } + + public string create_child_id_for_urn (string urn) { + return this.id + "," + urn; + } + + // Returns the URN and the ID of the parent this item belongs to, or null + // if item_id is invalid + protected string? get_item_info (string item_id, + out string parent_id) { + var tokens = item_id.split (",", 2); + + if (tokens[0] != null && tokens[1] != null) { + parent_id = tokens[0]; + + return tokens[1]; + } else { + parent_id = null; + + return null; + } + } + + internal async void get_children_count () { + try { + var query = new SelectionQuery.clone (this.query); + + query.variables = new ArrayList<string> (); + query.variables.add ("COUNT(" + + SelectionQuery.ITEM_VARIABLE + + ") AS ?x"); + + yield query.execute (this.resources); + + if (query.result.next ()) { + this.child_count = int.parse (query.result.get_string (0)); + this.updated (); + } + + } catch (GLib.Error error) { + critical (_("Error getting item count under category “%s”: %s"), + this.item_factory.category, + error.message); + + return; + } + } + + private bool is_our_child (string id) { + return id.has_prefix (this.id + ","); + } + + private SelectionQuery? create_query (RelationalExpression? expression, + int offset, + int max_count, + string sort_criteria = "") { + if (expression.operand1 == "upnp:class" && + !this.item_factory.upnp_class.has_prefix (expression.operand2)) { + return null; + } + + SelectionQuery query; + if (sort_criteria == null || sort_criteria == "") { + query = new SelectionQuery.clone (this.query); + } else { + query = create_sorted_query (sort_criteria); + } + + if (expression.operand1 == "@parentID") { + if (!expression.compare_string (this.id)) { + return null; + } + } else if (expression.operand1 != "upnp:class") { + var filter = create_filter_for_child (expression); + if (filter != null) { + query.filters.insert (0, filter); + } else { + return null; + } + } + + query.offset = offset; + query.max_count = max_count; + + return query; + } + + private SelectionQuery? create_sorted_query (string sort_criteria) { + var key_chain_map = UPnPPropertyMap.get_property_map (); + var sort_props = sort_criteria.split (","); + string order = ""; + ArrayList<string> variables = new ArrayList<string> (); + ArrayList<string> filters = new ArrayList<string> (); + + variables.add_all (this.query.variables); + filters.add_all (this.query.filters); + + foreach (string s in sort_props) { + var key = key_chain_map[s.substring(1)]; + if (key.index_of (SelectionQuery.ITEM_VARIABLE) == 0) { + continue; + } + + if (s.has_prefix("-")) { + order += "DESC (" + + key + ") "; + } else { + order += key + " "; + } + } + + if (order == "") { + order = this.query.order_by; + } + + return new SelectionQuery ( + variables, + new QueryTriplets.clone(this.query.triplets), + filters, + order); + } + + private string? urn_to_utf8 (string urn) { + var urn_builder = new StringBuilder (); + unowned string s = urn; + + for (; s.get_char () != 0; s = s.next_char ()) { + unichar character = s.get_char (); + if (!(character.iscntrl () || !character.validate ())) { + urn_builder.append_unichar (character); + } + } + + return urn_builder.str; + } + + private string? create_filter_for_child (RelationalExpression expression) { + string filter = null; + string variable = null; + string value = null; + + if (expression.operand1 == "@id") { + variable = SelectionQuery.ITEM_VARIABLE; + + string parent_id; + + var urn = this.get_item_info (expression.operand2, out parent_id); + + if (!urn.validate ()) { + urn = urn_to_utf8 (urn); + } + + if (urn == null || parent_id == null || parent_id != this.id) { + return null; + } + + urn = Query.escape_string (urn); + + switch (expression.op) { + case SearchCriteriaOp.EQ: + value = "<" + urn + ">"; + break; + case SearchCriteriaOp.CONTAINS: + value = expression.operand2; + break; + } + } + + if (variable == null || value == null) { + return null; + } + + switch (expression.op) { + case SearchCriteriaOp.EQ: + filter = variable + " = " + value; + break; + case SearchCriteriaOp.CONTAINS: + // We need to escape this twice for Tracker + var regex = Query.escape_regex (value); + + filter = "regex(" + variable + ", \"" + regex + "\", \"i\")"; + break; + } + + return filter; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-selection-query.vala b/src/plugins/tracker3/rygel-tracker-selection-query.vala new file mode 100644 index 00000000..9a0f8282 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-selection-query.vala @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2010-2012 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Represents Tracker SPARQL Selection query + */ +public class Rygel.Tracker.SelectionQuery : Query { + public const string ITEM_VARIABLE = "?item"; + private const string SHARED_FILTER = "(!BOUND(nmm:uPnPShared(" + + ITEM_VARIABLE + ")) ||" + + " nmm:uPnPShared(" + + ITEM_VARIABLE + + ") = true) && " + + "(BOUND(nie:url(" + + ITEM_VARIABLE + ")))"; + private const string STRICT_SHARED_FILTER = "(BOUND(nmm:dlnaProfile(" + + ITEM_VARIABLE + ")))"; + private const string AVAILABLE_FILTER = "(tracker:available(" + + ITEM_VARIABLE + ") = true)"; + + private string uri_filter; + + public ArrayList<string> variables; + public ArrayList<string> filters; + + public string order_by; + public int offset; + public int max_count; + + public Sparql.Cursor result; + + public SelectionQuery (ArrayList<string> variables, + QueryTriplets triplets, + ArrayList<string>? filters, + string? order_by = null, + int offset = 0, + int max_count = -1) { + base (triplets); + + if (filters != null) { + this.filters = filters; + } else { + this.filters = new ArrayList<string> (); + } + + this.variables = variables; + this.order_by = order_by; + this.offset = offset; + this.max_count = max_count; + + ArrayList<string> uris; + string[] uri_filters = new string[0]; + + var config = MetaConfig.get_default (); + + try { + uris = config.get_string_list ("Tracker", "only-export-from"); + } catch (Error error) { + uris = new ArrayList<string> (); + } + + var home_dir = File.new_for_path (Environment.get_home_dir ()); + unowned string pictures_dir = Environment.get_user_special_dir + (UserDirectory.PICTURES); + unowned string videos_dir = Environment.get_user_special_dir + (UserDirectory.VIDEOS); + unowned string music_dir = Environment.get_user_special_dir + (UserDirectory.MUSIC); + + foreach (var uri in uris) { + var file = File.new_for_commandline_arg (uri); + if (!file.equal (home_dir)) { + var actual_uri = uri; + + if (pictures_dir != null) { + actual_uri = actual_uri.replace ("@PICTURES@", pictures_dir); + } + if (videos_dir != null) { + actual_uri = actual_uri.replace ("@VIDEOS@", videos_dir); + } + if (music_dir != null) { + actual_uri = actual_uri.replace ("@MUSIC@", music_dir); + } + + if (actual_uri.contains ("@PICTURES@") || + actual_uri.contains ("@VIDEOS@") || + actual_uri.contains ("@MUSIC@")) { + continue; + } + + // protect against special directories expanding to $HOME + file = File.new_for_commandline_arg (actual_uri); + if (file.equal (home_dir)) { + continue; + } + + uri_filters += "tracker:uri-is-descendant(\"%s\", nie:url(%s))".printf + (file.get_uri (), ITEM_VARIABLE); + } + } + + if (uri_filters.length != 0) { + this.uri_filter = "(%s)".printf (string.joinv ("||", uri_filters)); + } else { + this.uri_filter = null; + } + } + + public SelectionQuery.clone (SelectionQuery query) { + this (copy_str_list (query.variables), + new QueryTriplets.clone (query.triplets), + copy_str_list (query.filters), + query.order_by, + query.offset, + query.max_count); + } + + public override async void execute (Sparql.Connection resources) + throws Error, + IOError, + Sparql.Error, + DBusError { + var str = this.to_string (); + + critical ("Executing SPARQL query: %s", str); + + result = yield resources.query_async (str); + } + + public override string to_string () { + var query = "SELECT "; + + foreach (var variable in this.variables) { + query += " " + variable; + } + + query += " WHERE { " + base.to_string (); + + var filters = new ArrayList<string> (); + filters.add_all (this.filters); + // Make sure we don't expose items that are marked not to be shared + filters.add (SHARED_FILTER); + + // Make sure we don't expose items on removable media that isn't + // mounted + filters.add (AVAILABLE_FILTER); + + // If strict sharing is enabled, only expose files that have a DLNA + // profile set + try { + var config = MetaConfig.get_default (); + if (config.get_bool ("Tracker", "strict-sharing")) { + filters.add (STRICT_SHARED_FILTER); + } + } catch (Error error) {}; + + // Limit the files to a set of folders that may have been configured + if (uri_filter != null) { + filters.add (uri_filter); + } + + if (filters.size > 0) { + query += " FILTER ("; + for (var i = 0; i < filters.size; i++) { + query += filters[i]; + + if (i < filters.size - 1) { + query += " && "; + } + } + query += ")"; + } + + query += " }"; + + if (this.order_by != null) { + query += " ORDER BY " + order_by; + } + + if (this.offset > 0) { + query += " OFFSET " + this.offset.to_string (); + } + + if (this.max_count > 0) { + query += " LIMIT " + this.max_count.to_string (); + } + + return query; + } + + private static ArrayList<string> copy_str_list (Gee.List<string> str_list) { + var copy = new ArrayList<string> (); + + copy.add_all (str_list); + + return copy; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-tags.vala b/src/plugins/tracker3/rygel-tracker-tags.vala new file mode 100644 index 00000000..196a093e --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-tags.vala @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008 Nokia Corporation. + * + * Author: Zeeshan Ali <zeenix@gmail.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using GUPnP; +using Gee; + +/** + * Container listing all available tag labels in Tracker DB. + */ +public class Rygel.Tracker.Tags : MetadataMultiValues { + /* class-wide constants */ + private const string TITLE = "Tags"; + + private const string[] KEY_CHAIN = { "nao:hasTag", "nao:prefLabel", null }; + + public Tags (MediaContainer parent, ItemFactory item_factory) { + base (parent.id + TITLE, parent, TITLE, item_factory, KEY_CHAIN); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-titles.vala b/src/plugins/tracker3/rygel-tracker-titles.vala new file mode 100644 index 00000000..c51f7525 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-titles.vala @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +/** + * Container providing a title-based hierarchy. + * + * Under each category container, add a container providing a title-based + * hierarchy: One container for each unique starting character of all the titles + * available for the contegory in question. Something like this: + * + * Music + * | + * |----> Genre + * |.. + * ^ + * |----> Titles + * | + * |---> A + * | + * |--> Alpha + * |--> alright + * ^ + * |---> B + * | + * |--> Bravo + * |--> brave + * |.. + * ^ + * ^ |.. + * |.. + */ +public class Rygel.Tracker.Titles : MetadataValues { + private const string[] KEY_CHAIN = { "dc:title", null }; + + public Titles (MediaContainer parent, ItemFactory item_factory) { + base (parent.id + "Titles", + parent, + _("Titles"), + item_factory, + "dc:title"); + } + + // The parent class will only create a child container for each unique + // title this method returns so we don't need to worry about multiple + // containers being created for each letter. + protected override string? create_title_for_value (string value) { + var c = value.get_char_validated (); + + if (unlikely (c < 0)) { + return null; + } + + return c.to_string ().up (); + } + + protected override string create_filter (string variable, string value) { + var title = Query.escape_regex (this.create_title_for_value (value)); + + return "regex(" + variable + ", \"^" + title + "\", \"i\")"; + } +} diff --git a/src/plugins/tracker3/rygel-tracker-upnp-property-map.vala b/src/plugins/tracker3/rygel-tracker-upnp-property-map.vala new file mode 100644 index 00000000..7670b57c --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-upnp-property-map.vala @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2010 MediaNet Inh. + * Copyright (C) 2012 Jens Georg <mail@jensge.org> + * + * Author: Sunil Mohan Adapa <sunil@medhas.org> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * A map of UPnP properties to tracker property functions, coalesces, + * subqueries or other custom functions + */ +public class Rygel.Tracker.UPnPPropertyMap : Object { + HashMap<string, ArrayList<string>> property_map; + HashMap<string, string> functions; + private static UPnPPropertyMap instance; + + public static UPnPPropertyMap get_property_map () { + if (unlikely (instance == null)) { + instance = new UPnPPropertyMap (); + } + + return instance; + } + + private UPnPPropertyMap () { + this.property_map = new HashMap<string, ArrayList<string>> (); + this.functions = new HashMap<string, string> (); + + // Item + this.add_key_chain ("res", "nie:url"); + this.add_function ("place_holder", + "tracker:coalesce((SELECT false WHERE { { %s a ?o } " + + "FILTER (?o IN (nfo:FileDataObject, " + + "nfo:RemoteDataObject)) }), true)"); + this.add_key_chain ("fileName", "nfo:fileName"); + this.add_alternative ("dc:title", "nie:title", "nfo:fileName"); + this.add_key_chain ("dlnaProfile", "nmm:dlnaProfile"); + this.add_alternative ("mimeType", "nmm:dlnaMime", "nie:mimeType"); + this.add_alternative ("res@size", "nfo:fileSize", "nie:byteSize"); + this.add_alternative ("date", + "nie:contentCreated", + "nfo:fileLastModified"); + + // Music Item + this.add_key_chain ("res@duration", "nfo:duration"); + this.add_key_chain ("upnp:artist", "nmm:performer", "nmm:artistName"); + this.add_key_chain ("dc:creator", "nmm:performer", "nmm:artistName"); + this.add_key_chain ("upnp:album", "nmm:musicAlbum", "nie:title"); + this.add_key_chain ("upnp:originalTrackNumber", "nmm:trackNumber"); + this.add_key_chain ("upnp:genre", "nfo:genre"); + this.add_key_chain ("sampleRate", "nfo:sampleRate"); + this.add_key_chain ("upnp:nrAudioChannels", "nfo:channels"); + this.add_key_chain ("upnp:bitsPerSample", "nfo:bitsPerSample"); + this.add_key_chain ("upnp:bitrate", "nfo:averageBitrate"); + + // Picture & Video Items + this.add_key_chain ("width", "nfo:width"); + this.add_key_chain ("height", "nfo:height"); + + this.add_key_chain ("rygel:originalVolumeNumber", + "nmm:musicAlbumDisc", + "nmm:setNumber"); + } + + public new string @get (string property) { + var str = SelectionQuery.ITEM_VARIABLE; + + if (this.property_map.has_key (property)) { + foreach (var key in this.property_map[property]) { + str = key + "(" + str + ")"; + } + } else if (this.functions.has_key (property)) { + str = this.functions[property].printf (str); + } + + return str; + } + + private void add_key_chain (string property, ...) { + var key_chain = new ArrayList<string> (); + + var list = va_list (); + string key = list.arg (); + + while (key != null) { + key_chain.add (key); + + key = list.arg (); + } + + this.property_map[property] = key_chain; + } + + private void add_function (string property, string function) { + this.functions[property] = function; + } + + private void add_alternative (string property, ...) { + var list = va_list (); + + var str = new StringBuilder ("tracker:coalesce("); + + string alternative = list.arg (); + while (alternative != null) { + str.append_printf ("%s(%%1$s),", alternative); + alternative = list.arg (); + } + + str.truncate (str.len - 1); + str.append (")"); + + this.add_function (property, str.str); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-video-item-factory.vala b/src/plugins/tracker3/rygel-tracker-video-item-factory.vala new file mode 100644 index 00000000..07aac77b --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-video-item-factory.vala @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>. + * Copyright (C) 2008-2012 Nokia Corporation. + * Copyright (C) 2010 MediaNet Inh. + * + * Authors: Zeeshan Ali <zeenix@gmail.com> + * Sunil Mohan Adapa <sunil@medhas.org> + * Jens Georg <jensg@openismus.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; +using Tracker; + +/** + * Tracker video item factory. + */ +public class Rygel.Tracker.VideoItemFactory : ItemFactory { + private enum VideoMetadata { + HEIGHT = Metadata.LAST_KEY, + WIDTH, + DURATION, + + LAST_KEY + } + + private const string CATEGORY = "nmm:Video"; + private const string CATEGORY_IRI = "http://www.tracker-project.org/" + + "temp/nmm#Video"; + + public VideoItemFactory () { + var upload_folder = Environment.get_user_special_dir + (UserDirectory.VIDEOS); + try { + var config = MetaConfig.get_default (); + upload_folder = config.get_video_upload_folder (); + } catch (Error error) {}; + + base (CATEGORY, CATEGORY_IRI, VideoItem.UPNP_CLASS, upload_folder); + + // These must be in the same order as enum VideoMetadata + this.properties.add ("height"); + this.properties.add ("width"); + this.properties.add ("res@duration"); + } + + public override MediaFileItem create (string id, + string uri, + SearchContainer parent, + Sparql.Cursor metadata) + throws GLib.Error { + var item = new VideoItem (id, parent, ""); + + this.set_metadata (item, uri, metadata); + + return item; + } + + protected override void set_metadata (MediaFileItem item, + string uri, + Sparql.Cursor metadata) + throws GLib.Error { + base.set_metadata (item, uri, metadata); + + this.set_ref_id (item, "AllVideos"); + + var video = item as VideoItem; + + if (metadata.is_bound (VideoMetadata.WIDTH)) + video.width = (int) metadata.get_integer (VideoMetadata.WIDTH); + + if (metadata.is_bound (VideoMetadata.HEIGHT)) + video.height = (int) metadata.get_integer (VideoMetadata.HEIGHT); + + if (metadata.is_bound (VideoMetadata.DURATION)) + video.duration = (int) metadata.get_integer + (VideoMetadata.DURATION); + + base.add_resources(video); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-videos.vala b/src/plugins/tracker3/rygel-tracker-videos.vala new file mode 100644 index 00000000..bd0741d6 --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-videos.vala @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2009 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * Container listing video content hierarchy. + */ +public class Rygel.Tracker.Videos : CategoryContainer { + public Videos (string id, MediaContainer parent, string title) { + base (id, parent, title, new VideoItemFactory ()); + + this.add_child_container (new Years (this, this.item_factory)); + this.search_classes.add (VideoItem.UPNP_CLASS); + } +} diff --git a/src/plugins/tracker3/rygel-tracker-years.vala b/src/plugins/tracker3/rygel-tracker-years.vala new file mode 100644 index 00000000..5beedf4b --- /dev/null +++ b/src/plugins/tracker3/rygel-tracker-years.vala @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * <zeeshan.ali@nokia.com> + * + * This file is part of Rygel. + * + * Rygel 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. + * + * Rygel 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 + */ + +using Gee; + +/** + * Container listing content hierarchy by year of creation. + */ +public class Rygel.Tracker.Years : MetadataValues { + public Years (MediaContainer parent, ItemFactory item_factory) { + base (parent.id + "Year", + parent, + _("Year"), + item_factory, + "date"); + } + + protected override string? create_title_for_value (string value) { + return value.substring (0, 4); + } + + protected override string create_filter (string variable, string value) { + var year = this.create_title_for_value (value); + var next_year = (int.parse (year) + 1).to_string (); + + year += "-01-01T00:00:00Z"; + next_year += "-01-01T00:00:00Z"; + + return variable + " > \"" + year + "\" && " + + variable + " < \"" + next_year + "\""; + } +} diff --git a/src/plugins/tracker3/tracker3.plugin.in b/src/plugins/tracker3/tracker3.plugin.in new file mode 100644 index 00000000..5491c6a8 --- /dev/null +++ b/src/plugins/tracker3/tracker3.plugin.in @@ -0,0 +1,8 @@ +[Plugin] +Version = @VERSION@ +Module = tracker3 +Name = Tracker3 +License = LGPL +Conflicts = Tracker +Description = Share media using the Tracker meta-data store +Copyright = Copyright © Rygel maintainers |