ICS Kalender in Owncloud importieren
Posted by quark007 | Posted in Programmieren / Coden | Posted on 01-01-2016-05-2008
0
Wer einmal mit Owncloud angefangen wird davon vermutlich nicht mehr loskommen. Doch einige Punkte sind noch nicht optimal gelöst bzw. für bestimmte Anforderungen gibt es noch keine OutOfTheBox Lösung. Dazu gehört auch das importieren von KalenderFeeds. In meinem Fall sind das z.B. Abfuhrtermine für Haushaltsmüll oder aber Sportveranstaltungen am Wochenende.
Mit PHP-Skripten habe ich mir bereits aus den Internetseiten die Daten für eine ICS-File extrahiert und daraus eine konforme ics-datei erzeugt. Dies geschieht bei jedem Aufruf des Scripts automatisch. Ein Beispiel, das die Spieltermine der Badmintonabteilung des TSV Lauf 1 aufbereitet (bereits ausgetragene Spiele werden dabei herausgefiltert):
<?php $ch = curl_init(); $URL = "http://www.alleturniere.de/sport/drawmatches.aspx?id=5892ECDD-1447-4D3B-ABF2-99A596D92E79&draw=1"; curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //Set the URL curl_setopt($ch, CURLOPT_URL, $URL); //Execute the fetch $data = curl_exec($ch); //Close the connection curl_close($ch); $position = strpos($data,'<table class="ruler matches">'); $text_new = substr($data,$position); $ics_data = array("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nMETHOD:PUBLISH\r\nPRODID:-//ABC Corporation//NONSGML My Product//EN\r\nBEGIN:VTIMEZONE\r\nTZID:Europe/Berlin\r\nBEGIN:DAYLIGHT\r\nTZOFFSETFROM:+0200\r\nTZOFFSETTO:+0100\r\nTZNAME:PDT\r\nDTSTART:19700308T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\nEND:DAYLIGHT\r\nBEGIN:STANDARD\r\nTZOFFSETFROM:+0100\r\nTZOFFSETTO:+0200\r\nTZNAME:PST\r\nDTSTART:19701101T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\nEND:STANDARD\r\nEND:VTIMEZONE\r\n"); //SammelArray für ICS-Einträge if(preg_match_all('~<tr>(.*)<\/tr>~isU', trim($text_new), $matches)) { foreach($matches[0] as $array) { if(preg_match('~<td class="plannedtime" align="right">([A-Za-z]{2}) ([0-9]{2}).([0-9]{2}).([0-9]{4}) <span class="time">([0-9]{2}):([0-9]{2}){1}</span><\/td><td align="right">[0-9]{1,2}<\/td><td align="right">[H|R]<\/td><td>[0-9]{1,2}<\/td><td class="nowrap" align="right">(.*)<a class(.*)>(.*)<\/a>(.*)<\/td><td align="center">\-<\/td><td class="nowrap">(.*)<a class(.*)>(.*)</a>(.*)<\/td><td>(.*)<\/td><td><a href(.*)>(.*)<\/a><\/td>~',$array,$splits)) { if(preg_match('~(TSV Lauf)~is',$splits[9].$splits[13]) AND $splits[15] == "") { $ics_data[] = "BEGIN:VEVENT\r\nDTSTART;TZID=Europe/Berlin:".$splits[4].$splits[3].$splits[2]."T".$splits[5].$splits[6]."00\r\nDTEND;TZID=Europe/Berlin:".$splits[4].$splits[3].$splits[2]."T".($splits[5]+3).$splits[6]."00\r\nLOCATION:".str_replace(",","\,",$splits[17])."\r\nCATEGORIES:Sport\r\nTRANSP: OPAQUE\r\nSEQUENCE:0\r\nUID:\r\nDTSTAMP:".date("Ymd\THis\Z")."\r\nSUMMARY:Badmintonspiel ".$splits[9]." - ".$splits[13]."\r\nDESCRIPTION: \r\nPRIORITY:1\r\nCLASS:PUBLIC\r\nBEGIN:VALARM\r\nRIGGER:-PT10080M\r\nACTION:DISPLAY\r\nDESCRIPTION:Reminder\r\nEND:VALARM\r\nEND:VEVENT\r\n"; } } } } foreach($ics_data AS $date) { print($date); } echo "END:VCALENDAR"; ?>
Damit werden mir alle noch zu spielenden Begegnungen von der Seite ausgelesen und als ICS-Format angezeigt. Diese ICS-Daten müssen nun nur noch in OwnCloud integriert werden. Dazu habe ich ein sehr einfaches Skript gefunden, das ich auf meinen Server gelegt habe und per CronJob regelmäßig aufrufe:
<?php ini_set("memory_limit","256M"); //Hier den Pfad zur Owncloud-Installation einfügen define('OWNCLOUD_DIR', '/var/www/owncloud'); require_once(OWNCLOUD_DIR . '/lib/base.php'); require_once(OWNCLOUD_DIR . '/apps/calendar/lib/import.php'); require_once(OWNCLOUD_DIR . '/apps/calendar/lib/object.php'); require_once(OWNCLOUD_DIR . '/apps/calendar/lib/calendar.php'); require_once(OWNCLOUD_DIR . '/apps/calendar/lib/app.php'); /* * Hier die verschiedenen zu importierenden Feeds eintragen * userid: Der Benutzername auf dessen Konto der Kalender importiert werden soll * displayname: Der Name des Kalenders in der Owncloud (muss vorher angelegt werden) * filename: Die URL zum ICAL-Feed */ $Import = array( array( "userid" => "OwncloudUSER", "displayname" => "OwncloudKalender", "filename" => "https://server.ip/ics_generator.php" ) ); foreach($Import AS $cal) { //Nachsehen ob der Kalender auf der Owncloud auch existiert try { $stmt = OCP\DB::prepare( 'SELECT * FROM `*PREFIX*clndr_calendars` WHERE `userid` = ? AND `displayname` = ?' ); $result = $stmt->execute(array($cal["userid"], $cal["displayname"])); $row = $result->fetchRow(); $calendar_id = $row['id']; if (!$calendar_id) { echo "No calendar for userid " . $cal["userid"] . " with displayname '" . $cal["displayname"] . "'"; } } catch (Exception $e) { echo "DB exception: " . $e; } // Daten aus dem Feed laden $file = file_get_contents($cal["filename"]); if ($file === FALSE) { echo "Couldn't read file: ".$cal["filename"]; } //Import durchführen $import = new OC_Calendar_Import($file); $import->setUserID($cal["userid"]); $import->setTimeZone(OC_Calendar_App::$tz); $import->setCalendarID($calendar_id); $import->setOverwrite(true); OC_User::setUserId($cal["userid"]); try { $import->import(); $count = $import->getCount(); echo "Imported ".$count." objects in Calendar ".$cal["displayname"]."(".$cal["userid"].")\n"; } catch (Exception $e) { echo "Import failed: " . $e; } } ?>
Den CronJob richtet man wie auch den Cronjob für Owncloud über:
sudo crontab -u www-data -e
ein. Meiner sieht dann wie folgt aus:
0 0 * * * php -f /var/www/owncloud_import.php > /dev/null 2>&1
Damit läuft alles automatisch und geänderte Zeiten, Orte etc werden einmal am Tag aktualisiert. Manuelle Änderungen der Termine werden durch diesen Vorgang jedoch überschrieben. Daher kann es durchaus sinnvoll sein den Import nur manuell über den Aufruf des PHP-Skriptes auszuführen.