From 70f268b6fff0037cbff265cf849663755223ffed Mon Sep 17 00:00:00 2001 From: Dieter Hametner Date: Tue, 8 May 2007 22:59:40 +0000 Subject: - Control recordings playback from Infobox - Added button images (Buttons by skiller2k1) - Made recordings look more like schedule - Made all tables 100% width to have a common look over all pages - some cleanup in ajax xml responses - common file for xmlresponses - Added translations for recordings related strings - Javascript updates in vdr_status.js for new playback control functions - Added tasks for playback control actions --- css/styles.css | 38 ++++++++++++- i18n.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++ images/Makefile | 9 +-- images/ffw.png | Bin 0 -> 852 bytes images/pause.png | Bin 0 -> 748 bytes images/rwd.png | Bin 0 -> 863 bytes images/stop.png | Bin 748 -> 713 bytes images/stop_update.png | Bin 0 -> 748 bytes javascript/vdr_status.js | 37 +++++++++++- pages/Makefile | 6 +- pages/ffw_recording.ecpp | 26 +++++++++ pages/ibox.ecpp | 65 ++++++--------------- pages/menu.ecpp | 4 +- pages/pageelems.ecpp | 20 ++++--- pages/pause_recording.ecpp | 26 +++++++++ pages/play_recording.ecpp | 13 +---- pages/recordings.ecpp | 15 +++-- pages/rwd_recording.ecpp | 26 +++++++++ pages/stop_recording.ecpp | 26 +++++++++ pages/switch_channel.ecpp | 9 +-- pages/xmlresponse.ecpp | 62 ++++++++++++++++++++ tasks.cpp | 139 ++++++++++++++++++++++++++++++++++++++++++--- tasks.h | 61 ++++++++++++++++++-- tntconfig.cpp | 4 +- 24 files changed, 613 insertions(+), 105 deletions(-) create mode 100644 images/ffw.png create mode 100644 images/pause.png create mode 100644 images/rwd.png create mode 100644 images/stop_update.png create mode 100644 pages/ffw_recording.ecpp create mode 100644 pages/pause_recording.ecpp create mode 100644 pages/rwd_recording.ecpp create mode 100644 pages/stop_recording.ecpp create mode 100644 pages/xmlresponse.ecpp diff --git a/css/styles.css b/css/styles.css index 46f21b0..b3f5b22 100644 --- a/css/styles.css +++ b/css/styles.css @@ -11,8 +11,15 @@ body { } table { + width: 100%; font-size: 11px; font-family: Verdana, Arial, Helvetica, sans-serif; + margin: 0px; +} + +tr, td { + padding-top: 0px; + padding-bottom: 0px; } input { @@ -245,10 +252,23 @@ div#infobox div.st_controls div.st_pbar { float: right; } -div#infobox div.st_controls div.st_btns { +div#infobox div.st_controls div { float: left; } +div#infobox div.st_controls div.st_update { + padding-right: 5px; + border-right: 1px solid #C0C1DA; +} + +div#infobox div.st_controls div#infobox_recording_buttons { + padding-left: 5px; +} + +div#infobox div.st_controls div#infobox_channel_buttons { + padding-left: 5px; +} + /* ####################### # Head Box ####################### @@ -270,7 +290,6 @@ div.head_box_m { padding: 0; } - div.head_box_r { background-image: url(bg_header_r.png); background-position: top right; @@ -551,7 +570,7 @@ table.schedule tr td.head { table.schedule tr td { vertical-align: top; - padding: 3px 7px 3px 3px; + padding: 0px 7px 0px 3px; background: url(bg_line.png) bottom repeat-x; border-bottom: 1px solid #C0C1DA; } @@ -653,6 +672,18 @@ div.recording_item { cursor: pointer; } +.recording_item div.recording_name span { + font-weight: normal; + cursor: pointer; +} + +.recording_item div.recording_arch { + float: right; + padding-top: 0.5ex; + padding-left: 0.5em; + padding-right: 0.5em; +} + .recording_item div.recording_actions { float: right; padding-right: 3em; @@ -829,6 +860,7 @@ table.searchresults td.border { table.login { margin: 0 auto; + padding: 20ox; } table.login tr td { diff --git a/i18n.cpp b/i18n.cpp index 5119a56..5ad04d4 100644 --- a/i18n.cpp +++ b/i18n.cpp @@ -245,6 +245,138 @@ const tI18nPhrase Phrases[] = { "", // Dansk "", // Czech }, + { "playing recording", // English + "Wiedergabe", // Deutsch + "", // Slovenski + "", // Italiano + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "", // Finnish + "", // Polski + "", // Español + "", // Greek + "", // Svenska + "", // Românã + "", // Magyar + "", // Català + "", // Russian + "", // Hrvatski + "", // Eesti + "", // Dansk + "", // Czech + }, + { "stop playback", // English + "Anhalten", // Deutsch + "", // Slovenski + "", // Italiano + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "", // Finnish + "", // Polski + "", // Español + "", // Greek + "", // Svenska + "", // Românã + "", // Magyar + "", // Català + "", // Russian + "", // Hrvatski + "", // Eesti + "", // Dansk + "", // Czech + }, + { "resume playback", // English + "Fortsetzen", // Deutsch + "", // Slovenski + "", // Italiano + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "", // Finnish + "", // Polski + "", // Español + "", // Greek + "", // Svenska + "", // Românã + "", // Magyar + "", // Català + "", // Russian + "", // Hrvatski + "", // Eesti + "", // Dansk + "", // Czech + }, + { "pause playback", // English + "Pause", // Deutsch + "", // Slovenski + "", // Italiano + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "", // Finnish + "", // Polski + "", // Español + "", // Greek + "", // Svenska + "", // Românã + "", // Magyar + "", // Català + "", // Russian + "", // Hrvatski + "", // Eesti + "", // Dansk + "", // Czech + }, + { "fast forward", // English + "Suchlauf vorwärts", // Deutsch + "", // Slovenski + "", // Italiano + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "", // Finnish + "", // Polski + "", // Español + "", // Greek + "", // Svenska + "", // Românã + "", // Magyar + "", // Català + "", // Russian + "", // Hrvatski + "", // Eesti + "", // Dansk + "", // Czech + }, + { "fast rewind", // English + "Suchlauf rückwärts", // Deutsch + "", // Slovenski + "", // Italiano + "", // Nederlands + "", // Português + "", // Français + "", // Norsk + "", // Finnish + "", // Polski + "", // Español + "", // Greek + "", // Svenska + "", // Românã + "", // Magyar + "", // Català + "", // Russian + "", // Hrvatski + "", // Eesti + "", // Dansk + "", // Czech + }, { "Remote Control", // English "Fernbedienung", // Deutsch "", // Slovenski diff --git a/images/Makefile b/images/Makefile index f62a90a..294ce65 100644 --- a/images/Makefile +++ b/images/Makefile @@ -20,10 +20,11 @@ OBJS = logo.o record.o active.o inactive.o button_blue.o \ bg_header_h.o bg_header_l.o bg_header_r.o bg_box_h.o \ bg_box_l.o bg_box_r.o movie.o menu_line_bg.o \ bg_line.o bg_tools.o zap.o favicon.o bg_line_top.o \ - reload.o stop.o one_uparrow.o one_downarrow.o tv.o \ - remotecontrol.o search.o record_timer.o button_red.o \ - button_green.o button_new.o help.o logo_login.o \ - button_yellow.o arrow.o arrow_rec.o on_dvd.o + reload.o stop_update.o one_uparrow.o one_downarrow.o \ + tv.o remotecontrol.o search.o record_timer.o \ + button_red.o button_green.o button_new.o help.o \ + logo_login.o button_yellow.o arrow.o arrow_rec.o \ + on_dvd.o pause.o ffw.o rwd.o stop.o ### Default rules: diff --git a/images/ffw.png b/images/ffw.png new file mode 100644 index 0000000..aeec194 Binary files /dev/null and b/images/ffw.png differ diff --git a/images/pause.png b/images/pause.png new file mode 100644 index 0000000..1b44908 Binary files /dev/null and b/images/pause.png differ diff --git a/images/rwd.png b/images/rwd.png new file mode 100644 index 0000000..54ec330 Binary files /dev/null and b/images/rwd.png differ diff --git a/images/stop.png b/images/stop.png index 4ffdef7..bb79efb 100644 Binary files a/images/stop.png and b/images/stop.png differ diff --git a/images/stop_update.png b/images/stop_update.png new file mode 100644 index 0000000..4ffdef7 Binary files /dev/null and b/images/stop_update.png differ diff --git a/javascript/vdr_status.js b/javascript/vdr_status.js index 073d568..d9505e3 100644 --- a/javascript/vdr_status.js +++ b/javascript/vdr_status.js @@ -39,6 +39,25 @@ function LiveStatusRequest(url, containerid) function LiveStatusShowInfo(xmldoc, containerId) { + var infoType = xmldoc.getElementsByTagName('type').item(0); + + var channel = document.getElementById(containerId + '_channel_buttons'); + var playback = document.getElementById(containerId + '_recording_buttons'); + + if (infoType.firstChild.nodeValue != "channel") { + channel.style.display = 'none'; + playback.style.display = 'block'; + LiveStatusSetTextContent(containerId, 'pause', infoType.firstChild.nodeValue); + LiveStatusSetTextContent(containerId, 'play', infoType.firstChild.nodeValue); + LiveStatusSetTextContent(containerId, 'rwd', infoType.firstChild.nodeValue); + LiveStatusSetTextContent(containerId, 'ffw', infoType.firstChild.nodeValue); + LiveStatusSetTextContent(containerId, 'stop', infoType.firstChild.nodeValue); + } + else { + playback.style.display = 'none'; + channel.style.display = 'block'; + } + var epgInfo = xmldoc.getElementsByTagName('epginfo').item(0); for (var i = 0; i < epgInfo.childNodes.length; i++) { @@ -89,6 +108,22 @@ function LiveStatusSetTextContent(containerId, nodeName, textContent) else { docNode.style.visibility = "hidden"; } + break; + } + case "pause": + case "play": + case "rwd": + case "ffw": + case "stop": + { + if (textContent != "") { + docNode.href = "javascript:LiveSimpleAjaxRequest('" + nodeName + "_recording.xml', 'param', '" + textContent + "');"; + docNode.style.visibility = "visible"; + } + else { + docNode.style.visibility = "hidden"; + } + break; } default: break; @@ -110,6 +145,6 @@ function LiveStatusToggleUpdate() var img = document.getElementById('statusReloadBtn'); if (img != null) { // change image according to state. - img.src = vst_reload ? 'stop.png' : 'reload.png'; + img.src = vst_reload ? 'stop_update.png' : 'reload.png'; } } diff --git a/pages/Makefile b/pages/Makefile index fadb1b9..92a4932 100644 --- a/pages/Makefile +++ b/pages/Makefile @@ -18,9 +18,11 @@ VDRDIR ?= ../../../.. OBJS = menu.o channels.o recordings.o schedule.o \ screenshot.o timers.o whats_on.o switch_channel.o \ keypress.o remote.o channels_widget.o edit_timer.o \ - error.o pageelems.o tooltip.o play_recording.o \ + error.o pageelems.o tooltip.o \ searchtimers.o edit_searchtimer.o searchresults.o \ - searchepg.o login.o ibox.o + searchepg.o login.o ibox.o xmlresponse.o \ + play_recording.o pause_recording.o stop_recording.o \ + ffw_recording.o rwd_recording.o ### Default rules: diff --git a/pages/ffw_recording.ecpp b/pages/ffw_recording.ecpp new file mode 100644 index 0000000..5b2d8bc --- /dev/null +++ b/pages/ffw_recording.ecpp @@ -0,0 +1,26 @@ +<%pre> +#include +#include +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + + +<%args> + string param; + +<%session scope="global"> + bool logged_in(false); + +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + ForwardRecordingTask task( param ); + LiveTaskManager().Execute( task ); + +<& xmlresponse.ajax name=("ffw_recording") pname=("recording") value=(param) result=(task.Result()) error=(task.Error()) &> diff --git a/pages/ibox.ecpp b/pages/ibox.ecpp index e2b2fb8..0ed2f8c 100644 --- a/pages/ibox.ecpp +++ b/pages/ibox.ecpp @@ -10,6 +10,7 @@ #include "setup.h" #include "tools.h" #include "epg_events.h" +#include "recordings.h" using namespace vdrlive; using namespace std; @@ -30,18 +31,22 @@ bool logged_in(false); reply.setContentType( "application/xml" ); if (cReplayControl::NowReplaying()) { - cThreadLock RecordingsLock(&Recordings); - cRecording *Recording = Recordings.GetByName(cReplayControl::NowReplaying()); - if (Recording) { - const cRecordingInfo* info = Recording->Info(); + RecordingsManagerPtr recManager = LiveRecordingsManager(); + cRecording *recording = Recordings.GetByName(cReplayControl::NowReplaying()); + if (recording) { + string name(recording->Name()); + size_t index = name.find_last_of('~'); + if (index != string::npos) + name = name.substr(index, name.length()); + const cRecordingInfo* info = recording->Info(); if (info) { - EpgEventPtr epgEvent(new EpgEvent("recording", - Recording->Name(), - info->Title() ? info->Title() : Recording->Name(), + EpgEventPtr epgEvent(new EpgEvent(recManager->Md5Hash(recording), + tr("playing recording"), + info->Title() ? info->Title() : name, info->ShortText() ? info->ShortText() : "", info->Description() ? info->Description() : "", - Recording->start, - Recording->start)); + recording->start, + recording->start)); epgEvents.push_back(epgEvent); } } @@ -124,59 +129,25 @@ bool logged_in(false); if (prev_chan.Valid() && next_chan.Valid()) { -<& xmlresponse update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) prev_chan=(prev_chan) next_chan=(next_chan) &> +<& xmlresponse.ibox update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) prev_chan=(prev_chan) next_chan=(next_chan) &> <%cpp> } else if (prev_chan.Valid()) { -<& xmlresponse update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) prev_chan=(prev_chan) &> +<& xmlresponse.ibox update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) prev_chan=(prev_chan) &> <%cpp> } else if (next_chan.Valid()) { -<& xmlresponse update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) next_chan=(next_chan) &> +<& xmlresponse.ibox update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) next_chan=(next_chan) &> <%cpp> } else { -<& xmlresponse update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) &> +<& xmlresponse.ibox update=(update) type=(epg->Id()) caption=(epg->Caption()) currentTime=(epg->CurrentTime(tr("%I:%M:%S %p"))) duration=(epg->StartTime(tr("%I:%M %p")) + string(" - ") + epg->EndTime(tr("%I:%M %p"))) title=(epg->Title()) elapsed=(epg->Elapsed()) &> <%cpp> } break; } -<%def xmlresponse> -<%args> - int update; - string type; - string currentTime; - string caption; - string title; - string duration; - int elapsed; - string prev_chan; - string next_chan; - - - - - <$ update $> - - 1 - - - <$ update $> - - <$ type $> - <$ caption $> - <$ currentTime $> - <$ title $> - <$ duration $> - <$ elapsed $> - <$ next_chan $> - <$ prev_chan $> - - - - diff --git a/pages/menu.ecpp b/pages/menu.ecpp index 5acbc13..ac31d79 100644 --- a/pages/menu.ecpp +++ b/pages/menu.ecpp @@ -39,9 +39,9 @@ if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); % } ><$ tr("Recordings") $> | ><$ tr("Remote Control") $> - +--- #> % if (LiveSetup().UseAuth()) { | <$ tr("Logout") $> % } diff --git a/pages/pageelems.ecpp b/pages/pageelems.ecpp index a7fcf33..e12f9dc 100644 --- a/pages/pageelems.ecpp +++ b/pages/pageelems.ecpp @@ -41,13 +41,19 @@ using namespace vdrlive;
--:--
-
- > - - - <& ajax_action_href action=("switch_channel") id=("infobox_prevchan") image=("one_downarrow.png") tip=(tr("previous channel")) &> - <& ajax_action_href action=("switch_channel") id=("infobox_nextchan") image=("one_uparrow.png") tip=(tr("next channel")) &> - +
+ > +
+ +
+ <& ajax_action_href action=("switch_channel") id=("infobox_prevchan") image=("one_downarrow.png") tip=(tr("previous channel")) &> + <& ajax_action_href action=("switch_channel") id=("infobox_nextchan") image=("one_uparrow.png") tip=(tr("next channel")) &>
<& progressbar id=("infobox_elapsed") &> diff --git a/pages/pause_recording.ecpp b/pages/pause_recording.ecpp new file mode 100644 index 0000000..1208a42 --- /dev/null +++ b/pages/pause_recording.ecpp @@ -0,0 +1,26 @@ +<%pre> +#include +#include +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + + +<%args> + string param; + +<%session scope="global"> + bool logged_in(false); + +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + PauseRecordingTask task( param ); + LiveTaskManager().Execute( task ); + +<& xmlresponse.ajax name=("pause_recording") pname=("recording") value=(param) result=(task.Result()) error=(task.Error()) &> diff --git a/pages/play_recording.ecpp b/pages/play_recording.ecpp index 3d95352..5a26b41 100644 --- a/pages/play_recording.ecpp +++ b/pages/play_recording.ecpp @@ -14,20 +14,13 @@ using namespace vdrlive; string param; <%session scope="global"> -bool logged_in(false); + bool logged_in(false); <%cpp> if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); reply.setContentType( "application/xml" ); - ReplayRecordingTask task( param ); + PlayRecordingTask task( param ); LiveTaskManager().Execute( task ); - - - -<$ param $> - -<$ task.Result() $> -<$ task.Error() $> - +<& xmlresponse.ajax name=("play_recording") pname=("recording") value=(param) result=(task.Result()) error=(task.Error()) &> diff --git a/pages/recordings.ecpp b/pages/recordings.ecpp index 4993284..ebc68e7 100644 --- a/pages/recordings.ecpp +++ b/pages/recordings.ecpp @@ -102,10 +102,10 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) { } string day(FormatDateTime("%a,", recItem->StartTime())); string dayLen(lexical_cast(day.length() - 1) + ".25em;"); - string shortDescr(tr("Click to view details.")); if (epgEvent && !epgEvent->ShortDescr().empty()) shortDescr = (epgEvent->ShortDescr() + string("
") + shortDescr); + string hint(tr("Click to view details.")); if (epgEvent && !epgEvent->ShortDescr().empty()) hint = (epgEvent->ShortDescr() + "
" + hint);
  • - <& rec_item_file name=(recItem->Name()) level=(level) id=(recItem->Id()) day=(day) dayLen=(dayLen) startTime=(recItem->StartTime()) shortDescr=(shortDescr) archived=(epgEvent ? epgEvent->Archived() : "") archiveId=(recItem->ArchiveId()) &> + <& rec_item_file name=(recItem->Name()) level=(level) id=(recItem->Id()) day=(day) dayLen=(dayLen) startTime=(recItem->StartTime()) hint=(hint) shortDescr=(epgEvent ? epgEvent->ShortDescr() : "") archived=(epgEvent ? epgEvent->Archived() : "") archiveId=(recItem->ArchiveId()) &>
  • <%cpp> } @@ -177,6 +177,7 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) { string day; string dayLen; time_t startTime; + string hint; string shortDescr; string archived; string archiveId; @@ -187,8 +188,7 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) {
    <$ day $>
    <$ FormatDateTime(tr("%b %d %y"), startTime) $>
    <$ FormatDateTime(tr("%I:%M %p"), startTime) $>
    -
    <& tooltip.display domId=(id) &>><$ name $>
    - <%cpp> if (! archived.empty()) {
    <$ archived $>
    <%cpp> } +
    <& tooltip.display domId=(id) &>><$ name $>
    <%cpp>if ((name != shortDescr) && (!shortDescr.empty())) {<$ shortDescr $><%cpp> } else {  <%cpp> }
    <%cpp> @@ -206,5 +206,12 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) {
    +<%cpp> + if (! archived.empty()) { + +
    <$ archived $>
    +<%cpp> + } +
    diff --git a/pages/rwd_recording.ecpp b/pages/rwd_recording.ecpp new file mode 100644 index 0000000..a0ce569 --- /dev/null +++ b/pages/rwd_recording.ecpp @@ -0,0 +1,26 @@ +<%pre> +#include +#include +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + + +<%args> + string param; + +<%session scope="global"> + bool logged_in(false); + +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + BackwardRecordingTask task( param ); + LiveTaskManager().Execute( task ); + +<& xmlresponse.ajax name=("rwd_recording") pname=("recording") value=(param) result=(task.Result()) error=(task.Error()) &> diff --git a/pages/stop_recording.ecpp b/pages/stop_recording.ecpp new file mode 100644 index 0000000..869beb0 --- /dev/null +++ b/pages/stop_recording.ecpp @@ -0,0 +1,26 @@ +<%pre> +#include +#include +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + + +<%args> + string param; + +<%session scope="global"> + bool logged_in(false); + +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + StopRecordingTask task( param ); + LiveTaskManager().Execute( task ); + +<& xmlresponse.ajax name=("stop_recording") pname=("recording") value=(param) result=(task.Result()) error=(task.Error()) &> diff --git a/pages/switch_channel.ecpp b/pages/switch_channel.ecpp index 91f4f30..0031f4e 100644 --- a/pages/switch_channel.ecpp +++ b/pages/switch_channel.ecpp @@ -16,11 +16,4 @@ using namespace vdrlive; SwitchChannelTask task( param ); LiveTaskManager().Execute( task ); - - - -<$ param $> - -<$ task.Result() $> -<$ task.Error() $> - +<& xmlresponse.ajax name=("switch_channel") pname=("channel") value=(param) result=(task.Result()) error=(task.Error()) &> diff --git a/pages/xmlresponse.ecpp b/pages/xmlresponse.ecpp new file mode 100644 index 0000000..1123368 --- /dev/null +++ b/pages/xmlresponse.ecpp @@ -0,0 +1,62 @@ +<%pre> +#include + +using namespace std; + + +<# ------------------------------------------------------------------------- #> + +<%def ajax> +<%args> + string name; + string pname; + string value; + bool result; + string error; + + + + + <$ value $> + + <$ result $> + <$ error $> + + + +<# ------------------------------------------------------------------------- #> + +<%def ibox> +<%args> + int update; + string type; + string currentTime; + string caption; + string title; + string duration; + int elapsed; + string prev_chan; + string next_chan; + + + + + <$ update $> + + 1 + + + <$ update $> + + <$ type $> + <$ caption $> + <$ currentTime $> + <$ title $> + <$ duration $> + <$ elapsed $> + <$ next_chan $> + <$ prev_chan $> + + + + diff --git a/tasks.cpp b/tasks.cpp index 0faa76f..6e1bd07 100644 --- a/tasks.cpp +++ b/tasks.cpp @@ -24,7 +24,7 @@ StickyTask::~StickyTask() LiveTaskManager().RemoveStickyTask( *this ); } -void SwitchChannelTask::Action() +void SwitchChannelTask::Action() { ReadLock lock( Channels ); cChannel* channel = Channels.GetByChannelID( m_channel ); @@ -37,7 +37,7 @@ void SwitchChannelTask::Action() SetError( tr("Couldn't switch to channel.") ); } -void ReplayRecordingTask::Action() +void PlayRecordingTask::Action() { RecordingsManagerPtr recordings = LiveRecordingsManager(); cRecording const* recording = recordings->GetByMd5Hash( m_recording ); @@ -46,23 +46,144 @@ void ReplayRecordingTask::Action() return; } + const char *current = cReplayControl::NowReplaying(); + if (!current || (0 != strcmp(current, recording->FileName()))) { + cReplayControl::SetRecording( 0, 0 ); + cControl::Shutdown(); + cReplayControl::SetRecording( recording->FileName(), recording->Title() ); + cControl::Launch( new cReplayControl ); + cControl::Attach(); + } + else { + cReplayControl* replayControl = reinterpret_cast(cControl::Control()); + if (! replayControl) { + SetError(tr("Cannot control playback!")); + return; + } + + replayControl->Play(); + } +} + +void PauseRecordingTask::Action() +{ + RecordingsManagerPtr recordings = LiveRecordingsManager(); + cRecording const* recording = recordings->GetByMd5Hash( m_recording ); + if ( recording == 0 ) { + SetError( tr("Couldn't find recording or no recordings available.") ); + return; + } + + const char *current = cReplayControl::NowReplaying(); + if (!current) { + SetError(tr("Not playing a recording.")); + return; + } + + if (0 != strcmp(current, recording->FileName())) { + // not replaying same recording like in request + SetError(tr("Not playing the same recording as from request.")); + return; + } + + cReplayControl* replayControl = reinterpret_cast(cControl::Control()); + if (! replayControl) { + SetError(tr("Cannot control playback!")); + return; + } + + replayControl->Pause(); +} + +void StopRecordingTask::Action() +{ + RecordingsManagerPtr recordings = LiveRecordingsManager(); + cRecording const* recording = recordings->GetByMd5Hash( m_recording ); + if ( recording == 0 ) { + SetError( tr("Couldn't find recording or no recordings available.") ); + return; + } + + const char *current = cReplayControl::NowReplaying(); + if (!current) { + SetError(tr("Not playing a recording.")); + return; + } + cReplayControl::SetRecording( 0, 0 ); cControl::Shutdown(); - cReplayControl::SetRecording( recording->FileName(), recording->Title() ); - cControl::Launch( new cReplayControl ); - cControl::Attach(); +} + +void ForwardRecordingTask::Action() +{ + RecordingsManagerPtr recordings = LiveRecordingsManager(); + cRecording const* recording = recordings->GetByMd5Hash( m_recording ); + if ( recording == 0 ) { + SetError( tr("Couldn't find recording or no recordings available.") ); + return; + } + + const char *current = cReplayControl::NowReplaying(); + if (!current) { + SetError(tr("Not playing a recording.")); + return; + } + + if (0 != strcmp(current, recording->FileName())) { + // not replaying same recording like in request + SetError(tr("Not playing the same recording as from request.")); + return; + } + + cReplayControl* replayControl = reinterpret_cast(cControl::Control()); + if (! replayControl) { + SetError(tr("Cannot control playback!")); + return; + } + + replayControl->Forward(); +} + +void BackwardRecordingTask::Action() +{ + RecordingsManagerPtr recordings = LiveRecordingsManager(); + cRecording const* recording = recordings->GetByMd5Hash( m_recording ); + if ( recording == 0 ) { + SetError( tr("Couldn't find recording or no recordings available.") ); + return; + } + + const char *current = cReplayControl::NowReplaying(); + if (!current) { + SetError(tr("Not playing a recording.")); + return; + } + + if (0 != strcmp(current, recording->FileName())) { + // not replaying same recording like in request + SetError(tr("Not playing the same recording as from request.")); + return; + } + + cReplayControl* replayControl = reinterpret_cast(cControl::Control()); + if (! replayControl) { + SetError(tr("Cannot control playback!")); + return; + } + + replayControl->Backward(); } TaskManager::TaskManager() { } -void TaskManager::AddStickyTask( Task& task ) -{ +void TaskManager::AddStickyTask( Task& task ) +{ cMutexLock lock( this ); - m_stickyTasks.push_back( &task ); + m_stickyTasks.push_back( &task ); } - + void TaskManager::RemoveStickyTask( Task& task ) { cMutexLock lock( this ); diff --git a/tasks.h b/tasks.h index 841ee43..2a269fd 100644 --- a/tasks.h +++ b/tasks.h @@ -72,21 +72,70 @@ class SwitchChannelTask: public Task { public: explicit SwitchChannelTask( tChannelID channel ): m_channel( channel ) {} - + private: tChannelID m_channel; virtual void Action(); }; -class ReplayRecordingTask: public Task +class RecordingTask: public Task { -public: - explicit ReplayRecordingTask( std::string const& recording ): m_recording( recording ) {} +protected: + explicit RecordingTask(std::string const& recording) + : m_recording(recording) + {} -private: std::string m_recording; - +}; + +class PlayRecordingTask: public RecordingTask +{ +public: + explicit PlayRecordingTask( std::string const& recording ) + : RecordingTask(recording) + {} + + virtual void Action(); +}; + +class PauseRecordingTask: public RecordingTask +{ +public: + explicit PauseRecordingTask( std::string const& recording ) + : RecordingTask(recording) + {} + + virtual void Action(); +}; + +class StopRecordingTask: public RecordingTask +{ +public: + explicit StopRecordingTask( std::string const& recording ) + : RecordingTask(recording) + {} + + virtual void Action(); +}; + +class ForwardRecordingTask: public RecordingTask +{ +public: + explicit ForwardRecordingTask( std::string const& recording ) + : RecordingTask(recording) + {} + + virtual void Action(); +}; + +class BackwardRecordingTask: public RecordingTask +{ +public: + explicit BackwardRecordingTask( std::string const& recording ) + : RecordingTask(recording) + {} + virtual void Action(); }; diff --git a/tntconfig.cpp b/tntconfig.cpp index 1ca52ec..f047399 100644 --- a/tntconfig.cpp +++ b/tntconfig.cpp @@ -25,7 +25,7 @@ void TntConfig::WriteConfig() ostringstream builder; builder << Plugin::GetConfigDirectory() << "/httpd.config"; m_configPath = builder.str(); - + ofstream file( m_configPath.c_str(), ios::out | ios::trunc ); if ( !file ) { ostringstream builder; @@ -51,7 +51,7 @@ void TntConfig::WriteProperties() ostringstream builder; builder << Plugin::GetConfigDirectory() << "/httpd.properties"; m_propertiesPath = builder.str(); - + ofstream file( m_propertiesPath.c_str(), ios::out | ios::trunc ); if ( !file ) { ostringstream builder; -- cgit v1.2.3