mirror of
https://projects.vdr-developer.org/git/vdr-plugin-scraper2vdr.git
synced 2023-10-19 17:58:31 +02:00
initial commit
This commit is contained in:
commit
801610d259
340
COPYING
Normal file
340
COPYING
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General
|
||||||
|
Public License instead of this License.
|
6
HISTORY
Normal file
6
HISTORY
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
VDR Plugin 'scraper2vdr' Revision History
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
2014-03-02: Version 0.0.1
|
||||||
|
|
||||||
|
- Initial revision.
|
132
Makefile
Normal file
132
Makefile
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#
|
||||||
|
# Makefile for a Video Disk Recorder plugin
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
# External image lib to use: imagemagick, graphicsmagick
|
||||||
|
IMAGELIB = imagemagick
|
||||||
|
|
||||||
|
PLUGIN = scraper2vdr
|
||||||
|
|
||||||
|
### The version number of this plugin (taken from the main source file):
|
||||||
|
|
||||||
|
VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).h | awk '{ print $$6 }' | sed -e 's/[";]//g')
|
||||||
|
|
||||||
|
### The directory environment:
|
||||||
|
|
||||||
|
# Use package data if installed...otherwise assume we're under the VDR source directory:
|
||||||
|
PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
|
||||||
|
LIBDIR = $(call PKGCFG,libdir)
|
||||||
|
LOCDIR = $(call PKGCFG,locdir)
|
||||||
|
PLGCFG = $(call PKGCFG,plgcfg)
|
||||||
|
#
|
||||||
|
TMPDIR ?= /tmp
|
||||||
|
|
||||||
|
### The compiler options:
|
||||||
|
|
||||||
|
export CFLAGS = $(call PKGCFG,cflags)
|
||||||
|
export CXXFLAGS = $(call PKGCFG,cxxflags)
|
||||||
|
|
||||||
|
### The version number of VDR's plugin API:
|
||||||
|
|
||||||
|
APIVERSION = $(call PKGCFG,apiversion)
|
||||||
|
|
||||||
|
### Allow user defined options to overwrite defaults:
|
||||||
|
|
||||||
|
-include $(PLGCFG)
|
||||||
|
|
||||||
|
LIBS = -lmysqlclient_r -luuid
|
||||||
|
|
||||||
|
### The name of the distribution archive:
|
||||||
|
|
||||||
|
ARCHIVE = $(PLUGIN)-$(VERSION)
|
||||||
|
PACKAGE = vdr-$(ARCHIVE)
|
||||||
|
|
||||||
|
### The name of the shared object file:
|
||||||
|
|
||||||
|
SOFILE = libvdr-$(PLUGIN).so
|
||||||
|
|
||||||
|
### Includes and Defines (add further entries here):
|
||||||
|
|
||||||
|
INCLUDES +=
|
||||||
|
|
||||||
|
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
|
||||||
|
DEFINES += -DVDR_PLUGIN -DUSEUUID
|
||||||
|
|
||||||
|
ifeq ($(IMAGELIB), imagemagick)
|
||||||
|
INCLUDES += $(shell pkg-config --cflags Magick++)
|
||||||
|
LIBS += $(shell pkg-config --libs Magick++)
|
||||||
|
else ifeq ($(IMAGELIB), graphicsmagick)
|
||||||
|
INCLUDES += $(shell pkg-config --cflags GraphicsMagick++)
|
||||||
|
LIBS += $(shell pkg-config --libs GraphicsMagick++)
|
||||||
|
endif
|
||||||
|
|
||||||
|
### The object files (add further files here):
|
||||||
|
|
||||||
|
OBJS = $(PLUGIN).o config.o setup.o update.o scrapmanager.o tvdbseries.o moviedbmovie.o tools.o lib/db.o lib/tabledef.o lib/common.o lib/config.o
|
||||||
|
|
||||||
|
### The main target:
|
||||||
|
|
||||||
|
all: $(SOFILE) i18n
|
||||||
|
|
||||||
|
### Implicit rules:
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
|
||||||
|
|
||||||
|
### Dependencies:
|
||||||
|
|
||||||
|
MAKEDEP = $(CXX) -MM -MG
|
||||||
|
DEPFILE = .dependencies
|
||||||
|
$(DEPFILE): Makefile
|
||||||
|
@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
|
||||||
|
|
||||||
|
-include $(DEPFILE)
|
||||||
|
|
||||||
|
### Internationalization (I18N):
|
||||||
|
|
||||||
|
PODIR = po
|
||||||
|
I18Npo = $(wildcard $(PODIR)/*.po)
|
||||||
|
I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
|
||||||
|
I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
|
||||||
|
I18Npot = $(PODIR)/$(PLUGIN).pot
|
||||||
|
|
||||||
|
%.mo: %.po
|
||||||
|
msgfmt -c -o $@ $<
|
||||||
|
|
||||||
|
$(I18Npot): $(wildcard *.c)
|
||||||
|
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
|
||||||
|
|
||||||
|
%.po: $(I18Npot)
|
||||||
|
msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
|
||||||
|
@touch $@
|
||||||
|
|
||||||
|
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
|
||||||
|
install -D -m644 $< $@
|
||||||
|
|
||||||
|
.PHONY: i18n
|
||||||
|
i18n: $(I18Nmo) $(I18Npot)
|
||||||
|
|
||||||
|
install-i18n: $(I18Nmsgs)
|
||||||
|
|
||||||
|
### Targets:
|
||||||
|
|
||||||
|
$(SOFILE): $(OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
install-lib: $(SOFILE)
|
||||||
|
install -D -m644 $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
|
||||||
|
|
||||||
|
install: install-lib install-i18n
|
||||||
|
|
||||||
|
dist: $(I18Npo) 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 $(PODIR)/*.mo $(PODIR)/*.pot
|
||||||
|
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
|
79
README
Normal file
79
README
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
This is a "plugin" for the Video Disk Recorder (VDR).
|
||||||
|
|
||||||
|
Written by: Louis Braun <louis.braun@gmx.de>
|
||||||
|
|
||||||
|
Project's homepage: http://projects.vdr-developer.org/projects/plg-scraper2vdr
|
||||||
|
|
||||||
|
Latest version available at: http://projects.vdr-developer.org/git/vdr-plugin-scraper2vdr.git/
|
||||||
|
|
||||||
|
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.
|
||||||
|
See the file COPYING for more information.
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
scraper2vdr acts as client and provides scraped metadata for tvshows and
|
||||||
|
movies from epgd to other plugins via its service interface. The plugin
|
||||||
|
cares about caching the images locally and also cleans up the images if
|
||||||
|
not longer needed.
|
||||||
|
|
||||||
|
epgd itself uses the thetvdb.com API for collecting series metadata and
|
||||||
|
themoviedb.org API for movies. Check the websites of both services for
|
||||||
|
the terms of use.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
To run the plugin the following libaries have to be installed:
|
||||||
|
|
||||||
|
- VDR 1.7.x
|
||||||
|
- libmysql >= 5.07
|
||||||
|
- uuid-dev
|
||||||
|
- imagemagick or graphicksmagick
|
||||||
|
|
||||||
|
Installation and configuration
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Just install the plugin depending on your used distribution. During VDR
|
||||||
|
startup the following options can be set:
|
||||||
|
|
||||||
|
-i <IMAGEDIR>, --imagedir=<IMAGEDIR> Set directory where images are stored
|
||||||
|
-m <MODE>, --mode=<MODE> mode can be client or headless.
|
||||||
|
|
||||||
|
Each running scraper2vdr Plugin reports his recordings to the epgd
|
||||||
|
database, the epgd then checks these entries and tries to find
|
||||||
|
appropriate scraping information. epgd performs first a lookup for a
|
||||||
|
event in the database which belongs to the recording. If this fails, epgd
|
||||||
|
checks if another client has already reported this recording to the database.
|
||||||
|
After that, the scrapinfo file in the recording directory (if existing)
|
||||||
|
is checked. If nothing is successfull, a new scrap process for the name
|
||||||
|
of the recording is done. If in this case the length of the recording
|
||||||
|
is less than 70 minutes, a series recording is assumed, otherwise
|
||||||
|
the scraper searches for a movie.
|
||||||
|
|
||||||
|
In client mode both live epg and recordings metadata is loaded from the
|
||||||
|
database. In headless mode only recording metadata is loaded. This mode
|
||||||
|
is useful for headless VDRs so that recordings which are done from this
|
||||||
|
VDR during no other VDR client with running scraper2vdr Plugin is active
|
||||||
|
are not missed. The recording information is then written to the database
|
||||||
|
in time before the related and already reliably scraped event entry is
|
||||||
|
deleted from the database.
|
||||||
|
|
||||||
|
Service Interface
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Other Plugins can and should request information about meta data from
|
||||||
|
scraper2vdr via a call to the provided service interface.
|
||||||
|
|
||||||
|
First the service "GetEventType" which expects a pointer to a cEvent or
|
||||||
|
a cRecording object as input variable has to be called. This call provides
|
||||||
|
the type of the event or recording (tSeries, tMovie, tNone) and the seriesId,
|
||||||
|
episodeId and movieId. If type is tSeries, movieId is 0 and vice versa.
|
||||||
|
With that then a second call to GetSeries or GetMovie with the appropriate IDs
|
||||||
|
provides all stored information for the series or movie in form of a cSeries
|
||||||
|
or cMovie object.
|
||||||
|
|
||||||
|
For further information just check the self explanatory services.h file.
|
56
config.c
Normal file
56
config.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "lib/common.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
cScraper2VdrConfig::cScraper2VdrConfig() {
|
||||||
|
mainMenuEntry = 1;
|
||||||
|
headless = false;
|
||||||
|
uuid = "";
|
||||||
|
imgDirSet = false;
|
||||||
|
mysqlHost = "localhost";
|
||||||
|
mysqlPort = 3306;
|
||||||
|
mysqlDBName = "epg2vdr";
|
||||||
|
mysqlDBUser = "epg2vdr";
|
||||||
|
mysqlDBPass = "epg";
|
||||||
|
recScrapInfoName = "scrapinfo";
|
||||||
|
}
|
||||||
|
|
||||||
|
cScraper2VdrConfig::~cScraper2VdrConfig() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScraper2VdrConfig::SetUuid(cPlugin *plug) {
|
||||||
|
if (uuid.size() == 0) {
|
||||||
|
uuid = getUniqueId();
|
||||||
|
plug->SetupStore("uuid", uuid.c_str());
|
||||||
|
}
|
||||||
|
tell(0, "epgd uuid: %s", uuid.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScraper2VdrConfig::SetImageDir(cString dir) {
|
||||||
|
imageDir = *dir;
|
||||||
|
imgDirSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScraper2VdrConfig::SetDefaultImageDir(void) {
|
||||||
|
if (!imgDirSet) {
|
||||||
|
imageDir = cPlugin::CacheDirectory(PLUGIN_NAME_I18N);
|
||||||
|
}
|
||||||
|
tell (0, "using image directory %s", imageDir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScraper2VdrConfig::SetMode(string mode) {
|
||||||
|
if (!mode.compare("headless"))
|
||||||
|
headless = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScraper2VdrConfig::SetupParse(const char *Name, const char *Value) {
|
||||||
|
if (strcmp(Name, "uuid") == 0) uuid = Value;
|
||||||
|
else if (strcmp(Name, "mainMenuEntry") == 0) mainMenuEntry = atoi(Value);
|
||||||
|
else if (strcmp(Name, "mysqlHost") == 0) mysqlHost = Value;
|
||||||
|
else if (strcmp(Name, "mysqlPort") == 0) mysqlPort = atoi(Value);
|
||||||
|
else if (strcmp(Name, "mysqlDBName") == 0) mysqlDBName = Value;
|
||||||
|
else if (strcmp(Name, "mysqlDBUser") == 0) mysqlDBUser = Value;
|
||||||
|
else if (strcmp(Name, "mysqlDBPass") == 0) mysqlDBPass = Value;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
31
config.h
Normal file
31
config.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef __SCRAPER2VDR_CONFIG_H
|
||||||
|
#define __SCRAPER2VDR_CONFIG_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vdr/plugin.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class cScraper2VdrConfig {
|
||||||
|
private:
|
||||||
|
public:
|
||||||
|
cScraper2VdrConfig();
|
||||||
|
~cScraper2VdrConfig();
|
||||||
|
bool SetupParse(const char *Name, const char *Value);
|
||||||
|
void SetUuid(cPlugin *plug);
|
||||||
|
void SetImageDir(cString dir);
|
||||||
|
void SetDefaultImageDir(void);
|
||||||
|
void SetMode(string mode);
|
||||||
|
int mainMenuEntry;
|
||||||
|
bool headless;
|
||||||
|
string uuid;
|
||||||
|
bool imgDirSet;
|
||||||
|
string imageDir;
|
||||||
|
string mysqlHost;
|
||||||
|
int mysqlPort;
|
||||||
|
string mysqlDBName;
|
||||||
|
string mysqlDBUser;
|
||||||
|
string mysqlDBPass;
|
||||||
|
string recScrapInfoName;
|
||||||
|
};
|
||||||
|
#endif //__SCRAPER2VDR_CONFIG_H
|
7
lib/Makefile
Normal file
7
lib/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
all:
|
||||||
|
g++ -ggdb -DPLGDIR='"."' test.c common.c config.c db.c tabledef.c -lrt -lz -lmysqlclient -o t
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.a *~ core
|
812
lib/common.c
Normal file
812
lib/common.c
Normal file
@ -0,0 +1,812 @@
|
|||||||
|
/*
|
||||||
|
* common.c:
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#ifdef USEUUID
|
||||||
|
# include <uuid/uuid.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#ifdef USELIBARCHIVE
|
||||||
|
# include <archive.h>
|
||||||
|
# include <archive_entry.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
# include <vdr/thread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
cMutex logMutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Debug
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
void tell(int eloquence, const char* format, ...)
|
||||||
|
{
|
||||||
|
if (EPG2VDRConfig.loglevel < eloquence)
|
||||||
|
return ;
|
||||||
|
|
||||||
|
const int sizeBuffer = 100000;
|
||||||
|
char t[sizeBuffer+100]; *t = 0;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
cMutexLock lock(&logMutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
snprintf(t, sizeBuffer, "scraper2vdr: ");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vsnprintf(t+strlen(t), sizeBuffer-strlen(t), format, ap);
|
||||||
|
|
||||||
|
if (EPG2VDRConfig.logstdout)
|
||||||
|
{
|
||||||
|
char buf[50+TB];
|
||||||
|
time_t now;
|
||||||
|
time(&now);
|
||||||
|
strftime(buf, 50, "%y.%m.%d %H:%M:%S", localtime(&now));
|
||||||
|
printf("%s %s\n", buf, t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
syslog(LOG_ERR, "%s", t);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Host ID
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
unsigned int getHostId()
|
||||||
|
{
|
||||||
|
static unsigned int id = gethostid() & 0xFFFFFFFF;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// String Operations
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
void toUpper(std::string& str)
|
||||||
|
{
|
||||||
|
const char* s = str.c_str();
|
||||||
|
int lenSrc = str.length();
|
||||||
|
|
||||||
|
char* dest = (char*)malloc(lenSrc+TB); *dest = 0;
|
||||||
|
char* d = dest;
|
||||||
|
|
||||||
|
int csSrc; // size of character
|
||||||
|
|
||||||
|
for (int ps = 0; ps < lenSrc; ps += csSrc)
|
||||||
|
{
|
||||||
|
csSrc = max(mblen(&s[ps], lenSrc-ps), 1);
|
||||||
|
|
||||||
|
if (csSrc == 1)
|
||||||
|
*d++ = toupper(s[ps]);
|
||||||
|
else if (csSrc == 2 && s[ps] == (char)0xc3 && s[ps+1] >= (char)0xa0)
|
||||||
|
{
|
||||||
|
*d++ = s[ps];
|
||||||
|
*d++ = s[ps+1] - 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < csSrc; i++)
|
||||||
|
*d++ = s[ps+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*d = 0;
|
||||||
|
|
||||||
|
str = dest;
|
||||||
|
free(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeChars(std::string& str, const char* ignore)
|
||||||
|
{
|
||||||
|
const char* s = str.c_str();
|
||||||
|
int lenSrc = str.length();
|
||||||
|
int lenIgn = strlen(ignore);
|
||||||
|
|
||||||
|
char* dest = (char*)malloc(lenSrc+TB); *dest = 0;
|
||||||
|
char* d = dest;
|
||||||
|
|
||||||
|
int csSrc; // size of character
|
||||||
|
int csIgn; //
|
||||||
|
|
||||||
|
for (int ps = 0; ps < lenSrc; ps += csSrc)
|
||||||
|
{
|
||||||
|
int skip = no;
|
||||||
|
|
||||||
|
csSrc = max(mblen(&s[ps], lenSrc-ps), 1);
|
||||||
|
|
||||||
|
for (int pi = 0; pi < lenIgn; pi += csIgn)
|
||||||
|
{
|
||||||
|
csIgn = max(mblen(&ignore[pi], lenIgn-pi), 1);
|
||||||
|
|
||||||
|
if (csSrc == csIgn && strncmp(&s[ps], &ignore[pi], csSrc) == 0)
|
||||||
|
{
|
||||||
|
skip = yes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < csSrc; i++)
|
||||||
|
*d++ = s[ps+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*d = 0;
|
||||||
|
|
||||||
|
str = dest;
|
||||||
|
free(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeCharsExcept(std::string& str, const char* except)
|
||||||
|
{
|
||||||
|
const char* s = str.c_str();
|
||||||
|
int lenSrc = str.length();
|
||||||
|
int lenIgn = strlen(except);
|
||||||
|
|
||||||
|
char* dest = (char*)malloc(lenSrc+TB); *dest = 0;
|
||||||
|
char* d = dest;
|
||||||
|
|
||||||
|
int csSrc; // size of character
|
||||||
|
int csIgn; //
|
||||||
|
|
||||||
|
for (int ps = 0; ps < lenSrc; ps += csSrc)
|
||||||
|
{
|
||||||
|
int skip = yes;
|
||||||
|
|
||||||
|
csSrc = max(mblen(&s[ps], lenSrc-ps), 1);
|
||||||
|
|
||||||
|
for (int pi = 0; pi < lenIgn; pi += csIgn)
|
||||||
|
{
|
||||||
|
csIgn = max(mblen(&except[pi], lenIgn-pi), 1);
|
||||||
|
|
||||||
|
if (csSrc == csIgn && strncmp(&s[ps], &except[pi], csSrc) == 0)
|
||||||
|
{
|
||||||
|
skip = no;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < csSrc; i++)
|
||||||
|
*d++ = s[ps+i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*d = 0;
|
||||||
|
|
||||||
|
str = dest;
|
||||||
|
free(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeWord(std::string& pattern, std::string word)
|
||||||
|
{
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
if ((pos = pattern.find(word)) != std::string::npos)
|
||||||
|
pattern.swap(pattern.erase(pos, word.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// String Manipulation
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
void prepareCompressed(std::string& pattern)
|
||||||
|
{
|
||||||
|
// const char* ignore = " (),.;:-_+*!#?=&%$<>§/'`´@~\"[]{}";
|
||||||
|
const char* notignore = "ABCDEFGHIJKLMNOPQRSTUVWXYZßÖÄÜöäü0123456789";
|
||||||
|
|
||||||
|
toUpper(pattern);
|
||||||
|
removeWord(pattern, " TEIL ");
|
||||||
|
removeWord(pattern, " FOLGE ");
|
||||||
|
removeCharsExcept(pattern, notignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Left Trim
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
char* lTrim(char* buf)
|
||||||
|
{
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
char *tp = buf;
|
||||||
|
|
||||||
|
while (*tp && strchr("\n\r\t ",*tp))
|
||||||
|
tp++;
|
||||||
|
|
||||||
|
memmove(buf, tp, strlen(tp) +1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
// Right Trim
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
char* rTrim(char* buf)
|
||||||
|
{
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
char *tp = buf + strlen(buf);
|
||||||
|
|
||||||
|
while (tp >= buf && strchr("\n\r\t ",*tp))
|
||||||
|
tp--;
|
||||||
|
|
||||||
|
*(tp+1) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
// All Trim
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
char* allTrim(char* buf)
|
||||||
|
{
|
||||||
|
return lTrim(rTrim(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Number to String
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
std::string num2Str(int num)
|
||||||
|
{
|
||||||
|
char txt[16];
|
||||||
|
|
||||||
|
snprintf(txt, sizeof(txt), "%d", num);
|
||||||
|
|
||||||
|
return std::string(txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Long to Pretty Time
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
std::string l2pTime(time_t t)
|
||||||
|
{
|
||||||
|
char txt[30];
|
||||||
|
tm* tmp = localtime(&t);
|
||||||
|
|
||||||
|
strftime(txt, sizeof(txt), "%d.%m.%Y %T", tmp);
|
||||||
|
|
||||||
|
return std::string(txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// MS to Duration
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
std::string ms2Dur(uint64_t t)
|
||||||
|
{
|
||||||
|
char txt[30];
|
||||||
|
|
||||||
|
int s = t / 1000;
|
||||||
|
int ms = t % 1000;
|
||||||
|
|
||||||
|
snprintf(txt, sizeof(txt), "%d.%03d seconds", s, ms);
|
||||||
|
|
||||||
|
return std::string(txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Char to Char-String
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
const char* c2s(char c, char* buf)
|
||||||
|
{
|
||||||
|
sprintf(buf, "%c", c);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// TOOLS
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
int isEmpty(const char* str)
|
||||||
|
{
|
||||||
|
return !str || !*str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sstrcpy(char* dest, const char* src, int max)
|
||||||
|
{
|
||||||
|
if (!dest || !src)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strncpy(dest, src, max);
|
||||||
|
dest[max-1] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
int isLink(const char* path)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (lstat(path, &sb) == 0)
|
||||||
|
return S_ISLNK(sb.st_mode);
|
||||||
|
|
||||||
|
tell(0, "Error: Detecting state for '%s' failed, error was '%m'", path);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fileSize(const char* path)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (lstat(path, &sb) == 0)
|
||||||
|
return sb.st_size;
|
||||||
|
|
||||||
|
tell(0, "Error: Detecting state for '%s' failed, error was '%m'", path);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fileExists(const char* path)
|
||||||
|
{
|
||||||
|
return access(path, F_OK) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int createLink(const char* link, const char* dest, int force)
|
||||||
|
{
|
||||||
|
if (!fileExists(link) || force)
|
||||||
|
{
|
||||||
|
// may be the link exists and point to a wrong or already deleted destination ...
|
||||||
|
// .. therefore we delete the link at first
|
||||||
|
|
||||||
|
unlink(link);
|
||||||
|
|
||||||
|
if (symlink(dest, link) != 0)
|
||||||
|
{
|
||||||
|
tell(0, "Failed to create symlink '%s', error was '%m'", link);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Remove File
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
int removeFile(const char* filename)
|
||||||
|
{
|
||||||
|
int lnk = isLink(filename);
|
||||||
|
|
||||||
|
if (unlink(filename) != 0)
|
||||||
|
{
|
||||||
|
tell(0, "Can't remove file '%s', '%m'", filename);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tell(3, "Removed %s '%s'", lnk ? "link" : "file", filename);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Check Dir
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
int chkDir(const char* path)
|
||||||
|
{
|
||||||
|
struct stat fs;
|
||||||
|
|
||||||
|
if (stat(path, &fs) != 0 || !S_ISDIR(fs.st_mode))
|
||||||
|
{
|
||||||
|
tell(0, "Creating directory '%s'", path);
|
||||||
|
|
||||||
|
if (mkdir(path, ACCESSPERMS) == -1)
|
||||||
|
{
|
||||||
|
tell(0, "Can't create directory '%m'");
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USELIBXML
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Load XSLT
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
xsltStylesheetPtr loadXSLT(const char* name, const char* path, int utf8)
|
||||||
|
{
|
||||||
|
xsltStylesheetPtr stylesheet;
|
||||||
|
char* xsltfile;
|
||||||
|
|
||||||
|
asprintf(&xsltfile, "%s/%s-%s.xsl", path, name, utf8 ? "utf-8" : "iso-8859-1");
|
||||||
|
|
||||||
|
if ((stylesheet = xsltParseStylesheetFile((const xmlChar*)xsltfile)) == 0)
|
||||||
|
tell(0, "Error: Can't load xsltfile %s", xsltfile);
|
||||||
|
else
|
||||||
|
tell(0, "Info: Stylesheet '%s' loaded", xsltfile);
|
||||||
|
|
||||||
|
free(xsltfile);
|
||||||
|
return stylesheet;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Gnu Unzip
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
int gunzip(MemoryStruct* zippedData, MemoryStruct* unzippedData)
|
||||||
|
{
|
||||||
|
const int growthStep = 1024;
|
||||||
|
|
||||||
|
z_stream stream = {0,0,0,0,0,0,0,0,0,0,0,Z_NULL,Z_NULL,Z_NULL};
|
||||||
|
unsigned int resultSize = 0;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
unzippedData->clear();
|
||||||
|
|
||||||
|
// determining the size in this way is taken from the sources of the gzip utility.
|
||||||
|
|
||||||
|
memcpy(&unzippedData->size, zippedData->memory + zippedData->size -4, 4);
|
||||||
|
unzippedData->memory = (char*)malloc(unzippedData->size);
|
||||||
|
|
||||||
|
// zlib initialisation
|
||||||
|
|
||||||
|
stream.avail_in = zippedData->size;
|
||||||
|
stream.next_in = (Bytef*)zippedData->memory;
|
||||||
|
stream.avail_out = unzippedData->size;
|
||||||
|
stream.next_out = (Bytef*)unzippedData->memory;
|
||||||
|
|
||||||
|
// The '+ 32' tells zlib to process zlib&gzlib headers
|
||||||
|
|
||||||
|
res = inflateInit2(&stream, MAX_WBITS + 32);
|
||||||
|
|
||||||
|
if (res != Z_OK)
|
||||||
|
{
|
||||||
|
tellZipError(res, " during zlib initialisation", stream.msg);
|
||||||
|
inflateEnd(&stream);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip the header
|
||||||
|
|
||||||
|
res = inflate(&stream, Z_BLOCK);
|
||||||
|
|
||||||
|
if (res != Z_OK)
|
||||||
|
{
|
||||||
|
tellZipError(res, " while skipping the header", stream.msg);
|
||||||
|
inflateEnd(&stream);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (res == Z_OK)
|
||||||
|
{
|
||||||
|
if (stream.avail_out == 0)
|
||||||
|
{
|
||||||
|
unzippedData->size += growthStep;
|
||||||
|
unzippedData->memory = (char*)realloc(unzippedData->memory, unzippedData->size);
|
||||||
|
|
||||||
|
// Set the stream pointers to the potentially changed buffer!
|
||||||
|
|
||||||
|
stream.avail_out = resultSize - stream.total_out;
|
||||||
|
stream.next_out = (Bytef*)(unzippedData + stream.total_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = inflate(&stream, Z_SYNC_FLUSH);
|
||||||
|
resultSize = stream.total_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != Z_STREAM_END)
|
||||||
|
{
|
||||||
|
tellZipError(res, " during inflating", stream.msg);
|
||||||
|
inflateEnd(&stream);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
unzippedData->size = resultSize;
|
||||||
|
inflateEnd(&stream);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
// tellZipError
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
void tellZipError(int errorCode, const char* op, const char* msg)
|
||||||
|
{
|
||||||
|
if (!op) op = "";
|
||||||
|
if (!msg) msg = "None";
|
||||||
|
|
||||||
|
switch (errorCode)
|
||||||
|
{
|
||||||
|
case Z_OK: return;
|
||||||
|
case Z_STREAM_END: return;
|
||||||
|
case Z_MEM_ERROR: tell(0, "Error: Not enough memory to unzip file%s!\n", op); return;
|
||||||
|
case Z_BUF_ERROR: tell(0, "Error: Couldn't unzip data due to output buffer size problem%s!\n", op); return;
|
||||||
|
case Z_DATA_ERROR: tell(0, "Error: Zipped input data corrupted%s! Details: %s\n", op, msg); return;
|
||||||
|
case Z_STREAM_ERROR: tell(0, "Error: Invalid stream structure%s. Details: %s\n", op, msg); return;
|
||||||
|
default: tell(0, "Error: Couldn't unzip data for unknown reason (%6d)%s!\n", errorCode, op); return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************
|
||||||
|
// Host Data
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
|
||||||
|
static struct utsname info;
|
||||||
|
|
||||||
|
const char* getHostName()
|
||||||
|
{
|
||||||
|
// get info from kernel
|
||||||
|
|
||||||
|
if (uname(&info) == -1)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return info.nodename;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getFirstIp()
|
||||||
|
{
|
||||||
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
|
static char host[NI_MAXHOST] = "";
|
||||||
|
|
||||||
|
if (getifaddrs(&ifaddr) == -1)
|
||||||
|
{
|
||||||
|
tell(0, "getifaddrs() failed");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk through linked interface list
|
||||||
|
|
||||||
|
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next)
|
||||||
|
{
|
||||||
|
if (!ifa->ifa_addr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// For an AF_INET interfaces
|
||||||
|
|
||||||
|
if (ifa->ifa_addr->sa_family == AF_INET) // || ifa->ifa_addr->sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
int res = getnameinfo(ifa->ifa_addr,
|
||||||
|
(ifa->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) :
|
||||||
|
sizeof(struct sockaddr_in6),
|
||||||
|
host, NI_MAXHOST, 0, 0, NI_NUMERICHOST);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
tell(0, "getnameinfo() failed: %s", gai_strerror(res));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip loopback interface
|
||||||
|
|
||||||
|
if (strcmp(host, "127.0.0.1") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tell(5, "%-8s %-15s %s", ifa->ifa_name, host,
|
||||||
|
ifa->ifa_addr->sa_family == AF_INET ? " (AF_INET)" :
|
||||||
|
ifa->ifa_addr->sa_family == AF_INET6 ? " (AF_INET6)" : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifaddr);
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USELIBARCHIVE
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// unzip <file> and get data of first content which name matches <filter>
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
int unzip(const char* file, const char* filter, char*& buffer, int& size, char* entryName)
|
||||||
|
{
|
||||||
|
const int step = 1024*10;
|
||||||
|
|
||||||
|
int bufSize = 0;
|
||||||
|
int r;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
struct archive_entry* entry;
|
||||||
|
struct archive* a = archive_read_new();
|
||||||
|
|
||||||
|
*entryName = 0;
|
||||||
|
buffer = 0;
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
archive_read_support_filter_all(a);
|
||||||
|
archive_read_support_format_all(a);
|
||||||
|
|
||||||
|
r = archive_read_open_filename(a, file, 10204);
|
||||||
|
|
||||||
|
if (r != ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
tell(0, "Error: Open '%s' failed - %m", file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
strcpy(entryName, archive_entry_pathname(entry));
|
||||||
|
|
||||||
|
if (strstr(entryName, filter))
|
||||||
|
{
|
||||||
|
bufSize = step;
|
||||||
|
buffer = (char*)malloc(bufSize+1);
|
||||||
|
|
||||||
|
while ((res = archive_read_data(a, buffer+size, step)) > 0)
|
||||||
|
{
|
||||||
|
size += res;
|
||||||
|
bufSize += step;
|
||||||
|
|
||||||
|
buffer = (char*)realloc(buffer, bufSize+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[size] = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = archive_read_free(a);
|
||||||
|
|
||||||
|
if (r != ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
size = 0;
|
||||||
|
free(buffer);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size > 0 ? success : fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Class LogDuration
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
|
||||||
|
# include <vdr/plugin.h>
|
||||||
|
|
||||||
|
LogDuration::LogDuration(const char* aMessage, int aLogLevel)
|
||||||
|
{
|
||||||
|
logLevel = aLogLevel;
|
||||||
|
strcpy(message, aMessage);
|
||||||
|
|
||||||
|
// at last !
|
||||||
|
|
||||||
|
durationStart = cTimeMs::Now();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDuration::~LogDuration()
|
||||||
|
{
|
||||||
|
tell(logLevel, "duration '%s' was (%dms)",
|
||||||
|
message, cTimeMs::Now() - durationStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogDuration::show(const char* label)
|
||||||
|
{
|
||||||
|
tell(logLevel, "elapsed '%s' at '%s' was (%dms)",
|
||||||
|
message, label, cTimeMs::Now() - durationStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Get Unique ID
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
#ifdef USEUUID
|
||||||
|
const char* getUniqueId()
|
||||||
|
{
|
||||||
|
static char uuid[sizeUuid+TB] = "";
|
||||||
|
|
||||||
|
uuid_t id;
|
||||||
|
uuid_generate(id);
|
||||||
|
uuid_unparse_upper(id, uuid);
|
||||||
|
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
#endif // USEUUID
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Create MD5
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
#ifdef USEMD5
|
||||||
|
|
||||||
|
int createMd5(const char* buf, md5* md5)
|
||||||
|
{
|
||||||
|
MD5_CTX c;
|
||||||
|
unsigned char out[MD5_DIGEST_LENGTH];
|
||||||
|
|
||||||
|
MD5_Init(&c);
|
||||||
|
MD5_Update(&c, buf, strlen(buf));
|
||||||
|
MD5_Final(out, &c);
|
||||||
|
|
||||||
|
for (int n = 0; n < MD5_DIGEST_LENGTH; n++)
|
||||||
|
sprintf(md5+2*n, "%02x", out[n]);
|
||||||
|
|
||||||
|
md5[sizeMd5] = 0;
|
||||||
|
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
int createMd5OfFile(const char* path, const char* name, md5* md5)
|
||||||
|
{
|
||||||
|
FILE* f;
|
||||||
|
char buffer[1000];
|
||||||
|
int nread = 0;
|
||||||
|
MD5_CTX c;
|
||||||
|
unsigned char out[MD5_DIGEST_LENGTH];
|
||||||
|
char* file = 0;
|
||||||
|
|
||||||
|
asprintf(&file, "%s/%s", path, name);
|
||||||
|
|
||||||
|
if (!(f = fopen(file, "r")))
|
||||||
|
{
|
||||||
|
tell(0, "Fatal: Can't access '%s'; %m", file);
|
||||||
|
free(file);
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
MD5_Init(&c);
|
||||||
|
|
||||||
|
while ((nread = fread(buffer, 1, 1000, f)) > 0)
|
||||||
|
MD5_Update(&c, buffer, nread);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
MD5_Final(out, &c);
|
||||||
|
|
||||||
|
for (int n = 0; n < MD5_DIGEST_LENGTH; n++)
|
||||||
|
sprintf(md5+2*n, "%02x", out[n]);
|
||||||
|
|
||||||
|
md5[sizeMd5] = 0;
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USEMD5
|
179
lib/common.h
Normal file
179
lib/common.h
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* common.h: EPG2VDR plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __COMMON_H
|
||||||
|
#define __COMMON_H
|
||||||
|
|
||||||
|
#include <stdint.h> // uint_64_t
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <openssl/md5.h> // MD5_*
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
# include <vdr/tools.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USELIBXML
|
||||||
|
# include <libxslt/transform.h>
|
||||||
|
# include <libxslt/xsltutils.h>
|
||||||
|
# include <libexslt/exslt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
//
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
#ifndef VDR_PLUGIN
|
||||||
|
inline long min(long a, long b) { return a < b ? a : b; }
|
||||||
|
inline long max(long a, long b) { return a > b ? a : b; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
success = 0,
|
||||||
|
done = success,
|
||||||
|
fail = -1,
|
||||||
|
na = -1,
|
||||||
|
ignore = -2,
|
||||||
|
all = -3,
|
||||||
|
abrt = -4,
|
||||||
|
yes = 1,
|
||||||
|
on = 1,
|
||||||
|
off = 0,
|
||||||
|
no = 0,
|
||||||
|
TB = 1,
|
||||||
|
|
||||||
|
sizeMd5 = 2 * MD5_DIGEST_LENGTH,
|
||||||
|
sizeUuid = 36,
|
||||||
|
|
||||||
|
tmeSecondsPerMinute = 60,
|
||||||
|
tmeSecondsPerHour = tmeSecondsPerMinute * 60,
|
||||||
|
tmeSecondsPerDay = 24 * tmeSecondsPerHour
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Tell
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
void tell(int eloquence, const char* format, ...);
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// MemoryStruct for curl callbacks
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
struct MemoryStruct
|
||||||
|
{
|
||||||
|
MemoryStruct() { memory = 0; clear(); }
|
||||||
|
~MemoryStruct() { clear(); }
|
||||||
|
|
||||||
|
// data
|
||||||
|
|
||||||
|
char* memory;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
// tag attribute
|
||||||
|
|
||||||
|
char tag[100]; // the tag to be compared
|
||||||
|
char name[100]; // content name (filename)
|
||||||
|
int headerOnly;
|
||||||
|
|
||||||
|
int isEmpty() { return memory == 0; }
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
free(memory);
|
||||||
|
memory = 0;
|
||||||
|
size = 0;
|
||||||
|
*tag = 0;
|
||||||
|
*name = 0;
|
||||||
|
headerOnly = no;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Tools
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
unsigned int getHostId();
|
||||||
|
const char* getHostName();
|
||||||
|
const char* getFirstIp();
|
||||||
|
|
||||||
|
#ifdef USEUUID
|
||||||
|
const char* getUniqueId();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void removeChars(std::string& str, const char* ignore);
|
||||||
|
void removeCharsExcept(std::string& str, const char* except);
|
||||||
|
void removeWord(std::string& pattern, std::string word);
|
||||||
|
void prepareCompressed(std::string& pattern);
|
||||||
|
|
||||||
|
char* rTrim(char* buf);
|
||||||
|
char* lTrim(char* buf);
|
||||||
|
char* allTrim(char* buf);
|
||||||
|
char* sstrcpy(char* dest, const char* src, int max);
|
||||||
|
std::string num2Str(int num);
|
||||||
|
std::string l2pTime(time_t t);
|
||||||
|
std::string ms2Dur(uint64_t t);
|
||||||
|
const char* c2s(char c, char* buf);
|
||||||
|
|
||||||
|
int fileExists(const char* path);
|
||||||
|
int fileSize(const char* path);
|
||||||
|
int createLink(const char* link, const char* dest, int force);
|
||||||
|
int isLink(const char* path);
|
||||||
|
int isEmpty(const char* str);
|
||||||
|
int removeFile(const char* filename);
|
||||||
|
int chkDir(const char* path);
|
||||||
|
|
||||||
|
#ifdef USELIBXML
|
||||||
|
xsltStylesheetPtr loadXSLT(const char* name, const char* path, int utf8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USEMD5
|
||||||
|
typedef char md5Buf[sizeMd5+TB];
|
||||||
|
typedef char md5;
|
||||||
|
int createMd5(const char* buf, md5* md5);
|
||||||
|
int createMd5OfFile(const char* path, const char* name, md5* md5);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Zip
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
int gunzip(MemoryStruct* zippedData, MemoryStruct* unzippedData);
|
||||||
|
void tellZipError(int errorCode, const char* op, const char* msg);
|
||||||
|
|
||||||
|
#ifdef USELIBARCHIVE
|
||||||
|
int unzip(const char* file, const char* filter, char*& buffer,
|
||||||
|
int& size, char* entryName);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Log Duration
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class LogDuration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
LogDuration(const char* aMessage, int aLogLevel = 2);
|
||||||
|
~LogDuration();
|
||||||
|
|
||||||
|
void show(const char* label = "");
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
char message[1000];
|
||||||
|
uint64_t durationStart;
|
||||||
|
int logLevel;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
#endif //___COMMON_H
|
63
lib/config.c
Normal file
63
lib/config.c
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* config.c:
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
cEPG2VDRConfig EPG2VDRConfig;
|
||||||
|
|
||||||
|
cEPG2VDRConfig::cEPG2VDRConfig(void)
|
||||||
|
{
|
||||||
|
mainmenuVisible = yes;
|
||||||
|
mainmenuFullupdate = 0;
|
||||||
|
|
||||||
|
useproxy = no;
|
||||||
|
sstrcpy(httpproxy, "127.0.0.1:8000", sizeof(httpproxy));
|
||||||
|
sstrcpy(username, "", sizeof(username));
|
||||||
|
sstrcpy(password, "", sizeof(password));
|
||||||
|
|
||||||
|
checkInitial = yes;
|
||||||
|
updatetime = 6; // hours
|
||||||
|
days = 8;
|
||||||
|
upddays = 2;
|
||||||
|
storeXmlToFs = no;
|
||||||
|
blacklist = no;
|
||||||
|
masterMode = 0;
|
||||||
|
|
||||||
|
getepgimages = yes;
|
||||||
|
maximagesperevent = 1;
|
||||||
|
epgImageSize = 2;
|
||||||
|
|
||||||
|
seriesEnabled = yes;
|
||||||
|
sstrcpy(seriesUrl, "eplists.constabel.net", sizeof(seriesUrl));
|
||||||
|
seriesPort = 2006;
|
||||||
|
storeSeriesToFs = no;
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
activeOnEpgd = no;
|
||||||
|
scheduleBoot = no;
|
||||||
|
#else
|
||||||
|
sstrcpy(cachePath, "/var/cache/epgd", sizeof(cachePath));
|
||||||
|
sstrcpy(pluginPath, PLGDIR, sizeof(pluginPath));
|
||||||
|
sstrcpy(epgView, "eventsview.sql", sizeof(epgView));
|
||||||
|
updateThreshold = 200;
|
||||||
|
maintanance = no;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sstrcpy(dbHost, "localhost", sizeof(dbHost));
|
||||||
|
dbPort = 3306;
|
||||||
|
sstrcpy(dbName, "epg2vdr", sizeof(dbName));
|
||||||
|
sstrcpy(dbUser, "epg2vdr", sizeof(dbUser));
|
||||||
|
sstrcpy(dbPass, "epg", sizeof(dbPass));
|
||||||
|
|
||||||
|
logstdout = no;
|
||||||
|
loglevel = 1;
|
||||||
|
|
||||||
|
uuid[0] = 0;
|
||||||
|
}
|
73
lib/config.h
Normal file
73
lib/config.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* config.h:
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: config.h,v 1.2 2012/10/26 08:44:13 wendel Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __EPG2VDR_CONFIG_H
|
||||||
|
#define __EPG2VDR_CONFIG_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Config
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
struct cEPG2VDRConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cEPG2VDRConfig(void);
|
||||||
|
|
||||||
|
int useproxy;
|
||||||
|
char httpproxy[256+TB];
|
||||||
|
char username[100+TB];
|
||||||
|
char password[100+TB];
|
||||||
|
|
||||||
|
int checkInitial;
|
||||||
|
int updatetime;
|
||||||
|
int days;
|
||||||
|
int upddays;
|
||||||
|
int storeXmlToFs;
|
||||||
|
int blacklist; // to enable noepg feature
|
||||||
|
|
||||||
|
int getepgimages;
|
||||||
|
int maximagesperevent;
|
||||||
|
int epgImageSize;
|
||||||
|
|
||||||
|
int seriesEnabled;
|
||||||
|
char seriesUrl[500+TB];
|
||||||
|
int seriesPort;
|
||||||
|
int storeSeriesToFs;
|
||||||
|
|
||||||
|
#ifdef VDR_PLUGIN
|
||||||
|
int activeOnEpgd;
|
||||||
|
int scheduleBoot;
|
||||||
|
#else
|
||||||
|
char cachePath[256+TB];
|
||||||
|
char pluginPath[256+TB];
|
||||||
|
char epgView[100+TB];
|
||||||
|
int updateThreshold;
|
||||||
|
int maintanance;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char dbHost[100+TB];
|
||||||
|
int dbPort;
|
||||||
|
char dbName[100+TB];
|
||||||
|
char dbUser[100+TB];
|
||||||
|
char dbPass[100+TB];
|
||||||
|
|
||||||
|
int logstdout;
|
||||||
|
int loglevel;
|
||||||
|
|
||||||
|
int mainmenuVisible;
|
||||||
|
int mainmenuFullupdate;
|
||||||
|
int masterMode;
|
||||||
|
char uuid[sizeUuid+TB];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern cEPG2VDRConfig EPG2VDRConfig;
|
||||||
|
|
||||||
|
#endif // __EPG2VDR_CONFIG_H
|
856
lib/tabledef.c
Normal file
856
lib/tabledef.c
Normal file
@ -0,0 +1,856 @@
|
|||||||
|
/*
|
||||||
|
* tabledef.c
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tabledef.h"
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cEpgdState
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
const char* cEpgdState::states[] =
|
||||||
|
{
|
||||||
|
"init",
|
||||||
|
"standby",
|
||||||
|
"stopped",
|
||||||
|
|
||||||
|
"busy (events)",
|
||||||
|
"busy (match)",
|
||||||
|
"busy (images)",
|
||||||
|
"busy (scraping)",
|
||||||
|
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* cEpgdState::toName(cEpgdState::State s)
|
||||||
|
{
|
||||||
|
if (!isValid(s))
|
||||||
|
return "unknown";
|
||||||
|
|
||||||
|
return states[s];
|
||||||
|
}
|
||||||
|
|
||||||
|
cEpgdState::State cEpgdState::toState(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < esCount; i++)
|
||||||
|
if (strcmp(states[i], name) == 0)
|
||||||
|
return (State)i;
|
||||||
|
|
||||||
|
return esUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Event Fields
|
||||||
|
//***************************************************************************
|
||||||
|
//***************************************************************************
|
||||||
|
// Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableEvents::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
|
||||||
|
{ "eventid", ffUInt, 0, fiEventId, ftPrimary },
|
||||||
|
{ "channelid", ffAscii, 50, fiChannelId, ftPrimary },
|
||||||
|
|
||||||
|
{ "masterid", ffUInt, 0, fiMasterId, ftAutoinc },
|
||||||
|
{ "useid", ffUInt, 0, fiUseId, ftData },
|
||||||
|
|
||||||
|
// meta
|
||||||
|
|
||||||
|
{ "source", ffAscii, 10, fiSource, ftMeta },
|
||||||
|
{ "fileref", ffAscii, 50, fiFileRef, ftMeta },
|
||||||
|
{ "inssp", ffInt, 10, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 10, fiUpdSp, ftMeta },
|
||||||
|
{ "updflg", ffAscii, 1, fiUpdFlg, ftMeta },
|
||||||
|
{ "delflg", ffAscii, 1, fiDelFlg, ftMeta },
|
||||||
|
|
||||||
|
// vdr event data
|
||||||
|
|
||||||
|
{ "tableid", ffInt, 2, fiTableId, ftData },
|
||||||
|
{ "version", ffInt, 3, fiVersion, ftData },
|
||||||
|
{ "title", ffAscii, 200, fiTitle, ftData },
|
||||||
|
{ "comptitle", ffAscii, 200, fiCompTitle, ftData },
|
||||||
|
{ "shorttext", ffAscii, 300, fiShortText, ftData },
|
||||||
|
{ "compshorttext", ffAscii, 300, fiCompShortText, ftData },
|
||||||
|
{ "longdescription", ffText, 25000, fiLongDescription, ftData },
|
||||||
|
{ "starttime", ffInt, 10, fiStartTime, ftData },
|
||||||
|
{ "duration", ffInt, 5, fiDuration, ftData },
|
||||||
|
{ "parentalrating", ffInt, 2, fiParentalRating, ftData },
|
||||||
|
{ "vps", ffInt, 10, fiVps, ftData },
|
||||||
|
|
||||||
|
{ "description", ffText, 50000, fiDescription, ftCalc },
|
||||||
|
|
||||||
|
// additional external data
|
||||||
|
|
||||||
|
{ "shortdescription", ffAscii, 3000, fiShortDescription, ftData },
|
||||||
|
{ "actor", ffAscii, 3000, fiActor, ftData },
|
||||||
|
{ "audio", ffAscii, 50, fiAudio, ftData },
|
||||||
|
{ "category", ffAscii, 50, fiCategory, ftData },
|
||||||
|
{ "country", ffAscii, 50, fiCountry, ftData },
|
||||||
|
{ "director", ffAscii, 250, fiDirector, ftData },
|
||||||
|
{ "flags", ffAscii, 100, fiFlags, ftData },
|
||||||
|
{ "genre", ffAscii, 100, fiGenre, ftData },
|
||||||
|
{ "info", ffText, 10000, fiInfo, ftData },
|
||||||
|
{ "music", ffAscii, 250, fiMusic, ftData },
|
||||||
|
{ "producer", ffText, 1000, fiProducer, ftData },
|
||||||
|
{ "screenplay", ffAscii, 500, fiScreenplay, ftData },
|
||||||
|
{ "shortreview", ffAscii, 500, fiShortreview, ftData },
|
||||||
|
{ "tipp", ffAscii, 250, fiTipp, ftData },
|
||||||
|
{ "topic", ffAscii, 500, fiTopic, ftData },
|
||||||
|
{ "year", ffAscii, 10, fiYear, ftData },
|
||||||
|
{ "rating", ffAscii, 250, fiRating, ftData },
|
||||||
|
{ "fsk", ffAscii, 2, fiFsk, ftData },
|
||||||
|
{ "movieid", ffAscii, 20, fiMovieid, ftData },
|
||||||
|
{ "moderator", ffAscii, 250, fiModerator, ftData },
|
||||||
|
{ "other", ffText, 2000, fiOther, ftData },
|
||||||
|
{ "guest", ffText, 1000, fiGuest, ftData },
|
||||||
|
{ "camera", ffText, 1000, fiCamera, ftData },
|
||||||
|
|
||||||
|
{ "extepnum", ffInt, 4, fiExtEpNum, ftData },
|
||||||
|
{ "imagecount", ffInt, 2, fiImageCount, ftData },
|
||||||
|
|
||||||
|
// episodes (constable)
|
||||||
|
|
||||||
|
{ "episode", ffAscii, 250, fiEpisode, ftData },
|
||||||
|
{ "episodepart", ffAscii, 250, fiEpisodePart, ftData },
|
||||||
|
{ "episodelang", ffAscii, 3, fiEpisodeLang, ftData },
|
||||||
|
|
||||||
|
// tv scraper
|
||||||
|
|
||||||
|
{ "scrseriesid", ffInt, 11, fiScrSeriesId, ftData },
|
||||||
|
{ "scrseriesepisode", ffInt, 11, fiScrSeriesEpisode, ftData },
|
||||||
|
{ "scrmovieid", ffInt, 11, fiScrMovieId, ftData },
|
||||||
|
{ "scrsp", ffInt, 11, fiScrSp, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableEvents::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableEvents::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ "comptitle", { fiCompTitle, na }, 0 },
|
||||||
|
{ "source", { fiSource, na }, 0 },
|
||||||
|
{ "FilerefSource", { fiFileRef, fiSource, na }, 0 },
|
||||||
|
{ "channelid", { fiChannelId, na }, 0 },
|
||||||
|
{ "useid", { fiUseId, na }, 0 },
|
||||||
|
{ "useidchannelid", { fiUseId, fiChannelId, na }, 0 },
|
||||||
|
{ "updflgupdsp", { fiUpdFlg, fiUpdSp, na }, 0 },
|
||||||
|
{ "idxsourcechannelid", { fiSource, fiChannelId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Components
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableComponents::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "eventid", ffUInt, 0, fiEventId, ftPrimary },
|
||||||
|
{ "channelid", ffAscii, 50, fiChannelId, ftPrimary },
|
||||||
|
{ "stream", ffInt, 3, fiStream, ftPrimary },
|
||||||
|
{ "type", ffInt, 3, fiType, ftPrimary },
|
||||||
|
{ "lang", ffAscii, 8, fiLang, ftPrimary },
|
||||||
|
{ "description", ffAscii, 100, fiDescription, ftPrimary },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// File References
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableFileRefs::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "name", ffAscii, 100, fiName, ftPrimary },
|
||||||
|
{ "source", ffAscii, 10, fiSource, ftPrimary },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
|
||||||
|
{ "extid", ffAscii, 10, fiExternalId, ftData },
|
||||||
|
{ "fileref", ffAscii, 100, fiFileRef, ftData }, // name + '-' + tag
|
||||||
|
{ "tag", ffAscii, 100, fiTag, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableFileRefs::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ "SourceFileref", { fiSource, fiFileRef, na }, 0 },
|
||||||
|
{ "Fileref", { fiFileRef, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Image Ref Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableImageRefs::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "eventid", ffUInt, 0, fiEventId, ftPrimary },
|
||||||
|
{ "lfn", ffInt, 0, fiLfn, ftPrimary },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
{ "source", ffAscii, 10, fiSource, ftMeta },
|
||||||
|
|
||||||
|
{ "fileref", ffAscii, 100, fiFileRef, ftData },
|
||||||
|
{ "imagename", ffAscii, 100, fiImgName, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableImageRefs::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ "lfn", { fiLfn, na }, 0 },
|
||||||
|
{ "name", { fiImgName, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Image Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableImages::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "imagename", ffAscii, 100, fiImgName, ftPrimary },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
|
||||||
|
{ "image", ffMlob, 200000, fiImage, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Series Episode Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableEpisodes::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
|
||||||
|
{ "compname", ffAscii, 100, fiCompName, ftPrimary }, // episode name compressed
|
||||||
|
{ "comppartname", ffAscii, 200, fiCompPartName, ftPrimary }, // part name compressed
|
||||||
|
{ "lang", ffAscii, 10, fiLang, ftPrimary },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
{ "link", ffInt, 0, fiLink, ftData },
|
||||||
|
|
||||||
|
// episode data
|
||||||
|
|
||||||
|
{ "shortname", ffAscii, 100, fiShortName, ftData },
|
||||||
|
{ "episodename", ffAscii, 100, fiEpisodeName, ftData }, // episode name
|
||||||
|
|
||||||
|
// part data
|
||||||
|
|
||||||
|
{ "partname", ffAscii, 300, fiPartName, ftData }, // part name
|
||||||
|
{ "season", ffInt, 0, fiSeason, ftData },
|
||||||
|
{ "part", ffInt, 0, fiPart, ftData },
|
||||||
|
{ "parts", ffInt, 0, fiParts, ftData },
|
||||||
|
{ "number", ffInt, 0, fiNumber, ftData },
|
||||||
|
|
||||||
|
{ "extracol1", ffAscii, 250, fiExtraCol1, ftData },
|
||||||
|
{ "extracol2", ffAscii, 250, fiExtraCol2, ftData },
|
||||||
|
{ "extracol3", ffAscii, 250, fiExtraCol3, ftData },
|
||||||
|
|
||||||
|
{ "comment", ffAscii, 250, fiComment, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableEpisodes::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ "updsp", { fiUpdSp, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Channel Map Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableChannelMap::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "extid", ffAscii, 10, fiExternalId, ftPrimary },
|
||||||
|
{ "channelid", ffAscii, 50, fiChannelId, ftPrimary },
|
||||||
|
{ "source", ffAscii, 20, fiSource, ftPrimary },
|
||||||
|
|
||||||
|
{ "channelname", ffAscii, 100, fiChannelName, ftData },
|
||||||
|
|
||||||
|
{ "vps", ffInt, 0, fiVps, ftData },
|
||||||
|
{ "merge", ffInt, 0, fiMerge, ftData },
|
||||||
|
{ "mergesp", ffInt, 0, fiMergeSp, ftData },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
{ "updflg", ffAscii, 1, fiUpdFlg, ftMeta },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableChannelMap::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ "sourceExtid", { fiSource, fiExternalId, na }, 0 },
|
||||||
|
{ "source", { fiSource, na }, 0 },
|
||||||
|
{ "updflg", { fiUpdFlg, na }, 0 },
|
||||||
|
{ "idxsourcechannelid", { fiSource, fiChannelId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// VDRs Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableVdrs::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "uuid", ffAscii, 40, fiUuid, ftPrimary },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
|
||||||
|
{ "name", ffAscii, 100, fiName, ftData },
|
||||||
|
{ "version", ffAscii, 100, fiVersion, ftData },
|
||||||
|
{ "dbapi", ffUInt, 0, fiDbApi, ftData },
|
||||||
|
{ "lastupd", ffInt, 0, fiLastUpdate, ftData },
|
||||||
|
{ "nextupd", ffInt, 0, fiNextUpdate, ftData },
|
||||||
|
{ "state", ffAscii, 20, fiState, ftData },
|
||||||
|
{ "master", ffAscii, 1, fiMaster, ftData },
|
||||||
|
{ "ip", ffAscii, 20, fiIp, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Parameter Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableParameters::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "owner", ffAscii, 40, fiOwner, ftPrimary },
|
||||||
|
{ "name", ffAscii, 40, fiName, ftPrimary },
|
||||||
|
|
||||||
|
{ "inssp", ffInt, 0, fiInsSp, ftMeta },
|
||||||
|
{ "updsp", ffInt, 0, fiUpdSp, ftMeta },
|
||||||
|
|
||||||
|
{ "value", ffAscii, 100, fiValue, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Analyse
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableAnalyse::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "channelid", ffAscii, 50, fiChannelId, ftPrimary },
|
||||||
|
{ "vdr_masterid", ffUInt, 0, fiVdrMasterId, ftData },
|
||||||
|
{ "vdr_eventid", ffUInt, 0, fiVdrEventId, ftPrimary },
|
||||||
|
|
||||||
|
{ "vdr_starttime", ffInt, 10, fiVdrStartTime, ftData },
|
||||||
|
{ "vdr_duration", ffInt, 5, fiVdrDuration, ftData },
|
||||||
|
{ "vdr_title", ffAscii, 200, fiVdrTitle, ftData },
|
||||||
|
{ "vdr_shorttext", ffAscii, 300, fiVdrShortText, ftData },
|
||||||
|
|
||||||
|
{ "ext_masterid", ffUInt, 0, fiExtMasterId, ftData },
|
||||||
|
{ "ext_eventid", ffUInt, 0, fiExtEventId, ftData },
|
||||||
|
{ "ext_starttime", ffInt, 10, fiExtStartTime, ftData },
|
||||||
|
{ "ext_duration", ffInt, 5, fiExtDuration, ftData },
|
||||||
|
{ "ext_title", ffAscii, 200, fiExtTitle, ftData },
|
||||||
|
{ "ext_shorttext", ffAscii, 300, fiExtShortText, ftData },
|
||||||
|
{ "ext_episode", ffAscii, 1, fiExtEpisode, ftData },
|
||||||
|
{ "ext_merge", ffInt, 11, fiExtMerge, ftData },
|
||||||
|
{ "ext_images", ffAscii, 1, fiExiImages, ftData },
|
||||||
|
|
||||||
|
{ "lvmin", ffInt, 3, fiLvMin, ftData },
|
||||||
|
{ "rank", ffInt, 5, fiRank, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableAnalyse::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ "vdr_masterid", { fiVdrMasterId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Snapshot
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableSnapshot::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
{ "channelid", ffAscii, 50, fiChannelId, ftData },
|
||||||
|
{ "source", ffAscii, 10, fiSource, ftData },
|
||||||
|
|
||||||
|
{ "masterid", ffUInt, 0, fiVdrMasterId, ftData },
|
||||||
|
{ "eventid", ffUInt, 0, fiEventId, ftData },
|
||||||
|
{ "useid", ffUInt, 0, fiUseId, ftData },
|
||||||
|
|
||||||
|
{ "starttime", ffInt, 10, fiStartTime, ftData },
|
||||||
|
{ "duration", ffInt, 5, fiDuration, ftData },
|
||||||
|
{ "title", ffAscii, 200, fiTitle, ftData },
|
||||||
|
{ "comptitle", ffAscii, 200, fiCompTitle, ftData },
|
||||||
|
{ "shorttext", ffAscii, 300, fiShortText, ftData },
|
||||||
|
{ "compshorttext", ffAscii, 300, fiCompShortText, ftData },
|
||||||
|
|
||||||
|
{ "updsp", ffInt, 10, fiUpdsp, ftData },
|
||||||
|
|
||||||
|
{ "episode", ffAscii, 1, fiEpisode, ftData },
|
||||||
|
{ "merge", ffInt, 0, fiMerge, ftData },
|
||||||
|
{ "images", ffAscii, 1, fiImages, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableSnapshot::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ "channelid", { fiChannelId, na }, 0 },
|
||||||
|
{ "starttimeSource", { fiStartTime, fiSource, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Series Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableSeries::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "series_id", ffUInt, 0, fiSeriesId, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "series_name", ffAscii, 200, fiSeriesName, ftData },
|
||||||
|
{ "series_last_scraped", ffUInt, 0, fiSeriesLastScraped, ftData },
|
||||||
|
{ "series_last_updated", ffUInt, 0, fiSeriesLastUpdated, ftData },
|
||||||
|
{ "series_overview", ffText, 10000, fiSeriesOverview, ftData },
|
||||||
|
{ "series_firstaired", ffAscii, 50, fiSeriesFirstAired, ftData },
|
||||||
|
{ "series_network", ffAscii, 100, fiSeriesNetwork, ftData },
|
||||||
|
{ "series_imdb_id", ffAscii, 20, fiSeriesIMDBId, ftData },
|
||||||
|
{ "series_genre", ffAscii, 100, fiSeriesGenre, ftData },
|
||||||
|
{ "series_rating", ffFloat, 31, fiSeriesRating, ftData },
|
||||||
|
{ "series_status", ffAscii, 50, fiSeriesStatus, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableSeries::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableSeries::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// SeriesEpisode Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableSeriesEpisode::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "episode_id", ffUInt, 0, fiEpisodeId, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "episode_number", ffUInt, 0, fiEpisodeNumber, ftData },
|
||||||
|
{ "season_number", ffUInt, 0, fiSeasonNumber, ftData },
|
||||||
|
{ "episode_name", ffAscii, 300, fiEpisodeName, ftData },
|
||||||
|
{ "episode_overview", ffText, 10000, fiEpisodeOverview, ftData },
|
||||||
|
{ "episode_firstaired", ffAscii, 20, fiEpisodeFirstAired, ftData },
|
||||||
|
{ "episode_gueststars", ffAscii, 1000, fiEpisodeGuestStars, ftData },
|
||||||
|
{ "episode_rating", ffFloat, 31, fiEpisodeRating, ftData },
|
||||||
|
{ "episode_last_updated", ffUInt, 0, fiEpisodeLastUpdated, ftData },
|
||||||
|
{ "series_id", ffUInt, 0, fiSeriesId, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableSeriesEpisode::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableSeriesEpisode::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
{ "series_id", { fiSeriesId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// SeriesMedia Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableSeriesMedia::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "series_id", ffUInt, 0, fiSeriesId, ftPrimary },
|
||||||
|
{ "season_number", ffUInt, 0, fiSeasonNumber, ftPrimary },
|
||||||
|
{ "episode_id", ffUInt, 0, fiEpisodeId, ftPrimary },
|
||||||
|
{ "actor_id", ffUInt, 0, fiActorId, ftPrimary },
|
||||||
|
{ "media_type", ffUInt, 0, fiMediaType, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "media_url", ffAscii, 100, fiMediaUrl, ftData },
|
||||||
|
{ "media_width", ffUInt, 0, fiMediaWidth, ftData },
|
||||||
|
{ "media_height", ffUInt, 0, fiMediaHeight, ftData },
|
||||||
|
{ "media_rating", ffFloat, 31, fiMediaRating, ftData },
|
||||||
|
{ "media_content", ffMlob, 1000000, fiMediaContent, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableSeriesMedia::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableSeriesMedia::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
{ "series_id", { fiSeriesId, na }, 0 },
|
||||||
|
{ "season_number", { fiSeasonNumber, na }, 0 },
|
||||||
|
{ "episode_id", { fiEpisodeId, na }, 0 },
|
||||||
|
{ "actor_id", { fiActorId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// SeriesActor Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableSeriesActor::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "actor_id", ffUInt, 0, fiActorId, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "actor_name", ffAscii, 100, fiActorName, ftData },
|
||||||
|
{ "actor_role", ffAscii, 500, fiActorRole, ftData },
|
||||||
|
{ "actor_sortorder", ffUInt, 0, fiSortOrder, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableSeriesActor::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableSeriesActor::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Movie Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableMovies::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "movie_id", ffUInt, 0, fiMovieId, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "movie_title", ffAscii, 300, fiTitle, ftData },
|
||||||
|
{ "movie_original_title", ffAscii, 300, fiOriginalTitle, ftData },
|
||||||
|
{ "movie_tagline", ffAscii, 1000, fiTagline, ftData },
|
||||||
|
{ "movie_overview", ffText, 5000, fiOverview, ftData },
|
||||||
|
{ "movie_adult", ffUInt, 0, fiIsAdult, ftData },
|
||||||
|
{ "movie_collection_id", ffUInt, 0, fiCollectionId, ftData },
|
||||||
|
{ "movie_collection_name", ffAscii, 300, fiCollectionName, ftData },
|
||||||
|
{ "movie_budget", ffUInt, 0, fiBudget, ftData },
|
||||||
|
{ "movie_revenue", ffUInt, 0, fiRevenue, ftData },
|
||||||
|
{ "movie_genres", ffAscii, 500, fiGenres, ftData },
|
||||||
|
{ "movie_homepage", ffAscii, 300, fiHomepage, ftData },
|
||||||
|
{ "movie_release_date", ffAscii, 20, fiReleaaseDate, ftData },
|
||||||
|
{ "movie_runtime", ffUInt, 0, fiRuntime, ftData },
|
||||||
|
{ "movie_popularity", ffFloat, 31, fiPopularity, ftData },
|
||||||
|
{ "movie_vote_average", ffFloat, 31, fiVoteAverage, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableMovies::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableMovies::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
{ "movie_id", { fiMovieId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// MovieActor Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableMovieActor::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "actor_id", ffUInt, 0, fiActorId, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "actor_name", ffAscii, 300, fiActorName, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableMovieActor::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableMovieActor::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
{ "actor_id", { fiActorId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// MovieActors Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableMovieActors::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "movie_id", ffUInt, 0, fiMovieId, ftPrimary },
|
||||||
|
{ "actor_id", ffUInt, 0, fiActorId, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "actor_role", ffAscii, 300, fiRole, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableMovieActors::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableMovieActors::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
{ "movie_id", { fiMovieId, na }, 0 },
|
||||||
|
{ "actor_id", { fiActorId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cTableMovieMedia Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableMovieMedia::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "movie_id", ffUInt, 0, fiMovieId, ftPrimary },
|
||||||
|
{ "actor_id", ffUInt, 0, fiActorId, ftPrimary },
|
||||||
|
{ "media_type", ffUInt, 0, fiMediaType, ftPrimary },
|
||||||
|
//Data
|
||||||
|
{ "media_url", ffAscii, 100, fiMediaUrl, ftData },
|
||||||
|
{ "media_width", ffUInt, 0, fiMediaWidth, ftData },
|
||||||
|
{ "media_height", ffUInt, 0, fiMediaHeight, ftData },
|
||||||
|
{ "media_content", ffMlob, 1000000, fiMediaContent, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableMovieMedia::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableMovieMedia::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
{ "movie_id", { fiMovieId, na }, 0 },
|
||||||
|
{ "actor_id", { fiActorId, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cTableRecordings Fields
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cDbService::FieldDef cTableRecordings::fields[] =
|
||||||
|
{
|
||||||
|
// name format size index type
|
||||||
|
|
||||||
|
// primary key
|
||||||
|
{ "uuid", ffAscii, 40, fiUuid, ftPrimary },
|
||||||
|
{ "rec_path", ffAscii, 200, fiRecPath, ftPrimary },
|
||||||
|
{ "rec_start", ffUInt, 0, fiRecStart, ftPrimary },
|
||||||
|
|
||||||
|
//Data
|
||||||
|
{ "event_id", ffUInt, 0, fiEventId, ftData },
|
||||||
|
{ "channel_id", ffAscii, 50, fiChannelId, ftData },
|
||||||
|
{ "scrapinfo_movie_id", ffUInt, 0, fiScrapInfoMovieId, ftData },
|
||||||
|
{ "scrapinfo_series_id", ffUInt, 0, fiScrapInfoSeriesId, ftData },
|
||||||
|
{ "scrapinfo_episode_id", ffUInt, 0, fiScrapInfoEpisodeId, ftData },
|
||||||
|
{ "scrap_new", ffUInt, 0, fiScrapNew, ftData },
|
||||||
|
{ "rec_title", ffAscii, 200, fiRecTitle, ftData },
|
||||||
|
{ "rec_subtitle", ffAscii, 500, fiRecSubTitle, ftData },
|
||||||
|
{ "rec_duration", ffUInt, 0, fiRecDuration, ftData },
|
||||||
|
{ "movie_id", ffUInt, 0, fiMovieId, ftData },
|
||||||
|
{ "series_id", ffUInt, 0, fiSeriesId, ftData },
|
||||||
|
{ "episode_id", ffUInt, 0, fiEpisodeId, ftData },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDbService::FieldDef* cTableRecordings::toField(const char* name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fiCount; i++)
|
||||||
|
if (strcmp(fields[i].name, name) == 0)
|
||||||
|
return &fields[i];
|
||||||
|
|
||||||
|
tell(0, "Request for unexpected field '%s', ignoring", name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDbService::IndexDef cTableRecordings::indices[] =
|
||||||
|
{
|
||||||
|
// index fields
|
||||||
|
{ "uuid", { fiUuid, na }, 0 },
|
||||||
|
{ "rec_path", { fiRecPath, na }, 0 },
|
||||||
|
{ "rec_start", { fiRecStart, na }, 0 },
|
||||||
|
|
||||||
|
{ 0 }
|
||||||
|
};
|
832
lib/tabledef.h
Normal file
832
lib/tabledef.h
Normal file
@ -0,0 +1,832 @@
|
|||||||
|
/*
|
||||||
|
* tabledef.h
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TABLEDEF_H
|
||||||
|
#define __TABLEDEF_H
|
||||||
|
|
||||||
|
#include "db.h"
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cEpgdState
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cEpgdState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
esUnknown = na,
|
||||||
|
|
||||||
|
esInit,
|
||||||
|
esStandby,
|
||||||
|
esStopped,
|
||||||
|
|
||||||
|
esBusy,
|
||||||
|
esBusyEvents = esBusy,
|
||||||
|
esBusyMatch,
|
||||||
|
|
||||||
|
esBusyImages,
|
||||||
|
|
||||||
|
esBusyScraping,
|
||||||
|
|
||||||
|
esCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* toName(State s);
|
||||||
|
static State toState(const char* name);
|
||||||
|
static int isValid(State s) { return s > esUnknown && s < esCount; }
|
||||||
|
|
||||||
|
static const char* states[];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef cEpgdState Es;
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cUpdateState
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cUpdateState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
// add to VDRs EPG
|
||||||
|
|
||||||
|
usActive = 'A',
|
||||||
|
usLink = 'L',
|
||||||
|
usPassthrough = 'P',
|
||||||
|
|
||||||
|
// remove from VDRs EPG
|
||||||
|
|
||||||
|
usChanged = 'C',
|
||||||
|
usDelete = 'D',
|
||||||
|
usRemove = 'R',
|
||||||
|
|
||||||
|
// don't care for VDRs EPG
|
||||||
|
|
||||||
|
usInactive = 'I',
|
||||||
|
usTarget = 'T'
|
||||||
|
};
|
||||||
|
|
||||||
|
// get lists for SQL 'in' statements
|
||||||
|
|
||||||
|
static const char* getDeletable() { return "'A','L','P','R','I'"; }
|
||||||
|
static const char* getNeeded() { return "'A','L','P','C','D','R'"; }
|
||||||
|
|
||||||
|
// checks fpr c++ code
|
||||||
|
|
||||||
|
static int isNeeded(char c) { return strchr("ALPCDR", c) != 0; }
|
||||||
|
static int isRemove(char c) { return strchr("CDR", c) != 0; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef cUpdateState Us;
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableFileRef
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableFileRefs : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableFileRefs(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "fileref"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiName,
|
||||||
|
fiSource,
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
|
||||||
|
fiExternalId,
|
||||||
|
fiFileRef,
|
||||||
|
fiTag,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableImageRef
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableImageRefs : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableImageRefs(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "imagerefs"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiEventId,
|
||||||
|
fiLfn,
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
fiSource,
|
||||||
|
fiFileRef,
|
||||||
|
|
||||||
|
fiImgName,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableImage
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableImages : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableImages(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "images"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiImgName,
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
fiImage,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableEvent
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableEvents : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableEvents(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "events"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiEventId,
|
||||||
|
fiChannelId,
|
||||||
|
|
||||||
|
fiMasterId,
|
||||||
|
fiUseId,
|
||||||
|
|
||||||
|
fiSource,
|
||||||
|
fiFileRef,
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
fiUpdFlg, // update flag
|
||||||
|
fiDelFlg, // deletion flag
|
||||||
|
|
||||||
|
fiTableId,
|
||||||
|
fiVersion,
|
||||||
|
fiTitle,
|
||||||
|
fiCompTitle, // compressed (without whitespace and special characters)
|
||||||
|
fiShortText,
|
||||||
|
fiCompShortText, // compressed (without whitespace and special characters)
|
||||||
|
fiLongDescription,
|
||||||
|
fiStartTime,
|
||||||
|
fiDuration,
|
||||||
|
fiParentalRating,
|
||||||
|
fiVps,
|
||||||
|
fiDescription, // view field, not stored!
|
||||||
|
|
||||||
|
fiShortDescription,
|
||||||
|
fiActor,
|
||||||
|
fiAudio,
|
||||||
|
fiCategory,
|
||||||
|
fiCountry,
|
||||||
|
fiDirector,
|
||||||
|
fiFlags,
|
||||||
|
fiGenre,
|
||||||
|
fiInfo,
|
||||||
|
fiMusic,
|
||||||
|
fiProducer,
|
||||||
|
fiScreenplay,
|
||||||
|
fiShortreview,
|
||||||
|
fiTipp,
|
||||||
|
fiTopic,
|
||||||
|
fiYear,
|
||||||
|
fiRating,
|
||||||
|
fiFsk,
|
||||||
|
fiMovieid,
|
||||||
|
fiModerator,
|
||||||
|
fiOther,
|
||||||
|
fiGuest,
|
||||||
|
fiCamera,
|
||||||
|
|
||||||
|
fiExtEpNum,
|
||||||
|
fiImageCount,
|
||||||
|
|
||||||
|
fiEpisode,
|
||||||
|
fiEpisodePart,
|
||||||
|
fiEpisodeLang,
|
||||||
|
|
||||||
|
fiScrSeriesId,
|
||||||
|
fiScrSeriesEpisode,
|
||||||
|
fiScrMovieId,
|
||||||
|
fiScrSp,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableComponent
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableComponents : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableComponents(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "components"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiEventId,
|
||||||
|
fiChannelId,
|
||||||
|
fiStream,
|
||||||
|
fiType,
|
||||||
|
fiLang,
|
||||||
|
fiDescription,
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableEpisode
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableEpisodes : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableEpisodes(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "episodes"; }
|
||||||
|
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
// primary key
|
||||||
|
|
||||||
|
fiCompName, // compressed name (without whitespace and special characters)
|
||||||
|
fiCompPartName, // " " "
|
||||||
|
fiLang, // "de", "en", ...
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
fiLink,
|
||||||
|
|
||||||
|
// episode data
|
||||||
|
|
||||||
|
fiShortName,
|
||||||
|
fiEpisodeName, // episode name (fielname without path and suffix)
|
||||||
|
|
||||||
|
// part data
|
||||||
|
|
||||||
|
fiPartName, // part name
|
||||||
|
fiSeason,
|
||||||
|
fiPart,
|
||||||
|
fiParts,
|
||||||
|
fiNumber,
|
||||||
|
|
||||||
|
fiExtraCol1,
|
||||||
|
fiExtraCol2,
|
||||||
|
fiExtraCol3,
|
||||||
|
fiComment,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableChannelMap
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableChannelMap : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableChannelMap(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "channelmap"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiExternalId, //
|
||||||
|
fiChannelId, //
|
||||||
|
fiSource,
|
||||||
|
|
||||||
|
fiChannelName,
|
||||||
|
|
||||||
|
fiVps,
|
||||||
|
fiMerge,
|
||||||
|
fiMergeSp,
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
fiUpdFlg,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableVdr
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableVdrs : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableVdrs(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "vdrs"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiUuid,
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
|
||||||
|
fiName,
|
||||||
|
fiVersion,
|
||||||
|
fiDbApi,
|
||||||
|
fiLastUpdate,
|
||||||
|
fiNextUpdate,
|
||||||
|
fiState,
|
||||||
|
fiMaster,
|
||||||
|
fiIp,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableParameters
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableParameters : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableParameters(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "parameters"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiOwner,
|
||||||
|
fiName,
|
||||||
|
|
||||||
|
fiInsSp,
|
||||||
|
fiUpdSp,
|
||||||
|
|
||||||
|
fiValue,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cTableAnalyse
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableAnalyse : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableAnalyse(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "analyse"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiChannelId,
|
||||||
|
fiVdrMasterId,
|
||||||
|
fiVdrEventId,
|
||||||
|
|
||||||
|
fiVdrStartTime,
|
||||||
|
fiVdrDuration,
|
||||||
|
fiVdrTitle,
|
||||||
|
fiVdrShortText,
|
||||||
|
|
||||||
|
fiExtMasterId,
|
||||||
|
fiExtEventId,
|
||||||
|
fiExtStartTime,
|
||||||
|
fiExtDuration,
|
||||||
|
fiExtTitle,
|
||||||
|
fiExtShortText,
|
||||||
|
fiExtEpisode,
|
||||||
|
fiExtMerge,
|
||||||
|
fiExiImages,
|
||||||
|
|
||||||
|
fiLvMin,
|
||||||
|
fiRank,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cTableSnapshot
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableSnapshot : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableSnapshot(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "snapshot"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiChannelId,
|
||||||
|
fiSource,
|
||||||
|
fiVdrMasterId,
|
||||||
|
fiEventId,
|
||||||
|
fiUseId,
|
||||||
|
fiStartTime,
|
||||||
|
fiDuration,
|
||||||
|
fiTitle,
|
||||||
|
fiCompTitle,
|
||||||
|
fiShortText,
|
||||||
|
fiCompShortText,
|
||||||
|
fiUpdsp,
|
||||||
|
fiEpisode,
|
||||||
|
fiMerge,
|
||||||
|
fiImages,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableSeries
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableSeries : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableSeries(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "series"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiSeriesId,
|
||||||
|
|
||||||
|
fiSeriesName,
|
||||||
|
fiSeriesLastScraped,
|
||||||
|
fiSeriesLastUpdated,
|
||||||
|
fiSeriesOverview,
|
||||||
|
fiSeriesFirstAired,
|
||||||
|
fiSeriesNetwork,
|
||||||
|
fiSeriesIMDBId,
|
||||||
|
fiSeriesGenre,
|
||||||
|
fiSeriesRating,
|
||||||
|
fiSeriesStatus,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableSeriesEpisode
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableSeriesEpisode : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableSeriesEpisode(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "series_episode"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiEpisodeId,
|
||||||
|
|
||||||
|
fiEpisodeNumber,
|
||||||
|
fiSeasonNumber,
|
||||||
|
fiEpisodeName,
|
||||||
|
fiEpisodeOverview,
|
||||||
|
fiEpisodeFirstAired,
|
||||||
|
fiEpisodeGuestStars,
|
||||||
|
fiEpisodeRating,
|
||||||
|
fiEpisodeLastUpdated,
|
||||||
|
fiSeriesId,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableSeriesMedia
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableSeriesMedia : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableSeriesMedia(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "series_media"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiSeriesId,
|
||||||
|
fiSeasonNumber,
|
||||||
|
fiEpisodeId,
|
||||||
|
fiActorId,
|
||||||
|
fiMediaType,
|
||||||
|
|
||||||
|
fiMediaUrl,
|
||||||
|
fiMediaWidth,
|
||||||
|
fiMediaHeight,
|
||||||
|
fiMediaRating,
|
||||||
|
fiMediaContent,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableSeriesActor
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableSeriesActor : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableSeriesActor(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "series_actor"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiActorId,
|
||||||
|
|
||||||
|
fiActorName,
|
||||||
|
fiActorRole,
|
||||||
|
fiSortOrder,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableMovies
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableMovies : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableMovies(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "movie"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiMovieId,
|
||||||
|
|
||||||
|
fiTitle,
|
||||||
|
fiOriginalTitle,
|
||||||
|
fiTagline,
|
||||||
|
fiOverview,
|
||||||
|
fiIsAdult,
|
||||||
|
fiCollectionId,
|
||||||
|
fiCollectionName,
|
||||||
|
fiBudget,
|
||||||
|
fiRevenue,
|
||||||
|
fiGenres,
|
||||||
|
fiHomepage,
|
||||||
|
fiReleaaseDate,
|
||||||
|
fiRuntime,
|
||||||
|
fiPopularity,
|
||||||
|
fiVoteAverage,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableMovieActor
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableMovieActor : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableMovieActor(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "movie_actor"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiActorId,
|
||||||
|
|
||||||
|
fiActorName,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableMovieActors
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableMovieActors : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableMovieActors(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "movie_actors"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiMovieId,
|
||||||
|
fiActorId,
|
||||||
|
|
||||||
|
fiRole,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableMovieMedia
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableMovieMedia : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableMovieMedia(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "movie_media"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiMovieId,
|
||||||
|
fiActorId,
|
||||||
|
fiMediaType,
|
||||||
|
|
||||||
|
fiMediaUrl,
|
||||||
|
fiMediaWidth,
|
||||||
|
fiMediaHeight,
|
||||||
|
fiMediaContent,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// class cTableRecordings
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cTableRecordings : public cDbTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cTableRecordings(cDbConnection* aConnection)
|
||||||
|
: cDbTable(aConnection, fields, indices) { }
|
||||||
|
|
||||||
|
virtual const char* TableName() { return "recordings"; }
|
||||||
|
|
||||||
|
enum FieldIndex
|
||||||
|
{
|
||||||
|
fiUuid,
|
||||||
|
fiRecPath,
|
||||||
|
fiRecStart,
|
||||||
|
|
||||||
|
fiEventId,
|
||||||
|
fiChannelId,
|
||||||
|
fiScrapInfoMovieId,
|
||||||
|
fiScrapInfoSeriesId,
|
||||||
|
fiScrapInfoEpisodeId,
|
||||||
|
fiScrapNew,
|
||||||
|
fiRecTitle,
|
||||||
|
fiRecSubTitle,
|
||||||
|
fiRecDuration,
|
||||||
|
fiMovieId,
|
||||||
|
fiSeriesId,
|
||||||
|
fiEpisodeId,
|
||||||
|
|
||||||
|
fiCount
|
||||||
|
};
|
||||||
|
|
||||||
|
static FieldDef* toField(const char* name);
|
||||||
|
static FieldDef fields[];
|
||||||
|
static IndexDef indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__TABLEDEF_H
|
130
moviedbmovie.c
Normal file
130
moviedbmovie.c
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#define __STL_CONFIG_H
|
||||||
|
#include "lib/common.h"
|
||||||
|
#include "moviedbmovie.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
cMovieDbMovie::cMovieDbMovie(void) {
|
||||||
|
title = "";
|
||||||
|
originalTitle = "";
|
||||||
|
tagline = "";
|
||||||
|
overview = "";
|
||||||
|
adult = false;
|
||||||
|
collectionID = 0;
|
||||||
|
collectionName = "";
|
||||||
|
budget = 0;
|
||||||
|
revenue = 0;
|
||||||
|
genres = "";
|
||||||
|
homepage = "";
|
||||||
|
imdbid = "";
|
||||||
|
releaseDate = "";
|
||||||
|
runtime = 0;
|
||||||
|
popularity = 0.0;
|
||||||
|
voteAverage = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMovieDbMovie::~cMovieDbMovie() {
|
||||||
|
for (map<int, cMovieActor*>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
cMovieActor *a = (cMovieActor*)it->second;
|
||||||
|
delete a;
|
||||||
|
}
|
||||||
|
for (map<int, cMovieMedia*>::iterator it = medias.begin(); it != medias.end(); it++) {
|
||||||
|
cMovieMedia *m = (cMovieMedia*)it->second;
|
||||||
|
delete m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMovieDbMovie::InsertMedia(cMovieMedia *media) {
|
||||||
|
medias.insert(pair<int, cMovieMedia*>(media->mediaType, media));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMovieDbMovie::InsertActor(cMovieActor *actor) {
|
||||||
|
cMovieMedia *m = new cMovieMedia();
|
||||||
|
actor->actorThumb = m;
|
||||||
|
actors.insert(pair<int, cMovieActor*>(actor->id, actor));
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> cMovieDbMovie::GetActorIDs(void) {
|
||||||
|
vector<int> IDs;
|
||||||
|
for (map<int, cMovieActor*>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
cMovieActor *a = it->second;
|
||||||
|
IDs.push_back(a->id);
|
||||||
|
}
|
||||||
|
return IDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMovieDbMovie::SetActorThumbSize(int actorId, int imgWidth, int imgHeight) {
|
||||||
|
map<int, cMovieActor*>::iterator hit = actors.find(actorId);
|
||||||
|
if (hit != actors.end()) {
|
||||||
|
cMovieActor *a = hit->second;
|
||||||
|
if (!a->actorThumb)
|
||||||
|
return;
|
||||||
|
cMovieMedia *thumb = a->actorThumb;
|
||||||
|
thumb->width = imgWidth;
|
||||||
|
thumb->height = imgHeight;
|
||||||
|
thumb->mediaType = mmActorThumb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMovieDbMovie::SetActorPath(int actorId, string path) {
|
||||||
|
map<int, cMovieActor*>::iterator hit = actors.find(actorId);
|
||||||
|
if (hit != actors.end()) {
|
||||||
|
cMovieActor *a = hit->second;
|
||||||
|
if (!a->actorThumb)
|
||||||
|
return;
|
||||||
|
a->actorThumb->path = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cMovieDbMovie::GetMedia(mediaMovies mediatype, cTvMedia *p) {
|
||||||
|
map<int, cMovieMedia*>::iterator hit = medias.find(mediatype);
|
||||||
|
if (hit == medias.end())
|
||||||
|
return false;
|
||||||
|
cMovieMedia *pStored = hit->second;
|
||||||
|
p->path = pStored->path;
|
||||||
|
p->width = pStored->width;
|
||||||
|
p->height = pStored->height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMovieDbMovie::GetActors(vector<cActor> *a) {
|
||||||
|
for (map<int, cMovieActor*>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
cMovieActor *aStored = it->second;
|
||||||
|
cActor act;
|
||||||
|
act.name = aStored->name;
|
||||||
|
act.role = aStored->role;
|
||||||
|
if (aStored->actorThumb) {
|
||||||
|
act.actorThumb.width = aStored->actorThumb->width;
|
||||||
|
act.actorThumb.height = aStored->actorThumb->height;
|
||||||
|
act.actorThumb.path = aStored->actorThumb->path;
|
||||||
|
}
|
||||||
|
a->push_back(act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMovieDbMovie::Dump(void) {
|
||||||
|
tell(0, "--------------------------- Movie Info ----------------------------------");
|
||||||
|
tell(0, "title %s, ID: %d", title.c_str(), id);
|
||||||
|
tell(0, "Orig. Title: %s", originalTitle.c_str());
|
||||||
|
tell(0, "Tagline: %s", tagline.c_str());
|
||||||
|
tell(0, "Overview: %s", overview.c_str());
|
||||||
|
tell(0, "Collection: %s", collectionName.c_str());
|
||||||
|
tell(0, "Genre: %s", genres.c_str());
|
||||||
|
tell(0, "Popularity: %f", popularity);
|
||||||
|
tell(0, "--------------------------- Actors ----------------------------------");
|
||||||
|
for (map<int, cMovieActor*>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
cMovieActor *a = it->second;
|
||||||
|
tell(0, "Actor %d, Name: %s, Role %s", a->id, a->name.c_str(), a->role.c_str());
|
||||||
|
if (a->actorThumb) {
|
||||||
|
tell(0, "thmbWidth %d, thmbHeight %d", a->actorThumb->width, a->actorThumb->height);
|
||||||
|
tell(0, "Path %s", a->actorThumb->path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tell(0, "--------------------------- Media ----------------------------------");
|
||||||
|
for (map<int, cMovieMedia*>::iterator it = medias.begin(); it != medias.end(); it++) {
|
||||||
|
cMovieMedia *m = it->second;
|
||||||
|
tell(0, "Media %d", m->mediaType);
|
||||||
|
tell(0, "width %d, height %d", m->width, m->height);
|
||||||
|
tell(0, "Path %s", m->path.c_str());
|
||||||
|
}
|
||||||
|
}
|
98
moviedbmovie.h
Normal file
98
moviedbmovie.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#ifndef __TVSCRAPER_MOVIEDBMOVIE_H
|
||||||
|
#define __TVSCRAPER_MOVIEDBMOVIE_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "services.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
enum mediaMovies {
|
||||||
|
mmPoster,
|
||||||
|
mmFanart,
|
||||||
|
mmCollectionPoster,
|
||||||
|
mmCollectionFanart,
|
||||||
|
mmActorThumb,
|
||||||
|
mmPosterThumb,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- cMovieMedia -------------------------------------------------------------
|
||||||
|
class cMovieMedia {
|
||||||
|
public:
|
||||||
|
cMovieMedia(void) {
|
||||||
|
path = "";
|
||||||
|
mediaType = mmPoster;
|
||||||
|
width = 0;
|
||||||
|
height = 0;
|
||||||
|
};
|
||||||
|
~cMovieMedia(void) {
|
||||||
|
};
|
||||||
|
string path;
|
||||||
|
int mediaType;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- cMovieActor -------------------------------------------------------------
|
||||||
|
class cMovieActor {
|
||||||
|
public:
|
||||||
|
cMovieActor(void) {
|
||||||
|
id = 0;
|
||||||
|
name = "";
|
||||||
|
role = "";
|
||||||
|
actorThumb = NULL;
|
||||||
|
};
|
||||||
|
~cMovieActor(void) {
|
||||||
|
if (actorThumb)
|
||||||
|
delete actorThumb;
|
||||||
|
};
|
||||||
|
int id;
|
||||||
|
string name;
|
||||||
|
string role;
|
||||||
|
cMovieMedia *actorThumb;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- cMovieDbMovie -------------------------------------------------------------
|
||||||
|
|
||||||
|
class cMovieDbMovie {
|
||||||
|
private:
|
||||||
|
map<int, cMovieActor*> actors;
|
||||||
|
map<int, cMovieMedia*> medias;
|
||||||
|
public:
|
||||||
|
cMovieDbMovie(void);
|
||||||
|
virtual ~cMovieDbMovie(void);
|
||||||
|
int id;
|
||||||
|
string title;
|
||||||
|
string originalTitle;
|
||||||
|
string tagline;
|
||||||
|
string overview;
|
||||||
|
bool adult;
|
||||||
|
int collectionID;
|
||||||
|
string collectionName;
|
||||||
|
int budget;
|
||||||
|
int revenue;
|
||||||
|
string genres;
|
||||||
|
string homepage;
|
||||||
|
string imdbid;
|
||||||
|
string releaseDate;
|
||||||
|
int runtime;
|
||||||
|
float popularity;
|
||||||
|
float voteAverage;
|
||||||
|
void InsertActor(cMovieActor *actor);
|
||||||
|
void InsertMedia(cMovieMedia *media);
|
||||||
|
vector<int> GetActorIDs(void);
|
||||||
|
void SetActorThumbSize(int actorId, int imgWidth, int imgHeight);
|
||||||
|
void SetActorPath(int actorId, string path);
|
||||||
|
//Getter for Serivice Calls
|
||||||
|
bool GetMedia(mediaMovies mediatype, cTvMedia *p);
|
||||||
|
void GetActors(vector<cActor> *a);
|
||||||
|
void Dump();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //__TVSCRAPER_TVDBSERIES_H
|
65
po/de_DE.po
Normal file
65
po/de_DE.po
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: vdr-scraper2vdr 0.0.1\n"
|
||||||
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
|
"POT-Creation-Date: 2014-03-30 14:37+0200\n"
|
||||||
|
"PO-Revision-Date: 2014-03-30 18:30+0100\n"
|
||||||
|
"Last-Translator: 3PO\n"
|
||||||
|
"Language-Team: German <vdr@linuxtv.org>\n"
|
||||||
|
"Language: de\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
msgid "Update Scraper Information from Database"
|
||||||
|
msgstr "Filme und Serien aus Datenbank aktualisieren"
|
||||||
|
|
||||||
|
msgid "Update Scraper Recordings Information from Database"
|
||||||
|
msgstr "Aufnahmen aus Datenbank aktualisieren"
|
||||||
|
|
||||||
|
msgid "Scan for new recordings in video directory"
|
||||||
|
msgstr "Videoverzeichnis nach neuen Aufnahmen scannen"
|
||||||
|
|
||||||
|
msgid "Scan for new or updated scrapinfo files"
|
||||||
|
msgstr "Nach neuen oder geänderten scrapinfo Dateien suchen"
|
||||||
|
|
||||||
|
msgid "Cleanup Recordings in Database"
|
||||||
|
msgstr "Aufnahmen in Datenbank bereinigen"
|
||||||
|
|
||||||
|
msgid "Updating Scraper EPG Information from Database"
|
||||||
|
msgstr "Filme und Serien werden aus Datenbank aktualisieren"
|
||||||
|
|
||||||
|
msgid "Updating Scraper Recordings Information from Database"
|
||||||
|
msgstr "Aufnahmen werden aus Datenbank aktualisieren"
|
||||||
|
|
||||||
|
msgid "Scanning for new recordings in video directory"
|
||||||
|
msgstr "Scanne Videoverzeichnis nach neuen Aufnahmen"
|
||||||
|
|
||||||
|
msgid "Scanning for new or updated scrapinfo files"
|
||||||
|
msgstr "Suche nach neuen oder geänderten scrapinfo Dateien"
|
||||||
|
|
||||||
|
msgid "Cleaning up Recordings in Database"
|
||||||
|
msgstr "Bereinige Aufnahmen in Datenbank"
|
||||||
|
|
||||||
|
msgid "Show Main Menu Entry"
|
||||||
|
msgstr "Hauptmenüeintrag anzeigen"
|
||||||
|
|
||||||
|
msgid "MySQL Host"
|
||||||
|
msgstr "MySQL Host"
|
||||||
|
|
||||||
|
msgid "MySQL Port"
|
||||||
|
msgstr "MySQL Port"
|
||||||
|
|
||||||
|
msgid "MySQL Database Name"
|
||||||
|
msgstr "MySQL Datenbannk Name"
|
||||||
|
|
||||||
|
msgid "MySQL User"
|
||||||
|
msgstr "MySQL Benutzer"
|
||||||
|
|
||||||
|
msgid "MySQL Password"
|
||||||
|
msgstr "MySQL Passwort"
|
||||||
|
|
249
scraper2vdr.c
Normal file
249
scraper2vdr.c
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* scraper2vdr.c: A plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scraper2vdr.h"
|
||||||
|
|
||||||
|
#if defined (APIVERSNUM) && (APIVERSNUM < 10600)
|
||||||
|
# error VDR API versions < 1.6.0 are not supported !
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Plugin Main Menu
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cScraper2VdrPluginMenu : public cOsdMenu {
|
||||||
|
public:
|
||||||
|
cScraper2VdrPluginMenu(const char* title, cUpdate *update);
|
||||||
|
virtual ~cScraper2VdrPluginMenu() { };
|
||||||
|
virtual eOSState ProcessKey(eKeys key);
|
||||||
|
protected:
|
||||||
|
cUpdate *update;
|
||||||
|
};
|
||||||
|
|
||||||
|
cScraper2VdrPluginMenu::cScraper2VdrPluginMenu(const char* title, cUpdate *update) : cOsdMenu(title) {
|
||||||
|
this->update = update;
|
||||||
|
Clear();
|
||||||
|
cOsdMenu::Add(new cOsdItem(tr("Update Scraper Information from Database")));
|
||||||
|
cOsdMenu::Add(new cOsdItem(tr("Update Scraper Recordings Information from Database")));
|
||||||
|
cOsdMenu::Add(new cOsdItem(tr("Scan for new recordings in video directory")));
|
||||||
|
cOsdMenu::Add(new cOsdItem(tr("Scan for new or updated scrapinfo files")));
|
||||||
|
cOsdMenu::Add(new cOsdItem(tr("Cleanup Recordings in Database")));
|
||||||
|
SetHelp(0, 0, 0,0);
|
||||||
|
Display();
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Process Key
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
eOSState cScraper2VdrPluginMenu::ProcessKey(eKeys key) {
|
||||||
|
eOSState state = cOsdMenu::ProcessKey(key);
|
||||||
|
|
||||||
|
if (state != osUnknown)
|
||||||
|
return state;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case kOk: {
|
||||||
|
if (Current() == 0) {
|
||||||
|
Skins.Message(mtInfo, tr("Updating Scraper EPG Information from Database"));
|
||||||
|
update->ForceUpdate();
|
||||||
|
} else if (Current() == 1) {
|
||||||
|
Skins.Message(mtInfo, tr("Updating Scraper Recordings Information from Database"));
|
||||||
|
update->ForceRecordingUpdate();
|
||||||
|
} else if (Current() == 2) {
|
||||||
|
Skins.Message(mtInfo, tr("Scanning for new recordings in video directory"));
|
||||||
|
update->ForceVideoDirUpdate();
|
||||||
|
} else if (Current() == 3) {
|
||||||
|
Skins.Message(mtInfo, tr("Scanning for new or updated scrapinfo files"));
|
||||||
|
update->ForceScrapInfoUpdate();
|
||||||
|
} else if (Current() == 4) {
|
||||||
|
Skins.Message(mtInfo, tr("Cleaning up Recordings in Database"));
|
||||||
|
update->TriggerCleanRecordingsDB();
|
||||||
|
}
|
||||||
|
return osEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cPluginScraper2vdr
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
cPluginScraper2vdr::cPluginScraper2vdr(void) {
|
||||||
|
cDbConnection::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
cPluginScraper2vdr::~cPluginScraper2vdr() {
|
||||||
|
delete update;
|
||||||
|
delete scrapManager;
|
||||||
|
cDbConnection::exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cPluginScraper2vdr::CommandLineHelp(void) {
|
||||||
|
return
|
||||||
|
" -i <IMAGEDIR>, --imagedir=<IMAGEDIR> Set directory where images are stored\n"
|
||||||
|
" -m <MODE>, --mode=<MODE> mode can be client or headless, see README\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cPluginScraper2vdr::ProcessArgs(int argc, char *argv[]) {
|
||||||
|
static const struct option long_options[] = {
|
||||||
|
{ "imagedir", required_argument, NULL, 'i' },
|
||||||
|
{ "mode", required_argument, NULL, 'm' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
int c;
|
||||||
|
while ((c = getopt_long(argc, argv, "i:m:", long_options, NULL)) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'i':
|
||||||
|
config.SetImageDir(optarg);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
config.SetMode(optarg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cPluginScraper2vdr::Initialize(void) {
|
||||||
|
config.SetUuid(this);
|
||||||
|
config.SetDefaultImageDir();
|
||||||
|
scrapManager = new cScrapManager();
|
||||||
|
update = new cUpdate(scrapManager);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cPluginScraper2vdr::Start(void) {
|
||||||
|
update->Start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPluginScraper2vdr::Stop(void) {
|
||||||
|
update->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPluginScraper2vdr::Housekeeping(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPluginScraper2vdr::MainThreadHook(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cPluginScraper2vdr::Active(void) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t cPluginScraper2vdr::WakeupTime(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cOsdObject *cPluginScraper2vdr::MainMenuAction(void) {
|
||||||
|
if (config.mainMenuEntry == 1)
|
||||||
|
return new cScraper2VdrPluginMenu("Scraper2Vdr", update);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMenuSetupPage *cPluginScraper2vdr::SetupMenu(void) {
|
||||||
|
return new cScraper2VdrSetup(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cPluginScraper2vdr::SetupParse(const char *Name, const char *Value) {
|
||||||
|
return config.SetupParse(Name, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cPluginScraper2vdr::Service(const char *Id, void *Data) {
|
||||||
|
if (Data == NULL)
|
||||||
|
return false;
|
||||||
|
if (strcmp(Id, "GetEventType") == 0) {
|
||||||
|
ScraperGetEventType* call = (ScraperGetEventType*) Data;
|
||||||
|
if (!call->event && !call->recording)
|
||||||
|
return false;
|
||||||
|
return scrapManager->GetEventType(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(Id, "GetSeries") == 0) {
|
||||||
|
cSeries* call = (cSeries*) Data;
|
||||||
|
if (call->seriesId == 0)
|
||||||
|
return false;
|
||||||
|
return scrapManager->GetSeries(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(Id, "GetMovie") == 0) {
|
||||||
|
cMovie* call = (cMovie*) Data;
|
||||||
|
if (call->movieId == 0)
|
||||||
|
return false;
|
||||||
|
return scrapManager->GetMovie(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(Id, "GetPosterBanner") == 0) {
|
||||||
|
ScraperGetPosterBanner* call = (ScraperGetPosterBanner*) Data;
|
||||||
|
if (!call->event)
|
||||||
|
return false;
|
||||||
|
return scrapManager->GetPosterBanner(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(Id, "GetPoster") == 0) {
|
||||||
|
ScraperGetPoster* call = (ScraperGetPoster*) Data;
|
||||||
|
if (!call->event && !call->recording)
|
||||||
|
return false;
|
||||||
|
return scrapManager->GetPoster(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(Id, "GetPosterThumb") == 0) {
|
||||||
|
ScraperGetPosterThumb* call = (ScraperGetPosterThumb*) Data;
|
||||||
|
if (!call->event && !call->recording)
|
||||||
|
return false;
|
||||||
|
return scrapManager->GetPosterThumb(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char **cPluginScraper2vdr::SVDRPHelpPages(void) {
|
||||||
|
static const char *HelpPages[] = {
|
||||||
|
"UPDT\n"
|
||||||
|
" Load all series and movies for events from database.",
|
||||||
|
"UPDR\n"
|
||||||
|
" Load recordings from database.",
|
||||||
|
"SCVD\n"
|
||||||
|
" Trigger scan fornew recordings in video directory.",
|
||||||
|
"SCSI\n"
|
||||||
|
" Trigger scan for scrapinfo files in video directory.",
|
||||||
|
"CRDB\n"
|
||||||
|
" Trigger cleanup of recordings database.",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
return HelpPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cPluginScraper2vdr::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) {
|
||||||
|
if (strcasecmp(Command, "UPDT") == 0) {
|
||||||
|
update->ForceUpdate();
|
||||||
|
return "SCRAPER2VDR full update from database forced.";
|
||||||
|
} else if (strcasecmp(Command, "UPDR") == 0) {
|
||||||
|
update->ForceRecordingUpdate();
|
||||||
|
return "SCRAPER2VDR scanning of recordings in database triggered.";
|
||||||
|
} else if (strcasecmp(Command, "SCVD") == 0) {
|
||||||
|
update->ForceVideoDirUpdate();
|
||||||
|
return "SCRAPER2VDR scan for new recordings in video dir triggered.";
|
||||||
|
} else if (strcasecmp(Command, "SCSI") == 0) {
|
||||||
|
update->ForceScrapInfoUpdate();
|
||||||
|
return "SCRAPER2VDR scan for new or updated scrapinfo files triggered.";
|
||||||
|
} else if (strcasecmp(Command, "CRDB") == 0) {
|
||||||
|
update->TriggerCleanRecordingsDB();
|
||||||
|
return "SCRAPER2VDR cleanup of recording DB triggered.";
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VDRPLUGINCREATOR(cPluginScraper2vdr); // Don't touch this!
|
57
scraper2vdr.h
Normal file
57
scraper2vdr.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef __SCRAPER2VDR_H
|
||||||
|
#define __SCRAPER2VDR_H
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <vdr/plugin.h>
|
||||||
|
#include "lib/common.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "setup.h"
|
||||||
|
#include "scrapmanager.h"
|
||||||
|
#include "update.h"
|
||||||
|
#include "services.h"
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Constants
|
||||||
|
//***************************************************************************
|
||||||
|
static const char *VERSION = "0.0.1";
|
||||||
|
static const char *DESCRIPTION = "'scraper2vdr' plugin";
|
||||||
|
static const char *MAINMENUENTRY = "Scraper2Vdr";
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// Globals
|
||||||
|
//***************************************************************************
|
||||||
|
cScraper2VdrConfig config;
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
// cPluginScraper2vdr
|
||||||
|
//***************************************************************************
|
||||||
|
|
||||||
|
class cPluginScraper2vdr : public cPlugin {
|
||||||
|
private:
|
||||||
|
cScrapManager *scrapManager;
|
||||||
|
cUpdate *update;
|
||||||
|
public:
|
||||||
|
cPluginScraper2vdr(void);
|
||||||
|
virtual ~cPluginScraper2vdr();
|
||||||
|
virtual const char *Version(void) { return VERSION; }
|
||||||
|
virtual const char *Description(void) { return DESCRIPTION; }
|
||||||
|
virtual const char *CommandLineHelp(void);
|
||||||
|
virtual bool ProcessArgs(int argc, char *argv[]);
|
||||||
|
virtual bool Initialize(void);
|
||||||
|
virtual bool Start(void);
|
||||||
|
virtual void Stop(void);
|
||||||
|
virtual void Housekeeping(void);
|
||||||
|
virtual void MainThreadHook(void);
|
||||||
|
virtual cString Active(void);
|
||||||
|
virtual time_t WakeupTime(void);
|
||||||
|
virtual const char *MainMenuEntry(void) { return (config.mainMenuEntry)?MAINMENUENTRY:NULL; }
|
||||||
|
virtual cOsdObject *MainMenuAction(void);
|
||||||
|
virtual cMenuSetupPage *SetupMenu(void);
|
||||||
|
virtual bool SetupParse(const char *Name, const char *Value);
|
||||||
|
virtual bool Service(const char *Id, void *Data = NULL);
|
||||||
|
virtual const char **SVDRPHelpPages(void);
|
||||||
|
virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
#endif // __SCRAPER2VDR_H
|
503
scrapmanager.c
Normal file
503
scrapmanager.c
Normal file
@ -0,0 +1,503 @@
|
|||||||
|
#define __STL_CONFIG_H
|
||||||
|
#include <vdr/recording.h>
|
||||||
|
#include "tools.h"
|
||||||
|
#include "scrapmanager.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
bool operator<(const sEventsKey& l, const sEventsKey& r) {
|
||||||
|
if (l.eventId != r.eventId)
|
||||||
|
return (l.eventId < r.eventId);
|
||||||
|
int comp = l.channelId.compare(r.channelId);
|
||||||
|
if (comp < 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const sRecordingsKey& l, const sRecordingsKey& r) {
|
||||||
|
if (l.recStart != r.recStart)
|
||||||
|
return (l.recStart < r.recStart);
|
||||||
|
int comp = l.recPath.compare(r.recPath);
|
||||||
|
if (comp < 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cScrapManager::cScrapManager(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cScrapManager::~cScrapManager(void) {
|
||||||
|
for (map<int, cTVDBSeries*>::iterator it = series.begin(); it != series.end(); it++) {
|
||||||
|
cTVDBSeries *s = (cTVDBSeries*)it->second;
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
series.clear();
|
||||||
|
for (map<int, cMovieDbMovie*>::iterator it = movies.begin(); it != movies.end(); it++) {
|
||||||
|
cMovieDbMovie *m = (cMovieDbMovie*)it->second;
|
||||||
|
delete m;
|
||||||
|
}
|
||||||
|
movies.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScrapManager::InitIterator(bool isRec) {
|
||||||
|
if (!isRec)
|
||||||
|
eventsIterator = events.begin();
|
||||||
|
else
|
||||||
|
recIterator = recordings.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
sEventsValue cScrapManager::GetEventInformation(int eventId, string channelId) {
|
||||||
|
sEventsKey k;
|
||||||
|
k.eventId = eventId;
|
||||||
|
k.channelId = channelId;
|
||||||
|
sEventsValue emptyVal;
|
||||||
|
emptyVal.seriesId = 0;
|
||||||
|
emptyVal.episodeId = 0;
|
||||||
|
emptyVal.movieId = 0;
|
||||||
|
emptyVal.isNew = false;
|
||||||
|
map<sEventsKey, sEventsValue>::iterator hit = events.find(k);
|
||||||
|
if (hit != events.end())
|
||||||
|
return hit->second;
|
||||||
|
return emptyVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cScrapManager::AddEvent(int eventId, string channelId, int seriesId, int episodeId, int movieId) {
|
||||||
|
sEventsKey k;
|
||||||
|
k.eventId = eventId;
|
||||||
|
k.channelId = channelId;
|
||||||
|
sEventsValue v;
|
||||||
|
v.seriesId = seriesId;
|
||||||
|
v.episodeId = episodeId;
|
||||||
|
v.movieId = movieId;
|
||||||
|
v.isNew = true;
|
||||||
|
events.insert(pair<sEventsKey, sEventsValue>(k, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetNextSeries(bool isRec, int &seriesId, int &episodeId) {
|
||||||
|
bool next = false;
|
||||||
|
if (!isRec) {
|
||||||
|
while (eventsIterator != events.end()) {
|
||||||
|
next = true;
|
||||||
|
sEventsValue ev = eventsIterator->second;
|
||||||
|
if (ev.isNew && (ev.seriesId > 0)) {
|
||||||
|
seriesId = ev.seriesId;
|
||||||
|
episodeId = ev.episodeId;
|
||||||
|
eventsIterator->second.isNew = false;
|
||||||
|
eventsIterator++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
eventsIterator++;
|
||||||
|
next = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (recIterator != recordings.end()) {
|
||||||
|
next = true;
|
||||||
|
sEventsValue ev = recIterator->second;
|
||||||
|
if (ev.isNew && (ev.seriesId > 0)) {
|
||||||
|
seriesId = ev.seriesId;
|
||||||
|
episodeId = ev.episodeId;
|
||||||
|
recIterator->second.isNew = false;
|
||||||
|
recIterator++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
recIterator++;
|
||||||
|
next = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetNextMovie(bool isRec, int &movieId) {
|
||||||
|
bool next = false;
|
||||||
|
if (!isRec) {
|
||||||
|
while (eventsIterator != events.end()) {
|
||||||
|
next = true;
|
||||||
|
sEventsValue ev = eventsIterator->second;
|
||||||
|
if (ev.isNew && (ev.movieId > 0)) {
|
||||||
|
movieId = ev.movieId;
|
||||||
|
eventsIterator->second.isNew = false;
|
||||||
|
eventsIterator++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
eventsIterator++;
|
||||||
|
next = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (recIterator != recordings.end()) {
|
||||||
|
next = true;
|
||||||
|
sEventsValue ev = recIterator->second;
|
||||||
|
if (ev.isNew && (ev.movieId > 0)) {
|
||||||
|
movieId = ev.movieId;
|
||||||
|
recIterator->second.isNew = false;
|
||||||
|
recIterator++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
recIterator++;
|
||||||
|
next = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTVDBSeries *cScrapManager::GetSeries(int seriesId) {
|
||||||
|
map<int, cTVDBSeries*>::iterator hit = series.find(seriesId);
|
||||||
|
if (hit == series.end())
|
||||||
|
return NULL;
|
||||||
|
return hit->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMovieDbMovie *cScrapManager::GetMovie(int movieId) {
|
||||||
|
map<int, cMovieDbMovie*>::iterator hit = movies.find(movieId);
|
||||||
|
if (hit == movies.end())
|
||||||
|
return NULL;
|
||||||
|
return hit->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTVDBSeries *cScrapManager::AddSeries(cTableSeries* tSeries) {
|
||||||
|
cTVDBSeries *s = new cTVDBSeries();
|
||||||
|
s->id = tSeries->getIntValue(cTableSeries::fiSeriesId);
|
||||||
|
s->name = tSeries->getStrValue(cTableSeries::fiSeriesName);
|
||||||
|
s->overview = tSeries->getStrValue(cTableSeries::fiSeriesOverview);
|
||||||
|
s->firstAired = tSeries->getStrValue(cTableSeries::fiSeriesFirstAired);
|
||||||
|
s->network = tSeries->getStrValue(cTableSeries::fiSeriesNetwork);
|
||||||
|
string genre = replaceString(tSeries->getStrValue(cTableSeries::fiSeriesGenre), "|", ", ");
|
||||||
|
s->genre = genre;
|
||||||
|
s->rating = tSeries->getFloatValue(cTableSeries::fiSeriesRating);
|
||||||
|
s->status = tSeries->getStrValue(cTableSeries::fiSeriesStatus);
|
||||||
|
series.insert(pair<int, cTVDBSeries*>(tSeries->getIntValue(cTableSeries::fiSeriesId), s));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMovieDbMovie *cScrapManager::AddMovie(cTableMovies* tMovies) {
|
||||||
|
cMovieDbMovie *m = new cMovieDbMovie();
|
||||||
|
m->id = tMovies->getIntValue(cTableMovies::fiMovieId);
|
||||||
|
m->title = tMovies->getStrValue(cTableMovies::fiTitle);
|
||||||
|
m->originalTitle = tMovies->getStrValue(cTableMovies::fiOriginalTitle);
|
||||||
|
m->tagline = tMovies->getStrValue(cTableMovies::fiTagline);
|
||||||
|
m->overview = tMovies->getStrValue(cTableMovies::fiOverview);
|
||||||
|
m->adult = tMovies->getIntValue(cTableMovies::fiIsAdult);
|
||||||
|
m->collectionName = tMovies->getStrValue(cTableMovies::fiCollectionName);
|
||||||
|
m->budget = tMovies->getIntValue(cTableMovies::fiBudget);
|
||||||
|
m->revenue = tMovies->getIntValue(cTableMovies::fiRevenue);
|
||||||
|
string genre = replaceString(tMovies->getStrValue(cTableMovies::fiGenres), "|", ",");
|
||||||
|
m->genres = genre;
|
||||||
|
m->homepage = tMovies->getStrValue(cTableMovies::fiHomepage);
|
||||||
|
m->releaseDate = tMovies->getStrValue(cTableMovies::fiReleaaseDate);
|
||||||
|
m->runtime = tMovies->getIntValue(cTableMovies::fiRuntime);
|
||||||
|
m->popularity = tMovies->getFloatValue(cTableMovies::fiPopularity);
|
||||||
|
m->voteAverage = tMovies->getFloatValue(cTableMovies::fiVoteAverage);
|
||||||
|
movies.insert(pair<int, cMovieDbMovie*>(tMovies->getIntValue(cTableMovies::fiMovieId), m));
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScrapManager::AddSeriesEpisode(cTVDBSeries *series, cTableSeriesEpisode* tEpisodes) {
|
||||||
|
cTVDBEpisode *e = new cTVDBEpisode();
|
||||||
|
e->id = tEpisodes->getIntValue(cTableSeriesEpisode::fiEpisodeId);
|
||||||
|
e->name = tEpisodes->getStrValue(cTableSeriesEpisode::fiEpisodeName);
|
||||||
|
e->number = tEpisodes->getIntValue(cTableSeriesEpisode::fiEpisodeNumber);
|
||||||
|
e->season = tEpisodes->getIntValue(cTableSeriesEpisode::fiSeasonNumber);
|
||||||
|
e->overview = tEpisodes->getStrValue(cTableSeriesEpisode::fiEpisodeOverview);
|
||||||
|
e->firstAired = tEpisodes->getStrValue(cTableSeriesEpisode::fiEpisodeFirstAired);
|
||||||
|
string guestStars = replaceString(tEpisodes->getStrValue(cTableSeriesEpisode::fiEpisodeGuestStars), "|", ", ");
|
||||||
|
e->guestStars = guestStars;
|
||||||
|
e->rating = tEpisodes->getFloatValue(cTableSeriesEpisode::fiEpisodeRating);
|
||||||
|
series->InsertEpisode(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScrapManager::AddSeriesActor(cTVDBSeries *series, cTableSeriesActor* tActors) {
|
||||||
|
cTVDBActor *a = new cTVDBActor();
|
||||||
|
a->id = tActors->getIntValue(cTableSeriesActor::fiActorId);
|
||||||
|
a->name = tActors->getStrValue(cTableSeriesActor::fiActorName);
|
||||||
|
a->role = tActors->getStrValue(cTableSeriesActor::fiActorRole);
|
||||||
|
series->InsertActor(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScrapManager::AddMovieMedia(cMovieDbMovie *movie, cTableMovieMedia* tMovieMedia, string path) {
|
||||||
|
cMovieMedia *m = new cMovieMedia();
|
||||||
|
m->mediaType = tMovieMedia->getIntValue(cTableMovieMedia::fiMediaType);
|
||||||
|
m->width = tMovieMedia->getIntValue(cTableMovieMedia::fiMediaWidth);
|
||||||
|
m->height = tMovieMedia->getIntValue(cTableMovieMedia::fiMediaHeight);
|
||||||
|
m->path = path;
|
||||||
|
movie->InsertMedia(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cScrapManager::AddMovieActor(cMovieDbMovie *movie, cTableMovieActor* tActor, string role) {
|
||||||
|
cMovieActor *a = new cMovieActor();
|
||||||
|
a->id = tActor->getIntValue(cTableMovieActor::fiActorId);
|
||||||
|
a->name = tActor->getStrValue(cTableMovieActor::fiActorName);
|
||||||
|
a->role = role;
|
||||||
|
movie->InsertActor(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::AddRecording(int recStart, string recPath, int seriesId, int episodeId, int movieId) {
|
||||||
|
sRecordingsKey k;
|
||||||
|
k.recStart = recStart;
|
||||||
|
k.recPath = recPath;
|
||||||
|
//check if recording already exists
|
||||||
|
map<sRecordingsKey, sEventsValue>::iterator hit = recordings.find(k);
|
||||||
|
if (hit != recordings.end()) {
|
||||||
|
sEventsValue v = hit->second;
|
||||||
|
if ((v.seriesId == seriesId) && (v.episodeId == episodeId) && (v.movieId == movieId))
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
recordings.erase(hit);
|
||||||
|
}
|
||||||
|
sEventsValue v;
|
||||||
|
v.seriesId = seriesId;
|
||||||
|
v.episodeId = episodeId;
|
||||||
|
v.movieId = movieId;
|
||||||
|
v.isNew = true;
|
||||||
|
recordings.insert(pair<sRecordingsKey, sEventsValue>(k, v));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::RecordingExists(int recStart, string recPath) {
|
||||||
|
sRecordingsKey k;
|
||||||
|
k.recStart = recStart;
|
||||||
|
k.recPath = recPath;
|
||||||
|
map<sRecordingsKey, sEventsValue>::iterator hit = recordings.find(k);
|
||||||
|
if (hit != recordings.end())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::SeriesInUse(int seriesId) {
|
||||||
|
map<int, cTVDBSeries*>::iterator hit = series.find(seriesId);
|
||||||
|
if (hit != series.end())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::MovieInUse(int movieId) {
|
||||||
|
map<int, cMovieDbMovie*>::iterator hit = movies.find(movieId);
|
||||||
|
if (hit != movies.end())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScrapManager::DumpSeries(int num) {
|
||||||
|
int i=0;
|
||||||
|
tell(0, "Dumping first %d series", num);
|
||||||
|
for (map<int, cTVDBSeries*>::iterator it = series.begin(); it != series.end(); it++) {
|
||||||
|
cTVDBSeries *s = it->second;
|
||||||
|
s->Dump();
|
||||||
|
if (i == num)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScrapManager::DumpMovies(int num) {
|
||||||
|
int i=0;
|
||||||
|
tell(0, "Dumping first %d movies", num);
|
||||||
|
for (map<int, cMovieDbMovie*>::iterator it = movies.begin(); it != movies.end(); it++) {
|
||||||
|
cMovieDbMovie *m = it->second;
|
||||||
|
m->Dump();
|
||||||
|
if (i == num)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScrapManager::DumpRecordings(int num) {
|
||||||
|
tell(0, "Dumping first %d recordings", num);
|
||||||
|
for (map<sRecordingsKey, sEventsValue>::iterator it = recordings.begin(); it != recordings.end(); it++) {
|
||||||
|
sRecordingsKey key = it->first;
|
||||||
|
sEventsValue val = it->second;
|
||||||
|
tell(0, "recStart %d, recPath %s, seriesId %d, episodeId %d, movieId %d", key.recStart, key.recPath.c_str(), val.seriesId, val.episodeId, val.movieId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetEventType(ScraperGetEventType *call) {
|
||||||
|
sEventsValue v;
|
||||||
|
if (call->event) {
|
||||||
|
sEventsKey k;
|
||||||
|
k.eventId = call->event->EventID();
|
||||||
|
k.channelId = *(call->event->ChannelID().ToString());
|
||||||
|
map<sEventsKey, sEventsValue>::iterator hit = events.find(k);
|
||||||
|
if (hit == events.end())
|
||||||
|
return false;
|
||||||
|
v = hit->second;
|
||||||
|
} else if (call->recording) {
|
||||||
|
sRecordingsKey k;
|
||||||
|
k.recStart = call->recording->Start();
|
||||||
|
k.recPath = call->recording->FileName();
|
||||||
|
map<sRecordingsKey, sEventsValue>::iterator hit = recordings.find(k);
|
||||||
|
if (hit == recordings.end())
|
||||||
|
return false;
|
||||||
|
v = hit->second;
|
||||||
|
}
|
||||||
|
if (v.seriesId > 0) {
|
||||||
|
call->type = tSeries;
|
||||||
|
} else if (v.movieId > 0) {
|
||||||
|
call->type = tMovie;
|
||||||
|
} else {
|
||||||
|
call->type = tNone;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
call->seriesId = v.seriesId;
|
||||||
|
call->episodeId = v.episodeId;
|
||||||
|
call->movieId = v.movieId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetSeries(cSeries *s) {
|
||||||
|
map<int, cTVDBSeries*>::iterator hit = series.find(s->seriesId);
|
||||||
|
if (hit == series.end())
|
||||||
|
return false;
|
||||||
|
cTVDBSeries *sStored = hit->second;
|
||||||
|
s->name = sStored->name;
|
||||||
|
s->overview = sStored->overview;
|
||||||
|
s->firstAired = sStored->firstAired;
|
||||||
|
s->network = sStored->network;
|
||||||
|
s->genre = sStored->genre;
|
||||||
|
s->rating = sStored->rating;
|
||||||
|
s->status = sStored->status;
|
||||||
|
//Episode
|
||||||
|
if (s->episodeId > 0) {
|
||||||
|
sStored->GetEpisode(s->episodeId, &s->episode);
|
||||||
|
sStored->GetSeasonPoster(s->episodeId, &s->seasonPoster);
|
||||||
|
}
|
||||||
|
//Media
|
||||||
|
sStored->GetPosters(&s->posters);
|
||||||
|
sStored->GetBanners(&s->banners);
|
||||||
|
sStored->GetFanart(&s->fanarts);
|
||||||
|
//Actors
|
||||||
|
sStored->GetActors(&s->actors);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetMovie(cMovie *m) {
|
||||||
|
map<int, cMovieDbMovie*>::iterator hit = movies.find(m->movieId);
|
||||||
|
if (hit == movies.end())
|
||||||
|
return false;
|
||||||
|
cMovieDbMovie *mStored = hit->second;
|
||||||
|
m->title = mStored->title;
|
||||||
|
m->originalTitle = mStored->originalTitle;
|
||||||
|
m->tagline = mStored->tagline;
|
||||||
|
m->overview = mStored->overview;
|
||||||
|
m->adult = mStored->adult;
|
||||||
|
m->collectionName = mStored->collectionName;
|
||||||
|
m->budget = mStored->budget;
|
||||||
|
m->revenue = mStored->revenue;
|
||||||
|
m->genres = mStored->genres;
|
||||||
|
m->homepage = mStored->homepage;
|
||||||
|
m->releaseDate = mStored->releaseDate;
|
||||||
|
m->runtime = mStored->runtime;
|
||||||
|
m->popularity = mStored->popularity;
|
||||||
|
m->voteAverage = mStored->voteAverage;
|
||||||
|
//Media
|
||||||
|
mStored->GetMedia(mmPoster, &m->poster);
|
||||||
|
mStored->GetMedia(mmFanart, &m->fanart);
|
||||||
|
mStored->GetMedia(mmCollectionPoster, &m->collectionPoster);
|
||||||
|
mStored->GetMedia(mmCollectionFanart, &m->collectionFanart);
|
||||||
|
//Actors
|
||||||
|
mStored->GetActors(&m->actors);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetPosterBanner(ScraperGetPosterBanner *call) {
|
||||||
|
sEventsKey k;
|
||||||
|
k.eventId = call->event->EventID();
|
||||||
|
k.channelId = *(call->event->ChannelID().ToString());
|
||||||
|
map<sEventsKey, sEventsValue>::iterator hit = events.find(k);
|
||||||
|
if (hit == events.end())
|
||||||
|
return false;
|
||||||
|
sEventsValue v = hit->second;
|
||||||
|
if (v.seriesId > 0) {
|
||||||
|
call->type = tSeries;
|
||||||
|
map<int, cTVDBSeries*>::iterator hitSeries = series.find(v.seriesId);
|
||||||
|
if (hitSeries == series.end())
|
||||||
|
return false;
|
||||||
|
cTVDBSeries *s = hitSeries->second;
|
||||||
|
bool found = s->GetRandomBanner(&call->banner);
|
||||||
|
if (v.episodeId > 0) {
|
||||||
|
s->GetSeasonPoster(v.episodeId, &call->poster);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
} else if (v.movieId > 0) {
|
||||||
|
call->type = tMovie;
|
||||||
|
map<int, cMovieDbMovie*>::iterator hitMovies = movies.find(v.movieId);
|
||||||
|
if (hitMovies == movies.end())
|
||||||
|
return false;
|
||||||
|
cMovieDbMovie *m = hitMovies->second;
|
||||||
|
return m->GetMedia(mmPoster, &call->poster);
|
||||||
|
} else {
|
||||||
|
call->type = tNone;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetPoster(ScraperGetPoster *call) {
|
||||||
|
sEventsValue v;
|
||||||
|
if (call->event) {
|
||||||
|
sEventsKey k;
|
||||||
|
k.eventId = call->event->EventID();
|
||||||
|
k.channelId = *(call->event->ChannelID().ToString());
|
||||||
|
map<sEventsKey, sEventsValue>::iterator hit = events.find(k);
|
||||||
|
if (hit == events.end())
|
||||||
|
return false;
|
||||||
|
v = hit->second;
|
||||||
|
} else if (call->recording) {
|
||||||
|
sRecordingsKey k;
|
||||||
|
k.recStart = call->recording->Start();
|
||||||
|
k.recPath = call->recording->FileName();
|
||||||
|
map<sRecordingsKey, sEventsValue>::iterator hit = recordings.find(k);
|
||||||
|
if (hit == recordings.end())
|
||||||
|
return false;
|
||||||
|
v = hit->second;
|
||||||
|
}
|
||||||
|
if (v.seriesId > 0) {
|
||||||
|
map<int, cTVDBSeries*>::iterator hitSeries = series.find(v.seriesId);
|
||||||
|
if (hitSeries == series.end())
|
||||||
|
return false;
|
||||||
|
cTVDBSeries *s = hitSeries->second;
|
||||||
|
return s->GetPoster(&call->poster);
|
||||||
|
} else if (v.movieId > 0) {
|
||||||
|
map<int, cMovieDbMovie*>::iterator hitMovies = movies.find(v.movieId);
|
||||||
|
if (hitMovies == movies.end())
|
||||||
|
return false;
|
||||||
|
cMovieDbMovie *m = hitMovies->second;
|
||||||
|
return m->GetMedia(mmPoster, &call->poster);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cScrapManager::GetPosterThumb(ScraperGetPosterThumb *call) {
|
||||||
|
sEventsValue v;
|
||||||
|
if (call->event) {
|
||||||
|
sEventsKey k;
|
||||||
|
k.eventId = call->event->EventID();
|
||||||
|
k.channelId = *(call->event->ChannelID().ToString());
|
||||||
|
map<sEventsKey, sEventsValue>::iterator hit = events.find(k);
|
||||||
|
if (hit == events.end())
|
||||||
|
return false;
|
||||||
|
v = hit->second;
|
||||||
|
} else if (call->recording) {
|
||||||
|
sRecordingsKey k;
|
||||||
|
k.recStart = call->recording->Start();
|
||||||
|
k.recPath = call->recording->FileName();
|
||||||
|
map<sRecordingsKey, sEventsValue>::iterator hit = recordings.find(k);
|
||||||
|
if (hit == recordings.end())
|
||||||
|
return false;
|
||||||
|
v = hit->second;
|
||||||
|
}
|
||||||
|
if (v.seriesId > 0) {
|
||||||
|
map<int, cTVDBSeries*>::iterator hitSeries = series.find(v.seriesId);
|
||||||
|
if (hitSeries == series.end())
|
||||||
|
return false;
|
||||||
|
cTVDBSeries *s = hitSeries->second;
|
||||||
|
return s->GetPosterThumb(&call->poster);
|
||||||
|
} else if (v.movieId > 0) {
|
||||||
|
map<int, cMovieDbMovie*>::iterator hitMovies = movies.find(v.movieId);
|
||||||
|
if (hitMovies == movies.end())
|
||||||
|
return false;
|
||||||
|
cMovieDbMovie *m = hitMovies->second;
|
||||||
|
return m->GetMedia(mmPosterThumb, &call->poster);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
81
scrapmanager.h
Normal file
81
scrapmanager.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#ifndef __SCRAPMANAGER_H
|
||||||
|
#define __SCRAPMANAGER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "lib/common.h"
|
||||||
|
#include "lib/db.h"
|
||||||
|
#include "lib/tabledef.h"
|
||||||
|
|
||||||
|
#include "services.h"
|
||||||
|
#include "tvdbseries.h"
|
||||||
|
#include "moviedbmovie.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct sEventsKey {
|
||||||
|
int eventId;
|
||||||
|
string channelId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sEventsValue {
|
||||||
|
int seriesId;
|
||||||
|
int episodeId;
|
||||||
|
int movieId;
|
||||||
|
bool isNew;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sRecordingsKey {
|
||||||
|
int recStart;
|
||||||
|
string recPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cScrapManager {
|
||||||
|
private:
|
||||||
|
map<sEventsKey, sEventsValue> events;
|
||||||
|
map<sEventsKey, sEventsValue>::iterator eventsIterator;
|
||||||
|
map<sRecordingsKey, sEventsValue> recordings;
|
||||||
|
map<sRecordingsKey, sEventsValue>::iterator recIterator;
|
||||||
|
map<int, cTVDBSeries*> series;
|
||||||
|
map<int, cMovieDbMovie*> movies;
|
||||||
|
public:
|
||||||
|
cScrapManager(void);
|
||||||
|
virtual ~cScrapManager(void);
|
||||||
|
//Series and Movies Handling
|
||||||
|
void AddEvent(int eventId, string channelId, int seriesId, int episodeId, int movieId);
|
||||||
|
void InitIterator(bool isRec);
|
||||||
|
int GetNumSeries(void) { return series.size(); };
|
||||||
|
int GetNumMovies(void) { return movies.size(); };
|
||||||
|
sEventsValue GetEventInformation(int eventId, string channelId);
|
||||||
|
bool GetNextSeries(bool isRec, int &seriesId, int &episodeId);
|
||||||
|
bool GetNextMovie(bool isRec, int &movieId);
|
||||||
|
cTVDBSeries *GetSeries(int seriesId);
|
||||||
|
cMovieDbMovie *GetMovie(int movieId);
|
||||||
|
cTVDBSeries *AddSeries(cTableSeries* tSeries);
|
||||||
|
cMovieDbMovie *AddMovie(cTableMovies* tMovies);
|
||||||
|
void AddSeriesEpisode(cTVDBSeries *series, cTableSeriesEpisode* tEpisodes);
|
||||||
|
void AddSeriesActor(cTVDBSeries *series, cTableSeriesActor* tActors);
|
||||||
|
void AddMovieActor(cMovieDbMovie *movie, cTableMovieActor* tActor, string role);
|
||||||
|
void AddMovieMedia(cMovieDbMovie *movie, cTableMovieMedia* tMovieMedia, string path);
|
||||||
|
//Recording Handling
|
||||||
|
bool AddRecording(int recStart, string recPath, int seriesId, int episodeId, int movieId);
|
||||||
|
bool RecordingExists(int recStart, string recPath);
|
||||||
|
bool SeriesInUse(int seriesId);
|
||||||
|
bool MovieInUse(int movieId);
|
||||||
|
//Debug
|
||||||
|
void DumpSeries(int num);
|
||||||
|
void DumpMovies(int num);
|
||||||
|
void DumpRecordings(int num);
|
||||||
|
//Service Calls
|
||||||
|
bool GetEventType(ScraperGetEventType *call);
|
||||||
|
bool GetSeries(cSeries *series);
|
||||||
|
bool GetMovie(cMovie *movie);
|
||||||
|
bool GetPosterBanner(ScraperGetPosterBanner *call);
|
||||||
|
bool GetPoster(ScraperGetPoster *call);
|
||||||
|
bool GetPosterThumb(ScraperGetPosterThumb *call);
|
||||||
|
};
|
||||||
|
#endif //__SCRAPMANAGER_H
|
194
services.h
Normal file
194
services.h
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#ifndef __SCRAPER2VDRSERVICES_H
|
||||||
|
#define __SCRAPER2VDRSERVICES_H
|
||||||
|
|
||||||
|
#include <vdr/epg.h>
|
||||||
|
#include <vdr/recording.h>
|
||||||
|
|
||||||
|
enum tvType {
|
||||||
|
tSeries,
|
||||||
|
tMovie,
|
||||||
|
tNone,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Helper Structures
|
||||||
|
*********************************************************************/
|
||||||
|
class cTvMedia {
|
||||||
|
public:
|
||||||
|
cTvMedia(void) {
|
||||||
|
path = "";
|
||||||
|
width = height = 0;
|
||||||
|
};
|
||||||
|
std::string path;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cEpisode {
|
||||||
|
public:
|
||||||
|
cEpisode(void) {
|
||||||
|
number = 0;
|
||||||
|
season = 0;
|
||||||
|
name = "";
|
||||||
|
firstAired = "";
|
||||||
|
guestStars = "";
|
||||||
|
overview = "";
|
||||||
|
rating = 0.0;
|
||||||
|
};
|
||||||
|
int number;
|
||||||
|
int season;
|
||||||
|
std::string name;
|
||||||
|
std::string firstAired;
|
||||||
|
std::string guestStars;
|
||||||
|
std::string overview;
|
||||||
|
float rating;
|
||||||
|
cTvMedia episodeImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cActor {
|
||||||
|
public:
|
||||||
|
cActor(void) {
|
||||||
|
name = "";
|
||||||
|
role = "";
|
||||||
|
};
|
||||||
|
std::string name;
|
||||||
|
std::string role;
|
||||||
|
cTvMedia actorThumb;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Data Structures for Service Calls
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
// Data structure for service "GetEventType"
|
||||||
|
class ScraperGetEventType {
|
||||||
|
public:
|
||||||
|
ScraperGetEventType(void) {
|
||||||
|
event = NULL;
|
||||||
|
recording = NULL;
|
||||||
|
type = tNone;
|
||||||
|
movieId = 0;
|
||||||
|
seriesId = 0;
|
||||||
|
episodeId = 0;
|
||||||
|
};
|
||||||
|
// in
|
||||||
|
const cEvent *event; // check type for this event
|
||||||
|
const cRecording *recording; // or for this recording
|
||||||
|
//out
|
||||||
|
tvType type; //typeSeries or typeMovie
|
||||||
|
int movieId;
|
||||||
|
int seriesId;
|
||||||
|
int episodeId;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Data structure for full series and episode information
|
||||||
|
class cMovie {
|
||||||
|
public:
|
||||||
|
cMovie(void) {
|
||||||
|
title = "";
|
||||||
|
originalTitle = "";
|
||||||
|
tagline = "";
|
||||||
|
overview = "";
|
||||||
|
adult = false;
|
||||||
|
collectionName = "";
|
||||||
|
budget = 0;
|
||||||
|
revenue = 0;
|
||||||
|
genres = "";
|
||||||
|
homepage = "";
|
||||||
|
releaseDate = "";
|
||||||
|
runtime = 0;
|
||||||
|
popularity = 0.0;
|
||||||
|
voteAverage = 0.0;
|
||||||
|
};
|
||||||
|
//IN
|
||||||
|
int movieId; // movieId fetched from ScraperGetEventType
|
||||||
|
//OUT
|
||||||
|
std::string title;
|
||||||
|
std::string originalTitle;
|
||||||
|
std::string tagline;
|
||||||
|
std::string overview;
|
||||||
|
bool adult;
|
||||||
|
std::string collectionName;
|
||||||
|
int budget;
|
||||||
|
int revenue;
|
||||||
|
std::string genres;
|
||||||
|
std::string homepage;
|
||||||
|
std::string releaseDate;
|
||||||
|
int runtime;
|
||||||
|
float popularity;
|
||||||
|
float voteAverage;
|
||||||
|
cTvMedia poster;
|
||||||
|
cTvMedia fanart;
|
||||||
|
cTvMedia collectionPoster;
|
||||||
|
cTvMedia collectionFanart;
|
||||||
|
std::vector<cActor> actors;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Data structure for full series and episode information
|
||||||
|
class cSeries {
|
||||||
|
public:
|
||||||
|
cSeries(void) {
|
||||||
|
seriesId = 0;
|
||||||
|
episodeId = 0;
|
||||||
|
name = "";
|
||||||
|
overview = "";
|
||||||
|
firstAired = "";
|
||||||
|
network = "";
|
||||||
|
genre = "";
|
||||||
|
rating = 0.0;
|
||||||
|
status = "";
|
||||||
|
};
|
||||||
|
//IN
|
||||||
|
int seriesId; // seriesId fetched from ScraperGetEventType
|
||||||
|
int episodeId; // episodeId fetched from ScraperGetEventType
|
||||||
|
//OUT
|
||||||
|
std::string name;
|
||||||
|
std::string overview;
|
||||||
|
std::string firstAired;
|
||||||
|
std::string network;
|
||||||
|
std::string genre;
|
||||||
|
float rating;
|
||||||
|
std::string status;
|
||||||
|
cEpisode episode;
|
||||||
|
std::vector<cActor> actors;
|
||||||
|
std::vector<cTvMedia> posters;
|
||||||
|
std::vector<cTvMedia> banners;
|
||||||
|
std::vector<cTvMedia> fanarts;
|
||||||
|
cTvMedia seasonPoster;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data structure for service "GetPosterBanner"
|
||||||
|
class ScraperGetPosterBanner {
|
||||||
|
public:
|
||||||
|
ScraperGetPosterBanner(void) {
|
||||||
|
type = tNone;
|
||||||
|
};
|
||||||
|
// in
|
||||||
|
const cEvent *event; // check type for this event
|
||||||
|
//out
|
||||||
|
tvType type; //typeSeries or typeMovie
|
||||||
|
cTvMedia poster;
|
||||||
|
cTvMedia banner;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data structure for service "GetPoster"
|
||||||
|
class ScraperGetPoster {
|
||||||
|
public:
|
||||||
|
// in
|
||||||
|
const cEvent *event; // check type for this event
|
||||||
|
const cRecording *recording; // or for this recording
|
||||||
|
//out
|
||||||
|
cTvMedia poster;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data structure for service "GetPosterThumb"
|
||||||
|
class ScraperGetPosterThumb {
|
||||||
|
public:
|
||||||
|
// in
|
||||||
|
const cEvent *event; // check type for this event
|
||||||
|
const cRecording *recording; // or for this recording
|
||||||
|
//out
|
||||||
|
cTvMedia poster;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__SCRAPER2VDRSERVICES_H
|
78
setup.c
Normal file
78
setup.c
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
extern cScraper2VdrConfig config;
|
||||||
|
|
||||||
|
cScraper2VdrSetup::cScraper2VdrSetup(cUpdate *update) {
|
||||||
|
this->update = update;
|
||||||
|
tmpConfig = config;
|
||||||
|
strn0cpy(host, tmpConfig.mysqlHost.c_str(), sizeof(host));
|
||||||
|
strn0cpy(dbname, tmpConfig.mysqlDBName.c_str(), sizeof(dbname));
|
||||||
|
strn0cpy(user, tmpConfig.mysqlDBUser.c_str(), sizeof(user));
|
||||||
|
strn0cpy(password, tmpConfig.mysqlDBPass.c_str(), sizeof(password));
|
||||||
|
Setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
cScraper2VdrSetup::~cScraper2VdrSetup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cScraper2VdrSetup::Setup(void) {
|
||||||
|
int currentItem = Current();
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
Add(new cMenuEditBoolItem(tr("Show Main Menu Entry"), &tmpConfig.mainMenuEntry));
|
||||||
|
Add(new cMenuEditStrItem(tr("MySQL Host"), host, sizeof(host), tr(FileNameChars)));
|
||||||
|
Add(new cMenuEditIntItem(tr("MySQL Port"), &tmpConfig.mysqlPort, 1, 99999));
|
||||||
|
Add(new cMenuEditStrItem(tr("MySQL Database Name"), dbname, sizeof(dbname), tr(FileNameChars)));
|
||||||
|
Add(new cMenuEditStrItem(tr("MySQL User"), user, sizeof(user), tr(FileNameChars)));
|
||||||
|
Add(new cMenuEditStrItem(tr("MySQL Password"), password, sizeof(password), tr(FileNameChars)));
|
||||||
|
|
||||||
|
Add(new cOsdItem(tr("Update Scraper Information from Database")));
|
||||||
|
Add(new cOsdItem(tr("Update Scraper Recordings Information from Database")));
|
||||||
|
Add(new cOsdItem(tr("Scan for new recordings in video directory")));
|
||||||
|
Add(new cOsdItem(tr("Scan for new or updated scrapinfo files")));
|
||||||
|
Add(new cOsdItem(tr("Cleanup Recordings in Database")));
|
||||||
|
|
||||||
|
SetCurrent(Get(currentItem));
|
||||||
|
Display();
|
||||||
|
}
|
||||||
|
|
||||||
|
eOSState cScraper2VdrSetup::ProcessKey(eKeys Key) {
|
||||||
|
bool hadSubMenu = HasSubMenu();
|
||||||
|
eOSState state = cMenuSetupPage::ProcessKey(Key);
|
||||||
|
if (Key == kOk) {
|
||||||
|
tmpConfig.mysqlHost = host;
|
||||||
|
tmpConfig.mysqlDBName = dbname;
|
||||||
|
tmpConfig.mysqlDBUser = user;
|
||||||
|
tmpConfig.mysqlDBPass = password;
|
||||||
|
Store();
|
||||||
|
if (Current() == 6) {
|
||||||
|
Skins.Message(mtInfo, tr("Updating Scraper EPG Information from Database"));
|
||||||
|
update->ForceUpdate();
|
||||||
|
} else if (Current() == 7) {
|
||||||
|
Skins.Message(mtInfo, tr("Updating Scraper Recordings Information from Database"));
|
||||||
|
update->ForceRecordingUpdate();
|
||||||
|
} else if (Current() == 8) {
|
||||||
|
Skins.Message(mtInfo, tr("Scanning for new recordings in video directory"));
|
||||||
|
update->ForceVideoDirUpdate();
|
||||||
|
} else if (Current() == 9) {
|
||||||
|
Skins.Message(mtInfo, tr("Scanning for new or updated scrapinfo files"));
|
||||||
|
update->ForceScrapInfoUpdate();
|
||||||
|
} else if (Current() == 10) {
|
||||||
|
Skins.Message(mtInfo, tr("Cleaning up Recordings in Database"));
|
||||||
|
update->TriggerCleanRecordingsDB();
|
||||||
|
}
|
||||||
|
return osEnd;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cScraper2VdrSetup::Store(void) {
|
||||||
|
config = tmpConfig;
|
||||||
|
SetupStore("mainMenuEntry", tmpConfig.mainMenuEntry);
|
||||||
|
SetupStore("mysqlHost", tmpConfig.mysqlHost.c_str());
|
||||||
|
SetupStore("mysqlPort", tmpConfig.mysqlPort);
|
||||||
|
SetupStore("mysqlDBName", tmpConfig.mysqlDBName.c_str());
|
||||||
|
SetupStore("mysqlDBUser", tmpConfig.mysqlDBUser.c_str());
|
||||||
|
SetupStore("mysqlDBPass", tmpConfig.mysqlDBPass.c_str());
|
||||||
|
}
|
25
setup.h
Normal file
25
setup.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __SCRAPER2VDR_SETUP_H
|
||||||
|
#define __SCRAPER2VDR_SETUP_H
|
||||||
|
|
||||||
|
#include <vdr/menuitems.h>
|
||||||
|
#include "update.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
class cScraper2VdrSetup : public cMenuSetupPage {
|
||||||
|
public:
|
||||||
|
cScraper2VdrSetup(cUpdate *update);
|
||||||
|
virtual ~cScraper2VdrSetup();
|
||||||
|
private:
|
||||||
|
cUpdate *update;
|
||||||
|
cScraper2VdrConfig tmpConfig;
|
||||||
|
char host[256];
|
||||||
|
char dbname[256];
|
||||||
|
char user[256];
|
||||||
|
char password[256];
|
||||||
|
void Setup(void);
|
||||||
|
protected:
|
||||||
|
virtual eOSState ProcessKey(eKeys Key);
|
||||||
|
virtual void Store(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif //__SCRAPER2VDR_SETUP_H
|
170
tools.c
Normal file
170
tools.c
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/vfs.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <cctype>
|
||||||
|
#include <locale>
|
||||||
|
#include <Magick++.h>
|
||||||
|
#include <vdr/plugin.h>
|
||||||
|
#include "lib/common.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace Magick;
|
||||||
|
|
||||||
|
bool CreateDirectory(string dir) {
|
||||||
|
mkdir(dir.c_str(), 0775);
|
||||||
|
//check if successfull
|
||||||
|
DIR *pDir;
|
||||||
|
bool exists = false;
|
||||||
|
pDir = opendir(dir.c_str());
|
||||||
|
if (pDir != NULL) {
|
||||||
|
exists = true;
|
||||||
|
closedir(pDir);
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileExists(string filename, bool isImage) {
|
||||||
|
ifstream ifile(filename.c_str());
|
||||||
|
if (ifile) {
|
||||||
|
//a valid image should be larger then 500 bytes
|
||||||
|
ifile.seekg (0, ifile.end);
|
||||||
|
int length = ifile.tellg();
|
||||||
|
int minimumLength = isImage ? 500 : 1;
|
||||||
|
if (length > minimumLength)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckDirExists(const char* dirName) {
|
||||||
|
struct statfs statfsbuf;
|
||||||
|
if (statfs(dirName,&statfsbuf)==-1) return false;
|
||||||
|
if ((statfsbuf.f_type!=0x01021994) && (statfsbuf.f_type!=0x28cd3d45)) return false;
|
||||||
|
if (access(dirName,R_OK|W_OK)==-1) return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteFile(string filename) {
|
||||||
|
remove(filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteDirectory(string dirname) {
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
if ((dir = opendir (dirname.c_str())) != NULL) {
|
||||||
|
while ((entry = readdir (dir)) != NULL) {
|
||||||
|
string file = entry->d_name;
|
||||||
|
if (!file.compare("."))
|
||||||
|
continue;
|
||||||
|
if (!file.compare(".."))
|
||||||
|
continue;
|
||||||
|
string delFile = dirname + "/" + file;
|
||||||
|
DeleteFile(delFile);
|
||||||
|
}
|
||||||
|
closedir (dir);
|
||||||
|
}
|
||||||
|
rmdir(dirname.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
string TwoFoldersHigher(string folder) {
|
||||||
|
unsigned found = folder.find_last_of("/");
|
||||||
|
if (found != string::npos) {
|
||||||
|
string firstDirRemoved = folder.substr(0,found);
|
||||||
|
unsigned found2 = firstDirRemoved.find_last_of("/");
|
||||||
|
if (found2 != string::npos) {
|
||||||
|
return firstDirRemoved.substr(0,found2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// trim from start
|
||||||
|
string <rim(string &s) {
|
||||||
|
s.erase(s.begin(), find_if(s.begin(), s.end(), not1(ptr_fun<int, int>(isspace))));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from end
|
||||||
|
string &rtrim(string &s) {
|
||||||
|
s.erase(find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(), s.end());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim from both ends
|
||||||
|
string &trim(string &s) {
|
||||||
|
return ltrim(rtrim(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void toLower(string &s) {
|
||||||
|
transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNumber(const string& s) {
|
||||||
|
string::const_iterator it = s.begin();
|
||||||
|
while (it != s.end() && isdigit(*it)) ++it;
|
||||||
|
return !s.empty() && it == s.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
string replaceString(string content, string search, string repl) {
|
||||||
|
size_t pos = 0;
|
||||||
|
while((pos = content.find(search, pos)) != std::string::npos) {
|
||||||
|
if (pos > 3 && pos < content.size() - 2) {
|
||||||
|
content.replace(pos, search.length(), repl);
|
||||||
|
} else {
|
||||||
|
content.replace(pos, search.length(), "");
|
||||||
|
}
|
||||||
|
pos += repl.length();
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* SPLTSTRING
|
||||||
|
****************************************************************************************/
|
||||||
|
// split: receives a char delimiter; returns a vector of strings
|
||||||
|
// By default ignores repeated delimiters, unless argument rep == 1.
|
||||||
|
vector<string>& splitstring::split(char delim, int rep) {
|
||||||
|
if (!flds.empty()) flds.clear(); // empty vector if necessary
|
||||||
|
string work = data();
|
||||||
|
string buf = "";
|
||||||
|
int i = 0;
|
||||||
|
while (i < work.length()) {
|
||||||
|
if (work[i] != delim)
|
||||||
|
buf += work[i];
|
||||||
|
else if (rep == 1) {
|
||||||
|
flds.push_back(buf);
|
||||||
|
buf = "";
|
||||||
|
} else if (buf.length() > 0) {
|
||||||
|
flds.push_back(buf);
|
||||||
|
buf = "";
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (!buf.empty())
|
||||||
|
flds.push_back(buf);
|
||||||
|
return flds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateThumbnail(string sourcePath, string destPath, int origWidth, int origHeight, int shrinkFactor) {
|
||||||
|
if (sourcePath.size() < 5 || destPath.size() < 5 || shrinkFactor < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int thumbWidth = origWidth / shrinkFactor;
|
||||||
|
int thumbHeight = origHeight / shrinkFactor;
|
||||||
|
|
||||||
|
InitializeMagick(NULL);
|
||||||
|
Image buffer;
|
||||||
|
try {
|
||||||
|
buffer.read(sourcePath.c_str());
|
||||||
|
buffer.sample(Geometry(thumbWidth, thumbHeight));
|
||||||
|
buffer.write(destPath.c_str());
|
||||||
|
} catch( ... ) {}
|
||||||
|
}
|
30
tools.h
Normal file
30
tools.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
//Filesystem Functions
|
||||||
|
bool CreateDirectory(string dir);
|
||||||
|
bool FileExists(string filename, bool isImage = true);
|
||||||
|
bool CheckDirExists(const char* dirName);
|
||||||
|
void DeleteFile(string filename);
|
||||||
|
void DeleteDirectory(string dirname);
|
||||||
|
string TwoFoldersHigher(string folder);
|
||||||
|
|
||||||
|
//String Functions
|
||||||
|
string <rim(string &s);
|
||||||
|
string &rtrim(string &s);
|
||||||
|
string &trim(string &s);
|
||||||
|
void toLower(string &s);
|
||||||
|
bool isNumber(const string& s);
|
||||||
|
string replaceString(string content, string search, string repl);
|
||||||
|
|
||||||
|
class splitstring : public string {
|
||||||
|
vector<string> flds;
|
||||||
|
public:
|
||||||
|
splitstring(const char *s) : string(s) { };
|
||||||
|
vector<string>& split(char delim, int rep=0);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Image Functions
|
||||||
|
void CreateThumbnail(string sourcePath, string destPath, int origWidth, int origHeight, int shrinkFactor);
|
289
tvdbseries.c
Normal file
289
tvdbseries.c
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
#define __STL_CONFIG_H
|
||||||
|
#include "lib/common.h"
|
||||||
|
#include "tvdbseries.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
cTVDBSeries::cTVDBSeries(void) {
|
||||||
|
id = 0;
|
||||||
|
name = "";
|
||||||
|
overview = "";
|
||||||
|
firstAired = "";
|
||||||
|
network = "";
|
||||||
|
genre = "";
|
||||||
|
rating = 0.0;
|
||||||
|
status = "";
|
||||||
|
posterThumb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTVDBSeries::~cTVDBSeries() {
|
||||||
|
for (map<int, cTVDBActor*>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
cTVDBActor *a = (cTVDBActor*)it->second;
|
||||||
|
delete a;
|
||||||
|
}
|
||||||
|
for (map<int, cTVDBEpisode*>::iterator it = episodes.begin(); it != episodes.end(); it++) {
|
||||||
|
cTVDBEpisode *e = (cTVDBEpisode*)it->second;
|
||||||
|
delete e;
|
||||||
|
}
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = posters.begin(); it != posters.end(); it++) {
|
||||||
|
cTVDBMedia *p = *it;
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = banners.begin(); it != banners.end(); it++) {
|
||||||
|
cTVDBMedia *b = *it;
|
||||||
|
delete b;
|
||||||
|
}
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = fanart.begin(); it != fanart.end(); it++) {
|
||||||
|
cTVDBMedia *f = *it;
|
||||||
|
delete f;
|
||||||
|
}
|
||||||
|
for (map<int, cTVDBMedia*>::iterator it = seasonPosters.begin(); it != seasonPosters.end(); it++) {
|
||||||
|
cTVDBMedia *s = (cTVDBMedia*)it->second;
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
for (map<int, cTVDBMedia*>::iterator it = seasonPosterThumbs.begin(); it != seasonPosterThumbs.end(); it++) {
|
||||||
|
cTVDBMedia *s = (cTVDBMedia*)it->second;
|
||||||
|
delete s;
|
||||||
|
}
|
||||||
|
if (posterThumb)
|
||||||
|
delete posterThumb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::InsertEpisode(cTVDBEpisode *episode) {
|
||||||
|
map<int, cTVDBEpisode*>::iterator hit = episodes.find(episode->id);
|
||||||
|
if (hit != episodes.end())
|
||||||
|
delete episode;
|
||||||
|
else
|
||||||
|
episodes.insert(pair<int, cTVDBEpisode*>(episode->id, episode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::InsertEpisodeImage(int episodeId, int width, int height, string path) {
|
||||||
|
map<int, cTVDBEpisode*>::iterator hit = episodes.find(episodeId);
|
||||||
|
if (hit != episodes.end()) {
|
||||||
|
cTVDBEpisode *e = hit->second;
|
||||||
|
cTVDBMedia *m = new cTVDBMedia();
|
||||||
|
m->width = width;
|
||||||
|
m->height = height;
|
||||||
|
m->path = path;
|
||||||
|
m->mediaType = msEpisodePic;
|
||||||
|
e->episodeImage = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::InsertActor(cTVDBActor *actor) {
|
||||||
|
actors.insert(pair<int, cTVDBActor*>(actor->id, actor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::InsertActorThumb(int actorId, int imgWidth, int imgHeight, string path) {
|
||||||
|
map<int, cTVDBActor*>::iterator hit = actors.find(actorId);
|
||||||
|
if (hit != actors.end()) {
|
||||||
|
cTVDBActor *a = hit->second;
|
||||||
|
cTVDBMedia *m = new cTVDBMedia();
|
||||||
|
m->width = imgWidth;
|
||||||
|
m->height = imgHeight;
|
||||||
|
m->path = path;
|
||||||
|
m->mediaType = msActorThumb;
|
||||||
|
a->actorThumb = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::InsertMedia(int mediaType, int imgWidth, int imgHeight, string path, int season) {
|
||||||
|
cTVDBMedia *media = new cTVDBMedia();
|
||||||
|
media->width = imgWidth;
|
||||||
|
media->height = imgHeight;
|
||||||
|
media->path = path;
|
||||||
|
media->mediaType = mediaType;
|
||||||
|
switch (mediaType) {
|
||||||
|
case msPoster1:
|
||||||
|
case msPoster2:
|
||||||
|
case msPoster3:
|
||||||
|
posters.push_back(media);
|
||||||
|
break;
|
||||||
|
case msFanart1:
|
||||||
|
case msFanart2:
|
||||||
|
case msFanart3:
|
||||||
|
fanart.push_back(media);
|
||||||
|
break;
|
||||||
|
case msBanner1:
|
||||||
|
case msBanner2:
|
||||||
|
case msBanner3:
|
||||||
|
banners.push_back(media);
|
||||||
|
case msSeasonPoster:
|
||||||
|
seasonPosters.insert(pair<int, cTVDBMedia*>(season, media));
|
||||||
|
break;
|
||||||
|
case msPosterThumb:
|
||||||
|
posterThumb = media;
|
||||||
|
break;
|
||||||
|
case msSeasonPosterThumb:
|
||||||
|
seasonPosterThumbs.insert(pair<int, cTVDBMedia*>(season, media));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::GetEpisode(int episodeId, cEpisode *e) {
|
||||||
|
map<int, cTVDBEpisode*>::iterator hit = episodes.find(episodeId);
|
||||||
|
if (hit == episodes.end())
|
||||||
|
return;
|
||||||
|
cTVDBEpisode *eStored = hit->second;
|
||||||
|
e->number = eStored->number;
|
||||||
|
e->season = eStored->season;
|
||||||
|
e->name = eStored->name;
|
||||||
|
e->firstAired = eStored->firstAired;
|
||||||
|
e->guestStars = eStored->guestStars;
|
||||||
|
e->overview = eStored->overview;
|
||||||
|
e->rating = eStored->rating;
|
||||||
|
if (eStored->episodeImage) {
|
||||||
|
e->episodeImage.path = eStored->episodeImage->path;
|
||||||
|
e->episodeImage.width = eStored->episodeImage->width;
|
||||||
|
e->episodeImage.height = eStored->episodeImage->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::GetPosters(vector<cTvMedia> *p) {
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = posters.begin(); it != posters.end(); it++) {
|
||||||
|
cTVDBMedia *mStored = *it;
|
||||||
|
cTvMedia m;
|
||||||
|
m.path = mStored->path;
|
||||||
|
m.width = mStored->width;
|
||||||
|
m.height = mStored->height;
|
||||||
|
p->push_back(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTVDBSeries::GetPoster(cTvMedia *p) {
|
||||||
|
if (posters.size() > 0) {
|
||||||
|
p->path = posters[0]->path;
|
||||||
|
p->width = posters[0]->width;
|
||||||
|
p->height = posters[0]->height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTVDBSeries::GetPosterThumb(cTvMedia *p) {
|
||||||
|
if (posterThumb) {
|
||||||
|
p->path = posterThumb->path;
|
||||||
|
p->width = posterThumb->width;
|
||||||
|
p->height = posterThumb->height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::GetBanners(vector<cTvMedia> *b) {
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = banners.begin(); it != banners.end(); it++) {
|
||||||
|
cTVDBMedia *bStored = *it;
|
||||||
|
cTvMedia m;
|
||||||
|
m.path = bStored->path;
|
||||||
|
m.width = bStored->width;
|
||||||
|
m.height = bStored->height;
|
||||||
|
b->push_back(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTVDBSeries::GetRandomBanner(cTvMedia *b) {
|
||||||
|
int numBanners = banners.size();
|
||||||
|
if (numBanners == 0)
|
||||||
|
return false;
|
||||||
|
srand((unsigned)time(NULL));
|
||||||
|
int banner = rand()%numBanners;
|
||||||
|
cTVDBMedia *bStored = banners[banner];
|
||||||
|
b->path = bStored->path;
|
||||||
|
b->width = bStored->width;
|
||||||
|
b->height = bStored->height;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::GetFanart(vector<cTvMedia> *f) {
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = fanart.begin(); it != fanart.end(); it++) {
|
||||||
|
cTVDBMedia *fStored = *it;
|
||||||
|
cTvMedia m;
|
||||||
|
m.path = fStored->path;
|
||||||
|
m.width = fStored->width;
|
||||||
|
m.height = fStored->height;
|
||||||
|
f->push_back(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::GetSeasonPoster(int episodeId, cTvMedia *sp) {
|
||||||
|
map<int, cTVDBEpisode*>::iterator hit = episodes.find(episodeId);
|
||||||
|
if (hit == episodes.end())
|
||||||
|
return;
|
||||||
|
cTVDBEpisode *e = hit->second;
|
||||||
|
map<int, cTVDBMedia*>::iterator hit2 = seasonPosters.find(e->season);
|
||||||
|
if (hit2 == seasonPosters.end())
|
||||||
|
return;
|
||||||
|
cTVDBMedia *spStored = hit2->second;
|
||||||
|
sp->width = spStored->width;
|
||||||
|
sp->height = spStored->height;
|
||||||
|
sp->path = spStored->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::GetActors(vector<cActor> *a) {
|
||||||
|
for (map<int, cTVDBActor*>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
cTVDBActor *aStored = it->second;
|
||||||
|
cActor act;
|
||||||
|
act.name = aStored->name;
|
||||||
|
act.role = aStored->role;
|
||||||
|
if (aStored->actorThumb) {
|
||||||
|
act.actorThumb.width = aStored->actorThumb->width;
|
||||||
|
act.actorThumb.height = aStored->actorThumb->height;
|
||||||
|
act.actorThumb.path = aStored->actorThumb->path;
|
||||||
|
}
|
||||||
|
a->push_back(act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTVDBSeries::Dump(void) {
|
||||||
|
tell(0, "--------------------------- Series Info ----------------------------------");
|
||||||
|
tell(0, "series %s, ID: %d", name.c_str(), id);
|
||||||
|
tell(0, "Overview: %s", overview.c_str());
|
||||||
|
tell(0, "FirstAired: %s", firstAired.c_str());
|
||||||
|
tell(0, "Network: %s", network.c_str());
|
||||||
|
tell(0, "Status: %s", status.c_str());
|
||||||
|
tell(0, "Genre: %s", genre.c_str());
|
||||||
|
tell(0, "Rating: %f", rating);
|
||||||
|
tell(0, "--------------------------- Media ----------------------------------");
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = posters.begin(); it != posters.end(); it++) {
|
||||||
|
cTVDBMedia *m = *it;
|
||||||
|
tell(0, "Poster %d, Path: %s", m->mediaType, m->path.c_str());
|
||||||
|
tell(0, "width %d, height %d", m->width, m->height);
|
||||||
|
}
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = banners.begin(); it != banners.end(); it++) {
|
||||||
|
cTVDBMedia *m = *it;
|
||||||
|
tell(0, "Banner %d, Path: %s", m->mediaType, m->path.c_str());
|
||||||
|
tell(0, "width %d, height %d", m->width, m->height);
|
||||||
|
}
|
||||||
|
for (vector<cTVDBMedia*>::iterator it = fanart.begin(); it != fanart.end(); it++) {
|
||||||
|
cTVDBMedia *m = *it;
|
||||||
|
tell(0, "Fanart %d, Path: %s", m->mediaType, m->path.c_str());
|
||||||
|
tell(0, "width %d, height %d", m->width, m->height);
|
||||||
|
}
|
||||||
|
tell(0, "--------------------------- Episodes ----------------------------------");
|
||||||
|
for (map<int, cTVDBEpisode*>::iterator it = episodes.begin(); it != episodes.end(); it++) {
|
||||||
|
cTVDBEpisode *e = it->second;
|
||||||
|
tell(0, "Episode %d, Name: %s", e->id, e->name.c_str());
|
||||||
|
if (e->episodeImage) {
|
||||||
|
tell(0, "Episode Image: %d x %d, Path: %s", e->episodeImage->width, e->episodeImage->height, e->episodeImage->path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tell(0, "--------------------------- Season Posters ----------------------------------");
|
||||||
|
for (map<int, cTVDBMedia*>::iterator it = seasonPosters.begin(); it != seasonPosters.end(); it++) {
|
||||||
|
int season = it->first;
|
||||||
|
cTVDBMedia *m = it->second;
|
||||||
|
tell(0, "Season %d, %d x %d, Path: %s", season, m->width, m->height, m->path.c_str());
|
||||||
|
}
|
||||||
|
tell(0, "--------------------------- Actors ----------------------------------");
|
||||||
|
for (map<int, cTVDBActor*>::iterator it = actors.begin(); it != actors.end(); it++) {
|
||||||
|
cTVDBActor *a = it->second;
|
||||||
|
tell(0, "Actor %d, Name: %s, Role %s", a->id, a->name.c_str(), a->role.c_str());
|
||||||
|
if (a->actorThumb) {
|
||||||
|
tell(0, "Thumb: %d x %d, Path: %s", a->actorThumb->width, a->actorThumb->height, a->actorThumb->path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (posterThumb) {
|
||||||
|
tell(0, "posterThumb path %s, width %d, height %d", posterThumb->path.c_str(), posterThumb->width, posterThumb->height);
|
||||||
|
}
|
||||||
|
}
|
143
tvdbseries.h
Normal file
143
tvdbseries.h
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#ifndef __TVSCRAPER_TVDBSERIES_H
|
||||||
|
#define __TVSCRAPER_TVDBSERIES_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "services.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
enum mediaSeries {
|
||||||
|
msBanner1,
|
||||||
|
msBanner2,
|
||||||
|
msBanner3,
|
||||||
|
msPoster1,
|
||||||
|
msPoster2,
|
||||||
|
msPoster3,
|
||||||
|
msSeasonPoster,
|
||||||
|
msFanart1,
|
||||||
|
msFanart2,
|
||||||
|
msFanart3,
|
||||||
|
msEpisodePic,
|
||||||
|
msActorThumb,
|
||||||
|
msPosterThumb,
|
||||||
|
msSeasonPosterThumb,
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- cTVDBMedia -------------------------------------------------------------
|
||||||
|
class cTVDBMedia {
|
||||||
|
public:
|
||||||
|
cTVDBMedia(void) {
|
||||||
|
path = "";
|
||||||
|
mediaType = msBanner1;
|
||||||
|
width = 0;
|
||||||
|
height = 0;
|
||||||
|
};
|
||||||
|
~cTVDBMedia(void) {
|
||||||
|
};
|
||||||
|
string path;
|
||||||
|
int mediaType;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- cTVDBEpisode -------------------------------------------------------------
|
||||||
|
class cTVDBEpisode {
|
||||||
|
public:
|
||||||
|
cTVDBEpisode(void) {
|
||||||
|
id = 0;
|
||||||
|
number = 0;
|
||||||
|
season = 0;
|
||||||
|
name = "";
|
||||||
|
firstAired = "";
|
||||||
|
guestStars = "";
|
||||||
|
overview = "";
|
||||||
|
rating = 0.0;
|
||||||
|
episodeImage = NULL;
|
||||||
|
};
|
||||||
|
~cTVDBEpisode(void) {
|
||||||
|
if (episodeImage)
|
||||||
|
delete episodeImage;
|
||||||
|
};
|
||||||
|
int id;
|
||||||
|
int number;
|
||||||
|
int season;
|
||||||
|
string name;
|
||||||
|
string firstAired;
|
||||||
|
string guestStars;
|
||||||
|
string overview;
|
||||||
|
float rating;
|
||||||
|
cTVDBMedia *episodeImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- cTVDBActor -------------------------------------------------------------
|
||||||
|
class cTVDBActor {
|
||||||
|
public:
|
||||||
|
cTVDBActor(void) {
|
||||||
|
id = 0;
|
||||||
|
name = "";
|
||||||
|
role = "";
|
||||||
|
thumbWidth = 0;
|
||||||
|
thumbHeight = 0;
|
||||||
|
actorThumb = NULL;
|
||||||
|
};
|
||||||
|
~cTVDBActor(void) {
|
||||||
|
if (actorThumb)
|
||||||
|
delete actorThumb;
|
||||||
|
};
|
||||||
|
int id;
|
||||||
|
string name;
|
||||||
|
string role;
|
||||||
|
int thumbWidth;
|
||||||
|
int thumbHeight;
|
||||||
|
cTVDBMedia *actorThumb;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- cTVDBSeries -------------------------------------------------------------
|
||||||
|
|
||||||
|
class cTVDBSeries {
|
||||||
|
private:
|
||||||
|
map<int, cTVDBEpisode*> episodes;
|
||||||
|
map<int, cTVDBActor*> actors;
|
||||||
|
vector<cTVDBMedia*> posters;
|
||||||
|
vector<cTVDBMedia*> banners;
|
||||||
|
vector<cTVDBMedia*> fanart;
|
||||||
|
map<int, cTVDBMedia*> seasonPosters;
|
||||||
|
map<int, cTVDBMedia*> seasonPosterThumbs;
|
||||||
|
cTVDBMedia *posterThumb;
|
||||||
|
public:
|
||||||
|
cTVDBSeries(void);
|
||||||
|
virtual ~cTVDBSeries(void);
|
||||||
|
int id;
|
||||||
|
string name;
|
||||||
|
string overview;
|
||||||
|
string firstAired;
|
||||||
|
string network;
|
||||||
|
string genre;
|
||||||
|
float rating;
|
||||||
|
string status;
|
||||||
|
void InsertEpisode(cTVDBEpisode *episode);
|
||||||
|
void InsertEpisodeImage(int episodeId, int width, int height, string path);
|
||||||
|
void InsertActor(cTVDBActor *actor);
|
||||||
|
void InsertActorThumb(int actorId, int imgWidth, int imgHeight, string path);
|
||||||
|
void InsertMedia(int mediaType, int imgWidth, int imgHeight, string path, int season = 0);
|
||||||
|
//Getter for Serivice Calls
|
||||||
|
void GetEpisode(int episodeId, cEpisode *e);
|
||||||
|
void GetPosters(vector<cTvMedia> *p);
|
||||||
|
bool GetPoster(cTvMedia *p);
|
||||||
|
bool GetPosterThumb(cTvMedia *p);
|
||||||
|
void GetBanners(vector<cTvMedia> *b);
|
||||||
|
bool GetRandomBanner(cTvMedia *b);
|
||||||
|
void GetFanart(vector<cTvMedia> *f);
|
||||||
|
void GetSeasonPoster(int episodeId, cTvMedia *sp);
|
||||||
|
void GetActors(vector<cActor> *a);
|
||||||
|
void Dump(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //__TVSCRAPER_TVDBSERIES_H
|
87
update.h
Normal file
87
update.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#ifndef __UPDATE_H
|
||||||
|
#define __UPDATE_H
|
||||||
|
|
||||||
|
#include <mysql/mysql.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <vdr/thread.h>
|
||||||
|
#include "lib/common.h"
|
||||||
|
#include "lib/db.h"
|
||||||
|
#include "lib/tabledef.h"
|
||||||
|
#include "scrapmanager.h"
|
||||||
|
|
||||||
|
#define EPGDNAME "epgd"
|
||||||
|
|
||||||
|
class cUpdate : public cThread {
|
||||||
|
private:
|
||||||
|
cScrapManager *scrapManager;
|
||||||
|
string imgPathSeries;
|
||||||
|
string imgPathMovies;
|
||||||
|
bool withutf8;
|
||||||
|
bool loopActive;
|
||||||
|
cDbConnection* connection;
|
||||||
|
cTableVdrs* vdrDb;
|
||||||
|
cTableEvents* tEvents;
|
||||||
|
cTableSeries* tSeries;
|
||||||
|
cTableSeriesEpisode* tEpisodes;
|
||||||
|
cTableSeriesMedia* tSeriesMedia;
|
||||||
|
cTableSeriesActor* tSeriesActors;
|
||||||
|
cTableMovies* tMovies;
|
||||||
|
cTableMovieActor* tMovieActor;
|
||||||
|
cTableMovieActors* tMovieActors;
|
||||||
|
cTableMovieMedia* tMovieMedia;
|
||||||
|
cTableRecordings* tRecordings;
|
||||||
|
int lastScrap;
|
||||||
|
cCondVar waitCondition;
|
||||||
|
cMutex mutex;
|
||||||
|
bool forceUpdate;
|
||||||
|
bool forceRecordingUpdate;
|
||||||
|
bool forceVideoDirUpdate;
|
||||||
|
bool forceScrapInfoUpdate;
|
||||||
|
bool forceCleanupRecordingDb;
|
||||||
|
int exitDb();
|
||||||
|
int dbConnected(int force = no) { return connection && (!force || connection->check() == success); };
|
||||||
|
int CheckConnection(int& timeout);
|
||||||
|
bool CheckEpgdBusy(void);
|
||||||
|
void Action(void);
|
||||||
|
int ReadScrapedEvents(void);
|
||||||
|
//SERIES
|
||||||
|
int ReadSeries(bool isRec);
|
||||||
|
void ReadEpisode(int episodeId, cTVDBSeries *series, string path);
|
||||||
|
void LoadEpisodeImage(cTVDBSeries *series, int episodeId, string path);
|
||||||
|
void LoadSeasonPoster(cTVDBSeries *series, int season, string path);
|
||||||
|
void ReadSeriesActors(cTVDBSeries *series, string path);
|
||||||
|
void LoadSeriesMedia(cTVDBSeries *series, string path);
|
||||||
|
string LoadMediaSeries(int seriesId, int mediaType, string path, int width, int height);
|
||||||
|
void LoadSeriesActorThumb(cTVDBSeries *series, int actorId, string path);
|
||||||
|
//MOVIES
|
||||||
|
int ReadMovies(bool isRec);
|
||||||
|
void ReadMovieActors(cMovieDbMovie *movie);
|
||||||
|
void LoadMovieActorThumbs(cMovieDbMovie *movie);
|
||||||
|
void LoadMovieMedia(cMovieDbMovie *movie, string moviePath);
|
||||||
|
string LoadMediaMovie(int movieId, int mediaType, string path, int width, int height);
|
||||||
|
//RECORDINGS
|
||||||
|
int ReadRecordings(void);
|
||||||
|
int ScanVideoDir(void);
|
||||||
|
int ScanVideoDirScrapInfo(void);
|
||||||
|
bool LoadRecording(int eventId, string recName);
|
||||||
|
bool ScrapInfoChanged(int scrapInfoMovieID, int scrapInfoSeriesID, int scrapInfoEpisodeID);
|
||||||
|
void ReadScrapInfo(string recDir, int &scrapInfoMovieID, int &scrapInfoSeriesID, int &scrapInfoEpisodeID);
|
||||||
|
//CLEANUP
|
||||||
|
int CleanupSeries(void);
|
||||||
|
int CleanupMovies(void);
|
||||||
|
int CleanupRecordings(void);
|
||||||
|
public:
|
||||||
|
cUpdate(cScrapManager *manager);
|
||||||
|
virtual ~cUpdate(void);
|
||||||
|
int initDb();
|
||||||
|
void Stop(void);
|
||||||
|
void ForceUpdate(void);
|
||||||
|
void ForceRecordingUpdate(void);
|
||||||
|
void ForceVideoDirUpdate(void);
|
||||||
|
void ForceScrapInfoUpdate(void);
|
||||||
|
void TriggerCleanRecordingsDB(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
//***************************************************************************
|
||||||
|
#endif //__UPDATE_H
|
Loading…
Reference in New Issue
Block a user