From f7e525019a7d73a0985691bd32bea2ddb66b1f1b Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Thu, 15 Oct 2009 00:40:27 +0000 Subject: [PATCH] * Add SRT subtitle support using Samsung's method. --- inotify.c | 3 ++ metadata.c | 50 ++++++++++++++++++++++++++++++++ metadata.h | 3 ++ scanner.c | 6 ++++ upnphttp.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++- upnphttp.h | 3 ++ 6 files changed, 148 insertions(+), 1 deletion(-) diff --git a/inotify.c b/inotify.c index ffc8e11..350cedb 100644 --- a/inotify.c +++ b/inotify.c @@ -23,6 +23,7 @@ #include "utils.h" #include "sql.h" #include "scanner.h" +#include "metadata.h" #include "albumart.h" #include "log.h" @@ -278,6 +279,8 @@ inotify_insert_file(char * name, const char * path) /* Is it cover art for another file? */ if( is_image(path) ) update_if_album_art(path); + else if( ends_with(path, ".srt") ) + check_for_captions(path, 0); /* Check if we're supposed to be scanning for this file type in this directory */ while( media_path ) diff --git a/metadata.c b/metadata.c index 45fb9df..fa3ebd5 100644 --- a/metadata.c +++ b/metadata.c @@ -118,6 +118,55 @@ get_fourcc(const char *s) return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24); } +void +check_for_captions(const char * path, sqlite_int64 detailID) +{ + char * sql; + char * file = malloc(PATH_MAX); + char **result; + int ret, rows; + + sprintf(file, "%s", path); + strip_ext(file); + + /* If we weren't given a detail ID, look for one. */ + if( !detailID ) + { + sql = sqlite3_mprintf("SELECT ID from DETAILS where PATH glob '%q.*'" + " and MIME glob 'video/*' limit 1", file); + ret = sql_get_table(db, sql, &result, &rows, NULL); + if( ret == SQLITE_OK ) + { + if( rows ) + { + detailID = strtoll(result[1], NULL, 10); + //DEBUG DPRINTF(E_DEBUG, L_METADATA, "New file %s looks like a caption file.\n", path); + } + /*else + { + DPRINTF(E_DEBUG, L_METADATA, "No file found for caption %s.\n", path); + }*/ + sqlite3_free_table(result); + } + sqlite3_free(sql); + if( !detailID ) + goto no_source_video; + } + + strcat(file, ".srt"); + if( access(file, R_OK) == 0 ) + { + sql = sqlite3_mprintf("INSERT into CAPTIONS" + " (ID, PATH) " + "VALUES" + " (%lld, %Q)", detailID, file); + sql_exec(db, sql); + sqlite3_free(sql); + } +no_source_video: + free(file); +} + sqlite_int64 GetFolderMetadata(const char * name, const char * path, const char * artist, const char * genre, const char * album_art) { @@ -942,6 +991,7 @@ GetVideoMetadata(const char * path, char * name) else { ret = sqlite3_last_insert_rowid(db); + check_for_captions(path, ret); } sqlite3_free(sql); if( m.dlna_pn ) diff --git a/metadata.h b/metadata.h index a819886..b64d842 100644 --- a/metadata.h +++ b/metadata.h @@ -73,6 +73,9 @@ ends_with(const char * haystack, const char * needle); char * modifyString(char * string, const char * before, const char * after, short like); +void +check_for_captions(const char * path, sqlite_int64 detailID); + sqlite_int64 GetFolderMetadata(const char * name, const char * path, const char * artist, const char * genre, const char * album_art); diff --git a/scanner.c b/scanner.c index 46d446d..24e2893 100644 --- a/scanner.c +++ b/scanner.c @@ -638,6 +638,12 @@ CreateDatabase(void) ")"); if( ret != SQLITE_OK ) goto sql_failed; + ret = sql_exec(db, "CREATE TABLE CAPTIONS (" + "ID INTEGER PRIMARY KEY, " + "PATH TEXT NOT NULL" + ")"); + if( ret != SQLITE_OK ) + goto sql_failed; ret = sql_exec(db, "CREATE TABLE SETTINGS (" "UPDATE_ID INTEGER PRIMARY KEY DEFAULT 0" ")"); diff --git a/upnphttp.c b/upnphttp.c index 36408fc..6baf85c 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -337,6 +337,10 @@ intervening space) by either an integer or the keyword "infinite". */ h->reqflags |= FLAG_XFERBACKGROUND; } } + else if(strncasecmp(line, "getCaptionInfo.sec", 18)==0) + { + h->reqflags |= FLAG_CAPTION; + } } next_header: while(!(line[0] == '\r' && line[1] == '\n')) @@ -791,6 +795,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h) SendResp_icon(h, HttpUrl+7); CloseSocket_upnphttp(h); } + else if(strncmp(HttpUrl, "/Captions/", 10) == 0) + { + SendResp_caption(h, HttpUrl+10); + CloseSocket_upnphttp(h); + } else { DPRINTF(E_WARN, L_HTTP, "%s not found, responding ERROR 404\n", HttpUrl); @@ -1119,7 +1128,6 @@ SendResp_icon(struct upnphttp * h, char * icon) free(header); } - void SendResp_albumArt(struct upnphttp * h, char * object) { @@ -1199,6 +1207,64 @@ SendResp_albumArt(struct upnphttp * h, char * object) sqlite3_free_table(result); } +void +SendResp_caption(struct upnphttp * h, char * object) +{ + char header[1500]; + char sql_buf[256]; + char **result; + int rows = 0; + char *path; + char date[30]; + time_t curtime = time(NULL); + off_t offset = 0, size; + int sendfh; + + memset(header, 0, 1500); + + strip_ext(object); + sprintf(sql_buf, "SELECT PATH from CAPTIONS where ID = %s", object); + sql_get_table(db, sql_buf, &result, &rows, NULL); + if( !rows ) + { + DPRINTF(E_WARN, L_HTTP, "CAPTION ID %s not found, responding ERROR 404\n", object); + Send404(h); + goto error; + } + path = result[1]; + DPRINTF(E_INFO, L_HTTP, "Serving caption ID: %s [%s]\n", object, path); + + if( access(path, F_OK) != 0 ) + goto error; + + strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime)); + sendfh = open(path, O_RDONLY); + if( sendfh < 0 ) { + DPRINTF(E_ERROR, L_HTTP, "Error opening %s\n", path); + goto error; + } + size = lseek(sendfh, 0, SEEK_END); + lseek(sendfh, 0, SEEK_SET); + + sprintf(header, "HTTP/1.1 200 OK\r\n" + "Content-Type: smi/caption\r\n" + "Content-Length: %jd\r\n" + "Connection: close\r\n" + "Date: %s\r\n" + "EXT:\r\n" + "Server: " MINIDLNA_SERVER_STRING "\r\n\r\n", + size, date); + + if( (send_data(h, header, strlen(header)) == 0) && (h->req_command != EHead) && (sendfh > 0) ) + { + send_file(h, sendfh, offset, size); + } + close(sendfh); + + error: + sqlite3_free_table(result); +} + void SendResp_thumbnail(struct upnphttp * h, char * object) { @@ -1631,6 +1697,22 @@ SendResp_dlnafile(struct upnphttp * h, char * object) } } + if( h->reqflags & FLAG_CAPTION ) + { + sprintf(sql_buf, "SELECT 1 from CAPTIONS where ID = '%lld'", id); + ret = sql_get_table(db, sql_buf, &result, &rows, NULL); + if( ret == SQLITE_OK ) + { + if( rows ) + { + sprintf(hdr_buf, "CaptionInfo.sec: http://%s:%d/Captions/%lld.srt\r\n", + lan_addr[0].str, runtime_vars.port, id); + strcat(header, hdr_buf); + } + sqlite3_free_table(result); + } + } + sprintf(hdr_buf, "Accept-Ranges: bytes\r\n" "Connection: close\r\n" "Date: %s\r\n" diff --git a/upnphttp.h b/upnphttp.h index 03bd235..1b42ce5 100644 --- a/upnphttp.h +++ b/upnphttp.h @@ -80,6 +80,7 @@ struct upnphttp { #define FLAG_XFERSTREAMING 0x00001000 #define FLAG_XFERINTERACTIVE 0x00002000 #define FLAG_XFERBACKGROUND 0x00004000 +#define FLAG_CAPTION 0x00008000 #define FLAG_DLNA 0x00100000 #define FLAG_MIME_AVI_DIVX 0x00200000 @@ -136,6 +137,8 @@ SendResp_icon(struct upnphttp *, char * url); void SendResp_albumArt(struct upnphttp *, char * url); void +SendResp_caption(struct upnphttp *, char * url); +void SendResp_resizedimg(struct upnphttp *, char * url); void SendResp_thumbnail(struct upnphttp *, char * url);