Lately I have been working on a modification of the funcionality of "Recover Movies" in the web interface of Enigma. Below this text I inserted a patch.
In the original image the file recordings.epl is completely deleted and filled again every time the option "Recover Movies" is chosen. The description field is always filled with the comlete filename (minus ".ts").
This has been modified. First recordings.epl is read. The contents of the description field will be reused. All records of non-existant recordings are deleted. New records will be added for recordings not yet in recordings.epl.
If an existing description equals the filename minus ".ts" then the contents of the description is recreated by using the right part of the filename.
The records will be sorted on the description. This was my choice. Maybe another sorting order is more convenient.
One big advantage is that once you edit the description (manually) these changes will be preserved. This opens the posibility to make applications that support the modification of descriptions of recordings. This could be a next step in the webinterface
Please let me know what you think of it.
Best regards,
Sat-turner
Here is the patch (thanks PLi for testing it):
Code: Alles auswählen
diff -ur enigma.org/src/enigma_dyn.cpp enigma/src/enigma_dyn.cpp
--- enigma.org/src/enigma_dyn.cpp 2005-03-16 10:00:55.000000000 +0100
+++ enigma/src/enigma_dyn.cpp 2005-03-20 18:31:37.489477808 +0100
@@ -1787,36 +1787,271 @@
}
#ifndef DISABLE_FILE
+// Try to extract the description from the filename.
+eString getDesc( const eString& str )
+{
+ unsigned int leftbound, rightbound ;
+ eString tbtrimmed ;
+
+ leftbound = str.find( '-' ) ;
+ rightbound = str.find( '-', leftbound + 1 ) ;
+ if ( ( rightbound == eString::npos ) || ( rightbound - leftbound < 1 ) )
+ {
+ tbtrimmed = str ;
+ } else {
+ tbtrimmed = str.substr( leftbound + 1, rightbound - leftbound - 1 ) ;
+ }
+
+ leftbound = tbtrimmed.find_first_not_of( ' ' ) ;
+ rightbound = tbtrimmed.find_last_not_of( ' ' ) ;
+
+ // If the extracted description is empty use the value of str as the description.
+ if ( rightbound - leftbound < 1 ) {
+ tbtrimmed = str ;
+ leftbound = tbtrimmed.find_first_not_of( ' ' ) ;
+ rightbound = tbtrimmed.find_last_not_of( ' ' ) ;
+ }
+ return tbtrimmed.substr( leftbound, rightbound - leftbound + 1 ) ;
+}
+
+struct rec_entry {
+ eString serv_line ;
+ eString desc_line ;
+ eString type_line ;
+ eString path_line ;
+ rec_entry *pnext_entry ;
+} ;
+
+void sort_entries( rec_entry **ppthe_top ) {
+ rec_entry *pprev_entry, *pcur_entry, *pold_chain ;
+
+ // Return if chain is empty.
+ if ( *ppthe_top == NULL )
+ return ;
+
+ // Make a sorted new chain under ppthe_top.
+ pold_chain = (*ppthe_top)->pnext_entry ;
+ (*ppthe_top)->pnext_entry = NULL ;
+ while ( pold_chain != NULL ) {
+ pprev_entry = NULL ;
+ pcur_entry = *ppthe_top ;
+ while ( ( pcur_entry != NULL ) && ( pold_chain->desc_line.compare( pcur_entry->desc_line ) > 0 ) ) {
+ pprev_entry = pcur_entry ;
+ pcur_entry = pcur_entry->pnext_entry ;
+ }
+ // If inserted before first element
+ if ( pprev_entry == NULL ) {
+ *ppthe_top = pold_chain ;
+ pold_chain = pold_chain->pnext_entry ;
+ (*ppthe_top)->pnext_entry = pcur_entry ;
+ } else {
+ pprev_entry->pnext_entry = pold_chain ;
+ pold_chain = pold_chain->pnext_entry ;
+ pprev_entry->pnext_entry->pnext_entry = pcur_entry ;
+ }
+ }
+}
+
+void insert_entry( rec_entry **ppthe_top, rec_entry *pnew_one ) {
+ rec_entry *pprev_entry, *pcur_entry ;
+
+ // Insert element into the entry chain in the right place.
+ // Order by path field and avoid duplicate entries.
+ if ( *ppthe_top == NULL ) {
+ // First new element.
+ *ppthe_top = pnew_one ;
+ (*ppthe_top)->pnext_entry = NULL ;
+ } else {
+ pprev_entry = NULL ;
+ pcur_entry = *ppthe_top ;
+ while ( ( pcur_entry != NULL )
+ && ( pnew_one->path_line.compare( pcur_entry->path_line ) > 0 ) ) {
+ pprev_entry = pcur_entry ;
+ pcur_entry = pcur_entry->pnext_entry ;
+ }
+ // Insert if this entry not already exists
+ if ( ( pcur_entry == NULL ) || ( pcur_entry->path_line.compare( pnew_one->path_line ) != 0 ) ) {
+ pnew_one->pnext_entry = pcur_entry ;
+ if ( pprev_entry == NULL ) {
+ *ppthe_top = pnew_one ;
+ } else {
+ pprev_entry->pnext_entry = pnew_one ;
+ }
+ } else
+ delete pnew_one ;
+ }
+}
+
+// Clear entry chain from memory.
+void clear_entries( rec_entry *pthe_top )
+{
+ rec_entry *pcurrent ;
+ pcurrent = pthe_top ;
+ while ( pthe_top != NULL ) {
+ pcurrent = pthe_top->pnext_entry ;
+ delete pthe_top ;
+ pthe_top = pcurrent ;
+ }
+}
+
+// Recover index with recordings on harddisk in /hdd/movie.
bool rec_movies()
{
+ FILE * rec ;
+ rec_entry *ptop_entry = NULL ;
+ rec_entry *pcurrent_entry, *pprevious_entry, *pnew_entry, *pentry_tbd ;
+ eString filen ;
+ char ln_read_from_file[256] ;
+ int linenr, valid_file ;
+
+ // First read existing entries.
+ rec = fopen("/hdd/movie/recordings.epl", "r");
+ if ( rec )
+ {
+ linenr = 0 ;
+ valid_file = 1 ; // The file will be validated
+ pnew_entry = new rec_entry ;
+ while ( fgets( ln_read_from_file, 256, rec ) != NULL ) {
+ // Strip LF and CR
+ ln_read_from_file[strlen(ln_read_from_file)-1]=0;
+ if (strlen(ln_read_from_file) && ln_read_from_file[strlen(ln_read_from_file)-1]=='\r')
+ ln_read_from_file[strlen(ln_read_from_file)-1]=0;
+
+ if ( !strncmp( "#NAME ", ln_read_from_file, 6 ) ) {
+ if ( linenr != 0 ) {
+ valid_file = 0 ;
+ break ;
+ }
+ linenr++ ;
+ } else if ( !strncmp( "#SERVICE: ", ln_read_from_file, 10 ) ) {
+ if ( linenr != 1 ) {
+ valid_file = 0 ;
+ break ;
+ }
+ linenr++ ;
+ pnew_entry->serv_line = ln_read_from_file ;
+ } else if ( !strncmp( "#DESCRIPTION: ", ln_read_from_file, 14 ) ) {
+ if ( linenr != 2 ) {
+ valid_file = 0 ;
+ break ;
+ }
+ linenr++ ;
+ pnew_entry->desc_line = ln_read_from_file ;
+ } else if ( !strncmp( "#TYPE ", ln_read_from_file, 6 ) ) {
+ if ( linenr != 3 ) {
+ valid_file = 0 ;
+ break ;
+ }
+ linenr++ ;
+ pnew_entry->type_line = ln_read_from_file ;
+ } else if ( !strncmp( "/hdd/movie/", ln_read_from_file, 11 ) ) {
+ if ( linenr != 4 ) {
+ valid_file = 0 ;
+ break ;
+ }
+ linenr = 1 ;
+ pnew_entry->path_line = ln_read_from_file ;
+
+ // Remind entry if the description is not the same
+ // as the filename.
+ if ( pnew_entry->path_line.substr(11,pnew_entry->path_line.length()-14).compare( pnew_entry->desc_line.substr(14,pnew_entry->desc_line.length()-14) ) != 0 ) {
+ insert_entry( &ptop_entry, pnew_entry ) ;
+ pnew_entry = new rec_entry ;
+ }
+ } else {
+ // File is invalid, will not be used.
+ valid_file = 0 ;
+ break ;
+ }
+ }
+ delete pnew_entry ;
+ fclose( rec ) ;
+ if ( !valid_file )
+ clear_entries( ptop_entry ) ;
+ }
+
bool result = false;
- FILE *rec = fopen("/hdd/movie/recordings.epl", "w");
+ rec = fopen("/hdd/movie/recordings.epl", "w");
if (rec)
{
- fprintf(rec, "#NAME Aufgenommene Filme\n");
-
+ fprintf(rec, "#NAME %s\n", _("recorded movies"));
struct dirent **namelist;
int n = scandir("/hdd/movie", &namelist, 0, alphasort);
if (n > 0)
{
+ // There will be 2 passes through namelist:
+ // 1) Delete entries from rec_entry chain that are not on disk.
+ // 2) Add entries to chain that do not exist yet.
+
+ // Pass 1
+ pcurrent_entry = ptop_entry ;
+ pprevious_entry = NULL ;
+ // For every entry in chain
+ while ( pcurrent_entry != NULL ) {
+ valid_file = 0 ;
+ // For every file in /hdd/movie
+ for (int i = 0; i < n; i++)
+ {
+ filen = namelist[i]->d_name;
+ // For every valid file
+ if ((filen.find(".ts") != eString::npos) && (filen.find(".ts.") == eString::npos) && !pcurrent_entry->path_line.substr(11,pcurrent_entry->path_line.length()-11).compare( filen ) ) {
+ valid_file = 1 ;
+ break ;
+ }
+ }
+ if ( !valid_file ) {
+ if ( pprevious_entry == NULL ) {
+ ptop_entry = pcurrent_entry->pnext_entry ;
+ } else {
+ pprevious_entry->pnext_entry = pcurrent_entry->pnext_entry ;
+ }
+ pentry_tbd = pcurrent_entry ;
+ pcurrent_entry = pcurrent_entry->pnext_entry ;
+ delete pentry_tbd ;
+ } else {
+ pprevious_entry = pcurrent_entry ;
+ pcurrent_entry = pcurrent_entry->pnext_entry ;
+ }
+ }
+
+ // Pass 2
+ // For every file in /hdd/movie
for (int i = 0; i < n; i++)
{
- eString filen = namelist[i]->d_name;
+ filen = namelist[i]->d_name;
+ // For every .ts file
if ((filen.find(".ts") != eString::npos) && (filen.find(".ts.") == eString::npos))
{
- fprintf(rec, "#SERVICE: 1:0:1:0:0:0:000000:0:0:0:/hdd/movie/%s\n", filen.c_str());
- fprintf(rec, "#DESCRIPTION: %s\n", getLeft(filen, '.').c_str());
- fprintf(rec, "#TYPE 16385\n");
- fprintf(rec, "/hdd/movie/%s\n", filen.c_str());
+ pnew_entry = new rec_entry ;
+ pnew_entry->serv_line = "#SERVICE: 1:0:1:0:0:0:000000:0:0:0:/hdd/movie/" ;
+ pnew_entry->serv_line.append( filen ) ;
+ pnew_entry->desc_line = "#DESCRIPTION: " ;
+ pnew_entry->desc_line.append( getLeft( getDesc( filen ), '.' ) ) ;
+ pnew_entry->type_line = "#TYPE 16385" ;
+ pnew_entry->path_line = "/hdd/movie/" ;
+ pnew_entry->path_line.append( filen ) ;
+ insert_entry( &ptop_entry, pnew_entry ) ;
}
free(namelist[i]);
}
+ sort_entries( &ptop_entry ) ;
+ // Write to file.
+ pcurrent_entry = ptop_entry ;
+ while ( pcurrent_entry != NULL ) {
+ fprintf(rec, "%s\n", pcurrent_entry->serv_line.c_str() ) ;
+ fprintf(rec, "%s\n", pcurrent_entry->desc_line.c_str() ) ;
+ fprintf(rec, "%s\n", pcurrent_entry->type_line.c_str() ) ;
+ fprintf(rec, "%s\n", pcurrent_entry->path_line.c_str() ) ;
+ pcurrent_entry = pcurrent_entry->pnext_entry ;
+ }
free(namelist);
result = true;
}
fclose(rec);
eZapMain::getInstance()->loadRecordings();
}
+
+ clear_entries( ptop_entry ) ;
return result;
}