--- /dev/null
+/*
+# Copyright and License:
+#
+# Copyright (C) 2007
+# gregor herrmann <gregor+debian@comodo.priv.at>,
+# Philipp Spitzer <philipp@spitzer.priv.at>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, or point
+# your browser to http://www.gnu.org/licenses/gpl.html
+*/
+
+#include <QtGlobal>
+#include <QtDebug>
+#include <QApplication>
+#include <QVector>
+#include <QFile>
+#include <QProcess>
+#include <QMessageBox>
+#include "main.h"
+#include "options.h"
+
+
+// Functions
+// =========
+
+void initConfigInfo(ConfigInfo& configInfo) {
+ QStringList environment = QProcess::systemEnvironment().filter(QRegExp("^HOME=")); // ("HOME=/home/gregoa")
+ if (environment.size() == 1) {
+ configInfo.home = environment.at(0).mid(5);
+ configInfo.userConfigFile = configInfo.home + + "/.teleschorschrc";
+ }
+ configInfo.systemConfigFile = "/etc/teleschorschrc";
+
+ // User config file
+ if (!configInfo.userConfigFile.isEmpty()) {
+ QFile configFileUser(configInfo.userConfigFile);
+ if (configFileUser.exists()) {configInfo.usedConfigFile = configInfo.userConfigFile;}
+ }
+
+ // System config file
+ if (configInfo.usedConfigFile.isEmpty()) {
+ QFile configFileSystem(configInfo.systemConfigFile);
+ if (configFileSystem.exists()) configInfo.usedConfigFile = configInfo.systemConfigFile;
+ }
+}
+
+
+bool addConfig(const QString& fileName, ChannelVec& cv, QString& error) {
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {error = QObject::tr("Could not open file %1").arg(fileName); return false;}
+ Channel channel; // current channel
+ bool sectionOccured = false;
+ while (!file.atEnd()) {
+ QString line = QString(file.readLine()).trimmed();
+ if (line.startsWith("#") || line.startsWith(";") || line.isEmpty()) continue; // strip comments
+
+ // Is the line a [section]?
+ bool section = line.startsWith("[") && line.endsWith("]") && line.size() >= 3;
+ if (section) {
+ if (sectionOccured) cv.push_back(channel);
+ sectionOccured = true;
+ channel = Channel();
+ channel.name = line.mid(1, line.size()-2);
+ }
+
+ // Read properties
+ int eqPos = line.indexOf("=");
+ bool property = !section && eqPos >= 1;
+ if (property) {
+ QString propKey = line.left(eqPos);
+ QString propVal = line.right(line.size()-eqPos-1);
+ if (!sectionOccured) {error = QObject::tr("Property %1 is only allowed in a [section].").arg(propKey); return false;}
+
+ if (propKey == "FULLNAME") channel.fullName = propVal;
+ else if (propKey == "STATICURL") channel.staticUrl = propVal;
+ else if (propKey == "PLAYER") channel.player = propVal;
+ else {error = QObject::tr("Unknown key in ini file: %1").arg(propKey); return false;}
+ }
+
+ if (!section && !property) {error = QObject::tr("Line %1 is not valid.").arg(line); return false;}
+ }
+ if (sectionOccured) cv.push_back(channel);
+ return true;
+}
+
+
+QString readChannelVec(const ConfigInfo& configInfo, ChannelVec& channelVec) {
+ if (configInfo.usedConfigFile.isEmpty()) return QObject::tr("Neither %1 nor %2 found.").arg(configInfo.systemConfigFile).arg(configInfo.userConfigFile);
+ QString error;
+ if (!addConfig(configInfo.usedConfigFile, channelVec, error));
+ return error;
+}
+
+
+
+// MainDialog
+// ==========
+
+MainDialog::MainDialog(QWidget *parent): QDialog(parent) {
+ // User interface
+ setupUi(this);
+ QObject::connect(btnOptions, SIGNAL(clicked()), this, SLOT(editOptions()));
+ QObject::connect(btnStart, SIGNAL(clicked()), this, SLOT(startAction()));
+
+ // Init configInfo
+ initConfigInfo(configInfo);
+
+ // Read config
+ QString error = readChannelVec(configInfo, channelVec);
+ if (!error.isEmpty()) QMessageBox::warning(this, tr("Problem when reading the configuration file"), error);
+
+ // Fill in channels
+ updateLwChannels();
+}
+
+
+void MainDialog::editOptions() {
+ OptionsDialog *od = new OptionsDialog();
+ if (od->exec(configInfo.userConfigFile)) {
+ channelVec.clear();
+ QString error = readChannelVec(configInfo, channelVec);
+ if (!error.isEmpty()) QMessageBox::warning(this, tr("Problem when reading the configuration file"), error);
+ updateLwChannels();
+ }
+ delete od;
+}
+
+
+void MainDialog::updateLwChannels() {
+ lwChannels->clear();
+ for (int i = 0; i != channelVec.size(); ++i) lwChannels->addItem(channelVec[i].fullName);
+}
+
+
+bool MainDialog::startAction() {
+ int row = lwChannels->currentRow();
+ if (row > 0) {
+ Channel channel = channelVec[row];
+ qDebug() << "User would like to see " << channel.staticUrl;
+
+ QString program = "/usr/bin/vlc";
+ QStringList arguments;
+ // arguments << "-style" << "motif";
+ // @args=("$player $url " . ${playeroptions}{$player} . " $offsetseconds");
+ QProcess player(0);
+ player.start(program, arguments);
+ player.waitForFinished();
+ return true;
+ }
+ return false;
+}
+
+
+
+// Main function
+// =============
+
+int main(int argc, char *argv[]) {
+ QApplication app(argc, argv);
+ MainDialog *mainDialog = new MainDialog();
+ mainDialog->show();
+ return app.exec();
+}
--- /dev/null
+#ifndef MAIN_H
+#define MAIN_H
+#include "ui_maindialog.h"
+
+// Types
+// =====
+
+struct Channel {
+ QString name;
+ QString fullName;
+ QString staticUrl;
+ QString player;
+};
+
+
+typedef QVector<Channel> ChannelVec;
+
+
+struct ConfigInfo {
+ QString home; ///< environment variable $HOME (e.g. /home/gregoa) or empty if $HOME does not exist
+ QString systemConfigFile; ///< system configuration file name (/etc/teleschorschrc)
+ QString userConfigFile; ///< user configuration file name (e.g. /home/gregoa/.teleschorschrc)
+ QString usedConfigFile; ///< currently used config file (e.g. /home/gregoa/.teleschorschrc)
+};
+
+
+
+// Functions
+// =========
+
+/// Determine ConfigInfo file names
+void initConfigInfo(ConfigInfo& configInfo);
+
+
+/// Adds the content of the specified config file to the channel vector
+bool addConfig(const QString& fileName, ChannelVec& cv, QString& error);
+
+
+/// \brief Read channel vector
+///
+/// In an error case, the error message is returned.
+QString readChannelVec(const ConfigInfo& configInfo, ChannelVec& channelVec);
+
+
+// MainDialog
+// ==========
+
+class MainDialog: public QDialog, private Ui::MainDialog {
+Q_OBJECT
+
+private:
+ ChannelVec channelVec;
+ ConfigInfo configInfo;
+
+public:
+ MainDialog(QWidget *parent = 0);
+
+public slots:
+ void editOptions();
+ void updateLwChannels();
+ bool startAction();
+};
+
+#endif
--- /dev/null
+<ui version="4.0" >
+ <class>MainDialog</class>
+ <widget class="QDialog" name="MainDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>339</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>TeleSchorsch</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labChannels" >
+ <property name="text" >
+ <string>Channel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="lwChannels" />
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="labDate" >
+ <property name="text" >
+ <string>Date</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCalendarWidget" name="calDate" >
+ <property name="firstDayOfWeek" >
+ <enum>Qt::Monday</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labOffset" >
+ <property name="text" >
+ <string>Offset</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTimeEdit" name="teOffset" >
+ <property name="calendarPopup" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="btnOptions" >
+ <property name="text" >
+ <string>Options</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnStart" >
+ <property name="text" >
+ <string>Start</string>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnQuit" >
+ <property name="text" >
+ <string>Quit</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>lwChannels</tabstop>
+ <tabstop>calDate</tabstop>
+ <tabstop>teOffset</tabstop>
+ <tabstop>btnStart</tabstop>
+ <tabstop>btnQuit</tabstop>
+ <tabstop>btnOptions</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>btnQuit</sender>
+ <signal>clicked()</signal>
+ <receiver>MainDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>352</x>
+ <y>308</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>199</x>
+ <y>169</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+#include <QMessageBox>
+#include <QFile>
+#include <QTextStream>
+#include "options.h"
+
+OptionsDialog::OptionsDialog(QWidget *parent): QDialog(parent) {
+ setupUi(this);
+}
+
+
+bool OptionsDialog::exec(const QString& configFile) {
+ if (configFile.isEmpty()) {
+ QMessageBox::warning(this, tr("No user config file location"), tr("The location of the user config file could not be determined."));
+ return false;
+ }
+ QFile configFileUser(configFile);
+ if (!configFileUser.exists()) {
+ QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Create user config file?"), tr("The user config file %1 does not exist. Do you want to create it?").arg(configFile), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
+ if (answer != QMessageBox::Yes) return false;
+ teIni->clear();
+ } else {
+ if (!configFileUser.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QMessageBox::warning(this, tr("File not readable"), tr("The user config file %1 is not readable.").arg(configFile));
+ return false;
+ }
+ QTextStream in(&configFileUser);
+ while (!in.atEnd()) teIni->append(in.readLine());
+ }
+ configFileUser.close();
+ if (QDialog::exec() == QDialog::Accepted) {
+ // Save
+ if (!configFileUser.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QMessageBox::warning(this, tr("File not writeable"), tr("The config file %1 is not writeable.").arg(configFile));
+ return false;
+ }
+ QTextStream out(&configFileUser);
+ out << teIni->toPlainText();
+ return true;
+ }
+ return false;
+}
+
--- /dev/null
+#include "ui_options.h"
+#include "main.h"
+
+class OptionsDialog: public QDialog, public Ui::OptionsDialog {
+Q_OBJECT
+
+public:
+ OptionsDialog(QWidget *parent = 0);
+
+ /// \brief Shows a dialog where the user can edit the specified configuration file.
+ ///
+ /// If the file was modified and successfully saved, true is returned, otherwise false.
+ /// The dialog shows error to the user itself.
+ /// \todo First try to save and afterwards save. This would give the user the chance to copy & paste his/her changes.
+ /// \param configFile file name with full path to the configuration file to edit.
+ bool exec(const QString& configFile);
+};
+
--- /dev/null
+<ui version="4.0" >
+ <class>OptionsDialog</class>
+ <widget class="QDialog" name="OptionsDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>TeleSchorsch channel configuration</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QTextEdit" name="teIni" >
+ <property name="lineWrapMode" >
+ <enum>QTextEdit::NoWrap</enum>
+ </property>
+ <property name="acceptRichText" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labHelp" >
+ <property name="text" >
+ <string>You may use the following special characters:
+
+<ul>
+<li>${d}: day of month (01-31)
+<li>${m}: month (01-12)
+<li>${y]: year (last two digits)
+<li>${Y}: year (4 digits}
+<li>${dow_DE}: day of week in German (Montag, ...)
+</ul></string>
+ </property>
+ <property name="textFormat" >
+ <enum>Qt::RichText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnSave" >
+ <property name="text" >
+ <string>Save</string>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnCancel" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>btnCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>OptionsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>352</x>
+ <y>269</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>btnSave</sender>
+ <signal>clicked()</signal>
+ <receiver>OptionsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>271</x>
+ <y>275</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+FORMS += maindialog.ui options.ui
+HEADERS += main.h options.h
+SOURCES += main.cpp options.cpp
+
--- /dev/null
+#!/usr/bin/perl -w
+#
+# Copyright and License:
+#
+# Copyright (C) 2007
+# gregor herrmann <gregor+debian@comodo.priv.at>,
+# Philipp Spitzer <philipp@spitzer.priv.at>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, or point
+# your browser to http://www.gnu.org/licenses/gpl.html
+
+use strict;
+use Config::IniFiles;
+use DateTime;
+
+sub error {
+ my $msg = shift(@_);
+ print "$msg\n";
+ exit(1);
+}
+
+# variables
+my $configfile;
+if (-r "$ENV{HOME}/.teleschorschrc") {
+ $configfile = "$ENV{HOME}/.teleschorschrc";
+} elsif (-r "/etc/teleschorschrc") {
+ $configfile = "/etc/teleschorschrc";
+} else {
+ error "Neiter /etc/teleschorschrc nor $ENV{HOME}/.teleschorschrc found";
+}
+
+my $defaultdate;
+if (DateTime->now->hour < 12) {
+ $defaultdate = DateTime->now->subtract(days => 1)->dmy(' ');
+} else {
+ $defaultdate = DateTime->now->dmy(' ');
+}
+
+my %playeroptions = ("vlc" => "--start-time", "gmplayer" => "-cache 512 -ss");
+
+# read config
+my %cfg;
+tie %cfg, 'Config::IniFiles', ( -file => $configfile, -allowcontinue => 1)
+ or error "Can't read $configfile: $!";
+my @channels = sort keys %cfg;
+
+sub create_list {
+ my $result;
+ foreach my $c (@channels) {
+ $result .= "$c '$cfg{$c}{'FULLNAME'}' off ";
+ }
+ return $result;
+}
+
+# call xdialog
+my $channellist = &create_list;
+my @args=("Xdialog --stdout --title 'TeleSchorsch' --no-tags --radiolist 'Choose your preferred stream:' 0 0 0 $channellist --calendar 'Date' 0 0 $defaultdate --timebox 'Offset\n(Start at beginning of stream: 0:0:0, start at position 3 minutes: 0:3:0, ...)' 0 0 0 0 0");
+my $selection = qx/@args/ or error "@args: $? // $!\n\n";
+my ($stream, $date, $offset) = split (/\n/, $selection);
+
+# manipulate results
+my ($hours, $minutes, $seconds) = split(/:/, $offset);
+my $offsetseconds = $hours * 3600 + $minutes * 60 + $seconds;
+
+my ($day, $month, $year) = split(/\//, $date);
+my $dt = DateTime->new(year => $year, month => $month, day => $day);
+my $y = $dt->strftime("%y");
+my $Y = $dt->strftime("%Y");
+my $m = $dt->strftime("%m");
+my $d = $dt->strftime("%d");
+my $dt_DE = DateTime->from_object(object => $dt, locale => qx(locale -a | grep ^de_ | head -n 1));
+my $dow_DE = $dt_DE->strftime("%A");
+
+# get missing parameters
+my $player = $cfg{$stream}{'PLAYER'};
+
+my $url = $cfg{$stream}{'STATICURL'};
+no warnings;
+$url =~ s/(\${\w+?})/$1/eeg;
+use warnings;
+
+@args=("$player $url " . ${playeroptions}{$player} . " $offsetseconds");
+print "Calling @args ...\n";
+system (@args) == 0
+ or error "@args: $? // $!";
--- /dev/null
+#!/bin/bash
+
+# Copyright and License:
+#
+# Copyright (C) 2007
+# gregor herrmann <gregor+debian@comodo.priv.at>,
+# Philipp Spitzer <philipp@spitzer.priv.at>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, or point
+# your browser to http://www.gnu.org/licenses/gpl.html
+
+# Changes:
+#
+# 0.1.1
+# add command line options "-xdialog" (default) and "-dialog"
+#
+# 0.1.0
+# use the new configuration file
+#
+# 0.0.6
+# move mplayer start options down
+#
+# 0.0.5
+# implement some more error checks
+#
+# 0.0.4
+# set default date to yesterday if current time < noon
+#
+# 0.0.3:
+# clarify description of "start time", i.e. "offset"
+#
+# 0.0.2:
+# check for required binaries
+#
+# 0.0.1:
+# first release
+
+# functions
+
+error() {
+ echo "$(basename $0) aborting with error:"
+ echo $1
+ exit 1
+}
+
+# parameters
+
+UI="xdialog"
+if [ -n "$1" ] ; then
+ case "$1" in
+ "-xdialog")
+ UI="xdialog"
+ ;;
+ "-dialog")
+ UI="dialog"
+ ;;
+ esac
+fi
+
+# checks
+
+case "$UI" in
+ "xdialog")
+ which Xdialog > /dev/null || error "Please install Xdialog or try -dialog."
+ ;;
+ "dialog")
+ which dialog > /dev/null || error "Please install dialog or try -xdialog."
+ ;;
+esac
+
+which vlc > /dev/null || error "Please install vlc."
+which gmplayer > /dev/null || error "Please install (g)mplayer."
+
+# some variables
+
+if [ -r $HOME/.teleschorschrc ] ; then
+ CONFIG=$HOME/.teleschorschrc
+elif [ -r /etc/teleschorschrc ] ; then
+ CONFIG=/etc/teleschorschrc
+else
+ error "Neiter /etc/teleschorschrc nor $HOME/.teleschorschrc found"
+fi
+
+if [ $(date +"%H") -lt 12 ] ; then
+ DEFAULT_DATE=$(date --date "yesterday" +"%d %m %Y")
+else
+ DEFAULT_DATE=$(date +"%d %m %Y")
+fi
+
+OUTFILE="/tmp/$(basename $0).tmp.$$"
+
+# start the fun
+
+# read config
+
+while read LINE ; do
+ if [ -z "$LINE" ] ; then continue; fi
+ if echo $LINE | egrep "^[#;]" > /dev/null ; then continue; fi
+ if echo $LINE | egrep "^\[" > /dev/null; then
+ if [ -n "$C" ] ; then CHANNELS+=("$C") ; fi
+ C="$LINE"
+ else
+ C+="~$LINE"
+ fi
+done < $CONFIG
+CHANNELS+=("$C")
+
+COUNT="${#CHANNELS[*]}"
+
+# create channel list for (x)dialog
+
+for ((i=0; i < COUNT; i++)) ; do # bashism
+ LIST+=$(echo ${CHANNELS[$i]} | sed -e "s/\[\(.\+\)\]/$i/" -e 's/FULLNAME=//' -e 's/ /\xa0/g' | awk -F '~' '{printf "%s\t%s\toff ", $1, $2}')
+done
+
+# call (x)dialog
+case "$UI" in
+ "xdialog")
+ Xdialog --title "TeleSchorsch" \
+ --no-tags \
+ --radiolist "Choose your preferred stream:" 0 0 0 \
+ $LIST \
+ --calendar "Date" 0 0 $DEFAULT_DATE \
+ --timebox "Offset\n(Start at beginning of stream: 0:0:0, start at position 3 minutes: 0:3:0, ...)" 0 0 0 0 0 \
+ 2>$OUTFILE
+ ;;
+ "dialog")
+ dialog --title "TeleSchorsch" \
+ --radiolist "Choose your preferred stream" 0 0 0 \
+ $LIST \
+ --calendar "Date" 0 0 $DEFAULT_DATE \
+ --timebox "Offset\n(Start at beginning of stream: 0:0:0, start at position 3 minutes: 0:3:0, ...)" 0 0 0 0 0 \
+ 2>$OUTFILE
+ ;;
+esac
+
+RETVAL=$?
+
+case $RETVAL in
+ 0)
+ ;;
+ *)
+ echo "$(basename $0) exiting (user abort, error, whatnot) with return value: $RETVAL"
+ exit $RETVAL
+ ;;
+esac
+
+[ -e "$OUTFILE" ] && perl -pi -e 's;\n; ;' $OUTFILE \
+ || error "$OUTFILE not found"
+read STREAM DATE OFFSET < $OUTFILE
+[ -n "$STREAM" ] && [ -n "$DATE" ] && [ -n "$OFFSET" ] && rm -f $OUTFILE \
+ || error "Problem with variables, check contents of $OUTFILE"
+
+DATE=$(echo $DATE | perl -p -e 's;(.+)/(.+)/(.+);$3-$2-$1;')
+SECONDS=$(echo $OFFSET | perl -n -e '($h,$m,$s) = split(/:/); print $h*3600 + $m*60 + $s;')
+y=$(date --date "$DATE" +"%y")
+Y=$(date --date "$DATE" +"%Y")
+m=$(date --date "$DATE" +"%m")
+d=$(date --date "$DATE" +"%d")
+dow_DE=$(LANG=$(locale -a | grep ^de_ | head -n 1) date --date "$DATE" +"%A")
+
+URL=$(echo "${CHANNELS[$STREAM]}" | perl -pe 's/^.*STATICURL=(.+?)(~.*|$)/$1/')
+PLAYER=$(echo "${CHANNELS[$STREAM]}" | perl -pe 's/^.*PLAYER=(.+?)(~.*|$)/$1/')
+
+case $PLAYER in
+ gmplayer)
+ STARTOPTION="-cache 512 -ss"
+ ;;
+ vlc)
+ STARTOPTION="--start-time"
+ ;;
+ *)
+ error "Unknown PLAYER: $PLAYER"
+ ;;
+esac
+
+$PLAYER $(eval echo $URL) $STARTOPTION $SECONDS
--- /dev/null
+[ORFZIB1]
+FULLNAME=ORF - Zeit im Bild 1
+STATICURL=rtsp://81.189.213.1:554/orf2/zb/zib${y}${m}${d}l.rm?URL=/ramgen/orf2/zb/zib${y}${m}${d}l.rm&cloakport=8088,554,7070
+PLAYER=gmplayer
+
+[ORFZIB2]
+FULLNAME=ORF - Zeit im Bild 2
+STATICURL=mms://stream4.orf.at/zib2/zib2_${dow_DE}.wmv
+PLAYER=vlc
+
+[F208h]
+FULLNAME=France 2 - 8 heures
+STATICURL=mms://sdmc.contents.edgestreams.net/horsgv/regions/siege/infos/f2/8h/HD_8h_${Y}${m}${d}.wmv?WMCache=0
+PLAYER=vlc
+
+[F213h]
+FULLNAME=France 2 - 13 heures
+STATICURL=mms://sdmc.contents.edgestreams.net/horsgv/regions/siege/infos/f2/13h/HD_13h_${Y}${m}${d}.wmv?WMCache=0
+PLAYER=vlc
+
+[F220h]
+FULLNAME=France 2 - 20 heures
+STATICURL=mms://sdmc.contents.edgestreams.net/horsgv/regions/siege/infos/f2/20h/HD_20h_${Y}${m}${d}.wmv?WMCache=0
+PLAYER=vlc
+
+[F31213]
+FULLNAME=France 3 - JT 12/13h national
+STATICURL=mms://sdmc.contents.edgestreams.net/horsgv/regions/siege/infos/f3/1214/HD_1214_${Y}${m}${d}.wmv?WMCache=0
+PLAYER=vlc
+
+[F31920]
+FULLNAME=France 3 - JT 19/20h national
+STATICURL=mms://sdmc.contents.edgestreams.net/horsgv/regions/siege/infos/f3/1920/HD_1920_${Y}${m}${d}.wmv?WMCache=0
+PLAYER=vlc
+
+[F3lesoir]
+FULLNAME=France 3 - JT le soir national
+STATICURL=mms://sdmc.contents.edgestreams.net/horsgv/regions/siege/infos/f3/soir3/HD_soir3_${Y}${m}${d}.wmv?WMCache=0
+PLAYER=vlc
+
+[M61250]
+FULLNAME=M6 - le 12 50
+STATICURL=mms://stream1.m6.fr.ipercast.net/m6.fr/6minutes/d/92/d${y}${m}${d}211150SARAV9200000.wmv
+PLAYER=vlc
+
+[M6six]
+FULLNAME=M6 - six
+STATICURL=mms://stream1.m6.fr.ipercast.net/m6.fr/6minutes/d/92/d${y}${m}${d}190000SARAV9200000.wmv
+PLAYER=vlc
+
+[TF1jt13]
+FULLNAME=TF1 - JT 13h
+STATICURL=http://213.205.97.105/tf1jt/jt13d${d}${m}${Y}.asf
+PLAYER=vlc
+
+[TF1jt20]
+FULLNAME=TF1 - JT 20h
+STATICURL=http://213.205.97.105/tf1jt/jt20d${d}${m}${Y}.asf
+PLAYER=vlc
+
+[ORFoe107]
+FULLNAME=ORF - Ö1 Morgenjournal (only current broadcast)
+STATICURL=`wget -q -O- "http://oe1.orf.at/konsole/journal?type=frueh" | grep -Eo "mms://stream2\.orf\.at/oe1/demand/frueh/.+\.WMA"`
+PLAYER=vlc
+
+[ORFoe112]
+FULLNAME=ORF - Ö1 Mittagsjournal (only current broadcast)
+STATICURL=`wget -q -O- "http://oe1.orf.at/konsole/journal?type=mittag" | grep -Eo "mms://stream2\.orf\.at/oe1/demand/mittag/.+\.WMA"`
+PLAYER=vlc
+
+[ORFoe118]
+FULLNAME=ORF - Ö1 Abendjournal (only current broadcast)
+STATICURL=`wget -q -O- "http://oe1.orf.at/konsole/journal?type=abend" | grep -Eo "mms://stream2\.orf\.at/oe1/demand/abend/.+\.WMA"`
+PLAYER=vlc
\ No newline at end of file