diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT new file mode 100644 index 0000000..4d0dc3d --- /dev/null +++ b/CHANGELOG.TXT @@ -0,0 +1,170 @@ +Build 200. Beta Release. + Fixed an issue that was causing blank "referer" errors in Apache 2's error.log. + Added two new flags in the prg.conf under [datadirect2sql] for controlling if the new data appears or not. The default for both is true/enabled. (syndicate/production episode number and original airdate/first aired date are the data fields.) + Fixed an issue where the script would change to the user's home directory. This is fixed. + Fixed a bug I introduced during a code cleanup of datadirect_client and broke it so it only gave you a few days. Fixed now. *Blush*. + Fixed a problem where the Replay guidesnapshot was not updating after scheduling a show even if the option was enabled. + Added support for several new DataDirect fields (they will appear in the PRG description), syndicated ep # and original airdate. This new data should begin appearing on or about April 12th 2004. + Improved the providerid detection. + Fixed a problem with handling the lineup and lineupdevice fields. + +Build 199. Beta Release. + Added support for PRG_CONFPATH environment variable if you want your .conf in a different location. + Added DSN to [database] section for cases where the ODBC DSN may not be the same as the database name. (This isn't recommended, however.) + sqlconfig will now create databases. This isn't recommended for ODBC (best practice is to have the ODBC DSN automatically switch to the database which means it has to already exist.) + Fixed some errors in the SQL script parser. + Fixed some .sql scripts. + Removed CGI::ReadParse in favor of something more modern. Removed CGI module from most scripts since they didn't need it. + Scheduling shows on ReplayTVs that don't use the standard port number should work now. + Attempted a fix for Unicode UTF-8 error under Perl 5.8 + Fixed an issue with the tvgrid rendering where it would mistakenly group shows in a slot when it shouldn't. + Fixed an issue with the tvgrid rendering where it would still attempt to print an extra column. + Improved directory change code, should be much more reliable. + Improved Apache environment detection both with and without mod_perl. + Found and fixed a bug that would cause some blank lines to be sent to the console even if verbose was set to 0. + Added ALLOWSQLSUBSTITUTIONS to the conf and rg_database. When running SQL scripts any hardcoded table or database names it recognizes it will change to the settings in the conf at run time. This allows supplied SQL scripts to work both in sqlconfig.pl and in the various database management utilities. (This was why 'use tvlistings;' was missing from the scripts - it's back in now.) + Put USINGAPACHE back into the conf as my Apache detection isn't as good as I thought it was. It's now called SUPRESSHTTPHEADER although USINGAPACHE will also work. If mod_perl with PerlSendHeader set to ON, supresshttpheader and SUPRESSCONTENTTYPE will automatically be set to true. + Removed input source from manual recording. The protocol has it but the Replay always says the slot is unavailable if it's any value other than 3 so I suspect it's not implemented. I've just commented it out for now. + +Build 198. Beta Release. + Thanks to ndrake we now have a logo :) More logos are invited, it's not a problem to include several with the distribution. + Updatetvdata now shows an estimate for data downloads, this is based on a 150 channel lineup and will vary. + Both datadirect2sql and xmltv2sql give time estimates for XML to SQL conversion. + Cast/Crew searches and data (on program detail) is now available. + The version of replaySchedule being run is now logged and if it's less than the version tested in development of PRG there is a warning. + Added code to writeLogFile to guarantee no extra newlines will be written. + Important: The "channel" table has changed! + Improved datadirect support for multiple lineups. + Added sqlconfig.pl for creating/updating databases. + Manual recording is in via the new ReplayTV menu. + j.m. has provided a much improved getchannelicons.pl. There is a new section in the prg.conf called geticons. + Added a bunch of stuff to detect mod_perl and if you have PerlSendHeader turned on. It should be much more pleasant under mod_perl now. + Some minor bug fixes. + + +Build 197. Beta Release. Added rg_null.pl which is essentially used if Replay support is disabled. + Added some new functions to the 'scheduler module' "API", mostly to allow different defaults for different modules. + Fixed an incorrect field name when deciding if we should force an update or not. + Corrected some field names in prg.conf.dist + Removed the erroneous inline comment in prg.conf.dist. + Added support for reading the prime time button icon + For the ScheduleBar if a program is not padded significantly on either side it will not be adjusted + Standardized function names + Cleaned up output code + Added logging to all modules + schedule.pl has been merged into the main project. If you wish to use schedule.pl independantly of PRG you will need to base it from ind_schedule.pl which will no longer be updated aside from bug fixes. + Loaded modules now identify themselves + Added support for inline comments within the rg_config reader. + Fixed, cleaned up and streamlined the RTV unit initalization in replayguide. Should work more consistantly now. + Schedule Resolver Modules (NULL, RG_GUIDE and RG_SCHEDULER) can now completely override refresh interval. + Inline comments work in conf files now (# // and ; are comment characters.) + Added a new script called "updatetvdata.pl" which does the download and SQL placement for either datafeed. + Added new [xmltv] section to the .conf for updatetvdata. Added new values for [datadirect] for updatetvdata. + Changed DELETE FROM to TRUNCATE TABLE for ODBC/MSSQL since DELETE makes the translaction log get huge. + Failed DBI functions should now fail gracefully so more useful error messages can be logged. + Implemented defaultmode. Available modes are now (default), search, todo (if your SRM supports it). This goes in the [replayguide] section. + rg_database now has a run SQL script function, eventually this will lead to some type of configure tool/installer. + Added $^X (pathname to perl interpreter) so that each time we execute a Perl script with system it calls the interpreter explicitly. This probably breaks the Perl ISAPI filter but this will be addressed before 198 is released. + +Build 196. Beta Release. Bug fixes. + Fixed a problem with schedule.pl, rg_guide.pl and rg_replay.pl causing problems with + units not being able to schedule shows! (Eek!) + Added a new check when replayguide first executes to have it force a refresh no matter + what so everything is set properly. + Fixed a bug in configure.pl which was preventing the 'defaultkeep' value from being set. + +Build 195: Beta Release. + Added other authors to the byline. + Added support for a centralized configuration file. + Made the scheduler modules completely modular, made the original the default to ease install headaches for now. (This is actually just a test.) + Added support for viewing ReplayChannels/Shows. You can find all episodes or find repeats as well. + Added support for finding repeats of a specific episode on the show details screen. + Created a new Replay tool on the toolbox and removed "Refresh" and "To Do" buttons since they are now integrated. + Added options to control To Do list display ranges (ALL, From Today, From Now) + Added options to control To Do list's overlapping criteria (start time or end time of shows) + Made a number of improvements to the tvgrid rendering routines + Added a replayScheduler module SQL update to the end of the data feed to SQL process + Added DataDirect support + Fixed some issues with the PDA mode. + Offically added SQLite support and made it the default database. (Thanks j.m.) + Locate updated to actually move the browser's display to the exact time/show. + Updated database routines to allow simultaneous multiple connections to the database. + Made some initial steps to move the grid generation into a plug-in structure. + Added ability to search (data feed providing) other fields such as episode title, genre, etc. + Made "prime time" definable in the conf file. + Ensured latest XMLTV works ok (0.5.30) + +Build 190: Beta. Maintenance. + +Build 189: Beta. Maintenance. + +Build 188: Beta. Maintenance. getchannelicons.pl + +Build 187: Beta. Maintenance. + +Build 186: Beta. ScheduleBar added. + +Build 183: Beta. ReplaySchedule integration begins. To Do list added. + +Build 180: THIRD RELEASE + Made table names soft. + +Build 179: Added Philip Van Baren's enhancements for displaying a single channel for 1-3 days. + +Build 178: SECOND RELEASE + Fixed a few issues with PDA mode. + +Build 175: Finished new theme icon generator/conflict checker. + Fixed numerous bugs in the grid mode, mostly dealing with missing data (start and end of the tvlistings) + Added button to schedule a RTV guide snapshot refresh. + Added new .conf option to control show end overlap (see .conf.dist for details) + +Build 166: Added code to handle things if listings for some channels don't start at midnight on first day. + Rewrote theme icon generator. + +Build 165: Fixed a problem where IVS shows were being listed as events. + Fixed a problem where the "first run" only disqualification was sometimes being reset. + Added Kevin Moye's show title comparison code which should improve hits. + +Build 162: Fixed "Searches need to translate HTML stuff like & to & etc" + +Build 161: Added 'skipversioncheck' option and added some additional debugging information. + +Build 160: FIRST GENERAL RELEASE + Added "allowtitleedit" to the replayguide.conf. If enabled you can edit the showtitle before submitting the slot request. + Removed "showpdaformat" from the .conf since it's been basically replaced with the pda= string. SHOWPDAFORMAT can still be passed on the query string to force PDA mode on or off. + + +Build 159: Bug fixes. + +Build 157: LAST BETA RELEASE + Bug fixes, tweaking. Improved the theme display. + +Build 152: Finished the channel next/prev buttons (finally ;) ) + + +Build 151: Theme display with conflict checking is done. The conflict checking *only* checks the shows visible on the screen and isn't as detailed as on the ReplayTV. Also if you have more than one Replay with overlapping themes you won't be able to tell which unit is in conflict. For something more comprehensive please use Kevin J. Moye's ReplaySchedule utility. + +Program details will now show if the program matches a theme recording. This is NOT conflict checked at all but it will show you which ReplayTVs have that keyword search enabled. + +RTV style show tracking is not possible with this design because only one program is in memory at any one moment. + + +Build 148: Very very simple theme display (no conflict checks of any kind). + Added LOCATE button to details/schedule screen. + +Build 145: Added PDA support. + +Build 142: Added showrtvtext option + Fixed some remaining bugs with the tvgrid. + +Build 141: Added support for multiple listings display modes. + +Build 140: Skinning/Color Support. + Bug fixes. + Can now have icons for ratings, audio, closed caption, etc. + Can now have a title graphic. + Added multiple headend support (eg. basic cable + satellite) + + + diff --git a/FUTURE.TXT b/FUTURE.TXT new file mode 100644 index 0000000..5e7b995 --- /dev/null +++ b/FUTURE.TXT @@ -0,0 +1,9 @@ +Future Enhancements for Personal ReplayGuide + +This document contains a list of possible future additions to this program, since this program is open source *you* are more than welcome to add/change things as you see fit as well. This document is not binding. + +Ability to modify existing ReplayChannels remotely. +Ability to delete recorded shows remotely. +Web based administration/configuration tool +Support for other countries and foreign program listings, if the ReplayTV isn't supported directly have show scheduling make a "Manual Recording" entry. + diff --git a/INSTALL.TXT b/INSTALL.TXT new file mode 100644 index 0000000..0780f01 --- /dev/null +++ b/INSTALL.TXT @@ -0,0 +1,750 @@ +Personal ReplayGuide +(C) 2003 by Lee Thompson +Includes contributions by Philip Van Baren, Kanji T. Bates, Kevin J. Moye, J.M. and Rick Quartarone + +Thanks to Todd Larason, and Matthew Linehan. + + +Personal ReplayGuide is a package of Perl scripts designed to provide a local, personal, web-based tvlistings service directly integrated with ReplayTVs running the 5.0 software. (4.x versions of the software cannot remotely schedule programming.) ReplayTV support is optional. + +NOTE: All cross platform files are LF only and thus may not format properly in notepad. http://www.winvi.de is a text editor for Win32 that can handle both formats and convert between them. + + +________________ +PROJECT HOMEPAGE + +http://replayguide.sourceforge.net +http://replayguide.sourceforge.net/replaySchedule +http://sourceforge.net/projects/replayguide/ + + +_____ +LEGAL + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +_________ +IMPORTANT + +This document as well as the installation and configuration of this software is not for novice users. While I'm happy to help if you should run into a bug or even have a feature request or two I cannot help you install and configure the software beyond this document. + +For additional assistance you might try the appropriate forums at http://www.avsforum.com or http://www.planetreplay.com + +Please do not email the authors with support questions regarding Personal ReplayGuide (bug reports and feature requests are ok, however). + + + +____________ +REQUIREMENTS + +Personal ReplayGuide is dependant on five other software packages: + 1. Perl + 2. (Optional) A supported database server (such as MySQL or Microsoft SQL; see Databases for more info) + 3. A web server capable of using CGI (Common Gateway Interface) + 4. XMLTV or a DataDirect Account* + 5. (Optional) replaySchedule + +These must all be installed and properly configured before Personal ReplayGuide can be installed and configured. +In general the best install order is: Web Server, Perl, Database (if required), DataFeed, replaySchedule (if required) + +Other sources of TV listing data may be adapted to this program using xmltv2sql or datadirect2sql as a guide. + + +________________ +NOTE ABOUT XMLTV + +Starting with 0.5.31, XMLTV now includes a DataDirect grabber. This new grabber is *NOT* supported by Personal ReplayGuide, please use the native DataDirect support instead. They can both, however, use the same DataDirect account. + +The XMLTV team has also stated that a future release of XMLTV will drop the tv_grab_na grabber (which scrapes the listings.zap2it.com website). The current tv_grab_na support in Personal ReplayGuide will be left in, at the very least until the tv_grab_na grabber in legacy versions of XMLTV no longer works. + + +_________ +DATABASES + +Personal ReplayGuide now supports SQLite out of the box since it does not require any software installation. The database file is included (tvlistings without a file extension), all you need to do is make sure the DBD::SQLite Perl module is installed. + +Currently PRG supports SQLite, MySQL and Microsoft SQL databases in terms of testing, making SQL statements and providing .sql scripts to create the tables. + +Other DBMS packages will probably work but may require manual creation of tables and/or modifications to the SQL statements. + +Consult Perl documentation for more information on DBI and DBD (and what drivers are available). + + +Tips on Modifications: + +1. All SQL statements are always set up in a $Stmt variable before being passed. +2. The DBI/DBD database driver is always available in the '$db_driver' variable, this allows for conditional $Stmt building. + +For example, in xmltv2sql we need to do a conditional Stmt build because of a difference between MSSQL and MySQL's SELECT with a limited number of records syntax. + +if ($db_driver eq "mysql") { + $Stmt = "SELECT * FROM tvlistings WHERE (programid <> '$programid' AND starttime > '$starttime') AND tuning = $tuning ORDER BY tuning, starttime LIMIT 1;"; +} + +if ($db_driver eq "ODBC") { + $Stmt = "SELECT TOP 1 * FROM tvlistings WHERE (programid <> '$programid' AND starttime > '$starttime') AND tuning = $tuning ORDER BY tuning, starttime;"; +} + + +IMPORTANT ODBC NOTE: Your ODBC DSN name should be the same as the database name and it should change to the database automatically. + + +Database speed can be greatly increased (by a factor of 10 or more) and disk usage greatly decreased by making sure transaction logging and rollback capabilities are disabled for the database. The major tables: tvlistings, channels, castcrew are purged and repopulated whenever tvdata is refreshed. All these normally useful journaling features will do is take up huge amounts of disk space and slow things down. If you experience some type of power failure and the database is corrupted just recreate the database, add your ReplayTVs back in (it would make some sense to backup this table for this problem if you have more than one or two units) and run the tvdata update. + +The database creation scripts for SQLite automatically disable all the transaction logging for PRG's database. Other DBMS packages may need configuration. + +The sqlconfig Perl script can create databases and tables and can also upgrade tables. + +VERY IMPORTANT: If you are using alternate database and/or table names you *MUST* enable 'allowsqlsubstitutions' in the prg.conf for sqlconfig to work. (You may, alternately, modify the .sql scripts.) + + + + +____________________ +REPLAYTV INTEGRATION + +If you happen to have a ReplayTV you can define them to be available to Personal ReplayGuide. + +Versions running 5.0 and greater of the ReplayTV OS can remotely schedule programming, prior versions will only show what is scheduled in the Personal ReplayGuide channel grid. + +The replaySchedule/rg_scheduler module can also greatly enhance ReplayTV/PRG integration. + + + +________________________________ +WHERE TO FIND DEPENDANT SOFTWARE + +Perl can be found at http://www.perl.com or http://www.activeperl.com. Personal ReplayGuide was designed and tested with ActivePerl 5.6.1 Build 635. + +MySQL is a database server that can be found at http://www.mysql.com. It is free for personal use. Personal ReplayGuide was designed and tested with MySQL 3.22. + +XMLTV can be found at http://membled.com/work/apps/xmltv/. It has been ported to most operating systems including Win32. XMLTV v6 will be changing the file format, this will break Personal ReplayGuide which is developed with XMLTV v0.5.14. +Personal ReplayGuide was tested and designed on an IIS 5.0 web server. It should also work just fine with Apache and others. + +You don't have to download the SQLite management tool unless you want to run SQL scripts manually or make changes to the database. You can find information on SQLite and download the tools at http://www.hwaci.com/sw/sqlite. + +You can get replaySchedule from http://replayguide.sourceforge.net/replaySchedule/ it is available as source, windows binary and linux binary. This version of Personal ReplayGuide requires replaySchedule 116.26 or greater if you wish to use replaySchedule and the rg_scheduler.pl module. + + + +__________ +DATADIRECT + +Zap2It DataDirect Service + +Use of DataDirect with Personal ReplayGuide is free, although you will need to fill out a quarterly survey for Zap2It (Tribune Media Services). + +To sign up for the service, please visit http://datadirect.zap2it.com and click on "New User? Sign-Up". You will need to accept the "TRIBUNE MEDIA SERVICES LICENSED DATA SUBSCRIBER AGREEMENT". + +You will also need to fill out the initial survey which is also a requirement to use the DataDirect service for free. It's fairly short and largely related to PVRs and television anyway. + +The DataDirect Personal ReplayGuide/ReplaySchedule Certificate Code is DGYM-ZKZM-CBUT + +All users and developers for Personal ReplayGuide may use this certificate code. + +NOTE TO DEVELOPERS: DO NOT use the certificate code within this document for non Personal ReplayGuide projects. Instead please write to labs@zap2it.com and request your own certificate code. + +If you already have a DataDirect account, you can use it with Personal ReplayGuide. + + + +_____________ +FILE MANIFEST + +LICENSE.TXT Gnu Public License (GPL) +INSTALL.TXT This Document +FUTURE.TXT Possible Future Enhancements +README.TXT Project Description +CHANGELOG.TXT Revision History +SUPPORT.TXT Support Policies + +prg.conf.dist Configuration File Original (copy to prg.conf and edit) +replayguide.conf.dist Sample replayguide.conf (no longer used if prg.conf exists) +schd2sql.conf.dist Sample schd2sql.conf (no longer used if prg.conf exists) +schedule.conf.dist Sample schedule.conf (not used with PRG) +datadirect.conf.dist Sample datadirect.conf (not used if prg.conf exists) +datadirect2sql.conf.dist Sample datadirect2sql.conf (not used if prg.conf exists) +xmltv2sql.conf.dist Sample xmltv2sql.conf (not used if prg.conf exists) + +configure.pl Script for Configuring ReplayTVs for Personal ReplayGuide +datadirect_client.pl Script for Downloading DataDirect TV Data +datadirect2sql.pl Script for Converting DataDirect Data to SQL +getchannelicons.pl Script to Download Channel Icons +replayguide.pl Script for Personal ReplayGuide +rg_common.pl Common Function Library for Personal ReplayGuide +rg_config.pl Configuration Function Library for Personal ReplayGuide +rg_database.pl Database Function Library for Personal ReplayGuide +rg_guide.pl Native scheduler module for Personal ReplayGuide +rg_info.pl ReplayTV Database Information Library for Personal ReplayGuide +rg_null.pl ReplayTV Integration Null Stub (for when RTV support is off) +rg_refresh.pl ReplayTV GuideSnapshot Batch Refresh Script for Personal ReplayGuide +rg_replay.pl ReplayTV Integration Functions for Personal ReplayGuide +rg_scheduler.pl replaySchedule scheduler module for Personal ReplayGuide +schedule.pl Script for ReplayTV Recording Scheduler +schedule2sql.pl Script for Converting replaySchedule output to SQL +sqlconfig.pl Script for Configuring SQL (ODBC, SQLite, mysql) - the .sql files must be present. +updatetvdata.pl Script for Running the DataFeed Client and then Converter. Works for all DataFeeds. Can also be set to run getchannelicons for you. +xmltv2sql.pl Script for Converting XMLTV to SQL + +configure.bat Runs configure.pl +datadirect_update.bat DataDirect Download / Convert Batch File +geticons.bat Downloads Icons from www.MyReplay.com +setup_perl.bat Installs Perl Modules +updatetvdata.bat Runs updatetvdata.pl +xmltv_update.bat XMLTV Download / Convert Batch File + + +tvlistings_mysql.sql SQL Script for Creating the TVLISTINGS Database Tables for MySQL* +tvlistings_mssql.sql SQL Script for Creating the TVLISTINGS Database Tables for Microsoft SQL* +tvlistings_sqlite.sql SQL Script for Creating the TVLISTINGS Database Tables for SQLite* + +upgrade_mssql.sql SQL Script for Upgrading MSSQL PRG Database from build 195 to build 198* +upgrade_mysql.sql SQL Script for Upgrading MySQL PRG Database from build 195 to build 198* + +* sqlconfig will run these for you. + + + +_____________________ +REQUIRED PERL MODULES + +POSIX* +CGI* +Time::Local* +LWP* +DBI +DBD::SQLite (Required if using SQLite) +DBD::mysql (Required if using MySQL) +DBD::ODBC (Required if using any other DB engine other than MySQL if using ODBC) +DBD::?? (Not supported officially, good luck ;) - see "Databases") +SOAP::Lite (Required if using DataDirect) +Unicode::String* (Required if using Datadirect) + +* denotes standard with ActiveState ActivePerl. + + +Consult your Perl distribution's documentation for how to install modules. Generally it's in the form of "ppm install modulename". + +NOTE: Other modules may be required for XMLTV (on non-win32 platforms). +NOTE: There is no harm in having multiple DBD drivers (eg. DBD::MySQL) installed. +NOTE: As of the date of this file, the ActiveState PPM repository does not have a working version of DBD-SQLite for Perl 5.8 on the Win32 platform. Worse, it may appear to install when it actually does not. You can either use Perl 5.6, which does have a working version, OR use "ppm install http://theoryx5.uwinnipeg.ca/ppms/DBD-SQLite.ppd" to get a working version of DBD-SQLite for Perl 5.8. +WIN32: Change "::" to "-" when trying to install modules with ActivePerl. +TIP: Some of the beta testers for this program have said that you're better off using stock Perl 5.6.1 instead of ActivePerl on Linux. + + + +_______ +UPGRADE + +If you are upgrading from a prior build of Personal ReplayGuide, there are SQL scripts for altering the databases. Individual conf files are still used if the prg.conf cannot be found (or the section is missing). There's a lot of new stuff so reconfiguring it might be a good idea. + + +____________ +INSTALLATION + +NOTE: If transferring to a Unix based system, you will want to FTP the files in ASCII mode, not BINARY. This will strip the extra CRLF pairs. + +Environment Variables: + These are both optional. + + PRG_HOME is the path for where all the Personal ReplayGuide perl and other files are located. + PRG_CONFPATH is where the prg.conf file is located. A trailing slash is required. If this isn't set, the rg_config module will *always* look in the same directory as rg_config.pl. + + +BEFORE YOU BEGIN you will need to have a web server up and running and set up a script (CGI execute) path on it. + + +Step 1: Copying Files + + 1. The .pl files will all need to be copied into a directory where appropriate permissions have been set to allow the execution of scripts. The files "rg_common.pl", "rg_database.pl", "rg_info.pl" and "rg_guide.pl" can be located anywhere in Perl's @INC path. If you don't know what I'm talking about, leave them with the others. + 2. Copy the prg.conf.dist file to the same directory as step 1. + 3. Next, copy or rename "prg.conf.dist" to "prg.conf". + 4. (Optional) You must have the replaySchedule.exe program installed in the same directory as rg_scheduler.pl + + + +Step 2: Database + + If you plan on just using SQLite and the required Perl module is installed, you can skip this step. + + There is also now a sqlconfig.pl utility which will do the database and table creation for you, it will also upgrade existing tables. + + There are one prerequisite: + 1. The [database] section of the prg.conf must be correct. + + To invoke type "perl sqlconfig.pl" at the command line, you may also just double click on "sqlconfig.pl" on Windows. + + +Step 2A: MySQL Setup + + Next, we need to set up the MySQL database and tables. + + 1. Login to your MySQL server (consult MySQL documentation) + 2. Create the database. Type "source /createdb.sql". Substitute path for where your Personal ReplayGuide files are located. (eg. "source c:\install\replayguide\createdb.sql") + 3. Create the tables. Type "source /tvlistings_mysql.sql". Again, substitute path for where your Personal ReplayGuide files are located. + 4. Edit "prg.conf" and under [database] set the driver and login credentials. If need be you can edit "host" as well. + + example: + driver=mysql + username=myuser + password=mypass + + + +Step 2B: Microsoft SQL Setup + + Next, we need to set up the Microsoft SQL database and tables. + + 1. Connect to the database with the Microsoft SQL Query Analyzer + 2. run 'createdb.sql' (or create a database called 'tvlistings' manually) + 3. run 'tvlistings_mssql.sql' + 4. Create an ODBC System DSN called 'tvlistings' + 5. Edit "prg.conf" and under [database] set the driver and login credentials. If need be you can edit "host" as well. + + example: + driver=ODBC + username=myuser + password=mypass + + + NOTE: Other ODBC based databases may work too but the scripts may require some editing. + + +Step 3: Select and Configure a Data Feed + + Next, decide between XMLTV or DataDirect for your listing provider. Both are free. + + DataDirect does require a quarterly questionnaire to use the service, but is orders of magnitude faster than XMLTV. + + XMLTV on the other hand doesn't require any registration. + + XMLTV NOTE: The tv_grab_na_dd grabber is not supported. + + + +Step 3A: XMLTV + + 1. Install and configure XMLTV + 2. Edit prg.conf and in the [global] section enter 'xmltv' for "datafeed". (eg. datafeed=xmltv) You will also need to specify an xmlfile, you may include a complete pathname if you wish. + 3. Download some TVlistings using the xmltv_update.bat file (WIN32) or by invoking: + + xmltv tv_grab_na --days 12 > na.xml + perl xmltv2sql.pl + + Change "na.xml" to whatever you put for the 'xmlfile' field. + + + This process will likely take between 1-2 hours (yes, hours) depending on the speed of your internet connection and computer. If you already have a complete set of listings you can skip running xmltv again. + + NOTE: You might want to start with only 2 days of data, to do this invoke xmltv with --days 2 instead of --days 12. + NOTE: Each time you run xmltvsql it will delete all content of the channel and tvlistings tables. + + If you have multiple headends (i.e. antenna + directv etc), you can specify multiple .xml files in the configuration file - separate them with a comma (eg. antenna.xml,directv.xml) + + WARNING: In various tests on Windows, MySQL consumed a lot of CPU when processing multiple headends. + + +Step 3B: DataDirect + + 1. Sign Up for DataDirect and Create a Lineup + 2. Edit prg.conf and in the [global] section enter 'datadirect' for "datafeed". (eg. datafeed=datadirect) You will also need to specify an xmlfile, you may include a complete pathname if you wish. + 3. Also in the prg.conf file under the [datadirect] section enter the username and password for your DataDirect account. + 4. Download some TVlistings using the datadirect_update.bat file (WIN32) or by invoking: + + perl datadirect_client.pl + perl datadirect2sql.pl + + By default this will download 12 days of data unless you specified otherwise. Assuming you have a broadband connection, the data download will take approximately two minutes and the database import will take another 15-20 minutes. + + +Step 4: Configure Personal ReplayGuide + + First we need to set up Personal ReplayGuide to integrate with your ReplayTVs. + NOTE: Should you add (or remove) ReplayTVs in the future, you will need to rerun this script. + + 1. From a command window, run the configure.bat file (or invoke the configure.pl script yourself). + 3. You will need to edit prg.conf files. At the very least, under [global] the scripts directory needs to be the virtual directory where your web server is configured to run scripts from. + + NOTE: If you don't have a ReplayTV, you can skip this step. + + + +Step 5: Optional but Recommended + + 1. You will, at some point, probably want to set up a scheduled event to run your data feed programs at an interval of your choosing. There are batch files provided you can also just updatetvdata.pl which will automatically run the datafeed software and then the required SQL converter. + 2. It might be wise to limit those that can access Personal ReplayGuide. Even if you've locked down who can schedule a program on your ReplayTVs, you might not want others to see what you have scheduled. + 3. On Win32 with IIS you may get better performance if you rename "schedule.pl" and "replayguide.pl" to "schedule.plx" and "replayguide.plx". The prg.conf file will need to be edited reflecting this change. + 4. If your web server is open to the internet "at large" be sure to secure it properly and keep up on patches. + 5. All of the options available to PRG are fully documented in the .conf file, be sure to take a look! + +You are now ready to run Personal ReplayGuide! + + + +______________ +replaySchedule + +The default ReplayTV integration is fairly limited in it's capabilities. For superior conflict checking and other features such as To Do lists and more you will need to change scheduler modules. + +1. Download and install "replaySchedule". The binary will need to be placed in the same directory as Personal ReplayGuide. +2. Edit the prg.conf: + a. Under [global] change scheduler=rg_guide.pl to scheduler=rg_scheduler.pl + b. Under [global] add schedule2sql=schedule2sql.pl + c. Under [replayguide] change refreshinterval=15 to refreshinterval=0 + d. Under [schedule2sql] ensure that replayschedule=./replaySchedule.exe is present +3. Two things will cause the replayschedule.exe process to run, + a) a manual refresh under the web server's security context + b) after data feed conversion to SQL. Make sure permissions are set accordingly in both cases! + + + + +____________________________ +RUNNING PERSONAL REPLAYGUIDE + + +Simply load up your favorite web browser and type in: + + http://YOUR_WEB_SERVER_ADDRESS/YOUR_CGI_SCRIPT_DIR/replayguide.pl + +eg. + http://192.168.0.1/cgi/replayguide.pl + + or + + http://myserver/cgi/replayguide.pl + + + + +_______________ +TROUBLESHOOTING + + +ALL PLATFORMS + + +1. Try to run "replayguide.pl" directly from a command line prompt, see if there are any errors. If it appears to have valid data and is complete, the problem is more likely with the web server settings. + +2. Check Personal ReplayGuide's configuration file, prg.conf. Ensure that the database section is set up properly. + +3. If it freezes at the header in both the web browser and when you run it from the command line chances are it is having trouble contacting the database server. + +4. Enable and check the log file. + +5. Enable debug mode. + + + +WINDOWS + +1. Make sure the virtual directory you created for replayguide's scripts has read and execute permissions. + +2. If you installed ActivePerl before IIS, make sure .pl is mapped properly to the Perl executeable (check ActivePerl documentation for specifics). + +3. If you're using MS SQL, make sure that you have a system DSN called "tvlistings" that is pointing to the SQL server (does not have to be on the same box) and that it automatically changes the active database to "tvlistings". + +4. If you change to the ISAPI filter (.plx) be sure to update the .conf to reflect the proper filenames. I've noticed that DLLHOST leaks memory with ActiveState's Perl. Use caution. + + + +UNIX + +1. This was developed on a Windows platform so the various files may have CRLF patterns. You'll need to use a utility to strip the CR characters. + +2. You will probably need to adjust the #! line at the top of the scripts to point to your Perl interpreter. + +3. Some Perl modules may not install directly from CPAN, check your ports collection if you experience a failed install. + + +_____________ +LISTINGS NOTE + +Sometimes shows differ slightly in name on zap2it's listings and on the Replay. If this occurs you will not be able to schedule it by just clicking on the title. For example, zap2it lists Lois & Clark as "Lois & Clark: The New Adventures of Superman" but on the ReplayTV channel guide, it's listed as "Lois & Clark: New Adventures of Superman". + + +________ +XML DATA + +There may be some differences in the way the Replay and datafeed see a show title. This can cause the scheduling to fail. + +The data feed SQL converters include remappers which can be configured in the prg.conf under the section for your data feed. It is under ADVANCED OPTIONS. + + +_____________ +titlemap.conf + +Format is OLD TITLE=NEW TITLE, one per line. + +Example: + +To change "Lois & Clark: The New Adventures of Superman" to "Lois & Clark: New Adventures of Superman" you would add the following to your titlemap file: + +Lois & Clark: The New Adventures of Superman=Lois & Clark: New Adventures of Superman + +_______________ +channelmap.conf + +This allows for a channel number to be remapped and/or the call letters to be altered. + +Format is OLD_CHANNELID,OLD_TUNING=NEW_CHANNELID,NEW_TUNING + + +Example: + +To remap "57 TNN" to "69 TNNP" you would add the following to your channelmap file: + +TNN,57=TNNP,69 + + + + +________ +APPENDIX + +_____ +ICONS + +Not included within this package are icons to be used within the tvlistings of Personal ReplayGuide. I have not included these since that would be a violation of copyright. + +By default, Personal ReplayGuide simply links to the images, but you may find better performance if you use them locally. + + +The batch file "geticons.bat" does the following (you'll need WGET installed): + +wget http://my.replaytv.com/images/x_+00-.gif +wget http://my.replaytv.com/images/x_-00+.gif +wget http://my.replaytv.com/images/x_+00+.gif +wget http://my.replaytv.com/images/x_-00-.gif +wget http://my.replaytv.com/images/x_-oo-.gif +wget http://my.replaytv.com/images/x_+oo-.gif +wget http://my.replaytv.com/images/x_-oo+.gif +wget http://my.replaytv.com/images/x_+oo+.gif +wget http://my.replaytv.com/images/x_-0-.gif +wget http://my.replaytv.com/images/x_-o-.gif +wget http://my.replaytv.com/images/x_+0-.gif +wget http://my.replaytv.com/images/x_-0+.gif +wget http://my.replaytv.com/images/x_+0+.gif +wget http://my.replaytv.com/images/x_+o-.gif +wget http://my.replaytv.com/images/x_-o+.gif +wget http://my.replaytv.com/images/x_+o+.gif + +You can create your own, download them manually or edit the replayguide.conf file to use the full url for each icon instead of trying to use them locally. You are only entitled to use these icons if you are a registered MyReplayTV.com user. + +The legend of the symbols are: + 00 Guaranteed, Recurring + oo Not Guaranteed, Recurring + 0 Guaranteed + o Not Guaranteed + + Padding (if before the 0 or o it's before padding) + - No Padding + +Examples: + -00+ Guaranteed, Recurring, After Padding + +o+ Not Guaranteed with Padding Both Before and After + + + +If you elect to use local icons, you will need to edit replayguide.conf: + +image_bpgr=http://my.replaytv.com/images/x_+00-.gif +... + +to + +image_bpgr=x_+00-.gif +image_apgr=x_-00+.gif +image_ppgr=x_+00+.gif +image_gr=x_-00-.gif +image_r=x_-oo-.gif +image_bpr=x_+oo-.gif +image_apr=x_-oo+.gif +image_ppr=x_+oo+.gif +image_gs=x_-0-.gif +image_s=x_-o-.gif +image_bpgs=x_+0-.gif +image_apgs=x_-0+.gif +image_ppgs=x_+0+.gif +image_bps=x_+o-.gif +image_aps=x_-o+.gif +image_pps=x_+o+.gif + + +You'll want to make sure that the 'imagedir' option points to the virtual directory where the images can be found. + +imagedir=/rtvimages + + + +Other icons are supported as well: + +image_stereo is the image to use for stereo programming. +image_repeat is the image to use for repeats. +image_cc is the image to use for closed captioning. +image_tvg is the image to use for TV-G rated programs. +image_tvpg is the image to use for TV-PG rated programs. +image_tv14 is the image to use for TV-14 rated programs. +image_tvma is the image to use for TV-MA rated programs. +image_tvy is the image to use for TV-Y rated programs. +image_tvy7 is the image to use for TV-Y7 rated programs. +image_mpaag is the image to use for MPAA G rated programs. +image_mpaapg is the image to use for MPAA PG rated programs. +image_mpaapg13 is the image to use for MPAA PG13 rated programs. +image_mpaar is the image to use for MPAA R rated programs. +image_mpaanc17 is the image to use for MPAA NC17 rated programs. +image_mpaanr is the image to use for movies that aren't rated. +image_tl is the image to use for a theme that lost conflict rules. +image_tw is the image to use for a theme that won conflict rules. + + + +You can also use icon images for most buttons, check the prg.conf.dist for more. + + + + +_______________ +DATABASE SCHEMA + +This schema is provided for database administrators and to provide enough information so that you can manually create tables if need be (or using an "unsupported" DBMS). + + +NOTE: Some databases use a "tinyint(1)" for bits. Basically only a '0' or a '1' value is stored. +NOTE: (uniqueid) just needs to be unique id of some kind. This can be an int(10), a rowguid... it will vary between databases. + + +table: replayunits + +replayid int ID Number +replayname char 16 Replay Name +replayaddress char 65 fqdn or IP +replayport int TCP port number +defaultquality int default quality (0 high to 2 standard) +defaultkeep int default number of eps to keep +lastsnapshot int last time a guide snapshot request was made +guideversion int version of the guidesnapshot +replayosversion int version of the ReplayTV OS +categories char 255 delimited list of the ReplayTV categories + +Key field is "replayid" which in turn just needs to be an auto_incrementing identity field. + +NOTE: If you aren't using ReplayTV integration, this table isn't used (but must exist). + + + +table: tvlistings + +programid (uniqueid) unique number for fast lookups +tmsprogramid char 12 TMS program ID +tmsid int TMS channel ID +starttime datetime start time of the program +endtime datetime end time of the program +tuning int channel # +channel char 16 call letters +title char 255 program title +subtitle char 255 episode title +description text description text +category char 255 categories (comma delimited if more than one) +captions char 32 closed captioning system 'teletext' etc +advisories char 255 program advisories (usually delimited) +episodenum char 16 episode x of y +vchiprating char 16 TV-?? rating +mpaarating char 16 MPAA rating +starrating char 16 eg. 2.5/4 stars +movieyear char 16 movie release year +repeat bit 1 = yes +stereo bit 1 = yes +movie bit 1 = yes +subtitled bit 1 = yes + +Key field is "programid" which needs to be a unique identifier for each record. + +NOTE: tmsprogramid, tmsid and advisories are only used by DataDirect. + + +table: channels + +channelid (uniqueid) channelid +tmsid int TMS channel ID +tuning int channel # +displaynumber int channel display number (no multiplier) +channel char 16 call letters +display char 64 display name +iconsrc char 255 url to the icon +affiliate char 32 affiliation description +headend char 16 ReplayTV headend code +hidden bit is hidden +postalcode char 16 Postal Code of the Lineup +systemtype char 16 System Time of the Lineup (Antenna, DBS or Cable) +lineupname char 32 Name of the Lineup +lineupdevice char 32 Device of Lineup (e.g. Digital, Digital Rebuild) + +Key field is "channelid" which needs to be a unique identifier for each record. + +NOTE: tmsid is only used by DataDirect. postalcode isn't currently used. headend isn't currently used. iconsrc is only used by XMLTV or if you setup and use getchannelicons.pl. displaynumber, systemtype, and lineupname are only used by the manual recording code at this time. + + + + +table: schedule + +scheduleid int record number +programid (uniqueid) links to the listings table +replayid int links to the replayunits table +firstrun bit flag for first run only recordings +guaranteed bit flag for guaranteed +theme bit flag for theme data +recurring bit flag for repeat scheduling +manual bit flag for manual recording +conflict bit flag for a show that's in conflict +created int epoch second value of when the item was scheduled +padbefore int number of minutes padded before show's scheduled start +padafter int number of minutes padded after show's scheduled end + +Key field is "scheduleid" which needs to be a unique identifier for each record. + +NOTE: At present "schedule" is only used by the replaySchedule SRM. + + +table: castcrew + +castcrewid (uniqueid) castcrewid +tmsprogramid char 12 TMS program ID +role int role category +surname char 64 last name +givenname char 64 first name + +Key field is "castcrewid" which in turn just needs to be an auto_incrementing identity field. + +NOTE: This table is not yet used and is even subject to change. + + + + +_______________________ +DEVELOPMENT ENVIRONMENT + +This describes the environment where Personal ReplayGuide was developed. + +Windows 2000 +IIS 5.0 +ActivePerl 5.6.1 Build 635 +Microsoft SQL Server 2000 +MySQL 3.22 + +WindowsXP Professional +IIS 5.1 +ActivePerl 5.6.1 Build 635 +Microsoft SQL Server 2000 via System DSN to separate machine + + +____________________ +THANKS AND GREETINGS + +I'd like to extend both thanks and greetings to the following people: Philip Van Baren, Kanji T. Bates, Kevin J. Moye, J.M., Rick Quartarone, Todd Larason, Matthew Linehan, Gerry Duprey, and all of the Personal ReplayGuide Users and Tesrers! + diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README.TXT b/README.TXT new file mode 100644 index 0000000..2037544 --- /dev/null +++ b/README.TXT @@ -0,0 +1,9 @@ +Personal ReplayGuide is a package of Perl scripts designed to provide a local, personal, web-based tvlistings service directly integrated with ReplayTVs running the 5.0 software. (4.x versions of the software cannot remotely schedule programming.) ReplayTV support is optional if you're just looking to run your own web based TV listings engine. + +If you're looking for a desktop application for TVlistings/ReplayTV integration this is probably overkill and you should probably check out DVArchive 3.0 (or greater). You can find it at http://www.dvarchive.org. It is a cross platform Java applet. + + +Please see INSTALL.TXT for more details and setup instructions. + + + diff --git a/SUPPORT.txt b/SUPPORT.txt new file mode 100644 index 0000000..22a24d1 --- /dev/null +++ b/SUPPORT.txt @@ -0,0 +1,9 @@ +While we're happy to help if you should run into a bug or even have a feature request or two we cannot help you install and configure the software beyond the installation document (see INSTALL.txt) + +For additional assistance you might try the appropriate forums at http://www.avsforum.com or http://www.planetreplay.com + +Please do not email the authors with support questions regarding Personal ReplayGuide (bug reports and feature requests are ok, however). + +You may also use the tech support/bug tracking on sourceforge but you may experience faster results on AVSForum. + + diff --git a/configure.bat b/configure.bat new file mode 100644 index 0000000..9dadd23 --- /dev/null +++ b/configure.bat @@ -0,0 +1 @@ +perl configure.pl diff --git a/configure.pl b/configure.pl new file mode 100644 index 0000000..fce3788 --- /dev/null +++ b/configure.pl @@ -0,0 +1,457 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide Configuration Utility +# by Lee Thompson +# with bits by Kanji T. Bates +# $Id: configure.pl,v 1.6 2003/07/19 13:33:44 pvanbaren Exp $ +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +use POSIX qw( strftime getcwd ); +use English; +use Time::Local; +require LWP::Simple; +require LWP::UserAgent; +require HTTP::Request; +require HTTP::Headers; + +my $_version = "Personal ReplayGuide|ReplayTV Configure|1|0|17|Lee Thompson,Philip Van Baren,Kanji T. Bates"; + +#------------------------------------------------------------------------------------ +# Determine Current Directory +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_config.pl'; # Load config functions +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Load database config + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Debug Options +#----------------------------------------------------------------------------------- +$do_not_drop_rows = 0; # Controls of replayunits gets replaced +$do_not_insert = 0; # Skip the DB insert + +#----------------------------------------------------------------------------------- +# Define Options +#----------------------------------------------------------------------------------- +$debug = 0; # Debug Messages + + +$configfile = "configure.conf"; # This is optional +$configstatus = getConfig($configfile); # Read Configuration +$verbose = 1; + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$null = ""; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + $remotemode = 1; +} + + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +if ($debug) { + &writeOutput("Debug Messages are ON"); +} + + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; # Disabled +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + +#------------------------------------------------------------------- + + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + +writeDebug("Job started at $now"); + +#------------------------------------------------------------------- +# Set up Database +#------------------------------------------------------------------- + +&InitDB; +&InitDSN; + +#------------------------------------------------------------------- +# Start Database +#------------------------------------------------------------------- + +$DSNLink = &StartDSN; + +if ($DSNLink ne $null) { + writeDebug("Database Connection Established to $DATASOURCE{DSN} using handle $DSNLink"); +}else{ + writeDebug("Attempt to Connect to $DATASOURCE{DSN} Failed: " . &GetLastSQLError()); + abend("Could not establish database connection!"); +} + + + +#---------------------------------------------------------------- +# Set Defaults +#---------------------------------------------------------------- + +$inp_scriptdir = ""; + +#---------------------------------------------------------------- +# Start +#---------------------------------------------------------------- + +writeDebug("Entering Interactive Mode"); + +print "\nWelcome to the $program_title configuration utility.\n"; + + +#---------------------------------------------------------------- +# Gather Information +#---------------------------------------------------------------- + +$inp_dortv = 1; + +if ($inp_dortv) { + $choiceok = 0; + do { + print "\nHow many ReplayTV's do you want to use with $program_title?\n[default: 1] > "; + $inp_replaynum = int ; + if ($inp_replaynum == 0) { + $inp_replaynum = 1; + } + if (($inp_replaynum > 0) && ($inp_replaynum < 99)) { + $choiceok = 1; + } + } while ($choiceok < 1); + + $ctr = 1; + do { + print "\n\nReplay Number $ctr:\n"; + + $choiceok = 0; + do { + if ($ctr == 1) { + print "(This will be used as the default unit)\n"; + } + + print "\nWhat is the FQDN or IP address of this unit [eg. 192.168.0.1]?\n> "; + $inp_unitip = ; + $inp_unitip =~ s/\r//g; # Eat LF + $inp_unitip =~ s/\n//g; # Eat CR + + if (length($inp_unitip) > 0) { + $choiceok = 1; + } + } while ($choiceok < 1); + + print "\nWhat http port does it use [default: 80]?\n> "; + $inp_unitport = ; + $inp_unitport =~ s/\r//g; # Eat LF + $inp_unitport =~ s/\n//g; # Eat CR + + if (length($inp_unitport) > 0) { + $inp_unitport = int $inp_unitport; + } else { + $inp_unitport = 80; + } + + $choiceok = 0; + do { + print "\nWhat is the network name of this unit [eg. Bedroom]?\n> "; + $inp_unitname = ; + $inp_unitname =~ s/\r//g; # Eat LF + $inp_unitname =~ s/\n//g; # Eat CR + + if (length($inp_unitname) > 0) { + $choiceok = 1; + } + } while ($choiceok < 1); + + $choiceok = 0; + do { + print "\nWhat quality level would you like (S)tandard, M)edium, H)igh)?\n[default: S] > "; + $inp_quality = uc ; + $inp_quality =~ s/\r//g; # Eat LF + $inp_quality =~ s/\n//g; # Eat CR + + if (length($inp_quality) < 1) { + $inp_quality = 2; + } + if ($inp_quality =~ 'S') { + $inp_quality = 2; + } + if ($inp_quality =~ 'M') { + $inp_quality = 1; + } + if ($inp_quality =~ 'H') { + $inp_quality = 0; + } + if (($inp_quality > -1) && ($inp_quality < 3)) { + $choiceok = 1; + } + } while ($choiceok < 1); + + $choiceok = 0; + do { + print "\nHow many episodes would you like to keep?\n[default: 1] > "; + $inp_keep = int ; + if ($inp_keep == 0) { + $inp_keep = int 1; + } + if (($inp_keep > 0) && ($inp_keep < 10)) { + $choiceok = 1; + } + } while ($choiceok < 1); + + if ($ctr == 1) { + $replayunits = "$inp_unitip,$inp_unitport,$inp_unitname,$inp_quality,$inp_keep"; + $defaultreplaytv = $inp_unitip; + }else{ + $replayunits .= ";$inp_unitip,$inp_unitport,$inp_unitname,$inp_quality,$inp_keep"; + } + + $ctr++; + + } while ($ctr < $inp_replaynum + 1); +} + +print "\n"; + +writeDebug("Interactive Mode Completed"); + +#------------------------------------------------------------------- +# Clean ReplayTV Database +#------------------------------------------------------------------- + +if ($do_not_drop_rows) { + writeDebug("Skipping Row Delete"); +}else{ + writeDebug("Purging old data from database"); + + $Stmt = "DELETE FROM $db_table_replayunits;"; + if (sqlStmt($DSNLink,$Stmt)) { + writeDebug("Table $db_table_replayunits purged"); + }else{ + writeDebug("Failed: " . &GetLastSQLError() . " (" &GetLastSQLStmt() . ")"); + abend("Failed to purge table $db_table_replayunits"); + } + + writeDebug("Purge Complete"); + +} + +#------------------------------------------------------------------- +# Insert Rows +#------------------------------------------------------------------- + +$rows = 0; + +if ($do_not_insert) { + writeDebug("Database Insert Disabled"); +} + + +for ( split /;/, $replayunits ) { + /;/; + ($rtv_unit,$rtv_port,$rtv_label,$rtv_quality,$rtv_keep) = split(',', $_, 5); + if ($do_not_insert) { + writeDebug(">> $rtv_label ($rtv_unit:$rtv_port) [$rtv_quality, $rtv_keep]"); + }else{ + if (insertRTVRow($rtv_label,$rtv_unit,$rtv_port,$rtv_quality,$rtv_keep)) { + $rows++; + } + } +} + +writeDebug("$rows added to $db_table_replayunits table."); + + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Terminating Database Connection from $DATASOURCE{DSN} ($DSNLink)"); +endDSN("",$DSNLink); +writeDebug("Job finished at $now ($runtime seconds)"); + +writeDebug("********************************************************"); + + +#------------------------------------------------------------------- +sub insertRTVRow { + # + # Inserts a Row Into the ReplayUnits DB + # + #----------------------------------------------------------------------------- + my $replayname = shift; + my $replayaddress = shift; + my $replayport = int shift; + my $replayquality = int shift; + my $replaykeep = int shift; + + my $FieldNames = ""; + my $FieldValues = ""; + + $FieldNames = $null; + $FieldNames .= "replayname, replayaddress, replayport, "; + $FieldNames .= "defaultquality, defaultkeep, lastsnapshot"; + + $FieldValues = $null; + $FieldValues .= "'$replayname', '$replayaddress', $replayport, "; + $FieldValues .= "$replayquality, $replaykeep, 0"; + + $Stmt = "INSERT INTO $db_table_replayunits ($FieldNames) VALUES ($FieldValues);"; + + if (sqlStmt($DSNLink,$Stmt)) { + return 1; + }else{ + return 0; + } + +} diff --git a/createdb.sql b/createdb.sql new file mode 100644 index 0000000..f3666d4 --- /dev/null +++ b/createdb.sql @@ -0,0 +1 @@ +CREATE DATABASE tvlistings; diff --git a/datadirect2sql.pl b/datadirect2sql.pl new file mode 100644 index 0000000..e192bbd --- /dev/null +++ b/datadirect2sql.pl @@ -0,0 +1,1424 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide SQL Converter +# by Lee Thompson +# +# Requirements: +# DataDirect Service +# +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- +# +# Zap2It DataDirect Service +# +# Use of DataDirect with Personal ReplayGuide is free, although you will need to +# fill out a quarterly survey for Zap2It (Tribune Media Services). +# +# To sign up for the service, please visit http://datadirect.zap2it.com and click +# to use the DataDirect service for free. It's fairly short and largely +# related to PVRs and television anyway. +# +# The DataDirect Personal ReplayGuide/ReplaySchedule Certificate Code is: +# DGYM-ZKZM-CBUT +# +# All users and developers for Personal ReplayGuide may use this certificate code. +# (Including replaySchedule). +# +# NOTE TO DEVELOPERS: DO NOT use the certificate code within this document for non +# Personal ReplayGuide projects. Instead please write to labs@zap2it.com and request +# your own certificate code. +# +#----------------------------------------------------------------------------------- +# NOTE: If you select multiple lineups that have the same feeds (like two SCIFIPs) +# the lowest channel number will appear. +#----------------------------------------------------------------------------------- + +use POSIX qw( strftime getcwd ); +use English; +use Time::Local; +require LWP::Simple; +require LWP::UserAgent; +require HTTP::Request; +require HTTP::Headers; + +my $_version = "Personal ReplayGuide|DataDirect XML to SQL Converter|1|2|41|Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Load database info +require 'rg_config.pl'; # Load config functions + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Debug Options +#----------------------------------------------------------------------------------- +$do_not_drop_rows = 0; # Do not DELETE rows first +$do_not_insert = 0; # Skip the DB insert +$verbose = 1; # Talky + + +#----------------------------------------------------------------------------------- +# Set Required Defaults +#----------------------------------------------------------------------------------- + +$scheduler = "rg_scheduler.pl"; + +# OS-Sensitive defaults + +if ($^O eq 'MSWin32') { + $schedule2sql = "schedule2sql.pl"; +} else { + $schedule2sql = "./schedule2sql.pl"; +} + +#----------------------------------------------------------------------------------- +# Define Options +#----------------------------------------------------------------------------------- + +$show_episode_number = 1; +$show_first_aired_date = 1; +$retcode = 0; +$debug = 0; # Debug Messages +$multiplier = 1000; # Default Multiplier +$dotinterval = 500; # Interval for the "." +$maxrows = 0; # Maximum Number of rows to INSERT +$cnf_xmlfile = "./na.xml"; # Data Direct file +$cnf_channelmap = ""; # Channel Mapping +$cnf_titlemap = ""; # Title Mapping +$use_castcrew = 1; # Use Cast and Crew Data +$configfile = "datadirect2sql.conf"; # This is optional +$configstatus = getConfig($configfile); # Read Configuration + + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$null = ""; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +$rows = 0; +$dotctr = 0; +$emptystop = 0; +$lineup = 0; # Lineup Number + + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + $remotemode = 1; +} + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +if ($debug) { + &writeOutput("Debug Messages are ON"); +} + + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + +#------------------------------------------------------------------- + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + +writeDebug("Job started at $now"); + +#------------------------------------------------------------------- +# Set up Database +#------------------------------------------------------------------- + +&InitDB; +&InitDSN; + +#------------------------------------------------------------------- +# Start Database +#------------------------------------------------------------------- + +$prgdb_handle = &StartDSN; + +if ($prgdb_handle ne $null) { + writeDebug("Database Connection Established! $DATASOURCE{DSN} ($prgdb_handle)"); +}else{ + writeDebug("Attempt to Connect to $DATASOURCE{DSN} Failed: " . &GetLastSQLError()); + abend("Could not establish database connection!"); +} + + +#------------------------------------------------------------------- +# Build Arrays +#------------------------------------------------------------------- + +if (length($cnf_channelmap) > 0) { + writeDebug("Loading channelmap from $cnf_channelmap"); + + @channelmap = loadFile($cnf_channelmap); + $cmap_ctr = countElements(@channelmap); + + if ($cmap_ctr > 0) { + writeDebug("Found $cmap_ctr channel mappings."); + $do_channelmap = 1; + }else{ + writeDebug("No channel mappings found."); + + } +} + +if (length($cnf_titlemap) > 0) { + writeDebug("Loading titlemap from $cnf_titlemap"); + + @titlemap = loadFile($cnf_titlemap); + $tmap_ctr = countElements(@titlemap); + + if ($tmap_ctr > 0) { + writeDebug("Found $tmap_ctr title mappings."); + $do_titlemap = 1; + }else{ + writeDebug("No title mappings found."); + + } +} + +#------------------------------------------------------------------- +# Check Files +#------------------------------------------------------------------- + +for ( split /,/, $cnf_xmlfile ) { + /,/; + $xml_file = $_; + + #------------------------------------------------------------------- + # Open File + #------------------------------------------------------------------- + + if (open(LISTINGS, "<$xml_file")) { + writeDebug("Checking DataDirect Feed ($xml_file)"); + + $exitflag = 0; + $file_status = 0; + $linetotal = 0; + $scheduleline = 0; + $endscheduleline = 0; + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + if ($original_line =~ //) { + $scheduleline = $linetotal; + } + if ($original_line =~ /<\/schedules>/) { + $endscheduleline = $linetotal; + $exitflag = 1; + $file_status = 1; + } + if (eof(LISTINGS)) { + $exitflag = 1; + } + $linetotal++; + + } until ($exitflag > 0); + + close LISTINGS; + + if (($endscheduleline - $scheduleline) < 2) { + writeDebug("File $xml_file has an empty schedule block."); + $file_status = 0; + } + + if ($file_status < 1) { + abend("File $xml_file does not contain schedule data, aborted."); + } + + + }else{ + abend("Could not open $xml_file"); + } +} + +getConfig("datadirect",1,"days"); +$timeestimate = 0; + +#------------------------------------------------------------------- +# Calculate Estimates for Processing Time +# +# These are based on a typical digital cable lineup of 170 channels. +# +#------------------------------------------------------------------- +# +# If this process takes more than an hour with 12 days of listings +# on a modern machine you probably have data recovery/journaling/ +# transaction logging running on the DBMS. Turn it off, at least +# for PRG's database, you'll see an increase in speed by a factor +# of 10 or more. +# +#------------------------------------------------------------------- + +if ($db_driver eq "ODBC") { + #-------------------------------------------------- + # The ODBC driver is set to use TRUNCATE TABLE + # which bypasses journaling. + #-------------------------------------------------- + + $timeestimate = $timeestimate + ($days * 1.25); + + if ($use_castcrew) { + $timeestimate = $timeestimate + ($days * 1.50); + } + + $timeestimate = int $timeestimate; +} + +if ($db_driver eq "mysql") { + $timeestimate = $timeestimate + ($days * 0.25); + + if ($use_castcrew) { + $timeestimate = $timeestimate + ($days * 0.25); + } +} + +if ($db_driver eq "SQLite") { + #-------------------------------------------------- + # If PRAGMA default_synchronous isn't set to OFF + # castcraw is 6.25 minutes per day of listings + # tvlistings is 10.25 minutes per day of listings + # + #-------------------------------------------------- + + $timeestimate = $timeestimate + ($days * 0.25); + + if ($use_castcrew) { + $timeestimate = $timeestimate + ($days * 0.50); + } +} + + +writeDebug("Depending on the speed of the machine this may take approximately $timeestimate minutes."); + + +#------------------------------------------------------------------- +# Clean TVListings +#------------------------------------------------------------------- + +if ($do_not_drop_rows) { + writeDebug("Skipping Row Delete"); +}else{ + + writeDebug("Deleting Rows..."); + + if ($db_driver eq "ODBC") { + #---------------------------------------------------- + # MSSQL logs all transactions so DELETE will store a + # complete copy of the table. TRUNCATE gets around + # this buy just logging the event not the records. + #---------------------------------------------------- + + $Stmt = "TRUNCATE TABLE $db_table_tvlistings;"; + }else{ + $Stmt = "DELETE FROM $db_table_tvlistings;"; + } + if (sqlStmt($prgdb_handle,$Stmt)) { + writeDebug("Table $db_table_tvlistings purged"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + } + + if ($db_driver eq "ODBC") { + $Stmt = "TRUNCATE TABLE $db_table_channels;"; + }else{ + $Stmt = "DELETE FROM $db_table_channels;"; + } + + if (sqlStmt($prgdb_handle,$Stmt)) { + writeDebug("Table $db_table_channels purged"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + } + + if ($db_driver eq "ODBC") { + $Stmt = "TRUNCATE TABLE $db_table_castcrew;"; + }else{ + $Stmt = "DELETE FROM $db_table_castcrew;"; + } + + if (sqlStmt($prgdb_handle,$Stmt)) { + writeDebug("Table $db_table_castcrew purged"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + + } + + writeDebug("Deleting Rows... Completed"); + +} + +#------------------------------------------------------------------- +# If INSERT is disabled, log data to a CSV +#------------------------------------------------------------------- + +if ($do_not_insert) { + open(CSVFILE, ">$db_table_tvlistings.csv"); + + $FieldNames = ""; + $FieldNames .= "tmsprogramid, tmsid, "; + $FieldNames .= "starttime, endtime, tuning, "; + $FieldNames .= "channel, title, subtitle, "; + $FieldNames .= "description, category, stereo, "; + $FieldNames .= "captions, episodenum, vchiprating, "; + $FieldNames .= "mpaarating, starrating, movieyear, "; + $FieldNames .= "repeat, movie, subtitled, "; + $FieldNames .= "advisories"; + + print CSVFILE $FieldNames; + print CSVFILE "\n"; + + + open(CSVFILE2, ">$db_table_channels.csv"); + + $FieldNames = ""; + $FieldNames .= "tmsid, affiliate, "; + $FieldNames .= "tuning, displaynumber, channel, "; + $FieldNames .= "display, iconsrc, hidden, "; + $FieldNames .= "postalcode, systemtype, lineupname, "; + $FieldNames .= "lineupdevice"; + + print CSVFILE2 $FieldNames; + print CSVFILE2 "\n"; + + + open(CSVFILE3, ">$db_table_castcrew.csv"); + + $FieldNames = ""; + $FieldNames .= "tmsprogramid, role, "; + $FieldNames .= "surname, givenname"; + + print CSVFILE3 $FieldNames; + print CSVFILE3 "\n"; + + +} + + +$iteration = 0; + + +for ( split /,/, $cnf_xmlfile ) { + /,/; + $xml_file = $_; + $lineupnumber = 0; + + #------------------------------------------------------------------- + # Open File + #------------------------------------------------------------------- + + if (open(LISTINGS, "<$xml_file")) { + writeDebug("$iteration: Reading DataDirect Feed ($xml_file)"); + }else{ + abend("Could not open $xml_file"); + } + + #------------------------------------------------------------------- + # Convert XML to SQL + #------------------------------------------------------------------- + + writeDebug("$xml_file: First Pass..."); + + if ($verbose) { + writeDebug("$xml_file: Seeking Stations Block"); + } + + #---------------------------------------- + # First we need to build an array of + # stations and call letters + #---------------------------------------- + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + + } until ($original_line =~ //); + + writeDebug("$xml_file: Parsing Stations"); + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + + if ($line =~ //) { + $callsign = $line; + $callsign =~ s/.*([^<]*)\W.*/$1/; + } + if ($line =~ //) { + $name = $line; + $name =~ s/.*([^<]*)\W.*/$1/; + } + if ($line =~ //) { + $affiliate = $line; + $affiliate =~ s/.*([^<]*)\W.*/$1/; + } + if ($line =~ /<\/station>/) { + $stationarray{$stationid} = "$stationid\|$callsign\|$name\|$affiliate"; + } + + } until ($original_line =~ /<\/stations>/); + + + writeDebug("$xml_file: Parsing Lineups"); + + #---------------------------------------- + # Next we need the TMS Mapping + #---------------------------------------- + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + + if ($line =~ / 0) { + if ($lineupname ne $prevlineup) { + if (length($prevlineup) > 0) { + $lineupnumber++; + } + } + } + + $prevlineup = $lineupname; + + } + + if ($line =~ //); + +# +# close DEBUG; +############## + + if ($verbose) { + writeDebug("$xml_file: Seeking Program Block"); + } + + #---------------------------------------- + # Now we need to build a list of program + # data. + #---------------------------------------- + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + } until ($original_line =~ //); + + writeDebug("$xml_file: Parsing Programs"); + + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + + if ($line =~ //) { + $title = $line; + $title =~ s/.*([^<]*)\W.*/$1/; + } + if ($line =~ /<subtitle>/) { + $subtitle = $line; + $subtitle =~ s/.*<subtitle>([^<]*)\W.*/$1/; + } + if ($line =~ /<description>/) { + $description = $line; + $description =~ s/.*<description>([^<]*)\W.*/$1/; + } + if ($line =~ /<showType>/) { + $showType = $line; + $showType =~ s/.*<showType>([^<]*)\W.*/$1/; + } + if ($line =~ /<syndicatedEpisodeNumber>/) { + $syndicatedEpisodeNumber = $line; + $syndicatedEpisodeNumber =~ s/.*<syndicatedEpisodeNumber>([^<]*)\W.*/$1/; + } + if ($line =~ /<originalAirDate>/) { + $originalAirDate = $line; + $originalAirDate =~ s/.*<originalAirDate>([^<]*)\W.*/$1/; + } + if ($line =~ /<mpaaRating>/) { + $mpaaRating = $line; + $mpaaRating =~ s/.*<mpaaRating>([^<]*)\W.*/$1/; + } + if ($line =~ /<starRating>/) { + $starRating = $line; + $starRating =~ s/.*<starRating>([^<]*)\W.*/$1/; + } + if ($line =~ /<runTime>/) { + $runTime = $line; + $runTime =~ s/.*<runTime>([^<]*)\W.*/$1/; + } + if ($line =~ /<year>/) { + $year = $line; + $year =~ s/.*<year>([^<]*)\W.*/$1/; + } + if ($line =~ /<advisory>/) { + $advisory_entry = $line; + $advisory_entry =~ s/.*<advisory>([^<]*)\W.*/$1/; + if (length($advisory) > 0) { + $advisory .= ","; + } + $advisory .= $advisory_entry; + } + if ($line =~ /<\/program>/) { + + #------------------------------------------------------------------------------------- + # DataDirect offers some extra fields, we will just add them to the description field. + #------------------------------------------------------------------------------------- + + if (length($showType) > 0) { + $description = "$showType. $description"; + } + + my $temp_field = ""; + my $temp_flag = 0; + + if ($show_episode_number) { + if (length($syndicatedEpisodeNumber) > 0) { + $temp_field .= "Ep \#$syndicatedEpisodeNumber"; + $temp_flag = 1; + } + } + + if ($show_first_aired_date) { + if (length($originalAirDate) > 0) { + if ($temp_flag) { + $temp_field .= " "; + } + $temp_field .= "First Aired: $originalAirDate"; + $temp_flag = 1; + } + } + + if ($temp_flag) { + $temp_field = " ($temp_field)"; + } + + $description .= $temp_field; + + $programarray{$programid} = "$programid\|$title\|$subtitle\|$description\|$mpaaRating\|$starRating\|$runTime\|$year\|$advisory"; + } + + } until ($original_line =~ /<\/programs>/); + + + if ($use_castcrew > 0) { + if ($verbose) { + writeDebug("$xml_file: Seeking Cast/Crew Block"); + } + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + } until ($original_line =~ /<productionCrew>/); + + writeDebug("$xml_file: Parsing Cast/Crew",1); + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + + if ($line =~ /<crew program=/) { + $programid = $line; + $programid =~ s/.*program='([^']*).*/$1/; + $role = ""; + $surname = ""; + $givenname = ""; + + } + + if ($line =~ /<member>/) { + $role = ""; + $surname = ""; + $givenname = ""; + } + if ($line =~ /<role>/) { + $role = $line; + $role =~ s/.*<role>([^<]*)\W.*/$1/; + } + if ($line =~ /<givenname>/) { + $givenname = $line; + $givenname =~ s/.*<givenname>([^<]*)\W.*/$1/; + } + if ($line =~ /<surname>/) { + $surname = $line; + $surname =~ s/.*<surname>([^<]*)\W.*/$1/; + } + + if ($line =~ /<\/member>/) { + $roleid = 0; + if (uc $role eq 'ACTOR') { + $roleid = 1; + } + if (uc $role eq 'GUEST STAR') { + $roleid = 2; + } + if (uc $role eq 'HOST') { + $roleid = 3; + } + if (uc $role eq 'DIRECTOR') { + $roleid = 4; + } + if (uc $role eq 'PRODUCER') { + $roleid = 5; + } + if (uc $role eq 'EXECUTIVE PRODUCER') { + $roleid = 6; + } + if (uc $role eq 'WRITER') { + $roleid = 7; + } + + # Write Data + + $programid = filterfield($programid); + $surname = filterfield($surname); + $givenname = filterfield($givenname); + + $FieldNames = ""; + $FieldNames .= "tmsprogramid, role, "; + $FieldNames .= "surname, givenname "; + + $FieldValues = $null; + $FieldValues .= "'$programid', $roleid, "; + $FieldValues .= "'$surname', '$givenname'"; + + if ($do_not_insert) { + print CSVFILE3 $FieldValues; + print CSVFILE3 "\n"; + }else{ + $Stmt = "INSERT INTO $db_table_castcrew ($FieldNames) VALUES ($FieldValues);"; + + if (sqlStmt($prgdb_handle,$Stmt)) { + $rows++; + $dotctr++; + }else{ + my $sql_error = &GetLastSQLError() . "\n(" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error at record $rows"); + + } + } + + if ($dotctr == $dotinterval) { + if ($verbose) { + displayText(".",0,1); + } + $dotctr = 0; + } + + + + } + } until ($original_line =~ /<\/productionCrew>/); + + writeDebug("Done!"); + writeDebug("$xml_file: Added $rows records of cast/crew information"); + } + + + if ($verbose) { + writeDebug("$xml_file: Seeking Genre Block"); + } + + #---------------------------------------- + # Now we need to build a list of genre + # data. + #---------------------------------------- + + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + } until ($original_line =~ /<genres>/); + + writeDebug("$xml_file: Parsing Genre Data"); + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + + if ($line =~ /<programGenre program=/) { + $programid = $line; + $programid =~ s/.*program='([^']*).*/$1/; + $genre = ""; + } + if ($line =~ /<class>/) { + $class = $line; + $class =~ s/.*<class>([^<]*)\W.*/$1/; + if (length($genre) > 0) { + $genre .= "/"; + } + $genre .= $class; + } + if ($line =~ /<\/programGenre>/) { + $categoryarray{$programid} = "$genre"; + } + } until ($original_line =~ /<\/genres>/); + + close LISTINGS; + + + $rows = 0; + $dotctr = 0; + + if (open(LISTINGS, "<$xml_file")) { + writeDebug("$xml_file: Second Pass..."); + }else{ + abend("Could not open $xml_file"); + } + + if ($verbose) { + writeDebug("$xml_file: Seeking Schedule Block"); + } + + #---------------------------------------- + # Now we need to build a list of schedule + # data. + #---------------------------------------- + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + } until ($original_line =~ /<schedules>/); + + writeDebug("$xml_file: Parsing Schedule",1); + $endrec = 0; + + do { + $line = readline LISTINGS; + chomp($line); + $original_line = $line; + + if ($line =~ /<schedule program=/) { + $programid = ""; + $stationid = ""; + $starttime = ""; + $duration = ""; + $closeCaptioned = ""; + $tvRating = ""; + $repeat = ""; + $subtitled = ""; + $stereo = ""; + $hdtv = ""; + $part = ""; + $partnumber = ""; + $parttotal = ""; + + $programid = $line; + $programid =~ s/.*program='([^']*).*/$1/; + $stationid = $line; + $stationid =~ s/.*station='(\d*)[^']*.*/$1/; + $starttime = $line; + $starttime =~ s/.*time='([^']*).*/$1/; + $duration = $line; + $duration =~ s/.*duration='([^']*).*/$1/; + $repeat = $line; + $repeat =~ s/.*repeat='([^']*).*/$1/; + if ($repeat eq $line) { + $repeat = ""; + } + $tvRating = $line; + $tvRating =~ s/.*tvRating='([^']*).*/$1/; + if ($tvRating eq $line) { + $tvRating = ""; + } + $stereo = $line; + $stereo =~ s/.*stereo='([^']*).*/$1/; + if ($stereo eq $line) { + $stereo = ""; + } + $hdtv = $line; + $hdtv =~ s/.*hdtv='([^']*).*/$1/; + if ($hdtv eq $line) { + $hdtv = ""; + } + $subtitled = $line; + $subtitled =~ s/.*subtitled='([^']*).*/$1/; + if ($subtitled eq $line) { + $subtitled = ""; + } + $closeCaptioned = $line; + $closeCaptioned =~ s/.*closeCaptioned='([^']*).*/$1/; + if ($closeCaptioned eq $line) { + $closeCaptioned = ""; + } + if ($line =~ /\/>/) { + $endrec = 1; + }else{ + $endrec = 0; + } + } + + if ($line =~ /<part number/) { + $partnumber = $line; + $partnumber =~ s/.*number='([^']*).*/$1/; + $parttotal = $line; + $parttotal =~ s/.*total='([^']*).*/$1/; + $part = "Part $partnumber of $parttotal"; + } + + if ($line =~ /<\/schedule>/) { + $endrec = 1; + } + + + if ($endrec) { + + #---------------------------------------- + # Build Record and Normalize Data + #---------------------------------------- + + ($program_tmsprgid,$program_title,$program_subtitle,$program_desc,$program_mpaarating,$program_starrating,$program_runtime,$program_movieyear,$program_advisories) = split(/\|/,$programarray{$programid}); + ($program_tmsid,$program_channel,$program_channelname,$program_affiliate,$program_displaynumber,$program_tuning) = split(/\|/,$stationarray{$stationid}); + + $program_category = $categoryarray{$programid}; + + #---------------------------------------- + # convert $time to timestring and then to + # local and then to a local timestring + #---------------------------------------- + + $timeGMT = substr($starttime,0,4) . substr($starttime,5,2) . substr($starttime,8,2) . substr($starttime,11,2) . substr($starttime,14,2) . substr($starttime,17,2); + $eventtime = as_epoch_seconds($timeGMT); + $hour = substr($duration,2,2); + $minutes = substr($duration,5,2); + $program_length = ($hour * 60) + $minutes; + $starttime = timegm(localtime($eventtime)); + + $stoptime = $starttime + ($program_length * 60); + $program_start = as_time_string($starttime); + $program_stop = as_time_string($stoptime); + + # Adjust Fields + + if ($repeat eq 'true') { + $program_repeat = 1; + }else{ + $program_repeat = 0; + } + + if ($stereo eq 'true') { + $program_audio = 1; + }else{ + $program_audio = 0; + } + + if ($closeCaptioned eq 'true') { + $program_captions = $closeCaptioned; + }else{ + $program_captions = ""; + } + + if ($subtitled eq 'true') { + $program_issubtitled = 1; + }else{ + $program_issubtitled = 0; + } + + + if (substr($program_tmsprgid,0,2) eq 'MV') { + $program_ismovie = 1; + }else{ + $program_ismovie = 0; + } + + if ($tvRating =~ /-/) { + $program_vchiprating = substr($tvRating,3); + }else{ + $program_vchiprating = substr($tvRating,2); + } + $program_episodenum = $part; + + if (length($program_starrating) > 0) { + my $starsize = length($program_starrating); + if (substr($program_starrating,$starsize-1,1) eq "+") { + $starsize--; + if ($starsize < 0) { + $starsize = 0; + } + $starsize = $starsize + .5; + } + $program_starrating = "$starsize/4"; + } + + if ($do_titlemap) { + $program_title = &mapTitle($program_title); + } + + if ($do_channelmap) { + ($program_tuning,$program_channel) = &mapChannel($program_tuning,$program_channel); + } + + +# $program_tuning = $program_tuning + ($iteration * $multiplier); + + + $Stmt = ""; + $dataok = 1; + + $program_title = filterfield(convertfromhtml($program_title)); + $program_desc = filterfield(convertfromhtml($program_desc)); + $program_subtitle = filterfield(convertfromhtml($program_subtitle)); + $program_category = filterfield($program_category); + $program_advisories = filterfield($program_advisories); + $program_tmsprgid = filterfield($program_tmsprgid); + $program_vchiprating = filterfield($program_vchiprating); + $program_episodenum = filterfield($program_episodenum); + + ($Y,$M,$D,$h,$m,$s) = unpack 'A4 A2 A2 A2 A2 A2', $program_start; + $program_start = "$Y-$M-$D $h:$m:$s"; + + ($Y,$M,$D,$h,$m,$s) = unpack 'A4 A2 A2 A2 A2 A2', $program_stop; + $program_stop = "$Y-$M-$D $h:$m:$s"; + + + $FieldNames = $null; + $FieldNames .= "tmsprogramid, tmsid, "; + $FieldNames .= "starttime, endtime, tuning, "; + $FieldNames .= "channel, title, subtitle, "; + $FieldNames .= "description, category, stereo, "; + $FieldNames .= "captions, episodenum, vchiprating, "; + $FieldNames .= "mpaarating, starrating, movieyear, "; + $FieldNames .= "repeat, movie, subtitled, "; + $FieldNames .= "advisories"; + + $FieldValues = $null; + $FieldValues .= "'$program_tmsprgid', $program_tmsid, "; + $FieldValues .= "'$program_start', '$program_stop', $program_tuning, "; + $FieldValues .= "'$program_channel', '$program_title', '$program_subtitle', "; + $FieldValues .= "'$program_desc', '$program_category', $program_audio, "; + $FieldValues .= "'$program_captions', '$program_episodenum', '$program_vchiprating', "; + $FieldValues .= "'$program_mpaarating', '$program_starrating', '$program_movieyear', "; + $FieldValues .= "$program_repeat, $program_ismovie, $program_issubtitled, "; + $FieldValues .= "'$program_advisories'"; + + if ($dataok) { + if ($do_not_insert) { + writeDebug("SQL Insert Disabled, Writing to CSV:"); + + print CSVFILE $FieldValues; + print CSVFILE "\n"; + + }else{ + $Stmt = "INSERT INTO $db_table_tvlistings ($FieldNames) VALUES ($FieldValues);"; + +######### +# DEBUG +# +# print DEBUG "$rows:$Stmt\n"; +# +######## + if (sqlStmt($prgdb_handle,$Stmt)) { + $rows++; + $dotctr++; + }else{ + my $sql_error = &GetLastSQLError() . "\n(" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error at record $rows"); + + } + } + } + + if ($dotctr == $dotinterval) { + if ($verbose) { + displayText(".",0,1); + } + $dotctr = 0; + } + + if ($maxrows) { + if ($rows > $maxrows) { + close LISTINGS; + if ($do_not_insert) { + close CSVFILE; + } + abend("Done! Max Rows Reached ($maxrows)"); + } + } + + $endrec = 0; + } + + } until ($original_line =~ /<\/schedules>/); + + close LISTINGS; + writeDebug("Done!"); + writeDebug("$xml_file: Processing Complete!"); + $iteration++; +} + + +if ($do_not_insert) { + close CSVFILE; + close CSVFILE2; + $rows = 0; +}else{ + writeDebug("$rows rows were added"); +} + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Terminating Database Connection from $DATASOURCE{DSN} ($prgdb_handle)"); +endDSN("",$prgdb_handle); + +writeDebug("Job finished at $now ($runtime seconds)"); + +if ($rows) { + writeDebug("Dispatching rg_refresh"); + require 'rg_refresh.pl'; # Load RTV refresh functions + identifyLoadedModules('rg_refresh.pl'); # ID + refreshRTV($verbose); # Refresh + writeDebug("Returned from rg_refresh"); + $retcode = 1; +} + +&ShowHTTPFooter; + +writeDebug("********************************************************"); + +exit($retcode); + +#---------------------------------------------------------------------------- +sub mapChannel { + # + # Remap Channel (Tuning,ChannelID) + # + # Returns (Tuning,ChannelID) + # + # ------------------------------------------------------------------------------ + + my $tuning = shift; + my $channelid = shift; + + if ($cmap_ctr < 1) { + return ($tuning,$channelid); + } + + my $before = ""; + my $after = ""; + my $ctr = 0; + + do { + $ctr++; + ($before,$after) = split('=', $channelmap[$ctr], 2); + + if ($before eq "$channelid,$tuning") { + ($channelid,$tuning) = split(',', $after, 2); + } + + } while ($ctr <= $cmap_ctr); + + return ($tuning,$channelid); +} + +#---------------------------------------------------------------------------- +sub mapTitle { + # + # Remap Title (Title) + # + # Returns (Title) + # + # ------------------------------------------------------------------------------ + + my $title = shift; + + if ($tmap_ctr < 1) { + return $title; + } + + my $before = ""; + my $after = ""; + my $ctr = 0; + + do { + $ctr++; + ($before,$after) = split('=', $titlemap[$ctr], 2); + + if ($before eq $title) { + $title = $after; + } + + } while ($ctr <= $tmap_ctr); + + return $title; +} diff --git a/datadirect_client.pl b/datadirect_client.pl new file mode 100644 index 0000000..0349a7e --- /dev/null +++ b/datadirect_client.pl @@ -0,0 +1,411 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide SQL Converter +# by Lee Thompson <thompsonl@logh.net> +# +# Requirements: +# DataDirect Service +# +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- +# +# Zap2It DataDirect Service +# +# Use of DataDirect with Personal ReplayGuide is free, although you will need to +# fill out a quarterly survey for Zap2It (Tribune Media Services). +# +# To sign up for the service, please visit http://datadirect.zap2it.com and click +# to use the DataDirect service for free. It's fairly short and largely +# related to PVRs and television anyway. +# +# The DataDirect Personal ReplayGuide/ReplaySchedule Certificate Code is: +# DGYM-ZKZM-CBUT +# +# All users and developers for Personal ReplayGuide may use this certificate code. +# (Including replaySchedule). +# +# NOTE TO DEVELOPERS: DO NOT use the certificate code within this document for non +# Personal ReplayGuide projects. Instead please write to labs@zap2it.com and request +# your own certificate code. +# +#----------------------------------------------------------------------------------- +# NOTE: If you select multiple lineups that have the same feeds (like two SCIFIPs) +# the lowest channel number will appear. +#----------------------------------------------------------------------------------- + +use POSIX qw( strftime getcwd ); +use English; +use Time::Local; +use SOAP::Lite; +use Unicode::String; +use bytes; +Unicode::String->stringify_as( 'latin1' ); + +require LWP::Simple; +require LWP::UserAgent; +require HTTP::Request; +require HTTP::Headers; + +my $_version = "Personal ReplayGuide|DataDirect Client|1|0|24|Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; # Load common functions +require 'rg_config.pl'; # Load config functions + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Set Defaults and Read Config +#----------------------------------------------------------------------------------- + +$retcode = 0; +$htmlmode = 0; +$webservice = "http://docs.tms.tribune.com/tech/tmsdatadirect/zap2it/xtvd.wsdl"; +$username = "username"; # Username for DataDirect +$password = "password"; # Password for DataDirect +$days = 3; # Default Days to Download +$verbose = 1; # If this is zero, run silently +$cnf_xmlfile = "./na.xml"; # Output File +$configfile = "datadirect.conf"; # This is optional +$configstatus = getConfig($configfile); # Read Configuration + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$null = ""; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + $remotemode = 1; +} + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +if ($debug) { + &writeOutput("Debug Messages are ON"); +} + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; # Disabled +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + + + +#------------------------------------------------------------------- + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + +$starttime_seconds = as_epoch_seconds(strftime( "%Y%m%d%", gmtime ) . "000000" ); +$endtime_seconds = $starttime_seconds + ((($days * 24) * 60) * 60); + +$starttime_ts = as_time_string($starttime_seconds); +$endtime_ts = as_time_string($endtime_seconds); + +$starttime = substr($starttime_ts,0,4) . "-" . substr($starttime_ts,4,2) . "-" . substr($starttime_ts,6,2) . "T" . substr($starttime_ts,8,2) . ":" . substr($starttime_ts,10,2) . ":" . substr($starttime_ts,12,2) . "Z"; +$endtime = substr($endtime_ts,0,4) . "-" . substr($endtime_ts,4,2) . "-" . substr($endtime_ts,6,2) . "T" . substr($endtime_ts,8,2) . ":" . substr($endtime_ts,10,2) . ":" . substr($endtime_ts,12,2) . "Z"; + +writeDebug("Job started at $now"); +writeDebug("Requesting up to $days days of data from DataDirect"); + +if ($debug) { + writeDebug("DEBUG: Range is $starttime - $endtime"); +} + +if ($debug) { + writeDebug("DEBUG: Account: $username Password: $password"); +} + +writeDebug("Building SOAP Object for $webservice"); + +$soapenv = SOAP::Lite + -> service($webservice) + -> outputxml('true') + -> on_fault( sub { + my($soap,$res)=@_; + writeDebug("FATAL ERROR - SOAP call failed: " . + (ref $res ? $res->faultstring : $soap->transport->status)); + exit 1; + } ); + +writeDebug("SOAP Object Completed"); + +writeDebug("Starting Data Download"); + + +$xtvddoc = $soapenv + -> proxy('http://notused/', options => {compress_threshold => 10000}, timeout => 420) + -> download("<startTime>$starttime</startTime><endTime>$endtime</endTime>"); + +writeDebug("Data Download Complete"); + +$accessdenied = 0; +$message = ""; + +writeDebug("Converting to UTF8"); + +$xtvddoc = Unicode::String::utf8( $xtvddoc ); + +writeDebug("Conversion Complete"); + +writeDebug("Checking for Errors"); + +if ($xtvddoc =~ "<HTML><HEAD><TITLE>401") { + writeDebug("FATAL ERROR - DataDirect->Access Denied"); + $accessdenied = 1; + $xtvddoc = ""; +} + +if ($xtvddoc =~ "<HTML><HEAD><TITLE>500") { + writeDebug("FATAL ERROR - DataDirect->Server Error"); + $message = $xtvddoc; + $message =~ s/.*<PRE>([^<]*)\W.*/$1/; + if ($message eq $xtvddoc) { + $message = ""; + } + $xtvddoc = ""; +} + +if ($xtvddoc =~ "<HTML><HEAD><TITLE>") { + writeDebug("FATAL ERROR - DataDirect: Unknown Error"); + $xtvddoc = ""; +} + +writeDebug("Check Complete"); + +writeDebug("Looking for Data Block"); + +if ($xtvddoc =~ m#(<xtvd\s.*</xtvd>)#s) { + writeDebug("Found Data Block"); + + writeDebug("Writing Data"); + + if (open(HOUTPUT,">$cnf_xmlfile")) { + binmode HOUTPUT; + print HOUTPUT $xtvddoc; + close HOUTPUT; + writeDebug("Wrote data successfully to \"$cnf_xmlfile\"."); + }else{ + writeDebug("Attempt to write data to \"$cnf_xmlfile\" failed."); + } + + $exitflag = 0; + + if(open(HINPUT,"<$cnf_xmlfile")) { + do { + $line = readline HINPUT; + chomp($line); + if ($line =~ /message/) { + $message = $line; + $message =~ s/.*<message>([^<]*)\W.*/$1/; + if ($message eq $line) { + $message = ""; + } + } + if ($line =~ /faultstring/) { + $message = $line; + $message =~ s/.*<faultstring>([^<]*)\W.*/$1/; + if ($message eq $line) { + $message = ""; + } + $exitflag = 1; + } + + if ($line =~ /<\/messages>/) { + $exitflag = 1; + } + if ($line =~ /<messages\/>/) { + $message = ""; + $exitflag = 1; + } + } until ($exitflag > 0); + + close HINPUT; + + if (length($message) > 0) { + writeDebug("From DataDirect: $message"); + $message = ""; + }else{ + writeDebug("No alerts or messages from DataDirect"); + $retcode = 1; + } + + } + + + +}else{ + writeDebug("No Data Block"); + + if (!$accessdenied) { + if (length($message) > 0) { + writeDebug("$message"); + }else{ + writeDebug("Error: $xtvddoc"); + } + }else{ + writeDebug("Access was denied"); + } +} + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Job finished at $now ($runtime seconds)"); + +&ShowHTTPFooter; + +writeDebug("********************************************************"); + +exit($retcode); + +#---------------------------------------------------- +sub SOAP::Transport::HTTP::Client::get_basic_credentials { + # + # Callback for HTTP Login Info + # + # ------------------------------------------------------------------------------ + return "$username" => "$password"; +} + diff --git a/datadirect_update.bat b/datadirect_update.bat new file mode 100644 index 0000000..b7e7324 --- /dev/null +++ b/datadirect_update.bat @@ -0,0 +1,2 @@ +perl datadirect_client.pl +perl datadirect2sql.pl diff --git a/getchannelicons.pl b/getchannelicons.pl new file mode 100644 index 0000000..af5e10d --- /dev/null +++ b/getchannelicons.pl @@ -0,0 +1,642 @@ +#!/usr/bin/perl +# +#------------------------------------------------------------------------------------ +# $Id: getchannelicons.pl,v 1.3 2003/07/19 13:34:39 pvanbaren Exp $ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#------------------------------------------------------------------------------------ + +use POSIX qw( strftime getcwd ); + +#------------------------------------------------------------- +# Subclass LWP::UserAgent to permit redirected POST methods +#------------------------------------------------------------- + +package RedirectUserAgent; +use LWP::UserAgent; +@ISA = qw(LWP::UserAgent); +sub redirect_ok { 1; } + +package main; +use LWP::Simple; +use LWP::UserAgent; +use HTTP::Cookies; +use HTTP::Request::Common; + +my $_version = "Personal ReplayGuide|Get Channel Icons|1|0|23|J.M.,Philip Van Baren,Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_config.pl'; # Load config functions +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Database Info + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Set Defaults and Read Config +#----------------------------------------------------------------------------------- + +$providerid = 0; +$zipcode = 0; +$channelicondir = ""; + +$debug = 0; # Debug Output +$verbose = 1; # Verbose Output +$configfile = "getchannelicons.conf"; # This is optional +$configstatus = &getConfig($configfile); # Read Configuration + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$null = ""; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + $remotemode = 1; +} + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build) $script_pathname"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +if ($debug) { + writeOutput("Debug Messages are ON"); +} + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; # Disabled +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + + +writeDebug("Job started at $now"); + +$defaultproviderid = $providerid; +$defaultzipcode = $zipcode; + +#------------------------------------------------------------------- +# Set up Database +#------------------------------------------------------------------- + +&InitDB; +&InitDSN; + +#------------------------------------------------------------------- +# Start Database +#------------------------------------------------------------------- + +$DSNLink = &StartDSN; + +if ($DSNLink ne $null) { + writeDebug("Database Connection Established to $DATASOURCE{DSN} using handle $DSNLink"); +}else{ + writeDebug("Attempt to Connect to $DATASOURCE{DSN} Failed: " . &GetLastSQLError()); + abend("Could not establish database connection!"); +} + +#------------------------------------------------------------------- +# Get Channel Icons +#------------------------------------------------------------------- + +$Stmt = ""; +$Stmt .= "SELECT * "; +$Stmt .= "FROM $db_table_channels "; +$Stmt .= "WHERE hidden = 0 "; +$Stmt .= "ORDER BY postalcode, lineupname, lineupdevice;"; + +$records = 0; + +$sth = sqlStmt($DSNLink,$Stmt); +if ( $sth ) { + while ( $row = $sth->fetchrow_hashref ) { + $tmsid = $row->{'tmsid'}; + + $channel_iconsrc = $row->{'iconsrc'}; + + #------------------------------------------------------------- + # Only do the work if there is not an icon defined. + #------------------------------------------------------------- + + if (( $tmsid ) && ( length($channel_iconsrc) == 0)) { + + #------------------------------------------------------------- + # Should be a Data Direct populated DB... + # We have to add the channel icons to the DB on our own by + # scraping Zap2It. + #------------------------------------------------------------- + + $channel_postalcode = $row->{'postalcode'}; + $channel_lineupname = $row->{'lineupname'}; + $channel_lineupdevice = $row->{'lineupdevice'}; + + #------------------------------------------------------------- + # If the extended lineup fields aren't populated, just go + # with defaults, otherwise attempt to calculate the providerid + #------------------------------------------------------------- + + if (length($channel_postalcode) > 0) { + $currentlineup = "$channel_postalcode $channel_lineupname $channel_lineupdevice"; + }else{ + $zipcode = $defaultzipcode; + $providerid = $defaultproviderid; + $currentlineup = ""; + $prevlineup = ""; + } + + if ($currentlineup ne $prevlineup) { + $iconlist = ""; + + writeDebug("Lineup: $currentlineup"); + + $channel_providerid = getProviderID($channel_postalcode,$channel_lineupname,$channel_lineupdevice); + + writeDebug("getProviderID returned $channel_providerid"); + + if ($channel_postalcode ne $null) { + $zipcode = $channel_postalcode; + }else{ + $zipcode = $defaultzipcode; + writeDebug("Using default zipcode ($zipcode)"); + } + + if ($channel_providerid != 0) { + $providerid = $channel_providerid; + }else{ + $providerid = $defaultproviderid; + writeDebug("Using default providerid ($providerid)"); + } + + } + + + #------------------------------------------------------------- + # Try to get an icon. If providerid is 0 or zipcode is null + # getChannelIconURL will return null immediately. + #------------------------------------------------------------- + + $channel_iconsrc = getChannelIconURL($tmsid); + + if ( $channelicondir ) { + downloadChannelIcon($channel_iconsrc); + } + + if (length($channel_iconsrc) > 0) { + #------------------------------------------------------------- + # If we got an icon, update the table. + #------------------------------------------------------------- + + $channel_iconsrc = filterfield($channel_iconsrc); + + my $db_handle = &StartDSN; + + my $Stmt = "UPDATE $db_table_channels SET iconsrc = '$channel_iconsrc' WHERE tmsid = '$tmsid';"; + + if ( sqlStmt($db_handle,$Stmt) ) { + writeDebug("$tmsid: Updated with $channel_iconsrc"); + $records++; + } else { + writeDebug("Attempt to update table $db_table_channels Failed: " . &GetLastSQLError()); + abend("Failed to update table: $db_table_channels."); + } + + endDSN("",$db_handle); + undef $Stmt; + }else{ + writeDebug("$tmsid: Could not find an icon"); + } + + } else { + + #------------------------------------------------------------- + # Probably an XMLTV populated DB... + # The channel icons should already be in the DB. + #------------------------------------------------------------- + + $channel_iconsrc = $row->{'iconsrc'}; + if ( $channelicondir ) { + downloadChannelIcon($channel_iconsrc); + } + } + + $prevlineup = $currentlineup; + } +}else{ + abend("Error getting icons"); + $retcode = 0; +} + + +if ($records > 0) { + $retcode = 1; +} + +writeDebug("$records icons added"); + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Terminating Database Connection from $DATASOURCE{DSN} ($DSNLink)"); + +endDSN($sth,$DSNLink); + +writeDebug("Job finished at $now ($runtime seconds)"); + +&ShowHTTPFooter; + +writeDebug("********************************************************"); + +exit($retcode); + +#---------------------------------------------------------------------------- +sub getProviderID { + # + # Gets the provider list and tries to match it with the arguments passed in + # (PostalCode,LineupName,LineupDevice) + # + # Returns providerid or 0. + # + # ------------------------------------------------------------------------------ + + my $postalcode = shift; + my $lineupname = shift; + my $lineupdevice = shift; + my $providerid = 0; + my $buffer = ""; + my $specialdebug = 0; + + my $ua = RedirectUserAgent->new( + cookie_jar => HTTP::Cookies->new(), + ); + + my $req = POST('http://tvlistings2.zap2it.com/zipcode.asp?partner_id=national&zipcode=$postalcode', + [ + zipcode => "$postalcode", + partner_id => "national", + FormName => "zipcode.asp", + ]); + + if ($debug) { + writeDebug("getProviderID::Connecting to Zap2It... ",1); + } + + my $res = $ua->request($req); + + if ($debug) { + writeDebug("Done!"); + } + + if ($debug) { + writeDebug(" REQUEST: $req->as_string"); + writeDebug("RESPONSE: $res->as_string"); + } + + $buffer = $res->content(); + + if ( $buffer =~ /\<select name=\"provider\" size=\"4\"\>/i ) { + + (my $junk, my $option1, my $junk2) = split ( /\<select name=\"provider\" size=\"4\"\>/i, $buffer, 3); + (my $optionlist, my $junk3) = split ( /\<\/select\>/, $option1, 2); + + $optionlist =~ s/\ //g; + my @options = split(/\<\/option\>/,$optionlist); + + foreach my $option ( @options ) { + (my $optionvalue,my $optiondesc) = split(/\>/,$option); + my $optionid = $optionvalue; + $optionid =~ s/.*<option value=\"([^\"]*).*/$1/; + (my $o_lineup,my $o_city,my $o_device) = split(/ - /,$optiondesc); + + if ($specialdebug) { + writeDebug("$optionid: $o_lineup,$o_city,$o_device"); + } + + if ($specialdebug) { + writeDebug("Checking " . substr($lineupname,0,31) . "==" . substr($o_lineup,0,31) . "?"); + } + + if (substr($lineupname,0,31) eq substr($o_lineup,0,31)) { + if ($specialdebug) { + writeDebug("Checking " . substr($lineupname,0,31) . "==" . substr($o_lineup,0,31) . " MATCH"); + } + + if ($specialdebug) { + writeDebug("Checking " . substr($lineupdevice,0,31) . "==" . substr($o_device,0,31) . "?"); + } + if (substr($lineupdevice,0,31) eq substr($o_device,0,31)) { + if ($specialdebug) { + writeDebug("Checking " . substr($lineupdevice,0,31) . "==" . substr($o_device,0,31) . " MATCH ($optionid)"); + } + + $providerid = $optionid; + } + } + } + } + + return $providerid; +} + +#---------------------------------------------------------------------------- +sub GetChannelIconList { + # + # Returns one day's worth of listings from Zap2It from which to scrape icons + # + # ------------------------------------------------------------------------------ + +# Code below only works on Perl 5.8+ so we use RedirectUserAgent, a subclassed LWP::UserAgent +# my $ua = LWP::UserAgent->new( +# requests_redirectable => ['GET', 'HEAD', 'POST'], +# cookie_jar => HTTP::Cookies->new(), +# ); + + my $ua = RedirectUserAgent->new( + cookie_jar => HTTP::Cookies->new(), + ); + + my $req = POST('http://tvlistings2.zap2it.com/system.asp?partner_id=national&zipcode=$zipcode&id=form1&name=form1', + [ + provider => "$providerid", + zipcode => "$zipcode", + FormName => "system.asp", + page_from => "", + saveProvider => "See Listings" + ]); + + if ($debug) { + writeDebug("GetChannelIconList::Connecting to Zap2It... ",1); + } + + my $res = $ua->request($req); + + if ($debug) { + writeDebug("Done!"); + } + + if ($debug) { + writeDebug(" REQUEST: $req->as_string"); + writeDebug("RESPONSE: $res->as_string"); + } + + #----------------------------------------- + # Get the all the values for current time + #----------------------------------------- + my ($Second, $Minute, $Hour, $Day, $Month, $Year, $WeekDay, $DayOfYear, $IsDST) = localtime(time); + + #----------------------------------------- + # Increment the month by 1 because in Perl months of the year are zero-based + #----------------------------------------- + + my $RealMonth = $Month + 1; + + #----------------------------------------- + # Add 1900 to the year because in Perl + # year is reported as the number of years + # since 1900. + #----------------------------------------- + + my $Fixed_Year = $Year + 1900; + + $req = POST('http://tvlistings2.zap2it.com/listings_redirect.asp?partner_id=national&id=form1&name=form1', + [ + displayType => "Grid", + duration => "1", + startDay => "$RealMonth/$Day/$Fixed_Year", + startTime => "0", + category => "0", + station => "0", + rowdisplay => "0", + goButton => "GO" + ]); + + if ($debug) { + writeDebug("GetChannelIconList::Retrieving icon listing... ",1); + } + + $res = $ua->request($req); + + if ($debug) { + writeDebug("Done!"); + } + + if ($debug) { + writeDebug(" REQUEST: $req->as_string"); + writeDebug("RESPONSE: $res->as_string"); + } + + return $res->content(); +} + +#---------------------------------------------------------------------------- +sub getChannelIconURL { + # + # Get URL of Channel Icon (TMS Channel ID) + # + # Returns (Icon URL) + # + # ------------------------------------------------------------------------------ + + my $tmsid = shift; + my $channel_iconsrc = ""; + + if (($providerid eq $null) || ($zipcode eq $null) || ($providerid == 0)) { + #----------------------------------------------------- + # Absolutely no reason to do anything + #----------------------------------------------------- + + return; + } + + #-------------------------------------------------------- + # Only get the listings page from Zap2It once per lineup + #-------------------------------------------------------- + + if ($iconlist eq "") { + $iconlist = &GetChannelIconList; + } + + if ( $iconlist =~ /<img src="(.*)"><br>\s*<b><a href="listings_redirect.asp\?station_num=$tmsid/i ) { + $channel_iconsrc = "http://tvlistings2.zap2it.com$1"; + if ($debug) { + writeDebug("getChannelIconURL::Channel ID: $tmsid\nIcon: $channel_iconsrc"); + if (!$channelicondir) { + # + } + } + } else { + $channel_iconsrc = ""; + if ($debug) { + writeDebug("getChannelIconURL::Channel ID: $tmsid\nIcon: not found"); + } + } + + return $channel_iconsrc; +} + +#---------------------------------------------------------------------------- +sub downloadChannelIcon { + # + # Download Channel Icon (Icon URL) + # + # ------------------------------------------------------------------------------ + + my $channel_iconsrc = shift; + if( $channel_iconsrc ) { + if ($debug) { + writeDebug("downloadChannelIcon::Fetching icon... ",1); + } + my $filename = (reverse split(/\//,$channel_iconsrc))[0]; + if ( is_error( getstore($channel_iconsrc, "$channelicondir/$filename") ) ) { + if ($debug) { + writeDebug("Error!"); + } + } else { + if ($debug) { + writeDebug("Done!"); + } + } + } + + return 1; +} + + diff --git a/geticons.bat b/geticons.bat new file mode 100644 index 0000000..d4fa4bb --- /dev/null +++ b/geticons.bat @@ -0,0 +1,16 @@ +wget http://my.replaytv.com/images/x_+00-.gif +wget http://my.replaytv.com/images/x_-00+.gif +wget http://my.replaytv.com/images/x_+00+.gif +wget http://my.replaytv.com/images/x_-00-.gif +wget http://my.replaytv.com/images/x_-oo-.gif +wget http://my.replaytv.com/images/x_+oo-.gif +wget http://my.replaytv.com/images/x_-oo+.gif +wget http://my.replaytv.com/images/x_+oo+.gif +wget http://my.replaytv.com/images/x_-0-.gif +wget http://my.replaytv.com/images/x_-o-.gif +wget http://my.replaytv.com/images/x_+0-.gif +wget http://my.replaytv.com/images/x_-0+.gif +wget http://my.replaytv.com/images/x_+0+.gif +wget http://my.replaytv.com/images/x_+o-.gif +wget http://my.replaytv.com/images/x_-o+.gif +wget http://my.replaytv.com/images/x_+o+.gif diff --git a/logo_ndrake.jpg b/logo_ndrake.jpg new file mode 100644 index 0000000..e998b65 Binary files /dev/null and b/logo_ndrake.jpg differ diff --git a/prg.conf.dist b/prg.conf.dist new file mode 100644 index 0000000..35c411a --- /dev/null +++ b/prg.conf.dist @@ -0,0 +1,1132 @@ +#********************************************************************** +# Personal ReplayGuide Configuration File +# Global Configuration File +#********************************************************************** +# You will need to edit this file before you can start using +# Personal ReplayGuide. +# +# Individual conf files aren't required from build 191 and higher but +# can still be used if this file is missing or if the module's section +# is missing. (A section is denoted with [module].) +# +#*********************************************************************** +# SEE rg_info.pl for defining favorite channel groups and listing maps! +#*********************************************************************** +# COMMENTS +# +# If a # // or ; appears in the first position on a line the entire +# line is a comment. +# +# Inline Comments are now available also with a # // or ; there is a +# limitation that double comment characters aren't seen as comments. +# There has to be at least one non-whitespace character between them. +# +# Works: RIGHT +# myoption=myvalue # this is my value +# eg. "myvalue" +# +# Doesn't Work: WRONG +# myoption=myvalue ## this is my value +# eg. "myvalue # this is my value" +# +#---------------------------------------------------------------------- +# SECURITY NOTE: +# +# If open to the public reading this .conf file via the web server +# should be disabled/prevented by setting permissions on the file or +# blocking the .conf file type. +# +# Consult your web server's documentation for specifics. +# +#---------------------------------------------------------------------- + +#********************************************************************** +# GLOBAL OPTIONS +#********************************************************************** +# Global Options take priority over local ones. If you'd rather it be +# the other way, edit rg_config.pl +#---------------------------------------------------------------------- + +[global] + +#---------------------------------------------------------------------- +# Debugging +#---------------------------------------------------------------------- +# This flag controls debug messages. Generally you'll want this set +# to 0 unless you're troubleshooting or programming. + +debug=0 + +#---------------------------------------------------------------------- +# Data Feeds +#---------------------------------------------------------------------- +# This controls various functions concerning the data feed of your tv +# listings in relation to Personal ReplayGuide. +# +# Valid Feeds are "xmltv" and "datadirect". Consult the data feed +# documentation for more information. +# +# xmlfile is the XML file used by the Data Feed. Generally you can +# leave this set as is. + +datafeed=xmltv +xmlfile=./na.xml + +#---------------------------------------------------------------------- +# Schedule Resolver Modules (SRMs) +#---------------------------------------------------------------------- +# By default, Personal ReplayGuide uses a simple module called +# rg_guide.pl - this module is slow and does not offer advanced +# features such as TO DO lists, Schedule Bar or full conflict +# resolution for scheduling status. +# +# If you are using Personal ReplayGuide with one or more ReplayTVs, +# we highly recommend that you download replaySchedule and select +# rg_scheduler.pl as your schedule resolver module for best results. +# +# rg_null Disables all SRM functions. If you do not have any +# RTV units defined (run configure.pl to define them) +# this will run automatically regardless of setting. +# +# rg_guide Simple, slow and limited schedule resolver module. +# +# rg_scheduler Advanced schedule resolver module which uses the +# binary replaySchedule for processing. +# http://replayguide.sourceforge.net/replaySchedule +# +# schedule2sql Part of the rg_scheduler package. Defaults to +# "schedule2sql.pl" so unless you've renamed it +# you can leave the schedule2sql= line commented out. + +scheduler=rg_guide.pl +# scheduler=rg_scheduler.pl +# schedule2sql=schedule2sql.pl + +#---------------------------------------------------------------------- +# Logging +#---------------------------------------------------------------------- +# If missing or empty, logging is disabled. Otherwise logging will be +# done to the path/filename given. eg. c:\logfiles\prg.log +# +# Obviously the process running the perl interpreter will need write +# permission. +# +# When initially testing Personal ReplayGuide it is recommended that +# you enable logging. +# +# NOTE: Setting logfile under global will enable logging for ALL +# modules. +# +# logfile= +# +# NOTE: You can have the logging routine add the module as a prefix +# (eg: replayguide::log message instead of just log message). +# +# To enable add logmodulename=1 + +logfile=prg.log + +#---------------------------------------------------------------------- +# Access List +#---------------------------------------------------------------------- +# Access list controls what connecting IP addresses can see what you +# have scheduled or schedule new shows. +# +# The format is comma delimited IP addresses. +# Wildcards and ranges are not permitted. +# +# To shut off permissions: +# Everyone: ALL +# No One: NONE +# +# Setting allow=NONE will *disable* all ReplayTV integration. +# +# Setting allow=ALL will allow everyone who can access your server to +# see what you have scheduled and make new schedule requests. +# NOTE: They will NOT be allowed to watch or delete shows. +# + +allow=ALL + +# Examples: +# allow=192.168.0.3,192.168.0.4 + +#---------------------------------------------------------------------- +# PDA List +#---------------------------------------------------------------------- +# PDA list controls what connecting IP addresses are using PDA +# devices (dimensions of 240x320 or so). +# +# The format is comma delimited IP addresses. +# Wildcards and ranges are not permitted. +# +# Everyone: ALL +# No One: NONE +# +# Setting allow=NONE will shut off the PDA List by IP. +# +# Generally if you're going to do ALL or NONE you should just use +# showpdaformat. +# +# Setting allow=ALL will allow force everyone who can access your server +# to PDA format. +# + +pda=NONE + +# Examples: +# pda=192.168.0.3,192.168.0.4 + + + +#---------------------------------------------------------------------- +# Web Server Virtual Directory Locations +#---------------------------------------------------------------------- +# +# wwwdir is the root of your web pages. Usually / +# +# scriptdir is the location of your perl scripts. +# +# imagedir is where local images for Personal ReplayGuide are located. +# +# scriptname is the full name of the script. If your web server uses +# a different extension for perl scripts, change it here. +# +# schedulename is the full name of the ReplayTV Recording Scheduler +# script. If your web server uses a different extension for perl +# scripts, change it here. +# +# usingapache should be set to 1 if your web server does NOT require +# "HTTP/1.0 200 OK" to be sent (like Apache). +# NOTE: If you are using mod_perl this will be detected automatically. + +wwwdir=/ +scriptdir=/cgi +imagedir=/cgi/images +scriptname=replayguide.pl +schedulename=schedule.pl +usingapache=0 + +#---------------------------------------------------------------------- +# Fonts and Colors +#---------------------------------------------------------------------- +# +# headingbackgroundcolor is the background color of the header row. +# +# headingtextcolor is the foreground color of the header row. +# +# backgroundcolor is the general background color. +# +# textcolor is the general text color. +# +# visitedlinkcolor is the color of links that have been clicked on. +# +# activelinkcolor is the color of the link currently highlighted. +# +# linkcolor is the color of links that have not been visited or +# highlighted. +# +# titlefont is the name of the font to use for titles. +# +# menufont is the name of the font for the menu section. +# + +image_logo=replaytvlogo.jpg + +#********************************************************************** +# End of Global Settings +#********************************************************************** + + +#********************************************************************** +# DATABASE SETTINGS +#********************************************************************** +# These options configure Personal ReplayGuide to interact with your +# database. +#---------------------------------------------------------------------- + +[database] + +#---------------------------------------------------------------------- +# Database Settings +#---------------------------------------------------------------------- +# +# The default database now included in Personal ReplayGuide is +# SQLite which is a free database system available for most platforms. +# +# If you wish to use SQLite support, you don't need to make any changes +# to this section. +# +#---------------------------------------------------------------------- +# driver is which DBD driver to use. Supported are: ODBC, mysql and +# SQLite. ODBC covers a wide range but most of the testing has +# been done with Microsoft SQL Server 2000 Developer's Edition. +# Chances are Microsoft Access won't work with modification since it's +# SQL syntax is a little different. +# +# username is the SQL userid to use. It needs read, write, delete and +# update permissions. Not used with SQLite. +# +# password is the SQL password to use with the userid. +# Not used with SQLite. +# +# host is the machine that SQL is on (if the SQL server you are using +# supports network). If it's on the same machine, leave it at the +# default of localhost. NOTE: ODBC users should leave it as +# localhost even if the System DSN is talking to a remote machine. +# +# database is the name of the database, DSN, instance or filename +# to talk to (the type depends on which database you are using.) +# +# table_replayunits, table_channels, table_tvlistings, table_schedule +# and table_castcrew allow the use of different table names than the +# default. These should be left alone unless you know what you are +# doing. +# (NOTE: sqlconfig is aware of these settings so if you change them +# and only use sqlconfig you will be fine.) +# +# dsn is the ODBC connection name *IF* different from the database name. +# Having these separate will cause a slight performance hit since the +# core SQL routine will do "USE database;" for you. It is also a +# better idea to have the ODBC DSN switch to the database for you +# from a security standpoint. +# + +driver=SQLite +username= +password= +host=localhost +database=tvlistings + +# table_replayunits=replayunits +# table_channels=channels +# table_tvlistings=tvlistings +# table_schedule=schedule +# table_castcrew=castcrew + +#********************************************************************** +# DataDirect DataFeed +#********************************************************************** +# See DATADIRECT.txt for information on setting up an account. it is +# free for all Personal ReplayGuide users. +#---------------------------------------------------------------------- + +[datadirect] + +#---------------------------------------------------------------------- +# DataDirect Client +#---------------------------------------------------------------------- +# +# username is the DataDirect username. +# +# password is the password for the DataDirect account. +# +# days is the number of days of listings to download. Maximum is 14. +# (Roughly DataDirect takes about 10 seconds per day of listings) +# +# verbose controls if the client runs silently or not. It's +# recommended that this be set to 1 until you're sure it's working. +# +# webservice is the URL for the WSDL for the SOAP client to download +# from. This shouldn't need to be changed from the automatic +# default. +# +# debug controls debug information (note, this doesn't log to a +# logfile but outputs to STDOUT). +# +# xmlfile is the file to store the data in. Generally you should +# define this in the global section. +# +# allow is a comma limited list of IP addresses allowed to run +# the script in CGI mode. This isn't yet available. +# +# client is the client for the datafeed. +# This should be a fully qualified pathname if required. +# (Used by updatetvdata) +# +# converter is the SQL converter for the datafeed. +# This should be a fully qualified pathname if required. +# (Used by updatetvdata) +# +# parameters are the command line parameters, if any, for the datafeed +# client. +# (Used by updatetvdata) +# +# redirectoutput is a flag for the datafeed client if it just outputs +# to STDOUT. Can be a 1 (yes) or 0 (no). Default is off. +# (Used by updatetvdata) +# +# successcode is the value that the client returns to indicate a +# successful download. The default if not specified is 1. +# (Used by updatetvdata) +# +# geticons enables the automatic running of getchannelicons after +# a successful refresh. (Used by updatetvdata) (see [geticons]) +# +# geticonscript is the fully qualified (if needed) pathname to +# the script or program to download icons. (Used by updatetvdata) +# if missing this defaults to ./getchannelicons.pl +# +# showfirstaireddate determines if the premiere/first air date of the +# show or episode should be added to the description. +# +# showepisodenumber determines if the syndicator's episode number for +# the individual episode should be added to the description (please +# note that this is usually a production number and the format differs +# between shows and syndicators.) +# + + +username= +password= +days=12 +verbose=1 +client=.\datadirect_client.pl +converter=.\datadirect2sql.pl +successcode=1 +geticons=0 +showfirstaireddate=1 +showepisodenumber=1 + +#---------------------------------------------------------------------- +# Logging +#---------------------------------------------------------------------- +# If missing or empty, logging is disabled. Otherwise logging will be +# done to the path/filename given. eg. c:\logfiles\prg.log +# +# Obviously the process running the perl interpreter will need write +# permission. +# +# When initially testing Personal ReplayGuide it is recommended that +# you enable logging. +# +# NOTE: Setting logfile under global will enable logging for ALL +# modules. +# +# logfile= +# +# NOTE: You can have the logging routine add the module as a prefix +# (eg: replayguide::log message instead of just log message). +# +# To enable add logmodulename=1 + +#---------------------------------------------------------------------- +# DataDirect to SQL Converter +#---------------------------------------------------------------------- + +[datadirect2sql] + +#---------------------------------------------------------------------- +# DataDirect Support +#---------------------------------------------------------------------- +# Debugging +#---------------------------------------------------------------------- +# debug controls debug messages. Generally you'll want this set +# to 0 unless you're troubleshooting or programming. +# +# other options are: +# do_not_insert create a CSV instead of inserting to DB +# do_not_delete_rows do not drop tvlistings table rows first +# +# maxrows is the maximum number of rows to INSERT into TVLISTINGS +# (0 is unlimited) +# +# dotinterval is the number of rows before a '.' is shown for progress +# (default 500) +# +# multiplier is the increment between lineups. (default is 1000) +# +# xmlfile is the file to read from. Must match the datadirect client's +# setting. +# +# allow is a comma limited list of IP addresses allowed to run +# the script in CGI mode. This isn't yet available. +# +# logfile specifies the pathname for the log file. +# +# use_castcrew controls if cast/crew data will be imported into the +# database. This isn't implemented yet. +# +#---------------------------------------------------------------------- +# Advanced Options +#---------------------------------------------------------------------- +# titlemap refers to the config file to use for title mapping +# +# channelmap refers to the config file to use for channel mapping +# +# eg. titlemap=titlemap.conf +# +# +# CHANNEL MAP FORMAT +# OLD_CHANNELID,OLD_TUNING=NEW_CHANNELID,NEW_TUNING +# +# For example to remap TNN channel 57 to TNNP channel 69: +# TNN,57=TNNP,69 +# +# +# TITLE MAP FORMAT +# OLD_TITLE=NEW_TITLE +# +# For example: +# Lois & Clark: The New Adventures of Superman=Lois & Clark: New Adventures of Superman +# +# +# Both mapping files support comments in the exact same format as this file. +# + +#********************************************************************** +# End of DataDirect Settings +#********************************************************************** + + +#********************************************************************** +# RG_Scheduler / replaySchedule - Schedule2SQL Settings +#********************************************************************** + +[schedule2sql] + +#---------------------------------------------------------------------- +# replaySchedule (rg_scheduler) Settings +#---------------------------------------------------------------------- +# Debugging +#---------------------------------------------------------------------- +# debug controls debug messages. Generally you'll want this set +# to 0 unless you're troubleshooting or programming. +# +# other options are: +# do_not_insert create a CSV instead of inserting to DB +# do_not_delete_rows do not drop tvlistings table rows first +# +# maxrows is the maximum number of rows to INSERT into TVLISTINGS +# (0 is unlimited) +# +# multiplier is the increment between lineups. (default is 1000) +# +# xmlfile is the file to read from. +# +# replayschedule is a pathname to the replaySchedule binary. You +# may need to set permissions on your web server to allow this to +# execute from a web-context. The data feed SQL converter will +# also invoke this when it is complete each time it is run. +# +# allow is a comma limited list of IP addresses allowed to run +# the script in CGI mode. This isn't yet available. +# +# logfile specifies the pathname for the log file. +# +# datafeed specifies the format of the XML file. Valid options +# are "xmltv" and "datadirect". +# + +replayschedule=./replaySchedule.exe + +#********************************************************************** +# End of replayschedule/schedule2sql settings +#********************************************************************** + + +#********************************************************************** +# XMLTV DataFeed +#********************************************************************** + +[xmltv] + +#---------------------------------------------------------------------- +# XMLTV Support +#---------------------------------------------------------------------- +# client is the client for the datafeed. +# This should be a fully qualified pathname if required. +# eg. D:\XMLTV\xmltv.exe or /usr/bin/xmltv/xmltv +# (Used by updatetvdata) +# +# converter is the SQL converter for the datafeed. +# This should be a fully qualified pathname if required. +# Usually this should be xmltv2sql.pl. +# (Used by updatetvdata) +# +# parameters are the command line parameters, if any, for the datafeed +# client. For XMLTV specify the grabber and number of days here. +# (Roughly XMLTV takes 15 minutes per day of listings to grab.) +# (Used by updatetvdata) +# +# redirectoutput is a flag for the datafeed client if it just outputs +# to STDOUT. Can be a 1 (yes) or 0 (no). +# (Used by updatetvdata) +# +# successcode is the value that the client returns to indicate a +# successful download. The default if not specified is 1. For XMLTV +# this should be 0. +# (Used by updatetvdata) +# +# geticons enables the automatic running of getchannelicons after +# a successful refresh. (Used by updatetvdata) (see [geticons]) +# +# geticonscript is the fully qualified (if needed) pathname to +# the script or program to download icons. (Used by updatetvdata) +# if missing this defaults to ./getchannelicons.pl +# +#---------------------------------------------------------------------- +# NOTE: XMLTV's own DataDirect support introduced in XMLTV 0.5.31 is +# not supported by Personal ReplayGuide, please use PRG's native +# DD support instead. +# +# You can use your XMLTV DataDirect login information if you wish. +#---------------------------------------------------------------------- + +client=c:\xmltv\xmltv.exe +converter=.\xmltv2sql.pl +parameters=tv_grab_na --days 12 +redirectoutput=1 +successcode=0 +geticons=0 + +#---------------------------------------------------------------------- +# XMLTV to SQL Converter +#---------------------------------------------------------------------- + +[xmltv2sql] + +#---------------------------------------------------------------------- +# XMLTV Support +#---------------------------------------------------------------------- +# Debugging +#---------------------------------------------------------------------- +# debug controls debug messages. Generally you'll want this set +# to 0 unless you're troubleshooting or programming. +# +# other options are: +# do_not_insert create a CSV instead of inserting to DB +# do_not_delete_rows do not drop tvlistings table rows first +# +#---------------------------------------------------------------------- +# Other Options +#---------------------------------------------------------------------- +# maxrows is the maximum number of rows to INSERT into TVLISTINGS +# (0 is unlimited) +# +# dotinterval is the number of rows before a '.' is shown for progress +# (default 500) +# +# multiplier is the increment between lineups. (default is 1000) +# +# xmlfile is the file to read from. +# +# allow is a comma limited list of IP addresses allowed to run +# the script in CGI mode. This isn't yet available. +# +# logfile specifies the pathname for the log file. +# +# postalcode is the zip/postal code for the lineup. this isn't really +# used yet. +# +# lineupname is the name of the lineup. eg. "DIRECTV" or "Comcast". +# this is displayed when setting up a manual recording. +# +# systemtype is the type of lineup used for manual recordings. +# valid systemtypes are: Antenna, Cable, DBS +# +#---------------------------------------------------------------------- +# Advanced Options +#---------------------------------------------------------------------- +# titlemap refers to the config file to use for title mapping +# +# channelmap refers to the config file to use for channel mapping +# +# eg. titlemap=titlemap.conf +# +# +# CHANNEL MAP FORMAT +# OLD_CHANNELID,OLD_TUNING=NEW_CHANNELID,NEW_TUNING +# +# For example to remap TNN channel 57 to TNNP channel 69: +# TNN,57=TNNP,69 +# +# +# TITLE MAP FORMAT +# OLD_TITLE=NEW_TITLE +# +# For example: +# Lois & Clark: The New Adventures of Superman=Lois & Clark: New Adventures of Superman +# +# +# Both mapping files support comments in the exact same format as this file. +# + +#********************************************************************** +# End of XMLTV DataFeed Settings +#********************************************************************** + + +#********************************************************************** +# Get Channel Icons +#********************************************************************** + +[geticons] + +#---------------------------------------------------------------------- +# Debugging +#---------------------------------------------------------------------- +# This flag controls debug messages. Generally you'll want this set +# to 0 unless you're troubleshooting or programming. + +debug=0 + +#---------------------------------------------------------------------- +# General Configuration +#---------------------------------------------------------------------- +# +# channelicondir is where local channel icon images will be stored. +# This must be a full/relative path to an existing directory with +# write access. (OPTIONAL) +# +# verbose is a flag that controls whether information is displayed in +# the console. The default (and recommended) value is 1. +# +#---------------------------------------------------------------------- +# Uncomment to enable storing channel icons locally +#---------------------------------------------------------------------- + +# channelicondir=./channelicons +# verbose=0 + +#---------------------------------------------------------------------- +# Data Direct Configuration +#---------------------------------------------------------------------- +# The following options are only needed if Personal ReplayGuide is +# using Data Direct to retrieve TV listings instead of XMLTV. Data +# Direct does not currently include channel icons, so we have to get +# them from Zap2It.com separately. +# +# getchannelicons will try to automatically detect the providerid so +# these fields are all optional. the zip/postal code is provided by +# the datadirect feed. +# +# providerid is the unique number associated with your cable/satellite +# provider on Zap2It.com. You can get this number by browsing to +# http://www.zap2it.com, entering your zip code, selecting your +# provider, and clicking "Confirm Channel Lineup." The URL of the +# page that appears will contain a "&system=XXXXX" parameter. Use +# that number for the providerid value. This is typically a +# five digit number. +# +# zipcode is your zip/postal code. +# +#---------------------------------------------------------------------- + +# providerid=0 +# zipcode=0 + +#********************************************************************** +# End of Get Channel Icons +#********************************************************************** + + +#********************************************************************** +# REPLAYGUIDE OPTIONS +#********************************************************************** + +[replayguide] + +# These options cover the behavior of the replayguide.pl file. +#---------------------------------------------------------------------- +# Debugging +#---------------------------------------------------------------------- +# This flag controls debug messages. Generally you'll want this set +# to 0 unless you're troubleshooting or programming. + +debug=0 + +#---------------------------------------------------------------------- +# Logging +#---------------------------------------------------------------------- +# If missing or empty, logging is disabled. Otherwise logging will be +# done to the path/filename given. eg. c:\logfiles\prg.log +# +# Obviously the process running the perl interpreter will need write +# permission. +# +# When initially testing Personal ReplayGuide it is recommended that +# you enable logging. +# +# +# NOTE: You can have the logging routine add the module as a prefix +# (eg: replayguide::log message instead of just log message). +# +# To enable add logmodulename=1 + +logfile=prg.log + +#---------------------------------------------------------------------- +# Personal ReplayGuide Options +#---------------------------------------------------------------------- +# +# NOTE: Some of these options depend on the capabilities of the selected +# Schedule Resolver Module (SRM). +# +# +# defaultslot is the number of minutes represented by each column. +# +# defaultshowhours sets the number of hours to display if not specified +# by the hours setting in the toolbar. The default if this value is +# missing is 3. +# +# newwindow is a flag that determines if a new window will be opened +# if you click on a title or date/time. +# +# showchannelicons is a flag that determines if the channel icons should +# be shown or not. +# +# showrtvicons is a flag that determines if ReplayTV recording status +# icons should be shown in listings and search results. +# +# showbuttonicons is a flag that determines if buttons will use bitmaps +# instead of text (if defined) +# +# showheaderrows sets the frequency that the grid header is shown (the +# horizontal time markers). The default is 0 which will cause the +# header to be shown only at the start and end of the grid. A setting +# of '15' would show the header after every 15th channel or so. +# +# searchfutureonly tells the search engine to only look for shows from +# the current date/hour onwards. +# +# showschedulebar enables an extra row of schedule info for each unit +# at the top of the tv listings table +# (if == 1, show full program details) +# (if == 2, show abbreviated program details) +# +# allowtitleedit enables an edit text field for show titles when +# scheduling a show. If not enabled (default) the listings provided +# title will be used. +# +# skipversioncheck causes Personal ReplayGuide to allow schedule attempts +# regardless of what version it has determined that the remote ReplayTV +# is running. The default (and recommended) value is 0. +# +# gridendoverlap allows you to adjust how much overlap time you will +# see (in grid mode) for shows that are ending after the grid starts. +# The default if this value is missing is 15 minutes. +# (eg. if a movie is ending at 9:05 but your grid starts at 9PM you +# won't see that movie listed. However, if the movie ends at 9:20 +# instead, you would see it as part of the 9 PM column.) +# +# channelicondir is where local channel icon images are located. +# (hint: use the getchannelicons.pl script to download the icons +# to a local directory) +# +# todooption is for scheduler modules that have ToDo list functions. +# 0 (default) Display all events for the entire schedule +# range. +# 1 Display all events from today. +# 2 Display all events from right now (nearest +# hour.) +# +# todofromstart is for scheduler modules that have ToDo list +# functions. If enabled then events that start during the window +# will be shown, otherwise any overlapping events will be shown. +# The default is off. +# +# primetimestart is the hour (24 hour clock) that is considered +# prime time (for the Prime button). Default is 20 (8PM). +# +# rtv_updatesleepseconds specifies the amount (in seconds) that +# Personal ReplayGuide should pause after scheduling a show to +# ensure that guide data is updated. This has no effect if +# guide refreshes are disabled. +# +# rtv_allowdelete controls if the DELETE button for ReplayShows +# should be enabled. Default is off. +# NOTE: NOT IMPLEMENTED YET. +# +# defaultmode controls the first screen you'll see when +# running Personal ReplayGuide. +# Valid options are: NOW (default), SEARCH, TODO (if supported by +# the selected SRM). +# +# showrtvtext is a flag that determines if text should be displayed +# in addition or in lieu of the icons. The behavior depends on the +# current setting of showrtvicons. +# +# If showrtvicons is on, showrtvtext will show the unit next +# to the graphic. This is useful if your web browser does not +# use ALT tags as tooltips. +# +# If showrtvicons is off, showrtvtext will show all the same +# information in a text format. +# +# NOTE: showrtvtext is forced to on with PDA devices. +# +# showrtvthemes enables theme support. +# + +defaultslot=30 +newwindow=0 +showchannelicons=1 +showrtvicons=1 +showschedulebar=2 +showbuttonicons=0 +showheaderrows=0 +searchfutureonly=0 +allowtitleedit=0 +skipversioncheck=0 +gridendoverlap=15 + +#---------------------------------------------------------------------- +# Default RTV Information +#---------------------------------------------------------------------- +# defaultreplaytv is the friendly name of your most commonly used +# ReplayTV +# + +defaultreplaytv=Living Room + + +#---------------------------------------------------------------------- +# ReplayTV Parameters +#---------------------------------------------------------------------- +# refreshinterval is how many minutes between guide refreshes. +# (whenever you schedule a show a refresh is triggered automatically) +# (software default varies between scheduler modules). +# NOTE: Some scheduler modules will ignore this value, this will be +# noted in the log file. +# +# snapshotpath is a relative path where Personal ReplayGuide stores +# guide snapshots. Default is the same directory as the perl script. +# The process running the perl interpreter will need read and write +# permission. +# +# NOTE: This directory *MUST* exist. +# NOTE: You can always select "Manual Refresh" with the Replay tool. + +refreshinterval=15 +snapshotpath=./ + +#---------------------------------------------------------------------- +# Personal ReplayGuide Colors/Fonts +#---------------------------------------------------------------------- +# +# You can customize the look and feel of Personal ReplayGuide +# +# +# All of these use standard HTML color codes +# (eg. #RRGGBB or #A0F000 etc) +# +# futureshowcolor is for shows that have not started yet. +# Default is white. +# +# currentshowcolor is for shows that have started and are in progress. +# Default is light gray. +# +# pastshowcolor is for shows that have ended before the current time. +# Default is dark gray. +# +# futurescheduledcolor is for shows that will record in the future. +# Default is light green. +# +# currentscheduledcolor is for shows that have started and are recording. +# Default is medium green. +# +# pastscheduledcolor is for shows that have recorded in the past. +# Default is darker green. +# +# futureconflictcolor is for shows that will not record due to conflict. +# Default is light red. +# +# currentconflictcolor is for shows that have started and didn't record due to conflict. +# Default is medium red. +# +# pastconflictcolor is for shows that have didn't record due to conflict in the past. +# Default is darker red. +# +# futurethemecolor is for themes that will record. +# Default is light blue. +# +# currentthemecolor is for themes that are recording. +# Default is medium blue. +# +# pastthemecolor is for themes that have recorded in the past. +# Default is darker blue. +# +# futurethemeconflictcolor is for themes that will not record due to conflict. +# Default is light red. +# +# currentthemeconflictcolor is for themes that have started and didn't record due to conflict. +# Default is medium red. +# +# pastthemeconflictcolor is for themes that have didn't record due to conflict in the past. +# Default is darker red. +# +# channelbackgroundcolor is the background color of the channel column. +# +# channeltextcolor is the foreground color of the channel column. +# +# listingsfont is the name of the font to use for television listings. +# For example: listingsfont=Arial Narrow +# +# detailfont is the name of the font to use on the program details/schedule show screens. +# +# channelfont is the name of the font to use in the channel column. +# +# headingfont is the name of the font to use for the header row. +# +# nowicon is the name of the bitmap to use for the now button. +# +# goicon is the name of the bitmap to use for the go button. +# +# allicon is the name of the bitmap to use for the all (channels) button. +# +# prevwindowicon is the name of the bitmap to use for the <<< button. +# +# nextwindowicon is the name of the bitmap to use for the >>> button. +# +# prevchanicon is the name of the bitmap to use for the < button. +# +# nextchanicon is the name of the bitmap to use for the > button. +# +# findicon is the name of the bitmap to use for the find button. +# +# selecticon is the name of the bitmap to use for the select button. +# +# scheduleicon is the name of the bitmap to use for the schedule button. +# +# doneicon is the name of the bitmap to use for the done button. +# +# primeicon is the name of the bitmap to use for the prime button. +# +# confirmicon is the name of the bitmap to use for the confirm button. +# +# locateicon is the name of the bitmap to use for the locate button. +# +# findallicon is the name of the bitmap to use for the find all button. +# +# headingbackgroundcolor is the background color of the header row. +# +# headingtextcolor is the foreground color of the header row. +# +# backgroundcolor is the general background color. +# +# textcolor is the general text color. +# +# visitedlinkcolor is the color of links that have been clicked on. +# +# activelinkcolor is the color of the link currently highlighted. +# +# linkcolor is the color of links that have not been visited or +# highlighted. +# +# titlefont is the name of the font to use for titles. +# +# menufont is the name of the font for the menu section. +# + +#---------------------------------------------------------------------- +# Images for Listings Icons +#---------------------------------------------------------------------- +# These are the definitions for the icons used for ReplayTV recording +# status. +# +# To use the following links, you'll need to be a registered user of +# MyReplayTV. +# +# The images can be local or remote (http://). +# +# Legend: +# b - before +# a - after +# p - padding +# pp- before & after padding +# g - guaranteed +# r - recurring +# s - single + +image_logo=logo_ndrake.jpg +image_bpgr=http://my.replaytv.com/images/x_+00-.gif +image_apgr=http://my.replaytv.com/images/x_-00+.gif +image_ppgr=http://my.replaytv.com/images/x_+00+.gif +image_gr=http://my.replaytv.com/images/x_-00-.gif +image_r=http://my.replaytv.com/images/x_-oo-.gif +image_bpr=http://my.replaytv.com/images/x_+oo-.gif +image_apr=http://my.replaytv.com/images/x_-oo+.gif +image_ppr=http://my.replaytv.com/images/x_+oo+.gif +image_gs=http://my.replaytv.com/images/x_-0-.gif +image_s=http://my.replaytv.com/images/x_-o-.gif +image_bpgs=http://my.replaytv.com/images/x_+0-.gif +image_apgs=http://my.replaytv.com/images/x_-0+.gif +image_ppgs=http://my.replaytv.com/images/x_+0+.gif +image_bps=http://my.replaytv.com/images/x_+o-.gif +image_aps=http://my.replaytv.com/images/x_-o+.gif +image_pps=http://my.replaytv.com/images/x_+o+.gif + +# +# Conflict loser versions of the above +# + +image_cbpgr=http://my.replaytv.com/images/x_+00-.gif +image_capgr=http://my.replaytv.com/images/x_-00+.gif +image_cppgr=http://my.replaytv.com/images/x_+00+.gif +image_cgr=http://my.replaytv.com/images/x_-00-.gif +image_cr=http://my.replaytv.com/images/x_-oo-.gif +image_cbpr=http://my.replaytv.com/images/x_+oo-.gif +image_capr=http://my.replaytv.com/images/x_-oo+.gif +image_cppr=http://my.replaytv.com/images/x_+oo+.gif +image_cgs=http://my.replaytv.com/images/x_-0-.gif +image_cs=http://my.replaytv.com/images/x_-o-.gif +image_cbpgs=http://my.replaytv.com/images/x_+0-.gif +image_capgs=http://my.replaytv.com/images/x_-0+.gif +image_cppgs=http://my.replaytv.com/images/x_+0+.gif +image_cbps=http://my.replaytv.com/images/x_+o-.gif +image_caps=http://my.replaytv.com/images/x_-o+.gif +image_cpps=http://my.replaytv.com/images/x_+o+.gif + +#---------------------------------------------------------------------- +# Other Icons for Channels and Details +# +# These should be around 9x9 or 10x10 depending on your font sizes. +#---------------------------------------------------------------------- +# image_stereo is the image to use for stereo programming. +# +# image_repeat is the image to use for repeats. +# +# image_cc is the image to use for closed captioning. +# +# image_tvg is the image to use for TV-G rated programs. +# +# image_tvpg is the image to use for TV-PG rated programs. +# +# image_tv14 is the image to use for TV-14 rated programs. +# +# image_tvma is the image to use for TV-MA rated programs. +# +# image_tvy is the image to use for TV-Y rated programs. +# +# image_tvy7 is the image to use for TV-Y7 rated programs. +# +# image_mpaag is the image to use for MPAA G rated programs. +# +# image_mpaapg is the image to use for MPAA PG rated programs. +# +# image_mpaapg13 is the image to use for MPAA PG13 rated programs. +# +# image_mpaar is the image to use for MPAA R rated programs. +# +# image_mpaanc17 is the image to use for MPAA NC17 rated programs. +# +# image_mpaanr is the image to use for movies that aren't rated. +# +# image_tl is the image to use for a non-guaranteed theme that lost conflict rules. +# +# image_tw is the image to use for a non-guaranteed theme that won conflict rules. +# +# image_gt is the image to use for a guaranteed theme. +# +# image_cgt is the image to use for a guaranteed theme that lost conflict rules. +# + +#********************************************************************** +# End of ReplayGuide Settings +#********************************************************************** + +#********************************************************************** +# END OF FILE +#********************************************************************** + diff --git a/replayguide.pl b/replayguide.pl new file mode 100644 index 0000000..77c2fc3 --- /dev/null +++ b/replayguide.pl @@ -0,0 +1,7502 @@ +#!C:/Perl/bin/perl.exe +#[/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson <thompsonl@logh.net> +# with bits by Philip Van Baren, Kanji T. Bates and Kevin J. Moye +# $Id: replayguide.pl,v 1.30 2003/11/04 00:29:59 pvanbaren Exp $ +# +# Requirements: +# XMLTV or DataDirect +# +# +# NOTE: If you have not read the INSTALL.txt or the prg.conf file please do so +# RIGHT NOW! +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#------------------------------------------------------------------------------------ +# NOTE: The more complex routines have special debug modes that can +# be set by module. Simply look for $specialdebug=0 near the +# top of each routine and change to 1. Logging goes to +# the log file. Warning: It can get *very* chatty. +#------------------------------------------------------------------------------------ + +use POSIX qw( strftime getcwd ); +use CGI qw(:standard); +use Time::Local; + +my $_version = "Personal ReplayGuide|Main|1|1|200|Lee Thompson,Philip Van Baren,Kevin J. Moye,Kanji T. Bates"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Database Info +require 'rg_config.pl'; # Load config functions + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + + +#------------------------------------------------------------------------------------ +# Set up any arrays +#------------------------------------------------------------------------------------ + +@productionrole = ( + "", + "Actor", + "Guest Star", + "Host", + "Director", + "Producer", + "Executive Producer", + "Writer" +); + +#------------------------------------------------------------------- +# Initialize and Load Configuration +#------------------------------------------------------------------- + +$verbose = 0; +$scriptname = $script_pathname; +$configfile = "replayguide.conf"; +$configstatus = &ReadConfig; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + + +$prg_start = time; + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +CGI::import_names('input'); + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "console"; +} + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $rtvaccess = 1; +}else{ + $rtvaccess = 0; +} + + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress is set for PDA +# mode +#------------------------------------------------------------------- + +if (isPDA($RemoteAddress)) { + $showpdaformat = 1; +}else{ + $showpdaformat = 0; +} + +if (length($input::SHOWPDAFORMAT) > 0) { + $showpdaformat = int $input::SHOWPDAFORMAT; +} + + +#------------------------------------------------------------------------------------------- +# Modify Settings to PDA Mode (If Needed) +#------------------------------------------------------------------------------------------- + +if ($showpdaformat) { + $size_pdalistings = "H5"; + $defaultshowhours = 1; # PDA mode only shows an hour + $showrtvtext = 1; # Force Text +} + +#------------------------------------------------------------------------------------------- +# Start it up! +#------------------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress ($rtvaccess)"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +if ($ENV{SERVER_SOFTWARE} ne $null) { + writeDebug("Running on $ENV{SERVER_SOFTWARE}"); +} + +if ($showpdaformat) { + writeDebug("PDA mode is ON"); +} + +if ($debug) { + writeDebug("Debug Messages are ON"); +} + +&InitializeDisplay; + +#------------------------------------------------------------------- +# Set up Database +#------------------------------------------------------------------- + +&InitDB; +&InitDSN; + +#------------------------------------------------------------------- +# Log what modules are loaded +#------------------------------------------------------------------- + +identifyLoadedModules(); + +#------------------------------------------------------------------- +# Start Database +#------------------------------------------------------------------- + + +writeDebug("Start DSN->$DATASOURCE{DSN}"); +writeDebug("If this is the last line in your log file you may have incorrectly configured the database."); +writeDebug("(Check prg.conf's [database] section, database.conf or rg_info.pl and the INSTALL.txt file for troubleshooting.)"); + +$prgdb_handle = &StartDSN; + +if ($prgdb_handle ne $null) { + writeDebug("Database Connection Established to $DATASOURCE{DSN} ($prgdb_handle)"); +}else{ + writeDebug("Database Connection Failed to $DATASOURCE{DSN}"); + writeDebug("Reason: " . &GetLastSQLError()); + writeDebug("(Check prg.conf's [database] section, database.conf or rg_info.pl and the INSTALL.txt file for troubleshooting.)"); + abend("Could not establish DSN ($DATASOURCE{DSN})"); +} + +#------------------------------------------------------------------- +# Set up Variables +#------------------------------------------------------------------- + +$null = ""; +$stars = "****"; +$url_parms = ""; + +#------------------------------------------------------------------- +# Parse Input Fields +#------------------------------------------------------------------- + +if (length($ENV{'QUERY_STRING'}) > 0) { + $default_mode = ""; +} + +$inp_startdate = $input::STARTDATE; +$inp_starthour = $input::STARTHOUR; +$inp_showhours = int $input::SHOWHOURS; +$inp_showslots = int $input::SHOWSLOTS; +$inp_firsttune = int $input::FIRSTTUNE; +$inp_lasttune = int $input::LASTTUNE; +$inp_favorite = $input::FAVORITE; +$inp_searchfield = $input::FIELD; +$inp_search = $input::SEARCH; +$inp_todo = filterfield($input::TODO); +$inp_programid = $input::PROGRAMID; +$inp_selectedrtv = $input::SELECTEDRTV; +$inp_recordtype = $input::RECORDTYPE; +$inp_updatedrtv = $input::UPDATE; +$inp_showsrtv = $input::SHOWSHOWS; +$inp_rtvunit = $input::RTVUNIT; +$inp_rtvaction = int $input::RTVACTION; +$inp_showdetail = $input::SHOWDETAIL; +$inp_deletertvshow = $input::DELETESHOW; +$inp_manualrec = $input::MANUALREC; +$inp_inputsource = $input::INPUTSOURCE; + +writeDebug("CGI: STARTDATE: $inp_startdate"); +writeDebug("CGI: STARTHOUR: $inp_starthour"); +writeDebug("CGI: SHOWHOURS: $inp_showhours"); +writeDebug("CGI: SHOWSLOTS: $inp_showslots"); +writeDebug("CGI: FAVORITE: $inp_favorite"); +writeDebug("CGI: SEARCHFIELD: $inp_searchfield"); +writeDebug("CGI: FIRSTTUNE: $inp_firsttune"); +writeDebug("CGI: LASTTUNE: $inp_lasttune"); +writeDebug("CGI: SEARCH: $inp_search"); +writeDebug("CGI: PROGRAMID: $inp_programid"); +writeDebug("CGI: SELECTEDRTV: $inp_selectedrtv"); +writeDebug("CGI: RECORDTYPE: $inp_recordtype"); +writeDebug("CGI: UPDATE: $inp_updatedrtv"); +writeDebug("CGI: RTVUNIT: $inp_rtvunit"); +writeDebug("CGI: RTVACTION: $inp_rtvaction"); +writeDebug("CGI: SHOWSHOWS: $inp_showsrtv"); +writeDebug("CGI: SHOWDETAIL: $inp_showdetail"); +writeDebug("CGI: DELETESHOW: $inp_deletertvshow"); +writeDebug("CGI: MANUALREC: $inp_manualrec"); +writeDebug("CGI: INPUTSOURCE: $inp_inputsource"); +writeDebug("CGI: SHOWPDAFORMAT: $showpdaformat"); + + + +#------------------------------------------------------------------- +# If icons are not enabled clear them out +#------------------------------------------------------------------- + +if ($showbuttonicons < 1) { + $icon_schedule = ""; + $icon_now = ""; + $icon_go = ""; + $icon_locate = ""; + $icon_findall = ""; + $icon_findrepeat = ""; + $icon_all = ""; + $icon_locate = ""; + $icon_prevwindow = ""; + $icon_nextwindow = ""; + $icon_prevchan = ""; + $icon_nextchan = ""; + $icon_todo = ""; + $icon_find = ""; + $icon_select = ""; + $icon_schedule = ""; + $icon_done = ""; +} + +if ($showchannelicons < 1) { + $image_stereo = ""; + $image_repeat = ""; + $image_cc = ""; + + $image_tvg = ""; + $image_tvpg = ""; + $image_tv14 = ""; + $image_tvy = ""; + $image_tvy7 = ""; + $image_tvma = ""; + + $image_mpaag = ""; + $image_mpaapg = ""; + $image_mpaapg13 = ""; + $image_mpaar = ""; + $image_mpaanc17 = ""; +} + + +#------------------------------------------------------------------- +# Load Schedule Resolver Module (SRM) Plug-In +#------------------------------------------------------------------- + +writeDebug("Attempting to load $scheduler SRM module"); + +if (!fileExists($scheduler)) { + writeDebug("Failed to load $scheduler SRM module"); + if (fileExists("rg_null.pl")) { + writeDebug("Defaulting to rg_null.pl SRM module"); + $rtvaccess = 0; + }else{ + abend("Could not load null SRM"); + } +} + +if (!$rtvaccess) { + $scheduler = "rg_null.pl"; # No RTV Access +} + +writeDebug("Loading $scheduler SRM module"); +require $scheduler; # Functions handling scheduled recording display +identifyLoadedModules($scheduler); # Ask SRM to ID itself +writeDebug(&AboutScheduler); # +$rtv_refreshinterval = &SchedulerDefaultRefresh; + +if ($defaultrefreshinterval != -1) { + if ($rtv_refreshinterval != $defaultrefreshinterval) { + if ($rtv_refreshinterval > 0) { + writeDebug("$scheduler forced guide refresh interval to $rtv_refreshinterval minutes"); + }else{ + if (&SchedulerDoBatchUpdate) { + writeDebug("$scheduler disabled automatic guide refresh"); + }else{ + writeDebug("$scheduler does not support guide data"); + } + } + } +}else{ + if ($rtv_refreshinterval > 0) { + writeDebug("$scheduler guide refresh interval set to $rtv_refreshinterval minutes"); + }else{ + writeDebug("$scheduler disabled automatic guide refresh"); + } +} + +if ($rtv_refreshinterval > 0) { + writeDebug("$scheduler is set to automatically refresh guide data every $rtv_refreshinterval minutes."); +}else{ + writeDebug("$scheduler automatic guide refresh is disabled."); +} + +#------------------------------------------------------------------- +# Process ReplayTVs... +#------------------------------------------------------------------- +# +# This builds three sets of data structures for dealing with +# ReplayTV units. +# +# $replaylist is a comma delimited list of replayunits IDs. These +# are ALL the ReplayTV units defined in the replayunits table. +# +# $schedulinglist is a semicolon delimited list of replay unit IDs. +# What makes this different from replaylist, is these are units that +# are capable of remote scheduling. (If skipversioncheck is on +# this will always be the same as replaylist.) +# +# In addition there is a set of hash arrays for additional +# ReplayTV unit data. +# +# $rtvlabel{REPLAYID} Network Name (e.g. Office) +# $rtvaddress{REPLAYID} FQDN or IP Address of the RTV +# $rtvport{REPLAYID} Port number to use for the RTV +# $rtvversion{REPLAYID} ReplayTV Version +# $guideversion{REPLAYID} Guide Snapshot Version +# $lastsnapshot{REPLAYID} Epoch Seconds of Last Database Refresh +# $categories{REPLAYID} Semicolon delimited list of Categories +# Cat #,Category Format +# $rtvdefaultquality{ID} Default quality level for ReplayID # +# $rtvdefaultkeep{ID} Default episodes to keep for ReplayID # +# +# $rtvunit{LABEL} Uses the Network Name and gives you +# the replayid. +# +# Note if $rtvaccess is zero, none of this will be set! +# +#------------------------------------------------------------------- + +$replaylist = ""; +$schedulinglist = ""; + +if ($rtvaccess > 0) { + writeDebug("Processing ReplayTVs..."); + + my $need_update = 0; + my $db_handle = &StartDSN; + + $Stmt = "SELECT * FROM $db_table_replayunits ORDER BY replayaddress;"; + + my $sth = sqlStmt($db_handle,$Stmt); + if($sth) { + while ( my $row = $sth->fetchrow_hashref ) { + + my $replayid = $row->{'replayid'}; + + $replaylist = buildcommastring($replaylist,$replayid); + + $rtvlabel{$replayid} = $row->{'replayname'}; + $rtvunit{$rtvlabel{$replayid}} = $replayid; + $rtvaddress{$replayid} = $row->{'replayaddress'}; + $rtvport{$replayid} = $row->{'replayport'}; + $rtvversion{$replayid} = $row->{'replayosversion'}; + $rtvdefaultquality{$replayid} = int $row->{'defaultquality'}; + $rtvdefaultkeep{$replayid} = int $row->{'defaultkeep'}; + $guideversion{$replayid} = $row->{'guideversion'}; + $lastsnapshot{$replayid} = $row->{'lastsnapshot'}; + $categories{$replayid} = $row->{'categories'}; + + #------------------------------------------ + # Any one of these criteria will force an + # update. + #------------------------------------------ + if ($row->{'lastsnapshot'} == 0) { + $need_update = 1; + } + if ($rtvversion{$replayid} == 0) { + $need_update = 1; + } + if ($guideversion{$replayid}== 0) { + $need_update = 1; + } + if ($rtvport{$replayid} != 80) { + writeDebug("Warning! $replayid) $rtvlabel{$replayid} at $rtvaddress{$replayid} has non standard port of $rtvport{$replayid}. Integration functions may fail for this unit."); + } + + if ($skipversioncheck) { + if (length($schedulinglist) > 0) { + $schedulinglist .= ";"; + } + $schedulinglist .= "$replayid"; + }else{ + if ($guideversion{$replayid} == 2) { + if (length($schedulinglist) > 0) { + $schedulinglist .= ";"; + } + $schedulinglist .= "$replayid"; + } + } + + } + } + endDSN($sth,$db_handle); + undef $db_handle; + undef $sth; + + if ($replaylist eq $null) { + writeDebug("No ReplayTVs defined. ReplayTV functionality disabled."); + $rtvaccess = 0; + $inp_rtvaction = 0; + }else{ + writeDebug(countArray($replaylist) . " ReplayTV units found:"); + for ( split /,/, $replaylist ) { + /,/; + writeDebug("$_) '$rtvlabel{$_}' at $rtvaddress{$_}"); + } + + if ($need_update) { + $inp_updatedrtv = "ALL"; + writeDebug("$db_table_replayunits table has never been refreshed for 1 or more units, forcing update"); + } + } + + #------------------------------------------------------------------- + # Process RTVUNIT/ACTION + #------------------------------------------------------------------- + + if ($inp_rtvaction > 0) { + + writeDebug("Processing ReplayTV Actions... ( $inp_rtvaction -> $inp_rtvunit )"); + + if ($inp_rtvaction == 1) { + #------------------------------- + # Refresh + #------------------------------- + if ($inp_rtvunit > 0) { + if (length($inp_updatertv) > 0) { + $inp_updatedrtv = "ALL"; + }else{ + $inp_updatedrtv = $rtvaddress{$inp_rtvunit}; + } + }else{ + $inp_updatedrtv = "ALL"; + } + } + + if ($inp_rtvaction == 2) { + #------------------------------- + # To-Do List + #------------------------------- + $inp_todo = $inp_rtvunit; + } + + if ($inp_rtvaction == 3) { + #------------------------------- + # Manage Shows/Channels + #------------------------------- + $inp_showsrtv = $inp_rtvunit; + } + + if ($inp_rtvaction == 4) { + #------------------------------- + # Manual Recording + #------------------------------- + $inp_manualrec = $inp_rtvunit; + } + } + + + + if (length($inp_updatedrtv) > 0) { + if ($rtv_updatesleepseconds) { + writeDebug("Sleeping for $rtv_updatesleepseconds seconds to allow guidesnapshot(s) to show new recording on unit $inp_updatedrtv"); + sleep($rtv_updatesleepseconds); + writeDebug("Awake"); + } + } + + my $lastsnapshot = 0; + my $right_now = time; + my $addr; + + + if ($rtvaccess > 0) { + writeDebug("Checking ReplayTV guide data..."); + + for ( split /,/, $replaylist ) { + /,/; + + my $replayid = $_; + my $refresh = 0; + + #------------------------------------------------------------------- + # If the guide data is stale, get a fresh copy + # if rtv_refreshinterval == 0, then only do manually forced refreshes + # i.e. disable the autorefresh on time interval and after a scheduling change + #------------------------------------------------------------------- + + if (($rtv_refreshinterval > 0) && (($right_now - $lastsnapshot{$replayid}) > ($rtv_refreshinterval * 60))) { + writeDebug("$replayid) $rtvlabel{$replayid}: $rtv_refreshinterval is non-zero and snapshot is stale"); + $refresh = 1; + } + + if (uc $inp_updatedrtv eq uc $rtvaddress{$replayid}) { + writeDebug("$replayid) $rtvlabel{$replayid}: $rtvaddress{$replayid} matches $inp_updatedrtv, forcing getFreshScheduleTable"); + $refresh = 1; + } + + if ($inp_updatedrtv eq 'ALL') { + writeDebug("$replayid) $rtvlabel{$replayid}: $inp_updatedrtv set to ALL, forcing getFreshScheduleTable"); + $refresh = 1; + } + + if ( $refresh ) { + + displayText("Refreshing $rtvlabel{$replayid} ... ",0,1); + writeDebug("Attempting to refresh $rtvlabel{$replayid}"); + if(0 != getFreshScheduleTable($replayid)) { + displayText("Failed\n"); + writeDebug("getFreshScheduleTable failed for $rtvlabel{$replayid}"); + } else { + displayText("Complete\n"); + writeDebug("Refresh Complete"); + #----------------------------------------- + # Update the snapshot time in the database + #----------------------------------------- + writeDebug("Attempting to update $rtvlabel{$replayid} snapshot marker"); + my $Update = "UPDATE $db_table_replayunits SET lastsnapshot = $right_now WHERE replayid = '$replayid';"; + my $db_handle = &StartDSN; + + if ( ! sqlStmt($db_handle,$Update) ) { + displayText("ReplayTV database update Failed: <PRE>$Update\n" . &GetLastSQLError() . " \n</PRE>"); + writeDebug("Failed to update marker"); + } + endDSN("",$db_handle); + undef $db_handle; + writeDebug("Finished processing RTV $rtvlabel{$replayid}"); + } + } else { + writeDebug("Refresh not required for $rtvlabel{$replayid}"); + if(0 != getCachedScheduleTable($replayid)) { + writeDebug("getCachedScheduleTable failed for $rtvlabel{$replayid}"); + displayText("Failed to load cached schedule for $rtvlabel{$replayid}"); + } + } + } + } + +}else{ + writeDebug("No access to ReplayTV data."); + $replaylist = ""; + $inp_updatedrtv = ""; +} + + + + +#------------------------------------------------------------------- +# Prepare Time Calculations +#------------------------------------------------------------------- + +$now_startdate = substr($now,0,4) . substr($now,5,2) . substr($now,8,2); +$now_starthour = int substr($now,11,2); +$now_timestring = substr($now,0,4) . substr($now,5,2) . substr($now,8,2) . substr($now,11,2) . substr($now,14,2) . "59"; +$now_searchstart = substr($now,0,4) . substr($now,5,2) . substr($now,8,2) . substr($now,11,2) . "0000"; +$now_todaystart = substr($now,0,4) . substr($now,5,2) . substr($now,8,2) . "000000"; + +if ($inp_startdate eq $null) { + $inp_startdate = $now_startdate; +} + +if ($inp_starthour eq $null) { + $inp_starthour = $now_starthour; +} else { + $inp_starthour = int $inp_starthour; +} + +if ($inp_showhours < 1) { + $inp_showhours = $defaultshowhours; +} + +if ($inp_showslots < 1) { + $inp_showslots = $defaultshowslots; +} + +if (($primetime_start < 0) || ($primetime_start > 23)) { + $primetime_start = 20; # 8 PM +} + +if (($inp_starthour < 0) || ($inp_starthour > 23)) { + $inp_starthour = $now_starthour; +} + + +$starthour = sprintf("%02d",$inp_starthour); +$starttime = $inp_startdate . $starthour . "0000"; + +$startseconds = as_epoch_seconds($starttime); +$previousseconds = $startseconds - (($inp_showhours * 60) * 60); + +$overlap = $startseconds + ($grid_end_overlap * 60); +$overlap = as_time_string($overlap); + +$endseconds = $startseconds + (($inp_showhours * 60) * 60); + +$previoustime = as_time_string($previousseconds); +$starttime = as_time_string($startseconds); +$endtime = as_time_string($endseconds); + + +#------------------------------------------------------------------- +# Ready Grid Settings +#------------------------------------------------------------------- + +$maxpos = ($inp_showhours * 60) / $inp_showslots; +$maxpos = int $maxpos; + +$colpos = 1; + + +#------------------------------------------------------------------- +# Get Channel Range +#------------------------------------------------------------------- + +$Stmt = ""; +$Stmt .= "SELECT * "; +$Stmt .= "FROM $db_table_channels "; +$Stmt .= "WHERE hidden = 0 "; +$Stmt .= "ORDER BY tuning;"; + +$records = 0; +$first_channel = 0; +$last_channel = 0; + +my $db_handle = &StartDSN; + +my $sth = sqlStmt($db_handle,$Stmt); +if ( $sth ) { + + while ( $row = $sth->fetchrow_hashref ) { + $records++; + + if ($records == 1) { + $firstrecord = int $row->{'tuning'}; + } + + $currentrecord = int $row->{'tuning'}; + $currentchannel = $row->{'channel'}; + $iconsrc = $row->{'iconsrc'}; + if($channelicondir && $iconsrc) { + $iconsrc =~ s|^.*/([^\/]+)$|$channelicondir/$1|; + } + $icon{$currentchannel} = $iconsrc; + $tuningnumber{$currentchannel} = $currentrecord; + $channel[$records] = $currentrecord . " " . $currentchannel; + $tuning[$records] = $currentrecord; + } + + $lastrecord = $currentrecord; + $first_channel = $firstrecord; + $last_channel = $lastrecord; + $channelcount = $records; +}else{ + abend("Error building channel range"); +} + +endDSN($sth,$db_handle); +undef $db_handle; + +if ($records == 0) { + abend("No channels defined.\nHave you run updatetvdata yet?\nAlso check database configuration and/or datafeed configuration"); +} + +#------------------------------------------------------------------------ +# For more than 12-hour displays, force to a single channel rotated table +#------------------------------------------------------------------------ + +if ($inp_showhours > 12) { + $inp_lasttune = $inp_firsttune; +} + +if ($inp_firsttune > $inp_lasttune) { + $inp_firsttune = $first_channel; +} + +if ($inp_lasttune < $inp_firsttune) { + $inp_lasttune = $last_channel; +} + + +if ($inp_firsttune == 0) { + $inp_firsttune = $first_channel; +} + + +if ($inp_lasttune == 0) { + $inp_lasttune = $last_channel; +} + + +#------------------------------------------------------------------- +# Set up channel next/prev buttons +#------------------------------------------------------------------- + +$records = 0; + +do { + $records++; + if ($tuning[$records] == $inp_firsttune) { + $first_rec = $records; + } + if ($tuning[$records] == $inp_lasttune) { + $last_rec = $records; + } +} while ($records < $channelcount); + +$display_rec = ($last_rec - $first_rec) + 1; + +if ($display_rec eq $channelcount) { + $next_rec = 0; + $prev_rec = 0; +}else{ + $next_chan = $tuning[$last_rec + 1]; + $prev_chan = $tuning[$first_rec - 1]; + + if ($next_chan > $last_channel) { + $next_chan = $last_channel; + } + + if ($prev_chan < $first_channel) { + $prev_chan = $first_channel; + } + + $range_chan = $display_rec; + +} + +writeDebug("Channel Range is $first_channel to $last_channel ($channelcount)"); + +#------------------------------------------------------------------- +# Get First and Last date in the database +#------------------------------------------------------------------- + +$selected_channel = $first_channel; +$channel_populated = 1; + +my $db_handle = &StartDSN; +my $sth = ""; + +do { + + $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings "; + $Stmt .= "WHERE tuning = $selected_channel "; + $Stmt .= "ORDER BY starttime;"; + + $records = 0; + + $sth = sqlStmt($db_handle,$Stmt); + if ( $sth ) { + if (!$sth->fetchrow_hashref) { + + #------------------------------------------ + # Channel has no data, try the next one. + #------------------------------------------ + + $channel_populated = 0; + $selected_channel++; + }else{ + $channel_populated = 1; + } + + }else{ + abend("Error building date range"); + } + + if ($selected_channel > $last_channel ) { + abend("Error building date range, no data found."); + } + +} while ($channel_populated < 1); + + +while ( $row = $sth->fetchrow_hashref ) { + $records++; + + if ($records == 1) { + $firstrecord = sqltotimestring($row->{'starttime'}); + } + + $currentrecord = sqltotimestring($row->{'starttime'}); +} + +$lastrecord = $currentrecord; +$rng_startdate = substr($firstrecord,0,4) . substr($firstrecord,4,2) . substr($firstrecord,6,2); +$rng_stopdate = substr($lastrecord,0,4) . substr($lastrecord,4,2) . substr($lastrecord,6,2); + +endDSN($sth,$db_handle); +undef $sth; +undef $db_handle; + +#------------------------------------------------------------------- +# Set Date Boundaries +#------------------------------------------------------------------- + +$rng_start = as_epoch_seconds($rng_startdate . "000000"); +$rng_end = as_epoch_seconds($rng_stopdate . "000000") + 86400; +$prev_time = as_epoch_seconds($previoustime); +$next_time = as_epoch_seconds($endtime); +$dayone = timestringtosql(as_time_string($rng_start)); + +#------------------------------------------------------------------- +# Final Range Checks +#------------------------------------------------------------------- + +if ($prev_time < $rng_start) { + $prevok = 0; +}else{ + $prevok = 1; +} + +if ($next_time > $rng_end) { + $nextok = 0; +}else{ + $nextok = 1; +} + +if (length($prev_chan) < 1) { + $prev_chan = $first_channel; +} + +if (length($next_chan) < 1) { + $next_chan = $last_channel; +} + + +if ($prev_chan <= $first_channel) { + $prevchanok = 0; +}else{ + $prevchanok = 1; +} + +if ($next_chan >= $last_channel) { + $nextchanok = 0; +}else{ + $nextchanok = 1; +} + +writeDebug("Listings Range is $rng_startdate to $rng_stopdate"); + +displayText(); + +#------------------------------------------------------------------- +# See if Cast Crew Database is Populated +#------------------------------------------------------------------- + +writeDebug("Checking castcrew table ($db_table_castcrew)"); + +$Stmt = "SELECT *"; + +if ($db_driver eq "ODBC") { + $Stmt = "SELECT TOP 1 *"; +} + +$Stmt .= " FROM $db_table_castcrew"; + + +if (($db_driver eq "SQLite") || ($db_driver eq "mysql")) { + $Stmt .= " LIMIT 1"; +} + + +$Stmt .= ";"; + +$records = 0; + +my $db_handle = &StartDSN; + +my $sth = sqlStmt($db_handle,$Stmt); +if ( $sth ) { + + while ( $row = $sth->fetchrow_hashref ) { + $records++; + } +}else{ + my $lasterror = &GetLastSQLError(); + my $laststmt = &GetLastSQLStmt(); + + writeDebug("$lasterror, $laststmt"); + + #----------------------------------- + # Quietly fail. + #----------------------------------- +} + +endDSN($sth,$db_handle); +undef $db_handle; + +if ($records > 0) { + writeDebug("Castcrew table ($db_table_castcrew) returned 1 record, use_castcrew enabled"); + + $use_castcrew = 1; +}else{ + writeDebug("Castcrew table ($db_table_castcrew) did not return any records, use_castcrew disabled"); + + $use_castcrew = 0; + +} + + +#------------------------------------------------------------------- +# Display Toolbox +#------------------------------------------------------------------- + +if ($showpdaformat) { + &PDADisplayToolbox; +}else{ + &DisplayToolbox; +} + +#------------------------------------------------------------------- +# Set SQL Format Times +#------------------------------------------------------------------- + +$sql_start = timestringtosql($starttime); +$sql_end = timestringtosql($endtime); +$sql_overlap = timestringtosql($overlap); +$sql_now = timestringtosql($now_searchstart); +$sql_today = timestringtosql($now_todaystart); + + +#------------------------------------------------------------------- +# Collect ReplayTV Events +# If we are showing replay scheduling information, +# initialize the variables required for this +#------------------------------------------------------------------- +if ( $rtvaccess > 0 ) { + &ProcessScheduleTable; +} + +#------------------------------------------------------------------- +# Handle Modes +#------------------------------------------------------------------- + +if (uc $default_mode eq 'NOW') { + # Show Listings from now +} + +if (uc $default_mode eq 'SEARCH') { + # + # Search Mode + + print "<$size_section><font face=\"$font_title\">Search Mode</$size_section><p></font>"; + + &ShowFooter; + exit(1); +} + +if (uc $default_mode eq 'TODO') { + if (&ToDoSupported) { + $inp_todo = "ALL"; + } +} + +#------------------------------------------------------------------- +# Dispatch If Mode Has Changed +#------------------------------------------------------------------- + +if (length($inp_programid) > 0) { + writeDebug("Dispatch::ProgramDetails->$inp_programid"); + &DoSchedule; + &ShowFooter; + exit(1); +} + +if (length($inp_search) > 0) { + writeDebug("Dispatch::Search->$inp_search"); + displayHeading("Search Results:"); + &DoSearch; + &ShowFooter; + exit(1); +} + +if (length($inp_todo) > 0) { + writeDebug("Dispatch::ToDo->$inp_todo"); + displayHeading("To-Do List:"); + &DoToDo; + &ShowFooter; + exit(1); +} + +if (length($inp_showsrtv) > 0) { + writeDebug("Dispatch::ShowShows->$inp_showsrtv"); + showRTVShows($inp_showsrtv); + &ShowFooter; + exit(1); +} + +if (length($inp_showdetail) > 0) { + writeDebug("Dispatch::ShowDetail->$inp_showdetail"); + showDetail($inp_showdetail); + &ShowFooter; + exit(1); +} + +if (length($inp_deletertvshow) > 0) { + writeDebug("Dispatch::DeleteShow->$inp_deletertvshow"); + deleteRTVShow($inp_deletertvshow); + &ShowFooter; + exit(1); +} + +if (length($inp_manualrec) > 0) { + writeDebug("Dispatch::ManualRecord->$inp_manualrec"); + displayHeading("Schedule a Manual Recording"); + scheduleManualRecording($inp_manualrec); + &ShowFooter; + exit(1); +} + + + +#------------------------------------------------------------------- +# Show Listings +#------------------------------------------------------------------- + +print "<font face=\"$font_listings\">"; + +if ($showpdaformat) { + + #----------------------------------------------------------------- + # Keep it as compact as possible, no table. + #----------------------------------------------------------------- + +}elsif ($inp_firsttune == $inp_lasttune) { + + #----------------------------------------------------------------- + # If only a single channel or long time duration, rotate the table + #----------------------------------------------------------------- + + print "<table border=1>"; +}else{ + print "<table border=1>"; + + $heading = "<tr><td width=10% align=center bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" size=2 color=\"$color_headingtext\"><B>Channel</B></font>\n"; + + $ctr = 1; + $blockstart = as_epoch_seconds($starttime); + + do { + $heading .= "<td width=15% align=center bgcolor=\"$color_headingbackground\"><font size=2 face=\"$font_heading\" color=\"$color_headingtext\"><B>\n"; + $heading .= as_hhmm($blockstart); + $heading .= "</B></font>"; + $blockstart = $blockstart + ($inp_showslots * 60); + $ctr++; + + } while ($ctr < $maxpos+1); + + $heading .= "</tr>\n"; + + print $heading; +} + +#------------------------------------------------------------------- +# We print out the heading at the start and bottom, it would be +# trivial to add the heading every N rows. +#------------------------------------------------------------------- + +$Stmt = ""; + +if ($showpdaformat) { + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels "; + $Stmt .= "WHERE ((((starttime < '$sql_end') AND (endtime > '$sql_start') "; + if( $inp_favorite ) { + $Stmt .= "AND $db_table_tvlistings.tuning IN ($favorites{$inp_favorite})) "; + } else { + $Stmt .= "AND $db_table_tvlistings.tuning BETWEEN $inp_firsttune AND $inp_lasttune) "; + } + $Stmt .= "AND $db_table_tvlistings.tuning = $db_table_channels.tuning) "; + $Stmt .= "AND $db_table_tvlistings.channel = $db_table_channels.channel) "; + $Stmt .= "AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY starttime, $db_table_tvlistings.tuning;"; +}else{ + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels "; + $Stmt .= "WHERE ((((starttime < '$sql_end') AND (endtime > '$sql_start') "; + if( $inp_favorite ) { + $Stmt .= "AND $db_table_tvlistings.tuning IN ($favorites{$inp_favorite})) "; + } else { + $Stmt .= "AND $db_table_tvlistings.tuning BETWEEN $inp_firsttune AND $inp_lasttune) "; + } + $Stmt .= "AND $db_table_tvlistings.tuning = $db_table_channels.tuning) "; + $Stmt .= "AND $db_table_tvlistings.channel = $db_table_channels.channel) "; + $Stmt .= "AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY $db_table_tvlistings.tuning, $db_table_tvlistings.channel, starttime;"; +} + +if ($debug) { + print "<PRE>SQL: $Stmt\n</PRE>"; +} + + +$records = 0; +$hdr_ctr = 0; +$debug_state = 0; +$end_row = 1; + +if ($rtvaccess > 0) { + + #------------------------------------------------------------------- + # If we are showing replay scheduling information, + # compare the scheduled event list against the displayed event list + #------------------------------------------------------------------- + + if ($debug) { + writeDebug("Attempting to Comparing Event Tables"); + } + + compareScheduleTable($Stmt); + + if ($debug) { + writeDebug("Comparing Event Tables Completed"); + } +} + +writeDebug("Display Grid for $sql_start through $sql_end"); +writeDebug("Display Grid with $inp_showslots minute slots"); + +if($inp_favorite) { + writeDebug("Display Grid containing channels $favorites{$inp_favorite}"); +} else { + writeDebug("Display Grid containing channels $inp_firsttune - $inp_lasttune"); +} + +$records = 0; +$hdr_ctr = 0; +$debug_state = 0; +$end_row = 1; +$previous_date = ""; + +#------------------------------------------------------------------- +# Display scheduled recordings at the top +#------------------------------------------------------------------- + +if (&SchedulebarSupported) { + writeDebug("Display Options: Schedule Bar: $showschedulebar"); +}else{ + if ($showschedulebar) { + writeDebug("$scheduler does not support the schedulebar, disabled."); + } + $showschedulebar = 0; +} + +writeDebug("Display Options: PDA Format: $showpdaformat"); + +if ( $rtvaccess && $showschedulebar && !$showpdaformat + && ($inp_firsttune != $inp_lasttune)) { + writeDebug("Schedulebar Enabled"); + + + #----------------------------------------------------------- + # If you would rather have LOCATE find the show in the + # schedulebar, change $create_anchor to a 1. + #----------------------------------------------------------- + + my $specialdebug = 0; + + $create_anchor = 0; + + my $db_handle = &StartDSN; + + my $sth = ""; + + for ( split /,/, $replaylist ) { + /,/; + $displayunitlabel = $rtvlabel{$_}; + if( ! $displayunitlabel ) { + $displayunitlabel = $rtvaddress{$_}; + if( ! $displayunitlabel ) { + $displayunitlabel = $_; + } + } + + writeDebug("Creating schedule bar for '$displayunitlabel'"); + + for( $conflict = 0; $conflict < 2; $conflict++) { + + $Stmt2 = "SELECT * FROM $db_table_schedule,$db_table_tvlistings "; + $Stmt2 .= "WHERE (replayid = $_) "; + $Stmt2 .= "AND ($db_table_schedule.programid = $db_table_tvlistings.programid) "; + $Stmt2 .= "AND ($db_table_schedule.conflict = $conflict) "; + $Stmt2 .= "AND ($db_table_tvlistings.starttime < '$sql_end') "; + $Stmt2 .= "AND ($db_table_tvlistings.endtime > '$sql_start') "; + $Stmt2 .= "ORDER BY $db_table_tvlistings.starttime;"; + + if ($specialdebug) { + writeDebug("SQL: $Stmt2"); + } + + if( $conflict ) { + $displayunitlabel .= " (conflicts)"; + } + $sth = sqlStmt($db_handle,$Stmt2); + if ( $sth ) { + while ( $row = $sth->fetchrow_hashref ) { + $temp_value = 0; + $length_offset = 0; + + $program_id = $row->{'programid'}; + + $program_start = sqltotimestring($row->{'starttime'}); + $program_true_start = $program_start; + $program_stop = sqltotimestring($row->{'endtime'}); + $program_title = $row->{'title'}; + $program_subtitle = $row->{'subtitle'}; + $program_desc = $row->{'description'}; + $program_tuning = $row->{'tuning'}; + $program_channel = $row->{'channel'}; + $program_advisories = $row->{'advisories'}; + $program_category = $row->{'category'}; + $program_mpaarating = $row->{'mpaarating'}; + $program_vchiprating = $row->{'vchiprating'}; + $program_episodenum = $row->{'episodenum'}; + $program_movieyear = int $row->{'movieyear'}; + $program_stereo = int $row->{'stereo'}; + $program_repeat = int $row->{'repeat'}; + $program_starrating = $row->{'starrating'}; + $program_captions = $row->{'captions'}; + $program_theme = $row->{'theme'}; + $program_icon = ""; + + ($program_stars,$junk) = split(/\//,$program_starrating); + + $program_beforepad = $row->{'padbefore'}; + $program_afterpad = $row->{'padafter'}; + + + if ($specialdebug) { + writeDebug("Scheduled program: $program_title Padding: ($program_beforepad, $program_afterpad)"); + } + + #---------------------------------------------------------------------------- + # Because in it's infinite wisdom XMLTV does not provide a STOP time + # at the end of the listings, if we're looking at the last available + # data we can't calculate an endpoint so we just make something up. + # (Basically we give it one slot) + #---------------------------------------------------------------------------- + + $fudged_length = 0; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($program_start)) { + $program_stop = as_time_string(as_epoch_seconds($program_start) + ($inp_showslots * 60)); + $fudged_length = 1; + } + + #---------------------------------------------------------------------------- + # Fudge the program start and stop times by the padding factors + #---------------------------------------------------------------------------- + # Only fudge grid for the schedulebar if the padding is significant + #---------------------------------------------------------------------------- + + if ( ( $program_beforepad > $inp_showslots ) || ( $program_afterpad > $inp_showslots) ) { + if( $program_beforepad ) { + writeDebug("Adjusting start time to account for $program_beforepad minutes of padding"); + $program_start = as_time_string(as_epoch_seconds($program_start) - ($program_beforepad * 60)); + } + if( $program_afterpad ) { + writeDebug("Adjusting stop time to account for $program_afterpad minutes of padding"); + $program_stop = as_time_string(as_epoch_seconds($program_stop) + ($program_afterpad * 60)); + } + } + + #---------------------------------------------------------------------------- + # Make sure the fudged times still match the displayed interval + #---------------------------------------------------------------------------- + if( (as_epoch_seconds($program_start) > as_epoch_seconds($endtime)) + || (as_epoch_seconds($program_stop) < as_epoch_seconds($starttime)) ) { + next; + } + + $records++; + $program_length = getMinutes($program_start,$program_stop); + $display_length = $program_length; + $program_time = ""; + $program_extra = ""; + + $rng_string = substr(as_time_string(as_epoch_seconds($program_true_start)),0,8); + $wday = strftime( "%A", localtime(as_epoch_seconds($program_true_start))); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2) . "/" . substr($rng_string,0,4); + + $program_starthour = substr($program_start,8,2); + $program_startdate = substr($program_start,0,8); + + $starttime = $inp_startdate . $starthour . "0000"; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($now_timestring)) { + # Past show + $program_timing = 0; + }elsif (as_epoch_seconds($program_start) < as_epoch_seconds($now_timestring)) { + # Current show + $program_timing = 1; + } else { + # Future show + $program_timing = 2; + } + &DisplayListings; + } + } + } + } + if( $records > 0 ) { + + #---------------------------------------------------------- + # If we showed the schedule bar, force another header bar + # to give a separator between the schedule bar and programs + #---------------------------------------------------------- + + $hdr_ctr = -1; + } + endDSN($sth,$db_handle); + undef $db_handle; + writeDebug("Schedulebar Complete"); + +} + +#---------------------------------------------------------------------------- +# End the schedulebar type display format in displaylistings +# and reset the display counters so we get another time bar as a separator +#---------------------------------------------------------------------------- + +$shortslot = 0; +$max_span = 0; +$previous_display = 0; +$force_new_column = 0; +$debug_state = 0; +$previous_date = ""; +$displayunitlabel = ""; +$create_anchor = 1; + +#$records = 0; # Don't reset this, because it would inhibit drawing a separator header bar +#$end_row = 1; # Don't set this, because we may need to clean up the previous row + + +#------------------------------------------------------------------- +# Get Data from SQL and Display Grid +#------------------------------------------------------------------- + +writeDebug("SQL: $Stmt"); + +my $sth = sqlStmt($prgdb_handle,$Stmt); +if ( $sth ) { + + while ( $row = $sth->fetchrow_hashref ) { + $temp_value = 0; + $length_offset = 0; + + $records++; + + $program_id = $row->{'programid'}; + $program_start = sqltotimestring($row->{'starttime'}); + $program_true_start = $program_start; + $program_stop = sqltotimestring($row->{'endtime'}); + $program_true_stop = $program_stop; + $program_title = $row->{'title'}; + $program_subtitle = $row->{'subtitle'}; + $program_desc = $row->{'description'}; + $program_tuning = $row->{'tuning'}; + $program_channel = $row->{'channel'}; + + $program_category = $row->{'category'}; + $program_mpaarating = $row->{'mpaarating'}; + $program_vchiprating = $row->{'vchiprating'}; + $program_episodenum = $row->{'episodenum'}; + $program_movieyear = int $row->{'movieyear'}; + $program_stereo = int $row->{'stereo'}; + $program_repeat = int $row->{'repeat'}; + $program_starrating = $row->{'starrating'}; + $program_captions = $row->{'captions'}; + $program_theme = $row->{'theme'}; + $program_icon = ""; + + ($program_stars,$junk) = split(/\//,$program_starrating); + + + #------------------------------------------------------------------- + # If we have a duplicate record, skip (more of a sanity check) + #------------------------------------------------------------------- + + if ($program_id eq $prev_id) { + next; + } + + #------------------------------------------------------------------- + # Because in it's infinite wisdom XMLTV does not provide a STOP time + # at the end of the listings, if we're looking at the last available + # data we can't calculate an endpoint so we just make something up. + # (Basically we give it one slot) + #------------------------------------------------------------------- + + $fudged_length = 0; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($program_start)) { + $program_stop = as_time_string($rng_end); + $fudged_length = 1; + } + + #------------------------------------------------------------------- + # Prepare Variables and Calculate Running Time + #------------------------------------------------------------------- + + $program_length = getMinutes($program_start,$program_stop); + $display_length = $program_length; + $program_time = ""; + $program_extra = ""; + + #------------------------------------------------------------------- + # Handle programming that's partially visible on the grid + #------------------------------------------------------------------- + + if (as_epoch_seconds($program_start) < as_epoch_seconds($starttime)) { + $program_start = $starttime; + $program_length = getMinutes($program_start,$program_stop); + } + + if (as_epoch_seconds($program_stop) > as_epoch_seconds($endtime)) { + $program_true_stop = $program_stop; + $program_stop = $endtime; + $program_length = getMinutes($program_start,$program_stop); + if (length($program_extra) > 0) { + $program_extra .= " (continues until " . displaytime($program_true_stop) . ")"; + }else{ + $program_extra = "(continues until " . displaytime($program_true_stop) . ")"; + } + + } + + #------------------------------------------------------------------- + # Activate tvgrid driver + #------------------------------------------------------------------- + + if ($showpdaformat) { + if ($inp_firsttune == $inp_lasttune) { + &PDASingleChannelListings; + }else{ + &PDADisplayListings; + } + }else{ + if ($inp_firsttune == $inp_lasttune) { + &SingleChannelListings; + }else{ + if ($records == 1) { + $dl_lasttuning = $program_tuning; + } + + &DisplayListings; + } + + } + + #------------------------------------------------------------------- + # Set up sanity check + #------------------------------------------------------------------- + + $prev_id = $program_id; + + } + +}else{ + #------------------------------------------------------------------- + # Something Went Amiss + #------------------------------------------------------------------- + + writeDebug("Fatal Error: " . &GetLastSQLStmt() . " / " . &GetLastSQLError() ); + print "<p>Fatal Error!<p><PRE>Query Failed: " . &GetLastSQLStmt() . "\n" . &GetLastSQLError() . "</PRE><p>"; +} + +if ($records) { + if ($showpdaformat) { + }elsif ($inp_firsttune != $inp_lasttune) { + print "</table>\n"; + } else { + if (!$end_row) { + $colspan = ($maxpos+1) - $colpos; + print "<td colspan=$colspan align=left valign=top bgcolor=$color_show[0]>"; + print "</td></tr>\n"; + } + + if ($hdr_ctr > 1) { + print $heading; + } + print "</table>\n"; + } + print "</font>\n"; + writeDebug("TV Listings Returned $records Rows"); + +}else{ + writeDebug("TV Listings SQL Query Returned No Rows"); + print "<tr><td><td colspan=$maxpos align=center><$size_title>No data</center></$size_title></table></font>"; +} + +&ShowFooter; + +#--------------------------------------------------------------------------------------- +# FUNCTIONS **************************************************************************** +#--------------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------------- +sub PDADisplayListings{ + # + # Display Program Listings (PDA Format) + # aka. This is a lot easier than a program grid + # + #------------------------------------------------------------------------------- + + $curr_date = substr($program_start,0,8); + $curr_time = $program_start; + + if ($prev_date ne $curr_date) { + if ($records > 1) { + print "<p>\n"; + } + $wday = strftime( "%A", localtime(as_epoch_seconds($program_start))); + $dsp_string = $wday . ", " . substr($curr_date,4,2) . "/" . substr($curr_date,6,2) . "/" . substr($curr_date,0,4); + print "<B>$dsp_string</B><p>\n"; + } + + if ($prev_time != $curr_time) { + if ($records > 1) { + print "<p>\n"; + } + print "<$size_pdalistings>"; + print as_hhmm(as_epoch_seconds($program_start)); + print "<br>"; + } + + print "<$size_pdalistings>$program_tuning "; + + print "<a "; + + if ($create_anchor) { + print "name=\"$program_id\" "; + } + + $url_parms = ""; + addParameter("PROGRAMID",$program_id); + addParameter("STARTDATE",$inp_startdate); + addParameter("STARTHOUR",$inp_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print " href=\"$scriptdir/$scriptname$url_parms\">\n"; + + print renderhtml($program_title); + print "\n</a>"; + + if ($program_length > 30) { + print " <small>" . getRunningTime($display_length) . "</small>"; + } + + print "<br>\n"; + + $prev_date = $curr_date; + $prev_time = $curr_time; + + return 1; +} + + +#--------------------------------------------------------------------------------------- +sub PDADisplayToolbox{ + # + # Show Toolbox (PDA Format) + # + #------------------------------------------------------------------------------- + + print "<center><font face=\"$font_menu\">"; + print "<table border=0><tr><td>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$now_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$now_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + + if (length($icon_now) > 0) { + print "<input type=image src=\"$imagedir/$icon_now\" ALT=\"Now\">\n"; + }else{ + print "<input type=submit value=\"NOW\" name=\"SUBMIT2\">\n"; + } + print "</form><td>"; + + print "<center>"; + print "<font face=\"$font_menu\">"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$now_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$prime_start\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$defaultshowhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + if (length($icon_tonight) > 0) { + print "<input type=image src=\"$imagedir/$icon_tonight\" ALT=\"Prime\">\n"; + }else{ + print "<input type=submit value=\"Prime\" name=\"SUBMIT4\">\n"; + } + print "</form>"; + + $form_date = substr($previoustime,0,4) . substr($previoustime,4,2) . substr($previoustime,6,2); + $form_time = substr($previoustime,8,2); + + print "<td>"; + + if ($prevok) { + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$form_date\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$form_time\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + + if (length($icon_prevwindow) > 0) { + print "<input type=image src=\"$imagedir/$icon_prevwindow\" ALT=\"<<<\">\n"; + }else{ + print "<input type=submit value=\"<<<\" name=\"SUBMITPW\">"; + } + + print "</form>\n\n"; + } + + print "<td>"; + + $form_date = substr($endtime,0,4) . substr($endtime,4,2) . substr($endtime,6,2); + $form_time = substr($endtime,8,2); + + if ($nextok) { + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$form_date\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$form_time\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + + if (length($icon_nextwindow) > 0) { + print "<input type=image src=\"$imagedir/$icon_nextwindow\" ALT=\">>>\">\n"; + }else{ + print "<input type=submit value=\">>>\" name=\"SUBMITNW\">\n"; + } + + print "</form>\n\n"; + } + + + + print "</table>\n "; + + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "Date: <select size=\"1\" name=\"STARTDATE\">\n"; + + do { + $rng_string = substr(as_time_string($rng_start),0,8); + $wday = strftime( "%A", localtime($rng_start)); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2) . "/" . substr($rng_string,0,4); + print "<option value=\"$rng_string\""; + if ($rng_string eq substr($starttime,0,4) . substr($starttime,4,2) . substr($starttime,6,2)) { + print " selected"; + } + print ">$dsp_string</option>\n"; + + $rng_start = $rng_start + 86400; + $ctr++; + + } while ($rng_start < $rng_end); + print "</select>\n"; + print "<br>"; + + print "Time: "; + print "<select size=\"1\" name=\"STARTHOUR\">\n"; + + $ctr = 0; + do { + $dsp_string = as_ampm($ctr); + print "<option value=\"$ctr\""; + if ($ctr == int substr($starttime,8,2)) { + print " selected"; + } + print ">$dsp_string</option>\n"; + $ctr++; + + } while ($ctr < 24); + print "</select>\n"; + + print " "; + + if (length($icon_go) > 0) { + print "<input type=image src=\"$imagedir/$icon_go\" ALT=\"Go\">\n"; + }else{ + print "<input type=submit value=\"Go\" name=\"SUBMITGO\">"; + } + print "</form>\n"; + + print "<br>\n"; + + + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + print "<input type=text name=\"SEARCH\" value=\"\" size=20>\n"; + print "<br>"; + print "<select size=\"1\" name=\"FIELD\">\n"; + print "<option value=\"title\" selected>Title</option>\n"; + print "<option value=\"subtitle\">Episode</option>\n"; + print "<option value=\"description\">Desc.</option>\n"; + print "<option value=\"category\">Genre</option>\n"; + print "<option value=\"advisories\">Alerts</option>\n"; + + if ($use_castcrew) { + print "<option value=\"1\">Actor</option>\n"; + print "<option value=\"2\">Guest</option>\n"; + print "<option value=\"3\">Host</option>\n"; + print "<option value=\"4\">Director</option>\n"; + print "<option value=\"5\">Producer</option>\n"; + print "<option value=\"6\">Exec.</option>\n"; + print "<option value=\"7\">Writer</option>\n"; + } + + print "</select>\n"; + + if (length($icon_find) > 0) { + print "<input type=image src=\"$imagedir/$icon_find\" ALT=\"Find\">\n"; + }else{ + print "<input type=submit value=\"Find\" name=\"SUBMITFIND\">\n"; + } + + print "</form>"; + + + my $s_todo = &ToDoSupported; + my $s_guide = 0; + + if ($rtvaccess) { + $s_guide = 1; + + } + + if ($rtvaccess) { + print "<td valign=top>RTV:\n"; + print "<td valign=top><form action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + print "<select size=\"1\" name=\"RTVUNIT\">\n"; + for ( split /,/, $replaylist ) { + /,/; + my $addr = $rtvaddress{$_}; + my $label = $rtvlabel{$_}; + print "<option value=$_"; + print ">$label</option>\n"; + } + print "<option value=0 selected>ALL</option>\n"; + print "</select>\n"; + + print "<select size=\"1\" name=\"RTVACTION\">\n"; + print "<option value=-1 selected>Action?</option>\n"; + if ($s_guide) { + print "<option value=1>Refresh</option>\n"; + } + if ($s_todo) { + print "<option value=2>To-Do</option>\n"; + } + if ($s_guide) { + print "<option value=3>Manage</option>\n"; + } + if ($s_guide) { + print "<option value=4>Manual</option>\n"; + } + print "</select>\n"; + + if (length($icon_go) > 0) { + print "<input type=image src=\"$imagedir/$icon_go\" ALT=\"Go\">\n"; + }else{ + print "<input type=submit value=\"Go\" name=\"SUBMITRTV\">\n"; + } + print "</form>\n"; + } + + print "</center><center>\n"; + + return 1; +} + + +#--------------------------------------------------------------------------------------- +sub PDASingleChannelListings{ + # + # Display Program Listings (Single Channel vertical format) + # + #------------------------------------------------------------------------------- + + my $specialdebug = 0; # Enable Debug Logging + + if ($specialdebug) { + writeDebug("PDASingleChannelListings::$program_tuning $program_title $program_start $program_id"); + } + + #------------------------------------------------------------ + # When the date advances, display the header again + #------------------------------------------------------------ + + $rng_string = substr(as_time_string(as_epoch_seconds($program_true_start)),0,8); + $wday = strftime( "%A", localtime(as_epoch_seconds($program_true_start))); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2) . "/" . substr($rng_string,0,4); + + if( $dsp_string ne $previous_date ) { + print "<$size_pdalistings><B>$dsp_string ($program_tuning $program_channel)</B><p>\n"; + $previous_date = $dsp_string; + } + + #------------------------------------------------------------ + # Display the start time to the left of each show + #------------------------------------------------------------ + + print as_hhmm(as_epoch_seconds($program_true_start)) . "<br>"; + + #------------------------------------------------------------ + # Force some variables so the odd start times aren't duplicated in the render + #------------------------------------------------------------ + + $starttime = $program_true_start; + $colpos = 1; + $colspan = 1; + $shortslot = 0; + + print "<a "; + + if ($create_anchor) { + print "name=\"$program_id\" "; + } + + $url_parms = ""; + addParameter("PROGRAMID",$program_id); + addParameter("STARTDATE",$inp_startdate); + addParameter("STARTHOUR",$inp_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print " href=\"$scriptdir/$scriptname$url_parms\">\n"; + + print renderhtml($program_title); + print "\n</a>"; + + if ($program_length > 30) { + print " <small>" . getRunningTime($display_length) . "</small>"; + } + + print "<br>\n"; + + + #------------------------------------------------------------------- + # Only one show per row + #------------------------------------------------------------------- + + $rows++; + + if ($specialdebug) { + writeDebug("PDASingleChannelListings::(exiting)"); + } + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub SingleChannelListings{ + # + # Display Program Listings (Single Channel vertical format) + # + #------------------------------------------------------------------------------- + + my $specialdebug = 0; # Enable Debug Logging + + if ($specialdebug) { + writeDebug("SingleChannelListings::$program_tuning $program_title $program_start $program_id CP: $colpos ER: $end_row"); + } + + #------------------------------------------------------------ + # When the date advances, display the header again + #------------------------------------------------------------ + + $rng_string = substr(as_time_string(as_epoch_seconds($program_true_start)),0,8); + $wday = strftime( "%A", localtime(as_epoch_seconds($program_true_start))); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2) . "/" . substr($rng_string,0,4); + + if( $dsp_string ne $previous_date ) { + print "<tr><td width=10% align=center bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" size=2 color=\"$color_headingtext\"><B>$dsp_string</B></font>\n"; + print "<td align=center bgcolor=\"$color_channelbackground\">"; + if ($showchannelicons > 0) { + if (length($icon{$program_channel}) > 0) { + print "<img src=$icon{$program_channel}><br>"; + } + } + print "<font size=2 face=\"$font_channel\" color=\"$color_channeltext\"><B>$program_tuning<br>$program_channel</B></font>\n"; + print "</td></tr>\n"; + $previous_date = $dsp_string; + } + + #------------------------------------------------------------ + # Display the start time to the left of each show + #------------------------------------------------------------ + + print "<TR><TD>" . as_hhmm(as_epoch_seconds($program_true_start)) . "</TD>\n"; + + #------------------------------------------------------------ + # Force some variables so the odd start times aren't duplicated in the render + #------------------------------------------------------------ + + $starttime = $program_true_start; + $colpos = 1; + $colspan = 1; + $shortslot = 0; + + #------------------------------------------------------------------- + # Render the show data + #------------------------------------------------------------------- + &RenderShow; + + #------------------------------------------------------------------- + # Only one show per row + #------------------------------------------------------------------- + + $rows++; + print "</tr>\n"; + + if ($specialdebug) { + writeDebug("SingleChannelListings::(exiting)"); + } + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub DisplayListings{ + # + # Display Program Listings + # + #------------------------------------------------------------------------------- + + my $specialdebug = 0; # Enable Debug Logging + + + #------------------------------------------------------------------------------- + # Precalculate epoch seconds for a number of fields, $es_ means epoch seconds. + # (Duh). You can get HH:MM with as_hhmm($es_blah) + #------------------------------------------------------------------------------- + + $es_program_true_start = as_epoch_seconds($program_true_start); + $es_program_start = as_epoch_seconds($program_start); + $es_program_stop = as_epoch_seconds($program_stop); + $es_starttime = as_epoch_seconds($starttime); + $es_endtime = as_epoch_seconds($endtime); + + &CalculateSlotTimes; + + #------------------------------------------------------------------------------- + # These will contain "previous" position data. + #------------------------------------------------------------------------------- + + $tmp_slotstart = $es_slotstart; + $tmp_shortslot = $shortslot; + $tmp_colspan = $colspan; + $tmp_colpos = $colpos; + + my $clean_up = 0; + + #------------------------------------------------------------------------------- + # Vomit debug information. + #------------------------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("DisplayListings::START***"); + writeDebug("DisplayListings::Starting processing for timeslot " . as_hhmm($es_slotstart) . " $es_slotstart )"); + writeDebug("DisplayListings::$program_tuning $program_title $program_start $program_id CP: $colpos ER: $end_row CL: $clean_up TM: $total_minutes PD: $previous_display"); + writeDebug("DisplayListings:: Program True: " . as_hhmm($es_program_true_start) . " $es_program_true_start $program_true_start "); + writeDebug("DisplayListings::Program Start: " . as_hhmm($es_program_start) . " $es_program_start $program_start "); + writeDebug("DisplayListings:: Program Stop: " . as_hhmm($es_program_stop) . " $es_program_stop $program_stop "); + writeDebug("DisplayListings:: Current Slot: " . as_hhmm($es_slotstart) . " $es_slotstart"); + writeDebug("DisplayListings:: Next Slot: " . as_hhmm($es_nextslot) . " $es_nextslot"); + writeDebug("DisplayListings::Previous Slot: " . as_hhmm($es_prevslot) . " $es_prevslot"); + writeDebug("DisplayListings:: Window Start: " . as_hhmm($es_starttime) . " $es_starttime"); + writeDebug("DisplayListings:: Window End: " . as_hhmm($es_endtime) . " $es_endtime"); + + } + + + #------------------------------------------------------------------------------- + # See if we are the start of a row, if the previous row ended early, grey out + # the remainder with the pastshow color. + #------------------------------------------------------------------------------- + + if(($colpos > 1) && !$shortslot && ($es_program_start > $es_slotstart) ) { + + #------------------------------------------------------------------- + # If we have a gap in the data, fill with blank columns + # This happens primarily for scheduled programs + # (colpos = 1 case is handled later, when we start a new column) + # ??? If total_minutes < inp_showslots, then we simply have a case of short programs + # ??? in which case we don't want any extra padding + #------------------------------------------------------------------- + + local($temp_value) = $es_program_start - $es_slotstart; + local($temp_value) = int $temp_value / 60; + + if ($temp_value < $inp_showslots) { + # Should be alright + }else{ + if ($colpos < $maxpos) { + + #------------------------------------------------------------------- + # nearly truncate so we don't leave too much of a gap + #------------------------------------------------------------------- + + $colspan = sprintf("%.0f",$temp_value / $inp_showslots - 0.4); + + if( $colspan > 0 ) { + if ($specialdebug) { + writeDebug("DisplayListings::Filling with $colspan columns because program $program_title starts $temp_value minutes late"); + writeDebug("DisplayListings::program_start = $program_start, starttime = $starttime, colpos = $colpos, showslots = $inp_showslots"); + } + + print "<td colspan=$colspan align=left valign=top bgcolor=$color_show[0]>\n"; + $colpos += $colspan; + $td_ctr += $colspan; + } + } + } + } + + + if ( ( $displayunitlabel && ($dl_lasttuning ne $displayunitlabel)) + || (!$displayunitlabel && ($dl_lasttuning != $program_tuning)) ) { + if (!$end_row) { + $colspan = ($maxpos+1) - $colpos; + print "<td colspan=$colspan align=left valign=top bgcolor=$color_show[0]>"; + print "</td>\n"; + if ($specialdebug) { + writeDebug("DisplayListings::prior row adjusted ($dl_lasttuning != $program_tuning)"); + } + $colpos = 1; + $end_row = 1; + } + $clean_up = 1; + }else{ + if ($rows > 1) { + if ($end_row) { + if (!$shortslot) { + if ($specialdebug) { + writeDebug("DisplayListings::no room to display record(A)"); + } + $colpos = 1; + $shortslot = 0; + $end_row = 1; + $total_minutes = 0; + if ($specialdebug) { + writeDebug("DisplayListings::bailing early(A)"); + } + if ($specialdebug) { + writeDebug("DisplayListings::(exiting)(A)"); + } + return 1; + } + } + } + } + + + $reset_flag = 1; + + + if ($end_row) { + if ($clean_up) { + if ($specialdebug) { + writeDebug("DisplayListings::cleanup on aisle 7 - reset: $reset_flag"); + } + $rows++; + $hdr_ctr++; + print "</tr>\n"; + $shortslot = 0; + $debug_state = 0; + $clean_up = 0; + + #------------------------------------------------------------------- + # PVB: I needed to add this so that a schedulebar after a very long show + # (starts before starttime, ends after endtime) + # gets displayed properly + # Question: does this mess up any other column reset logic??? + # Answer: YES, if first show of next row is not at column 1 + #------------------------------------------------------------------- + + # $colpos = 1; # Reset column position since we are starting a new row + + + if ($specialdebug) { + writeDebug("DisplayListings::cleanup with colpos = $colpos"); + } + if( $colpos >= $maxpos ) { + $colpos = 1; + } + + #-------------------------------------------------------------------- + # Special case: can force a heading by setting hdr_ctr = -1 + #-------------------------------------------------------------------- + + if($hdr_ctr == 0) { + print "$heading\n"; + } elsif ($showheaderrows) { + if ($hdr_ctr >= $showheaderrows) { + print "$heading\n"; + $hdr_ctr = 0; + } + } + + $force_new_column = 1; + + if ($specialdebug) { + writeDebug("DisplayListings::finished cleaning up ($rows / $hdr_ctr)"); + } + + } + + + if($es_program_start > $es_starttime) { + local($temp_value) = $es_program_start - $es_starttime; + local($temp_value) = int $temp_value / 60; + + if ($specialdebug) { + writeDebug("DisplayListings::Data Short by $temp_value minutes"); + } + + if ($temp_value < $inp_showslots) { + + #-------------------------------------------------------------------- + # Should be alright + #-------------------------------------------------------------------- + if ($specialdebug) { + writeDebug("DisplayListings::no padding because $temp_value < $inp_showslots"); + } + }else{ + if ($colpos < $maxpos) { + $colspan = sprintf("%.0f",$temp_value / $inp_showslots); # round + #-------------------------------------------------------------------- + # If we fall short of the end, leave one slot for what must come after + #-------------------------------------------------------------------- + if( ($colspan > 1) && ($temp_value > ($colspan-1)*$inp_showslots) && ($temp_value < ($colspan*$inp_showslots)) ) { + if ($specialdebug) { + writeDebug("DisplayListings::Leaving one slot open at the end for the next show because pad is $temp_value minutes and display is $colspan * $inp_showslots wide"); + } + $colspan--; + } + + + if ($specialdebug) { + writeDebug("DisplayListings::Filling with $colspan columns"); + } + + print"\n<tr><td align=center bgcolor=\"$color_channelbackground\">"; + $td_ctr = 0; + + if ( $displayunitlabel ) { + print "<font size=2 face=\"$font_channel\" color=\"$color_channeltext\">$displayunitlabel</FONT>\n"; + } else { + if ($showchannelicons > 0) { + if (length($icon{$program_channel}) > 0) { + print "<img src=$icon{$program_channel}><br>"; + } + } + print "<font size=2 face=\"$font_channel\" color=\"$color_channeltext\"><B>$program_tuning<br>\n"; + + #-------------------------------------------------------------------- + # Add a link to show just the single channel with 2 days of listings + #-------------------------------------------------------------------- + + $url_parms = ""; + addParameter("FIRSTTUNE",$program_tuning); + addParameter("LASTTUNE",$program_tuning); + addParameter("SHOWHOURS","48"); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print "<a href=\"$scriptdir/$scriptname$url_parms\">$program_channel</a></b></font>\n"; + } + + + print "<td colspan=$colspan align=middle valign=middle bgcolor=$color_show[0]>\n"; + $td_ctr += $colspan; + + + #-------------------------------------------------------------------- + # When displaying a bar of scheduled programming, never say "NO DATA" + #-------------------------------------------------------------------- + + if ( !$displayunitlabel ) { + print "<font size=2><B><I>NO DATA</I></B></FONT>\n"; + } + $colpos = 1 + $colspan; + $reset_flag = 0; + $end_row = 0; + $total_minutes = 0; + }else{ + if (!$shortslot) { + if ($specialdebug) { + writeDebug("DisplayListings::no room to display record(B)"); + } + $colpos = 1; + $shortslot = 0; + $end_row = 1; + $total_minutes = 0; + if ($specialdebug) { + writeDebug("DisplayListings::bailing early(B)"); + } + if ($specialdebug) { + writeDebug("DisplayListings::(exiting)(B)"); + } + return 1; + } + } + } + } + + $colspan = 0; + $end_row = 0; + $total_minutes= 0; + if ($reset_flag) { + $colpos = 1; + } + } + + #------------------------------------------------------------------------------- + # Cleanup (if needed) is finished and we're ready to begin working on this + # slot. + #------------------------------------------------------------------------------- + + + $tmp_slotstart = $es_starttime + ((($colpos - 1) * $inp_showslots) * 60); + + if ($tmp_slotstart != $es_slotstart) { + if ($specialdebug) { + writeDebug("DisplayListings::selected slot has changed, updating."); + } + &CalculateSlotTimes; + + if ($specialdebug) { + writeDebug("DisplayListings:: Current Slot: " . as_hhmm($es_slotstart) . " $es_slotstart"); + writeDebug("DisplayListings:: Next Slot: " . as_hhmm($es_nextslot) . " $es_nextslot"); + writeDebug("DisplayListings::Previous Slot: " . as_hhmm($es_prevslot) . " $es_prevslot"); + } + } + + if ($specialdebug) { + writeDebug("DisplayListings::Slot starting at " . as_hhmm($tmp_slotstart)); + } + + if ($specialdebug) { + writeDebug("DisplayListings::SS: $shortslot TM: $total_minutes CP: $colpos ER: $end_row ST: $starttime PS: $program_start PTS: ($program_true_start)"); + } + + #------------------------------------------------------------------------------- + # Calculate the number of columns we need to span, the calculation can vary + # depending if the show will end cleanly on the next slot or not + # + # These checks help 'snap' the show to the grid. + # + # NOTE: If $colpos changes, you must run &CalculateSlotTimes again for it to + # process properly later. + #------------------------------------------------------------------------------- + + + if ($total_minutes > $inp_showslots) { + $tmp_slotstart = $es_slotstart + ($total_minutes * 60); + } + + if ($specialdebug) { + writeDebug("DisplayListings::initial checks"); + writeDebug("DisplayListings::check 1 PTS:" . as_hhmm($es_program_true_start) . " PS " . as_hhmm($es_program_start) . " NXS " . as_hhmm($es_nextslot)); + } + + if ($es_program_true_start >= $es_nextslot) { + if ($specialdebug) { + writeDebug("DisplayListings::check 1 triggered ($shortslot)"); + } + + if ($shortslot) { + $force_new_column = 1; + $colpos++; + $shortslot = 0; + $total_minutes = 0; + &CalculateSlotTimes; + + if ($specialdebug) { + writeDebug("DisplayListings::check 1: FNC forced to 1, SS canceled, CP incremented to $colpos"); + writeDebug("DisplayListings::Updating..."); + writeDebug("DisplayListings:: Current Slot: " . as_hhmm($es_slotstart) . " $es_slotstart"); + writeDebug("DisplayListings:: Next Slot: " . as_hhmm($es_nextslot) . " $es_nextslot"); + writeDebug("DisplayListings::Previous Slot: " . as_hhmm($es_prevslot) . " $es_prevslot"); + } + } + } + + if ($specialdebug) { + writeDebug("DisplayListings::check 2 PTS:" . as_hhmm($es_program_true_start) . " PS " . as_hhmm($es_program_start) . " NXS " . as_hhmm($es_slotstart)); + } + + if ($es_program_true_start == $es_slotstart) { + if ($specialdebug) { + writeDebug("DisplayListings::check 2 triggered ($shortslot)"); + } + + if ($shortslot) { + $force_new_column = 1; + $shortslot = 0; + $total_minutes = 0; + + if ($specialdebug) { + writeDebug("DisplayListings::check 2 confirmed: FNC forced to 1, SS canceled"); + } + } + } + + + if ($specialdebug) { + writeDebug("DisplayListings::check 3 PTS:" . as_hhmm($es_program_true_start) . " PS " . as_hhmm($es_program_start) . " NXS " . as_hhmm($es_prevslot)); + } + + if ($es_program_true_start == $es_prevslot) { + if ($specialdebug) { + writeDebug("DisplayListings::check 3 triggered ($shortslot)"); + } + if ($shortslot) { + $force_new_column = 1; + $colpos--; + $shortslot = 0; + $total_minutes = 0; + &CalculateSlotTimes; + + if ($specialdebug) { + writeDebug("DisplayListings::check 3 confirmed: FNC forced to 1, SS canceled, CP decremented to $colpos"); + writeDebug("DisplayListings::Updating..."); + writeDebug("DisplayListings:: Current Slot: " . as_hhmm($es_slotstart) . " $es_slotstart"); + writeDebug("DisplayListings:: Next Slot: " . as_hhmm($es_nextslot) . " $es_nextslot"); + writeDebug("DisplayListings::Previous Slot: " . as_hhmm($es_prevslot) . " $es_prevslot"); + } + } + } + + if ($specialdebug) { + writeDebug("DisplayListings::initial checks completed"); + } + + #-------------------------------------------------------------------------------- + # Check slot alignments + #-------------------------------------------------------------------------------- + + + if ($specialdebug) { + writeDebug("DisplayListings::checking for shows that need aligned"); + } + + if (($es_program_true_start != $es_slotstart) && ($program_stop != $endtime)) { + + if ($specialdebug) { + writeDebug("DisplayListings::start alignment processing"); + } + + $length_offset = $es_slotstart - $es_program_true_start; + $length_offset = int $length_offset / 60; + if ($length_offset < 1) { + $length_offset = 0; + } + + $temp_value = $display_length - $length_offset; + + if ($specialdebug) { + writeDebug("DisplayListings::SLOT: $es_slotstart TV: $temp_value NSLOT: " . $es_nextslot); + writeDebug("DisplayListings::SLOT: " . as_hhmm($es_slotstart) . " TV: $temp_value NSLOT: " . as_hhmm($es_nextslot) . " / " . as_hhmm($es_slotstart + (($temp_value + $total_minutes) * 60))); + } + + + if (($es_slotstart + (($temp_value + $total_minutes) * 60)) == $es_nextslot) { + $shortslot = 0; + $total_minutes = 0; + if ($specialdebug) { + writeDebug("DisplayListings::SS: $shortslot (cancelled) TM: $total_minutes - ends perfectly on the next slot"); + } + } + + #----------------------------------------------------------------- + # Experimental *** + #----------------------------------------------------------------- + + if ($total_minutes > 0) { + if ($specialdebug) { + writeDebug("DisplayListings::TV: $temp_value, TM: $total_minutes, SS: $shortslot"); + } + + $temp_value = $temp_value + $total_minutes; + + if ($specialdebug) { + writeDebug("DisplayListings::Adjusted TV to $temp_value"); + } + + } + + #----------------------------------------------------------------- + # Experimental End ** + #----------------------------------------------------------------- + + + $colspan = sprintf("%.0f",$temp_value / $inp_showslots); # round + + if ($colspan < 1) { + $colspan = 1; + if ($specialdebug) { + writeDebug("DisplayListings::CS: Column not visible, correcting"); + } + } + + if ($specialdebug) { + writeDebug("DisplayListings::CS: $colspan ($es_program_true_start!=$es_starttime)"); + } + if ($specialdebug) { + writeDebug("DisplayListings::TV: $temp_value, LO: $length_offset, DL: $display_length"); + } + + # $colspan = int $temp_value / $inp_showslots; + + if ($specialdebug) { + writeDebug("DisplayListings::alignment processing complete"); + } + + }else{ + if ($specialdebug) { + writeDebug("DisplayListings::show already aligned"); + } + + $colspan = sprintf("%.0f",$program_length / $inp_showslots); # round + # $colspan = int $program_length / $inp_showslots; + if ($colspan < 1) { + $colspan = 1; + if ($specialdebug) { + writeDebug("DisplayListings::Column not visible, correcting"); + } + } + + if ($specialdebug) { + writeDebug("DisplayListings::CS: $colspan ($es_program_true_start==$es_starttime)"); + } + } + + if ($specialdebug) { + writeDebug("DisplayListings::alignment checks complete"); + } + + + #------------------------------------------------------------------- + # If the endtime is LESS than the next slot's time, decrement the + # colspan. + #------------------------------------------------------------------- + + + if ($specialdebug) { + writeDebug("DisplayListings::checking column span"); + } + + $tmp_slotend = ($es_starttime + (((($colpos + $colspan) -1) * $inp_showslots) * 60)); + $tmp_nextslot = ($es_starttime + ((($colpos + $colspan) * $inp_showslots) * 60)); + + if ($es_program_stop < $tmp_slotend) { + if ($shortslot) { + #-------------------------------------------------------------------- + # Do not modify colspan + #-------------------------------------------------------------------- + + }else{ + + if (($tmp_slotend - $es_program_stop) < $grid_leeway_second) { + if ($specialdebug) { + writeDebug("DisplayListings::Leeway check " . ($tmp_slotend - $es_program_stop) . " < $grid_leeway_second"); + writeDebug("DisplayListings::CS left at $colspan (" . as_hhmm($es_program_stop) . " < " . as_hhmm($tmp_slotend) . " [" . as_hhmm($tmp_nextslot) . "]) (1) - within $grid_leeway_second seconds"); + } + }else{ + $colspan--; + if ($specialdebug) { + writeDebug("DisplayListings::CS adjusted to $colspan (" . as_hhmm($es_program_stop) . " < " . as_hhmm($tmp_slotend) . " [" . as_hhmm($tmp_nextslot) . "]) (1)"); + } + } + } + } + + #------------------------------------------------------------------- + # If the endtime of the program IS the next slot, go for it. + #------------------------------------------------------------------- + + + if ($es_program_stop == $tmp_nextslot) { + if ($shortslot) { + #-------------------------------------------------------------------- + # Do not modify colspan + #-------------------------------------------------------------------- + + }else{ + $colspan++; + if ($specialdebug) { + writeDebug("DisplayListings::CS adjusted to $colspan (" . as_hhmm($es_program_stop) . " == " . as_hhmm($tmp_nextslot) . ") (2)"); + } + } + } + + + #-------------------------------------------------------------------- + # Sanity Check colspan + #-------------------------------------------------------------------- + + if ($colspan < 1) { + $colspan = 1; + + if ($specialdebug) { + writeDebug("DisplayListings::colspan less than 1, readjusting"); + } + + } + + #-------------------------------------------------------------------- + # Flag if the slot is approximate + #-------------------------------------------------------------------- + + if ($colspan > int ($program_length / $inp_showslots)) { + $slot_approximate = 1; + }else{ + $slot_approximate = 0; + } + + if ($specialdebug) { + writeDebug("DisplayListings::CS: $colspan - is approximate? $slot_approximate"); + } + + + #------------------------------------------------------------------- + # Handle programming less than one slot in length. + # + # There is a debug_state variable for tracing this path. + #------------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("DisplayListings::entering partial slot processor"); + writeDebug("DisplayListings::SS: $shortslot PD: $previous_display TM: $total_minutes DL: $display_length"); + } + + + if ($display_length < $inp_showslots) { + if ($specialdebug) { + writeDebug("DisplayListings::potential partial slot detected"); + } + + $debug_state = "A1"; + if ($total_minutes <= $inp_showslots) { + $debug_state = "A1A"; + if (($total_minutes + $display_length) <= $inp_showslots) { + $debug_state = "A1AA"; + if (!$shortslot) { + if ($previous_display >= $inp_showslots) { + $total_minutes = 0; + }else{ + $total_minutes = $previous_display; + } + } + $shortslot = 1; + if ($specialdebug) { + writeDebug("DisplayListings::SS adjusted to $shortslot at $debug_state"); + } + }else{ + $debug_state = "A1AB"; + if ($specialdebug) { + writeDebug("DisplayListings::TM adjusted to $total_minutes at $debug_state SS: $shortslot"); + } + + if (($total_minutes + $display_length) < $inp_showslots) { + $debug_state = "A1ABA"; + if ($shortslot) { + $colpos = $colpos + 1; + if ($specialdebug) { + writeDebug("DisplayListings::CP adjusted to $colpos at $debug_state TM: $total_minutes SS: $shortslot"); + } + } + $shortslot = 1; + }else{ + $debug_state = "A1ABB"; + if (($es_nextslot - $es_program_true_start) >= $grid_leeway_second) { + $debug_state = "A1ABB1"; + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state (" . as_hhmm($es_program_true_start) . " > " . as_hhmm($es_nextslot) . " - within $grid_leeway_second seconds)"); + } + }else{ + $debug_state = "A1ABB2"; + $shortslot = 0; + # $total_minutes = 0; + if ($specialdebug) { + writeDebug("DisplayListings::SS reset ($shortslot) at $debug_state TM $total_minutes PD $previous_display"); + writeDebug("DisplayListings::" . ($es_nextslot - $es_program_true_start)); + } + } + } + } + }else{ + $debug_state = "A1B"; + $tmp_nextslot = (as_epoch_seconds($starttime) + ((($colpos) * $inp_showslots) * 60)); + if (($es_nextslot - $es_program_true_start) < $grid_leeway_second) { + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state (" . as_hhmm($es_program_true_start) . " < " . as_hhmm($es_nextslot) . " - within $grid_leeway_second seconds)"); + } + $debug_state = "A1BA"; + if ($shortslot == 1) { + $debug_state = "A1BA1"; + $colpos = $colpos + 1; + if ($specialdebug) { + writeDebug("DisplayListings::CP adjusted to $colpos at $debug_state"); + } + } + $shortslot = 1; + if ($specialdebug) { + writeDebug("DisplayListings::SS set to $shortslot at $debug_state"); + } + }else{ + $debug_state = "A1BAB"; + $shortslot = 1; + if ($specialdebug) { + writeDebug("DisplayListings::SS set to $shortslot at $debug_state"); + } + } + } + }else{ + $debug_state = "A2"; + if ($total_minutes > 0) { + $debug_state = "A2A"; + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state TM $total_minutes"); + writeDebug("DisplayListings::$debug_state SS: $shortslot DL: $display_length CP: $colpos CS: $colspan"); + } + if (($total_minutes + $display_length) <= $inp_showslots) { + $debug_state = "A2AA"; + if ($es_program_true_start > $es_slotstart) { + if ($specialdebug) { + writeDebug("DisplayListings::PTS " . as_hhmm($es_program_true_start) . " > " . as_hhmm($es_slotstart)); + } + $colpos = $colpos + 1; + local($temp_value) = ($program_length / $inp_showslots); + if ($specialdebug) { + writeDebug("DisplayListings::CP adjusted to $colpos at $debug_state ($temp_value)"); + } + + if ($colspan > $temp_value) { + $colspan--; + if ($specialdebug) { + writeDebug("DisplayListings::CS adjusted to $colspan at $debug_state"); + } + } + }else{ + $debug_state = "A2AA1"; + } + } + } + +# $shortslot = 0; +# $total_minutes = 0; + + $temp_value3 = 0; + if ($es_program_stop == $es_nextslot) { # Was $colpos+1 bug? that's 2 slots ahead + + $temp_value3 = (($inp_showslots * $colspan) - ($es_program_stop) - $es_program_true_start) / 60; + local($spanstop) = ($es_starttime + ($inp_showslots * ($colspan+$colpos-1) * 60)); + local($showstop) = $es_program_stop; + + if (($temp_value3 < 0) && ($temp_value3 > -15)) { + if ($spanstop != $showstop) { + $debug_state = "A3AAA"; + $colspan++; + if ($specialdebug) { + writeDebug("DisplayListings::CS adjusted to $colspan at $debug_state (" . as_hhmm($spanstop) . " != " . as_hhmm($showstop) . ") TV3: $temp_value3"); + } + }else{ + $debug_state = "A3AAB"; + } + }else{ + $debug_state = "A3AB"; + } + }else{ + $debug_state = "A3B"; + } + + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state CS: $colspan"); + } + + } + + + if ($shortslot) { + $debug_state = "B"; + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state final check"); + } + if ($max_span) { + $debug_state = "B1"; + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state $max_span > 0"); + } + if ($colspan > $max_span) { + $debug_state = "B1A"; + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state $max_span > $colspan"); + } + + $colspan = $colspan - $max_span; + $colpos = $colpos + $max_span; + + + &CalculateSlotTimes; + + + $shortslot = 0; + + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state SS canceled CP: $colpos CS: $colspan ER: $end_row MP: $maxpos"); + writeDebug("DisplayListings::Updating..."); + writeDebug("DisplayListings:: Current Slot: " . as_hhmm($es_slotstart) . " $es_slotstart"); + writeDebug("DisplayListings:: Next Slot: " . as_hhmm($es_nextslot) . " $es_nextslot"); + writeDebug("DisplayListings::Previous Slot: " . as_hhmm($es_prevslot) . " $es_prevslot"); + } + } + }else{ + $debug_state = "B2"; + + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state $max_span is zero or undefined"); + } + + if ($specialdebug) { + writeDebug("DisplayListings::program ends at " . as_hhmm($es_program_stop) . " next slot starts at " . as_hhmm($es_nextslot)); + } + + if ($es_program_stop >= $es_nextslot) { + $debug_state = "B2A"; + if ($es_program_true_start == $es_slotstart) { + $debug_state = "B1A1"; + $shortslot = 0; + + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state SS canceled CP: $colpos CS: $colspan ER: $end_row MP: $maxpos"); + } + } + } + + + if ($specialdebug) { + writeDebug("DisplayListings::$debug_state final complete (SS: $shortslot)"); + } + } + + } + + + + + if ($specialdebug) { + writeDebug("DisplayListings::finished partial slot processor (SS: $shortslot)"); + } + + + #------------------------------------------------------------------- + # If it's a short slot we may need to make some adjustments + #------------------------------------------------------------------- + + if ($shortslot) { + if ($total_minutes == $display_length) { + $temp_value2 = $es_endtime - $es_program_true_start; + $temp_value2 = int ( $temp_value2 / 60 ); + if ($temp_value2 < 0) { + $temp_value2 = 0; + } + + if (($temp_value2 < $inp_showslots) && ($colpos > $maxpos)) { + $shortslot = 0; + $total_minutes = 0; + if ($specialdebug) { + writeDebug("DisplayListings::shortslot cancelled"); + writeDebug("DisplayListings::TV2: $temp_value2 CP: $colpos MP: $maxpos ISS: $inp_showslots"); + } + } + + + } + } + + #------------------------------------------------------------------- + # If it's a regular slot check ranges. + # + # This could be part of the previous if as an else but there may + # be times when you want to comment one out and not the other. + # (For testing or an alternate application.) + # + #------------------------------------------------------------------- + + if (!$shortslot) { + if (($colpos + $colspan) > $maxpos) { + if ($specialdebug) { + writeDebug("DisplayListings::span would cross edge, ending at edge and flagging end_row CS: $colspan TD: $td_ctr"); + } + $colspan = ($maxpos+1) - $colpos; + $end_row = 1; + if ($specialdebug) { + writeDebug("DisplayListings::CP: $colpos MP: $maxpos CS: $colspan MS: $max_span SS: $shortslot ER: $end_row TD: $td_ctr"); + } + } + + if (($colspan > $maxpos) || ($es_program_stop >= $es_endtime)) { + if ($specialdebug) { + writeDebug("DisplayListings::span is past edge, ending at edge and flagging end_row CS: $colspan TD: $td_ctr"); + } + $colspan = ($maxpos+1) - $colpos; + $end_row = 1; + + if ($specialdebug) { + writeDebug("DisplayListings::CP: $colpos MP: $maxpos CS: $colspan MS: $max_span SS: $shortslot ER: $end_row TD: $td_ctr"); + } + + } + + #-------------------------------------------------------------------------------- + # Due to limitations by doing this one row at a time, sometimes the grid is a + # little bit off and we end up wanting to do an extra column. To keep the + # display nice we just chop it off early. + # + # This won't occur very often. + #-------------------------------------------------------------------------------- + + + if ((($colpos == $maxpos) && ($td_ctr == $maxpos)) ) { + if ($specialdebug) { + writeDebug("DisplayListings::start is off edge, supressing display and flagging end_row CS: $colspan TD: $td_ctr FNC: $force_new_column"); + } + $colspan = 0; + $end_row = 1; + + if ($specialdebug) { + writeDebug("DisplayListings::CP: $colpos MP: $maxpos CS: $colspan MS: $max_span SS: $shortslot ER: $end_row TD: $td_ctr FNC: $force_new_column"); + } + + } + } + + + if (($total_minutes == 0) && ($shortslot)) { + + if ($specialdebug) { + writeDebug("DisplayListings::check 2 PTS:" . as_hhmm(as_epoch_seconds($program_true_start)) . " PS " . as_hhmm($es_program_start) . " NXS " . as_hhmm(as_epoch_seconds($starttime) + ((($colpos-1) * $inp_showslots) * 60))); + } + + if ($es_program_true_start > $es_slotstart -1) { + if ($shortslot) { + $force_new_column = 1; + + if ($specialdebug) { + writeDebug("DisplayListings::forcing new column (TM is $total_minutes and SS $shortslot)"); + } + } + } + } + + if ($specialdebug) { + writeDebug("DisplayListings::CP: $colpos CS: $colspan SS: $shortslot DS: $debug_state MP $maxpos TM: $total_minutes DL: $display_length MS: $max_span TD: $td_ctr"); + } + + + #------------------------------------------------------------------- + # If colSpan is non-zero then we have something to display + #------------------------------------------------------------------- + + if ($colspan > 0) { + #------------------------------------------------------------------- + # Display channel or replay unit names in the left column + #------------------------------------------------------------------- + if ($colpos == 1) { + if ($shortslot) { + if ($new_row){ + if ($specialdebug) { + writeDebug("DisplayListings::starting row, NR: $new_row / FNC: $force_new_column"); + } + print"\n<tr><td align=center bgcolor=\"$color_channelbackground\">"; + $td_ctr = 0; + + if ( $displayunitlabel ) { + print "<font size=2 face=\"$font_channel\" color=\"$color_channeltext\">$displayunitlabel</FONT>\n"; + } else { + if ($showchannelicons > 0) { + if (length($icon{$program_channel}) > 0) { + print "<img src=$icon{$program_channel}><br>"; + } + } + print "<font size=2 face=\"$font_channel\" color=\"$color_channeltext\"><B>$program_tuning<br>\n"; + #-------------------------------------------------------------------- + # Add a link to show just the single channel with 2 days of listings + #-------------------------------------------------------------------- + + $url_parms = ""; + addParameter("FIRSTTUNE",$program_tuning); + addParameter("LASTTUNE",$program_tuning); + addParameter("SHOWHOURS","48"); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print "<a href=\"$scriptdir/$scriptname$url_parms\">$program_channel</a></b></font>\n"; + + } + $new_row = 0; + $force_new_column = 1; + if ($specialdebug) { + writeDebug("DisplayListings::row started, NR: $new_row / FNC: $force_new_column"); + } + + } + }else{ + if (($dl_lasttuning == $program_tuning) && ($previous_display > 0)) { + if ($specialdebug) { + writeDebug("DisplayListings::using same row ($dl_lasttuning, $program_tuning, $previous_display, $new_row)"); + } + }else{ + if ($specialdebug) { + writeDebug("DisplayListings::starting row ($dl_lasttuning, $program_tuning, $new_row)"); + } + print"\n<tr><td align=center bgcolor=\"$color_channelbackground\">"; + $td_ctr = 0; + + if ( $displayunitlabel ) { + print "<font size=2 face=\"$font_channel\" color=\"$color_channeltext\">$displayunitlabel</FONT>\n"; + } else { + if ($showchannelicons > 0) { + if (length($icon{$program_channel}) > 0) { + print "<img src=$icon{$program_channel}><br>"; + } + } + + print "<font size=2 face=\"$font_channel\" color=\"$color_channeltext\"><B>$program_tuning<br>\n"; + #-------------------------------------------------------------------- + # Add a link to show just the single channel with 2 days of listings + #-------------------------------------------------------------------- + + $url_parms = ""; + addParameter("FIRSTTUNE",$program_tuning); + addParameter("LASTTUNE",$program_tuning); + addParameter("SHOWHOURS","48"); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print "<a href=\"$scriptdir/$scriptname$url_parms\">$program_channel</a></b></font>\n"; + } + $new_row = 0; + $force_new_column = 1; + if ($specialdebug) { + writeDebug("DisplayListings::row started, NR: $new_row / FNC: $force_new_column"); + } + } + + } + } + + #------------------------------------------------------------------- + # Render the show data + #------------------------------------------------------------------- + if ($specialdebug) { + writeDebug("DisplayListings::dispatching render"); + } + &RenderShow; + if ($specialdebug) { + writeDebug("DisplayListings::render complete"); + } + + + #------------------------------------------------------------------- + # How many minutes were displayed? + #------------------------------------------------------------------- + + + $tmp_slotstart = $es_starttime + ((($colpos - 1) * $inp_showslots) * 60); + $temp_value = $tmp_slotstart - $es_program_true_start; + $temp_value = int $temp_value / 60; + if ($temp_value < 1) { + $temp_value = 0; + } + $temp_value = $display_length - $temp_value; + if ($temp_value < 0) { + $temp_value = 0; + } + $previous_display = $temp_value; + + + + if ($es_program_stop >= $es_endtime) { + $shortslot = 0; + $end_row = 1; + + if ($specialdebug) { + writeDebug("DisplayListings::$es_program_stop >= $es_endtime. ER: $end_row flagged true"); + } + + } + + #------------------------------------------------------------------- + # Update Column Position (colpos) + #------------------------------------------------------------------- + + if ($shortslot == 1) { + if ($specialdebug) { + writeDebug("DisplayListings::CP: $colpos TM: $total_minutes ISS: $inp_showslots"); + } + if ($total_minutes == $inp_showslots) { + $total_minutes = 0; + $colpos = $colpos + 1; + } + }else{ + if ($specialdebug) { + writeDebug("DisplayListings::CP: $colpos + CS: $colspan"); + } + + $colpos = $colpos + $colspan; + + if ($specialdebug) { + writeDebug("DisplayListings::CP: $colpos"); + } + } + + if ($colpos > $maxpos) { + $end_row = 1; + } + } + + + #------------------------------------------------------------------- + # If at the end of the row, reset + #------------------------------------------------------------------- + + if ($end_row) { + if ($specialdebug) { + writeDebug("DisplayListings::ending row ($rows / $hdr_ctr)"); + } + + if(($colpos > 1) && ($colpos <= $maxpos)) { + $colspan = $maxpos - $colpos + 1; + print "<td colspan=$colspan align=left valign=top bgcolor=$color_show[0]></td>\n"; + $colpos += $colspan; + $td_ctr += $colspan; + + } + $shortslot = 0; + $debug_state = 0; + $previous_display = 0; + #$end_row = 0; + $total_minutes = 0; + $new_row = 1; + } + + if ( $displayunitlabel ) { + $dl_lasttuning = $displayunitlabel; + } else { + $dl_lasttuning = $program_tuning; + } + + if ($specialdebug) { + writeDebug("DisplayListings::(exiting)"); + } + + return 1; +} + +#------------------------------------------------------------------------------------------- +sub RenderShow { + # + # Render Show Data + #------------------------------------------------------------------------------------ + + my $specialdebug = 0; + + if ($specialdebug) { + writeDebug("rendershow::starting render for $program_title ($program_id)"); + writeDebug("rendershow::$es_starttime"); + } + + #------------------------------------------------------------------- + # If RTV mode, check to see if this program is scheduled + #------------------------------------------------------------------- + #------------------------------------------------------------------- + # Color Code the Column + #------------------------------------------------------------------- + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($now_timestring)) { + #------------- + # Past show + #------------- + $program_timing = 0; + }elsif ($es_program_start < as_epoch_seconds($now_timestring)) { + #------------- + # Current show + #------------- + $program_timing = 1; + } else { + #------------- + # Future show + #------------- + $program_timing = 2; + } + $bgcolor = $color_show[$program_timing]; + + if($rtvaccess) { + $program_icon = getScheduleDetails($program_id,$program_timing); + } + + if (length($bgcolor) > 0) { + $bgcolor = " bgcolor=\"$bgcolor\""; + } + + + #------------------------------------------------------------------- + # If it's a short slot, determine if we need a secondary row or not + #------------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("rendershow::SS: $shortslot TM: $total_minutes DL: $display_length CS: $colspan CP: $colpos MP: $maxpos ER: $end_row TD: $td_ctr"); + } + + if ($shortslot) { + if (($new_row) || ($force_new_column)){ + if ($specialdebug) { + writeDebug("rendershow::starting new column, SS: $shortslot FNC: $force_new_column NR: $new_row"); + } + + if ($td_ctr >= $maxpos) { + if ($specialdebug) { + writeDebug("rendershow::canceling new column start since $td_ctr >= $maxpos"); + } + return 0; + } + + print "<td colspan=$colspan align=left valign=top $bgcolor>"; + $td_ctr += $colspan; + + $new_row = 0; + $force_new_column = 0; + $tmp_offset = (($es_starttime + ((($colpos - 1) * $inp_showslots) * 60)) - ($es_program_true_start)) / 60; + $total_minutes = $display_length; + if ($tmp_offset > 0) { + $total_minutes = $total_minutes + $tmp_offset; + } + $max_span = $colspan; + if ($specialdebug) { + writeDebug("rendershow::TO: $tmp_offset TM: $total_minutes DL: $display_length MS: $max_span CS: $colspan"); + } + }else{ + print "<hr>\n"; + $total_minutes = $total_minutes + $display_length; + if ($specialdebug) { + writeDebug("rendershow::continuing column, SS: $shortslot TM: $total_minutes DL: $display_length"); + + } + + #---------------------------------------------------------------- + # If the continuing the column is a *late* decision, backtrack + # the column position. + #---------------------------------------------------------------- + + if (!$tmp_shortslot) { + $colpos = $colpos - $tmp_colspan; + if ($colpos < 1) { + $colpos = 1; + } + if ($specialdebug) { + writeDebug("rendershow::adjusting colpos to $colpos"); + + } + } + + + + } + }else{ + print "<td colspan=$colspan align=left valign=top $bgcolor>"; + $td_ctr += $colspan; + + if ($specialdebug) { + writeDebug("rendershow::starting new column"); + } + $force_new_column = 0; + $max_span = $colspan; + if ($display_length < $inp_showslots) { + $total_minutes = $display_length; + $shortslot = 1; + if ($specialdebug) { + writeDebug("rendershow::show is smaller than slot, SS: $shortslot TM: $total_minutes DL: $display_length"); + } + + }else{ + $max_span = 0; + } + + } + + #------------------------------------------------------------------- + # Display Data + #------------------------------------------------------------------- + print "\n<font size=2>"; + #-------------------------------------------------------------------- + # When showing the schedule bar, prefix the show with the channel number + #-------------------------------------------------------------------- + if ( $displayunitlabel && $program_tuning ) { + print "$program_tuning: "; + } else { + if ($es_program_true_start != ($es_starttime + ((($colpos - 1) * $inp_showslots) * 60)) ) { + if ($specialdebug) { + writeDebug("rendershow::" . as_hhmm($es_program_true_start) . "!=" . as_hhmm($es_starttime + ((($colpos - 1) * $inp_showslots) * 60)) ); + } + print "(" . as_hhmm($es_program_true_start) . ")<br>"; +#-------------------------------------------------------------------------------- +# This is useful for debugging +# +# print "($colpos " . as_hhmm($es_starttime + ($inp_showslots * ($colpos * 60))) . ")<br>"; +#-------------------------------------------------------------------------------- + + } + } + if ($debug) { + print "(S: " . as_hhmm($es_program_start) . ")<br>"; + print "(E: " . as_hhmm($es_program_stop) . ")<br>"; + print "(V: CP)$colpos,CS)$colspan,PL)$program_length,LO)$length_offset,TV)$temp_value,TV2)$temp_value2,TV3)$temp_value3,SS)$shortslot,DS)$debug_state)<br>"; + } + + print "<a "; + if ($create_anchor) { + print "name=\"$program_id\" "; + } + + $url_parms = ""; + addParameter("PROGRAMID",$program_id); + addParameter("STARTDATE",$inp_startdate); + addParameter("STARTHOUR",$inp_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print "href=\"$scriptdir/$scriptname$url_parms\""; + + if ($newwindow) { + print " target=\"_blank\""; + } + print ">"; + print renderhtml($program_title) . "</B>"; + + if ($program_movieyear) { + print " <small>" . substr($stars,1,$program_stars); + print " ($program_movieyear, $program_category)</small>"; + } + print "</a>\n"; + + print "</font>\n"; + + #--------------------------------------------------------------------- + # If showschedulebar == 2, skip the details to keep things brief + #--------------------------------------------------------------------- + + if( ! ($displayunitlabel && ($showschedulebar == 2))) { + print "<br>\n"; + if (length($program_subtitle) > 0) { + print "<font size=-1>\"". renderhtml($program_subtitle) . "\"</font><br>\n"; + } + print "<font size=-2>"; + + if (length($program_episodenum) > 0) { + print "$program_episodenum. \n"; + } + + if ((length($program_category) > 0) && ($program_movieyear == 0)) { + print "($program_category)\n"; + } + + if (length($program_desc) > 0) { + if (length($program_category) > 0) { + print " "; + } + print renderhtml($program_desc); + } + + if (length($program_advisories) > 0) { + if (length($program_desc) > 0) { + print " "; + } + + print "(" . renderhtml($program_advisories) . ")"; + } + + print " $display_length minutes"; + if ($fudged_length) { + print "(approx)"; + } + print ".\n"; + if (length($program_mpaarating) > 0) { + $temp_display = "$program_mpaarating."; + if ($showchannelicons > 0) { + if (($program_mpaarating eq "G") && (length($image_mpaag))) { + $temp_display = buildImage($image_mpaag,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "PG") && (length($image_mpaapg))) { + $temp_display = buildImage($image_mpaapg,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "PG-13") && (length($image_mpaapg13))) { + $temp_display = buildImage($image_mpaapg13,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "R") && (length($image_mpaar))) { + $temp_display = buildImage($image_mpaar,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "NC17") && (length($image_mpaanc17))) { + $temp_display = buildImage($image_mpaanc17,$imagedir,$program_mpaarating); + } + + } + print " $temp_display\n"; + }else{ + if ($program_movieyear) { + $temp_display = "NR."; + if ($showchannelicons > 0) { + if (length($image_mpaanr)) { + $temp_display = buildImage($image_mpaanr,$imagedir,"NR"); + } + } + print " $temp_display\n"; + + } + } + + if (length($program_vchiprating) > 0) { + $temp_display = "TV-$program_vchiprating."; + if ($showchannelicons > 0) { + if (($program_vchiprating eq "G") && (length($image_tvg))) { + $temp_display = buildImage($image_tvg,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "PG") && (length($image_tvpg))) { + $temp_display = buildImage($image_tvpg,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "14") && (length($image_tv14))) { + $temp_display = buildImage($image_tv14,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "MA") && (length($image_tvma))) { + $temp_display = buildImage($image_tvma,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "Y") && (length($image_tvy))) { + $temp_display = buildImage($image_tvy,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "Y7") && (length($image_tvy7))) { + $temp_display = buildImage($image_tvy7,$imagedir,"TV-$program_vchiprating"); + } + } + print " $temp_display\n"; + } + + if (length($program_captions) > 0) { + $temp_display = "CC"; + if ($showchannelicons > 0) { + if (length($image_cc) > 0) { + $temp_display = buildImage($image_cc,$imagedir,"CC"); + } + } + print " $temp_display\n"; + } + + if ($program_stereo) { + $temp_display = "Stereo."; + if ($showchannelicons > 0) { + if (length($image_stereo) > 0) { + $temp_display = buildImage($image_stereo,$imagedir,"Stereo"); + } + } + print " $temp_display\n"; + } + + if ($program_repeat) { + $temp_display = "(Repeat)"; + if ($showchannelicons > 0) { + if (length($image_repeat) > 0) { + $temp_display = buildImage($image_repeat,$imagedir,"Repeat"); + } + } + print " $temp_display\n"; + } + + + if (length($program_extra) > 0) { + print "<br>\n$program_extra\n"; + } + + + if ($slot_approximate) { +#-------------------------------------------------------------------------------- +# print "****"; +#-------------------------------------------------------------------------------- + } + + if (length($program_icon) > 0) { + print "\n<br>$program_icon"; + } + + print "</font>\n"; + } + + if ($specialdebug) { + writeDebug("rendershow::CS: $colspan MS: $max_span CP: $colpos TM: $total_minutes DL: $display_length SS: $shortslot TD: $td_ctr"); + } + + if ($specialdebug) { + writeDebug("rendershow::render complete"); + } + + return 1; +} + +#------------------------------------------------------------------------------------------- +sub DisplayToolbox{ + # + # Display Toolbox + # + #------------------------------------------------------------------------------- + + print "<center><font face=\"$font_menu\">"; + + #------------------------------------------------------------------- + # First Toolbox Row + #------------------------------------------------------------------- + + print "<table><tr>"; + + print "<td width=%5 valign=top>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$now_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$now_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + + if (length($icon_now) > 0) { + print "<input type=image src=\"$imagedir/$icon_now\" ALT=\"Now\">\n"; + }else{ + print "<input type=submit value=\"NOW\" name=\"SUBMIT2\">\n"; + } + + print "</form>\n\n"; + + print "<td width=%5 valign=top>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$now_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$primetime_start\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$defaultshowhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + if (length($icon_tonight) > 0) { + print "<input type=image src=\"$imagedir/$icon_tonight\" ALT=\"Prime\">\n"; + }else{ + print "<input type=submit value=\"Prime\" name=\"SUBMIT4\">\n"; + } + print "</form>\n\n "; + + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<td valign=top>Date: <td valign=top><select size=\"1\" name=\"STARTDATE\">\n"; + + do { + $rng_string = substr(as_time_string($rng_start),0,8); + $wday = strftime( "%A", localtime($rng_start)); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2) . "/" . substr($rng_string,0,4); + print "<option value=\"$rng_string\""; + if ($rng_string eq substr($starttime,0,4) . substr($starttime,4,2) . substr($starttime,6,2)) { + print " selected"; + } + print ">$dsp_string</option>\n"; + + $rng_start = $rng_start + 86400; + $ctr++; + + } while ($rng_start < $rng_end); + print "</select>\n"; + + print "<td valign=top>Time: <td valign=top>"; + print "<select size=\"1\" name=\"STARTHOUR\">\n"; + + $ctr = 0; + do { + $dsp_string = as_ampm($ctr); + print "<option value=\"$ctr\""; + if ($ctr == int substr($starttime,8,2)) { + print " selected"; + } + print ">$dsp_string</option>\n"; + $ctr++; + + } while ($ctr < 24); + print "</select>\n"; + + print "<td valign=top>Hours to Display: <td valign=top>"; + print "<select size=\"1\" name=\"SHOWHOURS\">\n"; + for $hours (2,3,4,5,6,7,8,9,12,24,48,72,96) { + print "<option value=\"$hours\""; + if ($inp_showhours == $hours) { + print " selected"; + } + print ">$hours Hours</option>\n"; + } + print "<td valign=top>"; + + if (length($icon_go) > 0) { + print "<input type=image src=\"$imagedir/$icon_go\" ALT=\"Go\">\n"; + }else{ + print "<input type=submit value=\"Go\" name=\"SUBMITGO\">"; + } + + print "</tr></table>\n"; + + #------------------------------------------------------------------- + # Second Row + #------------------------------------------------------------------- + + print "<table border=0><tr>\n"; + + if( defined %favorites ) { + print "<td valign=top>Channels:\n"; + print "<select name=\"FAVORITE\">\n"; + print "<option value=0"; + if( !$inp_favorite ) { + print " selected"; + } + print ">Selected range --></option>\n"; + foreach $key (keys %favorites) { + print "<option"; + if($key eq $inp_favorite) { + print " selected"; + } + print ">$key</option>\n"; + } + print "</select>\n"; + } + + print "<td valign=top>From: <td valign=top>"; + print "<select size=\"1\" name=\"FIRSTTUNE\">\n"; + $records = 0; + do { + $records++; + if (length($tuning[$records]) > 0) { + print "<option value=\"$tuning[$records]\""; + if ($tuning[$records] == $inp_firsttune) { + print " selected"; + } + print ">$channel[$records]</option>\n"; + } + } while ($records < $last_channel+1); + + print "<td valign=top>To: <td valign=top>"; + print "<select size=\"1\" name=\"LASTTUNE\">\n"; + $records = 0; + do { + $records++; + if (length($tuning[$records]) > 0) { + print "<option value=\"$tuning[$records]\""; + if ($tuning[$records] == $inp_lasttune) { + print " selected"; + } + print ">$channel[$records]</option>\n"; + } + } while ($records < $channelcount); + + print "<td valign=top>"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "</form>\n"; + + print "<td width=\"5%\" valign=top>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$defaultshowhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$first_channel\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$last_channel\">\n"; + + if (length($icon_all) > 0) { + print "<input type=image src=\"$imagedir/$icon_all\" ALT=\"All\">\n"; + }else{ + print "<input type=submit value=\"ALL\" name=\"SUBMIT3\">"; + } + + print "</form>\n"; + + print "<td width=\"5%\">"; + + $form_end = $tuning[$first_rec + $display_rec]; + if (length($form_end) < 1) { + $form_end = $last_channel; + } + + if ($prevchanok) { + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$prev_chan\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$form_end\">\n"; + + if (length($icon_prevchan) > 0) { + print "<input type=image src=\"$imagedir/$icon_prevchan\" ALT=\"<<<\">\n"; + }else{ + print "<input type=submit value=\"<<<\" name=\"SUBMITPC\">"; + } + + print "</form>\n\n"; + } + + print "<td width=5%>"; + + + $form_end = $tuning[$last_rec + $display_rec]; + if (length($form_end) < 1) { + $form_end = $last_channel; + } + + if ($nextchanok) { + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$next_chan\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$form_end\">\n"; + + if (length($icon_prevchan) > 0) { + print "<input type=image src=\"$imagedir/$icon_nextchan\" ALT=\">>>\">\n"; + }else{ + print "<input type=submit value=\">>>\" name=\"SUBMITNC\">"; + } + + print "</form>\n\n"; + } + + my $s_todo = &ToDoSupported; + my $s_guide = 0; + + if ($rtvaccess) { + $s_guide = 1; + + } + + if ($rtvaccess) { + print "<td valign=top>Replay:\n"; + print "<td valign=top><form action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + print "<select size=\"1\" name=\"RTVUNIT\">\n"; + for ( split /,/, $replaylist ) { + /,/; + my $addr = $rtvaddress{$_}; + my $label = $rtvlabel{$_}; + print "<option value=$_"; + print ">$label</option>\n"; + } + print "<option value=0 selected>ALL</option>\n"; + print "</select>\n"; + + print "<select size=\"1\" name=\"RTVACTION\">\n"; + print "<option value=-1 selected>Select Action</option>\n"; + if ($s_guide) { + print "<option value=1>Refresh Replay</option>\n"; + } + if ($s_todo) { + print "<option value=2>To-Do List</option>\n"; + } + if ($s_guide) { + print "<option value=3>Manage Shows</option>\n"; + } + if ($s_guide) { + print "<option value=4>Manual Recording</option>\n"; + } + print "</select>\n"; + + if (length($icon_go) > 0) { + print "<input type=image src=\"$imagedir/$icon_go\" ALT=\"Go\">\n"; + }else{ + print "<input type=submit value=\"Go\" name=\"SUBMITRTV\">\n"; + } + print "</form>\n"; + } + + +# if(($rtvaccess > 0) && ($scheduler eq "rg_scheduler.pl")) { +# #--------------------------------------------- +# # Add todo list links if todo.pl is executable +# #--------------------------------------------- +# print "<td valign=top>To-Do list:\n"; +# print "<td valign=top><form action=\"$scriptdir/$scriptname\">\n"; +# print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; +# print "<select size=\"1\" name=\"TODO\">\n"; +# for ( split /,/, $replaylist ) { +# /,/; +# my $addr = $rtvaddress{$_}; +# my $label = $rtvlabel{$_}; +# print "<option value=$_"; +# #----------------------------------------------------- +# #if($_ == $inp_selectedrtv) { print " selected"; } +# #----------------------------------------------------- +# print ">$label</option>\n"; +# } +# print "<option value=0 selected>ALL</option>\n</select>\n"; +# print "<td valign=top> "; +# if (length($icon_go) > 0) { +# print "<input type=image src=\"$imagedir/$icon_go\" ALT=\"Go\">\n"; +# }else{ +# print "<input type=submit value=\"Go\" name=\"SUBMITTODO\">\n"; +# } +# print "</form>\n"; +# } + + + print "</tr>\n"; + print "</table>"; + + #------------------------------------------------------------------- + # Third Toolbox Row + #------------------------------------------------------------------- + + print "<table>"; + print "\n<tr>"; + + + $form_date = substr($previoustime,0,4) . substr($previoustime,4,2) . substr($previoustime,6,2); + $form_time = substr($previoustime,8,2); + + print "<td width=5%>"; + if ($prevok) { + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$form_date\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$form_time\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + + if (length($icon_prevwindow) > 0) { + print "<input type=image src=\"$imagedir/$icon_prevwindow\" ALT=\"<<<\">\n"; + }else{ + print "<input type=submit value=\"<<<\" name=\"SUBMITPW\">"; + } + + print "</form>\n\n"; + } + + +# if ($rtvaccess) { +# print "<td width=10% align=center>"; +# print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; +# print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; +# print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; +# print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; +# print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; +# print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; +# print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; +# print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; +# print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; +# print "<input type=hidden name=\"UPDATE\" value=\"ALL\">\n"; +# +# if (length($icon_refresh) > 0) { +# print "<input type=image src=\"$imagedir/$icon_refresh\" ALT=\"Refresh ReplayTVs\">\n"; +# }else{ +# print "<input type=submit value=\"Refresh\" name=\"SUBMIT21\">\n"; +# } +# print "</form>\n\n"; +# } + + + print "<td width=50% align=center>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$inp_startdate\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$inp_starthour\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + print "<input type=text name=\"SEARCH\" value=\"\" size=40>\n"; + print "<select size=\"1\" name=\"FIELD\">\n"; + print "<option value=\"title\" selected>Title</option>\n"; + print "<option value=\"subtitle\">Episode</option>\n"; + print "<option value=\"description\" >Description</option>\n"; + print "<option value=\"category\">Category</option>\n"; + print "<option value=\"advisories\">Advisories</option>\n"; + + if ($use_castcrew) { + print "<option value=\"1\">Actor</option>\n"; + print "<option value=\"2\">Guest Star</option>\n"; + print "<option value=\"3\">Host</option>\n"; + print "<option value=\"4\">Director</option>\n"; + print "<option value=\"5\">Producer</option>\n"; + print "<option value=\"6\">Exec. Producer</option>\n"; + print "<option value=\"7\">Writer</option>\n"; + } + + print "</select>\n"; + + if (length($icon_find) > 0) { + print "<input type=image src=\"$imagedir/$icon_find\" ALT=\"Find\">\n"; + }else{ + print "<input type=submit value=\"Find\" name=\"SUBMITFIND\">\n"; + } + + print "</form>\n\n"; + + $form_date = substr($endtime,0,4) . substr($endtime,4,2) . substr($endtime,6,2); + $form_time = substr($endtime,8,2); + + print "<td width=5%>"; + + if ($nextok) { + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=\"STARTDATE\" value=\"$form_date\">\n"; + print "<input type=hidden name=\"STARTHOUR\" value=\"$form_time\">\n"; + print "<input type=hidden name=\"SHOWHOURS\" value=\"$inp_showhours\">\n"; + print "<input type=hidden name=\"SHOWSLOTS\" value=\"$inp_showslots\">\n"; + print "<input type=hidden name=\"FIRSTTUNE\" value=\"$inp_firsttune\">\n"; + print "<input type=hidden name=\"LASTTUNE\" value=\"$inp_lasttune\">\n"; + print "<input type=hidden name=\"FAVORITE\" value=\"$inp_favorite\">\n"; + + if (length($icon_nextwindow) > 0) { + print "<input type=image src=\"$imagedir/$icon_nextwindow\" ALT=\">>>\">\n"; + }else{ + print "<input type=submit value=\">>>\" name=\"SUBMITNW\">\n"; + } + + print "</form>\n\n"; + } + + print "</table><p></font>"; + + return 1; + +} + +#--------------------------------------------------------------------------------------- +sub ShowFooter{ + # + # Show HTML Termination + # + # ------------------------------------------------------------------------------ + + $prg_end = time; + $prg_runtime = $prg_end - $prg_start; + + + #------------------------------------------------------------------- + # Close the DB Connection + #------------------------------------------------------------------- + + writeDebug("Terminating Database Connection from $DATASOURCE{DSN} ($prgdb_handle)"); + endDSN("",$prgdb_handle); + + &ShowHTTPFooter; + + writeDebug("Exiting ($prg_runtime seconds)"); + + writeDebug("********************************************************"); + + close; + + return 1; + +} + +#--------------------------------------------------------------------------------------- +sub DoSchedule { + # + # Prepare to Schedule a Show + # (Actual Scheduling is Done by schedule.pl) + # + # ------------------------------------------------------------------------------ + + my $program_starttime = ""; + my $program_title = ""; + my $program_tuning = ""; + my $program_minutes = 0; + my $program_quality = 2; + my $program_guaranteed = 1; + my $program_recurring = 1; + my $program_category = 0; + my $program_beforepad = 0; + my $program_afterpad = 0; + my $program_daysofweek = 127; + my $program_keep = 1; + my $program_replaytv = 0; + my $program_stop = ""; + my $program_length = 0; + my $program_icon = ""; + my $program_true_start = ""; + my $display_time = ""; + my $replayid = ""; + my $replayname = ""; + my $replayaddress = ""; + my $replaydefaultquality = 0; + my $replaydefaultkeep = 0; + + my $replaylist = ""; + + print "<$size_section><font face=\"$font_title\">Program Details</$size_section><p></font>\n"; + + #------------------------------------------------------------------------ + # Lookup Program + #------------------------------------------------------------------------ + + my $db_handle = &StartDSN; + + $Stmt = "SELECT * FROM $db_table_tvlistings WHERE programid = '$inp_programid';"; + + my $sth = sqlStmt($db_handle,$Stmt); + if ( $sth ) { + $row = $sth->fetchrow_hashref; + + $program_starttime = sqltotimestring($row->{'starttime'}); + $program_tmsprgid = $row->{'tmsprogramid'}; + $program_true_start = $program_starttime; + $program_stop = sqltotimestring($row->{'endtime'}); + $program_tuning = int $row->{'tuning'}; + $program_title = $row->{'title'}; + $program_subtitle = $row->{'subtitle'}; + $program_desc = $row->{'description'}; + $program_category = $row->{'category'}; + $program_advisories = $row->{'advisories'}; + $program_mpaarating = $row->{'mpaarating'}; + $program_vchiprating = $row->{'vchiprating'}; + $program_episodenum = $row->{'episodenum'}; + $program_movieyear = int $row->{'movieyear'}; + $program_stereo = int $row->{'stereo'}; + $program_movie = int $row->{'movie'}; + $program_repeat = int $row->{'repeat'}; + $program_starrating = $row->{'starrating'}; + $program_captions = $row->{'captions'}; + $program_channel = $row->{'channel'}; + $program_subtitled = int $row->{'subtitled'}; + + ($program_stars,$junk) = split(/\//,$program_starrating); + + $fudged_length = 0; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($program_starttime)) { + $program_stop = as_time_string($rng_end); + $fudged_length = 1; + } + + $program_length = getMinutes($program_starttime,$program_stop); + + }else{ + print "<PRE>Lookup Failed: " . &GetLastSQLStmt() . "\n" . &GetLastSQLError() . "</PRE>"; + return 0; + } + + endDSN($sth,$db_handle); + + + #------------------------------------------------------------------------ + # Cast / Crew Data + #------------------------------------------------------------------------ + + if ($use_castcrew) { + my $db_handle = &StartDSN; + + $Stmt = "SELECT * FROM $db_table_castcrew WHERE tmsprogramid = '$program_tmsprgid' ORDER BY role;"; + + my $sth = sqlStmt($db_handle,$Stmt); + if ( $sth ) { + while ( my $row = $sth->fetchrow_hashref ) { + + my $program_prodrole = int $row->{'role'}; + my $program_surname = $row->{'surname'}; + my $program_givenname = $row->{'givenname'}; + my $program_productionrole = $productionrole[$program_prodrole]; + $program_rolelist[$program_prodrole] = buildcommastring($program_rolelist[$program_prodrole],convertfromhtml(trimstring("$program_givenname $program_surname"))); + } + }else{ + print "<PRE>Lookup Failed: " . &GetLastSQLStmt() . "\n" . &GetLastSQLError() . "</PRE>"; + return 0; + } + + endDSN($sth,$db_handle); + + $program_actor = buildMultiWordList($program_rolelist[1]); + $program_guest = buildMultiWordList($program_rolelist[2]); + $program_host = buildMultiWordList($program_rolelist[3]); + $program_director = buildMultiWordList($program_rolelist[4]); + $program_producer = buildMultiWordList($program_rolelist[5]); + $program_eproducer = buildMultiWordList($program_rolelist[6]); + $program_writer = buildMultiWordList($program_rolelist[7]); + }else{ + $program_actor = ""; + $program_guest = ""; + $program_host = ""; + $program_director = ""; + $program_producer = ""; + $program_eproducer = ""; + $program_writer = ""; + } + + #------------------------------------------------------------------------ + # Process Record + #------------------------------------------------------------------------ + + $wday = strftime( "%A", localtime(as_epoch_seconds($program_starttime))); + $dsp_string = $wday . ", " . displaytime($program_starttime); + + my $year = substr($program_starttime,0,4); + my $month = substr($program_starttime,4,2); + my $day = substr($program_starttime,6,2); + my $hour = substr($program_starttime,8,2); + my $minute = substr($program_starttime,10,2); + my $seconds = "00"; + + print "<hr>\n</CENTER><blockquote><font face=\"$font_detail\"><$size_subsection>\n" . renderhtml($program_title); + + if ($program_subtitle) { + print ": \"" . renderhtml($program_subtitle) . "\""; + } + + if ($program_movieyear) { + print " <small>" . substr($stars,1,$program_stars); + print " ($program_movieyear, $program_category)</small>"; + } + + print "</$size_subsection>$dsp_string ($program_length minutes) on $program_tuning ($program_channel)<p>\n"; + + if ($showpdaformat) { + print "<small>"; + } + + if (length($program_desc) > 0) { + print "\"" . renderhtml($program_desc) . "\"<br>\n"; + } + + if (length($program_episodenum) > 0) { + print "$program_episodenum. "; + } + + + if ((length($program_category) > 0) && ($program_movieyear == 0)) { + print "($program_category)"; + } + + if (length($program_mpaarating) > 0) { + $temp_display = "$program_mpaarating."; + if ($showchannelicons > 0) { + if (($program_mpaarating eq "G") && (length($image_mpaag))) { + $temp_display = buildImage($image_mpaag,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "PG") && (length($image_mpaapg))) { + $temp_display = buildImage($image_mpaapg,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "PG-13") && (length($image_mpaapg13))) { + $temp_display = buildImage($image_mpaapg13,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "R") && (length($image_mpaar))) { + $temp_display = buildImage($image_mpaar,$imagedir,$program_mpaarating); + } + if (($program_mpaarating eq "NC17") && (length($image_mpaanc17))) { + $temp_display = buildImage($image_mpaanc17,$imagedir,$program_mpaarating); + } + } + print " $temp_display"; + }else{ + if ($program_movieyear) { + $temp_display = "NR."; + if ($showchannelicons > 0) { + if (length($image_mpaanr)) { + $temp_display = buildImage($image_mpaanr,$imagedir,"NR"); + } + } + print " $temp_display"; + + } + } + + if (length($program_vchiprating) > 0) { + $temp_display = "TV-$program_vchiprating."; + if ($showchannelicons > 0) { + if (($program_vchiprating eq "G") && (length($image_tvg))) { + $temp_display = buildImage($image_tvg,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "PG") && (length($image_tvpg))) { + $temp_display = buildImage($image_tvpg,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "14") && (length($image_tv14))) { + $temp_display = buildImage($image_tv14,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "MA") && (length($image_tvma))) { + $temp_display = buildImage($image_tvma,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "Y") && (length($image_tvy))) { + $temp_display = buildImage($image_tvy,$imagedir,"TV-$program_vchiprating"); + } + if (($program_vchiprating eq "Y7") && (length($image_tvy7))) { + $temp_display = buildImage($image_tvy7,$imagedir,"TV-$program_vchiprating"); + } + } + print " $temp_display"; + } + + if (length($program_captions) > 0) { + $temp_display = "CC"; + if ($showchannelicons > 0) { + if (length($image_cc) > 0) { + $temp_display = buildImage($image_cc,$imagedir,"CC"); + } + } + print " $temp_display"; + } + + if ($program_stereo) { + $temp_display = "Stereo."; + if ($showchannelicons > 0) { + if (length($image_stereo) > 0) { + $temp_display = buildImage($image_stereo,$imagedir,"Stereo"); + } + } + print " $temp_display"; + } + + if ($program_repeat) { + $temp_display = "(Repeat)"; + if ($showchannelicons > 0) { + if (length($image_repeat) > 0) { + $temp_display = buildImage($image_repeat,$imagedir,"Repeat"); + } + } + print " $temp_display"; + } + + + if (length($program_advisories) > 0) { + print " <small>($program_advisories)</small>"; + } + + if (length($program_actor) > 0) { + print " <small>Cast: $program_actor.</small>"; + } + + if (length($program_host) > 0) { + print " <small>Host: $program_host.</small>"; + } + + if (length($program_guest) > 0) { + print " <small>Guests: $program_guest.</small>"; + } + + if (length($program_eproducer) > 0) { + print " <small>Executive Producer: $program_eproducer.</small>"; + } + + if (length($program_producer) > 0) { + print " <small>Produced by $program_producer.</small>"; + } + + + if (length($program_writer) > 0) { + print " <small>Written by $program_writer.</small>"; + } + + if (length($program_director) > 0) { + print " <small>Directed by $program_director.</small>"; + } + + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($now_timestring)) { + #------------------------ + # Past show + #------------------------ + $program_timing = 0; + }elsif (as_epoch_seconds($program_start) < as_epoch_seconds($now_timestring)) { + #------------------------ + # Current show + #------------------------ + $program_timing = 1; + } else { + #------------------------ + # Future show + #------------------------ + $program_timing = 2; + } + $bgcolor = $color_show[$program_timing]; + + if($rtvaccess) { + $program_icon = getScheduleDetails($inp_programid,$program_timing); + } + if (length($bgcolor) > 0) { + $bgcolor = " bgcolor=\"$bgcolor\""; + } + if (length($program_icon) > 0) { + print "<br>\n$program_icon"; + } + + + print "</blockquote>\n"; + + + if ($showpdaformat) { + print "</small>"; + } + + print "<p><CENTER>\n"; + print "<table border=0><tr>"; + + print "<td>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=SEARCH value=\"$program_title\">\n"; + if (length($icon_findall) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_findall\" ALT=\"Find All\">\n"; + }else{ + print "<input type=submit value=\"Find All\" name=\"FIND\">\n"; + } + print "</form>\n"; + print "<td>"; + + + print "<td>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=SEARCH value=\"$program_title|$program_subtitle\">\n"; + print "<input type=hidden name=FIELD value=\"title,subtitle\">\n"; + if (length($icon_findrepeat) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_findrepeat\" ALT=\"Find Repeats\">\n"; + }else{ + print "<input type=submit value=\"Find Repeats\" name=\"FINDREPEATS\">\n"; + } + print "</form>\n"; + print "<td>"; + + print "<form method=POST action=\"$scriptdir/$scriptname#$inp_programid\">\n"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + print "<input type=hidden name=STARTDATE value=\"" . substr($program_true_start,0,8) . "\">"; + print "<input type=hidden name=STARTHOUR value=\"" . substr($program_true_start,8,2) . "\">"; + print "<input type=hidden name=SHOWHOURS value=\"$inp_showhours\">"; + print "<input type=hidden name=SHOWSLOTS value=\"$inp_showslots\">"; + if (length($icon_locate) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_locate\" ALT=\"Locate\">\n"; + }else{ + print "<input type=submit value=\"Locate\" name=\"LOCATE\">\n"; + } + print "</form>\n"; + print "<td>"; + + #------------------------------------------------------------------------ + # If there isn't access to RTV, this is simply a program details screen + #------------------------------------------------------------------------ + + if (!$rtvaccess) { + writeDebug("doschedule::No RTV Access"); + + print " <form method=POST action=\"$scriptdir/$scriptname\">"; + if (length($inp_search) > 0) { + print "<input type=hidden name=SEARCH value=\"$inp_search\">"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + }else{ + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + print "<input type=hidden name=STARTDATE value=\"$inp_startdate\">"; + print "<input type=hidden name=STARTHOUR value=\"$inp_starthour\">"; + print "<input type=hidden name=SHOWHOURS value=\"$inp_showhours\">"; + print "<input type=hidden name=SHOWSLOTS value=\"$inp_showslots\">"; + } + + if (length($icon_done) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_done\" ALT=\"Done\">\n"; + }else{ + print "<input type=submit value=\"Done\" name=\"DONE\">\n"; + } + + + print "</form>"; + print "<td>"; + print "</table>"; + print "</CENTER><p>"; + + return 1; + } + + print "</table>"; + print "</CENTER><p>"; + + if (countArray($schedulinglist,";") < 1) { + if (countArray($replaylist,",") > 0) { + print "<p><CENTER><$size_subsection>No ReplayTV Units With Remote Scheduling Found</$size_subsection><p>"; + }else{ + print "<p><CENTER><$size_subsection>No ReplayTV Units Defined</$size_subsection><p>"; + } + print "<form method=POST action=\"$scriptdir/$scriptname\">"; + if (length($inp_search) > 0) { + print "<input type=hidden name=SEARCH value=\"$inp_search\">"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + }else{ + print "<input type=hidden name=STARTDATE value=\"$inp_startdate\">"; + print "<input type=hidden name=STARTHOUR value=\"$inp_starthour\">"; + print "<input type=hidden name=SHOWHOURS value=\"$inp_showhours\">"; + print "<input type=hidden name=SHOWSLOTS value=\"$inp_showslots\">"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + } + print "<input type=submit value=\"Done\" name=\"SUBMIT\"></form></CENTER><p>"; + return 1; + } + + print "</FONT></CENTER><CENTER>"; + + print "<hr>\n"; + + print "<$size_section><font face=\"$font_title\">Schedule a Recording</$size_section><p></font>\n"; + + if (countArray($schedulinglist,";") == 1) { + $inp_selectedrtv = $schedulinglist; + } + + if (!$inp_recordtype) { + + $url_parms = ""; + addParameter("PROGRAMID",$inp_programid); + + print "\n<form method=POST action=\"$scriptdir/$scriptname$url_parms\">\n"; + print "<table>\n"; + print "<input type=hidden name=PROGRAMID value=\"$inp_programid\">"; + print "<input type=hidden name=STARTDATE value=\"$inp_startdate\">"; + print "<input type=hidden name=STARTHOUR value=\"$inp_starthour\">"; + print "<input type=hidden name=SHOWHOURS value=\"$inp_showhours\">"; + print "<input type=hidden name=SHOWSLOTS value=\"$inp_showslots\">"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + + if (length($inp_search) > 0) { + print "<input type=hidden name=SEARCH value=\"$inp_search\">"; + } + if (length($inp_selectedrtv) < 1) { + print "<tr>\n"; + print "<td align=right><B>ReplayTV:</B></td>\n"; + print "<td><select size=\"1\" name=\"SELECTEDRTV\">\n"; + + for ( split /;/, $schedulinglist ) { + /;/; + if ($rtvlabel{$_} eq $defaultreplaytv) { + print "<option value=\"$_\" selected>$rtvlabel{$_}</option>\n"; + }else{ + print "<option value=\"$_\">$rtvlabel{$_}</option>\n"; + } + } + print "</select></td></tr>\n"; + }else{ + print "<tr><td align=right><B>ReplayTV:</B></td><td>"; + print $rtvlabel{$inp_selectedrtv}; + print " ($rtvaddress{$inp_selectedrtv})"; + print "</td></tr>\n"; + + print "<input type=hidden name=\"SELECTEDRTV\" value=\"$inp_selectedrtv\">\n"; + } + + print "<tr><td align=right><B>Record:</B></td>\n"; + print "<td>"; + print "<select size=\"1\" name=\"RECORDTYPE\">\n"; + print "<option value=\"1\">First run and repeats</option>\n"; + print "<option value=\"2\">First run episodes</option>\n"; + print "<option value=\"3\">This show only</option>\n"; + print "</select>\n"; + print "</td></tr></table>\n"; + + if (length($icon_select) > 0) { + print "<input type=image src=\"$imagedir/$icon_select\" ALT=\"Select\">\n"; + }else{ + print "<input type=submit value=\"Select\" name=\"SUBMITSEL\">\n"; + } + + print "</form><p>\n"; + + return 1; + } + + print "<form method=POST action=\"$scriptdir/$schedulename?STATE=slotrequest\">\n"; + if (!$showpdaformat) { + print "<table>\n"; + print "<tr><td align=right>"; + }else{ + print "</CENTER>"; + } + + print "<B>ReplayTV:</B>"; + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + print $rtvlabel{$inp_selectedrtv}; + print " ($rtvaddress{$inp_selectedrtv})"; + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<p>"; + } + + print "\n"; + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Record:</B>"; + + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + + if ($inp_recordtype == 1) { + print "First run and repeats"; + } + + if ($inp_recordtype == 2) { + print "First run episodes"; + } + + if ($inp_recordtype == 3) { + print "This show only"; + } + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<p>"; + } + print "\n"; + + + #------------------------------------------------------------------------ + # Known Fields + #------------------------------------------------------------------------ + + + if ($allowtitleedit) { + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + print "<B>Show Title:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + print "\n"; + + if (!$showpdaformat) { + print "<td>"; + } + + print "<input type=text name=\"SHOWTITLE\" value=\"$program_title\" size=50>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + }else{ + print "<input type=hidden name=\"SHOWTITLE\" value=\"$program_title\">\n"; + } + + print "<input type=hidden name=\"MONTH\" value=\"$month\">\n"; + print "<input type=hidden name=\"YEAR\" value=\"$year\">\n"; + print "<input type=hidden name=\"DAY\" value=\"$day\">\n"; + print "<input type=hidden name=\"HOUR\" value=\"$hour\">\n"; + print "<input type=hidden name=\"MINUTE\" value=\"$minute\">\n"; + print "<input type=hidden name=\"LENGTH\" value=\"$program_length\">\n"; + print "<input type=hidden name=\"TUNING\" value=\"$program_tuning\">\n"; + print "<input type=hidden name=\"ISMANUAL\" value=\"0\">\n"; + if ($rtvport{$inp_selectedrtv} != 80) { + print "<input type=\"hidden\" name=\"REPLAYTV\" value=\"$rtvaddress{$inp_selectedrtv}:$rtvport{$inp_selectedrtv}\">\n"; + }else{ + print "<input type=\"hidden\" name=\"REPLAYTV\" value=\"$rtvaddress{$inp_selectedrtv}\">\n"; + } + print "<input type=hidden name=\"RECORDTYPE\" value=\"$inp_recordtype\">\n"; + + + if ($inp_recordtype == 3) { + #------------------------------------------------------------------------ + # Keep Until (This Show Only) + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + print "<B>Keep Until:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + print "\n"; + + if (!$showpdaformat) { + print "<td>"; + } + print "<select size=\"1\" name=\"GUARANTEED\">\n"; + print "<option value=\"1\">I delete</option>\n"; + print "<option value=\"0\">Space needed</option>\n"; + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + print "<input type=\"hidden\" name=\"KEEP\" value=\"1\">\n"; + }else{ + #------------------------------------------------------------------------ + # Episodes to Keep + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + print "<B>Episodes to Keep:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + + print "\n"; + + if (!$showpdaformat) { + print "<td>"; + } + + print "<select size=\"1\" name=\"KEEP\">"; + selectNumbers($rtvdefaultkeep{$inp_selectedrtv},10,1); + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + print "\n"; + + #------------------------------------------------------------------------ + # Delete oldest + #------------------------------------------------------------------------ + + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + print "<B>Delete oldest:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + print "\n"; + + + if (!$showpdaformat) { + print "<td>"; + } + print "<select size=\"1\" name=\"GUARANTEED\">\n"; + print "<option value=\"1\">Only for new episode</option>\n"; + print "<option value=\"0\">If space needed</option>\n"; + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + } + + #------------------------------------------------------------------------ + # Quality + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr>\n"; + print "<td align=right>"; + } + + print "<B>Quality:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + print "\n"; + + if (!$showpdaformat) { + print "<td>"; + } + print "\n"; + + print "<select size=\"1\" name=\"QUALITY\">\n"; + if ($rtvdefaultquality{$inp_selectedrtv} == 2) { + print "<option value=\"2\" selected>Standard</option>\n"; + }else{ + print "<option value=\"2\">Standard</option>\n"; + } + if ($rtvdefaultquality{$inp_selectedrtv} == 1) { + print "<option value=\"1\" selected>Medium</option>\n"; + }else{ + print "<option value=\"1\">Medium</option>\n"; + } + if ($rtvdefaultquality{$inp_selectedrtv} == 0) { + print "<option value=\"0\" selected>High</option>\n"; + }else{ + print "<option value=\"0\">High</option>\n"; + } + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + print "\n"; + + + #------------------------------------------------------------------------ + # Advanced Options + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td><p></td><td></td></tr>\n"; + print "<tr><td></td><td align=left>"; + } + + print "<font size=+1><B><I>Advanced Settings</I></B></font><p>"; + + if (!$showpdaformat) { + print "</td></tr>\n"; + print "<tr><td><p></td><td></td></tr>\n"; + } + + + #------------------------------------------------------------------------ + # Padding + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Start recording:</B>"; + + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + print "<input type=text size=\"3\" name=\"PREPAD\" value=\"0\"> min. before"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + print "\n"; + + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>End recording:</B>"; + + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + + print "<input type=text size=\"3\" name=\"POSTPAD\" value=\"0\"> min. after"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + print "\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + print "\n"; + + + #------------------------------------------------------------------------ + # Category + #------------------------------------------------------------------------ + + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Store in category:</B>"; + + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + + print "<select size=\"1\" name=\"CATEGORY\">"; + print "<option value=\"255\" selected>All Shows</option>\n"; + + $ctr = 0; + + if (countArray($categories{$inp_selectedrtv},";")) { + for ( split /;/, $categories{$inp_selectedrtv} ) { + /;/; + ($cat_num,$cat_label) = split(',', $_, 2); + print "<option value=\"$cat_num\">$cat_label</option>\n"; + $ctr++; + } + } + print "</select>"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + #------------------------------------------------------------------------ + # Days of Week + #------------------------------------------------------------------------ + + if ($inp_recordtype == 3) { + print "<input type=hidden name=\"SUN\" value=\"1\">\n"; + print "<input type=hidden name=\"MON\" value=\"1\">\n"; + print "<input type=hidden name=\"TUE\" value=\"1\">\n"; + print "<input type=hidden name=\"WED\" value=\"1\">\n"; + print "<input type=hidden name=\"THU\" value=\"1\">\n"; + print "<input type=hidden name=\"FRI\" value=\"1\">\n"; + print "<input type=hidden name=\"SAT\" value=\"1\">\n"; + }else{ + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Record shows on:</B>"; + + if (!$showpdaformat) { + print "</td>\n<td>"; + }else{ + print "<br>"; + } + + print "<input type=checkbox name=\"SUN\" value=\"1\" checked> Sun.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"MON\" value=\"1\" checked> Mon.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"TUE\" value=\"1\" checked> Tue.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"WED\" value=\"1\" checked> Wed.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"THU\" value=\"1\" checked> Thu.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"FRI\" value=\"1\" checked> Fri.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"SAT\" value=\"1\" checked> Sat.\n"; + if ($showpdaformat) { + print "<br> "; + } + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + } + + #------------------------------------------------------------------------ + # Set up Return Path + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "\n<tr><td></td><td>"; + }else{ + print "<p>\n"; + } + + if (length($inp_search) > 0) { + $url_parms = ""; + addParameter("SEARCH",$inp_search); + addParameter("SHOWPDAFORMAT",$showpdaformat); + writeDebug("doschedule::ReturnPath: $scriptdir/$scriptname$url_parms"); + print "\n<input type=hidden name=RETURNURL value=\"$scriptdir/$scriptname?SEARCH=$inp_search&SHOWPDAFORMAT=$showpdaformat\">\n"; + print "\n<input type=hidden name=RETURNTEXT value=\"Back to Search Results\">\n"; + }else{ + $url_parms = ""; + addParameter("PROGRAMID",$inp_programid); + addParameter("STARTDATE",$inp_startdate); + addParameter("STARTHOUR",$inp_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + addParameter("UPDATE",$rtvaddress{$inp_selectedrtv}); + + writeDebug("doschedule::ReturnPath: $scriptdir/$scriptname$url_parms"); + print "\n<input type=hidden name=RETURNURL value=\"$scriptdir/$scriptname$url_parms\">\n"; + print "\n<input type=hidden name=RETURNTEXT value=\"Back to Schedule\">\n"; + } + + #------------------------------------------------------------------------ + # Integrate schedule.pl with our font/color scheme + #------------------------------------------------------------------------ + + print "<input type=hidden name=PRGCONF value=\"$configfile\">\n"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + + if (length($icon_schedule) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_schedule\" ALT=\"Schedule\">\n"; + }else{ + print "\n<input type=submit value=Schedule name=SUBMIT>\n"; + } + + + print "</form><p>"; + + if (!$showpdaformat) { + print "</td></tr>\n</table>"; + } + + print "\n"; + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub DoSearch { + # + # Perform a Search + # + # ------------------------------------------------------------------------------ + + my $specialdebug = 1; + my $searchmode = 0; + + if ($inp_searchfield eq $null) { + $inp_searchfield = "title"; + } + + if (int $inp_searchfield > 0) { + #------------------------------- + # If it's a number, we're + # searching the cast crew table + #------------------------------- + $searchmode = 1; + } + + if ($specialdebug) { + writeDebug("dosearch::inp_searchfield: $inp_searchfield, inp_search: $inp_search, searchmode: $searchmode, searchfutureonly: $searchfutureonly"); + } + + if ($inp_searchfield eq "title,subtitle") { + ($inp_search1,$inp_search2) = split(/\|/,$inp_search); + if ($inp_search2 eq $null) { + $inp_searchfield = "title"; + $inp_search = $inp_search1; + } + } + + my $db_handle = &StartDSN; + + + if ($inp_searchfield eq "title,subtitle") { + if ($searchfutureonly) { + writeDebug("dosearch::Searching Future Only for $inp_search1 (title) $inp_search2 (subtitle)"); + + $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels "; + $Stmt .= "WHERE (((((title LIKE '%" . filterfield($inp_search1) . "%' AND subtitle LIKE '%'". filterfield($inp_search2) . "%' ) AND endtime > '$sql_now') AND $db_table_tvlistings.tuning = $db_table_channels.tuning) AND $db_table_tvlistings.channel = $db_table_channels.channel) AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel, $inp_searchfield;"; + }else{ + writeDebug("dosearch::Searching for $inp_search1 (title) $inp_search2 (subtitle)"); + + $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels "; + $Stmt .= "WHERE (((title LIKE '%" . filterfield($inp_search1) . "%' AND subtitle LIKE '%" . filterfield($inp_search2) . "%') AND $db_table_tvlistings.tuning = $db_table_channels.tuning) AND $db_table_tvlistings.channel = $db_table_channels.channel) AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel, $inp_searchfield;"; + } + }else{ + if ($searchmode == 0) { + if ($searchfutureonly) { + writeDebug("dosearch::Searching Future Only for $inp_search within $inp_searchfield"); + + $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels "; + $Stmt .= "WHERE (((($inp_searchfield LIKE '%" . filterfield($inp_search) . "%') AND endtime > '$sql_now') AND $db_table_tvlistings.tuning = $db_table_channels.tuning) AND $db_table_tvlistings.channel = $db_table_channels.channel) AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel, $inp_searchfield;"; + }else{ + writeDebug("dosearch::Searching for $inp_search within $inp_searchfield"); + + $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels "; + $Stmt .= "WHERE ((($inp_searchfield LIKE '%" . filterfield($inp_search) . "%') AND $db_table_tvlistings.tuning = $db_table_channels.tuning) AND $db_table_tvlistings.channel = $db_table_channels.channel) AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel, $inp_searchfield;"; + } + + } + if ($searchmode == 1) { + # + # break field into surname, givenname and search on role # + # + + my($givenname,$surname) = $inp_search =~ /^(.*?) (\S+)$/; + + if (($givenname eq "") && ($surname eq "")) { + $surname = $inp_search; + } + + if ($searchfutureonly) { + writeDebug("dosearch::Searching Future Only for $inp_search within " . $productionrole[$inp_searchfield]); + + $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels, $db_table_castcrew "; + $Stmt .= "WHERE ((($db_table_castcrew.surname = '" . filterfield($surname) . "' "; + if (length($givenname) > 0) { + $Stmt .= "AND $db_table_castcrew.givenname = '" . filterfield($givenname) . "' "; + } + $Stmt .= ") AND $db_table_castcrew.role = $inp_searchfield "; + $Stmt .= " ) AND endtime > '$sql_now') AND $db_table_tvlistings.tmsprogramid = $db_table_castcrew.tmsprogramid AND $db_table_tvlistings.tuning = $db_table_channels.tuning AND $db_table_tvlistings.channel = $db_table_channels.channel AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel;"; + }else{ + $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_tvlistings, $db_table_channels, $db_table_castcrew "; + $Stmt .= "WHERE (($db_table_castcrew.surname = '" . filterfield($surname) . "' "; + if (length($givenname) > 0) { + $Stmt .= "AND $db_table_castcrew.givenname = '" . filterfield($givenname) . "' "; + } + $Stmt .= ") AND $db_table_castcrew.role = $inp_searchfield "; + $Stmt .= " ) AND $db_table_tvlistings.tmsprogramid = $db_table_castcrew.tmsprogramid AND $db_table_tvlistings.tuning = $db_table_channels.tuning AND $db_table_tvlistings.channel = $db_table_channels.channel AND $db_table_channels.hidden = 0 "; + $Stmt .= "ORDER BY starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel;"; + } + + $inp_searchfield = $productionrole[$inp_searchfield]; + + } + } + + if ($debug) { + print "<PRE>SQL: $Stmt\n</PRE>"; + } + + if ($specialdebug) { + writeDebug("dosearch::SQL: $Stmt"); + } + + $records = 0; + + print "<font face=\"$font_detail\">"; + + my $sth = sqlStmt($db_handle,$Stmt); + if ( $sth ) { + + while ( $row = $sth->fetchrow_hashref ) { + $records++; + + $program_id = $row->{'programid'}; + $program_start = sqltotimestring($row->{'starttime'}); + $program_true_start = $program_start; + $program_stop = sqltotimestring($row->{'endtime'}); + $program_title = $row->{'title'}; + $program_subtitle = $row->{'subtitle'}; + $program_desc = $row->{'description'}; + $program_tuning = $row->{'tuning'}; + $program_channel = $row->{'channel'}; + $program_advisories = $row->{'advisories'}; + $program_category = $row->{'category'}; + $program_mpaarating = $row->{'mpaarating'}; + $program_vchiprating = $row->{'vchiprating'}; + $program_episodenum = $row->{'episodenum'}; + $program_movieyear = int $row->{'movieyear'}; + $program_stereo = int $row->{'stereo'}; + $program_repeat = int $row->{'repeat'}; + $program_starrating = $row->{'starrating'}; + $program_captions = $row->{'captions'}; + $program_theme = $row->{'theme'}; + + ($program_stars,$junk) = split(/\//,$program_starrating); + + #---------------------------------------------------------------------------- + # Because in it's infinite wisdom XMLTV does not provide a STOP time + # at the end of the listings, if we're looking at the last available + # data we can't calculate an endpoint so we just make something up. + # (Basically we give it one slot) + #---------------------------------------------------------------------------- + + $fudged_length = 0; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($program_start)) { + $program_stop = as_time_string(as_epoch_seconds($program_start) + ($inp_showslots * 60)); + $fudged_length = 1; + } + + + $program_length = getMinutes($program_start,$program_stop); + $display_length = $program_length; + $program_time = ""; + $program_extra = ""; + + + $wday = substr(strftime( "%A", localtime(as_epoch_seconds($program_start))),0,3); + $dsp_string = $wday . ", " . displaytime($program_start); + + $program_starthour = substr($program_start,8,2); + $program_startdate = substr($program_start,0,8); + + $starttime = $inp_startdate . $starthour . "0000"; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($now_timestring)) { + #-------------------------- + # Past show + #-------------------------- + $program_timing = 0; + }elsif (as_epoch_seconds($program_start) < as_epoch_seconds($now_timestring)) { + #-------------------------- + # Current show + #-------------------------- + $program_timing = 1; + } else { + #-------------------------- + # Future show + #-------------------------- + $program_timing = 2; + } + $bgcolor = $color_show[$program_timing]; + if($rtvaccess) { + $program_icon = getScheduleDetails( $program_id , $program_timing ); + } + if (length($bgcolor) > 0) { + $bgcolor = " bgcolor=\"$bgcolor\""; + } + + if ($records == 1) { + if (!$showpdaformat) { + print "<table border=1>"; + print "<tr>"; + print "<td width=\"20%\" align=left valign=top bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" color=\"$color_headingtext\">Date</font>"; + print "<td width=\"10%\" align=left valign=top bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" color=\"$color_headingtext\">Channel</font>"; + print "<td width=\"70%\" align=left valign=top bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" color=\"$color_headingtext\">Title</font>"; + #print "<td width=12% align=left valign=top bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" color=\"$color_headingtext\">Attributes</font>"; + print "</tr>"; + }else{ + print "<p>"; + } + } + + if (!$showpdaformat) { + print "<tr>"; + print "<td align=left valign=top $bgcolor><font size=2 face=\"$font_listings\">"; + }else{ + print "<$size_pdalistings>"; + } + + + $url_parms = ""; + addParameter("STARTDATE",$program_startdate); + addParameter("STARTHOUR",$program_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print "<a href=\"$scriptdir/$scriptname$url_parms\">"; + print $dsp_string; + print "</a>\n"; + + if (!$showpdaformat) { + print "<td align=left valign=top $bgcolor><font size=2 face=\"$font_listings\">"; + }else{ + print " "; + } + + #------------------------------------------------------------------------ + # Add a link to show just the single channel with 2 days of listings + #------------------------------------------------------------------------ + + $url_parms = ""; + addParameter("FIRSTTUNE",$program_tuning); + addParameter("LASTTUNE",program_tuning); + addParameter("STARTDATE",$program_startdate); + addParameter("STARTHOUR",$program_starthour); + addParameter("SHOWHOURS","48"); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print "$program_tuning (<a href=\"$scriptdir/$scriptname$url_parms\">$program_channel</a>)\n"; + + #------------------------------------------------------------------------ + # Force some variables so the odd start times aren't + # duplicated in the render + #------------------------------------------------------------------------ + $starttime = $program_true_start; + $colpos = 1; + $colspan = 1; + $shortslot = 0; + #$showrtvtext = 1; + + &RenderShow; + + if (!$showpdaformat) { + print "</tr>\n"; + }else{ + print "<p>\n"; + } + } + }else{ + } + + print "</table><p>"; + + if ($inp_searchfield eq "title,subtitle") { + $inp_search = "$inp_search1\" and \"$inp_search2"; + $inp_searchfield = "title and episode title"; + } + + if ($inp_searchfield eq "subtitle") { + $inp_searchfield = "episode title"; + } + + if ($records) { + writeDebug("dosearch::Search Returned $records Rows"); + print "<p><font face=\"$font_menu\">Found $records show(s) matching \"$inp_search\" within $inp_searchfield.<p></font>"; + }else{ + writeDebug("dosearch::Search Did Not Return Any Rows"); + print "<p><font face=\"$font_menu\">Did not find any matches for \"$inp_search\" within $inp_searchfield.<p></font>"; + } + + endDSN($sth,$db_handle); + + return 1; + +} + +#--------------------------------------------------------------------------------------- +sub DoToDo { + # + # Display the To-Do list + # + # Options: + # replayguide.conf todofromstart - if 1 then todo time ranges will + # be from program start instead of + # end. + # + # replayguide.conf todooption 0 - ALL + # 1 - From Today + # 1 - From Right Now + # + # ------------------------------------------------------------------------------ + my $label = $rtvlabel{$inp_todo}; + + if($label eq "") { + $label = "ALL"; + $inp_todo = 0; + } + + if ($todooption == 0) { + + #------------------------------------------------------ + # All + #------------------------------------------------------ + + writeDebug("dotodo::Searching for $label"); + + $Stmt = ""; + $Stmt .= "SELECT * FROM $db_table_schedule,$db_table_tvlistings WHERE "; + if($inp_todo > 0) { + $Stmt .= "(replayid = $inp_todo) AND "; + } + $Stmt .= "($db_table_schedule.programid = $db_table_tvlistings.programid) "; + $Stmt .= "ORDER BY $db_table_tvlistings.starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel, title;"; + } + + + if ($todooption == 1) { + + #------------------------------------------------------ + # From Today + #------------------------------------------------------ + + writeDebug("dotodo::Searching From Today for $label"); + + + $Stmt = ""; + $Stmt .= "SELECT * FROM $db_table_schedule,$db_table_tvlistings WHERE "; + if($inp_todo > 0) { + $Stmt .= "(replayid = $inp_todo) AND "; + } + $Stmt .= "($db_table_schedule.programid = $db_table_tvlistings.programid) "; + if ($todofromstart) { + $Stmt .= " AND $db_table_tvlistings.starttime > '$sql_today'"; + }else{ + $Stmt .= " AND $db_table_tvlistings.endtime > '$sql_today'"; + } + $Stmt .= "ORDER BY $db_table_tvlistings.starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel, title;"; + } + + if ($todooption == 2) { + + #------------------------------------------------------ + # From Now + #------------------------------------------------------ + + writeDebug("dotodo::Searching Future Only for $label"); + + + $Stmt = ""; + $Stmt .= "SELECT * FROM $db_table_schedule,$db_table_tvlistings WHERE "; + if($inp_todo > 0) { + $Stmt .= "(replayid = $inp_todo) AND "; + } + $Stmt .= "($db_table_schedule.programid = $db_table_tvlistings.programid) "; + if ($todofromstart) { + $Stmt .= " AND $db_table_tvlistings.starttime > '$sql_now'"; + }else{ + $Stmt .= " AND $db_table_tvlistings.endtime > '$sql_now'"; + } + $Stmt .= "ORDER BY $db_table_tvlistings.starttime, $db_table_tvlistings.tuning, $db_table_tvlistings.channel, title;"; + } + + + if ($debug) { + print "<PRE>SQL: $Stmt\n</PRE>"; + } + + + $records = 0; + $last_program_id = 0; + + print "<font face=\"$font_detail\">"; + + my $db_handle = &StartDSN; + + my $sth = sqlStmt($db_handle,$Stmt); + + if ($sth) { + + while ( $row = $sth->fetchrow_hashref ) { + $records++; + + $program_id = $row->{'programid'}; + # Skip over duplicate programs (scheduled on multiple units) + if($program_id eq $last_program_id) { + next; + } + $last_program_id = $program_id; + + $program_start = sqltotimestring($row->{'starttime'}); + $program_true_start = $program_start; + $program_stop = sqltotimestring($row->{'endtime'}); + $program_title = $row->{'title'}; + $program_subtitle = $row->{'subtitle'}; + $program_desc = $row->{'description'}; + $program_tuning = $row->{'tuning'}; + $program_channel = $row->{'channel'}; + $program_advisories = $row->{'advisories'}; + $program_category = $row->{'category'}; + $program_mpaarating = $row->{'mpaarating'}; + $program_vchiprating = $row->{'vchiprating'}; + $program_episodenum = $row->{'episodenum'}; + $program_movieyear = int $row->{'movieyear'}; + $program_stereo = int $row->{'stereo'}; + $program_repeat = int $row->{'repeat'}; + $program_starrating = $row->{'starrating'}; + $program_captions = $row->{'captions'}; + $program_theme = $row->{'theme'}; + + ($program_stars,$junk) = split(/\//,$program_starrating); + + #---------------------------------------------------------------------------- + # Because in it's infinite wisdom XMLTV does not provide a STOP time + # at the end of the listings, if we're looking at the last available + # data we can't calculate an endpoint so we just make something up. + # (Basically we give it one slot) + #---------------------------------------------------------------------------- + + $fudged_length = 0; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($program_start)) { + $program_stop = as_time_string(as_epoch_seconds($program_start) + ($inp_showslots * 60)); + $fudged_length = 1; + } + + + $program_length = getMinutes($program_start,$program_stop); + $display_length = $program_length; + $program_time = ""; + $program_extra = ""; + + $rng_string = substr(as_time_string(as_epoch_seconds($program_true_start)),0,8); + $wday = strftime( "%A", localtime(as_epoch_seconds($program_true_start))); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2) . "/" . substr($rng_string,0,4); + + $program_starthour = substr($program_start,8,2); + $program_startdate = substr($program_start,0,8); + + $starttime = $inp_startdate . $starthour . "0000"; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($now_timestring)) { + # Past show + $program_timing = 0; + }elsif (as_epoch_seconds($program_start) < as_epoch_seconds($now_timestring)) { + # Current show + $program_timing = 1; + } else { + # Future show + $program_timing = 2; + } + $bgcolor = $color_show[$program_timing]; + if($rtvaccess) { + $program_icon = getScheduleDetails( $program_id , $program_timing ); + } + if (length($bgcolor) > 0) { + $bgcolor = " bgcolor=\"$bgcolor\""; + } + + if( $dsp_string ne $previous_date ) { + if (!$showpdaformat) { + if ($records == 1) { + print "<table border=1>"; + } + print "<tr><td width=10% align=center bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" size=2 color=\"$color_headingtext\"><B>$dsp_string</B></font>\n"; + print "<td width=\"10%\" align=center bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" color=\"$color_headingtext\">Channel</font>"; + print "<td width=\"70%\" align=left bgcolor=\"$color_headingbackground\"><font face=\"$font_heading\" color=\"$color_headingtext\">Title</font>"; + print "</tr>"; + } else { + print "<p>$dsp_string<p>\n"; + } + $previous_date = $dsp_string; + } + + if (!$showpdaformat) { + print "<tr>"; + print "<td align=left valign=top $bgcolor><font size=2 face=\"$font_listings\">"; + }else{ + print "<$size_pdalistings>"; + } + + $url_parms = ""; + addParameter("STARTDATE",$program_startdate); + addParameter("STARTHOUR",$program_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + + print "<a href=\"$scriptdir/$scriptname$url_parms\">"; + print as_hhmm(as_epoch_seconds($program_true_start)); + print "</a>\n"; + + if (!$showpdaformat) { + print "<td align=left valign=top $bgcolor><font size=2 face=\"$font_listings\">"; + }else{ + print " "; + } + + + #-------------------------------------------------------------------- + # Add a link to show just the single channel with 2 days of listings + #------------------------------------------------------------------- + + $url_parms = ""; + addParameter("FIRSTTUNE",$program_tuning); + addParameter("LASTTUNE",$program_tuning); + addParameter("STARTDATE",$program_startdate); + addParameter("STARTHOUR",$program_starthour); + addParameter("SHOWHOURS","48"); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + print "$program_tuning (<a href=\"$scriptdir/$scriptname$url_parms\">$program_channel</a>)\n"; + + #----------------------------------------------------------------------------- + # Force some variables so the odd start times aren't duplicated in the render + #----------------------------------------------------------------------------- + + $starttime = $program_true_start; + $colpos = 1; + $colspan = 1; + $shortslot = 0; + #$showrtvtext = 1; + + &RenderShow; + + if (!$showpdaformat) { + print "</tr>\n"; + }else{ + print "<p>\n"; + } + } + }else{ + } + + print "</table><p>"; + + if ($records) { + writeDebug("dotodo::ToDo List Returned $records Rows"); + print "<p><font face=\"$font_menu\">Found $records title(s) matching \"$label\"<p></font>"; + }else{ + writeDebug("dotodo::ToDo List Did Not Return Any Rows"); + print "<p><font face=\"$font_menu\">Did not find any matches for \"$label\".<p></font>"; + } + + endDSN($sth,$db_handle); + undef $db_handle; + + + return 1; + +} + + +#---------------------------------------------------- +sub scheduleManualRecording { + + my $unitid = int shift; + + if (countArray($schedulinglist,";") == 1) { + $inp_selectedrtv = $schedulinglist; + } + + #------------------------------------------------------------------------ + # First Pass + #------------------------------------------------------------------------ + + if (!$inp_recordtype) { + + $url_parms = ""; + + print "\n<form method=POST action=\"$scriptdir/$scriptname$url_parms\">\n"; + print "<table>\n"; + print "<input type=hidden name=ISMANUAL value=\"1\">\n"; + print "<input type=hidden name=MANUALREC value=\"1\">"; + print "<input type=hidden name=STARTDATE value=\"$inp_startdate\">"; + print "<input type=hidden name=STARTHOUR value=\"$inp_starthour\">"; + print "<input type=hidden name=SHOWHOURS value=\"$inp_showhours\">"; + print "<input type=hidden name=SHOWSLOTS value=\"$inp_showslots\">"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + + if (length($inp_search) > 0) { + print "<input type=hidden name=SEARCH value=\"$inp_search\">"; + } + if ($unitid == 0) { + $unitid = $rtvunit{$defaultreplaytv}; + } + + if (length($inp_selectedrtv) < 1) { + print "<tr>\n"; + print "<td align=right><B>ReplayTV:</B></td>\n"; + print "<td><select size=\"1\" name=\"SELECTEDRTV\">\n"; + + for ( split /;/, $schedulinglist ) { + /;/; + if ($_ eq $unitid) { + print "<option value=\"$_\" selected>$rtvlabel{$_}</option>\n"; + }else{ + print "<option value=\"$_\">$rtvlabel{$_}</option>\n"; + } + } + print "</select></td></tr>\n"; + }else{ + print "<tr><td align=right><B>ReplayTV:</B></td><td>"; + print $rtvlabel{$inp_selectedrtv}; + print " ($rtvaddress{$inp_selectedrtv})"; + print "</td></tr>\n"; + + print "<input type=hidden name=\"SELECTEDRTV\" value=\"$inp_selectedrtv\">\n"; + } + + print "<tr><td align=right><B>Manual:</B></td>\n"; + print "<td>"; + print "<select size=\"1\" name=\"RECORDTYPE\">\n"; + print "<option value=\"3\">Single Recording</option>\n"; + print "<option value=\"1\">Repeat Recording</option>\n"; + print "</select>\n"; + print "</td></tr>"; + + #----------------------------------------------------------------------- + # While the protocol has all the stuff for different inputsources it + # does not seem to work. So this is disabled for now and it will + # force the tuner. + #----------------------------------------------------------------------- + + print "<input type=hidden name=\"INPUTSOURCE\" value=\"3\">"; + +# print "<tr>\n"; +# print "<td align=right><B>Input:</B></td>\n"; +# print "<td>\n"; +# print "<select size=\"1\" name=\"INPUTSOURCE\">\n"; +# print "<option value=\"0\">Direct RF</option>\n"; +# print "<option value=\"1\">Line 1</option>\n"; +# print "<option value=\"2\">Line 2</option>\n"; +# print "<option value=\"3\" selected>ReplayTV Tuner</option>\n"; +# print "</select>\n"; +# print "</td></tr>\n"; + + print "</table>\n"; + + if (length($icon_select) > 0) { + print "<input type=image src=\"$imagedir/$icon_select\" ALT=\"Select\">\n"; + }else{ + print "<input type=submit value=\"Select\" name=\"SUBMITSEL\">\n"; + } + + print "</form><p>\n"; + + return 1; + } + + #------------------------------------------------------------------------ + # Second Pass + #------------------------------------------------------------------------ + + $url_parms = ""; + addParameter("state","slotrequest"); + print "<form method=POST action=$scriptdir/$schedulename$url_parms>\n"; + print "<input type=\"hidden\" name=\"ISMANUAL\" value=\"1\">\n"; + print "<input type=\"hidden\" name=\"INPUTSOURCE\" value=\"$inp_inputsource\">\n"; + if ($rtvport{$inp_selectedrtv} != 80) { + print "<input type=\"hidden\" name=\"REPLAYTV\" value=\"$rtvaddress{$inp_selectedrtv}:$rtvport{$inp_selectedrtv}\">\n"; + }else{ + print "<input type=\"hidden\" name=\"REPLAYTV\" value=\"$rtvaddress{$inp_selectedrtv}\">\n"; + } + print "<input type=\"hidden\" name=\"RECORDTYPE\" value=\"$inp_recordtype\">\n"; + + (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = localtime(time); + + $year += 1900; + $mon++; + + + #------------------------------------------------------------------------ + # Show Current Data + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<table>\n"; + print "<tr><td align=right>"; + }else{ + print "</CENTER>"; + } + + print "<B>ReplayTV:</B>"; + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + print $rtvlabel{$inp_selectedrtv}; + print " ($rtvaddress{$inp_selectedrtv})"; + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<p>"; + } + + print "\n"; + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Manual:</B>"; + + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + + if ($inp_recordtype == 1) { + print "Repeat Recording"; + } + + if ($inp_recordtype == 3) { + print "Single Recording"; + } + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<p>"; + } + print "\n"; + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Input:</B>"; + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + if ($inp_inputsource == 0) { + print "Direct RF"; + } + if ($inp_inputsource == 1) { + print "Line 1"; + } + if ($inp_inputsource == 2) { + print "Line 2"; + } + if ($inp_inputsource == 3) { + print "ReplayTV Tuner"; + } + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<p>"; + } + + + if ($inp_recordtype == 1) { + + #---------------------------------------------------------------- + # REPEATING + #---------------------------------------------------------------- + # Days, Time, Channel/Input, Keep/Quality/(Keep Until), Category + #---------------------------------------------------------------- + + print "<input type=\"hidden\" name=\"RECURRING\" value=\"1\">\n"; + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Record on:</B>"; + + if (!$showpdaformat) { + print "</td>\n<td>"; + }else{ + print "<br>"; + } + + print "<input type=checkbox name=\"SUN\" value=\"1\" checked> Sun.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"MON\" value=\"1\" checked> Mon.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"TUE\" value=\"1\" checked> Tue.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"WED\" value=\"1\" checked> Wed.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"THU\" value=\"1\" checked> Thu.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"FRI\" value=\"1\" checked> Fri.\n"; + if ($showpdaformat) { + print "<br> "; + } + + print "<input type=checkbox name=\"SAT\" value=\"1\" checked> Sat.\n"; + if ($showpdaformat) { + print "<br> "; + } + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + } + + if ($inp_recordtype == 3) { + #---------------------------------------------------------------- + # SINGLE + #---------------------------------------------------------------- + # Date, Time, Channel/Input, Quality/Keep Until/Category + #---------------------------------------------------------------- + + print "<input type=\"hidden\" name=\"RECURRING\" value=\"0\">\n"; + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Date:</B>"; + + if (!$showpdaformat) { + print "</td>\n<td>"; + }else{ + print "<br>"; + } + + print "<select size=\"1\" name=\"MONTH\">\n"; + selectMonth($mon); + print "</select>\n"; + + print "<select size=\"1\" name=\"DAY\">\n"; + selectDay($mday,31); + print "</select>\n"; + + print "<select size=\"1\" name=\"YEAR\">\n"; + selectYear($year,$year+2); + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + } + + #------------------------------------------------------------------------ + # Time of Recording + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Time:</B>"; + + if (!$showpdaformat) { + print "</td>\n<td>"; + }else{ + print "<br>"; + } + + print "<select size=\"1\" name=\"HOUR\">\n"; + selectNumbers($hour,24,0); + print "</select>\n"; + print ":"; + print "<select size=\"1\" name=\"MINUTE\">\n"; + print "<option value=\"0\">00</option>\n"; + print "<option value=\"5\">05</option>\n"; + print "<option value=\"15\">15</option>\n"; + print "<option value=\"30\">30</option>\n"; + print "<option value=\"45\">45</option>\n"; + print "<option value=\"55\">55</option>\n"; + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + #------------------------------------------------------------------------ + # Length of Recording + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Record for</B>"; + + if (!$showpdaformat) { + print "</td>\n<td>"; + }else{ + print "<br>"; + } + + print "<select size=\"1\" name=\"LENGTH\">\n"; + print "<option value=\"15\">15 Minutes</option>\n"; + print "<option value=\"30\" selected>30 Minutes</option>\n"; + print "<option value=\"45\">45 Minutes</option>\n"; + print "<option value=\"60\">60 Minutes</option>\n"; + print "<option value=\"75\">75 Minutes</option>\n"; + print "<option value=\"90\">90 Minutes</option>\n"; + print "<option value=\"120\">2 Hours</option>\n"; + print "<option value=\"180\">3 Hours</option>\n"; + print "<option value=\"240\">4 Hours</option>\n"; + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + #------------------------------------------------------------------------ + # Select Tuning/Input + #------------------------------------------------------------------------ + + if ($inp_inputsource < 3) { + + #---------------------------------------------------------------- + # Input Source: ANT/CATV, Line 1, Line 2 + # Channel: No Tuning, Tune to #0000 + #---------------------------------------------------------------- + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Tuning:</B>"; + + if (!$showpdaformat) { + print "</td>\n<td>"; + }else{ + print "<br>"; + } + + print "<input type=\"text\" size=\"4\" name=\"TUNING\" value=\"\">"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + }else{ + + #---------------------------------------------------------------- + # List Channels + # NOTE: Need to tag with (Cable) (DBS) or (Air) in the + # slotrequest - eg BBCA(Cable) + #---------------------------------------------------------------- + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Channel:</B>"; + + if (!$showpdaformat) { + print "</td>\n<td>"; + }else{ + print "<br>"; + } + + print "<select size=\"1\" name=\"CHANNEL\">\n"; + + my $Stmt = ""; + $Stmt .= "SELECT * "; + $Stmt .= "FROM $db_table_channels "; + $Stmt .= "WHERE hidden = 0 "; + $Stmt .= "ORDER BY display;"; + + my $db_handle = &StartDSN; + + my $sth = sqlStmt($db_handle,$Stmt); + if ( $sth ) { + + while ( $row = $sth->fetchrow_hashref ) { + my $channel_label = convertfromhtml($row->{'display'}); + my $callsign = $row->{'channel'}; + my $systemtype = $row->{'systemtype'}; + my $lineup = $row->{'lineupname'}; + my $displaynumber = $row->{'displaynumber'}; + my $tuning = $row->{'tuning'}; + + print "<option value=\"$callsign($systemtype)\">"; + if (!$showpdaformat) { + print "$channel_label ($lineup: $displaynumber)"; + }else{ + print "$channel_label ($lineup: $displaynumber)"; + } + print "</option>\n"; + } + + }else{ + abend("Couldn't get channels"); + } + + endDSN($sth,$db_handle); + undef $db_handle; + + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + } + + + #------------------------------------------------------------------------ + # Category + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + + print "<B>Store in category:</B>"; + + if (!$showpdaformat) { + print "</td><td>"; + }else{ + print " "; + } + + print "<select size=\"1\" name=\"CATEGORY\">"; + print "<option value=\"255\" selected>All Shows</option>\n"; + + $ctr = 0; + + if (countArray($categories{$inp_selectedrtv},";")) { + for ( split /;/, $categories{$inp_selectedrtv} ) { + /;/; + ($cat_num,$cat_label) = split(',', $_, 2); + print "<option value=\"$cat_num\">$cat_label</option>\n"; + $ctr++; + } + } + print "</select>"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + if ($inp_recordtype == 3) { + #------------------------------------------------------------------------ + # Keep Until (This Show Only) + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + print "<B>Keep Until:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + print "\n"; + + if (!$showpdaformat) { + print "<td>"; + } + print "<select size=\"1\" name=\"GUARANTEED\">\n"; + print "<option value=\"1\">I delete</option>\n"; + print "<option value=\"0\">Space needed</option>\n"; + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + + print "<input type=\"hidden\" name=\"KEEP\" value=\"1\">\n"; + }else{ + #------------------------------------------------------------------------ + # Episodes to Keep + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + print "<B>Episodes to Keep:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + + print "\n"; + + if (!$showpdaformat) { + print "<td>"; + } + + print "<select size=\"1\" name=\"KEEP\">"; + selectNumbers($rtvdefaultkeep{$inp_selectedrtv},10,1); + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + print "\n"; + + #------------------------------------------------------------------------ + # Delete oldest + #------------------------------------------------------------------------ + + + if (!$showpdaformat) { + print "<tr><td align=right>"; + } + print "<B>Delete oldest:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + print "\n"; + + + if (!$showpdaformat) { + print "<td>"; + } + print "<select size=\"1\" name=\"GUARANTEED\">\n"; + print "<option value=\"1\">Only for new episode</option>\n"; + print "<option value=\"0\">If space needed</option>\n"; + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + + print "\n"; + } + + #------------------------------------------------------------------------ + # Quality + #------------------------------------------------------------------------ + + if (!$showpdaformat) { + print "<tr>\n"; + print "<td align=right>"; + } + + print "<B>Quality:</B>"; + + if (!$showpdaformat) { + print "</td>"; + }else{ + print " "; + } + print "\n"; + + if (!$showpdaformat) { + print "<td>"; + } + print "\n"; + + print "<select size=\"1\" name=\"QUALITY\">\n"; + if ($rtvdefaultquality{$inp_selectedrtv} == 2) { + print "<option value=\"2\" selected>Standard</option>\n"; + }else{ + print "<option value=\"2\">Standard</option>\n"; + } + if ($rtvdefaultquality{$inp_selectedrtv} == 1) { + print "<option value=\"1\" selected>Medium</option>\n"; + }else{ + print "<option value=\"1\">Medium</option>\n"; + } + if ($rtvdefaultquality{$inp_selectedrtv} == 0) { + print "<option value=\"0\" selected>High</option>\n"; + }else{ + print "<option value=\"0\">High</option>\n"; + } + print "</select>\n"; + + if (!$showpdaformat) { + print "</td></tr>"; + }else{ + print "<br>"; + } + print "\n"; + + + if (!$showpdaformat) { + print "\n<tr><td></td><td>"; + }else{ + print "<p>\n"; + } + + #------------------------------------------------------------------------ + # Set Up Return Paths and Show Button + #------------------------------------------------------------------------ + + $url_parms = ""; + addParameter("STARTDATE",$inp_startdate); + addParameter("STARTHOUR",$inp_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + + writeDebug("scheduleManualRecording::ReturnPath: $scriptdir/$scriptname$url_parms"); + print "\n<input type=hidden name=RETURNURL value=\"$scriptdir/$scriptname$url_parms\">\n"; + print "\n<input type=hidden name=RETURNTEXT value=\"Back to Schedule\">\n"; + + if (length($icon_schedule) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_schedule\" ALT=\"Schedule\">\n"; + }else{ + print "\n<input type=submit value=Schedule name=SUBMIT>\n"; + } + print "</form><p>"; + + if (!$showpdaformat) { + print "</td></tr>\n</table>"; + } + + return 1; +} + +#---------------------------------------------------- +sub editRTVChannel($) { +# ****** NOT IMPLEMENTED **************************** + return 0; +} + +#---------------------------------------------------- +sub deleteRTVShow($) { +# ****** NOT IMPLEMENTED **************************** + + + if (!$rtv_allowdelete) { + return 0; + } + + return 0; +} + + + +#---------------------------------------------------- +sub showDetail($) { + # + # Show detail for a ReplayShow and allow some actions + # + # Parameter is + # + # + #------------------------------------------------------------------------------ + + my $specialdebug = 0; + my $rtvshow = shift; + + print "<$size_title>ReplayShow Detail</$size_title><p>"; + + if ($specialdebug) { + writeDebug("showdetail::starting($rtvshow)"); + } + + if ($rtvshow eq $null) { + writeDebug("showdetail::no show, no go"); + return 0; + } + + #--------------------------------------------------------------------- + # Permission Check + #--------------------------------------------------------------------- + + if (!$rtvaccess) { + writeDebug("showdetail::exiting(no rtv access)"); + return 0; + } + + + #--------------------------------------------------------------------- + # Load the module with ReplayTV functions + #--------------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("showdetail::loading module rg_replay.pl"); + } + + require 'rg_replay.pl'; + identifyLoadedModules("rg_replay.pl"); + + if ($specialdebug) { + writeDebug("showdetail::loaded module rg_replay.pl"); + } + + $rtvshow = decodehex($rtvshow); + if ($specialdebug) { + writeDebug("showdetail::decoded: $rtvshow"); + } + + undef $show_rtvcc; + undef $show_rtvstereo; + undef $show_rtvrepeat; + undef $show_rtvsap; + undef $show_rtvlbx; + undef $show_rtvmovie; + undef $show_rtvrating; + ($show_replayid,$chan_showlabel,$show_rtvtitle,$show_rtvrecorded,$show_rtvepisode,$show_rtvdescription,$show_rtvminutes,$show_inputsource,$show_quality,$chan_rtvcreate,$chan_daysofweek,$chan_beforepadding,$chan_afterpadding,$show_beforepadding,$show_afterpadding,$chan_themeflags,$chan_themestring,$chan_thememinutes,$chan_channeltype,$chan_guaranteed,$show_channelname,$show_channellabel,$show_tuning,$show_rtvcc,$show_rtvstereo,$show_rtvrepeat,$show_rtvsap,$show_rtvlbx,$show_rtvmovie,$show_rtvrating,$show_category,$chan_keep,$chan_norepeats,$chan_minutes) = split(/\|/,$rtvshow); + + if ($specialdebug) { + writeDebug("showdetail::$show_replayid,$chan_showlabel,$show_rtvtitle,$show_rtvrecorded,$show_rtvepisode,$show_rtvdescription,$show_rtvminutes,$show_inputsource,$show_quality,$chan_rtvcreate,$chan_daysofweek,$chan_beforepadding,$chan_afterpadding,$show_beforepadding,$show_afterpadding,$chan_themeflags,$chan_themestring,$chan_thememinutes,$chan_channeltype,$chan_guaranteed,$show_channelname,$show_channellabel,$show_tuning,$show_rtvcc,$show_rtvstereo,$show_rtvrepeat,$show_rtvsap,$show_rtvlbx,$show_rtvmovie,$show_rtvrating,$show_category,$chan_keep,$chan_norepeats,$chan_minutes"); + } + + + #------------------------------------- + # Channel Stuff + #------------------------------------- + + print "<font size=+1><B>$chan_showlabel</B></font><br>"; + print "($show_category)<p>"; + + my $chan_reservedtime = 0; + + #---------------- + # First Row + #---------------- + + if ($chan_channeltype == 1) { + print "Keep $chan_keep "; + if ($chan_keep > 1) { + print "episodes"; + }else{ + print "episode"; + } + print "; "; + $chan_reservedtime = ( $chan_minutes + $chan_beforepadding + $chan_afterpadding ) * $chan_keep; + $chan_reservedtime = getRunningTime($chan_reservedtime,1); + print "$chan_reservedtime "; + if ($chan_guaranteed) { + print "reserved "; + } + print "at " . lc $qualitylabel[$show_quality] . " quality.<p>"; + } + + if (($chan_channeltype == 2) || ($chan_channeltype == 4)) { + $chan_reservedtime = getRunningTime($chan_thememinutes,1); + print "$chan_reservedtime "; + print "at " . lc $qualitylabel[$show_quality] . " quality.<p>"; + } + + if ($chan_channeltype == 3) { + $chan_reservedtime = $show_rtvminutes + $show_beforepadding + $show_afterpadding; + $chan_reservedtime = getRunningTime($chan_reservedtime,1); + print "Keep until I delete; $chan_reservedtime reserved "; + print "at " . lc $qualitylabel[$show_quality] . " quality.<p>"; + } + + #--------------- + # Second Row + #--------------- + + print "This Replay Channel "; + + if ($chan_channeltype == 1) { + print "will record "; + if ($chan_norepeats) { + print "only new"; + }else{ + print "all"; + } + print " episodes of $show_rtvtitle occuring "; + + my $days = ""; + my $flag = 0; + my $group = 0; + + if ($chan_daysofweek == 1) { + $days = "every Sunday"; + } + + if ($chan_daysofweek == 2) { + $days = "every Monday"; + } + + if ($chan_daysofweek == 4) { + $days = "every Tuesday"; + } + + if ($chan_daysofweek == 8) { + $days = "every Wednesday"; + } + + if ($chan_daysofweek == 16) { + $days = "every Thursday"; + } + + if ($chan_daysofweek == 32) { + $days = "every Friday"; + } + + if ($chan_daysofweek == 64) { + $days = "every Saturday"; + } + + if ($chan_daysofweek == 127) { + $days = "any day"; + } + + if ($days eq $null) { + $days = "every "; + + if ($chan_daysof_week & 1) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Sun"; + } + + if ($chan_daysof_week & 2) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Mon"; + } + + + if ($chan_daysof_week & 4) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Tue"; + } + + + if ($chan_daysof_week & 8) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Wed"; + } + + + if ($chan_daysof_week & 16) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Thu"; + } + + + if ($chan_daysof_week & 32) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Fri"; + } + + + if ($chan_daysof_week & 64) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Sat"; + } + + } + + $show_rtvrecorded_local = as_time_string($show_rtvrecorded+5); + $dsp_string = as_hhmm(as_epoch_seconds($show_rtvrecorded_local)); + $dsp_string .= " - " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local) + ($show_rtvminutes+$show_beforepadding+$show_afterpadding) * 60); + + print "$days from $dsp_string on channel $show_tuning ($show_channelname).<br>"; + } + + if (($chan_channeltype == 2) || ($chan_channeltype == 4)) { + print " will record shows on any channel with the title: \"$chan_themestring\"<br>"; + } + + + if ($chan_channeltype == 3) { + $show_rtvrecorded_local = as_time_string($show_rtvrecorded+5); + $rng_string = substr($show_rtvrecorded_local,0,8); + $wday = strftime( "%A", localtime($show_rtvrecorded)); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2); + + $dsp_string .= " from " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local)); + $dsp_string .= " - " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local) + ($show_rtvminutes+$show_beforepadding+$show_afterpadding) * 60); + + print "recorded $show_rtvtitle on $dsp_string on channel $show_tuning ($show_channelname)."; + } + + print "<p>"; + + #------------------------------------- + # Show Stuff + #------------------------------------- + + + if (length($show_rtvepisode) > 0) { + if ($show_rtvtitle ne $show_rtvepisode) { + print "<B>$show_rtvtitle</B>: "; + } + print "<B>$show_rtvepisode</B>"; + }else{ + print "<B>$show_rtvtitle</B>"; + } + + my $show_rtvrecorded_local = as_time_string($show_rtvrecorded+5); + my $rng_string = substr($show_rtvrecorded_local,0,8); + my $wday = strftime( "%A", localtime($show_rtvrecorded)); + my$dsp_string = substr($rng_string,4,2) . "/" . substr($rng_string,6,2); # . "/" . substr($rng_string,0,4); + + my $dsp_string .= " at " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local)); + + print "<br>"; + + print getRunningTime($show_rtvminutes+$show_beforepadding+$show_afterpadding,1); + + print "; recorded $dsp_string from $show_tuning ($show_channelname)<br>"; + + my $flag = 0; + + $dsp_string = ""; + + if (length($show_rtvmovie) > 0) { + $dsp_string .= $show_rtvmovie; + $show_rtvrating = ""; + $flag = 1; + } + + + if (length($show_rtvcc) > 0) { +# if ($flag) { +# $dsp_string .= ", "; +# $flag = 0; +# } +# $dsp_string .= $show_rtvcc; +# $flag = 1; + } + + if (length($show_rtvstereo) > 0) { +# if ($flag) { +# $dsp_string .= ", "; +# $flag = 0; +# } +# $dsp_string .= $show_rtvstereo; +# $flag = 1; + } + + if (length($show_rtvrating) > 0) { + if ($flag) { + $dsp_string .= ", "; + $flag = 0; + } + $dsp_string .= $show_rtvrating; + $flag = 1; + } + + + + if (length($show_rtvrepeat) > 0) { + if ($flag) { + $dsp_string .= ", "; + $flag = 0; + } + $dsp_string .= $show_rtvrepeat; + $flag = 1; + } + + if (length($show_rtvlbx) > 0) { + if ($flag) { + $dsp_string .= ", "; + $flag = 0; + } + $dsp_string .= $show_rtvlbx; + $flag = 1; + } + + + if ($flag) { + $flag = 0; + } + + if (length($dsp_string) > 0) { + print "($dsp_string) "; + } + + if (length($show_rtvepisode) > 0) { + print "$show_rtvepisode: "; + } + + if (length($show_rtvdescription) > 0) { + print "$show_rtvdescription"; + } + + + print "<br>\n"; + + + # Buttons to do things (Find All Episodes,Find Repeat) and eventually "Delete" + + print "<p><CENTER>\n"; + print "<table border=0><tr>"; + + print "<td>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=SEARCH value=\"$chan_showlabel\">\n"; + if (length($icon_findall) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_findall\" ALT=\"Find All\">\n"; + }else{ + print "<input type=submit value=\"Find All\" name=\"FIND\">\n"; + } + print "</form>\n"; + print "<td>"; + + + print "<td>"; + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=\"SHOWPDAFORMAT\" value=\"$showpdaformat\">\n"; + print "<input type=hidden name=SEARCH value=\"$chan_showlabel|$show_rtvepisode\">\n"; + print "<input type=hidden name=FIELD value=\"title,subtitle\">\n"; + if (length($icon_findrepeat) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_findrepeat\" ALT=\"Find Repeats\">\n"; + }else{ + print "<input type=submit value=\"Find Repeats\" name=\"FINDREPEATS\">\n"; + } + print "</form>\n"; + + if ($rtv_allowdelete) { + print "<td>"; + + print "<form method=POST action=\"$scriptdir/$scriptname\">\n"; + print "<input type=hidden name=SHOWPDAFORMAT value=\"$showpdaformat\">\n"; + print "<input type=hidden name=DELETESHOW value=\"" . converttext($rtvshow,length($rtvshow)) . "\">"; + if (length($icon_delete) > 0) { + print "\n<input type=image src=\"$imagedir/$icon_delete\" ALT=\"Delete\">\n"; + }else{ + print "<input type=submit value=\"Delete\" name=\"DELETE\">\n"; + } + print "</form>"; + } + + print "</table>\n"; + + if ($specialdebug) { + writeDebug("showdetail::exiting"); + } + + return 1; + +} + + +#---------------------------------------------------- +sub showRTVShows($) { + # + # Show ReplayGuide equiv for the given RTV(s) + # + # Parameter is a comma delimited list of ReplayID(s). The keyword "ALL" can be + # used for all units defined in Personal ReplayGuide. If no parameter is + # present all is assumed. + # + # NOTE: $replaylist must already be parsed and $rtvaccess must be nonzero or + # the function will fail. + # + #------------------------------------------------------------------------------ + + #--------------------------------------------------------------------- + # Set defaults + #--------------------------------------------------------------------- + + my $specialdebug = 0; + my $rtvlist = shift; + my $prev_channel = ""; + my $prev_id = ""; + + print "<$size_title>ReplayShows</$size_title><p>"; + + if ($specialdebug) { + writeDebug("showrtvshows::starting($rtvlist)"); + } + + if (($rtvlist eq $null) || ($rtvlist eq "0")) { + $rtvlist = "ALL"; + } + + if ($rtvlist eq "ALL") { + $rtvlist = $replaylist; + } + + #--------------------------------------------------------------------- + # Sanity check + #--------------------------------------------------------------------- + + if ($replaylist eq $null) { + writeDebug("showrtvshows::exiting(no units defined)"); + return 0; + } + + if ($rtvlist eq $null) { + writeDebug("showrtvshows::exiting(nothing to do)"); + return 0; + } + + #--------------------------------------------------------------------- + # Permission Check + #--------------------------------------------------------------------- + + if (!$rtvaccess) { + writeDebug("showrtvshows::exiting(no rtv access)"); + return 0; + } + + + #--------------------------------------------------------------------- + # Load the module with ReplayTV functions + #--------------------------------------------------------------------- + + + if ($specialdebug) { + writeDebug("showrtvshows::loading module rg_replay.pl"); + } + + require 'rg_replay.pl'; + identifyLoadedModules("rg_replay.pl"); + + if ($specialdebug) { + writeDebug("showrtvshows::loaded module rg_replay.pl"); + } + + #--------------------------------------------------------------------- + # Gather ReplayChannels + #--------------------------------------------------------------------- + + + if ($specialdebug) { + writeDebug("showrtvshows::getting replaychannels"); + } + + my $rtvchannelcount = collectRTVChannels($rtvlist); + + if ($specialdebug) { + writeDebug("showrtvshows::found $rtvchannelcount replaychannels"); + } + + #--------------------------------------------------------------------- + # Gather ReplayShows + #--------------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("showrtvshows::getting replayshows"); + } + + my $rtvshowcount = collectRTVShows($rtvlist); + + + if ($specialdebug) { + writeDebug("showrtvshows::found $rtvshowcount replayshows"); + } + + #--------------------------------------------------------------------- + # If either are 0, something is bad and we need to bail + #--------------------------------------------------------------------- + + if (($rtvshowcount == 0) || ($rtvchannelcount == 0)) { + writeDebug("showrtvshows::exiting(could not find any channels or shows for \"$rtvlist\")"); + return 0; + } + + #--------------------------------------------------------------------- + # Merge the ReplayChannel/Show data into a new structure for optimal + # sorting. + #--------------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("showrtvshows::processing shows and channels"); + } + + + my $ctr = 0; + + do { + $ctr++; + if ($specialdebug) { + writeDebug("showrtvshows::processing $ctr of $rtvshowcount"); + } + my $retcode = getShowAndParent($rtvshows[$ctr]); + if ($specialdebug) { + writeDebug("showrtvshows::getShowAndParent returned $retcode"); + } + $rtventry[$ctr] = "$show_replayid|$chan_showlabel|$show_rtvtitle|$show_rtvrecorded|$show_rtvepisode|$show_rtvdescription|$show_rtvminutes|$show_inputsource|$show_quality|$chan_rtvcreate|$chan_daysofweek|$chan_beforepadding|$chan_afterpadding|$show_beforepadding|$show_afterpadding|$chan_themeflags|$chan_themestring|$chan_thememinutes|$chan_channeltype|$chan_guaranteed|$show_channelname|$show_channellabel|$show_tuning|$show_rtvcc|$show_rtvstereo|$show_rtvrepeat|$show_rtvsap|$show_rtvlbx|$show_rtvmovie|$show_rating|$show_category|$chan_keep|$chan_norepeats|$chan_minutes"; + if ($specialdebug) { + writeDebug("showrtvshows::rtventry[$ctr]: $rtventry[$ctr]"); + } + } while $ctr < $rtvshowcount; + + if ($specialdebug) { + writeDebug("showrtvshows::processed $ctr shows"); + } + + @rtventry = sort @rtventry; + + #--------------------------------------------------------------------- + # Display an anchor menu for jumping to a particular Replay + #--------------------------------------------------------------------- + + print "<center><font size=+2>"; + + my $ctr = 0; + + for ( split /,/, $replaylist ) { + /,/; + $ctr++; + my $addr = $rtvaddress{$_}; + my $label = $rtvlabel{$_}; + if ($ctr > 1) { + print " | "; + } + print "<a href=\"#$label\">$label</a>"; + } + print "</font><p>"; + + #--------------------------------------------------------------------- + # Display All Recorded Shows from Selected ReplayTV(s) + #--------------------------------------------------------------------- + + print "<table border=1>"; + + $ctr = 0; + my $no_sep_flag = 0; + + + do { + #--------------------------------------------------------------------- + # This will always be sorted by replayid,showtitle,recorddate + #--------------------------------------------------------------------- + + $ctr++; + if ($specialdebug) { + writeDebug("showrtvshows::processing $ctr of $rtvshowcount"); + } + + undef $show_rtvcc; + undef $show_rtvstereo; + undef $show_rtvrepeat; + undef $show_rtvsap; + undef $show_rtvlbx; + undef $show_rtvmovie; + undef $show_rtvrating; + ($show_replayid,$chan_showlabel,$show_rtvtitle,$show_rtvrecorded,$show_rtvepisode,$show_rtvdescription,$show_rtvminutes,$show_inputsource,$show_quality,$chan_rtvcreate,$chan_daysofweek,$chan_beforepadding,$chan_afterpadding,$show_beforepadding,$show_afterpadding,$chan_themeflags,$chan_themestring,$chan_thememinutes,$chan_channeltype,$chan_guaranteed,$show_channelname,$show_channellabel,$show_tuning,$show_rtvcc,$show_rtvstereo,$show_rtvrepeat,$show_rtvsap,$show_rtvlbx,$show_rtvmovie,$show_rtvrating,$show_category,$chan_keep,$chan_norepeats,$chan_minutes) = split(/\|/,$rtventry[$ctr]); + + if ($specialdebug) { + writeDebug("showrtvshows::getShowAndParent returned $retcode"); + writeDebug("showrtvshows::rtventry($ctr): $show_replayid,$chan_showlabel,$show_rtvtitle,$show_rtvrecorded,$show_rtvepisode,$show_rtvdescription,$show_rtvminutes,$show_inputsource,$show_quality,$chan_rtvcreate,$chan_daysofweek,$chan_beforepadding,$chan_afterpadding,$show_beforepadding,$show_afterpadding,$chan_themeflags,$chan_themestring,$chan_thememinutes,$chan_channeltype,$chan_guaranteed,$show_channelname,$show_channellabel,$show_tuning,$show_rtvcc,$show_rtvstereo,$show_rtvrepeat,$show_rtvsap,$show_rtvlbx,$show_rtvmovie,$show_rtvrating,$show_category,$chan_keep,$chan_norepeats,$chan_minutes"); + } + + if ($specialdebug) { + writeDebug("showrtvshows::prev_id: $prev_id show_replayid: $show_replayid"); + } + + #--------------------------------------------------------------------- + # If the ReplayID has changed, make a new anchor and show the label. + #--------------------------------------------------------------------- + + if ($prev_id ne $show_replayid) { + print "<tr><td colspan=2><$size_title><a name=\"$rtvlabel{$show_replayid}\">$rtvlabel{$show_replayid}</a></$size_title></td></tr>\n"; + } + + if ($specialdebug) { + writeDebug("showrtvshows::prev_channel: $prev_channel chan_rtvcreate: $chan_rtvcreate"); + } + + #--------------------------------------------------------------------- + # If ReplayChannel ID has changed, start a new row. + #--------------------------------------------------------------------- + + if ($prev_channel ne $chan_rtvcreate) { + if ($specialdebug) { + writeDebug("showrtvshows::processing new replayChannel"); + writeDebug("showrtvshows::chan_minutes: $chan_minutes, chan_keep: $chan_keep, chan_beforepadding: $chan_beforepadding, chan_afterpadding: $chan_afterpadding"); + } + if ($ctr == 1) { + print "<tr><td align=center valign=center width=25%>"; + }else{ + print "<tr><td align=center valign=center>"; + } + print "<font size=+1><B>$chan_showlabel</B></font><br>"; + print "($show_category)<p>"; + + my $chan_reservedtime = 0; + + #---------------- + # First Row + #---------------- + + if ($chan_channeltype == 1) { + print "Keep $chan_keep "; + if ($chan_keep > 1) { + print "episodes"; + }else{ + print "episode"; + } + print "; "; + $chan_reservedtime = ( $chan_minutes + $chan_beforepadding + $chan_afterpadding ) * $chan_keep; + $chan_reservedtime = getRunningTime($chan_reservedtime,1); + print "$chan_reservedtime "; + if ($chan_guaranteed) { + print "reserved "; + } + print "at " . lc $qualitylabel[$show_quality] . " quality.<p>"; + } + + if (($chan_channeltype == 2) || ($chan_channeltype == 4)) { + $chan_reservedtime = getRunningTime($chan_thememinutes,1); + print "$chan_reservedtime "; + print "at " . lc $qualitylabel[$show_quality] . " quality.<p>"; + } + + if ($chan_channeltype == 3) { + $chan_reservedtime = $show_rtvminutes + $show_beforepadding + $show_afterpadding; + $chan_reservedtime = getRunningTime($chan_reservedtime,1); + print "Keep until I delete; $chan_reservedtime reserved "; + print "at " . lc $qualitylabel[$show_quality] . " quality.<p>"; + } + + #--------------- + # Second Row + #--------------- + + print "This Replay Channel "; + + if ($chan_channeltype == 1) { + print "will record "; + if ($chan_norepeats) { + print "only new"; + }else{ + print "all"; + } + print " episodes of $show_rtvtitle occuring "; + + my $days = ""; + my $flag = 0; + my $group = 0; + + if ($chan_daysofweek == 1) { + $days = "every Sunday"; + } + + if ($chan_daysofweek == 2) { + $days = "every Monday"; + } + + if ($chan_daysofweek == 4) { + $days = "every Tuesday"; + } + + if ($chan_daysofweek == 8) { + $days = "every Wednesday"; + } + + if ($chan_daysofweek == 16) { + $days = "every Thursday"; + } + + if ($chan_daysofweek == 32) { + $days = "every Friday"; + } + + if ($chan_daysofweek == 64) { + $days = "every Saturday"; + } + + if ($chan_daysofweek == 127) { + $days = "any day"; + } + + if ($days eq $null) { + $days = "every "; + + if ($chan_daysof_week & 1) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Sun"; + } + + if ($chan_daysof_week & 2) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Mon"; + } + + + if ($chan_daysof_week & 4) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Tue"; + } + + + if ($chan_daysof_week & 8) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Wed"; + } + + + if ($chan_daysof_week & 16) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Thu"; + } + + + if ($chan_daysof_week & 32) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Fri"; + } + + + if ($chan_daysof_week & 64) { + if ($flag) { + $days .= ", "; + $flag = 0; + } + $flag = 1; + $days .= "Sat"; + } + + } + $show_rtvrecorded_local = as_time_string($show_rtvrecorded+5); + $dsp_string = as_hhmm(as_epoch_seconds($show_rtvrecorded_local)); + $dsp_string .= " - " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local) + ($show_rtvminutes+$show_beforepadding+$show_afterpadding) * 60); + + print "$days from $dsp_string on channel $show_tuning ($show_channelname).<br>"; + } + + if (($chan_channeltype == 2) || ($chan_channeltype == 4)) { + print " will record shows on any channel with the title: \"$chan_themestring\"<br>"; + } + + + if ($chan_channeltype == 3) { + $show_rtvrecorded_local = as_time_string($show_rtvrecorded+5); + $rng_string = substr($show_rtvrecorded_local,0,8); + $wday = strftime( "%A", localtime($show_rtvrecorded)); + $dsp_string = $wday . ", " . substr($rng_string,4,2) . "/" . substr($rng_string,6,2); + + $dsp_string .= " from " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local)); + $dsp_string .= " - " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local) + ($show_rtvminutes+$show_beforepadding+$show_afterpadding) * 60); + + print "recorded $show_rtvtitle on $dsp_string on channel $show_tuning ($show_channelname)."; + } + + + print "<td valign=top align=left>"; + $no_sep_flag = 1; + } + + #--------------------------------------------------------------------- + # If it's not the first ReplayShow for the Channel, add a horizontal + # break + #--------------------------------------------------------------------- + + if ($no_sep_flag) { + $no_sep_flag = 0; + }else{ + print "<br><hr>"; + } + + + #--------------------------------------------------------------------- + # Display Data for the ReplayShow + #--------------------------------------------------------------------- + + $url_parms = ""; + addParameter("STARTDATE",$inp_startdate); + addParameter("STARTHOUR",$inp_starthour); + addParameter("SHOWHOURS",$inp_showhours); + addParameter("SHOWSLOTS",$inp_showslots); + addParameter("SHOWPDAFORMAT",$showpdaformat); + addParameter("SHOWDETAIL",converttext($rtventry[$ctr],length($rtventry[$ctr]))); + + print "<a href=\"$scriptdir/$scriptname$url_parms\">"; + + if (length($show_rtvepisode) > 0) { + print "<B>$show_rtvepisode</B>"; + }else{ + print "<B>$show_rtvtitle</B>"; + } + + print "</a>"; + + $show_rtvrecorded_local = as_time_string($show_rtvrecorded+5); + $rng_string = substr($show_rtvrecorded_local,0,8); + $wday = strftime( "%A", localtime($show_rtvrecorded)); + $dsp_string = substr($rng_string,4,2) . "/" . substr($rng_string,6,2); # . "/" . substr($rng_string,0,4); + + $dsp_string .= " at " . as_hhmm(as_epoch_seconds($show_rtvrecorded_local)); + + print "<br>"; + + print getRunningTime($show_rtvminutes+$show_beforepadding+$show_afterpadding,1); + + print "; recorded $dsp_string from $show_tuning ($show_channelname)<br>"; + + my $flag = 0; + + $dsp_string = ""; + + if (length($show_rtvmovie) > 0) { + $dsp_string .= $show_rtvmovie; + $show_rtvrating = ""; + $flag = 1; + } + + + if (length($show_rtvcc) > 0) { +# if ($flag) { +# $dsp_string .= ", "; +# $flag = 0; +# } +# $dsp_string .= $show_rtvcc; +# $flag = 1; + } + + if (length($show_rtvstereo) > 0) { +# if ($flag) { +# $dsp_string .= ", "; +# $flag = 0; +# } +# $dsp_string .= $show_rtvstereo; +# $flag = 1; + } + + if (length($show_rtvrating) > 0) { + if ($flag) { + $dsp_string .= ", "; + $flag = 0; + } + $dsp_string .= $show_rtvrating; + $flag = 1; + } + + + + if (length($show_rtvrepeat) > 0) { + if ($flag) { + $dsp_string .= ", "; + $flag = 0; + } + $dsp_string .= $show_rtvrepeat; + $flag = 1; + } + + if (length($show_rtvlbx) > 0) { + if ($flag) { + $dsp_string .= ", "; + $flag = 0; + } + $dsp_string .= $show_rtvlbx; + $flag = 1; + } + + + if ($flag) { + $flag = 0; + } + + if (length($dsp_string) > 0) { + print "($dsp_string) "; + } + + if (length($show_rtvepisode) > 0) { + print "$show_rtvepisode: "; + } + + if (length($show_rtvdescription) > 0) { + print "$show_rtvdescription"; + } + + + print "<br>\n"; + + $prev_channel = $chan_rtvcreate; + $prev_id = $show_replayid; + + } while $ctr < $rtvshowcount; + + if ($specialdebug) { + writeDebug("showrtvshows::done"); + } + + print "</table>\n"; + + if ($specialdebug) { + writeDebug("showrtvshows::exiting"); + } + + return 1; +} + +#---------------------------------------------------- +sub CalculateSlotTimes{ + # + # Calculate (in epoch seconds) times for the slot based on position + # + #--------------------------------------------------------------------------- + + $es_slotstart = $es_starttime + ((($colpos - 1) * $inp_showslots) * 60); + $es_nextslot = $es_starttime + ((($colpos) * $inp_showslots) * 60); + $es_prevslot = $es_starttime + ((($colpos - 2) * $inp_showslots) * 60); + + return 1; +} + + + +#---------------------------------------------------- +sub ReadConfig{ + # + # Read Configuration File + # + # ------------------------------------------------------------------------------ + + my $retcode = 0; + + + #------------------------------------------------------------------------------ + # Set Defaults + #------------------------------------------------------------------------------ + + $wwwdir = "/"; + $scriptdir = "/scripts"; + $scriptname = "replayguide.pl"; + $schedulename = "schedule.pl"; + $scheduler = "rg_scheduler.pl"; + + # OS-Sensitive defaults + if ($^O eq 'MSWin32') { + $schedule2sql = "schedule2sql.pl"; + } else { + $schedule2sql = "./schedule2sql.pl"; + } + + $defaultshowslots = 30; + $defaultshowhours = 3; + + $defaultreplaytv = ""; + $defaultrefreshinterval = -1; + $rtv_snapshotpath = "."; + + $newwindow = 0; + $usingapache = 0; + $showchannelicons = 0; + $channelicondir = ""; + + $showheaderrows = 0; + $searchfutureonly = 0; + $showbuttonicons = 0; + $showpdaformat = 0; + + $showrtvicons = 1; + $showrtvtext = 1; + $showrtvthemes = 1; + + $allowtitleedit = 0; + $skipversioncheck= 0; + $showschedulebar = 0; + + $rtv_updatesleepseconds = 0; + $rtv_allowdelete = 0; + + + $primetime_start = 20; + $todooption = 0; + $todofromstart = 0; + + $grid_end_overlap = 15; + $grid_leeway_second = 300; + + # Default show colors: past, present, future + @color_show = ( "#C0C0C0", "#F0F0F0", "#FFFFFF" ); + @color_scheduled = ( "#A0C0A0", "#B0F0B0", "#D0FFD0" ); + @color_conflict = ( "#C0A0A0", "#F0B0B0", "#FFD0D0" ); + @color_theme = ( "#C0C0CF", "#D0D0DF", "#E0E0FF" ); + @color_theme_conflict = ( "#C0C060", "#F0F090", "#FFFFB0" ); + $color_background = "#FFFFFF"; + $color_text = "#000000"; + $color_visitedlink = "#0000A0"; + $color_activelink = "#0000FF"; + $color_link = "#0000D0"; + $color_channelbackground = "#F0F0F0"; + $color_channeltext = "#000000"; + $color_headingbackground = "#E0E0E0"; + $color_headingtext = "#000000"; + + $pda_list = "NONE"; + $allow_list = "ALL"; + + $font_title = "Times New Roman"; + $font_heading = "Times New Roman"; + $font_menu = "Times New Roman"; + $font_listings = "Times New Roman"; + $font_detail = "Times New Roman"; + $font_channel = "Terminal"; + + $icon_refresh = ""; + $icon_now = ""; + $icon_go = ""; + $icon_all = ""; + $icon_prevwindow = ""; + $icon_nextwindow = ""; + $icon_prevchan = ""; + $icon_nextchan = ""; + $icon_find = ""; + $icon_select = ""; + $icon_schedule = ""; + $icon_done = ""; + + $image_stereo = ""; + $image_repeat = ""; + $image_cc = ""; + + $image_tvg = ""; + $image_tvpg = ""; + $image_tv14 = ""; + $image_tvy = ""; + $image_tvy7 = ""; + $image_tvma = ""; + + $image_mpaag = ""; + $image_mpaapg = ""; + $image_mpaapg13 = ""; + $image_mpaar = ""; + $image_mpaanc17 = ""; + $image_mpaanr = ""; + + $default_mode = "now"; + + #------------------------------------------------------------------- + # read config + #------------------------------------------------------------------- + + $retcode = getConfig($configfile); # &getConfig; would work too + + return $retcode; +} + diff --git a/rg_common.pl b/rg_common.pl new file mode 100644 index 0000000..23bc5d0 --- /dev/null +++ b/rg_common.pl @@ -0,0 +1,1861 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson <thompsonl@logh.net> +# with bits by Kanji T. Bates +# $Id: rg_common.pl,v 1.4 2003/07/23 03:03:11 pvanbaren Exp $ +# +# COMMON FUNCTIONS +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +use Time::Local; + +my $_version = "Personal ReplayGuide|Common Function Library|1|1|223|Lee Thompson,Kanji T. Bates"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} + +$prg_module{$module_name} = $_version; + + +#----------------------------------------------------------------- +sub converttext { + # + # Convert Text to HexStrings + # + # Parameters: Text String, Size of String (Bytes) + # + # Returns: Hex Encoded String with Zero Fills + # + #--------------------------------------------------------- + + my $ascii = shift; + my $size = shift; + my $retvalue = ""; + my $char = ""; + + $flen = $size; + $fpos = 0; + + do { + $char = ord substr($ascii,$fpos,1); + $retvalue .= converthex($char,2); + + $fpos++; + + } while ($fpos < $flen); + + return $retvalue; + +} + +#----------------------------------------------------------------- +sub decodehex { + # + # Convert HexString to Binary ASCII + # + # Parameters: Hex String (terminates at a null or at character x if given) + # + # Returns: Binary Data + # + #--------------------------------------------------------- + + my $hexstring = shift; + my $stopat = int shift; + my $binarystring = ""; + + my $fpos = 0; + my $flen = length($hexstring); + my $stoponnull = 1; + + if ($stopat > 0) { + $flen = $stopat; + $stoponnull = 0; + } + + my $blen = int($flen / 2); + + + my $hexvalue = ""; + my $value = ""; + my $binvalue = ""; + + do { + $hexvalue = substr($hexstring,$fpos,2); + + $value = hex $hexvalue; + $binvalue = pack("C",$value); + + $binarystring .= $binvalue; + + $fpos++; + $fpos++; + + if ($stoponnull) { + if ($hexvalue eq "00") { + $fpos = $flen; + } + } + + } while ($fpos < $flen); + + return $binarystring; +} + +#----------------------------------------------------------------- +sub converthex { + # + # Convert Values to HexString + # + # Parameters: Decimal Value, Number of Bytes + # + # Returns: Hex Encoded String + # + #--------------------------------------------------------- + + my $value = int shift; + my $size = int shift; + my $hexvalue = ""; + + $hexvalue = uc sprintf("%x",$value); + + if ($size == 1) { + $hexvalue = uc sprintf("%01x",$value); + } + + if ($size == 2) { + $hexvalue = uc sprintf("%02x",$value); + } + + if ($size == 4) { + $hexvalue = uc sprintf("%04x",$value); + } + + if ($size == 8) { + $hexvalue = uc sprintf("%08x",$value); + } + + if ($size == 16) { + $hexvalue = uc sprintf("%016x",$value); + } + + return $hexvalue; + +} + +#--------------------------------------------------------------------------------------- +sub converttohtml { + # + # Convert special characters to HTML + # + # Parameters: String + # Returns: String (Altered) + # + # ------------------------------------------------------------------------------ + + my $tempvar = shift; + + $tempvar =~ s/\&/\&/g; + $tempvar =~ s/\'/\'/g; + $tempvar =~ s/\"/\'/g; + $tempvar =~ s/\</\</g; + $tempvar =~ s/\>/\>/g; + + return $tempvar; + +} + +#--------------------------------------------------------------------------------------- +sub convertfromhtml { + # + # Convert special characters from HTML + # + # Parameters: String + # Returns: String (Altered) + # + # ------------------------------------------------------------------------------ + + my $tempvar = shift; + + $tempvar =~ s/\&/\&/g; + $tempvar =~ s/\'/\'/g; + $tempvar =~ s/\"/\"/g; + $tempvar =~ s/\</\</g; + $tempvar =~ s/\>/\>/g; + + return $tempvar; + +} + +#--------------------------------------------------------------------------------------- +sub renderhtml($) { + # + # Convert special characters from HTML + # + # Parameters: String + # Returns: String (Altered) + # + # ------------------------------------------------------------------------------ + + my $tempvar = shift; + + $tempvar =~ s/\'/\'/g; + + return $tempvar; + +} + +#--------------------------------------------------------------------------------------- +sub buildcommastring { + # + # Build comma delimited string + # + # Parameters: stringtoaddto + # addedvalue + # + # Returns: longer string + #---------------------------------------------------------------------- + + my $oldstring = shift; + my $newstring = shift; + + if ($newstring eq $null) { + return $oldstring; + } + + if ($oldstring ne $null) { + $oldstring .= ","; + } + + $newstring = $oldstring . $newstring; + + return $newstring; + +} + +#---------------------------------------------------------------------- +sub trimstring { + # + # Trim whitespace from a string (both ends) + # + # Parameters: String + # Returns: String (Altered) + # + # ------------------------------------------------------------------------------ + + my $tempvar = shift; + + $tempvar =~ s/^\s+//; + $tempvar =~ s/\s+$//; + + return $tempvar; + +} + + +#---------------------------------------------------------------------- +sub removedashes { + # + # Remove dashes from a string + # + # Parameters: String + # Returns: String (Altered) + # + # ------------------------------------------------------------------------------ + + my $tempvar = shift; + + $tempvar =~ s/-//g; + + return $tempvar; +} + + +#---------------------------------------------------------------------- +sub removeescapes { + # + # Remove HTML escapes from a string + # + # Parameters: String + # Returns: String (Altered) + # + # ------------------------------------------------------------------------------ + + my $tempvar = shift; + + $tempvar =~ s/%20/ /g; + + return $tempvar; +} + +#--------------------------------------------------------------------------------------- +sub as_hhmm { + # + # Show a Time As HH:MM AM/PM + # + # Parameters: epochseconds + # Returns: human readable string + # + # ------------------------------------------------------------------------------ + + my $string = as_time_string(shift); + my $hour = substr($string,8,2); + my $minute = substr($string,10,2); + my $pm = 0; + + $hour = int $hour; + + if ($hour > 11) { + $pm = 1; + $hour = $hour - 12; + } + + if ($hour == 0) { + $hour = 12; + } + + $string = "$hour:$minute "; + + if ($pm) { + $string .= "PM"; + }else{ + $string .= "AM"; + } + + return $string; +} + + + +#--------------------------------------------------------------------------------------- +sub as_ampm { + # + # Show an Hour As HH AM/PM + # + # Parameter: Hour (24 hour clock) + # Returns: String + # + # ------------------------------------------------------------------------------ + + my $hour = int shift; + my $pm = 0; + + if ($hour > 24) { + return; + } + + if ($hour < 0) { + return; + } + + + if ($hour > 11) { + $pm = 1; + $hour = $hour - 12; + } + + if ($hour == 0) { + $hour = 12; + } + + $string = sprintf("%02d",$hour); + $string .= ":00 "; + + if ($pm) { + $string .= "PM"; + }else{ + $string .= "AM"; + } + + return $string; +} + + +#--------------------------------------------------------------------------------------- +sub as_time_string { + # + # Converts epoch seconds to a time string (eg. 200403181942) + # + # Parameters: epoch seconds + # Returns: string + # + # ------------------------------------------------------------------------------ + + (my $seconds,my $minute,my $hour,my $day,my $month,my $year,my $wday,my $yday) = localtime(shift); + $year += 1900; + $month++; + + my $string = ""; + + $seconds = sprintf("%02d",$seconds); + $minute = sprintf("%02d",$minute); + $hour = sprintf("%02d",$hour); + $day = sprintf("%02d",$day); + $month = sprintf("%02d",$month); + $year = sprintf("%04d",$year); + + $string .= $year; + $string .= $month; + $string .= $day; + $string .= $hour; + $string .= $minute; + $string .= $seconds; + + return $string; +} + + +#--------------------------------------------------------------------------------------- +sub as_epoch_seconds { + # + # Converts a time string to epoch seconds + # + # Parameters: String + # Returns: EpochSeconds + # + # ------------------------------------------------------------------------------ + + my($Y,$M,$D,$h,$m,$s) = unpack 'A4 A2 A2 A2 A2 A2', shift; + + if (int $Y < 1970) { + return 0; + } + if ((int $M < 1) || (int $M > 12)) { + return 0; + } + if ((int $D < 1) || (int $D > 31)) { + return 0; + } + return timelocal( 0, $m, $h, $D, $M - 1, $Y - 1900 ); +} + +#--------------------------------------------------------------------------------------- +sub getMinutes { + # + # Returns the number of minutes between two epoch seconds. + # + # Parameters: start,end + # Returns: minutes + # + # ------------------------------------------------------------------------------ + + my $program_start = shift; + my $program_stop = shift; + my $minutes = 0; + + $minutes = (as_epoch_seconds($program_stop) - as_epoch_seconds($program_start)) / 60; + + return $minutes; +} + +#--------------------------------------------------------------------------------------- +sub addParameter { + # + # Add CGI Parameter + # + # Usage: addParameter(name,value) + # Returns: Adds to global $url_parms + # + # ------------------------------------------------------------------------------ + + my $parmname = uc shift; + my $parmvalue = shift; + + if ($parmname eq $null) { + writeDebug("Warning: addParameter: No name given."); + return 0; + } + + if ($parmvalue eq $null) { + writeDebug("Warning: addParameter: Value set to null for parameter '$parmname'"); + } + + #---------------------------------------------------------- + # if null, start with a ? otherwise add a & and our stuff + #---------------------------------------------------------- + + unless ( $url_parms =~ /[?&]$parmname=/ ) { + if ($url_parms eq $null) { + $url_parms = "\?$parmname=$parmvalue"; + }else{ + $url_parms .= "\&$parmname=$parmvalue"; + } + } + + return 1; + +} + +#--------------------------------------------------------------------------------------- +sub getParameter { + # + # Get CGI Parameter + # + # Usage: getParameter(name) + # Returns: Parameter or null + # + # ------------------------------------------------------------------------------ + + + my $parmname = uc shift; + my $parameter = $null; + my $parmvalue = $null; + + $parmvalue = param($parmname); + + ($junk,$parameter) = split(/=/,$parmvalue); + + if ($parameter eq $null) { + # if split was unsuccessful, revert. + $parameter = $parmvalue; + } + + if ($parameter eq $null) { + # if we still have nothing, try to just get the query + $parmvalue = $ENV{'QUERY_STRING'}; + + # attempt the split again + + ($junk,$parameter) = split(/=/,$parmvalue); + + if ($junk ne $parmname) { + # + # if it's not the right one, zero it. + $parameter = $null; + } + + + } + + return $parameter; + +} + +#--------------------------------------------------------------------------------------- +sub ShowHTTPHeader { + # + # Display HTTP Header + # + # Usage &ShowHTTPHeader or showHTTPHeader() + # + # ------------------------------------------------------------------------------ + + $htmlmode = 1; + + if (uc $ENV{PERL_SEND_HEADER} eq "ON") { + #----------------------------------- + # Apache with ModPerl, override conf + #----------------------------------- + + $supresshttpheader = 1; + $supresscontenttype = 1; + } + + if ($ENV{SERVER_SOFTWARE} =~ /Apache/i ) { + #----------------------------------- + # Apache + #----------------------------------- + + $supresshttpheader = 1; + } + + if (!$supresshttpheader) { + print "HTTP/1.0 200 OK\n"; + } + + if (!$supresscontenttype) { + print "Content-Type: text/html\n\n"; + } + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub ShowHTTPFooter { + + #------------------------------------------------------------------- + # Print the footer, if you want to add your own text at the bottom + # of every page, this is the place. + #------------------------------------------------------------------- + + if ($verbose eq "") { + my $verbose = 1; + } + + if ($htmlmode) { + print "</center>\n"; + print "</BODY></HTML>\n"; + }else{ + if ($verbose) { + print "\n"; + } + } + + $htmlmode = 0; + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub getPathAndFile { + # + # Parameters: Pathname + # Returns; Path,File + # + # ------------------------------------------------------------------------------ + + my $pathname = shift; + my @data = ""; + my $dataline = ""; + my $path = ""; + my $filename = ""; + my $count = 0; + + if ($pathname eq "") { + return; + } + + if ($pathname =~ /\// ) { + (@data) = split(/\//,$pathname); + } + + if ($pathname =~ /\\/ ) { + (@data) = split(/\\/,$pathname); + } + + $count = countElements(@data); + + if ($count) { + my $ctr = 0; + $filename = $data[$count]; + foreach $dataline ( @data ) { + $ctr++; + if ($ctr <= $count) { + if ($ctr > 1) { + $path .= "/"; + } + $path .= $dataline; + } + } + }else{ + $filename = $pathname; + } + + + if ($path eq "") { + $path = "."; + } + + return ($path,$filename); + +} + +#--------------------------------------------------------------------------------------- +sub abend { + # + # Used for Abnormal Termination + # Text reason is the only parameter. + # + # NOTE: It will NOT return from this function! + # + # ------------------------------------------------------------------------------ + + my $outputtext = shift; + (my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); + + displayText($outputtext); + writeLogFile("********************************************************"); + if ($outputtext =~ /\n/) { + foreach my $outtext ( split(/\n/, $outputtext ) ) { + writeLogFile("***** " . convertfromhtml($outtext)); + } + }else{ + writeLogFile("***** " . convertfromhtml($outputtext)); + } + + writeLogFile("***** Program Abend: $debug_filename at $debug_line"); + + if ($htmlmode) { + print "<p><B>Program terminated due to fatal error or condition.</B>"; + }else{ + print "\nProgram terminated due to fatal error or condition.\n"; + } + + if ($htmlmode) { + print "<PRE>***** Execute halted for $debug_filename at $debug_line</PRE><p>"; + print "</BODY></HTML>\n"; + }else{ + print "***** Execute halted for $debug_filename at $debug_line\n"; + } + + writeDebug("********************************************************"); + + exit(0); +} + +#--------------------------------------------------------------------------------------- +sub displayHeading { + # + # Display Heading (Wrapper for DisplayText) + # + # Parameters: Text, [Mode] + # + # Modes: 0 Normal, 1 Debug, 2 Literal Debug + # + # ------------------------------------------------------------------------------ + + my $outputtext = shift; + my $debugmode = int shift; + my $printstring = ""; + + if ($size_section eq "") { + $size_section = "<H2>"; + } + + if ($htmlmode) { + print "<$size_section>"; + if ($font_title ne "") { + print "<font face=\"$font_title\">"; + } + displayText($outputtext,$debugmode); + print "</$size_section>"; + print "<p>"; + if ($font_title ne "") { + print "</font>"; + } + + }else{ + displayText($outputtext,$debugmode); + } + + return; +} + +#--------------------------------------------------------------------------------------- +sub displayText { + # + # Display Text + # + # Parameters: Text[,Mode][,No \n] + # + # Modes: 0 Normal, 1 Debug, 2 Literal Debug + # + # ------------------------------------------------------------------------------ + + my $outputtext = shift; + my $debugmode = int shift; + my $nocrlf = int shift; + my $printstring = ""; + + if ($htmlmode) { + if ($debugmode) { + if ($debugmode == 1) { + $printstring = "<PRE>DEBUG:: $outputtext</PRE>"; + } + if ($debugmode == 2) { + $printstring = "<PRE>$outputtext</PRE>"; + } + }else{ + if ($nocrlf) { + $printstring = $outputtext; + }else{ + $printstring = $outputtext . "\n"; + $printstring = converttohtml($outputtext); + $printstring =~ s/\r//g; # Eat LF + $printstring =~ s/\n/<br>/g; # Convert CR to Paragraph + } + } + }else{ + if ($debugmode) { + if ($debugmode == 1) { + $printstring = "DEBUG:: $outputtext"; + } + if ($debugmode == 2) { + $printstring = "$outputtext"; + } + }else{ + $printstring = $outputtext; + } + + } + + + if ($nocrlf) { + $printstring =~ s/\r//g; + $printstring =~ s/\n//g; + + print "$printstring"; + }else{ + print "$printstring\n"; + } + + return; + +} + + +#---------------------------------------------------- +sub selectMonth{ + # + # Display an HTML FORM SELECT range for Month + # + # + # Parameter: month (numeric) + # + # ------------------------------------------------------------------------------ + + my $current_month = int shift; + my $ctr = 1; + + do { + print "<option value=\"$ctr\""; + if ($ctr == $current_month) { + print " selected"; + } + print ">"; + if ($ctr == 1) { + print "Jan"; + } + if ($ctr == 2) { + print "Feb"; + } + if ($ctr == 3) { + print "Mar"; + } + if ($ctr == 4) { + print "Apr"; + } + if ($ctr == 5) { + print "May"; + } + if ($ctr == 6) { + print "Jun"; + } + if ($ctr == 7) { + print "Jul"; + } + if ($ctr == 8) { + print "Aug"; + } + if ($ctr == 9) { + print "Sep"; + } + if ($ctr == 10) { + print "Oct"; + } + if ($ctr == 11) { + print "Nov"; + } + if ($ctr == 12) { + print "Dec"; + } + print "</option>\n"; + $ctr++; + } while ($ctr < 13); + + return; +} + +#---------------------------------------------------- +sub selectDay { + # + # HTML FORM SELECT for Days - wrapper for selectNumbers + # + # Parameters: current day + # maximum day + # + # ------------------------------------------------------------------------------ + + my $current_day = int shift; + my $maximum_day = int shift; + + selectNumbers($current_day,$maximum_day+1,1); + + return; +} + +#---------------------------------------------------- +sub selectYear { + # + # Display a Year HTML FORM SELECT + # + # Parameters: current year + # maximum year (-1) + # + # ------------------------------------------------------------------------------ + + my $current_year = int shift; + my $maximum_year = int shift; + my $ctr = $current_year; + + do { + print "<option value=\"$ctr\""; + if ($ctr == $current_year) { + print " selected"; + } + print ">"; + print $ctr; + print "</option>\n"; + $ctr++; + } while ($ctr < $maximum_year); + + return; + +} + +#---------------------------------------------------- +sub selectNumbers { + # + # Display an HTML SELECT for a range of numbers + # + # Parameters: current number (selected) + # maximum number (-1) + # start number + # + # ------------------------------------------------------------------------------ + + my $current_number = int shift; + my $maximum_number = int shift; + my $start_number = int shift; + + my $ctr = $start_number; + + do { + print "<option value=\"$ctr\""; + if ($ctr == $current_number) { + print " selected"; + } + print ">"; + printf "%2d",$ctr; + print "</option>\n"; + $ctr++; + } while ($ctr < $maximum_number); + + return; + +} + +#---------------------------------------------------- +sub daysInMonth { + # + # Determine the Number of Days in a Month + # Parameters: Year, Month + # Returns: Days + # + # ------------------------------------------------------------------------------ + + my $year = int shift; + my $month = int shift; + + if ($year < 1970) { + return 0; + } + + if (($month < 1) || ($month > 12)) { + return 0; + } + + $year -= 1900; + $year += 1 unless $month %= 12; + my $date = timelocal( 0, 0, 12, 1, $month, $year ); + my $days = ( localtime( $date - 86_400 ) )[3]; + return $days; +} + +#---------------------------------------------------- +sub displaytime { + # + # Display the Time in a Human Format + # + # Parameter: Time String + # Returns; Display String + # + # ------------------------------------------------------------------------------ + + my $timestring = shift; + my $dsp_string = ""; + + + $dsp_string = substr($timestring,4,2) . "/" . substr($timestring,6,2) . "/" . substr($timestring,0,4) . " "; + $dsp_string .= as_hhmm(as_epoch_seconds($timestring)); + + return $dsp_string; +} + + +#---------------------------------------------------- +sub countElements { + # + # Counts the number of entries in an array + # delimited array. + # + # Parameters: Array + # Returns: Number of Elements + # + # ------------------------------------------------------------------------------ + + my $ctr = 0; + my $aref = ""; + + foreach $aref ( @_ ) { + $ctr++; + } + + return ($ctr-1); +} + +#---------------------------------------------------- +sub countArray { + # + # Counts the number of entries in a comma + # delimited array. + # + # Parameters: Array[,Delimiter] + # Returns: Number of Elements + # + # ------------------------------------------------------------------------------ + + my $carray = shift; + my $cdelimiter = shift; + my $ctr = 0; + + if (length($cdelimiter) < 1) { + $cdelimiter = ","; + } + + for ( split /$cdelimiter/, $carray ) { + $ctr++; + } + + return $ctr; +} + +#---------------------------------------------------- +sub hasAccess { + # + # Determines what rights a connecting IP has + # + # Parameter: IP Address + # Usage: hasAccess(IP Address) + # Returns TRUE or FALSE + # + # ------------------------------------------------------------------------------ + + my $testaddress = shift; + my $returncode = 0; + + if ($allow_list eq "ALL") { + $returncode = 1; + } + + if ($allow_list eq "NONE") { + $returncode = 0; + } + + for ( split /,/, $allow_list ) { + /,/; + if ($testaddress eq $_) { + $returncode = 1; + } + } + + return $returncode; +} + +#---------------------------------------------------- +sub isPDA { + # + # Determines if the remote address is a PDA + # + # Parameter: IP Address + # + # Usage: isPDA(IP Address) + # + # Returns TRUE or FALSE + # + # ------------------------------------------------------------------------------ + + my $testaddress = shift; + my $returncode = 0; + + if ($pda_list eq "ALL") { + $returncode = 1; + } + + if ($pda_list eq "NONE") { + $returncode = 0; + } + + for ( split /,/, $pda_list ) { + /,/; + if ($testaddress eq $_) { + $returncode = 1; + } + } + + return $returncode; +} + +#--------------------------------------------------------------------------------------- +sub identifyLoadedModules { + # + # Writes loaded modules to output + # + # Parameter (optional): New module to id + # (use &identifyLoadedModules or identifyLoadedModules() if not identifying a new + # mod + # + #------------------------------------------------------------------------------- + + my $newmodule = shift; + my $moduledata = $null; + my $modulename = $null; + my $currentrec = $null; + my $prevname = $null; + my $authorlist = $null; + my $text = $null; + my $flag = 0; + + foreach $currentrec (%prg_module) { + if ($currentrec =~ /\|/) { + $moduledata = $currentrec; + if ($flag) { + $flag = 2; + $prevname = $modulename; + + } + }else{ + if ($prevname ne $currentrec) { + $modulename = $currentrec; + $flag = 1; + } + } + + if ($flag == 2) { + if (length($newmodule) > 0) { + if ($newmodule ne $modulename) { + $flag = 0; + } + } + } + + if ($flag == 2) { + + + (my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($moduledata); + $authorlist = ""; + for ( split /,/, $authors ) { + /,/; + $authorlist = buildcommastring($authorlist,$_); + } + if ($modulename =~ /\.pl/ ) { + ($modulename,$text) = split(/\.pl/, $modulename, 2); + } + writeDebug("$modulename v$major.$minor build $build ($desc) loaded."); + } + + + + } +} + + +#--------------------------------------------------------------------------------------- +sub parseModuleData { + # + # Parse Module Data + # + # Parameter: module datastring + # + # Returns $parent,$desc,$major,$minor,$build,$authors + # ------------------------------------------------------------------------------ + + my $moduledata = shift; + + (my $parent,my $desc,my $major,my $minor,my $build,my $authors) = split(/\|/, $moduledata, 6); + + return ($parent,$desc,$major,$minor,$build,$authors); + +} + + +#--------------------------------------------------------------------------------------- +sub buildMultiWordList { + # + # buildMultiWordList + # + # + # Parameter: Text (comma delimited) + # Returns: nice text like "Word, Word, Word and Word." + # ------------------------------------------------------------------------------ + + my $authorstring = ""; + my $liststring = shift; + my $wordcount = countArray($liststring); + my $ctr = 0; + + if ($wordcount < 2) { + return $liststring; + } + + for ( split /,/, $liststring ) { + /,/; + my $wordtext = $_; + $ctr++; + if (($ctr > 1) && ($ctr < $wordcount)) { + $authorstring .= ", "; + } + if ($ctr == $wordcount) { + $authorstring .= " and "; + } + $authorstring .= $wordtext; + } + + return $authorstring; +} + +#--------------------------------------------------------------------------------------- +sub writeDebug { + # + # Write Debug Message + # + # + # Parameter: Text + # no CRLF flag (optional) + # Force Modulename (optional) + # + # Usage: WriteDebug (Message[,module]) + # + # Returns nothing. (NOTE: If debug is off, regular non debug text is given + # instead) + # + # Module is ignored if debug is off. + # + # ------------------------------------------------------------------------------ + + my $debug_message = shift; + my $nocrlf = int shift; + my $debug_module = shift; + my $debug_subroutine = $null; + my $debug_package = $null; + my $debug_filename = $null; + my $debug_line = $null; + my $debug_hasargs = $null; + my $debug_wantarray = $null; + my $debug_evaltext = $null; + my $debug_isrequire = $null; + my $debug_outputtext = $null; + my $text = ""; + my $debug_marker = "|"; + + if ($debug < 1) { + writeOutput($debug_message,$nocrlf); + return 1; + } + + ($debug_package, $debug_filename, $debug_line, $debug_subroutine, $debug_hasargs, $debug_wantarray, $debug_evaltext, $debug_isrequire) = caller(0); + my $debug_sectionname = $debug_filename; + + if ($debug_filename =~ /\.pl/ ) { + ($debug_sectionname,$text) = split(/\.pl/, $debug_filename, 2); + } + + if ($debug_sectionname eq $null ) { + $debug_sectionname = $debug_filename; + } + + if ($debug_message eq $null) { + $debug_message = "MARKER"; + } + + if (($debug_line eq $null) || ($debug_subroutine eq $null)) { + ($debug_package, $debug_filename, $debug_line, $debug_subroutine, $debug_hasargs, $debug_wantarray, $debug_evaltext, $debug_isrequire) = caller(0); + $debug_subroutine = $debug_module; + if ($debug_filename =~ /\.pl/ ) { + ($debug_sectionname,$text) = split(/\.pl/, $debug_filename, 2); + } + if ($debug_sectionname eq $null ) { + $debug_sectionname = $debug_filename; + } + if ($debug_subroutine eq $null ) { + $debug_subroutine = $debug_sectionname; + } + } + + $debug_outputtext = "DEBUG|$debug_subroutine:$debug_line\:\:$debug_message"; + + writeOutput($debug_outputtext,$nocrlf); + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub writeOutput { + # + # Write to STDOUT (if defined) *AND* Log file (if defined) + # + # If verbose is 0 and log_pathname isn't defined, you won't see a damn thing. + # If verbose is undefined it will be forced on + # + # Parameter text to write with optional nocrlf flag to the STDOUT display + # + # Always returns true. + # + #--------------------------------------------------------------------------------------- + + my $outputtext = shift; + my $nocrlf = int shift; + + if ($verbose eq $null) { + writeLogFile("Warning: Verbose was undefined."); + my $verbose = 1; + + } + + if (($verbose) && (length($outputtext) > 0)) { + displayText($outputtext,$debug,$nocrlf); + } + writeLogFile($outputtext); + + return 1; +} + + +#--------------------------------------------------------------------------------------- +sub writeLogFile { + # + # Write to Log file + # + # (This is now a wrapper for updateLogFile which adds the ability to process \n 's + # properly.) + # + # Parameter text to write + # Always returns true. + # + #--------------------------------------------------------------------------------------- + + my $outputtext = shift; + + if (length($log_pathname) < 1) { + return 1; + } + + $outputtext =~ s/\r//g; + + if ($outputtext =~ /\n/) { + (my @outputlines) = split(/\n/,$outputtext); + + foreach $outputtext ( @outputlines ) { + $outputtext =~ s/\n//g; + updateLogFile($outputtext); + } + }else{ + updateLogFile($outputtext); + } + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub updateLogFile { + # + # update the log file + # + # Parameters: filename + # output buffer + # + #--------------------------------------------------------------------------------------- + + my $outputtext = shift; + + if (length($log_pathname) < 1) { + return 1; + } + + if (length($outputtext) < 1 ) { + return 1; + } + + my $module = ""; + + if ($log_module_name) { + (my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + if ($path eq "") { + $basename = $script_pathname; + } + + ($module,my $junk) = split(/\.pl/,$basename); + $module .= "\:\:"; + } + + my $log_time = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + + if (open(HDEBUGFILE, ">>$log_pathname")) { + print HDEBUGFILE "$log_time $module$outputtext\n"; + close(HDEBUGFILE); + } + +} + + +#--------------------------------------------------------------------------------------- +sub dumpFile { + # + # dump a File + # + # Parameters: filename + # output buffer + # filemode (optional) - if 1 output is binary, default is 0 (Text) + # + # + # Usage: dumpFile(filename,content) + # Returns true if successful + # + # (This is primarily for debugging purposes.) + # + #--------------------------------------------------------------------------------------- + + my $filename = shift; + my $outputtext = shift; + my $filemode = int shift; + + if (length($filename) < 1) { + return 1; + } + + if (length($outputtext) < 1) { + return 1; + } + + if (open(HDEBUGFILE, ">>$filename")) { + if ($filemode) { + binmode HDEBUGFILE; + print HDEBUGFILE $outputtext; + }else{ + print HDEBUGFILE "$outputtext\n"; + } + close(HDEBUGFILE); + return 1; + }else{ + return 0; + } + + return 0; + +} + + +#--------------------------------------------------------------------------------------- +sub getRunningTime { + # + # Get Running Time + # + # Usage: getRunningTime(minutes[,format]) + # Returns: 0 if failed + # + # ------------------------------------------------------------------------------ + + + my $minutes = int shift; + my $format = int shift; + + my $ret = ""; + + if ($minutes < 0) { + return 0; + } + + my $hours = int $minutes / 60; + my $remminutes = $minutes - (int $hours * 60); + + if ($hours) { + if ($format == 0) { + $ret .= $hours; + } + if ($format == 1) { + if ($hours > 1) { + $ret .= "$hours hours"; + }else{ + $ret .= "$hours hour"; + } + } + + } + + if ($format == 0) { + $ret .= ":"; + } + + if ($format == 0) { + $ret .= sprintf("%02d",$remminutes); + } + + if ($format == 1) { + if ($remminutes > 0) { + $ret .= " $remminutes"; + + if ($remminutes == 1) { + $ret .= " minute"; + }else{ + $ret .= " minutes"; + } + } + } + + + return $ret; + +} + +#--------------------------------------------------------------------------------------- +sub doTimesOverlap($$$$) { + # + # Do Times Overlap + # + # Parameters: start time (A), end time (A), start time (B), end time (B) + # Returns true if they overlap + # + # ------------------------------------------------------------------------------ + + my $a_start = int shift; + my $a_end = int shift; + my $b_start = int shift; + my $b_end = int shift; + + if (($a_start == $b_start) && ($a_end == $b_end)) { + return 1; + } + + if ($a_start == $b_start) { + return 1; + } + + for my $time ( $a_start, $a_end ) { + return 1 if $time > $b_start && $time < $b_end; + } + return 0; +} + +#--------------------------------------------------------------------------------------- +sub resolveHostname { + # + # Resolve a hostname to an IP string (X.X.X.X) + # + # Usage: resolve_hostname(string) + # + # Returns: IP address + # + # ------------------------------------------------------------------------------ + + my $ipaddress = ""; + + (my $a,my $b,my $c,my $d) = unpack('C4',gethostbyname(shift)); + $ipaddress = "$a.$b.$c.$d"; + + if (is_ipaddress($ipaddress)) { + return $ipaddress; + }else{ + return; + } +} + +#--------------------------------------------------------------------------------------- +sub isIPAddress { + # + # Is this an IP address? + # + # Usage: isIPAddress(string) + # + # Returns: True (1) or False (0) + # + # ------------------------------------------------------------------------------ + + my $retcode = 0; + my $fail = 0; + my $ctr = 0; + my @iparray = split(/\./, shift); + + foreach my $octet ( @iparray ) { + if ($octet =~ /^-?\d+$/) { + }else{ + $fail = 1; + } + if (($octet < 0) || ($octet > 255)) { + $fail = 1; + } + $ctr++; + } + + if ($ctr != 4) { + $fail = 1; + } + + if ($fail) { + $retcode = 0; + }else{ + $retcode = 1; + } + + return $retcode; + +} + + +#---------------------------------------------------- +sub showImage { + # + # Show Image + # + # Parameters: ImageName[,Dir,ALT,Align,Width,Height] + # + # Optional: + # Directory (uses $imagedir if not included) + # Alignment + # Width + # Height + # Alt Tag + # + # Outputs img src to STDOUT + # + # ------------------------------------------------------------------------------ + + my $img_name = shift; + my $img_dir = shift; + my $img_alt = shift; + my $img_align = shift; + my $img_width = int shift; + my $img_height = int shift; + my $null = ""; + + my $img_src = buildImage($img_name,$img_dir,$img_alt,$img_align,$img_width,$img_height); + + + if ($img_src eq $null) { + return 0; + } + + print $img_src; + + return 1; +} + +#---------------------------------------------------- +sub buildImage { + # + # Build Image + # + # This will build img src code but with awareness of remote (http://) graphics. + # + # Parameters: ImageName[,Dir,ALT,Align,Width,Height] + # + # Optional: + # Directory (uses $imagedir if not included) + # Alt Tag + # Alignment + # Width + # Height + # + # Returns <img src string. + # + # ------------------------------------------------------------------------------ + + my $img_name = shift; + my $img_dir = shift; + my $img_alt = shift; + my $img_align = shift; + my $img_width = int shift; + my $img_height = int shift; + + my $img_src = $null; + + if (length($img_name) < 1) { + return $img_src; + } + + if (length($img_dir) < 1) { + $img_dir = $imagedir; + } + + if ($img_name =~ "http://") { + $img_dir = ""; + } + + $img_src = "<img "; + + if (length($img_align) > 0) { + $img_src .= "align=$img_align "; + } + + $img_src .= "src=\""; + + if (length($img_dir) > 0) { + $img_src .= "$img_dir/"; + } + + $img_src .= "$img_name"; + + $img_src .= "\" "; + + if ($img_width > 0) { + $img_src .= "width=$img_width "; + } + + if ($img_height > 0) { + $img_src .= "height=$img_height "; + } + + if (length($img_alt) > 0) { + $img_src .= "ALT=\"$img_alt\" "; + } + + $img_src .= ">"; + + return $img_src; +} + +#--------------------------------------------------------------------------------------- +sub fileExists { + my $pathname = shift; + my $retcode = 0; + + if (open(HANDLE, "$pathname")) { + $retcode = 1; + }else{ + $retcode = 0; + } + + return $retcode; + +} + +#--------------------------------------------------------------------------------------- +sub InitializeDisplay { + # + # Display HTTP Header and Banner + # + #------------------------------------------------------------------- + + #------------------------------------------------------------------- + # Set up some defaults just in case something bad happens + #------------------------------------------------------------------- + + if ($color_background eq $null) { + $color_background = "\#FFFFFF"; + } + + if ($color_text eq $null) { + $color_text = "\#000000"; + } + + if ($color_visitedlink eq $null) { + $color_visitedlink = "\#000040"; + } + + if ($color_activelink eq $null) { + $color_activelink = "\#0000FF"; + } + + if ($color_link eq $null) { + $color_link = "\#00009F"; + } + + if ($showpdaformat) { + $size_title = "H5"; + $size_section = "H6"; + $size_subsection = "H4"; + }else{ + $size_title = "H2"; + $size_section = "H2"; + $size_subsection = "H3"; + } + + &ShowHTTPHeader; + print "<HTML>\n<HEAD>\n"; + print "<meta http-equiv=\"Pragma\" content=\"no-cache\">\n"; + print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n"; + if ((uc $program_module eq "MAIN") || (length($program_module) < 1)) { + print "<TITLE>$program_title\n"; + }else{ + print "$program_title:$program_module\n"; + } + print "\n\n"; + + #------------------------------------------------------------------------------------------- + # Prepare Titles + #------------------------------------------------------------------------------------------- + + if ((uc $program_module eq "MAIN") || (length($program_module) < 1)) { + $program_hdr = "<$size_title>$program_title v$program_version (Build $program_build)<$size_subsection>by $program_author

\n"; + }else{ + $program_hdr = "<$size_title>$program_title:$program_module v$program_version (Build $program_build)<$size_subsection>by $program_author

\n"; + } + + if (length($image_logo) > 0) { + if ($showpdaformat) { + showImage($image_logo); + }else{ + showImage($image_logo); + } + } + + print $program_hdr; + + +} + +1; diff --git a/rg_config.pl b/rg_config.pl new file mode 100644 index 0000000..1dec95c --- /dev/null +++ b/rg_config.pl @@ -0,0 +1,2353 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# Configuration Library +# by Lee Thompson +# with bits by Philip Van Baren, Kanji T. Bates and Kevin J. Moye +# +# CONFIGURATION FUNCTIONS +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#------------------------------------------------------------------------------------ + +my $_version = "Personal ReplayGuide|Configuration Function Library|1|0|26|Lee Thompson,Philip Van Baren,Kanji T. Bates,Kevin J. Moye"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} + +$prg_module{$module_name} = $_version; + + +#------------------------------------------------------------------------------------ +# NOTE: Configuration Values are the only Global variables defined in this. +#------------------------------------------------------------------------------------ +# Variables local to rg_config +#------------------------------------------------------------------------------------ + +my $configfile = "prg.conf"; # master configuration file +my $configpath = ""; # configuration path +my $s_replayguide = 0; # look in replayguide +my $s_xmltv2sql = 0; # look in xmltv2sql +my $s_datadirect = 0; # look in datadirect +my $s_xmltv = 0; # look in xmltv +my $s_datadirect2sql = 0; # look in datadirect2sql +my $s_schd2sql = 0; # look in schd2sql +my $s_database = 0; # look in database +my $s_geticons = 0; # look in geticons +my $s_global = 1; # always read global section +my $s_global_priority = 1; # set to 0 to allow sections to override globals +my $null = ""; # handy +my $do_downgrade_search = 1; # downgrade to individual .conf files if section or + # master file cannot be found. +my $allowinlinecomments_1 = 1; # Allow inline comments (like this one) +my $allowinlinecomments_2 = 1; # NOTE: The comment sequence cannot be doubled up! Like +my $allowinlinecomments_3 = 1; # ## or it will not see it as a comment. # Blah # is ok. + # + # If you need to, disable with allowinlinecomment_N to 0. + # + # allowinlinecomments_1 allows # inline comments + # allowinlinecomments_2 allows // inline comments + # allowinlinecomments_3 allows ; inline comments + +my $specialdebug = 0; # special debug +my $option = ""; # init local +my $parameter = ""; # init local +my $iscomment = 0; # init local + + +if (length($ENV{PRG_CONFPATH}) > 0) { + $configpath = $ENV{PRG_CONFPATH}; +} + + +#------------------------------------------------------------------------------------ +sub getConfig { + # Parameters: section to look for + # ignore global (optional) + # specific value (optional) + # + # getConfig(Section) eg. getConfig($configfile) will usually work + # (the .conf suffix will be removed) + # + # eg. getConfig("replayguide",1,"logfile") would load the log_pathname + # variable from the replayguide section. Nothing else will be loaded or + # updated. + # + # if the section is the same as the perl script + # minus the suffix you can also do + # getConfig($0) + # + # Returns a bitmask 1 File Opened + # 2 Globals Read + # 4 Section Read as Requested + # + # So a 7 is 'all successful'. + # + #---------------------------------------------------------------------------- + + my $section = shift; # look for this section + my $noglobal = shift; # No global + my $specificvalue = shift; # Specific Value + + my $specialdebug = 0; # Special Debug Crap + my $retcode = 0; # return code + + if ($specialdebug ) { + print "getConfig::Starting\n"; + print "getConfig::parameters are section: \"$section\", noglobal: \"$noglobal\", specificvalue: \"$specificvalue\"\n"; + } + + if ($section eq $null) { + if ($specialdebug ) { + print "getConfig::section is null, using calling script name ($script_pathname)\n"; + } + + $section = $script_pathname; + } + + #------------------------------------------------------------------- + # Determine What Section to Read + #------------------------------------------------------------------- + + $sectionsearch = $section; + + if ($specialdebug ) { + print "getConfig::section: \"$section\", s_global: \"$s_global\"\n"; + } + + + if ($specialdebug ) { + print "getConfig::checking \"$section\" for .conf\n"; + } + + if ($sectionsearch =~ /\.conf/ ) { + ($sectionsearch,$text) = split(/\.conf/, $section, 2); + if ($specialdebug ) { + print "getConfig::split $sectionsearch,$text\n"; + } + + } + + if ($specialdebug ) { + print "getConfig::checking \"$section\" for .pl\n"; + } + + if ($sectionsearch =~ /\.pl/ ) { + ($sectionsearch,$text) = split(/\.pl/, $section, 2); + if ($specialdebug ) { + print "getConfig::split $sectionsearch,$text\n"; + } + } + + + if ($specialdebug ) { + print "getConfig::checking \"$section\" for .exe\n"; + } + + if ($sectionsearch =~ /\.exe/ ) { + ($sectionsearch,$text) = split(/\.exe/, $section, 2); + if ($specialdebug ) { + print "getConfig::split $sectionsearch,$text\n"; + } + } + + if ($specialdebug ) { + print "getConfig::section search for \"$sectionsearch\"\n"; + } + + if (length($noglobal) > 0) { + $s_global = 0; + if ($specialdebug ) { + print "getConfig::global search is disabled\n"; + } + } + + + if (length($specificvalue) > 0) { + $valuesearch = $specificvalue; + if ($specialdebug ) { + print "getConfig::looking for specific value \"$valuesearch\"\n"; + } + } + + #---------------------------------------------------- + # Make sure if the script name is passed in we look + # for the right thing + #---------------------------------------------------- + + if ($specialdebug ) { + print "getConfig::translating script names to section names\n"; + } + + if (uc $sectionsearch eq 'GETCHANNELICONS') { + $sectionsearch = "geticons"; + } + if (uc $sectionsearch eq 'DATADIRECT_CLIENT') { + $sectionsearch = "datadirect"; + } + + if (uc $sectionsearch eq 'SCHEDULE2SQL') { + $sectionsearch = "SCHD2SQL"; + } + + if (uc $sectionsearch eq 'RG_INFO') { + $sectionsearch = "DATABASE"; + } + + if ($specialdebug ) { + print "getConfig::$section->$sectionsearch\n"; + } + + if (uc $sectionsearch eq 'GLOBAL') { + $sectionsearch = ""; + $s_global = 1; + $do_downgrade_search = 0; + if ($specialdebug ) { + print "getConfig::doing global only search. global enabled, downgrade disabled, section nulled\n"; + } + } + + + + #---------------------------------------------------- + # Raise Flags + #---------------------------------------------------- + + if ($specialdebug ) { + print "getConfig::raising flags\n"; + } + + if (uc $sectionsearch eq 'REPLAYGUIDE') { + $s_replayguide = 1; + } + + if (uc $sectionsearch eq 'XMLTV2SQL') { + $s_xmltv2sql = 1; + } + + + if (uc $sectionsearch eq 'XMLTV') { + $s_xmltv = 1; + } + + if (uc $sectionsearch eq 'DATADIRECT') { + $s_datadirect = 1; + } + + if (uc $sectionsearch eq 'DATADIRECT2SQL') { + $s_datadirect2sql = 1; + } + + if (uc $sectionsearch eq 'SCHD2SQL') { + $s_schd2sql = 1; + } + + if (uc $sectionsearch eq 'DATABASE') { + $s_database = 1; + } + + if (uc $sectionsearch eq 'GETICONS') { + $s_geticons = 1; + } + + if ($specialdebug ) { + print "getConfig::section flags:\n"; + print "getConfig:: REPLAYGUIDE: $s_replayguide\n"; + print "getConfig:: XMLTV2SQL: $s_xmltv2sql\n"; + print "getConfig:: XMLTV: $s_xmltv\n"; + print "getConfig:: DATADIRECT: $s_datadirect\n"; + print "getConfig::DATADIRECT2SQL: $s_datadirect2sql\n"; + print "getConfig:: SCHD2SQL: $s_schd2sql\n"; + print "getConfig:: DATABASE: $s_database\n"; + print "getConfig:: GETICONS: $s_geticons\n"; + print "getConfig:: GLOBAL: $s_global_priority Is Priority: $s_global_priority\n"; + } + + + #----------------------------------------------------------------------------- + # First try the global configuration + #----------------------------------------------------------------------------- + + if ($specialdebug ) { + print "getConfig::Attempting to search for \"$sectionsearch\" within $configfile\n"; + } + + $retcode = &loadConfigFile($configfile,$null,$valuesearch); + + if ($specialdebug ) { + print "getConfig::loadConfigFile($configfile) returned $retcode\n"; + } + + + #----------------------------------------------------------------------------- + # Process Return Codes + #----------------------------------------------------------------------------- + + if ($specialdebug ) { + print "getConfig::processing return codes for $configfile\n"; + } + + if ($retcode & 1) { + if ($specialdebug ) { + print "getConfig::$configfile read successfully\n"; + } + }else{ + if ($specialdebug ) { + print "getConfig::$configfile could not be opened or found\n"; + } + } + + if ($retcode & 2) { + if ($specialdebug ) { + print "getConfig::loaded values for global successfully\n"; + } + }else{ + if ($specialdebug ) { + print "getConfig::failed to find values for global\n"; + } + } + + if ($retcode & 4) { + #----------------------------------------------------------------------------- + # Succeeded to read the section we wanted + #----------------------------------------------------------------------------- + + if ($specialdebug ) { + print "getConfig::loaded values for $sectionsearch successfully\n"; + } + }else{ + if ($do_downgrade_search) { + + #----------------------------------------------------------------------------- + # Try to load old config file + #----------------------------------------------------------------------------- + + if ($specialdebug ) { + print "getConfig::Attempting to search within $sectionsearch.conf (downgrade)\n"; + } + + $retcode = &loadConfigFile("$sectionsearch.conf",$sectionsearch,$valuesearch); + + if ($specialdebug ) { + print "getConfig::loadConfigFile($sectionsearch.conf) returned $retcode\n"; + } + + #----------------------------------------------------------------------------- + # Process Return Codes + #----------------------------------------------------------------------------- + + if ($specialdebug ) { + print "getConfig::processing return codes for $sectionsearch.conf\n"; + } + + + if ($retcode & 1) { + if ($specialdebug ) { + print "getConfig::$sectionsearch.conf read successfully\n"; + } + }else{ + if ($specialdebug ) { + print "getConfig::$sectionsearch.conf could not be opened or found\n"; + } + } + + if ($retcode & 2) { + if ($specialdebug ) { + print "getConfig::loaded values for global successfully\n"; + } + }else{ + if ($specialdebug ) { + print "getConfig::failed to find values for global\n"; + } + } + + if ($retcode & 4) { + if ($specialdebug ) { + print "getConfig::loaded values for $sectionsearch successfully\n"; + } + }else{ + if ($specialdebug ) { + print "getConfig::failed to find values for $sectionsearch\n"; + } + } + }else{ + if ($specialdebug ) { + print "getConfig::failed to find values for $sectionsearch (downgrade not permitted)\n"; + } + } + } + + if ($specialdebug ) { + print "getConfig::Exiting($retcode)\n"; + } + + + return $retcode; + +} + + +#------------------------------------------------------------------------------------ +sub loadConfigFile($$$) { + # + # Process a Configuration File + # + # Parameters: configuration file + # section to force (optional) + # + # Returns the same bitmask as getConfig + # + #---------------------------------------------------------------------------- + + #--------------------------------- + # Read File + #--------------------------------- + + my $configfile = shift; + my $forcesection = shift; + my $forceoption = shift; + + my $specialdebug = 0; + my $comment = ""; + my $retcode = 0; + my $currentsection = ""; + my $forced = 0; + + if ($specialdebug) { + print "loadConfigFile::Start($configfile,$forcesection,$forceoption)\n"; + } + + #--------------------------------- + # If need be force a section + #--------------------------------- + + + if (length($forcesection) > 0) { + $currentsection = $forcesection; + $currentsection = lc $currentsection; + $forced = 1; + if ($specialdebug) { + print "loadConfigFile::$configfile->Forcing Section: \"$currentsection\"\n"; + } + + } + + + if ($specialdebug) { + print "loadConfigFile::Attempting to open $configfile for read\n"; + } + + if (open(CONFIGFILE, "<$configpath$configfile")) { + while () { + chop $_; + + #--------------------------------- + # Ignore Comments + #--------------------------------- + + + $iscomment = 0; + + if (substr($_,0,1) eq '#') { + $iscomment = 1; + } + + if (substr($_,0,1) eq ';') { + $iscomment = 1; + } + + if (substr($_,0,1) eq '/') { + $iscomment = 1; + } + + if ($_ eq $null) { + $iscomment = 1; + } + + #--------------------------------- + # We just started a section... + #--------------------------------- + + + if (substr($_,0,1) eq '[') { + $iscomment = 1; + if (!$forced) { + $_ = substr($_,1); + ($currentsection,$junk) = split(']', $_, 2); + $currentsection = lc $currentsection; + if ($specialdebug) { + print "loadConfigFile::$configfile->Found Section \"$currentsection\"\n"; + } + } + } + + + #--------------------------------- + # Get Option=Param + #--------------------------------- + + if ($iscomment) { + $option = ""; + $parameter = ""; + }else{ + ($option,$parameter) = split('=', $_, 2); + + #------------------------- + # Trim Whitespace + #------------------------- + + $option =~ s/^\s+//; + $option =~ s/\s+$//; + + #------------------------- + # Allow inline comments + #------------------------- + + + if ($allowinlinecomments_1) { + $parameter =~ s/\s+#\s.*//; + } + + if ($allowinlinecomments_2) { + $parameter =~ s/\s+;\s.*//; + } + + if ($allowinlinecomments_3) { + $parameter =~ s/\s+\/\/\s.*//; + } + + + #------------------------- + # Trim Whitespace + #------------------------- + + $parameter =~ s/^\s+//; + $parameter =~ s/\s+$//; + + + #--------------------------------- + # Looking for a specific option + #--------------------------------- + + if ((length($forceoption) > 0)) { + if ((uc $option) ne (uc $forceoption)) { + $iscomment = 1; + if ($specialdebug) { + print "loadConfigFile::$configfile->no match ($option!=$forceoption)\n"; + } + }else{ + if ($specialdebug) { + print "loadConfigFile::$configfile->match ($option==$forceoption)\n"; + } + } + } + + + } + + #--------------------------------- + # Handle GLOBALs if they aren't + # priority. + #--------------------------------- + + + if (($currentsection eq "global") && ($s_global) && (!$s_global_priority)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadGlobalOptions($option)\n"; + } + + &loadGlobalOptions; + $retcode = $retcode | 2; + } + } + + #--------------------------------- + # Handle replayguide.conf + #--------------------------------- + + if (($currentsection eq "replayguide") && ($s_replayguide)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadReplayGuideOptions($option)\n"; + } + &loadReplayGuideOptions; + $retcode = $$retcode | 4; + } + } + #--------------------------------- + # Handle xmltv.conf + #--------------------------------- + + if (($currentsection eq "xmltv") && ($s_xmltv)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadXMLTVClientOptions($option)\n"; + } + &loadXMLTVClientOptions; + $retcode = $retcode | 4; + } + } + + + #--------------------------------- + # Handle xmltv2sql.conf + #--------------------------------- + + if (($currentsection eq "xmltv2sql") && ($s_xmltv2sql)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadXMLTVToSQLOptions($option)\n"; + } + &loadXMLTVToSQLOptions; + $retcode = $retcode | 4; + } + } + + #--------------------------------- + # Handle datadirect.conf + #--------------------------------- + + if (($currentsection eq "datadirect") && ($s_datadirect)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadDataDirectOptions($option)\n"; + } + &loadDataDirectOptions; + $retcode = $retcode | 4; + } + } + + + #--------------------------------- + # Handle datadirect2sql.conf + #--------------------------------- + + if (($currentsection eq "datadirect2sql") && ($s_datadirect2sql)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadDataDirectToSQLOptions($option)\n"; + } + &loadDataDirectToSQLOptions; + $retcode = $retcode | 4; + } + } + + + #--------------------------------- + # Handle schd2sql.conf + #--------------------------------- + + if (($currentsection eq "schd2sql") && ($s_schd2sql)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadScheduleToSQLOptions($option)\n"; + } + &loadScheduleToSQLOptions; + $retcode = $retcode | 4; + } + } + + + #--------------------------------- + # Handle database.conf + #--------------------------------- + + if (($currentsection eq "database") && ($s_database)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadDatabaseOptions($option)\n"; + } + &loadDatabaseOptions; + $retcode = $retcode | 4; + } + } + + #--------------------------------- + # Handle getchannelicons.conf + #--------------------------------- + + if (($currentsection eq "geticons") && ($s_geticons)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadGetChannelIconsOptions($option)\n"; + } + &loadGetChannelIconsOptions; + $retcode = $retcode | 4; + } + } + + + } + close CONFIGFILE; + $retcode = $retcode | 1; + + + if ($specialdebug) { + print "loadConfigFile::$configfile->Closed\n"; + } + + if (($s_global_priority) && ($s_global) && (!$forced)) { + if ($forced) { + $currentsection = "global"; + if ($specialdebug) { + print "loadConfigFile::$configfile->Forced to $currentsection\n"; + } + }else{ + $currentsection = ""; + } + + if (open(CONFIGFILE, "$configpath$configfile")) { + if ($specialdebug) { + print "loadConfigFile::$configfile->Open (Reading)\n"; + } + + while () { + chop $_; + + #--------------------------------- + # Ignore Comments + #--------------------------------- + + $iscomment = 0; + + if (substr($_,0,1) eq '#') { + $iscomment = 1; + } + + if (substr($_,0,1) eq ';') { + $iscomment = 1; + } + + if (substr($_,0,1) eq '/') { + $iscomment = 1; + } + + if ($_ eq $null) { + $iscomment = 1; + } + + #--------------------------------- + # We just started a section... + #--------------------------------- + + + if (substr($_,0,1) eq '[') { + $iscomment = 1; + if (!$forced) { + $_ = substr($_,1); + ($currentsection,$junk) = split(']', $_, 2); + $currentsection = lc $currentsection; + if ($specialdebug) { + print "loadConfigFile::$configfile->Found Section \"$currentsection\"\n"; + } + } + } + + #--------------------------------- + # Get Option=Param + #--------------------------------- + + if ($iscomment) { + $option = ""; + $parameter = ""; + }else{ + ($option,$parameter) = split('=', $_, 2); + + #------------------------- + # Trim Whitespace + #------------------------- + + $option =~ s/^\s+//; + $option =~ s/\s+$//; + + + #------------------------- + # Allow inline comments + #------------------------- + + if ($allowinlinecomments_1) { + $parameter =~ s/\s+#\s.*//; + } + + if ($allowinlinecomments_2) { + $parameter =~ s/\s+;\s.*//; + } + + if ($allowinlinecomments_3) { + $parameter =~ s/\s+\/\/\s.*//; + } + + + + #------------------------- + # Trim Whitespace + #------------------------- + + + $parameter =~ s/^\s+//; + $parameter =~ s/\s+$//; + + #--------------------------------- + # Looking for a specific option + #--------------------------------- + + if ((length($forceoption) > 0)) { + if ((uc $option) ne (uc $forceoption)) { + $iscomment = 1; + if ($specialdebug) { + print "loadConfigFile::$configfile->no match ($forceoption!=$option)\n"; + } + }else{ + if ($specialdebug) { + print "loadConfigFile::$configfile->match ($forceoption==$option)\n"; + } + } + } + + } + + + + #--------------------------------- + # Handle GLOBAL if they take + # priority over locals. + #--------------------------------- + + if (($currentsection eq "global") && ($s_global) && ($s_global_priority)) { + if (!$iscomment) { + if ($specialdebug) { + print "loadConfigFile::$configfile->loadGlobalOptions->Priority->($option)\n"; + } + &loadGlobalOptions; + $retcode = $retcode | 2; + }else{ + if (length($forceoption) > 0) { + $retcode = $retcode | 2; + } + } + } + + + } + } + close CONFIGFILE; + $retcode = $retcode | 1; + + + if ($specialdebug) { + print "loadConfigFile::$configfile->Closed\n"; + } + + + } + + }else{ + if ($specialdebug) { + print "loadConfigFile::$configfile->Failed\n"; + } + + } + + #--------------------------------- + # All done, return status. + #--------------------------------- + + if ($specialdebug) { + print "loadConfigFile::Exiting($retcode)\n"; + } + + return $retcode; + +} + + +#------------------------------------------------------------------------------------ +sub loadFile($$) { + # + # Load a file into an array. + # + # Parameters: file to load + # + # Returns array,elementcount + # + #---------------------------------------------------------------------------- + + #--------------------------------- + # Read File + #--------------------------------- + + my $filename = shift; + my $nocomments = int shift; + + my $dataline = ""; + my $specialdebug = 0; + my $dataarray = ""; + my $comment = ""; + my $ctr = 0; + + if ($specialdebug) { + print "loadFile::Start($filename,$nocomments)\n"; + } + + if ($nocomments) { + $allowinlinecomments_1 = 0; + $allowinlinecomments_2 = 0; + $allowinlinecomments_3 = 0; + } + + + if ($specialdebug) { + print "loadFile::Attempting to open $filename for read\n"; + } + + if (open(FHANDLE, $filename)) { + while () { + chop $_; + $dataline = $_; + + #--------------------------------- + # Ignore Comments + #--------------------------------- + + + $iscomment = 0; + + if (!$nocomments) { + if (substr($dataline,0,1) eq '#') { + $iscomment = 1; + } + + if (substr($dataline,0,1) eq ';') { + $iscomment = 1; + } + + if (substr($dataline,0,1) eq '/') { + $iscomment = 1; + } + } + + if ($dataline eq $null) { + $iscomment = 1; + } + + + if ($iscomment) { + $dataline = ""; + }else{ + + + + #------------------------- + # Allow inline comments + #------------------------- + + if ($allowinlinecomments_1) { + if ($dataline =~ /\#/ ) { + ($dataline,$comment) = split(/\#/, $dataline, 2); + } + } + + if ($allowinlinecomments_2) { + if ($dataline =~ /;/ ) { + ($dataline,$comment) = split(/;/, $dataline, 2); + } + } + + if ($allowinlinecomments_3) { + if ($dataline =~ /\/\// ) { + ($dataline,$comment) = split(/\/\//, $dataline, 2); + } + } + + #------------------------- + # Trim Whitespace + #------------------------- + + $dataline =~ s/^\s+//; + $dataline =~ s/\s+$//; + + $ctr++; + $dataarray[$ctr] = $dataline; + } + } + + close FHANDLE; + }else{ + return; + } + + + return @dataarray; +} + + + +#------------------------------------------------------------------------------------ +sub loadGlobalOptions{ + # + # Load values for Personal ReplayGuide + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadGlobalOptions::starting\n"; + } + + if (uc $option eq "VERBOSE") { + $verbose = $parameter; + } + + if (uc $option eq "DEBUG") { + $debug = $parameter; + } + + if (uc $option eq "DATAFEED") { + $datafeed = $parameter; + } + + if (uc $option eq "ALLOW") { + $allow_list = $parameter; + } + + if (uc $option eq "PDA") { + $pda_list = $parameter; + } + + if (uc $option eq "LOGFILE") { + $log_pathname = $parameter; + } + + if (uc $option eq "LOGMODULENAME") { + $log_module_name = $parameter; + } + + if (uc $option eq "SCHEDULER") { + $scheduler = $parameter; + } + + if (uc $option eq "SCHEDULE2SQL") { + $schedule2sql = $parameter; + } + + if (uc $option eq "IMAGE_LOGO") { + $image_logo = $parameter; + } + + if (uc $option eq "IMAGEDIR") { + $imagedir = $parameter; + } + + if (uc $option eq "WWWDIR") { + $wwwdir = $parameter; + } + + if (uc $option eq "SCRIPTDIR") { + $scriptdir = $parameter; + } + + if (uc $option eq "SCRIPTNAME") { + $scriptname = $parameter; + } + + if (uc $option eq "SCHEDULENAME") { + $schedulename = $parameter; + } + + if (uc $option eq "XMLFILE") { + $cnf_xmlfile = $parameter; + } + + if (uc $option eq "BACKGROUNDCOLOR") { + $color_background = $parameter; + } + + if (uc $option eq "TEXTCOLOR") { + $color_text = $parameter; + } + + if (uc $option eq "VISITEDLINKCOLOR") { + $color_visitedlink = $parameter; + } + + if (uc $option eq "ACTIVELINKCOLOR") { + $color_activelink = $parameter; + } + + if (uc $option eq "LINKCOLOR") { + $color_link = $parameter; + } + + if (uc $option eq "HEADINGBACKGROUNDCOLOR") { + $color_headingbackground = $parameter; + } + + if (uc $option eq "HEADINGTEXTCOLOR") { + $color_headingtext = $parameter; + } + + if (uc $option eq "TITLEFONT") { + $font_title = $parameter; + } + + if (uc $option eq "MENUFONT") { + $font_menu = $parameter; + } + + if ((uc $option eq "USINGAPACHE") || (uc $option eq "SUPRESSHTTPHEADER")) { + $supresshttpheader = $parameter; + } + + if (uc $option eq "SUPRESSCONTENTTYPE") { + $supresscontenttype = $parameter; + } + + if (uc $option eq "ALLOWSQLSUBSTITUTIONS") { + $allow_sql_substitutions = $parameter; + } + + + if ($specialdebug ) { + print "loadGlobalOptions::exiting\n"; + } + + return 1; +} + + +#------------------------------------------------------------------------------------ +sub loadDatabaseOptions{ + # + # Load values for rg_info.pl + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadDatabaseOptions::starting\n"; + } + + if (uc $option eq "DRIVER") { + $db_driver = $parameter; + } + + if (uc $option eq "USERNAME") { + $db_user = $parameter; + } + + if (uc $option eq "PASSWORD") { + $db_pass = $parameter; + } + + if (uc $option eq "HOST") { + $db_host = $parameter; + } + + if (uc $option eq "DATABASE") { + $db_name = $parameter; + } + + if (uc $option eq "DSN") { + $db_dsn_name = $parameter; + } + + if (uc $option eq "TABLE_REPLAYUNITS") { + $db_table_replayunits = $parameter; + } + + if (uc $option eq "TABLE_CHANNELS") { + $db_table_channels = $parameter; + } + + if (uc $option eq "TABLE_TVLISTINGS") { + $db_table_tvlistings = $parameter; + } + + if (uc $option eq "TABLE_SCHEDULE") { + $db_table_schedule = $parameter; + } + + if (uc $option eq "TABLE_CASTCREW") { + $db_table_castcrew= $parameter; + } + + if ($specialdebug ) { + print "loadDatabaseOptions::exiting\n"; + } + + return 1; +} + +#------------------------------------------------------------------------------------ +sub loadScheduleToSQLOptions{ + # + # Load values for schd2sql.pl + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadScheduleToSQLOptions::starting\n"; + } + + + if (uc $option eq "XMLFILE") { + $cnf_xmlfile = $parameter; + } + + if (uc $option eq "DATAFEED") { + $datafeed = $parameter; + } + + if (uc $option eq "DEBUG") { + $debug = $parameter; + } + + if (uc $option eq "LOGFILE") { + $log_pathname = $parameter; + } + + if (uc $option eq "LOGMODULENAME") { + $log_module_name = $parameter; + } + + if (uc $option eq "REPLAYSCHEDULE") { + $replaySchedule = $parameter; + } + + if (uc $option eq "DO_NOT_INSERT") { + $do_not_insert = $parameter; + } + + if (uc $option eq "DO_NOT_DROP_ROWS") { + $do_not_drop_rows = $parameter; + } + + if (uc $option eq "ALLOW") { + $allow_list = $parameter; + } + + if (uc $option eq "VERBOSE") { + $verbose = $parameter; + } + + if (uc $option eq "BACKGROUNDCOLOR") { + $color_background = $parameter; + } + + if (uc $option eq "TEXTCOLOR") { + $color_text = $parameter; + } + + if (uc $option eq "VISITEDLINKCOLOR") { + $color_visitedlink = $parameter; + } + + if (uc $option eq "ACTIVELINKCOLOR") { + $color_activelink = $parameter; + } + + if (uc $option eq "LINKCOLOR") { + $color_link = $parameter; + } + + if (uc $option eq "HEADINGBACKGROUNDCOLOR") { + $color_headingbackground = $parameter; + } + + if (uc $option eq "HEADINGTEXTCOLOR") { + $color_headingtext = $parameter; + } + + if (uc $option eq "TITLEFONT") { + $font_title = $parameter; + } + + if (uc $option eq "MENUFONT") { + $font_menu = $parameter; + } + + + if ($specialdebug ) { + print "loadScheduleToSQLOptions::exiting\n"; + } + + return 1; +} + +#------------------------------------------------------------------------------------ +sub loadDataDirectToSQLOptions{ + # + # Load values for datadirect2sql.pl + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadDataDirectToSQLOptions::starting\n"; + } + + + if (uc $option eq "XMLFILE") { + $cnf_xmlfile = $parameter; + } + + if (uc $option eq "MULTIPLIER") { + $multiplier = $parameter; + } + + if (uc $option eq "DEBUG") { + $debug = $parameter; + } + + if (uc $option eq "DOTINTERVAL") { + $dotinterval = $parameter; + } + + if (uc $option eq "TITLEMAP") { + $cnf_titlemap = $parameter; + } + + if (uc $option eq "CHANNELMAP") { + $cnf_channelmap = $parameter; + } + + if (uc $option eq "MAXROWS") { + $maxrows = $parameter; + } + + if (uc $option eq "DO_NOT_INSERT") { + $do_not_insert = $parameter; + } + + if (uc $option eq "DO_NOT_DROP_ROWS") { + $do_not_drop_rows = $parameter; + } + + if (uc $option eq "USE_CASTCREW") { + $use_castcrew = $parameter; + } + + if (uc $option eq "ALLOW") { + $allow_list = $parameter; + } + + if (uc $option eq "VERBOSE") { + $verbose = $parameter; + } + + if (uc $option eq "BACKGROUNDCOLOR") { + $color_background = $parameter; + } + + if (uc $option eq "TEXTCOLOR") { + $color_text = $parameter; + } + + if (uc $option eq "VISITEDLINKCOLOR") { + $color_visitedlink = $parameter; + } + + if (uc $option eq "ACTIVELINKCOLOR") { + $color_activelink = $parameter; + } + + if (uc $option eq "LINKCOLOR") { + $color_link = $parameter; + } + + if (uc $option eq "HEADINGBACKGROUNDCOLOR") { + $color_headingbackground = $parameter; + } + + if (uc $option eq "HEADINGTEXTCOLOR") { + $color_headingtext = $parameter; + } + + if (uc $option eq "TITLEFONT") { + $font_title = $parameter; + } + + if (uc $option eq "MENUFONT") { + $font_menu = $parameter; + } + + if (uc $option eq "LOGFILE") { + $log_pathname = $parameter; + } + + if (uc $option eq "LOGMODULENAME") { + $log_module_name = $parameter; + } + + if (uc $option eq "SHOWEPISODENUMBER") { + $show_episode_number = $parameter; + } + + if (uc $option eq "SHOWFIRSTAIREDDATE") { + $show_first_aired_date = $parameter; + } + if ($specialdebug ) { + print "loadDataDirectToSQLOptions::exiting\n"; + } + + return 1; + +} + + +#------------------------------------------------------------------------------------ +sub loadDataDirectOptions{ + # + # Load values for datadirect_client.pl + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadDataDirectOptions::starting\n"; + } + + + if (uc $option eq "SUCCESSCODE") { + $datafeed_success= $parameter; + } + + if (uc $option eq "CLIENT") { + $datafeed_client = $parameter; + } + + if (uc $option eq "CONVERTER") { + $datafeed_converter = $parameter; + } + + if (uc $option eq "PARAMETERS") { + $datafeed_parameters = $parameter; + } + + if (uc $option eq "REDIRECTOUTPUT") { + $datafeed_redirectoutput = $parameter; + } + + if (uc $option eq "GETICONS") { + $datafeed_geticons = $parameter; + } + + if (uc $option eq "GETICONSCRIPT") { + $datafeed_geticonscript = $parameter; + } + + if (uc $option eq "XMLFILE") { + $cnf_xmlfile = $parameter; + } + + if (uc $option eq "WEBSERVICE") { + $webservice = $parameter; + } + + if (uc $option eq "USERNAME") { + $username = $parameter; + } + + if (uc $option eq "PASSWORD") { + $password = $parameter; + } + + if (uc $option eq "DAYS") { + $days = $parameter; + } + + if (uc $option eq "DEBUG") { + $debug = $parameter; + } + + if (uc $option eq "VERBOSE") { + $verbose = $parameter; + } + + if (uc $option eq "ALLOW") { + $allow_list = $parameter; + } + + if (uc $option eq "BACKGROUNDCOLOR") { + $color_background = $parameter; + } + + if (uc $option eq "TEXTCOLOR") { + $color_text = $parameter; + } + + if (uc $option eq "VISITEDLINKCOLOR") { + $color_visitedlink = $parameter; + } + + if (uc $option eq "ACTIVELINKCOLOR") { + $color_activelink = $parameter; + } + + if (uc $option eq "LINKCOLOR") { + $color_link = $parameter; + } + + if (uc $option eq "HEADINGBACKGROUNDCOLOR") { + $color_headingbackground = $parameter; + } + + if (uc $option eq "HEADINGTEXTCOLOR") { + $color_headingtext = $parameter; + } + + if (uc $option eq "TITLEFONT") { + $font_title = $parameter; + } + + if (uc $option eq "MENUFONT") { + $font_menu = $parameter; + } + + if (uc $option eq "LOGFILE") { + $log_pathname = $parameter; + } + + if (uc $option eq "LOGMODULENAME") { + $log_module_name = $parameter; + } + + + if ($specialdebug ) { + print "loadDataDirectOptions::exiting\n"; + } + + return 1; +} + + + + +#------------------------------------------------------------------------------------ +sub loadXMLTVClientOptions{ + # + # Load values for xmltv + # + #---------------------------------------------------------------------------- + + + if ($specialdebug ) { + print "loadXMLTVClientOptions::starting\n"; + } + + if (uc $option eq "SUCCESSCODE") { + $datafeed_success= $parameter; + } + + if (uc $option eq "CLIENT") { + $datafeed_client = $parameter; + } + + if (uc $option eq "CONVERTER") { + $datafeed_converter = $parameter; + } + + if (uc $option eq "PARAMETERS") { + $datafeed_parameters = $parameter; + } + + if (uc $option eq "REDIRECTOUTPUT") { + $datafeed_redirectoutput = $parameter; + } + + if (uc $option eq "GETICONS") { + $datafeed_geticons = $parameter; + } + + if (uc $option eq "GETICONSCRIPT") { + $datafeed_geticonscript = $parameter; + } + + + if ($specialdebug ) { + print "loadXMLTVClientOptions::exiting\n"; + } + + return 1; + +} + + +#------------------------------------------------------------------------------------ +sub loadXMLTVToSQLOptions{ + # + # Load values for xmltv2sql.pl + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadXMLTVToSQLOptions::starting\n"; + } + + if (uc $option eq "XMLFILE") { + $cnf_xmltv = $parameter; + } + + if (uc $option eq "POSTALCODE") { + $postalcode = $parameter; + } + + if (uc $option eq "LINEUPNAME") { + $lineupname = $parameter; + } + + if (uc $option eq "SYSTEMTYPE") { + $systemtype = $parameter; + } + + if (uc $option eq "MULTIPLIER") { + $multiplier = $parameter; + } + + if (uc $option eq "DEBUG") { + $debug = $parameter; + } + + if (uc $option eq "DOTINTERVAL") { + $dotinterval = $parameter; + } + + if (uc $option eq "TITLEMAP") { + $cnf_titlemap = $parameter; + } + + if (uc $option eq "CHANNELMAP") { + $cnf_channelmap = $parameter; + } + + if (uc $option eq "MAXROWS") { + $maxrows = $parameter; + } + + if (uc $option eq "DO_NOT_INSERT") { + $do_not_insert = $parameter; + } + + if (uc $option eq "DO_NOT_DROP_ROWS") { + $do_not_drop_rows = $parameter; + } + + if (uc $option eq "LOGFILE") { + $log_pathname = $parameter; + } + + if (uc $option eq "LOGMODULENAME") { + $log_module_name = $parameter; + } + + if (uc $option eq "ALLOW") { + $allow_list = $parameter; + } + + if (uc $option eq "VERBOSE") { + $verbose = $parameter; + } + + if (uc $option eq "BACKGROUNDCOLOR") { + $color_background = $parameter; + } + + if (uc $option eq "TEXTCOLOR") { + $color_text = $parameter; + } + + if (uc $option eq "VISITEDLINKCOLOR") { + $color_visitedlink = $parameter; + } + + if (uc $option eq "ACTIVELINKCOLOR") { + $color_activelink = $parameter; + } + + if (uc $option eq "LINKCOLOR") { + $color_link = $parameter; + } + + if (uc $option eq "HEADINGBACKGROUNDCOLOR") { + $color_headingbackground = $parameter; + } + + if (uc $option eq "HEADINGTEXTCOLOR") { + $color_headingtext = $parameter; + } + + if (uc $option eq "TITLEFONT") { + $font_title = $parameter; + } + + if (uc $option eq "MENUFONT") { + $font_menu = $parameter; + } + + if ($specialdebug ) { + print "loadXMLTVToSQLOptions::exiting\n"; + } + + return 1; + +} + + +#------------------------------------------------------------------------------------ +sub loadGetChannelIconsOptions{ + # + # Load values for getchannelicons.pl + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadGetChannelIconsOptions::starting\n"; + } + + if (uc $option eq "PROVIDERID") { + $providerid = $parameter; + } + + if (uc $option eq "ZIPCODE") { + $zipcode = $parameter; + } + + if (uc $option eq "CHANNELICONDIR") { + $channelicondir = $parameter; + } + + if (uc $option eq "DEBUG") { + $debug = $parameter; + } + + if (uc $option eq "VERBOSE") { + $verbose = $parameter; + } + + if ($specialdebug ) { + print "loadGetChannelIconsOptions::exiting\n"; + } + + return 1; + +} + +#------------------------------------------------------------------------------------ +sub loadReplayGuideOptions{ + # + # Load values for replayguide.pl + # + #---------------------------------------------------------------------------- + + if ($specialdebug ) { + print "loadReplayGuideOptions::starting\n"; + } + + if (uc $option eq "DEFAULTSLOT") { + $defaultshowslots = $parameter; + } + + if (uc $option eq "DEFAULTSHOWHOURS") { + $defaultshowhours = $parameter; + } + + if (uc $option eq "ALLOW") { + $allow_list = $parameter; + } + + if (uc $option eq "PDA") { + $pda_list = $parameter; + } + + if (uc $option eq "DEBUG") { + $debug = $parameter; + } + + if (uc $option eq "WWWDIR") { + $wwwdir = $parameter; + } + + if (uc $option eq "SCRIPTDIR") { + $scriptdir = $parameter; + } + + if (uc $option eq "SCRIPTNAME") { + $scriptname = $parameter; + } + + if (uc $option eq "IMAGEDIR") { + $imagedir = $parameter; + } + + if (uc $option eq "SCHEDULENAME") { + $schedulename = $parameter; + } + + if (uc $option eq "SCHEDULER") { + $scheduler = $parameter; + } + + if (uc $option eq "SCHEDULE2SQL") { + $schedule2sql = $parameter; + } + + if (uc $option eq "NEWWINDOW") { + $newwindow = $parameter; + } + + if (uc $option eq "SHOWCHANNELICONS") { + $showchannelicons = $parameter; + } + + if (uc $option eq "CHANNELICONDIR") { + $channelicondir = $parameter; + } + + if (uc $option eq "SHOWRTVICONS") { + $showrtvicons = $parameter; + } + + if (uc $option eq "SHOWRTVTHEMES") { + $showrtvthemes = $parameter; + } + + if (uc $option eq "SHOWHEADERROWS") { + $showheaderrows = $parameter; + } + + if (uc $option eq "SHOWBUTTONICONS") { + $showbuttonicons = $parameter; + } + + if (uc $option eq "DEFAULTREPLAYTV") { + $defaultreplaytv = $parameter; + } + + if (uc $option eq "IMAGE_BPGR") { + $image_bpgr = $parameter; + } + + if (uc $option eq "IMAGE_CBPGR") { + $image_cbpgr = $parameter; + } + + if (uc $option eq "IMAGE_LOGO") { + $image_logo = $parameter; + } + + if (uc $option eq "IMAGE_APGR") { + $image_apgr = $parameter; + } + + if (uc $option eq "IMAGE_CAPGR") { + $image_capgr = $parameter; + } + + if (uc $option eq "IMAGE_PPGR") { + $image_ppgr = $parameter; + } + + if (uc $option eq "IMAGE_CPPGR") { + $image_cppgr = $parameter; + } + + if (uc $option eq "IMAGE_GR") { + $image_gr = $parameter; + } + + if (uc $option eq "IMAGE_CGR") { + $image_cgr = $parameter; + } + + if (uc $option eq "IMAGE_R") { + $image_r = $parameter; + } + + if (uc $option eq "IMAGE_CR") { + $image_cr = $parameter; + } + + if (uc $option eq "IMAGE_BPR") { + $image_bpr = $parameter; + } + + if (uc $option eq "IMAGE_CBPR") { + $image_cbpr = $parameter; + } + + if (uc $option eq "IMAGE_APR") { + $image_apr = $parameter; + } + + if (uc $option eq "IMAGE_CAPR") { + $image_capr = $parameter; + } + + if (uc $option eq "IMAGE_PPR") { + $image_ppr = $parameter; + } + + if (uc $option eq "IMAGE_CPPR") { + $image_cppr = $parameter; + } + + if (uc $option eq "IMAGE_GS") { + $image_gs = $parameter; + } + + if (uc $option eq "IMAGE_CGS") { + $image_cgs = $parameter; + } + + if (uc $option eq "IMAGE_S") { + $image_s = $parameter; + } + + if (uc $option eq "IMAGE_CS") { + $image_cs = $parameter; + } + + if (uc $option eq "IMAGE_BPGS") { + $image_bpgs = $parameter; + } + + if (uc $option eq "IMAGE_CBPGS") { + $image_cbpgs = $parameter; + } + + if (uc $option eq "IMAGE_APGS") { + $image_apgs = $parameter; + } + + if (uc $option eq "IMAGE_CAPGS") { + $image_capgs = $parameter; + } + + if (uc $option eq "IMAGE_PPGS") { + $image_ppgs = $parameter; + } + + if (uc $option eq "IMAGE_CPPGS") { + $image_cppgs = $parameter; + } + + if (uc $option eq "IMAGE_BPS") { + $image_bps = $parameter; + } + + if (uc $option eq "IMAGE_CBPS") { + $image_cbps = $parameter; + } + + if (uc $option eq "IMAGE_APS") { + $image_aps = $parameter; + } + + if (uc $option eq "IMAGE_CAPS") { + $image_caps = $parameter; + } + + if (uc $option eq "IMAGE_PPS") { + $image_pps = $parameter; + } + + if (uc $option eq "IMAGE_CPPS") { + $image_cpps = $parameter; + } + + if (uc $option eq "IMAGE_TW") { + $image_tw = $parameter; + } + + if (uc $option eq "IMAGE_TL") { + $image_tl = $parameter; + } + + if (uc $option eq "IMAGE_GT") { + $image_gt = $parameter; + } + + if (uc $option eq "IMAGE_CGT") { + $image_cgt = $parameter; + } + + if (uc $option eq "REFRESHINTERVAL") { + $defaultrefreshinterval = $parameter; + } + + if (uc $option eq "SNAPSHOTPATH") { + $rtv_snapshotpath = $parameter; + } + + if (uc $option eq "SEARCHFUTUREONLY") { + $searchfutureonly = $parameter; + } + + if (uc $option eq "TODOOPTION") { + $todooption = $parameter; + } + + if (uc $option eq "TODOFROMSTART") { + $todofromstart = $parameter; + } + + if (uc $option eq "LOGFILE") { + $log_pathname = $parameter; + } + + if (uc $option eq "LOGMODULENAME") { + $log_module_name = $parameter; + } + + if (uc $option eq "FUTURESHOWCOLOR") { + $color_show[2] = $parameter; + } + + if (uc $option eq "CURRENTSHOWCOLOR") { + $color_show[1] = $parameter; + } + + if (uc $option eq "PASTSHOWCOLOR") { + $color_show[0] = $parameter; + } + + if (uc $option eq "FUTURESCHEDULEDCOLOR") { + $color_scheduled[2] = $parameter; + } + + if (uc $option eq "CURRENTSCHEDULEDCOLOR") { + $color_scheduled[1] = $parameter; + } + + if (uc $option eq "PASTSCHEDULEDCOLOR") { + $color_scheduled[0] = $parameter; + } + + if (uc $option eq "FUTURECONFLICTCOLOR") { + $color_conflict[2] = $parameter; + } + + if (uc $option eq "CURRENTCONFLICTCOLOR") { + $color_conflict[1] = $parameter; + } + + if (uc $option eq "PASTCONFLICTCOLOR") { + $color_conflict[0] = $parameter; + } + + if (uc $option eq "FUTURETHEMECOLOR") { + $color_theme[2] = $parameter; + } + + if (uc $option eq "CURRENTTHEMECOLOR") { + $color_theme[1] = $parameter; + } + + if (uc $option eq "PASTTHEMECOLOR") { + $color_theme[0] = $parameter; + } + + if (uc $option eq "FUTURETHEMECONFLICTCOLOR") { + $color_theme_conflict[2] = $parameter; + } + + if (uc $option eq "CURRENTTHEMECONFLICTCOLOR") { + $color_theme_conflict[1] = $parameter; + } + + if (uc $option eq "PASTTHEMECONFLICTCOLOR") { + $color_theme_conflict[0] = $parameter; + } + + if (uc $option eq "BACKGROUNDCOLOR") { + $color_background = $parameter; + } + + if (uc $option eq "TEXTCOLOR") { + $color_text = $parameter; + } + + if (uc $option eq "VISITEDLINKCOLOR") { + $color_visitedlink = $parameter; + } + + if (uc $option eq "ACTIVELINKCOLOR") { + $color_activelink = $parameter; + } + + if (uc $option eq "LINKCOLOR") { + $color_link = $parameter; + } + + if (uc $option eq "CHANNELBACKGROUNDCOLOR") { + $color_channelbackground = $parameter; + } + + if (uc $option eq "CHANNELTEXTCOLOR") { + $color_channeltext = $parameter; + } + + if (uc $option eq "HEADINGBACKGROUNDCOLOR") { + $color_headingbackground = $parameter; + } + + if (uc $option eq "HEADINGTEXTCOLOR") { + $color_headingtext = $parameter; + } + + if (uc $option eq "TITLEFONT") { + $font_title = $parameter; + } + + if (uc $option eq "MENUFONT") { + $font_menu = $parameter; + } + + if (uc $option eq "LISTINGSFONT") { + $font_listings = $parameter; + } + + if (uc $option eq "DETAILFONT") { + $font_detail = $parameter; + } + + if (uc $option eq "CHANNELFONT") { + $font_channel = $parameter; + } + + if (uc $option eq "HEADINGFONT") { + $font_heading = $parameter; + } + + if (uc $option eq "CONFIRMICON") { + $icon_confirm = $parameter; + } + + if (uc $option eq "LOCATEICON") { + $icon_locate = $parameter; + } + + if (uc $option eq "NOWICON") { + $icon_now = $parameter; + } + +# if (uc $option eq "REFRESHICON") { +# $icon_refresh = $parameter; +# } + + if (uc $option eq "GOICON") { + $icon_go = $parameter; + } + + if (uc $option eq "ALLICON") { + $icon_all = $parameter; + } + + if (uc $option eq "FINDALLICON") { + $icon_findall = $parameter; + } + + if (uc $option eq "PREVWINDOWICON") { + $icon_prevwindow = $parameter; + } + + if (uc $option eq "NEXTWINDOWICON") { + $icon_nextwindow = $parameter; + } + + if (uc $option eq "PREVCHANICON") { + $icon_prevchan = $parameter; + } + + if (uc $option eq "NEXTCHANICON") { + $icon_nextchan = $parameter; + } + + if (uc $option eq "FINDICON") { + $icon_find = $parameter; + } + + if (uc $option eq "SELECTICON") { + $icon_select = $parameter; + } + + if (uc $option eq "SCHEDULEICON") { + $icon_schedule = $parameter; + } + + if (uc $option eq "DONEICON") { + $icon_done = $parameter; + } + + if (uc $option eq "PRIMEICON") { + $icon_tonight = $parameter; + } + + if (uc $option eq "IMAGE_STEREO") { + $image_stereo = $parameter; + } + + if (uc $option eq "IMAGE_REPEAT") { + $image_repeat = $parameter; + } + + if (uc $option eq "IMAGE_CC") { + $image_cc = $parameter; + } + + if (uc $option eq "IMAGE_TVG") { + $image_tvg = $parameter; + } + + if (uc $option eq "IMAGE_TVPG") { + $image_tvpg = $parameter; + } + + if (uc $option eq "IMAGE_TV14") { + $image_tv14 = $parameter; + } + + if (uc $option eq "IMAGE_TVMA") { + $image_tvma = $parameter; + } + + if (uc $option eq "IMAGE_TVY") { + $image_tvy = $parameter; + } + + if (uc $option eq "IMAGE_TVY7") { + $image_tvy7 = $parameter; + } + + if (uc $option eq "IMAGE_MPAAG") { + $image_mpaag = $parameter; + } + + if (uc $option eq "IMAGE_MPAAPG") { + $image_mpaapg = $parameter; + } + + if (uc $option eq "IMAGE_MPAAPG13") { + $image_mpaapg13 = $parameter; + } + + if (uc $option eq "IMAGE_MPAANR") { + $image_mpaanr = $parameter; + } + + if (uc $option eq "IMAGE_MPAAR") { + $image_mpaar = $parameter; + } + + if (uc $option eq "IMAGE_MPAANC17") { + $image_mpaanc17 = $parameter; + } + + if (uc $option eq "SHOWRTVTEXT") { + $showrtvtext = $parameter; + } + + if (uc $option eq "ALLOWTITLEEDIT") { + $allowtitleedit = $parameter; + } + + if (uc $option eq "SKIPVERSIONCHECK") { + $skipversioncheck = $parameter; + } + + if (uc $option eq "SHOWSCHEDULEBAR") { + $showschedulebar = $parameter; + } + + if (uc $option eq "GRIDENDOVERLAP") { + $grid_end_overlap = $parameter; + } + + if (uc $option eq "GRIDLEEWAYSECOND") { + $grid_leeway_second = $parameter; + } + + if (uc $option eq "DEFAULTMODE") { + $default_mode = $parameter; + } + + if (uc $option eq "PRIMETIMESTART") { + $primetime_start = $parameter; + } + + if (uc $option eq "RTV_UPDATESLEEPSECONDS") { + $rtv_updatesleepseconds = $parameter; + } + + if (uc $option eq "RTV_ALLOWDELETE") { + $rtv_allowdelete = $parameter; + } + + if ((uc $option eq "USINGAPACHE") || (uc $option eq "SUPRESSHTTPHEADER")) { + $supresshttpheader = $parameter; + } + + if (uc $option eq "SUPRESSCONTENTTYPE") { + $supresscontenttype = $parameter; + } + + if ($specialdebug ) { + print "loadReplayGuideOptions::exiting\n"; + } + + return 1; + +} + +1; + diff --git a/rg_database.pl b/rg_database.pl new file mode 100644 index 0000000..f02c7e8 --- /dev/null +++ b/rg_database.pl @@ -0,0 +1,1033 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson +# with bits by Kanji T. Bates +# $Id: rg_database.pl,v 1.5 2003/07/19 13:34:20 pvanbaren Exp $ +# +# DATABASE FUNCTIONS +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +use DBI; + +my $_version = "Personal ReplayGuide|Database Function Library|1|1|228|Lee Thompson,Philip Van Baren,Kanji T. Bates"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} + +$prg_module{$module_name} = $_version; + +my $_lastsqlerror = ""; +my $_lastsqlstmt = ""; + +#--------------------------------------------------------------------------------------- +sub CreateDatabase { + # + # This will create a database. + # This only works with certain drivers. + # + # ------------------------------------------------------------------------------ + + if ($db_driver eq "SQLite") { + return 1; + } + + if ($db_driver eq "ODBC") { + return 1; + } + + my $specialdebug = 0; + + my $drh = DBI->install_driver($db_driver); + + if ($specialdebug) { + writeDebug("DBI driver handle is $drh"); + } + + if ($specialdebug) { + writeDebug("Values: $db_name, $db_host, $db_user, $db_pass"); + } + + my $rc = $drh->func("createdb", $db_name, $db_host, $db_user, $db_pass, 'admin'); + + if ($specialdebug) { + writeDebug("admin function returned $rc"); + } + + undef $drh; + + return $rc; +} + + +#--------------------------------------------------------------------------------------- +sub InitDSN { + # + # Define the global DSN + # + # Usage: &InitDSN + # + # NOTE: This must be called before ANYTHING else. + # + # ------------------------------------------------------------------------------ + + if ($db_host eq "localhost") { + $db_host = ""; + } + + if (length($db_host) > 0 ) { + %DATASOURCE = ( + DSN => "DBI:$db_driver:host=$db_host;database=$db_dsn_name", + Username => $db_user, + Password => $db_pass, + Options => { + AutoCommit => 1, + PrintError => 0, + RaiseError => 0, + LongReadLen => 65_535, + LongTruncOk => 0, + }, + usage => $db_dsn_name, + desc => "Personal ReplayGuide", + enabled => 1, + ); + }else{ + %DATASOURCE = ( + DSN => "DBI:$db_driver:$db_dsn_name", + Username => $db_user, + Password => $db_pass, + Options => { + AutoCommit => 1, + PrintError => 0, + RaiseError => 0, + LongReadLen => 65_535, + LongTruncOk => 0, + }, + usage => $db_dsn_name, + desc => "Personal ReplayGuide", + enabled => 1, + ); + } +} + + +#--------------------------------------------------------------------------------------- +sub StartDSN{ + # + # Open a DSN + # + # Usage: &StartDSN + # Returns: DB Handle + # + # ------------------------------------------------------------------------------ + + if ($debug > 0) { + writeDebug("Establishing Connection"); + } + + if ($db_conflict > 0) { + $_lastsqlerror = "Database Namespace Conflict!"; + return $null; + } + + my $dbh = DBI->connect( @DATASOURCE{qw( DSN Username Password Options )} ); + + if ($dbh eq $null) { + $_lastsqlerror = $DBI::errstr; + if ($debug > 0) { + writeDebug("Failed to establish database handle."); + } + }else{ + if ($debug > 0) { + writeDebug("Database handle established as $dbh"); + } + } + + if ($db_dsn_name ne $db_name) { + sqlStmt($dbh,"USE $db_name;"); + } + + if ($debug > 1) { + writeDebug("Exit"); + } + + return $dbh; + +} + +#--------------------------------------------------------------------------------------- +sub endDSN { + # + # Close a DSN + # + # Parameters: sql handle + # dsn/connection handle + # Returns: True (1) + # + # ------------------------------------------------------------------------------ + + my $handle = shift; + my $dhandle = shift; + + if ($debug > 0) { + writeDebug("Closing Connection"); + } + + if ($handle == 0) { + $handle = ""; + } + + + if ($dhandle == 0) { + $dhandle = ""; + } + + + if ($debug > 0) { + if (defined $handle) { + writeDebug("Closing SQL transaction handle $handle"); + } + if (defined $dhandle) { + writeDebug("Closing SQL database handle $dhandle"); + } + } + + if (length($handle) > 0) { + $handle->finish; + } + + if (length($dhandle) > 0) { + $dhandle->disconnect; + } + + if ($debug > 0) { + writeDebug("Exit"); + } + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub sqlStmt{ + # + # Send SQL Statement to ODBC/SQL + # + # Parameters: database hash + # SQL Statement + # + # Usage: sqlStmt (DBHash, Stmt) + # Returns: SQL Execute Handle + # + # ------------------------------------------------------------------------------ + + my $db_handle = shift; + my $sql_stmt = shift; + my $handle; + + if ($debug > 1) { + writeDebug("Start($db_handle,$sql_stmt)"); + } + + $status = 0; + + if ($db_handle eq $null) { + if ($debug > 1) { + writeDebug("No DSN Link Established"); + } + if ($debug > 1) { + writeDebug("Exit"); + } + return 0; + } + + if ($sql_stmt eq $null) { + if ($debug > 1) { + writeDebug("No SQL Statement"); + } + if ($debug > 1) { + writeDebug("Exit"); + } + return 0; + } + + + if ($debug > 1) { + writeDebug("Database handle is $db_handle"); + } + + $_lastsqlstmt = $sql_stmt; + + $handle = $db_handle->prepare($sql_stmt); + + + if ($handle eq $null) { + writeDebug("Failed to Set Handle ($db_handle)"); + return 0; + }else{ + if ($debug > 1 ) { + writeDebug("SQL handle set to $handle for $db_handle"); + } + } + + if ($debug > 1) { + writeDebug("Attempting to post $sql_stmt with handle $handle"); + } + + if ($handle->execute) { + if ($debug > 0) { + writeDebug("$sql_stmt posted to SQL"); + } + return $handle; + }else{ + $_lastsqlerror = $DBI::errstr; + + if ($debug > 0) { + writeDebug("$sql_stmt failed. Error: $_lastsqlerror"); + } + + + return 0; + } + + return 0; + +} + +#--------------------------------------------------------------------------------------- +sub runSQLScript{ + # + # Execute a SQL script + # + # Parameters: filename + # + # Usage: runSQLScript(Filename) + # Returns: + # + # + # ------------------------------------------------------------------------------ + + my $sqlfilename = shift; + my $sqlscript = ""; + my $retcode = 0; + my $junk = ""; + my $size = 0; + my $dataline = ""; + my $buffer = ""; + my $execcount = 0; + my $abort = 0; + my $specialdebug = 0; + my $debug = 0; + + if ($debug > 1) { + writeDebug("Start($sqlfilename"); + } + + my $db_handle = &StartDSN; + + if ($debug > 1) { + writeDebug("DSN handle is $db_handle"); + } + + if ($debug > 1) { + if ($allow_sql_substitutions) { + writeDebug("Allowing Substitutions"); + } + } + + if ($specialdebug) { + writeDebug("allow_sql_substitutions: $allow_sql_substitutions"); + } + + #--------------------------------------------------------------- + # Open the file and start processing + #--------------------------------------------------------------- + + if (open(FHANDLE, $sqlfilename)) { + if ($debug > 1) { + writeDebug("File $sqlfilename open"); + } + + while () { + $dataline = $_; + chop $dataline; + + if ($debug > 2) { + writeDebug("$sqlfilename: $dataline"); + } + + if (substr($dataline,0,1) eq "#") { + $dataline = ""; + } + + if ($abort) { + $dataline = ""; + } + + if (($allow_sql_substitutions) && (length($dataline) > 0)) { + if ($specialdebug) { + writeDebug("Processing Substitutions"); + } + + #------------------------------------------------------- + # Modify USE statement + #------------------------------------------------------- + + if ((uc $dataline) =~ /USE/) { + my $d_name = $dataline; + $d_name =~ s/.*use ([^;]*).*/$1/i; + + if ($d_name ne $dataline) { + $d_name = trimstring($d_name); + + if ($specialdebug) { + writeDebug("old dataline: $dataline"); + writeDebug(" database: $d_name -> $db_name"); + } + + $dataline =~ s/$d_name/$db_name/g; + + if ($specialdebug) { + writeDebug("new dataline: $dataline"); + } + } + } + + #------------------------------------------------------- + # Modify Table References + #------------------------------------------------------- + + if (((uc $dataline) =~ /CREATE TABLE/) || ((uc $dataline) =~ /DROP TABLE/) || ((uc $dataline) =~ /TRUNCATE TABLE/) || ((uc $dataline) =~ /OBJECT_ID/) || ((uc $dataline) =~ /ALTER TABLE/)) { + my $t_name = $dataline; + + if ($dataline =~ /dbo/i) { + $t_name =~ s/.*\[dbo\].\[([^]]*).*/$1/i; + if ($t_name eq $dataline) { + $t_name =~ s/.*dbo.([^+]*).*/$1/i; + } + }else{ + if ((uc $dataline) =~ /DROP/) { + $t_name =~ s/.*table ([^;]*).*/$1/i; + }else{ + $t_name =~ s/.*table ([^(]*).*/$1/i; + } + if (((uc $dataline) =~ /ALTER/) && ($tname eq $dataline)) { + $t_name =~ s/.*table ([^+]*).*/$1/i; + } + + } + + if ($t_name ne $dataline) { + + $t_name = trimstring($t_name); + + if ($specialdebug) { + writeDebug("old dataline: $dataline"); + } + + my $nt_name = $t_name; + + if ((uc $t_name) eq "SCHEDULE" ) { + $nt_name = "$db_table_schedule"; + } + + if ((uc $t_name) eq "CHANNELS" ) { + $nt_name = "$db_table_channels"; + } + + if ((uc $t_name) eq "REPLAYUNITS" ) { + $nt_name = "$db_table_replayunits"; + } + + if ((uc $t_name) eq "TVLISTINGS" ) { + $nt_name = "$db_table_tvlistings"; + } + + if ((uc $t_name) eq "CASTCREW" ) { + $nt_name = "$db_table_castcrew"; + } + + + if ($specialdebug) { + writeDebug(" table: $t_name -> $nt_name"); + } + + $dataline =~ s/$t_name/$nt_name/g; + + if ($specialdebug) { + writeDebug("new dataline: $dataline"); + } + } + } + + #------------------------------------------------------- + # Modify Insert References + #------------------------------------------------------- + + if ((uc $dataline) =~ /INSERT/) { + my $t_name = $dataline; + + if ((uc $dataline) =~ /DBO/) { + $t_name =~ s/.*\[dbo\].\[([^]]*).*/$1/i; + }else{ + $t_name =~ s/.*INTO ([^(]*).*/$1/i; + } + + if ($t_name ne $dataline) { + + $t_name = trimstring($t_name); + + if ($specialdebug) { + writeDebug("old dataline: $dataline"); + } + + my $nt_name = $t_name; + + if ((uc $t_name) eq "SCHEDULE" ) { + $nt_name = "$db_table_schedule"; + } + + if ((uc $t_name) eq "CHANNELS" ) { + $nt_name = "$db_table_channels"; + } + + if ((uc $t_name) eq "REPLAYUNITS" ) { + $nt_name = "$db_table_replayunits"; + } + + if ((uc $t_name) eq "TVLISTINGS" ) { + $nt_name = "$db_table_tvlistings"; + } + + if ((uc $t_name) eq "CASTCREW" ) { + $nt_name = "$db_table_castcrew"; + } + + if ($specialdebug) { + writeDebug(" table: $t_name -> $nt_name"); + } + + $dataline =~ s/$t_name/$nt_name/g; + + if ($specialdebug) { + writeDebug("new dataline: $dataline"); + } + } + } + + #------------------------------------------------------- + # Modify Update References + #------------------------------------------------------- + + if ((uc $dataline) =~ /UPDATE/) { + my $t_name = $dataline; + + if ((uc $dataline) =~ /DBO/) { + $t_name =~ s/.*\[dbo\].\[([^]]*).*/$1/i; + }else{ + $t_name =~ s/.*UPDATE ([^(]*).*/$1/i; + } + + if ($t_name ne $dataline) { + + $t_name = trimstring($t_name); + + if ($specialdebug) { + writeDebug("old dataline: $dataline"); + } + + my $nt_name = $t_name; + + if ((uc $t_name) eq "SCHEDULE" ) { + $nt_name = "$db_table_schedule"; + } + + if ((uc $t_name) eq "CHANNELS" ) { + $nt_name = "$db_table_channels"; + } + + if ((uc $t_name) eq "REPLAYUNITS" ) { + $nt_name = "$db_table_replayunits"; + } + + if ((uc $t_name) eq "TVLISTINGS" ) { + $nt_name = "$db_table_tvlistings"; + } + + if ((uc $t_name) eq "CASTCREW" ) { + $nt_name = "$db_table_castcrew"; + } + + + if ($specialdebug) { + writeDebug(" table: $t_name -> $nt_name"); + } + + $dataline =~ s/$t_name/$nt_name/g; + + if ($specialdebug) { + writeDebug("new dataline: $dataline"); + } + } + } + + #------------------------------------------------------- + # Modify Index References + #------------------------------------------------------- + + if ((uc $dataline) =~ /INDEX/) { + my $t_name = $dataline; + + $t_name =~ s/.*ON ([^(]*).*/$1/i; + + if ($t_name ne $dataline) { + + $t_name = trimstring($t_name); + + if ($specialdebug) { + writeDebug("old dataline: $dataline"); + } + + my $nt_name = $t_name; + + if ((uc $t_name) eq "SCHEDULE" ) { + $nt_name = "$db_table_schedule"; + } + + if ((uc $t_name) eq "CHANNELS" ) { + $nt_name = "$db_table_channels"; + } + + if ((uc $t_name) eq "REPLAYUNITS" ) { + $nt_name = "$db_table_replayunits"; + } + + if ((uc $t_name) eq "TVLISTINGS" ) { + $nt_name = "$db_table_tvlistings"; + } + + if ((uc $t_name) eq "CASTCREW" ) { + $nt_name = "$db_table_castcrew"; + } + + + if ($specialdebug) { + writeDebug(" table: $t_name -> $nt_name"); + } + + $dataline =~ s/$t_name/$nt_name/g; + + if ($specialdebug) { + writeDebug("new dataline: $dataline"); + } + } + } + + + + + } + + + #--------------------------------------------------------------- + # If the line is GO and this is ODBC, this is probably MSSQL + # and we need to send the buffer + #--------------------------------------------------------------- + + if (($dataline eq "GO") && ($db_driver eq "ODBC")) { + # + # Microsoft SQL + # + #-------------------------------------------------------- + + if ($debug > 1) { + writeDebug("Using Small Buffer with GO Syntax"); + } + + chop $buffer; + $buffer .= ";"; + + if (!$abort) { + if ($debug > 1) { + writeDebug("Executing: $buffer"); + } + + my $sql_handle = sqlStmt($db_handle,$buffer); + + if ($debug > 1) { + writeDebug("Buffer returned SQL handle $sql_handle"); + } + + if ($sql_handle) { + $retcode = 1; + }else{ + $retcode = 0; + $abort = 1; + } + + $execcount++; + + undef $sql_handle; + $buffer = ""; + + if ($debug > 1) { + writeDebug("Sent $execcount statements. Return Code: $retcode. Abort Flag: $abort"); + } + } + }elsif (($dataline eq ");") && (($db_driver eq "SQLite") || ($db_driver eq "mysql")|| ($db_driver eq "ODBC"))) { + + #--------------------------------------------------------------- + # Likewise, if this is SQLite and the line ends with a ; + #--------------------------------------------------------------- + + if ($debug > 1) { + writeDebug("Using Small Buffer Syntax"); + } + + $buffer .= $dataline . "\n"; + + if (!$abort) { + if ($debug > 1) { + writeDebug("Executing: $buffer"); + } + + my $sql_handle = sqlStmt($db_handle,trimstring($buffer)); + + if ($debug > 1) { + writeDebug("Buffer returned SQL handle $sql_handle"); + } + + if ($sql_handle) { + $retcode = 1; + }else{ + $retcode = 0; + $abort = 1; + } + + $execcount++; + + undef $sql_handle; + $buffer = ""; + + if ($debug > 1) { + writeDebug("Sent $execcount statements. Abort Flag: $abort"); + } + } + + + }else{ + + #--------------------------------------------------------------- + # Finish processing the dataline if it's not null. + #--------------------------------------------------------------- + + if (length($dataline) > 1) { + if (($dataline =~ /;/) && (($db_driver eq "SQLite") || ($db_driver eq "mysql") || ($db_driver eq "ODBC"))) { + #--------------------------------------------------------------- + # If this is a single line and this is SQLite, we need to send + # the dataline. + #--------------------------------------------------------------- + + $buffer .= $dataline . "\n"; + + if (!$abort) { + if ($debug > 1) { + writeDebug("Executing: $buffer"); + } + + my $sql_handle = sqlStmt($db_handle,trimstring($buffer)); + + if ($debug > 1) { + writeDebug("Buffer returned SQL handle $sql_handle"); + } + + if ($sql_handle) { + $retcode = 1; + }else{ + $retcode = 0; + $abort = 1; + } + + $execcount++; + + undef $sql_handle; + $buffer = ""; + + if ($debug > 1) { + writeDebug("Sent $execcount statements. Abort Flag: $abort"); + } + } + + }else{ + #--------------------------------------------------------------- + # Otherwise we need to add the line to the buffer. + #--------------------------------------------------------------- + + if ($debug > 3) { + writeDebug("Appending \"$dataline\" to buffer"); + } + + + $buffer .= $dataline . "\n"; + } + } + } + } + close FHANDLE; + if ($debug > 1) { + writeDebug("File closed"); + } + + }else{ + if ($debug > 1) { + writeDebug("DSN ($db_handle) shutting down, could not open $sqlfilename"); + } + $_lastsqlstmt = "runSQLScript Open $sqlfilename"; + $_lastsqlerror = "runSQLScript could not open $sqlfilename"; + endDSN("",$db_handle); + return 0; + } + + #--------------------------------------------------------------- + # If we haven't sent the buffer at all yet, do so now. + # + # mysql in particular can accept the entire script in a single + # transmission. + #--------------------------------------------------------------- + + if ((!$execcount) && (!$abort)) { + if ($debug > 1) { + writeDebug("Large Buffer Syntax Detected"); + writeDebug("Executing: $buffer"); + } + + my $sql_handle = sqlStmt($db_handle,trimstring($buffer)); + + if ($debug > 1) { + writeDebug("Buffer returned SQL handle $sql_handle"); + } + + if ($sql_handle) { + $retcode = 1; + $execcount++; + }else{ + $retcode = 0; + $abort = 1; + } + + if ($debug > 1) { + writeDebug("Sent $execcount statements. Abort Flag: $abort"); + } + + } + + + #--------------------------------------------------------------- + # cleanup and bail + #--------------------------------------------------------------- + + if ($debug > 1) { + writeDebug("Executed: $execcount statements. Abort Flag: $abort"); + } + + undef $sql_handle; + + if ($debug > 1) { + writeDebug("DSN: $db_handle closing. Returning: $retcode"); + } + + endDSN("",$db_handle); + + return $retcode; + +} + +#---------------------------------------------------------------------------- +sub GetLastSQLStmt{ + # + # Get last SQL Stmt + # + # This is stored as a local (library) variable until requested + # + # ------------------------------------------------------------------------------ + + return $_lastsqlstmt; +} + + +#---------------------------------------------------------------------------- +sub GetLastSQLError{ + # + # Get last SQL error message + # + # This is stored as a local (library) variable until requested + # + # ------------------------------------------------------------------------------ + + return $_lastsqlerror; +} + +#---------------------------------------------------------------------------- +sub filterfield { + # + # Escape a SQL field + # + # Usage: filterfield(String) + # + # ------------------------------------------------------------------------------ + + if ($debug > 1) { + writeDebug("Start"); + } + + my $tempvar = shift; + + if ($debug > 4) { + writeDebug($tempvar); + } + + if ($tempvar eq $null) { + return $tempvar; + } + + $tempvar =~ s/'/''/g; # Escape quotes + $tempvar =~ s/"/''/g; # Escape quotes + + if ($debug > 4) { + writeDebug($tempvar); + } + + if ($debug > 1) { + writeDebug("Exit"); + } + + return $tempvar; +} + + +#---------------------------------------------------------------------------- +sub timestringtosql{ + # + # Convert a time string (YYYYMMDDHHMMSS) to SQL time + # + # ------------------------------------------------------------------------------ + + my $input_time = shift; + my $output_time = 0; + + ($Y,$M,$D,$h,$m,$s) = unpack 'A4 A2 A2 A2 A2 A2', $input_time; + $Y = int $Y; + if ($Y > 0) { + $output_time = "$Y-$M-$D $h:$m:$s"; + } + + return $output_time; + +} + +#---------------------------------------------------------------------------- +sub sqltotimestring{ + # + # Convert a SQL time to a time string (YYYYMMDDHHMMSS) + # + # ------------------------------------------------------------------------------ + + my $input_time = shift; + my $output_time = 0; + + $output_time = substr($input_time,0,4) . substr($input_time,5,2) . substr($input_time,8,2) . substr($input_time,11,2) . substr($input_time,14,2) . "00"; + + return $output_time; + +} + +#---------------------------------------------------------------------------- +sub pruneDatabase{ + # + # Prune the Database based on a Cut Off Time + # + # Parameter: Time (SQL format date/time) + # Returns true or false. + # + # ------------------------------------------------------------------------------ + + my $cutofftime = shift; + my $iRetCode = 1; + + my $db_handle = &StartDSN; + + my $Stmt = "DELETE FROM $db_table_tvlistings WHERE starttime < '$cutofftime';"; + + my $sth = SQLStmt($db_handle,$Stmt); + + if ($sth) { + $iRetCode = 1; + }else{ + writeDebug("Failed:"); + writeDebug(&GetLastSQLStmt); + writeDebug(&GetLastSQLError); + $iRetCode = 0; + } + + endDSN($sth,$db_handle); + + return $iRetCode; + +} + +1; + diff --git a/rg_guide.pl b/rg_guide.pl new file mode 100644 index 0000000..26e8a58 --- /dev/null +++ b/rg_guide.pl @@ -0,0 +1,1450 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson +# with bits by Kanji T. Bates +# Theme Stuff based upon ReplaySchedule.pl by Kevin J. Moye +# $Id: rg_guide.pl,v 1.5 2003/11/04 00:31:05 pvanbaren Exp $ +# +# SCHEDULE RESOLVER MODULE: RG_GUIDE +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- +#----------------------------------------------------------------------------------- +# +# The Schedule interface must define the following functions. +# All functions must be defined +# +# getFreshScheduleTable ( $replayid ) +# - $replayid is the database identifier of the unit to check +# - download a fresh set of schedule information from the replaytv +# - must save the schedule information so a cached copy can be loaded later +# - returns 0 if successful +# +# getCachedScheduleTable ( $replayid ) +# - $replayid is the database identifier of the unit to check +# - load in the previously cached copy of the schedule information +# - returns 0 if successful +# +# ProcessScheduleTable ( ) +# - called after all tables are loaded, but prior to displaying any details +# - prepares the schedule information for use and initialize any related variables +# - does not return any value +# +# compareScheduleTable ( $Stmt ) +# - $Stmt is a database query statement that returns the list of shows +# to be displayed +# - process all schedule tables to prepare scheduling details +# and priorities for the selected shows +# - called after all tables are loaded, but prior to displaying any details +# - does not return any value +# +# getScheduleDetails ( $programid , $timing ) +# - $programid is the database identifier the program to check +# - $timing is 0 for a past show, 1 for a present show, 2 for a future show +# - returns an icon or text string to be inserted into the html code +# indicating if the show is to scheduled to be recorded. +# - returns a "" string if no information available +# - may set the global $bgcolor variable to determing table background color +# +# AboutScheduler +# - Returns optional text which is placed in the program log file. +# +# SchedulerDoBatchUpdate +# - If some type of nightly processing is perferred or required this should +# return true (1), otherwise return 0. +# +# SchedulebarSupported +# - If the module supports the ScheduleBar (within replayguide.pl) this should +# return true (1), otherwise return 0. +# +# ToDoSupported +# - If the module supports the ToDo List (within replayguide.pl) this should +# return true (1), otherwise return 0. +# +#----------------------------------------------------------------------------------- + +require HTTP::Request; +require HTTP::Headers; +require LWP::UserAgent; +use Time::Local; +use POSIX qw( strftime getcwd ); + +my $_version = "Personal ReplayGuide|Simple Scheduler Resolver Module|1|1|201|Lee Thompson,Philip Van Baren,Kanji T. Bates,Kevin J. Moye"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_replay.pl'; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#------------------------------------------------------------------------------------ +# Set up locals +#------------------------------------------------------------------------------------ + +my $program_starttime = ""; +my $program_title = ""; +my $program_tuning = ""; +my $program_minutes = 0; +my $program_quality = 2; +my $program_guaranteed = 1; +my $program_recurring = 1; +my $program_category = 0; +my $program_beforepad = 0; +my $program_afterpad = 0; +my $program_daysofweek = 127; +my $program_keep = 1; +my $program_replaytv = 0; +my $program_stop = ""; +my $program_length = 0; +my $program_icon = ""; +my $program_true_start = ""; +my $display_time = ""; +my $showlist = ""; + +#------------------------------------------------ +sub getCachedScheduleTable { + + my $retcode = 0; + my $replayid = shift; + + #------------------------------------------------------------------- + # Read the snapshot files into memory + #------------------------------------------------------------------- + + my $replayaddr = $rtvaddress{$replayid}; + my $replaylabel = $rtvlabel{$replayid}; + + + if (open(SNAPSHOT,"<$rtv_snapshotpath/$replayaddr.bin")) { + binmode SNAPSHOT; + ($junk,$junk,$junk,$junk,$junk,$junk,$junk,$size,$junk,$junk,$junk,$junk,$junk) = stat("$rtv_snapshotpath/$replayaddr.bin"); + read SNAPSHOT,$snapshotbody,$size; + close SNAPSHOT; + if (length($snapshotbody) == $size) { + $retcode = 0; + writeDebug("Using cached GuideSnapshot for ReplayTV \#$replayid \"$replaylabel\" at $replayaddr"); + }else{ + writeDebug("Warning! Attempt to read '$rtv_snapshotpath/$replayaddr.bin' failed (wrong size)"); + $retcode = 1; + } + }else{ + writeDebug("Warning! Attempt to open '$rtv_snapshotpath/$replayaddr.bin' failed (not present)"); + $retcode = 1; + } + return $retcode; +} + +#------------------------------------------------ +sub ProcessScheduleTable { + # Process the schedule tables to create ReplayTV Events + #--------------------------------------------------------------------------- + + #------------------------------------------------------------------- + # Collect ReplayTV Events + #------------------------------------------------------------------- + + $eventcount = collectRTVChannels($replaylist,1); + writeDebug("There are $eventcount ReplayTV Events"); +} + +#------------------------------------------------ +sub getFreshScheduleTable { + # Refresh the tables used to determine scheduled programs + #--------------------------------------------------------------------------- + my $retcode = 0; + my $replayid = shift; + my $replayaddr = $rtvaddress{$replayid}; + my $replaylabel = $rtvlabel{$replayid}; + my $snapshottime = time; + my $specialdebug = 0; + + $guideptr = 0; + + if ($specialdebug) { + writeDebug("getFreshScheduleTable::starting($replayid)"); + } + + if (length($replayaddr) < 1) { + writeDebug("getFreshScheduleTable::replayaddr is null"); + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Exiting(1)"); + } + + return 1; + } + + if ($rtvport{$replayid} != 80) { + $replaycmd = "http://$replayaddr:$rtvport{$replayid}/http_replay_guide-get_snapshot?guide_file_name=0"; + }else{ + $replaycmd = "http://$replayaddr/http_replay_guide-get_snapshot?guide_file_name=0"; + } + + $ua = LWP::UserAgent->new; + $request = HTTP::Request->new(GET => $replaycmd); + $response = $ua->request($request); + + if ($response->is_success) { + writeDebug("Downloaded GuideSnapshot from ReplayTV \#$replayid \"$replaylabel\" at $replayaddr using $replaycmd"); + $guidesnapshot = $response->content; + } else { + # + # If we can't contact the unit, try to just use the + # cache. + # + + writeDebug("Warning! Could Not Contact $replayaddr for a fresh snapshot"); + + if (open(SNAPSHOT,"<$rtv_snapshotpath/$replayaddr.bin")) { + binmode SNAPSHOT; + ($junk,$junk,$junk,$junk,$junk,$junk,$junk,$size,$junk,$junk,$junk,$junk,$junk) = stat("$rtv_snapshotpath/$replayaddr.bin"); + read SNAPSHOT,$snapshotbody,$size; + close SNAPSHOT; + if (length($snapshotbody) == $size) { + writeDebug("getFreshScheduleTable::Warning! Using cached information for ReplayTV \#$replayid \"$replaylabel\" at $replayaddr"); + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Exiting(0)"); + } + + return 0; + }else{ + writeDebug("getFreshScheduleTable::Attempt to read cached '$rtv_snapshotpath/$replayaddr.bin' failed (wrong size)"); + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Exiting(1)"); + } + + return 1; + } + }else{ + writeDebug("getFreshScheduleTable::Attempt to open cached '$rtv_snapshotpath/$replayaddr.bin' failed (not present)"); + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Exiting(1)"); + } + + return 1; + } + } + + #-------------------------------------------------------------- + # Strip off extra bits + #-------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Trimming Data"); + } + + + $snapshotbody = ""; + ($guidetag,$junk,$snapshotbody,$junk2) = split(/#####/, $guidesnapshot, 9); + + #-------------------------------------------------------------- + # Update Database + #-------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Parsing Header"); + } + + &ParseRTVHeader; + + if ($specialdebug) { + writeDebug("getFreshScheduleTable::SV: $guideheader{snapshotversion} OS: $guideheader{osversion} CC: $guideheader{channelcount}"); + writeDebug("getFreshScheduleTable::$category"); + } + + my $replayosversion = $guideheader{snapshotversion} * 10 + 30 + $guideheader{osversion}; + my $guideversion = $guideheader{snapshotversion}; + my $categories = $category; + + $Stmt = "UPDATE $db_table_replayunits SET categories = '$categories', " . + "replayosversion = '$replayosversion', " . + "guideversion='$guideversion'" . + "WHERE replayid = '$replayid';"; + + # $Stmt = "UPDATE $db_table_replayunits SET lastsnapshot = $snapshottime WHERE replayid = '$replayid';"; + #-------------------------------------------------------------- + # Dump Snapshot to Disk + #-------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Dumping to Disk"); + } + + + if (open(SNAPSHOT,">$rtv_snapshotpath/$replayaddr.bin")) { + binmode SNAPSHOT; + print SNAPSHOT $snapshotbody; + close SNAPSHOT; + + my $db_handle = &StartDSN; + + if (sqlStmt($db_handle,$Stmt)) { + writeDebug("getFreshScheduleTable::Refresh for ReplayTV \#$replayid \"$replaylabel\" at $replayaddr successful, cache saved successfully, database update successful"); + }else{ + writeDebug("getFreshScheduleTable::Refresh for ReplayTV \#$replayid \"$replaylabel\" at $replayaddr successful, cache saved successfully, database update failed"); + } + + endDSN("",$db_handle); + undef $db_handle; + }else{ + writeDebug("getFreshScheduleTable::Warning! Attempt to write '$rtv_snapshotpath/$replayaddr.bin' failed"); + } + + if ($specialdebug) { + writeDebug("getFreshScheduleTable::Exiting(0)"); + } + + return 0; +} + + +#------------------------------------------------ +sub compareScheduleTable { + # Compare the scheduled events with the displayed events + # This assumes $Stmt is defined such that it returns the displayed events + #--------------------------------------------------------------------------- + + my $Stmt = shift; + + writeDebug("Building show list for $sql_start through $sql_end"); + writeDebug("Building show list containing channels $inp_firsttune - $inp_lasttune"); + writeDebug("SQL: $Stmt"); + + my $db_handle = &StartDSN; + my $sth = sqlStmt($db_handle,$Stmt); + + if ($sth) { + + while ( $row = $sth->fetchrow_hashref ) { + $program_id = $row->{'programid'}; + $program_start = sqltotimestring($row->{'starttime'}); + $program_true_start = $program_start; + $program_stop = sqltotimestring($row->{'endtime'}); + $program_true_stop = $program_stop; + $program_title = $row->{'title'}; + $program_subtitle = $row->{'subtitle'}; + $program_desc = $row->{'description'}; + $program_tuning = $row->{'tuning'}; + $program_channel = $row->{'channel'}; + + $program_category = $row->{'category'}; + $program_mpaarating = $row->{'mpaarating'}; + $program_vchiprating = $row->{'vchiprating'}; + $program_episodenum = $row->{'episodenum'}; + $program_movieyear = int $row->{'movieyear'}; + $program_stereo = int $row->{'stereo'}; + $program_repeat = int $row->{'repeat'}; + $program_starrating = $row->{'starrating'}; + $program_captions = $row->{'captions'}; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($program_start)) { + $program_stop = as_time_string($rng_end); + $fudged_length = 1; + } + + #------------------------------------------------------------------- + # Prepare Variables and Calculate Running Time + #------------------------------------------------------------------- + + $program_length = getMinutes($program_start,$program_stop); + $display_length = $program_length; + + + if ($program_id eq $prev_id) { + next; + } + + $tempvar = isScheduled($program_true_start,$program_channel,$program_title,$program_repeat); + + if (length($tempvar) > 0) { + if (length($showlist) > 0) { + $showlist .= "|"; + } + $showlist .= $tempvar; + } + + + + $prev_id = $program_id; + + } + } + + endDSN("",$db_handle); + undef $db_handle; + + return 1; +} + + +#------------------------------------------------ +sub getScheduleDetails { + # + # Check if a show is scheduled, and if so, return an icon + #--------------------------------------------------------------------------- + my $inp_programid = shift; + my $inp_timing = shift; + my $retval = ""; + my $theme_icon = ""; + my $specialdebug = 0; + my $Stmt = ""; + + + if ($specialdebug) { + writeDebug("getScheduleDetails::starting($inp_programid,$inp_timing)"); + } + + my $db_handle = &StartDSN; + $Stmt = "SELECT * FROM $db_table_tvlistings WHERE programid = '$inp_programid';"; + + my $sth = sqlStmt($db_handle,$Stmt); + + if ($specialdebug) { + writeDebug("getScheduleDetails::DSN: $db_handle STH: $sth ($Stmt)"); + } + + + if ( $sth ) { + $row = $sth->fetchrow_hashref; + + $program_starttime = sqltotimestring($row->{'starttime'}); + $program_true_start = $program_starttime; + $program_stop = sqltotimestring($row->{'endtime'}); + $program_tuning = int $row->{'tuning'}; + $program_title = $row->{'title'}; + $program_subtitle = $row->{'subtitle'}; + $program_desc = $row->{'description'}; + $program_category = $row->{'category'}; + $program_advisories = $row->{'advisories'}; + $program_mpaarating = $row->{'mpaarating'}; + $program_vchiprating = $row->{'vchiprating'}; + $program_episodenum = $row->{'episodenum'}; + $program_movieyear = int $row->{'movieyear'}; + $program_stereo = int $row->{'stereo'}; + $program_repeat = int $row->{'repeat'}; + $program_starrating = $row->{'starrating'}; + $program_captions = $row->{'captions'}; + $program_channel = $row->{'channel'}; + + ($program_stars,$junk) = split(/\//,$program_starrating); + + $fudged_length = 0; + + if (as_epoch_seconds($program_stop) < as_epoch_seconds($program_starttime)) { + $program_stop = as_time_string($rng_end); + $fudged_length = 1; + } + + $program_length = getMinutes($program_starttime,$program_stop); + + }else{ + writeDebug("getScheduleDetails::Lookup Failed: $Stmt / Error: " . &GetLastSQLError()); + } + + endDSN($sth,$db_handle); + + + if ($rtvaccess > 0) { + if ($specialdebug) { + writeDebug("getScheduleDetails::rtvaccess enabled, getting schedule icons"); + writeDebug("getScheduleDetails::$program_true_start,$program_channel,$program_title,$program_repeat"); + } + + $isScheduled = isScheduled($program_true_start,$program_channel,$program_title,$program_repeat); + if ($specialdebug) { + writeDebug("getScheduleDetails::isScheduled: $isScheduled"); + writeDebug(as_hhmm(as_epoch_seconds($program_true_start))); + } + if (length($isScheduled) > 0) { + $retval .= buildIcon($isScheduled); + if ($showrtvthemes) { + if (length($showlist) < 1) { + $theme_icon = getThemeIcon($isScheduled); + }else{ + $theme_icon = getThemeIcon($showlist); + } + } + $retval .= $theme_icon; + } + }else{ + if ($specialdebug) { + writeDebug("getScheduleDetails::rtvaccess disabled"); + } + + $isScheduled = 0; + } + + #------------------------------------------------------------------- + # Color Code the Column + #------------------------------------------------------------------- + + if (length($theme_icon)) { + $bgcolor = $color_theme[ $inp_timing ]; + } elsif(length($retval)) { + $bgcolor = $color_scheduled[ $inp_timing ]; + } + + if ($specialdebug) { + writeDebug("getScheduleDetails::exiting($retval)"); + } + + return $retval; +} + +#--------------------------------------------------------------------------------------- +sub getThemeIcon { + # + # Return the Icon for the Theme Recording + # + # Parameter: rtvevent structure, separate multiples with a | + # + # ------------------------------------------------------------------------------ + + my $rtvdata = shift; + my $specialdebug = 0; # Enable Debug Logging + my $programtitle = $program_title; + my $retaddr = ""; + my $themetext = ""; + my $theme_icon_alt = ""; + my $themeicon = ""; + + my $ctr = 0; + my $overlap_flag = 0; + + my $curr_rtv = ""; + my $curr_show = ""; + + my $slotstart = as_epoch_seconds($program_true_start); + my $slotstop = as_epoch_seconds($program_stop) - 1; + my $showstart = 0; + my $showstop = 0; + + my $laststart = 0; + my $laststop = 0; + my $lasttuning = 0; + my $lastcreate = 0; + my $lastguaranteed = 0; + my $lasttype = 0; + + if ($specialdebug) { + writeDebug("getThemeIcon::starting($rtvdata)"); + writeDebug("getThemeIcon::" . as_hhmm(as_epoch_seconds($program_true_start)) . " for $program_tuning ($program_channel) \"$programtitle\""); + } + + if (length($rtvdata) < 1) { + #---------------------------------------------- + # No scheduled data, nothing to do! + #---------------------------------------------- + if ($specialdebug) { + writeDebug("getThemeIcon::nothing to do"); + writeDebug("getThemeIcon::(exiting)"); + } + return $retval; + }else{ + if ($specialdebug) { + writeDebug("getThemeIcon::$rtvdata"); + } + } + + if (length(isTheme($program_title)) < 1) { + #---------------------------------------------- + # Not a theme, might as well just quit now! + #---------------------------------------------- + if ($specialdebug) { + writeDebug("getThemeIcon::$program_title is not a theme"); + writeDebug("getThemeIcon::(exiting)"); + } + return $retval; + } + + + + #------------------------------------------------------ + # Initialize + #------------------------------------------------------ + + for ( split /,/, $replaylist ) { + /,/; + $curr_rtv = $rtvaddress{$_}; + $ctr = 0; + + do { + $ctr++; + $curr_show = $scheduledshows{$curr_rtv}[$ctr]; + $scheduledshows{$curr_rtv}[$ctr] = ""; + } while (length($curr_show) > 0); + + $retval{$curr_rtv} = ""; + } + + #----------------------------------------------------- + # For each Replay build a list of shows that overlap + # with the slot. + # + # (Basically this sorts by address) + #----------------------------------------------------- + + for ( split /,/, $replaylist ) { + /,/; + + $curr_rtv = $rtvaddress{$_}; + $ctr = 0; + + for ( split /\|/, $rtvdata ) { + /\|/; + + (my $replayid,my $rtveventtime,my $guaranteed,my $channeltype,my $daysofweek,my $channelflags,my $beforepadding,my $afterpadding,my $showlabel,my $channelname,my $themeflags,my $themestring,my $thememinutes,my $rtvcreate,my $scheduledtime,my $programtuning,my $displaylength,my $programtruestart) = split(/;/,$_); + $eventtime = timegm(gmtime($rtveventtime)); + + $showstart = $scheduledtime; + $showstop = $scheduledtime + ($displaylength * 60) -1; + + if ($curr_rtv eq $rtvaddress{$replayid}) { + $overlap_flag = 0; + $overlap_flag = &doTimesOverlap($slotstart,$slotstop,$showstart,$showstop); + + if ($specialdebug) { + writeDebug("getThemeIcon::$replayid,OF:$overlap_flag,SLOTS:$slotstart,SLOTE:$slotstop,SHOWS:$showstart,SHOWE:$showstop;EVENT:$eventtime;CT:$channeltype;SL:$showlabel"); + } + + if ($overlap_flag) { + $ctr++; + $scheduledshows{$rtvaddress{$replayid}}[$ctr] = $_; + if ($specialdebug) { + writeDebug("getThemeIcon::found a candidate for $rtvaddress{$replayid} (#$ctr)"); + } + } + } + } + } + + + #---------------------------------------------------- + # Now that we have the list of potentials we need + # to do conflict resolution (if there's more than one + # qualifying show) for each Replay. + #---------------------------------------------------- + + if ($specialdebug) { + writeDebug("getThemeIcon::resolving conflicts"); + } + + for ( split /,/, $replaylist ) { + /,/; + + $curr_rtv = $rtvaddress{$_}; + $ctr = 0; + + if ($specialdebug) { + writeDebug("getThemeIcon::resolving conflicts for $curr_rtv"); + } + + do { + $ctr++; + $curr_show = $scheduledshows{$curr_rtv}[$ctr]; + + if ($specialdebug) { + writeDebug("getThemeIcon::$curr_rtv: $ctr \"$curr_show\""); + } + + if (length($curr_show) > 0) { + (my $replayid,my $rtveventtime,my $guaranteed,my $channeltype,my $daysofweek,my $channelflags,my $beforepadding,my $afterpadding,my $showlabel,my $channelname,my $themeflags,my $themestring,my $thememinutes,my $rtvcreate,my $scheduledtime,my $programtuning,my $displaylength,my $programtruestart) = split(/;/,$curr_show); + $eventtime = timegm(gmtime($rtveventtime)); + + if (length($showlabel) > 0) { + $showlabel = normalizertvname($showlabel); + } + + if (length($themestring) > 0) { + $themestring = normalizertvname($themestring); + } + + if ($specialdebug) { + writeDebug("getThemeIcon::$curr_rtv: $channeltype $showlabel "); + } + + + $showstart = $scheduledtime; + $showstop = $scheduledtime + ($displaylength * 60) -1; + + $overlap_flag = 0; + $overlap_flag = doTimesOverlap($showstart,$showstop,$laststart,$laststop); + + if ($overlap_flag > 0) { + if ($specialdebug) { + writeDebug("getThemeIcon::$curr_rtv: $channeltype $showlabel: Overlap Detected. Using Mode: $rtv_version{$replayid} for Conflict Checks for $showlabel ($themestring) type: $channeltype"); + } + + if ($rtv_version{$replayid} == 2) { + #-------------------------------------------------------- + # 5.x Conflict Resolution + #-------------------------------------------------------- + if ($rtvcreate > $lastcreate) { + $retval{$curr_rtv} = $image_tw; + }else{ + $retval{$curr_rtv} = $image_tl; + } + }else{ + #-------------------------------------------------------- + # 4.x Conflict Resolution + #-------------------------------------------------------- + if ($programtuning > $lasttuning) { + $retval{$curr_rtv} = $image_tw; + }else{ + $retval{$curr_rtv} = $image_tl; + } + } + + + #--------------------------------------------------------------- + # If the previous one is guaranteed and this one isn't, this one + # will lose. + #--------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("getThemeIcon::$curr_rtv: $channeltype $showlabel: checking guaranteed levels $guaranteed vs $lastguaranteed"); + } + + + if ($guaranteed > $lastguaranteed) { + $retval{$curr_rtv} = $image_tw; + }else{ + $retval{$curr_rtv} = $image_tl; + } + + + #--------------------------------------------------------------- + # If it's up against a replaychannel (recurring or single) it + # loses immediately. + # + # NOTE: This may no longer be true for 5.0 + # + #--------------------------------------------------------------- + + if ($specialdebug) { + writeDebug("getThemeIcon::$curr_rtv: $channeltype $showlabel: checking to see if current overlap is not a theme ($channeltype)"); + } + + if (($channeltype == 1) || ($channeltype == 3 )) { + $retval{$curr_rtv} = $image_tl; + if (($programtuning == $lasttuning) && ($lasttype == 2)){ + #------------------------------------------------------- + # If it matches as both a replaychannel AND a theme, + # just hide the theme. + # + # If you'd rather see both comment the following line + # out. + # + #------------------------------------------------------- + $retval{$curr_rtv} = ""; + } + next; + } + + + #--------------------------------------------------------------- + # If the theme just won't fit, it goes away. + #--------------------------------------------------------------- + + if ($speicaldebug) { + writeDebug("getThemeIcon::$curr_rtv: $channeltype $showlabel: checking to see if $display_length fits in $thememinutes"); + } + + if ($thememinutes < $display_length) { + $retval{$curr_rtv} = $image_tl; + } + + $lasttuning = $programtuning; + $lastcreate = $rtvcreate; + $lastguaranteed = $guaranteed; + $lasttype = $channeltype; + }else{ + if ($channeltype == 2) { + if ($specialdebug) { + writeDebug("getThemeIcon::$curr_rtv: $channeltype $showlabel: won due to no overlap"); + } + + $retval{$curr_rtv} = $image_tw; + + $lasttuning = $programtuning; + $lastcreate = $rtvcreate; + $lastguaranteed = $guaranteed; + $lasttype = $channeltype; + }else{ + if ($specialdebug) { + writeDebug("getThemeIcon::$curr_rtv: $channeltype $showlabel: no winner this round (not a theme)"); + } + } + } + + $laststart = $showstart; + $laststop = $showstop; + } + + #------------------------------------------------------- + # If the only entry for this Replay's slot is a theme + # it wins automatically if the show fits in the theme. + #------------------------------------------------------- + + + if (($ctr == 2) && (length($scheduledshows{$curr_rtv}[$ctr]) < 1)) { + (my $replayid,my $rtveventtime,my $guaranteed,my $channeltype,my $daysofweek,my $channelflags,my $beforepadding,my $afterpadding,my $showlabel,my $channelname,my $themeflags,my $themestring,my $thememinutes,my $rtvcreate,my $scheduledtime,my $programtuning,my $displaylength,my $programtruestart) = split(/;/,$scheduledshows{$curr_rtv}[1]); + if ($channeltype == 2) { + if ($specialdebug) { + writeDebug("getThemeIcon::$themestring is winning by default"); + } + + if ($specialdebug) { + writeDebug("getThemeIcon::checking to see if $display_length fits in $thememinutes"); + } + + if ($thememinutes < $display_length) { + $retval{$curr_rtv} = $image_tl; + }else{ + $retval{$curr_rtv} = $image_tw; + } + } + } + + } while (length($curr_show) > 0); + + } + + #---------------------------------------------------- + # By this point we should have a winner for each + # Replay in the list. + # + # $retval{address} contains the winning or losing + # image name ($image_tw or $image_tl) - or null. + #---------------------------------------------------- + + + #---------------------------------------------------- + # Build the icon for each Replay + #---------------------------------------------------- + + for ( split /,/, $replaylist ) { + /,/; + + if (length($retval{$rtvaddress{$_}}) > 0 ) { + if (length($themeicon) > 0) { + $themeicon .= " / "; + } + + if ($retval{$rtvaddress{$_}} eq $image_tl) { + $themetext = "Theme in Conflict"; + } + if ($retval{$rtvaddress{$_}} eq $image_tw) { + $themetext = "Theme"; + } + + + $theme_icon_alt = $rtvlabel{$_} . " - " . $themetext; + + if ($showrtvicons) { + if (length($retval{$rtvaddress{$_}})) { + if (substr($retval{$rtvaddress{$_}},0,7) eq "http://" ) { + $themeicon .= "\"$theme_icon_alt\""; + }else{ + $themeicon .= "\"$theme_icon_alt\""; + } + if ($showrtvtext) { + $themeicon .= "($theme_icon_alt)"; + } + } + }else{ + if ($retval{$rtvaddress{$_}} eq $image_tl) { + $themetext = "Theme in Conflict"; + } + if ($retval{$rtvaddress{$_}} eq $image_tw) { + $themetext = "Theme"; + } + + if ($showrtvtext) { + $themeicon .= "$theme_icon_alt: $themetext"; + } + } + + } + } + + #---------------------------------------------------- + # Exit + #---------------------------------------------------- + + if ($specialdebug) { + writeDebug("getThemeIcon::themeicon: $themeicon"); + writeDebug("getThemeIcon::(exiting)"); + } + + + return $themeicon; +} + + +#--------------------------------------------------------------------------------------- +sub buildIcon { + # + # Build a RTV Status Icon + # + # Parameter: one or more rtvevent structs separated by a | + # + # ------------------------------------------------------------------------------ + + my $rtvdata = shift; + my $retval = ""; + my $program_icon = ""; + my $program_icon_alt = ""; + my $program_text = ""; + + if (length($rtvdata) < 1) { + return $retval; + } + + for ( split /\|/, $rtvdata ) { + /\|/; + (my $replayid,my $rtveventtime,my $guaranteed,my $channeltype,my $daysofweek,my $channelflags,my $beforepadding,my $afterpadding,my $showlabel,my $channelname,my $themeflags,my $themestring,my $thememinutes,my $rtvcreate,my $scheduledtime,my $programtuning,my $displaylength,my $programtruestart) = split(/;/,$_); + + my $recurring = 0; + my $theme = 0; + my $single = 0; + + if ($channeltype == 1) { + $recurring = 1; + } + + if ($channeltype == 2) { + $theme = 1; + } + + if ($channeltype == 3) { + $single = 1; + } + + + if ($recurring) { + if ($guaranteed) { + $program_icon = $image_gr; + $program_text = "Guaranteed, Recurring"; + + if ($afterpadding > 0) { + $program_icon = $image_apgr; + $program_text = "Guaranteed, Recurring, Post-Padded"; + } + if ($beforepadding > 0) { + $program_icon = $image_bpgr; + $program_text = "Guaranteed, Recurring, Pre-Padded"; + + } + if (($afterpadding > 0) && ($beforepadding > 0)) { + $program_icon = $image_ppgr; + $program_text = "Guaranteed, Recurring, Padded"; + } + }else{ + $program_icon = $image_r; + $program_text = "Recurring"; + + if ($afterpadding) { + $program_icon = $image_apr; + $program_text = "Recurring, Post-Padded"; + } + if ($beforepadding) { + $program_icon = $image_bpr; + $program_text = "Recurring, Pre-Padded"; + } + if (($afterpadding) && ($beforepadding)) { + $program_icon = $image_ppr; + $program_text = "Recurring, Padded"; + } + } + } + + if ($single) { + if ($guaranteed) { + $program_icon = $image_gs; + $program_text = "Guaranteed, Single"; + + if ($afterpadding) { + $program_icon = $image_apgs; + $program_text = "Guaranteed, Single, Post-Padded"; + } + if ($beforepadding) { + $program_icon = $image_bpgs; + $program_text = "Guaranteed, Single, Pre-Padded"; + } + if (($afterpadding) && ($beforepadding)) { + $program_icon = $image_ppgs; + $program_text = "Guaranteed, Single, Padded"; + } + }else{ + $program_icon = $image_s; + $program_text = "Single"; + if ($afterpadding) { + $program_icon = $image_aps; + $program_text = "Single, Post-Padded"; + } + if ($beforepadding) { + $program_icon = $image_bps; + $program_text = "Single, Pre-Padded"; + } + if (($afterpadding) && ($beforepadding)) { + $program_icon = $image_pps; + $program_text = "Single, Padded"; + } + } + } + + if ($theme) { + #------------------------------------------------------------ + # Themes are handled separately + #------------------------------------------------------------ + next; + } + + $program_icon_alt = $rtvlabel{$replayid} . " - " . $program_text; + + if (length($retval) > 0) { + $retval .= "/"; + } + + if ($showrtvicons) { + if (length($program_icon) > 0) { + if (substr($program_icon,0,7) eq "http://" ) { + $retval .= "\"$program_icon_alt\""; + }else{ + $retval .= "\"$program_icon_alt\""; + } + } + if ($showrtvtext) { + $retval .= "($program_icon_alt)"; + } + }else{ + if ($showrtvtext) { + $retval .= "$program_icon_alt: $program_text"; + } + } + } + + return $retval; +} + +#--------------------------------------------------------------------------------------- +sub isTheme { + # + # Determine if A Program is A Theme + # + # Parameter: text to match + # + # Returns array + # + # ------------------------------------------------------------------------------ + + my $searchfor = shift; + my $retval = ""; + my $specialdebug = 0; # Enable Debug Logging + my $ctr = 1; + + if (length($searchfor) > 0) { + #---------------------------------------------------- + # If program title is passed in, make sure it doesn't + # contain HTML coding or non alphas that the Replay + # does not use. + #---------------------------------------------------- + + $searchfor = convertfromhtml($searchfor); + $searchfor = normalizertvname($searchfor); + }else{ + #---------------------------------------------------- + # Otherwise, bail + #---------------------------------------------------- + if ($specialdebug) { + writeDebug("isTheme::null parameter, returning"); + } + return $retval; + } + + if ($specialdebug) { + writeDebug("isTheme::Looking for '$searchfor'"); + writeDebug("isTheme::$eventcount events to search"); + } + + do { + $match = 0; + + (my $replayid,my $rtveventtime,my $guaranteed,my $channeltype,my $daysofweek,my $channelflags,my $beforepadding,my $afterpadding,my $showlabel,my $channelname,my $themeflags,my $themestring,my $thememinutes,my $rtvcreate) = split(/;/,$rtvevent[$ctr]); + + if ($specialdebug) { + writeDebug("isTheme::event $ctr:$replayid,$rtveventtime,$guaranteed,$channeltype,$daysofweek,$channelflags,$beforepadding,$afterpadding,$showlabel,$channelname,$themeflags,$themestring,$thememinutes,$rtvcreate"); + } + + if (length($showlabel) > 0) { + $showlabel = normalizertvname($showlabel); + } + + if (length($themestring) > 0) { + $themestring = normalizertvname($themestring); + } + + if ($channeltype == 2) { + if ($specialdebug) { + writeDebug("isTheme::$searchfor==$themestring"); + } + + if ($themeflags & 4) { + if ($searchfor eq $themestring) { + $match = 1; + } + } + if ($themeflags & 8) { + if ($searchfor =~ $themestring) { + $match = 1; + } + } + if ($themeflags & 16) { + # Search Desc/Subtitle + } + + if ($match) { + if ($specialdebug) { + writeDebug("isTheme::match found (type $themeflags)"); + } + + if (length($retval) > 0) { + $retval .= "|"; + } + $retval .= $replayid; + } + + } + $ctr++; + } while ($ctr <= $eventcount); + + if ($specialdebug) { + writeDebug("isTheme::exiting($retval)"); + } + return $retval; + +} +#--------------------------------------------------------------------------------------- +sub isScheduled { + # + # Determine if A Program is Scheduled by one or more RTVs + # + # Parameters: scheduled time, channel ID (call letters), title, repeat flag + # + # ------------------------------------------------------------------------------ + + my $scheduledtime = as_epoch_seconds(shift); + my $channelid = shift; + my $programtitle = shift; # Optional + my $isrepeat = int shift; # Optional + my $retval = ""; + + my $specialdebug = 0; # Enable Debug Logging + my $ctr = 1; + my $match = 0; + + my $replayid = ""; + my $eventtime = ""; + my $guaranteed = ""; + my $channeltype = ""; + my $daysofweek = ""; + my $channelflags = ""; + my $beforepadding = ""; + my $afterpadding = ""; + my $showlabel = ""; + my $channelname = ""; + my $rtveventtime = 0; + + if (length($programtitle) > 0) { + + # If program title is passed in, make sure it doesn't + # contain HTML coding or non alphas that the Replay + # does not use. + + $programtitle = convertfromhtml($programtitle); + $programtitle = normalizertvname($programtitle); + } + + if ($specialdebug) { + writeDebug("isScheduled::Looking at " . &as_hhmm($scheduledtime) . " on $channelid for '$programtitle' repeat=$isrepeat"); + writeDebug("isScheduled::$eventcount events to search"); + } + + do { + $match = 0; + ($replayid,$rtveventtime,$guaranteed,$channeltype,$daysofweek,$channelflags,$beforepadding,$afterpadding,$showlabel,$channelname,$themeflags,$themestring,$thememinutes,$rtvcreate) = split(/;/,$rtvevent[$ctr]); + $eventtime = timegm(gmtime($rtveventtime)); + + if ($specialdebug) { + writeDebug("isScheduled::event $ctr:$replayid,$rtveventtime,$guaranteed,$channeltype,$daysofweek,$channelflags,$beforepadding,$afterpadding,$showlabel,$channelname,$themeflags,$themestring,$thememinutes,$rtvcreate"); + } + + + if (length($showlabel) > 0) { + $showlabel = normalizertvname($showlabel); + } + if (length($themestring) > 0) { + $themestring = normalizertvname($themestring); + } + + if ($specialdebug) { + writeDebug("isScheduled::$channelname==$channelid"); + } + + if ($channelname eq $channelid) { + if ($specialdebug) { + writeDebug("isScheduled::Match Found ($channelid) Type: $channeltype"); + } + + + if ($channeltype == 3) { + if ($eventtime == $scheduledtime) { + if (length($retval) > 0) { + $retval .= "|"; + } + $retval = $rtvevent[$ctr]; + $retval .= ";$scheduledtime;$program_tuning;$display_length;" . as_epoch_seconds($program_true_start); + } + } + + if ($channeltype == 1) { + (my $rtvsec,my $rtvmin,my $rtvhour,my $rtvmday,my $rtvmon,my $rtvyear,my $rtvwday,my $rtvyday,my $rtvisdst) = + localtime($eventtime); + + (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday,my $isdst) = + localtime($scheduledtime); + + if (($rtvhour == $hour) && ($rtvmin == $min)) { + + if ($specialdebug) { + writeDebug("isScheduled::$programtitle==$showlabel"); + } + + if ($programtitle eq $showlabel) { + $match = 1; + if ($specialdebug) { + writeDebug("isScheduled::Match Found ($showlabel)"); + writeDebug("isScheduled::Day of Week: $daysofweek (" . 2**$wday . ")"); + writeDebug("isScheduled::Repeat: $isrepeat, Channel Flags: $channelflags"); + } + + if ($daysofweek & (2**$wday)) { + $match = 1; + }else{ + $match = 0; + } + + if (($isrepeat) && ($channelflags & 32)) { + $match = 0; + } + if ($match) { + if (length($retval) > 0) { + $retval .= "|"; + } + $retval .= $rtvevent[$ctr]; + $retval .= ";$scheduledtime;$program_tuning;$display_length;" . as_epoch_seconds($program_true_start); + + } + } + } + } + + } + if ($channeltype == 2) { + if ($themeflags & 4) { + if ($programtitle eq $themestring) { + if ($specialdebug) { + writeDebug("isScheduled::Theme Match ($themestring) type 4"); + } + + $match = 1; + } + } + if ($themeflags & 8) { + if ($programtitle =~ $themestring) { + if ($specialdebug) { + writeDebug("isScheduled::Theme Match ($themestring) type 8"); + } + $match = 1; + } + } + if ($themeflags & 16) { + # Search Desc/Subtitle + } + + if ($match) { + if (length($retval) > 0) { + $retval .= "|"; + } + $retval .= $rtvevent[$ctr]; + $retval .= ";$scheduledtime;$program_tuning;$display_length;" . as_epoch_seconds($program_true_start); + + } + + } + $ctr++; + } while ($ctr <= $eventcount); + + + if ($specialdebug) { + writeDebug("isScheduled::exiting($retval)"); + } + + return $retval; +} + + +#------------------------------------------------ +sub AboutScheduler{ + # About Schedule Module + #--------------------------------------------------------------------------- + + my $about = ""; + $about .= "rg_guide by Lee Thompson, Kevin J. Moye and Philip Van Baren. "; + $about .= "Simple, slow and buggy ;)"; + + return $about; +} + + +#------------------------------------------------ +sub SchedulerDefaultRefresh{ + # + # Refresh options for the scheduler module. + # + # Time in minutes between guide refreshes + # (0 is batch only if do_batch_update is enabled, otherwise completely + # disabled.) + #--------------------------------------------------------------------------- + + my $retcode = 15; + + if ($defaultrefreshinterval != -1) { + $retcode = $defaultrefreshinterval; + } + + return $retcode; +} + +#------------------------------------------------ +sub SchedulerDoBatchUpdate{ + # Refresh options for the scheduler module. + # + # Should scheduler module be updated at SQL time? + #--------------------------------------------------------------------------- + + return 0; +} + + +#------------------------------------------------ +sub SchedulebarSupported{ + # Does this processor support the schedulebar? + #--------------------------------------------------------------------------- + + return 0; +} + +#------------------------------------------------ +sub ToDoSupported{ + # Does this processor support the todolist? + #--------------------------------------------------------------------------- + + return 0; +} + + +1; diff --git a/rg_info.pl b/rg_info.pl new file mode 100644 index 0000000..b1f219e --- /dev/null +++ b/rg_info.pl @@ -0,0 +1,200 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson +# +# DATABASE INFO +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +#------------------------------------------------------------------------------------ +# About the only reason to edit this file now is to edit the listingmap or favorites +# lists. +# +# For database configuration you are better off editing prg.conf's [database] section +# or creating a database.conf. +# +#------------------------------------------------------------------------------------ + +use POSIX qw( strftime getcwd ); + +my $_version = "Personal ReplayGuide|Database Initialization Library|1|2|103|Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_config.pl'; + + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#------------------------------------------------------------------- +# Define a mapping from IP address to xmltv or datadirect headend +# listings. +# +# If specific replay units use other than the standard listings, +# define the specific mapping here. +# Separate multiple headends with the comma "," +#------------------------------------------------------------------- +%listingmap = ( + "0.0.0.0", "na.xml", +); + + +#------------------------------------------------------------------- +# Define the favorite channels lists +# Uncomment these lines and change the labels/channel lists +# to enable the favorite channels selection box +#------------------------------------------------------------------- +#%favorites = ( +# "Broadcast", "10,11,42,59,60", +# "Movies", "550,551,575,576,533,534", +#); + + + +#------------------------------------------------------------------------------------ +sub InitDB{ + # + # Load Database Configuration (getconfig does all the work) + # + #------------------------------------------------------------------------------------ + + $db_driver = "SQLite"; # Database Type (ODBC,mysql,SQLite) + $db_host = "localhost"; # Computer running SQL server + $db_name = "tvlistings"; # Database Name + $db_user = "username"; # Database User + $db_pass = "password"; # Database Password + + $db_table_replayunits = "replayunits"; # Table for ReplayTV Units + $db_table_channels = "channels"; # Table for Channel Information + $db_table_tvlistings = "tvlistings"; # Table for Television Listings + $db_table_schedule = "schedule"; # Table for Scheduled Recordings + $db_table_castcrew = "castcrew"; # Table for Cast and Crew Data + + my $configfile = "database.conf"; # This is optional + my $configstatus = getConfig($configfile); # Read Configuration + + + if (length($db_dsn_name) < 1) { + $db_dsn_name = $db_name; + } + + $db_conflict = 0; + + if (($db_table_replayunits eq $db_table_channels) || ($db_table_replayunits eq $db_table_tvlistings) || ($db_table_replayunits eq $db_table_schedule) || ($db_table_replayunits eq db_table_castcrew)) { + $db_conflict = 1; + } + + if (($db_table_channels eq $db_table_tvlistings) || ($db_table_channels eq $db_table_schedule) || ($db_table_channels eq db_table_castcrew)) { + $db_conflict = 1; + } + + if (($db_table_tvlistings eq $db_table_schedule) || ($db_table_tvlistings eq db_table_castcrew)) { + $db_conflict = 1; + } + + if ($db_table_schedule eq db_table_castcrew) { + $db_conflict = 1; + } + + return $configstatus; + + + +} + +1; + diff --git a/rg_null.pl b/rg_null.pl new file mode 100644 index 0000000..339fa86 --- /dev/null +++ b/rg_null.pl @@ -0,0 +1,180 @@ +#!/usr/bin/perl +# +# +# PERSONAL REPLAYGUIDE SCHEDULER MODULE +# NULL MODULE (for no RTV support) +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2004 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +#----------------------------------------------------------------------------------- +# +# The Schedule interface must define the following functions. +# All functions must be defined +# +# getFreshScheduleTable ( $replayid ) +# - $replayid is the database identifier of the unit to check +# - download a fresh set of schedule information from the replaytv +# - must save the schedule information so a cached copy can be loaded later +# - returns 0 if successful +# +# getCachedScheduleTable ( $replayid ) +# - $replayid is the database identifier of the unit to check +# - load in the previously cached copy of the schedule information +# - returns 0 if successful +# +# ProcessScheduleTable ( ) +# - called after all tables are loaded, but prior to displaying any details +# - prepares the schedule information for use and initialize any related variables +# - does not return any value +# +# compareScheduleTable ( $Stmt ) +# - $Stmt is a database query statement that returns the list of shows +# to be displayed +# - process all schedule tables to prepare scheduling details +# and priorities for the selected shows +# - called after all tables are loaded, but prior to displaying any details +# - does not return any value +# +# getScheduleDetails ( $programid , $timing ) +# - $programid is the database identifier the program to check +# - $timing is 0 for a past show, 1 for a present show, 2 for a future show +# - returns an icon or text string to be inserted into the html code +# indicating if the show is to scheduled to be recorded. +# - returns a "" string if no information available +# - may set the global $bgcolor variable to determing table background color +# +# AboutScheduler +# - Returns optional text which is placed in the program log file. +# +# SchedulerDoBatchUpdate +# - If some type of nightly processing is perferred or required this should +# return true (1), otherwise return 0. +# +# SchedulebarSupported +# - If the module supports the ScheduleBar (within replayguide.pl) this should +# return true (1), otherwise return 0. +# +# ToDoSupported +# - If the module supports the ToDo List (within replayguide.pl) this should +# return true (1), otherwise return 0. +# +#----------------------------------------------------------------------------------- + +my $_version = "Personal ReplayGuide|Null Schedule Resolver Module|1|0|4|Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#------------------------------------------------------------------------------------ + +sub getFreshScheduleTable { + return 1; +} + +sub getCachedScheduleTable { + return 1; +} + +sub ProcessScheduleTable { + return 1; +} + +sub compareScheduleTable { + return 1; +} + +sub getScheduleDetails { + return ""; +} + +sub AboutScheduler { + return "(Null SRM) ReplayTV Support Disabled"; +} + +sub SchedulerDefaultRefresh{ + return 0; +} + +sub SchedulerDoBatchUpdate { + return 0; +} + +sub SchedulebarSupported { + return 0; +} + +sub ToDoSupported { + return 0; +} + +1; + diff --git a/rg_refresh.pl b/rg_refresh.pl new file mode 100644 index 0000000..cbe8248 --- /dev/null +++ b/rg_refresh.pl @@ -0,0 +1,274 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson +# with bits by Kanji T. Bates +# Theme Stuff based upon ReplaySchedule.pl by Kevin J. Moye +# $Id: rg_scheduler.pl,v 1.9 2003/07/24 02:00:22 pvanbaren Exp $ +# +# BATCH REFRESH FUNCTIONS +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +#----------------------------------------------------------------------------------- +# This module will refresh guide data using the scheduler module's +# GetFreshScheduleTable call. +# +# To save time, only scheduler modules that return true (1) for the +# scheduler_do_batch_update call will be processed. +# +# DEVS: If your scheduler module uses the schedule table within SQL (or similar) +# we highly encourage you to use the scheduler_do_batch_update functionality. +# +#----------------------------------------------------------------------------------- + +use POSIX qw( strftime getcwd ); +use Time::Local; + +my $_version = "Personal ReplayGuide|Batch Guide Refresh Library|1|0|5|Lee Thompson,Philip Van Baren,Kanji T. Bates,Kevin J. Moye"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Database Info +require 'rg_config.pl'; # Load config functions + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +sub refreshRTV { + # + # Refresh ReplayTV scheduling for all units. + # + # Optional Parameter is if this is silent or not (default is silent) + # Verbosity of 2 is debug. + # + #------------------------------------------------------------------- + my $local_verbose = shift; + + if ($local_verbose eq $null) { + $local_verbose = int $verbose; # Try to use global if it's there + } + + if ($local_verbose > 1) { + writeDebug("refreshRTV::Start"); + } + + if ($local_verbose) { + writeDebug("Refreshing ReplayTV Schedule Data"); + } + + #------------------------------------------------------------------- + # Load Scheduler Plug-In + #------------------------------------------------------------------- + + if ($local_verbose > 1) { + writeDebug("Loading Plug-In $scheduler"); + } + + require $scheduler; # Functions handling scheduled recording display + identifyLoadedModules($scheduler); + writeDebug(&AboutScheduler); + + if (!&SchedulerDoBatchUpdate) { + if ($local_verbose > 1) { + writeDebug("Schedule Resolver Module ($scheduler) does not support batch updates"); + } + return 0; + } + + my $replaylist = ""; + my $db_handle = &StartDSN; + my $Stmt = "SELECT * FROM $db_table_replayunits ORDER BY replayaddress;"; + my $lastsnapshot = 0; + my $right_now = time; + my $addr; + my $rows = 0; + + if ($local_verbose > 1) { + writeDebug("SQL: $db_handle -> $Stmt"); + } + + my $sth = sqlStmt($db_handle,$Stmt); + + if( $sth ) { + while ( $row = $sth->fetchrow_hashref ) { + $rows++; + + + my $replayid = $row->{'replayid'}; + + $replaylist = buildcommastring($replaylist,$replayid); + + $replaylist .= "$replayid"; + $rtvlabel{$replayid} = $row->{'replayname'}; + $rtvaddress{$replayid} = $row->{'replayaddress'}; + $rtvport{$replayid} = $row->{'replayport'}; + $rtvversion{$replayid} = $row->{'replayosversion'}; + $guideversion{$replayid} = $row->{'guideversion'}; + $categories{$replayid} = $row->{'categories'}; + $lastsnapshot = $row->{'lastsnapshot'}; + + if ($local_verbose) { + writeDebug("Refreshing Data for $rtvlabel{$replayid}"); + } + + if (0 != getFreshScheduleTable($replayid)) { + + if ($local_verbose) { + writeDebug("getFreshScheduleTable Failed for $rtvlabel{$replayid}"); + } + }else{ + if ($local_verbose) { + writeDebug("getFreshScheduleTable Complete for $rtvlabel{$replayid}"); + } + + my $Update = "UPDATE $db_table_replayunits SET lastsnapshot = $right_now WHERE replayid = '$replayid';"; + my $db_handle = &StartDSN; + + if ($local_verbose) { + writeDebug("Updating Database for $rtvlabel{$replayid}..."); + } + + if ( ! sqlStmt($db_handle,$Update) ) { + if ($local_verbose) { + writeDebug("Database update failed for $rtvlabel{$replayid}"); + } + }else{ + if ($local_verbose) { + writeDebug("Datebase update completed for $rtvlabel{$replayid}"); + } + } + + if ($local_verbose > 1) { + writeDebug("Closing Database Handle $db_handle"); + } + + endDSN("",$db_handle); + undef $db_handle; + } + + + } + } + + if ($local_verbose > 1) { + writeDebug("Closing Database Handle $db_handle"); + } + + endDSN($sth,$db_handle); + undef $db_handle; + + if ($rows) { + if ($local_verbose) { + writeDebug("Refresh Complete"); + } + }else{ + if ($local_verbose) { + writeDebug("No ReplayTVs Defined."); + } + } + + + if ($local_verbose > 1) { + writeDebug("refreshRTV::Exiting"); + } + + return 1; +} + + diff --git a/rg_replay.pl b/rg_replay.pl new file mode 100644 index 0000000..88b687f --- /dev/null +++ b/rg_replay.pl @@ -0,0 +1,2366 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson +# with bits by Kanji T. Bates +# Theme Stuff based upon ReplaySchedule.pl by Kevin J. Moye +# +# REPLAYTV/GUIDESNAPSHOT FUNCTIONS +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +require HTTP::Request; +require HTTP::Headers; +require LWP::UserAgent; +use Time::Local; +use POSIX qw( strftime getcwd ); + +my $_version = "Personal ReplayGuide|ReplayTV GuideSnapshot Library|1|0|10|Lee Thompson,Kanji T. Bates,Kevin J. Moye"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +@qualitylabel = ( + "High", + "Medium", + "Standard" +); + +#------------------------------------------------------------------------------------ +# Set up arrays +#------------------------------------------------------------------------------------ + +@channeltypelabel = ( + "Recurring", + "Theme", + "Single", + "Zone" +); + +#------------------------------------------------ +sub getReplayGuide { + # + # Get ReplayGuide replayid + # + #--------------------------------------------------------------------------- + my $retcode = 0; + my $replayid = shift; + my $replayaddr = $rtvaddress{$replayid}; + my $replayport = $rtvport{$replayid}; + my $snapshottime = time; + + if ($debug) { + print "getReplayGuide::Downloading Guide Snapshot for $replayid: $rtvaddress{$replayid}\n"; + } + + $guideptr = 0; + + if (length($replayaddr) < 1) { + return 0; + } + + #-------------------------------------------------------------- + # Ready URL + #-------------------------------------------------------------- + + if ($replayport != 80) { + $replaycmd = "http://$replayaddr:$replayport/http_replay_guide-get_snapshot?guide_file_name=0"; + }else{ + $replaycmd = "http://$replayaddr/http_replay_guide-get_snapshot?guide_file_name=0"; + } + + #-------------------------------------------------------------- + # Download Guide Snapshot + #-------------------------------------------------------------- + + if ($debug) { + print "getReplayGuide::HTTP::Request->new(GET => $replaycmd)\n"; + } + + $ua = LWP::UserAgent->new; + $request = HTTP::Request->new(GET => $replaycmd); + $response = $ua->request($request); + + if ($response->is_success) { + $guidesnapshot = $response->content; + if ($debug) { + print "getReplayGuide::Download Successful\n"; + } + + }else{ + if ($debug) { + print "getReplayGuide::Download Failed\n"; + } + return 0; + } + + #-------------------------------------------------------------- + # Strip off extra bits + #-------------------------------------------------------------- + + if ($debug) { + print "getReplayGuide::Trimming\n"; + } + + ($guidetag,$junk,$snapshotbody,$junk2) = split(/#####/, $guidesnapshot, 9); + + #-------------------------------------------------------------- + # $guidesnapshot contains the binary image of the snapshot + #-------------------------------------------------------------- + + if ($debug) { + print "getReplayGuide::Completed\n"; + } + + return 1; +} + + + +#------------------------------------------------ +sub normalizertvname { + # Normalize a program/show title + # + # returns altered string + # + #--------------------------------------------------------------------------- + + my @string = split(//,shift); + + my $newstring = ""; + my ($i, $j, $add, $c); + my @s = (); + $j = 0; + for( $i=0; $i<=$#string; $i++ ) { + $add = 1; + $c = $string[$i]; + ## Non-alphanumeric and non-space character are skipped + if( $c !~ /([a-z]|[0-9])/i && ! ($c eq " ") ) { + if ( $c eq "-" || "$c" eq "/" ) { + $c = ' '; + } else { + $add = 0; + } + } + + ## Avoid 2 spaces in a row + if( $j > 0 && $c eq " " && $s[$j-1] eq " " ) { + $add = 0; + } + + if( $add ) { + $s[$j++] = lc($c); + } + } + + return(join("",@s)); +} + +#------------------------------------------------ +sub collectRTVShows { + # + # Collect RTV shows + # Parameter: Replay IDs (comma delimited) + # + # Builds $events array + # + # replayid;eventtime (GMT);guaranteed;channeltype;daysofweek;channelflags; + # beforepadding;afterpadding;showlabel;channelname + # + #--------------------------------------------------------------------------- + + my $replayidlist = shift; + + if ($debug) { + print "collectRTVShows::gather shows from replay units #$replayidlist\n"; + } + + my $ctr = 1; + my $rtvshowcount = 0; + + for ( split /,/, $replayidlist ) { + /,/; + my $replayid = $_; + my $replayaddr = $rtvaddress{$replayid}; + $category = ""; + my $guideptr = 0; + my $guideheader = ""; + my $groupdata = ""; + my $snapshotbody = ""; + my $rtvchannel = ""; + my $rtvshow = ""; + + if ($debug) { + print "collectRTVShows::Processing Data for $replayid: $rtvaddress{$replayid}\n"; + } + + + if ($debug) { + print "collectRTVShows::Attempting to Download Snapshot from $replayid: $rtvaddress{$replayid}\n"; + } + + if (length($guidesnapshot{$replayid}) < 1) { + if (getReplayGuide($replayid)) { + if ($debug) { + print "collectRTVShows::Snapshot download from $replayid: $rtvaddress{$replayid} OK\n"; + } + $guidesnapshot{$replayid} = $snapshotbody; + }else{ + if ($debug) { + print "collectRTVShows::Snapshot download from $replayid: $rtvaddress{$replayid} FAILED\n"; + } + next; + } + }else{ + if ($debug) { + print "collectRTVShows::Using snapshot from memory\n"; + } + $snapshotbody = $guidesnapshot{$replayid}; + } + + if ($debug) { + print "collectRTVShows::Parsing Snapshot Header\n"; + } + + if (&ParseRTVHeader) { + + $rtv_version{$replayid} = $guideheader{snapshotversion}; + + if ($debug) { + print "collectRTVShows::Gathering Show Data\n"; + } + + $ctr = 1; + my $status = 0; + + do { + $status = getRTVShow($ctr); + if ($status) { + if ($debug) { + print "collectRTVShows::Processing Show #$ctr $replayid: $rtvaddress{$replayid} ($rtvshowcount total)\n"; + } + $ctr++; + $rtvshowcount++; + $rtvshows[$rtvshowcount] = "$replayid|$rtvshow{created}|$rtvshow{recorded}|$rtvshow{inputsource}|$rtvshow{quality}|$rtvshow{guaranteed}|$rtvshow{tmsid}|$rtvshow{channel}|$rtvshow{channelname}|$rtvshow{channellabel}|$rtvshow{tuning}|$rtvshow{eventtime}|$rtvshow{programtmsid}|$rtvshow{minutes}|$rtvshow{desc_block}|$rtvshow{beforepadding}|$rtvshow{afterpadding}"; + } + } while $status; + + $guideheader{showcount} = $ctr; # Fake Guide Entry :) + + } + } + +# @rtvshows = sort {$a <=> $b} @rtvshows; + + if ($debug) { + print "collectRTVShows::Completed ($rtvshowcount)\n"; + } + + return $rtvshowcount; +} + + +#------------------------------------------------ +sub collectRTVChannels { + # + # Collect RTV Events + # Parameter: Replay IDs (comma delimited) + # Format (if 1 uses the old rg_guide format) + # + # Builds $events array + # + # replayid;eventtime (GMT);guaranteed;channeltype;daysofweek;channelflags; + # beforepadding;afterpadding;showlabel;channelname + # + #--------------------------------------------------------------------------- + + my $replayidlist = shift; + my $format = int shift; + + if ($debug) { + print "collectRTVChannels::gather channels from replay units #$replayidlist\n"; + } + + my $ctr = 1; + my $events = 0; + + for ( split /,/, $replayidlist ) { + /,/; + my $replayid = $_; + my $replayaddr = $rtvaddress{$replayid}; + $category = ""; + my $guideptr = 0; + my $guideheader = ""; + my $groupdata = ""; + my $snapshotbody = ""; + my $rtvchannel = ""; + + if ($debug) { + print "collectRTVChannels::Processing Data for $replayid: $rtvaddress{$replayid}\n"; + } + + + if (length($guidesnapshot{$replayid}) < 1) { + if ($format) { + if (0 != getCachedScheduleTable($replayid)) { + if ($debug) { + print "collectRTVChannels::Using snapshot from disk.\n"; + } + $guidesnapshot{$replayid} = $snapshotbody; + } + }else{ + if ($debug) { + print "collectRTVChannels::Attempting to Download Snapshot from $replayid: $rtvaddress{$replayid}\n"; + } + if (getReplayGuide($replayid)) { + if ($debug) { + print "collectRTVChannels::Snapshot download from $replayid: $rtvaddress{$replayid} OK\n"; + } + $guidesnapshot{$replayid} = $snapshotbody; + }else{ + if ($debug) { + print "collectRTVChannels::Snapshot download from $replayid: $rtvaddress{$replayid} FAILED\n"; + } + next; + } + + } + + }else{ + if ($debug) { + print "collectRTVChannels::Using snapshot from memory\n"; + } + $snapshotbody = $guidesnapshot{$replayid}; + } + + + if ($debug) { + print "collectRTVChannels::Parsing Snapshot Header\n"; + } + + + if (&ParseRTVHeader) { + $rtv_version{$replayid} = $guideheader{snapshotversion}; + $rtv_categories{$replayid} = "$groupdata{categorycount}|$category"; + + if ($debug) { + print "collectRTVChannels::Loading Categories\n"; + } + + $categories{$replayid} = $category; + + if ($debug) { + print "collectRTVChannels::Gathering Channel Data ($guideheader{channelcount})\n"; + } + + + $ctr = 1; + + do { + if (getRTVChannel($ctr)) { + if ($debug) { + print "collectRTVChannels::Processing Channel #$ctr $replayid: $rtvaddress{$replayid} ($events total)\n"; + } + $ctr++; + if ($rtvchannel{ivsstatus} < 1) { + if ($rtvchannel{channeltype} > 0) { + $events++; + if ($format) { + $rtvevent[$events] = "$replayid;$rtvchannel{eventtime};$rtvchannel{guaranteed};$rtvchannel{channeltype};$rtvchannel{daysofweek};$rtvchannel{channelflags};$rtvchannel{beforepadding};$rtvchannel{afterpadding};$rtvchannel{showlabel};$rtvchannel{channelname};$rtvchannel{themeflags};$rtvchannel{searchstring};$rtvchannel{thememinutes};$rtvchannel{created}"; + }else{ + $rtvevent[$events] = "$replayid|$rtvchannel{created}|$rtvchannel{eventtime}|$rtvchannel{guaranteed}|$rtvchannel{channeltype}|$rtvchannel{daysofweek}|$rtvchannel{channelflags}|$rtvchannel{beforepadding}|$rtvchannel{afterpadding}|$rtvchannel{showlabel}|$rtvchannel{channelname}|$rtvchannel{themeflags}|$rtvchannel{searchstring}|$rtvchannel{thememinutes}|$rtvchannel{category}|$rtvchannel{keep}|$rtvchannel{_norepeats}|$rtvchannel{minutes}"; + } + + + + } + } + } + } while $ctr <= $guideheader{channelcount}; + } + } + + + @rtvevent = sort {$a <=> $b} @rtvevent; + + if ($debug) { + print "collectRTVChannels::Completed ($events)\n"; + } + + return $events; +} + + +#---------------------------------------------------------------------------------------- +sub ParseRTVHeader { + # Parse GuideSnapshot Header and Load Categories into a String (comma delim) + # + #-------------------------------------------------------------------------------- + + $guideptr = 0; + + $guideheader{osversion} = &GetNextWORD; + $guideheader{snapshotversion} = &GetNextWORD; + + if (($guideheader{snapshotversion} == 2) && ($guideheader{osversion} == 0)) { + &ParseRTV50; + return 1; + } + + if (($guideheader{snapshotversion} == 1) && ($guideheader{osversion} == 5)) { + &ParseRTV45; + return 1; + } + + if (($guideheader{snapshotversion} == 1) && ($guideheader{osversion} == 3)) { + &ParseRTV43; + return 1; + } + + return 0; +} + +#---------------------------------------------------------------------------------------- +sub ParseRTV50 { + # Parse 5.0 Header + # + #-------------------------------------------------------------------------------- + + $guideheader{structuresize} = &GetNextDWORD; + $guideheader{unknown1} = &GetNextDWORD; + $guideheader{unknown2} = &GetNextDWORD; + $guideheader{channelcount} = &GetNextDWORD; + $guideheader{channelcountcheck} = &GetNextDWORD; + $guideheader{unknown3} = &GetNextDWORD; + $guideheader{groupdataoffset} = &GetNextDWORD; + $guideheader{channeloffset} = &GetNextDWORD; + $guideheader{showoffset} = &GetNextDWORD; + $guideheader{snapshotsize} = &GetNextDWORD; + $guideheader{freebytes} = &GetRaw(8); + $guideheader{flags} = &GetNextDWORD; + $guideheader{unknown6} = &GetNextDWORD; + $guideheader{unknown7} = &GetNextDWORD; + + $groupdata{structuresize} = &GetNextDWORD; + $groupdata{categorycount} = &GetNextDWORD; + + my $ctr = 0; + + do { + $categories[$ctr] = &GetNextDWORD; + $ctr++; + } while ($ctr < 32); + + + $ctr = 0; + + do { + $categoryoffset[$ctr] = &GetNextDWORD; + $ctr++; + } while ($ctr < 32); + + + $groupdata{catbuffer} = &GetRaw(512); + + + # Load Categories + + $category = ""; + $ctr = 0; + + do { + if ($ctr) { + $category .= ";"; + } + $category .= "$categories[$ctr],"; + $category .= unpack("Z16",substr($groupdata{catbuffer},$categoryoffset[$ctr])); + $ctr++; + } while ($ctr < $groupdata{categorycount}); + + return 1; +} + +#---------------------------------------------------------------------------------------- +sub ParseRTV45 { + # Parse 4.5 Header + # + #-------------------------------------------------------------------------------- + + $guideheader{structuresize} = &GetNextDWORD; + $guideheader{channelcount} = &GetNextDWORD; + $guideheader{channelcountcheck} = &GetNextDWORD; + $guideheader{groupdataoffset} = &GetNextDWORD; + $guideheader{channeloffset} = &GetNextDWORD; + $guideheader{showoffset} = &GetNextDWORD; + $guideheader{flags} = &GetNextDWORD; + + $groupdata{structuresize} = &GetNextDWORD; + $groupdata{categorycount} = &GetNextDWORD; + + my $ctr = 0; + + do { + $categories[$ctr] = &GetNextDWORD; + $ctr++; + } while ($ctr < 32); + + + $ctr = 0; + + do { + $categoryoffset[$ctr] = &GetNextDWORD; + $ctr++; + } while ($ctr < 32); + + + $groupdata{catbuffer} = &GetRaw(512); + + + # Load Categories + + $ctr = 0; + + do { + if ($ctr) { + $category .= ";"; + } + $category .= "$categories[$ctr],"; + $category .= unpack("Z16",substr($groupdata{catbuffer},$categoryoffset[$ctr])); + $ctr++; + } while ($ctr < $groupdata{categorycount}); + + return 1; +} + +#---------------------------------------------------------------------------------------- +sub ParseRTV43 { + # Parse 4.3 Header + # + #-------------------------------------------------------------------------------- + + $guideheader{structuresize} = &GetNextDWORD; + $guideheader{channelcount} = &GetNextDWORD; + $guideheader{channelcountcheck} = &GetNextDWORD; + $guideheader{groupdataoffset} = &GetNextDWORD; + $guideheader{channeloffset} = &GetNextDWORD; + $guideheader{showoffset} = &GetNextDWORD; + $guideheader{flags} = &GetNextDWORD; + + $groupdata{structuresize} = &GetNextDWORD; + $groupdata{categorycount} = &GetNextDWORD; + + my $ctr = 0; + + do { + $categories[$ctr] = &GetNextDWORD; + $ctr++; + } while ($ctr < 32); + + + $ctr = 0; + + do { + $categoryoffset[$ctr] = &GetNextDWORD; + $ctr++; + } while ($ctr < 32); + + + $groupdata{catbuffer} = &GetRaw(512); + + + # Load Categories + + $ctr = 0; + + do { + if ($ctr) { + $category .= ";"; + } + $category .= "$categories[$ctr],"; + $category .= unpack("Z16",substr($groupdata{catbuffer},$categoryoffset[$ctr])); + $ctr++; + } while ($ctr < $groupdata{categorycount}); + + return 1; +} + +#---------------------------------------------------------------------------------------- +sub getRTVChannel { + # Get RTV ReplayChannel # + # + # Dispatcher + # + #-------------------------------------------------------------------------------- + + my $rtvchannel = int shift; + + if ($rtvchannel < 1) { + return 0; + } + + if (($guideheader{snapshotversion} == 2) && ($guideheader{osversion} == 0)) { + &getRTVChannel50($rtvchannel); + return 1; + } + + if (($guideheader{snapshotversion} == 1) && ($guideheader{osversion} == 5)) { + &getRTVChannel45($rtvchannel); + return 1; + } + + if (($guideheader{snapshotversion} == 1) && ($guideheader{osversion} == 3)) { + &getRTVChannel43($rtvchannel); + return 1; + } + + return 0; +} + + +#---------------------------------------------------------------------------------------- +sub getRTVChannel50 { + # Get RTV ReplayChannel # + # + # For Channel Size: 712 (5.0) + # + #-------------------------------------------------------------------------------- + + my $rtvchannel = int shift; + + #-------------------------------------------------------------------------------- + # Set Base + #-------------------------------------------------------------------------------- + + $guideptr = $guideheader{channeloffset} - 712; + + $guideptr = $guideptr + ($rtvchannel * 712); + + $rtvchannel{created} = &GetNextDWORD; + $rtvchannel{recorded} = &GetNextDWORD; + $rtvchannel{inputsource} = &GetNextDWORD; + $rtvchannel{quality} = &GetNextDWORD; + $rtvchannel{guaranteed} = &GetNextDWORD; + $rtvchannel{playbackflags} = &GetNextDWORD; + $rtvchannel{channelstructsize} = &GetNextDWORD; + $rtvchannel{usetuner} = &GetNextDWORD; + $rtvchannel{isvalid} = &GetNextDWORD; + $rtvchannel{tmsid} = &GetNextDWORD; + $rtvchannel{channel} = &GetNextWORD; + $rtvchannel{device} = &GetNextBYTE; + $rtvchannel{tier} = &GetNextBYTE; + $rtvchannel{channelname} = &GetSZ(16); + $rtvchannel{channellabel} = &GetSZ(32); + $rtvchannel{headend} = &GetSZ(8); + $rtvchannel{channelindex} = &GetNextDWORD; + $rtvchannel{programstructsize} = &GetNextDWORD; + $rtvchannel{autorecord} = &GetNextDWORD; + $rtvchannel{isvalid} = &GetNextDWORD; + $rtvchannel{tuning} = &GetNextDWORD; + $rtvchannel{programflags} = &GetNextDWORD; + $rtvchannel{eventtime} = &GetNextDWORD; + $rtvchannel{programtmsid} = &GetNextDWORD; + $rtvchannel{minutes} = &GetNextWORD; + $rtvchannel{genre1} = &GetNextBYTE; + $rtvchannel{genre2} = &GetNextBYTE; + $rtvchannel{genre3} = &GetNextBYTE; + $rtvchannel{genre4} = &GetNextBYTE; + $rtvchannel{reclen} = &GetNextWORD; + $rtvchannel{titlelen} = &GetNextBYTE; + $rtvchannel{episodelen} = &GetNextBYTE; + $rtvchannel{descriptionlen} = &GetNextBYTE; + $rtvchannel{actorlen} = &GetNextBYTE; + $rtvchannel{guestlen} = &GetNextBYTE; + $rtvchannel{suzukilen} = &GetNextBYTE; + $rtvchannel{producerlen} = &GetNextBYTE; + $rtvchannel{directorlen} = &GetNextBYTE; + $rtvchannel{description} = &GetRaw(228); + $rtvchannel{ivsstatus} = &GetNextDWORD; + $rtvchannel{guideid} = &GetNextDWORD; + $rtvchannel{downloadid} = &GetNextDWORD; + $rtvchannel{timessent} = &GetNextDWORD; + $rtvchannel{seconds} = &GetNextDWORD; + $rtvchannel{gopcount} = &GetNextDWORD; + $rtvchannel{gophighest} = &GetNextDWORD; + $rtvchannel{goplast} = &GetNextDWORD; + $rtvchannel{checkpointed} = &GetNextDWORD; + $rtvchannel{intact} = &GetNextDWORD; + $rtvchannel{upgradeflag} = &GetNextDWORD; + $rtvchannel{instance} = &GetNextDWORD; + $rtvchannel{unused} = &GetNextWORD; + $rtvchannel{beforepadding} = &GetNextBYTE; + $rtvchannel{afterpadding} = &GetNextBYTE; + $rtvchannel{indexsize} = &GetRaw(8); + $rtvchannel{mpegsize} = &GetRaw(8); + $rtvchannel{reserved} = &GetRaw(68); + $rtvchannel{themeflags} = &GetNextDWORD; + $rtvchannel{suzukiid} = &GetNextDWORD; + $rtvchannel{thememinutes} = &GetNextDWORD; + $rtvchannel{searchstring} = &GetSZ(48); + $rtvchannel{created} = &GetNextDWORD; + $rtvchannel{category} = &GetNextDWORD; # 2^category number + $rtvchannel{channeltype} = &GetNextDWORD; + $rtvchannel{quality} = &GetNextDWORD; + $rtvchannel{stored} = &GetNextDWORD; + $rtvchannel{keep} = &GetNextDWORD; + $rtvchannel{daysofweek} = &GetNextBYTE; + $rtvchannel{afterpadding} = &GetNextBYTE; + $rtvchannel{beforepadding} = &GetNextBYTE; + $rtvchannel{channelflags} = &GetNextBYTE; + $rtvchannel{timereserved} = &GetRaw(8); + $rtvchannel{showlabel} = &GetSZ(48); + $rtvchannel{unknown1} = &GetNextDWORD; + $rtvchannel{unknown2} = &GetNextDWORD; + $rtvchannel{unknown3} = &GetNextDWORD; + $rtvchannel{unknown4} = &GetNextDWORD; + $rtvchannel{unknown5} = &GetNextDWORD; + $rtvchannel{unknown6} = &GetNextDWORD; + $rtvchannel{unknown7} = &GetNextDWORD; + $rtvchannel{unknown8} = &GetNextDWORD; + $rtvchannel{allocatedspace} = &GetRaw(8); + $rtvchannel{unknown9} = &GetNextDWORD; + $rtvchannel{unknown10} = &GetNextDWORD; + $rtvchannel{unknown11} = &GetNextDWORD; + $rtvchannel{unknown12} = &GetNextDWORD; + + if ($rtvchannel{channelflags} & 32) { + $rtvchannel{_norepeats} = 1; + }else{ + $rtvchannel{_norepeats} = 0; + } + + return 1; + +} + + +#---------------------------------------------------------------------------------------- +sub getRTVChannel45($) { + # UNTESTED + # + # Get RTV ReplayChannel # + # + # For Channel Size: 712 + # + #-------------------------------------------------------------------------------- + + my $rtvchannel = int shift; + + #-------------------------------------------------------------------------------- + # Set Base + #-------------------------------------------------------------------------------- + + $guideptr = $guideheader{channeloffset} - 712; + + $guideptr = $guideptr + ($rtvchannel * 712); + + $rtvchannel{created} = &GetNextDWORD; + $rtvchannel{recorded} = &GetNextDWORD; + $rtvchannel{inputsource} = &GetNextDWORD; + $rtvchannel{quality} = &GetNextDWORD; + $rtvchannel{guaranteed} = &GetNextDWORD; + $rtvchannel{playbackflags} = &GetNextDWORD; + $rtvchannel{channelstructsize} = &GetNextDWORD; + $rtvchannel{usetuner} = &GetNextDWORD; + $rtvchannel{isvalid} = &GetNextDWORD; + $rtvchannel{tmsid} = &GetNextDWORD; + $rtvchannel{channel} = &GetNextWORD; + $rtvchannel{device} = &GetNextBYTE; + $rtvchannel{tier} = &GetNextBYTE; + $rtvchannel{channelname} = &GetSZ(16); + $rtvchannel{channellabel} = &GetSZ(32); + $rtvchannel{headend} = &GetSZ(8); + $rtvchannel{channelindex} = &GetNextDWORD; + $rtvchannel{programstructsize} = &GetNextDWORD; + $rtvchannel{autorecord} = &GetNextDWORD; + $rtvchannel{isvalid} = &GetNextDWORD; + $rtvchannel{tuning} = &GetNextDWORD; + $rtvchannel{programflags} = &GetNextDWORD; + $rtvchannel{eventtime} = &GetNextDWORD; + $rtvchannel{programtmsid} = &GetNextDWORD; + $rtvchannel{minutes} = &GetNextWORD; + $rtvchannel{genre1} = &GetNextBYTE; + $rtvchannel{genre2} = &GetNextBYTE; + $rtvchannel{genre3} = &GetNextBYTE; + $rtvchannel{genre4} = &GetNextBYTE; + $rtvchannel{reclen} = &GetNextWORD; + $rtvchannel{titlelen} = &GetNextBYTE; + $rtvchannel{episodelen} = &GetNextBYTE; + $rtvchannel{descriptionlen} = &GetNextBYTE; + $rtvchannel{actorlen} = &GetNextBYTE; + $rtvchannel{guestlen} = &GetNextBYTE; + $rtvchannel{suzukilen} = &GetNextBYTE; + $rtvchannel{producerlen} = &GetNextBYTE; + $rtvchannel{directorlen} = &GetNextBYTE; + $rtvchannel{description} = &GetRaw(228); + $rtvchannel{ivsstatus} = &GetNextDWORD; + $rtvchannel{guideid} = &GetNextDWORD; + $rtvchannel{downloadid} = &GetNextDWORD; + $rtvchannel{timessent} = &GetNextDWORD; + $rtvchannel{seconds} = &GetNextDWORD; + $rtvchannel{gopcount} = &GetNextDWORD; + $rtvchannel{gophighest} = &GetNextDWORD; + $rtvchannel{goplast} = &GetNextDWORD; + $rtvchannel{checkpointed} = &GetNextDWORD; + $rtvchannel{intact} = &GetNextDWORD; + $rtvchannel{upgradeflag} = &GetNextDWORD; + $rtvchannel{instance} = &GetNextDWORD; + $rtvchannel{unused} = &GetNextWORD; + $rtvchannel{beforepadding} = &GetNextBYTE; + $rtvchannel{afterpadding} = &GetNextBYTE; + $rtvchannel{indexsize} = &GetRaw(8); + $rtvchannel{mpegsize} = &GetRaw(8); + $rtvchannel{reserved} = &GetRaw(68); + $rtvchannel{themeflags} = &GetNextDWORD; + $rtvchannel{suzukiid} = &GetNextDWORD; + $rtvchannel{thememinutes} = &GetNextDWORD; + $rtvchannel{searchstring} = &GetSZ(48); + $rtvchannel{created} = &GetNextDWORD; + $rtvchannel{category} = &GetNextDWORD; # 2^category number + $rtvchannel{channeltype} = &GetNextDWORD; + $rtvchannel{quality} = &GetNextDWORD; + $rtvchannel{stored} = &GetNextDWORD; + $rtvchannel{keep} = &GetNextDWORD; + $rtvchannel{daysofweek} = &GetNextBYTE; + $rtvchannel{afterpadding} = &GetNextBYTE; + $rtvchannel{beforepadding} = &GetNextBYTE; + $rtvchannel{channelflags} = &GetNextBYTE; + $rtvchannel{timereserved} = &GetRaw(8); + $rtvchannel{showlabel} = &GetSZ(48); + $rtvchannel{unknown1} = &GetNextDWORD; + $rtvchannel{unknown2} = &GetNextDWORD; + $rtvchannel{unknown3} = &GetNextDWORD; + $rtvchannel{unknown4} = &GetNextDWORD; + $rtvchannel{unknown5} = &GetNextDWORD; + $rtvchannel{unknown6} = &GetNextDWORD; + $rtvchannel{unknown7} = &GetNextDWORD; + $rtvchannel{unknown8} = &GetNextDWORD; + $rtvchannel{allocatedspace} = &GetRaw(8); + $rtvchannel{unknown9} = &GetNextDWORD; + $rtvchannel{unknown10} = &GetNextDWORD; + $rtvchannel{unknown11} = &GetNextDWORD; + $rtvchannel{unknown12} = &GetNextDWORD; + + return 1; + +} + +#---------------------------------------------------------------------------------------- +sub getRTVChannel43($) { + # Get RTV ReplayChannel # + # + # For Channel Size: 624 + # + #-------------------------------------------------------------------------------- + + my $rtvchannel = int shift; + + #-------------------------------------------------------------------------------- + # Set Base + #-------------------------------------------------------------------------------- + + $guideptr = $guideheader{channeloffset} - 624; + + $guideptr = $guideptr + ($rtvchannel * 624); + + $rtvchannel{channeltype} = &GetNextDWORD; + $rtvchannel{quality} = &GetNextDWORD; + $rtvchannel{allocatedspace} = &GetRaw(8); + $rtvchannel{keep} = &GetNextDWORD; + $rtvchannel{stored} = &GetNextDWORD; + $rtvchannel{daysofweek} = &GetNextBYTE; + $rtvchannel{afterpadding} = &GetNextBYTE; + $rtvchannel{beforepadding} = &GetNextBYTE; + $rtvchannel{channelflags} = &GetNextBYTE; + $rtvchannel{category} = &GetNextDWORD; # 2^category number + $rtvchannel{created} = &GetNextDWORD; + $rtvchannel{unknown1} = &GetNextDWORD; + $rtvchannel{unknown2} = &GetNextDWORD; + $rtvchannel{unknown3} = &GetNextDWORD; + $rtvchannel{unknown4} = &GetNextDWORD; + $rtvchannel{unknown5} = &GetNextDWORD; + $rtvchannel{unknown6} = &GetNextDWORD; + $rtvchannel{unknown7} = &GetNextDWORD; + $rtvchannel{secondsallocated} = &GetNextDWORD; + $rtvchannel{showlabel} = &GetSZ(48); + $rtvchannel{created} = &GetNextDWORD; + $rtvchannel{recorded} = &GetNextDWORD; + $rtvchannel{inputsource} = &GetNextDWORD; + $rtvchannel{quality} = &GetNextDWORD; + $rtvchannel{guaranteed} = &GetNextDWORD; + $rtvchannel{playbackflags} = &GetNextDWORD; + $rtvchannel{channelstructsize} = &GetNextDWORD; + $rtvchannel{usetuner} = &GetNextDWORD; + $rtvchannel{isvalid} = &GetNextDWORD; + $rtvchannel{tmsid} = &GetNextDWORD; + $rtvchannel{channel} = &GetNextWORD; + $rtvchannel{device} = &GetNextBYTE; + $rtvchannel{tier} = &GetNextBYTE; + $rtvchannel{channelname} = &GetSZ(16); + $rtvchannel{channellabel} = &GetSZ(32); + $rtvchannel{headend} = &GetSZ(8); + $rtvchannel{channelindex} = &GetNextDWORD; + $rtvchannel{programstructsize} = &GetNextDWORD; + $rtvchannel{autorecord} = &GetNextDWORD; + $rtvchannel{isvalid} = &GetNextDWORD; + $rtvchannel{tuning} = &GetNextDWORD; + $rtvchannel{programflags} = &GetNextDWORD; + $rtvchannel{eventtime} = &GetNextDWORD; + $rtvchannel{programtmsid} = &GetNextDWORD; + $rtvchannel{minutes} = &GetNextWORD; + $rtvchannel{genre1} = &GetNextBYTE; + $rtvchannel{genre2} = &GetNextBYTE; + $rtvchannel{genre3} = &GetNextBYTE; + $rtvchannel{genre4} = &GetNextBYTE; + $rtvchannel{reclen} = &GetNextWORD; + $rtvchannel{titlelen} = &GetNextBYTE; + $rtvchannel{episodelen} = &GetNextBYTE; + $rtvchannel{descriptionlen} = &GetNextBYTE; + $rtvchannel{actorlen} = &GetNextBYTE; + $rtvchannel{guestlen} = &GetNextBYTE; + $rtvchannel{suzukilen} = &GetNextBYTE; + $rtvchannel{producerlen} = &GetNextBYTE; + $rtvchannel{directorlen} = &GetNextBYTE; + $rtvchannel{description} = &GetRaw(228); + $rtvchannel{ivsstatus} = &GetNextDWORD; + $rtvchannel{guideid} = &GetNextDWORD; + $rtvchannel{downloadid} = &GetNextDWORD; + $rtvchannel{timessent} = &GetNextDWORD; + $rtvchannel{seconds} = &GetNextDWORD; + $rtvchannel{gopcount} = &GetNextDWORD; + $rtvchannel{gophighest} = &GetNextDWORD; + $rtvchannel{goplast} = &GetNextDWORD; + $rtvchannel{checkpointed} = &GetNextDWORD; + $rtvchannel{intact} = &GetNextDWORD; + $rtvchannel{upgradeflag} = &GetNextDWORD; + $rtvchannel{instance} = &GetNextDWORD; + $rtvchannel{unused} = &GetNextWORD; + $rtvchannel{beforepadding} = &GetNextBYTE; + $rtvchannel{afterpadding} = &GetNextBYTE; + $rtvchannel{indexsize} = &GetRaw(8); + $rtvchannel{mpegsize} = &GetRaw(8); + $rtvchannel{themeflags} = &GetNextDWORD; + $rtvchannel{suzukiid} = &GetNextDWORD; + $rtvchannel{thememinutes} = &GetNextDWORD; + $rtvchannel{searchstring} = &GetSZ(52); + + return 1; + +} + +#---------------------------------------------------------------------------------------- +sub getRTVShow { + # + # Get RTV ReplayShow # + # + # For Channel Size: 512 + # + #-------------------------------------------------------------------------------- + + my $rtvshow = int shift; + + if ($debug) { + print "getRTVShow::Searching for # ($rtvshow)\n"; + print "getRTVShow::checking $guideheader{snapshotversion}\n"; + } + + if ($rtvshow < 1) { + if ($debug) { + print "No Show Requested($rtvshow)\n"; + } + return 0; + } + + if ($guideptr >= $guideheader{snapshotsize}) { + if ($debug) { + print "At or Past End $guideptr >= $guideheader{snapshotsize}\n"; + } + return 0; + } + + if (($guideheader{snapshotversion} == 2) && ($guideheader{osversion} == 0)) { + &getRTVShow50($rtvshow); + $rtvshow{desc_block} = &ParseDescBlock; + return 1; + } + + if (($guideheader{snapshotversion} == 1) && ($guideheader{osversion} == 5)) { + &getRTVShow45($rtvshow); + $rtvshow{desc_block} = &ParseDescBlock; + return 1; + } + + if (($guideheader{snapshotversion} == 1) && ($guideheader{osversion} == 3)) { + &getRTVShow43($rtvshow); + $rtvshow{desc_block} = &ParseDescBlock; + return 1; + } + + return 0; +} + +#---------------------------------------------------------------------------------------- +sub ParseDescBlock { + # + # Parse the description/extended data block of a rtvshow + # + #-------------------------------------------------------------------------------- + + my $ctr = 0; + my $return_block = ""; + my $ext_data = ""; + my $cc = ""; + my $stereo = ""; + my $repeat = ""; + my $sap = ""; + my $lbx = ""; + my $ppv = ""; + my $movie = ""; + my $rating = ""; + my $movieblock = ""; + my $mpaa = ""; + my $stars = ""; + my $starsicon = ""; + my $year = ""; + my $part = 0; + my $maxpart = 0; + + if ($rtvshow{programflags} & 1) { + $cc = "CC"; + } + + if ($rtvshow{programflags} & 2) { + $stereo = "Stereo"; + } + + if ($rtvshow{programflags} & 4) { + $repeat = "Repeat"; + } + + if ($rtvshow{programflags} & 8) { + $sap = "SAP"; + } + + if ($rtvshow{programflags} & 16) { + $lbx = "Letterboxed"; + } + + + if ($rtvshow{programflags} & 32) { + # + # Skip MovieInfo + # + $movieblock = substr($rtvshow{description},0,7); + $mpaa = unpack("n",substr($movieblock,0,2)); + $stars = unpack("n",substr($movieblock,2,2)); + $year = unpack("n",substr($movieblock,4,2)); + + $stars = int $stars / 10; + + $starsicon = substr("*********",0,$stars); + + if ($stars % 10) { + $starsicon .= "1/2"; + } + + if ($mpaa & 1) { + $rating = "AO"; + } + + if ($mpaa & 2) { + $rating = "G"; + } + + if ($mpaa & 4) { + $rating = "NC-17"; + } + + if ($mpaa & 8) { + $rating = "NR"; + } + + if ($mpaa & 16) { + $rating = "PG"; + } + + if ($mpaa & 32) { + $rating = "PG-13"; + } + + if ($mpaa & 64) { + $rating = "R"; + } + + $movie = "$starsicon,$rating,$year"; + $ctr += 4; + } + + if ($rtvshow{programflags} & 64) { + # + # Skip PartsInfo + # + + $part = unpack("n",substr($rtvshow{description},0,2)); + $maxpart = unpack("n",substr($rtvshow{description},2,2)); + $ctr += 2; + } + + if ($rtvshow{programflags} & 128) { + # + # Skip PartsInfo + # + $ppv = "PPV"; + } + + if ($rtvshow{programflags} & 32768) { + $rating = "TV-Y"; + } + + if ($rtvshow{programflags} & 65536) { + $rating = "TV-Y7"; + } + + if ($rtvshow{programflags} & 4096) { + $rating = "TV-G"; + } + + if ($rtvshow{programflags} & 16384) { + $rating = "TV-PG"; + } + + if ($rtvshow{programflags} & 8192) { + $rating = "TV-MA"; + } + + + + $ext_data = "$cc;$stereo;$repeat;$sap;$lbx;$movie;$rating"; + + my $description_block = substr($rtvshow{description},$ctr,$rtvshow{reclen}); + + my $title = substr($description_block,$ctr,$rtvshow{titlelen}-1); + $ctr += $rtvshow{titlelen}; + + my $episode = substr($description_block,$ctr,$rtvshow{episodelen}-1); + $ctr += $rtvshow{episodelen}; + + my $description = substr($description_block,$ctr,$rtvshow{descriptionlen}-1); + $ctr += $rtvshow{descriptionlen}; + + if ($part > 0) { + $description .= " (Part $part of $maxpart)"; + } + + my $actors = substr($description_block,$ctr,$rtvshow{actorlen}-1); + $ctr += $rtvshow{actorlen}; + + my $guests = substr($description_block,$ctr,$rtvshow{guestlen}-1); + $ctr += $rtvshow{guestlen}; + + my $suzuki = substr($description_block,$ctr,$rtvshow{suzukilen}-1); + $ctr += $rtvshow{suzukilen}; + + my $producers = substr($description_block,$ctr,$rtvshow{producerlen}-1); + $ctr += $rtvshow{producerlen}; + + my $directors = substr($description_block,$ctr,$rtvshow{directorlen}-1); + $ctr += $rtvshow{directorlen}; + + $return_block = "$title|$episode|$description|$actors|$guests|$suzuki|$producers|$directors|$ext_data"; + + return $return_block; +} + +#---------------------------------------------------------------------------------------- +sub getRTVShow50($){ + # + # Get RTV ReplayShow # + # + # For Channel Size: 512 + # + #-------------------------------------------------------------------------------- + + my $rtvshow = int shift; + + #-------------------------------------------------------------------------------- + # Set Base + #-------------------------------------------------------------------------------- + + $guideptr = $guideheader{showoffset} - 512; + + $guideptr = $guideptr + ($rtvshow * 512); + + $rtvshow{created} = &GetNextDWORD; + $rtvshow{recorded} = &GetNextDWORD; + $rtvshow{inputsource} = &GetNextDWORD; + $rtvshow{quality} = &GetNextDWORD; + $rtvshow{guaranteed} = &GetNextDWORD; + $rtvshow{playbackflags} = &GetNextDWORD; + $rtvshow{channelstructsize} = &GetNextDWORD; + $rtvshow{usetuner} = &GetNextDWORD; + $rtvshow{isvalid} = &GetNextDWORD; + $rtvshow{tmsid} = &GetNextDWORD; + $rtvshow{channel} = &GetNextWORD; + $rtvshow{device} = &GetNextBYTE; + $rtvshow{tier} = &GetNextBYTE; + $rtvshow{channelname} = &GetSZ(16); + $rtvshow{channellabel} = &GetSZ(32); + $rtvshow{headend} = &GetSZ(8); + $rtvshow{channelindex} = &GetNextDWORD; + $rtvshow{programstructsize} = &GetNextDWORD; + $rtvshow{autorecord} = &GetNextDWORD; + $rtvshow{isvalid} = &GetNextDWORD; + $rtvshow{tuning} = &GetNextDWORD; + $rtvshow{programflags} = &GetNextDWORD; + $rtvshow{eventtime} = &GetNextDWORD; + $rtvshow{programtmsid} = &GetNextDWORD; + $rtvshow{minutes} = &GetNextWORD; + $rtvshow{genre1} = &GetNextBYTE; + $rtvshow{genre2} = &GetNextBYTE; + $rtvshow{genre3} = &GetNextBYTE; + $rtvshow{genre4} = &GetNextBYTE; + $rtvshow{reclen} = &GetNextWORD; + $rtvshow{titlelen} = &GetNextBYTE; + $rtvshow{episodelen} = &GetNextBYTE; + $rtvshow{descriptionlen} = &GetNextBYTE; + $rtvshow{actorlen} = &GetNextBYTE; + $rtvshow{guestlen} = &GetNextBYTE; + $rtvshow{suzukilen} = &GetNextBYTE; + $rtvshow{producerlen} = &GetNextBYTE; + $rtvshow{directorlen} = &GetNextBYTE; + $rtvshow{description} = &GetRaw(228); + $rtvshow{ivsstatus} = &GetNextDWORD; + $rtvshow{guideid} = &GetNextDWORD; + $rtvshow{downloadid} = &GetNextDWORD; + $rtvshow{timessent} = &GetNextDWORD; + $rtvshow{seconds} = &GetNextDWORD; + $rtvshow{gopcount} = &GetNextDWORD; + $rtvshow{gophighest} = &GetNextDWORD; + $rtvshow{goplast} = &GetNextDWORD; + $rtvshow{checkpointed} = &GetNextDWORD; + $rtvshow{intact} = &GetNextDWORD; + $rtvshow{upgradeflag} = &GetNextDWORD; + $rtvshow{instance} = &GetNextDWORD; + $rtvshow{unused} = &GetNextWORD; + $rtvshow{beforepadding} = &GetNextBYTE; + $rtvshow{afterpadding} = &GetNextBYTE; + $rtvshow{indexsize} = &GetRaw(8); + $rtvshow{mpegsize} = &GetRaw(8); + $rtvshow{reserved} = &GetRaw(68); + + + return 1; + +} + + +#---------------------------------------------------------------------------------------- +sub getRTVShow45($){ + # + # THIS IS UNTESTED + # + # + # Get RTV ReplayShow # + # + # For Channel Size: 512 (4.5) + # + #-------------------------------------------------------------------------------- + + my $rtvshow = int shift; + + #-------------------------------------------------------------------------------- + # Set Base + #-------------------------------------------------------------------------------- + + $guideptr = $guideheader{showoffset} - 512; + + $guideptr = $guideptr + ($rtvshow * 512); + + $rtvshow{created} = &GetNextDWORD; + $rtvshow{recorded} = &GetNextDWORD; + $rtvshow{inputsource} = &GetNextDWORD; + $rtvshow{quality} = &GetNextDWORD; + $rtvshow{guaranteed} = &GetNextDWORD; + $rtvshow{playbackflags} = &GetNextDWORD; + $rtvshow{channelstructsize} = &GetNextDWORD; + $rtvshow{usetuner} = &GetNextDWORD; + $rtvshow{isvalid} = &GetNextDWORD; + $rtvshow{tmsid} = &GetNextDWORD; + $rtvshow{channel} = &GetNextWORD; + $rtvshow{device} = &GetNextBYTE; + $rtvshow{tier} = &GetNextBYTE; + $rtvshow{channelname} = &GetSZ(16); + $rtvshow{channellabel} = &GetSZ(32); + $rtvshow{headend} = &GetSZ(8); + $rtvshow{channelindex} = &GetNextDWORD; + $rtvshow{programstructsize} = &GetNextDWORD; + $rtvshow{autorecord} = &GetNextDWORD; + $rtvshow{isvalid} = &GetNextDWORD; + $rtvshow{tuning} = &GetNextDWORD; + $rtvshow{programflags} = &GetNextDWORD; + $rtvshow{eventtime} = &GetNextDWORD; + $rtvshow{programtmsid} = &GetNextDWORD; + $rtvshow{minutes} = &GetNextWORD; + $rtvshow{genre1} = &GetNextBYTE; + $rtvshow{genre2} = &GetNextBYTE; + $rtvshow{genre3} = &GetNextBYTE; + $rtvshow{genre4} = &GetNextBYTE; + $rtvshow{reclen} = &GetNextWORD; + $rtvshow{titlelen} = &GetNextBYTE; + $rtvshow{episodelen} = &GetNextBYTE; + $rtvshow{descriptionlen} = &GetNextBYTE; + $rtvshow{actorlen} = &GetNextBYTE; + $rtvshow{guestlen} = &GetNextBYTE; + $rtvshow{suzukilen} = &GetNextBYTE; + $rtvshow{producerlen} = &GetNextBYTE; + $rtvshow{directorlen} = &GetNextBYTE; + $rtvshow{description} = &GetRaw(228); + $rtvshow{ivsstatus} = &GetNextDWORD; + $rtvshow{guideid} = &GetNextDWORD; + $rtvshow{downloadid} = &GetNextDWORD; + $rtvshow{timessent} = &GetNextDWORD; + $rtvshow{seconds} = &GetNextDWORD; + $rtvshow{gopcount} = &GetNextDWORD; + $rtvshow{gophighest} = &GetNextDWORD; + $rtvshow{goplast} = &GetNextDWORD; + $rtvshow{checkpointed} = &GetNextDWORD; + $rtvshow{intact} = &GetNextDWORD; + $rtvshow{upgradeflag} = &GetNextDWORD; + $rtvshow{instance} = &GetNextDWORD; + $rtvshow{unused} = &GetNextWORD; + $rtvshow{beforepadding} = &GetNextBYTE; + $rtvshow{afterpadding} = &GetNextBYTE; + $rtvshow{indexsize} = &GetRaw(8); + $rtvshow{mpegsize} = &GetRaw(8); + $rtvshow{reserved} = &GetRaw(68); + + + return 1; + +} + +#---------------------------------------------------------------------------------------- +sub getRTVShow43($){ + # + # THIS IS UNTESTED + # + # + # Get RTV ReplayShow # + # + # For Channel Size: 444 (4.3) + # + #-------------------------------------------------------------------------------- + + my $rtvshow = int shift; + + #-------------------------------------------------------------------------------- + # Set Base + #-------------------------------------------------------------------------------- + + $guideptr = $guideheader{showoffset} - 444; + + $guideptr = $guideptr + ($rtvshow * 444); + + $rtvshow{created} = &GetNextDWORD; + $rtvshow{recorded} = &GetNextDWORD; + $rtvshow{inputsource} = &GetNextDWORD; + $rtvshow{quality} = &GetNextDWORD; + $rtvshow{guaranteed} = &GetNextDWORD; + $rtvshow{playbackflags} = &GetNextDWORD; + $rtvshow{channelstructsize} = &GetNextDWORD; + $rtvshow{usetuner} = &GetNextDWORD; + $rtvshow{isvalid} = &GetNextDWORD; + $rtvshow{tmsid} = &GetNextDWORD; + $rtvshow{channel} = &GetNextWORD; + $rtvshow{device} = &GetNextBYTE; + $rtvshow{tier} = &GetNextBYTE; + $rtvshow{channelname} = &GetSZ(16); + $rtvshow{channellabel} = &GetSZ(32); + $rtvshow{headend} = &GetSZ(8); + $rtvshow{channelindex} = &GetNextDWORD; + $rtvshow{programstructsize} = &GetNextDWORD; + $rtvshow{autorecord} = &GetNextDWORD; + $rtvshow{isvalid} = &GetNextDWORD; + $rtvshow{tuning} = &GetNextDWORD; + $rtvshow{programflags} = &GetNextDWORD; + $rtvshow{eventtime} = &GetNextDWORD; + $rtvshow{programtmsid} = &GetNextDWORD; + $rtvshow{minutes} = &GetNextWORD; + $rtvshow{genre1} = &GetNextBYTE; + $rtvshow{genre2} = &GetNextBYTE; + $rtvshow{genre3} = &GetNextBYTE; + $rtvshow{genre4} = &GetNextBYTE; + $rtvshow{reclen} = &GetNextWORD; + $rtvshow{titlelen} = &GetNextBYTE; + $rtvshow{episodelen} = &GetNextBYTE; + $rtvshow{descriptionlen} = &GetNextBYTE; + $rtvshow{actorlen} = &GetNextBYTE; + $rtvshow{guestlen} = &GetNextBYTE; + $rtvshow{suzukilen} = &GetNextBYTE; + $rtvshow{producerlen} = &GetNextBYTE; + $rtvshow{directorlen} = &GetNextBYTE; + $rtvshow{description} = &GetRaw(228); + $rtvshow{ivsstatus} = &GetNextDWORD; + $rtvshow{guideid} = &GetNextDWORD; + $rtvshow{downloadid} = &GetNextDWORD; + $rtvshow{timessent} = &GetNextDWORD; + $rtvshow{seconds} = &GetNextDWORD; + $rtvshow{gopcount} = &GetNextDWORD; + $rtvshow{gophighest} = &GetNextDWORD; + $rtvshow{goplast} = &GetNextDWORD; + $rtvshow{checkpointed} = &GetNextDWORD; + $rtvshow{intact} = &GetNextDWORD; + $rtvshow{upgradeflag} = &GetNextDWORD; + $rtvshow{instance} = &GetNextDWORD; + $rtvshow{unused} = &GetNextWORD; + $rtvshow{beforepadding} = &GetNextBYTE; + $rtvshow{afterpadding} = &GetNextBYTE; + $rtvshow{indexsize} = &GetRaw(8); + $rtvshow{mpegsize} = &GetRaw(8); + + return 1; + +} + + +#---------------------------------------------------------------------------------------- +sub getCategory { + my $lookfor = int shift; + my $replayid = int shift; + my ($categorycount,$categories) = split(/\|/,$rtv_categories{$replayid}); + my $c_num = 0; + my $c_text = ""; + my $retcode = ""; + + if ($debug) { + print "getCategory::Looking for \"$lookfor\" on unit \"$replayid\"\n"; + print "getCategory::$categorycount categories ($categories)\n"; + } + + for ( split /\;/, $categories ) { + /\;/; + my $categoryentry = $_; + my ($c_num,$c_text) = split(/\,/,$categoryentry); + $c_num = 2 ** int $c_num; + if ($debug) { + print "getCategory::Comparing \"$c_num\" with \"$lookfor\" ($c_text)\n"; + } + + if ($c_num == $lookfor) { + $retcode = $c_text; + } + } + + if (length($retcode) == 0) { + $retcode = "All Shows"; + } + + if ($debug) { + print "getCategory::returning \"$retcode\"\n"; + } + + return $retcode; + +} + +#---------------------------------------------------------------------------------------- +sub getShowAndParent { + my $rtvshow = shift; + my $retcode = 0; + + parseShow($rtvshow); + + my $channelnum = findChannel($show_rtvcreated,$show_replayid); + + if ($channelnum) { + parseChannel($rtvevent[$channelnum]); + $show_category = getCategory($chan_rtvcategory,$show_replayid); + $retcode = 1; + }else{ + $retcode = 0; + } + + return $retcode; +} + +#---------------------------------------------------------------------------------------- +sub findChannel { + + my $rtv_event = int shift; + my $rtv_id = int shift; + my $event_num = 0; + my $status = 0; + my $ctr = 0; + + if ($debug) { + print "findChannel::Starting($rtv_event,$rtv_id)\n"; + } + + if ($debug) { + print "findChannel::Searching\n"; + } + + do { + $ctr++; + if (length($rtvevent[$ctr]) > 0) { + parseChannel($rtvevent[$ctr]); + if ($chan_replayid == $rtv_id) { + if ($chan_rtvcreate == $rtv_event) { + $event_num = $ctr; + $status = 1; + if ($debug) { + print "findChannel::found event ($ctr)\n"; + } + + } + } + }else{ + $status = 1; + } + + } while $status == 0; + + if ($debug) { + print "findChannel::exiting ($event_num,$status)\n"; + } + + + return $event_num; +} + +#---------------------------------------------------------------------------------------- +sub parseChannel { + my $rtvchannel = shift; + + undef $chan_replayid; + undef $chan_rtveventtime; + undef $chan_guaranteed; + undef $chan_channeltype; + undef $chan_daysofweek; + undef $chan_channelflags; + undef $chan_beforepadding; + undef $chan_afterpadding; + undef $chan_showlabel; + undef $chan_channelname; + undef $chan_themeflags; + undef $chan_themestring; + undef $chan_thememinutes; + undef $chan_rtvcreate; + undef $chan_rtvcategory; + undef $chan_keep; + undef $chan_norepeats; + undef $chan_minutes; + + ($chan_replayid,$chan_rtvcreate,$chan_rtveventtime,$chan_guaranteed,$chan_channeltype,$chan_daysofweek,$chan_channelflags,$chan_beforepadding,$chan_afterpadding,$chan_showlabel,$chan_channelname,$chan_themeflags,$chan_themestring,$chan_thememinutes,$chan_rtvcategory,$chan_keep,$chan_norepeats,$chan_minutes) = split(/\|/,$rtvchannel); + + $chan_categoryname = getCategory($chan_rtvcreate,$chan_replayid); + + return 1; +} + + +#---------------------------------------------------------------------------------------- +sub parseShow{ + my $rtvshow = shift; + + undef $show_replayid; + undef $show_rtvcreated; + undef $show_rtvrecorded; + undef $show_inputsource; + undef $show_quality; + undef $show_guaranteed; + undef $show_tmsid; + undef $show_channel; + undef $show_channelname; + undef $show_channellabel; + undef $show_tuning; + undef $show_rtveventtime; + undef $show_programtmsid; + undef $show_rtvminutes; + undef $show_rtvtitle; + undef $show_rtvepisode; + undef $show_rtvdescription; + undef $show_rtvactors; + undef $show_rtvguests; + undef $show_rtvsuzuki; + undef $show_rtvproducers; + undef $show_rtvdirectors; + undef $show_ext_data; + undef $show_beforepadding; + undef $show_afterpadding; + undef $show_rtvcc; + undef $show_rtvstereo; + undef $show_rtvrepeat; + undef $show_rtvsap; + undef $show_rtvlbx; + undef $show_rtvmovie; + undef $show_category; + undef $show_rating; + + ($show_replayid,$show_rtvcreated,$show_rtvrecorded,$show_inputsource,$show_quality,$show_guaranteed,$show_tmsid,$show_channel,$show_channelname,$show_channellabel,$show_tuning,$show_rtveventtime,$show_programtmsid,$show_rtvminutes,$show_rtvtitle,$show_rtvepisode,$show_rtvdescription,$show_rtvactors,$show_rtvguests,$show_rtvsuzuki,$show_rtvproducers,$show_rtvdirectors,$show_ext_data,$show_beforepadding,$show_afterpadding) = split(/\|/,$rtvshow); + ($show_rtvcc,$show_rtvstereo,$show_rtvrepeat,$show_rtvsap,$show_rtvlbx,$show_rtvmovie,$show_rating) = split(/;/,$show_ext_data); + + + return 1; +} + +#------------------------------------------------------------------------------------- +sub processSlotResponse { + # + # Process returned slot_data, patch in quality flag (not passed back on non + # manual recordings for some reason). + # + # Expects slot_data,quality + # Returns recordrequest for recordshow + # + #-------------------------------------------- + + my $slotdata = substr(shift,0,144); + my $quality = int shift; + my $recordrequest = ""; + my $specialdebug = 1; + + $recordrequest = substr($slotdata,0,48); + $recordrequest .= converthex($quality,$DWORD); + $recordrequest .= substr($slotdata,56); + + if (($debug) || ($specialdebug)) { + writeDebug("processSlotResponse returning $recordrequest"); + } + + return $recordrequest; + +} + +#----------------------------------------------------------------- +sub recordShow { + # + # Makes a RecordShow Request to Specified DVR + # + # Parameters: Replay FQDN or IP, RecordRequest HexString + # + # Returns: Response Code + # + # Codes: 2 (Debug), 1 (Success), 0 (Failed) + # + #--------------------------------------------------------- + my $replaytv = shift; + my $recordrequest = shift; + my $returndata = ""; + my $replaycmd = ""; + my $specialdebug = 1; + + + $replaycmd = "http://$replaytv/http_replay_guide-record_show?record_request=$recordrequest"; + + if ($RemoteAddress eq "") { + my $RemoteAddress = "127.0.0.1"; + } + + my $h = HTTP::Headers->new( + Host => '$RemoteAddress:80', + Accept_Coding => 'gzip'); + + if ($debug_supress_show_request) { + if ($debug) { + writeDebug("record_request: $recordrequest"); + } + return 2; + } + + $ua = LWP::UserAgent->new; + $request = HTTP::Request->new(GET => $replaycmd, $h); + $response = $ua->request($request); + + + if (($debug) || ($specialdebug)) { + writeDebug("recordShow http_replay_guide-recordshow returned: $response->content"); + } + + + if ($response->is_success) { + if ($response->content =~ /record_result=0x0/) { # Cheesy + $returndata = 1; + } + else + { + $returndata = 0; + } + + } else { + $returndata = -1; + } + + if (($debug) || ($specialdebug)) { + writeDebug("recordShow returning $returndata"); + } + + return $returndata; +} + +#----------------------------------------------------------------- +sub getManualSlotRequest { + # + # Makes a SlotRequest to Specified DVR + # + # Parameters: Replay FQDN or IP, SlotData HexString + # + # Returns: Numeric Code on Failure or + # Returned SlotData Struct + # + # + # Codes: 2 (Debug), -1 (Connect Fail), 0 (No Slots) + # + #--------------------------------------------------------- + my $replaytv = shift; + my $slotdata = shift; + my $returndata = ""; + my $replaycmd = ""; + my $manual_record_struct_size = 224; + my $specialdebug = 1; + + $replaycmd = "http://$replaytv/http_replay_guide-get_manual_record_slots?slot_data=$slotdata"; + + if ($RemoteAddress eq "") { + my $RemoteAddress = "127.0.0.1"; + } + + my $h = HTTP::Headers->new( + Host => '$RemoteAddress:80', + Accept_Coding => 'gzip'); + + if ($debug_supress_slot_request) { + return 2; + } + + if (($debug) || ($specialdebug)) { + writeDebug("getManualSlotRequest Requesting Slot: $slotdata"); + } + + if (length($slotdata) != $manual_record_struct_size) { + writeDebug("getManualSlotRequest Error: SlotData incorrect length. $manual_record_struct_size !" . length($slotdata)); + return 0; + } + + + $ua = LWP::UserAgent->new; + $request = HTTP::Request->new(GET => $replaycmd, $h); + $response = $ua->request($request); + + if (($debug) || ($specialdebug)) { + my $raw_response = $response->content; + writeDebug("getManualSlotRequest http_replay_guide-get_manual_record_slots returned: $raw_response"); + } + + if ($response->is_success) { + if ($response->content =~ /n_slots=0x0/) { # Cheesy + $returndata = 0; + } + else + { + $returndata = substr($response->content,31); # Cheesy + } + + } else { + $returndata = -1; + + } + + if (($debug) || ($specialdebug)) { + writeDebug("getManualSlotRequest returning: $returndata"); + } + + + if (($debug) || ($specialdebug)) { + writeDebug("getManualSlotRequest exiting"); + } + + return $returndata; +} + +#----------------------------------------------------------------- +sub getSlotRequest { + # + # Makes a SlotRequest to Specified DVR + # + # Parameters: Replay FQDN or IP, Program HexString, RecordRequest HexString + # + # Returns: Numeric Code on Failure or + # Returned SlotData Struct + # + # + # Codes: 2 (Debug), -1 (Connect Fail), 0 (No Slots) + # + #--------------------------------------------------------- + + my $replaytv = shift; + my $program = shift; + my $recordrequest = shift; + my $returndata = ""; + my $replaycmd = ""; + my $program_struct_size = 544; + my $record_request_struct_size = 144; + my $manual_record_struct_size = 224; + + my $specialdebug = 1; + + $replaycmd = "http://$replaytv/http_replay_guide-get_record_slots?time_based=0x1&program=$program&record_request=$recordrequest"; + + if ($RemoteAddress eq "") { + my $RemoteAddress = "127.0.0.1"; + } + + my $h = HTTP::Headers->new( + Host => '$RemoteAddress:80', + Accept_Coding => 'gzip'); + + + if ($debug_supress_slot_request) { + return 2; + } + + if (($debug) || ($specialdebug)) { + writeDebug("getSlotRequest Program: $program"); + } + + if (($debug) || ($specialdebug)) { + writeDebug("getSlotRequest Request: $recordrequest"); + } + + if (length($program) != $program_struct_size) { + writeDebug("getSlotRequest Error: Program structure incorrect length. $program_struct_size!" . length($program)); + return 0; + } + + + if (length($recordrequest) != $record_request_struct_size) { + writeDebug("getSlotRequest Error: Record request incorrect length. $record_request_struct_size!" . length($recordrequest)); + return 0; + } + + $ua = LWP::UserAgent->new; + $request = HTTP::Request->new(GET => $replaycmd, $h); + $response = $ua->request($request); + + if (($debug) || ($specialdebug)) { + writeDebug("getSlotRequest http_replay_guide-get_record_slots returned: $response->content"); + } + + if ($response->is_success) { + if ($response->content =~ /n_slots=0x0/) { # Cheesy + $returndata = 0; + } + else + { + $returndata = substr($response->content,31); # Cheesy + } + + } else { + $returndata = -1; + + } + + if (($debug) || ($specialdebug)) { + writeDebug("getSlotRequest returned: $returndata"); + } + + return $returndata; +} + +#----------------------------------------------------------------- +sub parseSlotData { + # + # Parse Slot Data + # + # Parameters: Slot_Data Response (224 chars) + # + # Returns: Printable String + # + #--------------------------------------------------------- + + my $slotdata = shift; + my $parsedstring = ""; + my $specialdebug = 1; + + my $year = hex(substr($slotdata,8,4)); + my $month = hex(substr($slotdata,12,4)); + my $day = hex(substr($slotdata,16,4)); + my $hour = hex(substr($slotdata,20,4)); + my $minute = hex(substr($slotdata,24,4)); + my $minutes = hex(substr($slotdata,40,8)); + my $textstring = &decodehex(substr($slotdata,152)); + my $timestamp = ""; + my $eventtime = timegm(0,$minute,$hour,$day,$month-1,$year); + # my $event_time = localtime($eventtime); + my $event_time = strftime "%b %d %Y %H:%M", localtime($eventtime); + + $parsedstring = "$event_time ($minutes" . "m) " . converttohtml($inp_title) . " $textstring"; + + if (($debug) || ($specialdebug)) { + writeDebug("parseSlotData $parsedstring"); + } + + return $parsedstring; +} + +#----------------------------------------------------------------- +sub buildProgram { + # + # Year,Month,Day,Hour,Minute,Title,[Running Time,[Tuning] + #------------------------------------------------------------ + + # We really only need to minimally populate this. Anything + # After Title is optional + + my $year = int shift; + my $month = int shift; + my $day = int shift; + my $hour = int shift; + my $minute = int shift; + my $titletext = shift; + + my $runningtime = int shift; + my $tuning = int shift; + + my $specialdebug = 1; + + my $programdata = ""; + my $timestamp = ""; + my $genre1 = 0; + my $genre2 = 0; + my $genre3 = 0; + my $genre4 = 0; + + $year = sprintf("%04d",$year); + $month = sprintf("%02d",$month); + $hour = sprintf("%02d",$hour); + $minute = sprintf("%02d",$minute); + $day = sprintf("%02d",$day); + + $timestamp .= $year; + $timestamp .= $month; + $timestamp .= $day; + $timestamp .= $hour; + $timestamp .= $minute; + $timestamp .= $seconds; + + $eventtime = timegm(gmtime(as_epoch_seconds($timestamp))); + + my $titleLen = length($titletext)+1; + + $programdata .= converthex(272,$DWORD); # struct_size + $programdata .= converthex(1,$DWORD); # autorecord + $programdata .= converthex(1,$DWORD); # isvalid + $programdata .= converthex($tuning,$DWORD); # tuning + $programdata .= converthex(0,$DWORD); # ProgramFlags + $programdata .= converthex($eventtime,$DWORD); # Eventtime + $programdata .= converthex(0,$DWORD); # TMSID + $programdata .= converthex($runningtime,$WORD); # minutes + $programdata .= converthex(0,$BYTE); # genre 1 + $programdata .= converthex(0,$BYTE); # genre 2 + $programdata .= converthex(0,$BYTE); # genre 3 + $programdata .= converthex(0,$BYTE); # genre 4 + $programdata .= converthex(248,$WORD); # rec len + $programdata .= converthex($titleLen,$BYTE); # title len + $programdata .= converthex(1,$BYTE); # episode length + $programdata .= converthex(1,$BYTE); # desc. length + $programdata .= converthex(1,$BYTE); # actor length + $programdata .= converthex(1,$BYTE); # guest length + $programdata .= converthex(1,$BYTE); # suzuki length + $programdata .= converthex(1,$BYTE); # prod. length + $programdata .= converthex(1,$BYTE); # dir. length + $programdata .= converttext($titletext,228); # description block + + if (($debug) || ($specialdebug)) { + writeDebug("buildProgram $programdata"); + } + + return $programdata; + +} + +#----------------------------------------------------------------- +sub buildSlotData { + # + # Builds SlotData Structure + # + # Parameters: Year,Month,Day,Hour,Minute,Length,Channel, + # Quality,Guaranteed,Recurring,DaysofWeek, + # Keep,IS GMT,Input Source,Tuning) + # + # Returns: SlotData HexString + # + #--------------------------------------------------------- + + # Year,Month,Day,Hour,Minute,Length,Channel,Quality,Guaranteed,Recurring,DaysofWeek,Keep,IS GMT,Input Source[,Tuning]) + + my $year = int shift; + my $month = int shift; + my $day = int shift; + my $hour = int shift; + my $minute = int shift; + my $runningtime = int shift; + my $channel = shift; + my $quality = int shift; + my $guaranteed = int shift; + my $recurring = int shift; + my $daysofweek = int shift; + my $keep = int shift; + my $isgmt = int shift; + my $inputsource = int shift; # Usually 3 + my $tuning = int shift; # 0 is fine. + my $slotdata = ""; + my $seconds = "00"; + + my $specialdebug = 1; + + if ($guaranteed) { + $guaranteed = "FFFFFFFF"; + }else{ + $guaranteed = "00000000"; + } + + if ($recurring) { + $recurring = "FFFFFFFF"; + }else{ + $recurring = "00000000"; + $keep = 0; + } + + if ($daysofweek == 0) { + $daysofweek = 127; + } + + $year = sprintf("%04d",$year); + $month = sprintf("%02d",$month); + $hour = sprintf("%02d",$hour); + $minute = sprintf("%02d",$minute); + $day = sprintf("%02d",$day); + + my $timestamp = ""; + + $timestamp .= $year; + $timestamp .= $month; + $timestamp .= $day; + $timestamp .= $hour; + $timestamp .= $minute; + $timestamp .= $seconds; + + + if ($isgmt == 0) { + + $eventtime = timegm(gmtime(as_epoch_seconds($timestamp))); + + ($seconds,$minute,$hour,$day,$month,$year,$wday,$yday) = + gmtime($eventtime); + $year += 1900; + $month++; + + } + + $slotdata .= converthex(3,$DWORD); # unknown1 (required) + $slotdata .= converthex($year,$WORD); # year + $slotdata .= converthex($month,$WORD); # month + $slotdata .= converthex($day,$WORD); # day + $slotdata .= converthex($hour,$WORD); # hour + $slotdata .= converthex($minute,$WORD); # minute + $slotdata .= converthex(0,$WORD); # second (unused) + $slotdata .= converthex(26924,$DWORD); # 0x692C is manual rec. + $slotdata .= converthex($runningtime,$DWORD); # minutes + $slotdata .= converthex($quality,$DWORD); # quality level + $slotdata .= converthex($inputsource,$DWORD); # input source (0 ANT/Raw RF, 1 LINE 1,2 LINE 2, 3 is tuner) + $slotdata .= converthex($tuning,$DWORD); # channel index (doesn't matter on a slot reqeuest) + $slotdata .= converthex(1,$DWORD); # manual record (should be 0x01 for manual recordings) + $slotdata .= $guaranteed; # guaranteed 0xFFFFFFFF if true + $slotdata .= $recurring; # recurring 0xFFFFFFFF if true + $slotdata .= converthex($keep,$DWORD); # keep + $slotdata .= converthex($daysofweek,$BYTE); # days of week flag + $slotdata .= converthex(0,$BYTE); # after padding + $slotdata .= converthex(0,$BYTE); # before padding + $slotdata .= converthex(0,$BYTE); # flags (unused) + $slotdata .= converthex(0,$DWORD); # unused1 + $slotdata .= converthex(0,$DWORD); # category (index) + $slotdata .= converthex(0,$DWORD); # unused2 + $slotdata .= converthex(0,$DWORD); # firstrun (0x00 = all) + $slotdata .= converthex(0,$DWORD); # flags1 + $slotdata .= converttext($channel,20); # channel label (eg. BBCA(Cable) ) + $slotdata .= converthex(0,$DWORD); # flags2 + $slotdata .= converthex(0,$DWORD); # flags3 + $slotdata .= converthex(0,$DWORD); # flags4 + $slotdata .= converthex(0,$DWORD); # flags5 + + if (($debug) || ($specialdebug)) { + writeDebug("buildSlotData $slotdata"); + } + return $slotdata; + +} + + +#----------------------------------------------------------------- +sub buildRecordRequest { + # + # Builds RecordRequest Structure for get_slot_request + # + # Parameters: Year,Month,Day,Hour,Minute,Length,Channel, + # Quality,Guaranteed,Recurring,DaysofWeek, + # Keep,[First Run Only],[IS GMT],[Category],[post Pad],[PrePad]) + # + # Returns: RecordRequest HexString + # + #--------------------------------------------------------- + + # Year,Month,Day,Hour,Minute,Length,Channel(Tuning),Quality,Guaranteed,Recurring,DaysofWeek,Keep,[FirstRun],[IS GMT],[Category],[Post Pad],[Pre Pad]) + + my $year = int shift; + my $month = int shift; + my $day = int shift; + my $hour = int shift; + my $minute = int shift; + my $runningtime = int shift; + my $channel = int shift; + my $quality = int shift; + my $guaranteed = int shift; + my $recurring = int shift; + my $daysofweek = int shift; + my $keep = int shift; + my $firstrun = int shift; + my $isgmt = int shift; + my $category = int shift; + my $postpad = int shift; + my $prepad = int shift; + + my $specialdebug = 1; + + my $recordrequest = ""; + my $seconds = "00"; + + if ($guaranteed) { + $guaranteed = "FFFFFFFF"; + }else{ + $guaranteed = "00000000"; + } + + if ($recurring) { + $recurring = "FFFFFFFF"; + }else{ + $recurring = "00000000"; + $keep = 0; + } + + if ($daysofweek == 0) { + $daysofweek = 127; + } + + $year = sprintf("%04d",$year); + $month = sprintf("%02d",$month); + $hour = sprintf("%02d",$hour); + $minute = sprintf("%02d",$minute); + $day = sprintf("%02d",$day); + + my $timestamp = ""; + + $timestamp .= $year; + $timestamp .= $month; + $timestamp .= $day; + $timestamp .= $hour; + $timestamp .= $minute; + $timestamp .= $seconds; + + if ($isgmt == 0) { + + $eventtime = timegm(gmtime(as_epoch_seconds($timestamp))); + + ($seconds,$minute,$hour,$day,$month,$year,$wday,$yday) = + gmtime($eventtime); + $year += 1900; + $month++; + } + + $recordrequest .= converthex(3,$DWORD); # unknown1 (required) + $recordrequest .= converthex($year,$WORD); # year + $recordrequest .= converthex($month,$WORD); # month + $recordrequest .= converthex($day,$WORD); # day + $recordrequest .= converthex($hour,$WORD); # hour + $recordrequest .= converthex($minute,$WORD); # minute + $recordrequest .= converthex(0,$WORD); # second (unused) + $recordrequest .= converthex(0,$DWORD); # doesn't matter + $recordrequest .= converthex($runningtime,$DWORD); # minutes + $recordrequest .= converthex($quality,$DWORD); # quality level + $recordrequest .= converthex(3,$DWORD); # input source (3 is tuner) + $recordrequest .= converthex($channel,$DWORD); # channel index (doesn't matter on a slot reqeuest) + $recordrequest .= converthex(0,$DWORD); # manual record (should be 0x01 for manual recordings) + $recordrequest .= $guaranteed; # guaranteed 0xFFFFFFFF if true + $recordrequest .= $recurring; # recurring 0xFFFFFFFF if true + $recordrequest .= converthex($keep,$DWORD); # keep + $recordrequest .= converthex($daysofweek,$BYTE); # days of week flag + $recordrequest .= converthex($postpad,$BYTE); # after padding + $recordrequest .= converthex($prepad,$BYTE); # before padding + $recordrequest .= converthex(0,$BYTE); # flags (unused) + $recordrequest .= converthex(0,$DWORD); # unused1 + $recordrequest .= converthex($category,$DWORD); # category (index) + $recordrequest .= converthex(0,$DWORD); # unused2 + $recordrequest .= converthex($firstrun,$DWORD); # firstrun (0x00 = all) + + if (($debug) || ($specialdebug)) { + writeDebug("buildRecordRequest $recordrequest"); + } + + return $recordrequest; + +} + + +#-------------------------------------------------------------------------------- +# Read Binary Data Routines - it always looks in snapshotbody at guideptr +#-------------------------------------------------------------------------------- + +#---------------------------------------------------------------------------------------- +sub GetNextDWORD{ + my $retval = unpack("N",substr($snapshotbody,$guideptr,4)); + + $guideptr = $guideptr + 4; + + return int $retval; +} + +#---------------------------------------------------------------------------------------- +sub GetNextWORD{ + my $retval = unpack("n",substr($snapshotbody,$guideptr,2)); + + $guideptr = $guideptr + 2; + + return int $retval; +} + +#---------------------------------------------------------------------------------------- +sub GetNextBYTE{ + my $retval = unpack("C",substr($snapshotbody,$guideptr,1)); + + $guideptr = $guideptr + 1; + + return $retval; +} + +#---------------------------------------------------------------------------------------- +sub GetSZ($){ + my $count = int shift; + if ($count < 0) { + return ""; + } + my $retval = unpack("Z$count",substr($snapshotbody,$guideptr,$count)); + + $guideptr = $guideptr + $count; + + return $retval; +} + +#---------------------------------------------------------------------------------------- +sub GetRaw($){ + my $count = int shift; + if ($count < 0) { + return ""; + } + my $retval = unpack("a$count",substr($snapshotbody,$guideptr,$count)); + + $guideptr = $guideptr + $count; + + return $retval; +} + +1; diff --git a/rg_scheduler.pl b/rg_scheduler.pl new file mode 100644 index 0000000..2bc2dd7 --- /dev/null +++ b/rg_scheduler.pl @@ -0,0 +1,602 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide +# by Lee Thompson +# with bits by Kanji T. Bates +# Theme Stuff based upon ReplaySchedule.pl by Kevin J. Moye +# $Id: rg_scheduler.pl,v 1.9 2003/07/24 02:00:22 pvanbaren Exp $ +# +# SCHEDULE RESOLVER MODULE: RG_SCHEDULER +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +#----------------------------------------------------------------------------------- +# +# The Schedule interface must define the following functions. +# All functions must be defined +# +# getFreshScheduleTable ( $replayid ) +# - $replayid is the database identifier of the unit to check +# - download a fresh set of schedule information from the replaytv +# - must save the schedule information so a cached copy can be loaded later +# - returns 0 if successful +# +# getCachedScheduleTable ( $replayid ) +# - $replayid is the database identifier of the unit to check +# - load in the previously cached copy of the schedule information +# - returns 0 if successful +# +# ProcessScheduleTable ( ) +# - called after all tables are loaded, but prior to displaying any details +# - prepares the schedule information for use and initialize any related variables +# - does not return any value +# +# compareScheduleTable ( $Stmt ) +# - $Stmt is a database query statement that returns the list of shows +# to be displayed +# - process all schedule tables to prepare scheduling details +# and priorities for the selected shows +# - called after all tables are loaded, but prior to displaying any details +# - does not return any value +# +# getScheduleDetails ( $programid , $timing ) +# - $programid is the database identifier the program to check +# - $timing is 0 for a past show, 1 for a present show, 2 for a future show +# - returns an icon or text string to be inserted into the html code +# indicating if the show is to scheduled to be recorded. +# - returns a "" string if no information available +# - may set the global $bgcolor variable to determing table background color +# +# AboutScheduler +# - Returns optional text which is placed in the program log file. +# +# scheduler_do_batch_update +# - If some type of nightly processing is perferred or required this should +# return true (1), otherwise return 0. +# +# schedulebar_supported +# - If the module supports the ScheduleBar (within replayguide.pl) this should +# return true (1), otherwise return 0. +# +# todo_supported +# - If the module supports the ToDo List (within replayguide.pl) this should +# return true (1), otherwise return 0. +# +#----------------------------------------------------------------------------------- + +use POSIX qw( getcwd ); +use Time::Local; + +my $_version = "Personal ReplayGuide|replaySchedule Schedule Resolver Module|1|1|108|Philip Van Baren,Kevin J. Moye"; + + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#------------------------------------------------ +sub getFreshScheduleTable { + # + # Refresh the tables used to determine scheduled programs + #--------------------------------------------------------------------------- + + my $retval; + my $replayid = shift; + my $replayaddress = $rtvaddress{ $replayid }; + my $replaylabel = $rtvlabel{ $replayid }; + my $s2sdebug = $debug; + my $prefix = ""; + my $curr_dir = getcwd; + + if ($replayid eq $null) { + writeDebug("replayid is null!"); + return 1; + } + + if ($schedule2sql eq $null) { + writeDebug("schedule2sql is undefined, check prg.conf settings!"); + return 1; + } + + if ($replayaddress eq $null) { + writeDebug("no address found for Replay #$replayid"); + return 1; + } + + my $old_verbose = $verbose; + + $verbose = 1; + + if ($schedule2sql =~ /\.pl/) { + $prefix = $^X; + if ($prefix =~ /\.dll/i) { + $prefix = ""; + } + } + + writeLogFile("Calling: '$prefix $schedule2sql $replayaddress PRG $s2sdebug' from '$curr_dir'"); + + my $result = system("$prefix $schedule2sql $replayaddress PRG $s2sdebug"); + + if ($result == -1) { + writeDebug("Could not execute $schedule2sql. Check file permissions."); + $retval = 1; + }else{ + # Get the exit value from schedule2sql.pl + $retval = $? >> 8; + } + + $verbose = $old_verbose; + + return $retval; +} + +#------------------------------------------------ +sub getCachedScheduleTable { + # Initialize the variables used for finding scheduled programs + #--------------------------------------------------------------------------- + + my $retcode = 0; + my $replayid = shift; + + # Everything is in the database already, so there is nothing + # to initialize here + + return $retcode; +} + +#------------------------------------------------ +sub ProcessScheduleTable { + # Do any processing requires to prepare the schedule tables for use + #--------------------------------------------------------------------------- + + return 1; +} + +#--------------------------------------------------------------------------------------- +sub compareScheduleTable { + # Compare the scheduled events with the displayed events + # This assumes $Stmt is defined such that it returns the displayed events + #--------------------------------------------------------------------------- + + # Nothing needed as the info is already in the database + + my $Stmt = shift; + return 1; +} + +#--------------------------------------------------------------------------------------- +sub getScheduleDetails { + # + # Build a RTV Status Icon + # + # Parameter: none + # + # ------------------------------------------------------------------------------ + + my $inp_programid = shift; + my $inp_timing = shift; + + my $retval = ""; + my $program_icon = ""; + my $program_text = ""; + my $program_icon_alt = ""; + + my $program_replayid = 0; + my $program_conflict = 0; + my $program_guaranteed = 0; + my $program_recurring = 0; + my $program_theme = 0; + my $program_beforepad = 0; + my $program_afterpad = 0; + + my $specialdebug = 0; + + if ( ! $rtvaccess) { + if ($specialdebug) { + writeDebug("getScheduleDetails::rtvaccess disabled"); + } + } else { + if ($specialdebug) { + writeDebug("getScheduleDetails::rtvaccess enabled, getting schedule icons"); + } + + #------------------------------------------------- + # Read the scheduling information from the database + #------------------------------------------------- + + my $Stmt = "SELECT * FROM $db_table_schedule WHERE programid = '$inp_programid';"; + + my $db_handle = &StartDSN; + + if ($specialdebug) { + writeDebug("getScheduleDetails::database handle is $db_handle"); + writeDebug("getScheduleDetails::attempting to execute query $Stmt"); + } + + + my $handle = sqlStmt($db_handle,$Stmt); + + + if ( $handle ) { + + #------------------------------------------------- + # Iterate through all replaytv's scheduled for this program + #------------------------------------------------- + + my $color = ""; + while ( $row = $handle->fetchrow_hashref ) { + $program_replayid = $row->{'replayid'}; + $program_beforepad = $row->{'padbefore'}; + $program_afterpad = $row->{'padafter'}; + $program_conflict = $row->{'conflict'}; + $program_guaranteed = $row->{'guaranteed'}; + $program_recurring = $row->{'recurring'}; + $program_theme = $row->{'theme'}; + + #------------------------------------------------- + # Note: should map to bits, and do a table lookup + # so the code is cleaner and faster + #------------------------------------------------- + + if ($specialdebug) { + writeDebug("getScheduleDetails::program $row->{'programid'} RTV: $program_replayid C: $program_conflict G: $program_guaranteed R: $program_recurring T: $program_theme -: $program_beforepad +: $program_afterpad"); + } + + + if ($program_theme) { + if ($showrtvthemes) { + if ($program_guaranteed) { + $program_text = "Guaranteed Theme"; + if ($program_conflict) { + $program_icon = $image_cgt; + }else{ + $program_icon = $image_gt; + } + } else { + $program_text = "Theme"; + if ($program_conflict) { + $program_icon = $image_tl; + }else{ + $program_icon = $image_tw; + } + } + } + + #------------------------------------------------- + # Theme match background color always shown + # To hide this, just set colors to an empty string + #------------------------------------------------- + + if( $program_conflict ) { + $program_text .= " in Conflict"; + $color = combine_color($color,$color_theme_conflict[ $inp_timing ]); + } else { + $color = combine_color($color,$color_theme[ $inp_timing ]); + } + } elsif ($program_recurring) { + if($program_guaranteed) { + #------------------------------------------------- + # Guaranteed Recurring + #------------------------------------------------- + if (($program_afterpad > 0) && ($program_beforepad > 0)) { + $program_text = "Guaranteed, Recurring, Padded"; + if ($program_conflict) { + $program_icon = $image_cppgr; + }else{ + $program_icon = $image_ppgr; + } + } elsif ($program_afterpad > 0) { + $program_text = "Guaranteed, Recurring, Post-Padded"; + if ($program_conflict) { + $program_icon = $image_capgr; + }else{ + $program_icon = $image_apgr; + } + } elsif ($program_beforepad > 0) { + $program_text = "Guaranteed, Recurring, Pre-Padded"; + if ($program_conflict) { + $program_icon = $image_cbpgr; + }else{ + $program_icon = $image_bpgr; + } + } else { + $program_text = "Guaranteed, Recurring"; + if ($program_conflict) { + $program_icon = $image_cgr; + }else{ + $program_icon = $image_gr; + } + } + }else{ + #------------------------------------------------- + # Non-guaranteed Recurring + #------------------------------------------------- + if (($program_afterpad) && ($program_beforepad)) { + $program_text = "Recurring, Padded"; + if ($program_conflict) { + $program_icon = $image_cppr; + }else{ + $program_icon = $image_ppr; + } + } elsif ($program_afterpad) { + $program_text = "Recurring, Post-Padded"; + if ($program_conflict) { + $program_icon = $image_capr; + }else{ + $program_icon = $image_apr; + } + } elsif ($program_beforepad) { + $program_text = "Recurring, Pre-Padded"; + if ($program_conflict) { + $program_icon = $image_cbpr; + }else{ + $program_icon = $image_bpr; + } + } else { + $program_text = "Recurring"; + if ($program_conflict) { + $program_icon = $image_cr; + }else{ + $program_icon = $image_r; + } + } + } + if ($program_conflict) { + $program_text .= " in Conflict"; + $color = combine_color($color,$color_conflict[ $inp_timing ]); + } else { + $color = combine_color($color,$color_scheduled[ $inp_timing ]); + } + }else{ + if ($program_guaranteed) { + if (($program_afterpad) && ($program_beforepad)) { + $program_text = "Guaranteed, Single, Padded"; + if ($program_conflict) { + $program_icon = $image_cppgs; + }else{ + $program_icon = $image_ppgs; + } + } elsif ($program_afterpad) { + $program_text = "Guaranteed, Single, Post-Padded"; + if ($program_conflict) { + $program_icon = $image_capgs; + }else{ + $program_icon = $image_apgs; + } + } elsif ($program_beforepad) { + $program_text = "Guaranteed, Single, Pre-Padded"; + if ($program_conflict) { + $program_icon = $image_cbpgs; + }else{ + $program_icon = $image_bpgs; + } + } else { + $program_text = "Guaranteed, Single"; + if ($program_conflict) { + $program_icon = $image_cgs; + }else{ + $program_icon = $image_gs; + } + } + }else{ + if (($program_afterpad) && ($program_beforepad)) { + $program_text = "Single, Padded"; + if ($program_conflict) { + $program_icon = $image_cpps; + }else{ + $program_icon = $image_pps; + } + } elsif ($program_afterpad) { + $program_text = "Single, Post-Padded"; + if ($program_conflict) { + $program_icon = $image_caps; + }else{ + $program_icon = $image_aps; + } + } elsif ($program_beforepad) { + $program_text = "Single, Pre-Padded"; + if ($program_conflict) { + $program_icon = $image_cbps; + }else{ + $program_icon = $image_bps; + } + }else{ + $program_text = "Single"; + if ($program_conflict) { + $program_icon = $image_cs; + }else{ + $program_icon = $image_s; + } + } + } + if ($program_conflict) { + $program_text .= " in Conflict"; + $color = combine_color($color,$color_conflict[ $inp_timing ]); + }else{ + $color = combine_color($color,$color_scheduled[ $inp_timing ]); + } + } + + $program_icon_alt = $rtvlabel{$program_replayid} . " - " . $program_text; + + if ($showrtvicons) { + if (length($program_icon) > 0) { + if (substr($program_icon,0,7) eq "http://" ) { + $retval .= "\"$program_icon_alt\""; + }else{ + $retval .= "\"$program_icon_alt\""; + } + if ($showrtvtext) { + $retval .= "($program_icon_alt)"; + } + }else{ + if ($specialdebug) { + writeDebug("getScheduleDetails::scheduled program ($row->{'programid'}) is a theme but theme display is disabled"); + } + } + }else{ + if ($showrtvtext) { + $retval .= "$program_icon_alt"; + } + } + } + #------------------------------------------------- + # Set the global bgcolor with the desired color + #------------------------------------------------- + + if($color) { + $bgcolor = $color; + } + } + + endDSN($handle,$db_handle); + } + + return $retval; +} + +#------------------------------------------------ +sub combine_color { + my $retval; + my $a = shift; + my $b = shift; + if( (length($a) != 7) || (length($b) != 7) ) { + if( $b ) { + $retval = $b; + } else { + $retval = $a; + } + } else { + # Merge the two colors together using averaging + $ar = hex substr($a,1,2); + $ag = hex substr($a,3,2); + $ab = hex substr($a,5,2); + $br = hex substr($b,1,2); + $bg = hex substr($b,3,2); + $bb = hex substr($b,5,2); + $retval = sprintf('#%02x%02x%02x', ($ar+$br)>>1, ($ag+$bg)>>1, ($ab+$bb)>>1); + } + return $retval; +} + +#------------------------------------------------ +sub AboutScheduler{ + # About Schedule Module + #--------------------------------------------------------------------------- + + my $about = ""; + $about .= "rg_scheduler SRM for replaySchedule by Kevin J. Moye and Philip Van Baren."; + + return $about; +} + +#------------------------------------------------ +sub SchedulerDefaultRefresh{ + # Refresh options for the scheduler module. + # + # Time in minutes between guide refreshes + # (0 is batch only if do_batch_update is enabled, otherwise completely + # disabled.) + #--------------------------------------------------------------------------- + + return 0; +} + + +#------------------------------------------------ +sub SchedulerDoBatchUpdate{ + # Refresh options for the scheduler module. + # + # Should scheduler module be updated at SQL time? + #--------------------------------------------------------------------------- + + return 1; +} + + +#------------------------------------------------ +sub SchedulebarSupported{ + # Does this processor support the schedulebar? + #--------------------------------------------------------------------------- + + return 1; +} + +#------------------------------------------------ +sub ToDoSupported{ + # Does this processor support the todolist? + #--------------------------------------------------------------------------- + + return 1; +} + +1; diff --git a/schedule.pl b/schedule.pl new file mode 100644 index 0000000..977f791 --- /dev/null +++ b/schedule.pl @@ -0,0 +1,1099 @@ +#!/usr/bin/perl +# +# ReplayTV Recording Scheduler +# by Lee Thompson +# with bits by Kanji T. Bates +# $Id: schedule.pl,v 1.6 2003/07/29 12:46:17 pvanbaren Exp $ +# +# NOTE: This will break in 2038. +# +#------------------------------------------------------------------------------------ +# +# This version of schedule.pl is branched to be part of Personal ReplayGuide, if you +# want an independant version it is available as "ind_schedule.pl" in this package. +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#------------------------------------------------------------------------------------- + +require HTTP::Request; +require HTTP::Headers; +require LWP::UserAgent; +use Time::Local; +use CGI qw(:standard); +use POSIX qw( strftime getcwd ); + +my $_version = "Personal ReplayGuide|ReplayTV Recording Scheduler|1|1|64|Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; +require 'rg_config.pl'; +require 'rg_replay.pl'; + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + + +#------------------------------------------------------------------------------------- +# Initialize and Process Options +#------------------------------------------------------------------------------------- + +$scriptname = $script_pathname; +$configfile = "schedule.conf"; +$createconfig = 0; +$configstatus = getConfig("replayguide"); +$configstatus = getConfig($configfile); + +#------------------------------------------------------------------------------------- + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +$debug_supress_slot_request = 0; +$debug_supress_show_request = 0; # Flip to 1 if you don't want it to really request the recording! + +CGI::import_names('input'); + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +$started = time; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +writeDebug("Job started at $now"); + +&GetWebData; + +&InitializeDisplay; + +if ($showbuttonicons < 1) { + $icon_confirm = ""; + $icon_schedule = ""; + $icon_done = ""; +} + + +#------------------------------------------------------------------------ +# Set up Variables + +$null = ""; + +$DWORD = 8; +$WORD = 4; +$BYTE = 2; + +$html_state = 0; +$slot_response_size = 224; + +$do_slot_request = 1; +$do_slot_confirm = 1; +$do_record_request = 1; + +if ($debug) { + writeDebug("Debug Messages are ON"); +} + +if ($debug_supress_slot_request) { + writeDebug("Slot requests will NOT be made"); +} + +if ($debug_supress_show_request) { + writeDebug("Show requests will NOT be made"); +} + +if ($interactive) { + writeDebug("Interactive Mode"); +} + +if (hasAccess($RemoteAddress) > 0) { + # Access Granted +}else{ + abend("Access Denied"); +} + +#------------------------------------------------------------------------------------- +# Set Up Headers + + + +#------------------------------------------------------------------------------------- +# Parse Input Fields and Build Slot Data + +# depending on state, either prsent a form or process form input + +$url_parms = ""; +$htmlstate = getParameter("state"); +if ($htmlstate eq $null) { + $htmlstate = "start"; +} + +if ($htmlstate eq "start") { + $do_slot_request = 0; + $do_slot_confirm = 0; + $do_record_request = 0; + &FormStart; +} + +if ($htmlstate eq "manual") { + if ($debug) { + writeDebug("ManualRecording"); + } + $do_slot_request = 0; + $do_slot_confirm = 0; + $do_record_request = 0; + &FormManual; +} + +if ($htmlstate eq "regular") { + if ($debug) { + writeDebug("RegularRecording"); + } + $do_slot_request = 0; + $do_slot_confirm = 0; + $do_record_request = 0; + &FormRegular; +} + +if ($htmlstate eq "slotrequest") { + if ($debug) { + writeDebug("SlotRequest"); + } + $do_slot_request = 1; + $do_slot_confirm = 1; + $do_record_request = 0; +} + +if ($htmlstate eq "recordshow") { + if ($debug) { + writeDebug("RecordShow"); + } + $do_slot_request = 0; + $do_slot_confirm = 0; + $do_record_request = 1; + $inp_selectedslot = $input::SELECTEDSLOT; + $inp_quality = $input::QUALITY; + $inp_return_url = $input::RETURNURL; # Special Applications + $inp_return_text = $input::RETURNTEXT; # Special Applications + $ReplayTV = $input::REPLAYTV; +} + +if ($debug) { + if (($do_slot_request) || ($do_slot_confirm) || ($do_record_request)) { + &DisplayOptions; + } +} + +#------------------------------------------------------------------------------------- +# If HTML Mode, check to see if we have a CURRENTSLOT already, if so skip this section + +#------------------------------------------------------------------------------------- +# Make the Slot Request + +if ($do_slot_request) { + if ($inp_manual) { + if ($debug) { + writeDebug("Getting ManualSlotRequest"); + } + + if ($debug) { + writeDebug("buildSlotData: $inp_year,$inp_month,$inp_day,$inp_hour,$inp_minute,$inp_length,$inp_channel,$inp_quality,$inp_guaranteed,$inp_recurring,$inp_daysofweek,$inp_keep,$inp_isgmt,$inp_inputsource,$inp_tuning"); + } + + $SlotData = buildSlotData($inp_year,$inp_month,$inp_day,$inp_hour,$inp_minute,$inp_length,$inp_channel,$inp_quality,$inp_guaranteed,$inp_recurring,$inp_daysofweek,$inp_keep,$inp_isgmt,$inp_inputsource,$inp_tuning); + + if ($debug) { + writeDebug("buildSlotData Returned: $SlotData"); + writeDebug("getManualSlotRequest: $ReplayTV,$SlotData"); + } + + $SlotResponse = getManualSlotRequest($ReplayTV,$SlotData); + + if ($debug) { + writeDebug("getManualSlotRequest Returned: $SlotResponse"); + } + + }else{ + if ($debug) { + writeDebug("Building Program Structure"); + } + + if ($debug) { + writeDebug("buildProgram: $inp_year,$inp_month,$inp_day,$inp_hour,$inp_minute,$inp_title,$inp_length"); + } + + $Program = buildProgram($inp_year,$inp_month,$inp_day,$inp_hour,$inp_minute,$inp_title,$inp_length); + + if ($debug) { + writeDebug("buildProgram Returned: $Program"); + writeDebug("Building Record Request Structure"); + writeDebug("buildRecordRequest: $inp_year,$inp_month,$inp_day,$inp_hour,$inp_minute,$inp_length,$inp_tuning,$inp_quality,$inp_guaranteed,$inp_recurring,$inp_daysofweek,$inp_keep,$inp_firstrun,$inp_isgmt,$inp_category,$inp_postpad,$inp_prepad"); + } + + $RecordRequest = buildRecordRequest($inp_year,$inp_month,$inp_day,$inp_hour,$inp_minute,$inp_length,$inp_tuning,$inp_quality,$inp_guaranteed,$inp_recurring,$inp_daysofweek,$inp_keep,$inp_firstrun,$inp_isgmt,$inp_category,$inp_postpad,$inp_prepad); + + if ($debug) { + writeDebug("buildRecordRequest Returned: $RecordRequest"); + writeDebug("getSlotRequest: $ReplayTV,$Program,$RecordRequest"); + } + + $SlotResponse = getSlotRequest($ReplayTV,$Program,$RecordRequest); + + if ($debug) { + writeDebug("getManualSlotRequest Returned: $SlotResponse"); + } + } + + + # Handle any errors + + if ($SlotResponse == -1) { + displayText("Error contacting DVR at $ReplayTV."); + writeDebug("Error contacting DVR at $ReplayTV."); + $do_record_request = 0; + $do_slot_request = 0; + $do_slot_confirm = 0; + } + + if ($SlotResponse == 0) { + displayText("Slot not available on DVR at $ReplayTV."); + writeDebug("Slot not available on DVR at $ReplayTV."); + $do_record_request = 0; + $do_slot_request = 0; + $do_slot_confirm = 0; + } + + if ($SlotResponse == 2) { + displayText("Slot not requested to DVR at $ReplayTV."); + writeDebug("Slot not requested to DVR at $ReplayTV."); + } +} + + +#------------------------------------------------------------------------------------- +# Show Available Slots and either present a confirmation or selection + +#------------------------------------------------------------------------------------- + +if ($do_slot_confirm) { + $n_slots = int (length($SlotResponse) / $slot_response_size); + $c_slot = 1; + + $SelectedSlot = 1; + + if ($n_slots == 1) { + displayHeading("Confirm Selection:"); + }else{ + displayHeading("Select which program to schedule:\n"); + } + + $do_record_request = 0; + $url_parms = ""; + addParameter("state","recordshow"); + print "

\n"; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + + do { + $CurrentSlot = substr($SlotResponse,($c_slot-1) * $slot_response_size,$slot_response_size); + print ""; + print "\n"; + if ($showpdaformat) { + print ""; + } + print parseSlotData($CurrentSlot); + if ($showpdaformat) { + print ""; + } + print "
\n"; + $c_slot++; + + } while ($c_slot <= $n_slots); + + print "

"; + if (length($icon_confirm) > 0) { + print "\n"; + }else{ + print "\n"; + } + print "

\n"; + + if ($SelectedSlot > 0) { + $CurrentSlot = substr($SlotResponse,($SelectedSlot-1) * $slot_response_size,$slot_response_size); + }else{ + $CurrentSlot = "CANCEL"; + } +}else{ + # Already have the slot selected, make the record request + $CurrentSlot = $inp_selectedslot; +} + +#------------------------------------------------------------------------------------- +# Handle Cancelation +#------------------------------------------------------------------------------------- + +if ($CurrentSlot eq "CANCEL") { + writeDebug("Recording cancelled"); + $do_record_request = 0; +}else{ + if (($do_slot_request) || ($do_slot_confirm)) { + if (length($CurrentSlot) != $slot_response_size) { + + writeDebug("No slot selected or invalid slot"); + $do_record_request = 0; + }else{ + $ShowDetails = parseSlotData($CurrentSlot); + } + } +} + + + +#------------------------------------------------------------------------------------- +# Make Record Request +#------------------------------------------------------------------------------------- + + +if ($do_record_request) { + + $ShowDetails = parseSlotData($CurrentSlot); + $RecordRequest = processSlotResponse($CurrentSlot,$inp_quality); + + if ($debug) { + writeDebug("Requesting Show to Be Recorded"); + } + + $RecordRequestResponse = recordShow($ReplayTV,$RecordRequest); + + if ($RecordRequestResponse == -1) { + displayHeading("Request Failed"); + writeDebug("Error contacting DVR at $ReplayTV."); + } + + if ($RecordRequestResponse == 0) { + displayHeading("Request Failed"); + writeDebug("Record show request failed on DVR at $ReplayTV."); + } + + if ($RecordRequestResponse == 1) { + displayHeading("Request Confirmed"); + writeDebug("$ShowDetails has been scheduled on DVR at $ReplayTV."); + if (length($inp_return_url) > 0) { + $inp_return_url .= "&UPDATE=$ReplayTV"; + } + } + + if ($RecordRequestResponse == 2) { + displayHeading("Request Failed"); + writeDebug("Record show for $ShowDetails not requested to DVR at $ReplayTV."); + } + +} + +#------------------------------------------------------------------------------------- +# Create Return Link +#------------------------------------------------------------------------------------- + +if (length($inp_return_url) > 0) { + print "

$inp_return_text

"; +}else{ + $url_parms = ""; + addParameter("state","start"); + print "

New

"; +} + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + + +writeDebug("Job finished at $now ($runtime seconds)"); + +writeDebug("********************************************************"); + + +&ShowHTTPFooter; + +exit(1); + + + +#----------------------------------------------------------------- +# +# Functions +# +#----------------------------------------------------------------- + + +#--------------------------------------------------------------------------------------- +sub LoadValues { + # + # Load Hard Coded Values for Special Purposes (like me testing) + # + # ------------------------------------------------------------------------------ + + $ReplayTV = "replay.sgc.logh.net"; # FQDN or IP of the Replay + + $inp_manual = 0; # Manual Recording? + + $inp_year = 2003; # Year of Recording + $inp_month = 6; # Month of Recording + $inp_day = 13; # Day of Recording + $inp_hour = 21; # Hour of Recording (0-23) + $inp_minute = 00; # Minute of Recording + $inp_length = 60; # Length (Minutes) + $inp_quality = 1; # Quality (2 Low, 1 Med, 0 High) + $inp_guaranteed = 0; # Delete For New Episodes/Keep Until I Delete + $inp_recurring = 0; # Recurring + $inp_daysofweek = 127; # Days of the Week Bitmask (127 for all) + # + # SU MO TU WE TH FR SA + # 1 2 4 8 16 32 64 + # + $inp_keep = 1; # Number of Episodes to Keep + $inp_isgmt = 0; # Is Recording Time Already GMT? + $inp_firstrun = 0; # Record First Run Episodes Only? + $inp_category = 255; # Category to Use (use 255 for ALL SHOWS) + + + # Required for REGULAR RECORDINGS only + + $inp_title = "Stargate SG-1"; # Used for Regular Lookups + # eg. Stargate SG-1 + + + # Required for MANUAL RECORDINGS only + + $inp_channel = "SCIFIP(Cable)"; # Used for Manual Lookups + # eg. SCIFIP(Cable) + + # Optional Fields + + $inp_tuning = 0; # Optional and often no effect whatsoever + $inp_postpad = 0; + $inp_prepad = 0; + $inp_inputsource = 3; # Almost always tuner + + return; +} + +#----------------------------------------------------------------- +sub DisplayOptions { + # + # Display Running Configuration (this is mostly for debugging purposes and the + # output is not very pretty.) + # + # ------------------------------------------------------------------------------ + + writeDebug("\nSelected Options"); + writeDebug(" ReplayTV: $ReplayTV"); + writeDebug(" Is Manual: $inp_manual"); + writeDebug(" Event Time: $inp_month/$inp_day/$inp_year $inp_hour:$inp_minute"); + writeDebug(" Length: $inp_length"); + writeDebug(" Quality: $inp_quality"); + writeDebug("Is Guaranteed: $inp_guaranteed"); + writeDebug(" Is Recurring: $inp_recurring"); + writeDebug(" Days: $inp_daysofweek"); + writeDebug(" Keep: $inp_keep"); + writeDebug(" First Run: $inp_firstrun"); + writeDebug(" Category: $inp_category"); + writeDebug(" Record Type: $inp_recordtype"); + if ($inp_manual) { + writeDebug(" Channel: $inp_channel"); + }else{ + writeDebug(" Title: " . &converttohtml($inp_title)); + } + writeDebug(" Tuning: $inp_tuning"); + writeDebug(" Pre Pad: $inp_prepad"); + writeDebug(" Post Pad: $inp_postpad\n"); + writeDebug(" Input Source: $inp_inputsource\n"); + return; + +} + +#----------------------------------------------------------------- +sub GetWebData { + # + # Get Show Data via CGI + # + #--------------------------------------------------------- + + $ReplayTV = $input::REPLAYTV; + + $inp_manual = int $input::ISMANUAL; # Recording Type + # 0 Regular 1 Manual + + $inp_year = int $input::YEAR; # Year of Recording + $inp_month = int $input::MONTH; # Month of Recording + $inp_day = int $input::DAY; # Day of Recording + $inp_hour = int $input::HOUR; # Hour of Recording + $inp_minute = int $input::MINUTE; # Minute of Recording + $inp_length = int $input::LENGTH; # Running Time in Minutes + + $inp_quality = int $input::QUALITY; # Quality Level (2 Standard, 1 Medium, 0 High) + $inp_guaranteed = int $input::GUARANTEED; # Delete For New Episodes/Keep Until I Delete + $inp_recurring = int $input::RECURRING; # Recurring + $inp_firstrun = int $input::FIRSTRUN; # Record First Run Episodes Only? + $inp_keep = int $input::KEEP; # Episodes to Keep + + + # DAYS OF THE WEEK Mask + $inp_SU = $input::SUN; # 1 + $inp_MO = $input::MON; # 2 + $inp_TU = $input::TUE; # 4 + $inp_WE = $input::WED; # 8 + $inp_TH = $input::THU; # 16 + $inp_FR = $input::FRI; # 32 + $inp_SA = $input::SAT; # 64 + + $inp_recordtype = int $input::RECORDTYPE; + + if ($inp_recordtype == 1) { + # First Run and Repeats + $inp_firstrun = 0; + $inp_recurring = 1; + } + + if ($inp_recordtype == 2) { + # First Run + $inp_firstrun = 1; + $inp_recurring = 1; + } + + if ($inp_recordtype == 3) { + # This Show Only + $inp_firstrun = 0; + $inp_recurring = 0; + } + + + + # Exclusive to REGULAR RECORDINGS + + $inp_category = int $input::CATEGORY; # Category to Use (use 0 for ALL SHOWS) + $inp_title = $input::SHOWTITLE; # Used for Regular Lookups + # eg. Stargate SG-1 + + $inp_title = convertfromhtml($inp_title); + + # Exclusive to MANUAL RECORDINGS + + $inp_channel = $input::CHANNEL; # Used for Manual Lookups + # eg. SCIFIP(Cable) + + $inp_inputsource = $input::INPUTSOURCE; # Input Source + + if ($inp_inputsource eq "") { + $inp_inputsource = 3; # Tuner + } + + # OPTIONAL SETTINGS + + $inp_isgmt = 0; # set to 1 to skip GMT convert + $inp_tuning = int $input::TUNING; # Channel Number + $inp_postpad = int $input::POSTPAD; # After Padding (Minutes) + $inp_prepad = int $input::PREPAD; # Before Padding (Minutes) + + + $inp_return_url = $input::RETURNURL; # Special Applications + $inp_return_text = $input::RETURNTEXT; # Special Applications + + + # Process Options + + + if ($inp_SU) { + $inp_daysofweek = $inp_daysofweek + 1; + } + + if ($inp_MO) { + $inp_daysofweek = $inp_daysofweek + 2; + } + + if ($inp_TU) { + $inp_daysofweek = $inp_daysofweek + 4; + } + + if ($inp_WE) { + $inp_daysofweek = $inp_daysofweek + 8; + } + + if ($inp_TH) { + $inp_daysofweek = $inp_daysofweek + 16; + } + + if ($inp_FR) { + $inp_daysofweek = $inp_daysofweek + 32; + } + + if ($inp_SA) { + $inp_daysofweek = $inp_daysofweek + 64; + } + + $showpdaformat = int $input::SHOWPDAFORMAT; + + + return; +} + + + +#--------------------------------------------------------------------------------------- +# WEB FORM Generation +#--------------------------------------------------------------------------------------- + +#---------------------------------------------------- +sub FormStart{ + print "

You may schedule a:
\n

    "; + $url_parms = ""; + addParameter("state","manual"); + print "
  • Manual Recording
    \n"; + $url_parms = ""; + addParameter("state","regular"); + print "
  • Regular Recording
    \n"; + print "

\n"; + return; +} + +#---------------------------------------------------- +sub FormManual{ + displayHeading("Manual Recording\n"); + + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = + localtime(time); + $year += 1900; + $mon++; + + my $lastyear = $year - 1; + + $url_parms = ""; + addParameter("state","slotrequest"); + print "

\n"; + print "\n"; + print "\n"; + + # Select ReplayTV + + print "\n"; + print "\n"; + print "\n"; + + # Select Date of Recording + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + print "\n"; + + + if ($systemtype == 1) { + $systemtype = "Cable"; + } + if ($systemtype == 2) { + $systemtype = "DBS"; + } + if ($systemtype == 3) { + $systemtype = "Air"; + } + + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + + print "
ReplayTV:
Date:\n"; + + print "\n"; + + print "\n"; + + print "\n"; + print "
Time:\n"; + print "\n"; + print ":"; + print "\n"; + print "
Record for\n"; + print "\n"; + print "
Channel:\n"; + if (open(XMLTVFILE, $xmltvconfiguration)) { + print "\n"; + }else{ + print ""; + print "
Call Letters and System for Channel (eg. BBCA($systemtype))"; + } + print "
Quality:\n"; + print "\n"; + print "
Options:"; + print " Guaranteed\n"; + print " Recurring\n"; + print "
Record on "; + print " Sun.\n"; + print " Mon.\n"; + print " Tue.\n"; + print " Wed.\n"; + print " Thu.\n"; + print " Fri.\n"; + print " Sat.\n"; + print "
Episodes to Keep:"; + print "\n"; + print "
"; + if (length($icon_schedule) > 0) { + print "\n\n"; + }else{ + print "\n\n"; + } + print "

"; + print "

"; + + return; +} + +#---------------------------------------------------- +sub FormRegular{ + + displayHeading("Regular Recording\n"); + + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = + localtime(time); + $year += 1900; + $mon++; + + my $lastyear = $year - 1; + + $url_parms = ""; + addParameter("state","slotrequest"); + print "
\n"; + print "\n"; + print "\n"; + + # Select ReplayTV + + print "\n"; + print "\n"; + print "\n"; + + # Select Date of Recording + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + print "\n"; + + print "\n\n"; + print "\n\n"; + print "\n"; + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + + print "\n"; + print "\n"; + + print "
ReplayTV:
Date:\n"; + + print "\n"; + + print "\n"; + + print "\n"; + print "
Time:\n"; + print "\n"; + print ":"; + print "\n"; + print "
Record for\n"; + print "\n"; + print "
Pad Before: minutes
Pad After: minutes
Title:\n"; + print ""; + print "
Quality:\n"; + print "\n"; + print "
Options:"; + print " Guaranteed\n"; + print " Recurring\n"; + print " First Run Only\n"; + print "
Record on "; + print " Sun.\n"; + print " Mon.\n"; + print " Tue.\n"; + print " Wed.\n"; + print " Thu.\n"; + print " Fri.\n"; + print " Sat.\n"; + print "
Episodes to Keep:"; + print "\n"; + print "
"; + if (length($icon_schedule) > 0) { + print "\n\n"; + }else{ + print "\n\n"; + } + print "

"; + print "

"; + + return; +} + diff --git a/schedule2sql.pl b/schedule2sql.pl new file mode 100644 index 0000000..008d24b --- /dev/null +++ b/schedule2sql.pl @@ -0,0 +1,733 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide SQL Converter +# by Phil Van Baren +# based on code by Lee Thompson +# with bits by Kanji T. Bates +# $Id: schedule2sql.pl,v 1.18 2003/11/04 00:28:36 pvanbaren Exp $ +# +# RG_SCHEDULER SQL INJECTOR +# +# Requirements: +# replaySchedule +# +# replaySchedule is (C) 2003 by Kevin J. Moye +# http://replayguide.sourceforge.net/replaySchedule +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +use POSIX qw( strftime getcwd ); +use English; +use Time::Local; +require LWP::Simple; +require LWP::UserAgent; +require HTTP::Request; +require HTTP::Headers; + +my $_version = "Personal ReplayGuide|replaySchedule SRM to SQL Converter|1|0|21|Philip Van Baren,Kanji T. Bates,Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Load database info +require 'rg_config.pl'; # Load config library + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Debug Options +#----------------------------------------------------------------------------------- +$do_not_drop_rows = 0; # Do not DELETE rows first +$do_not_insert = 0; # Skip the DB insert + +#----------------------------------------------------------------------------------- +# Define Options +#----------------------------------------------------------------------------------- +$debug = 1; # Debug Messages +$multiplier = 1000; # Default Multiplier +$maxrows = 0; # Maximum Number of rows to INSERT +$datafeed = "xmltv"; # Default Format (xmltv or datadirect) +$cnf_xmlfile = "na.xml"; # XMLTV output +$verbose = 1; # Talky + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$min_rs = 116.26; # Minimum version of replaySchedule + # NOTE: It is not a fatal error if the rs + # executable is less than this value. + #------------------------------------------- + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +$rows = 0; +$null = ""; + +#----------------------------- +# OS-Sensitive defaults +#----------------------------- + +if ($^O eq 'MSWin32') { + $replaySchedule = "replaySchedule.exe"; # Command to run replaySchedule +} else { + $replaySchedule = "./replaySchedule"; # Command to run replaySchedule +} + + + +$configfile = "schd2sql.conf"; # This is optional +$configstatus = getConfig($configfile); # Read Configuration + +#------------------------------------------------------------------------------- +# Process Command Line +#------------------------------------------------------------------------------- +# Syntax: schedule2sql.pl IPADDRESS FLAG VERBOSE +# +# FLAG is "PRG" which allows it to make an exception and be run in HTTP context. +# +# VERBOSE is optional and can be 1 (true) or 0 (false). If true then output +# will be rendered to STDOUT in either HTML or plaintext (depending on context). +# +#------------------------------------------------------------------------------- + +$rtvaddress = $ARGV[0]; +$specialflag = $ARGV[1]; +if (defined($ARGV[2])) { + $verbose = int $ARGV[2]; +} + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + if (uc $specialflag eq 'PRG') { + $remotemode = 0; # Special Permission Granted + }else{ + $remotemode = 1; + } +} + + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + + +identifyLoadedModules(); + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + + +#------------------------------------------------------------------- +# Check command line arguments +#------------------------------------------------------------------- + +writeDebug("Command Line: IP: $ARGV[0] FLAG: $ARGV[1] VERBOSE: $ARGV[2]"); + +if( ! $rtvaddress ) { + abend("rtvaddress not defined!"); +} + + + +#----------------------------------------------------------------------------------- +# Override default listing selection if listingmap is defined +#----------------------------------------------------------------------------------- + +if( $listingmap{$rtvaddress} ) { + $cnf_xmlfile = $listingmap{$rtvaddress}; +} + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + +if ($debug) { + writeDebug("Debug Messages are ON"); +} + +writeDebug("Current Time: $now"); +writeDebug("Connecting to ReplayTV: $rtvaddress"); + +#------------------------------------------------------------------- +# Set up Database +#------------------------------------------------------------------- + +&InitDB; +&InitDSN; + +#------------------------------------------------------------------- +# Start Database +#------------------------------------------------------------------- + +$prgdb_handle = &StartDSN; + +if ($prgdb_handle ne $null) { + writeDebug("Database Connection Established! $DATASOURCE{DSN} ($prgdb_handle)"); +}else{ + writeDebug("Attempt to Connect Failed: " . &GetLastSQLError()); + abend("Could not establish database connection!"); +} + +#------------------------------------------------------------------- +# Get the unique replayid for this address +#------------------------------------------------------------------- + +$Stmt = "SELECT * FROM $db_table_replayunits WHERE replayaddress = '$rtvaddress';"; +$handle = sqlStmt($prgdb_handle,$Stmt); + +if( $handle ) { + if ( $row = $handle->fetchrow_hashref ) { + $replayid = $row->{'replayid'}; + $replayname = $row->{'replayname'}; + $replayport = $row->{'replayport'}; + } else { + abend("No replaytv unit configured for address $rtvaddress"); + } + $handle->finish; +} else { + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); +} + + +#------------------------------------------------------------------- +# Clean previous schedule info +#------------------------------------------------------------------- + +if ($do_not_drop_rows) { + writeDebug("Skipping Row Delete"); +}else{ + writeDebug("Deleting previous schedule info ..."); + + $Stmt = "DELETE FROM $db_table_schedule WHERE replayid = '$replayid';"; + + if ( sqlStmt($prgdb_handle,$Stmt) ) { + writeDebug("Database flushed"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + } +} + +$FieldNames = "programid, replayid, firstrun, guaranteed, theme, " . + "recurring, manual, conflict, created, padbefore, padafter"; + +#------------------------------------------------------------------- +# If INSERT is disabled, log data to a CSV +#------------------------------------------------------------------- + +if ($do_not_insert) { + open(CSVFILE, ">schedule.csv"); + writeDebug("SQL Insert Disabled, Writing to CSV (schedule.csv)"); + + print CSVFILE $FieldNames; + print CSVFILE "\n"; +} + + +$categories = ""; +$replayversion = 0; +$guideversion = 0; + + +#----------------------------------------------------------------------------------- +# Get version information for replaySchedule +#----------------------------------------------------------------------------------- + +if(!open(REPLAYSCHEDULE, "$replaySchedule --quiet |")) { + abend("Could not execute $replaySchedule"); +} + +while() { + $line = $_; + chomp($line); + $original_line = $line; + + if ( /Version: / ) { + $string = $line; + } +} + +close REPLAYSCHEDULE; + +(my $junk,my $junk,my $rs_title,my $rs_version,my $rs_date,my $rs_time,my $rs_author,my $junk,my $junk) = split( / /,$string,9); + +writeDebug("$replaySchedule version $rs_version by $rs_author ($rs_date $rs_time)"); + +if ($rs_version < $min_rs) { + writeDebug("Warning! Your copy of $replaySchedule is older than the version tested with this version of $program_title ($min_rs)"); +} + +#----------------------------------------------------------------------------------- +# Dump the scheduled recordings to an XML file +#----------------------------------------------------------------------------------- + +if(($replayport) && ($replayport != 80)) { + $addr = "$rtvaddress:$replayport"; +} else { + $addr = $rtvaddress; +} + +$cmd_string = ""; + +if($cnf_xmlfile =~ m/xml/) { + $cmd_string = "--xml - --ip $addr --schedule $cnf_xmlfile --quiet"; +} else { + $cmd_string = "--xml - --ip $addr --guide $cnf_xmlfile --quiet "; +} + +#----------------------------------------------------------------------------------- +# If format is datadirect, tell replaySchedule +#----------------------------------------------------------------------------------- + +if((uc $datafeed eq 'DATADIRECT') || (uc $datafeed eq 'DD')){ + $cmd_string = "--dd " . $cmd_string; +} + +writeDebug("Calling->$replaySchedule $cmd_string"); + +if(!open(REPLAYSCHEDULE, "$replaySchedule $cmd_string |")) { + abend("Failed to download schedule from $rtvaddress"); +} + +#------------------------------------------------------------------- +# Convert XML to SQL +#------------------------------------------------------------------- + +writeDebug("Parsing Data and Inserting Rows"); + +while() { + + #----------------------------------------------------------- + # Parse XML + #----------------------------------------------------------- + + $line = $_; + chomp($line); + $original_line = $line; + + #----------------------------------------------------------- + # VERSION INFO + #----------------------------------------------------------- + + if ( /([^\"]*)<.*/$1/; + $replayversion = int $string; + } + + if ( /([^\"]*)<.*/$1/; + $guideversion = int $string; + } + + #----------------------------------------------------------- + # CATEGORIES + #----------------------------------------------------------- + + if ( /([^<]*)<.*/$1,$2/; + if($categories eq "") { $categories = $string; } + else { $categories .= ";" . $string; } + } + + #----------------------------------------------------------- + # PROGRAMS + #----------------------------------------------------------- + + if ( // ) { + $program_title = $line; + $program_title =~ s/.*([^<]*)\W.*/$1/; + } + + if ( /<sub-title>/ ) { + $program_subtitle = $line; + $program_subtitle =~ s/.*<sub-title>([^<]*)\W.*/$1/; + } + + if ( /<created>/ ) { + $created = $line; + $created =~ s/.*<created>([^<]*)\W.*/$1/; + } + + if ( /<address>/ ) { + $rtvaddress = $line; + $rtvaddress =~ s/.*<address>([^<]*)\W.*/$1/; + } + + if ( /<pad-before/ ) { + $padbefore = $line; + $padbefore =~ s/.*<pad-before>([^<]*)\W.*/$1/; + $padbefore = int $padbefore; + } + + if ( /<pad-after/ ) { + $padafter = $line; + $padafter =~ s/.*<pad-after>([^<]*)\W.*/$1/; + $padafter = int $padafter; + } + + if ( /<guaranteed>1/ ) { + $guaranteed = 1; + } + + if ( /<firstrun>1/ ) { + $firstrun = 1; + } + + if ( /<type.*recurring/i ) { + $recurring = 1; + } + + if ( /<type.*theme/i ) { + $theme = 1; + } + + if ( /<manual>1/ ) { + $manual = 1; + } + + if ( /<conflict/ ) { + if( /Loser/ ) { + $conflict = 1; # Will NOT record + } else { + $conflict = 0; # Will record + } + } + + if ( /<\/programme/ ) { + + $Stmt = ""; + + $dataok = 1; + + + ($Y,$M,$D,$h,$m,$s) = unpack 'A4 A2 A2 A2 A2 A2', $program_start; + $program_start = "$Y-$M-$D $h:$m:$s"; + $Y = int $Y; + + if ($Y < 1) { + $dataok = 0; + } + + $created = as_epoch_seconds($created); + + $program_title = filterfield($program_title); + $program_subtitle = filterfield($program_subtitle); + + if ($dataok) { + if ($do_not_insert) { + $FieldValues = "'$program_title', '$replayid', $firstrun, $guaranteed, " . + "$theme, $recurring, $manual, $conflict, '$created', " . + "$padbefore, $padafter"; + print CSVFILE $FieldValues; + print CSVFILE "\n"; + + $rows++; + + }else{ + if (&PostSQL) { + $rows++; + } + } + } + + #print "."; + + if ($maxrows) { + if ($rows > $maxrows) { + close REPLAYSCHEDULE; + if ($do_not_insert) { + close CSVFILE; + } + abend("Max Rows Reached ($maxrows)"); + } + } + + } + +} + +close REPLAYSCHEDULE; + +#----------------------------------------------------------------------------------- +# Get the return value from replaySchedule +#----------------------------------------------------------------------------------- + +$retcode = $? >> 8; + + +writeDebug("Completed processing replaySchedule data. $replaySchedule returned $retcode."); + + +if ($do_not_insert) { + close CSVFILE; + abend("Done! do_not_insert set to $do_not_insert."); +}elsif(! $categories || ! $rows) { + writeDebug("** No scheduled shows ** "); +}else{ + #--------------------------------------------------------------------------- + # Set the category list for this replay unit + #--------------------------------------------------------------------------- + + $replayosversion = $guideversion*10 + 30 + $replayversion; + $Stmt = "UPDATE $db_table_replayunits SET categories='$categories', " . + "replayosversion='$replayosversion', " . + "guideversion='$guideversion'" . + "WHERE replayid = '$replayid';"; + + if ( sqlStmt($prgdb_handle,$Stmt) ) { + writeDebug("Category list was updated"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Category list update failed: $sql_error"); + + } +} + +writeDebug("$rows rows were added"); + + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Terminating Database Connection from $DATASOURCE{DSN} ($prgdb_handle)"); +endDSN($handle,$prgdb_handle); + +writeDebug("Job finished at $now ($runtime seconds)"); + +writeDebug("exiting module with retcode $retcode"); + +&ShowHTTPFooter; + +writeDebug("********************************************************"); + +exit($retcode); + + + + +#---------------------------------------------------------------------------- +sub PostSQL{ + # + # Insert a Row into SCHEDULE table + # + # ------------------------------------------------------------------------------ + + my $iRetCode = 0; + my $programid = ""; + + #-------------------------------------------- + # Locate the program id for this show + #-------------------------------------------- + + if( $program_tmsid ) { + # Try find the channel using the tmsid + $Stmt = "SELECT * FROM $db_table_tvlistings " . + "WHERE tmsid = '$program_tmsid' AND starttime = '$program_start';"; + $handle = sqlStmt($prgdb_handle,$Stmt); + if ( $handle ) { + if( $row = $handle->fetchrow_hashref ) { + $programid = $row->{'programid'}; + } + } + } + + if( !$programid ) { + # Try with the channel name + $Stmt = "SELECT * FROM $db_table_tvlistings " . + "WHERE channel = '$program_channel' AND starttime = '$program_start';"; + $handle = sqlStmt($prgdb_handle,$Stmt); + if ( $handle ) { + if( $row = $handle->fetchrow_hashref ) { + $programid = $row->{'programid'}; + } + } + } + + if( ! $programid ) { + if ( $debug ) { + writeDebug("** Show not found in tvlistings database: $program_title on $program_channel at $program_start"); + } + $iRetCode = 0; + }else{ + $FieldValues = "'$programid', '$replayid', $firstrun, $guaranteed, " . + "$theme, $recurring, $manual, $conflict, '$created', " . + "$padbefore, $padafter"; + $Stmt = "INSERT INTO $db_table_schedule ($FieldNames) VALUES ($FieldValues);"; + if ( sqlStmt($prgdb_handle,$Stmt) ) { + $iRetCode = 1; + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Insert Failed: $sql_error"); + } + } + + return $iRetCode; +} + diff --git a/setup_perl.bat b/setup_perl.bat new file mode 100644 index 0000000..40f2dbf --- /dev/null +++ b/setup_perl.bat @@ -0,0 +1,26 @@ +echo off +echo This batch file will install the necessary Perl modules for use with +echo Personal ReplayGuide. +echo . +echo This utility has absolutely no warranty of any kind and has only been +echo tested with ActivePerl on Windows. Have fun :) +echo . +pause +echo You are brave! If you see messages about the modules already being +echo installed, don't worry. +echo . +echo If you're still sure you want to run this batch file, +pause +echo Installing. +ppm install cgi +ppm install time-local +ppm install dbi +ppm install dbd-odbc +ppm install dbd-mysql +ppm install dbd-sqlite +ppm install soap-lite +echo Done! + + + + diff --git a/sqlconfig.pl b/sqlconfig.pl new file mode 100644 index 0000000..ff1c7f1 --- /dev/null +++ b/sqlconfig.pl @@ -0,0 +1,446 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide Configuration Utility +# by Lee Thompson <thompsonl@logh.net> +# with bits by Kanji T. Bates +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2004 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +use POSIX qw( strftime getcwd ); +use English; +use Time::Local; +require LWP::Simple; +require LWP::UserAgent; +require HTTP::Request; +require HTTP::Headers; + +my $_version = "Personal ReplayGuide|SQL Configure|1|0|14|Lee Thompson,Kanji T. Bates"; + +#------------------------------------------------------------------------------------ +# Determine Current Directory +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_config.pl'; # Load config functions +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Load database config + + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Debug Options +#----------------------------------------------------------------------------------- +$debug = 0; # Debug Messages + +#----------------------------------------------------------------------------------- +# Define Options +#----------------------------------------------------------------------------------- +$allow_create_database = 1; + + +$configfile = "configure.conf"; # This is optional +$configstatus = getConfig($configfile); # Read Configuration +$verbose = 1; + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$null = ""; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + $remotemode = 1; +} + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +if ($debug) { + &writeOutput("Debug Messages are ON"); +} + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; # Disabled +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + + +#------------------------------------------------------------------- + + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + + + +writeDebug("Job started at $now"); + + +#------------------------------------------------------------------- +# Set up Database +#------------------------------------------------------------------- + +&InitDB; + +#---------------------------------------------------------------- +# Set Defaults +#---------------------------------------------------------------- + +$inp_scriptdir = ""; + +#---------------------------------------------------------------- +# Start +#---------------------------------------------------------------- + +writeDebug("Entering Interactive Mode"); + +print "\nWelcome to the $program_title configuration utility.\n"; + +#---------------------------------------------------------------- +# Warn about DBMS packages that do not support ALTER TABLE +#---------------------------------------------------------------- + + +if ($db_driver eq "SQLite") { + print "\n"; + print "Warning! $db_driver does not support commands needed to update table so\n"; + print " any data in any tables involved in an upgrade will be lost.\n"; + print "\n"; + print " $db_driver will automatically create the database if it does not exist.\n"; + $allow_create_database = 0; +} + +if ($db_driver eq "ODBC") { +# $allow_create_database = 0; +} + +#---------------------------------------------------------------- +# Gather Information +#---------------------------------------------------------------- + +$inp_dortv = 1; +$inp_createdb = 0; +$inp_isupgrade = "no"; + +if ($inp_dortv) { + $choiceok = 0; + do { + print "\nIs this an upgrade?\n[default: no] > "; + $inp_isupgrade = <STDIN>; + $inp_isupgrade =~ s/\r//g; # Eat LF + $inp_isupgrade =~ s/\n//g; # Eat CR + + if ($inp_isupgrade =~ /Y/i) { + $inp_isupgrade = 1; + }else{ + $inp_isupgrade = 0; + } + if (($inp_isupgrade > -1) && ($inp_isupgrade < 2)) { + $choiceok = 1; + } + } while ($choiceok < 1); + + if ((!$inp_isupgrade) && ($allow_create_database)) { + $choiceok = 0; + do { + print "\nCreate the $db_name database?\n[default: no] > "; + $inp_createdb = <STDIN>; + $inp_createdb =~ s/\r//g; # Eat LF + $inp_createdb =~ s/\n//g; # Eat CR + + if ($inp_createdb =~ /Y/i) { + $inp_createdb = 1; + } + if (($inp_createdb > -1) && ($inp_createdb < 2)) { + $choiceok = 1; + } + } while ($choiceok < 1); + + } + +} + +print "\n\n"; + +writeDebug("Interactive Mode Completed"); +writeDebug("Option Selected: isupgrade: $inp_isupgrade"); +if ($allow_create_database) { + writeDebug("Option Selected: createdb: $inp_createdb"); +} + +#------------------------------------------------------------------- +# Create Database (Untested) +#------------------------------------------------------------------- + +if ($inp_createdb) { + writeDebug("Creating Database ($db_name)"); + + $retcode = CreateDatabase(); + + &InitDSN; + + $db_link = &StartDSN; + $sth = sqlStmt($db_link,"CREATE DATABASE $db_name;"); + endDSN($sth,$db_link); + +} + +&InitDSN; + +#------------------------------------------------------------------- +# Start Database +#------------------------------------------------------------------- + +$DSNLink = &StartDSN; + +if ($DSNLink ne $null) { + writeDebug("Database Connection Established to $DATASOURCE{DSN} using handle $DSNLink"); +}else{ + writeDebug("Attempt to Connect to $DATASOURCE{DSN} Failed: " . &GetLastSQLError()); + writeDebug("Make sure $db_name database or ODBC DSN exists and check prg.conf [database] section!"); + abend("Could not establish database connection!"); +} + + + + +#------------------------------------------------------------------- +# Create Tables +#------------------------------------------------------------------- + +if (!$inp_isupgrade) { + + $sql_scriptname = "tvlistings"; + $sql_type = ""; + + if ($db_driver eq "ODBC") { + $sql_type = "mssql"; + } + + if ($db_driver eq "mysql") { + $sql_type = "mysql"; + } + + if ($db_driver eq "SQLite") { + $sql_type = "sqlite"; + } + + if ($sql_type eq "") { + writeDebug("Error! $db_driver has not been tested with $program_title. You will need to configure your database manually."); + abend("Unsupported Driver"); + } + + $sql_scriptname .= "_$sql_type"; + $sql_scriptname .= ".sql"; + + + writeDebug("Creating Tables ($sql_scriptname)"); + + $retcode = runSQLScript($sql_scriptname); + + if ($retcode) { + writeDebug("Tables created successfully"); + }else{ + my $lastsqlerror = &GetLastSQLError(); + my $lastsqlstmt = &GetLastSQLStmt(); + writeDebug("Attempt to execute $sql_scriptname failed: $lastsqlerror ($lastsqlstmt)"); + abend("Aborted"); + } +} + +#------------------------------------------------------------------- +# Update Tables +#------------------------------------------------------------------- + +if ($inp_isupgrade) { + $sql_scriptname = "update"; + $sql_type = ""; + + if ($db_driver eq "ODBC") { + $sql_type = "mssql"; + } + + if ($db_driver eq "mysql") { + $sql_type = "mysql"; + } + + if ($db_driver eq "SQLite") { + $sql_type = "sqlite"; + writeDebug("Warning! SQLite does not support ALTER TABLE. Will DROP TABLE first."); + } + + if ($sql_type eq "") { + writeDebug("Error! $db_driver has not been tested with $program_title. You will need to configure your database manually."); + abend("Unsupported Driver"); + } + + $sql_scriptname .= "_$sql_type"; + $sql_scriptname .= ".sql"; + + writeDebug("Updating Tables ($sql_scriptname)"); + + $retcode = runSQLScript($sql_scriptname); + + writeDebug("runSQLScript returned $retcode"); + + if ($retcode) { + writeDebug("Tables updated successfully"); + }else{ + my $lastsqlerror = &GetLastSQLError(); + my $lastsqlstmt = &GetLastSQLStmt(); + writeDebug("Attempt to execute $sql_scriptname failed: $lastsqlerror ($lastsqlstmt)"); + abend("Aborted"); + } +} + +#------------------------------------------------------------------- +# Finish Up +#------------------------------------------------------------------- + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Terminating Database Connection from $DATASOURCE{DSN} ($DSNLink)"); +endDSN("",$DSNLink); +writeDebug("Job finished at $now ($runtime seconds)"); + +writeDebug("********************************************************"); + +exit(1); diff --git a/tvlistings b/tvlistings new file mode 100644 index 0000000..2e0259a Binary files /dev/null and b/tvlistings differ diff --git a/tvlistings_mssql.sql b/tvlistings_mssql.sql new file mode 100644 index 0000000..c1c49fc --- /dev/null +++ b/tvlistings_mssql.sql @@ -0,0 +1,86 @@ +use tvlistings; + +CREATE TABLE [dbo].[schedule] ( + [scheduleid] uniqueidentifier PRIMARY KEY ROWGUIDCOL DEFAULT (newid()) NOT NULL , + [programid] uniqueidentifier NOT NULL, + [replayid] [int] NOT NULL , + [firstrun] [bit] NOT NULL , + [guaranteed] [bit] NOT NULL , + [theme] [bit] NOT NULL , + [recurring] [bit] NOT NULL , + [manual] [bit] NOT NULL , + [conflict] [bit] NOT NULL , + [created] [int] NOT NULL , + [padbefore] [int] NOT NULL , + [padafter] [int] NOT NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[castcrew] ( + [castcrewid] uniqueidentifier PRIMARY KEY ROWGUIDCOL DEFAULT (newid()) NOT NULL , + [tmsprogramid] [nvarchar] (12) NOT NULL , + [role] [int] NOT NULL , + [surname] [nvarchar] (64) NULL , + [givenname] [nvarchar] (64) NULL +) ON [PRIMARY] +GO + + +CREATE TABLE [dbo].[channels] ( + [channelid] uniqueidentifier PRIMARY KEY ROWGUIDCOL DEFAULT (newid()) NOT NULL , + [tmsid] [int] NULL , + [tuning] [int] NOT NULL , + [displaynumber] [int] NULL , + [channel] [nvarchar] (16) NULL , + [display] [nvarchar] (64) NULL , + [iconsrc] [nvarchar] (255) NULL , + [affiliate] [nvarchar] (32) NULL , + [headend] [nvarchar] (16) NULL , + [hidden] [bit] NULL , + [postalcode] [nvarchar] (16) NULL , + [systemtype] [nvarchar] (16) NULL , + [lineupname] [nvarchar] (32) NULL , + [lineupdevice] [nvarchar] (32) NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[replayunits] ( + [replayid] [int] IDENTITY (1, 1) PRIMARY KEY NOT NULL , + [replayname] [nvarchar] (16) NULL , + [replayaddress] [nvarchar] (65) NULL , + [replayport] [int] NULL , + [defaultquality] [int] NULL , + [defaultkeep] [int] NULL , + [lastsnapshot] [int] NULL , + [guideversion] [int] NULL , + [replayosversion] [int] NULL , + [categories] [nvarchar] (255) NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[tvlistings] ( + [programid] uniqueidentifier PRIMARY KEY ROWGUIDCOL DEFAULT (newid()) NOT NULL , + [tmsprogramid] [nvarchar] (12) NULL , + [tmsid] [int] NULL , + [starttime] [datetime] NULL , + [endtime] [datetime] NULL , + [tuning] [int] NULL , + [channel] [nvarchar] (16) NULL , + [title] [nvarchar] (255) NULL , + [subtitle] [nvarchar] (255) NULL , + [description] [ntext] NULL , + [category] [nvarchar] (255) NULL , + [captions] [nvarchar] (32) NULL , + [advisories] [nvarchar] (255) NULL , + [episodenum] [nvarchar] (16) NULL , + [vchiprating] [nvarchar] (16) NULL , + [mpaarating] [nvarchar] (16) NULL , + [starrating] [nvarchar] (16) NULL , + [movieyear] [nvarchar] (16) NULL , + [stereo] [bit] NULL , + [repeat] [bit] NULL , + [movie] [bit] NULL , + [subtitled] [bit] NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + diff --git a/tvlistings_mysql.sql b/tvlistings_mysql.sql new file mode 100644 index 0000000..290f004 --- /dev/null +++ b/tvlistings_mysql.sql @@ -0,0 +1,101 @@ +# MySQL +# Personal ReplayGuide +# Create Table Script +# +#-------------------------------------------------------- + +use tvlistings; + +CREATE TABLE schedule ( + scheduleid int(10) unsigned NOT NULL auto_increment, + programid int(10) unsigned NOT NULL, + replayid int(10) unsigned NOT NULL, + firstrun tinyint(1) NOT NULL, + guaranteed tinyint(1) NOT NULL, + theme tinyint(1) NOT NULL, + recurring tinyint(1) NOT NULL, + manual tinyint(1) NOT NULL, + conflict tinyint(1) NOT NULL, + created int(10) NOT NULL, + padbefore int(10) NOT NULL, + padafter int(10) NOT NULL, + PRIMARY KEY (scheduleid), + INDEX (programid, replayid), + INDEX (replayid) +); + +CREATE TABLE castcrew ( + castcrewid int(10) unsigned NOT NULL auto_increment, + tmsprogramid varchar(12) NOT NULL, + role int(10) unsigned NOT NULL, + surname varchar(64), + givenname varchar(64), + PRIMARY KEY (castcrewid), + INDEX (tmsprogramid, role), + INDEX (role) +); + +CREATE TABLE channels ( + channelid int(10) unsigned NOT NULL auto_increment, + tmsid int(10) unsigned, + tuning int(10) unsigned NOT NULL, + displaynumber int(10) unsigned, + channel varchar(16), + display varchar(64), + iconsrc varchar(255), + affiliate varchar(32), + headend varchar(16), + hidden tinyint(1) NOT NULL, + postalcode varchar(16), + systemtype varchar(16), + lineupname varchar(32), + lineupdevice varchar(32), + PRIMARY KEY (channelid), + INDEX (tuning, hidden), + INDEX (hidden) +); + +CREATE TABLE replayunits ( + replayid int(10) unsigned NOT NULL auto_increment, + replayname varchar(16), + replayaddress varchar(65), + replayport int(10) unsigned, + defaultquality int(10) unsigned, + defaultkeep int(10) unsigned, + lastsnapshot int(10) unsigned, + guideversion int(10) unsigned, + replayosversion int(10) unsigned, + categories varchar(255), + PRIMARY KEY (replayid) +); + +CREATE TABLE tvlistings ( + programid int(10) unsigned NOT NULL auto_increment, + tmsprogramid varchar(12), + tmsid int(10) unsigned, + starttime datetime NOT NULL, + endtime datetime NOT NULL, + tuning int(10) unsigned NOT NULL, + channel varchar(16), + title varchar(255), + subtitle varchar(255), + description text, + category varchar(255), + captions varchar(32), + advisories varchar(255), + episodenum varchar(16), + vchiprating varchar(16), + mpaarating varchar(16), + starrating varchar(16), + movieyear varchar(16), + stereo tinyint(1), + repeat tinyint(1), + movie tinyint(1), + subtitled tinyint(1), + PRIMARY KEY (programid), + KEY (starttime,tuning), + KEY (endtime,tuning), + KEY (starttime,endtime,tuning) +); + + diff --git a/tvlistings_sqlite.sql b/tvlistings_sqlite.sql new file mode 100644 index 0000000..4057ce4 --- /dev/null +++ b/tvlistings_sqlite.sql @@ -0,0 +1,86 @@ +CREATE TABLE schedule ( + scheduleid INTEGER PRIMARY KEY NOT NULL, + programid int(10) NOT NULL, + replayid int(10) NOT NULL, + firstrun tinyint(1) NOT NULL, + guaranteed tinyint(1) NOT NULL, + theme tinyint(1) NOT NULL, + recurring tinyint(1) NOT NULL, + manual tinyint(1) NOT NULL, + conflict tinyint(1) NOT NULL, + created int(10) NOT NULL, + padbefore int(10) NOT NULL, + padafter int(10) NOT NULL +); + +CREATE TABLE castcrew ( + castcrewid INTEGER PRIMARY KEY NOT NULL, + tmsprogramid varchar(12) NOT NULL, + role int(10) NOT NULL, + surname varchar(64), + givenname varchar(64) +); + +CREATE TABLE channels ( + channelid INTEGER PRIMARY KEY NOT NULL, + tmsid int(10), + tuning int(10) NOT NULL, + displaynumber int(10), + channel varchar(16), + display varchar(64), + iconsrc varchar(255), + affiliate varchar(32), + headend varchar(16), + hidden tinyint(1) NOT NULL, + postalcode varchar(16), + systemtype varchar(16), + lineupname varchar(32), + lineupdevice varchar(32) +); + +CREATE TABLE replayunits ( + replayid INTEGER PRIMARY KEY NOT NULL, + replayname varchar(16), + replayaddress varchar(65), + replayport int(10), + defaultquality int(10), + defaultkeep int(10), + lastsnapshot int(10), + guideversion int(10), + replayosversion int(10), + categories varchar(255) +); + +CREATE TABLE tvlistings ( + programid INTEGER PRIMARY KEY NOT NULL, + tmsprogramid varchar(12), + tmsid int(10), + starttime datetime NOT NULL, + endtime datetime NOT NULL, + tuning int(10) NOT NULL, + channel varchar(16), + title varchar(255), + subtitle varchar(255), + description text, + category varchar(255), + captions varchar(32), + advisories varchar(255), + episodenum varchar(16), + vchiprating varchar(16), + mpaarating varchar(16), + starrating varchar(16), + movieyear varchar(16), + stereo tinyint(1), + repeat tinyint(1), + movie tinyint(1), + subtitled tinyint(1) +); + +CREATE INDEX castcrew_index ON castcrew ( + tmsprogramid, + surname, + givenname +); + +PRAGMA default_synchronous = OFF; +PRAGMA default_cache_size = 4000; diff --git a/update_mssql.sql b/update_mssql.sql new file mode 100644 index 0000000..c74378a --- /dev/null +++ b/update_mssql.sql @@ -0,0 +1,9 @@ +use tvlistings; + +ALTER TABLE dbo.channels + ADD [displaynumber] [int] NULL , + [postalcode] [nvarchar] (16) NULL , + [systemtype] [nvarchar] (16) NULL , + [lineupname] [nvarchar] (32) NULL , + [lineupdevice] [nvarchar] (32) NULL +GO diff --git a/update_mysql.sql b/update_mysql.sql new file mode 100644 index 0000000..d6a2c8b --- /dev/null +++ b/update_mysql.sql @@ -0,0 +1,14 @@ +# MySQL +# Personal ReplayGuide +# Update Table Script +# +#-------------------------------------------------------- + +use tvlistings; + +ALTER TABLE channels + ADD displaynumber int(10) unsigned, + ADD postalcode varchar(16), + ADD systemtype varchar(16), + ADD lineupname varchar(32), + ADD lineupdevice varchar(32); diff --git a/update_sqlite.sql b/update_sqlite.sql new file mode 100644 index 0000000..fb342d7 --- /dev/null +++ b/update_sqlite.sql @@ -0,0 +1,18 @@ +DROP TABLE channels; + +CREATE TABLE channels ( + channelid INTEGER PRIMARY KEY NOT NULL, + tmsid int(10), + tuning int(10) NOT NULL, + displaynumber int(10), + channel varchar(16), + display varchar(64), + iconsrc varchar(255), + affiliate varchar(32), + headend varchar(16), + hidden tinyint(1) NOT NULL, + postalcode varchar(16), + systemtype varchar(16), + lineupname varchar(32), + lineupdevice varchar(32) +); diff --git a/updatetvdata.bat b/updatetvdata.bat new file mode 100644 index 0000000..749aaca --- /dev/null +++ b/updatetvdata.bat @@ -0,0 +1 @@ +perl updatetvdata.pl diff --git a/updatetvdata.pl b/updatetvdata.pl new file mode 100644 index 0000000..4a62f38 --- /dev/null +++ b/updatetvdata.pl @@ -0,0 +1,509 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide DataFeed Client +# by Lee Thompson <thompsonl@logh.net> +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2004 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + + +use POSIX qw( strftime getcwd ); +use English; +use Time::Local; + +my $_version = "Personal ReplayGuide|DataFeed Update Client|1|0|22|Lee Thompson"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; # Load common functions +require 'rg_config.pl'; # Load config functions + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Debug Options +#----------------------------------------------------------------------------------- + +$abort = 0; +$debug = 0; +$verbose = 1; # Talky + +#----------------------------------------------------------------------------------- +# Set Required Defaults +#----------------------------------------------------------------------------------- + +$datafeed_client = ""; +$datafeed_converter = ""; +$datafeed_parameters = ""; +$datafeed_redirectoutput = 0; +$datafeed_success = 1; +$datafeed_geticons = 0; +$datafeed_geticonscript = "./getchannelicons.pl"; + +$configfile = "updatetvdata.conf"; # This is optional +$configstatus = getConfig($configfile); # Read Configuration +$configstatus = getConfig($datafeed); # Load data feed settings + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$null = ""; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +my $current_path = getcwd; + +(my $xmlfile_path, my $xmlfile_filename) = getPathAndFile($cnf_xmlfile); + + +if ($xmlfile_path eq ".") { + $xmlfile_path = $current_path; +} + + + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + $remotemode = 1; +} + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +if ($debug) { + &writeOutput("Debug Messages are ON"); +} + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + +#------------------------------------------------------------------- + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + +#------------------------------------------------------------------- +# Final Checks +#------------------------------------------------------------------- + +if ($datafeed eq $null ) { + abend("No datafeed specified. Check prg.conf or INSTALL.txt"); +} + +if ($datafeed_client eq $null ) { + abend("No datafeed client specified for $datafeed"); +} + +if ($datafeed_converter eq $null ) { + abend("No datafeed converter specified for $datafeed"); +} + + +writeDebug("Job started at $now"); + + +#------------------------------------------------------------------- +# Calculate Estimates for TV Data Download Time +# +# These are based on a typical digital cable lineup of 170 channels. +# +#------------------------------------------------------------------- + +$timeestimate = 0; + +if ($datafeed eq "xmltv") { + (my $junk, $days) = split(/--days/,$datafeed_parameters,2); + $days = int $days; + + if ($days < 1) { + $days = 7; + writeDebug("Could not find the number of days specified for XMLTV, assuming $days."); + } + + $timeestimate = $timeestimate + ($days * 11.50); +} + +if ($datafeed eq "datadirect") { + getConfig("datadirect",1,"days"); + + $timeestimate = $timeestimate + ($days * 0.50); + +} + +(my $datafeed_path, my $datafeed_filename) = getPathAndFile($datafeed_client); + +#----------------------------------------------------------------------------------- +# Download New Listing Data +#----------------------------------------------------------------------------------- + +$prefix = ""; +if ($datafeed_filename =~ /\.pl/) { + $prefix = $^X; + if ($prefix =~ /\.dll/i) { + $prefix = ""; + } +} + +$client_cmd = "$prefix $datafeed_filename"; + +if (length($datafeed_parameters) > 0) { + $client_cmd .= " $datafeed_parameters"; +} + +if ($datafeed_redirectoutput) { + $client_cmd .= " > $xmlfile_path/$xmlfile_filename"; +} + +if ($client_cmd eq "") { + abend("No client specified. ($datafeed_client; $datafeed_path, $datafeed_filename)"); +} + +writeDebug("Calling Datafeed Client for $datafeed."); +writeDebug("Client: $client_cmd"); +writeDebug("Depending on the speed of the machine and internet connection this may take approximately $timeestimate minutes."); + + +my $dir_changed = 0; + +if ($datafeed_path ne ".") { + if ($datafeed_path ne "") { + chdir $datafeed_path; + $dir_changed = 1; + } +} + +$client_start = time; +my $result = system("$client_cmd"); +$client_finish = time; +$client_seconds = $client_finish - $client_start; +$client_minutes = int ($client_seconds / 60); + +if ($dir_changed) { + chdir $current_path; + undef $dir_changed; +} + +if ($result == -1) { + writeDebug("Could not execute $datafeed_filename. Check file permissions."); + $retval = 1; +}else{ + #----------------------------------- + # Get the exit value from client + #----------------------------------- + + $retval = $? >> 8; + + if ($retval == $datafeed_success ) { + writeDebug("Client for $datafeed was successful. ($retval)"); + writeDebug("Client for $datafeed took $client_minutes minutes to download TV data."); + }else{ + writeDebug("Client for $datafeed failed. ($retval) "); + $abort = 1; + } +} + +if ($datafeed_converter eq $null ) { + writeDebug("No datafeed converter specified for $datafeed"); + $abort = 1; +} + + +#----------------------------------------------------------------------------------- +# Run Converter +#----------------------------------------------------------------------------------- + +if (!$abort) { + + (my $datafeed_path, my $datafeed_filename) = getPathAndFile($datafeed_converter); + + my $dir_changed = 0; + + $prefix = ""; + if ($datafeed_filename =~ /\.pl/) { + $prefix = $^X; + if ($prefix =~ /\.dll/i) { + $prefix = ""; + } + } + + $converter_cmd = "$prefix $datafeed_filename"; + + if ($converter_cmd eq "") { + writeDebug("Warning: No converter specified. ($datafeed_converter; $datafeed_path, $datafeed_filename)"); + } + + writeDebug("Calling Datafeed Converter for $datafeed."); + writeDebug("Converter: $converter_cmd"); + + if ($datafeed_path ne ".") { + if ($datafeed_path ne "") { + chdir $datafeed_path; + $dir_changed = 1; + } + } + + $convert_start = time; + my $result = system("$converter_cmd"); + $convert_finish = time; + $convert_seconds = $convert_finish - $convert_start; + $convert_minutes = int ($convert_seconds / 60); + + if ($dir_changed) { + chdir $current_path; + undef $dir_changed; + } + + if ($result == -1) { + writeDebug("Could not execute $datafeed_filename. Check file permissions."); + $retval = 1; + }else{ + #----------------------------------- + # Get the exit value from converter + #----------------------------------- + + $retval = $? >> 8; + + if ($retval == 255) { + writeDebug("Converter for $datafeed failed. ($retval)"); + $abort = 1; + }elsif ($retval) { + writeDebug("Converter for $datafeed was successful. ($retval)"); + writeDebug("Converter for $datafeed took $convert_minutes minutes to process TV data."); + }else{ + writeDebug("Converter for $datafeed failed. ($retval)"); + $abort = 1; + } + } +} + +#----------------------------------------------------------------------------------- +# Run Get Icons if requested +#----------------------------------------------------------------------------------- + +if ((!$abort) && (length($datafeed_geticonscript) > 0)) { + + (my $datafeed_path, my $datafeed_filename) = getPathAndFile($datafeed_geticonscript); + + $prefix = ""; + if ($datafeed_filename =~ /\.pl/) { + $prefix = $^X; + if ($prefix =~ /\.dll/i) { + $prefix = ""; + } + } + + $icon_cmd = "$prefix $datafeed_filename"; + + if ($icon_cmd eq "") { + writeDebug("Warning: No icon script specified. ($datafeed_geticonscript; $datafeed_path, $datafeed_filename)"); + } + + writeDebug("Calling Icon Download Script for $datafeed."); + writeDebug("Icons: $icon_cmd"); + + my $dir_changed = 0; + + if ($datafeed_path ne ".") { + if ($datafeed_path ne "") { + chdir $datafeed_path; + $dir_changed = 1; + } + } + + $icon_start = time; + my $result = system("$icon_cmd"); + $icon_finish = time; + $icon_seconds = $icon_finish - $icon_start; + $icon_minutes = int ($icon_seconds / 60); + + if ($dir_changed) { + chdir $current_path; + undef $dir_changed; + } + + if ($result == -1) { + writeDebug("Could not execute $datafeed_filename. Check file permissions."); + $retval = 1; + }else{ + # Get the exit value from client + + $retval = $? >> 8; + + if ($retval == 255) { + writeDebug("Icon download for $datafeed failed. ($retval)"); + $abort = 1; + }elsif ($retval) { + writeDebug("Icon download for $datafeed was successful. ($retval)"); + writeDebug("Icon download for $datafeed took $icon_minutes minutes to locate icons."); + }else{ + writeDebug("Icon download for $datafeed failed. ($retval) "); + $abort = 1; + } + } +} + + +#----------------------------------------------------------------------------------- +# Finish Up +#----------------------------------------------------------------------------------- + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Job finished at $now ($runtime seconds)"); + +my $retcode = 0; + +if (!$abort) { + writeDebug("DataFeed Update Successful"); + $retcode = 1; +}else{ + writeDebug("DataFeed Update Failed"); + $retcode = 0; +} + + +&ShowHTTPFooter; + +writeDebug("********************************************************"); + +exit($retcode); + + diff --git a/xmltv2sql.pl b/xmltv2sql.pl new file mode 100644 index 0000000..0cab0dd --- /dev/null +++ b/xmltv2sql.pl @@ -0,0 +1,1094 @@ +#!/usr/bin/perl +# +# Personal ReplayGuide SQL Converter +# by Lee Thompson <thompsonl@logh.net> +# with bits by Kanji T. Bates +# $Id: xmltv2sql.pl,v 1.9 2003/08/10 19:12:44 pvanbaren Exp $ +# +# Requirements: +# XMLTV (using tv_grab_na) +# +# +#------------------------------------------------------------------------------------ +# This file is part of Personal ReplayGuide (C) 2003 by Lee Thompson +# +# Personal ReplayGuide 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. +# +# Personal ReplayGuide 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 Personal ReplayGuide; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#----------------------------------------------------------------------------------- + +use POSIX qw( strftime getcwd ); +use English; +use Time::Local; +require LWP::Simple; +require LWP::UserAgent; +require HTTP::Request; +require HTTP::Headers; + +my $_version = "Personal ReplayGuide|XMLTV XML to SQL Converter|1|2|84|Lee Thompson,Philip Van Baren,Kanji T. Bates"; + +#------------------------------------------------------------------------------------ +# Determine Current Directroy +#------------------------------------------------------------------------------------ + +$current_dir = getcwd; +$current_dir .= "/"; + +#------------------------------------------------------------------------------------ +# Get script pathname, unfortunately on Apache on Win32 $0 is not reliable since +# for some reason it gets changed to an 8.3 pathname. +# +# IIS and Apache both provide long filename pathnames in environment variables so +# if it's an 8.3 we look there. If we don't find it, we just tough it out. +#------------------------------------------------------------------------------------ + +$script_pathname = $0; + +if ($0 =~ /\~/) { + if (length($ENV{SCRIPT_FILENAME}) > 0 ) { + $script_pathname = $ENV{SCRIPT_FILENAME}; + } + + if (length($ENV{PATH_TRANSLATED}) > 0 ) { + $script_pathname = $ENV{PATH_TRANSLATED}; + } +} + +#------------------------------------------------------------------------------------ +# Get the path that the script is in +#------------------------------------------------------------------------------------ + +(my $path,my $basename) = $script_pathname =~ m|^(.*[/\\])([^/\\]+?)$|; + +#------------------------------------------------------------------------------------ +# PRG_HOME is an override environment variable +#------------------------------------------------------------------------------------ + +if (length($ENV{PRG_HOME}) > 0) { + $path = $ENV{PRG_HOME}; +} + +#------------------------------------------------------------------------------------ +# Normalize the path +#------------------------------------------------------------------------------------ + +$path =~ s/\\/\//g; + +#------------------------------------------------------------------------------------ +# If the current working directory is not where we need to be, change paths. +#------------------------------------------------------------------------------------ + +$changed_path = -1; + +if (($current_dir ne $path) && ($path ne "")) { + if (chdir $path) { + $changed_path = 1; + }else{ + $changed_path = 0; + } +} + +#------------------------------------------------------------------------------------ +# Load Libraries +#------------------------------------------------------------------------------------ + +require 'rg_common.pl'; # Load common functions +require 'rg_database.pl'; # Load database functions +require 'rg_info.pl'; # Load database info +require 'rg_config.pl'; # Load config functions + +#------------------------------------------------------------------------------------ +# Set up module identification +#------------------------------------------------------------------------------------ + +my $module_name = ""; +(my $debug_package, my $debug_filename, my $debug_line, my $debug_subroutine, my $debug_hasargs, my $debug_wantarray, my $debug_evaltext, my $debug_isrequire) = caller(0); +if (length($debug_evaltext) > 0) { + $module_name = $debug_evaltext; +}else{ + if ($path eq "") { + $basename = $script_pathname; + } + $module_name = $basename; +} +$prg_module{$module_name} = $_version; + +#----------------------------------------------------------------------------------- +# Debug Options +#----------------------------------------------------------------------------------- +$do_not_drop_rows = 0; # Do not DELETE rows first +$do_not_insert = 0; # Skip the DB insert + +#----------------------------------------------------------------------------------- +# Set Required Defaults +#----------------------------------------------------------------------------------- + +$scheduler = "rg_scheduler.pl"; + +# OS-Sensitive defaults + +if ($^O eq 'MSWin32') { + $schedule2sql = "schedule2sql.pl"; +} else { + $schedule2sql = "./schedule2sql.pl"; +} + + +#----------------------------------------------------------------------------------- +# Define Options +#----------------------------------------------------------------------------------- + +$retcode = 0; +$debug = 0; # Debug Messages +$multiplier = 1000; # Default Multiplier +$dotinterval = 500; # Interval for the "." +$maxrows = 0; # Maximum Number of rows to INSERT +$cnf_xmlfile = "./na.xml"; # XMLTV file +$cnf_channelmap = ""; +$cnf_titlemap = ""; +$verbose = 1; # Chatty +$systemtype = ""; +$lineupname = ""; +$postalcode = ""; +$lineupdevice = ""; + +$configfile = "xmltv2sql.conf"; # This is optional +$configstatus = getConfig($configfile); # Read Configuration + +#----------------------------------------------------------------------------------- +# Set Constants +#----------------------------------------------------------------------------------- + +$null = ""; + +(my $parent,my $desc,my $major,my $minor,my $build,my $authors) = parseModuleData($prg_module{$module_name}); + +$program_title = $parent; +$program_module = $desc; +$program_author = buildMultiWordList($authors); +$program_version = "$major.$minor"; +$program_build = $build; + +$rows = 0; +$dotctr = 0; +$emptystop = 0; +$lineup = 0; # Lineup Number + +#---------------------------------------------------------------------------------- +# Check to see if this is being run from the console +#---------------------------------------------------------------------------------- + +$RemoteAddress = $ENV{'REMOTE_ADDR'}; + +if ($RemoteAddress eq $null) { + $RemoteAddress = "127.0.0.1"; + $remotemode = 0; +}else{ + $remotemode = 1; +} + + +#----------------------------------------------------------------------------------- +# Display Header +#----------------------------------------------------------------------------------- + +writeDebug("********************************************************"); +writeDebug("$program_title\:$program_module v$program_version (Build $program_build)"); +writeDebug("Running as $script_pathname with PID $$"); +writeDebug("Remote Address: $RemoteAddress"); +if ($verbose) { + writeDebug("Console Output: Enabled"); +}else{ + writeDebug("Console Output: Disabled"); +} + +identifyLoadedModules(); + +if ($debug) { + &writeOutput("Debug Messages are ON"); +} + +#------------------------------------------------------------------- +# Check to see if the IP Address in $RemoteAddress has access to RTV +#------------------------------------------------------------------- + +if (hasAccess($RemoteAddress)) { + $remoteaccess = 0; +}else{ + $remoteaccess = 0; +} + +if (($remotemode) && (!$remoteaccess)) { + &InitializeDisplay; + abend("$program_module runs in console mode only"); +}else{ + if ($remotemode) { + &InitializeDisplay; + } +} + +#------------------------------------------------------------------- + +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); +$started = time; + +writeDebug("Job started at $now"); + + +#------------------------------------------------------------------- +# Set up Database +#------------------------------------------------------------------- + +&InitDB; +&InitDSN; + +#------------------------------------------------------------------- +# Start Database +#------------------------------------------------------------------- + +$prgdb_handle = &StartDSN; + +if ($prgdb_handle ne $null) { + writeDebug("Database Connection Established! $DATASOURCE{DSN} ($prgdb_handle)"); +}else{ + writeDebug("Attempt to Connect Failed: " . &GetLastSQLError()); + abend("Could not establish database connection!"); +} + + +#------------------------------------------------------------------- +# Build Arrays +#------------------------------------------------------------------- + +if (length($cnf_channelmap) > 0) { + writeDebug("Loading channelmap from $cnf_channelmap"); + + @channelmap = loadFile($cnf_channelmap); + $cmap_ctr = countElements(@channelmap); + + if ($cmap_ctr > 0) { + writeDebug("Found $cmap_ctr channel mappings."); + $do_channelmap = 1; + }else{ + writeDebug("No channel mappings found."); + + } +} + +if (length($cnf_titlemap) > 0) { + writeDebug("Loading titlemap from $cnf_titlemap"); + + @titlemap = loadFile($cnf_titlemap); + $tmap_ctr = countElements(@titlemap); + + if ($tmap_ctr > 0) { + writeDebug("Found $tmap_ctr title mappings."); + $do_titlemap = 1; + }else{ + writeDebug("No title mappings found."); + + } +} + +writeDebug("Depending on the speed of the machine and the number of days worth of listings this may take approximately 20 minutes."); + + +#------------------------------------------------------------------- +# Clean TVListings +#------------------------------------------------------------------- + +if ($do_not_drop_rows) { + writeDebug("Skipping Row Delete"); +}else{ + + writeDebug("Deleting Rows..."); + + if ($db_driver eq "ODBC") { + #---------------------------------------------------- + # MSSQL logs all transactions so DELETE will store a + # complete copy of the table. TRUNCATE gets around + # this buy just logging the event not the records. + #---------------------------------------------------- + + $Stmt = "TRUNCATE TABLE $db_table_tvlistings;"; + }else{ + $Stmt = "DELETE FROM $db_table_tvlistings;"; + } + if (sqlStmt($prgdb_handle,$Stmt)) { + writeDebug("Table $db_table_tvlistings purged"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + + } + + if ($db_driver eq "ODBC") { + $Stmt = "TRUNCATE TABLE $db_table_channels;"; + }else{ + $Stmt = "DELETE FROM $db_table_channels;"; + } + if (sqlStmt($prgdb_handle,$Stmt)) { + writeDebug("Table $db_table_channels purged"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + } + + if ($db_driver eq "ODBC") { + $Stmt = "TRUNCATE TABLE $db_table_castcrew;"; + }else{ + $Stmt = "DELETE FROM $db_table_castcrew;"; + } + if (sqlStmt($prgdb_handle,$Stmt)) { + writeDebug("Table $db_table_castcrew purged"); + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + } + + writeDebug("Deleting Rows... Completed"); + +} + +#------------------------------------------------------------------- +# If INSERT is disabled, log data to a CSV +#------------------------------------------------------------------- + +if ($do_not_insert) { + open(CSVFILE, ">$db_table_tvlistings.csv"); + + $FieldNames = ""; + $FieldNames .= "tmsprogramid, tmsid, "; + $FieldNames .= "starttime, endtime, tuning, "; + $FieldNames .= "channel, title, subtitle, "; + $FieldNames .= "description, category, audio, "; + $FieldNames .= "captions, episodenum, vchiprating, "; + $FieldNames .= "mpaarating, starrating, movieyear, "; + $FieldNames .= "repeat, movie, subtitled, "; + $FieldNames .= "advisories"; + + print CSVFILE $FieldNames; + print CSVFILE "\n"; + + + open(CSVFILE2, ">$db_table_channels.csv"); + + $FieldNames = ""; + $FieldNames .= "tmsid, affiliate, "; + $FieldNames .= "tuning, displaynumber, channel, "; + $FieldNames .= "display, iconsrc, hidden, "; + $FieldNames .= "postalcode, systemtype, lineupname, "; + $FieldNames .= "lineupdevice"; + + print CSVFILE2 $FieldNames; + print CSVFILE2 "\n"; + + +} + + +$iteration = 0; + + +for ( split /,/, $cnf_xmlfile ) { + /,/; + $xml_file = $_; + + #------------------------------------------------------------------- + # Open File + #------------------------------------------------------------------- + + if (open(LISTINGS, "<$xml_file")) { + writeDebug("$iteration: Reading XMLTV Feed ($xml_file)"); + + }else{ + abend("Could not open $xml_file"); + } + + #------------------------------------------------------------------- + # Convert XML to SQL + #------------------------------------------------------------------- + + writeDebug("$iteration: $xml_file Parsing Data...",1); + + while(<LISTINGS>) { + + #----------------------------------------------------------- + # Parse XML + #----------------------------------------------------------- + + $line = $_; + chomp($line); + $original_line = $line; + + #----------------------------------------------------------- + # CHANNELS + #----------------------------------------------------------- + + if ( /<channel\s/ ) { + $stationid = $line; + $stationid =~ s/.*id="([^"]*).*/$1/; + $channel_display = ""; + $channel_iconsrc = ""; + $channel_hidden = 0; + $channel_affiliate = ""; + $channel_tmsid = 0; + $channel_type = ""; + $channel_tuning = 0; + $channel_text = ""; + $tmp_channel_display = ""; + } + if ( /<channel-id system=\"TMSID\" id=\"(\d+)"/ ) { + $channel_tmsid = $1; + } + + if ( /<display-name/ ) { + $tmp_channel_display = $line; + $tmp_channel_display =~ s/.*<display-name>([^<]*)\W.*/$1/; + if ($tmp_channel_display =~ /(\d+) (\S+)/) { + $channel_display = $tmp_channel_display; + $channel_tuning = $1; + $channel_text = $2; + } + } + + if ( /<icon/ ) { + $channel_iconsrc = $line; + $channel_iconsrc =~ s/.*src="([^"]*)\W.*/$1/; + } + + if ( /<\/channel/ ) { + + if ($do_channelmap) { + ($channel_tuning,$channel_text) = &mapChannel($channel_tuning,$channel_text); + } + + $channel_displayname = $channel_tuning; + $channel_tuning = $channel_tuning + ($iteration * $multiplier); + + $channel_affiliate = filterfield($channel_affiliate); + $channel_text = filterfield($channel_text); + $channel_display = filterfield($channel_display); + $channel_iconsrc = filterfield($channel_iconsrc); + + $Stmt = ""; + + + $FieldNames = ""; + $FieldNames .= "tmsid, affiliate, "; + $FieldNames .= "tuning, displaynumber, channel, "; + $FieldNames .= "display, iconsrc, hidden, "; + $FieldNames .= "postalcode, systemtype, lineupname, "; + $FieldNames .= "lineupdevice"; + + $FieldValues = ""; + $FieldValues .= "$channel_tmsid, '$channel_affiliate',"; + $FieldValues .= "$channel_tuning, $channel_displayname, '$channel_text', "; + $FieldValues .= "'$channel_display', '$channel_iconsrc', $channel_hidden, "; + $FieldValues .= "'$postalcode', '$systemtype', '$lineupname', "; + $FieldValues .= "'$lineupdevice'"; + + if ($do_not_insert) { + print CSVFILE2 $FieldValues; + print CSVFILE2 "\n"; + }else{ + $Stmt = "INSERT INTO $db_table_channels ($FieldNames) VALUES ($FieldValues);"; + + if (sqlStmt($prgdb_handle,$Stmt)) { + # Added + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + + } + } + + + + $stationarray{$stationid} = "$stationid\|$channel_text\|$channel_display\|$channel_affiliate\|$channel_tuning"; + + } + + + #----------------------------------------------------------- + # PROGRAMS + #----------------------------------------------------------- + + if ( /<programme/ ) { + $program_start = $line; + $program_start =~ s/.*start="(\d*)[^"]*.*/$1/; + $program_stop = $line; + $program_stop =~ s/.*stop="(\d*)[^"]*.*/$1/; + $stationid = $line; + $stationid =~ s/.*channel="([^"]*).*/$1/; + + $program_title = ""; + $program_audio = 0; + $program_subtitle = ""; + $program_category = ""; + $program_desc = ""; + + $program_captions = ""; + $program_episodenum = ""; + $program_vchiprating = ""; + $program_mpaarating = ""; + $program_starrating = ""; + $program_movieyear = ""; + $program_repeat = 0; + $program_ismovie = 0; + $program_issubtitled = 0; + $program_advisories = ""; + + $program_ratingsystem = ""; + } + + if ( /<subtitles/ ) { + $program_captions = $line; + $program_captions =~ s/.*type="([^"]*).*/$1/; + + } + + if ( /<episode-num/ ) { + $program_episodenum = $line; + if ($program_episodenum =~ "onscreen") { + $program_episodenum =~ s/.*onscreen">([^<]*)\W.*/$1/; + } + if ($program_episodenum =~ "xmltv_ns") { + $program_episodenum =~ s/.*xmltv_ns">([^<]*)\W.*/$1/; + (my $series, my $episode, my $parts) = split(/\./,$program_episodenum); + (my $part, my $total) = split(/\//,trimstring($parts)); + if ($part > 0) { + if ($total > 0) { + $program_episodenum = "Part $part of $total"; + }else{ + $program_episodenum = "Part $part"; + } + }else{ + $program_episodenum = ""; + } + } + if ($program_episodenum eq $line) { + $program_episodenum = ""; + } + } + + if ( /<rating/ ) { + $program_ratingsystem = $line; + $program_ratingsystem =~ s/.*system="([^"]*).*/$1/; + if ($program_ratingsystem eq $line) { + $program_ratingsystem = ""; + } + } + + if ( /<star-rating/ ) { + $program_ratingsystem = "STAR"; + } + + if ( /<value/ ) { + if ($program_ratingsystem eq "VCHIP") { + $program_vchiprating = $line; + $program_vchiprating =~ s/.*<value>([^<]*)\W.*/$1/; + if ($program_vchiprating eq $line) { + $program_vchiprating = ""; + } + + } + if ($program_ratingsystem eq "MPAA") { + $program_mpaarating = $line; + $program_mpaarating =~ s/.*<value>([^<]*)\W.*/$1/; + if ($program_mpaarating eq $line) { + $program_mpaarating = ""; + } + } + if ($program_ratingsystem eq "STAR") { + $program_starrating = $line; + $program_starrating =~ s/.*<value>([^<]*)\W.*/$1/; + if ($program_starrating eq $line) { + $program_starrating = ""; + } + } + } + + if ( /<date>/ ) { + $program_movieyear = $line; + $program_movieyear =~ s/.*<date>([^<]*)\W.*/$1/; + if ($program_movieyear eq $line) { + $program_movieyear = ""; + } + } + + if ( /<title>/ ) { + $program_title = $line; + $program_title =~ s/.*<title>([^<]*)\W.*/$1/; + if ($program_title eq $line) { + $program_title = ""; + } + } + + if ( /<desc>/ ) { + $program_desc = $line; + $program_desc =~ s/.*<desc>([^<]*)\W.*/$1/; + if ($program_desc eq $line) { + $program_desc = ""; + } + } + + if ( /<sub-title>/ ) { + $program_subtitle = $line; + $program_subtitle =~ s/.*<sub-title>([^<]*)\W.*/$1/; + if ($program_subtitle eq $line) { + $program_subtitle = ""; + } + } + + if ( /<category>/ ) { + if (length($program_category) > 0) { + $old_category = $program_category; + } + + $program_category = $line; + $program_category =~ s/.*<category>([^<]*)\W.*/$1/; + + if (length($old_category) > 0) { + $program_category = "$old_category/$program_category"; + $old_category = ""; + } + } + + if ( /<stereo>/ ) { + $program_audio = 1; + } + + if ( /<previously-shown/ ) { + $program_repeat = 1; + } + + if ( /<\/programme/ ) { + ($program_tmsid,$program_channel,$program_channelname,$program_affiliate,$program_tuning) = split(/\|/,$stationarray{$stationid}); + + if ($do_titlemap) { + $program_title = &mapTitle($program_title); + } + + if ($do_channelmap) { + ($program_tuning,$program_channel) = &mapChannel($program_tuning,$program_channel); + } + + $Stmt = ""; + + $dataok = 1; + + + ($Y,$M,$D,$h,$m,$s) = unpack 'A4 A2 A2 A2 A2 A2', $program_start; + $program_start = "$Y-$M-$D $h:$m:$s"; + $Y = int $Y; + + if ($Y < 1) { + $dataok = 0; + } + + #----------------------------------------------------------- + # XMLTV is braindead if a program runs past midnight it + # omits the endtime entirely unless you use their sorter. + #----------------------------------------------------------- + + ($Y,$M,$D,$h,$m,$s) = unpack 'A4 A2 A2 A2 A2 A2', $program_stop; + $program_stop = "$Y-$M-$D $h:$m:$s"; + + if ($Y < 1) { + + #----------------------------------------------------------- + # We'll mark it by making the start and stop times the same and + # Do another pass + #----------------------------------------------------------- + + if ($dataok) { + $program_stop = $program_start; + $emptystop++; + }else{ + $dataok = 0; + } + } + + + $program_title = filterfield($program_title); + $program_desc = filterfield($program_desc); + $program_subtitle = filterfield($program_subtitle); + $program_category = filterfield($program_category); + $program_audio = filterfield($program_audio); + $program_vchiprating = filterfield($program_vchiprating); + $program_episodenum = filterfield($program_episodenum); + + if (int $program_movieyear > 0) { + $program_ismovie = 1; + }else{ + $program_ismovie = 0; + } + + #----------------------------------------------------------- + # Not Available for XMLTV + #----------------------------------------------------------- + + $program_tmsid = 0; + $program_advisories = ""; + $program_tmsprgid = ""; + + $FieldNames = ""; + $FieldNames .= "tmsprogramid, tmsid, "; + $FieldNames .= "starttime, endtime, tuning, "; + $FieldNames .= "channel, title, subtitle, "; + $FieldNames .= "description, category, stereo, "; + $FieldNames .= "captions, episodenum, vchiprating, "; + $FieldNames .= "mpaarating, starrating, movieyear, "; + $FieldNames .= "repeat, movie, subtitled, "; + $FieldNames .= "advisories"; + + $FieldValues = ""; + $FieldValues .= "'$program_tmsprgid', $program_tmsid, "; + $FieldValues .= "'$program_start', '$program_stop', $program_tuning, "; + $FieldValues .= "'$program_channel', '$program_title', '$program_subtitle', "; + $FieldValues .= "'$program_desc', '$program_category', $program_audio, "; + $FieldValues .= "'$program_captions', '$program_episodenum', '$program_vchiprating', "; + $FieldValues .= "'$program_mpaarating', '$program_starrating', '$program_movieyear', "; + $FieldValues .= "$program_repeat, $program_ismovie, $program_issubtitled, "; + $FieldValues .= "'$program_advisories'"; + + if ($dataok) { + if ($do_not_insert) { + writeDebug("SQL Insert Disabled, Writing to CSV:"); + + print CSVFILE $FieldValues; + print CSVFILE "\n"; + + }else{ + $Stmt = "INSERT INTO $db_table_tvlistings ($FieldNames) VALUES ($FieldValues);"; + + if ($debug) { + writeDebug("$Stmt"); + } + + if (sqlStmt($prgdb_handle,$Stmt)) { + $rows++; + $dotctr++; + }else{ + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + + } + } + } + + if ($dotctr == $dotinterval) { + if ($verbose) { + displayText(".",0,1); + } + $dotctr = 0; + } + + if ($maxrows) { + if ($rows > $maxrows) { + close LISTINGS; + if ($do_not_insert) { + close CSVFILE; + } + abend("Done! Max Rows Reached ($maxrows)"); + } + } + + } + + } + close LISTINGS; + displayText(); + writeDebug("Initial processing XMLTV data completed."); + $iteration++; +} + + +if ($do_not_insert) { + close CSVFILE; + close CSVFILE2; + abend("Done! Do not insert set to $do_not_insert"); +}else{ + +} + +writeDebug("$rows rows were added"); + + +#----------------------------------------------------------- +# Do Another Pass if Needed +#----------------------------------------------------------- + +if ($emptystop) { + + writeDebug("Fixing $emptystop occurances of missing end points"); + + writeDebug("Locating Records",1); + $dotctr = 0; + + #----------------------------------------------------------- + # First we need to locate them + #----------------------------------------------------------- + + $Stmt = "SELECT * FROM $db_table_tvlistings WHERE starttime = endtime ORDER BY tuning, channel, starttime;"; + $ctr = 1; + + my $lookup_handle = &StartDSN(1); + $sth = sqlStmt($lookup_handle,$Stmt); + if ( $sth ) { + + while ( $row = $sth->fetchrow_hashref ) { + $programid = $row->{'programid'}; + $tuning = $row->{'tuning'}; + $channel = $row->{'channel'}; + $starttime = $row->{'starttime'}; + + $arrayprogramid[$ctr] = $programid; + $arraytuning[$ctr] = $tuning; + $arraychannel[$ctr] = $channel; + $arraystarttime[$ctr] = $starttime; + $arrayendtime[$ctr] = $starttime; + + $ctr++; + $dotctr++; + + if ($dotctr == $dotinterval) { + if ($verbose) { + displayText(".",0,1); + } + $dotctr = 0; + } + + } + }else{ + displayText(); + writeDebug("Error at $ctr / $emptystop - (Phase 1)"); + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + + } + endDSN($sth,$lookup_handle); + undef $lookup_handle; + + + $maxctr = $ctr; + $ctr = 1; + $dotctr = 0; + + displayText(); + writeDebug("Collecting Endpoints",1); + + #----------------------------------------------------------- + # Now we need the end times + #----------------------------------------------------------- + + my $query_handle = &StartDSN; + + do { + $programid = $arrayprogramid[$ctr]; + $tuning = $arraytuning[$ctr]; + $channel = $arraychannel[$ctr]; + $starttime = $arraystarttime[$ctr]; + $endtime = $arrayendtime[$ctr]; + $endsearch = timestringtosql(as_time_string(as_epoch_seconds(sqltotimestring($starttime)) + 86400)); + + $Stmt = ""; + $Stmt = "SELECT * FROM $db_table_tvlistings WHERE (((programid <> '$programid' AND starttime > '$starttime') AND tuning = $tuning) AND channel = '$channel') ORDER BY tuning, channel, starttime;"; + + if ($db_driver eq "mysql") { + $Stmt = "SELECT * FROM $db_table_tvlistings WHERE (((programid <> '$programid' AND starttime > '$starttime') AND tuning = $tuning) AND channel = '$channel') ORDER BY tuning, channel, starttime LIMIT 1;"; + + } + + if ($db_driver eq "SQLite") { + $Stmt = "SELECT * FROM $db_table_tvlistings WHERE (((programid <> '$programid' AND starttime > '$starttime') AND tuning = $tuning) AND channel = '$channel') ORDER BY tuning, channel, starttime LIMIT 1;"; + + } + + if ($db_driver eq "ODBC") { + $Stmt = "SELECT TOP 1 * FROM $db_table_tvlistings WHERE (((programid <> '$programid' AND starttime > '$starttime') AND tuning = $tuning) AND channel = '$channel') ORDER BY tuning, channel, starttime;"; + } + + $sth = sqlStmt($query_handle,$Stmt); + if ( ! $sth ) { + displayText(); + writeDebug("Error at $ctr / $maxctr - (Phase 2)"); + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + + } + + $row = $sth->fetchrow_hashref; # this should be the one after it + + $endtime = $row->{'starttime'}; + + $arrayendtime[$ctr] = $endtime; + + $ctr++; + $dotctr++; + + if ($dotctr == $dotinterval) { + if ($verbose) { + displayText(".",0,1); + } + $dotctr = 0; + } + + + } while ($ctr < $maxctr); + endDSN($sth,$query_handle); + undef $query_handle; + + $ctr = 1; + + $dotctr = 0; + + displayText(); + writeDebug("Updating Records",1); + + #----------------------------------------------------------- + # now we update the records + #----------------------------------------------------------- + + my $update_handle = &StartDSN; + + do { + $programid = $arrayprogramid[$ctr]; + $tuning = $arraytuning[$ctr]; + $starttime = $arraystarttime[$ctr]; + $endtime = $arrayendtime[$ctr]; + + $Stmt = "UPDATE $db_table_tvlistings SET endtime = '$endtime' WHERE programid = '$programid';"; + if (sqlStmt($update_handle,$Stmt)) { + # Corrected + }else{ + displayText(); + writeDebug("Error at $ctr / $maxctr - (Phase 3)"); + my $sql_error = &GetLastSQLError() . " (" . &GetLastSQLStmt() . ")"; + abend("Failed: $sql_error"); + + } + + $ctr++; + $dotctr++; + + if ($dotctr == $dotinterval) { + if ($verbose) { + displayText(".",0,1); + } + $dotctr = 0; + } + + + } while ($ctr < $maxctr); + endDSN("",$update_handle); + + $ctr--; + + displayText(); + writeDebug("$ctr records corrected"); +} + + +$finished = time; +$runtime = $finished - $started; +$now = strftime( "%Y-%m-%d", localtime ) . " " . strftime( "%H:%M:%S", localtime ); + +writeDebug("Terminating Database Connection from $DATASOURCE{DSN} ($prgdb_handle)"); +endDSN($sth,$prgdb_handle); + +writeDebug("Job finished at $now ($runtime seconds)"); + + +if ($rows) { + writeDebug("Dispatching rg_refresh"); + require 'rg_refresh.pl'; # Load RTV refresh functions + identifyLoadedModules('rg_refresh.pl'); # ID + &refreshRTV($verbose); # Refresh (0 is silent, + # 1 is verbose + # 2 is debug) + writeDebug("Returned from rg_refresh"); + $retcode = 1; +} + +&ShowHTTPFooter; + +writeDebug("********************************************************"); + +exit($retcode); + +#---------------------------------------------------------------------------- +sub mapChannel($$) { + # + # Remap Channel (Tuning,ChannelID) + # + # Returns (Tuning,ChannelID) + # + # ------------------------------------------------------------------------------ + + my $tuning = shift; + my $channelid = shift; + + if ($cmap_ctr < 1) { + return ($tuning,$channelid); + } + + my $before = ""; + my $after = ""; + my $ctr = 0; + + do { + $ctr++; + ($before,$after) = split('=', $channelmap[$ctr], 2); + + if ($before eq "$channelid,$tuning") { + ($channelid,$tuning) = split(',', $after, 2); + } + + } while ($ctr <= $cmap_ctr); + + return ($tuning,$channelid); +} + +#---------------------------------------------------------------------------- +sub mapTitle($) { + # + # Remap Title (Title) + # + # Returns (Title) + # + # ------------------------------------------------------------------------------ + + my $title = shift; + + if ($tmap_ctr < 1) { + return $title; + } + + my $before = ""; + my $after = ""; + my $ctr = 0; + + do { + $ctr++; + ($before,$after) = split('=', $titlemap[$ctr], 2); + + if ($before eq $title) { + $title = $after; + } + + } while ($ctr <= $tmap_ctr); + + return $title; +} diff --git a/xmltv_update.bat b/xmltv_update.bat new file mode 100644 index 0000000..fbbff79 --- /dev/null +++ b/xmltv_update.bat @@ -0,0 +1,2 @@ +xmltv tv_grab_na --days 12 > na.xml +perl xmltv2sql.pl