2014-10-18 16:50:33 +02:00
|
|
|
#include "recfolderinfo.h"
|
|
|
|
|
|
|
|
|
|
|
|
class cFolderInfoInternList;
|
|
|
|
|
|
|
|
class cRecordingsFolderInfo::cFolderInfoIntern:public cListObject {
|
|
|
|
private:
|
|
|
|
cFolderInfoIntern *_parent;
|
|
|
|
cList<cFolderInfoIntern> *_subFolders;
|
|
|
|
|
|
|
|
cString _name;
|
|
|
|
time_t _latest;
|
|
|
|
int _count;
|
2014-10-19 07:47:42 +02:00
|
|
|
cString _latestFileName;
|
2014-10-18 16:50:33 +02:00
|
|
|
|
2016-03-13 16:02:26 +01:00
|
|
|
void UpdateData(const cRecording *Recording);
|
2014-10-18 16:50:33 +02:00
|
|
|
cFolderInfoIntern *FindSubFolder(const char *Name) const;
|
|
|
|
|
|
|
|
public:
|
|
|
|
cFolderInfoIntern(cFolderInfoIntern *Parent, const char *Name);
|
|
|
|
virtual ~cFolderInfoIntern(void);
|
|
|
|
|
|
|
|
// split Name and find folder-info in tree
|
|
|
|
// if "Add", missing folders are created
|
|
|
|
cFolderInfoIntern *Find(const char *Name, bool Add);
|
|
|
|
|
2016-03-13 16:02:26 +01:00
|
|
|
void Add(const cRecording *Recording);
|
2014-10-18 16:50:33 +02:00
|
|
|
|
|
|
|
cRecordingsFolderInfo::cFolderInfo *GetInfo(void) const;
|
|
|
|
|
|
|
|
cString FullName(void) const;
|
|
|
|
cString ToText(void) const;
|
|
|
|
cString DebugOutput(void) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-10-19 07:47:42 +02:00
|
|
|
cRecordingsFolderInfo::cFolderInfo::cFolderInfo(const char *Name, const char *FullName, time_t Latest, int Count, const char *LatestFileName)
|
2014-10-18 16:50:33 +02:00
|
|
|
{
|
|
|
|
this->Name = Name;
|
|
|
|
this->FullName = FullName;
|
|
|
|
this->Latest = Latest;
|
|
|
|
this->Count = Count;
|
2014-10-19 07:47:42 +02:00
|
|
|
this->LatestFileName= LatestFileName;
|
2014-10-18 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-13 16:02:26 +01:00
|
|
|
cRecordingsFolderInfo::cRecordingsFolderInfo()
|
|
|
|
: _root(NULL)
|
2014-10-18 16:50:33 +02:00
|
|
|
{
|
|
|
|
Rebuild();
|
|
|
|
}
|
|
|
|
|
|
|
|
cRecordingsFolderInfo::~cRecordingsFolderInfo(void)
|
|
|
|
{
|
|
|
|
delete _root;
|
|
|
|
_root = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cRecordingsFolderInfo::Rebuild(void)
|
|
|
|
{
|
2016-03-13 16:02:26 +01:00
|
|
|
cFolderInfoIntern *info;
|
|
|
|
|
|
|
|
delete _root;
|
|
|
|
_root = new cFolderInfoIntern(NULL, "");
|
|
|
|
|
|
|
|
#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
|
|
|
|
LOCK_RECORDINGS_READ;
|
|
|
|
const cRecordings* recordings = Recordings;
|
|
|
|
|
|
|
|
for (const cRecording *rec = recordings->First(); rec; rec = recordings->Next(rec))
|
|
|
|
{
|
|
|
|
info = _root->Find(rec->Folder(), true);
|
|
|
|
info->Add(rec);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
cString folder;
|
|
|
|
cThreadLock RecordingsLock(&Recordings);
|
|
|
|
|
|
|
|
// re-get state with lock held
|
|
|
|
|
|
|
|
Recordings.StateChanged(_recState);
|
|
|
|
|
|
|
|
for (cRecording *rec = Recordings.First(); rec; rec = Recordings.Next(rec))
|
|
|
|
{
|
|
|
|
# if APIVERSNUM < 20102
|
|
|
|
|
2014-10-19 15:40:02 +02:00
|
|
|
const char *recName = rec->Name();
|
2016-03-13 16:02:26 +01:00
|
|
|
if (const char *s = strrchr(recName, FOLDERDELIMCHAR))
|
|
|
|
{
|
2014-10-23 06:08:12 +02:00
|
|
|
folder = recName;
|
|
|
|
folder.Truncate(s - recName);
|
2016-03-13 16:02:26 +01:00
|
|
|
}
|
2014-10-19 15:40:02 +02:00
|
|
|
else
|
2014-10-23 06:08:12 +02:00
|
|
|
folder = "";
|
2016-03-13 16:02:26 +01:00
|
|
|
# else
|
2014-10-19 15:40:02 +02:00
|
|
|
folder = rec->Folder();
|
2016-03-13 16:02:26 +01:00
|
|
|
# endif
|
2014-10-19 07:47:42 +02:00
|
|
|
info = _root->Find(*folder, true);
|
2014-10-18 16:50:33 +02:00
|
|
|
info->Add(rec);
|
|
|
|
}
|
2016-03-13 16:02:26 +01:00
|
|
|
#endif
|
2014-10-18 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cRecordingsFolderInfo::cFolderInfo *cRecordingsFolderInfo::Get(const char *Folder)
|
|
|
|
{
|
2016-03-13 16:02:26 +01:00
|
|
|
cMutexLock lock(&_rootLock);
|
|
|
|
|
|
|
|
#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
|
|
|
|
static cStateKey recordingsKey;
|
|
|
|
const cRecordings* recordings = cRecordings::GetRecordingsRead(recordingsKey);
|
|
|
|
int recStateChanged = recordings != 0;
|
|
|
|
if (recordings) recordingsKey.Remove();
|
|
|
|
#else
|
|
|
|
int recStateChanged = Recordings.StateChanged(_recState);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (recStateChanged || (_root == NULL))
|
|
|
|
Rebuild();
|
|
|
|
|
|
|
|
cFolderInfoIntern *info = _root->Find(Folder, false);
|
|
|
|
if (info == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return info->GetInfo();
|
2014-10-18 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cString cRecordingsFolderInfo::DebugOutput(void) const
|
|
|
|
{
|
|
|
|
cMutexLock lock(&_rootLock);
|
|
|
|
|
|
|
|
return _root->DebugOutput();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cRecordingsFolderInfo::cFolderInfoIntern::cFolderInfoIntern(cFolderInfoIntern *Parent, const char *Name)
|
|
|
|
:_parent(Parent)
|
|
|
|
,_name(Name)
|
|
|
|
,_latest(0)
|
|
|
|
,_count(0)
|
2014-10-19 07:47:42 +02:00
|
|
|
,_latestFileName("")
|
2014-10-18 16:50:33 +02:00
|
|
|
{
|
|
|
|
_subFolders = new cList<cFolderInfoIntern>();
|
|
|
|
}
|
|
|
|
|
|
|
|
cRecordingsFolderInfo::cFolderInfoIntern::~cFolderInfoIntern(void)
|
|
|
|
{
|
|
|
|
delete _subFolders;
|
|
|
|
_subFolders = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cRecordingsFolderInfo::cFolderInfoIntern *cRecordingsFolderInfo::cFolderInfoIntern::Find(const char *Name, bool Add)
|
|
|
|
{
|
|
|
|
cFolderInfoIntern *info = NULL;
|
|
|
|
if (Add)
|
|
|
|
info = this;
|
|
|
|
|
|
|
|
if (Name && *Name) {
|
|
|
|
static char delim[2] = { FOLDERDELIMCHAR, 0 };
|
|
|
|
char *strtok_next;
|
|
|
|
cFolderInfoIntern *next;
|
|
|
|
char *folder = strdup(Name);
|
|
|
|
info = this;
|
|
|
|
for (char *t = strtok_r(folder, delim, &strtok_next); t; t = strtok_r(NULL, delim, &strtok_next)) {
|
|
|
|
next = info->FindSubFolder(t);
|
|
|
|
if (next == NULL) {
|
|
|
|
if (!Add) {
|
|
|
|
info = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
next = new cFolderInfoIntern(info, t);
|
|
|
|
info->_subFolders->Add(next);
|
|
|
|
}
|
|
|
|
info = next;
|
|
|
|
}
|
|
|
|
free(folder);
|
|
|
|
}
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2016-03-13 16:02:26 +01:00
|
|
|
void cRecordingsFolderInfo::cFolderInfoIntern::UpdateData(const cRecording *Recording)
|
2014-10-18 16:50:33 +02:00
|
|
|
{
|
|
|
|
// count every recording
|
|
|
|
_count++;
|
|
|
|
|
|
|
|
// update date if newer
|
|
|
|
time_t recdate = Recording->Start();
|
2014-10-19 07:47:42 +02:00
|
|
|
if (_latest < recdate) {
|
2014-10-18 16:50:33 +02:00
|
|
|
_latest = recdate;
|
2014-10-19 07:47:42 +02:00
|
|
|
_latestFileName = Recording->FileName();
|
|
|
|
}
|
2014-10-18 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cRecordingsFolderInfo::cFolderInfoIntern *cRecordingsFolderInfo::cFolderInfoIntern::FindSubFolder(const char *Name) const
|
|
|
|
{
|
|
|
|
for (cRecordingsFolderInfo::cFolderInfoIntern *info = _subFolders->First(); info; info = _subFolders->Next(info)) {
|
|
|
|
if (strcmp(info->_name, Name) == 0)
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-03-13 16:02:26 +01:00
|
|
|
void cRecordingsFolderInfo::cFolderInfoIntern::Add(const cRecording *Recording)
|
2014-10-18 16:50:33 +02:00
|
|
|
{
|
|
|
|
if (Recording == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// update this and all parent folders
|
|
|
|
for (cFolderInfoIntern *p = this; p; p = p->_parent)
|
|
|
|
p->UpdateData(Recording);
|
|
|
|
}
|
|
|
|
|
|
|
|
cRecordingsFolderInfo::cFolderInfo *cRecordingsFolderInfo::cFolderInfoIntern::GetInfo(void) const
|
|
|
|
{
|
2014-10-19 07:47:42 +02:00
|
|
|
return new cRecordingsFolderInfo::cFolderInfo(*_name, *FullName(), _latest, _count, *_latestFileName);
|
2014-10-18 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cString cRecordingsFolderInfo::cFolderInfoIntern::FullName(void) const
|
|
|
|
{
|
|
|
|
static char delim[2] = { FOLDERDELIMCHAR, 0 };
|
|
|
|
|
|
|
|
cString name = _name;
|
|
|
|
for (cFolderInfoIntern *p = _parent; p; p = p->_parent) {
|
|
|
|
// don't add FOLDERDELIMCHAR at start of FullName
|
|
|
|
if (p->_parent == NULL)
|
|
|
|
break;
|
|
|
|
name = cString::sprintf("%s%s%s", *p->_name, delim, *name);
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
cString cRecordingsFolderInfo::cFolderInfoIntern::ToText(void) const
|
|
|
|
{
|
|
|
|
return cString::sprintf("%s (%d recordings, latest: %s)\n", *FullName(), _count, *ShortDateString(_latest));
|
|
|
|
}
|
|
|
|
|
|
|
|
cString cRecordingsFolderInfo::cFolderInfoIntern::DebugOutput(void) const
|
|
|
|
{
|
|
|
|
cString output = ToText();
|
|
|
|
for (cFolderInfoIntern *i = _subFolders->First(); i; i = _subFolders->Next(i))
|
|
|
|
output = cString::sprintf("%s%s", *output, *i->DebugOutput());
|
|
|
|
return output;
|
|
|
|
}
|