From bbe35021b8d104258c800fef3ba5ab99f5492215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Wed, 24 Sep 2008 21:30:08 +0000 Subject: [PATCH] Make it possible to download recorded events directly from the web ui. --- dvr/dvr.h | 2 ++ dvr/dvr_db.c | 17 ++++++++++++ http.c | 7 +++-- webui/extjs.c | 13 +++++++++ webui/static/app/dvr.js | 7 +++++ webui/webui.c | 59 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 2 deletions(-) diff --git a/dvr/dvr.h b/dvr/dvr.h index 00326bb7..500a31cd 100644 --- a/dvr/dvr.h +++ b/dvr/dvr.h @@ -136,6 +136,8 @@ void dvr_rec_unsubscribe(dvr_entry_t *de); dvr_entry_t *dvr_entry_find_by_id(int id); +off_t dvr_get_filesize(dvr_entry_t *de); + void dvr_entry_cancel(dvr_entry_t *de); void dvr_entry_dec_ref(dvr_entry_t *de); diff --git a/dvr/dvr_db.c b/dvr/dvr_db.c index baa1f2bb..e888b554 100644 --- a/dvr/dvr_db.c +++ b/dvr/dvr_db.c @@ -660,3 +660,20 @@ dvr_query_sort(dvr_query_result_t *dqr) qsort(dqr->dqr_array, dqr->dqr_entries, sizeof(dvr_entry_t *), sf); } + +/** + * + */ +off_t +dvr_get_filesize(dvr_entry_t *de) +{ + struct stat st; + + if(de->de_filename == NULL) + return 0; + + if(stat(de->de_filename, &st) != 0) + return 0; + + return st.st_size; +} diff --git a/http.c b/http.c index e59cf5e0..6920965b 100644 --- a/http.c +++ b/http.c @@ -69,8 +69,11 @@ http_resolve(http_connection_t *hc, char **remainp, char **argsp) http_path_t *hp; char *v; LIST_FOREACH(hp, &http_paths, hp_link) { - if(!strncmp(hc->hc_url, hp->hp_path, hp->hp_len)) - break; + if(!strncmp(hc->hc_url, hp->hp_path, hp->hp_len)) { + if(hc->hc_url[hp->hp_len] == 0 || hc->hc_url[hp->hp_len] == '/' || + hc->hc_url[hp->hp_len] == '?') + break; + } } if(hp == NULL) diff --git a/webui/extjs.c b/webui/extjs.c index 9dcc6641..a4e7cdf1 100644 --- a/webui/extjs.c +++ b/webui/extjs.c @@ -1037,6 +1037,7 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque) dvr_entry_t *de; int start = 0, end, limit, i; const char *s, *t = NULL; + off_t fsize; if((s = http_arg_get(&hc->hc_req_args, "start")) != NULL) start = atoi(s); @@ -1105,6 +1106,18 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque) if(t != NULL) htsmsg_add_str(m, "schedstate", t); + if(de->de_sched_state == DVR_COMPLETED) { + fsize = dvr_get_filesize(de); + if(fsize > 0) { + char url[100]; + htsmsg_add_u64(m, "filesize", fsize); + + snprintf(url, sizeof(url), "/dvrfile/%d", de->de_id); + htsmsg_add_str(m, "url", url); + } + } + + htsmsg_add_msg(array, NULL, m); } diff --git a/webui/static/app/dvr.js b/webui/static/app/dvr.js index 4d2fbac6..0d2841a3 100644 --- a/webui/static/app/dvr.js +++ b/webui/static/app/dvr.js @@ -13,6 +13,8 @@ tvheadend.dvrStore = new Ext.data.JsonStore({ {name: 'schedstate'}, {name: 'creator'}, {name: 'duration'}, + {name: 'filesize'}, + {name: 'url'}, ], url: 'dvrlist', autoLoad: true, @@ -38,6 +40,11 @@ tvheadend.dvrDetails = function(entry) { content += '
' content += '
Status: ' + entry.status + '
'; + if(entry.url != null && entry.filesize > 0) { + content += '
' + + 'Download '+ + parseInt(entry.filesize/1000000) + ' MB
'; + } var win = new Ext.Window({ title: entry.title, diff --git a/webui/webui.c b/webui/webui.c index 6081d5ed..88b8c19a 100644 --- a/webui/webui.c +++ b/webui/webui.c @@ -33,6 +33,7 @@ #include "access.h" #include "http.h" #include "webui.h" +#include "dvr/dvr.h" static int is_client_simple(http_connection_t *hc) @@ -106,6 +107,63 @@ page_static(http_connection_t *hc, const char *remain, void *opaque) } +/** + * Download a recorded file + */ +static int +page_dvrfile(http_connection_t *hc, const char *remain, void *opaque) +{ + int fd; + struct stat st; + const char *content = NULL, *postfix, *range; + dvr_entry_t *de; + char *fname; + + if(remain == NULL) + return 404; + + pthread_mutex_lock(&global_lock); + de = dvr_entry_find_by_id(atoi(remain)); + if(de == NULL || de->de_filename == NULL) { + pthread_mutex_unlock(&global_lock); + return 404; + } + + fname = strdup(de->de_filename); + pthread_mutex_unlock(&global_lock); + + postfix = strrchr(remain, '.'); + if(postfix != NULL) { + postfix++; + if(!strcmp(postfix, "mkv")) + content = "video/x-matroska"; + } + + fd = open(fname, O_RDONLY); + free(fname); + if(fd < 0) + return 404; + + if(fstat(fd, &st) < 0) { + close(fd); + return 404; + } + + + range = http_arg_get(&hc->hc_args, "Range"); +#if 0 + if(range != NULL) { + printf("Range req: %s\n", range); + } +#endif + + http_send_header(hc, 200, content, st.st_size, NULL, NULL, 10); + sendfile(hc->hc_fd, fd, NULL, st.st_size); + close(fd); + return 0; +} + + /** * WEB user interface */ @@ -115,6 +173,7 @@ webui_init(void) http_path_add("/", NULL, page_root, ACCESS_WEB_INTERFACE); http_path_add("/static", NULL, page_static, ACCESS_WEB_INTERFACE); + http_path_add("/dvrfile", NULL, page_dvrfile, ACCESS_WEB_INTERFACE); // simpleui_start(); extjs_start();