Imported Upstream version 0.5.62
authorChris Butler <chrisb@debian.org>
Mon, 11 Jun 2012 22:46:54 +0000 (23:46 +0100)
committerChris Butler <chrisb@debian.org>
Mon, 11 Jun 2012 22:46:54 +0000 (23:46 +0100)
81 files changed:
.cvsignore
ChangeLog
MANIFEST
Makefile.PL
README
doc/README.win32
filter/tv_imdb
filter/tv_to_text
grab/ch_search/tv_grab_ch_search.in
grab/dk_dr/test.conf
grab/es_laguiatv/test.conf
grab/es_laguiatv/tv_grab_es_laguiatv
grab/eu_egon/.cvsignore [new file with mode: 0644]
grab/eu_egon/test.conf [new file with mode: 0644]
grab/eu_egon/tv_grab_eu_egon.PL [new file with mode: 0644]
grab/eu_epgdata/tv_grab_eu_epgdata
grab/fi/fi/common.pm
grab/fi/fi/programme.pm
grab/fi/fi/source/mtv3.pm
grab/fi/fi/source/telkku.pm
grab/fi/fi/source/telvis.pm
grab/fi/fi/source/tvnyt.pm
grab/fi/fi/source/yle.pm
grab/fi/test.conf
grab/fi/test.sh
grab/fi/tv_grab_fi.pl
grab/fi_sv/tv_grab_fi_sv
grab/hr/test.conf
grab/huro/tv_grab_huro.in
grab/il/tv_grab_il
grab/it/channel_ids
grab/it/tv_grab_it.in
grab/na_dd/tv_grab_na_dd.in
grab/na_dtv/test.conf
grab/na_dtv/tv_grab_na_dtv
grab/pt/tv_grab_pt
grab/pt_meo/tv_grab_pt_meo
grab/se_swedb/test.conf
grab/se_tvzon/.cvsignore [new file with mode: 0644]
grab/se_tvzon/test.conf [new file with mode: 0644]
grab/se_tvzon/tv_grab_se_tvzon.PL [new file with mode: 0644]
grab/test_grabbers
grab/uk_rt/channel_icons [new file with mode: 0644]
grab/uk_rt/channel_ids
grab/uk_rt/channels_platforms
grab/uk_rt/lineups/freesat.map
grab/uk_rt/lineups/freesat.xml [new file with mode: 0644]
grab/uk_rt/lineups/freesatfromsky.xml [new file with mode: 0644]
grab/uk_rt/lineups/freesathd.xml [new file with mode: 0644]
grab/uk_rt/lineups/freeview.map
grab/uk_rt/lineups/freeview.xml [new file with mode: 0644]
grab/uk_rt/lineups/freeviewhd.xml [new file with mode: 0644]
grab/uk_rt/lineups/lineups.xml [new file with mode: 0644]
grab/uk_rt/lineups/saorview.map [new file with mode: 0644]
grab/uk_rt/lineups/saorview.xml [new file with mode: 0644]
grab/uk_rt/lineups/sky.xml [new file with mode: 0644]
grab/uk_rt/lineups/skyhd.xml [new file with mode: 0644]
grab/uk_rt/lineups/upcireland.xml [new file with mode: 0644]
grab/uk_rt/lineups/upcirelandhd.xml [new file with mode: 0644]
grab/uk_rt/lineups/virgin.xml [new file with mode: 0644]
grab/uk_rt/lineups/virginhd.xml [new file with mode: 0644]
grab/uk_rt/lineups/xmltv-lineups.xsl [new file with mode: 0644]
grab/uk_rt/prog_titles_to_process
grab/uk_rt/regional_channels_by_postcode
grab/uk_rt/test.conf
grab/uk_rt/tv_grab_uk_rt [new file with mode: 0755]
grab/uk_rt/tv_grab_uk_rt.PL [deleted file]
grab/uk_rt/tv_grab_uk_rt.in [deleted file]
grab/uk_rt/utf8_fixups
lib/Configure.pm
lib/IMDB.pm
lib/Lineup.pm.PL [deleted file]
lib/Lineup.pm.in [deleted file]
lib/Options.pm
lib/ValidateFile.pm
lib/XMLTV.pm.in
lib/exe_opt.pl
lib/exe_wrap.pl
xmltv-lineup.dtd [deleted file]
xmltv-lineups.xsd [new file with mode: 0644]
xmltv.dtd

index 64567d8..66e3884 100644 (file)
@@ -1,4 +1,9 @@
+.git
+.gitignore
+.hg
+.hgignore
 Makefile
+MYMETA.yml
 blib
 pm_to_blib
 t_*_cache
index a06d66e..5113904 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+2012-06-10 17:10  rmeden
+
+       * Makefile.PL, README, doc/README.win32, lib/XMLTV.pm.in,
+         lib/exe_wrap.pl: prepare for 0.5.62 release
+
+2012-06-10 11:43  knowledgejunkie
+
+       * lib/Options.pm: Perldoc updates for lineups
+
+2012-06-10 11:31  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Perldoc updates
+
+2012-06-10 10:35  knowledgejunkie
+
+       * xmltv.dtd: Add a lang attribute to review elements
+
+2012-06-10 09:57  knowledgejunkie
+
+       * xmltv-lineups.xsd: Make the preset element optional in a
+         lineup-entry
+
+2012-06-10 09:54  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: utf8_decode the prog_titles_to_process
+         supplement file before extracting fixups
+
+2012-06-10 09:00  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Update some comments to reflect changes
+         in utf-8 handling
+
+2012-06-10 08:43  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Instead of disabling the automated
+         UTF-8 fixups when fixups are disabled at config time, only
+         disable those manual fixups which are sourced from the
+         utf8-fixups supplemental file. Removing
+         non-printing/control/malformed characters will always be required
+         for optimal output
+
+2012-06-10 08:38  knowledgejunkie
+
+       * grab/uk_rt/test.conf: Updated test.conf
+
+2012-06-10 08:04  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Remove use Data::Dumper
+
+2012-06-10 08:02  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Remove unused debug sub
+
+2012-06-10 07:38  knowledgejunkie
+
+       * grab/uk_rt/lineups/: freesat.xml, freesatfromsky.xml,
+         freesathd.xml, freeview.xml, freeviewhd.xml, lineups.xml,
+         saorview.xml, sky.xml, skyhd.xml, upcireland.xml,
+         upcirelandhd.xml, virgin.xml, virginhd.xml: Updated lineups
+
+2012-06-10 07:26  knowledgejunkie
+
+       * grab/uk_rt/: channel_icons, channel_ids, lineups/freesat.map:
+         Channel updates
+
+2012-06-09 08:57  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-06-09 07:15  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-06-09 04:15  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Whitespace
+
+2012-06-09 04:07  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Tidy up some referencing
+
+2012-06-09 03:36  knowledgejunkie
+
+       * grab/uk_rt/: channels_platforms, regional_channels_by_postcode,
+         tv_grab_uk_rt: Mark old platform/regional channel supplemental
+         files as deprecated following release of XMLTV 0.5.62. These
+         files are likely to be removed in the future.
+
+2012-06-09 03:27  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt: Remove TODO item
+
+2012-06-09 03:12  knowledgejunkie
+
+       * Makefile.PL: Whitespace. Tabs left in heredocs output directly to
+         Makefile, replaced with spaces otherwise.
+
+2012-06-09 02:43  knowledgejunkie
+
+       * MANIFEST, Makefile.PL: Update Makefile.PL for renaming of
+         tv_grab_uk_rt
+
+2012-06-09 02:42  knowledgejunkie
+
+       * grab/uk_rt/: tv_grab_uk_rt, tv_grab_uk_rt.PL, tv_grab_uk_rt.in:
+         Rename tv_grab_uk_rt.in to tv_grab_uk_rt and remove .in/.PL
+         files. Revision history wil be split between these two filenames
+         as a side-effect.
+
+2012-06-08 13:16  yunosh
+
+       * grab/eu_epgdata/tv_grab_eu_epgdata: Add automatic timezone
+         detection (Andreas Benneke, Request #2799196).
+
+2012-06-08 13:16  yunosh
+
+       * grab/eu_epgdata/tv_grab_eu_epgdata: Improve error handling.
+
+2012-06-08 13:16  yunosh
+
+       * grab/eu_epgdata/tv_grab_eu_epgdata: Improved EPG data.
+
+         - No entities in data anymore - Use the longest available
+         description (d21) instead of the shortest (d23) - Set length -
+         Set country - Set subtitles - Set audio/stereo to "dolby digital"
+         instead of "dolby" - Map more categories to "tvshow" - Use all
+         available channel names, and prefer the official name - Fix
+         rating calculation
+
+2012-06-08 13:15  yunosh
+
+       * grab/eu_epgdata/tv_grab_eu_epgdata: Consistently use UTF-8 for
+         input and output.
+
+2012-06-08 13:15  yunosh
+
+       * grab/eu_epgdata/tv_grab_eu_epgdata: Clean up temporary files (Bug
+         #2927243).
+
+2012-06-08 08:42  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: TODO items
+
+2012-06-08 07:34  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Only exit with a failure status if
+         listings for any complete channels are missing. If channels are
+         all available but some programmes cannot be processed, exit with
+         success but inform user of the fact
+
+2012-06-08 05:04  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Whitespace
+
+2012-06-08 04:40  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Enable UTF-8 fixups by default
+
+2012-06-03 21:49  mnbjhguyt
+
+       * grab/it/channel_ids: more channels
+
+2012-06-03 21:25  mnbjhguyt
+
+       * grab/it/channel_ids: new id updated
+
+2012-05-28 21:51  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-05-27 17:04  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-05-14 02:51  knowledgejunkie
+
+       * grab/uk_rt/lineups/: sky.xml, skyhd.xml, virgin.xml,
+         virginhd.xml: Remove XMLTV ID for Movies 24 channels
+
+2012-05-14 02:36  knowledgejunkie
+
+       * grab/uk_rt/: channel_icons, channel_ids, channels_platforms:
+         Disable Movies 24 channels - no listings for weeks
+
+2012-05-14 02:22  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-05-11 05:12  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Disable Movies4Men 2 (and +1, ceased)
+
+2012-05-11 05:12  knowledgejunkie
+
+       * grab/uk_rt/channel_icons: Remove Wonderful
+
+2012-05-11 05:08  knowledgejunkie
+
+       * grab/uk_rt/lineups/freesat.map: Remove Movies4Men 2 (and +1,
+         ceased)
+
+2012-05-11 05:07  knowledgejunkie
+
+       * grab/uk_rt/lineups/: freesat.xml, freesatfromsky.xml,
+         freesathd.xml, sky.xml, skyhd.xml: Remove Movies4Men 2 (and +1,
+         ceased). Replace with Sony Movie Channel (and +1). Remove
+         Wonderful (ceased)
+
+2012-05-06 15:08  stefanb2
+
+       * grab/fi/fi/source/mtv3.pm: - mtv3: update for site changes
+
+2012-05-05 05:20  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-05-05 05:04  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-05-04 17:07  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: remove wildtv.ca from tests
+
+2012-05-01 16:18  betlit
+
+       * grab/ch_search/tv_grab_ch_search.in: fixed a bug causing the
+         grabber to stop after 1 day no matter how many days are given
+         with --days
+
+2012-05-01 05:25  knowledgejunkie
+
+       * grab/uk_rt/lineups/: freesat.xml, freesatfromsky.xml,
+         freesathd.xml, freeview.xml, freeviewhd.xml, saorview.xml,
+         sky.xml, skyhd.xml, upcireland.xml, upcirelandhd.xml, virgin.xml,
+         virginhd.xml: Logo updates
+
+2012-04-30 16:17  dekarl
+
+       * grab/uk_rt/lineups/xmltv-lineups.xsl: _uk_rt: fix typo in lineup
+         stylesheet
+
+2012-04-29 16:53  dekarl
+
+       * Makefile.PL: remove Lineup.pm from the build so the nightly
+         tester will run
+
+2012-04-29 09:18  knowledgejunkie
+
+       * MANIFEST: Remove old Lineup lib and add new lineups files for
+         uk_rt
+
+2012-04-29 09:10  knowledgejunkie
+
+       * lib/: Lineup.pm.PL, Lineup.pm.in: Delete old Lineup lib
+
+2012-04-29 09:04  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Another large update to the grabber
+         - adding support for using XML lineups (per the xmltv-lineups
+         XSD) for channel configuration, selection and listings retrieval.
+         Testing is well underway, but early feedback is more than welcome
+         to catch the likely errors before a future release. More details
+         of these updates should appear on xmltv-users in the next few
+         days
+
+2012-04-29 08:54  knowledgejunkie
+
+       * grab/uk_rt/lineups/lineups.xml: Updates
+
+2012-04-29 08:39  knowledgejunkie
+
+       * Makefile.PL: Add lineups to list of supplemental files for uk_rt
+
+2012-04-29 08:30  knowledgejunkie
+
+       * grab/uk_rt/lineups/: freesat.xml, freesatfromsky.xml,
+         freesathd.xml, freeview.xml, freeviewhd.xml, saorview.xml,
+         skyhd.xml, sky.xml, upcireland.xml, upcirelandhd.xml, virgin.xml,
+         virginhd.xml: Add lineups for: Freeview, Freesat, Freesat from
+         Sky, Saorview, Sky, UPC Ireland, and Virgin, using separate
+         lineups for SD and HD services.
+
+2012-04-29 07:56  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Icon updates for ITV1, ITV1 +1 and
+         Channel 7
+
+2012-04-29 06:54  knowledgejunkie
+
+       * grab/uk_rt/channel_icons: Add a mapping file providing channel
+         logo URLs for lineup channels not supported in the grabber
+
+2012-04-27 06:07  knowledgejunkie
+
+       * grab/uk_rt/lineups/freesat.map: New service IDs for Movies4Men
+         channels
+
+2012-04-24 19:00  betlit
+
+       * grab/ch_search/tv_grab_ch_search.in: ouput now claims to be utf-8
+         instead of ISO-8859-1. replaced Date::Manip with DateTime to fix
+         DST issue
+
+2012-04-22 06:56  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-04-22 05:42  knowledgejunkie
+
+       * grab/uk_rt/lineups/: freesat.map, freeview.map: More updates to
+         DVB maps
+
+2012-04-21 06:30  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Add support for More4 +2
+
+2012-04-21 06:08  knowledgejunkie
+
+       * grab/uk_rt/lineups/xmltv-lineups.xsl: Add a basic XSLT to render
+         lineups as a simple table (including EPG preset, icon, name and
+         whether channel is supported by XMLTV)
+
+2012-04-21 06:03  knowledgejunkie
+
+       * grab/uk_rt/lineups/lineups.xml: Updated lineups list
+
+2012-04-21 05:52  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Add support for non-macro ITV1 +1
+         channels. Deprecate the macro-based variants. Also deprecate the
+         ITV1 Thames Valley sub-regions.
+
+2012-04-21 05:49  knowledgejunkie
+
+       * grab/uk_rt/lineups/: freesat.map, freeview.map: Further updates
+         to DVB mappings
+
+2012-04-20 13:38  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-04-16 18:16  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-04-14 13:56  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-04-14 13:00  knowledgejunkie
+
+       * grab/uk_rt/lineups/saorview.map: Add a Saorview/XMLTV DVB mapping
+         file
+
+2012-04-14 02:27  knowledgejunkie
+
+       * grab/uk_rt/lineups/freesat.map: Update and overhaul of
+         Freesat/XMLTV mapping
+
+2012-04-14 01:24  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Add support for Chart Show TV +1
+
+2012-04-13 17:53  knowledgejunkie
+
+       * grab/uk_rt/lineups/freeview.map: Update and overhaul of
+         Freeview/XMLTV mapping
+
+2012-04-12 05:35  dekarl
+
+       * grab/: se_tvzon/test.conf, hr/test.conf, se_swedb/test.conf:
+         track changes in nordic channels
+
+2012-04-10 08:44  knowledgejunkie
+
+       * lib/: Configure.pm, Options.pm: Add lineups support to
+         configuration and options parsing routines
+
+2012-04-10 08:36  knowledgejunkie
+
+       * xmltv-lineups.xsd: Add transmitter to the availability enum list
+
+2012-04-10 08:34  knowledgejunkie
+
+       * xmltv-lineups.xsd: Add generator/source/modified attributes to
+         xmltv-lineups and xmltv-lineup elements
+
+2012-04-06 10:45  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Add support for RTE One +1, RTE Two HD
+         and MGM. Add initial support for RTEjr, TRTE and Cula4
+
+2012-04-04 03:13  knowledgejunkie
+
+       * xmltv-lineups.xsd: Make a lineup-entry's section element
+         optional.
+
+2012-04-04 03:07  knowledgejunkie
+
+       * xmltv-lineups.xsd: Add optional availability element for
+         xmltv-lineup element, replacing region element.
+
+2012-04-02 01:01  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-03-28 19:36  knowledgejunkie
+
+       * xmltv-lineups.xsd: Make tsid optional for dvb-channel elements.
+         On a given digital service onid and sid are required to be
+         unique, however tsid (if provided) can be useful for i)
+         overriding broadcaster errors when different digital services are
+         multiplexed together, or ii) for services that require tsid to be
+         present for channel matching purposes. Thanks much to dekarl for
+         this info.
+
+2012-03-28 15:27  knowledgejunkie
+
+       * xmltv-lineups.xsd: Update network-id to original-network-id. Make
+         onid, tsid and sid required for dvb-channel elements
+
+2012-03-26 03:01  knowledgejunkie
+
+       * grab/uk_rt/lineups/lineups.xml: Remove FSFS. Update a couple
+         display-names
+
+2012-03-26 02:02  knowledgejunkie
+
+       * MANIFEST: Resort files into relevant sections, as a lot of files
+         have been added to the project in recent years. Should make it
+         easier to maintain going forwards.
+
+2012-03-26 01:53  knowledgejunkie
+
+       * MANIFEST: Update for new eu_egon and se_tvzon grabbers
+
+2012-03-26 01:48  knowledgejunkie
+
+       * MANIFEST: Update for lineups XSD and uk_rt lineups.xml
+
+2012-03-26 01:47  knowledgejunkie
+
+       * Makefile.PL: Add lineups.xml to Makefile, disable individual
+         lineup files for the moment
+
+2012-03-26 01:44  knowledgejunkie
+
+       * Makefile.PL: Add lineups XSD to Makefile
+
+2012-03-26 01:39  knowledgejunkie
+
+       * grab/uk_rt/lineups/lineups.xml: Add lineups.xml
+
+2012-03-26 01:38  knowledgejunkie
+
+       * xmltv-lineups.xsd: Add xmltv-lineups XSD
+
+2012-03-26 01:37  knowledgejunkie
+
+       * grab/uk_rt/lineups/lineups.map: Remove lineups.map
+
+2012-03-26 01:36  knowledgejunkie
+
+       * xmltv-lineup.dtd: Remove xmltv-lineups DTD
+
+2012-03-23 23:02  mnbjhguyt
+
+       * grab/it/tv_grab_it.in: fix for skylife
+
+2012-03-19 07:19  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: remove filmhd.canalplus.se
+         from test configuration
+
+2012-03-18 16:26  knowledgejunkie
+
+       * .cvsignore: Ignore git/mercurial files for any developers using
+         these locally
+
+2012-03-18 16:15  knowledgejunkie
+
+       * .cvsignore: Ignore MYMETA.yml
+
+2012-03-18 13:21  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-03-16 14:39  dekarl
+
+       * Makefile.PL: _fi_sv: disable as per #424135, the guide is
+         available from _fi, too
+
+2012-03-16 14:36  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: TV1000 channels have been
+         renamed
+
+2012-03-16 11:32  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-03-16 09:35  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-03-12 07:19  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Tweak name of S4C Freeview variant
+
+2012-03-12 06:54  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms,
+         regional_channels_by_postcode: Remove movies4men from Freeview
+         lineup
+
+2012-03-09 18:53  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-03-09 18:22  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Add support for Sky
+         Sports F1 and Sky Sports F1 HD
+
+2012-03-07 02:47  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Restore MTVNHD name until channel is
+         rebranded
+
+2012-03-07 02:40  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-03-07 02:19  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Update config for
+         MTV Live HD
+
+2012-03-06 06:27  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Add support for
+         Animal Planet HD, Dave HD, MTV HD and Watch HD
+
+2012-03-06 06:06  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Updates to some channel names
+
+2012-03-06 06:04  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Remove channels
+         that have ceased broadcasting
+
+2012-03-03 03:39  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-27 18:03  knowledgejunkie
+
+       * MANIFEST, Makefile.PL: Add lineups.map to distribution config
+
+2012-02-27 17:59  knowledgejunkie
+
+       * grab/uk_rt/lineups/lineups.map: Add header and CVS Id thingy
+
+2012-02-27 17:55  knowledgejunkie
+
+       * grab/uk_rt/lineups/lineups.map: Add lineups mapping file
+
+2012-02-27 16:20  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Update for mistitled Rome on
+         TCMs
+
+2012-02-27 15:59  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Couple more updates
+
+2012-02-27 15:15  knowledgejunkie
+
+       * grab/uk_rt/: prog_titles_to_process, tv_grab_uk_rt.in: Add a new
+         title fixup routine that caters for programme listings where the
+         title has been replaced by the programme's 'brand' and the
+         programme's title has been moved into the subtitle field.
+
+2012-02-27 08:53  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Remove some newlines in debug output
+
+2012-02-27 08:52  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Delay encoding Perl strings in
+         output (title/ep/desc/cast/genre) until the programme element is
+         to be written out
+
+2012-02-27 08:23  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Add automatic title fixup to check
+         for and remove a duplicated title and episode string from the
+         episode field (e.g. TITLE: EPISODE: EPISODE), leaving a single
+         copy of the episode name intact
+
+2012-02-27 07:09  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Spacing
+
+2012-02-27 06:59  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: More refactoring
+
+2012-02-27 06:14  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-27 06:01  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Prettify programme debug output a
+         bit
+
+2012-02-27 01:47  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Remove TODO item. RT reviews no
+         longer available since move to metabroadcast
+
+2012-02-26 10:01  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Significant code refactor to split
+         out programme processing elements into separate subroutines.
+         There should be no functional changes.
+
+2012-02-24 18:26  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-21 19:37  dekarl
+
+       * filter/tv_to_text: Enable warnings (and test if syncmail works
+         again)
+
+2012-02-21 12:31  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-16 07:46  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-13 11:41  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-13 10:46  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in, lib/Options.pm: Pass config hash to
+         all subs which may need access to its settings (e.g. output
+         encoding).
+
+2012-02-12 10:21  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Minor code layout changes
+
+2012-02-12 09:16  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Move duplicate title detection
+         routine into separate sub
+
+2012-02-12 09:15  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Fix an upstream typo
+
+2012-02-12 08:54  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-12 08:32  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Return non-zero exit status if
+         listings for any programmes are malformed/missing
+
+2012-02-11 20:31  stefanb2
+
+       * grab/fi/: test.conf, tv_grab_fi.pl, fi/programme.pm: - programme:
+         add option to strip parental level from titles
+
+2012-02-11 19:33  rmeden
+
+       * doc/README.win32, lib/exe_opt.pl, lib/exe_wrap.pl: add
+         tv_grab_eu_epgdata back to the xmltv.exe distribution
+
+2012-02-11 18:43  dekarl
+
+       * grab/pt/tv_grab_pt: update _pt to new hostname
+
+         Patch by Rokys Fixes #3483889
+
+2012-02-10 05:12  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Debug updates
+
+2012-02-09 15:56  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Remove single space after a colon
+         when removing title from subtitle
+
+2012-02-09 15:53  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in, Makefile.PL: Rewrite date/time
+         handling routines to use DateTime instead of Date::Manip and
+         XMLTV::DST. This brings about a ~7X speedup in grabbing
+         performance. DST behaviour has also been tested with no problems
+         detected using a mix of DST-flagged and unflagged programme
+         listings. Please test and report any issues.
+
+2012-02-09 15:34  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-08 10:54  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Remove timeshift for RT-sourced Channel 5
+         +1 data
+
+2012-02-08 08:42  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Remove occurences of the programme
+         title in the subtitle field (beginning or end) when separated
+         from the episode details with a hyphen
+
+2012-02-08 08:10  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Remove a couple of unnecessary TODO
+         items. Programme lengths should now be correct and programmes
+         should not overlap in the source data.
+
+2012-02-08 08:08  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Make detection and correction of
+         mis-encoded UTF-8 chars in the source data a configuration option
+         (default disabled). The data should be UTF-8 safe since the
+         transition to metabroadcast/Atlas, but this option will permit
+         the existing fixups to be used if required.
+
+2012-02-07 07:03  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Require at least (rather than
+         exactly) 23 data fields in each programme record. This is a
+         precautionary measure in case the delimited XMLTV feed continues
+         and adds more fields in the future.
+
+2012-02-07 06:57  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Remove completed TODO item
+
+2012-02-07 05:33  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-02-07 05:06  knowledgejunkie
+
+       * grab/uk_rt/: prog_titles_to_process, tv_grab_uk_rt.in: Adds a new
+         title fixup routine (type 10) to permit one title/subtitle
+         combination to be replaced with another, based on the contents of
+         a given programme description. This should help to alleviate the
+         problems associated with specific programme listings having the
+         subtitle field incorrectly elevated to the title field.
+
+2012-02-03 01:46  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-01-31 17:15  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-01-31 17:14  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Sort each group of fixups
+
+2012-01-31 17:05  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-01-30 08:46  dekarl
+
+       * grab/eu_egon/test.conf: _eu_egon: the code doesn't handle the new
+         channel list format, yet
+
+2012-01-30 06:53  dekarl
+
+       * grab/eu_egon/test.conf: _eu_egon: remove SWRinfo from test
+         configuration
+
+2012-01-30 06:52  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: remove nickjr.se from test
+         configuration
+
+2012-01-23 14:55  knowledgejunkie
+
+       * grab/uk_rt/channels_platforms: Re-enable Channel 5 +1 on Freeview
+
+2012-01-23 14:29  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-01-19 14:55  stefanb2
+
+       * grab/fi/: test.conf, test.sh, fi/source/tvnyt.pm:  - tvnyt:
+         replace _ with - in channel IDs
+
+2012-01-18 18:41  stefanb2
+
+       * grab/fi/fi/source/tvnyt.pm: tvnyt: Very funny... *NOT*!
+
+         After testing it succesfully yesterday evening, uploading the new
+         version to CVS, what happens overnight? They change the base URL.
+         Thus the new grabber failed again in the XMLTV nightly build test
+         :-(
+
+         Let's hope that tv.nyt.fi doesn't make a habbit out of this...
+
+2012-01-18 08:30  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Tweak to debug logging for possible
+         title fixups
+
+2012-01-18 08:21  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Tweak to debug logging for
+         title/episode replacements
+
+2012-01-18 08:12  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Couple more updates
+
+2012-01-18 07:54  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Remove a fixup handled
+         elsewhere
+
+2012-01-18 07:49  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Ignore the premiere flag and set the
+         repeat flag for 'premieres' on timeshifted (tsod) channels. Only
+         the first showing on a non-timeshifted channel should be flagged
+         as a premiere.
+
+2012-01-18 07:16  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-01-17 20:18  stefanb2
+
+       * Makefile.PL, grab/fi/test.conf, grab/fi/test.sh,
+         grab/fi/fi/source/tvnyt.pm: - tvnyt: rewritten from scratch for
+         new web page layout - modules HTML::Entities & JSON are no longer
+         required for installation
+
+2012-01-12 05:11  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Check for, and ignore, invalid/null
+         release dates.
+
+2012-01-12 04:22  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Remove a programme title if seen
+         duplicated at the end of the episode field after a colon
+
+2012-01-12 03:40  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Add debug output to list programmes
+         with episode field containing a colon/hyphen. The presence of a
+         colon/hyphen may indicate that the programme title is either
+         duplicated in the episode field, or has been demoted by the
+         presence of the programme's 'brand' in the title field.
+
+2012-01-12 03:29  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-01-12 02:42  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Check for films given without year
+         of release
+
+2012-01-12 02:34  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Additional checks for premieres and
+         repeat episodes
+
+2012-01-12 01:55  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2012-01-09 20:09  dekarl
+
+       * grab/eu_egon/test.conf: _eu_egon: update test configuration to
+         updated channels
+
+2012-01-08 13:54  alewando
+
+       * grab/na_dtv/: test.conf, tv_grab_na_dtv: Removed dependencies on
+         DateTime::Format::ISO8601 and DateTime::Format::XMLTV
+
+2012-01-05 22:49  dekarl
+
+       * grab/na_dtv/tv_grab_na_dtv, Makefile.PL: _na_dtv: remove
+         dependency on DateTime::Format::XMLTV as its pretty new and build
+         it again
+
+2012-01-04 18:44  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates, including some
+         requests from xmltv-users
+
+2012-01-02 04:14  alewando
+
+       * grab/na_dtv/test.conf: Updated test configuration
+
+2012-01-02 04:09  alewando
+
+       * grab/na_dtv/tv_grab_na_dtv: Updated grabber, works with current
+         DirecTV listings site.
+
+2012-01-01 18:45  candu_sf
+
+       * grab/es_laguiatv/: test.conf, tv_grab_es_laguiatv:
+         tv_grab_es_laguiatv rewrite
+
+2011-12-31 09:51  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Some final updates for 2011
+
+2011-12-30 22:49  rmeden
+
+       * grab/na_dd/tv_grab_na_dd.in: Deal with a Tribune bug causing no
+         <ROLE>
+
+2011-12-20 06:43  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-12-19 22:40  lightpriest
+
+       * grab/il/tv_grab_il: Updated il grabber to match changes in
+         scraped site
+
+2011-12-15 01:27  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-12-14 20:15  knowledgejunkie
+
+       * grab/uk_rt/channels_platforms: Remove Channel 5 +1 from freeview
+         lineup until broadcast hours are known
+
+2011-12-14 03:58  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates - first update since
+         switch to new Radio Times infrastructure. Of note are changes to
+         the way some programme titles are given: Title = Brand Name;
+         Sub-title = Prog Title: Ep Title
+
+2011-12-14 01:41  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Add support for PBS
+         (Sky/Virgin)
+
+2011-12-14 01:32  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Update logos for Channel 5 (and +1) and
+         5* +1. Thanks to Nigel Jewell for the details.
+
+2011-12-13 10:09  betlit
+
+       * grab/ch_search/tv_grab_ch_search.in: added sky channels manually
+
+2011-12-12 12:51  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-12-12 03:56  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-12-12 02:08  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Remove Showcase
+         listings (empty listings)
+
+2011-12-12 01:07  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms,
+         regional_channels_by_postcode: Remove some channels no longer
+         supported by Radio Times (empty files)
+
+2011-12-10 15:56  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates for Wheeler Dealers
+
+2011-12-10 15:45  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-12-10 04:52  knowledgejunkie
+
+       * grab/uk_rt/channels_platforms: Add 5*, 5USA and timeshifts to
+         Freesat platform
+
+2011-12-10 04:41  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Add support for
+         Channel 5 +1
+
+2011-12-10 02:12  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Series numbering updates for
+         QI and QI XL.
+
+2011-12-09 21:30  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates for The X Factor
+
+2011-12-09 15:58  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates, including changes to
+         handling of Strictly Come Dancing (regular and results shows)
+
+2011-12-07 18:16  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: disable testing of
+         yachtandsail.com
+
+2011-12-03 09:09  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates for MasterChef
+
+2011-12-02 18:15  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-12-01 14:31  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-11-26 02:27  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-11-25 09:14  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Instead of overwriting good data
+         with bad, only use episode and series numbering extracted from
+         the description if we have not found it elsewhere
+
+2011-11-25 08:54  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Add another fixup for a title
+         containing BBFC rating
+
+2011-11-25 08:16  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Ignore particular typo seen in
+         episode numbering
+
+2011-11-25 08:06  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Support double-bill episode
+         numbering of format 'i&j, series k&l' by ignoring numbering of
+         second episode. The title of the second episode in the double
+         bill is still output in the subtitle. Also, look for most common
+         stable episode numbering format first 'i/j, series k' before
+         trying more complicated regex matches for variants - provides a
+         small speed increase in testing.
+
+2011-11-25 06:58  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Add debug output for films that may
+         contain their BBFC certificate in their title text.
+
+2011-11-25 06:07  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Historical updates for
+         programme titles that have included a BBFC certificate
+
+2011-11-25 05:31  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates, including a request
+         from xmltv-users
+
+2011-11-18 18:08  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-11-15 06:04  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-11-11 18:32  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: remove OUTTV from test
+         configuration
+
+2011-11-08 14:39  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-11-02 19:29  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-10-26 08:55  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: disable two channels without
+         data
+
+2011-10-26 08:40  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-10-26 08:02  dekarl
+
+       * grab/pt_meo/tv_grab_pt_meo: _pt_meo: fix DST issues
+
+         Use first start time and then only add up durations to avoid
+         issues with ambiguous times.
+
+         Fixes #3248310 Tested by Daniel Leite (higuita)
+
+2011-10-22 19:50  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates, including a request
+         from xmltv-users
+
+2011-10-18 04:19  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-10-10 16:38  stefanb2
+
+       * grab/fi/: tv_grab_fi.pl, fi/common.pm, fi/source/mtv3.pm,
+         fi/source/telkku.pm, fi/source/telvis.pm, fi/source/tvnyt.pm,
+         fi/source/yle.pm: - telkku: add movie detection (using
+         http://www.telkku.com/movie) - common: implement timeout & retry
+         to work around current telkku.com problems.            NOTE: as
+         long as telkku.com isn't fixed, grabber will runs will take
+                    longer than usual!
+
+2011-10-07 12:31  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-10-02 14:13  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-10-02 13:58  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Request from xmltv-users to
+         allow Strictly Come Dancing's spinoff shows to retain separate
+         titles
+
+2011-09-30 23:05  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Update for 'Ceramics : A
+         Fragile History' whose title is being part-fixed via a UTF-8
+         fixup due to mis-encoded Windows-1252 char. Fixup the rest of the
+         title here to remove space before colon.
+
+2011-09-30 23:03  knowledgejunkie
+
+       * grab/uk_rt/utf8_fixups: [C2][80-9F] fixups need to start with
+         those chars, so remove leading space from dash-colon fixup
+
+2011-09-30 22:44  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-29 09:14  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-28 07:18  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-26 03:22  knowledgejunkie
+
+       * grab/uk_rt/utf8_fixups: Updates to handle mis-encoded
+         Windows-1252 characters
+
+2011-09-26 02:49  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-25 07:33  knowledgejunkie
+
+       * grab/uk_rt/test.conf: Sync test.conf with current channels
+
+2011-09-25 07:27  knowledgejunkie
+
+       * grab/uk_rt/regional_channels_by_postcode: Remove Virgin1/Channel
+         One details. Channel is no longer aired.
+
+2011-09-25 07:06  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Remove
+         Freeview-specific configs for Yesterday, Quest and ITV2 +1 which
+         are now 24hr. Adjust broadcast hours for Community Channel
+
+2011-09-25 05:53  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Add support for
+         Cartoon Network HD and Disney Channel HD
+
+2011-09-25 03:15  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Updated icons for some channels
+
+2011-09-25 02:54  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates, including requests
+         from xmltv-users
+
+2011-09-21 00:15  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-18 15:26  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-18 15:19  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Requests from xmltv-users
+
+2011-09-16 14:39  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: TODO item
+
+2011-09-16 14:36  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-15 18:46  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: don't test channels that
+         sometimes are without program
+
+2011-09-14 04:50  dekarl
+
+       * grab/se_tvzon/test.conf: _se_tvzon: adjust tested channels
+
+2011-09-10 11:21  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates including a request
+         from xmltv-users
+
+2011-09-08 21:31  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-08 00:18  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Update
+
+2011-09-08 00:15  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-09-01 06:59  dekarl
+
+       * grab/dk_dr/test.conf: _dr_dk: don't test with empty BBC
+         Knowledge, use DR channels instead
+
+2011-08-30 17:16  rmeden
+
+       * Makefile.PL, lib/exe_opt.pl: add tv_grab_pt_meo back to xmltv.exe
+
+2011-08-30 07:24  dekarl
+
+       * grab/pt_meo/tv_grab_pt_meo: _pt_meo: remove dependency on CGI
+
+         TODO rewrite to not request all channels in one serivce
+         invocation as the set of all channels is to much for the service
+         in the meantime, doh!
+
+2011-08-29 07:38  dekarl
+
+       * Makefile.PL, grab/eu_egon/.cvsignore, grab/eu_egon/test.conf,
+         grab/eu_egon/tv_grab_eu_egon.PL, grab/se_tvzon/.cvsignore,
+         grab/se_tvzon/test.conf, grab/se_tvzon/tv_grab_se_tvzon.PL: Add
+         two more grabbers for NonameTV sites. (Sweden / german)
+
+2011-08-28 08:56  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: TODO item
+
+2011-08-28 06:39  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-08-24 23:47  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-08-19 00:31  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: perldoc updates
+
+2011-08-19 00:21  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: Permit longer UTF-8 fixups for bytes
+         in range [C2][80-9F] and update related debug output
+
+2011-08-18 17:08  mnbjhguyt
+
+       * grab/it/channel_ids: fixed duplicate channel
+
+2011-08-18 14:39  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-08-16 12:27  knowledgejunkie
+
+       * grab/uk_rt/utf8_fixups: Update for Sky Living Loves
+
+2011-08-16 12:16  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-08-11 15:19  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-08-08 03:57  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Add support for
+         newly time-limited Dave ja vu on Freeview platform. Add Really to
+         Freeview lineups.
+
+2011-08-08 03:45  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-08-06 06:31  stefanb2
+
+       * README: README: add JSON as required module for tv_grab_fi
+
+2011-08-06 00:06  stefanb2
+
+       * grab/fi/fi/source/telvis.pm: telvis: add \Q & \E around $title
+         variable in substitution regex
+
+         Fixes bug #3386337: tv_grav_fi xmltv returned error code 65280
+
+         We are using the extracted title string in a substitution regex.
+         If the title contained an regex special character, e.g. "(", then
+         the regex compiler failed and aborted the script.
+
+2011-08-06 00:04  stefanb2
+
+       * MANIFEST: MANIFEST: add missing grab/fi/.cvsignore file
+
+2011-07-29 21:51  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-07-28 09:01  attila_nagy
+
+       * grab/huro/tv_grab_huro.in: Added patch from ticket #3379572 by
+         Pojar George
+
+2011-07-26 23:25  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: One last thing... a fixup for
+         Columbo
+
+2011-07-26 23:22  knowledgejunkie
+
+       * grab/uk_rt/utf8_fixups: Disable fixup until support for emtpy
+         replacement field is added to grabber
+
+2011-07-24 22:48  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-07-24 10:34  mnbjhguyt
+
+       * grab/it/: channel_ids, tv_grab_it.in: new channels added
+
+2011-07-18 09:37  knowledgejunkie
+
+       * grab/uk_rt/tv_grab_uk_rt.in: TODO item
+
+2011-07-18 08:00  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates, including suggestions
+         from xmltv-users
+
+2011-07-11 07:15  knowledgejunkie
+
+       * grab/uk_rt/: channel_ids, channels_platforms: Add support for
+         Food Network (Freeview), and update logos for Dave ja vu and Food
+         Network UK. Thanks to Nigel Jewell for these
+
+2011-07-07 05:33  knowledgejunkie
+
+       * grab/uk_rt/utf8_fixups: Update for Sky Living Loves
+
+2011-07-07 05:05  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-06-29 22:38  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-06-28 00:11  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-06-28 00:04  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Fix Radio Times ID for Quest (Freeview)
+
+2011-06-26 09:22  perlundberg
+
+       * grab/fi_sv/tv_grab_fi_sv: Added sub-title handling for certain
+         programs, based on hard-wired heuristics...
+
+2011-06-26 06:19  perlundberg
+
+       * grab/fi_sv/tv_grab_fi_sv: Minor changes + started working on
+         adding subtitle support
+
+2011-06-23 23:45  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Another tweak to S4C
+
+2011-06-23 22:59  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-06-23 14:07  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Add support for Radio Times version of
+         Quest (Freeview).
+
+2011-06-23 12:34  knowledgejunkie
+
+       * grab/uk_rt/channel_ids: Update descriptions for S4C
+
+2011-06-22 19:16  dekarl
+
+       * grab/test_grabbers: test_grabbers: test grabbers in alphabetical
+         order
+
+2011-06-22 19:08  dekarl
+
+       * grab/test_grabbers: test_grabbers: use the same regexp everywhere
+
+2011-06-22 19:07  dekarl
+
+       * filter/tv_imdb: tv_imdb: handle error if we filter something that
+         is not xmltv at all
+
+2011-06-22 19:04  dekarl
+
+       * lib/ValidateFile.pm: ValidateFile: catch more ways of doing utf-8
+         wrong
+
+2011-06-22 18:58  dekarl
+
+       * lib/IMDB.pm: tv_imdb: fix handling of star-rating
+
+         Fixes: #3315805
+
+2011-06-22 12:32  knowledgejunkie
+
+       * grab/uk_rt/prog_titles_to_process: Updates
+
+2011-06-22 09:45  attila_nagy
+
+       * grab/huro/tv_grab_huro.in: Fixed bug #3324206 data source change
+         resulted in no programs appearing at all
+
 2011-06-22 06:08  rmeden
 
        * Makefile.PL, README, doc/README.win32, lib/XMLTV.pm.in,
index 8132af3..ff43749 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,39 +1,41 @@
+.cvsignore
 COPYING
 MANIFEST
 Makefile.PL
-Uninstall.pm
 README
 README.cygwin
+Uninstall.pm
+xmltv.dtd
+xmltv-lineups.xsd
+lib/.cvsignore
 lib/Ask.pm
 lib/Ask/Term.pm
 lib/Ask/Tk.pm
+lib/Capabilities.pm
+lib/Clumps.pm
+lib/Configure.pm
+lib/Configure/Writer.pm
+lib/Date.pm
+lib/Description.pm
 lib/GUI.pm
+lib/Gunzip.pm
+lib/IMDB.pm
+lib/Options.pm
+lib/PreferredMethod.pm
 lib/ProgressBar.pm
 lib/ProgressBar/None.pm
 lib/ProgressBar/Term.pm
 lib/ProgressBar/Tk.pm
-lib/XMLTV.pm.PL
-lib/XMLTV.pm.in
+lib/Summarize.pm
+lib/Supplement.pm.PL
+lib/Supplement.pm.in
 lib/TZ.pm
-lib/Clumps.pm
-lib/IMDB.pm
 lib/Usage.pm
-lib/Version.pm
-lib/Summarize.pm
-lib/Gunzip.pm
-lib/Capabilities.pm
-lib/Date.pm
-lib/Options.pm
-lib/Configure.pm
-lib/Configure/Writer.pm
-lib/Description.pm
 lib/ValidateFile.pm
 lib/ValidateGrabber.pm
-lib/PreferredMethod.pm
-lib/Supplement.pm.in
-lib/Supplement.pm.PL
-lib/Lineup.pm.in
-lib/Lineup.pm.PL
+lib/Version.pm
+lib/XMLTV.pm.PL
+lib/XMLTV.pm.in
 lib/exe_opt.pl
 lib/exe_wrap.pl
 lib/set_share_dir.pl
@@ -52,54 +54,81 @@ doc/QuickStart
 doc/exe_build.html
 doc/code/coding_standards
 doc/code/grabber_interface
+filter/.cvsignore
+filter/Grep.pm
 filter/tv_cat
-filter/tv_split
 filter/tv_extractinfo_ar
 filter/tv_extractinfo_en
 filter/tv_grep.PL
 filter/tv_grep.in
-filter/Grep.pm
 filter/tv_imdb
 filter/tv_remove_some_overlapping
 filter/tv_sort
+filter/tv_split
 filter/tv_to_latex
-filter/tv_to_text
 filter/tv_to_potatoe
+filter/tv_to_text
 grab/Get_nice.pm
 grab/Grab_XML.pm
 grab/Memoize.pm
 grab/DST.pm
 grab/Config_file.pm
 grab/Mode.pm
+grab/ar/test.conf
 grab/ar/tv_grab_ar
 grab/au/channel_ids
-grab/au/tv_grab_au.in
+grab/au/test.conf
 grab/au/tv_grab_au.PL
+grab/au/tv_grab_au.in
 grab/be/channel_ids_fr
 grab/be/channel_ids_nl
-grab/be/tv_grab_be.in
+grab/be/test.conf
 grab/be/tv_grab_be.PL
+grab/be/tv_grab_be.in
+grab/br/test.conf
 grab/br/tv_grab_br
+grab/br_net/test.conf
 grab/br_net/tv_grab_br_net
-grab/ch_bluewin/channel_ids
-grab/ch_bluewin/tv_grab_ch_bluewin.in
-grab/ch_bluewin/tv_grab_ch_bluewin.PL
 grab/ch/channel_ids
-grab/ch/tv_grab_ch.in
+grab/ch/test.conf
 grab/ch/tv_grab_ch.PL
+grab/ch/tv_grab_ch.in
+grab/ch_bluewin/channel_ids
+grab/ch_bluewin/test.conf
+grab/ch_bluewin/tv_grab_ch_bluewin.PL
+grab/ch_bluewin/tv_grab_ch_bluewin.in
+grab/ch_search/.cvsignore
+grab/ch_search/test.conf
+grab/ch_search/tv_grab_ch_search.PL
+grab/ch_search/tv_grab_ch_search.in
+grab/combiner/test.conf
 grab/combiner/tv_grab_combiner
-grab/ee/tv_grab_ee
-grab/eu_epgdata/channel_ids
-grab/eu_epgdata/revision_log
-grab/eu_epgdata/tv_grab_eu_epgdata
-grab/es/tv_grab_es
+grab/cz/test.conf
+grab/cz/tv_grab_cz
+grab/de/tv_grab_de
+grab/dk/test.conf
 grab/dk/tv_grab_dk
+grab/dk_dr/test.conf
+grab/dk_dr/tv_grab_dk_dr
 grab/dk_tvtid/test.conf
 grab/dk_tvtid/tv_grab_dk_tvtid
-grab/dk_dr/tv_grab_dk_dr
+grab/dtv_la/test.conf
 grab/dtv_la/tv_grab_dtv_la
-grab/fi/merge.PL
-grab/fi/tv_grab_fi.pl
+grab/ee/test.conf
+grab/ee/tv_grab_ee
+grab/es/test.conf
+grab/es/tv_grab_es
+grab/es_laguiatv/test.conf
+grab/es_laguiatv/tv_grab_es_laguiatv
+grab/es_miguiatv/test.conf
+grab/es_miguiatv/tv_grab_es_miguiatv
+grab/eu_egon/.cvsignore
+grab/eu_egon/test.conf
+grab/eu_egon/tv_grab_eu_egon.PL
+grab/eu_epgdata/channel_ids
+grab/eu_epgdata/revision_log
+grab/eu_epgdata/tv_grab_eu_epgdata
+grab/fi/.cvsignore
 grab/fi/fi/common.pm
 grab/fi/fi/day.pm
 grab/fi/fi/programme.pm
@@ -109,51 +138,113 @@ grab/fi/fi/source/telkku.pm
 grab/fi/fi/source/telvis.pm
 grab/fi/fi/source/tvnyt.pm
 grab/fi/fi/source/yle.pm
+grab/fi/merge.PL
 grab/fi/test.conf
 grab/fi/test.sh
+grab/fi/tv_grab_fi.pl
+grab/fi_sv/test.conf
+grab/fi_sv/tv_grab_fi_sv
+grab/fr/test.conf
 grab/fr/tv_grab_fr
 grab/fr_kazer/test.conf
 grab/fr_kazer/tv_grab_fr_kazer
+grab/hr/.cvsignore
+grab/hr/test.conf
 grab/hr/tv_grab_hr.PL
-grab/huro/tv_grab_huro.PL
-grab/huro/tv_grab_huro.in
-grab/huro/jobmap
+grab/huro/.cvsignore
 grab/huro/catmap.cz
-grab/huro/catmap.ro
 grab/huro/catmap.hu
+grab/huro/catmap.ro
 grab/huro/catmap.sk
+grab/huro/jobmap
+grab/huro/test.conf
+grab/huro/tv_grab_huro.PL
+grab/huro/tv_grab_huro.in
+grab/il/test.conf
+grab/il/tv_grab_il
+grab/in/tv_grab_in
+grab/is/test.conf
 grab/is/tv_grab_is
+grab/it/.cvsignore
+grab/it/channel_ids
+grab/it/test.conf
 grab/it/tv_grab_it.PL
 grab/it/tv_grab_it.in
-grab/it/channel_ids
+grab/it_dvb/.cvsignore
+grab/it_dvb/channel_ids
+grab/it_dvb/sky_it.dict
+grab/it_dvb/sky_it.themes
+grab/it_dvb/tv_grab_it_dvb.PL
+grab/it_dvb/tv_grab_it_dvb.in
 grab/jp/README.CATV
 grab/jp/README.CATV.ja
+grab/jp/test.conf
 grab/jp/tv_grab_jp
-grab/na_dd/tv_grab_na_dd.in
+grab/na_dd/.cvsignore
 grab/na_dd/tv_grab_na_dd.PL
+grab/na_dd/tv_grab_na_dd.in
+grab/na_dtv/test.conf
 grab/na_dtv/tv_grab_na_dtv
-grab/na_icons/tv_grab_na_icons.in
+grab/na_icons/.cvsignore
 grab/na_icons/tv_grab_na_icons.PL
+grab/na_icons/tv_grab_na_icons.in
+grab/nc/test.conf
+grab/nc/tv_grab_nc
+grab/nl/test.conf
 grab/nl/tv_grab_nl
+grab/nl_wolf/test.conf
 grab/nl_wolf/tv_grab_nl_wolf
+grab/no/test.conf
 grab/no/tv_grab_no
+grab/no_gfeed/.cvsignore
+grab/no_gfeed/test.conf
 grab/no_gfeed/tv_grab_no_gfeed.PL
+grab/pt/test.conf
 grab/pt/tv_grab_pt
+grab/pt_meo/test.conf
+grab/pt_meo/tv_grab_pt_meo
+grab/re/test.conf
 grab/re/tv_grab_re
-grab/se_swedb/tv_grab_se_swedb.in
+grab/se_swedb/.cvsignore
+grab/se_swedb/test.conf
 grab/se_swedb/tv_grab_se_swedb.PL
+grab/se_swedb/tv_grab_se_swedb.in
+grab/se_tvzon/.cvsignore
+grab/se_tvzon/test.conf
+grab/se_tvzon/tv_grab_se_tvzon.PL
+grab/test_grabbers
+grab/uk_bleb/.cvsignore
 grab/uk_bleb/icon_urls
-grab/uk_bleb/tv_grab_uk_bleb.in
+grab/uk_bleb/test.conf
 grab/uk_bleb/tv_grab_uk_bleb.PL
-grab/uk_rt/tv_grab_uk_rt.in
-grab/uk_rt/tv_grab_uk_rt.PL
+grab/uk_bleb/tv_grab_uk_bleb.in
+grab/uk_rt/.cvsignore
+grab/uk_rt/channel_icons
 grab/uk_rt/channel_ids
 grab/uk_rt/channels_platforms 
+grab/uk_rt/lineups/freesat.map
+grab/uk_rt/lineups/freesat.xml
+grab/uk_rt/lineups/freesatfromsky.xml
+grab/uk_rt/lineups/freesathd.xml
+grab/uk_rt/lineups/freeview.map
+grab/uk_rt/lineups/freeview.xml
+grab/uk_rt/lineups/freeviewhd.xml
+grab/uk_rt/lineups/lineups.xml
+grab/uk_rt/lineups/saorview.map
+grab/uk_rt/lineups/saorview.xml
+grab/uk_rt/lineups/sky.xml
+grab/uk_rt/lineups/skyhd.xml
+grab/uk_rt/lineups/upcireland.xml
+grab/uk_rt/lineups/upcirelandhd.xml
+grab/uk_rt/lineups/virgin.xml
+grab/uk_rt/lineups/virginhd.xml
+grab/uk_rt/lineups/xmltv-lineups.xsl
 grab/uk_rt/prog_titles_to_process
 grab/uk_rt/regional_channels_by_postcode
+grab/uk_rt/test.conf
+grab/uk_rt/tv_grab_uk_rt
 grab/uk_rt/utf8_fixups
-grab/uk_rt/lineups/freeview.map
-grab/uk_rt/lineups/freesat.map
+grab/za/test.conf
 grab/za/tv_grab_za
 t/README
 t/parallel_test
@@ -163,8 +254,6 @@ t/test_library.t
 t/test_tv_split.t
 t/test_icon.t
 t/test_dst.t
-xmltv.dtd
-xmltv-lineup.dtd
 t/data/attrs.xml
 t/data/amp.xml
 t/data/clump.xml
@@ -1296,78 +1385,9 @@ t/data/tv_sort_by_channel_test_remove_some_overlapping_xml.expected
 t/data/tv_sort_test_remove_some_overlapping_xml.expected
 t/data/tv_to_latex_test_remove_some_overlapping_xml.expected
 t/data/tv_to_text_test_remove_some_overlapping_xml.expected
-tools/tv_validate_grabber.in
-tools/tv_validate_grabber.PL
-tools/tv_validate_file.in
-tools/tv_validate_file.PL
-tools/tv_find_grabbers
-grab/au/test.conf
-grab/be/test.conf
-grab/br/test.conf
-grab/br_net/test.conf
-grab/ch/test.conf
-grab/cz/test.conf
-grab/cz/tv_grab_cz
-grab/dk/test.conf
-grab/dk_dr/test.conf
-grab/ee/test.conf
-grab/es/test.conf
-grab/fr/test.conf
-grab/huro/test.conf
-grab/il/test.conf
-grab/il/tv_grab_il
-grab/is/test.conf
-grab/it/test.conf
-grab/jp/test.conf
-grab/na_dtv/test.conf
-grab/nl/test.conf
-grab/nl_wolf/test.conf
-grab/no/test.conf
-grab/pt/test.conf
-grab/re/test.conf
-grab/se_swedb/test.conf
-grab/test_grabbers
-grab/uk_bleb/test.conf
-grab/uk_rt/test.conf
-grab/ar/test.conf
-grab/ch_bluewin/test.conf
-grab/ch_search/test.conf
-grab/ch_search/tv_grab_ch_search.in
-grab/ch_search/tv_grab_ch_search.PL
-grab/de/tv_grab_de
-grab/dtv_la/test.conf
-grab/es_laguiatv/test.conf
-grab/es_laguiatv/tv_grab_es_laguiatv
-grab/es_miguiatv/test.conf
-grab/es_miguiatv/tv_grab_es_miguiatv
-grab/hr/test.conf
-grab/nc/test.conf
-grab/nc/tv_grab_nc
-grab/no_gfeed/test.conf
-grab/za/test.conf
-grab/it_dvb/channel_ids
-grab/it_dvb/sky_it.dict
-grab/it_dvb/sky_it.themes
-grab/it_dvb/tv_grab_it_dvb.in
-grab/it_dvb/tv_grab_it_dvb.PL
-.cvsignore
-filter/.cvsignore
-grab/ch_search/.cvsignore
-grab/combiner/test.conf
-grab/fi_sv/test.conf
-grab/fi_sv/tv_grab_fi_sv
-grab/hr/.cvsignore
-grab/huro/.cvsignore
-grab/in/tv_grab_in
-grab/it/.cvsignore
-grab/it_dvb/.cvsignore
-grab/na_dd/.cvsignore
-grab/na_icons/.cvsignore
-grab/no_gfeed/.cvsignore
-grab/pt_meo/test.conf
-grab/pt_meo/tv_grab_pt_meo
-grab/se_swedb/.cvsignore
-grab/uk_bleb/.cvsignore
-grab/uk_rt/.cvsignore
-lib/.cvsignore
 tools/.cvsignore
+tools/tv_find_grabbers
+tools/tv_validate_file.PL
+tools/tv_validate_file.in
+tools/tv_validate_grabber.PL
+tools/tv_validate_grabber.in
index a9acdbb..235972d 100644 (file)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-# $Id: Makefile.PL,v 1.386 2011/06/22 06:08:48 rmeden Exp $
+# $Id: Makefile.PL,v 1.400 2012/06/10 17:10:48 rmeden Exp $
 
 use ExtUtils::MakeMaker;
 use Config;
@@ -16,9 +16,9 @@ use Getopt::Long; Getopt::Long::Configure('pass_through');
 #
 $SIG{__WARN__} = sub {
     for (my $msg = shift) {
-       $_ = "warning: something's wrong" if not defined;
-       warn $_
-         unless /Argument .+ isn.t numeric in numeric lt .+MakeMaker.pm/;
+        $_ = "warning: something's wrong" if not defined;
+        warn $_
+          unless /Argument .+ isn.t numeric in numeric lt .+MakeMaker.pm/;
     }
 };
 
@@ -28,7 +28,7 @@ $SIG{__WARN__} = sub {
 #
 unless ($ExtUtils::MakeMaker::VERSION ge 6.21) {
     if (not grep /^PREFIX=/, @ARGV) {
-       warn "You may want to explicitly give PREFIX to work around MakeMaker bugs.\n";
+        warn "You may want to explicitly give PREFIX to work around MakeMaker bugs.\n";
     }
 }
 
@@ -60,15 +60,15 @@ my $opt_yes = 0;
 my $opt_default = 0;
 my $opt_components;
 my $opt_exclude;
-GetOptions('strict-deps'  => \$opt_strictdeps, # be strict about dependencies
-          yes            => \$opt_yes,         # answer yes to all questions
-          default        => \$opt_default,     # answer default to all questions
-          'components=s' => \$opt_components,
-          'exclude=s'    => \$opt_exclude,
-         );
+GetOptions('strict-deps'  => \$opt_strictdeps,  # be strict about dependencies
+           yes            => \$opt_yes,         # answer yes to all questions
+           default        => \$opt_default,     # answer default to all questions
+           'components=s' => \$opt_components,
+           'exclude=s'    => \$opt_exclude,
+          );
 
 our $VERSION;
-$VERSION = '0.5.61';
+$VERSION = '0.5.62';
 
 # Fragment of Makefile text to give the directory where files should
 # be installed.  The extra '.' in the middle of the path is to avoid
@@ -134,7 +134,7 @@ my %pm
      'lib/Ask.pm'                 => '$(INST_LIBDIR)/XMLTV/Ask.pm',
      'lib/Ask/Tk.pm'              => '$(INST_LIBDIR)/XMLTV/Ask/Tk.pm',
      'lib/Ask/Term.pm'            => '$(INST_LIBDIR)/XMLTV/Ask/Term.pm',
-     'lib/GUI.pm'                 => '$(INST_LIBDIR)/XMLTV/GUI.pm',     
+     'lib/GUI.pm'                 => '$(INST_LIBDIR)/XMLTV/GUI.pm',
      'lib/ProgressBar.pm'         => '$(INST_LIBDIR)/XMLTV/ProgressBar.pm',
      'lib/ProgressBar/None.pm'    => '$(INST_LIBDIR)/XMLTV/ProgressBar/None.pm',
      'lib/ProgressBar/Term.pm'    => '$(INST_LIBDIR)/XMLTV/ProgressBar/Term.pm',
@@ -151,7 +151,6 @@ my %pm
      'lib/ValidateFile.pm'        => '$(INST_LIBDIR)/XMLTV/ValidateFile.pm',
      'lib/ValidateGrabber.pm'     => '$(INST_LIBDIR)/XMLTV/ValidateGrabber.pm',
      'lib/PreferredMethod.pm'     => '$(INST_LIBDIR)/XMLTV/PreferredMethod.pm',
-     'lib/Lineup.pm'              => '$(INST_LIBDIR)/XMLTV/Lineup.pm',
      'filter/Grep.pm'             => '$(INST_LIBDIR)/XMLTV/Grep.pm',
      'grab/Memoize.pm'            => '$(INST_LIBDIR)/XMLTV/Memoize.pm',
      'grab/Grab_XML.pm'           => '$(INST_LIBDIR)/XMLTV/Grab_XML.pm',
@@ -179,13 +178,12 @@ my %prereqs
     );
 
 # Files which are run to generate source code.
-my %pl_files = ('filter/tv_grep.PL'     => 'filter/tv_grep',
-                'tools/tv_validate_file.PL'     => 'tools/tv_validate_file',
-                'tools/tv_validate_grabber.PL'     => 'tools/tv_validate_grabber',
-               'lib/XMLTV.pm.PL'       => 'lib/XMLTV.pm',
-               'lib/Supplement.pm.PL'     => 'lib/Supplement.pm',
-                'lib/Lineup.pm.PL'     => 'lib/Lineup.pm',
-              );
+my %pl_files = ('filter/tv_grep.PL' => 'filter/tv_grep',
+                'tools/tv_validate_file.PL' => 'tools/tv_validate_file',
+                'tools/tv_validate_grabber.PL' => 'tools/tv_validate_grabber',
+                'lib/XMLTV.pm.PL' => 'lib/XMLTV.pm',
+                'lib/Supplement.pm.PL' => 'lib/Supplement.pm',
+               );
 
 # Some tools which are generated from .PL files need the share/
 # directory passed as an extra argument.
@@ -197,7 +195,7 @@ my @need_share = ( 'tools/tv_validate_file',
 
 # Files to be installed in the system-wide share/ directory.
 my %share_files = ('xmltv.dtd' => 'xmltv.dtd',
-                   'xmltv-lineup.dtd' => 'xmltv-lineup.dtd');
+                   'xmltv-lineups.xsd' => 'xmltv-lineups.xsd');
 
 # Files which 'make clean' should remove, but doesn't by default, so
 # we have to patch it.
@@ -205,15 +203,15 @@ my %share_files = ('xmltv.dtd' => 'xmltv.dtd',
 my @to_clean = ('filter/tv_grep',
                 'tools/tv_validate_file',
                 'tools/tv_validate_grabber',
-               'lib/XMLTV.pm', 'lib/Supplement.pm', 'lib/Lineup.pm');
+                'lib/XMLTV.pm', 'lib/Supplement.pm');
 
 # Extra dependencies to add to the Makefile.
 my @deps = ('filter/tv_grep' => [ qw(filter/tv_grep.in pm_to_blib) ],
             'tools/tv_validate_file' => [ qw(tools/tv_validate_file.in) ],
             'tools/tv_validate_grabber' => [ qw(tools/tv_validate_grabber.in) ],
-           'lib/XMLTV.pm' => [ 'lib/XMLTV.pm.in' ],
-           'lib/Supplement.pm' => [ 'lib/Supplement.pm.in' ],
-            'lib/Lineup.pm' => [ 'lib/Lineup.pm.in' ]);
+            'lib/XMLTV.pm' => [ 'lib/XMLTV.pm.in' ],
+            'lib/Supplement.pm' => [ 'lib/Supplement.pm.in' ],
+            );
 
 # Some grabbers which are generated from .PL files need the share/
 # directory passed as an extra argument.
@@ -297,7 +295,7 @@ my @opt_components
 #       blurb => 'Grabber for Brazil NET Cable',
 #       exes => [ 'grab/br_net/tv_grab_br_net' ],
 #       prereqs => { 'WWW::Mechanize' => 1.16 ,
-#                  'HTTP::Cookies' => 1.39 , }
+#                   'HTTP::Cookies' => 1.39 , }
 #     },
 
 # disabled since blocked by www.fernsehen.ch guys
@@ -315,31 +313,31 @@ my @opt_components
 #     { name     => 'tv_grab_ch_bluewin',
 #       blurb    => 'Grabber for Switzerland',
 #       exes     => [ 'grab/ch_bluewin/tv_grab_ch_bluewin' ],
-#       deps     => [ 'grab/ch_bluewin/tv_grab_ch_bluewin' 
-#                              => [ 'grab/ch_bluewin/tv_grab_ch_bluewin.in' ] ],
-#       pl_files => { 'grab/ch_bluewin/tv_grab_ch_bluewin.PL' 
-#                              => 'grab/ch_bluewin/tv_grab_ch_bluewin' },
+#       deps     => [ 'grab/ch_bluewin/tv_grab_ch_bluewin'
+#                               => [ 'grab/ch_bluewin/tv_grab_ch_bluewin.in' ] ],
+#       pl_files => { 'grab/ch_bluewin/tv_grab_ch_bluewin.PL'
+#                               => 'grab/ch_bluewin/tv_grab_ch_bluewin' },
 #       to_clean => [ 'grab/ch_bluewin/tv_grab_ch_bluewin' ],
-#       share_files => { 'grab/ch_bluewin/channel_ids' 
-#                              => 'tv_grab_ch_bluewin/channel_ids' },
+#       share_files => { 'grab/ch_bluewin/channel_ids'
+#                               => 'tv_grab_ch_bluewin/channel_ids' },
 #       grab_need_share => [ 'ch_bluewin' ],
 #       prereqs => { 'HTML::Entities' => 1.27,
-#                  'HTML::TreeBuilder' => 0 },
+#                   'HTML::TreeBuilder' => 0 },
 #     },
-     
+
      { name     => 'tv_grab_ch_search',
-          blurb    => 'Grabber for Switzerland',
-          exes     => [ 'grab/ch_search/tv_grab_ch_search' ],
-          deps     => [ 'grab/ch_search/tv_grab_ch_search' 
-                       => [ 'grab/ch_search/tv_grab_ch_search.in' ] ],
-          pl_files => { 'grab/ch_search/tv_grab_ch_search.PL' 
-                           => 'grab/ch_search/tv_grab_ch_search' },
-          to_clean => [ 'grab/ch_search/tv_grab_ch_search' ],
-#         share_files => { 'grab/ch_search/channel_ids' 
-#                  => 'tv_grab_ch_search/channel_ids' },
-          grab_need_share => [ 'ch_search' ],
-          prereqs  => { 'HTML::Entities' => 1.27,
-               'HTML::TreeBuilder' => 0 },
+           blurb    => 'Grabber for Switzerland',
+           exes     => [ 'grab/ch_search/tv_grab_ch_search' ],
+           deps     => [ 'grab/ch_search/tv_grab_ch_search'
+                        => [ 'grab/ch_search/tv_grab_ch_search.in' ] ],
+           pl_files => { 'grab/ch_search/tv_grab_ch_search.PL'
+                            => 'grab/ch_search/tv_grab_ch_search' },
+           to_clean => [ 'grab/ch_search/tv_grab_ch_search' ],
+#          share_files => { 'grab/ch_search/channel_ids'
+#                   => 'tv_grab_ch_search/channel_ids' },
+           grab_need_share => [ 'ch_search' ],
+           prereqs  => { 'HTML::Entities' => 1.27,
+                'HTML::TreeBuilder' => 0 },
      },
 
      { name => 'tv_grab_dtv_la',
@@ -351,30 +349,66 @@ my @opt_components
      { name => 'tv_grab_uk_rt',
        blurb => 'Grabber for UK and Ireland (Radio Times)',
        exes => [ 'grab/uk_rt/tv_grab_uk_rt' ],
-       pl_files => { 'grab/uk_rt/tv_grab_uk_rt.PL' 
-                        => 'grab/uk_rt/tv_grab_uk_rt' },
-       share_files => { 'grab/uk_rt/channel_ids' 
-                           => 'tv_grab_uk_rt/channel_ids',
-                        'grab/uk_rt/prog_titles_to_process' 
-                           => 'tv_grab_uk_rt/prog_titles_to_process',
-                        'grab/uk_rt/regional_channels_by_postcode' 
-                           => 'tv_grab_uk_rt/regional_channels_by_postcode',
-                        'grab/uk_rt/channels_platforms'
-                           => 'tv_grab_uk_rt/channels_platforms',
-                        'grab/uk_rt/utf8_fixups'
-                           => 'tv_grab_uk_rt/utf8_fixups',
-                        'grab/uk_rt/lineups/freeview.map'
-                           => 'tv_grab_uk_rt/lineups/freeview.map',
-                        'grab/uk_rt/lineups/freesat.map'
-                           => 'tv_grab_uk_rt/lineups/freesat.map', },
-       to_clean => [ 'grab/uk_rt/tv_grab_uk_rt' ],
-       deps => [ 'grab/uk_rt/tv_grab_uk_rt' 
-                    => [ 'grab/uk_rt/tv_grab_uk_rt.in' ] ],
-       grab_need_share => [ 'uk_rt' ],
-       prereqs => { 'HTTP::Cache::Transparent' => 1.0, 
-                    'IO::Stringy' => 0,
+       share_files => {
+            'grab/uk_rt/channel_ids'
+                => 'tv_grab_uk_rt/channel_ids',
+            'grab/uk_rt/prog_titles_to_process'
+                => 'tv_grab_uk_rt/prog_titles_to_process',
+            'grab/uk_rt/regional_channels_by_postcode'
+                => 'tv_grab_uk_rt/regional_channels_by_postcode',
+            'grab/uk_rt/channels_platforms'
+                => 'tv_grab_uk_rt/channels_platforms',
+            'grab/uk_rt/utf8_fixups'
+                => 'tv_grab_uk_rt/utf8_fixups',
+            'grab/uk_rt/channel_icons'
+                => 'tv_grab_uk_rt/channel_icons',
+
+            'grab/uk_rt/lineups/xmltv-lineups.xsl'
+                => 'tv_grab_uk_rt/lineups/xmltv-lineups.xsl',
+
+            'grab/uk_rt/lineups/lineups.xml'
+                => 'tv_grab_uk_rt/lineups/lineups.xml',
+
+            'grab/uk_rt/lineups/freesatfromsky.xml'
+                => 'tv_grab_uk_rt/lineups/freesatfromsky.xml',
+            'grab/uk_rt/lineups/freesathd.xml'
+                => 'tv_grab_uk_rt/lineups/freesathd.xml',
+            'grab/uk_rt/lineups/freesat.xml'
+                => 'tv_grab_uk_rt/lineups/freesat.xml',
+            'grab/uk_rt/lineups/freeviewhd.xml'
+                => 'tv_grab_uk_rt/lineups/freeviewhd.xml',
+            'grab/uk_rt/lineups/freeview.xml'
+                => 'tv_grab_uk_rt/lineups/freeview.xml',
+            'grab/uk_rt/lineups/saorview.xml'
+                => 'tv_grab_uk_rt/lineups/saorview.xml',
+            'grab/uk_rt/lineups/skyhd.xml'
+                => 'tv_grab_uk_rt/lineups/skyhd.xml',
+            'grab/uk_rt/lineups/sky.xml'
+                => 'tv_grab_uk_rt/lineups/sky.xml',
+            'grab/uk_rt/lineups/upcirelandhd.xml'
+                => 'tv_grab_uk_rt/lineups/upcirelandhd.xml',
+            'grab/uk_rt/lineups/upcireland.xml'
+                => 'tv_grab_uk_rt/lineups/upcireland.xml',
+            'grab/uk_rt/lineups/virginhd.xml'
+                => 'tv_grab_uk_rt/lineups/virginhd.xml',
+            'grab/uk_rt/lineups/virgin.xml'
+                => 'tv_grab_uk_rt/lineups/virgin.xml',
+
+            'grab/uk_rt/lineups/freeview.map'
+                => 'tv_grab_uk_rt/lineups/freeview.map',
+            'grab/uk_rt/lineups/freesat.map'
+                => 'tv_grab_uk_rt/lineups/freesat.map',
+            'grab/uk_rt/lineups/saorview.map'
+                => 'tv_grab_uk_rt/lineups/saorview.map',
+       },
+       prereqs => { 'HTTP::Cache::Transparent' => 1.0,
+                    'IO::Stringy'    => 0,
                     'LWP::UserAgent' => 0,
-                    'HTML::Entities' => 1.27 } ,
+                    'DateTime'       => 0,
+                    'DateTime::Duration' => 0,
+                    'DateTime::TimeZone' => 0,
+                    'HTML::Entities' => 1.27,
+                    'XML::LibXML' => 0, },
      },
 
      { name => 'tv_grab_uk_bleb',
@@ -423,7 +457,7 @@ my @opt_components
        exes => [ 'grab/it_dvb/tv_grab_it_dvb' ],
        pl_files => { 'grab/it_dvb/tv_grab_it_dvb.PL' => 'grab/it_dvb/tv_grab_it_dvb' },
        share_files => { 'grab/it_dvb/channel_ids' => 'tv_grab_it_dvb/channel_ids',
-                               'grab/it_dvb/sky_it.dict' => 'tv_grab_it_dvb/sky_it.dict',
+                        'grab/it_dvb/sky_it.dict' => 'tv_grab_it_dvb/sky_it.dict',
                         'grab/it_dvb/sky_it.themes' => 'tv_grab_it_dvb/sky_it.themes',
                    },
        to_clean => [ 'grab/it_dvb/tv_grab_it_dvb' ],
@@ -431,7 +465,7 @@ my @opt_components
        grab_need_share => [ 'it_dvb' ],
        prereqs => { 'Data::Dump' => 0,
                     'IO::Select' => 0,
-                    'Linux::DVB' => 0, 
+                    'Linux::DVB' => 0,
                     'Time::HiRes' => 0 } ,
      },
 
@@ -450,8 +484,8 @@ my @opt_components
        deps     => [ 'grab/na_dd/tv_grab_na_dd' => [ 'grab/na_dd/tv_grab_na_dd.in' ] ],
        to_clean => [ 'grab/na_dd/tv_grab_na_dd' ],
        prereqs => { 'SOAP::Lite' => 0.67,
-                           'Term::ReadKey' => 0,
-                     'XML::Twig' => 3.28,                          },
+                            'Term::ReadKey' => 0,
+                     'XML::Twig' => 3.28,                           },
        grab_need_share => [ 'na_dd' ],
      },
 
@@ -471,38 +505,38 @@ my @opt_components
        blurb    => 'Grabber for Finland',
        exes     => [ 'grab/fi/tv_grab_fi' ],
        deps     => [
-                    'grab/fi/tv_grab_fi' => [
-                                              'grab/fi/tv_grab_fi.pl',
-                                              'grab/fi/fi/common.pm',
-                                              'grab/fi/fi/day.pm',
-                                              'grab/fi/fi/programme.pm',
-                                              'grab/fi/fi/programmeStartOnly.pm',
-                                              'grab/fi/fi/source/mtv3.pm',
-                                              'grab/fi/fi/source/telkku.pm',
-                                              'grab/fi/fi/source/telvis.pm',
-                                              'grab/fi/fi/source/tvnyt.pm',
-                                              'grab/fi/fi/source/yle.pm',
-                                            ],
-                  ],
+                     'grab/fi/tv_grab_fi' => [
+                         'grab/fi/tv_grab_fi.pl',
+                         'grab/fi/fi/common.pm',
+                         'grab/fi/fi/day.pm',
+                         'grab/fi/fi/programme.pm',
+                         'grab/fi/fi/programmeStartOnly.pm',
+                         'grab/fi/fi/source/mtv3.pm',
+                         'grab/fi/fi/source/telkku.pm',
+                         'grab/fi/fi/source/telvis.pm',
+                         'grab/fi/fi/source/tvnyt.pm',
+                         'grab/fi/fi/source/yle.pm',
+                     ],
+                   ],
        pl_files => { 'grab/fi/merge.PL' => 'grab/fi/tv_grab_fi' },
        to_clean => [ 'grab/fi/tv_grab_fi' ],
        prereqs  => {
-                   'HTML::Entities'    => 0,
-                   'HTML::TreeBuilder' => 0,
-                   'JSON'              => 0,
-                   'Time::Local'       => 0,
-                  },
+                    'HTML::TreeBuilder' => 0,
+                    'Time::Local'       => 0,
+                   },
      },
 
-     { name     => 'tv_grab_fi_sv',
-       blurb    => 'Grabber for Finland (Swedish)',
-       exes     => [ 'grab/fi_sv/tv_grab_fi_sv' ],
-       prereqs  => {
-                     'DateTime'    => 0,
-                     'IO::Stringy' => 0,
-                     'XML::LibXML' => 0,
-          },
-     },
+# 2012-03-16 no longer works and maintainer suggests to use _fi now which was extended to
+# provide the swedish guide earlier
+#     { name     => 'tv_grab_fi_sv',
+#       blurb    => 'Grabber for Finland (Swedish)',
+#       exes     => [ 'grab/fi_sv/tv_grab_fi_sv' ],
+#       prereqs  => {
+#                     'DateTime'    => 0,
+#                     'IO::Stringy' => 0,
+#                     'XML::LibXML' => 0,
+#          },
+#     },
 
 # 2009-03-08 removed due to breakage after source site changes
 #     { name => 'tv_grab_es',
@@ -539,7 +573,7 @@ my @opt_components
        prereqs => { 'HTML::TreeBuilder' => 0 },
      },
 
-# 2008-07-12 - removed by rmeden, not getting programs for a while. 
+# 2008-07-12 - removed by rmeden, not getting programs for a while.
 #
 #     { name => 'tv_grab_nl_wolf',
 #       blurb => 'Alternative grabber for the Netherlands',
@@ -550,16 +584,16 @@ my @opt_components
        blurb => 'Grabber for Hungary and Romania',
        exes => [ 'grab/huro/tv_grab_huro' ],
        pl_files => { 'grab/huro/tv_grab_huro.PL'
-                    => 'grab/huro/tv_grab_huro' },
+                     => 'grab/huro/tv_grab_huro' },
        share_files => { 'grab/huro/jobmap' => 'tv_grab_huro/jobmap',
-                                'grab/huro/catmap.hu' => 'tv_grab_huro/catmap.hu',
-                                'grab/huro/catmap.ro' => 'tv_grab_huro/catmap.ro',
-                                'grab/huro/catmap.sk' => 'tv_grab_huro/catmap.sk',
-                                'grab/huro/catmap.cz' => 'tv_grab_huro/catmap.cz',
+                        'grab/huro/catmap.hu' => 'tv_grab_huro/catmap.hu',
+                        'grab/huro/catmap.ro' => 'tv_grab_huro/catmap.ro',
+                        'grab/huro/catmap.sk' => 'tv_grab_huro/catmap.sk',
+                        'grab/huro/catmap.cz' => 'tv_grab_huro/catmap.cz',
                      },
        to_clean => [ 'grab/huro/tv_grab_huro' ],
        deps => [ 'grab/huro/tv_grab_huro'
-                => [ 'grab/huro/tv_grab_huro.in' ] ],
+                 => [ 'grab/huro/tv_grab_huro.in' ] ],
        grab_need_share => [ 'huro' ],
        prereqs => { 'HTML::TreeBuilder' => 0 } },
 
@@ -588,20 +622,20 @@ my @opt_components
      #  blurb => 'Grabber for Japan',
      #  exes => [ 'grab/jp/tv_grab_jp' ],
      #  prereqs => { 'HTML::TreeBuilder' => 0,
-       #           'Text::Kakasi' => 0 } },
+     #               'Text::Kakasi' => 0 } },
 
      { name => 'tv_grab_se_swedb',
        blurb => 'Grabber for Sweden',
        exes => [ 'grab/se_swedb/tv_grab_se_swedb' ],
        pl_files => { 'grab/se_swedb/tv_grab_se_swedb.PL'
-                    => 'grab/se_swedb/tv_grab_se_swedb' },
+                     => 'grab/se_swedb/tv_grab_se_swedb' },
        to_clean => [ 'grab/se_swedb/tv_grab_se_swedb' ],
        deps => [ 'grab/se_swedb/tv_grab_se_swedb'
-                => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
+                 => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
        prereqs => { 'XML::LibXML' => 0,
                     'Compress::Zlib' => 0,
                     'IO::Stringy' => 0,
-                   'HTTP::Cache::Transparent' => 0,
+                    'HTTP::Cache::Transparent' => 0,
                   },
      },
 
@@ -609,14 +643,14 @@ my @opt_components
        blurb => 'Grabber for Croatia',
        exes => [ 'grab/hr/tv_grab_hr' ],
        pl_files => { 'grab/hr/tv_grab_hr.PL'
-                    => 'grab/hr/tv_grab_hr' },
+                     => 'grab/hr/tv_grab_hr' },
        to_clean => [ 'grab/hr/tv_grab_hr' ],
        deps => [ 'grab/hr/tv_grab_hr'
-                => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
+                 => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
        prereqs => { 'XML::LibXML' => 0,
                     'Compress::Zlib' => 0,
                     'IO::Stringy' => 0,
-                   'HTTP::Cache::Transparent' => 0,
+                    'HTTP::Cache::Transparent' => 0,
                   },
      },
 
@@ -624,14 +658,44 @@ my @opt_components
        blurb => 'Grabber for Norway (gfeed.info)',
        exes => [ 'grab/no_gfeed/tv_grab_no_gfeed' ],
        pl_files => { 'grab/no_gfeed/tv_grab_no_gfeed.PL'
-                    => 'grab/no_gfeed/tv_grab_no_gfeed' },
+                     => 'grab/no_gfeed/tv_grab_no_gfeed' },
        to_clean => [ 'grab/no_gfeed/tv_grab_no_gfeed' ],
        deps => [ 'grab/no_gfeed/tv_grab_no_gfeed'
-                => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
+                 => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
+       prereqs => { 'XML::LibXML' => 0,
+                    'Compress::Zlib' => 0,
+                    'IO::Stringy' => 0,
+                    'HTTP::Cache::Transparent' => 0,
+                  },
+     },
+
+     { name => 'tv_grab_eu_egon',
+       blurb => 'Grabber for german speaking area (Egon zappt)',
+       exes => [ 'grab/eu_egon/tv_grab_eu_egon' ],
+       pl_files => { 'grab/eu_egon/tv_grab_eu_egon.PL'
+                     => 'grab/eu_egon/tv_grab_eu_egon' },
+       to_clean => [ 'grab/eu_egon/tv_grab_eu_egon' ],
+       deps => [ 'grab/eu_egon/tv_grab_eu_egon'
+                 => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
        prereqs => { 'XML::LibXML' => 0,
                     'Compress::Zlib' => 0,
                     'IO::Stringy' => 0,
-                   'HTTP::Cache::Transparent' => 0,
+                    'HTTP::Cache::Transparent' => 0,
+                  },
+     },
+
+     { name => 'tv_grab_se_tvzon',
+       blurb => 'Grabber for Sweden (tvzon.se)',
+       exes => [ 'grab/se_tvzon/tv_grab_se_tvzon' ],
+       pl_files => { 'grab/se_tvzon/tv_grab_se_tvzon.PL'
+                     => 'grab/se_tvzon/tv_grab_se_tvzon' },
+       to_clean => [ 'grab/se_tvzon/tv_grab_se_tvzon' ],
+       deps => [ 'grab/se_tvzon/tv_grab_se_tvzon'
+                 => [ 'grab/se_swedb/tv_grab_se_swedb.in' ] ],
+       prereqs => { 'XML::LibXML' => 0,
+                    'Compress::Zlib' => 0,
+                    'IO::Stringy' => 0,
+                    'HTTP::Cache::Transparent' => 0,
                   },
      },
 
@@ -639,7 +703,7 @@ my @opt_components
        blurb => 'Grabber for France',
        exes => [ 'grab/fr/tv_grab_fr' ],
        prereqs => { 'HTML::Entities' => 1.27,
-                   'HTML::TreeBuilder' => 0 },
+                    'HTML::TreeBuilder' => 0 },
      },
 
      { name => 'tv_grab_fr_kazer',
@@ -651,7 +715,7 @@ my @opt_components
 #
 # depreciate tv_grab_no as it is no longer supported (per author, cwattengard@gmail.com)
 # has been replaced by tv_grab_no_gfeed
-# 
+#
 #     { name => 'tv_grab_no',
 #       blurb => 'Grabber for Norway',
 #       exes => [ 'grab/no/tv_grab_no' ],
@@ -662,14 +726,13 @@ my @opt_components
        blurb => 'Grabber for Portugal',
        exes => [ 'grab/pt/tv_grab_pt' ],
        prereqs => { 'HTML::TreeBuilder' => 0,
-                 }
+                  }
      },
 
      { name => 'tv_grab_pt_meo',
        blurb => 'Grabber for Portugal (MEO)',
        exes => [ 'grab/pt_meo/tv_grab_pt_meo' ],
-       prereqs => { 'CGI' => 0,
-                    'DateTime' => 0,
+       prereqs => { 'DateTime' => 0,
                     'XML::LibXML' => 0,
                     'LWP' => 0,
                   },
@@ -704,12 +767,12 @@ my @opt_components
        blurb => 'Program to report exceptions and changes in a schedule',
        exes => [ 'choose/tv_check/tv_check' ],
        docs => [ qw(choose/tv_check/README.tv_check
-                   choose/tv_check/tv_check_doc.html
-                   choose/tv_check/tv_check_doc.jpg
-                  ) ],
+                    choose/tv_check/tv_check_doc.html
+                    choose/tv_check/tv_check_doc.jpg
+                   ) ],
        prereqs => { 'Tk' => 0,
-                   'Tk::TableMatrix' => 0,
-                 } },
+                    'Tk::TableMatrix' => 0,
+                  } },
 
      { name => 'tv_pick_cgi',
        blurb => 'CGI program to filter listings (to install manually)',
@@ -739,16 +802,18 @@ my @opt_components
 #                   'HTML::Entities'    => 0 } },
 
 # rmeden 2011-06-12 not working
-#     { name => 'tv_grab_na_dtv',
-#       blurb => 'Grabber for DirecTV in North America',
-#       exes => [ 'grab/na_dtv/tv_grab_na_dtv' ],
-#       prereqs => {
-#         'WWW::Mechanize' => 0,
-#         'HTML::TokeParser' => 0,
-#         'Date::Parse' => 0,
-#         'Time::Local' => 0
-#       },
-#     },
+# dekarl 2012-01-05 fixed by #3163183
+     { name => 'tv_grab_na_dtv',
+       blurb => 'Grabber for DirecTV in North America',
+       exes => [ 'grab/na_dtv/tv_grab_na_dtv' ],
+       prereqs => {
+         'DateTime'                  => 0,
+         'DateTime::Format::ISO8601' => 0,
+         'JSON'                      => 0,
+         'HTML::TokeParser'          => 0,
+         'WWW::Mechanize'            => 0,
+       },
+     },
 
     );
 
@@ -767,30 +832,30 @@ foreach my $info (@opt_components) {
     our %module_prereqs;
     local *module_prereqs = $info->{prereqs} || {};
     foreach (sort keys %module_prereqs) {
-       my $ver = $module_prereqs{$_};
-       next if test_module($_, $ver)->[0] eq 'OK';
-       warn "strange, module prereq $_ mentioned twice"
-         if defined $modules_missing{$_};
-       $modules_missing{$_} = $ver;
+        my $ver = $module_prereqs{$_};
+        next if test_module($_, $ver)->[0] eq 'OK';
+        warn "strange, module prereq $_ mentioned twice"
+          if defined $modules_missing{$_};
+        $modules_missing{$_} = $ver;
     }
 
     our @special_prereqs;
     my %special_missing;
     local *special_prereqs = $info->{special_prereqs} || {};
     foreach (@special_prereqs) {
-       my ($sub, $name, $ver, $friendly_ver) = @$_;
-       next if test_special($sub, $ver)->[0] eq 'OK';
-       warn "strange, special prereq $name mentioned twice"
-         if defined $special_missing{$name};
-       $special_missing{$name} = $friendly_ver;
+        my ($sub, $name, $ver, $friendly_ver) = @$_;
+        next if test_special($sub, $ver)->[0] eq 'OK';
+        warn "strange, special prereq $name mentioned twice"
+          if defined $special_missing{$name};
+        $special_missing{$name} = $friendly_ver;
     }
-       
+
     my %missing = (%modules_missing, %special_missing);
     if (not keys %missing) {
-       $info->{missing} = 0;
+        $info->{missing} = 0;
     }
     else {
-       $info->{missing} = \%missing;
+        $info->{missing} = \%missing;
     }
 }
 
@@ -822,70 +887,70 @@ END
 
     my $width = 0;
     foreach my $info (@opt_components) {
-       my $w = length("$info->{blurb} ($info->{name})");
-       $width = $w if $w > $width;
+        my $w = length("$info->{blurb} ($info->{name})");
+        $width = $w if $w > $width;
     }
     foreach my $info (@opt_components) {
-       my $missing = $info->{missing};
-       my $s = "$info->{blurb} ($info->{name})";
+        my $missing = $info->{missing};
+        my $s = "$info->{blurb} ($info->{name})";
 
-       # Guess a default value for {install} based on whether
-       # prerequisites were found.
-       #
-       $info->{install} = (not $info->{exclude}) && ($opt_yes || not $info->{missing});
+        # Guess a default value for {install} based on whether
+        # prerequisites were found.
+        #
+        $info->{install} = (not $info->{exclude}) && ($opt_yes || not $info->{missing});
 
-       print STDERR ($s, ' ' x (1 + $width - length $s),
-                     $info->{install} ? '[yes]' : '[no]',
-                     "\n");
+        print STDERR ($s, ' ' x (1 + $width - length $s),
+                      $info->{install} ? '[yes]' : '[no]',
+                      "\n");
     }
     print STDERR "\n";
     if (not ask(0, 'Do you want to proceed with this configuration?', 1)) {
-       # Need to set {install} for each component by prompting.
-       foreach my $info (@opt_components) {
-           my $missing = $info->{missing};
-           my $name = $info->{name};
-           print STDERR "\n* $info->{blurb} ($name)\n\n";
-           if ($missing) {
-               print STDERR "These dependencies are missing for $name:\n\n";
-               foreach (sort keys %$missing) {
-                   print STDERR "$_";
-                   my $min_ver = $missing->{$_};
-                   if ($min_ver) {
-                       print STDERR " (version $min_ver or higher)";
-                   }
-                   print STDERR "\n";
-               }
-               print STDERR "\n";
-           }
-
-           my $msg;
-           my $type = $info->{type};
-           if (not defined $type or $type eq 'install') {
-               $msg = "Do you wish to install $name?";
-           } elsif ($type eq 'run') {
-               $msg = "Do you plan to run $name?";
-           } else {
-               die;
-           }
-       
-           $info->{install} =
-             ask(0, $msg, not $missing);
-       }
+        # Need to set {install} for each component by prompting.
+        foreach my $info (@opt_components) {
+            my $missing = $info->{missing};
+            my $name = $info->{name};
+            print STDERR "\n* $info->{blurb} ($name)\n\n";
+            if ($missing) {
+                print STDERR "These dependencies are missing for $name:\n\n";
+                foreach (sort keys %$missing) {
+                    print STDERR "$_";
+                    my $min_ver = $missing->{$_};
+                    if ($min_ver) {
+                        print STDERR " (version $min_ver or higher)";
+                    }
+                    print STDERR "\n";
+                }
+                print STDERR "\n";
+            }
+
+            my $msg;
+            my $type = $info->{type};
+            if (not defined $type or $type eq 'install') {
+                $msg = "Do you wish to install $name?";
+            } elsif ($type eq 'run') {
+                $msg = "Do you plan to run $name?";
+            } else {
+                die;
+            }
+
+            $info->{install} =
+              ask(0, $msg, not $missing);
+        }
     }
 }
 else {
     my @to_install = split /\s+/, $opt_components;
     my %by_name;
     foreach (@opt_components) {
-       $by_name{$_->{name}} = $_;
-       $_->{install} = 0; # default if not mentioned
+        $by_name{$_->{name}} = $_;
+        $_->{install} = 0; # default if not mentioned
     }
     foreach (@to_install) {
-       my $i = $by_name{$_};
-       die "unknown component $_\n" if not $i;
-       $i->{install} = 1;
+        my $i = $by_name{$_};
+        die "unknown component $_\n" if not $i;
+        $i->{install} = 1;
     }
-}      
+}
 
 foreach my $info (@opt_components) {
     next if not $info->{install};
@@ -923,24 +988,24 @@ sub test_module( $$ ) {
     die if not defined $mod; die if not defined $minver;
     eval "require $mod";
     if ($@) {
-       # This if-test is separate to suppress spurious 'Use of
-       # uninitialized value in numeric lt (<)' warning.
-       #
-       if ($@ ne '') {
-           if ($@ =~ /^Can\'t locate \S+\.pm in \@INC/) {
-               return [ 'NOT_INSTALLED', undef ];
-           }
-           else {
-               chomp (my $msg = $@);
-               return [ 'FAILED', $msg ];
-           }
-       }
+        # This if-test is separate to suppress spurious 'Use of
+        # uninitialized value in numeric lt (<)' warning.
+        #
+        if ($@ ne '') {
+            if ($@ =~ /^Can\'t locate \S+\.pm in \@INC/) {
+                return [ 'NOT_INSTALLED', undef ];
+            }
+            else {
+                chomp (my $msg = $@);
+                return [ 'FAILED', $msg ];
+            }
+        }
     }
 
     my $ver = $mod->VERSION;
     if ($minver ne '0') {
-       return [ 'TOO_OLD', undef ] if not defined $ver;
-       return [ 'TOO_OLD', $ver ] if $ver lt $minver;
+        return [ 'TOO_OLD', undef ] if not defined $ver;
+        return [ 'TOO_OLD', $ver ] if $ver lt $minver;
     }
 
     return [ 'OK', undef ];
@@ -962,8 +1027,8 @@ sub test_special( $$ ) {
     my $ver = $sub->();
     return [ 'NOT_INSTALLED', undef ] if not defined $ver;
     if ($minver ne '0') {
-       return [ 'TOO_OLD', undef ] if not defined $ver;
-       return [ 'TOO_OLD', $ver ] if $ver lt $minver;
+        return [ 'TOO_OLD', undef ] if not defined $ver;
+        return [ 'TOO_OLD', $ver ] if $ver lt $minver;
     }
     return [ 'OK', undef ];
 }
@@ -981,35 +1046,35 @@ foreach my $p ((sort keys %prereqs), (sort keys %recommended)) {
     die "bad minver for $p" if not defined $minver;
     my ($r, $more) = @{test_module($p, $minver)};
     if ($r eq 'OK') {
-       # Installed and recent enough.
+        # Installed and recent enough.
     }
     elsif ($r eq 'NOT_INSTALLED') {
-       print STDERR "Module $p seems not to be installed.\n";
-       print(($minver ? "$p $minver" : $p), " is $verbed.\n");
-       ++ $err if $required;
+        print STDERR "Module $p seems not to be installed.\n";
+        print(($minver ? "$p $minver" : $p), " is $verbed.\n");
+        ++ $err if $required;
     }
     elsif ($r eq 'FAILED') {
-       print STDERR "$Verbed module $p failed to load: $more\n";
-       print(($minver ? "$p $minver" : $p), " is $verbed.\n");
-       ++ $err if $required;
+        print STDERR "$Verbed module $p failed to load: $more\n";
+        print(($minver ? "$p $minver" : $p), " is $verbed.\n");
+        ++ $err if $required;
     }
     elsif ($r eq 'TOO_OLD') {
-       if (defined $more) {
-           print STDERR "$p-$minver is $verbed, but $more is installed\n";
-       }
-       else {
-           print STDERR "$p-$minver is $verbed, but an unknown version is installed\n";
-       }
-       ++ $err if $required;
+        if (defined $more) {
+            print STDERR "$p-$minver is $verbed, but $more is installed\n";
+        }
+        else {
+            print STDERR "$p-$minver is $verbed, but an unknown version is installed\n";
+        }
+        ++ $err if $required;
     }
     else { die }
 }
 if ($err) {
     if ($opt_strictdeps) {
-       die "Required modules missing.  Makefile will not be created.\n";
+        die "Required modules missing.  Makefile will not be created.\n";
     }
     else {
-       warn "Required modules missing, 'make' is unlikely to work\n";
+        warn "Required modules missing, 'make' is unlikely to work\n";
     }
 }
 
@@ -1043,17 +1108,17 @@ sub MY::install {
     #
     my %extra_deps = (install => [ 'plaindoc_install', 'share_install' ]);
     foreach my $t (keys %extra_deps) {
-       foreach my $d (@{$extra_deps{$t}}) {
-           $inherited =~ s/^(\s*$t\s+::\s.+)/$1 $d/m or die;
-       }
+        foreach my $d (@{$extra_deps{$t}}) {
+            $inherited =~ s/^(\s*$t\s+::\s.+)/$1 $d/m or die;
+        }
     }
 
     foreach (qw(plaindoc share)) {
-       my $target = $_ . '_install';
-       my $uc = uc;
+        my $target = $_ . '_install';
+        my $uc = uc;
 
-       my $inst_var = "INST_$uc";
-       my $extra = <<END
+        my $inst_var = "INST_$uc";
+        my $extra = <<END
 # Add code to create the directory under blib/.
 \$($inst_var)/.exists :: \$(PERL_INC)/perl.h
        \@\$(MKPATH) \$($inst_var)
@@ -1068,8 +1133,8 @@ $target ::
 
 END
   ;
-       $extra =~ s/ {8}/\t/g;
-       $inherited .= $extra;
+        $extra =~ s/ {8}/\t/g;
+        $inherited .= $extra;
     }
 
     # Remove existing non-working 'uninstall' target.
@@ -1079,24 +1144,24 @@ END
     # For each *_install create a corresponding _uninstall.
     my $targets = ::targets($inherited);
     foreach (qw(pure_perl_install pure_site_install plaindoc_install share_install)) {
-       die "no $_ in: $inherited" if not defined $targets->{$_};
-       my @t = @{$targets->{$_}}; # make a copy
-       my $done = 0;
-       foreach (@t) {
-           if (s/\@\$\(MOD_INSTALL\)/\$(PERL) -I. -MUninstall -e "uninstall(\@ARGV)"/) {
-               $done = 1;
-               last;
-           }
-           s/Installing contents of (\S+) into (\S+)/Removing contents of $1 from $2/;
-       }
-       if (not $done) {
-           print STDERR "couldn't find \@\$(MOD_INSTALL) in target $_, uninstall may not work\n"
-             unless $warned_uninstall_broken;
-       }
-       (my $new_target = $_) =~ s/install$/uninstall/ or die;
-       foreach ("\n\n$new_target ::\n", @t) {
-           $inherited .= $_;
-       }
+        die "no $_ in: $inherited" if not defined $targets->{$_};
+        my @t = @{$targets->{$_}}; # make a copy
+        my $done = 0;
+        foreach (@t) {
+            if (s/\@\$\(MOD_INSTALL\)/\$(PERL) -I. -MUninstall -e "uninstall(\@ARGV)"/) {
+                $done = 1;
+                last;
+            }
+            s/Installing contents of (\S+) into (\S+)/Removing contents of $1 from $2/;
+        }
+        if (not $done) {
+            print STDERR "couldn't find \@\$(MOD_INSTALL) in target $_, uninstall may not work\n"
+              unless $warned_uninstall_broken;
+        }
+        (my $new_target = $_) =~ s/install$/uninstall/ or die;
+        foreach ("\n\n$new_target ::\n", @t) {
+            $inherited .= $_;
+        }
     }
     $inherited .= 'pure_uninstall :: pure_$(INSTALLDIRS)_uninstall' . "\n";
     $inherited .= 'uninstall :: all pure_uninstall plaindoc_uninstall share_uninstall' . "\n";
@@ -1149,7 +1214,7 @@ windows_dist ::
         #
        perl -MExtUtils::Command -e rm_rf $location/bin/ $location/lib/ $(INSTMANDIR) $(INSTALLMAN3DIR)
        perl -MExtUtils::Command -e cp xmltv.dtd $location
-       perl -MExtUtils::Command -e cp xmltv-lineup.dtd $location
+       perl -MExtUtils::Command -e cp xmltv-lineups.xsd $location
        perl -MExtUtils::Command -e cp ChangeLog $location/ChangeLog.txt
        # The following command will not be necessary when the source
        # tree was checked out on a DOSish system.  It may not even
@@ -1179,69 +1244,69 @@ sub MY::installbin {
     # Add a target for each documentation file.
     my %doc_files;
     foreach (@::docs) {
-       $doc_files{$_} = File::Basename::basename($_);
+        $doc_files{$_} = File::Basename::basename($_);
     }
 
     my %new_filetypes = (plaindoc => \%doc_files, share => \%share_files);
     my %seen_dir;
     foreach my $filetype (sort keys %new_filetypes) {
-       my $uc = uc $filetype;
-       our %files; local *files = $new_filetypes{$filetype};
-       foreach my $src (sort keys %files) {
-           my $inst_pos = $files{$src};
-           my $extra = '';
-
-           # The directory containing this file in blib/ needs to be created.
-           my @dirs = split m!/!, $inst_pos; pop @dirs;
-           foreach (0 .. $#dirs) {
-               my $dir = join('/', @dirs[0 .. $_]);
-               my $parent = join('/', @dirs[0 .. $_-1]);
-               next if $seen_dir{$dir}++;
-               die if (length $parent and not $seen_dir{$parent});
-               my $parent_exists = "\$(INST_$uc)/$parent/.exists";
-               $parent_exists =~ tr!/!/!s;
-               $extra .= <<END
+        my $uc = uc $filetype;
+        our %files; local *files = $new_filetypes{$filetype};
+        foreach my $src (sort keys %files) {
+            my $inst_pos = $files{$src};
+            my $extra = '';
+
+            # The directory containing this file in blib/ needs to be created.
+            my @dirs = split m!/!, $inst_pos; pop @dirs;
+            foreach (0 .. $#dirs) {
+                my $dir = join('/', @dirs[0 .. $_]);
+                my $parent = join('/', @dirs[0 .. $_-1]);
+                next if $seen_dir{$dir}++;
+                die if (length $parent and not $seen_dir{$parent});
+                my $parent_exists = "\$(INST_$uc)/$parent/.exists";
+                $parent_exists =~ tr!/!/!s;
+                $extra .= <<END
 \$(INST_$uc)/$dir/.exists :: \$(PERL_INC)/perl.h $parent_exists
        \@\$(MKPATH) \$(INST_$uc)/$dir
        \@\$(EQUALIZE_TIMESTAMP) \$(PERL_INC)/perl.h \$(INST_$uc)/$dir/.exists
        -\@\$(CHMOD) \$(PERM_RWX) \$(INST_$uc)/$dir
 END
   ;
-           }
-           my $dir_exists = "\$(INST_$uc)/" . join('/', @dirs) . '/.exists';
-           $dir_exists =~ tr!/!/!s;
+            }
+            my $dir_exists = "\$(INST_$uc)/" . join('/', @dirs) . '/.exists';
+            $dir_exists =~ tr!/!/!s;
 
-           $extra .= <<END
+            $extra .= <<END
 \$(INST_$uc)/$inst_pos: $src Makefile $dir_exists
        \@\$(RM_F) \$(INST_$uc)/$inst_pos
        perl -MExtUtils::Command -e cp $src \$(INST_$uc)/$inst_pos
        -\@\$(CHMOD) \$(PERM_RW) \$(INST_$uc)/$inst_pos
 END
-             ;
-           $extra =~ s/ {8}/\t/g;
-           $inherited .= $extra;
-       }
+              ;
+            $extra =~ s/ {8}/\t/g;
+            $inherited .= $extra;
+        }
 
-       # These targets need to be added to pure_all, using a new target
-       # pure_$filetype.
-       #
-       $inherited =~ s/^(\s*pure_all\s+::\s.+)/$1 pure_$filetype/m
-         or die "no pure_all in: $inherited";
-       $inherited .= "pure_$filetype :: ";
-       foreach (sort keys %files) {
-           my $inst_pos = $files{$_};
-           $inherited .= "\$(INST_$uc)/$inst_pos ";
-       }
-       $inherited .= "\n\t\@\$(NOOP)\n";
-       
-       # And realclean should remove them, by calling realclean_$filetype.
-       $inherited =~ s/^(\s*realclean\s+::\s[^\\]+)/$1 realclean_$filetype /m or die;
-       $inherited .= "realclean_$filetype ::\n\t\$(RM_F) ";
-       foreach (sort keys %files) {
-           my $inst_pos = $files{$_};
-           $inherited .= "\$(INST_$uc)/$inst_pos ";
-       }
-       $inherited .= "\n";
+        # These targets need to be added to pure_all, using a new target
+        # pure_$filetype.
+        #
+        $inherited =~ s/^(\s*pure_all\s+::\s.+)/$1 pure_$filetype/m
+          or die "no pure_all in: $inherited";
+        $inherited .= "pure_$filetype :: ";
+        foreach (sort keys %files) {
+            my $inst_pos = $files{$_};
+            $inherited .= "\$(INST_$uc)/$inst_pos ";
+        }
+        $inherited .= "\n\t\@\$(NOOP)\n";
+
+        # And realclean should remove them, by calling realclean_$filetype.
+        $inherited =~ s/^(\s*realclean\s+::\s[^\\]+)/$1 realclean_$filetype /m or die;
+        $inherited .= "realclean_$filetype ::\n\t\$(RM_F) ";
+        foreach (sort keys %files) {
+            my $inst_pos = $files{$_};
+            $inherited .= "\$(INST_$uc)/$inst_pos ";
+        }
+        $inherited .= "\n";
     }
 
     return $inherited;
@@ -1265,9 +1330,9 @@ sub MY::processPL {
     # Add some exra dependencies.
     my ($k, $v);
     while (@deps) {
-       ($k, $v, @deps) = @deps;
-       $inherited =~ s!^(\s*$k\s+::\s.+)!"$1 " . join(' ', @$v)!me
-         or die "no $k in: $inherited";
+        ($k, $v, @deps) = @deps;
+        $inherited =~ s!^(\s*$k\s+::\s.+)!"$1 " . join(' ', @$v)!me
+          or die "no $k in: $inherited";
     }
 
     # And some of the .in generators need the share/ directory passed
@@ -1276,17 +1341,17 @@ sub MY::processPL {
     # no $(DESTDIR).
     #
     foreach (@grab_need_share) {
-       $inherited =~
-         s<(grab/$_/tv_grab_$_.PL grab/$_/tv_grab_$_)\s*$>
-           <$1 \$(PREFIX)/share/xmltv>m
-           or die "no call to $_.PL in: $inherited";
+        $inherited =~
+          s<(grab/$_/tv_grab_$_.PL grab/$_/tv_grab_$_)\s*$>
+            <$1 \$(PREFIX)/share/xmltv>m
+            or die "no call to $_.PL in: $inherited";
     }
 
     foreach (@need_share) {
-       $inherited =~
-         s<($_.PL $_)\s*$>
-           <$1 \$(PREFIX)/share/xmltv>m
-           or die "no call to $_.PL in: $inherited";
+        $inherited =~
+          s<($_.PL $_)\s*$>
+            <$1 \$(PREFIX)/share/xmltv>m
+            or die "no call to $_.PL in: $inherited";
     }
 
 
@@ -1303,11 +1368,11 @@ sub MY::makefile {
 sub MY::manifypods {
     package MY;
     for (my $inherited = shift->SUPER::manifypods(@_)) {
-       foreach my $s (qw(Grab_XML DST Config_file Get_nice Mode Summarize Gunzip GUI Date Supplement)) {
-           s!\$\(INST_MAN3DIR\)/(?:grab::|)$s[.]\$\(MAN3EXT\)!"\$(INST_MAN3DIR)/XMLTV::$s.\$(MAN3EXT)"!;
-           s!\$\(INSTALLMAN3DIR\)/$s.\$\(MAN3EXT\)!"\$(INSTALLMAN3DIR)/XMLTV::$s.\$(MAN3EXT)"!;
-       }
-       return $_;
+        foreach my $s (qw(Grab_XML DST Config_file Get_nice Mode Summarize Gunzip GUI Date Supplement)) {
+            s!\$\(INST_MAN3DIR\)/(?:grab::|)$s[.]\$\(MAN3EXT\)!"\$(INST_MAN3DIR)/XMLTV::$s.\$(MAN3EXT)"!;
+            s!\$\(INSTALLMAN3DIR\)/$s.\$\(MAN3EXT\)!"\$(INSTALLMAN3DIR)/XMLTV::$s.\$(MAN3EXT)"!;
+        }
+        return $_;
     }
 }
 
@@ -1318,26 +1383,26 @@ sub targets( $ ) {
     my %r;
     my $curr_target;
     foreach (@lines) {
-       if (/^(\S+)\s+:/) {
-           # Beginning of a new target.
-           my $name = $1;
-           die "target $name seen twice" if defined $r{$name};
-           $r{$name} = $curr_target = [];
-       }
-       elsif (/^\s+/ and defined $curr_target) {
-           # Commands for the target.
-           push @$curr_target, $_;
-       }
+        if (/^(\S+)\s+:/) {
+            # Beginning of a new target.
+            my $name = $1;
+            die "target $name seen twice" if defined $r{$name};
+            $r{$name} = $curr_target = [];
+        }
+        elsif (/^\s+/ and defined $curr_target) {
+            # Commands for the target.
+            push @$curr_target, $_;
+        }
         elsif (/^$/) {
             # Blank lines are legal in a target definition
         }
-       elsif (/^\s*(?:\#.*)?$/) {
-           undef $curr_target;
-       }
-       else {
-           chomp;
-           die "bad makefile line: '$_'";
-       }
+        elsif (/^\s*(?:\#.*)?$/) {
+            undef $curr_target;
+        }
+        else {
+            chomp;
+            die "bad makefile line: '$_'";
+        }
     }
     return \%r;
 }
diff --git a/README b/README
index 37ff47e..8b005dc 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-XMLTV 0.5.61
+XMLTV 0.5.62
 
 Gather television listings, process them and organize your viewing.
 XMLTV is a file format for storing TV listings, defined in xmltv.dtd.
@@ -10,13 +10,11 @@ and xmltv.dtd for documentation on the file format.
 Progress is being made for a 1.0 release.  We've really been stable for
 a while I and consider it well overdue. 
 
-* Changes in this release (0.5.61)
+* Changes in this release (0.5.62)
 
-       tv_grab_re     - disable broken grabber
-       tv_grab_na_dtv - disable broken grabber
-       tv_grab_fr_kazer - new graber for Kazer.org
-       tv_grab_ar      - rewrite! back in distro
-       tv_grab_fi      - rewrite! back in distro
+       xmltv.dtd: Add a lang attribute to review elements
+       tv_grab_uk_rt  improved unicode handling
+       tv_grab_pt_meo and tv_grab_eu-epgdata added back to xmltv.exe
     lots of grabber updates.  See Changelog for details
 
 And some bugfixes and polish.
@@ -66,6 +64,7 @@ HTTP::Cookies            (if you want to run tv_grab_br_net)
 IO::File                 (if you want to run tv_grab_fr)
 IO::Scalar               (if you want to run tv_grab_uk_bleb, tv_grab_in)
 IO::Stringy              (if you want to run tv_grab_se_swedb)
+JSON                     (if you want to run tv_grab_fi)
 Parse::RecDescent        (if you want to run tv_grab_dk_dr)
 SOAP::Lite               (if you want to run tv_grab_na_dd)
 Term::ReadKey            (if you want to run tv_grab_na_dd)
@@ -130,5 +129,5 @@ project 'XMLTV'.  There are some mailing lists:
 You ought to subscribe to the announce list at least.  Contact the
 users list with most problems.
 
--- Robert Eden, rmeden@yahoo.com, 2011-06-22
-$Id: README,v 1.165 2011/06/22 06:08:48 rmeden Exp $
+-- Robert Eden, rmeden@yahoo.com, 2012-06-10
+$Id: README,v 1.167 2012/06/10 17:10:48 rmeden Exp $
index 792d0bb..6cf3816 100644 (file)
@@ -1,4 +1,4 @@
-XMLTV 0.5.61, Windows binary release
+XMLTV 0.5.62, Windows binary release
 
 Gather television listings, process them and organize your viewing.
 XMLTV is a file format for storing TV listings, defined in xmltv.dtd.
@@ -25,18 +25,13 @@ tv_grab_se_swedb sometimes fails to work on Windows if there are spaces
 in the path to your home-directory. This can be avoided by setting
 the environment variable HOME to a path without spaces (e.g. c:\home).
 
-tv_grab_eu_epgdata has been removed from the Win32 release because adding it
-would grow XMLTV.EXE by 5mb. 
-
 Progress is being made for a 1.0 release.  We've really been stable for
 a while I and consider it well overdue. 
 
-* Changes in this release (0.5.61)
-       tv_grab_re     - disable broken grabber
-        tv_grab_na_dtv - disable broken grabber
-        tv_grab_fr_kazer - new graber for Kazer.org
-        tv_grab_ar      - rewrite! back in distro
-        tv_grab_fi      - rewrite! back in distro
+* Changes in this release (0.5.62)
+       xmltv.dtd: Add a lang attribute to review elements
+       tv_grab_uk_rt  improved unicode handling
+       tv_grab_pt_meo and tv_grab_eu-epgdata added back to xmltv.exe
     lots of grabber updates.  See Changelog for details
 
 And some bugfixes and polish. 
@@ -126,5 +121,5 @@ Sourceforge also hosts the following mailing lists
     xmltv-users    - how to use XMLTV
     xmltv-devel    - detailed discussions among developers
 
--- Robert Eden, rmeden@yahoo.com, 2011-06-22
-$Id: README.win32,v 1.94 2011/06/22 06:08:48 rmeden Exp $
+-- Robert Eden, rmeden@yahoo.com, 2012-06-10
+$Id: README.win32,v 1.96 2012/06/10 17:10:48 rmeden Exp $
index 946614d..9edae60 100755 (executable)
@@ -150,7 +150,7 @@ Jerry Veldhuis, jerry@matilda.com
 =cut
 
 use strict;
-use XMLTV::Version '$Id: tv_imdb,v 1.23 2004/03/22 22:01:14 epaepa Exp $ ';
+use XMLTV::Version '$Id: tv_imdb,v 1.24 2011/06/22 19:07:07 dekarl Exp $ ';
 use Data::Dumper;
 use Getopt::Long;
 
@@ -313,7 +313,10 @@ sub programme_cb( $ ) {
 XMLTV::parsefiles_callback(\&encoding_cb, \&credits_cb,
                           \&channel_cb, \&programme_cb,
                           @ARGV);
-$w->end();
+# we only get a Writer if the encoding callback gets called
+if ( $w ) {
+    $w->end();
+}
 
 if ( $opt_stats ) {
     print STDERR $imdb->getStatsLines($numberOfSeenChannels);
index 474f01a..e736f66 100755 (executable)
@@ -28,7 +28,8 @@ Ed Avis, ed@membled.com
 =cut
 
 use strict;
-use XMLTV::Version '$Id: tv_to_text,v 1.4 2003/06/29 15:53:51 epaepa Exp $ ';
+use warnings;
+use XMLTV::Version '$Id: tv_to_text,v 1.5 2012/02/21 19:37:20 dekarl Exp $ ';
 use IO::File;
 use Date::Manip; Date_Init('TZ=UTC');
 use POSIX 'tmpnam';
index 28c81b9..8cd3757 100755 (executable)
-#!/usr/bin/perl
-
-=pod
-
-=head1 NAME
-
-tv_grab_ch_search - Grab TV listings for Switzerland (from tv.search.ch webpage).
-
-=head1 SYNOPSIS
-
-tv_grab_ch_search --help
-
-tv_grab_ch_search [--config-file FILE] --configure [--gui OPTION]
-
-tv_grab_ch_search [--config-file FILE] [--output FILE] [--quiet]
-           [--days N] [--offset N]
-
-tv_grab_ch_search --list-channels
-
-tv_grab_ch_search --capabilities
-
-tv_grab_ch_search --version
-
-=head1 DESCRIPTION
-
-Output TV listings for several channels available in Switzerland and
-(partly) central Europe. 
-The data comes from tv.search.ch. The grabber relies on
-parsing HTML so it might stop working at any time.
-
-First run B<tv_grab_ch_search --configure> to choose, which channels 
-you want to download. Then running B<tv_grab_ch_search> with no 
-arguments will output listings in XML format to standard output.
-
-B<--configure> Ask for each available channel whether to download
-and write the configuration file.
-
-B<--config-file FILE> Set the name of the configuration file, the
-default is B<~/.xmltv/tv_grab_ch_search.conf>.  This is the file 
-written by B<--configure> and read when grabbing.
-
-B<--gui OPTION> Use this option to enable a graphical interface to be used.
-OPTION may be 'Tk', or left blank for the best available choice.
-Additional allowed values of OPTION are 'Term' for normal terminal output
-(default) and 'TermNoProgressBar' to disable the use of Term::ProgressBar.
-
-B<--output FILE> Write to FILE rather than standard output.
-
-B<--days N> Grab N days.  The default is fourteen.
-
-B<--offset N> Start N days in the future.  The default is to start
-from now on (= zero).
-
-B<--quiet> Suppress the progress messages normally written to standard
-error.
-
-B<--list-channels> Write output giving <channel> elements for every
-channel available (ignoring the config file), but no programmes.
-
-B<--capabilities> Show which capabilities the grabber supports. For more
-information, see L<http://wiki.xmltv.org/index.php/XmltvCapabilities>
-
-B<--version> Show the version of the grabber.
-
-B<--help> print a help message and exit.
-
-
-=head1 SEE ALSO
-
-L<xmltv(5)>.
-
-=head1 AUTHOR
-
-Daniel Bittel <betlit@gmx.net>. Inspired by tv_grab_ch by Stefan Siegl.
-
-=head1 BUGS
-
-If you happen to find a bug, you're requested to send a mail to me
-at B<betlit@gmx.net> or to one of the XMLTV mailing lists, see webpages
-at http://sourceforge.net/projects/xmltv/.
-
-=cut
-
-use warnings;
-use strict;
-use Date::Manip;
-use LWP::Simple;
-use HTTP::Cookies;
-use XMLTV::Version '$Id: tv_grab_ch_search.in,v 1.14 2010/10/26 08:43:10 betlit Exp $ ';
-use XMLTV::Capabilities qw/baseline manualconfig cache/;
-use XMLTV::Description 'Switzerland (tv.search.ch)';
-use XMLTV::Supplement qw/GetSupplement/;
-use Getopt::Long;
-use HTML::TreeBuilder;
-use HTML::Entities;
-use URI::Escape;
-use XMLTV;
-use XMLTV::Ask;
-use XMLTV::ProgressBar;
-use XMLTV::DST;
-use XMLTV::Config_file;
-use XMLTV::Mode;
-use XMLTV::Get_nice;
-use XMLTV::Memoize;
-use XMLTV::Usage<<END
-$0: get Swiss television listings from tv.search.ch in XMLTV format
-To configure: $0 --configure [--config-file FILE] [--gui OPTION]
-To grab data: $0 [--config-file FILE] [--output FILE] [--quiet]
-                 [--days N] [--offset N]
-Channel List: $0 --list-channels
-To show capabilities: $0 --capabilities
-To show version: $0 --version
-
-END
-  ;
-
-# Use Log::TraceMessages if installed.
-BEGIN {
-    eval { require Log::TraceMessages };
-    if ($@) {
-        *t = sub {};
-        *d = sub { '' };
-    }
-    else {
-        *t = \&Log::TraceMessages::t;
-        *d = \&Log::TraceMessages::d;
-    }
-}
-
-
-
-## our own prototypes first ...
-sub get_channels();
-sub channel_id($);
-sub get_page($);
-sub grab_channel($);
-
-## attributes of xmltv root element
-my $head = { 
-    'source-data-url'      => 'http://tv.search.ch/channels.de.html',
-    'source-info-url'      => 'http://tv.search.ch/index.de.html',
-    'generator-info-name'  => 'XMLTV',
-    'generator-info-url'   => 'http://xmltv.org/',
-};
-
-
-
-## the timezone tv.search.ch lives in is, CET/CEST
-my constant $TZ = "+0100";
-my constant $lang = "de";
-
-
-
-## Parse argv now.  First do undocumented --cache option.
-XMLTV::Memoize::check_argv('XMLTV::Get_nice::get_nice_aux');
-
-
-
-my $opt_configure;
-my $opt_config_file;
-my $opt_gui;
-my $opt_output;
-my $opt_days = 14;
-my $opt_offset = 0;
-my $opt_quiet = 0;
-my $opt_slow = 0;
-my $opt_list_channels;
-my $opt_help;
-
-GetOptions(
-    'configure'      => \$opt_configure,
-    'config-file=s'  => \$opt_config_file,
-    'gui:s'          => \$opt_gui,
-    'output=s'       => \$opt_output,
-    'days=i'         => \$opt_days,
-    'offset=i'       => \$opt_offset,
-    'quiet'          => \$opt_quiet,
-    'slow'           => \$opt_slow,    
-    'list-channels'  => \$opt_list_channels,
-    'help'           => \$opt_help,
-) or usage(0);
-
-usage(1) if $opt_help;
-
-XMLTV::Ask::init($opt_gui);
-
-## make sure offset+days arguments are within range
-die "neither offset nor days may be negative"
-  if($opt_offset < 0 || $opt_days < 0);
-
-
-## calculate global start/stop times ...
-my $grab_start = DateCalc("00:00:00", "+ $opt_offset days");
-my $grab_stop = DateCalc($grab_start, "+ $opt_days days");
-
-
-my $mode = XMLTV::Mode::mode('grab', # default value
-    $opt_configure     => 'configure',
-    $opt_list_channels => 'list-channels',
-);
-
-
-
-## initialize config file support
-my $config_file = XMLTV::Config_file::filename($opt_config_file, 'tv_grab_ch_search', $opt_quiet);
-my @config_lines;
-
-if($mode eq 'configure') {
-    XMLTV::Config_file::check_no_overwrite($config_file);
-} 
-elsif($mode eq 'grab' || $mode eq 'list-channels') {
-    @config_lines = XMLTV::Config_file::read_lines($config_file);
-} 
-else { die("never heard of XMLTV mode $mode, sorry :-(") }
-
-
-
-## hey, we can't live without channel data, so let's get those now!
-my $bar = new XMLTV::ProgressBar( 'getting list of channels', 1 )
-    if not $opt_quiet;
-
-my %channels = get_channels();
-$bar->update() if not $opt_quiet;
-$bar->finish() if not $opt_quiet;
-
-
-my @requests;
-
-## read our configuration file now
-my $line = 1;
-foreach(@config_lines) {
-    $line ++;
-    next unless defined;
-
-    if (/^channel:?\s+(\S+)/) {
-       warn("\nConfigured channel $1 not available anymore. \nPlease reconfigure tv_grab_ch_search.\n"),
-         next unless(defined($channels{$1}));
-       push @requests, $1;
-    } 
-    else {
-       warn "$config_file:$line: bad line\n";
-    }
-}
-
-## if we're requested to do so, write out a new config file ...
-if ($mode eq 'configure') {
-    open(CONFIG, ">$config_file") or die("cannot write to $config_file, due to: $!");
-
-    ## now let's annoy the user, sorry, I meant ask ..
-    my @chs = sort keys %channels;
-    my @names = map { $channels{$_} } @chs;
-    my @qs = map { "add channel $_?" } @names;
-    my @want = ask_many_boolean(1, @qs);
-
-    foreach (@chs) {
-       my $w = shift @want;
-       my $chname = shift @names;
-       
-       warn("cannot read input, stopping to ask questions ..."), last if not defined $w;
-
-       print CONFIG '#' if not $w; #- comment line out if user answer 'no'
-
-       # shall we store the display name in the config file?
-       # leave it in, since it probably makes it a lot easier for the
-       # user to choose which channel to comment/uncommet - when manually
-       # viing the config file -- are there people who do that?
-       print CONFIG "channel $_ #$chname\n";
-    }
-
-    close CONFIG or warn "unable to nicely close the config file: $!";
-    say("Finished configuration.");
-
-    exit();
-}
-
-
-
-## well, we don't have to write a config file, so, probably it's some xml stuff :)
-## if not, let's go dying ...
-die unless($mode eq 'grab' or $mode eq 'list-channels');
-
-my %writer_args;
-if (defined $opt_output) {
-    my $handle = new IO::File(">$opt_output");
-    die "cannot write to output file, $opt_output: $!" unless (defined $handle);
-    $writer_args{'OUTPUT'} = $handle;
-}
-
-$writer_args{'encoding'} = 'ISO-8859-1';
-
-
-if( defined( $opt_days )) {
-    $writer_args{offset} = $opt_offset;
-       $writer_args{days} = $opt_days;
-       $writer_args{cutoff} = "000000";
-}
-
-## create our writer object
-my $writer = new XMLTV::Writer(%writer_args);
-$writer->start($head);
-
-
-
-if ($mode eq 'list-channels') {
-    foreach (keys %channels) {
-        my %channel = ('id'           => channel_id($_), 
-                       'display-name' => [[$channels{$_}, $lang]]); 
-        $writer->write_channel(\%channel);
-    }
-
-    $writer->end();
-    exit();
-}
-
-
-
-## there's only one thing, why we might exist: write out tvdata!
-die unless ($mode eq 'grab');
-die "No channels specified, run me with --configure flag\n" unless(scalar(@requests));
-
-
-
-## write out <channel> tags
-my $paramstr ="";
-foreach(@requests) {
-    my $id = channel_id($_);
-    my %channel = ('id'           => $id, 
-                   'display-name' => [[$channels{$_}, $lang]]); 
-    $writer->write_channel(\%channel);
-     $paramstr = $paramstr."&channel[]=".$_; 
-
-}
-
-
-## the page doesn't specify the year when the programmes begin or end, thus
-## we need to guess, store current year and month globally as needed for every
-## programme ...
-my ($cur_year, $cur_month) = ParseDate('now') =~ m/(....)(..)/;
-
-my $url=$head->{q(source-data-url)};
-
-       
-my $ua = LWP::UserAgent->new(keep_alive => 300);       
-$ua->cookie_jar(HTTP::Cookies->new());
-$ua->agent("xmltv/$XMLTV::VERSION");
-$ua->env_proxy;
-       
-my $req = HTTP::Request->new(POST => $url);
-$req->content_type('application/x-www-form-urlencoded');
-$req->content(substr ( $paramstr, 1));
-
-# FIXME what is this request doing? It fills the cookie jar
-$ua->request($req);
-$ua->request($req);
-
-## write out <programme> tags
-grab_channels();
-
-## hey, looks like we've finished ...
-$writer->end();
-
-
-## channel_id($s) :: turn site channel id into an xmltv id
-sub channel_id($) {  
-    my $s = shift;
-    #for (my $s = shift) {
-    #$_ = lc(defined($chid_mapping{$_}) ? $chid_mapping{$_} : "$_.search.ch");
-       #$_ = "C$_" if /^\d/;
-       #return $_;
-    #}
-    $s =~ s|^tv_||;
-    return "$s.search.ch"
-}
-
-
-
-sub grab_channels
-{
- my $grabDate = $grab_start;
- my $url = $head->{q(source-info-url)};
- $bar = new XMLTV::ProgressBar('grabbing channels       ', (6*$opt_days))
-  if not $opt_quiet;
-
- grab_channel_loop:
- for (my $count = 0; $count < 6; $count++) 
- {
-  my $tb = HTML::TreeBuilder->new();
-
-  my $loop_date = substr($grabDate,0,4) . '-' . substr($grabDate,4,2) . '-' . substr($grabDate,6,2);
-
-  my $req = HTTP::Request->new(GET => "$url?time=$loop_date+" . 4*$count .".00");
-  $req->header('Accept' => 'text/html');
-    
-  $tb->parse(($ua->request($req))->content)
-      or die "cannot parse content of http://tv.search.ch/?time=$loop_date+" . 4*$count .".00"; ;    
-  $tb->eof;
-    
-
-  foreach my $tv_channel ( $tb->look_down('_tag' => 'div', 'class' => 'tv_channel') )
-  {
-   my $channel_id = $tv_channel->attr('id');
-   if ( defined($channel_id) )
-   {
-    foreach my $tv_show ( $tv_channel ->look_down('_tag' => 'tr', sub { ($_[0]->as_HTML() =~ m{tv_b_}) && !($_[0]->as_HTML() =~ m{tv_before})  && !($_[0]->as_HTML() =~ m{tv_timegroup}) } ) )
-    {
-     my %show;
-     $show{channel} = channel_id($channel_id);
-     my $tmp = substr($grabDate,0,4) . substr($grabDate,4,2) .  substr($grabDate,6,2) .(($tv_show->look_down('_tag', 'td'))[0])->as_text();
-     $tmp =~ s/://;
-     my $start = "$tmp"."00 $TZ";
-     $show{start} = $start;
-     $tmp  = $tv_show->as_HTML();
-     if ( $tmp =~ /Untertitel für Gehörlose/)
-     {
-      $show{subtitles} = [{ type => 'teletext' }];
-     }
-     if ( $tmp =~ /Zweikanalton/)
-     {
-      $show{audio}{stereo} = 'bilingual';
-     }
-     if ( $tmp =~ /16:9/)
-     {
-      $show{video}{aspect} = '16:9';
-     }  
-     
-     foreach my $div ( $tv_show->look_down('_tag' => 'div', 
-               sub {
-                       ( ( $_[0]->attr ('class') eq "tv_tooltip") || ( $_[0]->attr ('class') eq "tv_tr_notooltip" ) )
-                   } )
-            )
-     {
-      if ( $div->attr ('class') eq 'tv_tr_notooltip' )
-      {
-             $show{'title'} = [[$div->as_text(), $lang]]; 
-      }
-      else
-      {
-      
-       my $title = (($div->look_down('_tag' => 'td', 'class' => 'title'))->look_down('_tag' => 'h2'))->as_text();
-       my $sub_title = ($div->look_down('_tag' => 'td', 'class' => 'title'))->as_text();
-
-       $sub_title =~ s/\Q$title \E//;
-       if ( "$title" eq "$sub_title" )
-       {
-        $sub_title ="";
-       } 
-
-       foreach  my $year ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Produktionsjahr<\/th>} } ) )
-       {
-        $show{date} =  (($year->look_down('_tag', 'td'))->as_text());        
-       }
-       
-       foreach  my $category ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Kategorie<\/th>} } ) )
-          {
-        my $s =  (($category->look_down('_tag', 'td'))->as_text());        
-        my @categories = split(m/\s*[\/]\s*/, $s);
-        foreach ( @categories )
-        {
-         if ( $_ )
-         {
-          push @{$show{category}}, [$_, $lang ];
-         }
-        }
-          }
-          
-          foreach  my $category ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Produktionsinfos<\/th>} } ) )
-       {
-        my $s = (($category->look_down('_tag', 'td'))->as_text());        
-        $s=~ s/\(.*//;
-        my @categories = split(m/\s*[\/,]\s*/, $s);
-        foreach my $category ( @categories )
-        {
-         if ( $category )
-         {
-          my $is_defined = 0;
-                 foreach ( @{$show{category}} )
-                 {
-                   if ("${$_}[0]" eq "$category" )
-                   {
-                    $is_defined = 1;
-                    last;
-                   }
-                 }
-                 if ( $is_defined == 0 )
-                 {
-                       push @{$show{category}}, [$category, $lang ];
-                 }               
-         }
-        }
-       }          
-       
-
-          foreach  my $country ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Produktionsland<\/th>} } ) )
-       {
-        my $s =  (($country->look_down('_tag', 'td'))->as_text());        
-        my @countries = split(m/\s*[\/,]\s*/, $s);
-        foreach ( @countries )
-        {
-                 push @{$show{country}}, [$_, $lang ];         
-        }
-       }
-
-       my $description =  "";
-       foreach  my $desc ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Beschreibung<\/th>} } ) )
-       {
-        $description = (($desc->look_down('_tag', 'td'))->as_text());
-        $description =~ s/ mehr... / /;
-        $description =~ s/Folge verpasst(.*)voller Länge zum kostenlosen Abruf bereit\.//;
-        
-       }
-
-       foreach  my $cast ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Cast<\/th>} } ) )
-       {
-        my $s = (($cast->look_down('_tag', 'td'))->as_text());        
-        $s=~ s/\(.*//;
-        my @actors = split(m/\s*,\s*/, $s);
-        $show{credits}{actor} = \@actors;
-       }
-
-       foreach my $directors ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Regisseur<\/th>} } ) )
-       {
-        my @directors = split(m/\s*,\s*/, (($directors->look_down('_tag', 'td'))->as_text()));
-        $show{credits}{director} = \@directors;
-       }
-
-       foreach  ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Wiederholung<\/th>} } ) )
-       {
-        $show{'previously-shown'} = {}
-       }
-       foreach my $writers ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Drehbuch<\/th>} } ) )
-       {
-        my @writers = split(m/\s*,\s*/, (($writers->look_down('_tag', 'td'))->as_text()));
-        $show{credits}{writer} = \@writers;
-       }
-       $show{'title'} = [[$title, $lang]]; 
-       $show{'sub-title'} = [[$sub_title, $lang]] if(length($sub_title));
-       $show{desc} = [[ $description, $lang ]] if(length($description));
-      }
-     }
-     $writer->write_programme(\%show); 
-
-    } 
-   }
-  }
-  $tb->delete();
-  update $bar if not $opt_quiet;
-
- }
- $grabDate = &DateCalc($grabDate,"+ 1 day");
- if(Date_Cmp($grab_stop, $grabDate) > 0) 
- {
-  goto grab_channel_loop;
- }
- $bar->finish()
-  unless($opt_quiet);
-}
-
-
-## get channel listing
-sub get_channels() {
-    my %channels;
-    my $url=$head->{q(source-data-url)};
-
-    my $tb=new HTML::TreeBuilder();
-    $tb->parse(get_page($url))
-         or die "cannot parse content of $url";    
-    $tb->eof;
-
-       ## getting the channels directly selectable
-       foreach($tb->look_down('_tag' => 'span', 'style' => 'float:right;display:inline' )) {
-        next unless(ref($_) eq "HTML::Element");
-        my $channel_name = $_->as_text();
-       my $id = (((($_->look_up('_tag' => 'div'))[0])->look_down('_tag' => 'input', 'type' => 'checkbox'))[0])->attr('value');
-
-        $channels{uri_escape($id)} = $channel_name;      
-    }
-    $tb->delete;
-    
-    return %channels;
-}
-
-
-
-## get_page($url) :: try to download $url via http://, look for closing </body> tag or die
-sub get_page($) {
-    my $url = shift;
-    my $retry = 0;
-
-    local $SIG{__DIE__} = sub { die "\n$url: $_[0]" };
-    
-    while($retry < 2) {
-        my $got = eval { get_nice($url . ($retry ? "&retry=$retry" : "")); };
-        $retry ++;
-
-        next if($@); # unable to download, doesn't look too good for us.
-        return $got;
-    }
-
-    die "cannot grab webpage $url (tried $retry times). giving up. sorry";
-}
+#!/usr/bin/perl\r
+\r
+=pod\r
+\r
+=head1 NAME\r
+\r
+tv_grab_ch_search - Grab TV listings for Switzerland (from tv.search.ch webpage).\r
+\r
+=head1 SYNOPSIS\r
+\r
+tv_grab_ch_search --help\r
+\r
+tv_grab_ch_search [--config-file FILE] --configure [--gui OPTION]\r
+\r
+tv_grab_ch_search [--config-file FILE] [--output FILE] [--quiet]\r
+           [--days N] [--offset N]\r
+\r
+tv_grab_ch_search --list-channels\r
+\r
+tv_grab_ch_search --capabilities\r
+\r
+tv_grab_ch_search --version\r
+\r
+=head1 DESCRIPTION\r
+\r
+Output TV listings for several channels available in Switzerland and\r
+(partly) central Europe. \r
+The data comes from tv.search.ch. The grabber relies on\r
+parsing HTML so it might stop working at any time.\r
+\r
+First run B<tv_grab_ch_search --configure> to choose, which channels \r
+you want to download. Then running B<tv_grab_ch_search> with no \r
+arguments will output listings in XML format to standard output.\r
+\r
+B<--configure> Ask for each available channel whether to download\r
+and write the configuration file.\r
+\r
+B<--config-file FILE> Set the name of the configuration file, the\r
+default is B<~/.xmltv/tv_grab_ch_search.conf>.  This is the file \r
+written by B<--configure> and read when grabbing.\r
+\r
+B<--gui OPTION> Use this option to enable a graphical interface to be used.\r
+OPTION may be 'Tk', or left blank for the best available choice.\r
+Additional allowed values of OPTION are 'Term' for normal terminal output\r
+(default) and 'TermNoProgressBar' to disable the use of Term::ProgressBar.\r
+\r
+B<--output FILE> Write to FILE rather than standard output.\r
+\r
+B<--days N> Grab N days.  The default is fourteen.\r
+\r
+B<--offset N> Start N days in the future.  The default is to start\r
+from now on (= zero).\r
+\r
+B<--quiet> Suppress the progress messages normally written to standard\r
+error.\r
+\r
+B<--list-channels> Write output giving <channel> elements for every\r
+channel available (ignoring the config file), but no programmes.\r
+\r
+B<--capabilities> Show which capabilities the grabber supports. For more\r
+information, see L<http://wiki.xmltv.org/index.php/XmltvCapabilities>\r
+\r
+B<--version> Show the version of the grabber.\r
+\r
+B<--help> print a help message and exit.\r
+\r
+\r
+=head1 SEE ALSO\r
+\r
+L<xmltv(5)>.\r
+\r
+=head1 AUTHOR\r
+\r
+Daniel Bittel <betlit@gmx.net>. Inspired by tv_grab_ch by Stefan Siegl.\r
+\r
+=head1 BUGS\r
+\r
+If you happen to find a bug, you're requested to send a mail to me\r
+at B<betlit@gmx.net> or to one of the XMLTV mailing lists, see webpages\r
+at http://sourceforge.net/projects/xmltv/.\r
+\r
+=cut\r
+\r
+use warnings;\r
+use strict;\r
+use DateTime;\r
+use LWP::Simple;\r
+use HTTP::Cookies;\r
+use XMLTV::Version '$Id: tv_grab_ch_search.in,v 1.17 2012/05/01 16:18:23 betlit Exp $ ';\r
+use XMLTV::Capabilities qw/baseline manualconfig cache/;\r
+use XMLTV::Description 'Switzerland (tv.search.ch)';\r
+use XMLTV::Supplement qw/GetSupplement/;\r
+use Getopt::Long;\r
+use HTML::TreeBuilder;\r
+use HTML::Entities;\r
+use URI::Escape;\r
+use XMLTV;\r
+use XMLTV::Ask;\r
+use XMLTV::ProgressBar;\r
+use XMLTV::DST;\r
+use XMLTV::Config_file;\r
+use XMLTV::Mode;\r
+use XMLTV::Get_nice;\r
+use XMLTV::Memoize;\r
+use XMLTV::Usage<<END\r
+$0: get Swiss television listings from tv.search.ch in XMLTV format\r
+To configure: $0 --configure [--config-file FILE] [--gui OPTION]\r
+To grab data: $0 [--config-file FILE] [--output FILE] [--quiet]\r
+                 [--days N] [--offset N]\r
+Channel List: $0 --list-channels\r
+To show capabilities: $0 --capabilities\r
+To show version: $0 --version\r
+\r
+END\r
+  ;\r
+\r
+# Use Log::TraceMessages if installed.\r
+BEGIN {\r
+    eval { require Log::TraceMessages };\r
+    if ($@) {\r
+        *t = sub {};\r
+        *d = sub { '' };\r
+    }\r
+    else {\r
+        *t = \&Log::TraceMessages::t;\r
+        *d = \&Log::TraceMessages::d;\r
+    }\r
+}\r
+\r
+\r
+\r
+## our own prototypes first ...\r
+sub get_channels();\r
+sub channel_id($);\r
+sub get_page($);\r
+sub grab_channel($);\r
+\r
+## attributes of xmltv root element\r
+my $head = { \r
+    'source-data-url'      => 'http://tv.search.ch/channels.de.html',\r
+    'source-info-url'      => 'http://tv.search.ch/index.de.html',\r
+    'generator-info-name'  => 'XMLTV',\r
+    'generator-info-url'   => 'http://xmltv.org/',\r
+};\r
+\r
+\r
+\r
+## the timezone tv.search.ch lives in is, CET/CEST\r
+my constant $TZ = "+0100";\r
+my constant $lang = "de";\r
+\r
+\r
+\r
+## Parse argv now.  First do undocumented --cache option.\r
+XMLTV::Memoize::check_argv('XMLTV::Get_nice::get_nice_aux');\r
+\r
+\r
+\r
+my $opt_configure;\r
+my $opt_config_file;\r
+my $opt_gui;\r
+my $opt_output;\r
+my $opt_days = 14;\r
+my $opt_offset = 0;\r
+my $opt_quiet = 0;\r
+my $opt_slow = 0;\r
+my $opt_list_channels;\r
+my $opt_help;\r
+\r
+GetOptions(\r
+    'configure'      => \$opt_configure,\r
+    'config-file=s'  => \$opt_config_file,\r
+    'gui:s'          => \$opt_gui,\r
+    'output=s'       => \$opt_output,\r
+    'days=i'         => \$opt_days,\r
+    'offset=i'       => \$opt_offset,\r
+    'quiet'          => \$opt_quiet,\r
+    'slow'           => \$opt_slow,    \r
+    'list-channels'  => \$opt_list_channels,\r
+    'help'           => \$opt_help,\r
+) or usage(0);\r
+\r
+usage(1) if $opt_help;\r
+\r
+XMLTV::Ask::init($opt_gui);\r
+\r
+## make sure offset+days arguments are within range\r
+die "neither offset nor days may be negative"\r
+  if($opt_offset < 0 || $opt_days < 0);\r
+\r
+\r
+## calculate global start/stop times ...\r
+my $grab_start = DateTime->now()->add( days => $opt_offset );\r
+my $grab_stop = DateTime->now()->add ( days => $opt_offset + $opt_days );\r
+\r
+\r
+my $mode = XMLTV::Mode::mode('grab', # default value\r
+    $opt_configure     => 'configure',\r
+    $opt_list_channels => 'list-channels',\r
+);\r
+\r
+\r
+\r
+## initialize config file support\r
+my $config_file = XMLTV::Config_file::filename($opt_config_file, 'tv_grab_ch_search', $opt_quiet);\r
+my @config_lines;\r
+\r
+if($mode eq 'configure') {\r
+    XMLTV::Config_file::check_no_overwrite($config_file);\r
+} \r
+elsif($mode eq 'grab' || $mode eq 'list-channels') {\r
+    @config_lines = XMLTV::Config_file::read_lines($config_file);\r
+} \r
+else { die("never heard of XMLTV mode $mode, sorry :-(") }\r
+\r
+\r
+\r
+## hey, we can't live without channel data, so let's get those now!\r
+my $bar = new XMLTV::ProgressBar( 'getting list of channels', 1 )\r
+    if not $opt_quiet;\r
+\r
+my %channels = get_channels();\r
+$bar->update() if not $opt_quiet;\r
+$bar->finish() if not $opt_quiet;\r
+\r
+\r
+my @requests;\r
+\r
+## read our configuration file now\r
+my $line = 1;\r
+foreach(@config_lines) {\r
+    $line ++;\r
+    next unless defined;\r
+\r
+    if (/^channel:?\s+(\S+)/) {\r
+       warn("\nConfigured channel $1 not available anymore. \nPlease reconfigure tv_grab_ch_search.\n"),\r
+         next unless(defined($channels{$1}));\r
+       push @requests, $1;\r
+    } \r
+    else {\r
+       warn "$config_file:$line: bad line\n";\r
+    }\r
+}\r
+\r
+## if we're requested to do so, write out a new config file ...\r
+if ($mode eq 'configure') {\r
+    open(CONFIG, ">$config_file") or die("cannot write to $config_file, due to: $!");\r
+\r
+    ## now let's annoy the user, sorry, I meant ask ..\r
+    my @chs = sort keys %channels;\r
+    my @names = map { $channels{$_} } @chs;\r
+    my @qs = map { "add channel $_?" } @names;\r
+    my @want = ask_many_boolean(1, @qs);\r
+\r
+    foreach (@chs) {\r
+       my $w = shift @want;\r
+       my $chname = shift @names;\r
+       \r
+       warn("cannot read input, stopping to ask questions ..."), last if not defined $w;\r
+\r
+       print CONFIG '#' if not $w; #- comment line out if user answer 'no'\r
+\r
+       # shall we store the display name in the config file?\r
+       # leave it in, since it probably makes it a lot easier for the\r
+       # user to choose which channel to comment/uncommet - when manually\r
+       # viing the config file -- are there people who do that?\r
+       print CONFIG "channel $_ #$chname\n";\r
+    }\r
+\r
+    close CONFIG or warn "unable to nicely close the config file: $!";\r
+    say("Finished configuration.");\r
+\r
+    exit();\r
+}\r
+\r
+\r
+\r
+## well, we don't have to write a config file, so, probably it's some xml stuff :)\r
+## if not, let's go dying ...\r
+die unless($mode eq 'grab' or $mode eq 'list-channels');\r
+\r
+my %writer_args;\r
+if (defined $opt_output) {\r
+    my $handle = new IO::File(">$opt_output");\r
+    die "cannot write to output file, $opt_output: $!" unless (defined $handle);\r
+    $writer_args{'OUTPUT'} = $handle;\r
+}\r
+\r
+$writer_args{'encoding'} = 'utf-8';\r
+\r
+\r
+if( defined( $opt_days )) {\r
+    $writer_args{offset} = $opt_offset;\r
+       $writer_args{days} = $opt_days;\r
+       $writer_args{cutoff} = "000000";\r
+}\r
+\r
+## create our writer object\r
+my $writer = new XMLTV::Writer(%writer_args);\r
+$writer->start($head);\r
+\r
+\r
+\r
+if ($mode eq 'list-channels') {\r
+    foreach (keys %channels) {\r
+        my %channel = ('id'           => channel_id($_), \r
+                       'display-name' => [[$channels{$_}, $lang]]); \r
+        $writer->write_channel(\%channel);\r
+    }\r
+\r
+    $writer->end();\r
+    exit();\r
+}\r
+\r
+\r
+\r
+## there's only one thing, why we might exist: write out tvdata!\r
+die unless ($mode eq 'grab');\r
+die "No channels specified, run me with --configure flag\n" unless(scalar(@requests));\r
+\r
+\r
+\r
+## write out <channel> tags\r
+my $paramstr ="";\r
+foreach(@requests) {\r
+    my $id = channel_id($_);\r
+    my %channel = ('id'           => $id, \r
+                   'display-name' => [[$channels{$_}, $lang]]); \r
+    $writer->write_channel(\%channel);\r
+     $paramstr = $paramstr."&channel[]=".$_; \r
+\r
+}\r
+\r
+\r
+## the page doesn't specify the year when the programmes begin or end, thus\r
+## we need to guess, store current year and month globally as needed for every\r
+## programme ...\r
+my $cur_year = DateTime->now()->year();\r
+my $cur_month = DateTime->now()->month();\r
+\r
+my $url=$head->{q(source-data-url)};\r
+\r
+       \r
+my $ua = LWP::UserAgent->new(keep_alive => 300);       \r
+$ua->cookie_jar(HTTP::Cookies->new());\r
+$ua->agent("xmltv/$XMLTV::VERSION");\r
+$ua->env_proxy;\r
+       \r
+my $req = HTTP::Request->new(POST => $url);\r
+$req->content_type('application/x-www-form-urlencoded');\r
+$req->content(substr ( $paramstr, 1));\r
+\r
+# FIXME what is this request doing? It fills the cookie jar\r
+$ua->request($req);\r
+$ua->request($req);\r
+\r
+## write out <programme> tags\r
+grab_channels();\r
+\r
+## hey, looks like we've finished ...\r
+$writer->end();\r
+\r
+\r
+## channel_id($s) :: turn site channel id into an xmltv id\r
+sub channel_id($) {  \r
+    my $s = shift;\r
+    #for (my $s = shift) {\r
+    #$_ = lc(defined($chid_mapping{$_}) ? $chid_mapping{$_} : "$_.search.ch");\r
+       #$_ = "C$_" if /^\d/;\r
+       #return $_;\r
+    #}\r
+    $s =~ s|^tv_||;\r
+    return "$s.search.ch"\r
+}\r
+\r
+\r
+\r
+sub grab_channels\r
+{\r
+ my $grabDate = $grab_start;\r
+ my $url = $head->{q(source-info-url)};\r
\r
+ $bar = new XMLTV::ProgressBar('grabbing channels       ', (6*$opt_days))\r
+  if not $opt_quiet;\r
+\r
+ grab_channel_loop:\r
+ for (my $count = 0; $count < 6; $count++) \r
+ {\r
+  my $tb = HTML::TreeBuilder->new();\r
+\r
+  my $loop_date = $grabDate->year() . '-' . substr("0".$grabDate->month(),-2) . '-' . substr("0".$grabDate->day(),-2);\r
+  my $req = HTTP::Request->new(GET => "$url?time=$loop_date+" . 4*$count .".00");\r
+  $req->header('Accept' => 'text/html');\r
+    \r
+  $tb->parse(($ua->request($req))->content)\r
+      or die "cannot parse content of http://tv.search.ch/?time=$loop_date+" . 4*$count .".00"; ;    \r
+  $tb->eof;\r
+\r
+  foreach my $tv_channel ( $tb->look_down('_tag' => 'div', 'class' => 'tv_channel') )\r
+  {\r
+   my $channel_id = $tv_channel->attr('id');\r
+   if ( defined($channel_id) )\r
+   {\r
+    foreach my $tv_show ( $tv_channel ->look_down('_tag' => 'tr', sub { ($_[0]->as_HTML() =~ m{tv_b_}) && !($_[0]->as_HTML() =~ m{tv_before})  && !($_[0]->as_HTML() =~ m{tv_timegroup}) } ) )\r
+    {\r
+     my %show;\r
+     $show{channel} = channel_id($channel_id);\r
+     \r
+     my $tmp = (($tv_show->look_down('_tag', 'td'))[0])->as_text();\r
+     $show{start} = DateTime->new (\r
+        year => $grabDate->year()\r
+       ,month => $grabDate->month() \r
+       ,day   => $grabDate->day()\r
+       ,hour  => substr($tmp,0,2) \r
+       ,minute => substr($tmp,3,2)\r
+       ,second => 00\r
+       ,time_zone => 'Europe/Zurich'\r
+      )->strftime( "%Y%m%d%H%M%S %z" );\r
+\r
+     $tmp  = $tv_show->as_HTML();\r
+     if ( $tmp =~ /Untertitel für Gehörlose/)\r
+     {\r
+      $show{subtitles} = [{ type => 'teletext' }];\r
+     }\r
+     if ( $tmp =~ /Zweikanalton/)\r
+     {\r
+      $show{audio}{stereo} = 'bilingual';\r
+     }\r
+     if ( $tmp =~ /16:9/)\r
+     {\r
+      $show{video}{aspect} = '16:9';\r
+     }  \r
+     \r
+     foreach my $div ( $tv_show->look_down('_tag' => 'div', \r
+               sub {\r
+                       ( ( $_[0]->attr ('class') eq "tv_tooltip") || ( $_[0]->attr ('class') eq "tv_tr_notooltip" ) )\r
+                   } )\r
+            )\r
+     {\r
+      if ( $div->attr ('class') eq 'tv_tr_notooltip' )\r
+      {\r
+             $show{'title'} = [[$div->as_text(), $lang]]; \r
+      }\r
+      else\r
+      {\r
+      \r
+       my $title = (($div->look_down('_tag' => 'td', 'class' => 'title'))->look_down('_tag' => 'h2'))->as_text();\r
+       my $sub_title = ($div->look_down('_tag' => 'td', 'class' => 'title'))->as_text();\r
+\r
+       $sub_title =~ s/\Q$title \E//;\r
+       if ( "$title" eq "$sub_title" )\r
+       {\r
+        $sub_title ="";\r
+       } \r
+\r
+if($channel_id  =~ /tv_nickch/)\r
+\r
+                                {\r
+\r
+    $title =~ m/(.*?)([\s](((\d+\D+)|(\d+))))?$/;\r
+\r
+               $title = $1;           # only get first group with the title (there is always content in it)\r
+\r
+                # group 3 matches something like "123", "123B", "123BB" (not yet seen, but taken care of), after a title with a space, and could be prepended to sub_title\r
+\r
+}\r
+\r
+       foreach  my $year ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Produktionsjahr<\/th>} } ) )\r
+       {\r
+        $show{date} =  (($year->look_down('_tag', 'td'))->as_text());        \r
+       }\r
+       \r
+       foreach  my $category ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Kategorie<\/th>} } ) )\r
+          {\r
+        my $s =  (($category->look_down('_tag', 'td'))->as_text());        \r
+        my @categories = split(m/\s*[\/]\s*/, $s);\r
+        foreach ( @categories )\r
+        {\r
+         if ( $_ )\r
+         {\r
+          push @{$show{category}}, [$_, $lang ];\r
+         }\r
+        }\r
+          }\r
+          \r
+          foreach  my $category ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Produktionsinfos<\/th>} } ) )\r
+       {\r
+        my $s = (($category->look_down('_tag', 'td'))->as_text());        \r
+        $s=~ s/\(.*//;\r
+        my @categories = split(m/\s*[\/,]\s*/, $s);\r
+        foreach my $category ( @categories )\r
+        {\r
+         if ( $category )\r
+         {\r
+          my $is_defined = 0;\r
+                 foreach ( @{$show{category}} )\r
+                 {\r
+                   if ("${$_}[0]" eq "$category" )\r
+                   {\r
+                    $is_defined = 1;\r
+                    last;\r
+                   }\r
+                 }\r
+                 if ( $is_defined == 0 )\r
+                 {\r
+                       push @{$show{category}}, [$category, $lang ];\r
+                 }               \r
+         }\r
+        }\r
+       }          \r
+       \r
+\r
+          foreach  my $country ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Produktionsland<\/th>} } ) )\r
+       {\r
+        my $s =  (($country->look_down('_tag', 'td'))->as_text());        \r
+        my @countries = split(m/\s*[\/,]\s*/, $s);\r
+        foreach ( @countries )\r
+        {\r
+                 push @{$show{country}}, [$_, $lang ];         \r
+        }\r
+       }\r
+\r
+       my $description =  "";\r
+       foreach  my $desc ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Beschreibung<\/th>} } ) )\r
+       {\r
+        $description = (($desc->look_down('_tag', 'td'))->as_text());\r
+        $description =~ s/ mehr... / /;\r
+        $description =~ s/Folge verpasst(.*)voller Länge zum kostenlosen Abruf bereit\.//;\r
+        \r
+       }\r
+\r
+       foreach  my $cast ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Cast<\/th>} } ) )\r
+       {\r
+        my $s = (($cast->look_down('_tag', 'td'))->as_text());        \r
+        $s=~ s/\(.*//;\r
+        my @actors = split(m/\s*,\s*/, $s);\r
+        $show{credits}{actor} = \@actors;\r
+       }\r
+\r
+       foreach my $directors ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Regisseur<\/th>} } ) )\r
+       {\r
+        my @directors = split(m/\s*,\s*/, (($directors->look_down('_tag', 'td'))->as_text()));\r
+        $show{credits}{director} = \@directors;\r
+       }\r
+\r
+       foreach  ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Wiederholung<\/th>} } ) )\r
+       {\r
+        $show{'previously-shown'} = {}\r
+       }\r
\r
+       foreach my $writers ($div->look_down('_tag' => 'tr', sub { $_[0]->as_HTML() =~ m{<th>Drehbuch<\/th>} } ) )\r
+       {\r
+        my @writers = split(m/\s*,\s*/, (($writers->look_down('_tag', 'td'))->as_text()));\r
+        $show{credits}{writer} = \@writers;\r
+       }\r
+       $show{'title'} = [[$title, $lang]]; \r
+       $show{'sub-title'} = [[$sub_title, $lang]] if(length($sub_title));\r
+       $show{desc} = [[ $description, $lang ]] if(length($description));\r
+      }\r
+     }\r
+     $writer->write_programme(\%show); \r
+\r
+    } \r
+   }\r
+  }\r
+  $tb->delete();\r
+  update $bar if not $opt_quiet;\r
+\r
+ }\r
+ $grabDate = $grabDate->add ( days => 1 );\r
+ if( DateTime->compare ( $grab_stop, $grabDate ) > 0) \r
+ {\r
+  goto grab_channel_loop;\r
+ }\r
+ $bar->finish()\r
+  unless($opt_quiet);\r
+}\r
+\r
+\r
+## get channel listing\r
+sub get_channels() {\r
+    my %channels;\r
+    my $url=$head->{q(source-data-url)};\r
+\r
+    my $tb=new HTML::TreeBuilder();\r
+    $tb->parse(get_page($url))\r
+         or die "cannot parse content of $url";    \r
+    $tb->eof;\r
+\r
+       ## getting the channels directly selectable\r
+       foreach($tb->look_down('_tag' => 'span', 'style' => 'float:right;display:inline' )) {\r
+        next unless(ref($_) eq "HTML::Element");\r
+        my $channel_name = $_->as_text();\r
+       my $id = (((($_->look_up('_tag' => 'div'))[0])->look_down('_tag' => 'input', 'type' => 'checkbox'))[0])->attr('value');\r
+\r
+        $channels{uri_escape($id)} = $channel_name;      \r
+    }\r
+    $tb->delete;\r
+\r
+    # adding the sky-channels manually... why do these sites _NEVER_ stick to their own design?\r
+    $channels{uri_escape("skyaction")} = "SKY ACTION";\r
+    $channels{uri_escape("skycinema")} = "SKY CINEMA";\r
+    $channels{uri_escape("skycinema1")} = "SKY CINEMA +1";\r
+    $channels{uri_escape("skycinema24")} = "SKY CINEMA +24";\r
+    $channels{uri_escape("skycinemahits")} = "SKY CINEMA HITS";\r
+    $channels{uri_escape("skycomedy")} = "SKY COMEDY";\r
+    $channels{uri_escape("skyemotion")} = "SKY EMOTION";\r
+    $channels{uri_escape("skyfussballbundesliga")} = "Sky Fussball Bundesliga";\r
+    $channels{uri_escape("skykrimi")} = "SKY KRIMI";\r
+    $channels{uri_escape("skynostalgie")} = "SKY NOSTALGIE";\r
+    $channels{uri_escape("skyselect")} = "Sky Select";\r
+    $channels{uri_escape("skysport1")} = "Sky Sport 1";\r
+    $channels{uri_escape("skysport2")} = "Sky Sport 2";\r
+    $channels{uri_escape("skysportaustria")} = "SKY SPORT AUSTRIA";\r
+    $channels{uri_escape("skysporthd")} = "SKY SPORT HD"; \r
+    return %channels;\r
+}\r
+\r
+\r
+\r
+## get_page($url) :: try to download $url via http://, look for closing </body> tag or die\r
+sub get_page($) {\r
+    my $url = shift;\r
+    my $retry = 0;\r
+\r
+    local $SIG{__DIE__} = sub { die "\n$url: $_[0]" };\r
+    \r
+    while($retry < 2) {\r
+        my $got = eval { get_nice($url . ($retry ? "&retry=$retry" : "")); };\r
+        $retry ++;\r
+\r
+        next if($@); # unable to download, doesn't look too good for us.\r
+        return $got;\r
+    }\r
+\r
+    die "cannot grab webpage $url (tried $retry times). giving up. sorry";\r
+}\r
index a8c2153..8740af8 100644 (file)
@@ -5,7 +5,7 @@ channel=041.dr.dk
 channel=042.dr.dk
 channel=047.dr.dk
 channel=048.dr.dk
-channel=049.dr.dk
+#channel=049.dr.dk
 #channel=050.dr.dk
 #channel=052.dr.dk
 #channel=053.dr.dk
@@ -51,8 +51,8 @@ channel=049.dr.dk
 #channel=218.dr.dk
 #channel=3st.dr.dk
 #channel=999.dr.dk
-#channel=DR1.dr.dk
-#channel=DR2.dr.dk
+channel=DR1.dr.dk
+channel=DR2.dr.dk
 #channel=TVH.dr.dk
 #channel=TVK.dr.dk
 #channel=TVR.dr.dk
index e017fb5..370dd45 100644 (file)
-getdescriptions no
-#channel C13-20TV 13 TV
-#channel C33 33
-#channel C40-20Latino 40 Latino
-#channel C40TV 40TV
-#channel C7RM 7RM
-#channel C8Madrid 8Madrid
-channel CAXN AXN
-#channel CAl-20Jazeera-20English Al Jazeera English
-#channel CAndaluc-7Bicute-7Da-20TV Andalucía TV
-#channel CAnimax Animax
-#channel CAntena-203 Antena 3
-#channel CAntena-2Eneox Antena.neox
-#channel CAntena-2Enova Antena.nova
-#channel CArag-7Bocute-7Dn-20TV Aragón TV
-#channel CBBC-20World BBC World
-#channel CBarcelona-20TV Barcelona TV
-#channel CBilbovisi-7Bocute-7Dn Bilbovisión
-#channel CBiography Biography
-#channel CBloomberg Bloomberg
-#channel CBoing Boing
-#channel CBoomerang Boomerang
-#channel CCCValenciana CCValenciana
-#channel CCNBC CNBC
-#channel CCNN-2B CNN+
-#channel CCalle-2013 Calle 13
-#channel CCanal-2010-20TV Canal 10 TV
-#channel CCanal-202-20Andaluc-7Bicute-7Da Canal 2 Andalucía
-#channel CCanal-2024-20horas Canal 24 horas
-#channel CCanal-20300 Canal 300
-#channel CCanal-2033-20TDT Canal 33 TDT
-#channel CCanal-206 Canal 6
-#channel CCanal-208-20DM Canal 8 DM
-#channel CCanal-20Bar-7Bccute-7Da Canal Barça
-#channel CCanal-20Cl-7Bacute-7Dsico Canal Clásico
-#channel CCanal-20Cocina Canal Cocina
-#channel CCanal-20Extremadura-20TV Canal Extremadura TV
-#channel CCanal-20Feria-20de-20Abril Canal Feria de Abril
-#channel CCanal-20Fox Canal Fox
-#channel CCanal-20Sur Canal Sur
-#channel CCanal-20de-20las-20Estrellas Canal de las Estrellas
-channel CCanal-20-2B Canal+
-#channel CCanal-2B-20-2E-2E-2E30 Canal+ ...30
-#channel CCanal-20-2B-202 Canal+ 2
-#channel CCanal-20-2B-20Acci-7Bocute-7Dn Canal+ Acción
-#channel CCanal-20-2B-20Acci-7Bocute-7Dn-2030 Canal+ Acción 30
-#channel CCanal-20-2B-20Comedia Canal+ Comedia
-#channel CCanal-20-2B-20Comedia-2030 Canal+ Comedia 30
-#channel CCanal-20-2B-20DCine Canal+ DCine
-#channel CCanal-20-2B-20Deportes Canal+ Deportes
-#channel CCanal-20-2B-20Eventos Canal+ Eventos
-#channel CCanal-20-2B-20F-7Bucute-7Dtbol Canal+ Fútbol
-#channel CCanal-20-2B-20HD Canal+ HD
-#channel CCanal-2BToros Canal+ Toros
-#channel CCanal-2BXtra Canal+ Xtra
-#channel CCaracol-20TV Caracol TV
-#channel CCartoon-20Network Cartoon Network
-#channel CCastilla-20La-20Mancha-20TV2 Castilla La Mancha TV2
-#channel CCastilla-2DLa-20Mancha-20TV Castilla-La Mancha TV
-#channel CCaza-20y-20Pesca Caza y Pesca
-#channel CCineman-7Bicute-7Da-202 Cinemanía 2
-#channel CClan-20-2F-20TVE-2050 Clan / TVE 50
-#channel CClub-20Super-203 Club Super 3
-#channel CCosmopolitan Cosmopolitan
-#channel CCuatro Cuatro
-#channel CCubavisi-7Bocute-7Dn Cubavisión
-#channel CC-7Bocute-7Ddigo-20TV Código TV
-#channel CD-20Cine-20Espa-7Bncute-7Dol D Cine Español
-channel CDiscovery-20Channel Discovery Channel
-#channel CDisney-20Ch-2E-20-2B1 Disney Ch. +1
-#channel CDisney-20Channel Disney Channel
-#channel CDisney-20Cinemagic Disney Cinemagic
-#channel CDisney-20XD Disney XD
-#channel CDocu-20TVE Docu TVE
-#channel CDocuman-7Bicute-7Da Documanía
-#channel CEHS EHS
-#channel CETB-201 ETB 1
-#channel CETB-202 ETB 2
-#channel CETB-20SAT-20-20TV-20Euskadi ETB SAT / TV Euskadi
-#channel CETB3 ETB3
-#channel CEcuavisa-20Int-2E Ecuavisa Int.
-#channel CEurosport Eurosport
-#channel CExpansi-7Bocute-7Dn-20TV Expansión TV
-#channel CFRANCE-2024 FRANCE 24
-channel CFactor-7Bicute-7Da-20de-20Ficci-7Bocute-7Dn-20Telecinco Factoría de Ficción Telecinco
-#channel CFox-20Crime Fox Crime
-#channel CFox-20News Fox News
-#channel CG2 G2
-#channel CGalavisi-7Bocute-7Dn Galavisión
-#channel CGol-20TV Gol TV
-#channel CGolf-2B Golf+
-#channel CGran-20Canaria-20TV Gran Canaria TV
-#channel CHistoria Historia
-#channel CHollywood Hollywood
-#channel CIB3 IB3
-#channel CIntereconom-7Bicute-7Da Intereconomía
-#channel CLa-2010 La 10
-#channel CLa-202 La 2
-#channel CLa-20Otra La Otra
-#channel CLa-20Sexta La Sexta
-#channel CLa-20Siete La Siete
-#channel CLaSexta2 LaSexta2
-#channel CLaSexta3 LaSexta3
-#channel CMTV MTV
-#channel CMeteo Meteo
-#channel CMezzo Mezzo
-#channel CNational-20Geographic National Geographic
-#channel CNickelodeon Nickelodeon
-#channel CNitro Nitro
-#channel CNou Nou
-#channel CNou2 Nou2
-#channel COdisea Odisea
-#channel COnda-20Luz Onda Luz
-#channel CParamount-20Comedy Paramount Comedy
-#channel CPeople-20-26-20Arts People & Arts
-#channel CPlayboy-20TV Playboy TV
-#channel CPlayhouse-20Disney Playhouse Disney
-#channel CPlayin-20TV Playin TV
-#channel CPopular-20TV Popular TV
-#channel CReal-20Madrid-20TV Real Madrid TV
-#channel CSci-2DFi Sci-Fi
-#channel CSevilla-20TV Sevilla TV
-#channel CSportman-7Bicute-7Da Sportmanía
-#channel CTCM TCM
-#channel CTCM-20Cl-7Bacute-7Dsico TCM Clásico
-#channel CTM3-20Telemadrid TM3 Telemadrid
-#channel CTNT TNT
-#channel CTPA TPA
-#channel CTV-20Canaria TV Canaria
-#channel CTV-20Castilla-20y-20Le-7Bocute-7Dn TV Castilla y León
-#channel CTV-20Galicia TV Galicia
-#channel CTV-20Record TV Record
-#channel CTV3 TV3
-#channel CTV5 TV5
-#channel CTVE-201 TVE 1
-#channel CTVG TVG
-#channel CTd8 Td8
-#channel CTele-205 Tele 5
-#channel CTeledeporte Teledeporte
-#channel CTeledonosti Teledonosti
-#channel CTeleideal Teleideal
-#channel CTelemadrid-20SATLaOtra Telemadrid SAT/LaOtra
-#channel CTelenovelas Telenovelas
-#channel CTelevisi-7Bocute-7D-20Catalunya-20Int-2E Televisió Catalunya Int.
-#channel CToon-20Disney Toon Disney
-#channel CTvCanaria TvCanaria
-#channel CVH1 VH1
-#channel CVeo7 Veo7
-#channel CViajar Viajar
-#channel CZTV ZTV
-#channel C-7BAcute-7Dlava-207 Álava 7
+configversion 2
+getdescriptions yes
+#channel 13tv 13TV
+#channel 40-latino 40 Latino
+#channel 40tv 40TV
+#channel 7rm 7RM
+#channel axn AXN
+#channel axn-hd AXN HD
+#channel al-jazeera-english Al Jazeera English
+#channel andalucia-tv Andalucía TV
+#channel animax Animax
+channel antena-3 Antena 3
+#channel aragon-tv Aragón TV
+#channel bbc-world BBC World
+#channel baby-tv Baby TV
+#channel biography Biography
+#channel bloomberg Bloomberg
+#channel boing Boing
+#channel boomerang Boomerang
+#channel cmt-1 CMT 1
+#channel cmt-2 CMT 2
+#channel cnbc CNBC
+#channel cnn-int CNN Int
+#channel cnnplus CNN+
+#channel calle-13 Calle 13
+#channel canal-plus Canal +
+#channel canal-plus-30 Canal + ...30
+#channel canal-plus-2 Canal + 2
+#channel canal-plus-3d Canal + 3D
+#channel canal-plus-accion Canal + Acción
+#channel canal-plus-accion-30 Canal + Acción 30
+#channel canal-plus-accion-hd Canal + Acción HD
+#channel canal-plus-comedia Canal + Comedia
+#channel canal-plus-comedia-hd Canal + Comedia HD
+#channel canal-plus-dcine Canal + DCine
+#channel canal-plus-dcine-hd Canal + DCine HD
+#channel canal-plus-deportes Canal + Deportes
+#channel canal-plus-deportes-hd Canal + Deportes HD
+#channel canal-plus-eventos Canal + Eventos
+#channel canal-plus-futbol Canal + Fútbol
+#channel canal-plus-futbol-hd Canal + Fútbol HD
+#channel canal-plus-hd Canal + HD
+#channel canal-plus-liga-hd Canal + Liga HD
+#channel canal-plus-xtra Canal + XTRA
+#channel canal-plus-xtra-hd Canal + Xtra HD
+#channel canal-33 Canal 33
+#channel canal-club Canal Club
+#channel canal-cocina Canal Cocina
+#channel canal-extremadura Canal Extremadura
+#channel canal-fox Canal Fox
+#channel canal-sur Canal Sur
+#channel canal-sur-2 Canal Sur 2
+#channel canal-de-las-estrellas Canal de las Estrellas
+#channel canalplus-deportes-2-hd Canal+ Deportes 2 HD
+#channel canalplus-deportes-mixto Canal+ Deportes Mixto
+#channel canalplus-liga-2 Canal+ Liga 2
+#channel canalplus-liga-2-a Canal+ Liga 2 A
+#channel canalplus-liga-2-b Canal+ Liga 2 B
+#channel canalplus-liga-2-c Canal+ Liga 2 C
+#channel canalplus-liga-2-d Canal+ Liga 2 D
+#channel canalplus-liga-2-e Canal+ Liga 2 E
+#channel cartoon-network Cartoon Network
+#channel cartoonito Cartoonito
+#channel caza-y-pesca Caza y Pesca
+#channel clan Clan
+#channel cosmopolitan Cosmopolitan
+#channel cosmopolitan-hd Cosmopolitan HD
+channel cuatro Cuatro
+#channel cubavision Cubavisión
+#channel d-cine-espanol D Cine Español
+#channel decasa Decasa
+#channel discovery-channel Discovery Channel
+#channel disney-channel Disney Channel
+#channel disney-cinemagic Disney Cinemagic
+#channel disney-cinemagic-hd Disney Cinemagic HD
+#channel disney-xd Disney XD
+#channel divinity Divinity
+#channel ehs EHS
+#channel etb-1 ETB 1
+#channel etb-2 ETB 2
+#channel etb-3 ETB 3
+#channel eurosport Eurosport
+#channel eurosport-hd Eurosport HD
+#channel fdf FDF
+#channel france-24 FRANCE 24
+#channel fox-crime Fox Crime
+#channel fox-hd Fox HD
+#channel fox-news Fox News
+#channel golfplus Golf+
+#channel historia Historia
+#channel hogar-util Hogar Útil
+#channel hollywood Hollywood
+#channel hollywood-hd Hollywood HD
+#channel ib3 IB3
+#channel infometeo InfoMeteo
+#channel intereconomia Intereconomía
+#channel la-10 La 10
+channel la-2 La 2
+#channel la-sexta La Sexta
+#channel la-sexta-2 La Sexta 2
+#channel la-sexta-3 La Sexta 3
+#channel la-siete La Siete
+#channel mtv MTV
+#channel mtv-2 MTV 2
+#channel mtv-esp MTV ESP
+#channel mtv-hd MTV HD
+#channel marca-tv Marca TV
+#channel mezzo Mezzo
+#channel mezzo-live-hd Mezzo Live HD
+#channel multi-x--1- Multi-X (1)
+#channel multi-x--2- Multi-X (2)
+#channel multi-x--3- Multi-X (3)
+#channel multideporte-1 Multideporte 1
+#channel multideporte-2 Multideporte 2
+#channel multideporte-3 Multideporte 3
+#channel multideporte-4 Multideporte 4
+#channel multideporte-5 Multideporte 5
+#channel multideporte-6 Multideporte 6
+#channel multideporte-7 Multideporte 7
+#channel nhk-world NHK World
+#channel nick-jr NICK JR
+#channel nat-geo-wild-hd Nat Geo Wild HD
+#channel nat-geographic-hd Nat Geographic HD
+#channel nat-geographic-wild Nat Geographic Wild
+#channel national-geographic National Geographic
+#channel neox Neox
+#channel nickelodeon Nickelodeon
+#channel nitro Nitro
+#channel nou Nou
+#channel nou-2 Nou 2
+#channel nova Nova
+#channel odisea Odisea
+#channel panda Panda
+#channel paramount-comedy Paramount Comedy
+#channel playboy-tv Playboy TV
+#channel playhouse-disney Playhouse Disney
+#channel rt-espanol RT Español
+#channel radios Radios.
+#channel real-madrid-tv Real Madrid TV
+#channel russia-today Russia Today
+#channel syfy-hd SYFY HD
+#channel sci-fi Sci-Fi
+#channel sony-entertaiment-tv Sony Entertaiment TV
+#channel sportmania Sportmanía
+#channel super-3 Super 3
+#channel tcm TCM
+#channel tcm-clasico TCM Clásico
+#channel tnt TNT
+#channel tpa TPA
+#channel tv-canaria TV Canaria
+#channel tv-record TV RECORD
+#channel tv3 TV3
+#channel tv5 TV5
+channel tve-1 TVE 1
+#channel tvg TVG
+#channel tvod TVOD
+#channel taquilla-hd Taquilla HD
+channel tele-5 Tele 5
+#channel teledeporte Teledeporte
+#channel telemadrid Telemadrid
+#channel telemadrid-sat-laotra Telemadrid SAT/LaOtra
+#channel telesur Telesur
+#channel televisio-catalunya-int Televisió Catalunya Int.
+#channel vh1 VH1
+#channel viajar Viajar
+#channel viajar-hd Viajar HD
+#channel laotra laOtra
index b224dd6..1707021 100755 (executable)
@@ -79,7 +79,7 @@ CandU, candu_sf@sourceforge.net, based on tv_grab_es, from Ramon Roca.
 # initializations
 
 use strict;
-use XMLTV::Version '$Id: tv_grab_es_laguiatv,v 1.19 2011/03/20 11:03:51 dekarl Exp $ ';
+use XMLTV::Version '$Id: tv_grab_es_laguiatv,v 1.20 2012/01/01 18:45:43 candu_sf Exp $ ';
 use XMLTV::Capabilities qw/baseline manualconfig cache/;
 use XMLTV::Description 'Spain (laguiatv.com)';
 use Getopt::Long;
@@ -121,6 +121,8 @@ my $HEAD = { 'source-info-url'     => 'http://www.laguiatv.com/programacion.php'
 # Whether zero-length programmes should be included in the output.
 my $WRITE_ZERO_LENGTH = 0;
 my $DO_SLOWER_DESC_GET = 0;
+my $CONFIG_VERSION = 1; # default to v1 (v1 doesnt have version info)
+my $EXPECTED_CONFIG_VERSION = 2;
 
 # default language
 my $LANG="es";
@@ -135,27 +137,8 @@ sub debug_print
 #      print "$str";
 }
 
-# hard-coded list of TDT channels since laguia dont list them separately
-my @tdt_channels = (
-    "La 10",
-    "Antena.neox",
-    "Antena.nova",
-    "Clan / TVE 50", # missing / in name
-    "Factor{icute}a de Ficci{ocute}n Telecinco",
-    "Boing",
-    "Gol TV",
-    "La Siete",
-    "Veo7",
-    "LaSexta2",
-    "LaSexta3",
-    "Nitro",
-    "Canal 24 horas",
-    "CNN+"
-);
-
-# hard-coded list of channels to hide from channel list
 my @hide_channels = (
-    "Clan  TVE 50", # missing / in name
+    "canal-bar.a", # currently gives 404 not found
 );
 
 
@@ -167,7 +150,7 @@ XMLTV::Memoize::check_argv('XMLTV::Get_nice::get_nice_aux');
 my ($opt_days, $opt_offset, $opt_help, $opt_output,
     $opt_configure, $opt_config_file, $opt_gui,
     $opt_quiet, $opt_list_channels);
-$opt_days  = 3; # default
+$opt_days  = 1; # default
 $opt_offset = 0; # default
 $opt_quiet  = 0; # default
 GetOptions('days=i'        => \$opt_days,
@@ -181,6 +164,9 @@ GetOptions('days=i'        => \$opt_days,
           'list-channels' => \$opt_list_channels
          )
   or usage(0);
+
+# Force days to be 1, since we get all days at once
+$opt_days = 1;
 die 'number of days must not be negative'
   if (defined $opt_days && $opt_days < 0);
 usage(1) if $opt_help;
@@ -213,6 +199,15 @@ my %channels; # sets @ch_all
 my @channels;
 
 my %icons;
+
+my %categories = (
+    "tag-a" => "Cine",
+    "tag-b" => "Deportes",
+    "tag-c" => "Programas",
+    "tag-d" => "Series",
+    "tag-e" => "Noticias"
+);
+
 ######################################################################
 # write configuration
 
@@ -221,6 +216,7 @@ if ($mode eq 'configure') {
     
     open(CONF, ">$config_file") or die "cannot write to $config_file: $!";
 
+    print CONF "configversion 2\n";
     # Ask about getting descs
     my $getdescs = ask_boolean("Do you want to get descriptions (very slow)");
     warn("cannot read input, using default")
@@ -230,9 +226,9 @@ if ($mode eq 'configure') {
     print CONF "yes\n" if $getdescs;
     print CONF "no\n" if not $getdescs;
 
-    my $cacheicons = ask_boolean('Do you want to get and cache icons during configure', 'yes');
-    warn("cannot read input, using default")
-        if not defined $cacheicons;
+    #my $cacheicons = ask_boolean('Do you want to get and cache icons during configure', 'yes');
+    #warn("cannot read input, using default")
+    #    if not defined $cacheicons;
 
     # Ask about each channel.
     my @chs = sort { $channels{$a} cmp $channels{$b} } keys %channels;
@@ -240,8 +236,8 @@ if ($mode eq 'configure') {
     my @qs = map { "Add channel $_?" } @names;
     my @want = ask_many_boolean(1, @qs);
 
-    my $iconbar = new XMLTV::ProgressBar({name => 'getting icon urls', count => scalar @chs})
-    if ((not $opt_quiet) && $cacheicons);
+    #my $iconbar = new XMLTV::ProgressBar({name => 'getting icon urls', count => scalar @chs})
+    #if ((not $opt_quiet) && $cacheicons);
 
     foreach (@chs) {
        my $w = shift @want;
@@ -252,18 +248,18 @@ if ($mode eq 'configure') {
        # Print a config line, but comment it out if channel not wanted.
        print CONF '#' if not $w;
        my $name = shift @names;
-        if ($cacheicons)
-        {
-            my $icon = get_icon($_);
-           print CONF "channel $_ $name icon:$icon\n";
-        }
-        else
-        {
+#        if ($cacheicons)
+#        {
+#            my $icon = get_icon($_);
+#          print CONF "channel $_ $name icon:$icon\n";
+#        }
+#        else
+#        {
             print CONF "channel $_ $name\n";
-        }
+#        }
        # TODO don't store display-name in config file.
 
-        update $iconbar if ((not $opt_quiet) && $cacheicons);
+#        update $iconbar if ((not $opt_quiet) && $cacheicons);
     }
 
     close CONF or warn "cannot close $config_file: $!";
@@ -304,12 +300,21 @@ my $line_num = 1;
 foreach (@config_lines) {
     ++ $line_num;
     next if not defined;
-    if (/getdescriptions:?\s+(\S+)/)
-       {
-               if($1 eq "yes")
-               {
-                       $DO_SLOWER_DESC_GET = 1;
-               }
+
+    if (/configversion:?\s+(\S+)/)
+    {
+        $CONFIG_VERSION = $1;
+    }
+    elsif (/getdescriptions:?\s+(\S+)/)
+    {
+        if("$CONFIG_VERSION" ne "$EXPECTED_CONFIG_VERSION")
+        {
+            die "Config file is out of date, please rerun with --configure\n";
+        }
+        if($1 eq "yes")
+        {
+            $DO_SLOWER_DESC_GET = 1;
+        }
     }
     elsif (/^channel:?\s+(\S+)\s+([^#]+)icon\:([^#]+)/)
     {
@@ -354,23 +359,23 @@ my $iconbar = new XMLTV::ProgressBar({name => 'getting channel info', count => s
 foreach my $ch_did (@channels) {
     my $ch_name=$channels{$ch_did};
     my $ch_xid="$ch_did.laguiatv.com";
-    my $ch_icon=$icons{$ch_did};
-    if (!$ch_icon)
-    {
-        $ch_icon = get_icon($ch_did);
-    }
-
-    if(index($ch_icon, "shim.gif") < 0)
-    {
-               $writer->write_channel({ id => $ch_xid,
-                                        'display-name' => [ [ $ch_name ] ] ,
-                                        'icon' => [ { 'src' => $ch_icon } ] });
-       }
-       else
-       {
+#    my $ch_icon=$icons{$ch_did};
+#    if (!$ch_icon)
+#    {
+#        $ch_icon = get_icon($ch_did);
+#    }
+#
+#    if(index($ch_icon, "shim.gif") < 0)
+#    {
+#              $writer->write_channel({ id => $ch_xid,
+#                                       'display-name' => [ [ $ch_name ] ] ,
+#                                       'icon' => [ { 'src' => $ch_icon } ] });
+#      }
+#      else
+#      {
                $writer->write_channel({ id => $ch_xid,
                                         'display-name' => [ [ $ch_name ] ] });
-       }
+#      }
     my $day=UnixDate($now,'%Q');
     for (my $i=0;$i<$opt_days;$i++) {
         push @to_get, [ $day, $ch_xid, $ch_did ];
@@ -428,7 +433,7 @@ sub process_table {
        my $ch_conv_id = convert_id_to_laguiatvid($ch_es_id);
     my $today = UnixDate($date, '%d/%m/%Y');
 
-    my $url = "http://www.laguiatv.com/programacion.php?vertical=1&fecha=$today&cadena=$ch_conv_id";
+    my $url = "http://www.laguiatv.com/programacion/$ch_es_id";
        debug_print "Getting $url\n";
     t $url;
     local $SIG{__WARN__} = sub 
@@ -458,7 +463,7 @@ sub process_table {
        }
 
        if (!$bump_start_day && bump_start_day($cur,$next)) {
-           $bump_start_day=1;
+           #$bump_start_day=1;
            $date = UnixDate(DateCalc($date,"+ 1 day"),'%Q');
        }
     }
@@ -509,134 +514,69 @@ sub get_program_data
     my ($tree) = @_;
     my @data;
 
-       # find schedule table
-       my @tables = $tree->find_by_tag_name("_tag"=>"table");
+    # find schedule table
 
-       foreach my $table (@tables)
-       {
-               my $class = $table->attr('class');
+    my @divs = $tree->find_by_tag_name("_tag"=>"div");
+
+    foreach my $div (@divs)
+    {
+        my $class = $div->attr('class');
                
-               if ($class && $class eq "grid cadena")
-               {
-                       debug_print("Got correct class\n");
-                       my @trs = $table->find_by_tag_name("_tag"=>"tr");
-                       my $state = 1;
-                       my $p_title = "";
-                       my $p_stime = "";
-                       my $p_category = "";
-                       my $p_description = "";
-
-                       foreach my $tr(@trs)
-                       {
-                               my @ths = $tr->find_by_tag_name("_tag"=>"th");
-                               my $nths = @ths;
-                               
-                               debug_print("Got tr with $nths ths\n");
-                               if($nths == 1)
-                               {
-                                       my $class = $ths[0]->attr('scope');
-                                       if($class && $class eq "row")
-                                       {
-                                               # time data
-                                               my @txts = $ths[0]->content_list;
-                                               $p_stime = $txts[0];
-                                               debug_print("Time: ".$p_stime."\n");
-                                       }
-                                       
-                               }
-
-                               my @tds = $tr->find_by_tag_name("_tag"=>"td");
-                               my $ntds = @tds;
-                               
-                               debug_print("Got tr with $ntds tds\n");
-                               foreach my $td(@tds)
-                               {
-                                       my $td_class = $td->attr('row');
-                               
-                                       # title & link data
-                                       debug_print("Got td with parrilla\n");
-
-                                       my @as = $td->find_by_tag_name("_tag"=>"a");
-                                       my $size = @as;
-                                       if($size > 0)
-                                       {
-                                               my $a = $as[0];
-                                               if ($DO_SLOWER_DESC_GET)
-                                               {
-                                                       ($p_description, $p_category) = get_prog_info($a->attr('href'));
-                                               }
-                                               else
-                                               {
-                                                       $p_category = $a->attr('href');
-                                                       $p_category =~ s/^\///;
-                                                       $p_category =~ s/\/.*//;
-                                               }
-
-                                               debug_print "Descript: -".$p_description."-\n";
-                                               if($p_description && $p_description ne '') { debug_print "D\n";}
-                                               debug_print "Category: ".$p_category."\n";
-
-                                               my @atxts = $a->content_list;
-                                               $p_title = $atxts[0];
-
-                                               if($p_title)
-                                               {
-                                                       debug_print("Title: ".$p_title."\n");
-                                               }
-
-                                               if($p_title && $p_title ne "" && $p_stime && $p_stime ne "")
-                                               {
-                                                       my %h = (       time =>         $p_stime,
-                                                                               title=>         $p_title);
-
-                                                       $h{desc} = $p_description if $p_description ne "";
-                                                       $h{category} = $p_category if $p_category ne "";
-                                                       push @data, \%h;
-
-                                                       $p_title = "";
-                                                       $p_stime = "";
-                                                       $p_category = "";
-                                               }
-                                       }
-                                       else
-                                       {
-                                               my @atxts = get_txt_elems($td);
-                                               $p_title = $atxts[0];
-                                               
-                                               if($p_title)
-                                               {
-                                                       debug_print("Title: ".$p_title."\n");
-                                               }
-
-                                               if($p_title && $p_title ne "" && $p_stime && $p_stime ne "")
-                                               {
-                                                       my %h = (       time =>         $p_stime,
-                                                                               title=>         $p_title);
-
-                                                       $h{desc} = $p_description if $p_description ne "";
-                                                       $h{category} = $p_category if $p_category ne "";
-
-                                                       push @data, \%h;
-
-                                                       $p_title = "";
-                                                       $p_stime = "";
-                                                       $p_category = "";
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
+        if ($class && $class eq "clip")
+        {
+            debug_print("Got clip\n");
+            my $p_category = "";
+
+            my @litems = $div->find_by_tag_name("_tag"=>"li"); 
+            foreach my $litem (@litems)
+            {
+                $p_category = $litem->attr('class');
+            }
+
+            my @links = $div->find_by_tag_name("_tag"=>"a");
+
+            foreach my $link (@links)
+            {
+                my @txts = get_txt_elems($link);
+                my $p_title = $txts[0];
+                my ($p_stime, $ignore, $p_etime) = split(/\ /, $txts[1]);
+                my $p_description = "";
+
+                debug_print("title: $p_title start: $p_stime end: $p_etime cat: $p_category c2: " . $categories{$p_category} . "\n");
+                if($p_title && $p_title ne "" && $p_stime && $p_stime ne "")
+                {
+                    my %h = (time =>        $p_stime,
+                             title=>        $p_title);
+
+                    if($p_category && $p_category ne "")
+                    {
+                        my $cat = $categories{$p_category};
+                        if($cat && $cat ne "")
+                        {
+                            $h{category} = $cat;
+                        }
+                    }
+                    $h{desc} = $p_description if $p_description ne "";
+
+                    push @data, \%h;
+
+                    $p_title = "";
+                    $p_stime = "";
+                    $p_category = "";
+                }
+            }
+        }
+    }
     return @data;
 }
 
 sub get_icon 
 {
     my ($ch_did) = @_;
+
+    return "";
        
-    my $ch_xid = convert_id_to_laguiatvid($ch_did);
-       
-    my $url = "http://www.laguiatv.com/programacion.php?vertical=1&cadena=$ch_xid";
+    my $url = "http://www.laguiatv.com/programacion/$ch_did";
        debug_print "Getting $url\n";
     t $url;
     local $SIG{__WARN__} = sub 
@@ -731,7 +671,7 @@ sub get_channels
     my $bar = new XMLTV::ProgressBar({name => 'finding channels', count => 1})
        if not $opt_quiet;
     my %channels;
-    my $url="http://www.laguiatv.com/programacion.php";
+    my $url="http://www.laguiatv.com/programacion";
     t $url;
 
     my $channel_id;
@@ -740,73 +680,43 @@ sub get_channels
 
     my $tree = get_nice_tree $url;
 
-    # Add hard-coded TDT channels (bad chris)
-    foreach $channel_name (@tdt_channels)
-    {
-        $channel_id = convert_laguiatvid_to_id($channel_name);
-        debug_print "Channel $channel_name, id $channel_id\n";
-        # "Factor{icute}a de Ficci{ocute}n Telecinco",
-        $channel_name =~ s/{icute}/\x{00ED}/g;
-        $channel_name =~ s/{ocute}/\x{00F3}/g;
-        $channels{$channel_id}=$channel_name;
-    }
+    my @uls = $tree->find_by_tag_name("_tag"=>"ul");
 
-# <input type="checkbox" name="nacionales1" value="TVE 1"
-# find the channels that are in check boxes
-    my @options = $tree->find_by_tag_name("_tag"=>"input");
-
-    foreach $elem (@options) 
+    foreach my $ul (@uls) 
     {
-        my $ename = $elem->attr('name');
-        my $val = $elem->attr('value');
-        $channel_name = $elem->parent->as_text();
-               
-        if ($ename && $val)
+        my $uclass = $ul->attr('class');
+        if ($uclass && $uclass eq 'channel-list')
         {
-            if ($ename =~ m/^nacionales/)
+            my @links = $ul->find_by_tag_name("_tag"=>"a");
+
+            # <a href="/programacion/intereconomia" title="Intereconomía">
+            foreach my $link (@links) 
             {
-                $channel_id = convert_laguiatvid_to_id($val);
+                $channel_name = $link->attr('title');
+                $channel_id = $link->attr('href');
 
-                debug_print "Channel $channel_name, id $channel_id\n";
-                $channels{$channel_id}=$channel_name;
-            }
-        }
-    }
+                $channel_id =~ s/^\/programacion\///;
 
-    # find the channels that are in drop down lists
-    @options = $tree->find_by_tag_name("_tag"=>"option");
+                my $hide = 0;
+                foreach my $hide_id (@hide_channels)
+                {
+                    if($channel_id =~ m/$hide_id/)
+                    {
+                        $hide = 1;
+                    }
+                }
 
-    foreach $elem (@options) 
-    {
-        my $laguiatv_id = $elem->attr('value');
-        $channel_name = $elem->as_text();
-        my $parent = $elem->parent();
-        my $pname = $parent->attr('name');
-               
-        if ($pname && $laguiatv_id)
-        {
-            if ($pname =~ m/^locales/ ||
-                $pname =~ m/^digitales/ ||
-                $pname =~ m/^autonomicas/)
-           {
-               $channel_id = convert_laguiatvid_to_id($laguiatv_id);
-               $channel_name =~ s/Canal \+/Canal+/;
-               $channel_name =~ s/Canal\+Toros/Canal+ Toros/;
-               $channel_name =~ s/Canal\+Xtra/Canal+ Xtra/;
-
-               debug_print "Channel $channel_name, id $channel_id\n";
-               $channels{$channel_id}=$channel_name;
-           }
+                if($hide == 0)
+                { 
+                    $channels{$channel_id}=$channel_name;
+                    print("Got channel $channel_name with id $channel_id\n");
+                }
+            }
         }
     }
 
     # remove channels that should not be listed
-    foreach $channel_name (@hide_channels)
-    {
-        $channel_id = convert_laguiatvid_to_id($channel_name);
-        delete $channels{$channel_id};
-        delete $icons{$channel_id};
-    }
+
 
     die "no channels could be found" if not keys %channels;
     update $bar if not $opt_quiet;
diff --git a/grab/eu_egon/.cvsignore b/grab/eu_egon/.cvsignore
new file mode 100644 (file)
index 0000000..09c1efe
--- /dev/null
@@ -0,0 +1 @@
+tv_grab_eu_egon
diff --git a/grab/eu_egon/test.conf b/grab/eu_egon/test.conf
new file mode 100644 (file)
index 0000000..343be83
--- /dev/null
@@ -0,0 +1,48 @@
+root-url=http://xmltv.spaetfruehstuecken.org/xmltv/channels.xml.gz
+cachedir=/tmp/.xmltv/cache
+channel=3sat.de
+channel=arte.de
+channel=arteeinsextra.ard.de
+channel=bw.swr.de
+channel=bw.swr1.swr.de
+channel=bw.swr2.swr.de
+channel=bw.swr4.swr.de
+channel!coretime.fm
+channel=dasding.swr.de
+channel=daserste.de
+channel=dkultur.dradio.de
+channel=dlf.dradio.de
+channel=eins-extra.ard.de
+channel=einsfestival.ard.de
+channel=einsplus.ard.de
+channel!hardbase.fm
+channel=hd.arte.de
+channel=hd.daserste.de
+channel=hd.einsfestival.ard.de
+channel=hd.orf1.orf.at
+channel=hd.orf2.orf.at
+channel=hd.zdf.de
+channel!housetime.fm
+channel!info.swr.de
+channel=infokanal.zdf.de
+channel=kika.de
+channel=kultur.zdf.de
+channel=neo.zdf.de
+channel=neokika.zdfmobil.de
+channel=ok54.de
+channel=orf1.orf.at
+channel=orf2.orf.at
+channel=radioseven.se
+channel=radiox.de
+channel=rp.swr.de
+channel=rp.swr1.swr.de
+channel=rp.swr2.swr.de
+channel=rp.swr4.swr.de
+channel=sportplus.orf.at
+channel=sr.swr.de
+channel=swr3.de
+channel=technobase.fm
+channel=tele5.de
+channel!trancebase.fm
+channel=wissen.dradio.de
+channel=zdf.de
diff --git a/grab/eu_egon/tv_grab_eu_egon.PL b/grab/eu_egon/tv_grab_eu_egon.PL
new file mode 100644 (file)
index 0000000..cd13320
--- /dev/null
@@ -0,0 +1,23 @@
+# Generate tv_grab_eu_egon from tv_grab_se_swedb.in. 
+#
+
+use strict;
+
+use IO::File;
+my $out = shift @ARGV; die "no output file given" if not defined $out;
+my $in = 'grab/se_swedb/tv_grab_se_swedb.in';
+my $out_fh = new IO::File "> $out" or die "cannot write to $out: $!";
+my $in_fh = new IO::File "< $in" or die "cannot read $in: $!";
+my $seen = 0;
+while (<$in_fh>) {
+    s/\@\@name/tv_grab_eu_egon/;
+    s/\@\@nspc/          /;
+    s/\@\@country/German speaking area/;
+    s/\@\@desc/German speaking area (Egon zappt)/;
+    s%\@\@url%http://xmltv.spaetfruehstuecken.org/xmltv/channels.xml.gz%;
+    s%\@\@site%http://xmltv.spaetfruehstuecken.org/xmltv/%;
+    print $out_fh $_;
+}
+close $out_fh or die "cannot close $out: $!";
+close $in_fh or die "cannot close $in: $!";
+
index fe29234..80cd7c5 100755 (executable)
@@ -162,13 +162,12 @@ use XMLTV::Memoize; XMLTV::Memoize::check_argv('getstore');
 # set user agent
 $ua->agent("xmltv/$XMLTV::VERSION");
 
-#our $tmp= tempdir( CLEANUP => 1 ) . '/';
-our $tmp= tempdir() . '/';
+our $tmp = tempdir( CLEANUP => 1 ) . '/';
 # set up XML::Twig
-our $epg= new XML::Twig( twig_handlers => { data => \&printepg } );
-our $channels = new XML::Twig( twig_handlers => { data => \&printchannels } );
+our $epg= new XML::Twig( twig_handlers => { data => \&printepg }, output_encoding => 'UTF-8' );
+our $channels = new XML::Twig( twig_handlers => { data => \&printchannels }, output_encoding => 'UTF-8' );
 our %genre;
-our $genre = new XML::Twig( twig_handlers => { data => \&makegenrehash } );
+our $genre = new XML::Twig( twig_handlers => { data => \&makegenrehash }, output_encoding => 'UTF-8' );
 
 # build a hash: epgdata.com channel id -> xmltv channel id
 my $chanids = GetSupplement( 'tv_grab_eu_epgdata', 'channel_ids' );
@@ -191,7 +190,7 @@ my( $opt, $conf ) = ParseOptions( {
     capabilities => [qw/baseline manualconfig tkconfig apiconfig cache preferredmethod/],
     stage_sub => \&config_stage,
     listchannels_sub => \&list_channels,
-    version => '$Id: tv_grab_eu_epgdata,v 1.31 2010/09/04 10:28:44 dekarl Exp $',
+    version => '$Id: tv_grab_eu_epgdata,v 1.36 2012/06/08 13:16:47 yunosh Exp $',
     description => "Parts of Europe (commercial) (www.epgdata.com)",
     preferredmethod => "allatonce",
 } );
@@ -200,12 +199,19 @@ my $pin = $conf->{pin}->[0];
 die 'Sorry, your PIN is not defined. Run tv_grab_eu_epgdata --configure to fix this.\n' unless $pin;
 
 our $tz = $conf->{tz}->[0];
-if (not $tz) {
-    $tz = 'local';
-}
-my $start_stop_parser =
-    DateTime::Format::Strptime->new( pattern => '%Y-%m-%d %H:%M:%S',
-                                     time_zone => $tz );
+# country is determined by the filenames downloaded from the server
+# and used to determine the time zone if not specified in the config
+our $country;
+my %country_tz = (
+    'at', 'Europe/Vienna',
+    'ch', 'Europe/Zurich',
+    'de', 'Europe/Berlin',
+    'es', 'Europe/Madrid',
+    'fr', 'Europe/Paris',
+    'it', 'Europe/Rome',
+    'nl', 'Europe/Amsterdam',
+);
+my $start_stop_parser;
 
 sub config_stage {
     # shamelessly stolen from http://wiki.xmltv.org/index.php/HowtoWriteAGrabber
@@ -232,10 +238,11 @@ sub config_stage {
         id => 'tz', 
         title => [ [ 'Time zone for your EPG data', 'en' ] ],
         description => [ 
-        [ 'Enter your time zone or the time offset from UTC here. 
-        Examples: "local" (your local system timezone), "Europe/Berlin", "+0100". (without quotation marks)',
+        [ 'Enter the time zone or the time offset from UTC of the data here.
+        Your may omit this to activate automatic detection.
+        Examples: "" (to activate automatic detection), "local" (your local system timezone), "Europe/Berlin", "+0100" (without quotation marks)',
             'en' ] ],
-        default => 'local',
+        default => '',
     } );
 
     $configwriter->end( 'select-channels' );
@@ -254,13 +261,29 @@ if (defined $opt->{output}) {
                             die "ERROR: cannot write to $opt->{output}: $!" if not defined $fh;
                             $w_args{OUTPUT} = $fh;
 }
-$w_args{encoding} = 'ISO-8859-1';
+$w_args{encoding} = 'UTF-8';
+$w_args{ENCODING} = 'UTF-8';
 
 our $writer = new XMLTV::Writer(%w_args);
 
+# determine the timezone
+if (not $tz) {
+    $tz = $country_tz{$country} if $country;
+}
+if (not $tz) {
+    warn "Unable to determine country/timezone of data. ",
+         "You may specify tz in your configuration. ",
+         "Falling back to your local system time zone.\n";
+    $tz = 'local';
+}
+warn "tz=", $tz, "\n" if $opt->{debug};
+$start_stop_parser =
+    DateTime::Format::Strptime->new( pattern => '%Y-%m-%d %H:%M:%S',
+                                     time_zone => $tz );
 
-our @xmlfiles = downloadepg($opt->{days},$opt->{offset},$pin);
 prepareinclude($conf,$opt);
+our @xmlfiles = downloadepg($opt->{days},$opt->{offset},$pin);
+exit 1 unless @xmlfiles;
 # it looks like we can also extract the language from the file 
 # name of the epg data
 processxml(@xmlfiles);
@@ -292,6 +315,7 @@ sub downloadepg {
             $expiry_date = $response->{"_headers"}{"x-epgdata-timeout"};
             $channelgroup = sanitize($response->{"_headers"}{"x-epgdata-channelgroup"});
             $filename =~  s/^.*=//;
+            ($country) = ($filename =~ /[^_]*_[^_]*_([^_]*)_[^_]*/) unless $country; # format: xyz########_########_de_qy.zip
 
             warn "filename=", $filename, "\n" if $opt->{debug};
             warn "Downloading zip file for day ", $dataoffset + 1, "\n" unless $opt->{quiet};
@@ -303,10 +327,11 @@ sub downloadepg {
         }
         else {
             warn "No more zip files available for download\n" unless $opt->{quiet};
-            return unzip(@filenames);
+            last;
         }
        $i++;
     }
+    warn "Your PIN will expire around ",  time2str("%C", $expiry_date),"\n" unless $opt->{quiet};
     return unzip(@filenames);
 }
 
@@ -319,7 +344,6 @@ sub prepareinclude {
         . "&dataType=xml";
     warn "Downloading include zip file\n" unless $opt->{quiet};
     getstore($includeurl, $tmp . "includezip");
-    warn "Your PIN will expire around ",  time2str("%C", $expiry_date),"\n" unless $opt->{quiet};
     my @zipfiles=( $tmp . "includezip");
     unzip(@zipfiles)
 }
@@ -391,28 +415,31 @@ sub printepg {
     # BTW: this is not a lot more efficient in our case than looping over a list
     # but a few seconds are better than nothing :)
     if($configuredchannels{$chanid} && $internalregionid == '0') {
-            my $title = decode_entities($sendung->first_child('d19')->text);
-            my $subtitle = decode_entities($sendung->first_child('d20')->text);
-            my $desc = decode_entities($sendung->first_child('d23')->text);
+            my $title = $sendung->first_child('d19')->text;
+            my $subtitle = $sendung->first_child('d20')->text;
+            my $desc = $sendung->first_child('d21')->text;
             my $start = $sendung->first_child('d4')->text;
             my $stop = $sendung->first_child('d5')->text;
+            my $length = $sendung->first_child('d7')->text;
             my $category = $sendung->first_child('d10')->text;
             my $internalgenreid = $sendung->first_child('d25')->text;
             my $age_rating = $sendung->first_child('d16')->text;
             my $star_rating = $sendung->first_child('d30')->text;
             my $wide_aspect = $sendung->first_child('d29')->text;
             my $sequence = $sendung->first_child('d26')->text;
-            my $production_year = decode_entities($sendung->first_child('d33')->text);
+            my $country = $sendung->first_child('d32')->text;
+            my $production_year = $sendung->first_child('d33')->text;
 
             # people
-            my $presenter = decode_entities($sendung->first_child('d34')->text);
-            my $studio_guest = decode_entities($sendung->first_child('d35')->text);
-            my $director = decode_entities($sendung->first_child('d36')->text);
-            my $actor = decode_entities($sendung->first_child('d37')->text);
+            my $presenter = $sendung->first_child('d34')->text;
+            my $studio_guest = $sendung->first_child('d35')->text;
+            my $director = $sendung->first_child('d36')->text;
+            my $actor = $sendung->first_child('d37')->text;
 
             
             # black and white?
             my $bw_colour = $sendung->first_child('d11')->text;
+            my $subtitles = $sendung->first_child('d13')->text;
             my $stereo_audio = $sendung->first_child('d27')->text;
             my $dolby_audio = $sendung->first_child('d28')->text;
             # I was told that technics_hd is supposed to exist
@@ -424,9 +451,12 @@ sub printepg {
                          "stop" => format_start_stop( $stop ), 
                          "title" => [ [ $title ] ]);
 
-             if ( length($subtitle) > 0 ) {
+            if ( length($subtitle) > 0 ) {
                 push @{$prog{'sub-title'}}, [$subtitle];
             }
+            if ( length($length) > 0 ) {
+                $prog{'length'} = $length * 60;
+            }
             
             # use hardcoded categories for mythtv
             if ($category eq "100") {
@@ -438,7 +468,7 @@ sub printepg {
             elsif ($category eq "300") {
                 push @{$prog{'category'}}, ["sports"];
             } 
-            elsif ($category eq "400") {
+            elsif ($category eq "400" || $category eq "500" || $category eq "600") {
                 push @{$prog{'category'}}, ["tvshow"];
             }
            
@@ -452,7 +482,7 @@ sub printepg {
 
             # people
             if ( length($actor)>0 ) {
-                $actor =~ s/\s\(.*\)//g;                    # chop the rolenames
+                $actor =~ s/\s\([^)]*\)//g;                 # chop the rolenames
                 my @actors = split / - /, $actor;           # split people
                 foreach (@actors) { s/^\s+// ; s/\s+$//}    # strip blanks
                     push @{$prog{'credits'}{'actor'}}, @actors;
@@ -480,7 +510,7 @@ sub printepg {
             # valid values seem to be 1 to 5
             # 2 is never used
             if ( $star_rating gt 0 ) {
-                $prog{'star-rating'} = ["$star_rating/5"];
+                $prog{'star-rating'} = [($star_rating - 1) . "/4"];
             }
 
             if ( $age_rating gt 0 ) {
@@ -489,10 +519,14 @@ sub printepg {
 
             if ($wide_aspect == 1 ) {
                 $prog{'video'}->{'aspect'} = '16:9';
+            } else {
+                $prog{'video'}->{'aspect'} = '4:3';
             }
 
             if ($bw_colour == 1 ) {
-                $prog{'video'}->{'colour'} = '0';
+                $prog{'video'}->{'colour'} = 0;
+            } else {
+                $prog{'video'}->{'colour'} = 1;
             }
 
             if ( $sequence gt 0 ) {
@@ -509,12 +543,23 @@ sub printepg {
             # Also, what does dolby mean in this context? 
             # How does it apply to analog broadcasts?
             if ($dolby_audio == 1) {
-                 $prog{'audio'}->{'stereo'} = 'dolby';
+                $prog{'audio'}->{'stereo'} = 'dolby digital';
             }
             elsif ($stereo_audio == 1) {
                 $prog{'audio'}->{'stereo'} = 'stereo';
             }
 
+            if ($subtitles == 1) {
+                $prog{'subtitles'} = [ { type => 'teletext' } ];
+            }
+
+            if ( length($country) > 0 ) {
+                my @countries = split /\|/, $country;
+                foreach (@countries) {
+                    push @{$prog{'country'}}, [$_];
+                }
+            }
+
             if ( length($production_year) > 0 ) {
                 $production_year =~ s/(\d*).*/$1/;     #take only first year
                 $prog{'date'} = $production_year;
@@ -542,10 +587,12 @@ sub printchannels {
     # FIXME: not sure if this is correct.
     # Maybe we should just return if we don't know the channel id
     }
-    my $name = decode_entities($sendung->first_child('ch0')->text); 
+    my $name1 = decode_entities($sendung->first_child('ch11')->text); 
+    my $name2 = decode_entities($sendung->first_child('ch0')->text); 
+    my $name3 = decode_entities($sendung->first_child('ch1')->text); 
     foreach my $channel (@{$conf->{channel}}) {
         if($channel eq $chanid) {
-        my %ch = (id => $chanid, 'display-name' => [ [ $name ] ]); 
+        my %ch = (id => $chanid, 'display-name' => [ [$name1], [$name2], [$name3] ]); 
         $writer->write_channel(\%ch);
         }
     }
index ee63c74..a6f2476 100644 (file)
@@ -6,7 +6,7 @@
 #
 # Setup
 #
-# VERSION: $Id: common.pm,v 2.00 2011/03/10 21:20:11 stefanb2 Exp $
+# VERSION: $Id: common.pm,v 2.01 2011/10/10 16:38:57 stefanb2 Exp $
 #
 # INSERT FROM HERE ############################################################
 package fi::common;
@@ -55,19 +55,48 @@ use XMLTV::Get_nice;
 }
 
 # Fetch URL as UTF8 encoded string
-sub fetchRaw($;$) {
-  my($url, $encoding) = @_;
+sub fetchRaw($;$$) {
+  my($url, $encoding, $nofail) = @_;
   debug(2, "Fetching URL '$url'");
-  my $content = eval { decode($encoding || "utf8", get_nice($url)) };
-  croak "fetchRaw(): $@" if $@;
+  my $content;
+  my $retries = 5; # this seems to be enough?
+ RETRY:
+  while (1) {
+      eval {
+         local $SIG{ALRM} = sub { die "Timeout" };
+
+         # Default TCP timeouts are too long. If we don't get a response
+         # within 20 seconds, then that's usually an indication that
+         # something is really wrong on the server side.
+         alarm(20);
+         $content = get_nice($url);
+         alarm(0);
+      };
+
+      unless ($@) {
+         # Everything is OK
+         $content = decode($encoding || "utf8", $content);
+         last RETRY;
+      } elsif (($@ =~ /error: 500 Timeout/) && $retries--) {
+         # Let's try this one more time
+         carp "fetchRaw(): timeout. Retrying...";
+      } elsif ($nofail) {
+         # Caller requested not to fail
+         $content = "";
+         last RETRY;
+      } else {
+         # Fail on everything else
+         croak "fetchRaw(): $@";
+      }
+  }
   debug(5, $content);
   return($content);
 }
 
 # Fetch URL as parsed HTML::TreeBuilder
-sub fetchTree($;$) {
-  my($url, $encoding) = @_;
-  my $content = fetchRaw($url, $encoding);
+sub fetchTree($;$$) {
+  my($url, $encoding, $nofail) = @_;
+  my $content = fetchRaw($url, $encoding, $nofail);
   my $tree = HTML::TreeBuilder->new();
   local $SIG{__WARN__} = sub { carp("fetchTree(): $_[0]") };
   $tree->parse($content) or croak("fetchTree() parse failure for '$url'");
index 9ddb748..7feffb3 100644 (file)
@@ -6,7 +6,7 @@
 #
 # Setup
 #
-# VERSION: $Id: programme.pm,v 2.00 2011/03/10 21:20:11 stefanb2 Exp $
+# VERSION: $Id: programme.pm,v 2.01 2012/02/11 20:31:39 stefanb2 Exp $
 #
 # INSERT FROM HERE ############################################################
 package fi::programme;
@@ -90,6 +90,7 @@ sub _epoch_to_xmltv_time($) {
 my %series_description;
 my %series_title;
 my @title_map;
+my $title_strip_parental;
 
 sub dump {
   my($self, $writer) = @_;
@@ -102,6 +103,10 @@ sub dump {
   #
   # Programme post-processing
   #
+  # Parental level removal (catch also the duplicates)
+  $title =~ s/(?:\s+\((?:S|T|7|9|12|16|18)\))+\s*$//
+      if $title_strip_parental;
+  #
   # Title mapping
   #
   foreach my $map (@title_map) {
@@ -216,14 +221,22 @@ sub parseConfigLine {
       # Unknown series configuration
       return;
     }
-  } elsif (($command eq "title") &&
-          ($keyword eq "map")   &&
-          # Accept "title" and 'title' for each parameter
-          (my(undef, $from, undef, $to) =
-           ($param =~ /^([\'\"])([^\1]+)\1\s+([\'\"])([^\3]+)\3/))) {
-    debug(3, "title mapping from '$from' to '$to'");
-    $from = qr/^\Q$from\E/;
-    push(@title_map, sub { $_[0] =~ s/$from/$to/ });
+  } elsif ($command eq "title") {
+      if (($keyword eq "map") &&
+         # Accept "title" and 'title' for each parameter
+         (my(undef, $from, undef, $to) =
+          ($param =~ /^([\'\"])([^\1]+)\1\s+([\'\"])([^\3]+)\3/))) {
+         debug(3, "title mapping from '$from' to '$to'");
+         $from = qr/^\Q$from\E/;
+         push(@title_map, sub { $_[0] =~ s/$from/$to/ });
+      } elsif (($keyword eq "strip") &&
+              ($param   =~ /parental\s+level/)) {
+         debug(3, "stripping parental level from titles");
+         $title_strip_parental++;
+      } else {
+         # Unknown title configuration
+         return;
+      }
   } else {
     # Unknown command
     return;
index ea26122..6a6acbc 100644 (file)
@@ -6,7 +6,7 @@
 #
 # Setup
 #
-# VERSION: $Id: mtv3.pm,v 2.00 2011/03/10 21:20:11 stefanb2 Exp $
+# VERSION: $Id: mtv3.pm,v 2.02 2012/05/06 15:08:03 stefanb2 Exp $
 #
 # INSERT FROM HERE ############################################################
 package fi::source::mtv3;
@@ -84,7 +84,7 @@ sub _toEpoch($$) {
 
 # Grab one day
 sub grab {
-  my($self, $id, $yesterday, $today, $tomorrow) = @_;
+  my($self, $id, $yesterday, $today, $tomorrow, $offset) = @_;
 
   # Get channel number from XMLTV id
   return unless my($channel, $page) = ($id =~ /^(\d+)\.([^.]+)\.mtv3\.fi$/);
@@ -127,7 +127,7 @@ sub grab {
        foreach my $cell (@cells) {
          if (my @programmes = $cell->look_down("class" => qr/^ohjelma/)) {
            foreach my $programme (@programmes) {
-             my $title = $programme->look_down("class" => "nimi");
+             my $title = $programme->look_down("class" => qr/^nimi/);
              my $time  = $programme->look_down("class" => "tvsel_aika");
 
              if ($title && $time &&
index 14214f0..7df2f6f 100644 (file)
@@ -6,7 +6,7 @@
 #
 # Setup
 #
-# VERSION: $Id: telkku.pm,v 2.00 2011/03/10 21:20:11 stefanb2 Exp $
+# VERSION: $Id: telkku.pm,v 2.01 2011/10/10 16:38:57 stefanb2 Exp $
 #
 # INSERT FROM HERE ############################################################
 package fi::source::telkku;
@@ -74,9 +74,74 @@ sub channels {
   return;
 }
 
+#
+# http://www.telkku.com/movie contains information about (all?) movies for
+# today and the next 7 days, i.e. offsets 0 to 7. We extract the URL to the
+# detailed programme information (http://www.telkku.com/program/show/......)
+# that can then be used to identify movies when processing programme entries.
+#
+{
+  my %ids;
+
+  sub _getMovieIDsForOffset($) {
+    my($offset) = @_;
+
+    # There is only data for the next 7 days
+    return({}) if $offset > 7;
+
+    # Reuse cached data
+    return(\%ids) if %ids;
+
+    # In order to reduce website traffic, we only try this once
+    $ids{__DUMMY_ID_THAT_NEVER_MATCHES__}++;
+
+    # Fetch & parse HTML
+    # This is entirely optional, so please don't abort on failure...
+    my $root = fetchTree("http://www.telkku.com/movie", undef, 1);
+    if ($root) {
+      my $test;
+
+      #
+      # Document structure for movie entries:
+      #
+      # <div id="movieItems">
+      #   ...
+      #   <div class="movieItem">
+      #     <span class="heading">
+      #       <a href="http://www.telkku.fi/program/show/2011100211009">Aikuinen nainen</a>
+      #     </span>
+      #     ...
+      #   </div>
+      #   ...
+      # </div>
+      #
+      if (my @list = $root->look_down("class" => "movieItem")) {
+       debug(2, "Source telkku.com found " . scalar(@list) . " movies");
+       foreach my $list_entry (@list) {
+         if (my $heading = $list_entry->look_down("class" => "heading")) {
+           if (my $link = $heading->find("a")) {
+             my $href = $link->attr("href");
+             if (defined($href) && length($href)) {
+               debug(3, "movie ID: " . $href);
+               $ids{$href}++;
+             }
+           }
+         }
+       }
+      }
+
+      # Done with the HTML tree
+      $root->delete();
+    }
+
+    debug(2, "Source telkku.com parsed " . (scalar(keys %ids) - 1) . " movies");
+    return(\%ids);
+  }
+}
+
 # Grab one day
 sub grab {
-  my($self, $id, $yesterday, $today, $tomorrow) = @_;
+  my($self, $id, $yesterday, $today, $tomorrow, $offset) = @_;
 
   # Get channel number from XMLTV id
   return unless my($channel) = ($id =~ /^(\d+)\.telkku\.com$/);
@@ -84,6 +149,7 @@ sub grab {
   # Fetch & parse HTML
   my $root = fetchTree("http://www.telkku.com/channel/list/$channel/$today");
   if ($root) {
+    my $movie_ids = _getMovieIDsForOffset($offset);
 
     #
     # All program info is contained within a unsorted list with class "programList"
@@ -103,21 +169,27 @@ sub grab {
          my $date = $list_entry->look_down("class", "programDate");
          my $desc = $list_entry->look_down("class", "programDescription");
          if ($date && $desc) {
-           my $href = $date->find("a");
-           if ($href) {
+           my $link = $date->find("a");
+           if ($link) {
 
              # Extract texts from HTML elements. Entities are already decoded.
-             $date = $href->as_text();
+             $date = $link->as_text();
              $desc = $desc->as_text();
 
              # Use "." to match &nbsp; character (it's not included in \s?)
              if (my($hour, $minute, , $title) =
                  $date =~ /^(\d{2}):(\d{2}).(.+)/) {
+               my $href     = $link->attr("href");
+               my $category = (defined($href) && exists($movie_ids->{$href})) ?
+                   "elokuvat" : undef;
+
                debug(3, "List entry $channel ($hour:$minute) $title");
                debug(4, $desc);
+               debug(4, $category) if defined $category;
 
                # Only record entry if title isn't empty
-               appendProgramme($opaque, $hour, $minute, $title, undef, $desc)
+               appendProgramme($opaque, $hour, $minute, $title, $category,
+                               $desc)
                  if length($title) > 0;
              }
            }
index bb47336..b52aa51 100644 (file)
@@ -6,7 +6,7 @@
 #
 # Setup
 #
-# VERSION: $Id: telvis.pm,v 2.00 2011/03/10 21:20:11 stefanb2 Exp $
+# VERSION: $Id: telvis.pm,v 2.02 2011/10/10 16:38:57 stefanb2 Exp $
 #
 # INSERT FROM HERE ############################################################
 package fi::source::telvis;
@@ -72,7 +72,7 @@ sub channels {
 
 # Grab one day
 sub grab {
-  my($self, $id, $yesterday, $today, $tomorrow) = @_;
+  my($self, $id, $yesterday, $today, $tomorrow, $offset) = @_;
 
   # Get channel number from XMLTV id
   return unless my($channel) = ($id =~ /^([^.]+)\.telvis\.fi$/);
@@ -116,7 +116,7 @@ sub grab {
              $title = $title->as_text();
              if (my($hour, $minute) = ($start =~ /^(\d{2}):(\d{2})/)) {
                my $desc  = $columns[1]->as_text(); # includes $title
-               $desc =~ s/^$title\s+//;
+               $desc =~ s/^\Q$title\E\s+//;
                debug(3, "List entry $channel ($hour:$minute) $title");
                debug(4, $desc);
 
index 80c3576..6e78485 100644 (file)
@@ -1,12 +1,12 @@
 # -*- mode: perl; coding: utf-8 -*- ###########################################
 #
-# tv_grab_fi: source specific grabber code for http://www.tvnyt.fi
+# tv_grab_fi: source specific grabber code for http://tv.nyt.fi
 #
 ###############################################################################
 #
 # Setup
 #
-# VERSION: $Id: tvnyt.pm,v 2.01 2011/03/11 08:20:05 stefanb2 Exp $
+# VERSION: $Id: tvnyt.pm,v 2.05 2012/01/19 14:55:37 stefanb2 Exp $
 #
 # INSERT FROM HERE ############################################################
 package fi::source::tvnyt;
@@ -18,162 +18,194 @@ BEGIN {
 }
 
 use Carp;
-use HTML::Entities qw(decode_entities);
-use JSON qw(-support_by_pp); # enable allow_barekey() for JSON:XS
 
 # Import from internal modules
 fi::common->import();
 
 # Description
-sub description { 'tvnyt.fi' }
-
-# Copied from Javascript code. No idea why we should do this...
-sub _timestamp() {
-  # This obviously breaks caching. Use constant value instead
-  #return("timestamp=" . int(rand(10000)));
-  return("timestamp=0");
-}
+sub description { 'tv.nyt.fi' }
 
 # Grab channel list
 sub channels {
+  my %channels;
+  my @groups = ( "free_air_fi" );
+  my $added;
+
+  # Next group
+  while (defined(my $group = shift(@groups))) {
+
+    # Fetch & parse HTML
+    my $root = fetchTree("http://tv.nyt.fi/grid?service=tvnyt&grid_type=list&layout=false&group=$group");
+    if ($root) {
+
+      #
+      # Group list can be found in dropdown
+      #
+      #  <select id="group_select" ...>
+      #   <option value="tvnyt*today*free_air_fi*list" selected>...</option>
+      #   <option value="tvnyt*today*sanoma_fi*list">...</option>
+      #   ...
+      #  </select>
+      #
+      unless ($added) {
+       if (my $container = $root->look_down("id" => "group_select")) {
+         if (my @options = $container->find("option")) {
+           debug(2, "Source tv.nyt.fi found " . scalar(@options) . " groups");
+            foreach my $option (@options) {
+             unless ($option->attr("selected")) {
+               my $value = $option->attr("value");
+
+               if (defined($value) &&
+                   (my($tag) = ($value =~ /^tvnyt\*today\*(\w+)\*/))) {
+                 debug(3, "group '$tag'");
+                 push(@groups, $tag);
+               }
+             }
+           }
+         }
+       }
+       $added++;
+      }
+
+      #
+      # Channel list can be found in table headers
+      #
+      #  <table class="grid_table" cellspacing="0px">
+      #   <thead>
+      #    <tr>
+      #     <th class="yle_tv1">...</th>
+      #     <th class="yle_tv2">...</th>
+      #     ...
+      #    </tr>
+      #   </thead>
+      #   ...
+      #  </table>
+      #
+      if (my $container = $root->look_down("class" => "grid_table")) {
+       my $head = $container->find("thead");
+       if ($head && (my @headers = $head->find("th"))) {
+         debug(2, "Source tv.nyt.fi found " . scalar(@headers) . " channels in group '$group'");
+         foreach my $header (@headers) {
+             if (my $image = $header->find("img")) {
+               my $name = $image->attr("alt");
+               my $channel_id = $header->attr("class");
+
+               if (defined($channel_id) && length($channel_id) &&
+                   defined($name)       && length($name)) {
+                 debug(3, "channel '$name' ($channel_id)");
+
+                 # Underscore is not a valid XMLTV channel ID character
+                 ($channel_id = "${channel_id}.${group}.tv.nyt.fi") =~ s/_/-/g;
+
+                 $channels{$channel_id} = "fi $name";
+               }
+             }
+           }
+       }
+      }
+
+      # Done with the HTML tree
+      $root->delete();
+    }
 
-  # Fetch JavaScript code as raw file
-  my $content = fetchRaw("http://www.tvnyt.fi/ohjelmaopas/wp_channels.js?" . _timestamp());
-  if (length($content)) {
-    my $count = 0;
-    # 1) pattern match JS arrays (example: ["1","TV1","tv1.gif"] -> 1, "TV1")
-    # 2) even entries in the list are converted to XMLTV ID
-    # 3) fill hash from list (even -> key [id], odd -> value [name])
-    my %channels = (
-                   map { ($count++ % 2) == 0 ? "$_.tvnyt.fi" : "fi $_" }
-                     $content =~ /\["(\d+)","([^\"]+)","[^\"]+"\]/g
-                  );
-    debug(2, "Source tvnyt.fi parsed " . scalar(keys %channels) . " channels");
-    return(\%channels);
   }
 
-  return;
+  debug(2, "Source tv.nyt.fi parsed " . scalar(keys %channels) . " channels");
+  return(\%channels);
 }
 
-# Parse time stamp and convert to Epoch using local time zone
-#
-# Example time stamp: 20101218040000
-#
-sub _toEpoch($) {
-  my($string) = @_;
-  return unless defined($string);
-  return unless my($year, $month, $day, $hour, $minute) =
-    ($string =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})\d{2}$/);
-  return(fullTimeToEpoch($year, $month, $day, $hour, $minute));
+# Parse time and convert to seconds since midnight
+sub _toEpoch($$$$) {
+  my($today, $tomorrow, $time, $switch) = @_;
+  my($hour, $minute) = ($time =~ /^(\d{2})(\d{2})$/);
+  return(timeToEpoch($switch ? $tomorrow : $today, $hour, $minute));
 }
 
-# Category number to name map
-my %category_map = (
-                   0 => undef,
-                   1 => "dokumentit",
-                   2 => "draama",
-                   3 => "lapset",
-                   4 => "uutiset",
-                   5 => "urheilu",
-                   6 => "vapaa aika",
-                  );
-
 # Grab one day
 sub grab {
-  my($self, $id, $yesterday, $today, $tomorrow) = @_;
+  my($self, $id, $yesterday, $today, $tomorrow, $offset) = @_;
 
   # Get channel number from XMLTV id
-  return unless my($channel) = ($id =~ /^(\d+)\.tvnyt\.fi$/);
+  return unless my($channel, $group) = ($id =~ /^(\w+)\.(\w+)\.tv\.nyt\.fi$/);
 
-  # Fetch JavaScript code as raw file
-  my $content = fetchRaw("http://www.tvnyt.fi/ohjelmaopas/getChannelPrograms.aspx?channel=$channel&start=${today}0000&" . _timestamp());
-  if (length($content)) {
-    # Accept "x:.." instead of the correct "'x':..."
-    my $parser = JSON->new()->allow_barekey();
+  # Replace Dash with Underscore for URL
+  $channel =~ s/-/_/g;
+  $group   =~ s/-/_/g;
 
-    # Fixup data
-    $content =~ s/\\/\\\\/g; # some string contain illegal escapes
+  # Fetch & parse HTML
+  my $root = fetchTree("http://tv.nyt.fi/grid?service=tvnyt&grid_type=list&layout=false&group=$group&date=" .
+                      sprintf("%04d-%02d-%02d",
+                              $today->year(), $today->month(), $today->day()));
+  if ($root) {
+    my @objects;
 
-    # Parse data
-    my $data   = eval {
-      $parser->decode($content)
-    };
-    croak "JSON parse error: $@" if $@;
-    undef $parser;
-
-    #
-    # Program information is encoded in JSON:
     #
-    # {
-    #  1: [
-    #      {
-    #       id:       "17111541",
-    #       desc:     "&#x20;",
-    #       title:    "Uutisikkuna",
-    #       category: "0",
-    #       start:    "20101218040000",
-    #       stop:     "20101218080000"
-    #      },
-    #      ...
-    #     ]
-    # }
+    # Programme data is contained inside a table cells with class="<channel>"
     #
-    # - the first entry always starts on $today.
-    # - the last entry is a duplicate of the first entry on $tomorrow. We drop
-    #   it to avoid duplicate programme entries.
+    #  <td class="yle_tv1">
+    #   <table class="be_list_table">
+    #    <tr class="s1210 e1230"> (start/end time, "+" for tomorrow)
+    #     <td class="be_time">12:10</td>
+    #     <td class="be_entry">
+    #      <span class="thb1916041"></span>
+    #      <span class="flw6390"></span>
+    #      <a href="/programs/show/1916041" class="program_link colorbox tip">
+    #       Hercules... (title)
+    #      </a>
+    #      <span class="tooltip">
+    #       <span class="wl_actions">...</span>
+    #       <span class="wl_synopsis">
+    #        Dokumenttielokuva bulgarialaisen perheen... (long description)
+    #       </span>
+    #      </span>
+    #      <span class="syn">
+    #       Dokumenttielokuva bulgarialaisen... (short description)
+    #      </span>
+    #     </td>
+    #    </tr>
+    #   ...
+    #   </table>
+    #  </td>
     #
-    # Category types:
-    #
-    #   0 - unknown
-    #   1 - dokumentit (documentary)
-    #   2 - draama     (drama)
-    #   3 - lapset     (children)
-    #   4 - uutiset    (news)
-    #   5 - urheilu    (sports)
-    #   6 - vapaa aika (recreational)
-    #
-    # Verify top-level of data structure
-    if ((ref($data) eq "HASH") &&
-       (exists $data->{1})    &&
-       (ref($data->{1}) eq "ARRAY")) {
-
-      my @objects;
-      foreach my $array_entry (@{ $data->{1} }) {
-       my $start = $array_entry->{start};
-       my $stop  = $array_entry->{stop};
-       my $title = decode_entities($array_entry->{title});
-       my $desc  = decode_entities($array_entry->{desc});
-
-       # Sanity check
-       # Drop "no programm" entries
-       if (($start = _toEpoch($start)) &&
-           ($stop  = _toEpoch($stop))  &&
-           length($title)              &&
-           ($title ne "Ei ohjelmaa.")) {
-         my $category = $array_entry->{category};
-
-         debug(3, "List entry $channel ($start -> $stop) $title");
-         debug(4, $desc);
-
-         # Map category number to name
-         $category = $category_map{$category} if defined($category);
-
-         # Create program object
-         my $object = fi::programme->new($id, "fi", $title, $start, $stop);
-         $object->category($category);
-         $object->description($desc);
-         push(@objects, $object);
+    if (my @cells = $root->look_down("class" => $channel,
+                                    "_tag"  => "td")) {
+      foreach my $cell (@cells) {
+       foreach my $row ($cell->find("tr")) {
+         my $start_stop = $row->attr("class");
+         my $entry      = $row->look_down("class" => "be_entry");
+          if (defined($start_stop) && $entry &&
+             (my($start, $stomorrow, $end, $etomorrow) =
+              ($start_stop =~ /^s(\d{4})(\+?)\s+e(\d{4})(\+?)$/))) {
+           my $title = $entry->look_down("class" => qr/program_link/);
+            my $desc  = $entry->look_down("class" => "wl_synopsis");
+           if ($title) {
+             $title = $title->as_text();
+              if (length($title)) {
+               $start = _toEpoch($today, $tomorrow, $start, $stomorrow);
+               $end   = _toEpoch($today, $tomorrow, $end,   $etomorrow);
+               $desc  = $desc->as_text() if $desc;
+
+               debug(3, "List entry ${channel}.${group} ($start -> $end) $title");
+               debug(4, $desc);
+
+               # Create program object
+               my $object = fi::programme->new($id, "fi", $title, $start, $end);
+               $object->description($desc);
+               push(@objects, $object);
+             }
+           }
+         }
        }
       }
+    }
 
-      # Drop last entry
-      pop(@objects);
+    # Done with the HTML tree
+    $root->delete();
 
-      # Fix overlapping programmes
-      fi::programme->fixOverlaps(\@objects);
+    # Fix overlapping programmes
+    fi::programme->fixOverlaps(\@objects);
 
-      return(\@objects);
-    }
+    return(\@objects);
   }
 
   return;
index 4a9453e..888249e 100644 (file)
@@ -6,7 +6,7 @@
 #
 # Setup
 #
-# VERSION: $Id: yle.pm,v 2.00 2011/03/10 21:20:11 stefanb2 Exp $
+# VERSION: $Id: yle.pm,v 2.01 2011/10/10 16:38:57 stefanb2 Exp $
 #
 # INSERT FROM HERE ############################################################
 package fi::source::yle;
@@ -119,7 +119,7 @@ sub _parseCategories($$) {
 
 # Grab one day
 sub grab {
-  my($self, $id, $yesterday, $today, $tomorrow) = @_;
+  my($self, $id, $yesterday, $today, $tomorrow, $offset) = @_;
 
   # Get channel number from XMLTV id
   return unless my($channel, $language) = ($id =~ /^([^.]+)\.([^.]+)\.yle\.fi$/);
index 635a5b3..88431c2 100644 (file)
@@ -2,13 +2,13 @@
 channel 1.telkku.com TV1
 channel tv1.fi.yle.fi TV1
 channel tv1.se.yle.fi TV1
-channel 1.tvnyt.fi TV1
+channel yle-tv1.free-air-fi.tv.nyt.fi TV1
 channel tv1.telvis.fi TV1
 channel 1.index.mtv3.fi TV1
 #channel 10.telkku.com YLE Teema
 #channel yte.fi.yle.fi YLE Teema
 #channel yte.se.yle.fi YLE Teema
-#channel 7.tvnyt.fi YLE Teema
+#channel yle-teema.free-air-fi.tv.nyt.fi YLE Teema
 #channel yleteema.telvis.fi YLE Teema
 #channel 3.avalivteemafstjim.mtv3.fi YLE Teema
 #channel 100.telkku.com RTL
@@ -25,7 +25,7 @@ channel 1.index.mtv3.fi TV1
 channel 2.telkku.com TV2
 channel tv2.fi.yle.fi TV2
 channel tv2.se.yle.fi TV2
-channel 2.tvnyt.fi TV2
+channel yle-tv2.free-air-fi.tv.nyt.fi TV2
 channel tv2.telvis.fi TV2
 channel 2.index.mtv3.fi TV3
 #channel 20.telkku.com Eurosport
@@ -41,7 +41,7 @@ channel 2.index.mtv3.fi TV3
 channel 3.telkku.com MTV3
 channel mtv.fi.yle.fi MTV3
 channel mtv.se.yle.fi MTV3
-channel 3.tvnyt.fi MTV3
+channel bonnier-mtv3.free-air-fi.tv.nyt.fi MTV3
 channel mtv3.telvis.fi MTV3
 channel 3.index.mtv3.fi MTV3
 #channel 30.telkku.com CANAL+ Action
@@ -57,7 +57,7 @@ channel 3.index.mtv3.fi MTV3
 #channel 4.telkku.com Nelonen
 #channel nel.fi.yle.fi Nelonen
 #channel nel.se.yle.fi Nelonen
-#channel 4.tvnyt.fi Nelonen
+#channel sanoma-nelonen.free-air-fi.tv.nyt.fi Nelonen
 #channel nelonen.telvis.fi Nelonen
 #channel 4.index.mtv3.fi Nelonen
 #channel 40.telkku.com TV1000 Nordic
@@ -73,7 +73,7 @@ channel 3.index.mtv3.fi MTV3
 #channel 5.telkku.com Sub
 #channel sub.fi.yle.fi Sub
 #channel sub.se.yle.fi Sub
-#channel 6.tvnyt.fi Sub
+#channel bonnier-subtv.free-air-fi.tv.nyt.fi Sub
 #channel sub.telvis.fi Sub
 #channel 5.index.mtv3.fi Sub
 #channel 50.telkku.com Viasat History
@@ -89,7 +89,7 @@ channel 3.index.mtv3.fi MTV3
 #channel 6.telkku.com FST5
 #channel fsd.fi.yle.fi FST5
 #channel fsd.se.yle.fi FST5
-#channel 5.tvnyt.fi FST5
+#channel yle-fst5.free-air-fi.tv.nyt.fi FST5
 #channel fst5.telvis.fi FST5
 #channel 4.avalivteemafstjim.mtv3.fi FST5
 #channel 60.telkku.com Playhouse Disney
@@ -105,7 +105,7 @@ channel 3.index.mtv3.fi MTV3
 #channel 7.telkku.com JIM
 #channel nep.fi.yle.fi JIM
 #channel nep.se.yle.fi JIM
-#channel 14.tvnyt.fi JIM
+#channel sanoma-jim.free-air-fi.tv.nyt.fi JIM
 #channel jim.telvis.fi JIM
 #channel 5.avalivteemafstjim.mtv3.fi JIM
 #channel 70.telkku.com CNBC
@@ -121,7 +121,6 @@ channel 3.index.mtv3.fi MTV3
 #channel 8.telkku.com 4 Sport
 #channel ur1.fi.yle.fi 4 Sport
 #channel ur1.se.yle.fi 4 Sport
-#channel 9.tvnyt.fi 4 Sport
 #channel urheilukanava.telvis.fi Nelonen Sport
 #channel 1.urheilu.mtv3.fi Nelonen Sport
 #channel 80.telkku.com Deutsche Welle
@@ -135,7 +134,7 @@ channel 3.index.mtv3.fi MTV3
 #channel 88.telkku.com TV5 Monde
 #channel 89.telkku.com Fashion TV
 #channel 9.telkku.com The Voice / TV Viisi
-#channel 10.tvnyt.fi The Voice / TV Viisi
+#channel sbs-viisi.free-air-fi.tv.nyt.fi The Voice / TV Viisi
 #channel thevoicetvviisi.telvis.fi The Voice / TV Viisi
 #channel 90.telkku.com Playboy TV
 #channel 91.telkku.com SVT 1
@@ -154,6 +153,9 @@ channel 3.index.mtv3.fi MTV3
 title map "70’s show" "70's show"
 title map "70s show"  "70's show"
 
+# Strip parental level from titles
+title strip parental level
+
 # Series definitions
 series description 70's show
 series title Prisma
index c3b7f1f..37639bb 100755 (executable)
@@ -15,6 +15,13 @@ check_log() {
        test_failure=1
     fi
 }
+validate_xml() {
+    local xml=$1
+    ${xmltv_script}/tv_validate_file $xml
+    if [ $? -ne 0 ]; then
+       test_failure=1
+    fi
+}
 
 # Configuration
 set -e
@@ -38,7 +45,7 @@ for arg in $*; do
        reuse)
            preserve_directory=1
            ;;
-       
+
        *)
            echo 1>&2 "unknown option '$arg"
            exit 1
@@ -69,6 +76,7 @@ perl -I ${xmltv_lib} ${script_file} --ahdmegkeja > /dev/null 2>&1
 perl -I ${xmltv_lib} ${script_file} --version > /dev/null 2>&1
 perl -I ${xmltv_lib} ${script_file} --description > /dev/null 2>&1
 perl -I ${xmltv_lib} ${script_file} --config-file ${script_dir}/test.conf --offset 1 --days 2 --cache  t_fi_cache  > t_fi_1_2.xml --quiet 2>t_fi_1.log
+validate_xml t_fi_1_2.xml
 ${xmltv_script}/tv_cat t_fi_1_2.xml > /dev/null 2>t_fi_6.log
 check_log t_fi_6.log
 ${xmltv_script}/tv_sort --duplicate-error t_fi_1_2.xml > t_fi_1_2.sorted.xml 2>t_fi_1_2.sort.log
@@ -86,8 +94,9 @@ check_log t_fi__1_2.diff
 #
 # Modified test run with 9 days and modified test.conf
 #
-perl -pe 's/^#(channel\s+(?:4|5|6|7|8|9|10|11|12|.+\.yle|.+\.telvis|.+\.mtv3)\..+)/$1/' <${script_dir}/test.conf >${test_dir}/test.conf
+perl -pe 's/^#(channel\s+(?:4|5|6|7|8|9|10|11|12|.+\.yle|.+\.telvis|.+\.tv\.nyt|.+\.mtv3)\..+)/$1/' <${script_dir}/test.conf >${test_dir}/test.conf
 perl -I ${xmltv_lib} ${script_file} --config-file ${test_dir}/test.conf --offset 1 --days 9 --cache  t_fi_cache  >t_fi_full_10.xml --quiet 2>t_fi_full.log
+validate_xml t_fi_full_10.xml
 for d in $(seq 1 9); do
     perl -I ${xmltv_lib} ${script_file} --config-file ${test_dir}/test.conf --offset $d --days 1 --cache  t_fi_cache  >t_fi_single_$d.xml --quiet 2>>t_fi_single.log
 done
index ff97ceb..638e256 100755 (executable)
@@ -8,7 +8,7 @@ use 5.008; # we process Unicode texts
 use strict;
 use warnings;
 
-use constant VERSION => '$Id: tv_grab_fi.pl,v 2.00 2011/03/10 21:20:11 stefanb2 Exp $ ';
+use constant VERSION => '$Id: tv_grab_fi.pl,v 2.02 2012/02/11 20:31:39 stefanb2 Exp $ ';
 
 ###############################################################################
 # INSERT: SOURCES
@@ -352,7 +352,8 @@ sub doGrab() {
       debug(1, "Fetching day $dates->[$i]");
       foreach my $source (@sources) {
        if (my $programmes = $source->grab($id,
-                                          @{ $dates }[$i - 1..$i + 1])) {
+                                          @{ $dates }[$i - 1..$i + 1],
+                                          $Option{offset} + $i - 1)) {
 
          if (@{ $programmes }) {
            # Add channel ID & name (once)
@@ -578,6 +579,15 @@ processing.
 
 =back
 
+=item B<title strip parental level>
+
+At the beginning of 2012 some programme descriptions started to include
+parental levels at the end of the title, e.g. C<(S)>. With this command all
+parental levels will be removed from the titles automatically. This removal
+occurs before the title mapping.
+
+=back
+
 =head1 SEE ALSO
 
 L<xmltv>.
index 6709a4c..f654209 100644 (file)
@@ -109,10 +109,10 @@ my $ua = LWP::UserAgent->new;
 $ua->agent("xmltv/$XMLTV::VERSION");
 
 # The list of channels available from the Yle Program Guide. Their
-# names are deliberately specified in a manner which would be normal
+# names are deliberately specified in a manner which would be natural
 # for people watching e.g. TV channels from Sweden (so that "TV1"
-# would not necessarily refer to Yle's TV1 channel - thus, the need
-# for the "Yle" prefixing here).
+# would in their mindset not necessarily refer to Yle's TV1 channel -
+# thus, the reason behind the "Yle" prefixing here).
 #
 # The key in this hash is the name of the channel as given on the Yle
 # program guide web page.
@@ -121,12 +121,12 @@ my $channels =
    'tv1.yle.fi' => {
                    'id' => 'tv1.yle.fi',
                    'group' => 2,
-                   'display-name' => [[ 'Yle TV1', $LANGUAGE_CODE ]]
+                   'display-name' => [[ 'YLE TV1', $LANGUAGE_CODE ]]
            },
    'tv2.yle.fi' => {
                    'id' => 'tv2.yle.fi',
                    'group' => 2,
-                   'display-name' => [[ 'Yle TV2', $LANGUAGE_CODE ]]
+                   'display-name' => [[ 'YLE TV2', $LANGUAGE_CODE ]]
            },
    'mtv3.yle.fi' => {
                    'id' => 'mtv3.yle.fi',
@@ -146,7 +146,7 @@ my $channels =
    'fst5.yle.fi' => {
                     'id' => 'fst5.yle.fi',
                     'group' => 2,
-                    'display-name' => [[ 'FST5', $LANGUAGE_CODE ]]
+                    'display-name' => [[ 'YLE FST5', $LANGUAGE_CODE ]]
             },
    'subtv.yle.fi' => {
                     'id' => 'subtv.yle.fi',
@@ -195,7 +195,7 @@ my ($opt, $conf) = ParseOptions(
      capabilities => [qw/baseline manualconfig apiconfig/],
      stage_sub => \&config_stage,
      listchannels_sub => \&list_channels,
-     version => '$Id: tv_grab_fi_sv,v 1.9 2010/12/09 20:15:39 perlundberg Exp $',
+     version => '$Id: tv_grab_fi_sv,v 1.11 2011/06/26 09:22:18 perlundberg Exp $',
      description => "Finland (Swedish)",
 });
 
@@ -458,14 +458,15 @@ sub write_listings_data
                    $program->find('div[@class="description"]')->[0]->childNodes();
                my $description = "";
                my $title = "";
+                my $subtitle = "";
                my $desc_time = "";
-               
+
                # Loop over the program nodes and grab out the data
                # from the relevant nodes.
                foreach my $programNode (@programNodes)
                {
                    my $nodeType = ref($programNode);
-                       
+
                    if ($nodeType eq 'XML::LibXML::Text')
                    {
                       $description = $programNode->data;
@@ -473,12 +474,25 @@ sub write_listings_data
                    else
                    {
                        my $class = $programNode->getAttribute("class");
-                       
+
                        if (defined($class))
-                       {                       
-                           if ($class eq 'desc_title')
+                       {
+                            if ($class eq 'desc_title')
                            {
-                               $title = $programNode->to_literal;
+                                # We special-case certain programs to
+                                # be able to get a title +
+                                # subtitle. This makes them much
+                                # easier to record using PVR software
+                                # for example.
+                                if ($programNode->to_literal =~ m/^BUU-klubben: .+$/ ||
+                                    $programNode->to_literal =~ m/^Tintin: .+$/)
+                                {
+                                    ($title, $subtitle) = $programNode->to_literal =~ m/^(.+?): (.+)$/;
+                                }
+                                else
+                                {
+                                    $title = $programNode->to_literal;
+                                }
                            }
                            elsif ($class eq 'desc_time')
                            {
@@ -492,7 +506,7 @@ sub write_listings_data
                        }
                    }
                }
-               
+
                my ($channel_name, $start_time, $end_time) =
                    ($desc_time) =~ m/^(.+?) (\d{2}\.\d{2}) - (\d{2}\.\d{2})$/;
 
@@ -500,7 +514,7 @@ sub write_listings_data
                # configured channels.  If it doesn't, ignore
                # it. (Since the data is provided to us in channel
                # groups, we cannot do it much better than this.)
-               my $channel_id = $channel_name_map->{$channel_name};               
+               my $channel_id = $channel_name_map->{$channel_name};
                unless( exists( $wanted{ $channel_id } ) )
                {
                    next;
@@ -515,12 +529,10 @@ sub write_listings_data
                    'stop' => xmltv_end_time($date, $start_time,
                                        $end_time)
                };
-               
-               if ($description ne '')
-               {
-                   $program->{desc} = [[ $description, $LANGUAGE_CODE ]];
-               }               
-       
+
+                $program->{'desc'} = [[ $description, $LANGUAGE_CODE ]] if ($description ne '');
+                $program->{'sub-title'} = [[ $subtitle, $LANGUAGE_CODE ]] if ($subtitle ne '');
+
                # All data has been gathered. We can now write the
                # program element to the output. (This could be
                # changed into a "two-pass" operation if wanted, so
index aff9816..424bed4 100644 (file)
@@ -41,7 +41,7 @@ channel!slo1.tv.gonix.net
 channel!slo2.tv.gonix.net
 channel!splitskatv.tv.gonix.net
 channel!stv.tv.gonix.net
-channel=tv1000.tv.gonix.net
+channel!tv1000.tv.gonix.net
 channel!tvnova.tv.gonix.net
 channel!vh1.tv.gonix.net
 channel!vtv.tv.gonix.net
index c0dfb65..6410c04 100755 (executable)
@@ -2,7 +2,7 @@
 # vi:noet:ts=4
 
 #-------------------------------------------------------------------------------
-# $Id: tv_grab_huro.in,v 1.45 2011/04/12 19:05:34 dekarl Exp $
+# $Id: tv_grab_huro.in,v 1.47 2011/07/28 09:01:54 attila_nagy Exp $
 #-------------------------------------------------------------------------------
 
 #-------------------------------------------------------------------------------
@@ -122,7 +122,7 @@ recommended by the XMLTV DTD.
 #-------------------------------------------------------------------------------
 
 use strict;
-use XMLTV::Version '$Id: tv_grab_huro.in,v 1.45 2011/04/12 19:05:34 dekarl Exp $';
+use XMLTV::Version '$Id: tv_grab_huro.in,v 1.47 2011/07/28 09:01:54 attila_nagy Exp $';
 use XMLTV::Capabilities qw/baseline manualconfig cache/;
 use XMLTV::Description 'Hungary/Romania';
 use XMLTV::Supplement qw/GetSupplement/;
@@ -338,7 +338,7 @@ sub process_table( $$$$ ) {
                $data =~ s|<span class=\"spons_link.*?</span>||g;
                $data =~ s|<div style=\"display:none\">.*?</div>||g;
                # strip links to divido.hu
-               $data =~ s|<a class=\"navs.*?</a>||g;
+               $data =~ s|<a onclick=\"loggin.*?</a>||g;
 
                $tree = HTML::TreeBuilder->new_from_content($data) or 
                        die "could not fetch/parse $url (progamtable)\n";
@@ -546,7 +546,7 @@ sub process_table( $$$$ ) {
                # New type of row: contains only the time of the event
                # but not the actual program data. So in this case we try to
                # jump to the next row
-               if (! $row->attr("class") || (not $row->attr("class") =~ /^event_/ )) {
+               if (! $row->attr("class") || (not $row->attr("class") =~ /[\s]*event_/ )) {
                        t "found line without event, the time is: $lasttimeHHMM";
                        next;
                }
index 7b719f0..3d802c4 100755 (executable)
@@ -113,13 +113,16 @@ use XMLTV::Get_nice qw(get_nice_tree);
 use POSIX qw(strftime);
 use DateTime;
 
+my $channel_link_regexp = "\\?w=\\/[0-9]\\/\\/[0-9]*\\/\\/[A-Za-z]*\\/1";
+my $channel_link_id = "\\?w=\\/[0-9]\\/\\/([0-9]*)\\/\\/[A-Za-z]*\\/1";
+
 # Use XMLTV::Options::ParseOptions to parse the options and take care of the basic capabilities that a tv_grabber should
 my ($opt, $conf) = ParseOptions({ 
   grabber_name => "tv_grab_il",
   capabilities => [qw/baseline manualconfig apiconfig/],
   stage_sub => \&config_stage,
   listchannels_sub => \&fetch_channels,
-  version => '$Id: tv_grab_il,v 1.24 2010/11/14 05:54:51 rmeden Exp $',
+  version => '$Id: tv_grab_il,v 1.25 2011/12/19 22:40:41 lightpriest Exp $',
   description => "Israel (tv.walla.co.il)"
 });
 
@@ -149,7 +152,7 @@ sub fetch_channels {
   # Get the page containing the list of channels 
   my $tree = XMLTV::Get_nice::get_nice_tree('http://tv.walla.co.il/?w=/4');
   my @channels = $tree->look_down("_tag", "a",
-    "href", qr/\?w=\/[0-9]\/\/[0-9]*\/\/[0-9-]*\/1/,
+    "href", qr/$channel_link_regexp/,
     sub { !$_[0]->look_down('_tag', 'img') }
   );
 
@@ -163,12 +166,12 @@ sub fetch_channels {
   # Browse through the downloaded list of channels and map them to a hash XMLTV::Writer would understand
   foreach my $channel (@channels) {
     if ($channel->as_text()) {
-      my ($id) = $channel->attr('href') =~ /\?w=\/[0-9]\/\/([0-9]*)\/\/[0-9-]*\/1/;
+      my ($id) = $channel->attr('href') =~ /$channel_link_id/;
 
       # Try to fetch the icon
       my $icon = $channel->parent();
       $icon = $icon->right if $icon;
-      $icon = $icon->look_down('_tag', 'a', 'href', qr/\?w=\/[0-9]\/\/[0-9]*\/\/[0-9-]*\/1/) if $icon;
+      $icon = $icon->look_down('_tag', 'a', 'href', qr/$channel_link_regexp/) if $icon;
       $icon = $icon->look_down('_tag', 'img') if $icon;
       $icon = $icon->attr('src') if $icon;
 
@@ -226,7 +229,7 @@ foreach my $channel_id (@{$conf->{channel}}) {
     # Now grab listings for each channel on each day, according to the options in $opt
     for (my $i=$opt->{offset}; $i < ($opt->{offset} + $opt->{days}); $i++) {
       my $theday = DateTime->today()->add (days => $i)->set_time_zone('Asia/Jerusalem');
-      my $url = "http://tv.walla.co.il/?w=/4//$walla_id//" . $theday->ymd() . "/1";
+      my $url = "http://tv.walla.co.il/?w=/4//$walla_id//" . $theday->day_name() . "/1";
 
       my $tree = XMLTV::Get_nice::get_nice_tree($url);
 
index 6fc5295..caa71ff 100644 (file)
@@ -181,7 +181,6 @@ nationalgeohd.skytv.it;National Geo HD
 www.reteallmusic.it;ALL Music
 fantasy.skytv.it;Fantasy
 nexthd.skytv.it;Next HD
-yoyo.raisat.it;Raisat YOYO
 piu.cartoonnetwork.it;Cartoon Network +1
 smash.raisat.it;Raisat Smash
 playhousedisney.skytv.it;Play House Disney
@@ -318,6 +317,72 @@ telesur.guidatv.sky.it;TeleSUR
 mtvclassic.guidatv.sky.it;MTV Classic
 mtvrocks.guidatv.sky.it;MTV Rocks
 mtvdance.guidatv.sky.it;MTV Dance
+www.boingtv.it;Boing
+canale5dtt.guidatv.sky.it;Canale 5 (DTT)
+canale51.guidatv.sky.it;Canale 5 + 1
+classhorsetv.guidatv.sky.it;Class Horse TV
+disneyjunior.mediasetpremium.mediaset.it;Disney Junior
+disneyjunior.guidatv.sky.it;Disney Junior +
+iris.mediaset.it;Iris
+divauniversal.guidatv.sky.it;Diva Universal
+foxbusiness.guidatv.sky.it;Fox Business
+frisbee.guidatv.sky.it;Frisbee
+skycinemacomedy.guidatv.sky.it;Sky Cinema Comedy
+skycinemapassion.guidatv.sky.it;Sky Cinema Passion
+nickjunior.guidatv.sky.it;Nick Junior
+nickjunior1.guidatv.sky.it;Nick Junior + 1
+italia1dtt.guidatv.sky.it;Italia 1 (DTT)
+italia11.guidatv.sky.it;Italia 1 + 1
+jimjam1.guidatv.sky.it;Jim Jam + 1
+rete4dtt.guidatv.sky.it;Rete 4 (DTT)
+rete41.guidatv.sky.it;Rete 4 + 1
+youme.guidatv.sky.it;You & Me
+mediasetextra.guidatv.sky.it;Mediaset Extra
+mtvmusic.guidatv.sky.it;MTV music
+pokeritalia24.guidatv.sky.it;PokerItalia24
+qvc.guidatv.sky.it;QVC
+la5.guidatv.sky.it;La5
+www.la7d.it;La7D
+rai1dtt.guidatv.sky.it;Rai 1 (DTT)
+rai2dtt.guidatv.sky.it;Rai 2 (DTT)
+rai3dtt.guidatv.sky.it;Rai 3 (DTT)
+rai4.raisat.it;Rai 4
+channel rai5.rai.it;Rai 5
+raigulp.rai.it;Rai Gulp
+raimovie.rai.it;Rai Movie
+raipremium.guidatv.sky.it;Rai Premium
+raisport1.rai.it;Rai Sport 1
+raisport2.rai.it;Rai Sport 2
+raistoria.rai.it;Rai Storia
+yoyo.raisat.it;Rai Yoyo
+natgeoadventurehd.guidatv.sky.it;Nat Geo Adventure HD
+worldfashionchannel.guidatv.sky.it;World Fashion Channel
+fashiontv.guidatv.sky.it;Fashion Tv
+fashionone.guidatv.sky.it;Fashion One
+sky3dch209.guidatv.sky.it;Sky 3D - Ch 209
+romauno.guidatv.sky.it;Roma Uno
+smtvsanmarino.guidatv.sky.it;SMtv San Marino
+nhkworldtv.guidatv.sky.it;NHK World TV
+russiatoday.guidatv.sky.it;Russia Today
+protvinternational.guidatv.sky.it;ProTV International
+disneyjunior1.guidatv.sky.it;Disney Junior + 1
+disneychannel2.guidatv.sky.it;Disney Channel +2
+disneyxd2.guidatv.sky.it;Disney XD +2
+deajunior.guidatv.sky.it;DeA Junior
+aljazeerachildren.guidatv.sky.it;Al Jazeera Children
+baraem.guidatv.sky.it;Baraem
+mtvlivehd.guidatv.sky.it;MTV Live HD
+rtl1025tv.guidatv.sky.it;RTL 102.5 TV
+virginradiotv.guidatv.sky.it;Virgin Radio TV
+horrorchannel.guidatv.sky.it;Horror Channel
+dmax.guidatv.sky.it;DMax
+extremesportchannelhd.guidatv.sky.it;Extreme Sport Channel HD
+sky3dch150.guidatv.sky.it;Sky 3D - Ch 150
+iliketv.guidatv.sky.it;ILIKETV
+sky3dch321.guidatv.sky.it;Sky 3D - Ch 321
+doctorslife.guidatv.sky.it;Doctor's Life
+supertennishd.guidatv.sky.it;SuperTennis HD
+super.guidatv.sky.it;Super!
 [boingtv]
 www.boingtv.it;boingtv
 [sitcom1]
@@ -359,6 +424,11 @@ premiumcinemaemotion.mediasetpremium.mediaset.it;Premium Cinema Emotion
 premiumcinemaenergy.mediasetpremium.mediaset.it;Premium Cinema Energy
 premiumextra.mediasetpremium.mediaset.it;Premium Extra
 premiumextra2.mediasetpremium.mediaset.it;Premium Extra 2
+bbcknowledge.mediasetpremium.mediaset.it;BBC Knowledge
+discoveryworld.mediasetpremium.mediaset.it;Discovery World
+disneyjunior.mediasetpremium.mediaset.it;Disney Junior
+premiumcinemacomedy.mediasetpremium.mediaset.it;Premium Cinema Comedy
+premiumcrime.mediasetpremium.mediaset.it;Premium Crime
 [raiit]
 cinema.raisat.it;RaiSat Cinema
 extra.raisat.it;Extra
@@ -379,7 +449,7 @@ raigulp.rai.it;Rai Gulp
 raisportpi.rai.it;Rai Sport più
 raistoria.rai.it;Rai Storia
 www.raitre.rai.it;Rai 3
-www.raiuno.rai.it;Rai Uno
+www.raiuno.rai.it;Rai 1
 www.rainews24.rai.it;RaiNews24
 smashgirls.skytv.it;Smash Girls
 yoyo.raisat.it;Yoyo
@@ -409,4 +479,7 @@ www.canale5.com;Canale 5
 www.italia1.com;Italia 1
 www.rete4.com;Rete 4
 la5.mediaset.it;La5
-mediasetextra.mediaset.it;Mediaset Extra
\ No newline at end of file
+mediasetextra.mediaset.it;Mediaset Extra
+iris.mediaset.it;Iris
+italia2.mediaset.it;Italia 2
+www.boingtv.it;Boing
\ No newline at end of file
index 17e50e8..7da9645 100755 (executable)
@@ -74,6 +74,8 @@
 # 25/02/2011
 # aggiunto patch per mediaset da charon66
 # tolto backend dahlia
+# 24/07/2011
+# nuovi canali
 #################################################
 # TODO
 # - add more informative errors in xml
@@ -90,7 +92,7 @@ my $DEF_LANG = 'eng';
 use warnings;
 use strict;
 
-use XMLTV::Version '$Id: tv_grab_it.in,v 1.99 2011/02/26 12:56:38 mnbjhguyt Exp $';
+use XMLTV::Version '$Id: tv_grab_it.in,v 1.101 2012/03/23 23:02:11 mnbjhguyt Exp $';
 use XMLTV::Capabilities qw/baseline manualconfig cache/;
 use XMLTV::Description 'Italy';
 use XMLTV::Supplement qw/GetSupplement/;
@@ -1208,15 +1210,20 @@ sub skylife_get_channels_list {
                                       "VERBOSE: Non sono riuscito a prendere la lista dei canali di skylife ($url). Il sito non funziona?\n") unless ($opt_quiet);
                         return ();
                 }
-
-        my @canali = split /\n/, $content;
+                
+        $content=~s/[\r|\n]//igm;
+        $content=~s/\s\s+//igm;
+        my @canali = split /\{/, $content;
         foreach my $canale (@canali) {
-                #{"id":"101","name":"SKY Cinema 1","number":"301","service":"101","channellogo":"http://guidatv.sky.it/app/guidatv/images/epgimages/channels/grid/301_grid.gif"}
-                $canale=~/\{\"id\":\"(.*?)\",\"name\":\"(.*?)\",\"number\":\"(.*?)\",\"service\":\"(.*?)\",\"channellogo\":\"(.*?)\"}/;
+                # "id":"101",        "name":"Sky Cinema 1",        "number":"301",        "service":"101",        "channellogo":"http://guidatv.sky.it/app/guidatv/images/epgimages/channels/grid/301_grid.gif",        "channelvisore":"http://guidatv.sky.it/app/guidatv/images/epgimages/channels/visore/301_visore.gif",        "logomsite":"http://guidatv.sky.it/app/guidatv/images/epgimages/channels/msite/LCh301_EPG.png"        }        ,    
+                $canale=~/\"id\":\"(.*?)\",\"name\":\"(.*?)\",\"number\":\"(.*?)\",\"service\":\"(.*?)\",\"channellogo\":\"(.*?)\",\"channelvisore\":\"(.*?)\",\"logomsite\":\"(.*?)\"}/;
                 next if (not defined $2);
-                #print "|$1|$2|$3|$4|$5|\n";
+                #print "|$1|$2|$3|$4|$5|$6|$7!\n";
+
                 my $name = tidy($2);
-                my $iconurl = $backend_info{skylife}{base_icon}.$3.'_grid.gif';
+                my $iconurl = $6;
+                my $logo2 = $5;
+                my $logo3 = $7;
                 my $channum = $3; #dove metto il 3???chi si ricorda??
                 $chan_hash{$name} = "$1";
                 
@@ -1877,6 +1884,11 @@ sub mediasetpremium_get_channels_list {
                   "Premium Cinema Energy", "KG",
                   "Premium Extra", "K8",
                   "Premium Extra 2", "K9",
+                  "BBC Knowledge", "EB",
+                  "Discovery World", "ED",
+                  "Disney Junior", "KP",
+                  "Premium Cinema Comedy", "LC",
+                  "Premium Crime", "LR",
       );
 
     foreach (keys %chan_hash) {
@@ -2032,11 +2044,16 @@ sub mediasetpremium_fetch_data {
                                $rating=$1;
                                #warn "categoria: $1\n";
                        }
+                       elsif ($l=~/trafficLight>(.*?)<\/trafficLight/){
+                               $rating=$1;
+                               #warn "categoria: $1\n";
+                       }
                        elsif ($l=~/parentalRating\/.*/){
                                #$rating=$1;
                                #warn "categoria: $1\n";
                        }                       
-                       elsif ($l=~/audio audioType=\"(.*?)\" doppioAudio=\"(.*?)\" sottotitoli=\"(.*?)\">Not used<\/audio/){
+                       elsif ($l=~/audio audioType=\"(.*?)\" doppioAudio=\"(.*?)\" sottotitoli=\"(.*?)\">Not used<\/audio/ or
+                              $l=~/audio audioType=\"(.*?)\" doppioAudio=\"(.*?)\" sottotitoli=\"(.*?)\">Not live<\/audio/){
                                ($audio, $doppioaudio, $sottotitoli) = ($1, $2, $3);
                                #warn "audio: $audio, $doppioaudio, $sottotitoli\n";
                        }
index 514ec6a..dd757f5 100644 (file)
@@ -353,7 +353,7 @@ and of course everyone else I forgot to mention. :)
 # initializations
 
 use strict;
-use XMLTV::Version '$Id: tv_grab_na_dd.in,v 1.82 2010/09/04 10:28:44 dekarl Exp $ ';
+use XMLTV::Version '$Id: tv_grab_na_dd.in,v 1.83 2011/12/30 22:49:05 rmeden Exp $ ';
 use XMLTV::Capabilities qw/baseline manualconfig share/;
 use XMLTV::Description 'North America (Data Direct)';
 use Data::Dumper;
@@ -1217,7 +1217,7 @@ $writer = new XMLTV::Writer(%w_args);
 $writer->start( {
               'source-info-name'     => 'Schedules Direct',
               'source-info-url'      => 'http://www.schedulesdirect.org/',
-              'generator-info-name'  => 'XMLTV/$Id: tv_grab_na_dd.in,v 1.82 2010/09/04 10:28:44 dekarl Exp $',
+              'generator-info-name'  => 'XMLTV/$Id: tv_grab_na_dd.in,v 1.83 2011/12/30 22:49:05 rmeden Exp $',
              'generator-info-url'   => 'http://www.xmltv.org/',
             });
 
@@ -1570,6 +1570,7 @@ foreach $_ (@schedules) {
                         $ptr->{member}=[$ptr->{member}] if (ref $ptr->{member} eq 'HASH');
                         foreach (@{$ptr->{member}})
                         {
+                           next unless exists $_->{role};
                             my $name="";
                             $name.=$_->{givenname}." " unless ref $_->{givenname};
                             $name.=$_->{surname}       unless ref $_->{surname};
index b9de053..550dae7 100644 (file)
@@ -1,51 +1,20 @@
-zone=p
-zip=94533
-channel=0003.directv.com
-channel!0006.directv.com
-channel!0010.directv.com
-channel!0013.directv.com
-channel!0019.directv.com
-channel!0029.directv.com
-channel!0031.directv.com
-channel!0040.directv.com
-channel!0058.directv.com
-channel!0064.directv.com
-channel!0069.directv.com
-channel!0070.directv.com
-channel!0071.directv.com
-channel!0072.directv.com
-channel!0073.directv.com
-channel!0074.directv.com
-channel!0075.directv.com
-channel!0076.directv.com
-channel!0077.directv.com
-channel!0078.directv.com
-channel!0079.directv.com
-channel!0080.directv.com
-channel!0081.directv.com
-channel!0082.directv.com
-channel!0083.directv.com
-channel!0086.directv.com
-channel!0087.directv.com
-channel!0088.directv.com
-channel!0089.directv.com
-channel!0092.directv.com
-channel!0094.directv.com
-channel!0095.directv.com
-channel!0098.directv.com
-channel!0099.directv.com
+zip=41017
+timezone=America/New_York
+channel!0001.directv.com
 channel!0100.directv.com
 channel!0101.directv.com
 channel!0102.directv.com
+channel!0103.directv.com
 channel!0104.directv.com
-channel!0105.directv.com
 channel!0106.directv.com
 channel!0107.directv.com
-channel!0108.directv.com
-channel!0109.directv.com
 channel!0110.directv.com
-channel!0115.directv.com
+channel!0111.directv.com
+channel!0112.directv.com
+channel!0113.directv.com
+channel!0114.directv.com
 channel!0119.directv.com
+channel!0012.directv.com
 channel!0120.directv.com
 channel!0121.directv.com
 channel!0122.directv.com
@@ -53,14 +22,25 @@ channel!0123.directv.com
 channel!0124.directv.com
 channel!0125.directv.com
 channel!0126.directv.com
+channel!0129.directv.com
 channel!0130.directv.com
-channel!0131.directv.com
 channel!0132.directv.com
+channel!0133.directv.com
+channel!0134.directv.com
+channel!0135.directv.com
+channel!0136.directv.com
+channel!0137.directv.com
+channel!0138.directv.com
+channel!0139.directv.com
+channel!0014.directv.com
 channel!0140.directv.com
 channel!0141.directv.com
 channel!0142.directv.com
 channel!0143.directv.com
+channel!0145.directv.com
+channel!0146.directv.com
 channel!0147.directv.com
+channel!0148.directv.com
 channel!0149.directv.com
 channel!0150.directv.com
 channel!0151.directv.com
@@ -71,35 +51,133 @@ channel!0155.directv.com
 channel!0156.directv.com
 channel!0157.directv.com
 channel!0158.directv.com
+channel!0159.directv.com
 channel!0160.directv.com
 channel!0161.directv.com
 channel!0162.directv.com
-channel!0163.directv.com
+channel!0164.directv.com
 channel!0165.directv.com
+channel!0166.directv.com
+channel!0167.directv.com
 channel!0168.directv.com
+channel!0169.directv.com
 channel!0170.directv.com
 channel!0171.directv.com
 channel!0172.directv.com
+channel!0173.directv.com
 channel!0174.directv.com
+channel!0175.directv.com
 channel!0176.directv.com
+channel!0177.directv.com
+channel!0178.directv.com
 channel!0179.directv.com
 channel!0180.directv.com
+channel!0181.directv.com
 channel!0182.directv.com
+channel!0183.directv.com
 channel!0185.directv.com
+channel!0186.directv.com
+channel!0187.directv.com
 channel!0188.directv.com
+channel!0189.directv.com
+channel!0019.directv.com
+channel!0190.directv.com
+channel!0191.directv.com
+channel!0192.directv.com
+channel!0193.directv.com
+channel!0194.directv.com
+channel!0195.directv.com
+channel!0196.directv.com
+channel!0197.directv.com
+channel!0198.directv.com
 channel!0199.directv.com
 channel!0200.directv.com
+channel!2001.directv.com
+channel!2002.directv.com
+channel!2003.directv.com
+channel!2005.directv.com
+channel!2006.directv.com
+channel!2007.directv.com
+channel!2008.directv.com
+channel!2009.directv.com
 channel!0201.directv.com
+channel!2010.directv.com
+channel!2012.directv.com
+channel!2013.directv.com
 channel!0202.directv.com
+channel!2024.directv.com
+channel!2027.directv.com
+channel!2028.directv.com
+channel!2029.directv.com
+channel!0203.directv.com
 channel!0204.directv.com
+channel!0205.directv.com
+channel!2050.directv.com
+channel!2051.directv.com
+channel!2052.directv.com
+channel!2053.directv.com
+channel!2054.directv.com
+channel!2055.directv.com
+channel!2056.directv.com
+channel!2057.directv.com
+channel!2058.directv.com
 channel!0206.directv.com
+channel!2060.directv.com
+channel!2061.directv.com
+channel!2062.directv.com
+channel!2063.directv.com
+channel!2064.directv.com
+channel!2065.directv.com
+channel!2066.directv.com
+channel!2067.directv.com
+channel!2068.directv.com
+channel!2069.directv.com
 channel!0207.directv.com
+channel!2072.directv.com
+channel!2073.directv.com
+channel!2074.directv.com
+channel!2075.directv.com
+channel!2076.directv.com
+channel!2077.directv.com
+channel!2078.directv.com
 channel!0208.directv.com
+channel!2080.directv.com
+channel!2081.directv.com
+channel!2082.directv.com
+channel!2083.directv.com
+channel!2084.directv.com
+channel!2085.directv.com
+channel!2086.directv.com
+channel!2087.directv.com
+channel!2088.directv.com
+channel!2089.directv.com
 channel!0209.directv.com
+channel!2090.directv.com
+channel!0210.directv.com
+channel!0211.directv.com
 channel!0212.directv.com
+channel!0213.directv.com
+channel!2134.directv.com
+channel!2135.directv.com
+channel!2136.directv.com
+channel!2137.directv.com
+channel!0214.directv.com
+channel!2140.directv.com
+channel!2141.directv.com
+channel!2142.directv.com
+channel!2143.directv.com
+channel!2144.directv.com
+channel!2145.directv.com
+channel!2147.directv.com
+channel!2148.directv.com
+channel!0215.directv.com
+channel!0216.directv.com
 channel!0217.directv.com
 channel!0218.directv.com
+channel!2183.directv.com
+channel!0219.directv.com
 channel!0220.directv.com
+channel!0221.directv.com
 channel!0222.directv.com
 channel!0223.directv.com
 channel!0224.directv.com
@@ -127,7 +205,8 @@ channel!0245.directv.com
 channel!0246.directv.com
 channel!0247.directv.com
 channel!0248.directv.com
-channel=0249.directv.com
+channel!0249.directv.com
+channel!0025.directv.com
 channel!0250.directv.com
 channel!0251.directv.com
 channel!0252.directv.com
@@ -139,26 +218,33 @@ channel!0257.directv.com
 channel!0258.directv.com
 channel!0259.directv.com
 channel!0260.directv.com
+channel!0261.directv.com
 channel!0262.directv.com
-channel!0263.directv.com
 channel!0264.directv.com
 channel!0265.directv.com
 channel!0266.directv.com
+channel!0267.directv.com
 channel!0268.directv.com
 channel!0269.directv.com
+channel!0270.directv.com
 channel!0271.directv.com
+channel!0272.directv.com
 channel!0273.directv.com
 channel!0274.directv.com
+channel!0275.directv.com
 channel!0276.directv.com
 channel!0277.directv.com
 channel!0278.directv.com
 channel!0279.directv.com
 channel!0280.directv.com
+channel!0281.directv.com
 channel!0282.directv.com
+channel!0283.directv.com
 channel!0284.directv.com
 channel!0285.directv.com
 channel!0286.directv.com
 channel!0287.directv.com
+channel!0288.directv.com
 channel!0289.directv.com
 channel!0290.directv.com
 channel!0291.directv.com
@@ -173,47 +259,61 @@ channel!0299.directv.com
 channel!0300.directv.com
 channel!0301.directv.com
 channel!0302.directv.com
+channel!0303.directv.com
+channel!0304.directv.com
 channel!0305.directv.com
+channel!0306.directv.com
 channel!0307.directv.com
 channel!0308.directv.com
 channel!0309.directv.com
+channel!0310.directv.com
 channel!0311.directv.com
 channel!0312.directv.com
-channel!0314.directv.com
+channel!0313.directv.com
 channel!0315.directv.com
 channel!0316.directv.com
 channel!0317.directv.com
+channel!0318.directv.com
 channel!0319.directv.com
 channel!0320.directv.com
-channel!0321.directv.com
-channel!0323.directv.com
 channel!0324.directv.com
-channel!0325.directv.com
 channel!0326.directv.com
 channel!0327.directv.com
+channel!0328.directv.com
 channel!0329.directv.com
 channel!0330.directv.com
 channel!0331.directv.com
 channel!0333.directv.com
+channel!0334.directv.com
 channel!0335.directv.com
 channel!0337.directv.com
+channel!0338.directv.com
 channel!0339.directv.com
+channel!0344.directv.com
+channel!0345.directv.com
+channel!0347.directv.com
+channel!0348.directv.com
 channel!0350.directv.com
 channel!0351.directv.com
+channel!0352.directv.com
 channel!0353.directv.com
 channel!0354.directv.com
 channel!0355.directv.com
 channel!0356.directv.com
 channel!0357.directv.com
+channel!0358.directv.com
 channel!0359.directv.com
 channel!0360.directv.com
+channel!0361.directv.com
 channel!0362.directv.com
+channel!0363.directv.com
 channel!0364.directv.com
 channel!0365.directv.com
 channel!0366.directv.com
 channel!0367.directv.com
 channel!0368.directv.com
 channel!0369.directv.com
+channel!0370.directv.com
 channel!0371.directv.com
 channel!0372.directv.com
 channel!0373.directv.com
@@ -222,23 +322,22 @@ channel!0375.directv.com
 channel!0376.directv.com
 channel!0377.directv.com
 channel!0378.directv.com
-channel!0379.directv.com
-channel!0380.directv.com
-channel!0381.directv.com
-channel!0382.directv.com
-channel!0383.directv.com
-channel!0384.directv.com
-channel!0385.directv.com
-channel!0386.directv.com
-channel!0387.directv.com
-channel!0388.directv.com
 channel!0389.directv.com
 channel!0390.directv.com
+channel!0391.directv.com
+channel!0392.directv.com
+channel!0393.directv.com
+channel!0394.directv.com
+channel!0395.directv.com
 channel!0396.directv.com
+channel!0397.directv.com
+channel!0398.directv.com
+channel!0399.directv.com
 channel!0401.directv.com
 channel!0402.directv.com
 channel!0403.directv.com
 channel!0404.directv.com
+channel!0405.directv.com
 channel!0406.directv.com
 channel!0407.directv.com
 channel!0408.directv.com
@@ -254,9 +353,10 @@ channel!0417.directv.com
 channel!0418.directv.com
 channel!0419.directv.com
 channel!0420.directv.com
-channel!0421.directv.com
 channel!0422.directv.com
 channel!0423.directv.com
+channel!0424.directv.com
+channel!0425.directv.com
 channel!0426.directv.com
 channel!0427.directv.com
 channel!0428.directv.com
@@ -269,59 +369,131 @@ channel!0434.directv.com
 channel!0436.directv.com
 channel!0437.directv.com
 channel!0438.directv.com
+channel!0439.directv.com
+channel!0440.directv.com
+channel!0441.directv.com
+channel!0442.directv.com
+channel!0443.directv.com
+channel!0444.directv.com
+channel!0445.directv.com
+channel!0446.directv.com
+channel!0447.directv.com
+channel!0448.directv.com
+channel!0449.directv.com
 channel!0450.directv.com
 channel!0451.directv.com
 channel!0452.directv.com
 channel!0453.directv.com
 channel!0454.directv.com
 channel!0455.directv.com
+channel!0456.directv.com
+channel!0457.directv.com
+channel!0458.directv.com
+channel!0459.directv.com
+channel!0460.directv.com
+channel!0476.directv.com
+channel!0477.directv.com
+channel!0478.directv.com
+channel!0479.directv.com
+channel!0048.directv.com
+channel!0480.directv.com
+channel!0481.directv.com
+channel!0482.directv.com
+channel!0483.directv.com
+channel!0484.directv.com
+channel!0485.directv.com
+channel!0486.directv.com
+channel!0487.directv.com
+channel!0488.directv.com
+channel!0489.directv.com
+channel!0490.directv.com
+channel!0491.directv.com
+channel!0493.directv.com
+channel!0494.directv.com
+channel!0495.directv.com
+channel!0496.directv.com
+channel!0497.directv.com
+channel!0499.directv.com
+channel=0005.directv.com
 channel!0500.directv.com
-channel=0501.directv.com
+channel!0501.directv.com
 channel!0502.directv.com
 channel!0503.directv.com
 channel!0504.directv.com
 channel!0505.directv.com
+channel!0506.directv.com
 channel!0507.directv.com
 channel!0508.directv.com
 channel!0509.directv.com
-channel!0510.directv.com
 channel!0511.directv.com
-channel!0512.directv.com
-channel!0513.directv.com
-channel!0514.directv.com
+channel!0515.directv.com
+channel!0516.directv.com
+channel!0517.directv.com
+channel!0519.directv.com
 channel!0520.directv.com
 channel!0521.directv.com
 channel!0522.directv.com
 channel!0523.directv.com
+channel!0525.directv.com
 channel!0526.directv.com
 channel!0527.directv.com
 channel!0528.directv.com
 channel!0529.directv.com
 channel!0530.directv.com
 channel!0531.directv.com
-channel!0532.directv.com
-channel!0533.directv.com
+channel!0535.directv.com
+channel!0536.directv.com
 channel!0537.directv.com
 channel!0538.directv.com
 channel!0539.directv.com
+channel!0054.directv.com
 channel!0540.directv.com
 channel!0541.directv.com
 channel!0542.directv.com
-channel!0543.directv.com
-channel!0544.directv.com
 channel!0545.directv.com
+channel!0546.directv.com
 channel!0547.directv.com
+channel!0548.directv.com
 channel!0549.directv.com
 channel!0550.directv.com
+channel!0551.directv.com
+channel!0552.directv.com
+channel!0554.directv.com
+channel!0555.directv.com
+channel!0556.directv.com
+channel!0557.directv.com
+channel!0558.directv.com
+channel!0559.directv.com
+channel!0560.directv.com
+channel!0561.directv.com
+channel!0562.directv.com
+channel!0563.directv.com
+channel!0564.directv.com
+channel!0565.directv.com
+channel!0566.directv.com
+channel!0567.directv.com
+channel!0568.directv.com
 channel!0570.directv.com
+channel!0571.directv.com
+channel!0572.directv.com
+channel!0573.directv.com
+channel!0574.directv.com
 channel!0575.directv.com
+channel!0576.directv.com
+channel!0577.directv.com
+channel!0578.directv.com
+channel!0579.directv.com
+channel!0580.directv.com
 channel!0582.directv.com
+channel!0584.directv.com
+channel!0585.directv.com
 channel!0586.directv.com
 channel!0587.directv.com
 channel!0588.directv.com
 channel!0589.directv.com
 channel!0590.directv.com
 channel!0591.directv.com
+channel!0592.directv.com
 channel!0593.directv.com
 channel!0594.directv.com
 channel!0595.directv.com
@@ -330,23 +502,28 @@ channel!0597.directv.com
 channel!0598.directv.com
 channel!0599.directv.com
 channel!0600.directv.com
-channel!0601.directv.com
 channel!0602.directv.com
 channel!0603.directv.com
+channel!0604.directv.com
 channel!0605.directv.com
 channel!0606.directv.com
 channel!0607.directv.com
 channel!0608.directv.com
 channel!0609.directv.com
 channel!0610.directv.com
+channel!0611.directv.com
 channel!0612.directv.com
 channel!0613.directv.com
 channel!0614.directv.com
 channel!0615.directv.com
 channel!0616.directv.com
+channel!0617.directv.com
+channel!0618.directv.com
+channel!0619.directv.com
 channel!0620.directv.com
 channel!0621.directv.com
 channel!0622.directv.com
+channel!0623.directv.com
 channel!0624.directv.com
 channel!0625.directv.com
 channel!0626.directv.com
@@ -355,7 +532,6 @@ channel!0628.directv.com
 channel!0629.directv.com
 channel!0630.directv.com
 channel!0631.directv.com
-channel!0632.directv.com
 channel!0633.directv.com
 channel!0634.directv.com
 channel!0635.directv.com
@@ -363,14 +539,18 @@ channel!0636.directv.com
 channel!0637.directv.com
 channel!0638.directv.com
 channel!0639.directv.com
+channel!0064.directv.com
 channel!0640.directv.com
 channel!0641.directv.com
 channel!0642.directv.com
 channel!0643.directv.com
 channel!0644.directv.com
 channel!0645.directv.com
+channel!0646.directv.com
 channel!0647.directv.com
+channel!0648.directv.com
 channel!0649.directv.com
+channel!0650.directv.com
 channel!0651.directv.com
 channel!0652.directv.com
 channel!0653.directv.com
@@ -378,9 +558,250 @@ channel!0654.directv.com
 channel!0655.directv.com
 channel!0656.directv.com
 channel!0657.directv.com
+channel!0658.directv.com
+channel!0659.directv.com
+channel!0660.directv.com
+channel!0661.directv.com
 channel!0662.directv.com
+channel!0663.directv.com
 channel!0664.directv.com
 channel!0665.directv.com
+channel!0666.directv.com
+channel!0667.directv.com
+channel!0668.directv.com
+channel!0669.directv.com
+channel!0671.directv.com
+channel!0672.directv.com
+channel!0673.directv.com
+channel!0675.directv.com
+channel!0676.directv.com
+channel!0677.directv.com
+channel!0678.directv.com
+channel!0679.directv.com
+channel!0680.directv.com
+channel!0681.directv.com
 channel!0682.directv.com
+channel!0683.directv.com
+channel!0684.directv.com
+channel!0685.directv.com
+channel!0686.directv.com
+channel!0687.directv.com
+channel!0688.directv.com
+channel!0692.directv.com
+channel!0693.directv.com
+channel!0694.directv.com
+channel!0695.directv.com
+channel!0696.directv.com
+channel!0697.directv.com
 channel!0698.directv.com
 channel!0699.directv.com
+channel!0070.directv.com
+channel!0701.directv.com
+channel!0702.directv.com
+channel!0703.directv.com
+channel!0704.directv.com
+channel!0705.directv.com
+channel!0706.directv.com
+channel!0707.directv.com
+channel!0708.directv.com
+channel!0709.directv.com
+channel!0710.directv.com
+channel!0711.directv.com
+channel!0712.directv.com
+channel!0713.directv.com
+channel!0714.directv.com
+channel!0715.directv.com
+channel!0716.directv.com
+channel!0717.directv.com
+channel!0718.directv.com
+channel!0720.directv.com
+channel!0721.directv.com
+channel!0722.directv.com
+channel!0723.directv.com
+channel!0724.directv.com
+channel!0725.directv.com
+channel!0726.directv.com
+channel!0727.directv.com
+channel!0728.directv.com
+channel!0729.directv.com
+channel!0074.directv.com
+channel!0750.directv.com
+channel!0751.directv.com
+channel!0752.directv.com
+channel!0753.directv.com
+channel!0754.directv.com
+channel!0755.directv.com
+channel!0756.directv.com
+channel!0757.directv.com
+channel!0758.directv.com
+channel!0759.directv.com
+channel!0760.directv.com
+channel!0761.directv.com
+channel!0762.directv.com
+channel!0763.directv.com
+channel!0764.directv.com
+channel!0765.directv.com
+channel!0766.directv.com
+channel!0767.directv.com
+channel!0768.directv.com
+channel!0769.directv.com
+channel!0077.directv.com
+channel!0770.directv.com
+channel!0771.directv.com
+channel!0772.directv.com
+channel!0773.directv.com
+channel!0774.directv.com
+channel!0775.directv.com
+channel!0776.directv.com
+channel!0777.directv.com
+channel!0778.directv.com
+channel!0779.directv.com
+channel!0078.directv.com
+channel!0780.directv.com
+channel!0781.directv.com
+channel!0782.directv.com
+channel!0783.directv.com
+channel!0784.directv.com
+channel!0785.directv.com
+channel!0786.directv.com
+channel!0787.directv.com
+channel!0801.directv.com
+channel!0802.directv.com
+channel!0803.directv.com
+channel!0804.directv.com
+channel!0805.directv.com
+channel!0806.directv.com
+channel!0807.directv.com
+channel!0808.directv.com
+channel!0809.directv.com
+channel!0081.directv.com
+channel!0810.directv.com
+channel!0811.directv.com
+channel!0812.directv.com
+channel!0813.directv.com
+channel!0814.directv.com
+channel!0815.directv.com
+channel!0816.directv.com
+channel!0817.directv.com
+channel!0818.directv.com
+channel!0819.directv.com
+channel!0082.directv.com
+channel!0820.directv.com
+channel!0821.directv.com
+channel!0822.directv.com
+channel!0823.directv.com
+channel!0824.directv.com
+channel!0825.directv.com
+channel!0826.directv.com
+channel!0827.directv.com
+channel!0828.directv.com
+channel!0829.directv.com
+channel!0083.directv.com
+channel!0830.directv.com
+channel!0831.directv.com
+channel!0832.directv.com
+channel!0833.directv.com
+channel!0834.directv.com
+channel!0835.directv.com
+channel!0836.directv.com
+channel!0837.directv.com
+channel!0838.directv.com
+channel!0839.directv.com
+channel!0084.directv.com
+channel!0840.directv.com
+channel!0841.directv.com
+channel!0842.directv.com
+channel!0843.directv.com
+channel!0844.directv.com
+channel!0845.directv.com
+channel!0846.directv.com
+channel!0847.directv.com
+channel!0848.directv.com
+channel!0849.directv.com
+channel!0085.directv.com
+channel!0850.directv.com
+channel!0851.directv.com
+channel!0852.directv.com
+channel!0853.directv.com
+channel!0854.directv.com
+channel!0855.directv.com
+channel!0856.directv.com
+channel!0857.directv.com
+channel!0858.directv.com
+channel!0859.directv.com
+channel!0860.directv.com
+channel!0861.directv.com
+channel!0862.directv.com
+channel!0863.directv.com
+channel!0864.directv.com
+channel!0865.directv.com
+channel!0866.directv.com
+channel!0867.directv.com
+channel!0868.directv.com
+channel!0869.directv.com
+channel!0870.directv.com
+channel!0871.directv.com
+channel!0872.directv.com
+channel!0873.directv.com
+channel!0874.directv.com
+channel!0875.directv.com
+channel!0876.directv.com
+channel!0877.directv.com
+channel!0878.directv.com
+channel!0879.directv.com
+channel!0088.directv.com
+channel!0880.directv.com
+channel!0881.directv.com
+channel!0882.directv.com
+channel!0883.directv.com
+channel!0884.directv.com
+channel!0009.directv.com
+channel!0095.directv.com
+channel!9500.directv.com
+channel!9501.directv.com
+channel!9502.directv.com
+channel!9503.directv.com
+channel!9506.directv.com
+channel!9507.directv.com
+channel!9508.directv.com
+channel!9509.directv.com
+channel!9510.directv.com
+channel!9511.directv.com
+channel!9512.directv.com
+channel!9513.directv.com
+channel!9514.directv.com
+channel!9515.directv.com
+channel!9560.directv.com
+channel!9561.directv.com
+channel!9562.directv.com
+channel!9563.directv.com
+channel!9564.directv.com
+channel!9565.directv.com
+channel!9566.directv.com
+channel!9567.directv.com
+channel!9568.directv.com
+channel!9569.directv.com
+channel!9570.directv.com
+channel!9571.directv.com
+channel!9572.directv.com
+channel!9573.directv.com
+channel!9574.directv.com
+channel!9901.directv.com
+channel!9902.directv.com
+channel!9903.directv.com
+channel!9904.directv.com
+channel!9905.directv.com
+channel!9906.directv.com
+channel!9907.directv.com
+channel!9908.directv.com
+channel!9909.directv.com
+channel!9910.directv.com
+channel!9911.directv.com
+channel!9912.directv.com
+channel!9913.directv.com
+channel!9921.directv.com
+channel!9922.directv.com
+channel!9923.directv.com
+channel!9924.directv.com
+channel!9925.directv.com
+channel!9926.directv.com
index 87a6f31..a335baf 100755 (executable)
@@ -76,17 +76,12 @@ files.  Default is "/tmp", so under Windows one of these is required.
 
 =head1 CREDITS
 
-Grabber written by Rod Roark (http://www.sunsetsystems.com/), lightly cloned
-from tv_grab_cz by Mattias Holmlund.  See that grabber for additional credits.
+Grabber written Rod Roark (http://www.sunsetsystems.com/), modified by 
+Adam Lewandowski (adam@alewando.com) in January 2011 to account for DirecTV site
+changes.
 
-=head1 BUGS
-
-DirecTV might want a county ID to show local channels for some zip codes.
-We do not support that.  If you encounter this problem, try entering a nearby
-zip code where your local channels appear by default.
 
-The XML generated for channel information is kludged for compatibility with
-MythTV and is not very pretty.
+=head1 BUGS
 
 Like any screen-scraping grabber, this one will break regularly as the web site
 changes, and you should try to fetch a new one from the project's repository.
@@ -100,8 +95,8 @@ use XMLTV::Configure::Writer;
 use XMLTV::Options qw/ParseOptions/;
 use WWW::Mechanize;
 use HTML::TokeParser;
-use Date::Parse;
-use Time::Local;
+use DateTime;
+use JSON;
 use Errno qw(EAGAIN);
 
 ######################################################################
@@ -113,85 +108,82 @@ use Errno qw(EAGAIN);
 my $MAX_PROCESSES = 8;
 
 my $VERBOSE = 1;
+my $DEBUG   = 0;
 
 my $TMP_FILEBASE = $ENV{TEMP} || $ENV{TMP} || '/tmp';
 $TMP_FILEBASE .= '/na_dtv_';
 
 my $queue_filename = "$TMP_FILEBASE" . "q";
 
-my $SITEBASE = "http://www.directv.com/DTVAPP";
+my $SITEBASE = "http://www.directv.com/entertainment";
+
+# URL for grabbing channel list
+my $CHANNEL_LIST_URL = "$SITEBASE/data/guideChannelList.json.jsp";
 
-# This URL contains a form including time zone and zip code, but we'll use
-# GET parameters instead of submitting it.  It includes a list of programs
-# for each 2-hour period.  These lists will be fetched and scanned to get
-# the program IDs.
-#
-my $START_URL = "$SITEBASE/epg/theGuide.jsp";
+# URL for schedule data
+my $SCHEDULE_URL = "$SITEBASE/data/guideScheduleSegment.json.jsp";
 
 # Each program ID will be appended to this URL to get its details.
-#
-my $DETAILS_URL = "$SITEBASE/listing/component/programDetailAjax.jsp?scheduleId=";
+my $DETAILS_URL = "$SITEBASE/program/details/";
 
 my $XML_PRELUDE =
-  '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" .
-  '<!DOCTYPE tv SYSTEM "xmltv.dtd">' . "\n" .
-  '<tv source-info-url="http://www.directv.com/" source-info-name="DirecTV" ' .
-  'generator-info-name="XMLTV" generator-info-url="http://www.xmltv.org/">' . "\n";
+    '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n"
+  . '<!DOCTYPE tv SYSTEM "xmltv.dtd">' . "\n"
+  . '<tv source-info-url="http://www.directv.com/" source-info-name="DirecTV" '
+  . 'generator-info-name="XMLTV" generator-info-url="http://www.xmltv.org/">'
+  . "\n";
 
 my $XML_POSTLUDE = "</tv>\n";
 
-my %zones = (
-  'e' => -5,
-  'c' => -6,
-  'm' => -7,
-  'p' => -8,
-  'a' => -9,
-  'h' => -10,
-);
-
 # Global stuff shared by the parent and child processes.
-my $zonechar = 'h';
-my $timeoff = $zones{h};
-my $year = 2000; # prepare_queue fixes this
 my $browser;
 my $fhq;
 my $proc_number;
 
+# Default to EST, will read from config file later
+my $timeZone;
+
+# This hash will contain accumulated channel and program information.
+# Key is channel number, value is (a reference to) a hash of channel data
+# derived from JSON data returned by DirecTV. Useful keys include:
+# chNum, chCall, chName, chLogoUrl, chId
+my %ch = ();
+
 ######################################################################
 #                      Main logic starts here                        #
 ######################################################################
 
 # prepare_queue creates the "queue file" of tasks for the child
-# processes and returns the number of program IDs to process, which
-# may be zero.  It always writes channel XML to stdout.
-#
-my $total_programs = &prepare_queue();
-
-if ($total_programs) {
+# processes. It always writes channel XML to stdout.
+if ( &prepare_queue() ) {
 
   # Reopen the queue file so the child processes will share its handle.
   open $fhq, "< $queue_filename";
   binmode $fhq;
 
   # Create the children.
-  for ($proc_number = 0; $proc_number < $MAX_PROCESSES; ++$proc_number) {
+  for ( $proc_number = 0 ; $proc_number < $MAX_PROCESSES ; ++$proc_number ) {
     my $pid = fork;
     if ($pid) {
+
       # We are the parent.  Keep on trucking.
     }
-    elsif (defined $pid) {
+    elsif ( defined $pid ) {
+
       # We are a child.  Do juvenile stuff and then terminate.
       exit &child_logic();
     }
     else {
+      
       # We are the parent and something is wrong.  If we have at least one
       # child process already started, then go with what we have.
-      if ($proc_number > 0) {
+      if ( $proc_number > 0 ) {
         $MAX_PROCESSES = $proc_number;
         last;
       }
+
       # Otherwise retry if possible, or die if not.
-      if ($! == EAGAIN) {
+      if ( $! == EAGAIN ) {
         print STDERR "Temporary fork failure, will retry.\n" if ($VERBOSE);
         sleep 5;
         --$proc_number;
@@ -203,7 +195,7 @@ if ($total_programs) {
   }
 
   if ($VERBOSE) {
-    print STDERR "Started $MAX_PROCESSES processes to fetch and parse $total_programs web pages.\n";
+    print STDERR "Started $MAX_PROCESSES processes to fetch and parse schedule and program data.\n";
   }
 
   # This would be a good place to implement a progress bar.  Just enter a
@@ -211,7 +203,8 @@ if ($total_programs) {
   # and writes the corresponding percentage completion.
 
   # Wait for all the children to finish.
-  while (wait != -1) {
+  while ( wait != -1 ) {
+
     # Getting here means that a child finished.
   }
 
@@ -223,38 +216,41 @@ if ($total_programs) {
   my @cdata = ();
 
   # Open all data files and read the first program of each.
-  for (my $procno = 0; $procno < $MAX_PROCESSES; ++$procno) {
+  for ( my $procno = 0 ; $procno < $MAX_PROCESSES ; ++$procno ) {
     my $fname = "$TMP_FILEBASE" . $procno;
     my $fh;
     open $fh, "< $fname" or die "Cannot open $fname: $!\n";
     $cdata[$procno] = [];
     $cdata[$procno][0] = $fh;
-    &read_program(\@cdata, $procno);
+    &read_queue( \@cdata, $procno );
   }
 
   # Merge the files and print their XML program data.
   my $lastkey = "";
   while (1) {
     my $plow = 0;
+
     # Get the next program, ordering chronologically within channel.
-    for (my $procno = 0; $procno < $MAX_PROCESSES; ++$procno) {
-      $plow = $procno if ($cdata[$procno][1] lt $cdata[$plow][1]);
+    for ( my $procno = 0 ; $procno < $MAX_PROCESSES ; ++$procno ) {
+      $plow = $procno if ( $cdata[$procno][1] lt $cdata[$plow][1] );
     }
-    last if ($cdata[$plow][1] eq 'ZZZZ');
-    if ($lastkey eq $cdata[$plow][1]) {
+    last if ( $cdata[$plow][1] eq 'ZZZZ' );
+    if ( $lastkey eq $cdata[$plow][1] ) {
+
       # There seems to be some race condition in my test setup's OS that
       # allows two child processes to grab the same qfile entry.
       # This is an attempt to work around it. -- Rod
       print STDERR "Skipping duplicate: $lastkey" if ($VERBOSE);
-    } else {
+    }
+    else {
       print $cdata[$plow][2];
       $lastkey = $cdata[$plow][1];
     }
-    &read_program(\@cdata, $plow);
+    &read_queue( \@cdata, $plow );
   }
 
   # Close and delete the temporary files.
-  for (my $procno = 0; $procno < $MAX_PROCESSES; ++$procno) {
+  for ( my $procno = 0 ; $procno < $MAX_PROCESSES ; ++$procno ) {
     close $cdata[$procno][0];
     unlink "$TMP_FILEBASE" . $procno;
   }
@@ -268,48 +264,22 @@ exit 0;
 #                        General Subroutines                         #
 ######################################################################
 
-# Determine if Daylight Saving Time is in effect, given the non-DST
-# values for month, day of month, day of week and hour.  As of 2007
-# the transition days are the second Sunday in March and the first
-# Sunday in November.
-#
-sub isDST {
-  my ($month, $mday, $wday, $hour) = @_;
-  return 1 if ($month > 2 && $month < 10);
-  if ($month == 2) {
-    my $secsun = ($mday + 6 - $wday) % 7 + 8;
-    return 1 if ($mday > $secsun);
-    return 1 if ($mday == $secsun && $hour >= 2);
-  }
-  elsif ($month == 10) {
-    my $firsun = ($mday + 6 - $wday) % 7 + 1;
-    return 1 if ($mday < $firsun);
-    return 1 if ($mday == $firsun && $hour < 1);
-  }
-  return 0;
-}
-
-# Compute a time string for display given a time in non-DST local time.
-#
-sub localTimeString {
-  my @tmp = @_;
-  my $toff = $zones{$zonechar};
-  if ($zonechar ne 'h' && &isDST($tmp[4], $tmp[3], $tmp[6], $tmp[2])) {
-    @tmp = gmtime(timegm(@tmp) + 3600);
-    ++$toff;
-  }
-  return sprintf('%04u%02u%02u%02u%02u%02u %+03d00',
-    $tmp[5] + 1900, $tmp[4] + 1, $tmp[3], $tmp[2], $tmp[1], $tmp[0], $toff);
+sub getBrowser {
+  my ($conf) = @_;
+  my $browser = WWW::Mechanize->new();
+  $browser->proxy( [ 'http', 'https' ], $conf->{proxy}->[0] )
+    if $conf->{proxy}->[0];
+  $browser->agent_alias('Windows Mozilla');
+  return $browser;
 }
 
 # For escaping characters not valid in xml.  More needed here?
-#
 sub xmltr {
   my $txt = shift;
   $txt =~ s/&/&amp;/g;
   $txt =~ s/</&lt;/g;
   $txt =~ s/>/&gt;/g;
-  $txt =~ s/"/&quot;/g;
+  $txt =~ s/\"/&quot;/g;
   return $txt;
 }
 
@@ -317,20 +287,18 @@ sub xmltr {
 #                 Subroutines for the Parent Process                 #
 ######################################################################
 
-# Read information for one program from the file created by the
-# specified process.
-#
-sub read_program {
-  my ($cdata, $procno) = @_;
+# Read one queue entry from the file created by the specified process.
+sub read_queue {
+  my ( $cdata, $procno ) = @_;
   $cdata->[$procno][2] = '';
   my $line = readline $cdata->[$procno][0];
-  if (defined $line) {
+  if ( defined $line ) {
     $cdata->[$procno][1] = $line;
     while (1) {
       $line = readline $cdata->[$procno][0];
-      last unless (defined $line);
+      last unless ( defined $line );
       $cdata->[$procno][2] .= $line;
-      last if ($line =~ /<\/programme>/i);
+      last if ( $line =~ /<\/programme>/i );
     }
   }
   else {
@@ -340,349 +308,222 @@ sub read_program {
 }
 
 # For sorting %ch by its (channel number) key:
-#
-sub numerically { $a <=> $b }
-
-# Increment the listings URL to the next 2-hour time slot.
-#
-sub update_list_url {
-  my ($url, $day, $hour) = @_;
-  $$url =~ s/\?d=\d+/?d=$$day/;
-  $$url =~ s/&h=\d+/&h=$$hour/;
-  $$hour += 2;
-  if ($$hour >= 24) {
-    $$hour -= 24;
-    ++$$day;
-  }
-}
+sub numerically { $a cmp $b }
 
 # This is what the main process does first.  Variables in here will
 # go nicely out of scope before the child processes are started.
-#
 sub prepare_queue {
 
-  my ($opt, $conf) = ParseOptions( {
-    grabber_name => "tv_grab_na_dtv",
-    capabilities => [qw/baseline manualconfig tkconfig apiconfig/],
-    stage_sub => \&config_stage,
-    listchannels_sub => \&list_channels,
-    version => '$Id: tv_grab_na_dtv,v 1.16 2008/12/09 15:48:50 sunsetsystems Exp $',
-    description => "North America using www.directv.com",
-  } );
+  my ( $opt, $conf ) = ParseOptions(
+    {
+      grabber_name     => "tv_grab_na_dtv",
+      capabilities     => [qw/baseline manualconfig tkconfig apiconfig/],
+      stage_sub        => \&config_stage,
+      listchannels_sub => \&list_channels,
+      version =>
+        '$Id: tv_grab_na_dtv,v 1.19 2012/01/08 13:54:00 alewando Exp $',
+      description => "North America using www.directv.com",
+    }
+  );
 
   # If we get here, then we are generating data normally.
 
   $VERBOSE = !$opt->{quiet};
-  $zonechar = $conf->{zone}->[0];
-
-  my @htime = gmtime($timeoff * 3600 + time);
-  $year = $htime[5] + 1900;
-
-  # This hash will contain accumulated channel and program information.
-  # Key is channel number, value is (a reference to) a 4-element array:
-  # channel name, array of "programID/timestamp" pairs, a continuation
-  # variable, the last "cell program ID".
-  #
-  my %ch = ();
-
-  $browser = WWW::Mechanize->new();
-
-  my $list_url = $START_URL . '?d=0&h=0&tz=h&z=' . $conf->{zip}->[0] . '&fl=_d&x=&y=';
-  my $url_day = $htime[7] + 1 + $opt->{offset};
-  my $url_hour = 0;
-
-  if ($opt->{days} > 0) {
-    # This scrapes all of the listing pages for the designated time period.
-    # The only things we save here are channel number and name, and the
-    # program ID/timestamp pairs.  Each page fetch gets us a 2-hour window
-    # for all channels.
-    for (my $day = 0; $day < $opt->{days}; ++$day) {
-      print STDERR "Getting IDs for day $day " if ($VERBOSE);
-      for (my $hour = 0; $hour < 24; $hour += 2) {
-        print STDERR "." if ($VERBOSE);
-        &update_list_url(\$list_url, \$url_day, \$url_hour);
-        &scrape_list($browser, $list_url, $conf->{channel}, \%ch, 0);
-      }
-      print STDERR "\n" if ($VERBOSE);
-    }
+  $DEBUG   = $opt->{debug};
+  
+  $timeZone = $conf->{timezone}[0];
+  $timeZone = "America/New_York" if !$timeZone; # Default to EST
 
-    # Scrape one more time slot with the continuation flag set.
-    print STDERR "Getting one more ...\n" if ($VERBOSE);
-    &update_list_url(\$list_url, \$url_day, \$url_hour);
-    &scrape_list($browser, $list_url, $conf->{channel}, \%ch, 1);
-  }
-  else {
-    # days=0 is a special case requiring only one page fetch.
-    print STDERR "Getting $list_url ...\n" if ($VERBOSE);
-    &scrape_list($browser, $list_url, $conf->{channel}, \%ch, 0);
-  }
+  $browser = getBrowser($conf);
+
+  # Populate %ch hash
+  &scrape_channel_list( $browser, $conf->{zip}[0], $conf->{channel}, \%ch );
 
   print $XML_PRELUDE;
 
   # Write XML for channels, and total the number of program IDs.
-  my $total_programs = 0;
-  foreach my $channel_number (sort numerically keys %ch) {
-    print &channel_xml($channel_number, 0, \%ch);
-    $total_programs += scalar @{$ch{$channel_number}[1]};
+  foreach my $channel_number ( sort numerically keys %ch ) {
+    print &channel_xml( $channel_number, 0, \%ch );
   }
 
   # Write all of the program IDs with their channel IDs and start times
   # to a temporary file. This file will later be read by child processes.
-  if ($opt->{days} > 0) {
-    open $fhq, "> $queue_filename";
-    binmode $fhq;
-    foreach my $channel_number (sort numerically keys %ch) {
-      my $channel_name = $ch{$channel_number}[0];
-      my $channel_id = &rfc2838($channel_number, $channel_name);
-      my $program_count = scalar @{$ch{$channel_number}[1]};
-      foreach my $tmp (@{$ch{$channel_number}[1]}) {
-        my ($program_id, $startmins) = split /\//, $tmp;
-        # Fixed-length records make life easier.  See comments in child_logic.
-        printf $fhq "%-25s %-13s %9u\n", $channel_id, $program_id, $startmins;
-      }
+  my $startDate = DateTime->now;
+  $startDate->set_time_zone($timeZone);
+
+  # Add offset to start date
+  $startDate -> add(days => $opt->{offset});
+
+  open $fhq, "> $queue_filename";
+  binmode $fhq;
+  foreach my $channel_number ( sort numerically keys %ch ) {
+    my %channel_data = %{ $ch{$channel_number} };
+    my $channel_name = $channel_data{chName};
+    my $channel_id   = &rfc2838( $channel_number, $channel_name );
+
+    # Write queue entry for each channel and day
+    # Queue file contains two fields: channel_number day(yyyy-mm-dd)
+    for ( my $day = 0 ; $day < $opt->{days} ; $day++ ) {
+      my $queueDate = $startDate->clone();
+      $queueDate->add(days => $day);
+      my $date = $queueDate->ymd;
+
+      # Fixed-length records make life easier.  See comments in child_logic.
+      printf $fhq "%-6s %10s\n", $channel_number, $date;
     }
-    close $fhq;
-    return $total_programs;
   }
-
-  return 0;
+  close $fhq;
 }
 
 # Create a channel ID.
-#
 sub rfc2838 {
-  my ($cnum, $cname) = @_;
-
-  # $cname =~ s/&amp;//g;
-  # $cname =~ s/&//g; # mythtv does not like ampersands here
-  # return sprintf('%04d.%s.directv.com', $cnum, $cname);
-
-  # The above did not work out very well because directv was making
-  # random changes to the channel names.  So now we just use numbers.
-  return sprintf('%04d.directv.com', $cnum);
+  my ( $cnum, $cname ) = @_;
+  my $num = $cnum;
+  my $extra = "";
+  if($cnum =~ /^(\d+)(-.*)/) {
+    $num = $1;
+    $extra = $2;  
+  } 
+  my $id = sprintf('%04s%s.directv.com', $num, $extra );
+  return $id;
 }
 
 # This gets channels and program IDs for the one 2-hour time slot from
 # the designated URL.
-#
-sub scrape_list {
-  my ($browser, $list_url, $channels, $ch, $overtime) = @_;
-
-  # This computes a timestamp in minutes since the beginning of
-  # the current year (Hawaii time).
-  $list_url =~ /\?d=(\d+)&h=(\d+)/;
-  my $start_timestamp = 60 * (($1 - 1) * 24 + $2);
-
-  $browser->get($list_url);
-  my $parser = HTML::TokeParser->new(\$browser->content());
-  my $previous_channel = '';
-
-  # Loop by channel within this time slot.
-  while(my $tag = $parser->get_tag("span")) {
-    next if (!$tag->[1]{class});
-    next unless ($tag->[1]{class} eq 'ep-lcl' or $tag->[1]{class} eq 'listing-channel-logo');
-    my $channel_name = $parser->get_trimmed_text("/span");
-    $tag = $parser->get_tag("span");
-    next unless ($tag->[1]{class} eq 'ep-lcb' or $tag->[1]{class} eq 'listing-channel-bug');
-    my $channel_number = $parser->get_trimmed_text("/span");
-
-    # Skip channel numbers that are not all digits.  Seems that some HD
-    # channels were coming through with numbers like "229-1".
-    next unless ($channel_number =~ /^\d+$/);
-
-    # Check for duplicate rows.  Mostly from HD versions of channels.
-    next if ($channel_number eq $previous_channel);
-    $previous_channel = $channel_number;
-
-    my $channel_id = &rfc2838($channel_number, $channel_name);
+sub scrape_channel_list {
+  my ( $browser, $zip, $channels, $ch ) = @_;
+
+  # Set zipcode (start session)
+  my $setZipUrl = "${SITEBASE}/lightbox/lightboxZipCode.jsp?_DARGS=/entertainment/lightbox/component/lightboxZipCodeComponent.jsp"; 
+  my %params = ( "/directv/eportal/formhandler/EportalProfileFormHandler.profileUpdateForm.zipCode" => "$zip" );
+  print STDERR "Setting zip code\n" if ($DEBUG);
+  $browser->post( $setZipUrl, Content => \%params );
+
+  print STDERR "Getting channel list\n" if ($DEBUG);
+  my $listUrl = $CHANNEL_LIST_URL . "?hideDupes=true&view=ALL&zipcode=${zip}";
+  $browser->get($listUrl);
+  my $json = $browser->content();
+  my $data = decode_json $json;
+
+  # Check status code
+  if ( !$data->{success} ) {
+    print STDERR "Error getting channel list: " . $data->{errorMessage} . "\n";
+    exit 1;
+  }
 
-    # If channels were passed, skip those not listed.
-    if ($channels) { next unless grep /^$channel_id$/, @$channels; }
-
-    # Create a new hash entry for this channel, but only if it does not
-    # already exist.  Its value is a reference to a 4-element array:
-    # channel name, array of "programID/timestamp" pairs, a continuation
-    # variable, the last "cell program ID".
-    if (!$ch->{$channel_number}) {
-      $ch->{$channel_number} = [$channel_name, [], 0, ''];
+  # Populate %ch hash for selected channels
+  my @channels = @{ $data->{channels} };
+  for my $chanRef (@channels) {
+    my %chanData       = %{$chanRef};
+    my $channel_number = $chanData{chNum};
+    my $channel_name   = $chanData{chName};
+
+    # Handle channels with both HD and SD versions (ie: 0756-1.directv.com)
+    # Usually only seen on sports subscriptions where some games are not available in HD 
+    # (ie: NBA League Pass, MLS, etc)
+    my $dual;
+    if($channel_name =~ /${channel_number}-1/ && $chanData{chHd}) {
+      $dual=1;
     }
 
-    # Append to the array of program IDs and times for this channel.
-    # We scan the cells in two passes in order to get the total pixel
-    # width, which is then needed to compute each cell's duration.
-    # Curiously, this total width can vary a bit from row to row.
-
-    # Pass 1: Scrape listings for this time slot and channel, save their
-    # widths and program IDs, and total the widths.
-    my $totwidth = 0;
-    my @cells = ();
-    while($tag = $parser->get_tag("li", "/tr")) {
-      last unless ($tag->[0] eq "li");
-      die "Missing style for li!" unless ($tag->[1]{style});
-      die "Missing width for li!" unless ($tag->[1]{style} =~ /width:\s*([\d.]+)px/);
-      my $width = $1;
-      $totwidth += $width;
-      my $programid = "";
-      if ($tag->[1]{id} && $tag->[1]{id} =~ /(\d+)/) {
-        $programid = $1;
-      }
-      push @cells, [$width, $programid];
+    my $channel_id     = &rfc2838( $channel_number, $channel_name );
+    # If channels were passed, skip those not listed.
+    if ($channels) {
+      next unless grep /^$channel_id$/, @$channels;
     }
 
-    # Pass 2: Process the above into the %ch array.
-    my $lastendtime = $start_timestamp;
-    foreach my $tmp (@cells) {
-      my ($width, $programid) = @$tmp;
-      # Computing cell size in minutes from its width in pixels.
-      my $duration = int($width * 120 / $totwidth + .5);
-      # Grab and clear a previously saved start time, if present.
-      my $tmp_start = $ch->{$channel_number}[2];
-      $ch->{$channel_number}[2] = 0;
-
-      if ($programid ne "") {
-        if ($ch->{$channel_number}[3] ne "" and $programid ne $ch->{$channel_number}[3])
-        {
-          $tmp_start = $lastendtime if ($tmp_start == 0);
-          push @{$ch->{$channel_number}[1]}, "$programid/$tmp_start";
-        }
-        $ch->{$channel_number}[3] = $programid;
-      }
-      elsif ($ch->{$channel_number}[3] eq "") {
-        # If this program ID is missing and it is the first cell for
-        # the channel, then set it to a non-empty dummy value so that the
-        # next cell will create a new program entry.
-        $ch->{$channel_number}[3] = "0";
-      }
-      elsif (($lastendtime % 120) > 105) {
-        # A program ID near the end of the time slot is missing.  In this
-        # case it starts a new program whose ID we do not yet know, and
-        # we save its start time for the next iteration.
-        $ch->{$channel_number}[2] = $lastendtime;
-      }
-      # Otherwise if the program ID is missing, we assume it extends the
-      # previous one (i.e. we do not change it here).
-
-      # Keep track of the corresponding time as cells are processed.
-      $lastendtime += $duration;
-
-      # Look at the first cell only if this is the overtime slot.
-      last if ($overtime);
-    } # end foreach
-  } # end while
+    # Add to ch hash
+    $ch->{$channel_number} = $chanRef if !$ch->{$channel_number};
+    if($dual) { 
+      $ch->{$channel_number}->{dual} = 1;
+    }
+  }
 }
 
 # Invoked by ParseOptions for configuration.
-#
-sub config_stage
-{
-    my ($stage, $conf) = @_;
-
-    die "Unknown stage $stage" if $stage ne "start";
-
-    my $result;
-    my $writer = new XMLTV::Configure::Writer(OUTPUT => \$result,
-      encoding => 'utf-8');
-    $writer->start( { grabber => 'tv_grab_na_dtv' } );
-
-    # DirecTV wants a time zone.
-    #
-    $writer->start_selectone( {
-      id => 'zone',
-      title => [ [ 'Time Zone', 'en' ] ],
-      description => [ [ 'Which is your time zone?', 'en' ] ],
-    } );
-    $writer->write_option( {
-      value=>'e',
-      text=> => [ [ 'Eastern', 'en' ] ]
-      } );
-    $writer->write_option( {
-      value=>'c',
-      text=> => [ [ 'Central', 'en' ] ]
-      } );
-    $writer->write_option( {
-      value=>'m',
-      text=> => [ [ 'Mountain', 'en' ] ]
-      } );
-    $writer->write_option( {
-      value=>'p',
-      text=> => [ [ 'Pacific', 'en' ] ]
-      } );
-    $writer->write_option( {
-      value=>'a',
-      text=> => [ [ 'Alaska', 'en' ] ]
-      } );
-    $writer->write_option( {
-      value=>'h',
-      text=> => [ [ 'Hawaii', 'en' ] ]
-      } );
-    $writer->end_selectone();
-
-    # Entering a zip code will cause local channels to be included, if
-    # available.  In some cases a county ID will also be desirable, but we
-    # do not support that yet.  Sorry.
-    #
-    $writer->write_string( {
-      id => 'zip',
+sub config_stage {
+  my ( $stage, $conf ) = @_;
+
+  die "Unknown stage $stage" if $stage ne "start";
+
+  my $result;
+  my $writer = new XMLTV::Configure::Writer(
+    OUTPUT   => \$result,
+    encoding => 'utf-8'
+  );
+  $writer->start( { grabber => 'tv_grab_na_dtv' } );
+
+  # Entering a zip code will cause local channels to be included, if
+  # available.
+  $writer->write_string(
+    {
+      id    => 'zip',
       title => [ [ 'Zip Code', 'en' ] ],
-      description => [ [ 'Enter your zip code to include local channels.', 'en' ] ],
-      } );
+      description =>
+        [ [ 'Enter your zip code to include local channels.', 'en' ] ],
+    }
+  );
+  
+  # Timezone is needed to adjust the UTC times provided by DirecTV to local time
+  my @timezones = DateTime::TimeZone->names_in_country("US");
+  $writer->start_selectone( {
+        id => 'timezone', 
+        title => [ [ 'Time Zone', 'en' ], ],
+        description => [ [ 'The timezone that you live in.', 'en' ], ],
+  } );
+  
+  foreach my $tz (@timezones) {
+        $writer->write_option( { 
+             value=>$tz,
+             text=> => [ [ $tz, 'en' ], ] 
+        } );
+  }
 
-    $writer->end('select-channels');
-    return $result;
+  $writer->end_selectone();
+
+  $writer->end('select-channels');
+  return $result;
 }
 
 # Invoked by ParseOptions when it wants the list of all channels.
-#
 sub list_channels {
-  my ($conf, $opt) = @_;
+  my ( $conf, $opt ) = @_;
 
   $VERBOSE = !$opt->{quiet};
-  $zonechar = $conf->{zone}->[0];
-
-  my @htime = gmtime($timeoff * 3600 + time);
-  $year = $htime[5] + 1900;
-
-  my $browser = WWW::Mechanize->new();
-
-  my $list_url = $START_URL . '?d=' . ($htime[7] + 1) . '&h=8&tz=h&z=' .
-    $conf->{zip}->[0] . '&fl=_d&x=&y=';
 
-  # see prepare_queue for a description of this hash.
-  my %ch = ();
-
-  # Scrape only one listings page to get the channels.
-  &scrape_list($browser, $list_url, 0, \%ch, 0);
+  my $browser = getBrowser($conf);
+  &scrape_channel_list( $browser, $conf->{zip}[0], $conf->{channel}, \%ch );
 
   my $xml = $XML_PRELUDE;
-  foreach my $channel_number (sort numerically keys %ch) {
-    $xml .= &channel_xml($channel_number, 1, \%ch);
+  foreach my $channel_number ( sort numerically keys %ch ) {
+    $xml .= &channel_xml( $channel_number, 1, \%ch );
   }
   $xml .= $XML_POSTLUDE;
 
   return $xml;
 }
 
-# Create XML for the designated channel.  Rules for this are slippery,
-# with mythfilldatabase containing grabber-specific code that expects
-# different output from different grabbers!  The arrangement below seems
-# to work compatibly with tv_grab_be_tvb or tv_grab_no.
-#
+# Create XML for the designated channel.
 sub channel_xml {
-  my ($channel_number, $setup, $ch) = @_;
-  my $channel_name = $ch->{$channel_number}[0];
-  my $channel_id = &rfc2838($channel_number, $channel_name);
-  my $xml = "  <channel id=\"$channel_id\">\n";
+  my ( $channel_number, $setup, $ch ) = @_;
+  my %channel_data = %{ $ch->{$channel_number} };
+
+  my $channel_name = $channel_data{chName};
+  my $channel_id   = &rfc2838( $channel_number, $channel_name );
+  my $xml          = "  <channel id=\"$channel_id\">\n";
   if ($setup) {
+
     # At --configure time the user will want to see channel numbers.
     $xml .=
-    "    <display-name>$channel_number " . &xmltr($channel_name) . "</display-name>\n";
-  }
-  else {
-    # Otherwise we go for compatibility with mythfilldatabase.
+        "    <display-name>$channel_number "
+      . &xmltr($channel_name)
+      . "</display-name>\n";
+  } else {
     $xml .=
-    "    <display-name>" . &xmltr($channel_name) . "</display-name>\n" .
-    "    <display-name>$channel_number</display-name>\n" .
-    "    <display-name>$channel_number</display-name>\n";
+        "    <display-name>"
+      . &xmltr($channel_name)
+      . "</display-name>\n"
+      . "    <display-name>$channel_number</display-name>\n";
   }
   $xml .= "  </channel>\n";
   return $xml;
@@ -693,7 +534,6 @@ sub channel_xml {
 ######################################################################
 
 # Top-level logic for child processes.
-#
 sub child_logic {
   my $fname = "$TMP_FILEBASE" . $proc_number;
   my $fh;
@@ -703,146 +543,274 @@ sub child_logic {
   # pointer sharing will work properly.  We expect the sysreads to be atomic.
   while (1) {
     my $line = '';
-    my $readlen = sysread $fhq, $line, 50;
+    my $readlen = sysread $fhq, $line, 18;
     last unless ($readlen);
-    if ($line =~ /^(\d\d\d\d\.\S+)\s+(\S+)\s+(\d+)\s*$/) {
-      print $fh &scrape_program($browser, $2, $1, $3);
+
+    #print STDERR "Process $proc_number Queue entry:$line\n" if ($VERBOSE);
+    # Queue line format (%-6s %10s)
+    if ( $line =~ /^([0-9-]+)\s+(.*)$/ ) {
+      my $channel_number = $1;
+      my $day            = $2;
+      print $fh &scrape_channel_day( $browser, $channel_number, $day );
     }
     else {
       # Errors here might mean that seek pointer sharing is broken.
       print STDERR "Process $proc_number: input syntax error: '$line'\n";
     }
   }
-
   close $fh;
   return 0;
 }
 
-# This generates XML for the designated program ID.  It retrieves and scrapes
-# the "program details" AJAX thingy, so a page fetch is required for each.
-#
-sub scrape_program {
-  my ($browser, $program_id, $channel_id, $startmins) = @_;
-
-  # Compute air time from $startmins and current year.
-  my $timeair = $startmins * 60 + timegm(0, 0, 0, 1, 0, $year - 1900);
-  my @stt = gmtime($timeair + 3600 * ($zones{$zonechar} - $zones{h}));
-  # We will also make use of this as a key string.
-  my $starttime = sprintf('%04u%02u%02u%02u%02u%02u',
-    $stt[5] + 1900, $stt[4] + 1, $stt[3], $stt[2], $stt[1], $stt[0]);
-  # Then produce a readable actual local date and time.
-  my $xml_start = 'start="' . &localTimeString(@stt) . '"';
-
-  $browser->get($DETAILS_URL . $program_id);
-  my $parser = HTML::TokeParser->new(\$browser->content());
-
-  my $xml_title    = '(Unknown)';
-  my $xml_desc     = '';
-  my $xml_stop     = ''; # attribue of <programme>
-  my $xml_length   = '';
-  my $xml_category = '';
-  my $xml_actor    = ''; # within <credits>
-  my $xml_rating   = '';
-  my $xml_date     = '';
-  my $xml_director = ''; # within <credits>
+# Parse a date from DirecTV (in ISO-8601 format)
+sub parseDate {
+  my ($input) = @_;
+  # Format 2012-01-09T04:00:00.000+0000
+  my ($y,$m, $d, $h, $min, $s, $z) = $input =~ /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.\d{3}([+-]\d+)/;
+  my $date = DateTime->new(
+        year       => $y,
+        month      => $m,
+        day        => $d,
+        hour       => $h,
+        minute     => $min,
+        second     => $s,
+        nanosecond => 0,
+        time_zone  => $z,
+    );
+    $date->set_time_zone($timeZone);
+    return $date;
+}
+
+sub printDate {
+  my ($dt) = @_;
+  #Format 20120109233500 -0500
+  my $str = $dt->strftime("%Y%m%d%H%M%S ") . DateTime::TimeZone->offset_as_string($dt->offset);
+  return $str;
+}
+
+# Check that the start date is on the requested day (after adjusting to the specified timezone) 
+sub checkStartDate {
+ my ($day, $startDt) = @_;
+ my $cmpDay = $startDt->ymd;
+ return $cmpDay eq $day;
+}
+
+# This generates XML for the designated channel on the designated day
+sub scrape_channel_day {
+  my ( $browser, $channel_number, $day ) = @_;
+
+  print STDERR "Retrieving schedule info for channel $channel_number on $day\n"
+    if ($VERBOSE);
+
+  my $shortNum = $channel_number;
+  $shortNum =~ s/(\d+)-.*/$1/;
+
+  #Get channel schedule data for the specified day from the DirecTV JSON URL
+  my %params = (
+    scheduleType   => 'custom',
+    starttime      => "$day 00:00",
+    channelnumbers => "$shortNum",
+    blockduration  => 24
+  );
+  $browser->post( $SCHEDULE_URL, Content => \%params );
+  my $json = $browser->content();
+
+  # Parse JSON
+  my $data = decode_json $json;
+
+  # Check status code
+  if ( !$data->{success} ) {
+    print STDERR
+      "Error getting schedule data for channel $channel_number on $day: "
+      . $data->{errorMessage} . "\n";
+    exit 1;
+  }
+
+  my $output    = "";
+  if( @{ $data->{channels} }[0]->{schedules} ) {
+    my @schedules = @{ @{ $data->{channels} }[0]->{schedules} };
+    foreach my $prog (@schedules) {
+           # Skip if program does not start on the target date (ie: started the previous day)
+           my $startDate = parseDate($prog->{prAir});
+           $prog->{startDt} = $startDate;
+           if (!checkStartDate($day, $startDate)) {
+             print STDERR "Skipping program $prog->{prId} because it doesn't start on $day: $prog->{prAir}\n" if ($DEBUG);
+             next;
+           }  
+           
+      # Get program details
+      $output .= &scrape_program_details( $browser, $channel_number, $prog );
+    }
+  }
+  return $output;
+}
+
+sub scrape_program_details {
+  my ( $browser, $channel_number, $program_data ) = @_;
+
+  # Get what we can from the JSON structure
+  my $program_id = $program_data->{prId};
+  my $title      = xmltr( $program_data->{prTitle} );
+  my $subtitle   = xmltr( $program_data->{episodeTitle} );
+  my $start      = xmltr( $program_data->{prAir} );
+  my $length     = $program_data->{prLen};
+  my $hd         = $program_data->{prHd};
+
+  # Append '-1' to channel number if this is an HD broadcast on a dual-numbered channel
+  # This is how the channel is entered mannualy on the receiver
+  if($ch{$channel_number}->{dual} && $hd) {
+    $channel_number .= "-1";
+  }
+  
+  my $channel_id = &rfc2838($channel_number);
+
+  # Calculate stop time
+  my $startDate = $program_data->{startDt};
+  my $stopDate = $startDate->clone();
+  $stopDate->add(minutes => $length);
+
+  # Get program details page
+  my $programDetailsUrl = $DETAILS_URL . $program_id;
+  print STDERR "Retrieving details for program id $program_id: $programDetailsUrl\n" if ($DEBUG);
+  my $resp = $browser->get( $programDetailsUrl );
+  if(! $resp->is_success()) {
+    print STDERR "Error getting program details for $program_id: " . $resp->status_line() . "\n";
+  }
+
+  my $detailContent = $browser->content();
+  my $parser = HTML::TokeParser->new( \$detailContent );
+
+  # Extract program details
+  my $xml_desc        = '';
+  my $xml_language    = '';
+  my $xml_rating      = '';
+  my $xml_date        = '';
   my $xml_star_rating = '';
-  my $tag;
-
-  while($tag = $parser->get_tag("span", "div", "dt")) {
-    if ($tag->[0] eq "span") {
-      next unless ($tag->[1]{class});
-      if ($tag->[1]{class} eq 'detTitle') {
-        $xml_title = "    <title lang=\"en\">" .
-          &xmltr($parser->get_trimmed_text("/span")) . "</title>\n";
-      }
-      elsif ($tag->[1]{class} eq 'detRating') {
-        $xml_rating = "    <rating system=\"MPAA\"><value>" .
-          &xmltr($parser->get_trimmed_text("/span")) . "</value></rating>\n";
-      }
-      elsif ($tag->[1]{class} eq 'detStar') {
-        $tag = $parser->get_tag("img", "/span");
-        if ($tag->[0] eq "img") {
-          if ($tag->[1]{src} =~ /icon_stars_(\d+)/) {
-            $xml_star_rating = "    <star-rating><value>" .
-              $1 . '/4' . "</value></star-rating>\n";
+  my @directors;
+  my @actors;
+  my @categories;
+
+# Description is in (xpath): //li[@id="details_tab_content"]/h4/following-sibling::p
+# Details are in (xpath): //li[@id="details_tab_content"]/h4[@id="additional_details"]
+OUTER: while ( my $tag = $parser->get_tag( "li", "span" ) ) {
+    if ( $tag->[0] eq "li" ) {
+      my $li_id = $tag->[1]{id};
+      next unless ($li_id);
+      if ( $li_id eq 'details_tab_content' ) {
+
+        # Skip ahead to h4 tags (description and details)
+        while ( my $h4Tag = $parser->get_tag("h4") ) {
+        &nbs