[rygel] media-export: Expose DVD images as playlists



commit 81b3f5e0d4e5c2dc4493d5b46f45e6000180ef7a
Author: Jens Georg <mail jensge org>
Date:   Wed Sep 9 15:38:49 2015 +0200

    media-export: Expose DVD images as playlists
    
    All titles are shown as items in the playlist contianer.

 src/media-engines/gstreamer/rygel-gst-utils.vala   |    2 +-
 src/plugins/media-export/Makefile.am               |    3 +-
 .../rygel-media-export-dvd-container.vala          |  178 ++++++++++++++++++++
 .../rygel-media-export-dvd-parser.vala             |   22 +--
 .../media-export/rygel-media-export-extract.vala   |    3 +-
 .../rygel-media-export-info-serializer.vala        |    2 +-
 .../rygel-media-export-item-factory.vala           |   13 +-
 .../rygel-media-export-object-factory.vala         |   13 +-
 .../rygel-media-export-root-container.vala         |   12 ++-
 9 files changed, 221 insertions(+), 27 deletions(-)
---
diff --git a/src/media-engines/gstreamer/rygel-gst-utils.vala 
b/src/media-engines/gstreamer/rygel-gst-utils.vala
index 20b7302..9934195 100644
--- a/src/media-engines/gstreamer/rygel-gst-utils.vala
+++ b/src/media-engines/gstreamer/rygel-gst-utils.vala
@@ -70,7 +70,7 @@ internal abstract class Rygel.GstUtils {
             }
 
             if (src.get_class ().find_property ("tcp-timeout") != null) {
-                // For rtspsrc since some RTSP sources takes a while to start
+   // For rtspsrc since some RTSP sources takes a while to start
                 // transmitting
                 src.tcp_timeout = (int64) 60000000;
             }
diff --git a/src/plugins/media-export/Makefile.am b/src/plugins/media-export/Makefile.am
index 37c720e..101e4cc 100644
--- a/src/plugins/media-export/Makefile.am
+++ b/src/plugins/media-export/Makefile.am
@@ -59,7 +59,8 @@ librygel_media_export_la_SOURCES = \
        rygel-media-export-photo-item.vala \
        rygel-media-export-playlist-item.vala \
        rygel-media-export-trackable-db-container.vala \
-       rygel-media-export-updatable-object.vala
+       rygel-media-export-updatable-object.vala \
+       rygel-media-export-dvd-container.vala
 
 librygel_media_export_la_VALAFLAGS = \
        --enable-experimental \
diff --git a/src/plugins/media-export/rygel-media-export-dvd-container.vala 
b/src/plugins/media-export/rygel-media-export-dvd-container.vala
new file mode 100644
index 0000000..6e2de58
--- /dev/null
+++ b/src/plugins/media-export/rygel-media-export-dvd-container.vala
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2015 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 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Rygel;
+using Gee;
+
+internal class Rygel.MediaExport.DVDContainer : MediaContainer, UpdatableObject {
+    public new const string UPNP_CLASS = MediaContainer.PLAYLIST + ".DVD";
+    public const string PREFIX = "dvd";
+    public const string TRACK_PREFIX = "dvd-track";
+
+    public string path { get; construct set; }
+
+    private GUPnP.XMLDoc doc;
+
+    public DVDContainer (string          id,
+                         MediaContainer? parent,
+                         string          title,
+                         string          path) {
+        Object (id : id,
+                upnp_class : DVDContainer.UPNP_CLASS,
+                title : title,
+                parent : parent,
+                child_count : 0,
+                path : path);
+    }
+
+    public override void constructed () {
+        base.constructed ();
+
+        var cache_path = this.get_cache_path (this.path);
+        var doc = Xml.Parser.read_file (cache_path,
+                                        null,
+                                        Xml.ParserOption.NOERROR |
+                                        Xml.ParserOption.NOWARNING);
+        this.doc = new GUPnP.XMLDoc (doc);
+        var it = doc->get_root_element ()->children;
+        var child_count = 0;
+
+        while (it != null) {
+            if (it->name == "title") {
+                this.title = it->children->content;
+            } else if (it->name == "track") {
+                child_count++;
+            }
+
+            it = it->next;
+        }
+
+        this.child_count = child_count;
+    }
+
+    public override async MediaObjects? get_children (
+                                                     uint         offset,
+                                                     uint         max_count,
+                                                     string       sort_criteria,
+                                                     Cancellable? cancellable)
+                                                     throws Error {
+        var children = new MediaObjects ();
+
+        var context = new Xml.XPath.Context (this.doc.doc);
+        var xpo = context.eval ("/lsdvd/track");
+        if (xpo->type != Xml.XPath.ObjectType.NODESET) {
+            delete xpo;
+            warning ("No tracks found in DVD");
+
+            return children;
+        }
+
+        for (int i = 0; i < xpo->nodesetval->length (); i++) {
+            var node = xpo->nodesetval->item (i);
+            var item = this.get_item_for_xml (i, node);
+            children.add (item);
+        }
+
+        delete xpo;
+
+        return children;
+    }
+
+    public override async MediaObject? find_object (string id,
+                                                    Cancellable? cancellable)
+                                                    throws Error {
+        if (!id.has_prefix (DVDContainer.TRACK_PREFIX)) {
+            return null;
+        }
+
+        var parts = id.split (":");
+        var track = int.parse (parts[2]);
+        var context = new Xml.XPath.Context (this.doc.doc);
+        var xpo = context.eval ("/lsdvd/track");
+        if (!(xpo->type == Xml.XPath.ObjectType.NODESET &&
+              xpo->nodesetval->length () >= track)) {
+            delete xpo;
+
+            warning ("No track %s in DVD", parts[2]);
+
+            return null;
+        }
+
+        var object = this.get_item_for_xml (int.parse (parts[2]),
+                                            xpo->nodesetval->item (track));
+        delete xpo;
+
+        return object;
+    }
+
+    private string get_cache_path (string image_path) {
+        unowned string user_cache = Environment.get_user_cache_dir ();
+        var id = Checksum.compute_for_string (ChecksumType.MD5, image_path);
+        var cache_folder = Path.build_filename (user_cache,
+                                                "rygel",
+                                                "dvd-content");
+        DirUtils.create_with_parents (cache_folder, 0700);
+        return Path.build_filename (cache_folder, id);
+    }
+
+    public async void commit () throws Error {
+        yield this.commit_custom (true);
+    }
+
+    public async void commit_custom (bool override_guarded) throws Error {
+        MediaCache.get_default ().save_container (this);
+    }
+
+    private string get_track_id (int track) {
+        var parts = this.id.split (":");
+
+        parts[0] = "dvd-track";
+        parts += track.to_string ();
+
+        return string.joinv (":", parts);
+    }
+
+    private MediaFileItem get_item_for_xml (int track, Xml.Node *node) {
+        var item = new VideoItem (this.get_track_id (track),
+                                  this,
+                                  "Track %d".printf (track + 1));
+        item.parent_ref = this;
+
+        var uri = new Soup.URI (this.get_uris ()[0]);
+        uri.set_scheme ("dvd");
+        uri.set_query ("title=%d".printf (track + 1));
+        item.add_uri (uri.to_string (false));
+                var media_engine = MediaEngine.get_default ( );
+                media_engine.get_resources_for_item.begin ( item,
+                                                            (obj, res) => {
+                    var added_resources = media_engine
+                                          .get_resources_for_item.end (res);
+                    debug ("Adding %d resources to item source %s",
+                           added_resources.size, item.get_primary_uri ());
+                    foreach (var resrc in added_resources) {
+                       debug ("Media-export item media resource %s",
+                              resrc.get_name ());
+                    }
+                    item.get_resource_list ().add_all (added_resources);
+                  });
+
+        return item;
+    }
+}
diff --git a/src/plugins/media-export/rygel-media-export-dvd-parser.vala 
b/src/plugins/media-export/rygel-media-export-dvd-parser.vala
index 522c9cd..087ef4a 100644
--- a/src/plugins/media-export/rygel-media-export-dvd-parser.vala
+++ b/src/plugins/media-export/rygel-media-export-dvd-parser.vala
@@ -29,29 +29,28 @@ internal class Rygel.DVDParser : GLib.Object {
     public File file { public get; construct; }
 
     private File cache_file;
-    private string id;
 
     public DVDParser (File file) {
         Object (file : file);
     }
 
-    public override void constructed () {
+    public static string get_cache_path (string image_path) {
         unowned string user_cache = Environment.get_user_cache_dir ();
-        this.id = this.get_id (this.file);
+        var id = Checksum.compute_for_string (ChecksumType.MD5, image_path);
         var cache_folder = Path.build_filename (user_cache,
                                                 "rygel",
                                                 "dvd-content");
         DirUtils.create_with_parents (cache_folder, 0700);
-        var cache_path = Path.build_filename (cache_folder, this.id);
+        return Path.build_filename (cache_folder, id);
+    }
 
-        this.cache_file = File.new_for_path (cache_path);
+    public override void constructed () {
+        var path = DVDParser.get_cache_path (this.file.get_path ());
+        this.cache_file = File.new_for_path (path);
     }
 
     public async void run () throws Error {
-        var doc = yield this.get_information ();
-        if (doc != null) {
-            doc->children;
-        }
+        yield this.get_information ();
     }
 
     public async Xml.Doc* get_information () throws Error {
@@ -81,9 +80,4 @@ internal class Rygel.DVDParser : GLib.Object {
                                      Xml.ParserOption.NOERROR |
                                      Xml.ParserOption.NOWARNING);
     }
-
-    private string get_id (File file) {
-        return Checksum.compute_for_string (ChecksumType.MD5,
-                                            file.get_uri ());
-    }
 }
diff --git a/src/plugins/media-export/rygel-media-export-extract.vala 
b/src/plugins/media-export/rygel-media-export-extract.vala
index 0410bac..5964d99 100644
--- a/src/plugins/media-export/rygel-media-export-extract.vala
+++ b/src/plugins/media-export/rygel-media-export-extract.vala
@@ -33,7 +33,8 @@ const string UPNP_CLASS_PHOTO = "object.item.imageItem.photo";
 const string UPNP_CLASS_MUSIC = "object.item.audioItem.musicTrack";
 const string UPNP_CLASS_VIDEO = "object.item.videoItem";
 const string UPNP_CLASS_PLAYLIST = "object.item.playlistItem";
-const string UPNP_CLASS_PLAYLIST_CONTAINER = "object.container.playlistContainer";
+const string UPNP_CLASS_PLAYLIST_CONTAINER_DVD =
+                                      "object.container.playlistContainer.DVD";
 
 const string STATUS_LINE_TEMPLATE = "RESULT|%s|%" + size_t.FORMAT + "|%s\n";
 const string ERROR_LINE_TEMPLATE = "ERROR|%s|%d|%s\n";
diff --git a/src/plugins/media-export/rygel-media-export-info-serializer.vala 
b/src/plugins/media-export/rygel-media-export-info-serializer.vala
index b24a556..c8cb786 100644
--- a/src/plugins/media-export/rygel-media-export-info-serializer.vala
+++ b/src/plugins/media-export/rygel-media-export-info-serializer.vala
@@ -88,7 +88,7 @@ internal class Rygel.InfoSerializer : GLib.Object {
             } else if (mime.has_suffix ("/xml")) { // application/xml or text/xml
                 upnp_class = UPNP_CLASS_PLAYLIST;
             } else if (mime == "application/x-cd-image") {
-                upnp_class = UPNP_CLASS_PLAYLIST_CONTAINER;
+                upnp_class = UPNP_CLASS_PLAYLIST_CONTAINER_DVD;
             } else {
                 debug ("Unsupported content-type %s, skipping %s…",
                        mime,
diff --git a/src/plugins/media-export/rygel-media-export-item-factory.vala 
b/src/plugins/media-export/rygel-media-export-item-factory.vala
index 0939787..a2207c0 100644
--- a/src/plugins/media-export/rygel-media-export-item-factory.vala
+++ b/src/plugins/media-export/rygel-media-export-item-factory.vala
@@ -100,10 +100,10 @@ namespace Rygel.MediaExport.ItemFactory {
         }
     }
 
-    static MediaFileItem? create_from_variant (MediaContainer parent,
-                                               File           file,
-                                               Variant        v)
-                                               throws Error {
+    static MediaObject? create_from_variant (MediaContainer parent,
+                                             File           file,
+                                             Variant        v)
+                                             throws Error {
         ItemFactory.check_variant_type (v,"(smvmvmvmvmvmv)");
 
         Variant? upnp_class,
@@ -151,6 +151,7 @@ namespace Rygel.MediaExport.ItemFactory {
         }
 
         MediaFileItem item = null;
+        MediaObject object = null;
         switch (upnp_class.get_string ()) {
             case Rygel.PhotoItem.UPNP_CLASS:
                 item = new PhotoItem (id, parent, "");
@@ -164,6 +165,10 @@ namespace Rygel.MediaExport.ItemFactory {
             case Rygel.PlaylistItem.UPNP_CLASS:
                 item = ItemFactory.create_playlist_item (file, parent, "");
                 break;
+            case DVDContainer.UPNP_CLASS:
+                object = new DVDContainer ("dvd:" + id, parent, "", file.get_path ());
+                object.add_uri (file.get_uri ());
+                return object;
             default:
                 return null;
         }
diff --git a/src/plugins/media-export/rygel-media-export-object-factory.vala 
b/src/plugins/media-export/rygel-media-export-object-factory.vala
index 4a60fcd..8b55abe 100644
--- a/src/plugins/media-export/rygel-media-export-object-factory.vala
+++ b/src/plugins/media-export/rygel-media-export-object-factory.vala
@@ -33,10 +33,10 @@ internal class Rygel.MediaExport.ObjectFactory : Object {
      * @param title title of the container
      * @param child_count number of children in the container
      */
-    public virtual DBContainer get_container (string     id,
-                                              string     title,
-                                              uint       child_count,
-                                              string?    uri) {
+    public virtual MediaContainer get_container (string     id,
+                                                 string     title,
+                                                 uint       child_count,
+                                                 string?    uri) {
         if (id == "0") {
             return RootContainer.get_instance ();
         } else if (id == RootContainer.FILESYSTEM_FOLDER_ID) {
@@ -65,6 +65,11 @@ internal class Rygel.MediaExport.ObjectFactory : Object {
             return new TrackableDbContainer (id, title);
         }
 
+        if (id.has_prefix ("dvd:")) {
+            var file = File.new_for_uri (uri);
+            return new DVDContainer (id, null, title, file.get_path ());
+        }
+
         if (id.has_prefix ("playlist:")) {
             return new PlaylistContainer (id, title);
         }
diff --git a/src/plugins/media-export/rygel-media-export-root-container.vala 
b/src/plugins/media-export/rygel-media-export-root-container.vala
index a9ed65c..9bfbd80 100644
--- a/src/plugins/media-export/rygel-media-export-root-container.vala
+++ b/src/plugins/media-export/rygel-media-export-root-container.vala
@@ -94,7 +94,17 @@ public class Rygel.MediaExport.RootContainer : TrackableDbContainer {
             return object;
         }
 
-        if (id.has_prefix (QueryContainer.PREFIX)) {
+        if (id.has_prefix (DVDContainer.TRACK_PREFIX)) {
+            var parts = id.split (":");
+            var parent_id = DVDContainer.PREFIX + ":" + parts[1];
+            object = yield base.find_object (parent_id, cancellable);
+            var container = object as MediaContainer;
+            if (container != null) {
+                return yield container.find_object (id, cancellable);
+            }
+
+            return null;
+        } else  if (id.has_prefix (QueryContainer.PREFIX)) {
             var factory = QueryContainerFactory.get_default ();
             var container = factory.create_from_hashed_id (id);
             if (container != null) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]