summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Georg <mail@jensge.org>2020-05-07 00:49:22 +0200
committerJens Georg <mail@jensge.org>2020-07-05 15:31:52 +0200
commit234603ff447de98bd8e640b984db877535af399e (patch)
tree1b85f0771aeec48a32c88f17dec94399720edd82
parent79f75e90e6f608539082f144c22b07160737ca75 (diff)
downloadrygel-234603ff447de98bd8e640b984db877535af399e.tar.gz
tracker3: Add plugin to support tracker3
Mainly just copy the tracker plugin and change the sparql connection.
-rw-r--r--meson_options.txt2
-rw-r--r--src/plugins/tracker3/meson.build49
-rw-r--r--src/plugins/tracker3/rygel-tracker-albums.vala36
-rw-r--r--src/plugins/tracker3/rygel-tracker-artists.vala36
-rw-r--r--src/plugins/tracker3/rygel-tracker-category-all-container.vala153
-rw-r--r--src/plugins/tracker3/rygel-tracker-category-container.vala85
-rw-r--r--src/plugins/tracker3/rygel-tracker-cleanup-query.vala66
-rw-r--r--src/plugins/tracker3/rygel-tracker-deletion-query.vala59
-rw-r--r--src/plugins/tracker3/rygel-tracker-genre.vala36
-rw-r--r--src/plugins/tracker3/rygel-tracker-insertion-query.vala182
-rw-r--r--src/plugins/tracker3/rygel-tracker-interfaces.vala51
-rw-r--r--src/plugins/tracker3/rygel-tracker-item-factory.vala145
-rw-r--r--src/plugins/tracker3/rygel-tracker-metadata-container.vala152
-rw-r--r--src/plugins/tracker3/rygel-tracker-metadata-multivalues.vala104
-rw-r--r--src/plugins/tracker3/rygel-tracker-metadata-values.vala90
-rw-r--r--src/plugins/tracker3/rygel-tracker-music-item-factory.vala143
-rw-r--r--src/plugins/tracker3/rygel-tracker-music.vala40
-rw-r--r--src/plugins/tracker3/rygel-tracker-new.vala58
-rw-r--r--src/plugins/tracker3/rygel-tracker-picture-item-factory.vala91
-rw-r--r--src/plugins/tracker3/rygel-tracker-pictures.vala37
-rw-r--r--src/plugins/tracker3/rygel-tracker-plugin-factory.vala59
-rw-r--r--src/plugins/tracker3/rygel-tracker-plugin.vala38
-rw-r--r--src/plugins/tracker3/rygel-tracker-query-triplet.vala106
-rw-r--r--src/plugins/tracker3/rygel-tracker-query-triplets.vala89
-rw-r--r--src/plugins/tracker3/rygel-tracker-query.vala115
-rw-r--r--src/plugins/tracker3/rygel-tracker-root-container.vala60
-rw-r--r--src/plugins/tracker3/rygel-tracker-search-container.vala374
-rw-r--r--src/plugins/tracker3/rygel-tracker-selection-query.vala221
-rw-r--r--src/plugins/tracker3/rygel-tracker-tags.vala39
-rw-r--r--src/plugins/tracker3/rygel-tracker-titles.vala81
-rw-r--r--src/plugins/tracker3/rygel-tracker-upnp-property-map.vala132
-rw-r--r--src/plugins/tracker3/rygel-tracker-video-item-factory.vala96
-rw-r--r--src/plugins/tracker3/rygel-tracker-videos.vala36
-rw-r--r--src/plugins/tracker3/rygel-tracker-years.vala52
-rw-r--r--src/plugins/tracker3/tracker3.plugin.in8
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