[PATCH 2/2] local-metadata: add series support
- From: lionel g landwerlin linux intel com
- To: grilo-list gnome org
- Subject: [PATCH 2/2] local-metadata: add series support
- Date: Fri, 18 Mar 2011 13:57:21 +0000
From: Lionel Landwerlin <lionel g landwerlin linux intel com>
Based on a patch for Tracker by Iain Holmes :
http://build.meego.com/package/view_file?file=0002-Tracker-extract-Parse-the-video-filename-to-obtain-e.patch&package=tracker&project=devel%3Acontentfw&srcmd5=c91b724488ee9ae476a9ce65755d8152
Signed-off-by: Lionel Landwerlin <lionel g landwerlin linux intel com>
---
configure.ac | 3 +
src/metadata/local-metadata/grl-local-metadata.c | 417 ++++++++++++++++++++--
2 files changed, 397 insertions(+), 23 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5d9d9a9..15304f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -709,6 +709,9 @@ AC_ARG_ENABLE(localmetadata,
if test "x$HAVE_GIO" = "xno"; then
AC_MSG_ERROR([gio-2.0 not found, install it or use --disable-localmetadata])
fi
+ if test "x$HAVE_GLIB_2_26" = "xno"; then
+ AC_MSG_ERROR([glib-2.26.0 or above not found, install it or use --disable-localmetadata])
+ fi
;;
esac
],
diff --git a/src/metadata/local-metadata/grl-local-metadata.c b/src/metadata/local-metadata/grl-local-metadata.c
index 62737ba..b53f6f2 100644
--- a/src/metadata/local-metadata/grl-local-metadata.c
+++ b/src/metadata/local-metadata/grl-local-metadata.c
@@ -24,6 +24,9 @@
#include "config.h"
#endif
+#include <string.h>
+#include <stdlib.h>
+
#include <grilo.h>
#include <gio/gio.h>
@@ -42,6 +45,43 @@ GRL_LOG_DOMAIN_STATIC(local_metadata_log_domain);
#define LICENSE "LGPL"
#define SITE "http://www.igalia.com"
+/**/
+
+#define TV_REGEX \
+ "(?<showname>.*)\\." \
+ "(?<season>(?:\\d{1,2})|(?:[sS]\\K\\d{1,2}))" \
+ "(?<episode>(?:\\d{2})|(?:[eE]\\K\\d{1,2}))" \
+ "\\.?(?<name>.*)?"
+#define MOVIE_REGEX \
+ "(?<name>.*)" \
+ "\\.?[\\(\\[](?<year>[12][90]\\d{2})[\\)\\]]"
+
+/**/
+
+typedef enum {
+ FLAG_VIDEO_TITLE = 0x1,
+ FLAG_VIDEO_SHOWNAME = 0x2,
+ FLAG_VIDEO_DATE = 0x4,
+ FLAG_VIDEO_SEASON = 0x8,
+ FLAG_VIDEO_EPISODE = 0x10,
+ FLAG_THUMBNAIL = 0x20,
+} resolution_flags_t;
+
+const gchar *video_blacklisted_prefix[] = {
+ "tpz-", NULL
+};
+
+
+const char *video_blacklisted_words[] = {
+ "720p", "1080p",
+ "ws", "WS", "proper", "PROPER",
+ "repack", "real.repack",
+ "hdtv", "HDTV", "pdtv", "PDTV", "notv", "NOTV",
+ "dsr", "DSR", "DVDRip", "divx", "DIVX", "xvid", "Xvid",
+ NULL
+};
+
+/**/
static GrlLocalMetadataSource *grl_local_metadata_source_new (void);
@@ -59,6 +99,9 @@ gboolean grl_local_metadata_source_plugin_init (GrlPluginRegistry *registry,
const GrlPluginInfo *plugin,
GList *configs);
+/**/
+
+static gboolean grl_local_metadata_guess_video = TRUE;
/* =================== GrlLocalMetadata Plugin =============== */
@@ -67,10 +110,27 @@ grl_local_metadata_source_plugin_init (GrlPluginRegistry *registry,
const GrlPluginInfo *plugin,
GList *configs)
{
+ guint config_count;
+ GrlConfig *config;
+
GRL_LOG_DOMAIN_INIT (local_metadata_log_domain, "local-metadata");
GRL_DEBUG ("grl_local_metadata_source_plugin_init");
+ if (!configs) {
+ GRL_WARNING ("\tConfiguration not provided! Using default configuration.");
+ } else {
+ config_count = g_list_length (configs);
+ if (config_count > 1) {
+ GRL_WARNING ("\tProvided %i configs, but will only use one", config_count);
+ }
+
+ config = GRL_CONFIG (configs->data);
+
+ grl_local_metadata_guess_video =
+ grl_config_get_boolean (config, "guess-video");
+ }
+
GrlLocalMetadataSource *source = grl_local_metadata_source_new ();
grl_plugin_registry_register_source (registry,
plugin,
@@ -115,6 +175,191 @@ G_DEFINE_TYPE (GrlLocalMetadataSource,
GRL_TYPE_METADATA_SOURCE);
/* ======================= Utilities ==================== */
+
+static gchar *
+video_sanitise_string (const gchar *str)
+{
+ int i;
+ gchar *line;
+
+ line = (gchar *) str;
+ for (i = 0; video_blacklisted_prefix[i]; i++) {
+ if (g_str_has_prefix (str, video_blacklisted_prefix[i])) {
+ int len = strlen (video_blacklisted_prefix[i]);
+
+ line = (gchar *) str + len;
+ }
+ }
+
+ for (i = 0; video_blacklisted_words[i]; i++) {
+ gchar *end;
+
+ end = strstr (line, video_blacklisted_words[i]);
+ if (end) {
+ return g_strndup (line, end - line);
+ }
+ }
+
+ return g_strdup (line);
+}
+
+/* tidies strings before we run them through the regexes */
+static gchar *
+video_uri_to_metadata (const gchar *uri)
+{
+ gchar *ext, *basename, *name, *whitelisted;
+
+ basename = g_path_get_basename (uri);
+ ext = strrchr (basename, '.');
+ if (ext) {
+ name = g_strndup (basename, ext - basename);
+ g_free (basename);
+ } else {
+ name = basename;
+ }
+
+ /* Replace _ <space> with . */
+ g_strdelimit (name, "_ ", '.');
+ whitelisted = video_sanitise_string (name);
+ g_free (name);
+
+ return whitelisted;
+}
+
+static void
+video_guess_values_from_uri (const gchar *uri,
+ gchar **title,
+ gchar **showname,
+ GDateTime **date,
+ gint *season,
+ gint *episode)
+{
+ gchar *metadata;
+ GRegex *regex;
+ GMatchInfo *info;
+
+ metadata = video_uri_to_metadata (uri);
+
+ regex = g_regex_new (MOVIE_REGEX, 0, 0, NULL);
+ g_regex_match (regex, metadata, 0, &info);
+
+ if (g_match_info_matches (info)) {
+ if (title) {
+ *title = g_match_info_fetch_named (info, "name");
+ /* Replace "." with <space> */
+ g_strdelimit (*title, ".", ' ');
+ }
+
+ if (date) {
+ gchar *year = g_match_info_fetch_named (info, "year");
+
+ *date = g_date_time_new_utc (atoi (year), 1, 1, 0, 0, 0.0);
+ g_free (year);
+ }
+
+ if (showname) {
+ *showname = NULL;
+ }
+
+ if (season) {
+ *season = 0;
+ }
+
+ if (episode) {
+ *episode = 0;
+ }
+
+ g_regex_unref (regex);
+ g_match_info_free (info);
+ g_free (metadata);
+
+ return;
+ }
+
+ g_regex_unref (regex);
+ g_match_info_free (info);
+
+ regex = g_regex_new (TV_REGEX, 0, 0, NULL);
+ g_regex_match (regex, metadata, 0, &info);
+
+ if (g_match_info_matches (info)) {
+ if (title) {
+ *title = g_match_info_fetch_named (info, "name");
+ g_strdelimit (*title, ".", ' ');
+ }
+
+ if (showname) {
+ *showname = g_match_info_fetch_named (info, "showname");
+ g_strdelimit (*showname, ".", ' ');
+ }
+
+ if (season) {
+ gchar *s = g_match_info_fetch_named (info, "season");
+ if (s) {
+ if (*s == 's' || *s == 'S') {
+ *season = atoi (s + 1);
+ } else {
+ *season = atoi (s);
+ }
+ } else {
+ *season = 0;
+ }
+
+ g_free (s);
+ }
+
+ if (episode) {
+ gchar *e = g_match_info_fetch_named (info, "episode");
+ if (e) {
+ if (*e == 'e' || *e == 'E') {
+ *episode = atoi (e + 1);
+ } else {
+ *episode = atoi (e);
+ }
+ } else {
+ *episode = 0;
+ }
+
+ g_free (e);
+ }
+
+ if (date) {
+ *date = NULL;
+ }
+
+ g_regex_unref (regex);
+ g_match_info_free (info);
+ g_free (metadata);
+
+ return;
+ }
+
+ g_regex_unref (regex);
+ g_match_info_free (info);
+
+ /* The filename doesn't look like a movie or a TV show, just use the
+ filename without extension as the title */
+ if (title) {
+ *title = g_strdelimit (metadata, ".", ' ');
+ }
+
+ if (showname) {
+ *showname = NULL;
+ }
+
+ if (date) {
+ *date = NULL;
+ }
+
+ if (season) {
+ *season = 0;
+ }
+
+ if (episode) {
+ *episode = 0;
+ }
+}
+
static void
got_file_info (GFile *file, GAsyncResult *result,
GrlMetadataSourceResolveSpec *rs)
@@ -168,21 +413,99 @@ exit:
}
static void
-resolve_image (GrlMetadataSourceResolveSpec *rs)
+resolve_video (GrlMetadataSourceResolveSpec *rs, resolution_flags_t flags)
+{
+ gchar *title, *showname;
+ GDateTime *date;
+ gint season, episode;
+ GrlData *data = GRL_DATA (rs->media);
+ resolution_flags_t miss_flags = 0, fill_flags;
+
+ GRL_DEBUG ("%s",__FUNCTION__);
+
+ if (!(flags & (FLAG_VIDEO_TITLE |
+ FLAG_VIDEO_SHOWNAME |
+ FLAG_VIDEO_DATE |
+ FLAG_VIDEO_SEASON |
+ FLAG_VIDEO_EPISODE)))
+ return;
+
+ miss_flags |= grl_data_key_is_known (data, GRL_METADATA_KEY_TITLE) ?
+ 0 : FLAG_VIDEO_TITLE;
+ miss_flags |= grl_data_key_is_known (data, GRL_METADATA_KEY_SHOW) ?
+ 0 : FLAG_VIDEO_SHOWNAME;
+ miss_flags |= grl_data_key_is_known (data, GRL_METADATA_KEY_DATE) ?
+ 0 : FLAG_VIDEO_DATE;
+ miss_flags |= grl_data_key_is_known (data, GRL_METADATA_KEY_SEASON) ?
+ 0 : FLAG_VIDEO_SEASON;
+ miss_flags |= grl_data_key_is_known (data, GRL_METADATA_KEY_EPISODE) ?
+ 0 : FLAG_VIDEO_EPISODE;
+
+ fill_flags = flags & miss_flags;
+
+ if (!fill_flags)
+ return;
+
+ video_guess_values_from_uri (grl_media_get_url (rs->media),
+ &title, &showname, &date,
+ &season, &episode);
+
+ GRL_DEBUG ("\tfound title=%s/showname=%s/year=%i/season=%i/episode=%i",
+ title, showname,
+ date != NULL ? g_date_time_get_year (date) : 0,
+ season, episode);
+
+ /* As this is just a guess, don't erase already provided values. */
+ if (title) {
+ if (fill_flags & FLAG_VIDEO_TITLE) {
+ grl_data_set_string (data, GRL_METADATA_KEY_TITLE, title);
+ }
+ g_free (title);
+ }
+
+ if (showname) {
+ if (fill_flags & FLAG_VIDEO_SHOWNAME) {
+ grl_data_set_string (data, GRL_METADATA_KEY_SHOW, showname);
+ }
+ g_free (showname);
+ }
+
+ if (date) {
+ if (fill_flags & FLAG_VIDEO_DATE) {
+ gchar *str_date = g_date_time_format (date, "%F");
+ grl_data_set_string (data, GRL_METADATA_KEY_DATE, str_date);
+ g_free (str_date);
+ }
+ g_date_time_unref (date);
+ }
+
+ if (season && (fill_flags & FLAG_VIDEO_SEASON)) {
+ grl_data_set_int (data, GRL_METADATA_KEY_SEASON, season);
+ }
+
+ if (episode && (fill_flags & FLAG_VIDEO_EPISODE)) {
+ grl_data_set_int (data, GRL_METADATA_KEY_EPISODE, episode);
+ }
+}
+
+static void
+resolve_image (GrlMetadataSourceResolveSpec *rs, resolution_flags_t flags)
{
GFile *file;
GRL_DEBUG ("resolve_image");
- file = g_file_new_for_uri (grl_media_get_url (rs->media));
+ if (flags & FLAG_THUMBNAIL) {
+ file = g_file_new_for_uri (grl_media_get_url (rs->media));
- g_file_query_info_async (file, G_FILE_ATTRIBUTE_THUMBNAIL_PATH,
- G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, NULL,
- (GAsyncReadyCallback)got_file_info, rs);
+ g_file_query_info_async (file, G_FILE_ATTRIBUTE_THUMBNAIL_PATH,
+ G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback)got_file_info, rs);
+ }
}
static void
-resolve_album_art (GrlMetadataSourceResolveSpec *rs)
+resolve_album_art (GrlMetadataSourceResolveSpec *rs, resolution_flags_t flags)
{
/* FIXME: implement this, according to
* http://live.gnome.org/MediaArtStorageSpec
@@ -214,6 +537,33 @@ has_compatible_media_url (GrlMedia *media)
return ret;
}
+
+static resolution_flags_t
+get_resolution_flags (GList *keys)
+{
+ GList *key = keys;
+ resolution_flags_t flags = 0;
+
+ while (key != NULL) {
+ if (key->data == GRL_METADATA_KEY_TITLE)
+ flags |= FLAG_VIDEO_TITLE;
+ else if (key->data == GRL_METADATA_KEY_SHOW)
+ flags |= FLAG_VIDEO_SHOWNAME;
+ else if (key->data == GRL_METADATA_KEY_DATE)
+ flags |= FLAG_VIDEO_DATE;
+ else if (key->data == GRL_METADATA_KEY_SEASON)
+ flags |= FLAG_VIDEO_SEASON;
+ else if (key->data == GRL_METADATA_KEY_EPISODE)
+ flags |= FLAG_VIDEO_EPISODE;
+ else if (key->data == GRL_METADATA_KEY_THUMBNAIL)
+ flags |= FLAG_THUMBNAIL;
+
+ key = key->next;
+ }
+
+ return flags;
+}
+
/* ================== API Implementation ================ */
static const GList *
@@ -222,6 +572,11 @@ grl_local_metadata_source_supported_keys (GrlMetadataSource *source)
static GList *keys = NULL;
if (!keys) {
keys = grl_metadata_key_list_new (GRL_METADATA_KEY_THUMBNAIL,
+ GRL_METADATA_KEY_TITLE,
+ GRL_METADATA_KEY_SHOW,
+ GRL_METADATA_KEY_DATE,
+ GRL_METADATA_KEY_SEASON,
+ GRL_METADATA_KEY_EPISODE,
NULL);
}
return keys;
@@ -233,13 +588,21 @@ grl_local_metadata_source_may_resolve (GrlMetadataSource *source,
GrlKeyID key_id,
GList **missing_keys)
{
- if (key_id != GRL_METADATA_KEY_THUMBNAIL
- || GRL_IS_MEDIA_AUDIO (media)
- || GRL_IS_MEDIA_BOX (media))
- return FALSE;
-
- if (media && grl_data_key_is_known (GRL_DATA (media), GRL_METADATA_KEY_URL))
- return has_compatible_media_url (media);
+ if (media) {
+ if (grl_data_key_is_known (GRL_DATA (media), GRL_METADATA_KEY_URL) &&
+ has_compatible_media_url (media)) {
+ if (key_id == GRL_METADATA_KEY_THUMBNAIL)
+ return TRUE;
+
+ if (grl_local_metadata_guess_video &&
+ (key_id == GRL_METADATA_KEY_TITLE ||
+ key_id == GRL_METADATA_KEY_SHOW ||
+ key_id == GRL_METADATA_KEY_DATE ||
+ key_id == GRL_METADATA_KEY_SEASON ||
+ key_id == GRL_METADATA_KEY_EPISODE))
+ return TRUE;
+ }
+ }
if (missing_keys)
*missing_keys = grl_metadata_key_list_new (GRL_METADATA_KEY_URL, NULL);
@@ -252,15 +615,18 @@ grl_local_metadata_source_resolve (GrlMetadataSource *source,
GrlMetadataSourceResolveSpec *rs)
{
GError *error = NULL;
+ resolution_flags_t flags;
GRL_DEBUG ("grl_local_metadata_source_resolve");
- if (!has_compatible_media_url (rs->media))
- error = g_error_new (GRL_CORE_ERROR, GRL_CORE_ERROR_RESOLVE_FAILED,
- "local-metadata needs a url in the file:// scheme");
- else if (!g_list_find (rs->keys, GRL_METADATA_KEY_THUMBNAIL))
- error = g_error_new (GRL_CORE_ERROR, GRL_CORE_ERROR_RESOLVE_FAILED,
- "local-metadata can only resolve the thumbnail key");
+ flags = get_resolution_flags (rs->keys);
+
+ if (!flags)
+ error = g_error_new (GRL_CORE_ERROR, GRL_CORE_ERROR_RESOLVE_FAILED,
+ "local-metadata cannot resolve any of the given keys");
+ else if (!has_compatible_media_url (rs->media))
+ error = g_error_new (GRL_CORE_ERROR, GRL_CORE_ERROR_RESOLVE_FAILED,
+ "local-metadata needs a url in the file:// scheme");
if (error) {
/* No can do! */
@@ -269,11 +635,16 @@ grl_local_metadata_source_resolve (GrlMetadataSource *source,
return;
}
- if (GRL_IS_MEDIA_VIDEO (rs->media)
- || GRL_IS_MEDIA_IMAGE (rs->media)) {
- resolve_image (rs);
+ GRL_DEBUG ("\ttrying to resolve for: %s", grl_media_get_url (rs->media));
+
+ if (GRL_IS_MEDIA_VIDEO (rs->media)) {
+ if (grl_local_metadata_guess_video)
+ resolve_video (rs, flags);
+ resolve_image (rs, flags);
+ } else if (GRL_IS_MEDIA_IMAGE (rs->media)) {
+ resolve_image (rs, flags);
} else if (GRL_IS_MEDIA_AUDIO (rs->media)) {
- resolve_album_art (rs);
+ resolve_album_art (rs, flags);
} else {
/* What's that media type? */
rs->callback (source, rs->media, rs->user_data, NULL);
--
1.7.4.1
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]