summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de>2007-10-21 15:56:00 (GMT)
committerDieter Hametner <dh (plus) vdr (at) gekrumbel (dot) de>2007-10-21 15:56:00 (GMT)
commit0fea7f3368ab6ca3f056c26151d30e978a2f2eee (patch)
tree8fe0c6eb5c3cd46ecf68a1cd52cc224b0349ed2d
parent8ac9758dd9dc502c64c06c3339b6a60a7d54e39c (diff)
downloadvdr-plugin-live-0fea7f3368ab6ca3f056c26151d30e978a2f2eee.tar.gz
vdr-plugin-live-0fea7f3368ab6ca3f056c26151d30e978a2f2eee.tar.bz2
- renamed recordings.h/cpp to recman.h/cpp. Preparations for
recordings updates.
-rw-r--r--Makefile4
-rw-r--r--doc/ChangeLog7
-rw-r--r--epg_events.cpp2
-rw-r--r--pages/Makefile2
-rw-r--r--pages/epginfo.ecpp2
-rw-r--r--pages/ibox.ecpp2
-rw-r--r--pages/recordings.ecpp16
-rw-r--r--recman.cpp464
-rw-r--r--recman.h313
-rw-r--r--recordings.cpp259
-rw-r--r--recordings.h153
-rw-r--r--tasks.cpp8
12 files changed, 803 insertions, 429 deletions
diff --git a/Makefile b/Makefile
index fe35907..72f0b2d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile,v 1.51 2007/10/21 14:26:09 winni Exp $
+# $Id: Makefile,v 1.52 2007/10/21 15:56:00 tadi Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,7 @@ SUBDIRS = httpd pages css javascript
### The object files (add further files here):
PLUGINOBJS = $(PLUGIN).o thread.o tntconfig.o setup.o i18n.o timers.o \
- tools.o recordings.o tasks.o status.o epg_events.o epgsearch.o \
+ tools.o recman.o tasks.o status.o epg_events.o epgsearch.o \
grab.o md5.o filecache.o livefeatures.o preload.o
WEBLIBS = pages/libpages.a css/libcss.a javascript/libjavascript.a
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 0cc3c58..68cb085 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,10 @@
+2007-10-21 Dieter Hametner <dh+vdr at gekrumbel dot de>
+
+ - Renamed recordings.h/cpp files to recman.h/cpp. Adapted
+ files that included them.
+ - recman.h have extended functionality for recordings. It is not used
+ yet.
+
2007-10-17 Dieter Hametner <dh+vdr at gekrumbel dot de>
* css/styles.css
diff --git a/epg_events.cpp b/epg_events.cpp
index 83d067d..2302827 100644
--- a/epg_events.cpp
+++ b/epg_events.cpp
@@ -2,7 +2,7 @@
#include <glob.h>
#include "tools.h"
-#include "recordings.h"
+#include "recman.h"
#include "epg_events.h"
#include "setup.h"
diff --git a/pages/Makefile b/pages/Makefile
index 09dfd63..9945f1f 100644
--- a/pages/Makefile
+++ b/pages/Makefile
@@ -43,7 +43,7 @@ all: libpages.a
MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies
-$(DEPFILE): Makefile $(OBJS:%.o=%.cpp)
+$(DEPFILE): Makefile $(OBJS:%.o=%.cpp) $(OBJS:%.o=%.ecpp)
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.cpp) > $@
-include $(DEPFILE)
diff --git a/pages/epginfo.ecpp b/pages/epginfo.ecpp
index c14d89d..4f49f0f 100644
--- a/pages/epginfo.ecpp
+++ b/pages/epginfo.ecpp
@@ -7,7 +7,7 @@
#include "setup.h"
#include "tools.h"
#include "epg_events.h"
-#include "recordings.h"
+#include "recman.h"
namespace vdrlive {
class SchedulesLock
diff --git a/pages/ibox.ecpp b/pages/ibox.ecpp
index 0118c07..147dcfa 100644
--- a/pages/ibox.ecpp
+++ b/pages/ibox.ecpp
@@ -10,7 +10,7 @@
#include "setup.h"
#include "tools.h"
#include "epg_events.h"
-#include "recordings.h"
+#include "recman.h"
using namespace vdrlive;
using namespace std;
diff --git a/pages/recordings.ecpp b/pages/recordings.ecpp
index dabb301..f0d6553 100644
--- a/pages/recordings.ecpp
+++ b/pages/recordings.ecpp
@@ -6,7 +6,7 @@
#include "tools.h"
#include "epg_events.h"
-#include "recordings.h"
+#include "recman.h"
#include "setup.h"
using namespace vdrlive;
@@ -19,7 +19,7 @@ using namespace std;
bool logged_in(false);
</%session>
<%request scope="page">
-RecordingsTree recordingsTree(LiveRecordingsManager());
+ RecordingsTreePtr recordingsTree(LiveRecordingsManager()->GetRecordingsTree());
</%request>
<%include>page_init.eh</%include>
<%cpp>
@@ -62,11 +62,11 @@ RecordingsTree recordingsTree(LiveRecordingsManager());
int level = 0;
</%args>
<%cpp>
-RecordingsTree::Map::iterator iter;
-RecordingsTree::Map::iterator end = recordingsTree.end(path);
+RecordingsMap::iterator iter;
+RecordingsMap::iterator end = recordingsTree->end(path);
-for (iter = recordingsTree.begin(path); iter != end; ++iter) {
- RecordingsTree::RecordingsItemPtr recItem = iter->second;
+for (iter = recordingsTree->begin(path); iter != end; ++iter) {
+ RecordingsItemPtr recItem = iter->second;
string folderimg("folder_closed.png");
string collapseimg("plus.png");
if (recItem->IsDir()) {
@@ -88,8 +88,8 @@ for (iter = recordingsTree.begin(path); iter != end; ++iter) {
% }
%}
<%cpp>
-for (iter = recordingsTree.begin(path); iter != end; ++iter) {
- RecordingsTree::RecordingsItemPtr recItem = iter->second;
+for (iter = recordingsTree->begin(path); iter != end; ++iter) {
+ RecordingsItemPtr recItem = iter->second;
if (!recItem->IsDir()) {
string day(FormatDateTime("%a,", recItem->StartTime()));
string dayLen(lexical_cast<string, int>(day.length() - 1) + ".25em;");
diff --git a/recman.cpp b/recman.cpp
new file mode 100644
index 0000000..eb993d5
--- /dev/null
+++ b/recman.cpp
@@ -0,0 +1,464 @@
+#include <unistd.h>
+#include <cstring>
+#include <string>
+#include <sstream>
+#include <fstream>
+#include <stack>
+
+#include "stdext.h"
+#include "tools.h"
+
+#include "epg_events.h"
+#include "recman.h"
+
+
+using namespace std::tr1;
+using namespace std;
+
+namespace vdrlive {
+
+ /**
+ * Implementation of class RecordingsManager:
+ */
+ weak_ptr< RecordingsManager > RecordingsManager::m_recMan;
+ shared_ptr< RecordingsTree > RecordingsManager::m_recTree;
+ shared_ptr< RecordingsList > RecordingsManager::m_recList;
+ int RecordingsManager::m_recordingsState = 0;
+
+ // The RecordingsManager holds a VDR lock on the
+ // Recordings. Additionally the singleton instance of
+ // RecordingsManager is held in a weak pointer. If it is not in
+ // use any longer, it will be freed automaticaly, which leads to a
+ // release of the VDR recordings lock. Upon requesting access to
+ // the RecordingsManager via LiveRecordingsManger function, first
+ // the weak ptr is locked (obtaining a shared_ptr from an possible
+ // existing instance) and if not successfull a new instance is
+ // created, which again locks the VDR Recordings.
+ //
+ // RecordingsManager provides factory methods to obtain other
+ // recordings data structures. The data structures returned keep if
+ // needed the instance of RecordingsManager alive until destructed
+ // themselfs. This way the use of LIVE::recordings is straight
+ // forward and does hide the locking needs from the user.
+
+ RecordingsManager::RecordingsManager() :
+ m_recordingsLock(&Recordings)
+ {
+ }
+
+ RecordingsTreePtr RecordingsManager::GetRecordingsTree() const
+ {
+ RecordingsManagerPtr recMan = EnsureValidData();
+ if (! recMan) {
+ return RecordingsTreePtr(recMan, shared_ptr< RecordingsTree >());
+ }
+ return RecordingsTreePtr(recMan, m_recTree);
+ }
+
+ RecordingsListPtr RecordingsManager::GetRecordingsList(bool ascending) const
+ {
+ RecordingsManagerPtr recMan = EnsureValidData();
+ if (! recMan) {
+ return RecordingsListPtr(recMan, shared_ptr< RecordingsList >());
+ }
+ return RecordingsListPtr(recMan, shared_ptr< RecordingsList >(new RecordingsList(m_recList, ascending)));
+ }
+
+ RecordingsListPtr RecordingsManager::GetRecordingsList(time_t begin, time_t end, bool ascending) const
+ {
+ RecordingsManagerPtr recMan = EnsureValidData();
+ if (! recMan) {
+ return RecordingsListPtr(recMan, shared_ptr< RecordingsList >());
+ }
+ return RecordingsListPtr(recMan, shared_ptr< RecordingsList >(new RecordingsList(m_recList, ascending)));
+ }
+
+ string RecordingsManager::Md5Hash(cRecording const * recording) const
+ {
+ return "recording_" + MD5Hash(recording->FileName());
+ }
+
+ cRecording const * RecordingsManager::GetByMd5Hash(string const & hash) const
+ {
+ if (!hash.empty()) {
+ for (cRecording* rec = Recordings.First(); rec != 0; rec = Recordings.Next(rec)) {
+ if (hash == Md5Hash(rec))
+ return rec;
+ }
+ }
+ return 0;
+ }
+
+ bool RecordingsManager::IsArchived(cRecording const * recording)
+ {
+ string filename = recording->FileName();
+
+ string vdrFile = filename + "/001.vdr";
+ if (0 == access(vdrFile.c_str(), R_OK))
+ return false;
+
+ filename += "/dvd.vdr";
+ return (0 == access(filename.c_str(), R_OK));
+ }
+
+ string const RecordingsManager::GetArchiveId(cRecording const * recording)
+ {
+ string filename = recording->FileName();
+
+ filename += "/dvd.vdr";
+ ifstream dvd(filename.c_str());
+
+ if (dvd) {
+ string archiveDisc;
+ string videoDisc;
+ dvd >> archiveDisc;
+ if ("0000" == archiveDisc) {
+ dvd >> videoDisc;
+ return videoDisc;
+ }
+ return archiveDisc;
+ }
+ return "";
+ }
+
+ string const RecordingsManager::GetArchiveDescr(cRecording const * recording)
+ {
+ string archived;
+ if (IsArchived(recording)) {
+ archived += " [";
+ archived += tr("On archive DVD No.");
+ archived += ": ";
+ archived += GetArchiveId(recording);
+ archived += "]";
+ }
+ return archived;
+ }
+
+ RecordingsManagerPtr RecordingsManager::EnsureValidData()
+ {
+ // Get singleton instance of RecordingsManager. 'this' is not
+ // an instance of shared_ptr of the singleton
+ // RecordingsManager, so we obtain it in the overall
+ // recommended way.
+ RecordingsManagerPtr recMan = LiveRecordingsManager();
+ if (! recMan) {
+ // theoretically this code is never reached ...
+ esyslog("[LIVE]: lost RecordingsManager instance while using it!");
+ return RecordingsManagerPtr();
+ }
+
+ // StateChanged must be executed every time, so not part of
+ // the short cut evaluation in the if statement below.
+ bool stateChanged = Recordings.StateChanged(m_recordingsState);
+ if ((!m_recTree) || (!m_recList) || stateChanged) {
+ if (stateChanged) {
+ m_recTree.reset();
+ m_recList.reset();
+ }
+ if (stateChanged || !m_recTree) {
+ m_recTree = shared_ptr< RecordingsTree >(new RecordingsTree(recMan));
+ }
+ if (!m_recTree) {
+ esyslog("[LIVE]: creation of recordings tree failed!");
+ return RecordingsManagerPtr();
+ }
+ if (stateChanged || !m_recList) {
+ m_recList = shared_ptr< RecordingsList >(new RecordingsList(RecordingsTreePtr(recMan, m_recTree)));
+ }
+ if (!m_recList) {
+ esyslog("[LIVE]: creation of recordings list failed!");
+ return RecordingsManagerPtr();
+ }
+ }
+ return recMan;
+ }
+
+
+ /**
+ * Implementation of class RecordingsItem:
+ */
+ RecordingsItem::RecordingsItem(string const & name, RecordingsItemPtr parent) :
+ m_name(name),
+ m_entries(),
+ m_parent(parent)
+ {
+ }
+
+ RecordingsItem::~RecordingsItem()
+ {
+ }
+
+
+ /**
+ * Implementation of class RecordingsItemDir:
+ */
+ RecordingsItemDir::RecordingsItemDir(const string& name, int level, RecordingsItemPtr parent) :
+ RecordingsItem(name, parent),
+ m_level(level)
+ {
+ esyslog("REC: C: dir %s -> %s", name.c_str(), parent ? parent->Name().c_str() : "ROOT");
+ }
+
+ RecordingsItemDir::~RecordingsItemDir()
+ {
+ esyslog("REC: D: dir %s", Name().c_str());
+ }
+
+
+ /**
+ * Implementation of class RecordingsItemRec:
+ */
+ RecordingsItemRec::RecordingsItemRec(const string& id, const string& name, const cRecording* recording, RecordingsItemPtr parent) :
+ RecordingsItem(name, parent),
+ m_recording(recording),
+ m_id(id)
+ {
+ esyslog("REC: C: rec %s -> %s", name.c_str(), parent->Name().c_str());
+ }
+
+ RecordingsItemRec::~RecordingsItemRec()
+ {
+ esyslog("REC: D: rec %s", Name().c_str());
+ }
+
+ time_t RecordingsItemRec::StartTime() const
+ {
+ return m_recording->start;
+ }
+
+
+ /**
+ * Implementation of class RecordingsTree:
+ */
+ RecordingsTree::RecordingsTree(RecordingsManagerPtr recMan) :
+ m_maxLevel(0),
+ m_root(new RecordingsItemDir("", 0, RecordingsItemPtr()))
+ {
+ // esyslog("DH: ****** RecordingsTree::RecordingsTree() ********");
+ for (cRecording* recording = Recordings.First(); recording != 0; recording = Recordings.Next(recording)) {
+ if (m_maxLevel < recording->HierarchyLevels()) {
+ m_maxLevel = recording->HierarchyLevels();
+ }
+
+ RecordingsItemPtr dir = m_root;
+ string name(recording->Name());
+
+ // esyslog("DH: recName = '%s'", recording->Name());
+ int level = 0;
+ size_t index = 0;
+ size_t pos = 0;
+ do {
+ pos = name.find('~', index);
+ if (pos != string::npos) {
+ string dirName(name.substr(index, pos - index));
+ index = pos + 1;
+ RecordingsMap::iterator i = findDir(dir, dirName);
+ if (i == dir->m_entries.end()) {
+ RecordingsItemPtr recPtr (new RecordingsItemDir(dirName, level, dir));
+ dir->m_entries.insert(pair< string, RecordingsItemPtr > (dirName, recPtr));
+ i = findDir(dir, dirName);
+ if (i != dir->m_entries.end()) {
+ // esyslog("DH: added dir: '%s'", dirName.c_str());
+ }
+ else {
+ // esyslog("DH: panic: didn't found inserted dir: '%s'", dirName.c_str());
+ }
+ }
+ dir = i->second;
+ // esyslog("DH: current dir: '%s'", dir->Name().c_str());
+ level++;
+ }
+ else {
+ string recName(name.substr(index, name.length() - index));
+ RecordingsItemPtr recPtr (new RecordingsItemRec(recMan->Md5Hash(recording), recName, recording, dir));
+ dir->m_entries.insert(pair< string, RecordingsItemPtr > (recName, recPtr));
+ // esyslog("DH: added rec: '%s'", recName.c_str());
+ }
+ } while (pos != string::npos);
+ }
+ // esyslog("DH: ------ RecordingsTree::RecordingsTree() --------");
+ }
+
+ RecordingsTree::~RecordingsTree()
+ {
+ // esyslog("DH: ****** RecordingsTree::~RecordingsTree() ********");
+ }
+
+ RecordingsMap::iterator RecordingsTree::begin(const vector< string >& path)
+ {
+ if (path.empty()) {
+ return m_root->m_entries.begin();
+ }
+
+ RecordingsItemPtr recItem = m_root;
+ for (vector< string >::const_iterator i = path.begin(); i != path.end(); ++i)
+ {
+ pair< RecordingsMap::iterator, RecordingsMap::iterator> range = recItem->m_entries.equal_range(*i);
+ for (RecordingsMap::iterator iter = range.first; iter != range.second; ++iter) {
+ if (iter->second->IsDir()) {
+ recItem = iter->second;
+ break;
+ }
+ }
+ }
+ return recItem->m_entries.begin();
+ }
+
+ RecordingsMap::iterator RecordingsTree::end(const vector< string >&path)
+ {
+ if (path.empty()) {
+ return m_root->m_entries.end();
+ }
+
+ RecordingsItemPtr recItem = m_root;
+ for (vector< string >::const_iterator i = path.begin(); i != path.end(); ++i)
+ {
+ pair< RecordingsMap::iterator, RecordingsMap::iterator> range = recItem->m_entries.equal_range(*i);
+ for (RecordingsMap::iterator iter = range.first; iter != range.second; ++iter) {
+ if (iter->second->IsDir()) {
+ recItem = iter->second;
+ break;
+ }
+ }
+ }
+ return recItem->m_entries.end();
+ }
+
+ RecordingsMap::iterator RecordingsTree::findDir(RecordingsItemPtr& dir, const string& dirName)
+ {
+ pair< RecordingsMap::iterator, RecordingsMap::iterator > range = dir->m_entries.equal_range(dirName);
+ for (RecordingsMap::iterator i = range.first; i != range.second; ++i) {
+ if (i->second->IsDir()) {
+ return i;
+ }
+ }
+ return dir->m_entries.end();
+ }
+
+
+ /**
+ * Implementation of class RecordingsTreePtr:
+ */
+ RecordingsTreePtr::RecordingsTreePtr(RecordingsManagerPtr recManPtr, std::tr1::shared_ptr< RecordingsTree > recTree) :
+ shared_ptr<RecordingsTree>(recTree),
+ m_recManPtr(recManPtr)
+ {
+ }
+
+ RecordingsTreePtr::~RecordingsTreePtr()
+ {
+ }
+
+
+ /**
+ * Implementation of class RecordingsList:
+ */
+ RecordingsList::RecordingsList(RecordingsTreePtr recTree) :
+ m_pRecVec(new RecVecType())
+ {
+ if (!m_pRecVec) {
+ return;
+ }
+
+ stack< RecordingsItemPtr > treeStack;
+ treeStack.push(recTree->Root());
+
+ while (!treeStack.empty()) {
+ RecordingsItemPtr current = treeStack.top();
+ treeStack.pop();
+ for (RecordingsMap::const_iterator iter = current->begin(); iter != current->end(); ++iter) {
+ RecordingsItemPtr recItem = iter->second;
+ if (recItem->IsDir()) {
+ treeStack.push(recItem);
+ }
+ else {
+ m_pRecVec->push_back(recItem);
+ }
+ }
+ }
+ }
+
+ RecordingsList::RecordingsList(shared_ptr< RecordingsList > recList, bool ascending) :
+ m_pRecVec(new RecVecType(recList->size()))
+ {
+ if (!m_pRecVec) {
+ return;
+ }
+ if (ascending) {
+ partial_sort_copy(recList->begin(), recList->end(), m_pRecVec->begin(), m_pRecVec->end(), Ascending());
+ }
+ else {
+ partial_sort_copy(recList->begin(), recList->end(), m_pRecVec->begin(), m_pRecVec->end(), Descending());
+ }
+ }
+
+ RecordingsList::RecordingsList(shared_ptr< RecordingsList > recList, time_t begin, time_t end, bool ascending) :
+ m_pRecVec(new RecVecType())
+ {
+ if (end > begin) {
+ return;
+ }
+ if (!m_pRecVec) {
+ return;
+ }
+ remove_copy_if(recList->begin(), recList->end(), m_pRecVec->end(), NotInRange(begin, end));
+
+ if (ascending) {
+ sort(m_pRecVec->begin(), m_pRecVec->end(), Ascending());
+ }
+ else {
+ sort(m_pRecVec->begin(), m_pRecVec->end(), Descending());
+ }
+ }
+
+ RecordingsList::~RecordingsList()
+ {
+ if (m_pRecVec) {
+ delete m_pRecVec, m_pRecVec = 0;
+ }
+ }
+
+
+ RecordingsList::NotInRange::NotInRange(time_t begin, time_t end) :
+ m_begin(begin),
+ m_end(end)
+ {
+ }
+
+ bool RecordingsList::NotInRange::operator()(RecordingsItemPtr const &x) const
+ {
+ return (x->StartTime() < m_begin) || (m_end >= x->StartTime());
+ }
+
+
+ /**
+ * Implementation of class RecordingsList:
+ */
+ RecordingsListPtr::RecordingsListPtr(RecordingsManagerPtr recManPtr, shared_ptr< RecordingsList > recList) :
+ shared_ptr< RecordingsList >(recList),
+ m_recManPtr(recManPtr)
+ {
+ }
+
+ RecordingsListPtr::~RecordingsListPtr()
+ {
+ }
+
+
+ /**
+ * Implementation of function LiveRecordingsManager:
+ */
+ RecordingsManagerPtr LiveRecordingsManager()
+ {
+ RecordingsManagerPtr r = RecordingsManager::m_recMan.lock();
+ if (r) {
+ return r;
+ }
+ else {
+ RecordingsManagerPtr n(new RecordingsManager);
+ RecordingsManager::m_recMan = n;
+ return n;
+ }
+ }
+
+} // namespace vdrlive
diff --git a/recman.h b/recman.h
new file mode 100644
index 0000000..0f8b8c5
--- /dev/null
+++ b/recman.h
@@ -0,0 +1,313 @@
+#ifndef VDR_LIVE_RECORDINGS_H
+#define VDR_LIVE_RECORDINGS_H
+
+#include <ctime>
+#include <map>
+#include <vector>
+#include <vdr/recording.h>
+#include "stdext.h"
+
+namespace vdrlive {
+
+ // Forward declations from epg_events.h
+ class EpgInfo;
+ typedef std::tr1::shared_ptr<EpgInfo> EpgInfoPtr;
+
+ /**
+ * Some forward declarations
+ */
+ class RecordingsManager;
+ class RecordingsTree;
+ class RecordingsTreePtr;
+ class RecordingsList;
+ class RecordingsListPtr;
+ class RecordingsItem;
+
+ typedef std::tr1::shared_ptr< RecordingsManager > RecordingsManagerPtr;
+ typedef std::tr1::shared_ptr< RecordingsItem > RecordingsItemPtr;
+ // typedef std::tr1::weak_ptr< RecordingsItem > RecordingsItemWeakPtr;
+ typedef std::multimap< std::string, RecordingsItemPtr > RecordingsMap;
+
+
+ /**
+ * Class for managing recordings inside the live plugin. It
+ * provides some convenience methods and provides automatic
+ * locking during requests on the recordings or during the
+ * traversion of the recordings tree or lists, which can only be
+ * obtained through methods of the RecordingsManager.
+ */
+ class RecordingsManager
+ {
+ friend RecordingsManagerPtr LiveRecordingsManager();
+
+ public:
+ /**
+ * Returns a shared pointer to a fully populated
+ * recordings tree.
+ */
+ RecordingsTreePtr GetRecordingsTree() const;
+
+ /**
+ * Return a shared pointer to a populated recordings
+ * list. The list is optionally sorted ascending or
+ * descending by date and may be constrained by a date
+ * range.
+ */
+ RecordingsListPtr GetRecordingsList(bool ascending = true) const;
+ RecordingsListPtr GetRecordingsList(time_t begin, time_t end, bool ascending = true) const;
+
+ /**
+ * generates a Md5 hash from a cRecording entry. It can be used
+ * to reidentify a recording.
+ */
+ std::string Md5Hash(cRecording const * recording) const;
+
+ /**
+ * fetches a cRecording from VDR's Recordings collection. Returns
+ * NULL if recording was not found
+ */
+ cRecording const* GetByMd5Hash(std::string const & hash) const;
+
+ /**
+ * Determine wether the recording has been archived on
+ * removable media (e.g. DVD-ROM)
+ */
+ static bool IsArchived(cRecording const * recording);
+
+ /**
+ * Provide an identification of the removable media
+ * (e.g. DVD-ROM Number or Name) where the recording has
+ * been archived.
+ */
+ static std::string const GetArchiveId(cRecording const * recording);
+
+ static std::string const GetArchiveDescr(cRecording const * recording);
+
+ private:
+ RecordingsManager();
+
+ static RecordingsManagerPtr EnsureValidData();
+
+ static std::tr1::weak_ptr< RecordingsManager > m_recMan;
+ static std::tr1::shared_ptr< RecordingsTree > m_recTree;
+ static std::tr1::shared_ptr< RecordingsList > m_recList;
+ static int m_recordingsState;
+
+ cThreadLock m_recordingsLock;
+ };
+
+
+ /**
+ * Base class for entries in recordings tree and recordings list.
+ * All opeations possible on recordings are performed against
+ * pointers to instances of recordings items. The C++ polymorphy
+ * delegates them to the 'right' class.
+ */
+ class RecordingsItem
+ {
+ friend class RecordingsTree;
+
+ protected:
+ RecordingsItem(const std::string& name, RecordingsItemPtr parent);
+
+ public:
+ virtual ~RecordingsItem();
+
+ virtual time_t StartTime() const = 0;
+ virtual bool IsDir() const = 0;
+ virtual const std::string& Name() const { return m_name; }
+ virtual const std::string Id() const = 0;
+
+ virtual const cRecording* Recording() const { return 0; }
+ virtual const cRecordingInfo* RecInfo() const { return 0; }
+
+ RecordingsMap::const_iterator begin() const { return m_entries.begin(); }
+ RecordingsMap::const_iterator end() const { return m_entries.end(); }
+
+ private:
+ std::string m_name;
+ RecordingsMap m_entries;
+ RecordingsItemPtr m_parent;
+ };
+
+
+ /**
+ * A recordings item that resembles a directory with other
+ * subdirectories and/or real recordings.
+ */
+ class RecordingsItemDir : public RecordingsItem
+ {
+ public:
+ RecordingsItemDir(const std::string& name, int level, RecordingsItemPtr parent);
+
+ virtual ~RecordingsItemDir();
+
+ virtual time_t StartTime() const { return 0; }
+ virtual bool IsDir() const { return true; }
+ virtual std::string const Id() const { return ""; }
+
+ private:
+ int m_level;
+ };
+
+
+ /**
+ * A recordings item that represents a real recording. This is
+ * the leaf item in the recordings tree or one of the items in
+ * the recordings list.
+ */
+ class RecordingsItemRec : public RecordingsItem
+ {
+ public:
+ RecordingsItemRec(const std::string& id, const std::string& name, const cRecording* recording, RecordingsItemPtr parent);
+
+ virtual ~RecordingsItemRec();
+
+ virtual time_t StartTime() const;
+ virtual bool IsDir() const { return false; }
+ virtual const std::string Id() const { return m_id; }
+
+ virtual const cRecording* Recording() const { return m_recording; }
+ virtual const cRecordingInfo* RecInfo() const { return m_recording->Info(); }
+
+ private:
+ const cRecording *m_recording;
+ std::string m_id;
+ };
+
+
+ /**
+ * The recordings tree contains all recordings in a file system
+ * tree like fashion.
+ */
+ class RecordingsTree
+ {
+ friend class RecordingsManager;
+
+ private:
+ RecordingsTree(RecordingsManagerPtr recManPtr);
+
+ public:
+ virtual ~RecordingsTree();
+
+ RecordingsItemPtr const & Root() const { return m_root; }
+
+ RecordingsMap::iterator begin(const std::vector< std::string >& path);
+ RecordingsMap::iterator end(const std::vector< std::string >&path);
+
+ int MaxLevel() const { return m_maxLevel; }
+
+ private:
+ int m_maxLevel;
+ RecordingsItemPtr m_root;
+
+ RecordingsMap::iterator findDir(RecordingsItemPtr& dir, const std::string& dirname);
+ };
+
+
+ /**
+ * A smart pointer to a recordings tree. As long as an instance of this
+ * exists the recordings are locked in the vdr.
+ */
+ class RecordingsTreePtr : public std::tr1::shared_ptr< RecordingsTree >
+ {
+ friend class RecordingsManager;
+
+ private:
+ RecordingsTreePtr(RecordingsManagerPtr recManPtr, std::tr1::shared_ptr< RecordingsTree > recTree);
+
+ public:
+ virtual ~RecordingsTreePtr();
+
+ private:
+ RecordingsManagerPtr m_recManPtr;
+ };
+
+
+ /**
+ * The recordings list contains all real recordings in a list
+ * sorted by a given sorting predicate function. The directory
+ * entries are not part of this list. The path towards the root
+ * can be obtained via the 'parent' members of the recordings
+ * items.
+ */
+ class RecordingsList
+ {
+ friend class RecordingsManager;
+
+ private:
+ RecordingsList(RecordingsTreePtr recTree);
+ RecordingsList(std::tr1::shared_ptr< RecordingsList > recList, bool ascending);
+ RecordingsList(std::tr1::shared_ptr< RecordingsList > recList, time_t begin, time_t end, bool ascending);
+
+ public:
+ typedef std::vector< RecordingsItemPtr > RecVecType;
+
+ virtual ~RecordingsList();
+
+ RecVecType::const_iterator begin() const { return m_pRecVec->begin(); }
+ RecVecType::const_iterator end() const { return m_pRecVec->end(); }
+
+ RecVecType::size_type size() const { return m_pRecVec->size(); }
+
+ private:
+ class Ascending
+ {
+ public:
+ bool operator()(RecordingsItemPtr const &x, RecordingsItemPtr const &y) const { return x->StartTime() < y->StartTime(); }
+ };
+
+ class Descending
+ {
+ public:
+ bool operator()(RecordingsItemPtr const &x, RecordingsItemPtr const &y) const { return y->StartTime() < x->StartTime(); }
+ };
+
+ class NotInRange
+ {
+ public:
+ NotInRange(time_t begin, time_t end);
+
+ bool operator()(RecordingsItemPtr const &x) const;
+
+ private:
+ time_t m_begin;
+ time_t m_end;
+ };
+
+ private:
+ RecVecType *m_pRecVec;
+ };
+
+
+ /**
+ * A smart pointer to a recordings list. As long as an instance of this
+ * exists the recordings are locked in the vdr.
+ */
+ class RecordingsListPtr : public std::tr1::shared_ptr< RecordingsList >
+ {
+ friend class RecordingsManager;
+
+ private:
+ RecordingsListPtr(RecordingsManagerPtr recManPtr, std::tr1::shared_ptr< RecordingsList > recList);
+
+ public:
+ virtual ~RecordingsListPtr();
+
+ private:
+ RecordingsManagerPtr m_recManPtr;
+ };
+
+
+ /**
+ * return singleton instance of RecordingsManager as a shared Pointer.
+ * This ensures that after last use of the RecordingsManager it is
+ * deleted. After deletion of the original RecordingsManager a repeated
+ * call to this function creates a new RecordingsManager which is again
+ * kept alive as long references to it exist.
+ */
+ RecordingsManagerPtr LiveRecordingsManager();
+
+} // namespace vdrlive
+
+#endif // VDR_LIVE_RECORDINGS_H
diff --git a/recordings.cpp b/recordings.cpp
deleted file mode 100644
index 5d5070a..0000000
--- a/recordings.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-#include <unistd.h>
-#include <cstring>
-#include <string>
-#include <sstream>
-#include <fstream>
-#include "tools.h"
-#include "epg_events.h"
-#include "recordings.h"
-#include "stdext.h"
-
-
-using namespace std::tr1;
-using namespace std;
-
-namespace vdrlive {
-
- RecordingsManager::RecordingsManager() :
- m_recordingsLock(&Recordings)
- {
- }
-
- string RecordingsManager::Md5Hash(const cRecording* recording) const
- {
- return "recording_" + MD5Hash(recording->FileName());
-/* unsigned char md5[MD5_DIGEST_LENGTH];
- const char* fileName = recording->FileName();
- MD5(reinterpret_cast<const unsigned char*>(fileName), strlen(fileName), md5);
-
- ostringstream hashStr;
- hashStr << "MD5" << hex;
- for (size_t i = 0; i < MD5_DIGEST_LENGTH; i++)
- hashStr << (0 + md5[i]);
- return hashStr.str();
-*/
- }
-
- const cRecording* RecordingsManager::GetByMd5Hash(const string& hash) const
- {
- if (!hash.empty()) {
- for (cRecording* rec = Recordings.First(); rec != 0; rec = Recordings.Next(rec)) {
- if (hash == Md5Hash(rec))
- return rec;
- }
- }
- return 0;
- }
-
- bool RecordingsManager::IsArchived(const cRecording* recording)
- {
- string filename = recording->FileName();
-
- string vdrFile = filename + "/001.vdr";
- if (0 == access(vdrFile.c_str(), R_OK))
- return false;
-
- filename += "/dvd.vdr";
- return (0 == access(filename.c_str(), R_OK));
- }
-
- const std::string RecordingsManager::GetArchiveId(const cRecording* recording)
- {
- string filename = recording->FileName();
-
- filename += "/dvd.vdr";
- ifstream dvd(filename.c_str());
-
- if (dvd) {
- string archiveDisc;
- string videoDisc;
- dvd >> archiveDisc;
- if ("0000" == archiveDisc) {
- dvd >> videoDisc;
- return videoDisc;
- }
- return archiveDisc;
- }
- return "";
- }
-
- const string RecordingsManager::GetArchiveDescr(const cRecording* recording)
- {
- string archived;
- if (IsArchived(recording)) {
- archived += " [";
- archived += tr("On archive DVD No.");
- archived += ": ";
- archived += GetArchiveId(recording);
- archived += "]";
- }
- return archived;
- }
-
-
- RecordingsTree::RecordingsTree(RecordingsManagerPtr recMan) :
- m_maxLevel(0),
- m_root(new RecordingsItemDir()),
- m_recManPtr(recMan)
- {
- // esyslog("DH: ****** RecordingsTree::RecordingsTree() ********");
- for ( cRecording* recording = Recordings.First(); recording != 0; recording = Recordings.Next( recording ) ) {
- if (m_maxLevel < recording->HierarchyLevels()) {
- m_maxLevel = recording->HierarchyLevels();
- }
-
- RecordingsItemPtr dir = m_root;
- string name(recording->Name());
-
- // esyslog("DH: recName = '%s'", recording->Name());
- int level = 0;
- size_t index = 0;
- size_t pos = 0;
- do {
- pos = name.find('~', index);
- if (pos != string::npos) {
- string dirName(name.substr(index, pos - index));
- index = pos + 1;
- Map::iterator i = findDir(dir, dirName);
- if (i == dir->m_entries.end()) {
- RecordingsItemPtr recPtr (new RecordingsItemDir(dirName, level));
- dir->m_entries.insert(pair< string, RecordingsItemPtr > (dirName, recPtr));
- i = findDir(dir, dirName);
- if (i != dir->m_entries.end()) {
- // esyslog("DH: added dir: '%s'", dirName.c_str());
- }
- else {
- // esyslog("DH: panic: didn't found inserted dir: '%s'", dirName.c_str());
- }
- }
- dir = i->second;
- // esyslog("DH: current dir: '%s'", dir->Name().c_str());
- level++;
- }
- else {
- string recName(name.substr(index, name.length() - index));
- RecordingsItemPtr recPtr (new RecordingsItemRec(m_recManPtr->Md5Hash(recording), recName, recording));
- dir->m_entries.insert(pair< string, RecordingsItemPtr > (recName, recPtr));
- // esyslog("DH: added rec: '%s'", recName.c_str());
- }
- } while (pos != string::npos);
- }
- // esyslog("DH: ------ RecordingsTree::RecordingsTree() --------");
- }
-
- RecordingsTree::~RecordingsTree()
- {
- // esyslog("DH: ****** RecordingsTree::~RecordingsTree() ********");
- }
-
- RecordingsTree::Map::iterator RecordingsTree::begin(const vector< string >& path)
- {
- if (path.empty()) {
- return m_root->m_entries.begin();
- }
-
- RecordingsItemPtr recItem = m_root;
- for (vector< string >::const_iterator i = path.begin(); i != path.end(); ++i)
- {
- pair< Map::iterator, Map::iterator> range = recItem->m_entries.equal_range(*i);
- for (Map::iterator iter = range.first; iter != range.second; ++iter) {
- if (iter->second->IsDir()) {
- recItem = iter->second;
- break;
- }
- }
- }
- return recItem->m_entries.begin();
- }
-
- RecordingsTree::Map::iterator RecordingsTree::end(const vector< string >&path)
- {
- if (path.empty()) {
- return m_root->m_entries.end();
- }
-
- RecordingsItemPtr recItem = m_root;
- for (vector< string >::const_iterator i = path.begin(); i != path.end(); ++i)
- {
- pair< Map::iterator, Map::iterator> range = recItem->m_entries.equal_range(*i);
- for (Map::iterator iter = range.first; iter != range.second; ++iter) {
- if (iter->second->IsDir()) {
- recItem = iter->second;
- break;
- }
- }
- }
- return recItem->m_entries.end();
- }
-
- RecordingsTree::Map::iterator RecordingsTree::findDir(RecordingsItemPtr& dir, const string& dirName)
- {
- pair< Map::iterator, Map::iterator > range = dir->m_entries.equal_range(dirName);
- for (Map::iterator i = range.first; i != range.second; ++i) {
- if (i->second->IsDir()) {
- return i;
- }
- }
- return dir->m_entries.end();
- }
-
- RecordingsTree::RecordingsItem::RecordingsItem(const string& name) :
- m_name(name),
- m_entries()
- {
- }
-
- RecordingsTree::RecordingsItem::~RecordingsItem()
- {
- }
-
- RecordingsTree::RecordingsItemDir::RecordingsItemDir() :
- RecordingsItem(""),
- m_level(0)
- {
- }
-
- RecordingsTree::RecordingsItemDir::~RecordingsItemDir()
- {
- }
-
- RecordingsTree::RecordingsItemDir::RecordingsItemDir(const string& name, int level) :
- RecordingsItem(name),
- m_level(level)
- {
- }
-
- RecordingsTree::RecordingsItemRec::RecordingsItemRec(const string& id, const string& name, const cRecording* recording) :
- RecordingsItem(name),
- m_recording(recording),
- m_id(id)
- {
- }
-
- RecordingsTree::RecordingsItemRec::~RecordingsItemRec()
- {
- }
-
- time_t RecordingsTree::RecordingsItemRec::StartTime() const
- {
- return m_recording->start;
- }
-
-
-
- RecordingsManagerPtr LiveRecordingsManager()
- {
- static weak_ptr<RecordingsManager> livingRecMan;
-
- RecordingsManagerPtr r = livingRecMan.lock();
- if (r) {
- return r;
- }
- else {
- RecordingsManagerPtr n(new RecordingsManager);
- livingRecMan = n;
- return n;
- }
- }
-
-} // namespace vdrlive
diff --git a/recordings.h b/recordings.h
deleted file mode 100644
index 81b971f..0000000
--- a/recordings.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef VDR_LIVE_RECORDINGS_H
-#define VDR_LIVE_RECORDINGS_H
-
-#include <ctime>
-#include <map>
-#include <vector>
-#include <vdr/recording.h>
-#include "stdext.h"
-
-namespace vdrlive {
-
- // Forward declations from epg_events.h
- class EpgInfo;
- typedef std::tr1::shared_ptr<EpgInfo> EpgInfoPtr;
-
- class RecordingsManager;
- typedef std::tr1::shared_ptr<RecordingsManager> RecordingsManagerPtr;
-
- class RecordingsManager
- {
- friend RecordingsManagerPtr LiveRecordingsManager();
-
- public:
- /**
- * generates a Md5 hash from a cRecording entry. It can be used
- * to reidentify a recording.
- */
- std::string Md5Hash(const cRecording* recording) const;
-
- /**
- * fetches a cRecording from VDR's Recordings collection. Returns
- * NULL if recording was not found
- */
- const cRecording* GetByMd5Hash(const std::string& hash) const;
-
- /**
- * Determine wether the recording has been archived on
- * removable media (e.g. DVD-ROM)
- */
- static bool IsArchived(const cRecording* recording);
-
- /**
- * Provide an identification of the removable media
- * (e.g. DVD-ROM Number or Name) where the recording has
- * been archived.
- */
- static const std::string GetArchiveId(const cRecording* recording);
-
- static const std::string GetArchiveDescr(const cRecording* recording);
-
- private:
- RecordingsManager();
-
- cThreadLock m_recordingsLock;
- };
-
-
- class RecordingsTree
- {
- public:
-
- class RecordingsItem;
-
- typedef std::tr1::shared_ptr< RecordingsItem > RecordingsItemPtr;
- typedef std::multimap< std::string, RecordingsItemPtr > Map;
-
- class RecordingsItem
- {
- friend class RecordingsTree;
-
- public:
- virtual ~RecordingsItem();
-
- virtual time_t StartTime() const = 0;
- virtual bool IsDir() const = 0;
- virtual const std::string& Name() const { return m_name; }
- virtual const std::string Id() const = 0;
-
- virtual const cRecording* Recording() const { return 0; }
- virtual const cRecordingInfo* RecInfo() const { return 0; }
-
- protected:
- RecordingsItem(const std::string& name);
-
- private:
- std::string m_name;
- Map m_entries;
- };
-
- class RecordingsItemDir : public RecordingsItem
- {
- public:
- RecordingsItemDir();
- RecordingsItemDir(const std::string& name, int level);
-
- virtual ~RecordingsItemDir();
-
- virtual time_t StartTime() const { return 0; }
- virtual bool IsDir() const { return true; }
- virtual const std::string Id() const { std::string e; return e; }
-
- private:
- int m_level;
- };
-
- class RecordingsItemRec : public RecordingsItem
- {
- public:
- RecordingsItemRec(const std::string& id, const std::string& name, const cRecording* recording);
-
- virtual ~RecordingsItemRec();
-
- virtual time_t StartTime() const;
- virtual bool IsDir() const { return false; }
- virtual const std::string Id() const { return m_id; }
-
- virtual const cRecording* Recording() const { return m_recording; }
- virtual const cRecordingInfo* RecInfo() const { return m_recording->Info(); }
-
- private:
- const cRecording *m_recording;
- std::string m_id;
- };
-
- RecordingsTree(RecordingsManagerPtr recManPtr);
-
- virtual ~RecordingsTree();
-
- Map::iterator begin(const std::vector< std::string >& path);
- Map::iterator end(const std::vector< std::string >&path);
-
- int MaxLevel() const { return m_maxLevel; }
-
- private:
- int m_maxLevel;
- RecordingsItemPtr m_root;
- RecordingsManagerPtr m_recManPtr;
-
- Map::iterator findDir(RecordingsItemPtr& dir, const std::string& dirname);
- };
-
- /**
- * return singleton instance of RecordingsManager as a shared Pointer.
- * This ensures that after last use of the RecordingsManager it is
- * deleted. After deletion of the original RecordingsManager a repeated
- * call to this function creates a new RecordingsManager which is again
- * kept alive as long references to it exist.
- */
- RecordingsManagerPtr LiveRecordingsManager();
-
-} // namespace vdrlive
-
-#endif // VDR_LIVE_RECORDINGS_H
diff --git a/tasks.cpp b/tasks.cpp
index 92b893e..d7acaf3 100644
--- a/tasks.cpp
+++ b/tasks.cpp
@@ -3,12 +3,14 @@
#include <vdr/i18n.h>
#include <vdr/menu.h>
#include <vdr/recording.h>
-#include "exception.h"
-#include "recordings.h"
+
#include "stdext.h"
-#include "tasks.h"
+#include "exception.h"
+#include "recman.h"
#include "tools.h"
+#include "tasks.h"
+
namespace vdrlive {
using namespace std;