--- /dev/null
+enigma2 radio stations to mediatomb converter
--- /dev/null
+<?php
+/**
+* Fetches bouqet information from the dreambox
+*
+* @author Christian Weiske <cweiske@cweiske.de>
+*/
+class DreamboxBouqets
+{
+ /**
+ * Fetch radio bouqets
+ *
+ * @param string $ip IP-address or hostname of the dreambox
+ *
+ * @return array Array of bouqets and the items
+ */
+ public static function fetchRadioBouqets($ip)
+ {
+ $host = 'http://' . $ip;
+ $streamhost = 'http://' . $ip . ':8001';
+ $url_getServices = $host . "/web/getservices?sRef=";
+ $url_stream_playlist = $host . '/web/stream.m3u?ref=';
+ //1%3A7%3A2%3A0%3A0%3A0%3A0%3A0%3A0%3A0%3A(type%20%3D%3D%202)%20FROM%20BOUQUET%20%22userbouquet.info_______________radio_.radio%22%20ORDER%20BY%20bouquet
+ $url_bouqet_epg = $host . '/web/epgnow?bRef=';
+ $url_stream = $streamhost . '/';
+
+ //TODO: fetch from dreambox config.js
+ $bouqet_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)FROM BOUQUET "bouquets.radio" ORDER BY bouquet';
+
+
+ $url = $url_getServices . urlencode($bouqet_radio);
+ $radiobouqets = new SimpleXMLElement(
+ file_get_contents($url)
+ );
+
+ $arBouqets = array();
+ foreach ($radiobouqets->e2service as $bouqet) {
+ $strBouqetName = self::properBouqetName($bouqet->e2servicename);
+ $arBouqets[$strBouqetName] = array();
+
+ $strRef = $bouqet->e2servicereference;
+ $url = $url_getServices . urlencode($strRef);
+ $epgurl = $url_bouqet_epg . urlencode($strRef);
+
+ $stations = new SimpleXMLElement(
+ file_get_contents(
+ $url
+ )
+ );
+ foreach ($stations->e2service as $station) {
+ $strStationRef = (string)$station->e2servicereference;
+ $arBouqets[$strBouqetName][$strStationRef] = array(
+ 'name' => (string)$station->e2servicename,
+ 'playlist' => $url_stream_playlist . $strStationRef,
+ 'stream' => $url_stream . $strStationRef
+ );
+ }
+
+ $epgs = new SimpleXMLElement(
+ file_get_contents($epgurl)
+ );
+ foreach ($epgs->e2event as $epg) {
+ $strStationRef = (string)$epg->e2eventservicereference;
+ $arBouqets[$strBouqetName][$strStationRef] = array_merge(
+ $arBouqets[$strBouqetName][$strStationRef],
+ array(
+ 'epgtitle' => (string)$epg->e2eventtitle,
+ 'epgdescription' => (string)$epg->e2eventdescription,
+ 'epgdescription2' => (string)$epg->e2eventdescriptionextendet,
+ )
+ );
+ }
+
+ }
+
+ return $arBouqets;
+ }//public static function fetchRadioBouqets(..)
+
+
+
+ protected static function properBouqetName($name)
+ {
+ return trim(preg_replace('#\(.+\)$#', '', $name));
+ }
+}
+
+?>
\ No newline at end of file
--- /dev/null
+<?php
+$GLOBALS['enigtombConfig'] = array(
+ 'dreambox' => array(
+ 'host' => 'dreambox'
+ ),
+ 'mediatomb' => array(
+ 'host' => 'dojo',
+ 'port' => 49152,
+ 'user' => 'cweiske',
+ 'pass' => 'mediatomb',
+
+ 'radiodir' => 'Radio',
+ 'rootBouqet' => 'Favourites',
+ 'mimetype' => 'audio/x-satellite-mpeg2'
+ ),
+ 'namefixes' => array(
+ 'DKULTUR' => 'D-Kultur',
+ 'DLF' => 'Deutschlandfunk',
+ 'JAZZ RADIO' => 'Jazz Radio',
+ 'MDR FIGARO' => 'Figaro',
+ 'MDR INFO' => 'mdr info',
+ 'MDR JUMP' => 'Jump',
+ 'MDR SPUTNIK' => 'Sputnik',
+ 'MDR1 SACHSEN' => 'mdr1 Radio Sachsen',
+ 'P-COUNTRY' => 'Premiere Country',
+ 'VIBRATION' => 'Vibration',
+ )
+);
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/**
+* Copies all radio bouqets into a folder on mediatomb.
+* Deletes/clears the folder at first.
+*
+* @author Christian Weiske <cweiske@php.net>
+* @license LGPL http://www.gnu.org/copyleft/lesser.html
+*/
+require_once 'DreamboxBouqets.php';
+require_once 'Services/MediaTomb.php';
+require_once 'config.php';
+
+echo "fetching bouqets\n";
+$arBouqets = DreamboxBouqets::fetchRadioBouqets(
+ $GLOBALS['enigtombConfig']['dreambox']['host']
+);
+
+$mt = new Services_MediaTomb(
+ $GLOBALS['enigtombConfig']['mediatomb']['user'],
+ $GLOBALS['enigtombConfig']['mediatomb']['pass'],
+ $GLOBALS['enigtombConfig']['mediatomb']['host'],
+ $GLOBALS['enigtombConfig']['mediatomb']['port']
+);
+
+$strRadiodir = $GLOBALS['enigtombConfig']['mediatomb']['radiodir'];
+
+$radiodir = $mt->getContainerByPath($strRadiodir);
+if ($radiodir !== null) {
+ $mt->delete($radiodir);
+}
+
+foreach ($arBouqets as $strBouqetName => $arStations) {
+ echo "adding " . $strBouqetName . "\n";
+ if ($strBouqetName == $GLOBALS['enigtombConfig']['mediatomb']['rootBouqet']) {
+ $dir = $mt->getContainerByPath($strRadiodir);
+ if ($dir === null) {
+ $dir = $mt->createContainerByPath($strRadiodir);
+ }
+ } else {
+ $dir = $mt->createContainerByPath($strRadiodir . '/' . $strBouqetName);
+ }
+
+ foreach ($arStations as $arStation) {
+ echo " adding " . $arStation['name'] . "\n";
+ $strName = $arStation['name'];
+ if ($arStation['epgtitle']) {
+ $strName .= ' - ' . $arStation['epgtitle'];
+ }
+ if ($arStation['epgdescription']) {
+ $strDescription = $arStation['epgdescription'];
+ } else {
+ $strDescription = '';
+ }
+ if ($arStation['epgdescription2']) {
+ $strDescription .= ' ' . $arStation['epgdescription2'];
+ }
+ if (!$strDescription) {
+ $strDescription = $strName;
+ }
+ $mt->createExternalLink(
+ $dir->id, $strName, $arStation['stream'], trim($strDescription),
+ $GLOBALS['enigtombConfig']['mediatomb']['mimetype'],
+ Services_MediaTomb::PROTOCOL_HTTP_GET
+ );
+ }
+}
+
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/**
+* Syncs all dreambox radio bouqets into a folder on mediatomb.
+* Renames/changes existing entries instead of deleting
+* everything first.
+*
+* @author Christian Weiske <cweiske@php.net>
+* @license LGPL http://www.gnu.org/copyleft/lesser.html
+*/
+require_once 'DreamboxBouqets.php';
+require_once 'Services/MediaTomb.php';
+require_once 'config.php';
+require_once dirname(__FILE__) . '/syncfunctions.php';
+
+$bReally = true;
+
+echo "Synchronizing dreambox radio bouqets and mediatomb radion station list\n";
+echo " fetching bouqets\n";
+$arBouqets = DreamboxBouqets::fetchRadioBouqets(
+ $GLOBALS['enigtombConfig']['dreambox']['host']
+);
+
+$mt = new Services_MediaTomb(
+ $GLOBALS['enigtombConfig']['mediatomb']['user'],
+ $GLOBALS['enigtombConfig']['mediatomb']['pass'],
+ $GLOBALS['enigtombConfig']['mediatomb']['host'],
+ $GLOBALS['enigtombConfig']['mediatomb']['port']
+);
+
+$strRadiodir = $GLOBALS['enigtombConfig']['mediatomb']['radiodir'];
+
+$radiodir = $mt->createContainerByPath($strRadiodir);
+
+/**
+* create bouqet/container sync list
+*/
+$arBouqetNames = array_keys($arBouqets);
+$arRadiodirContainers = $radiodir->getContainers();
+$arContainerNames = array();
+foreach ($arRadiodirContainers as $nId => $container) {
+ $arBouqetNames[] = $container->title;
+ $arContainerNames[$container->title] = $nId;
+}
+
+if (isset($GLOBALS['enigtombConfig']['mediatomb']['rootBouqet'])
+ && $GLOBALS['enigtombConfig']['mediatomb']['rootBouqet']
+) {
+ $arBouqetNames[] = $GLOBALS['enigtombConfig']['mediatomb']['rootBouqet'];
+ $arContainerNames[$GLOBALS['enigtombConfig']['mediatomb']['rootBouqet']] = $radiodir->id;
+ $arRadiodirContainers[$radiodir->id] = $radiodir;
+}
+
+$arBouqetNames = array_unique($arBouqetNames);
+
+/**
+* sync bouqets and containers
+* Does not know about renamed bouqets
+*/
+echo " syncing bouqets and containers\n";
+$arValidContainers = array();
+foreach ($arBouqetNames as $strBouqetName) {
+ if (isset($arContainerNames[$strBouqetName]) && isset($arBouqets[$strBouqetName])) {
+ //everything is ok
+ echo " " . $strBouqetName . " already exists, ok\n";
+ $nContainerId = $arContainerNames[$strBouqetName];
+ $arValidContainers[$nContainerId] = $arRadiodirContainers[$nContainerId];
+ } else if (!isset($arContainerNames[$strBouqetName])) {
+ //container does not exist
+ if ($strBouqetName != $GLOBALS['enigtombConfig']['mediatomb']['rootBouqet']) {
+ echo " creating " . $strBouqetName . "\n";
+ $container = $mt->createContainerByPath($strRadiodir . '/' . $strBouqetName);
+ $arValidContainers[$container->id] = $container;
+ }
+ } else if (!isset($arBouqets[$strBouqetName])) {
+ if ($strBouqetName != $GLOBALS['enigtombConfig']['mediatomb']['rootBouqet']) {
+ //bouqet does not exist anymore -> delete container
+ echo " deleting container " . $strBouqetName . "\n";
+ if ($bReally) {
+ $mt->delete($arContainerNames[$strBouqetName]);
+ }
+ }
+ }
+}
+
+/**
+* Sync radio stations
+*/
+echo " syncing stations\n";
+foreach ($arValidContainers as $nContainerId => $container) {
+ /**
+ * Build stations sync list
+ */
+ if (isset($GLOBALS['enigtombConfig']['mediatomb']['rootBouqet'])
+ && $GLOBALS['enigtombConfig']['mediatomb']['rootBouqet']
+ && $container == $radiodir
+ ) {
+ $strContainerTitle = $GLOBALS['enigtombConfig']['mediatomb']['rootBouqet'];
+ } else {
+ $strContainerTitle = $container->title;
+ }
+ echo " syncing stations in " . $strContainerTitle . "\n";
+
+ //existing stations in mediatomb
+ $arStationItems = $container->getItems(0, 1000);
+ $arStationUris = array();
+ $arStationItemsByUri = array();
+ foreach ($arStationItems as $item) {
+ $arStationUris[] = $item->url;
+ $arStationItemsByUri[$item->url] = $item;
+ }
+ unset($arStationItems);
+
+ //stations in bouqet
+ foreach ($arBouqets[$strContainerTitle] as $arStation) {
+ $arStationUris[] = $arStation['stream'];
+ $arBouqetStationsByUri[$arStation['stream']] = $arStation;
+ }
+ unset($arBouqets[$strContainerTitle]);
+
+ $arStationUris = array_unique($arStationUris);
+
+ //sync stations
+ foreach ($arStationUris as $strUri) {
+ echo ' syncing station ' . $strUri . "\n";
+ if (isset($arBouqetStationsByUri[$strUri]) && isset($arStationItemsByUri[$strUri])) {
+ //station exists on both dreambox and mediatomb
+ //update title
+ echo " updating title and description\n";
+ $arTitles = enigtombGetStationTitle($arBouqetStationsByUri[$strUri]);
+ echo " " . $arTitles['title'] . "\n";
+ if ($arTitles['description'] && $arTitles['description'] != $arTitles['title']) {
+ echo " " . $arTitles['description'] . "\n";
+ }
+ $arStationItemsByUri[$strUri]->title = $arTitles['title'];
+ $arStationItemsByUri[$strUri]->description = $arTitles['description'];
+ if ($bReally) {
+ $arStationItemsByUri[$strUri]->save();
+ }
+ } else if (!isset($arBouqetStationsByUri[$strUri])) {
+ //station does not exist on dreambox
+ //delete it in mediatomb
+ echo " deleting\n";
+ if ($bReally) {
+ $arStationItemsByUri[$strUri]->delete();
+ }
+ } else if (!isset($arStationItemsByUri[$strUri])) {
+ //station exists on dreambox only
+ //create it in mediatomb
+ echo " creating\n";
+ $arTitles = enigtombGetStationTitle($arBouqetStationsByUri[$strUri]);
+ echo " " . $arTitles['title'] . "\n";
+ if ($bReally) {
+ $arStationItemsByUri[$strUri]->createExternalLink(
+ $arTitles['title'], $strUri, $arTitles['description'],
+ $GLOBALS['enigtombConfig']['mediatomb']['mimetype'],
+ 'http-get', 'object.item', false
+ );
+ }
+ }
+ }
+}
+
+
+echo "done\n";
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/**
+* Functions used in syncing
+*
+* @author Christian Weiske <cweiske@cweiske.de>
+* @license LGPL http://www.gnu.org/copyleft/lesser.html
+*/
+
+if (!function_exists('enigtombGetStationTitle')) {
+ /**
+ * Returns a proper title from the bouqet station data
+ * for the mediatomb entry
+ *
+ * @param array $arStation Station in a dreambox bouqet
+ *
+ * @return array Array of title and description to use in the UPnP server.
+ * Keys title and description
+ */
+ function enigtombGetStationTitle($arStation)
+ {
+ $strName = enigtombFixName($arStation['name']);
+
+ if ($arStation['epgtitle']
+ && $arStation['epgtitle'] != 'None'
+ && $arStation['epgtitle'] != $arStation['name']
+ ) {
+ if (strtolower(substr($arStation['epgtitle'], 0, strlen($strName))) == strtolower($strName)) {
+ $strEpgTitle = substr($arStation['epgtitle'], strlen($strName));
+ } else if (strtolower(substr($arStation['epgtitle'], 0, strlen($arStation['name']))) == strtolower($arStation['name'])) {
+ $strEpgTitle = substr($arStation['epgtitle'], strlen($arStation['name']));
+ } else {
+ $strEpgTitle = $arStation['epgtitle'];
+ }
+ $strEpgTitle = trim($strEpgTitle);
+ if (substr($strEpgTitle, 0, 1) == '-') {
+ $strEpgTitle = trim(substr($strEpgTitle, 1));
+ }
+
+ if (strtoupper($strEpgTitle) == $strEpgTitle) {
+ $strEpgTitle = ucwords(strtolower($strEpgTitle));
+ }
+
+ $strName .= ' - ' . $strEpgTitle;
+ }
+
+ if ($arStation['epgdescription'] && $arStation['epgdescription'] != 'None') {
+ $strDescription = $arStation['epgdescription'];
+ } else {
+ $strDescription = '';
+ }
+ if ($arStation['epgdescription2'] && $arStation['epgdescription2'] != 'None') {
+ $strDescription .= ' ' . $arStation['epgdescription2'];
+ }
+ if (!$strDescription) {
+ $strDescription = $strName;
+ }
+
+ return array(
+ 'title' => trim($strName),
+ 'description' => trim($strDescription)
+ );
+ }//function enigtombGetStationTitle(..)
+}
+
+
+
+if (!function_exists('enigtombFixName')) {
+ /**
+ * Replaces the given name with a fixed one from the config.
+ * Necessary, because some stations send their names in ALL UPPERCASE
+ * which just isn't nicely readable.
+ *
+ * @param string $strName Name to fix
+ *
+ * @return string Fixed name
+ */
+ function enigtombFixName($strName)
+ {
+ $strName = trim($strName);
+ if (isset($GLOBALS['enigtombConfig']['namefixes'][$strName])) {
+ return $GLOBALS['enigtombConfig']['namefixes'][$strName];
+ } else {
+ return $strName;
+ }
+ }//function enigtombFixName(..)
+}
+
+?>
\ No newline at end of file