Mythical.pl
From MythTV Official Wiki
Author | David Greenhouse |
Description | Outputs information about upcoming recordings in iCalendar format, for use with iCal-enabled scheduling/calendar applications. |
Supports |
Generates an iCalendar (RFC2445) file for use with desktop calendar applications such as KOrganizer.
#!/usr/bin/perl -w # Name: mythical # Version: 0.1 # Release: 1 # Summary: Generate an iCalendar file of upcoming MythTV recordings # License: GPL - use at your own risk etc. # Copyright: (C) 2008 - David Greenhouse <daveg at dgnode dot screaming dot net> # Description: # Similar to http://www.mythtv.org/wiki/myth_upcoming_recordings.pl # but generates an iCalendar (RFC2445) file for use with desktop calendar # applications such as KOrganizer. # Why? # The information is already available within MythTV frontend and MythWeb but is # a natural fit for a desktop calendar application. With the data in iCalendar (RFC2445) # format it becomes very portable either by direct access or via synchronisation such # as SyncML. May even get my Palm to run as a IR remote and synchronise the recording # schedule via OBEX! # Usage: # # MythTV class gripes about UPnP missing so redirect stderr if run by cron etc. # mythical.pl 2>/dev/null >~/mythical.ics # TODO: # UTF-8. # Run-time options. # Timezones. # Testing for daylight saving etc. # Suggestions? # Further Development? # Could be merged with 'myth_upcoming_recordings.pl'. # Functionality could be included in MythWeb to provide a live webCal interface. # Use Data::iCal (not in Fedora 8 yet). # Suggestions? # Revision History: # * 2008-05-16 0.1-1 David Greenhouse <daveg at dgnode dot screaming dot net> # - Initial creation. use strict; use warnings; use MythTV; #program version my $VERSION="0.1"; # Connect to the MythTV backend my $myth = new MythTV(); # Get a list of upcoming recordings my %rows = $myth->backend_rows('QUERY_GETALLPENDING', 2); my $row; my $show; # iCalendar wrapper format_value('BEGIN', 'VCALENDAR'); format_value('VERSION', '2.0'); format_value('PROGID', "-//MythTV Recording Schedule//NONSGML mythical $VERSION//EN"); # Content foreach $row (@{$rows{'rows'}}) { $show = new MythTV::Program(@$row); # Selection criteria... if (include_this($show)) { format_event($show); } } format_value('END', 'VCALENDAR'); # Test to include the given programme or not. # May need some more work, run-time options etc. sub include_this { my $prog = shift; return $prog->{'recstatus'} == $MythTV::recstatus_willrecord; } # Output an iCalendar entry for the given programme. sub format_event { my $prog = shift; format_value('BEGIN', 'VEVENT'); format_value('DTSTAMP', format_date(time())); format_value('UID', format_uid($prog)); format_value('DTSTART', format_date($prog->{'starttime'})); format_value('DTEND', format_date($prog->{'endtime'})); format_value('LAST-MODIFIED', format_date($prog->{'lastmodified'})); if ($prog->{'subtitle'} ne 'Untitled') { format_value('SUMMARY', $prog->{'title'} . ' - "' . $prog->{'subtitle'} . '"'); } else { format_value('SUMMARY', $prog->{'title'}); } format_value('DESCRIPTION', $prog->{'description'}); format_value('LOCATION', $prog->{'channel'}{'name'}); format_value('CATEGORIES', $prog->{'category'}); format_value('TRANSP', $prog->{'recstatus'} == $MythTV::recstatus_willrecord ? 'OPAQUE' : 'TRANSPARENT'); format_value('STATUS', $prog->{'recstatus'} == $MythTV::recstatus_willrecord ? 'CONFIRMED' : 'TENTATIVE'); format_value('PRIORITY', format_priority($prog)); format_value('X-MYTHTV-RECSTATUS', $MythTV::RecStatus_Types{$prog->{'recstatus'}}); format_value('END', 'VEVENT'); } # Format an entry line with the given tag and value. # Escapes and wraps, terminate with CR-NL. sub format_value { my $tag = shift; my $value = shift; # Escapes $value =~ s/;/\\;/g; $value =~ s/,/\\,/g; $value =~ s/"/\\"/g; # Wrap at col 76 my $text = $tag . ":" . $value; while (length($text) > 76) { print substr($text, 0, 76) . "\r\n"; $text = ' ' . substr($text, 76); } if ($text ne ' ') { print $text . "\r\n"; } } # Format a date/time value as an iCalendar Date/Time sub format_date { my $localtime = shift; my ($ts,$tm,$th,$dd,$dm,$dy) = localtime($localtime); # YYYYMMDDThhmmss return sprintf "%4.4d%2.2d%2.2dT%2.2d%2.2d%2.2d", $dy + 1900, $dm + 1, $dd, $th, $tm, $ts; } # Generate a unique identifier for the given programme. # chanid_starttime@hostname sub format_uid { my $prog = shift; my ($ts,$tm,$th,$dd,$dm,$dy) = localtime($prog->{'starttime'}); return sprintf "%4.4s_%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d@%s", $prog->{'chanid'}, $dy + 1900, $dm + 1, $dd, $th, $tm, $ts, $prog->{'hostname'}; } # Simple classification of recording priority in to three levels. sub format_priority { my $prog = shift; my $pri = $prog->{'recpriority'}; if ($pri < 0) { return 'LOW'; } elsif ($pri > 0) { return 'HIGH'; } return 'MEDIUM'; }