summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING340
-rw-r--r--HISTORY10
-rw-r--r--Makefile110
-rw-r--r--README24
-rw-r--r--dataplaylist.c663
-rw-r--r--dataplaylist.h155
-rw-r--r--debian/changelog11
-rw-r--r--debian/control12
-rw-r--r--debian/copyright8
-rw-r--r--debian/dirs1
-rw-r--r--debian/docs1
-rwxr-xr-xdebian/rules79
-rw-r--r--i18n.c1594
-rw-r--r--i18n.h16
-rw-r--r--menucontrol.c391
-rw-r--r--menucontrol.h50
-rw-r--r--menuitemtext.c36
-rw-r--r--menuitemtext.h22
-rw-r--r--menuplaylist.c966
-rw-r--r--menuplaylist.h113
-rw-r--r--menuplaylists.c569
-rw-r--r--menuplaylists.h62
-rw-r--r--menusetup.c303
-rw-r--r--menusetup.h32
-rw-r--r--playlist.c608
-rw-r--r--playlist.h163
-rw-r--r--vdrtools.c217
-rw-r--r--vdrtools.h26
28 files changed, 6582 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..e47817d
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,10 @@
+VDR Plugin 'playlist' Revision History
+--------------------------------------
+
+2004-09-23: Version 0.0.1
+
+- Initial revision.
+
+2004-10-08: Version 0.0.2
+
+* Bug fixes
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..724b018
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id: Makefile 1.8 2002/12/13 14:54:14 kls Exp $
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = playlist
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX ?= g++
+CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+VDRVERSNUM = $(shell grep 'define VDRVERSNUM ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+
+### DEFINES += -DVDRVERSNUM=$(VDRVERSNUM)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
+
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+DEFINES += -D_GNU_SOURCE
+
+### Test Elchi
+
+#ELCHIVERSION = $(shell grep 'define ELCHIAIOVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+
+ifeq ($(shell test -f $(VDRDIR)/theme.h ; echo $$?),0)
+ DEFINES += -DHAVE_ELCHI
+endif
+
+### Test wareagle-patch
+
+ifeq ($(shell test -f $(VDRDIR)/iconpatch.h ; echo $$?),0)
+ DEFINES += -DHAVE_ICONPATCH
+endif
+
+#for more debug lines
+#DEFINES += -DPL_Debug1
+#DEFINES += -DPL_Debug2
+#DEFINES += -DPL_Debug3
+#CXXFLAGS += -g
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o dataplaylist.o menucontrol.o menuplaylist.o menuplaylists.o menusetup.o i18n.o vdrtools.o
+
+ifeq ($(shell test $(VDRVERSNUM) -lt 10307 ; echo $$?),0)
+ OBJS += menuitemtext.o
+endif
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: libvdr-$(PLUGIN).so
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(VDRVERSION)
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
diff --git a/README b/README
new file mode 100644
index 0000000..02923d4
--- /dev/null
+++ b/README
@@ -0,0 +1,24 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Hardy Flor <HFlor@web.de>
+
+Project's homepage (vdr): www.cadsoft.de/people/kls/vdr
+Project's homepage (playlist): www.fast-info.de/vdr/playlist
+
+See the file COPYING for license information.
+
+playlist-plugin version 0.0.2rc3
+
+hier kommt noch was ...
+
+TODO:
+
+- Komandozeilenoptionen und Konfigurationsdatei fehlen noch
+- Markierung in Aufnameauswahl
+- Verschiebung in Liste genauer Prüfen (z.Z. kann man Verzeichnisse verschieben --> ist aber nicht gut!)
+- Aufnahmenanzeige nicht im richtigen Verzeichnis bei vorheriger Auswahl eines Verzeichnisses mit Unterverzeichnissen
+- Aufnahmenanzeige enthält doppelte Einträge
+- auf roter taste standartwert anzeigen
+- Option für Wiedergabe im Detail-Ansicht
+x neue Playlist ohne inhalt auch namen-dialog schließen
+- Wenn nur 1 Verzeichniss in PL -> Name für PL übernehmen \ No newline at end of file
diff --git a/dataplaylist.c b/dataplaylist.c
new file mode 100644
index 0000000..d462b5b
--- /dev/null
+++ b/dataplaylist.c
@@ -0,0 +1,663 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: dataplaylist.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "dataplaylist.h"
+#include "playlist.h"
+#include "i18n.h"
+#include "vdrtools.h"
+#include <vdr/keys.h>
+#include <vdr/tools.h>
+#include <vdr/videodir.h>
+
+// -- cPlaylistMark -----------------------------------------------------------------
+
+cPlaylistMark::cPlaylistMark(char *Filename)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistMark::cPlaylistMark Name=%s", plugin_name, Filename);
+#endif
+ filename = Filename ? strdup(Filename) : NULL;
+}
+
+cPlaylistMark::~cPlaylistMark(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistMark::~cPlaylistMark Name=%s", plugin_name, filename);
+#endif
+ FREENULL(filename);
+}
+
+// -- cPlaylistMarkCol -----------------------------------------------------------------
+
+cPlaylistMarkCol PlaylistMark;
+
+// -- cPlaylistRecord -----------------------------------------------------------------
+
+cPlaylistRecord::cPlaylistRecord(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecord::cPlaylistRecord", plugin_name);
+#endif
+ SetName(NULL);
+ SetDefaults();
+ playlist = NULL;
+}
+
+cPlaylistRecord::cPlaylistRecord(cPlaylist *Playlist, char *Filename)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecord::cPlaylistRecord Filename=%s", plugin_name, Filename);
+#endif
+ playlist = Playlist;
+ SetName(Filename);
+ SetDefaults();
+}
+
+cPlaylistRecord::cPlaylistRecord(cPlaylist *Playlist, cRecording *Recording, cPlaylistRecord *Parent)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecord::cPlaylistRecord Parent=%s", plugin_name, Parent ? Parent->name : "(null)");
+#endif
+ playlist = Playlist;
+ SetName(Recording->FileName());
+ parent = Parent;
+ SetDefaults(Recording);
+}
+
+
+cPlaylistRecord::~cPlaylistRecord(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecord::~cPlaylistRecord [%s]", plugin_name, name);
+#endif
+ FREENULL(filename);
+ FREENULL(summary);
+ FREENULL(title);
+ FREENULL(path);
+ parent = NULL; // no delete!
+}
+
+void cPlaylistRecord::SetName(const char *Filename)
+{
+ if (Filename)
+ {
+ char *buffer = strdup(Filename + strlen(VideoDirectory) + 1);
+
+//suche record ..
+
+ buffer = ExchangeChars(buffer, false);
+
+ char *temp = strrchr(buffer, '~');
+ if (temp)
+ {
+ *temp = 0;
+ temp = strrchr(buffer, '~');
+ }
+ if (temp)
+ strn0cpy(name, temp + 1, MaxFileName);
+ else
+ strn0cpy(name, buffer, MaxFileName);
+ path = strdup(buffer);
+ free(buffer);
+ filename = strdup(Filename);
+ isdir = filename[strlen(filename) - 1] == '/';
+ } else
+ {
+ name[0] = 0;
+ filename = NULL;
+ path = NULL;
+ isdir = false;
+ }
+ parent = NULL;
+}
+
+void cPlaylistRecord::SetDefaults(cRecording *Recording)
+{
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ options[i] = parent ? NoYesDefault_defaultRecordDir : NoYesDefault_defaultPlaylist; // Option_playoption is not use
+ isdel = false;
+ isnew = false;
+ isedited = false;
+ start = 0;
+ title = NULL;
+ summary = NULL;
+ if (!isdir && filename)
+ if (!CopyFromRecording(Recording))
+ ERROR(tr("Error while accessing recording!"));
+}
+
+bool cPlaylistRecord::CopyFromRecording(cRecording *Recording)
+{
+ cRecording *recording = Recording ? Recording : Recordings.GetByName(filename);
+ if (recording)
+ {
+ isedited = recording->IsEdited();
+ isnew = recording->IsNew();
+ start = recording->start;
+ title = strdup(recording->Title('\t', true, recording->HierarchyLevels()));
+ char *temp = strrchr(title, '\t');
+ if (temp)
+ *temp = 0;
+ summary = recording->Summary() ? strdup(recording->Summary()) : NULL;
+ return true;
+ }
+ isdel = true;
+ return false;
+}
+
+void cPlaylistRecord::CopyOptions(cPlaylistRecord *PlaylistRecord)
+{
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ options[i] = PlaylistRecord->options[i];
+}
+
+bool cPlaylistRecord::Parse(const char *s)
+{
+ static cPlaylistRecord *lastdir = NULL;
+ char *namebuf = NULL;
+ char *filenamebuf = NULL;
+ int hasparent = false;
+ int opt1, opt2, opt3;
+ int fields = sscanf(s, "%a[^:]:%a[^:]:%d:%d:%d:%d:%d:%d:%d:%d:%d[:%d]", &namebuf,
+ &filenamebuf,
+ &hasparent,
+ &isdel,
+ &options[Option_confirmdeleterecord],
+ &options[Option_confirmstartnewrecord],
+ &options[Option_deletefromlist],
+ &options[Option_deleterecord],
+ &options[Option_jumpmark],
+ &opt1, &opt2, &opt3);
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecord::Parse fields=%d line=%s*", plugin_name, fields, s);
+#endif
+ if (namebuf)
+ {
+ strn0cpy(name, namebuf, sizeof(name));
+ free(namebuf);
+ }
+ FREENULL(filename);
+ filename = (filenamebuf && !strcasecmp(filenamebuf, "@null@")) ? NULL : filenamebuf;
+ strreplace(name, '|', ':');
+ if (filename)
+ {
+ strreplace(filename, '|', ':');
+ char *buffer = strdup(filename + strlen(VideoDirectory) + 1);
+ buffer = ExchangeChars(buffer, false);
+ char *temp = strrchr(buffer, '~');
+ if (temp)
+ *temp = 0;
+ path = strdup(buffer);
+ free(buffer);
+ isdir = filename[strlen(filename) - 1] == '/';
+ if (isdir)
+ lastdir = this;
+ else
+ {
+ if (lastdir && hasparent)
+ {
+ if (strstr(filename, lastdir->filename) == filename)
+ parent = lastdir;
+ }
+ if (!CopyFromRecording())
+ esyslog("%s: Error while accessing recording (deleted from playlist) %s", plugin_name, filename);
+ }
+ }
+ if (fields == 12)
+ {
+ options[Option_playonlynew] = opt1;
+ options[Option_searchnewrecord] = opt2;
+ options[Option_searchrecordsub] = opt3;
+ } else
+ {
+ options[Option_playonlynew] = isdir ? NoYesDefault_defaultPlaylist : NoYesDefault_defaultRecordDir;
+ options[Option_searchnewrecord] = opt1;
+ options[Option_searchrecordsub] = opt2;
+ }
+ return fields == 11 || fields == 12;
+}
+
+bool cPlaylistRecord::Save(FILE *f)
+{
+dsyslog("%s: cPlaylistRecord::Save", plugin_name);
+ char *buffer = NULL;
+ bool result = true;
+ if (!isdel || parent)
+ {
+ strreplace(name, ':', '|');
+ if (filename)
+ strreplace(filename, ':', '|');
+ asprintf(&buffer, "%s:%s:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+ name,
+ filename ? filename : "@null@",
+ parent ? true : false,
+ isdel,
+ options[Option_confirmdeleterecord],
+ options[Option_confirmstartnewrecord],
+ options[Option_deletefromlist],
+ options[Option_deleterecord],
+ options[Option_jumpmark],
+ options[Option_playonlynew],
+ options[Option_searchnewrecord],
+ options[Option_searchrecordsub]);
+
+ strreplace(name, '|', ':');
+ if (filename)
+ strreplace(filename, '|', ':');
+ result = fputs(buffer, f) > 0;
+ *(buffer + strlen(buffer) - 1) = 0;
+ if (verbose.u)
+ isyslog("%s: write line [%s]", plugin_name, buffer);
+ }
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecord::Save buffer=%s result=%s", plugin_name, buffer, result ? "true" : "false");
+#endif
+ FREENULL(buffer);
+ return result;
+}
+
+bool cPlaylistRecord::DeleteRecord(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecord::DeleteRecord Name=%s Filename=%s", plugin_name, name, filename);
+#endif
+ DeleteRecording(filename, false);
+ if (playlist && playlist->RecordCol2())
+ {
+ isdel = true;
+ playlist->RecordCol2()->SetChange();
+ }
+ return true;
+}
+
+int cPlaylistRecord::IndexRec(void)
+{
+ if (!playlist)
+ return -1;
+ int index = 0;
+ for (cPlaylistRecord *plr = playlist->First_PLR(); plr; plr = playlist->Next_PLR(plr))
+ {
+ if (!plr->isdir && !plr->isdel)
+ {
+ index++;
+ if (plr == this)
+ return index;
+ }
+ }
+ return -2;
+}
+
+bool cPlaylistRecord::Option(eOptions Select)
+{
+ if (Select < Option_confirmdeleterecord || Select >= Option_max)
+ return false;
+ switch (options[Select])
+ {
+ case NoYesDefault_no: return false;
+ case NoYesDefault_yes: return true;
+ case NoYesDefault_defaultRecordDir: if (parent)
+ return parent->Option(Select);
+ // no break
+ case NoYesDefault_defaultPlaylist: if (playlist)
+ return playlist->Option(Select);
+ // no break
+ case NoYesDefault_defaultPlugin: return PL_options[Select].u;
+ default: return PL_options[Select].d;
+ }
+}
+
+bool cPlaylistRecord::operator< (const cListObject &ListObject)
+{
+ return start == ((cPlaylistRecord *)&ListObject)->start ? strcmp(name, ((cPlaylistRecord *)&ListObject)->name) < 0 : start < ((cPlaylistRecord *)&ListObject)->start;
+}
+
+bool cPlaylistRecord::operator!= (const cPlaylistRecord &PlaylistRecordObject)
+{
+ bool temp;
+ if (strlen(PlaylistRecordObject.name))
+ if (strlen(name))
+ temp = strcmp(name, PlaylistRecordObject.name);
+ else
+ temp = true;
+ else
+ temp = strlen(name);
+ if (temp)
+ return true;
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ if (options[i] != PlaylistRecordObject.options[i])
+ return true;
+ return false;
+}
+
+// -- cPlaylistRecordCol ----------------------------------------------------------------
+
+cPlaylistRecordCol::cPlaylistRecordCol(cPlaylist *Parent)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecordCol::cPlaylistRecordCol", plugin_name);
+#endif
+ change = false;
+ parent = Parent;
+}
+
+cPlaylistRecordCol::~cPlaylistRecordCol(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecordCol::~cPlaylistRecordCol", plugin_name);
+#endif
+ parent = NULL;
+}
+
+void cPlaylistRecordCol::DeleteFile()
+{
+ if (!access(FileName(), F_OK))
+ if (remove(FileName()) < 0)
+ LOG_ERROR_STR(FileName());
+}
+
+bool cPlaylistRecordCol::SaveWithFilename()
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cPlaylistRecordCol::SaveWithFilename playlist=%s", plugin_name, parent ? parent->Name() : "(null)");
+#endif
+ DeleteFile();
+ if (!parent || !*parent->Name())
+ return false;
+ char *tempname = NULL;
+ asprintf(&tempname, "%s%s%s", "playlists.", parent->Name(), ".conf");
+ const char *filenew = PluginPlaylist->ExpandPath(tempname);
+ free(tempname);
+
+ bool result = true;
+ cSafeFile f(filenew);
+ if (f.Open())
+ {
+ for(cPlaylistRecord *plr = First(); plr; plr = Next(plr))
+ {
+ if (!plr->Save((FILE *)f))
+ {
+ result = false;
+ break;
+ }
+ }
+ if (!f.Close())
+ result = false;
+ } else
+ result = false;
+ if (result)
+// {
+// Load(filenew);
+ change = false;
+// }
+ return result;
+}
+
+bool cPlaylistRecordCol::SearchRecord(const char *Filename)
+{
+ bool result = false;
+ for (cPlaylistRecord *plr = First(); plr; plr = Next(plr))
+ {
+ if (strcasecmp(plr->Filename(), Filename) == 0)
+ {
+ result = true;
+ break;
+ }
+ }
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylistRecordCol::SearchRecord Filename=%s found=%s", plugin_name, Filename, result ? "true" : "false");
+#endif
+ return result;
+}
+
+
+// -- cPlaylistSortCol ----------------------------------------------------------------
+
+cPlaylistSortCol PlaylistSort;
+
+// -- cPlaylist ----------------------------------------------------------------
+
+cPlaylist::cPlaylist(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylist::cPlaylist", plugin_name);
+#endif
+ name[0] = 0;
+ lastrecord = NULL;
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ options[i] = NoYesDefault_defaultPlugin;
+ options[Option_playoption1] = PlayOptions_defaultPlugin;
+ options[Option_playoption2] = PlayOptions_defaultPlugin;
+ recordcount = 0;
+ recordnew = 0;
+ recordcol = new cPlaylistRecordCol(this);
+}
+
+cPlaylist::~cPlaylist(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylist::~cPlaylist [%s]", plugin_name, name);
+#endif
+ FREENULL(lastrecord);
+ if (recordcol)
+ DELETENULL(recordcol);
+}
+
+bool cPlaylist::Parse(const char *s)
+{
+ char *namebuf = NULL;
+ char *lastbuf = NULL;
+ int opt1, opt2, opt3, opt4;
+ int fields = sscanf(s, "%a[^:]:%a[^:]:%d:%d:%d:%d:%d:%d:%d:%d[:%d][:%d]", &namebuf,
+ &lastbuf,
+ &options[Option_confirmdeleterecord],
+ &options[Option_confirmstartnewrecord],
+ &options[Option_deletefromlist],
+ &options[Option_deleterecord],
+ &options[Option_jumpmark],
+ &options[Option_playoption1],
+ &opt1, &opt2, &opt3, &opt4);
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylist::Parse fields=%d line=%s*", plugin_name, fields, s);
+#endif
+ if (namebuf)
+ {
+ strn0cpy(name, namebuf, sizeof(name));
+ free(namebuf);
+ }
+ FREENULL(lastrecord);
+ lastrecord = (lastbuf && !strcasecmp(lastbuf, "@null@")) ? NULL : lastbuf;
+ strreplace(name, '|', ':');
+ if (lastrecord)
+ strreplace(lastrecord, '|', ':');
+ if (fields == 12)
+ {
+ options[Option_playoption2] = opt1;
+ options[Option_playonlynew] = opt2;
+ options[Option_searchnewrecord] = opt3;
+ options[Option_searchrecordsub] = opt4;
+ } else
+ {
+ options[Option_playoption2] = PlayOptions_defaultPlugin;
+ options[Option_playonlynew] = NoYesDefault_defaultPlugin;
+ options[Option_searchnewrecord] = opt1;
+ options[Option_searchrecordsub] = opt2;
+ }
+ return fields == 10 || fields == 12;
+}
+
+bool cPlaylist::Save(FILE *f)
+{
+ char *buffer = NULL;
+ strreplace(name, ':', '|');
+ if (lastrecord)
+ strreplace(lastrecord, ':', '|');
+ asprintf(&buffer, "%s:%s:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+ name,
+ lastrecord ? lastrecord : "@null@",
+ options[Option_confirmdeleterecord],
+ options[Option_confirmstartnewrecord],
+ options[Option_deletefromlist],
+ options[Option_deleterecord],
+ options[Option_jumpmark],
+ options[Option_playoption1],
+ options[Option_playoption2],
+ options[Option_playonlynew],
+ options[Option_searchnewrecord],
+ options[Option_searchrecordsub]);
+ strreplace(name, '|', ':');
+ if (lastrecord)
+ strreplace(lastrecord, '|', ':');
+ bool result = fputs(buffer, f) > 0;
+ if (verbose.u)
+ isyslog("%s: write line [%s]", plugin_name, buffer);
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylist::Save buffer=%s result=%s", plugin_name, buffer, result ? "true" : "false");
+#endif
+ free(buffer);
+ return result;
+}
+
+bool cPlaylist::SearchRecords(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylist::SearchRecords start", plugin_name);
+#endif
+ bool modifyplaylist = false;
+ for (cPlaylistRecord *searchdir = recordcol->First(); searchdir; searchdir = recordcol->Next(searchdir))
+ {
+ if (searchdir->IsDir() && searchdir->Option(Option_searchnewrecord))
+ {
+ PlaylistSort.Clear();
+ cPlaylistRecord *plr = NULL;
+ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
+ {
+ if (strstr(recording->FileName(), searchdir->Filename()) == recording->FileName())
+ {
+ const char *next = NULL;
+ if (!searchdir->Option(Option_searchrecordsub))
+ {
+ const char *test = recording->FileName() + strlen(searchdir->Filename());
+ const char *temp = strchr(test, '/');
+ if (temp)
+ next = strchr(temp + 1, '/');
+ }
+ if ((!next || searchdir->Option(Option_searchrecordsub)) && !recordcol->SearchRecord(recording->FileName()))
+ {
+ plr = new cPlaylistRecord(this, recording, searchdir);
+ PlaylistSort.Add(plr);
+ }
+ }
+ }
+ if (PlaylistSort.Count())
+ {
+ PlaylistSort.Sort();
+ cPlaylistRecord *temp = NULL;
+ cPlaylistRecord *lastrecord = NULL;
+ for (cPlaylistRecord *testrecord = recordcol->Next(searchdir); PlaylistSort.Count() && testrecord && testrecord->ParentObj() == searchdir; testrecord = recordcol->Next(testrecord))
+ {
+ lastrecord = testrecord;
+ temp = PlaylistSort.First();
+ if (testrecord->Start() > temp->Start())
+ {
+ PlaylistSort.Del(temp, false);
+ recordcol->Ins(temp, lastrecord);
+ modifyplaylist = true;
+ testrecord = temp; // if more then one recording to insert
+ }
+ }
+ for (plr = PlaylistSort.Last(); plr; plr = temp)
+ {
+ temp = PlaylistSort.Prev(plr);
+ PlaylistSort.Del(plr, false);
+ recordcol->Add(plr, lastrecord);
+ modifyplaylist = true;
+ }
+ }
+ }
+ }
+ CountRecords();
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylist::SearchRecords modified=%s count=%d new=%d", plugin_name, modifyplaylist ? "true" : "false", recordcount, recordnew);
+#endif
+ return modifyplaylist;
+}
+
+void cPlaylist::CountRecords(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPlaylist::CountRecords", plugin_name);
+#endif
+ recordcount = 0;
+ recordnew = 0;
+ for (cPlaylistRecord *plr = recordcol->First(); plr; plr = recordcol->Next(plr))
+ {
+ if (!plr->IsDirOrDel())
+ {
+ recordcount++;
+ if (plr->IsNew())
+ recordnew++;
+ }
+ }
+}
+
+cPlaylistRecord *cPlaylist::Firstnormal_PLR(void)
+{
+ if (recordcol)
+ for (cPlaylistRecord *plr = recordcol->First(); plr; plr = recordcol->Next(plr))
+ if (!plr->IsDirOrDel())
+ return plr;
+ return NULL;
+}
+
+cPlaylistRecord *cPlaylist::Firstnew_PLR(void)
+{
+ if (recordcol)
+ for (cPlaylistRecord *plr = recordcol->First(); plr; plr = recordcol->Next(plr))
+ if (!plr->IsDirOrDel())
+ if (plr->IsNew())
+ return plr;
+ return NULL;
+}
+
+cPlaylistRecord *cPlaylist::Lastplayed_PLR(void)
+{
+ if (recordcol && lastrecord)
+ for (cPlaylistRecord *plr = recordcol->First(); plr; plr = recordcol->Next(plr))
+ if (!plr->IsDirOrDel())
+ if (strcmp(lastrecord, plr->Filename()) == 0)
+ return plr;
+ FREENULL(lastrecord);
+ return NULL;
+}
+
+bool cPlaylist::operator!= (const cPlaylist &PlaylistObject)
+{
+ bool temp;
+ if (strlen(PlaylistObject.name))
+ if (strlen(name))
+ temp = strcmp(name, PlaylistObject.name);
+ else
+ return true;
+ else
+ temp = strlen(name);
+ if (temp)
+ return true;
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ if (options[i] != PlaylistObject.options[i])
+ return true;
+ return false;
+}
+
+cPlaylistRecord *SelectPLR = NULL;
+cPlaylistRecord *PlayedPLR = NULL;
+
+// -- cPlaylistCol ----------------------------------------------------------------
+
+cPlaylistCol PlaylistCol;
diff --git a/dataplaylist.h b/dataplaylist.h
new file mode 100644
index 0000000..e5e32fe
--- /dev/null
+++ b/dataplaylist.h
@@ -0,0 +1,155 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: dataplaylist.h 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#ifndef __DATAPLAYLIST_H
+#define __DATAPLAYLIST_H
+
+#include <vdr/tools.h>
+#include <vdr/interface.h>
+#include "playlist.h"
+
+class cPlaylistMark : public cListObject {
+private:
+ char *filename;
+public:
+ cPlaylistMark(char *Filename);
+ virtual ~cPlaylistMark(void);
+ char *Filename(void) { return filename; }
+ };
+
+class cPlaylistMarkCol : public cList<cPlaylistMark> {
+private:
+public:
+ };
+
+extern cPlaylistMarkCol PlaylistMark;
+
+class cPlaylist;
+
+class cPlaylistRecord : public cListObject {
+ friend class cMenuRecordingEdit;
+private:
+ char name[MaxFileName];
+ char *filename;
+ char *path;
+ bool isdir;
+ int isdel;
+ bool isnew; // copy from cRecording
+ time_t start; // copy from cRecording
+ char *title; // copy from cRecording
+ bool isedited; // copy from cRecording
+ char *summary; // copy from cRecording
+ int options[Option_max];
+ cPlaylistRecord *parent;
+ cPlaylist *playlist;
+ void SetName(const char *Filename);
+ void SetDefaults(cRecording *Recording = NULL);
+ bool CopyFromRecording(cRecording *Recording = NULL);
+public:
+ cPlaylistRecord(void);
+ cPlaylistRecord(cPlaylist *Playlist, char *Filename);
+ cPlaylistRecord(cPlaylist *Playlist, cRecording *Recording, cPlaylistRecord *Parent);
+ virtual ~cPlaylistRecord(void);
+ virtual bool operator< (const cListObject &ListObject);
+ virtual bool operator!= (const cPlaylistRecord &PlaylistRecordObject);
+ void CopyOptions(cPlaylistRecord *PlaylistRecord);
+ bool Parse(const char *s);
+ bool Save(FILE *f);
+ bool DeleteRecord(void);
+ int IndexRec(void);
+ const char *Name(void) { return &name[0]; }
+ char *Filename(void) { return filename; }
+ bool IsNew(void) { return isnew; }
+ bool IsEdited(void) { return isedited; }
+ bool IsDir(void) { return isdir; }
+ bool IsDel(void) { return isdel; }
+ bool IsDirOrDel(void) { return isdir || isdel; }
+ time_t Start(void) { return start; }
+ const char *Title(void) { return title; }
+ bool Parent(void) { return parent; }
+ cPlaylistRecord *ParentObj(void) { return parent; }
+ cPlaylist *Playlist(void) { return playlist; }
+ void Playlist(cPlaylist *PlayList) { playlist = PlayList; }
+ void SetDel(void) { isdel = true; }
+ void SetNew(bool Value) { isnew = Value; }
+ bool Option(eOptions Select);
+ bool OptionInherited(eOptions Select) { return (Select < Option_confirmdeleterecord || Select >= Option_max) ? false : options[Select] > NoYesDefault_yes; }
+ };
+
+class cPlaylistRecordCol : public cConfig<cPlaylistRecord> {
+private:
+ bool change;
+ cPlaylist *parent;
+public:
+ cPlaylistRecordCol(cPlaylist *Parent);
+ virtual ~cPlaylistRecordCol(void);
+ bool GetChange(void) { return change; }
+ void SetChange(void) { change = true; }
+ void DeleteFile();
+ bool SaveWithFilename();
+ bool SearchRecord(const char *Filename);
+ };
+
+class cPlaylistSortCol : public cList<cPlaylistRecord> {
+private:
+public:
+ };
+
+extern cPlaylistSortCol PlaylistSort;
+
+class cPlaylist : public cListObject {
+ friend class cMenuPlaylistEdit;
+private:
+ char name[MaxFileName];
+ char *lastrecord;
+ int options[Option_max];
+ int recordcount;
+ int recordnew;
+
+ cPlaylistRecordCol *recordcol;
+public:
+ cPlaylist(void);
+ virtual ~cPlaylist(void);
+ virtual bool operator!= (const cPlaylist &PlaylistObject);
+ cPlaylistRecordCol *RecordCol2(void) { return recordcol; }
+ bool Parse(const char *s);
+ bool Save(FILE *f);
+ bool SearchRecords(void);
+ void CountRecords(void);
+ cPlaylistRecord *First_PLR(void) { return recordcol ? recordcol->First() : NULL; }
+ cPlaylistRecord *Last_PLR(void) { return recordcol ? recordcol->Last() : NULL; }
+ cPlaylistRecord *Next_PLR(cPlaylistRecord *PLR) { return recordcol ? recordcol->Next(PLR) : NULL; }
+ cPlaylistRecord *Prev_PLR(cPlaylistRecord *PLR) { return recordcol ? recordcol->Prev(PLR) : NULL; }
+ cPlaylistRecord *Firstnormal_PLR(void);
+ cPlaylistRecord *Firstnew_PLR(void);
+ cPlaylistRecord *Lastplayed_PLR(void);
+ void SetChange(void) { if (recordcol) recordcol->SetChange(); }
+ void SaveRecordCol(void) { if (recordcol && recordcol->GetChange() && (!storeplaylist.u || Interface->Confirm(tr("Question$Save Playlist?")))) recordcol->SaveWithFilename(); }
+ void SetLastRecord(const char *LastRecord) { FREENULL(lastrecord); lastrecord = strdup(LastRecord); }
+ char *Name(void) { return &name[0]; }
+ int RecordCount(bool Refesh = false) { if (Refesh) CountRecords(); return recordcount; }
+ int RecordNew(void) { return recordnew; }
+ int Playoption(eOptions Select) { return Select == Option_playoption1 ? (options[Option_playoption1] == PlayOptions_defaultPlugin) ? PL_options[Option_playoption1].u : (options[Option_playoption1] < PlayOptions_defaultPlugin) ? options[Option_playoption1] : PL_options[Option_playoption1].d : Select == Option_playoption2 ? (options[Option_playoption2] == PlayOptions_defaultPlugin) ? PL_options[Option_playoption2].u : (options[Option_playoption2] < PlayOptions_defaultPlugin) ? options[Option_playoption2] : PL_options[Option_playoption2].d : PlayOptions_firstpos; }
+ bool Option(eOptions Select) { return (Select < Option_confirmdeleterecord || Select >= Option_max) ? false : (options[Select] == NoYesDefault_defaultPlugin) ? PL_options[Select].u : (options[Select] < NoYesDefault_defaultPlugin) ? options[Select] : PL_options[Select].d; }
+ bool OptionInherited(eOptions Select) { return (Select < Option_confirmdeleterecord || Select >= Option_max) ? false : (Select == Option_playoption1 || Select == Option_playoption2) ? options[Select] == PlayOptions_defaultPlugin : options[Select] > NoYesDefault_yes; }
+ };
+
+//extern cPlaylist *SelectPlaylist;
+//extern int Selectplayoption;
+//extern int Selectplayposition;
+extern cPlaylistRecord *SelectPLR;
+extern cPlaylistRecord *PlayedPLR;
+
+class cPlaylistCol : public cConfig<cPlaylist> {
+private:
+public:
+ };
+
+extern cPlaylistCol PlaylistCol;
+
+#endif //__DATAPLAYLIST_H
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..4416d09
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,11 @@
+vdr-plugin-playlist (0.0.2-1) unstable; urgency=low
+
+ * Bug fixes
+ -
+
+ -- Hardy Flor <HFlor@gmx.de> Fri, 08 Okt 2004 02:34:00 +0200
+vdr-plugin-playlist (0.0.1-1) unstable; urgency=low
+
+ * Initial revision
+
+ -- Hardy Flor <HFlor@gmx.de> Thu, 23 Sep 2004 23:42:32 +0200
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..a124ccd
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,12 @@
+Source: vdr-plugin-playlist
+Section: misc
+Priority: extra
+Maintainer: Hardy Flor <HFlor@gmx.de>
+Build-Depends: debhelper (>> 3.0.0), vdr-dev (>= 1.2.6-5)
+Standards-Version: 3.5.2
+
+Package: vdr-plugin-playlist
+Architecture: i386
+Depends: ${shlibs:Depends}, vdr (>= 1.2.6-5)
+Description: Plugin for VDR to display playlist for recordings
+ Patchlevel: ${patchlevel} \ No newline at end of file
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..6e5458d
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,8 @@
+This package was debianized by Hardy Flor on Thu, 23 Sep 2004 23:42:32 +0200.
+
+Copyright:
+
+ You are free to distribute this software under the terms of
+ the GNU General Public License.
+ On Debian systems, the complete text of the GNU General Public
+ License can be found in /usr/share/common-licenses/GPL file.
diff --git a/debian/dirs b/debian/dirs
new file mode 100644
index 0000000..aa338f5
--- /dev/null
+++ b/debian/dirs
@@ -0,0 +1 @@
+usr/lib/vdr/plugins
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..e845566
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1 @@
+README
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..20fd2fe
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,79 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatibility version to use.
+export DH_COMPAT=3
+
+ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -g
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+
+ touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+ dh_testdir
+
+ $(MAKE) all DVBDIR=/usr/include VDRDIR=/usr/include/vdr LIBDIR=. REMOTE=lirc
+
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+ rm -f debian/vdr-plugin-playlist.substvars
+ rm -f libvdr-*.so*
+ make clean
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+ cp libvdr-playlist*.so.* $(CURDIR)/debian/vdr-plugin-playlist/usr/lib/vdr/plugins/
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installdocs
+ dh_installexamples
+ dh_installmenu
+ dh_installcron
+ dh_installman
+ dh_installinfo
+ dh_installchangelogs HISTORY
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_shlibdeps
+ cd debian; mv vdr-plugin-playlist.substvars substvars.old; cat /usr/include/vdr/patchlevel substvars.old > vdr-plugin-playlist.substvars; rm -f substvars.old
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/i18n.c b/i18n.c
new file mode 100644
index 0000000..28d5c38
--- /dev/null
+++ b/i18n.c
@@ -0,0 +1,1594 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include "i18n.h"
+
+const tI18nPhrase Phrases[] = {
+ { "Add",
+ "Hinzufügen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Option",
+ "Optionen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Select",
+ "Auswahl",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "UnMark",
+ "Demakieren",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "playlist for recordings",
+ "Playlisten für Aufnahmen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Playlist",
+ "Playlist",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Add selected Record to Playlist?",
+ "Ausgewählte Aufnahme hinzufügen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Delete recording?",
+ "Aufnahme löschen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Discard all changes?",
+ "Alle Änderungen verwerfen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Display$Display Playlist",
+ "Anzeige Playlist",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Display$Display Playlists",
+ "Übersicht Playlisten",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Display$prepare playlists display...",
+ "Listenanzeige wird vorbereitet...",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Display$prepare recording display...",
+ "Listenanzeige wird vorbereitet...",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Edit$Confirm Options",
+ "Bestätigung der Optionen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Edit$Create Playlist",
+ "Erstelle Playlist",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Edit$Edit Playlist",
+ "Bearbeite Playlist",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Edit$Edit Record",
+ "Bearbeite Aufnahme",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Edit$Delete Playlist?",
+ "Löschen der Playlist?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Edit$Delete Playlistentry?",
+ "Löschen des Playlist-Eintrags?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$Playlistentry or Record is deleted",
+ "Playlisteintrag oder Aufnahme ist gelöscht",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$Missing playlistentry name!",
+ "Name für Eintrag in Playlist fehlt!",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$Missing playlist name!",
+ "Name für Playlist fehlt!",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$Move between folders and not folders not allowed.",
+ "Vers. zw. Verzeichniss und normal nicht erlaubt",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$Playlistentry is not set",
+ "Playlist-Eintrag ist fehlerhaft",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$Playlist is currently used by played recording",
+ "Aktuelle Wiedergabe benutzt diese Playliste",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$same name of playlist exists!",
+ "Gleicher Name der Playlist ist vorhanden",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$[from Folder]",
+ "[von Verzeichniss]",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$[from Playlist]",
+ "[von Playlist]",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$[from Setup]",
+ "[von Einstellung]",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$first new",
+ "erste neue",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$first pos",
+ "erste Position",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$last played",
+ "letzte Wiederg.",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$last pos",
+ "letzte Position",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$question",
+ "Frage",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$seletced pos",
+ "ausgewählte",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Character for folders",
+ " Zeichen für Verzeichniss",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Character for normal records",
+ " Zeichen für normale Aufnahmen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Character for records in folders",
+ " Zeichen für Aufn. im Verzeichnis",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Confirm delete records",
+ " Bestätigung löschen Aufnahmen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Confirm delete records",
+ " Bestätigung löschen Aufnahmen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Confirm start new record",
+ " Frage bei Start neue Wiedergabe",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Confirm start new record",
+ "Frage bei Start neue Wiedergabe",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Delete records after play",
+ " Löschen Aufn. nach Wiedergabe",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Delete records after play",
+ "Löschen Aufn. nach Wiedergabe",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Effective setting is:",
+ "Aktuelle Einstellung ist:",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$In detailview starts play at",
+ "Wiedergabe bei Playliste startet",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ In detailview starts play at",
+ " Wiedergabe bei Playliste startet",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$In playlistview starts play at",
+ "Wiedergabe bei Übersicht startet",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ In playlistview starts play at",
+ " Wiedergabe bei Übersicht startet",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Jump to first segment of movie",
+ " Zum ersten Filmteil sprigen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Jump to first segment of movie",
+ "Zum ersten Filmteil sprigen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Name",
+ "Name",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Play only new Records",
+ "Nur neue Aufzeichnungen abspielen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Play only new Records",
+ " Nur neue Aufzeichnungen abspielen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Remove records after play from list",
+ " PL-Eintrag n. Wiedergabe streichen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Remove records after play from list",
+ "PL-Eintrag n. Wiedergabe streichen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Search new records on folders",
+ " Verzeichnissuche neue Aufnahmen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Search new records on folders",
+ "Verzeichnissuche neue Aufnahmen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$ Search new records on subfolders",
+ " Aufnahmen in Unterverzei. suchen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$Search records on subfolders",
+ "Aufnahmen in Unterverzei. suchen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Play$Delete recording:",
+ "Aufnahme löschen:",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Play$Start next recording:",
+ "Nächste Aufnahme starten:",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Play$Currently play first Record! Jump to last?",
+ "Erste Aufnahme wird gespielt! Zur letzten gehen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Play$Currently play last Record! Jump to first?",
+ "Letzte Aufnahme wird gespielt! Zur ersten gehen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Question$No new recording found! Play first?",
+ "Keine neuen Aufnahmen! Erste abspielen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Question$Play first new recording?",
+ "Erste neue Aufnahme abspielen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Question$Play last played recording?",
+ "Zuletzt gespielte Aufnahme abspielen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Question$Save Playlist?",
+ "Playlist speichern?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$after question",
+ "nach Frage",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$automatically",
+ "automatisch",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Display last PL",
+ "Anz. letzte PL",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Display PL",
+ "Anzeige PL",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Edit",
+ "Bearbeitung",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$new empty PL",
+ "leere PL",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Play",
+ "Wiedergabe",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Play last PL",
+ "Wiedergabe PL",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Allow delete Records",
+ "Aufnahmen löschen erlauben",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Change Character for identification",
+ "Darstellungszeichen ändern",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Change default options for playlist",
+ "Standardoptionen für Playlist ändern",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Confirm delete playlistentries",
+ "Frage löschen PL-Eintragungen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$ Name for Mainmenu",
+ " Eintragname im Hauptmenü",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Path for store playlists",
+ "Speicherpfad für Playlisten",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Preferr Command Line Parameter",
+ "Kommandozeile hat Vorrang",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Press OK in Playlistview starts",
+ "OK in Playlist-Ansicht startet",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Startoptions for plugin",
+ "Startoptionen des Plugins",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Store playlist after change",
+ "Playlist nach Änderung speichern",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Verbose Log Mode",
+ "Ausführliche Protokollierung",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Visible in Mainmenu",
+ "Im Hauptmenü sichtbar",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Display playlists now",
+ "Jetzt Playlisten anzeigen",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Setup$Play last playlist now",
+ "Letzte Playlist wiedergeben",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Error$At this position and after no recording found!",
+ "Dieser Position und danach ist keine Aufnahme",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "Question$Play selected recording?",
+ "Ausgewählte Aufnahme abspielen?",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { "OptionPL$is:",
+ "ist:",
+ "",// TODO Slovenski
+ "",// TODO Italiano
+ "",// TODO Nederlands
+ "",// TODO Português
+ "",// TODO Français
+ "",// TODO Norsk
+ "",// TODO suomi
+ "",// TODO Polski
+ "",// TODO Español
+ "",// TODO Ellinika
+ "",// TODO Svenska
+ "",// TODO Romaneste
+ "",// TODO Magyar
+ "",// TODO Català
+ },
+ { NULL }
+ };
diff --git a/i18n.h b/i18n.h
new file mode 100644
index 0000000..c06e957
--- /dev/null
+++ b/i18n.h
@@ -0,0 +1,16 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.h 0.1 2004/09/23 23:42:32 hflor Exp $
+ */
+
+#ifndef _I18N__H
+#define _I18N__H
+
+#include <vdr/i18n.h>
+
+extern const tI18nPhrase Phrases[];
+
+#endif //_I18N__H
diff --git a/menucontrol.c b/menucontrol.c
new file mode 100644
index 0000000..4ea34ed
--- /dev/null
+++ b/menucontrol.c
@@ -0,0 +1,391 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menucontrol.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include "menucontrol.h"
+#include "menuplaylists.h"
+#include "playlist.h"
+#include "vdrtools.h"
+#include <vdr/recording.h>
+#include <vdr/remote.h>
+#include <vdr/interface.h>
+
+// --- cControlPlaylist -----------------------------------------------------------
+
+cControlPlaylist::cControlPlaylist(void)
+:cControl(NULL)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cControlPlaylist::cControlPlaylist", plugin_name);
+#endif
+
+ replaycontrol = NULL;
+ if (SelectPLR)
+ PlayRecording(SelectPLR);
+ else
+ cRemote::Put(kBack);
+}
+
+cControlPlaylist::~cControlPlaylist(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cControlPlaylist::~cControlPlaylist", plugin_name);
+#endif
+ if (replaycontrol)
+ DELETENULL(replaycontrol);
+ PlayedPLR = NULL;
+#ifdef PL_Debug2
+ dsyslog("%s: PlayedPLR=(null)", plugin_name);
+#endif
+}
+
+void cControlPlaylist::Hide(void)
+{
+ if (replaycontrol)
+ replaycontrol->Hide();
+}
+
+eOSState cControlPlaylist::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cControlPlaylist::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+
+ eOSState state = osUnknown;
+ if (replaycontrol)
+ state = replaycontrol->ProcessKey(Key);
+#ifdef PL_Debug3
+ if (!noneKey || state != osUnknown)
+ {
+ dsyslog("%s: cControlPlaylist::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ char *temp = NULL;
+ cPlaylistRecord *plr = PlayedPLR;
+ cPlaylist *playlist = plr ? plr->Playlist() : NULL;
+ switch (state)
+ {
+ case osUnknown: switch (NORMALKEY(Key))
+ {
+ case k1: if (playlist)
+ {
+ if (plr)
+ plr = playlist->Prev_PLR(plr);
+ while (plr && (plr->IsDirOrDel()))
+ plr = playlist->Prev_PLR(plr);
+ if (!plr && Interface->Confirm(tr("Play$Currently play first Record! Jump to last?")))
+ {
+ plr = playlist->Last_PLR();
+ while (plr && (plr->IsDirOrDel()))
+ plr = playlist->Prev_PLR(plr);
+ }
+ }
+ state = osContinue;
+ break;
+ case k3: if (playlist)
+ {
+ if (plr)
+ plr = playlist->Next_PLR(plr);
+ while (plr && (plr->IsDirOrDel()))
+ plr = playlist->Next_PLR(plr);
+ if (!plr && Interface->Confirm(tr("Play$Currently play last Record! Jump to first?")))
+ {
+ plr = playlist->First_PLR();
+ while (plr && (plr->IsDirOrDel()))
+ plr = playlist->Next_PLR(plr);
+ }
+ }
+ state = osContinue;
+ break;
+ case kBack: state = osEnd;
+ break;
+ default: break;
+ }
+ if (state == osContinue && plr)
+ {
+ bool visible = replaycontrol ? replaycontrol->Visible() : false;
+ UpdateRecording();
+ state = PlayRecording(plr, visible);
+ }
+ break;
+ case osRecordings: // kBack while playing
+ UpdateRecording();
+ cControl::Shutdown();
+ if (ControlMenuIsOpen)
+ state = osUser8;
+ else
+ {
+ if (playlist)
+ playlist->SaveRecordCol();
+ state = osEnd;
+ }
+ break;
+ case osEnd: // end of playing
+ {
+ bool visible = replaycontrol ? replaycontrol->Visible() : false;
+ UpdateRecording();
+ if (playlist)
+ {
+ cPlaylistRecord *plr_n = playlist->Next_PLR(plr);
+ asprintf(&temp, "%s %s", tr("Play$Delete recording:"), plr->Name());
+ if (deleterecords.u && plr->Option(Option_deleterecord) && (!plr->Option(Option_confirmdeleterecord) || Interface->Confirm(temp)))
+ plr->DeleteRecord();
+ else if (plr->Option(Option_deletefromlist))
+ {
+ plr->SetDel();
+ playlist->SetChange();
+ }
+ FREENULL(temp);
+ plr = plr_n;
+ while (plr && (plr->IsDirOrDel() || (plr->Option(Option_playonlynew) && !plr->IsNew())))
+ plr = playlist->Next_PLR(plr);
+ if (plr)
+ {
+ asprintf(&temp, "%s %s", tr("Play$Start next recording:"), plr->Name());
+ if (!plr->Option(Option_confirmstartnewrecord) || Interface->Confirm(temp))
+ state = PlayRecording(plr, visible);
+ else
+ plr = NULL;
+ FREENULL(temp);
+ }
+ } else
+ plr = NULL;
+ if (!plr)
+ {
+ if (playlist)
+ playlist->SaveRecordCol();
+ cControl::Shutdown();
+ }
+ }
+ break;
+ default: break;
+ }
+#ifdef PL_Debug3
+ if (!noneKey || state != osUnknown)
+ dsyslog("%s: cControlPlaylist::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
+
+eOSState cControlPlaylist::PlayRecording(cPlaylistRecord *PlaylistRecord, bool Visible)
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cControlPlaylist::PlayRecording Name=%s FileName=%s", plugin_name, PlaylistRecord ? PlaylistRecord->Name() : NULL, PlaylistRecord ? PlaylistRecord->Filename() : NULL);
+#endif
+
+ static char title[MaxFileName];
+ eOSState state = osEnd;
+ DELETENULL(replaycontrol);
+ if (PlaylistRecord)
+ {
+ if (PlaylistRecord->IsNew() && !PlaylistRecord->IsEdited() && PlaylistRecord->Option(Option_jumpmark))
+ {
+ cResumeFile *resume = new cResumeFile(PlaylistRecord->Filename());
+ int res = resume->Read();
+ delete resume;
+ if (res < 0) // new file
+ {
+ cMarks *marks = new cMarks;
+ if (marks)
+ {
+ marks->Load(PlaylistRecord->Filename());
+ if (marks->Count())
+ {
+ int mark = marks->First()->position;
+ if (mark < 100 && marks->Count() > 2)
+ {
+ mark = marks->GetNext(mark)->position;
+ mark = marks->GetNext(mark)->position;
+ }
+ cResumeFile *resume = new cResumeFile(PlaylistRecord->Filename());
+ if (mark > 0 && resume)
+ {
+ resume->Save(mark);
+ DELETENULL(resume);
+ }
+ }
+ }
+ }
+ }
+ char *buffer;
+ if (PlaylistRecord->Playlist())
+ {
+ asprintf(&buffer, "%d/%d %s", PlaylistRecord->IndexRec(), PlaylistRecord->Playlist()->RecordCount(true), PlaylistRecord->Name());
+ PlaylistRecord->Playlist()->SetLastRecord(PlaylistRecord->Filename());
+ PlaylistCol.Save();
+ } else
+ buffer = strdup(PlaylistRecord->Name());
+ strn0cpy(title, buffer, MaxFileName);
+ free(buffer);
+ if (verbose.u)
+ dsyslog("%s: start new replay Name=%s Directory=%s", plugin_name, title, PlaylistRecord->Filename());
+ cReplayControl::SetRecording(NULL, NULL);
+ cReplayControl::SetRecording(PlaylistRecord->Filename(), title);
+ replaycontrol = new cReplayControlPlaylist;
+ if (replaycontrol)
+ {
+ player = replaycontrol->GetPlayerPlaylist();
+ if (cDevice::PrimaryDevice()->AttachPlayer(player))
+ state = osContinue;
+ PlayedPLR = PlaylistRecord;
+#ifdef PL_Debug2
+ dsyslog("%s: PlayedPLR=(null)", plugin_name, PlayedPLR ? PlayedPLR->Name() : "(null)");
+#endif
+ if (Visible)
+ replaycontrol->Show();
+ if (PlaylistRecord && PlaylistRecord->Playlist())
+ strn0cpy(lastplaylist.u, PlaylistRecord->Playlist()->Name(), sizeof(lastplaylist.u));
+ else
+ lastplaylist.u[0] = 0;
+ if (strcmp(lastplaylist.u, lastplaylist.o))
+ {
+ PluginPlaylist->SetupStore("lastpl", lastplaylist.u);
+ strcpy(lastplaylist.o, lastplaylist.u);
+ }
+ }
+ }
+ return state;
+}
+
+void cControlPlaylist::UpdateRecording(void)
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cControlPlaylist::UpdateRecording PlayedPLR=%s", plugin_name, PlayedPLR ? PlayedPLR->Filename() : "(null)");
+#endif
+
+ DELETENULL(replaycontrol);
+ cRecording *recording_n = NULL;
+ if (PlayedPLR)
+ {
+ cRecording *recording_o = Recordings.GetByName(PlayedPLR->Filename());
+ recording_n = new cRecording(PlayedPLR->Filename());
+ if (recording_o && recording_n)
+ {
+ Recordings.Add(recording_n, recording_o);
+ Recordings.Del(recording_o);
+ }
+ }
+ for (cPlaylist *pl = PlaylistCol.First(); pl; pl = PlaylistCol.Next(pl))
+ for (cPlaylistRecord *plr = pl->First_PLR(); plr; plr = pl->Next_PLR(plr))
+ if (strcasecmp(plr->Filename(), PlayedPLR->Filename()) == 0)
+{
+ dsyslog("%s: playlist=%s isnew=%s", plugin_name, pl->Name(), recording_n ? recording_n->IsNew() ? "true" : "false" : "(null)");
+ if (recording_n)
+ plr->SetNew(recording_n->IsNew());
+ else
+ plr->SetDel();
+}
+}
+
+// --- cControlMenu -----------------------------------------------------------
+
+cControlMenu::cControlMenu(void)
+:cOsdObject(true)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cControlMenu::cControlMenu Startoption=%d", plugin_name, startoption.u);
+#endif
+
+ ControlMenuIsOpen = true;
+ switch (startoption.u)
+ {
+ case Start_DisplayPL: osdmenu = new cMenuPlaylists;
+ break;
+ case Start_DisplayLast: osdmenu = new cMenuPlaylists;
+ if (SelectPLR)
+ osdmenu->ProcessKey(kUser1);
+ break;
+ case Start_PlayLast: osdmenu = new cMenuPlaylists;
+ if (SelectPLR)
+ {
+ if (osdmenu->ProcessKey(kUser2) == osUser9)
+ {
+ DELETENULL(osdmenu);
+ cControl::Shutdown();
+ cControl::Launch(new cControlPlaylist);
+ }
+ }
+ break;
+ case Start_NewEmpty: osdmenu = new cMenuPlaylists;
+ osdmenu->ProcessKey(kUser3);
+ break;
+ }
+}
+
+cControlMenu::~cControlMenu()
+{
+#ifdef PL_Debug
+ dsyslog("%s: cControlMenu::~cControlMenu", plugin_name);
+#endif
+ if (osdmenu)
+ DELETENULL(osdmenu);
+ ControlMenuIsOpen = false;
+}
+
+void cControlMenu::Show(void)
+{
+ if (osdmenu)
+ osdmenu->Display();
+}
+
+eOSState cControlMenu::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cControlMenu::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+
+ eOSState state;
+ cOsdObject *Interact = osdmenu ? (cOsdObject*)osdmenu : cControl::Control();
+ if (Interact)
+ state = Interact->ProcessKey(Key);
+ else
+ state = cOsdObject::ProcessKey(Key);
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ {
+ dsyslog("%s: cControlMenu::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ switch (state)
+ {
+ case osUnknown: switch (NORMALKEY(Key))
+ {
+ case kBack: state = osEnd;
+ break;
+ default: break;
+ }
+ break;
+ case osUser8: osdmenu = new cMenuPlaylists;
+ if (SelectPLR)
+ osdmenu->ProcessKey(kUser1);
+ break;
+ case osUser9: if (SelectPLR)
+ {
+ DELETENULL(osdmenu);
+ cControl::Shutdown();
+ cControl::Launch(new cControlPlaylist);
+ }
+ state = osContinue;
+ break;
+ default: break;
+ }
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ dsyslog("%s: cControlMenu::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
diff --git a/menucontrol.h b/menucontrol.h
new file mode 100644
index 0000000..392d696
--- /dev/null
+++ b/menucontrol.h
@@ -0,0 +1,50 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menucontrol.h 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#ifndef __MENUCONTROL_H
+#define __MENUCONTROL_H
+
+#include "dataplaylist.h"
+#include <vdr/menu.h>
+
+
+// --- cReplayControlPlaylist -----------------------------------------------------------
+
+class cReplayControlPlaylist : public cReplayControl {
+public:
+ cPlayer *GetPlayerPlaylist() { return cControl::player; }
+ };
+
+// --- cControlPlaylist -----------------------------------------------------------
+
+class cControlPlaylist : public cControl {
+private:
+// cPlaylistRecord *playlistrecord;
+ cReplayControlPlaylist *replaycontrol;
+ eOSState PlayRecording(cPlaylistRecord *PlaylistRecord, bool Visible = false);
+ void UpdateRecording(void);
+public:
+ cControlPlaylist(void);
+ virtual ~cControlPlaylist(void);
+ virtual void Hide(void);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cControlMenu -----------------------------------------------------------
+
+class cControlMenu : public cOsdObject {
+private:
+ cOsdMenu *osdmenu;
+public:
+ cControlMenu(void);
+ virtual ~cControlMenu(void);
+ virtual void Show(void);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+#endif //__MENUCONTROL_H
diff --git a/menuitemtext.c b/menuitemtext.c
new file mode 100644
index 0000000..9bb0447
--- /dev/null
+++ b/menuitemtext.c
@@ -0,0 +1,36 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menuitemtext.c 0.1 2004/09/23 23:42:32 hflor Exp $
+ */
+
+#include "menuitemtext.h"
+#include <vdr/menuitems.h>
+
+// --- cMenuText -------------------------------------------------------------
+
+cMenuItemText::cMenuItemText(const char *Title, const char *Text, eDvbFont Font)
+:cOsdMenu(Title)
+{
+ Add(new cMenuTextItem(Text, 1, 2, Setup.OSDwidth - 2, MAXOSDITEMS, clrWhite, clrBackground, Font));
+}
+
+eOSState cMenuItemText::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ switch (state)
+ {
+ case osUnknown: switch (NORMALKEY(Key))
+ {
+ case kOk: state = osBack;
+ break;
+ default: break;
+ }
+ break;
+ default: break;
+ }
+ return state;
+}
diff --git a/menuitemtext.h b/menuitemtext.h
new file mode 100644
index 0000000..b53a0bd
--- /dev/null
+++ b/menuitemtext.h
@@ -0,0 +1,22 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menuitemtext.h 0.1 2004/09/23 23:42:32 hflor Exp $
+ */
+
+#ifndef __MENUITEMTEXT_H
+#define __MENUITEMTEXT_H
+
+#include <vdr/osd.h>
+
+// --- cMenuText -------------------------------------------------------------
+
+class cMenuItemText : public cOsdMenu {
+public:
+ cMenuItemText(const char *Title, const char *Text, eDvbFont Font = fontOsd);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+#endif // __MENUITEMTEXT_H
diff --git a/menuplaylist.c b/menuplaylist.c
new file mode 100644
index 0000000..e87588d
--- /dev/null
+++ b/menuplaylist.c
@@ -0,0 +1,966 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menuplaylist.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include "menuplaylist.h"
+#include "dataplaylist.h"
+#if VDRVERSNUM < 10307
+#include "menuitemtext.h"
+#endif
+#include "playlist.h"
+#include "i18n.h"
+#include "vdrtools.h"
+#include <vdr/interface.h>
+#include <vdr/videodir.h>
+#ifdef HAVE_ICONPATCH
+#include <vdr/iconpatch.h>
+#endif
+
+// --- cMenuRecordingSelectItem --------------------------------------------------------
+
+cMenuRecordingSelectItem::cMenuRecordingSelectItem(cRecording *Recording, int Level)
+{
+ filename = strdup(Recording->FileName());
+ totalEntries = newEntries = 0;
+ start = Recording->start;
+ SetText(Recording->Title('\t', true, Level));
+ if ((isdir = (*Text() == '\t')))
+ name = strdup(Text() + 2);
+ else
+ name = strdup(Recording->Name());
+ ismark = false;
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingSelectItem::cMenuRecordingSelectItem FileName=%s Level=%d Name=%s", plugin_name, filename, Level, name);
+#endif
+}
+
+cMenuRecordingSelectItem::~cMenuRecordingSelectItem()
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingSelectItem::~cMenuRecordingSelectItem FileName=%s Name=%s", plugin_name, filename, name);
+#endif
+ FREENULL(filename);
+ FREENULL(name);
+}
+
+bool cMenuRecordingSelectItem::operator< (const cListObject &ListObject)
+{
+ cMenuRecordingSelectItem *temp = (cMenuRecordingSelectItem *)&ListObject;
+ if (isdir != temp->isdir)
+ return isdir;
+ if (isdir)
+ return strcasecmp(name, temp->name) < 0;
+ return start < temp->start;
+}
+
+void cMenuRecordingSelectItem::IncrementCounter(bool New)
+{
+ totalEntries++;
+ if (New)
+ newEntries++;
+ char *buffer = NULL;
+ asprintf(&buffer, "%d\t%d\t%s", totalEntries, newEntries, name);
+ SetText(buffer, false);
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingSelectItem::IncrementCounter FileName=%s New=%s Buffer=%s", plugin_name, filename, New ? "true" : "false", buffer);
+#endif
+}
+
+// --- cMenuRecordingSelect --------------------------------------------------------
+
+cMenuRecordingSelect::cMenuRecordingSelect(const char *Base, int Level, bool OpenSubMenus, bool SingleSelect)
+:cOsdMenu(Base ? Base : tr("Recordings"), 6, 6, 6)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingSelect::cMenuRecordingSelect Base=%s Level=%d OpenSubMenus=%s", plugin_name, Base, Level, OpenSubMenus ? "true" : "false");
+#endif
+#if VDRVERSNUM < 10311
+#ifdef HAVE_ELCHI
+ Interface->Status(tr("Display$prepare recording display..."), Setup.Theme == themeVanilla ? clrBlack : (eDvbColor)fginfofont, Setup.Theme == themeVanilla ? clrCyan : clrInfoLine);
+#else
+ Interface->Status(tr("Display$prepare recording display..."));
+#endif
+ Interface->Flush();
+#else
+ STATUS(tr("Display$prepare recording display..."));
+#endif
+ base = Base ? strdup(Base) : NULL;
+ level = Level;
+ singleselect = SingleSelect;
+ Display();
+ cMenuRecordingSelectItem *LastItem = NULL;
+ char *LastItemText = NULL;
+ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
+ {
+ if (!Base || (strstr(recording->Name(), Base) == recording->Name() && recording->Name()[strlen(Base)] == '~'))
+ {
+ cMenuRecordingSelectItem *Item = new cMenuRecordingSelectItem(recording, level);
+ if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0))
+ {
+ Add(Item);
+ LastItem = Item;
+ FREENULL(LastItemText);
+ LastItemText = strdup(LastItem->Text());
+ } else
+ delete Item;
+ if (LastItem)
+ {
+ if (LastSelectedRecord && strncmp(LastSelectedRecord, recording->FileName(), strlen(LastSelectedRecord)) == 0)
+ SetCurrent(LastItem);
+ if (LastItem->IsDirectory())
+ LastItem->IncrementCounter(recording->IsNew());
+ }
+ }
+ }
+ free(LastItemText);
+ LastItem = Current() < 0 ? NULL : (cMenuRecordingSelectItem *)Get(Current());
+ Sort();
+ if (LastItem)
+ {
+ SetCurrent(LastItem);
+ if (OpenSubMenus && Open(true) == osContinue)
+ return;
+ } else
+ SetCurrent(First());
+ SetHelpKeys();
+}
+
+cMenuRecordingSelect::~cMenuRecordingSelect()
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingSelect::~cMenuRecordingSelect Base=%s Level=%d", plugin_name, base, level);
+#endif
+ FREENULL(base);
+}
+
+void cMenuRecordingSelect::SetHelpKeys(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingSelect::SetHelpKeys", plugin_name);
+#endif
+
+ cMenuRecordingSelectItem *ri = (cMenuRecordingSelectItem *)Get(Current());
+ if (ri)
+ {
+ if (ri->IsDirectory())
+ if (singleselect)
+ SetHelp(tr("Open"));
+ else
+ SetHelp(tr("Add"), ri->IsMark() ? tr("UnMark") : tr("Mark"), NULL, NULL);
+ else
+ {
+ cRecording *recording = GetRecording(ri);
+ SetHelp(singleselect ? tr("Select") : tr("Add"), singleselect ? NULL : ri->IsMark() ? tr("UnMark") : tr("Mark"), deleterecords.u ? tr("Delete") : NULL, (recording && recording->Summary() && *recording->Summary()) ? tr("Summary") : NULL);
+ }
+ } else
+ {
+ SetHelp(NULL);
+ }
+}
+
+cRecording *cMenuRecordingSelect::GetRecording(cMenuRecordingSelectItem *Item)
+{
+ cRecording *recording = Recordings.GetByName(Item->FileName());
+ if (!recording)
+ ERROR(tr("Error while accessing recording!"));
+ return recording;
+}
+
+eOSState cMenuRecordingSelect::Open(bool OpenSubMenus)
+{
+ cMenuRecordingSelectItem *ri = (cMenuRecordingSelectItem *)Get(Current());
+ if (ri)
+ {
+ if (ri->IsDirectory())
+ {
+ const char *t = ri->Name();
+ char *buffer = NULL;
+ if (base)
+ {
+ asprintf(&buffer, "%s~%s", base, t);
+ t = buffer;
+ }
+ AddSubMenu(new cMenuRecordingSelect(t, level + 1, OpenSubMenus, singleselect));
+ FREENULL(buffer);
+ return osContinue;
+ } else if (!OpenSubMenus)
+ return AddPlaylist();
+ }
+ return osUnknown;
+}
+
+eOSState cMenuRecordingSelect::AddPlaylist(void)
+{
+ FREENULL(LastSelectedRecord);
+ cMenuRecordingSelectItem *ri = (cMenuRecordingSelectItem *)Get(Current());
+ if (ri)
+ {
+ if (ri->IsDirectory() && singleselect)
+ return Open();
+ LastSelectedRecord = strdup(ri->FileName());
+ if (ri->IsDirectory())
+ {
+ char *last = LastSelectedRecord + strlen(VideoDirectory) + 1;
+ for (int i = level; *last && i >= 0; i--)
+ {
+ last = strchr(last, '/');
+ if (!last)
+ break;
+ last++;
+ }
+ if (last)
+ *last = 0;
+ }
+ if (PlaylistMark.Count() && !ri->IsMark() && Interface->Confirm(tr("Add selected Record to Playlist?")))
+ {
+ cPlaylistMark *pm = new cPlaylistMark(LastSelectedRecord);
+ PlaylistMark.Add(pm);
+ }
+ return osUser1; // Add to Playlist in cMenuPlaylist::ProcessKey
+ }
+ return osUnknown;
+}
+
+eOSState cMenuRecordingSelect::MarkSel(void)
+{
+ if (singleselect)
+ return osContinue;
+ INFO("kommt noch ...?");
+ return osContinue;
+}
+
+eOSState cMenuRecordingSelect::Delete(void)
+{
+ if (!deleterecords.u || HasSubMenu() || Count() == 0)
+ return osContinue;
+ cMenuRecordingSelectItem *ri = (cMenuRecordingSelectItem *)Get(Current());
+ if (ri && !ri->IsDirectory() && Interface->Confirm(tr("Delete recording?")) && DeleteRecording(ri->FileName()))
+ {
+ cOsdMenu::Del(Current());
+ Display();
+ if (!Count())
+ return osBack;
+ }
+ return osContinue;
+}
+
+eOSState cMenuRecordingSelect::Summary(void)
+{
+ if (HasSubMenu() || Count() == 0)
+ return osContinue;
+ cMenuRecordingSelectItem *ri = (cMenuRecordingSelectItem *)Get(Current());
+ if (ri && !ri->IsDirectory())
+ {
+ cRecording *recording = GetRecording(ri);
+ if (recording && recording->Summary() && *recording->Summary())
+#if VDRVERSNUM >= 10307
+ return AddSubMenu(new cMenuText(tr("Summary"), recording->Summary()));
+#else
+ return AddSubMenu(new cMenuItemText(tr("Summary"), recording->Summary()));
+#endif
+ }
+ return osContinue;
+}
+
+eOSState cMenuRecordingSelect::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cMenuRecordingSelect::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ {
+ dsyslog("%s: cMenuRecordingSelect::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ switch (state)
+ {
+ case osUnknown: switch (Key)
+ {
+ case kOk: state = Open();
+ break;
+ case kRed: state = AddPlaylist();
+ break;
+ case kGreen: state = MarkSel();
+ break;
+ case kYellow: state = Delete();
+ break;
+ case kBlue: state = Summary();
+ break;
+ default: break;
+ }
+ break;
+ default: break;
+ }
+ if (!HasSubMenu() && Key != kNone)
+ SetHelpKeys();
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ dsyslog("%s: cMenuRecordingSelect::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
+
+// --- cMenuRecordingEdit -----------------------------------------------------------
+
+cMenuRecordingEdit::cMenuRecordingEdit(cPlaylistRecord *PlaylistRecord, bool ConfirmOptions)
+:cOsdMenu(ConfirmOptions ? tr("Edit$Confirm Options") : tr("Edit$Edit Record"), 33)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingEdit::cMenuRecordingEdit Playlistentry=%s ConfirmOptions=%s", plugin_name, PlaylistRecord ? PlaylistRecord->Name() : "(null)", ConfirmOptions ? "true" : "false");
+#endif
+ playlistrecord = PlaylistRecord;
+ confirmoptions = ConfirmOptions;
+#if VDRVERSNUM >= 10307
+ editwidth = DisplayMenu()->EditableWidth();
+#endif
+ DisplayStatus[0] = 0;
+ if (playlistrecord)
+ {
+ data = *playlistrecord;
+ Set();
+ }
+ SetHelpKeys();
+}
+
+cMenuRecordingEdit::~cMenuRecordingEdit()
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingEdit::~cMenuRecordingEdit Playlistentry=%s", plugin_name, playlistrecord ? playlistrecord->Name() : "(null)");
+#endif
+ data.filename = NULL;
+ data.summary = NULL;
+ data.title = NULL;
+ data.path = NULL;
+}
+
+void cMenuRecordingEdit::SetHelpKeys(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingEdit:SetHelpKeys", plugin_name);
+#endif
+
+ char *buffer = NULL;
+ eOptions display = (Current() >= 0) && (Current() < MAXOptionLines) ? displayoption[Current()] : Option_max;
+ if (display < Option_max && data.OptionInherited(display))
+ asprintf(&buffer, "%s %s", tr("OptionPL$is:"), NoYesDefault[data.Option(display)]);
+ if (buffer)
+ {
+ if (strcmp(DisplayStatus, buffer))
+ strn0cpy(DisplayStatus, buffer, MAXOSDTEXTWIDTH);
+ free(buffer);
+ } else
+ if (strlen(DisplayStatus))
+ DisplayStatus[0] = 0;
+ const char *red = strlen(DisplayStatus) ? DisplayStatus : NULL;
+ if (confirmoptions)
+ SetHelp(red);
+ else
+ SetHelp(red, (data.isdir || data.parent) ? NULL : tr("Select"), tr("Delete"), (data.summary && *data.summary) ? tr("Summary") : NULL);
+}
+
+void cMenuRecordingEdit::Set(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuRecordingEdit::Set Current=%d", plugin_name, Current());
+#endif
+ for (int i = 0; i < MAXOptionLines; i++)
+ displayoption[i] = Option_max;
+ int current = Current();
+ Clear();
+
+ if (data.path)
+ {
+ char *buffer = NULL;
+ asprintf(&buffer, "%s: %s", tr("Path"), data.path);
+
+#if VDRVERSNUM >= 10307
+ cOsdItem *item;
+ strreplace(buffer, ' ', '|');
+ strreplace(buffer, '~', ' ');
+ cTextWrapper *textwrapper = new cTextWrapper(buffer, cFont::GetFont(fontOsd), editwidth);
+ for (int i = 0; i < textwrapper->Lines(); i++)
+ {
+ char *textbuf = strdup(textwrapper->GetLine(i));
+ strreplace(buffer, ' ', '/');
+ strreplace(buffer, '|', ' ');
+ item = new cOsdItem(textbuf);
+ free(textbuf);
+ item->SetSelectable(false);
+ Add(item);
+ }
+ delete textwrapper;
+ item = new cOsdItem(" ");
+ item->SetSelectable(false);
+ Add(item);
+#else
+ strreplace(buffer, '~', '/');
+ char *pos = buffer;
+ char *pos_next;
+ char *pos_last;
+ char text[MAXOSDWIDTH + 1];
+ int textlen;
+
+ while (*pos)
+ {
+ pos_next = strchr(pos, '\n');
+ if (!pos_next)
+ pos_next = pos + strlen(pos);
+ textlen = pos_next - pos;
+ if (textlen < (Setup.OSDwidth - 1))
+ {
+ strn0cpy(text, pos, textlen + 1);
+ } else
+ {
+ strn0cpy(text, pos, Setup.OSDwidth - 1);
+ pos_last = strrchr(text, '/');
+ if (!pos_last)
+ pos_last = text + Setup.OSDwidth - 1;
+ *pos_last = 0;
+ textlen = pos_last - text;
+ }
+ Add(new cOsdItem(text));
+ pos += textlen;
+ if (*pos) pos++;
+ }
+ Add(new cOsdItem(" "));
+#endif
+ free(buffer);
+ }
+#if VDRVERSNUM < 10307
+ firstline = Count();
+#endif
+
+ Add(new cMenuEditStrItem(tr("OptionPL$Name"), data.name, sizeof(data.name), tr(FileNameChars)));
+ if (current < Count())
+ current = Count();
+ if (data.isdir)
+ {
+ displayoption[Count()] = Option_searchnewrecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$Search new records on folders"), &data.options[Option_searchnewrecord], 4, NoYesDefault));
+ displayoption[Count()] = Option_searchrecordsub;
+ Add(new cMenuEditStraItem(tr("OptionPL$Search records on subfolders"), &data.options[Option_searchrecordsub], 4, NoYesDefault));
+ displayoption[Count()] = Option_playonlynew;
+ Add(new cMenuEditStraItem(tr("OptionPL$Play only new Records"), &data.options[Option_playonlynew], data.parent ? 5 : 4, NoYesDefault));
+ }
+ displayoption[Count()] = Option_jumpmark;
+ Add(new cMenuEditStraItem(tr("OptionPL$Jump to first segment of movie"), &data.options[Option_jumpmark], data.parent ? 5 : 4, NoYesDefault));
+ displayoption[Count()] = Option_confirmstartnewrecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$Confirm start new record"), &data.options[Option_confirmstartnewrecord], data.parent ? 5 : 4, NoYesDefault));
+ displayoption[Count()] = Option_deletefromlist;
+ Add(new cMenuEditStraItem(tr("OptionPL$Remove records after play from list"), &data.options[Option_deletefromlist], data.parent ? 5 : 4, NoYesDefault));
+ displayoption[Count()] = Option_deleterecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$Delete records after play"), &data.options[Option_deleterecord], data.parent ? 5 : 4, NoYesDefault));
+ if (data.options[Option_deleterecord] != NoYesDefault_no)
+ {
+ displayoption[Count()] = Option_confirmdeleterecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$ Confirm delete records"), &data.options[Option_confirmdeleterecord], data.parent ? 5 : 4, NoYesDefault));
+ }
+ SetCurrent(Get(current));
+ Display();
+}
+
+eOSState cMenuRecordingEdit::Summary(void)
+{
+ if (!HasSubMenu() && !data.isdir && data.summary && *data.summary)
+#if VDRVERSNUM >= 10307
+ return AddSubMenu(new cMenuText(tr("Summary"), data.summary));
+#else
+ return AddSubMenu(new cMenuItemText(tr("Summary"), data.summary));
+#endif
+
+
+ return osContinue;
+}
+
+eOSState cMenuRecordingEdit::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cMenuRecordingEdit::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+ int m_deleterecord = data.options[Option_deleterecord];
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ {
+ dsyslog("%s: cMenuRecordingEdit::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ if (m_deleterecord != data.options[Option_deleterecord])
+ Set();
+
+#if VDRVERSNUM < 10307
+ if (Current() < firstline)
+ {
+ DisplayCurrent(false);
+ SetCurrent(Get(firstline));
+ DisplayCurrent(true);
+ }
+#endif
+
+ char *buffer = NULL;
+ eOptions display = (Current() >= 0) && (Current() < MAXOptionLines) ? displayoption[Current()] : Option_max;
+/* if (display < Option_max && data.OptionInherited(display))
+ asprintf(&buffer, "%s %s", tr("OptionPL$Effective setting is:"), NoYesDefault[data.Option(display)]);
+ if (buffer)
+ {
+ if (strcmp(DisplayStatus, buffer))
+ {
+ strn0cpy(DisplayStatus, buffer, MAXOSDTEXTWIDTH);
+ SetStatus(DisplayStatus);
+ }
+ free(buffer);
+ } else
+ {
+ if (strlen(DisplayStatus))
+ {
+ DisplayStatus[0] = 0;
+ SetStatus(NULL);
+ }
+ }*/
+
+ switch (state)
+ {
+ case osUnknown: switch (Key)
+ {
+ case kOk: strn0cpy(data.name, skipspace(stripspace(data.name)), sizeof(data.name));
+ Display();
+ if (!strlen(data.name))
+ {
+ ERROR(tr("Error$Missing playlistentry name!"));
+ break;
+ }
+ if (playlistrecord)
+ {
+ data.isdel = playlistrecord->isdel;
+ if (data != *playlistrecord)
+ {
+ *playlistrecord = data;
+ if (playlistrecord->Playlist())
+ playlistrecord->Playlist()->SetChange();
+ if (verbose.u)
+ isyslog("%s: playlistentry %d modified (%s)", plugin_name, playlistrecord->Index() + 1, playlistrecord->name);
+ }
+ data.filename = NULL;
+ state = osBack;
+ }
+ break;
+ case kRed: state = osContinue;
+ break;
+ case kGreen: LastSelectedRecord = playlistrecord->filename;
+ state = AddSubMenu(new cMenuRecordingSelect(NULL, 0, true, true));
+ break;
+ case kYellow: state = osUser2; // delete Playlistentry in cMenuPlaylist::ProcessKey
+ break;
+ case kBlue: state = Summary();
+ break;
+ default: break;
+ }
+ break;
+ case osUser1: state = CloseSubMenu();
+ if (state == osContinue && LastSelectedRecord && *LastSelectedRecord && LastSelectedRecord[strlen(LastSelectedRecord) - 1] != '/')
+ {
+ playlistrecord->SetName(LastSelectedRecord);
+ playlistrecord->CopyFromRecording();
+ data = *playlistrecord;
+ Set();
+ }
+ break;
+ default: break;
+ }
+ if (!HasSubMenu() && Key != kNone)
+ SetHelpKeys();
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ dsyslog("%s: cMenuRecordingEdit::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
+
+// --- cMenuPlaylistItem --------------------------------------------------------
+
+cMenuPlaylistItem::cMenuPlaylistItem(cPlaylistRecord *PlaylistRecord)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistItem::cMenuPlaylistItem Playlistentry=%s", plugin_name, PlaylistRecord ? PlaylistRecord->Name() : "(null)");
+#endif
+ playlistrecord = PlaylistRecord;
+ Set();
+}
+
+cMenuPlaylistItem::~cMenuPlaylistItem()
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistItem::~cMenuPlaylistItem Playlistentry=%s", plugin_name, playlistrecord ? playlistrecord->Name() : "(null)");
+#endif
+}
+
+void cMenuPlaylistItem::Set(void)
+{
+ char *buffer = NULL;
+ if (playlistrecord)
+ {
+ if (playlistrecord->IsDel())
+ asprintf(&buffer, "\t%s", tr("Error$Playlistentry or Record is deleted"));
+ else if (playlistrecord->IsDir())
+ asprintf(&buffer, "%c\t%s", charfolder.u, playlistrecord->Name());
+ else
+ asprintf(&buffer, "%c\t%s\t%s", playlistrecord->Parent() ? charentry.u : charrecord.u, playlistrecord->Title(), playlistrecord->Name());
+ } else
+ buffer = strdup(tr("Error$Playlistentry is not set"));
+ SetText(buffer, false);
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistItem::Set SetText=%s", plugin_name, buffer);
+#endif
+}
+
+// --- cMenuPlaylist -----------------------------------------------------------
+
+cMenuPlaylist::cMenuPlaylist(cPlaylist *Playlist)
+:cOsdMenu(tr("Display$Display Playlist"), 2, 6, 7, 5)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::cMenuPlaylist", plugin_name);
+#endif
+
+ playlist = Playlist;
+ if (playlist)
+ for (cPlaylistRecord *plr = playlist->First_PLR(); plr; plr = playlist->Next_PLR(plr))
+ if (!plr->IsDel())
+ Add(new cMenuPlaylistItem(plr));
+ addrecords = false;
+ if (Count())
+ {
+ SetHelpKeys();
+ Display();
+ } else
+ AddSubMenu(new cMenuRecordingSelect(NULL, 0, true));
+}
+
+cMenuPlaylist::~cMenuPlaylist(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::~cMenuPlaylist", plugin_name);
+#endif
+ playlist = NULL;
+}
+
+void cMenuPlaylist::SetHelpKeys(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::SetHelpKeys", plugin_name);
+#endif
+ if (Count())
+ SetHelp((playlist && *playlist->Name()) ? tr("Play") : NULL, tr("New"), tr("Delete"), tr("Mark"));
+ else
+ SetHelp(NULL, tr("New"), NULL, NULL);
+}
+
+eOSState cMenuPlaylist::Play(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::Play", plugin_name);
+#endif
+ cPlaylistRecord *plr = CurrentPlaylistRecord();
+ if (HasSubMenu() || !plr || !playlist || !*playlist->Name())
+ return osContinue;
+ if (verbose.u)
+ isyslog("%s: start play PlaylistRecord %d Option=%d", plugin_name, plr->Index() + 1, playlist->Playoption(Option_playoption2));
+ playlist->SearchRecords();
+ cPlaylistRecord *plr_selected = plr;
+ cPlaylistRecord *plr_firstnomal = playlist->Firstnormal_PLR();
+ cPlaylistRecord *plr_firstnew = playlist->Firstnew_PLR();
+ cPlaylistRecord *plr_lastplayed = playlist->Lastplayed_PLR();
+ while (plr_selected && plr_selected->IsDirOrDel())
+ plr_selected = playlist->Next_PLR(plr_selected);
+ switch (playlist->Playoption(Option_playoption2))
+ {
+ case PlayOptions_selectpos: SelectPLR = plr_selected;
+ if (!SelectPLR)
+ ERROR(tr("Error$At this position and after no recording found!"));
+ break;
+ case PlayOptions_firstpos: SelectPLR = plr_firstnomal;
+ break;
+ case PlayOptions_firstnew: if (plr_firstnew)
+ SelectPLR = plr_firstnew;
+ else
+ SelectPLR = Interface->Confirm(tr("Question$No new recording found! Play first?")) ? plr_firstnomal : NULL;
+ break;
+ case PlayOptions_lastplay: if (plr_lastplayed)
+ {
+ SelectPLR = plr_lastplayed;
+ break;
+ }
+ // no break!
+ case PlayOptions_question: if (plr_selected && Interface->Confirm(tr("Question$Play selected recording?")))
+ {
+ SelectPLR = plr_selected;
+ break;
+ }
+ if (plr_lastplayed && Interface->Confirm(tr("Question$Play last played recording?")))
+ {
+ SelectPLR = plr_lastplayed;
+ break;
+ }
+ if (plr_firstnew && plr_firstnew != plr_firstnomal && Interface->Confirm(tr("Question$Play first new recording?")))
+ {
+ SelectPLR = plr_firstnew;
+ break;
+ }
+ SelectPLR = plr_firstnomal;
+ break;
+ }
+ return SelectPLR ? osUser9 : osContinue; // osUSer9 starts play playlist with SelectPLR in cControlMenu::ProcessKey
+}
+
+eOSState cMenuPlaylist::Edit(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::Edit", plugin_name);
+#endif
+ if (HasSubMenu() || !CurrentPlaylistRecord())
+ return osContinue;
+ isyslog("%s: editing Playlistentry %d", plugin_name, CurrentPlaylistRecord()->Index() + 1);
+ return AddSubMenu(new cMenuRecordingEdit(CurrentPlaylistRecord()));
+}
+
+bool cMenuPlaylist::AddPlaylistentrys()
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::AddPlaylistentrys Add=%s", plugin_name, LastSelectedRecord);
+#endif
+ static cPlaylistRecord *playlistrecord = NULL;
+ bool iswithdir = LastSelectedRecord && LastSelectedRecord[strlen(LastSelectedRecord) - 1] == '/';
+ if (!playlistrecord && iswithdir)
+ {
+ playlistrecord = new cPlaylistRecord(NULL,LastSelectedRecord);
+ AddSubMenu(new cMenuRecordingEdit(playlistrecord, true));
+ addrecords = true;
+ return true;
+ }
+ if (!playlist || !playlist->RecordCol2())
+ return false;
+ if (iswithdir)
+ {
+ PlaylistSort.Clear();
+ cPlaylistRecord *p_plr = new cPlaylistRecord(playlist, LastSelectedRecord);
+ p_plr->CopyOptions(playlistrecord);
+ playlist->RecordCol2()->Add(p_plr);
+ cMenuPlaylistItem *mpli = new cMenuPlaylistItem(p_plr);
+ Add(mpli);
+ SetCurrent(mpli);
+ cPlaylistRecord *plr = NULL;
+ for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
+ {
+ if (strstr(recording->FileName(), LastSelectedRecord) == recording->FileName())
+ {
+ const char *next = NULL;
+ if (!p_plr->Option(Option_searchrecordsub))
+ {
+ const char *test = recording->FileName() + strlen(LastSelectedRecord);
+ const char *temp = strchr(test, '/');
+ if (temp)
+ next = strchr(temp + 1, '/');
+ }
+ if (!next)
+ {
+ plr = new cPlaylistRecord(playlist, recording, p_plr);
+ PlaylistSort.Add(plr);
+ }
+ }
+ }
+ PlaylistSort.Sort();
+ cPlaylistRecord *nplr = NULL;
+ for (plr = PlaylistSort.First(); plr; plr = nplr)
+ {
+ nplr = PlaylistSort.Next(plr);
+ PlaylistSort.Del(plr, false);
+ playlist->RecordCol2()->Add(plr);
+ Add(new cMenuPlaylistItem(plr));
+ }
+ } else
+ { // one record to add
+ cPlaylistRecord *plr = new cPlaylistRecord(playlist, LastSelectedRecord);
+ playlist->RecordCol2()->Add(plr);
+ cMenuPlaylistItem *mpli = new cMenuPlaylistItem(plr);
+ Add(mpli);
+ SetCurrent(mpli);
+ }
+ playlist->SetChange();
+ addrecords = false;
+ DELETENULL(playlistrecord);
+ Display();
+ return true;
+}
+
+eOSState cMenuPlaylist::New(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::New", plugin_name);
+#endif
+ if (HasSubMenu())
+ return osContinue;
+ cOsdMenu *menu = new cMenuRecordingSelect(NULL, 0, true);
+ eOSState state = AddSubMenu(menu);
+ if (LastSelectedRecord && LastSelectedRecord[strlen(LastSelectedRecord) - 1] == '/')
+ menu->ProcessKey(kBack);
+ return state;
+}
+
+eOSState cMenuPlaylist::Delete(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::Delete", plugin_name);
+#endif
+ cPlaylistRecord *plr = CurrentPlaylistRecord();
+ if (plr && playlist)
+ {
+ if (!confirmdelplentry.u || Interface->Confirm(tr("Edit$Delete Playlistentry?")))
+ {
+ if (verbose.u)
+ isyslog("%s: Playlistentry %d deleted", plugin_name, plr->Index() + 1);
+ plr->SetDel();
+ playlist->SetChange();
+ cOsdMenu::Del(Current());
+ Display();
+ }
+ }
+ return osContinue;
+}
+
+void cMenuPlaylist::Move(int From, int To)
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cMenuPlaylist::Move from=%d to=%d", plugin_name, From, To);
+#endif
+ if (playlist && playlist->RecordCol2())
+ {
+ cMenuPlaylistItem *temp = (cMenuPlaylistItem *)Get(From);
+ cPlaylistRecord *plr_f = temp ? temp->PlaylistRecord() : NULL;
+ temp = (cMenuPlaylistItem *)Get(To);
+ cPlaylistRecord *plr_t = temp ? temp->PlaylistRecord() : NULL;
+ cPlaylistRecord *plr_p = NULL;
+ if (To > 0)
+ {
+ temp = (cMenuPlaylistItem *)Get(To - 1);
+ plr_p = temp ? temp->PlaylistRecord() : NULL;
+ }
+ // plr_f --> cPlaylistRecord (Source)
+ // plr_t --> cPlaylistRecord at Targetposition
+ // plr_p --> cPlaylistRecord before Targetposition
+ if (!plr_f || !plr_t)
+ {
+ esyslog("%s: Error while get playlistentries in move-function", plugin_name);
+ return;
+ }
+ if (plr_f->Parent() == plr_t->Parent() || (plr_p && plr_f->Parent() == plr_p->Parent()))
+ {
+ playlist->RecordCol2()->Move(plr_f->Index(), plr_t->Index());
+ playlist->SetChange();
+ cOsdMenu::Move(From, To);
+ Display();
+ } else
+ ERROR(tr("Error$Move between folders and not folders not allowed."));
+ }
+}
+
+cPlaylistRecord *cMenuPlaylist::CurrentPlaylistRecord(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylist::CurrentPlaylistRecord", plugin_name);
+#endif
+ cMenuPlaylistItem *item = (cMenuPlaylistItem *)Get(Current());
+ return item ? item->PlaylistRecord() : NULL;
+}
+
+eOSState cMenuPlaylist::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cMenuPlaylist::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+ int n;
+ bool hSubMenu = HasSubMenu();
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ {
+ dsyslog("%s: cMenuPlaylist::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ if (!HasSubMenu() && hSubMenu)
+ {
+ for (cOsdItem *item = First(); item; item = Next(item))
+ item->Set();
+ if (addrecords)
+ AddPlaylistentrys(); // submenu for folder-options is closed
+ else
+ Display();
+ }
+
+ switch (state)
+ {
+ case osUnknown: switch (Key)
+ {
+ case k0...k9: n = (Key == k0) ? 10 : (Key - k0);
+ if (n > Count())
+ break;
+ SetCurrent(Get(--n));
+ // no break!
+ case kOk: state = Edit();
+ break;
+ case kRed: state = Play();
+ break;
+ case kGreen: state = New();
+ break;
+ case kYellow: state = Delete();
+ break;
+ case kBlue: if (!HasSubMenu())
+ {
+ Mark();
+ state = osContinue;
+ }
+ break;
+ default: break;
+ }
+ break;
+ case osUser1: state = CloseSubMenu();
+ if (state == osContinue)
+ AddPlaylistentrys();
+ break;
+ case osUser2: state = CloseSubMenu();
+ if (state == osContinue)
+ state = Delete();
+ break;
+ default: break;
+ }
+ if (!HasSubMenu() && Key != kNone)
+ SetHelpKeys();
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ dsyslog("%s: cMenuPlaylist::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
diff --git a/menuplaylist.h b/menuplaylist.h
new file mode 100644
index 0000000..697c18b
--- /dev/null
+++ b/menuplaylist.h
@@ -0,0 +1,113 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menuplaylist.h 0.1 2004/09/23 23:42:32 hflor Exp $
+ */
+
+#ifndef __MENUPLAYLIST_H
+#define __MENUPLAYLIST_H
+
+#include "dataplaylist.h"
+#include <vdr/menu.h>
+#include <vdr/menuitems.h>
+
+// --- cMenuRecordingSelectItem --------------------------------------------------------
+
+class cMenuRecordingSelectItem : public cOsdItem {
+private:
+ char *filename;
+ char *name;
+ time_t start;
+ bool isdir;
+ bool ismark;
+ int totalEntries;
+ int newEntries;
+public:
+ cMenuRecordingSelectItem(cRecording *Recording, int Level);
+ ~cMenuRecordingSelectItem();
+ virtual bool operator< (const cListObject &ListObject);
+ void IncrementCounter(bool New);
+ const char *FileName(void) { return filename; }
+ const char *Name(void) { return name; }
+ bool IsDirectory(void) { return isdir; }
+ bool IsMark(void) { return ismark; }
+ void SetMark(bool Mark) { ismark = Mark; }
+ };
+
+// --- cMenuRecordingSelect --------------------------------------------------------
+
+class cMenuRecordingSelect : public cOsdMenu {
+private:
+ char *base;
+ int level;
+ bool singleselect;
+ void SetHelpKeys(void);
+ cRecording *GetRecording(cMenuRecordingSelectItem *Item);
+ eOSState Open(bool OpenSubMenus = false);
+ eOSState AddPlaylist(void);
+ eOSState MarkSel(void);
+ eOSState Delete(void);
+ eOSState Summary(void);
+public:
+ cMenuRecordingSelect(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false, bool SingleSelect = false);
+ ~cMenuRecordingSelect();
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cMenuRecordingEdit --------------------------------------------------------
+
+class cMenuRecordingEdit : public cOsdMenu {
+private:
+ cPlaylistRecord *playlistrecord;
+ cPlaylistRecord data;
+ bool confirmoptions;
+ eOptions displayoption[MAXOptionLines];
+#if VDRVERSNUM >= 10307
+ int editwidth;
+#else
+ int firstline;
+#endif
+ void SetHelpKeys(void);
+ eOSState Summary(void);
+public:
+ cMenuRecordingEdit(cPlaylistRecord *PlaylistRecord, bool ConfirmOptions = false);
+ virtual ~cMenuRecordingEdit();
+ virtual void Set(void);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cMenuPlaylistItem --------------------------------------------------------
+
+class cMenuPlaylistItem : public cOsdItem {
+private:
+ cPlaylistRecord *playlistrecord;
+public:
+ cMenuPlaylistItem(cPlaylistRecord *PlaylistRecord);
+ virtual ~cMenuPlaylistItem();
+ virtual void Set(void);
+ cPlaylistRecord *PlaylistRecord(void) { return playlistrecord; }
+ };
+
+// --- cMenuPlaylist -----------------------------------------------------------
+
+class cMenuPlaylist : public cOsdMenu {
+private:
+ cPlaylist *playlist;
+ bool addrecords;
+ void SetHelpKeys(void);
+ bool AddPlaylistentrys(void);
+ eOSState Edit(void);
+ eOSState Play(void);
+ eOSState New(void);
+ eOSState Delete(void);
+ cPlaylistRecord *CurrentPlaylistRecord(void);
+public:
+ cMenuPlaylist(cPlaylist *Playlist);
+ virtual ~cMenuPlaylist();
+ virtual void Move(int From, int To);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+#endif //__MENUPLAYLIST_H
diff --git a/menuplaylists.c b/menuplaylists.c
new file mode 100644
index 0000000..aacb9b2
--- /dev/null
+++ b/menuplaylists.c
@@ -0,0 +1,569 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menuplaylists.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include "menuplaylists.h"
+#include "dataplaylist.h"
+#include "playlist.h"
+#include "menuplaylist.h"
+#include "i18n.h"
+#include "vdrtools.h"
+#include <vdr/interface.h>
+
+// --- cMenuPlaylistEdit -----------------------------------------------------------
+
+cMenuPlaylistEdit::cMenuPlaylistEdit(cPlaylist *Playlist, bool New)
+:cOsdMenu(New ? tr("Edit$Create Playlist") : tr("Edit$Edit Playlist"), 33)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistEdit::cMenuPlaylistEdit Playlist=%s new=%s", plugin_name, Playlist ? Playlist->Name() : "(null)", New ? "true" : "false");
+#endif
+ playlist = Playlist;
+ addIfConfirmed = New;
+ DisplayStatus[0] = 0;
+ if (playlist)
+ {
+ data = *playlist;
+ Set();
+ }
+ if (New)
+ AddSubMenu(new cMenuPlaylist(playlist));
+}
+
+cMenuPlaylistEdit::~cMenuPlaylistEdit()
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistEdit::~cMenuPlaylistEdit Playlist=%s addIfConfirmed=%s", plugin_name, playlist ? playlist->Name() : "(null)", addIfConfirmed ? "true" : "false");
+#endif
+ data.lastrecord = NULL;
+ data.recordcol = NULL;
+ if (playlist && addIfConfirmed)
+ delete playlist; // apparently it wasn't confirmed
+}
+
+void cMenuPlaylistEdit::Set(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistEdit::Set Current=%d", plugin_name, Current());
+#endif
+ for (int i = 0; i < MAXOptionLines; i++)
+ displayoption[i] = Option_max;
+ int current = Current();
+ Clear();
+ Add(new cMenuEditStrItem(tr("OptionPL$Name"), data.name, sizeof(data.name), tr(FileNameChars)));
+ displayoption[Count()] = Option_playoption1;
+ Add(new cMenuEditStraItem(tr("OptionPL$In playlistview starts play at"), &data.options[Option_playoption1], PlayOptions_max, PlayOptions));
+ displayoption[Count()] = Option_playoption2;
+ Add(new cMenuEditStraItem(tr("OptionPL$In detailview starts play at"), &data.options[Option_playoption2], PlayOptions_max, PlayOptions));
+ displayoption[Count()] = Option_searchnewrecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$Search new records on folders"), &data.options[Option_searchnewrecord], 3, NoYesDefault));
+ displayoption[Count()] = Option_searchrecordsub;
+ Add(new cMenuEditStraItem(tr("OptionPL$Search records on subfolders"), &data.options[Option_searchrecordsub], 3, NoYesDefault));
+ displayoption[Count()] = Option_playonlynew;
+ Add(new cMenuEditStraItem(tr("OptionPL$Play only new Records"), &data.options[Option_playonlynew], 3, NoYesDefault));
+ displayoption[Count()] = Option_jumpmark;
+ Add(new cMenuEditStraItem(tr("OptionPL$Jump to first segment of movie"), &data.options[Option_jumpmark], 3, NoYesDefault));
+ displayoption[Count()] = Option_confirmstartnewrecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$Confirm start new record"), &data.options[Option_confirmstartnewrecord], 3, NoYesDefault));
+ displayoption[Count()] = Option_deletefromlist;
+ Add(new cMenuEditStraItem(tr("OptionPL$Remove records after play from list"), &data.options[Option_deletefromlist], 3, NoYesDefault));
+ displayoption[Count()] = Option_deleterecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$Delete records after play"), &data.options[Option_deleterecord], 3, NoYesDefault));
+ if (data.options[Option_deleterecord] != NoYesDefault_no)
+ {
+ displayoption[Count()] = Option_confirmdeleterecord;
+ Add(new cMenuEditStraItem(tr("OptionPL$ Confirm delete records"), &data.options[Option_confirmdeleterecord], 3, NoYesDefault));
+ }
+ SetCurrent(Get(current));
+}
+
+eOSState cMenuPlaylistEdit::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cMenuPlaylistEdit::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+ int m_searchnewrecord = data.options[Option_searchnewrecord];
+ int m_jumpmark = data.options[Option_jumpmark];
+ int m_deleterecord = data.options[Option_deleterecord];
+ int m_playoption = data.options[Option_playoption1];
+ bool hSubMenu = HasSubMenu();
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ {
+ dsyslog("%s: cMenuPlaylistEdit::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ if (m_searchnewrecord != data.options[Option_searchnewrecord] || m_jumpmark != data.options[Option_jumpmark] || m_deleterecord != data.options[Option_deleterecord])
+ {
+ Set();
+ Display();
+ } else if (m_playoption != data.options[Option_playoption1] && data.options[Option_playoption1] == PlayOptions_selectpos)
+ {
+ data.options[Option_playoption1] = m_playoption < PlayOptions_selectpos ? PlayOptions_question : PlayOptions_lastplay;
+ RefreshCurrent();
+ }
+
+ char *buffer = NULL;
+ eOptions display = (Current() >= 0) && (Current() < MAXOptionLines) ? displayoption[Current()] : Option_max;
+ if (display < Option_max && data.OptionInherited(display))
+ asprintf(&buffer, "%s %s", tr("OptionPL$Effective setting is:"), (display == Option_playoption1 || display == Option_playoption2) ? PlayOptions[data.Playoption(display)] : NoYesDefault[data.Option(display)]);
+ if (buffer)
+ {
+ if (strcmp(DisplayStatus, buffer))
+ {
+ strn0cpy(DisplayStatus, buffer, MAXOSDTEXTWIDTH);
+ SetStatus(DisplayStatus);
+ }
+ free(buffer);
+ } else
+ {
+ if (strlen(DisplayStatus))
+ {
+ DisplayStatus[0] = 0;
+ SetStatus(NULL);
+ }
+ }
+ if (hSubMenu && !HasSubMenu())
+ {
+ if (playlist && playlist->RecordCol2() && !playlist->RecordCol2()->Count())
+ state = osBack; // empty new list
+//TODO name
+ RefreshCurrent(); // name
+ }
+
+ cPlaylist *tempplaylist = NULL;
+ bool namefound = false;
+ switch (state)
+ {
+ case osUnknown: switch (Key)
+ {
+ case kOk: strn0cpy(data.name, skipspace(stripspace(data.name)), sizeof(data.name));
+ Display();
+ if (!strlen(data.name))
+ {
+ ERROR(tr("Error$Missing playlist name!"));
+ break;
+ }
+ tempplaylist = PlaylistCol.First();
+ while (tempplaylist)
+ {
+ if (tempplaylist != playlist && !strcasecmp(tempplaylist->name, data.name))
+ {
+ namefound = true;
+ break;
+ }
+ tempplaylist = PlaylistCol.Next(tempplaylist);
+ }
+ if (namefound)
+ {
+ ERROR(tr("Error$same name of playlist exists!"));
+ break;
+ }
+ if (playlist)
+ {
+ if (data != *playlist)
+ {
+ if (strcmp(data.name, playlist->name))
+ playlist->SetChange();
+ *playlist = data;
+ if (addIfConfirmed)
+ PlaylistCol.Add(playlist);
+ PlaylistCol.Save();
+ if (verbose.u)
+ isyslog("%s: playlist %d %s (%s)", plugin_name, playlist->Index() + 1, addIfConfirmed ? "added" : "modified", playlist->name);
+ addIfConfirmed = false;
+ }
+ state = osBack;
+ }
+ break;
+ case kRed:
+ case kGreen:
+ case kYellow:
+ case kBlue: state = osContinue;
+ break;
+ default: break;
+ }
+ break;
+ case osBack: if (playlist && !strlen(playlist->name) && playlist->RecordCol2() && playlist->RecordCol2()->Count() && playlist->RecordCol2()->GetChange() && !Interface->Confirm(tr("Discard all changes?")))
+ state = osContinue;
+ default: break;
+ }
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ dsyslog("%s: cMenuPlaylistEdit::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
+
+// --- cMenuPlaylistsItem --------------------------------------------------------
+
+cMenuPlaylistsItem::cMenuPlaylistsItem(cPlaylist *Playlist)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistsItem::cMenuPlaylistsItem Playlist=%s", plugin_name, Playlist ? Playlist->Name() : "(null)");
+#endif
+ playlist = Playlist;
+ Set();
+}
+
+cMenuPlaylistsItem::~cMenuPlaylistsItem()
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistsItem::~cMenuPlaylistsItem Playlist=%s", plugin_name, playlist ? playlist->Name() : "(null)");
+#endif
+}
+
+bool cMenuPlaylistsItem::operator< (const cListObject &ListObject)
+{
+ return strcmp(playlist->Name(), ((cMenuPlaylistsItem *)&ListObject)->playlist->Name()) < 0;
+}
+
+void cMenuPlaylistsItem::Set(void)
+{
+ char *buffer = NULL;
+ asprintf(&buffer, "%d\t%d\t%s", playlist->RecordCount(), playlist->RecordNew(), playlist->Name());
+ SetText(buffer, false);
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylistsItem::Set SetText=%s", plugin_name, buffer);
+#endif
+}
+
+// --- cMenuPlaylists -----------------------------------------------------------
+
+cMenuPlaylists::cMenuPlaylists(void)
+:cOsdMenu(tr("Display$Display Playlists"), 4, 4)
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cMenuPlaylists::cMenuPlaylists", plugin_name);
+#endif
+ helpkeys = 1;
+
+#if VDRVERSNUM >= 10311
+ if (Recordings.NeedsUpdate())
+ {
+ STATUS(tr("scanning recordings..."));
+#else
+ if (time(NULL) - LoadTime_Recordings > 3600)
+ {
+ LoadTime_Recordings = time(NULL);
+#ifdef HAVE_ELCHI
+ Interface->Status(tr("scanning recordings..."), Setup.Theme == themeVanilla ? clrBlack : (eDvbColor)fginfofont, Setup.Theme == themeVanilla ? clrCyan : clrInfoLine);
+#else
+ Interface->Status(tr("scanning recordings..."));
+#endif
+ Interface->Flush();
+#endif
+ if (verbose.u)
+ isyslog("%s: loading recordings", plugin_name);
+ Recordings.Load();
+ if (verbose.u)
+ isyslog("%s: %d recordings loaded", plugin_name, Recordings.Count());
+ PlaylistSort.Clear();
+ PlaylistMark.Clear();
+ } else
+ {
+#if VDRVERSNUM < 10311
+#ifdef HAVE_ELCHI
+ Interface->Status(tr("Display$prepare playlists display..."), Setup.Theme == themeVanilla ? clrBlack : (eDvbColor)fginfofont, Setup.Theme == themeVanilla ? clrCyan : clrInfoLine);
+#else
+ Interface->Status(tr("Display$prepare playlists display..."));
+#endif
+ Interface->Flush();
+#else
+ STATUS(tr("Display$prepare playlists display..."));
+#endif
+ }
+ if (verbose.u)
+ isyslog("%s: loading playlists", plugin_name);
+ SelectPLR = NULL;
+ cMenuPlaylistsItem *selitem = NULL;
+ PlaylistCol.Load(PluginPlaylist->ExpandPath("playlists.conf"), false);
+ for (cPlaylist *playlist = PlaylistCol.First(); playlist; playlist = PlaylistCol.Next(playlist))
+ if (playlist->RecordCol2())
+ {
+ char *tempname = NULL;
+ asprintf(&tempname, "playlists.%s.conf", playlist->Name());
+ playlist->RecordCol2()->Load(PluginPlaylist->ExpandPath(tempname), false);
+ free(tempname);
+ cPlaylistRecord *plr_n = NULL;
+ for (cPlaylistRecord *plr = playlist->First_PLR(); plr; plr = plr_n)
+ {
+ plr->Playlist(playlist);
+ plr_n = playlist->Next_PLR(plr);
+ if (!plr->IsDir() && plr->Start() == 0)
+ playlist->RecordCol2()->Del(plr);
+ }
+ if (playlist->SearchRecords())
+ playlist->RecordCol2()->SaveWithFilename();
+ if (verbose.u)
+ isyslog("%s playlist '%s' contain %d records, %d new", plugin_name, playlist->Name(), playlist->RecordCount(), playlist->RecordNew());
+ cMenuPlaylistsItem *item = new cMenuPlaylistsItem(playlist);
+ Add(item);
+ if (strcasecmp(playlist->Name(), lastplaylist.u) == 0)
+ {
+ selitem = item;
+ SelectPLR = playlist->First_PLR();
+ }
+ }
+ Sort();
+ SetStatus(NULL);
+ if (selitem)
+ SetCurrent(selitem);
+ SetHelpKeys();
+ Display();
+}
+
+cMenuPlaylists::~cMenuPlaylists(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::~cMenuPlaylists", plugin_name);
+#endif
+}
+
+void cMenuPlaylists::SetHelpKeys(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::SetHelpKeys", plugin_name);
+#endif
+ if (Count())
+ switch (helpkeys)
+ {
+ case 1: SetHelp(okstartplay.u ? tr("Edit") : tr("Play"), tr("New"), tr("Delete"), "-->"); break;
+ case 2: SetHelp("<--", okstartplay.u ? NULL : tr("Edit"), tr("Option"), NULL); break;
+ }
+ else
+ {
+ helpkeys = 1;
+ SetHelp(NULL, tr("New"), NULL, NULL);
+ }
+}
+
+eOSState cMenuPlaylists::Play(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::Play", plugin_name);
+#endif
+ cPlaylist *playlist = CurrentPlaylist();
+ if (HasSubMenu() || !playlist)
+ return osContinue;
+ if (verbose.u)
+ isyslog("%s: start play Playlist %d Option=%d", plugin_name, playlist->Index() + 1, playlist->Playoption(Option_playoption1));
+ playlist->SearchRecords();
+ cPlaylistRecord *plr_firstnomal = playlist->Firstnormal_PLR();
+ cPlaylistRecord *plr_firstnew = playlist->Firstnew_PLR();
+ cPlaylistRecord *plr_lastplayed = playlist->Lastplayed_PLR();
+ switch (playlist->Playoption(Option_playoption1))
+ {
+ case PlayOptions_selectpos: // select not allow
+ case PlayOptions_firstpos: SelectPLR = plr_firstnomal;
+ break;
+ case PlayOptions_firstnew: if (plr_firstnew)
+ SelectPLR = plr_firstnew;
+ else
+ SelectPLR = Interface->Confirm(tr("Question$No new recording found! Play first?")) ? plr_firstnomal : NULL;
+ break;
+ case PlayOptions_lastplay: if (plr_lastplayed)
+ {
+ SelectPLR = plr_lastplayed;
+ break;
+ }
+ // no break!
+ case PlayOptions_question: if (plr_lastplayed && Interface->Confirm(tr("Question$Play last played recording?")))
+ {
+ SelectPLR = plr_lastplayed;
+ break;
+ }
+ if (plr_firstnew && plr_firstnew != plr_firstnomal && Interface->Confirm(tr("Question$Play first new recording?")))
+ {
+ SelectPLR = plr_firstnew;
+ break;
+ }
+ SelectPLR = plr_firstnomal;
+ break;
+ }
+ return SelectPLR ? osUser9 : osContinue; // osUSer9 starts play playlist with SelectPLR in cControlMenu::ProcessKey
+}
+
+eOSState cMenuPlaylists::New(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::New", plugin_name);
+#endif
+ if (HasSubMenu())
+ return osContinue;
+ FREENULL(LastSelectedRecord);
+ return AddSubMenu(new cMenuPlaylistEdit(new cPlaylist, true));
+}
+
+eOSState cMenuPlaylists::Delete(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::Delete", plugin_name);
+#endif
+ cPlaylist *playlist = CurrentPlaylist();
+ if (PlayedPLR && PlayedPLR->Playlist() == playlist)
+ {
+ ERROR(tr("Error$Playlist is currently used by played recording"));
+ return osContinue;
+ }
+ if (playlist && playlist->RecordCol2())
+ {
+ if (Interface->Confirm(tr("Edit$Delete Playlist?")))
+ {
+ if (verbose.u)
+ isyslog("%s: Playlist %d deleted", plugin_name, playlist->Index() + 1);
+ playlist->RecordCol2()->DeleteFile();
+ PlaylistCol.Del(playlist);
+ PlaylistCol.Save();
+ cOsdMenu::Del(Current());
+ Display();
+ }
+ }
+ return osContinue;
+}
+
+eOSState cMenuPlaylists::EditPlaylist(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::EditPlaylist", plugin_name);
+#endif
+ if (HasSubMenu() || !CurrentPlaylist())
+ return osContinue;
+ isyslog("%s: editing Playlist %d", plugin_name, CurrentPlaylist()->Index() + 1);
+ cPlaylist *playlist = CurrentPlaylist();
+ if (playlist)
+ playlist->SearchRecords();
+ return AddSubMenu(new cMenuPlaylist(playlist));
+}
+
+eOSState cMenuPlaylists::EditOption(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::EditOption", plugin_name);
+#endif
+ if (HasSubMenu() || !CurrentPlaylist())
+ return osContinue;
+ isyslog("%s: editing option Playlist %d", plugin_name, CurrentPlaylist()->Index() + 1);
+ return AddSubMenu(new cMenuPlaylistEdit(CurrentPlaylist()));
+}
+
+cPlaylist *cMenuPlaylists::CurrentPlaylist(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuPlaylists::CurrentPlaylist", plugin_name);
+#endif
+ cMenuPlaylistsItem *item = (cMenuPlaylistsItem *)Get(Current());
+ return item ? item->Playlist() : NULL;
+}
+
+eOSState cMenuPlaylists::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cMenuPlaylists::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+ cOsdItem *Item;
+ int n;
+ int nPlaylists = PlaylistCol.Count();
+ bool hSubMenu = HasSubMenu();
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ {
+ dsyslog("%s: cMenuPlaylists::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ if (!HasSubMenu() && hSubMenu)
+ {
+ if (nPlaylists == PlaylistCol.Count())
+ {
+ Item = Get(Current());
+ RefreshCurrent();
+ } else
+ Add((Item = new cMenuPlaylistsItem(PlaylistCol.Get(nPlaylists))));
+ Sort();
+ SetCurrent(Item);
+ cPlaylist *playlist = CurrentPlaylist();
+ if (playlist)
+ {
+ playlist->SearchRecords();
+ RefreshCurrent();
+ Display();
+ playlist->SaveRecordCol();
+ } else
+ {
+ RefreshCurrent();
+ Display();
+ }
+ }
+
+ switch (state)
+ {
+ case osUnknown: switch (Key)
+ {
+ case k0...k9: n = (Key == k0) ? 10 : (Key - k0);
+ if (n > Count())
+ break;
+ SetCurrent(Get(--n));
+ // no break!
+ case kOk: state = okstartplay.u ? Play() : EditPlaylist();
+ break;
+ case kRed: switch (helpkeys)
+ {
+ case 1: okstartplay.u ? EditPlaylist() : state = Play(); break;
+ case 2: helpkeys = 1; break;
+ }
+ break;
+ case kGreen: switch (helpkeys)
+ {
+ case 1: state = New(); break;
+ case 2: state = okstartplay.u ? osUnknown : EditPlaylist(); break;
+ }
+ break;
+ case kYellow: switch (helpkeys)
+ {
+ case 1: state = Delete(); break;
+ case 2: state = EditOption(); break;
+ }
+ break;
+ case kBlue: switch (helpkeys)
+ {
+ case 1: helpkeys = 2; break;
+ case 2: break;
+ }
+ break;
+ case kUser1: state = EditPlaylist();
+ break;
+ case kUser2: state = Play();
+ break;
+ case kUser3: state = New();
+ break;
+ default: break;
+ }
+ break;
+ default: break;
+ }
+ if (!HasSubMenu() && Key != kNone)
+ SetHelpKeys();
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ dsyslog("%s: cMenuPlaylists::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
diff --git a/menuplaylists.h b/menuplaylists.h
new file mode 100644
index 0000000..6bf67d9
--- /dev/null
+++ b/menuplaylists.h
@@ -0,0 +1,62 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menuplaylists.h 0.1 2004/09/23 23:42:32 hflor Exp $
+ */
+
+#ifndef __MENUPLAYLISTS_H
+#define __MENUPLAYLISTS_H
+
+#include "dataplaylist.h"
+#include <vdr/osd.h>
+#include <vdr/menu.h>
+
+// --- cMenuPlaylistEdit --------------------------------------------------------
+
+class cMenuPlaylistEdit : public cOsdMenu {
+private:
+ cPlaylist *playlist;
+ cPlaylist data;
+ bool addIfConfirmed;
+ eOptions displayoption[MAXOptionLines];
+public:
+ cMenuPlaylistEdit(cPlaylist *Playlist, bool New = false);
+ virtual ~cMenuPlaylistEdit();
+ virtual void Set(void);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+// --- cMenuPlaylistsItem --------------------------------------------------------
+
+class cMenuPlaylistsItem : public cOsdItem {
+private:
+ cPlaylist *playlist;
+public:
+ cMenuPlaylistsItem(cPlaylist *Playlist);
+ virtual ~cMenuPlaylistsItem();
+ virtual bool operator< (const cListObject &ListObject);
+ virtual void Set(void);
+ cPlaylist *Playlist(void) { return playlist; }
+ };
+
+// --- cMenuPlaylists -----------------------------------------------------------
+
+class cMenuPlaylists : public cOsdMenu {
+private:
+ int helpkeys;
+ void SetHelpKeys(void);
+ eOSState Play(void);
+ eOSState New(void);
+ eOSState Delete(void);
+ eOSState EditPlaylist(void);
+ eOSState EditOption(void);
+ cPlaylist *CurrentPlaylist(void);
+public:
+ cMenuPlaylists(void);
+ virtual ~cMenuPlaylists();
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+#endif //__MENUPLAYLISTS_H
diff --git a/menusetup.c b/menusetup.c
new file mode 100644
index 0000000..39eb387
--- /dev/null
+++ b/menusetup.c
@@ -0,0 +1,303 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menusetup.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include "menusetup.h"
+#include "playlist.h"
+#include "menuplaylists.h"
+#include "menucontrol.h"
+#include "i18n.h"
+#include "vdrtools.h"
+#include <vdr/plugin.h>
+
+// --- cMenuSetupPlayList -------------------------------------------------------
+
+cMenuSetupPlayList::cMenuSetupPlayList(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuSetupPlayList::cMenuSetupPlayList", plugin_name);
+#endif
+ store = false;
+ changedefault = false;
+
+ #define StoreValue(T) T.o = T.u
+ #define StoreValueFile(T) strcpy(T.o, T.u)
+
+ // var pos7
+ StoreValue (charentry);
+ StoreValue (charfolder);
+ StoreValue (charrecord);
+ StoreValue (commandline_preference);
+ StoreValueFile (lastplaylist);
+ StoreValueFile (mainmenu_name);
+ StoreValue (mainmenu_visible);
+ StoreValue (confirmdelplentry);
+ StoreValue (okstartplay);
+ StoreValue (deleterecords);
+ StoreValueFile (pathplaylists);
+ StoreValue (startoption);
+ StoreValue (storeplaylist);
+ StoreValue (timeoutreadrecords);
+ StoreValue (verbose);
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ StoreValue (PL_options[i]);
+
+ #undef StoreValue
+ #undef StoreValueFile
+
+ Set();
+}
+
+cMenuSetupPlayList::~cMenuSetupPlayList(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuSetupPlayList::~cMenuSetupPlayList store=%s", plugin_name, store ? "true" : "false");
+#endif
+ if (!store)
+ {
+
+ #define RestoreValue(T) T.u = T.o
+ #define RestoreValueFile(T) strcpy(T.u, T.o)
+
+ // var pos8
+ RestoreValue (charentry);
+ RestoreValue (charfolder);
+ RestoreValue (charrecord);
+ RestoreValue (commandline_preference);
+ RestoreValueFile (lastplaylist);
+ RestoreValueFile (mainmenu_name);
+ RestoreValue (mainmenu_visible);
+ RestoreValue (confirmdelplentry);
+ RestoreValue (okstartplay);
+ RestoreValue (deleterecords);
+ RestoreValueFile (pathplaylists);
+ RestoreValue (startoption);
+ RestoreValue (storeplaylist);
+ RestoreValue (timeoutreadrecords);
+ RestoreValue (verbose);
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ RestoreValue (PL_options[i]);
+
+ #undef RestoreValue
+ #undef RestoreValueFile
+ }
+}
+
+void cMenuSetupPlayList::Store(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuSetupPlayList::Store", plugin_name);
+#endif
+
+ #define SaveValue(T, N) if (T.u != T.o) SetupStore(N, T.u);
+ #define SaveValueChar(T, N) if (T.u != T.o) SetupStore(N, T.u + 256);
+ #define SaveValueFile(T, N) if (strcmp(T.u, T.o)) SetupStore(N, T.u);
+
+ // var pos9
+ SaveValueChar (charentry, "cahre");
+ SaveValueChar (charfolder, "charf");
+ SaveValueChar (charrecord, "charr");
+ SaveValue (commandline_preference, "commandline");
+ SaveValueFile (lastplaylist, "lastpl");
+ SaveValueFile (mainmenu_name, "name");
+ SaveValue (mainmenu_visible, "visible");
+ SaveValue (confirmdelplentry, "deletentry");
+ SaveValue (okstartplay, "okplay");
+ SaveValue (deleterecords, "delete");
+ SaveValueFile (pathplaylists, "path");
+ SaveValue (startoption, "start");
+ SaveValue (storeplaylist, "storepl");
+ SaveValue (timeoutreadrecords, "timerecords");
+ SaveValue (verbose, "verbose");
+ SaveValue (PL_options[Option_confirmdeleterecord], "confdelete");
+ SaveValue (PL_options[Option_confirmstartnewrecord], "startnew");
+ SaveValue (PL_options[Option_deletefromlist], "deletel");
+ SaveValue (PL_options[Option_deleterecord], "deleter");
+ SaveValue (PL_options[Option_jumpmark], "jumpmark");
+ SaveValue (PL_options[Option_playoption1], "playoption1");
+ SaveValue (PL_options[Option_playoption2], "playoption2");
+ SaveValue (PL_options[Option_playonlynew], "playonlynew");
+ SaveValue (PL_options[Option_searchnewrecord], "searchnew");
+ SaveValue (PL_options[Option_searchrecordsub], "searchsub");
+
+ #undef SaveValue
+ #undef SaveValueChar
+ #undef SaveValueFile
+
+ store = true;
+}
+
+void cMenuSetupPlayList::Set(bool sel)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cMenuSetupPlayList::Set Current=%d", plugin_name, Current());
+#endif
+ int current = Current();
+ Clear();
+ fileitempos = -1;
+
+ #define DisplayLine(T) !T.h && (!commandline_preference.u || !T.c)
+
+ Add(new cOsdItem (tr("Setup$Display playlists now"), osUser6));
+ Add(new cOsdItem (tr("Setup$Play last playlist now"), osUser7));
+ if (DisplayLine(commandline_preference))
+ Add(new cMenuEditBoolItem(tr("Setup$Preferr Command Line Parameter"), &commandline_preference.u));
+ if (DisplayLine(mainmenu_visible))
+ Add(new cMenuEditBoolItem(tr("Setup$Visible in Mainmenu"), &mainmenu_visible.u));
+ if (DisplayLine(mainmenu_name) && mainmenu_visible.u)
+ Add(new cMenuEditStrItem (tr("Setup$ Name for Mainmenu"), mainmenu_name.u, sizeof(mainmenu_name.u), tr(FileNameChars)));
+ if (DisplayLine(startoption))
+ Add(new cMenuEditStraItem(tr("Setup$Startoptions for plugin"), &startoption.u, 4, StartOptions));
+ if (DisplayLine(okstartplay))
+ Add(new cMenuEditBoolItem(tr("Setup$Press OK in Playlistview starts"), &okstartplay.u, tr("Setup$Edit"), tr("Setup$Play")));
+ if (DisplayLine(storeplaylist))
+ Add(new cMenuEditBoolItem(tr("Setup$Store playlist after change"), &storeplaylist.u, tr("Setup$automatically"), tr("Setup$after question")));
+ if (DisplayLine(deleterecords))
+ Add(new cMenuEditBoolItem(tr("Setup$Allow delete Records"), &deleterecords.u));
+ if (DisplayLine(confirmdelplentry))
+ Add(new cMenuEditBoolItem(tr("Setup$Confirm delete playlistentries"), &confirmdelplentry.u));
+ if (DisplayLine(pathplaylists))
+ {
+ fileitempos = Count();
+ Add(new cMenuEditStrItem (tr("Setup$Path for store playlists"), pathplaylists.u, sizeof(pathplaylists.u), FileNameCharsAllowed));
+ }
+ Add(new cMenuEditBoolItem(tr("Setup$Change default options for playlist"), &changedefault));
+ if (changedefault)
+ {
+ if (DisplayLine(PL_options[Option_playoption1]))
+ Add(new cMenuEditStraItem(tr("OptionPL$ In playlistview starts play at"), &PL_options[Option_playoption1].u, PlayOptions_max - 1, PlayOptions));
+ if (DisplayLine(PL_options[Option_playoption2]))
+ Add(new cMenuEditStraItem(tr("OptionPL$ In detailview starts play at"), &PL_options[Option_playoption2].u, PlayOptions_max - 1, PlayOptions));
+ if (DisplayLine(PL_options[Option_searchnewrecord]))
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Search new records on folders"), &PL_options[Option_searchnewrecord].u));
+ if (DisplayLine(PL_options[Option_searchrecordsub]))
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Search new records on subfolders"), &PL_options[Option_searchrecordsub].u));
+ if (DisplayLine(PL_options[Option_playonlynew]))
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Play only new Records"), &PL_options[Option_playonlynew].u));
+ if (DisplayLine(PL_options[Option_jumpmark]))
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Jump to first segment of movie"), &PL_options[Option_jumpmark].u));
+ if (DisplayLine(PL_options[Option_confirmstartnewrecord]))
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Confirm start new record"), &PL_options[Option_confirmstartnewrecord].u));
+ if (DisplayLine(PL_options[Option_deletefromlist]))
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Remove records after play from list"), &PL_options[Option_deletefromlist].u));
+ if (DisplayLine(PL_options[Option_deleterecord]) && deleterecords.u)
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Delete records after play"), &PL_options[Option_deleterecord].u));
+ if (DisplayLine(PL_options[Option_confirmdeleterecord]) && PL_options[Option_deleterecord].u && deleterecords.u)
+ Add(new cMenuEditBoolItem(tr("OptionPL$ Confirm delete records"), &PL_options[Option_confirmdeleterecord].u));
+ }
+ Add(new cMenuEditBoolItem(tr("Setup$Change Character for identification"), &changechar));
+ if (changechar)
+ {
+ if (DisplayLine(charfolder))
+ Add(new cMenuEditChrItem(tr("OptionPL$ Character for folders"), &charfolder.u, AllCharsAllowed));
+ if (DisplayLine(charentry))
+ Add(new cMenuEditChrItem(tr("OptionPL$ Character for records in folders"), &charentry.u, AllCharsAllowed));
+ if (DisplayLine(charrecord))
+ Add(new cMenuEditChrItem(tr("OptionPL$ Character for normal records"), &charrecord.u, AllCharsAllowed));
+ }
+ if (DisplayLine(verbose))
+ Add(new cMenuEditBoolItem(tr("Setup$Verbose Log Mode"), &verbose.u));
+ if (sel && changechar)
+ SetCurrent(Get(Count() - 1));
+
+ #undef DisplayLine
+
+#ifdef PL_Debug2
+ dsyslog("%s: Count=%d", plugin_name, Count());
+#endif
+ SetCurrent(Get(current));
+}
+
+eOSState cMenuSetupPlayList::ProcessKey(eKeys Key)
+{
+#ifdef PL_Debug3
+ bool noneKey = Key == kNone;
+ if (!noneKey)
+ dsyslog("%s: cMenuSetupPlayList::ProcessKey Key=%s", plugin_name, KeyName(Key));
+#endif
+ static char oldstatus[MAXOSDTEXTWIDTH];
+ char status[MAXOSDTEXTWIDTH];
+ int pathlen;
+
+ int m_commandline_preference = commandline_preference.u;
+ int m_mainmenu_visible = mainmenu_visible.u;
+ int m_deleterecords = deleterecords.u;
+ int m_changedefault = changedefault;
+ int m_deleterecord = PL_options[Option_deleterecord].u;
+ int m_changechar = changechar;
+ int m_playoption = PL_options[Option_playoption1].u;
+
+ eOSState state = cMenuSetupPage::ProcessKey(Key);
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ {
+ dsyslog("%s: cMenuSetupPlayList::ProcessKey OSState=%s", plugin_name, OSStateName(state));
+ noneKey = false;
+ }
+#endif
+
+ if (m_commandline_preference != commandline_preference.u || m_mainmenu_visible != mainmenu_visible.u || m_deleterecords != deleterecords.u || m_changedefault != changedefault || m_deleterecord != PL_options[Option_deleterecord].u || m_changechar != changechar)
+ {
+ Set(m_changechar != changechar);
+ Display();
+ if (!m_changedefault && changedefault)
+ {
+ for (int i = 0; i < 5; i++)
+ CursorDown();
+ for (int i = 0; i < 5; i++)
+ CursorUp();
+ }
+ } else if (m_playoption != PL_options[Option_playoption1].u && PL_options[Option_playoption1].u == PlayOptions_selectpos)
+ {
+ PL_options[Option_playoption1].u = m_playoption < PlayOptions_selectpos ? PlayOptions_question : PlayOptions_lastplay;
+ RefreshCurrent();
+ }
+ if (Current() == fileitempos)
+ {
+ const char *temp = PluginPlaylist->ExpandPath("", false);
+ pathlen = strlen(temp);
+ if (pathlen > AKTOSDTEXTWIDTH - 10)
+ sprintf(status, "...%s", temp + pathlen - AKTOSDTEXTWIDTH + 10);
+ else
+ strcpy(status, temp);
+ if (oldstatus != status)
+ {
+ SetStatus(status);
+ strcpy(oldstatus, status);
+ }
+ } else if (strlen(oldstatus))
+ {
+ SetStatus(NULL);
+ oldstatus[0] = 0;
+ }
+ switch (state)
+ {
+ case osUser6: state = AddSubMenu(new cMenuPlaylists);
+ break;
+ case osUser7: {
+ cMenuPlaylists *menu = new cMenuPlaylists;
+ if (SelectPLR)
+ menu->ProcessKey(kUser2);
+ state = AddSubMenu(menu);
+ }
+ break;
+ case osUser9: if (SelectPLR)
+ {
+ cControl::Shutdown(); // Start play (SelectPLR)
+ cControl::Launch(new cControlPlaylist);
+ }
+ state = osEnd;
+ break;
+ default: break;
+ }
+
+#ifdef PL_Debug3
+ if (!noneKey || (state != osUnknown && state != osContinue))
+ dsyslog("%s: cMenuSetupPlayList::ProcessKey returned OSState=%s", plugin_name, OSStateName(state));
+#endif
+ return state;
+}
diff --git a/menusetup.h b/menusetup.h
new file mode 100644
index 0000000..aac738f
--- /dev/null
+++ b/menusetup.h
@@ -0,0 +1,32 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: menusetup.h 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#ifndef __MENUSETUP_H
+#define __MENUSETUP_H
+
+#include <vdr/menu.h>
+#include <vdr/menuitems.h>
+
+// --- cMenuSetupPlayList -------------------------------------------------------
+
+class cMenuSetupPlayList : public cMenuSetupPage {
+private:
+ int store;
+ int fileitempos;
+ int changedefault;
+ int changechar;
+protected:
+ virtual void Store(void);
+public:
+ cMenuSetupPlayList(void);
+ virtual ~cMenuSetupPlayList(void);
+ virtual void Set(bool sel = false);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+#endif //__MENUSETUP_H
diff --git a/playlist.c b/playlist.c
new file mode 100644
index 0000000..484644a
--- /dev/null
+++ b/playlist.c
@@ -0,0 +1,608 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: playlist.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include "playlist.h"
+#include "menuplaylists.h"
+#include "menucontrol.h"
+#include "menusetup.h"
+#include "i18n.h"
+#include "vdrtools.h"
+#include <getopt.h>
+#include <ctype.h>
+#include <vdr/recording.h>
+
+static const char *VERSION = "0.0.2";
+static const char *DESCRIPTION = "playlist for recordings";
+
+/* TODO
+option playonlynewrecords
+*/
+// Global variables that control the overall behaviour:
+
+// var pos2
+tParamFile playlistconfigfile = { false, false, false, "playlist.conf", "playlist.conf" };
+#ifdef HAVE_ICONPATCH
+tParamChar charentry = { false, false, false, 236 };
+tParamChar charfolder = { false, false, false, 237 };
+tParamChar charrecord = { false, false, false, 249 };
+#else
+tParamChar charentry = { false, false, false, 'e' };
+tParamChar charfolder = { false, false, false, 'f' };
+tParamChar charrecord = { false, false, false, 'r' };
+#endif
+tParamInt commandline_preference = { false, false, false, true };
+tParamFile lastplaylist = { false, false, false, "" };
+tParamFile mainmenu_name = { false, false, false, "Playlist" };
+tParamInt mainmenu_visible = { false, false, false, true };
+tParamInt confirmdelplentry = { false, false, false, true };
+tParamInt okstartplay = { false, false, false, true };
+tParamInt deleterecords = { false, false, false, true };
+tParamFile pathplaylists = { false, false, false, "" };
+tParamInt startoption = { false, false, false, 0 };
+tParamInt storeplaylist = { false, false, false, 0 };
+tParamInt timeoutreadrecords = { false, false, false, 60 };
+tParamInt verbose = { false, false, false, false, true };
+tParamInt PL_options[Option_max] ={{ false, false, false, true }, // confirmdeleterecord
+ { false, false, false, false }, // confirmstartnewrecord
+ { false, false, false, true }, // deletefromlist
+ { false, false, false, false }, // deleterecord
+ { false, false, false, true }, // jumpmark
+ { false, false, false, PlayOptions_firstnew }, // playoption1
+ { false, false, false, PlayOptions_selectpos }, // playoption2
+ { false, false, false, false }, // playonlynew
+ { false, false, false, true }, // searchnewrecord
+ { false, false, false, true }}; // searchrecordsub
+
+char plugin_name[MaxFileName] = "Playlist";
+char DisplayStatus[MAXOSDTEXTWIDTH] = "";
+const char *NoYesDefault[NoYesDefault_max];
+const char *StartOptions[Start_max];
+const char *PlayOptions[PlayOptions_max];
+char *FileNameCharsAllowed = NULL;
+char *AllCharsAllowed = NULL;
+char *LastSelectedRecord = NULL;
+bool ControlMenuIsOpen = false;
+#if VDRVERSNUM < 10311
+cRecordings Recordings;
+time_t LoadTime_Recordings;
+#endif
+
+void DisplaySetings(void)
+{
+ #define WriteSource(T) plugin_name, T.r ? 'r' : ' ', T.c ? 'c' : ' '
+ #define IsDefault(T) WriteSource(T), T.u == T.d ? '*' : ' '
+ #define IsDefaultChar(T) WriteSource(T), strcmp(T.u, T.d) ? ' ' : '*'
+ #define BoolValue(T) IsDefault(T), T.u ? "yes" : "no"
+
+ // var pos3
+ ExpandEnvironment(&pathplaylists);
+ if (verbose.u)
+ {
+ isyslog("%s: commandline_preference = [ %c%c%c ] %s", BoolValue(commandline_preference));
+ isyslog("%s: mainmenu_visible = [ %c%c%c ] %s", BoolValue(mainmenu_visible));
+ if (mainmenu_visible.u)
+ isyslog("%s: mainmenu_name = [ %c%c%c ] %s", IsDefaultChar(mainmenu_name), mainmenu_name.u);
+ }
+
+#ifdef PL_Debug1
+ if (!verbose.u)
+ {
+ dsyslog("%s: commandline_preference = [ %c%c%c ] %s", BoolValue(commandline_preference));
+ dsyslog("%s: mainmenu_visible = [ %c%c%c ] %s", BoolValue(mainmenu_visible));
+ if (mainmenu_visible.u)
+ dsyslog("%s: mainmenu_name = [ %c%c%c ] %s", IsDefaultChar(mainmenu_name), mainmenu_name.u);
+ }
+#endif
+
+ #undef WriteSource
+ #undef IsDefault
+ #undef IsDefaultChar
+ #undef BoolValue
+}
+
+void ExpandEnvironment(tParamFile *FileStruc)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: ExpandEnvironment text=%s", plugin_name, FileStruc->u);
+#endif
+ char *s;
+ char *p;
+ strn0cpy(FileStruc->e, FileStruc->u, sizeof(FileStruc->e));
+ while ((s = strstr(FileStruc->e, "$(")) || (s = strstr(FileStruc->e, "${")))
+ {
+ char c = *(s + 1) == '(' ? ')' : '}';
+ p = strchr(s, c); // search closing ) or }
+ if (p)
+ {
+ *p++ = 0;
+ *s = 0;
+ s += 2;
+ char *e = getenv(s);
+ if (e)
+ {
+ char *buffer = NULL;
+ asprintf(&buffer, "%s%s%s", FileStruc->e, e, p);
+ strn0cpy(FileStruc->e, buffer, sizeof(FileStruc->e));
+ FREENULL(buffer);
+ } else
+ {
+ esyslog("%s: environmentvariable '%s' not found path=%s", plugin_name, s, FileStruc->u);
+ FileStruc->e[0] = 0;
+ }
+ } else
+ {
+ esyslog("%s: missing ')' after '$(' path=%s", plugin_name, FileStruc->u);
+ FileStruc->e[0] = 0;
+ }
+ }
+ while ((p = strstr(FileStruc->e, "//")))
+ strcpy(p, p + 1);
+#ifdef PL_Debug2
+ dsyslog("%s: ExpandEnvironment return=%s", plugin_name, FileStruc->e);
+#endif
+}
+
+// --- cPluginPlaylist ----------------------------------------------------------
+
+cPluginPlaylist *PluginPlaylist;
+
+cPluginPlaylist::cPluginPlaylist(void)
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cPluginPlaylist::cPluginPlaylist", plugin_name);
+#endif
+ // Initialize any member variables here.
+ // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
+ // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
+ OSDLanguage = -1;
+ PluginPlaylist = this;
+}
+
+cPluginPlaylist::~cPluginPlaylist()
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cPluginPlaylist::~cPluginPlaylist", plugin_name);
+#endif
+ // Clean up after yourself!
+ FREENULL(FileNameCharsAllowed);
+ FREENULL(AllCharsAllowed);
+ FREENULL(LastSelectedRecord);
+ PluginPlaylist = NULL;
+}
+
+void cPluginPlaylist::TestAndSetOSDLanguage(void)
+{
+#ifdef PL_Debug2
+ dsyslog("%s: cPluginPlaylist::TestAndSetOSDLanguage OSDLanguage=%d", plugin_name, Setup.OSDLanguage);
+#endif
+ if (OSDLanguage != Setup.OSDLanguage)
+ {
+ OSDLanguage = Setup.OSDLanguage;
+
+ StartOptions[Start_DisplayPL] = tr("Setup$Display PL");
+ StartOptions[Start_DisplayLast] = tr("Setup$Display last PL");
+ StartOptions[Start_PlayLast] = tr("Setup$Play last PL");
+ StartOptions[Start_NewEmpty] = tr("Setup$new empty PL");
+ NoYesDefault[NoYesDefault_no] = tr("no");
+ NoYesDefault[NoYesDefault_yes] = tr("yes");
+ NoYesDefault[NoYesDefault_defaultPlugin] = tr("OptionPL$[from Setup]");
+ NoYesDefault[NoYesDefault_defaultPlaylist] = tr("OptionPL$[from Playlist]");
+ NoYesDefault[NoYesDefault_defaultRecordDir] = tr("OptionPL$[from Folder]");
+ PlayOptions[PlayOptions_firstpos] = tr("OptionPL$first pos");
+ PlayOptions[PlayOptions_firstnew] = tr("OptionPL$first new");
+ PlayOptions[PlayOptions_lastplay] = tr("OptionPL$last played");
+ PlayOptions[PlayOptions_selectpos] = tr("OptionPL$seletced pos");
+ PlayOptions[PlayOptions_question] = tr("OptionPL$question");
+ PlayOptions[PlayOptions_defaultPlugin] = tr("OptionPL$[from Setup]");
+ FREENULL(FileNameCharsAllowed);
+ asprintf(&FileNameCharsAllowed, "%s/$(){}!%%@", tr(FileNameChars));
+ if (!AllCharsAllowed)
+ {
+ AllCharsAllowed = MALLOC(char, 193);
+ char *next = AllCharsAllowed;
+ for (int i = 32; i <= 127; i++)
+ *next++ = i;
+ for (int i = 160; i <= 255; i++)
+ *next++ = i;
+ *next = 0;
+ }
+ }
+}
+
+bool cPluginPlaylist::ProcessArg(int argc, char *argv[])
+{
+ int c;
+ static struct option long_options[] = {
+ { "delete_begin", no_argument, NULL, 'b' },
+ { "nodelete_begin", no_argument, NULL, 'B' },
+ { "min_entrys", required_argument, NULL, 'd' },
+ { "delete_end", no_argument, NULL, 'e' },
+ { "nodelete_end", no_argument, NULL, 'E' },
+ { "holdtime_history", required_argument, NULL, 'h' },
+ { "visible_in_mainmenu", no_argument, NULL, 'm' },
+ { "hide_in_mainmenu", no_argument, NULL, 'M' },
+ { "mainmenu_name", required_argument, NULL, 'n' },
+ { "holdtime_respones", required_argument, NULL, 'r' },
+ { "sort_ascending", no_argument, NULL, 's' },
+ { "sort_descending", no_argument, NULL, 'S' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "noverbose", no_argument, NULL, 'V' },
+ { "nosetup_commandline", no_argument, NULL, 1 },
+ { "ns_commandline", no_argument, NULL, 1 },
+ { NULL }
+ };
+
+ if (argc >= 1)
+ strn0cpy(plugin_name, argv[0], sizeof(plugin_name));
+
+ for (c = 1; c < argc; c++)
+ dsyslog("%s: parameter%d=%s", plugin_name, c, argv[c]);
+
+ #define Setvalue(T) T.c = true; T.u
+ #define SetvalueChar(T) T.c = true; strn0cpy(T.u, optarg, sizeof(T.u))
+
+ while ((c = getopt_long(argc, argv, "bBd:eEh:mMn:r:sSvV", long_options, NULL)) != -1)
+ {
+ // var pos4
+ switch (c)
+ {
+ case 1: commandline_preference.h = true;
+ break;
+/* case 'b': Setvalue(delete_b_e) |= 0x1;
+ break;
+ case 'B': Setvalue(delete_b_e) &= ~0x1;
+ break;
+ case 'd': if (isnumber(optarg))
+ {
+ Setvalue(num_entrys) = atoi(optarg);
+ Setvalue(delete_b_e) = 0x3;
+ if (num_entrys.u > 0) break;
+ }
+ esyslog("%s: invalid parameter for -d option: %s", plugin_name, optarg);
+ return false;
+ case 'e': Setvalue(delete_b_e) |= 0x2;
+ break;
+ case 'E': Setvalue(delete_b_e) &= ~0x2;
+ break;
+ case 'h': if (isnumber(optarg))
+ {
+ Setvalue(message_in_queue) = atoi(optarg);
+ if (message_in_queue.u >=5 && message_in_queue.u <= 999) break;
+ }
+ esyslog("%s: invalid parameter for -h option: %s range 5-999", plugin_name, optarg);
+ return false;
+ case 'm': Setvalue(mainmenu_visible) = true;
+ break;
+ case 'M': Setvalue(mainmenu_visible) = false;
+ break;
+ case 'n': SetvalueChar(mainmenu_name);
+ Setvalue(mainmenu_visible) = true;
+ break;
+ case 'r': if (isnumber(optarg))
+ {
+ Setvalue(response_in_queue) = atoi(optarg);
+ if (response_in_queue.u >= 2 && response_in_queue.u <= 199) break;
+ }
+ esyslog("%s: invalid parameter for -r option: %s range 2-199", plugin_name, optarg);
+ return false;
+ case 's': Setvalue(sortdirection) = true;
+ break;
+ case 'S': Setvalue(sortdirection) = false;
+ break;*/
+ case 'v': Setvalue(verbose) = true;
+ break;
+ case 'V': Setvalue(verbose) = false;
+ break;
+ default: return false;
+ }
+ }
+
+ #undef Setvalue
+ #undef SetvalueChar
+
+ if (optind < argc && argv[optind][0] == '@')
+ {
+ strn0cpy(playlistconfigfile.u, &argv[optind][1], sizeof(playlistconfigfile.u));
+ optind++;
+ }
+ return optind >= argc;
+}
+
+const char *cPluginPlaylist::Version(void)
+{
+ return VERSION;
+}
+
+const char *cPluginPlaylist::Description(void)
+{
+ return tr(DESCRIPTION);
+}
+
+const char *cPluginPlaylist::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return " -m --visible_in_mainmenu Show the plugin in the mainmenu\n"
+ " -M --hide_in_mainmenu Hide the plugin in the mainmenu\n"
+ " -n Name --mainmenu_name=Name Select Name for entry in the mainmenu (set also -m)\n"
+ " -b --delete_begin Show the delete all messages line at begin of messagelist\n"
+ " -B --nodelete_begin Hide the delete all messages line at begin of messagelist\n"
+ " -e --delete_end Show the delete all messages line at end of messagelist\n"
+ " -E --nodelete_end Hide the delete all messages line at end of messagelist\n"
+ " -d xx --min_entrys=xx minimum entrys for display delete all messages line at begin and end (include -b and -e)\n"
+ " -h xx --holdtime_history=xx minimum time (min) for message in historyqueue (OSD-list) 5-999\n"
+ " -r xx --holdtime_respones=xx minumum time (min) for responses in queue (readable by SAQRESP) 2-199\n"
+ " -s --sort_ascending sortoption for messagelist (OSD)\n"
+ " -S --sort_descending sortoption for messagelist (OSD)\n"
+ " -v --verbose Enable more logging\n"
+ " -V --noverbose Disable more loggig\n"
+ " --nosetup_commandline Hide the Preferr Command Line Parameter form setup-menu\n"
+ " --ns_commandline same as --nosetup_commandline";
+ // free: a c f g i j k l o p q t u v w x y z
+}
+
+bool cPluginPlaylist::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+ return ProcessArg(argc, argv);
+}
+
+#ifdef PL_Debug1
+void TestI18n(char *Test)
+{
+ Setup.OSDLanguage = 0;
+ const char *eng = tr(Test);
+ Setup.OSDLanguage = 1;
+ const char *deu = tr(Test);
+ if (eng && deu && strcmp(eng, deu) == 0)
+ dsyslog("%s: missing: %s", plugin_name, Test);
+}
+#endif
+
+bool cPluginPlaylist::Start(void)
+{
+ // Start any background activities the plugin shall perform.
+ RegisterI18n(Phrases);
+ TestAndSetOSDLanguage();
+
+#ifdef PL_Debug1
+ dsyslog("%s: cPluginPlaylist::Start playlistconfigfile=%s", plugin_name, playlistconfigfile.u);
+#endif
+
+ char *p;
+ char *q = strdup(ConfigDirectory(""));
+ asprintf(&p, "%s%s%s", q, *(q + strlen(q) - 1) == '/' ? "" : "/", playlistconfigfile.u);
+ if (!access(playlistconfigfile.u, F_OK) && !access(playlistconfigfile.u, R_OK) || !access(p, F_OK) && !access(p, R_OK))
+ {
+ #define MAXARGS 100
+ int fargc = 1;
+ char *fargv[MAXARGS];
+ char buffer[MAXPARSEBUFFER];
+ bool done;
+ FILE *f;
+
+ if (!access(playlistconfigfile.u, F_OK))
+ {
+ f = fopen(playlistconfigfile.u, "r");
+#ifdef PL_Debug2
+ dsyslog("%s: cPluginPlaylist::Start open playlistconfigfile=%s", plugin_name, playlistconfigfile.u);
+#endif
+ } else
+ {
+ f = fopen(p, "r");
+#ifdef PL_Debug2
+ dsyslog("%s: cPluginPlaylist::Start open playlistconfigfile=%s", plugin_name, p);
+#endif
+ }
+ free(p);
+ free(q);
+ if (!f)
+ {
+ esyslog("%s: ERROR: cannot open config file: [%s]%s", plugin_name, ConfigDirectory(""), playlistconfigfile.u);
+ return false;
+ }
+ while (fgets(buffer, sizeof(buffer), f) > 0)
+ {
+ p = skipspace(stripspace(buffer));
+ q = NULL;
+ done = false;
+ while (!done)
+ {
+ if (!q)
+ q = p;
+ switch (*p)
+ {
+ case '\\': strcpy(p, p + 1);
+ if (*p)
+ p++;
+ else
+ {
+ esyslog("%s: ERROR: missing character after \\", plugin_name);
+ return false;
+ }
+ break;
+ case '"':
+ case '\'': if ((p = SkipQuote(p)) == NULL)
+ return false;
+ break;
+ default: if (!*p || isspace(*p))
+ {
+ done = !*p;
+ *p = 0;
+ if (q)
+ {
+ if (fargc < MAXARGS - 1)
+ {
+ if (*q != '#')
+ fargv[fargc++] = strdup(q);
+ } else
+ {
+ esyslog("%s: ERROR: plugin argument list too long", plugin_name);
+ return false;
+ }
+ q = NULL;
+ }
+ }
+ if (!done)
+ p = *p ? p + 1 : skipspace(p + 1);
+ }
+ }
+ }
+ fclose(f);
+ fargv[0] = strdup(plugin_name);
+ fargv[fargc] = NULL;
+ optind = 0; // to reset the getopt() data
+ if (fargc > 1)
+ if (!ProcessArg(fargc, fargv))
+ {
+ esyslog("%s: ERROR: cannot parse config file: [%s]%s", plugin_name, ConfigDirectory(""), playlistconfigfile.u);
+ return false;
+ }
+ while(fargc) free(fargv[--fargc]);
+ } else
+ {
+ free(p);
+ free(q);
+ if (strcmp(playlistconfigfile.u, playlistconfigfile.d))
+ {
+ esyslog("%s: ERROR: config file not found: [%s]%s", plugin_name, ConfigDirectory(""), playlistconfigfile.u);
+ return false;
+ } else if (verbose.u)
+ isyslog("%s: INFO: config file not found: [%s]%s", plugin_name, ConfigDirectory(""), playlistconfigfile.u);
+ }
+
+ // default parameter --> d_
+ // read parameter from commandline --> c_ (data in u_)
+ // value parameter from config-file --> s_
+ // read parameter from config-file --> r_
+ // paramater used --> u_
+
+ #define SetParam(T) { if (!T.c || (!commandline_preference.u && T.r)) T.u = (!T.c && !T.r) ? T.d : T.s; }
+ #define SetParamFile(T) { if (!T.c || (!commandline_preference.u && T.r)) strcpy(T.u, (!T.c && !T.r) ? T.d : T.s); }
+
+ commandline_preference.u = commandline_preference.r ? commandline_preference.s : commandline_preference.d;
+
+ // var pos5
+ SetParamFile (playlistconfigfile);
+ SetParam (charentry);
+ SetParam (charfolder);
+ SetParam (charrecord);
+ SetParamFile (lastplaylist);
+ SetParamFile (mainmenu_name);
+ SetParam (mainmenu_visible);
+ SetParam (confirmdelplentry);
+ SetParam (okstartplay);
+ SetParam (deleterecords);
+ SetParamFile (pathplaylists);
+ SetParam (startoption);
+ SetParam (storeplaylist);
+ SetParam (timeoutreadrecords);
+ SetParam (verbose);
+ for (int i = Option_confirmdeleterecord; i < Option_max; i++)
+ SetParam (PL_options[i]);
+
+ #undef SetParam
+ #undef SetParamFile
+
+ if (verbose.u)
+ isyslog("%s: Start", plugin_name);
+ DisplaySetings();
+ strcpy(lastplaylist.o, lastplaylist.u);
+ return true;
+}
+
+const char *cPluginPlaylist::MainMenuEntry(void)
+{
+ return mainmenu_visible.u ? mainmenu_name.u : NULL;
+}
+
+cOsdObject *cPluginPlaylist::MainMenuAction(void)
+{
+#ifdef PL_Debug1
+ dsyslog("%s: cPluginPlaylist::MainMenuAction", plugin_name);
+#endif
+ TestAndSetOSDLanguage();
+ return new cControlMenu;
+}
+
+cMenuSetupPage *cPluginPlaylist::SetupMenu(void)
+{
+ TestAndSetOSDLanguage();
+ return new cMenuSetupPlayList;
+}
+
+
+bool cPluginPlaylist::SetupParse(const char *Name, const char *Value)
+{
+ #define SetParam(T) { T.r = true; T.s = strtol(Value, NULL, 0); }
+ #define SetParamChar(T) { T.r = true; temp = strtol(Value, NULL, 0); T.s = temp > 255 ? temp - 256 : temp; }
+ #define SetParamFile(T) { T.r = true; strn0cpy(T.s, Value, sizeof(T.s)); }
+
+ // Parse your own setup parameters and store their values.
+ dsyslog("%s: Setupparameter %s=%s", plugin_name, Name, Value);
+ // var pos6
+ int temp;
+
+ if (!strcasecmp(Name, "cahre")) SetParamChar (charentry)
+ else if (!strcasecmp(Name, "charf")) SetParamChar (charfolder)
+ else if (!strcasecmp(Name, "charr")) SetParamChar (charrecord)
+ else if (!strcasecmp(Name, "commandline")) SetParam (commandline_preference)
+ else if (!strcasecmp(Name, "lastpl")) SetParamFile (lastplaylist)
+ else if (!strcasecmp(Name, "name")) SetParamFile (mainmenu_name)
+ else if (!strcasecmp(Name, "visible")) SetParam (mainmenu_visible)
+ else if (!strcasecmp(Name, "deletentry")) SetParam (confirmdelplentry)
+ else if (!strcasecmp(Name, "okplay")) SetParam (okstartplay)
+ else if (!strcasecmp(Name, "delete")) SetParam (deleterecords)
+ else if (!strcasecmp(Name, "path")) SetParamFile (pathplaylists)
+ else if (!strcasecmp(Name, "start")) SetParam (startoption)
+ else if (!strcasecmp(Name, "storepl")) SetParam (storeplaylist)
+ else if (!strcasecmp(Name, "timerecords")) SetParam (timeoutreadrecords)
+ else if (!strcasecmp(Name, "verbose")) SetParam (verbose)
+ else if (!strcasecmp(Name, "confdelete")) SetParam (PL_options[Option_confirmdeleterecord])
+ else if (!strcasecmp(Name, "startnew")) SetParam (PL_options[Option_confirmstartnewrecord])
+ else if (!strcasecmp(Name, "deletel")) SetParam (PL_options[Option_deletefromlist])
+ else if (!strcasecmp(Name, "deleter")) SetParam (PL_options[Option_deleterecord])
+ else if (!strcasecmp(Name, "jumpmark")) SetParam (PL_options[Option_jumpmark])
+ else if (!strcasecmp(Name, "playoption1")) SetParam (PL_options[Option_playoption1])
+ else if (!strcasecmp(Name, "playoption2")) SetParam (PL_options[Option_playoption2])
+ else if (!strcasecmp(Name, "playonlynew")) SetParam (PL_options[Option_playonlynew])
+ else if (!strcasecmp(Name, "searchnew")) SetParam (PL_options[Option_searchnewrecord])
+ else if (!strcasecmp(Name, "searchsub")) SetParam (PL_options[Option_searchrecordsub])
+ else
+ return false;
+ return true;
+
+ #undef SetParam
+ #undef SetParamChar
+ #undef SetParamFile
+}
+
+const char *cPluginPlaylist::ExpandPath(const char *Filename, bool CreateDir)
+{
+ static char path[MaxFileName];
+ char *c = strdup(ConfigDirectory(""));
+ char *p = NULL;
+
+ ExpandEnvironment(&pathplaylists);
+ if (pathplaylists.e[0] == '/')
+ asprintf(&p, "%s%s%s", pathplaylists.e, *(pathplaylists.e + strlen(pathplaylists.e) - 1) == '/' ? "" : "/", Filename);
+ else
+ asprintf(&p, "%s%s%s%s%s", c, *(c + strlen(c) - 1) == '/' ? "" : "/", pathplaylists.e, strlen(pathplaylists.e) ? *(pathplaylists.e + strlen(pathplaylists.e) - 1) == '/' ? "" : "/" : "", Filename);
+ if (strlen(p) >= MaxFileName)
+ esyslog("%s: max length for filename is %d this name is %d [%s]", plugin_name, MaxFileName, strlen(p), p);
+ strn0cpy(path, p, MaxFileName);
+ if (CreateDir)
+ MakeDirs(path, false);
+ free(c);
+ free(p);
+#ifdef PL_Debug1
+ dsyslog("%s: ExpandPath Filename=%s Return=%s", plugin_name, Filename, path);
+#endif
+ return &path[0];
+}
+
+VDRPLUGINCREATOR(cPluginPlaylist); // Don't touch this!
diff --git a/playlist.h b/playlist.h
new file mode 100644
index 0000000..bfb7e46
--- /dev/null
+++ b/playlist.h
@@ -0,0 +1,163 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: playlist.h 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#ifndef __PLAYLIST_H
+#define __PLAYLIST_H
+
+#include <vdr/config.h>
+#include <vdr/recording.h>
+#include <vdr/plugin.h>
+
+#define FREENULL(T) { if (T) { free(T); T = NULL; } }
+#if VDRVERSNUM >= 10307
+#define MAXOSDTEXTWIDTH 45
+#define AKTOSDTEXTWIDTH 45
+#define ERROR(E) Skins.Message(mtError, E)
+#define INFO(I) Skins.Message(mtInfo, I)
+#define STATUS(S) Skins.Message(mtStatus, S)
+#else
+#define MAXOSDTEXTWIDTH MAXOSDWIDTH
+#define AKTOSDTEXTWIDTH Setup.OSDwidth
+#define ERROR(E) Interface->Error(E)
+#define INFO(I) Interface->Info(I)
+#endif
+
+// Global variables that control the overall behaviour:
+
+enum eStartOption {
+ Start_DisplayPL = 0,
+ Start_DisplayLast,
+ Start_PlayLast,
+ Start_NewEmpty,
+ Start_max };
+
+enum eNoYesDefault {
+ NoYesDefault_no = 0,
+ NoYesDefault_yes,
+ NoYesDefault_defaultPlugin,
+ NoYesDefault_defaultPlaylist,
+ NoYesDefault_defaultRecordDir,
+ NoYesDefault_max };
+
+enum ePlayOptions {
+ PlayOptions_firstpos = 0,
+ PlayOptions_firstnew,
+ PlayOptions_lastplay,
+ PlayOptions_selectpos,
+ PlayOptions_question,
+ PlayOptions_defaultPlugin,
+ PlayOptions_max };
+
+enum eOptions {
+ Option_confirmdeleterecord = 0,
+ Option_confirmstartnewrecord,
+ Option_deletefromlist,
+ Option_deleterecord,
+ Option_jumpmark,
+ Option_playoption1,
+ Option_playoption2,
+ Option_playonlynew,
+ Option_searchnewrecord,
+ Option_searchrecordsub,
+ Option_max };
+
+#define MAXOptionLines 20
+
+struct tParamInt {
+ bool c; // read command line
+ bool r; // read config file
+ bool h; // hide in setup menu
+ int d; // default
+ int u; // used
+ int s; // config file
+ int o; // old value for setup menu
+ };
+
+struct tParamChar {
+ bool c; // read command line
+ bool r; // read config file
+ bool h; // hide in setup menu
+ char d; // default
+ char u; // used
+ char s; // config file
+ char o; // old value for setup menu
+ };
+
+struct tParamFile {
+ bool c; // read command line
+ bool r; // read config file
+ bool h; // hide in setup menu
+ char d[MaxFileName]; // default
+ char u[MaxFileName]; // used
+ char s[MaxFileName]; // config file
+ char o[MaxFileName]; // old value for setup menu
+ char e[MaxFileName]; // expanded name (environment)
+ };
+
+// var pos1
+
+extern tParamChar charentry;
+extern tParamChar charfolder;
+extern tParamChar charrecord;
+extern tParamInt commandline_preference;
+extern tParamFile lastplaylist;
+extern tParamFile mainmenu_name;
+extern tParamInt mainmenu_visible;
+extern tParamInt confirmdelplentry;
+extern tParamInt okstartplay;
+extern tParamInt deleterecords;
+extern tParamFile pathplaylists;
+extern tParamInt startoption;
+extern tParamInt storeplaylist;
+extern tParamInt timeoutreadrecords;
+extern tParamInt verbose;
+extern tParamInt PL_options[];
+
+extern char plugin_name[];
+extern char DisplayStatus[];
+extern const char *NoYesDefault[];
+extern const char *StartOptions[];
+extern const char *PlayOptions[];
+extern char *FileNameCharsAllowed;
+extern char *AllCharsAllowed;
+extern char *LastSelectedRecord;
+extern bool ControlMenuIsOpen;
+#if VDRVERSNUM < 10311
+extern cRecordings Recordings;
+extern time_t LoadTime_Recordings;
+#endif
+
+void ExpandEnvironment(tParamFile *FileStruc);
+
+// --- cPluginPlaylist ----------------------------------------------------------
+
+class cPluginPlaylist : public cPlugin {
+private:
+ // Add any member variables or functions you may need here.
+ int OSDLanguage;
+ void TestAndSetOSDLanguage(void);
+ bool ProcessArg(int argc, char *argv[]);
+
+public:
+ cPluginPlaylist(void);
+ virtual ~cPluginPlaylist();
+ virtual const char *Version(void);
+ virtual const char *Description(void);
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual bool Start(void);
+ virtual const char *MainMenuEntry(void);
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ const char *ExpandPath(const char *Filename, bool CreateDir = true);
+ };
+
+extern cPluginPlaylist *PluginPlaylist;
+
+#endif //__PLAYLIST_H
diff --git a/vdrtools.c b/vdrtools.c
new file mode 100644
index 0000000..c9a78f0
--- /dev/null
+++ b/vdrtools.c
@@ -0,0 +1,217 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: vdrtools.c 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#include "vdrtools.h"
+#include "playlist.h"
+#include "dataplaylist.h"
+#include "i18n.h"
+#include <vdr/menu.h>
+#include <vdr/interface.h>
+
+char *SkipQuote(char *s)
+{
+ char c = *s;
+ strcpy(s, s + 1);
+ while (*s && *s != c)
+ {
+ if (*s == '\\')
+ strcpy(s, s + 1);
+ if (*s)
+ s++;
+ }
+ if (*s)
+ {
+ strcpy(s, s + 1);
+ return s;
+ }
+ esyslog("ERROR: missing closing %c", c);
+ return NULL;
+}
+
+char *ExchangeChars(char *s, bool ToFileSystem)
+{
+// ToFileSystem is not use, only for comatibility with 'ExchangeChars' from 'recording.c'
+ char *p = s;
+ while (*p)
+ {
+ switch (*p)
+ {
+ // mapped characters:
+ case '_': *p = ' ';
+ break;
+ case '/': *p = '~';
+ break;
+ // encodes characters:
+ case '#': if (strlen(p) > 2)
+ {
+ char buf[3];
+ sprintf(buf, "%c%c", *(p + 1), *(p + 2));
+ unsigned char c = strtol(buf, NULL, 16);
+ *p = c;
+ memmove(p + 1, p + 3, strlen(p) - 2);
+ }
+ break;
+ // backwards compatibility:
+ case '\x01': *p = '\'';
+ break;
+ case '\x02': *p = '/';
+ break;
+ case '\x03': *p = ':';
+ break;
+ }
+ p++;
+ }
+ return s;
+}
+
+bool DeleteRecording(const char *Filename, bool Confirm)
+{
+ if (!Confirm || Interface->Confirm(tr("Delete recording?")))
+ {
+ cRecordControl *rc = cRecordControls::GetRecordControl(Filename);
+ if (rc)
+ {
+ if (!Confirm || Interface->Confirm(tr("Timer still recording - really delete?")))
+ {
+ cTimer *timer = rc->Timer();
+ if (timer)
+ {
+ timer->Skip();
+ cRecordControls::Process(time(NULL));
+ if (timer->IsSingleEvent())
+ {
+ isyslog("timer %d deleted", timer->Index() + 1);
+ Timers.Del(timer);
+ }
+ Timers.Save();
+ }
+ } else
+ return false;
+ }
+ cRecording *recording = Recordings.GetByName(Filename);
+ if (recording)
+ {
+ if (recording->Delete())
+ {
+ cReplayControl::ClearLastReplayed(Filename);
+ if (LastSelectedRecord && !strcmp(LastSelectedRecord, Filename))
+ FREENULL(LastSelectedRecord);
+ Recordings.Del(recording);
+ for (cPlaylist *pl = PlaylistCol.First(); pl; pl = PlaylistCol.Next(pl))
+ for (cPlaylistRecord *plr = pl->First_PLR(); plr; plr = pl->Next_PLR(plr))
+ if (strcasecmp(plr->Filename(), Filename) == 0)
+ plr->SetDel();
+ return true;
+ }
+ }
+ ERROR(tr("Error while accessing recording!"));
+ }
+ return false;
+}
+
+
+#ifdef PL_Debug1
+const char *KeyName(eKeys Key)
+{
+ switch (RAWKEY(Key))
+ {
+ case kUp: return tr("Up"); break;
+ case kDown: return tr("Down"); break;
+ case kMenu: return tr("Menu"); break;
+ case kOk: return tr("Ok"); break;
+ case kBack: return tr("Back"); break;
+ case kLeft: return tr("Left"); break;
+ case kRight: return tr("Right"); break;
+ case kRed: return tr("Red"); break;
+ case kGreen: return tr("Green"); break;
+ case kYellow: return tr("Yellow"); break;
+ case kBlue: return tr("Blue"); break;
+ case k0: return "0"; break;
+ case k1: return "1"; break;
+ case k2: return "2"; break;
+ case k3: return "3"; break;
+ case k4: return "4"; break;
+ case k5: return "5"; break;
+ case k6: return "6"; break;
+ case k7: return "7"; break;
+ case k8: return "8"; break;
+ case k9: return "9"; break;
+ case kPlay: return tr("Play"); break;
+ case kPause: return tr("Pause"); break;
+ case kStop: return tr("Stop"); break;
+ case kRecord: return tr("Record"); break;
+ case kFastFwd: return tr("FastFwd"); break;
+ case kFastRew: return tr("FastRew"); break;
+ case kPower: return tr("Power"); break;
+ case kChanUp: return tr("ChanUp"); break;
+ case kChanDn: return tr("ChanDn"); break;
+ case kVolUp: return tr("VolUp"); break;
+ case kVolDn: return tr("VolDn"); break;
+ case kMute: return tr("Mute"); break;
+ case kSchedule: return tr("Schedule"); break;
+ case kChannels: return tr("Channels"); break;
+ case kTimers: return tr("Timers"); break;
+ case kRecordings: return tr("Recordings"); break;
+ case kSetup: return tr("Setup"); break;
+ case kCommands: return tr("Commands"); break;
+ case kUser1: return tr("User1"); break;
+ case kUser2: return tr("User2"); break;
+ case kUser3: return tr("User3"); break;
+ case kUser4: return tr("User4"); break;
+ case kUser5: return tr("User5"); break;
+ case kUser6: return tr("User6"); break;
+ case kUser7: return tr("User7"); break;
+ case kUser8: return tr("User8"); break;
+ case kUser9: return tr("User9"); break;
+ case kNone: return tr("none"); break;
+ case kKbd: return tr("Kbd"); break;
+ default: return tr("unknow"); break;
+ }
+}
+
+const char *OSStateName(eOSState OSState)
+{
+ switch (OSState)
+ {
+ case osUnknown: return "osUnknown";
+ case osContinue: return "osContinue";
+ case osSchedule: return "osSchedule";
+ case osChannels: return "osChannels";
+ case osTimers: return "osTimers";
+ case osRecordings: return "osRecordings";
+ case osPlugin: return "osPlugin";
+ case osSetup: return "osSetup";
+ case osCommands: return "osCommands";
+ case osPause: return "osPause";
+ case osRecord: return "osRecord";
+ case osReplay: return "osReplay";
+ case osStopRecord: return "osStopRecord";
+ case osStopReplay: return "osStopReplay";
+ case osCancelEdit: return "osCancelEdit";
+ case osSwitchDvb: return "osSwitchDvb";
+ case osBack: return "osBack";
+ case osEnd: return "osEnd";
+ case os_User: return "os_User";
+ case osUser1: return "osUser1";
+ case osUser2: return "osUser2";
+ case osUser3: return "osUser3";
+ case osUser4: return "osUser4";
+ case osUser5: return "osUser5";
+ case osUser6: return "osUser6";
+ case osUser7: return "osUser7";
+ case osUser8: return "osUser8";
+ case osUser9: return "osUser9";
+ case osUser10: return "osUser10";
+#if VDRVERSNUM < 10307
+ case osUser11: return "osUser11";
+#endif
+ default: return "unknow";
+ }
+ return "";
+}
+#endif
diff --git a/vdrtools.h b/vdrtools.h
new file mode 100644
index 0000000..c17ef7a
--- /dev/null
+++ b/vdrtools.h
@@ -0,0 +1,26 @@
+/*
+ * playlist: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: vdrtools.h 0.2 2004/10/08 02:34:00 hflor Exp $
+ */
+
+#ifndef __VDRTOOLS_H
+#define __VDRTOOLS_H
+
+#include <vdr/keys.h>
+#include <vdr/osd.h>
+#include <vdr/osdbase.h>
+
+char *SkipQuote(char *s);
+char *ExchangeChars(char *s, bool ToFileSystem);
+bool DeleteRecording(const char *Filename, bool Confirm = true);
+
+#ifdef PL_Debug1
+const char *KeyName(eKeys Key);
+const char *OSStateName(eOSState OSState);
+#endif
+
+
+#endif //__VDRTOOLS_H