summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Eskola <timo@tolleri.net>2018-08-29 11:56:19 +0300
committerTimo Eskola <timo@tolleri.net>2018-08-29 11:56:19 +0300
commit72d7261885bf05599310f75883dcdc9d9e190d6c (patch)
tree1cff14186a40f6cfc8d3ea7cf94b2e40e9df069c
parent6deebe52d29a5401e88b0a9337c387a66ee04ea8 (diff)
downloadvdr-plugin-duplicates-72d7261885bf05599310f75883dcdc9d9e190d6c.tar.gz
vdr-plugin-duplicates-72d7261885bf05599310f75883dcdc9d9e190d6c.tar.bz2
Refactored duplicate detection to own classes.
-rw-r--r--HISTORY6
-rw-r--r--Makefile2
-rw-r--r--menu.c231
-rw-r--r--menu.h7
-rw-r--r--po/de_DE.po10
-rw-r--r--po/fi_FI.po10
-rw-r--r--po/it_IT.po10
-rw-r--r--recording.c160
-rw-r--r--recording.h52
9 files changed, 272 insertions, 216 deletions
diff --git a/HISTORY b/HISTORY
index db60e8a..18348c8 100644
--- a/HISTORY
+++ b/HISTORY
@@ -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.
diff --git a/Makefile b/Makefile
index 813bdb4..22afcfb 100644
--- a/Makefile
+++ b/Makefile
@@ -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:
diff --git a/menu.c b/menu.c
index 4323bf4..17ebe3f 100644
--- a/menu.c
+++ b/menu.c
@@ -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!"));
}
diff --git a/menu.h b/menu.h
index c935a6f..3044f72 100644
--- a/menu.h
+++ b/menu.h
@@ -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