[totem-pl-parser] podcast: Add itunes genre ( <itunes:category> ) support for podcast rss feeds



commit fb6eaaee686a4071532ec9cb62110819c38f170e
Author: crvi <crvisqr gmail com>
Date:   Sun Apr 11 19:16:27 2021 +0530

    podcast: Add itunes genre ( <itunes:category> ) support for podcast rss feeds
    
    Refer: https://podcasts.apple.com/us/genre/podcasts/id26 for full list
    of genres supported by <itunes:category> tag.
    
    Considering "MG = Main Genre" and "SG = Sub Genre", iTunes genre can
    be of the following 2 basic forms:
    
    1. MG ( E.g. Business )
    2. MG/SG ( E.g. Science/Astronomy )
    
    The first such genre value is assigned to TOTEM_PL_PARSER_FIELD_GENRE
    metadata field
    
    Combinations of the above 2 forms are valid too:
    
    1. MG,MG/SG etc ( E.g. Music,Leisure/Hobbies )
    2. MG1/SG1,MG2/SG2 etc ( E.g. Business/Investing,Education/Self Improvement )
    
    The full genre value is assigned to TOTEM_PL_PARSER_FIELD_GENRES
    metadata field

 plparse/totem-pl-parser-podcast.c | 87 +++++++++++++++++++++++++++++++++++++++
 plparse/totem-pl-parser.c         |  6 ++-
 plparse/totem-pl-parser.h         | 10 ++++-
 3 files changed, 101 insertions(+), 2 deletions(-)
---
diff --git a/plparse/totem-pl-parser-podcast.c b/plparse/totem-pl-parser-podcast.c
index 16a31d6..458fbb7 100644
--- a/plparse/totem-pl-parser-podcast.c
+++ b/plparse/totem-pl-parser-podcast.c
@@ -39,6 +39,9 @@
 #define ATOM_NEEDLE "<feed"
 #define OPML_NEEDLE "<opml"
 
+#define GENRE_SEPARATOR ','
+#define SUB_GENRE_SEPARATOR '/'
+
 static const char *
 totem_pl_parser_is_xml_type (const char *data,
                             gsize len,
@@ -111,6 +114,69 @@ xml_parser_get_node_value (xml_node_t *parent, const char *node_name)
        return NULL;
 }
 
+/*
+ * <itunes:category text="Health & Fitness">   <-- xml_node
+ *   <itunes:category text="Alternative Health"/>
+ * </itunes:category>
+ *
+ * get_itunes_subgenre (xml_node)
+ *
+ * returns "Alternative Health"
+ *
+ */
+static const char *
+get_itunes_subgenre (xml_node_t *parent)
+{
+       xml_node_t *child;
+       const char *sub_genre = NULL;
+
+       for (child = parent->child; child != NULL; child = child->next) {
+               if (child->name == NULL)
+                       continue;
+
+               if (g_ascii_strcasecmp (child->name, "itunes:category") == 0) {
+                       sub_genre = xml_parser_get_property (child, "text");
+
+                       /* we expect atmost one itunes subgenre */
+                       break;
+               }
+       }
+
+       return sub_genre;
+}
+
+/*
+ * <itunes:category text="Technology">         <-- xml_node
+ *   <itunes:category text="Tech News"/>
+ * </itunes:category>
+ *
+ * get_itunes_genre (xml_node)
+ *
+ * returns "Technology/Tech News"
+ *
+ */
+static char *
+get_itunes_genre (xml_node_t *node)
+{
+       char *genre = NULL;
+       const char *main_genre = NULL;
+
+       main_genre = xml_parser_get_property (node, "text");
+
+       /* if main genre exists, check and append sub-genres */
+       if (main_genre != NULL) {
+               const char *sub_genre;
+               sub_genre = get_itunes_subgenre (node);
+
+               if (sub_genre != NULL)
+                       genre = g_strdup_printf ("%s%c%s", main_genre, SUB_GENRE_SEPARATOR, sub_genre);
+               else
+                       genre = g_strdup (main_genre);
+       }
+
+       return genre;
+}
+
 static gboolean
 is_image (const char *url)
 {
@@ -323,8 +389,12 @@ parse_rss_items (TotemPlParser *parser, const char *uri, xml_node_t *parent)
 {
        const char *title, *language, *description, *author;
        const char *contact, *img, *pub_date, *copyright, *generator, *explicit;
+       g_autofree char *genre = NULL;
+       g_autofree char *genres = NULL;
+       GString *genres_str;
        xml_node_t *node;
 
+       genres_str = NULL;
        title = language = description = author = NULL;
        contact = img = pub_date = copyright = generator = explicit = NULL;
 
@@ -378,9 +448,24 @@ parse_rss_items (TotemPlParser *parser, const char *uri, xml_node_t *parent)
                        copyright = node->data;
                } else if (g_ascii_strcasecmp (node->name, "itunes:explicit") == 0) {
                        explicit = node->data;
+               } else if (g_ascii_strcasecmp (node->name, "itunes:category") == 0) {
+                       /* only one primary genre */
+                       if (genre == NULL) {
+                               genre = get_itunes_genre (node);
+                               genres_str = g_string_new (genre);
+                       } else {
+                               char *tmp;
+
+                               tmp = get_itunes_genre (node);
+                               g_string_append_printf (genres_str, "%c%s", GENRE_SEPARATOR, tmp);
+                               g_free (tmp);
+                       }
                }
        }
 
+       if (genres_str)
+               genres = g_string_free (genres_str, FALSE);
+
        /* update generator as author, only as last resort */
        if (!author && generator)
                author = generator;
@@ -390,6 +475,8 @@ parse_rss_items (TotemPlParser *parser, const char *uri, xml_node_t *parent)
                                 TOTEM_PL_PARSER_FIELD_IS_PLAYLIST, TRUE,
                                 TOTEM_PL_PARSER_FIELD_URI, uri,
                                 TOTEM_PL_PARSER_FIELD_TITLE, title,
+                                TOTEM_PL_PARSER_FIELD_GENRE, genre,
+                                TOTEM_PL_PARSER_FIELD_GENRES, genres,
                                 TOTEM_PL_PARSER_FIELD_LANGUAGE, language,
                                 TOTEM_PL_PARSER_FIELD_DESCRIPTION, description,
                                 TOTEM_PL_PARSER_FIELD_AUTHOR, author,
diff --git a/plparse/totem-pl-parser.c b/plparse/totem-pl-parser.c
index 32fd435..b16ccdb 100644
--- a/plparse/totem-pl-parser.c
+++ b/plparse/totem-pl-parser.c
@@ -462,7 +462,11 @@ totem_pl_parser_class_init (TotemPlParserClass *klass)
                                     G_PARAM_READABLE & G_PARAM_WRITABLE);
        g_param_spec_pool_insert (totem_pl_parser_pspec_pool, pspec, TOTEM_TYPE_PL_PARSER);
        pspec = g_param_spec_string ("genre", "genre",
-                                    "Genre of the item to be added", NULL,
+                                    "Primary genre of the item to be added", NULL,
+                                    G_PARAM_READABLE & G_PARAM_WRITABLE);
+       g_param_spec_pool_insert (totem_pl_parser_pspec_pool, pspec, TOTEM_TYPE_PL_PARSER);
+       pspec = g_param_spec_string ("genres", "genres",
+                                    "Full genre of the item to be added", NULL,
                                     G_PARAM_READABLE & G_PARAM_WRITABLE);
        g_param_spec_pool_insert (totem_pl_parser_pspec_pool, pspec, TOTEM_TYPE_PL_PARSER);
        pspec = g_param_spec_string ("album", "album",
diff --git a/plparse/totem-pl-parser.h b/plparse/totem-pl-parser.h
index 1b10d4f..7cee4d1 100644
--- a/plparse/totem-pl-parser.h
+++ b/plparse/totem-pl-parser.h
@@ -84,9 +84,17 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(TotemPlParser, g_object_unref)
 /**
  * TOTEM_PL_PARSER_FIELD_GENRE:
  *
- * Metadata field for an entry's genre.
+ * Metadata field for an entry's primary genre. This is a string of
+ * the form 'Genre1' or 'Genre1/SubGenre1".
  **/
 #define TOTEM_PL_PARSER_FIELD_GENRE            "genre"
+/**
+ * TOTEM_PL_PARSER_FIELD_GENRES:
+ *
+ * Metadata field for an entry's full genre. This is a concatenated
+ * string of the form 'Genre1/SubGenre1,Genre2/SubGenre2" etc.
+ **/
+#define TOTEM_PL_PARSER_FIELD_GENRES           "genres"
 /**
  * TOTEM_PL_PARSER_FIELD_TITLE:
  *


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