Ticket #5371: mythical.pl

File mythical.pl, 4.6 KB (added by daveg at dgnode dot screaming dot net, 16 years ago)

Perl script

Line 
1#!/usr/bin/perl -w
2# Name:          mythical
3# Version:       0.1
4# Release:       1
5# Summary:       Generate an iCalendar file of upcoming MythTV recordings
6# License:       GPL - use at your own risk etc.
7# Copyright:     (C) 2008 - David Greenhouse <daveg at dgnode dot screaming dot net>
8# Description:
9#   Similar to mythtv/contrib/misc_status_info/myth_upcoming_recordings.pl
10#   but generates an iCalendar (RFC2445) file for use with desktop calendar
11#   applications such as KOrganizer.
12# Why?
13#   The information is already available within MythTV frontend and MythWeb but is
14#   a natural fit for a desktop calendar application. With the data in iCalendar (RFC2445)
15#   format it becomes very portable either by direct access or via synchronisation such
16#   as SyncML. May even get my Palm to run as a IR remote and synchronise the recording
17#   schedule via OBEX!
18# Usage:
19#   # MythTV class gripes about UPnP missing so redirect stderr if run by cron etc.
20#   mythical.pl 2>/dev/null >~/mythical.ics
21# TODO:
22#   UTF-8.
23#   Run-time options.
24#   Timezones.
25#   Testing for daylight saving etc.
26#   Suggestions?
27# Further Development?
28#   Could be merged with 'myth_upcoming_recordings.pl'.
29#   Functionality could be included in MythWeb to provide a live webCal interface.
30#   Use Data::iCal (not in Fedora 8 yet).
31#   Suggestions?
32# Revision History:
33# * 2008-05-16  0.1-1   David Greenhouse <daveg at dgnode dot screaming dot net>
34#   - Initial creation.
35
36use strict;
37use warnings;
38use MythTV;
39
40#program version
41my $VERSION="0.1";
42
43# Connect to the MythTV backend
44my $myth = new MythTV();
45# Get a list of upcoming recordings
46my %rows = $myth->backend_rows('QUERY_GETALLPENDING', 2);
47my $row;
48my $show;
49# iCalendar wrapper
50format_value('BEGIN', 'VCALENDAR');
51format_value('VERSION', '2.0');
52format_value('PROGID', "-//MythTV Recording Schedule//NONSGML mythical $VERSION//EN");
53# Content
54foreach $row (@{$rows{'rows'}}) {
55        $show = new MythTV::Program(@$row);
56        # Selection criteria...
57        if (include_this($show)) {
58                format_event($show);
59        }
60}
61format_value('END', 'VCALENDAR');
62
63# Test to include the given programme or not.
64# May need some more work, run-time options etc.
65sub include_this {
66        my $prog = shift;
67        return $prog->{'recstatus'} == $MythTV::recstatus_willrecord;
68}
69
70# Output an iCalendar entry for the given programme.
71sub format_event {
72        my $prog = shift;
73        format_value('BEGIN', 'VEVENT');
74        format_value('DTSTAMP', format_date(time()));
75        format_value('UID', format_uid($prog));
76        format_value('DTSTART', format_date($prog->{'starttime'}));
77        format_value('DTEND', format_date($prog->{'endtime'}));
78        format_value('LAST-MODIFIED', format_date($prog->{'lastmodified'}));
79        if ($prog->{'subtitle'} ne 'Untitled') {
80                format_value('SUMMARY', $prog->{'title'} . ' - "' . $prog->{'subtitle'} . '"');
81        } else {
82                format_value('SUMMARY', $prog->{'title'});
83        }
84        format_value('DESCRIPTION', $prog->{'description'});
85        format_value('LOCATION', $prog->{'channel'}{'name'});
86        format_value('CATEGORIES', $prog->{'category'});
87        format_value('TRANSP', $prog->{'recstatus'} == $MythTV::recstatus_willrecord ? 'OPAQUE' : 'TRANSPARENT');
88        format_value('STATUS', $prog->{'recstatus'} == $MythTV::recstatus_willrecord ? 'CONFIRMED' : 'TENTATIVE');
89        format_value('PRIORITY', format_priority($prog));
90        format_value('X-MYTHTV-RECSTATUS', $MythTV::RecStatus_Types{$prog->{'recstatus'}});
91        format_value('END', 'VEVENT');
92}
93
94# Format an entry line with the given tag and value.
95# Escapes and wraps, terminate with CR-NL.
96sub format_value {
97        my $tag = shift;
98        my $value = shift;
99        # Escapes
100        $value =~ s/;/\\;/g;
101        $value =~ s/,/\\,/g;
102        $value =~ s/"/\\"/g;
103        # Wrap at col 76
104        my $text = $tag . ":" . $value;
105        while (length($text) > 76) {
106                print substr($text, 0, 76) . "\r\n";
107                $text = ' ' . substr($text, 76);
108        }
109        if ($text ne ' ') {
110                print $text . "\r\n";
111        }
112}
113
114# Format a date/time value as an iCalendar Date/Time
115sub format_date {
116        my $localtime = shift;
117        my ($ts,$tm,$th,$dd,$dm,$dy) = localtime($localtime);
118        # YYYYMMDDThhmmss
119        return sprintf "%4.4d%2.2d%2.2dT%2.2d%2.2d%2.2d", $dy + 1900, $dm + 1, $dd, $th, $tm, $ts;
120}
121
122# Generate a unique identifier for the given programme.
123# chanid_starttime@hostname
124sub format_uid {
125        my $prog = shift;
126        my ($ts,$tm,$th,$dd,$dm,$dy) = localtime($prog->{'starttime'});
127        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'};
128}
129
130# Simple classification of recording priority in to three levels.
131sub format_priority {
132        my $prog = shift;
133        my $pri = $prog->{'recpriority'};
134        if ($pri < 0) {
135                return 'LOW';
136        } elsif ($pri > 0) {
137                return 'HIGH';
138        }
139        return 'MEDIUM';
140}