diff options
author | Dieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de> | 2007-05-08 22:59:40 +0000 |
---|---|---|
committer | Dieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de> | 2007-05-08 22:59:40 +0000 |
commit | 70f268b6fff0037cbff265cf849663755223ffed (patch) | |
tree | 26806a8fa7fe319be310ba12266c80e2b2fee34a | |
parent | 805c2d6fec9d9b88d9d3d6e4cd8dcac33d062533 (diff) | |
download | vdr-plugin-live-70f268b6fff0037cbff265cf849663755223ffed.tar.gz vdr-plugin-live-70f268b6fff0037cbff265cf849663755223ffed.tar.bz2 |
- 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
-rw-r--r-- | css/styles.css | 38 | ||||
-rw-r--r-- | i18n.cpp | 132 | ||||
-rw-r--r-- | images/Makefile | 9 | ||||
-rw-r--r-- | images/ffw.png | bin | 0 -> 852 bytes | |||
-rw-r--r-- | images/pause.png | bin | 0 -> 748 bytes | |||
-rw-r--r-- | images/rwd.png | bin | 0 -> 863 bytes | |||
-rw-r--r-- | images/stop.png | bin | 748 -> 713 bytes | |||
-rw-r--r-- | images/stop_update.png | bin | 0 -> 748 bytes | |||
-rw-r--r-- | javascript/vdr_status.js | 37 | ||||
-rw-r--r-- | pages/Makefile | 6 | ||||
-rw-r--r-- | pages/ffw_recording.ecpp | 26 | ||||
-rw-r--r-- | pages/ibox.ecpp | 65 | ||||
-rw-r--r-- | pages/menu.ecpp | 4 | ||||
-rw-r--r-- | pages/pageelems.ecpp | 20 | ||||
-rw-r--r-- | pages/pause_recording.ecpp | 26 | ||||
-rw-r--r-- | pages/play_recording.ecpp | 13 | ||||
-rw-r--r-- | pages/recordings.ecpp | 15 | ||||
-rw-r--r-- | pages/rwd_recording.ecpp | 26 | ||||
-rw-r--r-- | pages/stop_recording.ecpp | 26 | ||||
-rw-r--r-- | pages/switch_channel.ecpp | 9 | ||||
-rw-r--r-- | pages/xmlresponse.ecpp | 62 | ||||
-rw-r--r-- | tasks.cpp | 139 | ||||
-rw-r--r-- | tasks.h | 61 | ||||
-rw-r--r-- | tntconfig.cpp | 4 |
24 files changed, 613 insertions, 105 deletions
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 { @@ -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 Binary files differnew file mode 100644 index 0000000..aeec194 --- /dev/null +++ b/images/ffw.png diff --git a/images/pause.png b/images/pause.png Binary files differnew file mode 100644 index 0000000..1b44908 --- /dev/null +++ b/images/pause.png diff --git a/images/rwd.png b/images/rwd.png Binary files differnew file mode 100644 index 0000000..54ec330 --- /dev/null +++ b/images/rwd.png diff --git a/images/stop.png b/images/stop.png Binary files differindex 4ffdef7..bb79efb 100644 --- a/images/stop.png +++ b/images/stop.png diff --git a/images/stop_update.png b/images/stop_update.png Binary files differnew file mode 100644 index 0000000..4ffdef7 --- /dev/null +++ b/images/stop_update.png 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 <string> +#include <vdr/recording.h> +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + +</%pre> +<%args> + string param; +</%args> +<%session scope="global"> + bool logged_in(false); +</%session> +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + ForwardRecordingTask task( param ); + LiveTaskManager().Execute( task ); +</%cpp> +<& 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()) { </%cpp> -<& 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()) { </%cpp> -<& 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()) { </%cpp> -<& 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 { </%cpp> -<& 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; } </%cpp> -<%def xmlresponse> -<%args> - int update; - string type; - string currentTime; - string caption; - string title; - string duration; - int elapsed; - string prev_chan; - string next_chan; -</%args> -<?xml version="1.0" encoding="ISO-8859-1"?> -<service> - <request name="ibox"> - <param name="update"><$ update $></param> - </request> - <response>1</response> - <error></error> - <values> - <update><$ update $></update> - <epginfo> - <type><$ type $></type> - <caption><$ caption $></caption> - <timenow><$ currentTime $></timenow> - <name><$ title $></name> - <duration><$ duration $></duration> - <elapsed><$ elapsed $></elapsed> - <nextchan><$ next_chan $></nextchan> - <prevchan><$ prev_chan $></prevchan> - </epginfo> - </values> -</service> -</%def> 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"); % } <a href="recordings.html" <& menu.setactive current=("recordings") &>><$ tr("Recordings") $></a> | <a href="remote.html" <& menu.setactive current=("remote") &>><$ tr("Remote Control") $></a> -<!-- Used by D.H. to test infobox (not part of the released version) +<# --- Used by D.H. to test infobox (not part of the released version) | <a href="ibox_status.html" <& menu.setactive current=("status") &>><$ tr("Status Test") $></a> ---> +--- #> % if (LiveSetup().UseAuth()) { | <a id="login" href="login.html?action=logout"><$ tr("Logout") $></a> % } 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; <div id="infobox_duration" class="duration">--:--</div> </div> <div class="st_controls"> - <div class="st_btns"> - <a href="javascript:LiveStatusToggleUpdate()" <& tooltip.hint text=(tr("Stop updates")) &>><img id="statusReloadBtn" src="stop.png" alt="" /></a> - <span id="infobox_recording_buttons" style="display: none"></span> - <span id="infobox_channel_buttons"> - <& 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")) &> - </span> + <div class="st_update"> + <a href="javascript:LiveStatusToggleUpdate()" <& tooltip.hint text=(tr("Stop updates")) &>><img id="statusReloadBtn" src="stop_update.png" alt="" /></a> + </div> + <div id="infobox_recording_buttons" style="display: none"> + <& ajax_action_href action=("stop_recording") id=("infobox_stop") image=("stop.png") tip=(tr("stop playback")) &> + <& ajax_action_href action=("play_recording") id=("infobox_play") image=("play.png") tip=(tr("resume playback")) &> + <& ajax_action_href action=("pause_recording") id=("infobox_pause") image=("pause.png") tip=(tr("pause playback")) &> + <& ajax_action_href action=("rwd_recording") id=("infobox_rwd") image=("rwd.png") tip=(tr("fast forward")) &> + <& ajax_action_href action=("ffw_recording") id=("infobox_ffw") image=("ffw.png") tip=(tr("fast rewind")) &> + </div> + <div id="infobox_channel_buttons"> + <& 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")) &> </div> <div class="st_pbar"> <& 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 <string> +#include <vdr/recording.h> +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + +</%pre> +<%args> + string param; +</%args> +<%session scope="global"> + bool logged_in(false); +</%session> +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + PauseRecordingTask task( param ); + LiveTaskManager().Execute( task ); +</%cpp> +<& 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; </%args> <%session scope="global"> -bool logged_in(false); + bool logged_in(false); </%session> <%cpp> if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); reply.setContentType( "application/xml" ); - ReplayRecordingTask task( param ); + PlayRecordingTask task( param ); LiveTaskManager().Execute( task ); </%cpp> -<?xml version="1.0"?> -<service> -<request name="play_recording"> -<param name="recording"><$ param $></param> -</request> -<response><$ task.Result() $></response> -<error><$ task.Error() $></error> -</service> +<& 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<string, int>(day.length() - 1) + ".25em;"); - string shortDescr(tr("Click to view details.")); if (epgEvent && !epgEvent->ShortDescr().empty()) shortDescr = (epgEvent->ShortDescr() + string("<br />") + shortDescr); + string hint(tr("Click to view details.")); if (epgEvent && !epgEvent->ShortDescr().empty()) hint = (epgEvent->ShortDescr() + "<br />" + hint); </%cpp> <li class="recording"> - <& 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()) &> </li> <%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) { <div class="recording_day" style="width: <$ dayLen $>"><$ day $></div> <div class="recording_date"><$ FormatDateTime(tr("%b %d %y"), startTime) $></div> <div class="recording_time"><$ FormatDateTime(tr("%I:%M %p"), startTime) $></div> - <div class="recording_name" <& tooltip.hint text=(shortDescr) &><& tooltip.display domId=(id) &>><$ name $></div> - <%cpp> if (! archived.empty()) { </%cpp><div><$ archived $></div><%cpp> } </%cpp> + <div class="recording_name" <& tooltip.hint text=(hint) &><& tooltip.display domId=(id) &>><$ name $><br /><%cpp>if ((name != shortDescr) && (!shortDescr.empty())) {</%cpp><span><$ shortDescr $></span><%cpp> } else { </%cpp><span> </span><%cpp> } </%cpp></div> </div> <div class="recording_actions"> <%cpp> @@ -206,5 +206,12 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) { <img src="edit.png" alt="" /> <img src="del.png" alt="" /> </div> +<%cpp> + if (! archived.empty()) { +</%cpp> + <div class="recording_arch"><$ archived $></div> +<%cpp> + } +</%cpp> </div> </%def> 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 <string> +#include <vdr/recording.h> +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + +</%pre> +<%args> + string param; +</%args> +<%session scope="global"> + bool logged_in(false); +</%session> +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + BackwardRecordingTask task( param ); + LiveTaskManager().Execute( task ); +</%cpp> +<& 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 <string> +#include <vdr/recording.h> +#include "exception.h" +#include "setup.h" +#include "tasks.h" +#include "tools.h" + +using namespace std; +using namespace vdrlive; + +</%pre> +<%args> + string param; +</%args> +<%session scope="global"> + bool logged_in(false); +</%session> +<%cpp> + if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); + reply.setContentType( "application/xml" ); + + StopRecordingTask task( param ); + LiveTaskManager().Execute( task ); +</%cpp> +<& 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 ); </%cpp> -<?xml version="1.0"?> -<service> -<request name="switch_channel"> -<param name="channel"><$ param $></param> -</request> -<response><$ task.Result() $></response> -<error><$ task.Error() $></error> -</service> +<& 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 <string> + +using namespace std; +</%pre> + +<# ------------------------------------------------------------------------- #> + +<%def ajax> +<%args> + string name; + string pname; + string value; + bool result; + string error; +</%args> +<?xml version="1.0" encoding="ISO-8859-1"?> +<service> + <request name="<$ name $>"> + <param name="<$ pname $>"><$ value $></param> + </request> + <response><$ result $></response> + <error><$ error $></error> +</service> +</%def> + +<# ------------------------------------------------------------------------- #> + +<%def ibox> +<%args> + int update; + string type; + string currentTime; + string caption; + string title; + string duration; + int elapsed; + string prev_chan; + string next_chan; +</%args> +<?xml version="1.0" encoding="ISO-8859-1"?> +<service> + <request name="ibox"> + <param name="update"><$ update $></param> + </request> + <response>1</response> + <error></error> + <values> + <update><$ update $></update> + <epginfo> + <type><$ type $></type> + <caption><$ caption $></caption> + <timenow><$ currentTime $></timenow> + <name><$ title $></name> + <duration><$ duration $></duration> + <elapsed><$ elapsed $></elapsed> + <nextchan><$ next_chan $></nextchan> + <prevchan><$ prev_chan $></prevchan> + </epginfo> + </values> +</service> +</%def> @@ -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<cReplayControl*>(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<cReplayControl*>(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<cReplayControl*>(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<cReplayControl*>(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 ); @@ -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; |