diff options
author | Timo Eskola <timo@tolleri.net> | 2018-08-29 11:56:19 +0300 |
---|---|---|
committer | Timo Eskola <timo@tolleri.net> | 2018-08-29 11:56:19 +0300 |
commit | 72d7261885bf05599310f75883dcdc9d9e190d6c (patch) | |
tree | 1cff14186a40f6cfc8d3ea7cf94b2e40e9df069c | |
parent | 6deebe52d29a5401e88b0a9337c387a66ee04ea8 (diff) | |
download | vdr-plugin-duplicates-72d7261885bf05599310f75883dcdc9d9e190d6c.tar.gz vdr-plugin-duplicates-72d7261885bf05599310f75883dcdc9d9e190d6c.tar.bz2 |
Refactored duplicate detection to own classes.
-rw-r--r-- | HISTORY | 6 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | menu.c | 231 | ||||
-rw-r--r-- | menu.h | 7 | ||||
-rw-r--r-- | po/de_DE.po | 10 | ||||
-rw-r--r-- | po/fi_FI.po | 10 | ||||
-rw-r--r-- | po/it_IT.po | 10 | ||||
-rw-r--r-- | recording.c | 160 | ||||
-rw-r--r-- | recording.h | 52 |
9 files changed, 272 insertions, 216 deletions
@@ -1,6 +1,12 @@ VDR Plugin 'duplicates' Revision History ---------------------------------------- +2018-08-29: Version 0.2.0 + +- Fixed compilation with VDR 2.4.0. +- Improved delete and hide performance. +- Refactored duplicate detection to own classes. + 2015-08-31: Version 0.1.0 - Added hiding of duplicate recordings. @@ -53,7 +53,7 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ### The object files (add further files here): -OBJS = $(PLUGIN).o menu.o config.o visibility.o +OBJS = $(PLUGIN).o menu.o config.o visibility.o recording.o ### The main target: @@ -13,12 +13,9 @@ #include <vdr/menu.h> #include <vdr/status.h> #include <vdr/interface.h> -#include <sys/time.h> #if VDRVERSNUM >= 20301 #include <vdr/svdrp.h> #endif -#include <string> -#include <sstream> static inline cOsdItem *SeparatorItem(const char *Label) { cOsdItem *Item = new cOsdItem(cString::sprintf("----- %s -----", Label)); @@ -101,88 +98,6 @@ eOSState cMenuDuplicate::ProcessKey(eKeys Key) return state; } -// --- cDuplicateRecording ------------------------------------------------------- - -class cDuplicateRecording : public cListObject { -private: - bool checked; - cVisibility visibility; - std::string fileName; - std::string name; - std::string title; - std::string description; -public: - cDuplicateRecording(const cRecording *Recording); - cDuplicateRecording(const cDuplicateRecording &DuplicateRecording); - bool HasDescription(void) const { return ! description.empty(); } - bool IsDuplicate(cDuplicateRecording *DuplicateRecording); - void SetChecked(bool chkd = true) { checked = chkd; } - bool Checked() { return checked; } - cVisibility Visibility() { return visibility; } - std::string FileName(void) { return fileName; } - std::string Name(void) { return name; } -}; - -cDuplicateRecording::cDuplicateRecording(const cRecording *Recording) : visibility(Recording->FileName()) { - checked = false; - fileName = std::string(Recording->FileName()); -#if defined LIEMIKUUTIO && LIEMIKUUTIO < 131 - name = std::string(Recording->Title('\t', true, -1, false)); -#else - name = std::string(Recording->Title('\t', true)); -#endif - if (dc.title && Recording->Info()->Title()) - title = std::string(Recording->Info()->Title()); - else - title = std::string(); - std::stringstream desc; - if (Recording->Info()->ShortText()) - desc << std::string(Recording->Info()->ShortText()); - if (Recording->Info()->Description()) - desc << std::string(Recording->Info()->Description()); - description = desc.str(); - while(true) { - size_t found = description.find("|"); - if (found == std::string::npos) - break; - description.replace(found, 1, ""); - } - while(true) { - size_t found = description.find(" "); - if (found == std::string::npos) - break; - description.replace(found, 1, ""); - } -} - -cDuplicateRecording::cDuplicateRecording(const cDuplicateRecording &DuplicateRecording) : - checked(DuplicateRecording.checked), - visibility(DuplicateRecording.visibility), - fileName(DuplicateRecording.fileName), - name(DuplicateRecording.name), - title(DuplicateRecording.title), - description(DuplicateRecording.description) {} - -bool cDuplicateRecording::IsDuplicate(cDuplicateRecording *DuplicateRecording) { - if (!HasDescription() || !DuplicateRecording->HasDescription()) - return false; - - size_t found; - if (dc.title) { - found = title.size() > DuplicateRecording->title.size() ? - title.find(DuplicateRecording->title) : DuplicateRecording->title.find(title); - if (found == std::string::npos) - return false; - } - - found = description.size() > DuplicateRecording->description.size() ? - description.find(DuplicateRecording->description) : DuplicateRecording->description.find(description); - if (found != std::string::npos) - return true; - - return false; -} - // --- cMenuDuplicateItem ---------------------------------------------------- class cMenuDuplicateItem : public cOsdItem { @@ -197,7 +112,7 @@ public: cMenuDuplicateItem::cMenuDuplicateItem(cDuplicateRecording *DuplicateRecording) : visibility(DuplicateRecording->Visibility()) { fileName = DuplicateRecording->FileName(); - SetText(DuplicateRecording->Name().c_str()); + SetText(DuplicateRecording->Text()); } // --- cMenuDuplicates ------------------------------------------------------- @@ -245,96 +160,22 @@ void cMenuDuplicates::SetHelpKeys(void) { } void cMenuDuplicates::Set(bool Refresh) { - struct timeval startTime, stopTime; - gettimeofday(&startTime, NULL); -#ifdef DEBUG_VISIBILITY - cVisibility::ClearCounters(); - int isDuplicateCount = 0, menuDuplicateItemCount = 0; -#endif + DuplicateRecordings.Update(); const char *CurrentRecording = NULL; int currentIndex = -1; if (Refresh) currentIndex = Current(); else CurrentRecording = cReplayControl::LastReplayed(); - cList<cDuplicateRecording> descriptionless; - cList<cDuplicateRecording> recordings; - Clear(); - { -#if VDRVERSNUM >= 20301 - cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); // write access is necessary for sorting! - Recordings->Sort(); - for (const cRecording *recording = Recordings->First(); recording; recording = Recordings->Next(recording)) { -#else - cThreadLock RecordingsLock(&Recordings); - Recordings.Sort(); - for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { -#endif - cDuplicateRecording *Item = new cDuplicateRecording(recording); - if (Item->HasDescription()) - recordings.Add(Item); - else if (dc.hidden || Item->Visibility().Read() != HIDDEN) - descriptionless.Add(Item); - } -#if VDRVERSNUM >= 20301 - recordingsStateKey.Remove(false); // sorting doesn't count as a real modification -#endif - } - for (cDuplicateRecording *recording = recordings.First(); recording; recording = recordings.Next(recording)) { - if (!recording->Checked()) { - recording->SetChecked(); - cList<cDuplicateRecording> duplicates; - duplicates.Add(new cDuplicateRecording(*recording)); - for (cDuplicateRecording *compare = recordings.First(); compare; compare = recordings.Next(compare)) { - if (!compare->Checked()) { -#ifdef DEBUG_VISIBILITY - isDuplicateCount++; -#endif - if (recording->IsDuplicate(compare)) { - duplicates.Add(new cDuplicateRecording(*compare)); - compare->SetChecked(); - } - } - } - int count = duplicates.Count(); - if (!dc.hidden && count > 1) { - for (cDuplicateRecording *DuplicateRecording = duplicates.First(); DuplicateRecording; DuplicateRecording = duplicates.Next(DuplicateRecording)) { - if (DuplicateRecording->Visibility().Read() == HIDDEN) - count--; - } - } - if (count > 1) { - Add(SeparatorItem(cString::sprintf(tr("%d duplicate recordings"), duplicates.Count()))); - for (cDuplicateRecording *DuplicateRecording = duplicates.First(); DuplicateRecording; DuplicateRecording = duplicates.Next(DuplicateRecording)) { - if (dc.hidden || DuplicateRecording->Visibility().Read() != HIDDEN) { - cMenuDuplicateItem *Item = new cMenuDuplicateItem(DuplicateRecording); -#ifdef DEBUG_VISIBILITY - menuDuplicateItemCount++; -#endif - if (*Item->Text()) { - Add(Item); - if (CurrentRecording && strcmp(CurrentRecording, Item->FileName()) == 0) - SetCurrent(Item); - } else - delete Item; - } - } - } - } - } - if (descriptionless.Count() > 0) - Add(SeparatorItem(cString::sprintf(tr("%d recordings without description"), descriptionless.Count()))); - for (cDuplicateRecording *DescriptionlessRecording = descriptionless.First(); DescriptionlessRecording; DescriptionlessRecording = descriptionless.Next(DescriptionlessRecording)) { - cMenuDuplicateItem *Item = new cMenuDuplicateItem(DescriptionlessRecording); -#ifdef DEBUG_VISIBILITY - menuDuplicateItemCount++; -#endif - if (*Item->Text()) { + cMutexLock MutexLock(&DuplicateRecordings.mutex); + for (cDuplicateRecording *Duplicates = DuplicateRecordings.First(); Duplicates; Duplicates = DuplicateRecordings.Next(Duplicates)) { + Add(SeparatorItem(Duplicates->Text())); + for (cDuplicateRecording *Duplicate = Duplicates->Duplicates()->First(); Duplicate; Duplicate = Duplicates->Duplicates()->Next(Duplicate)) { + cMenuDuplicateItem *Item = new cMenuDuplicateItem(Duplicate); Add(Item); if (CurrentRecording && strcmp(CurrentRecording, Item->FileName()) == 0) SetCurrent(Item); - } else - delete Item; + } } if (Count() == 0) Add(SeparatorItem(cString::sprintf(tr("%d duplicate recordings"), 0))); @@ -342,14 +183,6 @@ void cMenuDuplicates::Set(bool Refresh) { SetCurrentIndex(currentIndex); Display(); } - gettimeofday(&stopTime, NULL); - double seconds = (((long long)stopTime.tv_sec * 1000000 + stopTime.tv_usec) - ((long long)startTime.tv_sec * 1000000 + startTime.tv_usec)) / 1000000.0; -#ifdef DEBUG_VISIBILITY - dsyslog("duplicates: Displaying of duplicates took %.2f seconds, is duplicate count %d, get count %d, read count %d, access count %d, duplicate item count %d.", - seconds, isDuplicateCount, cVisibility::getCount, cVisibility::readCount, cVisibility::accessCount, menuDuplicateItemCount); -#else - dsyslog("duplicates: Displaying of duplicates took %.2f seconds.", seconds); -#endif } #if VDRVERSNUM >= 20301 @@ -367,7 +200,9 @@ static bool TimerStillRecording(const char *FileName) { if (cRecordControl *rc = cRecordControls::GetRecordControl(FileName)) { // local timer if (Interface->Confirm(trVDR("Timer still recording - really delete?"))) { +#if VDRVERSNUM >= 20301 LOCK_TIMERS_WRITE; +#endif if (cTimer *Timer = rc->Timer()) { Timer->Skip(); #if VDRVERSNUM >= 20301 @@ -441,6 +276,24 @@ void cMenuDuplicates::SetCurrentIndex(int index) { } } +void cMenuDuplicates::Del(int index) { + cOsdMenu::Del(index); + // remove items that have less than 2 duplicates + int d = 0; + for (int i = Count() - 1; i >= 0; i--) { + if (!SelectableItem(i)) { + if (d < 2) { + for (int j = 0; j <= d; j++) { + cOsdMenu::Del(i); + } + } + d = 0; + } else + d++; + } + SetCurrentIndex(index); +} + eOSState cMenuDuplicates::Delete(void) { if (HasSubMenu() || Count() == 0) return osContinue; @@ -494,22 +347,7 @@ eOSState cMenuDuplicates::Delete(void) { Recordings->SetModified(); recordingsStateKey.Remove(); #endif - int currentIndex = Current(); - cOsdMenu::Del(currentIndex); - // remove items that have less than 2 duplicates - int d = 0; - for (int i = Count() - 1; i >= 0; i--) { - if (!SelectableItem(i)) { - if (d < 2) { - for (int j = 0; j <= d; j++) { - cOsdMenu::Del(i); - } - } - d = 0; - } else - d++; - } - SetCurrentIndex(currentIndex); + Del(Current()); SetHelpKeys(); Display(); } else @@ -577,11 +415,14 @@ eOSState cMenuDuplicates::ToggleHidden(void) { bool hidden = ri->Visibility().Read() == HIDDEN; if (Interface->Confirm(hidden ? tr("Unhide recording?") : tr("Hide recording?"))) { if (ri->Visibility().Write(hidden)) { - if (dc.hidden) + if (dc.hidden) { ri->Visibility().Set(!hidden); - else - Set(true); - SetHelpKeys(); + SetHelpKeys(); + } else { + Del(Current()); + SetHelpKeys(); + Display(); + } } else Skins.Message(mtError, tr("Error while setting visibility!")); } @@ -16,11 +16,7 @@ #include <vdr/menuitems.h> #include <vdr/videodir.h> #include "config.h" - -// Define empty locking macros for backwards compatibility -#ifndef LOCK_TIMERS_WRITE -#define LOCK_TIMERS_WRITE -#endif +#include "recording.h" class cMenuSetupDuplicates; @@ -38,6 +34,7 @@ private: void SetHelpKeys(void); void Set(bool Refresh = false); void SetCurrentIndex(int index); + void Del(int index); eOSState Play(void); eOSState Setup(void); eOSState Delete(void); diff --git a/po/de_DE.po b/po/de_DE.po index a3c4d0a..e701287 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: vdr-duplicates 0.1.0\n" "Report-Msgid-Bugs-To: <see README>\n" -"POT-Creation-Date: 2018-08-24 13:00+0300\n" +"POT-Creation-Date: 2018-08-28 14:43+0300\n" "PO-Revision-Date: 2015-09-06 17:57+0100\n" "Last-Translator: Joerg Bornkessel <hd_brummy@gentoo.org>\n" "Language-Team: Deutsch\n" @@ -35,10 +35,6 @@ msgstr "Aufnahme sichtbar machen" msgid "%d duplicate recordings" msgstr "%d doppelte Aufnahmen" -#, c-format -msgid "%d recordings without description" -msgstr "%d Aufnahmen ohne Beschreibung" - msgid "Unhide recording?" msgstr "Versteckte Aufnahme sichtbar machen?" @@ -53,3 +49,7 @@ msgstr "Vergleiche Titel" msgid "Show hidden" msgstr "Zeige versteckte Aufnahmen" + +#, c-format +msgid "%d recordings without description" +msgstr "%d Aufnahmen ohne Beschreibung" diff --git a/po/fi_FI.po b/po/fi_FI.po index 6bf2513..833d29d 100644 --- a/po/fi_FI.po +++ b/po/fi_FI.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: vdr-duplicates 0.0.1\n" "Report-Msgid-Bugs-To: <see README>\n" -"POT-Creation-Date: 2018-08-24 13:00+0300\n" +"POT-Creation-Date: 2018-08-28 14:43+0300\n" "PO-Revision-Date: 2011-12-12 19:57+0300\n" "Last-Translator: Timo Eskola <timo@tolleri.net>\n" "Language-Team: Finnish\n" @@ -34,10 +34,6 @@ msgstr "Älä piilota" msgid "%d duplicate recordings" msgstr "%d päällekkäistä tallennetta" -#, c-format -msgid "%d recordings without description" -msgstr "%d tallennetta ilman kuvausta" - msgid "Unhide recording?" msgstr "Älä piilota tallennetta?" @@ -52,3 +48,7 @@ msgstr "Vertaa otsikkoa" msgid "Show hidden" msgstr "Näytä piilotetut" + +#, c-format +msgid "%d recordings without description" +msgstr "%d tallennetta ilman kuvausta" diff --git a/po/it_IT.po b/po/it_IT.po index 37e704b..e471943 100644 --- a/po/it_IT.po +++ b/po/it_IT.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: vdr-duplicates 0.0.1\n" "Report-Msgid-Bugs-To: <see README>\n" -"POT-Creation-Date: 2018-08-24 13:00+0300\n" +"POT-Creation-Date: 2018-08-28 14:43+0300\n" "PO-Revision-Date: 2011-06-05 23:37+0100\n" "Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" "Language-Team: \n" @@ -37,10 +37,6 @@ msgstr "" msgid "%d duplicate recordings" msgstr "%d registrazioni duplicate" -#, c-format -msgid "%d recordings without description" -msgstr "%d registrazioni senza descrizione" - msgid "Unhide recording?" msgstr "" @@ -55,3 +51,7 @@ msgstr "" msgid "Show hidden" msgstr "" + +#, c-format +msgid "%d recordings without description" +msgstr "%d registrazioni senza descrizione" diff --git a/recording.c b/recording.c new file mode 100644 index 0000000..c67bf61 --- /dev/null +++ b/recording.c @@ -0,0 +1,160 @@ +/* + * recording.c: Duplicate recording handling. + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#include "config.h" +#include "recording.h" +#include <sys/time.h> +#include <sstream> + +// --- cDuplicateRecording ------------------------------------------------------- + +cDuplicateRecording::cDuplicateRecording(void) : visibility(NULL) { + duplicates = new cList<cDuplicateRecording>; +} + +cDuplicateRecording::cDuplicateRecording(const cRecording *Recording) : visibility(Recording->FileName()) { + checked = false; + fileName = std::string(Recording->FileName()); +#if defined LIEMIKUUTIO && LIEMIKUUTIO < 131 + text = std::string(Recording->Title('\t', true, -1, false)); +#else + text = std::string(Recording->Title('\t', true)); +#endif + if (dc.title && Recording->Info()->Title()) + title = std::string(Recording->Info()->Title()); + else + title = std::string(); + std::stringstream desc; + if (Recording->Info()->ShortText()) + desc << std::string(Recording->Info()->ShortText()); + if (Recording->Info()->Description()) + desc << std::string(Recording->Info()->Description()); + description = desc.str(); + while(true) { + size_t found = description.find("|"); + if (found == std::string::npos) + break; + description.replace(found, 1, ""); + } + while(true) { + size_t found = description.find(" "); + if (found == std::string::npos) + break; + description.replace(found, 1, ""); + } + duplicates = NULL; +} + +cDuplicateRecording::cDuplicateRecording(const cDuplicateRecording &DuplicateRecording) : + checked(DuplicateRecording.checked), + visibility(DuplicateRecording.visibility), + fileName(DuplicateRecording.fileName), + text(DuplicateRecording.text), + title(DuplicateRecording.title), + description(DuplicateRecording.description), + duplicates(DuplicateRecording.duplicates) {} + +cDuplicateRecording::~cDuplicateRecording() { + delete duplicates; +} + +bool cDuplicateRecording::IsDuplicate(cDuplicateRecording *DuplicateRecording) { + if (!HasDescription() || !DuplicateRecording->HasDescription()) + return false; + + size_t found; + if (dc.title) { + found = title.size() > DuplicateRecording->title.size() ? + title.find(DuplicateRecording->title) : DuplicateRecording->title.find(title); + if (found == std::string::npos) + return false; + } + + found = description.size() > DuplicateRecording->description.size() ? + description.find(DuplicateRecording->description) : DuplicateRecording->description.find(description); + if (found != std::string::npos) + return dc.hidden || visibility.Read() != HIDDEN && DuplicateRecording->visibility.Read() != HIDDEN; + + return false; +} + +// --- cDuplicateRecordings ------------------------------------------------------ + +cDuplicateRecordings::cDuplicateRecordings(void) {} + +void cDuplicateRecordings::Update(void) { + struct timeval startTime, stopTime; + gettimeofday(&startTime, NULL); + cMutexLock MutexLock(&mutex); +#ifdef DEBUG_VISIBILITY + cVisibility::ClearCounters(); + int isDuplicateCount = 0; +#endif + cDuplicateRecording *descriptionless = new cDuplicateRecording(); + cList<cDuplicateRecording> recordings; + Clear(); + { +#if VDRVERSNUM >= 20301 + cRecordings *Recordings = cRecordings::GetRecordingsWrite(recordingsStateKey); // write access is necessary for sorting! + Recordings->Sort(); + for (const cRecording *recording = Recordings->First(); recording; recording = Recordings->Next(recording)) { +#else + cThreadLock RecordingsLock(&Recordings); + Recordings.Sort(); + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { +#endif + cDuplicateRecording *Item = new cDuplicateRecording(recording); + if (Item->HasDescription()) + recordings.Add(Item); + else if (dc.hidden || Item->Visibility().Read() != HIDDEN) + descriptionless->Duplicates()->Add(Item); + } +#if VDRVERSNUM >= 20301 + recordingsStateKey.Remove(false); // sorting doesn't count as a real modification +#endif + } + for (cDuplicateRecording *recording = recordings.First(); recording; recording = recordings.Next(recording)) { + if (!recording->Checked()) { + recording->SetChecked(); + cDuplicateRecording *duplicates = new cDuplicateRecording(); + duplicates->Duplicates()->Add(new cDuplicateRecording(*recording)); + for (cDuplicateRecording *compare = recordings.First(); compare; compare = recordings.Next(compare)) { + if (!compare->Checked()) { +#ifdef DEBUG_VISIBILITY + isDuplicateCount++; +#endif + if (recording->IsDuplicate(compare)) { + duplicates->Duplicates()->Add(new cDuplicateRecording(*compare)); + compare->SetChecked(); + } + } + } + if (duplicates->Duplicates()->Count() > 1) { + duplicates->SetText(cString::sprintf(tr("%d duplicate recordings"), duplicates->Duplicates()->Count())); + Add(duplicates); + } else + delete duplicates; + } + } + if (descriptionless->Duplicates()->Count() > 0) { + descriptionless->SetText(cString::sprintf(tr("%d recordings without description"), descriptionless->Duplicates()->Count())); + Add(descriptionless); + } else + delete descriptionless; + gettimeofday(&stopTime, NULL); + double seconds = (((long long)stopTime.tv_sec * 1000000 + stopTime.tv_usec) - ((long long)startTime.tv_sec * 1000000 + startTime.tv_usec)) / 1000000.0; +#ifdef DEBUG_VISIBILITY + dsyslog("duplicates: Scanning of duplicates took %.2f seconds, is duplicate count %d, get count %d, read count %d, access count %d.", + seconds, isDuplicateCount, cVisibility::getCount, cVisibility::readCount, cVisibility::accessCount); +#else + dsyslog("duplicates: Scanning of duplicates took %.2f seconds.", seconds); +#endif +} + +cDuplicateRecordings DuplicateRecordings; + diff --git a/recording.h b/recording.h new file mode 100644 index 0000000..0987af4 --- /dev/null +++ b/recording.h @@ -0,0 +1,52 @@ +/* + * recording.h: Duplicate recording handling. + * + * See the README file for copyright information and how to reach the author. + * + * $Id$ + */ + +#ifndef _DUPLICATES_RECORDING_H +#define _DUPLICATES_RECORDING_H + +#include "visibility.h" +#include <vdr/recording.h> +#include <string> + +// --- cDuplicateRecording ------------------------------------------------------- + +class cDuplicateRecording : public cListObject { +private: + bool checked; + cVisibility visibility; + std::string fileName; + std::string text; + std::string title; + std::string description; + cList<cDuplicateRecording> *duplicates; +public: + cDuplicateRecording(void); + cDuplicateRecording(const cRecording *Recording); + cDuplicateRecording(const cDuplicateRecording &DuplicateRecording); + ~cDuplicateRecording(); + bool HasDescription(void) const { return ! description.empty(); } + bool IsDuplicate(cDuplicateRecording *DuplicateRecording); + void SetChecked(bool chkd = true) { checked = chkd; } + bool Checked() { return checked; } + cVisibility Visibility() { return visibility; } + std::string FileName(void) { return fileName; } + void SetText(const char *t) { text = std::string(t); } + const char *Text(void) { return text.c_str(); } + cList<cDuplicateRecording> *Duplicates(void) { return duplicates; } +}; + +class cDuplicateRecordings : public cList<cDuplicateRecording> { +public: + cDuplicateRecordings(void); + cMutex mutex; + void Update(void); +}; + +extern cDuplicateRecordings DuplicateRecordings; + +#endif |