diff --git a/API.html b/API.html
index 5eca67a..e21654f 100644
--- a/API.html
+++ b/API.html
@@ -32,7 +32,7 @@
RESTFULAPI-Plugin for VDR
-
Version 0.1.1
+
Version 0.1.3
Copyright © 2011 yavdr-Team, Michael Eiler
Organization/Community:
team@yavdr.org
Developer:
eiler.mike@gmail.com or
aelo@yavdr.org
@@ -47,6 +47,7 @@
Table Of Contents
Preface
Requirements
Configuration
+Audio
Channels
@@ -57,8 +58,11 @@ Table Of Contents
Osd
Recordings
+ Move
+ Play
+ Rewind
Remote
Timers
- Reading/Deleting Timers
@@ -138,6 +142,66 @@
+
+
+
+
+
+This service retrieves audio commands, sends them to VDR and returns the result:
+
+Methods: POST, GET (for simple requests)
+
+Syntax:
+
+
+GET http://127.0.0.1:8002/audio.<format>
+POST http://<ip>:<port>/audio.<format>
+
+
+Description of the Body Parameters (POST only):
+
+
+
+- <format> - The requested format: json, xml or html.
+
- <volume>
+
+- volume=180 // 180 absolute
+
- volume=020 // +20
+
- volume=-20 // -20
+
+ - <mute> - 0 (mute), 1 (unmute) or 2(toggle).
+
- <track> - track number.
+
- <channel> - 0 (mono left), 1 (mono right) or 2(stereo).
+
+
+
+
+
+Example Result:
+
+
+
+GET http://127.0.0.1:8002/audio.xml
+POST http://127.0.0.1:8002/audio.xml
+volume=230&track=33
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<audio xmlns="http://www.domain.org/restfulapi/2011/channels-xml">
+ <volume>230</volume>
+ <mute>0</mute>
+ <tracks count="3">
+ <track type="1" description="französisch"/>
+ <track type="2" description="ohne Audiodeskription"/>
+ <track type="33" description="Dolby Digital 5.1"/>
+ </tracks>
+ <type>33</type>
+ <description>Dolby Digital 5.1</description>
+ <channel>dd 5.1</channel>
+</audio>
+
+
+
+
+
@@ -461,46 +525,79 @@
GET http://<ip>:<port>/info.<format>
+
+Description of the Parameters:
+
+
+
+- <format> - The requested format: json, xml or html.
+
+
Example Results:
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<info xmlns="http://www.domain.org/restfulapi/2011/info-xml">
- <version>0.0.1</version>
- <time>1311710291</time>
- <services>
- <service path="/info" version="1" internal="true" />
- <service path="/channels" version="1" internal="true" />
- <service path="/channels/groups" version="1" internal="true" />
- <service path="/channels/image" version="1" internal="true" />
- <service path="/events" version="1" internal="true" />
- <service path="/events/image" version="1" internal="true" />
- <service path="/events/search" version="1" internal="false" />
- <service path="/recordings" version="1" internal="true" />
- <service path="/remote" version="1" internal="true" />
- <service path="/timers" version="1" internal="true" />
- <service path="/osd" version="1" internal="true" />
- <service path="/searchtimers" version="1" internal="false" />
- </services>
- <channel>C-71-71-61920</channel>
- <vdr>
- <plugins>
- <plugin name="restfulapi" version="0.0.1" />
- <plugin name="shutdown" version="0.0.2" />
- <plugin name="vnsiserver" version="0.9.0" />
- <plugin name="live" version="0.2.0" />
- <plugin name="epgsearchonly" version="0.0.1" />
- <plugin name="svdrposd" version="0.1.0" />
- <plugin name="xineliboutput" version="1.0.90-cvs" />
- <plugin name="streamdev-server" version="0.5.1-git" />
- <plugin name="epgsearch" version="0.9.25.beta22" />
- <plugin name="quickepgsearch" version="0.0.1" />
- <plugin name="text2skin" version="1.3.1" />
- <plugin name="conflictcheckonly" version="0.0.1" />
- </plugins>
- </vdr>
-</info>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<info xmlns="http://www.domain.org/restfulapi/2011/info-xml">
+ <version>0.0.1</version>
+ <time>1372855585</time>
+ <services>
+ <service path="/audio" version="1" internal="true" />
+ <service path="/channels" version="1" internal="true" />
+ <service path="/channels/groups" version="1" internal="true" />
+ <service path="/channels/image" version="1" internal="true" />
+ <service path="/events" version="1" internal="true" />
+ <service path="/events/image" version="1" internal="true" />
+ <service path="/events/search" version="1" internal="false" />
+ <service path="/info" version="1" internal="true" />
+ <service path="/osd" version="1" internal="true" />
+ <service path="/recordings" version="1" internal="true" />
+ <service path="/recordings/cut" version="1" internal="true" />
+ <service path="/recordings/marks" version="1" internal="true" />
+ <service path="/recordings/play" version="1" internal="true" />
+ <service path="/recordings/rewind" version="1" internal="true" />
+ <service path="/remote" version="1" internal="true" />
+ <service path="/searchtimers" version="1" internal="false" />
+ <service path="/timers" version="1" internal="true" />
+ </services>
+ <channel>S19.2E-1-1019-10302</channel>
+ <channel_name>arte HD</channel_name>
+ <channel_number>4</channel_number>
+ <eventid>64734</eventid>
+ <start_time>1372853100</start_time>
+ <duration>5700</duration>
+ <title>Die schönsten Augen von Portugal</title>
+ <recording>false</recording>
+ <diskspace>1405401MB 156536MB 88%</diskspace>
+ <vdr>
+ <version>2.0.2</version>
+ <plugins>
+ <plugin name="softhddevice" version="0.6.0" />
+ <plugin name="dbus2vdr" version="12e" />
+ <plugin name="skinnopacity" version="0.1.2" />
+ <plugin name="play" version="0.0.14" />
+ <plugin name="menuorg" version="0.5.1" />
+ <plugin name="channellists" version="0.0.5" />
+ <plugin name="markad" version="0.1.5pre" />
+ <plugin name="tvguide" version="0.0.5" />
+ <plugin name="music" version="0.9.9-dev2" />
+ <plugin name="epgsearch" version="1.0.1.beta5" />
+ <plugin name="yaepghd" version="0.0.5_pre1" />
+ <plugin name="extrecmenu" version="1.2.2" />
+ <plugin name="streamdev-server" version="0.6.0-git" />
+ <plugin name="cinebars" version="0.1.0" />
+ <plugin name="conflictcheckonly" version="0.0.1" />
+ <plugin name="live" version="0.3.0" />
+ <plugin name="osdserver" version="0.1.3" />
+ <plugin name="quickepgsearch" version="0.0.1" />
+ <plugin name="restfulapi" version="0.1.2" />
+ <plugin name="sleeptimer" version="0.8.3-201205011650dev" />
+ <plugin name="vnsiserver3" version="0.9.1" />
+ <plugin name="femon" version="2.0.0" />
+ <plugin name="epgsearchonly" version="0.0.1" />
+ </plugins>
+ </vdr>
+</info>
Instead of the channel it can also contain the currently playing video file:
@@ -603,7 +700,7 @@
-GET http://127.0.0.1:8002/recordings.json?start=0&limit=1i&marks=true
+GET http://127.0.0.1:8002/recordings.json?start=0&limit=1&marks=true
{"recordings":[{
"number":0,
@@ -639,6 +736,31 @@
+
+
+
+This service can delete recordings by filename.
+
+Method: POST and DELETE
+
+Examples:
+
+
+POST http://<ip>:<port>/recordings/delete
+DELETE http://<ip>:<port>/recordings/delete
+
+
+Required Body Parameters:
+
+
+- file - source path of the recording (use an url-encoder for this text if you use special characters)
+
+
+
+file=/var/lib/video.00/Asterix_in_Amerika/2011-06-19.12.40.1-0.rec
+
+
+
@@ -680,19 +802,46 @@
{'marks':['0:02:18.10','0:34:08.24']}
+
+
+
+
+This service can move or copy recordings by filename.
+
+Method: POST
+
+Examples:
+
+
+POST http://<ip>:<port>/recordings/delete
+
+
+Required Body Parameters:
+
+- source - source path of the recording (use an url-encoder for this text if you use special characters)
+
- target - relative path of the recording.
+
+
+
+source=/var/lib/video.00/Asterix_in_Amerika/2011-06-19.12.40.1-0.rec
+target=Movies/Asterix_in_Amerika
+copy_only=false
+
+
+
+
-This service tells your VDR to play or rewind a recording:
+This service tells your VDR to play a recording:
-Method: GET, POST
+Method: POST
Examples:
-GET http://<ip>:<port>/recordings/play/<number>
POST http://<ip>:<port>/recordings/play/<number>
@@ -701,7 +850,28 @@
-- <number> - The number of the recording you want to play (GET).
+
- <number> - The number of the recording you want to play (POST).
+
+
+
+
+
+
+This service tells your VDR to play a recording from the beginning:
+
+Method: POST
+
+Examples:
+
+
+POST http://<ip>:<port>/recordings/rewind/<number>
+
+
+
+Description of the Parameters:
+
+
+
- <number> - The number of the recording you want to rewind (POST).
diff --git a/HISTORY b/HISTORY
index e344851..a0c3125 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,5 +1,8 @@
VDR Plugin 'restfulapi' Revision History
----------------------------------------
+2013-07-03: Version 0.1.3
+
+- New revision.
2011-05-16: Version 0.0.1
diff --git a/Makefile b/Makefile
index 07eb6e6..d672423 100644
--- a/Makefile
+++ b/Makefile
@@ -57,7 +57,7 @@ PLGCONFDIR = $(CONFDIR)/plugins/$(PLUGIN)
### The object files (add further files here):
-OBJS = $(PLUGIN).o serverthread.o tools.o info.o channels.o events.o recordings.o remote.o timers.o statusmonitor.o osd.o jsonparser.o epgsearch.o searchtimers.o
+OBJS = $(PLUGIN).o serverthread.o tools.o info.o channels.o events.o recordings.o remote.o timers.o statusmonitor.o osd.o jsonparser.o epgsearch.o searchtimers.o audio.o
CFGS = API.html
### The main target:
diff --git a/Makefile-1.7.33pre b/Makefile-1.7.33pre
index 7b65d69..d78841f 100644
--- a/Makefile-1.7.33pre
+++ b/Makefile-1.7.33pre
@@ -57,7 +57,7 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
-OBJS = $(PLUGIN).o serverthread.o tools.o info.o channels.o events.o recordings.o remote.o timers.o statusmonitor.o osd.o jsonparser.o epgsearch.o searchtimers.o
+OBJS = $(PLUGIN).o serverthread.o tools.o info.o channels.o events.o recordings.o remote.o timers.o statusmonitor.o osd.o jsonparser.o epgsearch.o searchtimers.o audio.o
### The main target:
diff --git a/README b/README
index d64c6e9..eb7e325 100644
--- a/README
+++ b/README
@@ -1,22 +1,39 @@
-yaVDR - vdr-plugin-restfulapi
+vdr-plugin-restfulapi
---------------------------------------
-"yet another VDR" (yaVDR) is a Linux distribution focussed on Klaus Schmidingers Video Disk Recorder and based on Ubuntu.
+A plugin for Klaus Schmidingers Video Disk Recorder.
-yaVDR tries to let you:
- * Watch and record TV easily and enjoy your media in a smart way: Quickly set up a digital video recorder (PVR) on your HTPC, receive SD and HD channels, manage it simply with a remote control. Furthermore, take advantage of the full blown media center software XBMC to listen to music, watch videos, check the weather.
+Preface:
+---------
+This plugin has been developed to offer a modern API for other developers to communicate with the VDR.
+The plugin supports the following outputs formats: xml, json and html.
+It also supports the folloing input formats: json and html.
- * Enjoy High Definition without high CPU load: HDTV normally needs a strong CPU to be displayed flawlessly. If you own a Nvidia ION based nettop or a HTPC with a Nvidia GPU that supports VDPAU, your CPU will remain cool and your energy bill won't hurt you. yaVDR relies on VDPAU which is currently the only simple way to get GPU based HD video decoding on Linux.
+For a detailed API description, see API.html
- * Start immediately after turning on the HTPC: yaVDR wants to compete with other living room devices as much as possible using upstart to speed up the boot. Besides that, the shutdown method S3 (Suspend to RAM) is enabled by default to bypass cold boot. It is possible to let the system automatically wake up on timers and go to sleep after a configurable timeout.
+Someone who wants to install the plugin on his/her VDR needs following applications and libraries:
-Links:
+ VDR >= 1.7.18
+ libcxxtools Rev. >= 1231, which is available as package for Ubuntu in the yavdr-PPA's
-Installation: http://www.yavdr.org/installation/
-Configuration: http://www.yavdr.org/configuration/
-Features: http://www.yavdr.org/features/
-Issue tracker: https://bugs.yavdr.com/projects/yavdr/issues/new
-Package source: https://github.com/yavdr/vdr-plugin-restfulapi
-Team members: http://www.yavdr.org/developer-zone/team-members/
+ The plugin can be installed like any other standard plugin (unpack, soft link, make plugins).
+ For Ubuntu it is available as package in the yavdr-PPA's
+
+Someone who wants to develop an application which uses this API:
+
+ XML or JSON Parser (Depends on which format you want to use! - You can also use the html-format, but that one is more a proof for the restful concept and does not show all information!)
+ URL Decoder or JSON Serializer (to send data to the webservice, required f.e. to create timers, searchtimers usw...)
+
+Configuration:
+---------------
+With yaVDR create a new file called plugin.restfulapi.conf in /etc/vdr/plugins/ .
+### Command line parameters for vdr-plugin-restfulapi
+--port=8002 --ip=0.0.0.0 --epgimages=/var/cache/vdr/epgimages --channellogos=/usr/share/vdr/channel-logos
+
+
+Links:
+-------
+Issue tracker: https://bugs.yavdr.com/projects/vdr-restfulapi/
+Package source: https://github.com/yavdr/vdr-plugin-restfulapi
diff --git a/audio.cpp b/audio.cpp
new file mode 100644
index 0000000..74cff3a
--- /dev/null
+++ b/audio.cpp
@@ -0,0 +1,257 @@
+#include "audio.h"
+using namespace std;
+
+void AudioResponder::reply(ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
+{
+ QueryHandler::addHeader(reply);
+ QueryHandler q("/audio", request);
+
+ if (request.method() == "POST") {
+ string vol = q.getBodyAsString("volume");
+ int level = q.getBodyAsInt("volume");
+ int mute = q.getBodyAsInt("mute");
+ int track = q.getBodyAsInt("track");
+ int channel = q.getBodyAsInt("channel");
+
+ if (vol.find("m") == 0) {
+ cDevice::PrimaryDevice()->ToggleMute();
+ mute = -1;
+ } else if (vol.find("0") == 0) {
+ cDevice::PrimaryDevice()->SetVolume(level, false);
+ } else if (vol.find("-") == 0) {
+ cDevice::PrimaryDevice()->SetVolume(level, false);
+ } else if ( level >= 0 && level <= 255 ) {
+ cDevice::PrimaryDevice()->SetVolume(level, true);
+ }
+
+ if (mute >= 0) {
+ if (mute == 2) {
+ cDevice::PrimaryDevice()->ToggleMute();
+ } else if (cDevice::PrimaryDevice()->IsMute()) {
+ if (mute == 0)
+ cDevice::PrimaryDevice()->ToggleMute();
+ } else {
+ if (mute == 1)
+ cDevice::PrimaryDevice()->ToggleMute();
+ }
+ }
+
+ if (track >= 0) {
+ const tTrackId *TrackId = cDevice::PrimaryDevice()->GetTrack(eTrackType(track));
+ if (TrackId && TrackId->id)
+ cDevice::PrimaryDevice()->SetCurrentAudioTrack(eTrackType(track));
+ }
+
+ if (channel >= 0 && channel < 3) {
+ cDevice::PrimaryDevice()->SetAudioChannel(channel);
+ }
+ }
+
+ if (request.method() == "POST" || request.method() == "GET") {
+ AudioList* audioList;
+ if ( q.isFormat(".html") ) {
+ reply.addHeader("Content-Type", "text/html; charset=utf-8");
+ audioList = (AudioList*)new HtmlAudioList(&out);
+ audioList->init();
+ } else if ( q.isFormat(".xml") ) {
+ reply.addHeader("Content-Type", "text/xml; charset=utf-8");
+ audioList = (AudioList*)new XmlAudioList(&out);
+ audioList->init();
+ } else { // if ( q.isFormat(".json") )
+ reply.addHeader("Content-Type", "application/json; charset=utf-8");
+ audioList = (AudioList*)new JsonAudioList(&out);
+ }
+ audioList->addContent();
+ audioList->finish();
+ delete audioList;
+ } else {
+ reply.httpReturn(403, "Only GET and POST methods are supported by the audio control");
+ }
+}
+
+void operator<<= (cxxtools::SerializationInfo& si, const SerTrack& t)
+{
+ si.addMember("type") <<= t.Number;
+ si.addMember("description") <<= t.Description;
+}
+
+void operator<<= (cxxtools::SerializationInfo& si, const SerTrackList& tl)
+{
+ si.addMember("count") <<= tl.Count;
+ si.addMember("track") <<= tl.track;
+}
+
+void operator<<= (cxxtools::SerializationInfo& si, const SerAudio& a)
+{
+ si.addMember("volume") <<= a.Volume;
+ si.addMember("mute") <<= a.Mute;
+ si.addMember("tracks") <<= a.Tracks;
+ si.addMember("type") <<= a.Number;
+ si.addMember("description") <<= a.Description;
+ si.addMember("channel") <<= a.Channel;
+}
+
+AudioList::AudioList(ostream *out)
+{
+ s = new StreamExtension(out);
+}
+
+AudioList::~AudioList()
+{
+ delete s;
+}
+
+void HtmlAudioList::init()
+{
+ s->writeHtmlHeader("HtmlAudioList");
+}
+
+void HtmlAudioList::addContent()
+{
+ cDevice *Device = cDevice::PrimaryDevice();
+ eTrackType currentTrack = Device->GetCurrentAudioTrack();
+ const char *desc;
+
+ s->write(cString::sprintf("volume: %d
\n", Device->CurrentVolume()));
+ if (Device->IsMute())
+ s->write(cString::sprintf("mute: 1
\n"));
+ else
+ s->write(cString::sprintf("mute: 0
\n"));
+
+ s->write(cString::sprintf("tracks: %i
\n", Device->NumAudioTracks()));
+ for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
+ const tTrackId *TrackId = Device->GetTrack(eTrackType(i));
+ if (TrackId && TrackId->id) {
+ s->write(cString::sprintf(" track: type=%i description=%s \n", i, *TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i)));
+ if (i == currentTrack)
+ desc = strdup(*TrackId->description ? TrackId->description : *TrackId->language ? TrackId->language : *itoa(i));
+ }
+ }
+
+ s->write(cString::sprintf("type: %i
\n", currentTrack));
+ s->write(cString::sprintf("description: %s
\n", desc));
+
+ if (IS_DOLBY_TRACK(currentTrack)) { // strncmp (Track->description, "Dolby", 5) == 0
+ if (strstr (desc, "5.1") == 0)
+ s->write(cString::sprintf("channel: dd 2.0
\n"));
+ else
+ s->write(cString::sprintf("channel: dd 5.1
\n"));
+ } else {
+ s->write(cString::sprintf("channel: %i
\n", Device->GetAudioChannel()));
+ }
+
+ s->write("\n");
+}
+
+void HtmlAudioList::finish()
+{
+ s->write("