summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de>2007-05-08 22:59:40 +0000
committerDieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de>2007-05-08 22:59:40 +0000
commit70f268b6fff0037cbff265cf849663755223ffed (patch)
tree26806a8fa7fe319be310ba12266c80e2b2fee34a
parent805c2d6fec9d9b88d9d3d6e4cd8dcac33d062533 (diff)
downloadvdr-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.css38
-rw-r--r--i18n.cpp132
-rw-r--r--images/Makefile9
-rw-r--r--images/ffw.pngbin0 -> 852 bytes
-rw-r--r--images/pause.pngbin0 -> 748 bytes
-rw-r--r--images/rwd.pngbin0 -> 863 bytes
-rw-r--r--images/stop.pngbin748 -> 713 bytes
-rw-r--r--images/stop_update.pngbin0 -> 748 bytes
-rw-r--r--javascript/vdr_status.js37
-rw-r--r--pages/Makefile6
-rw-r--r--pages/ffw_recording.ecpp26
-rw-r--r--pages/ibox.ecpp65
-rw-r--r--pages/menu.ecpp4
-rw-r--r--pages/pageelems.ecpp20
-rw-r--r--pages/pause_recording.ecpp26
-rw-r--r--pages/play_recording.ecpp13
-rw-r--r--pages/recordings.ecpp15
-rw-r--r--pages/rwd_recording.ecpp26
-rw-r--r--pages/stop_recording.ecpp26
-rw-r--r--pages/switch_channel.ecpp9
-rw-r--r--pages/xmlresponse.ecpp62
-rw-r--r--tasks.cpp139
-rw-r--r--tasks.h61
-rw-r--r--tntconfig.cpp4
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 {
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
--- /dev/null
+++ b/images/ffw.png
Binary files differ
diff --git a/images/pause.png b/images/pause.png
new file mode 100644
index 0000000..1b44908
--- /dev/null
+++ b/images/pause.png
Binary files differ
diff --git a/images/rwd.png b/images/rwd.png
new file mode 100644
index 0000000..54ec330
--- /dev/null
+++ b/images/rwd.png
Binary files differ
diff --git a/images/stop.png b/images/stop.png
index 4ffdef7..bb79efb 100644
--- a/images/stop.png
+++ b/images/stop.png
Binary files differ
diff --git a/images/stop_update.png b/images/stop_update.png
new file mode 100644
index 0000000..4ffdef7
--- /dev/null
+++ b/images/stop_update.png
Binary files 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 <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>&nbsp;</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>
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<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 );
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;