From c0e66e9997faed63b14ef82a7160a546ba6d8e2f Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Wed, 10 Jan 2018 18:02:17 -0800 Subject: [PATCH] metadata: Add episode season and number support Add upnp:episodeSeason and upnp:episodeNumber support for video items. The DISC and TRACK columns are multiplexed to store the data. --- metadata.c | 44 ++++++++++++++++++++++++++++++++++------- upnpsoap.c | 57 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/metadata.c b/metadata.c index 8a10c77..9564f4d 100644 --- a/metadata.c +++ b/metadata.c @@ -156,7 +156,7 @@ check_for_captions(const char *path, int64_t detailID) } } -void +static void parse_nfo(const char *path, metadata_t *m) { FILE *nfo; @@ -237,6 +237,14 @@ parse_nfo(const char *path, metadata_t *m) free(esc_tag); } + val = GetValueFromNameValueList(&xml, "season"); + if (val) + m->disc = atoi(val); + + val = GetValueFromNameValueList(&xml, "episode"); + if (val) + m->track = atoi(val); + ClearNameValueList(&xml); free(buf); } @@ -1499,10 +1507,8 @@ video_no_dlna: if( ext ) { strcpy(ext+1, "nfo"); - if( access(nfo, F_OK) == 0 ) - { + if( access(nfo, R_OK) == 0 ) parse_nfo(nfo, &m); - } } if( !m.mime ) @@ -1539,19 +1545,43 @@ video_no_dlna: strip_ext(m.title); } + if (!m.disc && !m.track) + { + /* Search for Season and Episode in the filename */ + char *p = (char*)name, *s; + while ((s = strpbrk(p, "Ss"))) + { + unsigned season = strtoul(s+1, &p, 10); + unsigned episode = 0; + if (season > 0 && p) + { + while (isblank(*p) || ispunct(*p)) + p++; + if (*p == 'E' || *p == 'e') + episode = strtoul(p+1, NULL, 10); + } + if (season && episode) + { + m.disc = season; + m.track = episode; + } + p = s + 1; + } + } + album_art = find_album_art(path, m.thumb_data, m.thumb_size); freetags(&video); lav_close(ctx); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, SIZE, TIMESTAMP, DURATION, DATE, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION," - " TITLE, CREATOR, ARTIST, GENRE, COMMENT, DLNA_PN, MIME, ALBUM_ART) " + " TITLE, CREATOR, ARTIST, GENRE, COMMENT, DLNA_PN, MIME, ALBUM_ART, DISC, TRACK) " "VALUES" - " (%Q, %lld, %lld, %Q, %Q, %u, %u, %u, %Q, '%q', %Q, %Q, %Q, %Q, %Q, '%q', %lld);", + " (%Q, %lld, %lld, %Q, %Q, %u, %u, %u, %Q, '%q', %Q, %Q, %Q, %Q, %Q, '%q', %lld, %u, %u);", path, (long long)file.st_size, (long long)file.st_mtime, m.duration, m.date, m.channels, m.bitrate, m.frequency, m.resolution, m.title, m.creator, m.artist, m.genre, m.comment, m.dlna_pn, - m.mime, album_art); + m.mime, album_art, m.disc, m.track); if( ret != SQLITE_OK ) { DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path); diff --git a/upnpsoap.c b/upnpsoap.c index b53b53d..dd0a5bf 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -261,6 +261,7 @@ GetSortCapabilities(struct upnphttp * h, const char * action) "dc:date," "upnp:class," "upnp:album," + "upnp:episodeNumber," "upnp:originalTrackNumber" "" ""; @@ -388,23 +389,25 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action) #define FILTER_UPNP_ALBUMARTURI 0x00010000 #define FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID 0x00020000 #define FILTER_UPNP_ARTIST 0x00040000 -#define FILTER_UPNP_GENRE 0x00080000 -#define FILTER_UPNP_ORIGINALTRACKNUMBER 0x00100000 -#define FILTER_UPNP_SEARCHCLASS 0x00200000 -#define FILTER_UPNP_STORAGEUSED 0x00400000 +#define FILTER_UPNP_EPISODENUMBER 0x00080000 +#define FILTER_UPNP_EPISODESEASON 0x00100000 +#define FILTER_UPNP_GENRE 0x00200000 +#define FILTER_UPNP_ORIGINALTRACKNUMBER 0x00400000 +#define FILTER_UPNP_SEARCHCLASS 0x00800000 +#define FILTER_UPNP_STORAGEUSED 0x01000000 /* Not normally used, so leave out of the default filter */ -#define FILTER_UPNP_PLAYBACKCOUNT 0x01000000 -#define FILTER_UPNP_LASTPLAYBACKPOSITION 0x02000000 +#define FILTER_UPNP_PLAYBACKCOUNT 0x02000000 +#define FILTER_UPNP_LASTPLAYBACKPOSITION 0x04000000 /* Vendor-specific filter flags */ -#define FILTER_SEC_CAPTION_INFO_EX 0x04000000 -#define FILTER_SEC_DCM_INFO 0x08000000 -#define FILTER_SEC 0x0C000000 -#define FILTER_PV_SUBTITLE_FILE_TYPE 0x10000000 -#define FILTER_PV_SUBTITLE_FILE_URI 0x20000000 -#define FILTER_PV_SUBTITLE 0x30000000 -#define FILTER_AV_MEDIA_CLASS 0x40000000 +#define FILTER_SEC_CAPTION_INFO_EX 0x08000000 +#define FILTER_SEC_DCM_INFO 0x10000000 +#define FILTER_SEC 0x18000000 +#define FILTER_PV_SUBTITLE_FILE_TYPE 0x20000000 +#define FILTER_PV_SUBTITLE_FILE_URI 0x40000000 +#define FILTER_PV_SUBTITLE 0x60000000 +#define FILTER_AV_MEDIA_CLASS 0x80000000 /* Masks */ -#define STANDARD_FILTER_MASK 0x00FFFFFF +#define STANDARD_FILTER_MASK 0x01FFFFFF #define FILTER_BOOKMARK_MASK (FILTER_UPNP_PLAYBACKCOUNT | \ FILTER_UPNP_LASTPLAYBACKPOSITION | \ FILTER_SEC_DCM_INFO) @@ -575,6 +578,14 @@ set_filter_flags(char *filter, struct upnphttp *h) { flags |= FILTER_AV_MEDIA_CLASS; } + else if( strcmp(item, "upnp:episodeNumber") == 0 ) + { + flags |= FILTER_UPNP_EPISODENUMBER; + } + else if( strcmp(item, "upnp:episodeSeason") == 0 ) + { + flags |= FILTER_UPNP_EPISODESEASON; + } item = strtok_r(NULL, ",", &saveptr); } @@ -635,9 +646,10 @@ parse_sort_criteria(char *sortCriteria, int *error) { strcatf(&str, "d.DATE"); } - else if( strcasecmp(item, "upnp:originalTrackNumber") == 0 ) + else if( strcasecmp(item, "upnp:originalTrackNumber") == 0 || + strcasecmp(item, "upnp:episodeNumber") == 0 ) { - strcatf(&str, "d.DISC, d.TRACK"); + strcatf(&str, "d.DISC%s, d.TRACK", reverse ? " DESC" : ""); } else if( strcasecmp(item, "upnp:album") == 0 ) { @@ -794,7 +806,7 @@ callback(void *args, int argc, char **argv, char **azColName) char *id = argv[0], *parent = argv[1], *refID = argv[2], *detailID = argv[3], *class = argv[4], *size = argv[5], *title = argv[6], *duration = argv[7], *bitrate = argv[8], *sampleFrequency = argv[9], *artist = argv[10], *album = argv[11], *genre = argv[12], *comment = argv[13], *nrAudioChannels = argv[14], *track = argv[15], *date = argv[16], *resolution = argv[17], - *tn = argv[18], *creator = argv[19], *dlna_pn = argv[20], *mime = argv[21], *album_art = argv[22], *rotate = argv[23]; + *tn = argv[18], *creator = argv[19], *dlna_pn = argv[20], *mime = argv[21], *album_art = argv[22], *rotate = argv[23], *disc = argv[24]; char dlna_buf[128]; const char *ext; struct string_s *str = passed_args->str; @@ -1006,8 +1018,15 @@ callback(void *args, int argc, char **argv, char **azColName) if( strncmp(id, MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 ) { track = strrchr(id, '$')+1; } - if( NON_ZERO(track) && (passed_args->filter & FILTER_UPNP_ORIGINALTRACKNUMBER) ) { - ret = strcatf(str, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track); + if( NON_ZERO(track) ) { + if( *mime == 'a' && (passed_args->filter & FILTER_UPNP_ORIGINALTRACKNUMBER) ) { + ret = strcatf(str, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track); + } else if( *mime == 'v' ) { + if( passed_args->filter & FILTER_UPNP_EPISODESEASON ) + ret = strcatf(str, "<upnp:episodeSeason>%s</upnp:episodeSeason>", disc); + if( passed_args->filter & FILTER_UPNP_EPISODENUMBER ) + ret = strcatf(str, "<upnp:episodeNumber>%s</upnp:episodeNumber>", track); + } } if( passed_args->filter & FILTER_RES ) { ext = mime_to_ext(mime);