rygel r128 - in trunk: . src src/media-providers src/media-providers/tracker
- From: zeeshanak svn gnome org
- To: svn-commits-list gnome org
- Subject: rygel r128 - in trunk: . src src/media-providers src/media-providers/tracker
- Date: Tue, 28 Oct 2008 21:01:01 +0000 (UTC)
Author: zeeshanak
Date: Tue Oct 28 21:01:01 2008
New Revision: 128
URL: http://svn.gnome.org/viewvc/rygel?rev=128&view=rev
Log:
Re-introduce MediaTracker as a plugin.
Added:
trunk/src/media-providers/Makefile.am
trunk/src/media-providers/tracker/Makefile.am
trunk/src/media-providers/tracker/gupnp-media-tracker.vala
Modified:
trunk/ChangeLog
trunk/configure.ac
trunk/src/Makefile.am
Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Tue Oct 28 21:01:01 2008
@@ -108,6 +108,8 @@
AC_OUTPUT([
Makefile
src/Makefile
+src/media-providers/Makefile
+src/media-providers/tracker/Makefile
data/Makefile
data/xml/Makefile
])
Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am (original)
+++ trunk/src/Makefile.am Tue Oct 28 21:01:01 2008
@@ -1,3 +1,5 @@
+SUBDIRS = . media-providers
+
if UNINSTALLED
shareddir = $(abs_top_builddir)/data
else
Added: trunk/src/media-providers/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/media-providers/Makefile.am Tue Oct 28 21:01:01 2008
@@ -0,0 +1 @@
+SUBDIRS = tracker
Added: trunk/src/media-providers/tracker/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/media-providers/tracker/Makefile.am Tue Oct 28 21:01:01 2008
@@ -0,0 +1,29 @@
+plugindir = $(libdir)/gupnp-media-server-1.0
+
+plugin_LTLIBRARIES = libgupnp-media-tracker.la
+
+AM_CFLAGS = $(LIBGUPNP_CFLAGS) \
+ $(LIBGUPNP_AV_CFLAGS) \
+ $(LIBDBUS_GLIB_CFLAGS) \
+ -I$(top_srcdir)/src
+
+BUILT_SOURCES = gupnp-media-tracker.stamp \
+ gupnp-media-tracker.h \
+ gupnp-media-tracker.c
+
+libgupnp_media_tracker_la_SOURCES = gupnp-media-tracker.h \
+ gupnp-media-tracker.c \
+ gupnp-media-tracker.vala
+
+gupnp-media-tracker.stamp: $(filter %.vala,$(libgupnp_media_tracker_la_SOURCES))
+ $(VALAC) -C --vapidir=$(top_srcdir)/src --pkg gupnp-media-server-1.0 \
+ --pkg gupnp-1.0 --pkg gupnp-av-1.0 --pkg dbus-glib-1 $^
+ touch $@
+
+libgupnp_media_tracker_la_LIBADD = $(LIBGUPNP_LIBS) \
+ $(LIBGUPNP_AV_LIBS) \
+ $(LIBDBUS_GLIB_LIBS)
+libgupnp_media_tracker_la_LDFLAGS = -shared -fPIC -module -avoid-version
+
+CLEANFILES = $(BUILT_SOURCES)
+MAINTAINERCLEANFILES = Makefile.in
Added: trunk/src/media-providers/tracker/gupnp-media-tracker.vala
==============================================================================
--- (empty file)
+++ trunk/src/media-providers/tracker/gupnp-media-tracker.vala Tue Oct 28 21:01:01 2008
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2008 Zeeshan Ali <zeenix gmail com>.
+ *
+ * Author: Zeeshan Ali <zeenix gmail com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ */
+
+using GUPnP;
+using DBus;
+
+private class Tracker.Container {
+ public string id;
+ public string title;
+ public string tracker_category;
+
+ /* UPnP class of items under this container */
+ public string child_class;
+
+ public Container (string id,
+ string title,
+ string tracker_category,
+ string child_class) {
+ this.id = id;
+ this.title = title;
+ this.tracker_category = tracker_category;
+ this.child_class = child_class;
+ }
+}
+
+public class GUPnP.MediaTracker : GLib.Object, MediaProvider {
+ /* class-wide constants */
+ public static const string TRACKER_SERVICE = "org.freedesktop.Tracker";
+ public static const string TRACKER_PATH = "/org/freedesktop/tracker";
+ public static const string TRACKER_IFACE = "org.freedesktop.Tracker";
+ public static const string FILES_IFACE = "org.freedesktop.Tracker.Files";
+ public static const string METADATA_IFACE =
+ "org.freedesktop.Tracker.Metadata";
+
+ public static const int MAX_REQUESTED_COUNT = 128;
+
+ public static const string IMAGE_CLASS = "object.item.imageItem";
+ public static const string VIDEO_CLASS = "object.item.videoItem";
+ public static const string MUSIC_CLASS = "object.item.audioItem.musicTrack";
+
+ /* FIXME: Make this a static if you know how to initize it */
+ private List<Tracker.Container> containers;
+
+ private dynamic DBus.Object metadata;
+ private dynamic DBus.Object files;
+ private dynamic DBus.Object tracker;
+
+ private DIDLLiteWriter didl_writer;
+ private SearchCriteriaParser search_parser;
+
+ /* Properties */
+ public string# root_id { get; construct; }
+ public string# root_parent_id { get; construct; }
+ public string# title { get; private construct; }
+ public GUPnP.Context context { get; construct; }
+
+ construct {
+ this.containers = new List<Tracker.Container> ();
+ this.containers.append
+ (new Tracker.Container ("16",
+ "All Images",
+ "Images",
+ MediaTracker.IMAGE_CLASS));
+ this.containers.append
+ (new Tracker.Container ("14",
+ "All Music",
+ "Music",
+ MediaTracker.MUSIC_CLASS));
+ this.containers.append
+ (new Tracker.Container ("15",
+ "All Videos",
+ "Videos",
+ MediaTracker.VIDEO_CLASS));
+
+ this.didl_writer = new DIDLLiteWriter ();
+ this.search_parser = new SearchCriteriaParser ();
+
+ DBus.Connection connection = DBus.Bus.get (DBus.BusType.SESSION);
+
+ this.metadata = connection.get_object (MediaTracker.TRACKER_SERVICE,
+ MediaTracker.TRACKER_PATH,
+ MediaTracker.METADATA_IFACE);
+ this.files = connection.get_object (MediaTracker.TRACKER_SERVICE,
+ MediaTracker.TRACKER_PATH,
+ MediaTracker.FILES_IFACE);
+ this.tracker = connection.get_object (MediaTracker.TRACKER_SERVICE,
+ MediaTracker.TRACKER_PATH,
+ MediaTracker.TRACKER_IFACE);
+
+ weak string home_dir = Environment.get_home_dir ();
+
+ /* Host the home dir of the user */
+ this.context.host_path (home_dir, home_dir);
+ }
+
+ /* Pubic methods */
+ public MediaTracker (string root_id,
+ string root_parent_id,
+ GUPnP.Context context) {
+ this.root_id = root_id;
+ this.root_parent_id = root_parent_id;
+ this.title = "Tracker";
+ this.context = context;
+ }
+
+ public string? browse (string container_id,
+ string filter,
+ uint starting_index,
+ uint requested_count,
+ string sort_criteria,
+ out uint number_returned,
+ out uint total_matches,
+ out uint update_id) {
+ string didl;
+
+ /* Start DIDL-Lite fragment */
+ this.didl_writer.start_didl_lite (null, null, true);
+
+ string id = this.remove_root_id_prefix (container_id);
+
+ if (id == this.root_id) {
+ number_returned = this.add_root_container_children ();
+ total_matches = number_returned;
+ } else {
+ Tracker.Container container;
+
+ if (requested_count == 0)
+ requested_count = MAX_REQUESTED_COUNT;
+
+ container = this.find_container_by_id (id);
+ if (container == null)
+ number_returned = 0;
+ else {
+ number_returned =
+ this.add_container_children_from_db (container,
+ starting_index,
+ requested_count,
+ out total_matches);
+ }
+ }
+
+ if (number_returned > 0) {
+ /* End DIDL-Lite fragment */
+ this.didl_writer.end_didl_lite ();
+
+ /* Retrieve generated string */
+ didl = this.didl_writer.get_string ();
+
+ update_id = uint32.MAX;
+ } else
+ didl = null;
+
+ /* Reset the parser state */
+ this.didl_writer.reset ();
+
+ return didl;
+ }
+
+ public string get_metadata (string object_id,
+ string filter,
+ string sort_criteria,
+ out uint update_id) {
+ string didl;
+ bool found;
+
+ /* Start DIDL-Lite fragment */
+ this.didl_writer.start_didl_lite (null, null, true);
+ found = false;
+
+ string id = this.remove_root_id_prefix (object_id);
+
+ if (id == this.root_id) {
+ add_root_container ();
+
+ found = true;
+ } else {
+ Tracker.Container container;
+
+ /* First try containers */
+ container = find_container_by_id (id);
+
+ if (container != null) {
+ add_container_from_db (container, this.root_id);
+
+ found = true;
+ } else {
+ /* Now try items */
+ container = get_item_parent (id);
+
+ if (container != null)
+ found = add_item_from_db (container, id);
+ }
+ }
+
+ if (found) {
+ /* End DIDL-Lite fragment */
+ this.didl_writer.end_didl_lite ();
+
+ /* Retrieve generated string */
+ didl = this.didl_writer.get_string ();
+ } else
+ didl = null;
+
+ /* Reset the parser state */
+ this.didl_writer.reset ();
+
+ update_id = uint32.MAX;
+
+ return didl;
+ }
+
+ public uint get_root_children_count () {
+ return this.containers.length ();
+ }
+
+ /* Private methods */
+ private uint add_root_container_children () {
+ foreach (Tracker.Container container in this.containers)
+ this.add_container_from_db (container, this.root_id);
+
+ return this.get_root_children_count ();
+ }
+
+ private void add_container_from_db (Tracker.Container container,
+ string parent_id) {
+ uint child_count;
+
+ child_count = get_container_children_count (container);
+
+ this.add_container (container.id,
+ parent_id,
+ container.title,
+ child_count);
+ }
+
+ private void add_container (string id,
+ string parent_id,
+ string title,
+ uint child_count) {
+ string exported_id, exported_parent_id;
+
+ if (id == this.root_id)
+ exported_id = id;
+ else
+ exported_id = this.root_id + ":" + id;
+
+ if (parent_id == this.root_id || parent_id == this.root_parent_id)
+ exported_parent_id = parent_id;
+ else
+ exported_parent_id = this.root_id + ":" + parent_id;
+
+ this.didl_writer.start_container (exported_id,
+ exported_parent_id,
+ (int) child_count,
+ false,
+ false);
+
+ this.didl_writer.add_string ("class",
+ DIDLLiteWriter.NAMESPACE_UPNP,
+ null,
+ "object.container.storageFolder");
+
+ this.didl_writer.add_string ("title",
+ DIDLLiteWriter.NAMESPACE_DC,
+ null,
+ title);
+
+ /* End of Container */
+ this.didl_writer.end_container ();
+ }
+
+ private uint get_container_children_count (Tracker.Container container) {
+ string[][] stats;
+
+ try {
+ stats = this.tracker.GetStats ();
+ } catch (GLib.Error error) {
+ critical ("error getting tracker statistics: %s", error.message);
+
+ return 0;
+ }
+
+ uint count = 0;
+ for (uint i = 0; i < stats.length; i++) {
+ if (stats[i][0] == container.tracker_category)
+ count = stats[i][1].to_int ();
+ }
+
+ return count;
+ }
+
+ private Tracker.Container? find_container_by_id (string container_id) {
+ Tracker.Container container;
+
+ container = null;
+
+ foreach (Tracker.Container tmp in this.containers)
+ if (container_id == tmp.id) {
+ container = tmp;
+
+ break;
+ }
+
+ return container;
+ }
+
+ private uint add_container_children_from_db
+ (Tracker.Container container,
+ uint offset,
+ uint max_count,
+ out uint child_count) {
+ string[] children;
+
+ children = this.get_container_children_from_db (container,
+ offset,
+ max_count,
+ out child_count);
+ if (children == null)
+ return 0;
+
+ /* Iterate through all items */
+ for (uint i = 0; i < children.length; i++)
+ this.add_item_from_db (container, children[i]);
+
+ return children.length;
+ }
+
+ private string[]? get_container_children_from_db
+ (Tracker.Container container,
+ uint offset,
+ uint max_count,
+ out uint child_count) {
+ string[] children = null;
+
+ child_count = get_container_children_count (container);
+
+ try {
+ children = this.files.GetByServiceType (0,
+ container.tracker_category,
+ (int) offset,
+ (int) max_count);
+ } catch (GLib.Error error) {
+ critical ("error: %s", error.message);
+
+ return null;
+ }
+
+ return children;
+ }
+
+ private bool add_item_from_db (Tracker.Container parent,
+ string path) {
+ if (parent.child_class == VIDEO_CLASS) {
+ return this.add_video_item_from_db (parent, path);
+ } else if (parent.child_class == IMAGE_CLASS) {
+ return this.add_image_item_from_db (parent, path);
+ } else {
+ return this.add_music_item_from_db (parent, path);
+ }
+ }
+
+ private bool add_video_item_from_db (Tracker.Container parent,
+ string path) {
+ string[] keys = new string[] {"File:Name",
+ "File:Mime",
+ "Video:Title",
+ "Video:Author",
+ "Video:Width",
+ "Video:Height",
+ "DC:Date"};
+
+ string[] values = null;
+
+ /* TODO: make this async */
+ try {
+ values = this.metadata.Get (parent.tracker_category, path, keys);
+ } catch (GLib.Error error) {
+ critical ("failed to get metadata for %s: %s\n",
+ path,
+ error.message);
+
+ return false;
+ }
+
+ int width = -1;
+ int height = -1;
+
+ if (values[4] != "")
+ width = values[4].to_int ();
+
+ if (values[5] != "")
+ height = values[5].to_int ();
+
+ string title;
+ if (values[2] != "")
+ title = values[2];
+ else
+ /* If title wasn't provided, use filename instead */
+ title = values[0];
+
+ string date = seconds_to_iso8601 (values[6]);
+
+ this.add_item (path,
+ parent.id,
+ values[1],
+ title,
+ values[3],
+ "",
+ date,
+ parent.child_class,
+ width,
+ height,
+ -1,
+ path);
+
+ return true;
+ }
+
+ private bool add_image_item_from_db (Tracker.Container parent,
+ string path) {
+ string[] keys = new string[] {"File:Name",
+ "File:Mime",
+ "Image:Title",
+ "Image:Creator",
+ "Image:Width",
+ "Image:Height",
+ "Image:Album",
+ "Image:Date",
+ "DC:Date"};
+
+ string[] values = null;
+
+ /* TODO: make this async */
+ try {
+ values = this.metadata.Get (parent.tracker_category, path, keys);
+ } catch (GLib.Error error) {
+ critical ("failed to get metadata for %s: %s\n",
+ path,
+ error.message);
+
+ return false;
+ }
+
+ int width = -1;
+ int height = -1;
+
+ if (values[4] != "")
+ width = values[4].to_int ();
+
+ if (values[5] != "")
+ height = values[5].to_int ();
+
+ string title;
+ if (values[2] != "")
+ title = values[2];
+ else
+ /* If title wasn't provided, use filename instead */
+ title = values[0];
+
+ string seconds;
+
+ if (values[8] != "") {
+ seconds = values[8];
+ } else {
+ seconds = values[7];
+ }
+
+ string date = seconds_to_iso8601 (seconds);
+
+ this.add_item (path,
+ parent.id,
+ values[1],
+ title,
+ values[3],
+ values[6],
+ date,
+ parent.child_class,
+ width,
+ height,
+ -1,
+ path);
+
+ return true;
+ }
+
+ private bool add_music_item_from_db (Tracker.Container parent,
+ string path) {
+ string[] keys = new string[] {"File:Name",
+ "File:Mime",
+ "Audio:Title",
+ "Audio:Artist",
+ "Audio:TrackNo",
+ "Audio:Album",
+ "Audio:ReleaseDate",
+ "Audio:DateAdded",
+ "DC:Date"};
+
+ string[] values = null;
+
+ /* TODO: make this async */
+ try {
+ values = this.metadata.Get (parent.tracker_category, path, keys);
+ } catch (GLib.Error error) {
+ critical ("failed to get metadata for %s: %s\n",
+ path,
+ error.message);
+
+ return false;
+ }
+
+ int track_number = -1;
+
+ if (values[4] != "")
+ track_number = values[4].to_int ();
+
+ string title;
+ if (values[2] != "")
+ title = values[2];
+ else
+ /* If title wasn't provided, use filename instead */
+ title = values[0];
+
+ string seconds;
+
+ if (values[8] != "") {
+ seconds = values[8];
+ } else if (values[6] != "") {
+ seconds = values[6];
+ } else {
+ seconds = values[7];
+ }
+
+ string date = seconds_to_iso8601 (seconds);
+
+ this.add_item (path,
+ parent.id,
+ values[1],
+ title,
+ values[3],
+ values[5],
+ date,
+ parent.child_class,
+ -1,
+ -1,
+ track_number,
+ path);
+
+ return true;
+ }
+
+ private void add_item (string id,
+ string parent_id,
+ string mime,
+ string title,
+ string author,
+ string album,
+ string date,
+ string upnp_class,
+ int width,
+ int height,
+ int track_number,
+ string path) {
+ string exported_parent_id;
+ if (parent_id == this.root_id)
+ exported_parent_id = parent_id;
+ else
+ exported_parent_id = this.root_id + ":" + parent_id;
+
+ this.didl_writer.start_item (this.root_id + ":" + id,
+ exported_parent_id,
+ null,
+ false);
+
+ /* Add fields */
+ this.didl_writer.add_string ("title",
+ DIDLLiteWriter.NAMESPACE_DC,
+ null,
+ title);
+
+ this.didl_writer.add_string ("class",
+ DIDLLiteWriter.NAMESPACE_UPNP,
+ null,
+ upnp_class);
+
+ if (author != "") {
+ this.didl_writer.add_string ("creator",
+ DIDLLiteWriter.NAMESPACE_DC,
+ null,
+ author);
+
+ if (upnp_class == VIDEO_CLASS) {
+ this.didl_writer.add_string ("author",
+ DIDLLiteWriter.NAMESPACE_UPNP,
+ null,
+ author);
+ } else if (upnp_class == MUSIC_CLASS) {
+ this.didl_writer.add_string ("artist",
+ DIDLLiteWriter.NAMESPACE_UPNP,
+ null,
+ author);
+ }
+ }
+
+ if (track_number >= 0) {
+ this.didl_writer.add_int ("originalTrackNumber",
+ DIDLLiteWriter.NAMESPACE_UPNP,
+ null,
+ track_number);
+ }
+
+ if (album != "") {
+ this.didl_writer.add_string ("album",
+ DIDLLiteWriter.NAMESPACE_UPNP,
+ null,
+ album);
+ }
+
+ if (date != "") {
+ this.didl_writer.add_string ("date",
+ DIDLLiteWriter.NAMESPACE_DC,
+ null,
+ date);
+ }
+
+ /* Add resource data */
+ DIDLLiteResource res;
+
+ /* URI */
+ string escaped_path = Uri.escape_string (path, "/", true);
+ string uri = "http://%s:%u%s".printf (context.host_ip,
+ context.port,
+ escaped_path);
+
+ res.reset ();
+
+ res.uri = uri;
+
+ /* Protocol info */
+ res.protocol = "http-get";
+ res.mime_type = mime;
+ res.dlna_profile = "MP3"; /* FIXME */
+
+ res.width = width;
+ res.height = height;
+
+ this.didl_writer.add_res (res);
+
+ /* FIXME: These lines should be remove once GB#526552 is fixed */
+ res.uri = null;
+ res.protocol = null;
+ res.mime_type = null;
+ res.dlna_profile = null;
+
+ /* End of item */
+ this.didl_writer.end_item ();
+ }
+
+ private void add_root_container () {
+ add_container (this.root_id,
+ this.root_parent_id,
+ this.title,
+ this.get_root_children_count ());
+ }
+
+ private Tracker.Container? get_item_parent (string uri) {
+ Tracker.Container container = null;
+ string category;
+
+ try {
+ category = this.files.GetServiceType (uri);
+ } catch (GLib.Error error) {
+ critical ("failed to find service type for %s: %s",
+ uri,
+ error.message);
+
+ return null;
+ }
+
+ foreach (Tracker.Container tmp in this.containers) {
+ if (tmp.tracker_category == category) {
+ container = tmp;
+
+ break;
+ }
+ }
+
+ return container;
+ }
+
+ string seconds_to_iso8601 (string seconds) {
+
+ string date;
+
+ if (seconds != "") {
+ TimeVal tv;
+
+ tv.tv_sec = seconds.to_int ();
+ tv.tv_usec = 0;
+
+ date = tv.to_iso8601 ();
+ } else {
+ date = "";
+ }
+
+ return date;
+ }
+
+ string remove_root_id_prefix (string id) {
+ string[] tokens;
+
+ tokens = id.split (":", 2);
+
+ if (tokens[1] != null)
+ return tokens[1];
+ else
+ return tokens[0];
+ }
+}
+
+[ModuleInit]
+public MediaProvider register_media_provider (string root_id,
+ string root_parent_id,
+ GUPnP.Context context) {
+ return new MediaTracker (root_id,
+ root_parent_id,
+ context);
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]