From 2d7ce8a4f421572f8c570c9146e774e49d655e7b Mon Sep 17 00:00:00 2001 From: "Zeeshan Ali (Khattak)" Date: Mon, 17 Oct 2011 01:12:49 +0300 Subject: [PATCH] core: Add base class for client hacks A new abstract base class for client-side hacks from which XBoxHacks derives. https://bugzilla.gnome.org/show_bug.cgi?id=661336 --- src/rygel/Makefile.am | 1 + src/rygel/rygel-browse.vala | 4 +- src/rygel/rygel-client-hacks.vala | 106 ++++++++++++++++++++++++++++++++ src/rygel/rygel-http-get.vala | 5 +- src/rygel/rygel-media-objects.vala | 6 +- src/rygel/rygel-media-query-action.vala | 12 ++-- src/rygel/rygel-search.vala | 14 ++--- src/rygel/rygel-xbox-hacks.vala | 70 +++++++-------------- 8 files changed, 151 insertions(+), 67 deletions(-) create mode 100644 src/rygel/rygel-client-hacks.vala diff --git a/src/rygel/Makefile.am b/src/rygel/Makefile.am index aec85e1..2ae265e 100644 --- a/src/rygel/Makefile.am +++ b/src/rygel/Makefile.am @@ -83,6 +83,7 @@ VAPI_SOURCE_FILES = \ rygel-media-query-action.vala \ rygel-browse.vala \ rygel-search.vala \ + rygel-client-hacks.vala \ rygel-xbox-hacks.vala \ rygel-import-resource.vala \ rygel-item-creator.vala \ diff --git a/src/rygel/rygel-browse.vala b/src/rygel/rygel-browse.vala index b45f5d0..2682cbf 100644 --- a/src/rygel/rygel-browse.vala +++ b/src/rygel/rygel-browse.vala @@ -39,8 +39,8 @@ internal class Rygel.Browse: Rygel.MediaQueryAction { owned ServiceAction action) { base (content_dir, action); - if (this.xbox_hacks != null) { - this.object_id_arg = this.xbox_hacks.object_id; + if (this.hacks != null) { + this.object_id_arg = this.hacks.object_id; } else { this.object_id_arg = "ObjectID"; } diff --git a/src/rygel/rygel-client-hacks.vala b/src/rygel/rygel-client-hacks.vala new file mode 100644 index 0000000..ae7c725 --- /dev/null +++ b/src/rygel/rygel-client-hacks.vala @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2010 Nokia Corporation. + * + * Author: Zeeshan Ali (Khattak) + * + * 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 Soup; +using GUPnP; + +internal errordomain Rygel.ClientHacksError { + NA +} + +internal abstract class Rygel.ClientHacks : GLib.Object { + private static string OBJECT_ID = "ObjectID"; + + public unowned string object_id { get; protected set; } + + protected Regex agent_regex; + + public static ClientHacks create_for_action (ServiceAction action) + throws ClientHacksError { + return new XBoxHacks.for_action (action); + } + + public static ClientHacks create_for_headers (MessageHeaders headers) + throws ClientHacksError { + return new XBoxHacks.for_headers (headers); + } + + protected ClientHacks (string agent_pattern, MessageHeaders? headers = null) + throws ClientHacksError { + try { + this.agent_regex = new Regex (agent_pattern, + RegexCompileFlags.CASELESS, + 0); + } catch (RegexError error) { + // This means subclasses did not provide a proper regular expression + assert_not_reached (); + } + + if (headers != null) { + this.check_headers (headers); + } + + this.object_id = OBJECT_ID; + } + + public bool is_album_art_request (Soup.Message message) { + unowned string query = message.get_uri ().query; + + if (query == null) { + return false; + } + + var params = Soup.Form.decode (query); + var album_art = params.lookup ("albumArt"); + + return (album_art != null) && bool.parse (album_art); + } + + public virtual void translate_container_id (MediaQueryAction action, + ref string container_id) {} + + public virtual void apply (MediaItem item) {} + + public virtual async MediaObjects? search + (SearchableContainer container, + SearchExpression? expression, + uint offset, + uint max_count, + out uint total_matches, + Cancellable? cancellable) + throws Error { + return yield container.search (expression, + offset, + max_count, + out total_matches, + cancellable); + } + + private void check_headers (MessageHeaders headers) + throws ClientHacksError { + var agent = headers.get_one ("User-Agent"); + if (agent == null || !(this.agent_regex.match (agent))) { + throw new ClientHacksError.NA (_("Not Applicable")); + } + } +} diff --git a/src/rygel/rygel-http-get.vala b/src/rygel/rygel-http-get.vala index 0ea407c..c830483 100644 --- a/src/rygel/rygel-http-get.vala +++ b/src/rygel/rygel-http-get.vala @@ -84,7 +84,8 @@ internal class Rygel.HTTPGet : HTTPRequest { } try { - var hack = new XBoxHacks.for_headers (this.msg.request_headers); + var hack = ClientHacks.create_for_headers + (this.msg.request_headers); if (hack.is_album_art_request (this.msg) && this.item is VisualItem) { var visual_item = this.item as VisualItem; @@ -100,7 +101,7 @@ internal class Rygel.HTTPGet : HTTPRequest { return; } - } catch (XBoxHacksError error) {} + } catch (ClientHacksError error) {} if (this.uri.thumbnail_index >= 0) { if (this.item is MusicItem) { diff --git a/src/rygel/rygel-media-objects.vala b/src/rygel/rygel-media-objects.vala index 40fb535..9cf657c 100644 --- a/src/rygel/rygel-media-objects.vala +++ b/src/rygel/rygel-media-objects.vala @@ -56,10 +56,10 @@ public class Rygel.MediaObjects : ArrayList { internal void serialize (DIDLLiteWriter didl_writer, HTTPServer http_server, - XBoxHacks? xbox_hacks) throws Error { + ClientHacks? hacks) throws Error { foreach (var result in this) { - if (result is MediaItem && xbox_hacks != null) { - xbox_hacks.apply (result as MediaItem); + if (result is MediaItem && hacks != null) { + hacks.apply (result as MediaItem); } result.serialize (didl_writer, http_server); diff --git a/src/rygel/rygel-media-query-action.vala b/src/rygel/rygel-media-query-action.vala index 5a615a8..1db1236 100644 --- a/src/rygel/rygel-media-query-action.vala +++ b/src/rygel/rygel-media-query-action.vala @@ -49,7 +49,7 @@ internal abstract class Rygel.MediaQueryAction : GLib.Object, StateMachine { protected uint32 system_update_id; protected ServiceAction action; protected DIDLLiteWriter didl_writer; - protected XBoxHacks xbox_hacks; + protected ClientHacks hacks; protected string object_id_arg; protected MediaQueryAction (ContentDirectory content_dir, @@ -63,8 +63,8 @@ internal abstract class Rygel.MediaQueryAction : GLib.Object, StateMachine { this.didl_writer = new DIDLLiteWriter (null); try { - this.xbox_hacks = new XBoxHacks.for_action (this.action); - } catch { /* This just means we are not dealing with Xbox, yay! */ } + this.hacks = ClientHacks.create_for_action (this.action); + } catch { /* This just means we need no hacks, yay! */ } } public async void run () { @@ -85,7 +85,7 @@ internal abstract class Rygel.MediaQueryAction : GLib.Object, StateMachine { results.serialize (this.didl_writer, this.http_server, - this.xbox_hacks); + this.hacks); // Conclude the successful Browse/Search action this.conclude (); @@ -132,8 +132,8 @@ internal abstract class Rygel.MediaQueryAction : GLib.Object, StateMachine { this.validate_sort_criteria (); - if (this.xbox_hacks != null) { - this.xbox_hacks.translate_container_id (this, ref this.object_id); + if (this.hacks != null) { + this.hacks.translate_container_id (this, ref this.object_id); } } diff --git a/src/rygel/rygel-search.vala b/src/rygel/rygel-search.vala index dd5231e..1d5e66a 100644 --- a/src/rygel/rygel-search.vala +++ b/src/rygel/rygel-search.vala @@ -69,13 +69,13 @@ internal class Rygel.Search: Rygel.MediaQueryAction { throw parser.err; } - if (this.xbox_hacks != null) { - return yield this.xbox_hacks.search (container, - parser.expression, - this.index, - this.requested_count, - out this.total_matches, - this.cancellable); + if (this.hacks != null) { + return yield this.hacks.search (container, + parser.expression, + this.index, + this.requested_count, + out this.total_matches, + this.cancellable); } else { return yield container.search (parser.expression, this.index, diff --git a/src/rygel/rygel-xbox-hacks.vala b/src/rygel/rygel-xbox-hacks.vala index 9407321..2d61326 100644 --- a/src/rygel/rygel-xbox-hacks.vala +++ b/src/rygel/rygel-xbox-hacks.vala @@ -24,11 +24,7 @@ using Soup; using GUPnP; -internal errordomain Rygel.XBoxHacksError { - NA -} - -internal class Rygel.XBoxHacks : GLib.Object { +internal class Rygel.XBoxHacks : ClientHacks { private static string AGENT = ".*Xbox.*|.*Allegro-Software-WebClient.*|.*SEC_HHP_Galaxy S/1\\.0.*"; private static string DMS = "urn:schemas-upnp-org:device:MediaServer"; @@ -37,49 +33,26 @@ internal class Rygel.XBoxHacks : GLib.Object { private static string MODEL_NAME = "Windows Media Player Sharing"; private static string MODEL_VERSION = "11"; private static string CONTAINER_ID = "ContainerID"; - private static string OBJECT_ID = "ObjectID"; - public unowned string object_id { get; private set; } + public XBoxHacks () throws ClientHacksError { + base (AGENT); + } - public XBoxHacks.for_action (ServiceAction action) throws XBoxHacksError { + public XBoxHacks.for_action (ServiceAction action) throws ClientHacksError { unowned MessageHeaders headers = action.get_message ().request_headers; - this.check_headers (headers); + this.for_headers (headers); } public XBoxHacks.for_headers (MessageHeaders headers) - throws XBoxHacksError { - this.check_headers (headers); - } + throws ClientHacksError { + base (AGENT, headers); - private void check_headers (MessageHeaders headers) throws XBoxHacksError { var agent = headers.get_one ("User-Agent"); - if (agent == null || - !(agent.contains ("Xbox")) && - !(agent.contains ("Allegro-Software-WebClient")) && - !(agent.contains ("SEC_HHP_Galaxy S/1.0"))) { - throw new XBoxHacksError.NA (_("Not Applicable")); - } - if (agent.contains ("Xbox")) { this.object_id = CONTAINER_ID; - } else { - this.object_id = OBJECT_ID; } } - public bool is_album_art_request (Soup.Message message) { - unowned string query = message.get_uri ().query; - - if (query == null) { - return false; - } - - var params = Soup.Form.decode (query); - var album_art = params.lookup ("albumArt"); - - return (album_art != null) && bool.parse (album_art); - } - public void apply_on_device (RootDevice device, string template_path) throws Error { if (!device.get_device_type ().has_prefix (DMS)) { @@ -92,13 +65,15 @@ internal class Rygel.XBoxHacks : GLib.Object { var desc_path = template_path.replace (".xml", "-xbox.xml"); this.save_modified_desc (doc, desc_path); - var regex = new Regex (AGENT, RegexCompileFlags.CASELESS, 0); var server_path = "/" + device.get_relative_location (); - device.context.host_path_for_agent (desc_path, server_path, regex); + device.context.host_path_for_agent (desc_path, + server_path, + this.agent_regex); } - public void translate_container_id (MediaQueryAction action, - ref string container_id) { + public override void translate_container_id + (MediaQueryAction action, + ref string container_id) { if (action is Search && (container_id == "1" || container_id == "4" || @@ -114,7 +89,7 @@ internal class Rygel.XBoxHacks : GLib.Object { } } - public void apply (MediaItem item) { + public override void apply (MediaItem item) { if (item.mime_type == "video/x-msvideo") { item.mime_type = "video/avi"; } else if (item.mime_type == "video/mpeg") { @@ -123,13 +98,14 @@ internal class Rygel.XBoxHacks : GLib.Object { } } - public async MediaObjects? search (SearchableContainer container, - SearchExpression? expression, - uint offset, - uint max_count, - out uint total_matches, - Cancellable? cancellable) - throws Error { + public override async MediaObjects? search + (SearchableContainer container, + SearchExpression? expression, + uint offset, + uint max_count, + out uint total_matches, + Cancellable? cancellable) + throws Error { var results = yield container.search (expression, offset, max_count, -- 2.7.4