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.
This commit is contained in:
parent
8bdba2f40d
commit
c0e66e9997
44
metadata.c
44
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)
|
parse_nfo(const char *path, metadata_t *m)
|
||||||
{
|
{
|
||||||
FILE *nfo;
|
FILE *nfo;
|
||||||
@ -237,6 +237,14 @@ parse_nfo(const char *path, metadata_t *m)
|
|||||||
free(esc_tag);
|
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);
|
ClearNameValueList(&xml);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
@ -1499,10 +1507,8 @@ video_no_dlna:
|
|||||||
if( ext )
|
if( ext )
|
||||||
{
|
{
|
||||||
strcpy(ext+1, "nfo");
|
strcpy(ext+1, "nfo");
|
||||||
if( access(nfo, F_OK) == 0 )
|
if( access(nfo, R_OK) == 0 )
|
||||||
{
|
|
||||||
parse_nfo(nfo, &m);
|
parse_nfo(nfo, &m);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !m.mime )
|
if( !m.mime )
|
||||||
@ -1539,19 +1545,43 @@ video_no_dlna:
|
|||||||
strip_ext(m.title);
|
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);
|
album_art = find_album_art(path, m.thumb_data, m.thumb_size);
|
||||||
freetags(&video);
|
freetags(&video);
|
||||||
lav_close(ctx);
|
lav_close(ctx);
|
||||||
|
|
||||||
ret = sql_exec(db, "INSERT into DETAILS"
|
ret = sql_exec(db, "INSERT into DETAILS"
|
||||||
" (PATH, SIZE, TIMESTAMP, DURATION, DATE, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION,"
|
" (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"
|
"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,
|
path, (long long)file.st_size, (long long)file.st_mtime, m.duration,
|
||||||
m.date, m.channels, m.bitrate, m.frequency, m.resolution,
|
m.date, m.channels, m.bitrate, m.frequency, m.resolution,
|
||||||
m.title, m.creator, m.artist, m.genre, m.comment, m.dlna_pn,
|
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 )
|
if( ret != SQLITE_OK )
|
||||||
{
|
{
|
||||||
DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path);
|
DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path);
|
||||||
|
57
upnpsoap.c
57
upnpsoap.c
@ -261,6 +261,7 @@ GetSortCapabilities(struct upnphttp * h, const char * action)
|
|||||||
"dc:date,"
|
"dc:date,"
|
||||||
"upnp:class,"
|
"upnp:class,"
|
||||||
"upnp:album,"
|
"upnp:album,"
|
||||||
|
"upnp:episodeNumber,"
|
||||||
"upnp:originalTrackNumber"
|
"upnp:originalTrackNumber"
|
||||||
"</SortCaps>"
|
"</SortCaps>"
|
||||||
"</u:%sResponse>";
|
"</u:%sResponse>";
|
||||||
@ -388,23 +389,25 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action)
|
|||||||
#define FILTER_UPNP_ALBUMARTURI 0x00010000
|
#define FILTER_UPNP_ALBUMARTURI 0x00010000
|
||||||
#define FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID 0x00020000
|
#define FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID 0x00020000
|
||||||
#define FILTER_UPNP_ARTIST 0x00040000
|
#define FILTER_UPNP_ARTIST 0x00040000
|
||||||
#define FILTER_UPNP_GENRE 0x00080000
|
#define FILTER_UPNP_EPISODENUMBER 0x00080000
|
||||||
#define FILTER_UPNP_ORIGINALTRACKNUMBER 0x00100000
|
#define FILTER_UPNP_EPISODESEASON 0x00100000
|
||||||
#define FILTER_UPNP_SEARCHCLASS 0x00200000
|
#define FILTER_UPNP_GENRE 0x00200000
|
||||||
#define FILTER_UPNP_STORAGEUSED 0x00400000
|
#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 */
|
/* Not normally used, so leave out of the default filter */
|
||||||
#define FILTER_UPNP_PLAYBACKCOUNT 0x01000000
|
#define FILTER_UPNP_PLAYBACKCOUNT 0x02000000
|
||||||
#define FILTER_UPNP_LASTPLAYBACKPOSITION 0x02000000
|
#define FILTER_UPNP_LASTPLAYBACKPOSITION 0x04000000
|
||||||
/* Vendor-specific filter flags */
|
/* Vendor-specific filter flags */
|
||||||
#define FILTER_SEC_CAPTION_INFO_EX 0x04000000
|
#define FILTER_SEC_CAPTION_INFO_EX 0x08000000
|
||||||
#define FILTER_SEC_DCM_INFO 0x08000000
|
#define FILTER_SEC_DCM_INFO 0x10000000
|
||||||
#define FILTER_SEC 0x0C000000
|
#define FILTER_SEC 0x18000000
|
||||||
#define FILTER_PV_SUBTITLE_FILE_TYPE 0x10000000
|
#define FILTER_PV_SUBTITLE_FILE_TYPE 0x20000000
|
||||||
#define FILTER_PV_SUBTITLE_FILE_URI 0x20000000
|
#define FILTER_PV_SUBTITLE_FILE_URI 0x40000000
|
||||||
#define FILTER_PV_SUBTITLE 0x30000000
|
#define FILTER_PV_SUBTITLE 0x60000000
|
||||||
#define FILTER_AV_MEDIA_CLASS 0x40000000
|
#define FILTER_AV_MEDIA_CLASS 0x80000000
|
||||||
/* Masks */
|
/* Masks */
|
||||||
#define STANDARD_FILTER_MASK 0x00FFFFFF
|
#define STANDARD_FILTER_MASK 0x01FFFFFF
|
||||||
#define FILTER_BOOKMARK_MASK (FILTER_UPNP_PLAYBACKCOUNT | \
|
#define FILTER_BOOKMARK_MASK (FILTER_UPNP_PLAYBACKCOUNT | \
|
||||||
FILTER_UPNP_LASTPLAYBACKPOSITION | \
|
FILTER_UPNP_LASTPLAYBACKPOSITION | \
|
||||||
FILTER_SEC_DCM_INFO)
|
FILTER_SEC_DCM_INFO)
|
||||||
@ -575,6 +578,14 @@ set_filter_flags(char *filter, struct upnphttp *h)
|
|||||||
{
|
{
|
||||||
flags |= FILTER_AV_MEDIA_CLASS;
|
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);
|
item = strtok_r(NULL, ",", &saveptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,9 +646,10 @@ parse_sort_criteria(char *sortCriteria, int *error)
|
|||||||
{
|
{
|
||||||
strcatf(&str, "d.DATE");
|
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 )
|
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],
|
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],
|
*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],
|
*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];
|
char dlna_buf[128];
|
||||||
const char *ext;
|
const char *ext;
|
||||||
struct string_s *str = passed_args->str;
|
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 ) {
|
if( strncmp(id, MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 ) {
|
||||||
track = strrchr(id, '$')+1;
|
track = strrchr(id, '$')+1;
|
||||||
}
|
}
|
||||||
if( NON_ZERO(track) && (passed_args->filter & FILTER_UPNP_ORIGINALTRACKNUMBER) ) {
|
if( NON_ZERO(track) ) {
|
||||||
ret = strcatf(str, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", 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 ) {
|
if( passed_args->filter & FILTER_RES ) {
|
||||||
ext = mime_to_ext(mime);
|
ext = mime_to_ext(mime);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user