#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (C) 2003-2005 Andrzej Wasowski # radio: a helper script for listening to the internet radio # date: $Date: 2008/03/29 17:21:46 $ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # $Id: radio,v 1.58 2008/03/29 17:21:46 wasowski Exp $ import os import signal import sys import time from optparse import OptionParser itvproot = "http://www.itvp.pl/radio/player/i.tvp/" # bitrate is given for a channel (do not sum) channels = {"abjazz" : ["mms://217.11.251.148/jazz", "-L1755:217.11.251.151:1755", "mss://localhost/jazz", "32", "JAZZ AB Radio a.s."], "allhits70s" : ["http://www.sky.fm/mp3/hit70s.pls", "", "http://64.236.34.196:80/stream/1076", "96", "SKY.FM All hits 70s"], "bis" : ["mms://stream.polskieradio.pl/Radio Bis", "", "", "?", ""], "cbcr1-toronto" : ["http://origin.www.cbc.ca/mrl2/livemedia/cbcr1-toronto.asx", "", "", "32", "CBC Radio One Toronto (Canadian)"], "cbcr1-toronto-ogg" : ["http://oggtrial.nm.cbc.ca:80/cbcr1-toronto.ogg", "", "http://oggtrial.nm.cbc.ca:80/cbcr1-toronto.ogg", "24", "CBC Radio One Toronto (Canadian)"], "cbcr2-toronto" : ["http://origin.www.cbc.ca/mrl2/livemedia/cbcr2-toronto.asx", "", "", "32", "CBC Radio Two Eastern Time (Canadian)"], "cbcr2-toronto-ogg" : ["http://oggtrial.nm.cbc.ca:80/cbcr2-toronto.ogg", "", "http://oggtrial.nm.cbc.ca:80/cbcr2-toronto.ogg", "32", "CBC Radio Two Eastern Time (Canadian)"], "ctv" : ["mms://a1544.l531039855.c5310.e.lm.akamaistream.net/D/1544/5310/v0001/reflector:39855", "", "", "?", ""], "deutsche-welle" : ["octoshape:DW.dw", "", "", "400", "Deutsche Welle TV stream (German)"], "domradio" : ["rtsp://217.115.138.73:555/broadcast/dom.rm", "", "", "44", ""], "dr-allegro" : ["http://wmscr1.dr.dk/e06ch03m?wmcontentbitrate=300000&MSWMExt=.asf", "", "", "128", "DR Allegro - lightweight classics (Danish)"], "dr-evergreen" : ["http://wmscr2.dr.dk/e06ch07m?wmcontentbitrate=300000", "", "", "128", "DR Evergreen - Danish and international evergreens"], "dr-folk" : ["http://wmscr2.dr.dk/e06ch11m?wmcontentbitrate=300000", "", "", "128", "DR Folk - folk from Denmark and elsewhere (Danish)"], "dr-jazz" : ["mms://wmsc.dr.dk/e02ch05m?wmcontentbitrate=300000", "-L1755:wmsc.dr.dk:1755", "mms://wmsc.dr.dk/e02ch05m?wmcontentbitrate=300000", "?", ""], "dr-klassisk" : #??? mms://wmsc.dr.dk/e02ch06m?wmcontentbitrate=40000 ["mms://drlive.dr.dk/e06ch1kb64", "-L1755:drlive.dr.dk:1755", "mms://localhost/e06ch1kb64", "?", "" ], "dr-p1" : ["mms://wmscr2.dr.dk/e02ch01m?wmcontentbitrate=300000", "-L1755:wmscr2.dr.dk:1755", "mms://localhost/e02ch01m?wmcontentbitrate=300000", "32", "Danmarks Radio P1 (Danish)"], "dr-p2" : ["mms://wmscr2.dr.dk/e02ch02m?wmcontentbitrate=300000", "", "", "32", "Danmarks Radio P2"], "dr-p3" : ["octoshape:DR.p3", "", "", "128", "Danmarks Radio P3"], "dr-p4" : ["http://wmscr1.dr.dk/e04ch09m?wmcontentbitrate=300000&MSWMExt=.asf", "", "", "128", "Danmarks Radio P4"], "dr1-hi" : ["mms://drcluster.jay.net/dr1?wmcontentbitrate=1000000", "", "", "1000", "Danmark Radio 1 (Main Public Service TV Channel in Danish)"], "dr1-lo" : ["mms://drcluster.jay.net/dr1?wmcontentbitrate=300000", "", "", "300", "Danmark Radio 1 (Main Public Service TV Channel in Danish)"], "dr2-hi" : ["mms://drcluster.jay.net/dr2?wmcontentbitrate=1000000", "", "", "1000", "Danmark Radio 2 (Second Channel of Danish Public TV)"], "ewtn" : ["mms://rx-lvl3-tex03.rbn.com/farm/pull/tx-rbn-sea65:1259/wmtencoder/ewtn/g2ewtn/wmlive/wmradioen.asf", "", "", "?", ""], "ewtntv" : ["mms://rx-lvl3-ny17.rbn.com/farm/pull/tx-rbn-sea11:1259/wmtencoder/ewtn/g2ewtn/wmlive/wmtv500en.asf", "", "", "?", ""], "fip" : ["http://viphttp.yacast.net/V4/fip/fip.asx", "", "", "64", ""], "fmusique" : ["http://www.tv-radio.com/station/france_musique_mp3/france_musique_mp3-128k.pls", "", "", "128", "France Musique"], "frenchkiss" : ["http://88.191.35.197/listen.pls", "", "", "192",""], "guitar" : ["http://www.sky.fm/mp3/guitar.pls", "", "", "96", "SKY.FM - a mix of classical, spanish, and flamenco guitar" ], "lounge" : ["http://www.di.fm/mp3/lounge.pls", "", "", "96", "DI.FM - Lounge - sit back and enjoy the lounge grooves"], "oldies" : ["http://www.sky.fm/mp3/oldies.pls", "", "", "96", "The 50s, 60s, & 70s - three decades of great oldies on www.sky.fm"], "pr1" : ["mms://stream.polskieradio.pl/Program 1", "fixme", "fixme", "??", ""], "pr2" : ["mms://stream.polskieradio.pl/Program 2", "fixme", "fixme", "??", ""], "pr3" : ["mms://stream.polskieradio.pl/Program 3", "fixme", "fixme", "??" ,""], "rmf" : ["http://www.abradio.cz/www/rmffm.asx", "", "", "20", "RMF FM"], "salsa" : ["http://205.188.234.65:8026", "-L8026:205.188.234.65:8026", "http://localhost:8026", "96", "" ], #dotad "parlament": ["mms://stream.polskieradio.pl/Radio Parlament", "", "", "??", ""], "polonia": ["mms://195.245.217.6/Radio Polonia", "", "mms://195.245.217.6/Radio Polonia", "?", ""], "polonia-itvp" : [itvproot + "radio/media/polonia", "fixme", "fixme", "32", ""], "bbc3" : ["http://www.bbc.co.uk/radio3/ram/r3g2.ram", "", "http://www.bbc.co.uk/radio3/ram/r3g2.ram", "?", ""], "radio2" : ["http://213.173.232.218:80/radio2-96?MSWMExt=.asf", "", "http://213.173.232.218:80/radio2-96?MSWMExt=.asf", "96", ""], "radiostacja" : ["mms://217.11.251.148/radiostacja", "", "", "?", ""], "skyradio" : ["http://193.159.244.28/live/skyradio_denmark/audio_64k", "", "http://193.159.244.28/live/skyradio_denmark/audio_64k", "64", ""], "smoothjazz" : ["http://smoothjazz.com/streams/smoothjazz_128.pls", "", "", "128", ""], # http://scfire-ntc0l-2.stream.aol.com/stream/1005", # #"http://64.236.34.67:80/stream/1005", # "",#"-L8080:64.236.34.67:80", # "",#"http://localhost:8080/stream/1005", # "128", ""], "smoothjazz-os" : ["octoshape:SMOOTHLOUNGE.smoothjazz_mp3", "", "", "192", ""], "smoothlounge-os" : ["octoshape:SMOOTHLOUNGE.smoothlounge_mp3", "", "", "192", ""], "paradise-os" : ["octoshape:PARADISE.stream1_mp3", "", "", "192", ""], "maryja" : ["mms://195.94.205.211/rm", "", "mms://195.94.205.211/rm", "?", ""], "modernjazz" : ["http://64.236.34.67:5190/stream/1019", "-L5190:64.236.34.67:5190", "http://localhost:5190/stream/1019", "96", ""], "mostlyclassical" : ["http://64.236.34.67:80/stream/1006", "-L8080:64.236.34.67:80", "http://localhost:8080/stream/1006", "96", ""], "jozef" : ["http://sielskiefale.pl/wmp.asx", "", "", "48", ""], "radyjko" : ["http://66.79.189.215:8000/", "-L8000:66.79.189.215:8000", "http://localhost:8000/", "32", ""], "rdn-malopolska" : ["http://radiointernetowe.net:7000/listen.pls", "", "", "64", "The main RDN channel - a mainstream Christian radio from SE Poland"], "rmfclassic" : ["mms://217.11.251.151/classic32", "-L1755:217.11.251.151:1755", "mms://localhost/classic32", "32", ""], "rmfclassic128" : ["mms://217.11.251.151/classic128", "-L1755:217.11.251.151:1755", "mms://localhost/classic128", "128", ""], "svoboda-wma" : ["http://mfile.akamai.com/10623/live/reflector:31074.asx", "", "http://mfile.akamai.com/10623/live/reflector:31074.asx", "?", ""], "svoboda-ram" : ["http://www.rferl.org/realaudio/c4.ram", "", "http://www.rferl.org/realaudio/c4.ram", "?", ""], "tokfm-96" : ["http://ml2.gazeta.pl/tokfm?MSWMExt=.asf", "", "http://ml2.gazeta.pl/tokfm?MSWMExt=.asf", "96", "Tok FM (Polish)"], "tokfm-320" : ["http://www.radio.pionier.net.pl/stream.pls?radio=radiotok", "", "http://www.radio.pionier.net.pl/stream.pls?radio=radiotok", "320", "Tok FM (Polish)"], "klux" : ["http://listenlive.klux.org", "", "", "?", ""], "polskastacja" : ["http://213.251.129.27:9000", "", "", "96", ""], "rdn-religia" : ["http://radiointernetowe.net:7002/listen.pls", "", "", "128","A Christian channel of RDN in SE Poland"], "trwam" : ["mms://195.94.205.211/Trwam", "", "", "?", ""], "taize" : ["http://www.taize.fr/ext/sound/wma/Taize_Recorded_Live_2005.wma", "", "", "?", ""], "smoothlounge" : ["http://213.251.187.11:80", "", "", "128", ""], "virgin" : ["http://network.virginradio.co.uk/core/audio/ogg/live.pls?service=vrbb", "", "", "160",""], "virgin-mp3" : ["http://network.virginradio.co.uk/core/audio/mp3/live.pls?service=vrbb", "", "", "128",""], "wcpe.org" : ["http://audio.ibiblio.org:8010/wcpe.ogg", "", "http://audio.ibiblio.org:8010/wcpe.ogg", "?", ""], "wnyc-am" : ["http://wnycam.streamguys.com/", "", "http://wnycam.streamguys.com/", "24", ""], "wnyc-fm" : ["http://wnycfm.streamguys.com/", "", "http://wnycfm.streamguys.com/", "32", ""], "zet" : ["http://194.150.185.31/listen.pls", "", "", "?", ""], "npr" : ["mms://a1671.l2063252432.c20632.g.lm.akamaistream.net/D/1671/20632/v0001/reflector:52432?v1st=U438921971158068501647&mt=5","","","?",""] } loop = 0 names = channels.keys() tunnel = False dump = False dumpfile = "" server = "" mplayer = "mplayer" octoshape = "/home/wasowski/opt/Octoshape/OctoshapeClient" realplay = "realplay" #oggplay = "ogg123" oggplay = "ogg123" #ao = "alsa:device=plughw=2,alsa:device=plughw=1,alsa:device=plughw=0" ao = [] vo = [] af = "dummy" killpid = -1 ### process command line options usage = "usage: radio [options] channelname" parser = OptionParser(usage) parser.add_option("-t", "--tunnel", dest="server", help="tunnel trough SERVER", metavar="SERVER") parser.add_option("-d", "--dump", dest="dumpfile", help="dump to a file FILE (only works with mplayer for now)", metavar="FILE") parser.add_option("-L", "--loop", action="store_true", dest="loop", default=False, help="loop if connection is lost") parser.add_option("", "--ao", dest="ao", help="alsa device AO (mplayer)", metavar="AO") parser.add_option("", "--vo", dest="vo", help="mplayer video output (mplayer video streams)", metavar="VO") parser.add_option("", "--af", dest="af", help="audio filter AF (mplayer)", metavar="AF") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="be verbose") parser.add_option("-l", "--list", action="store_true", dest="list_channels", default=False, help="list channels") (options, args) = parser.parse_args() ### some auxiliary stuff (main code below) def myspawnvp(mode, app, params): def sepwrite(s): sys.stdout.write (s+" ") if options.verbose: sepwrite(app) map (sepwrite, params) print os.spawnvp(mode, app, params) def play_url(url): playlist = "-nolirc" if url[-4:] == ".asx" or url[-4:] == ".ram" or url[-4:] == ".pls": playlist = "-playlist" if url[:10] == "octoshape:": myspawnvp(os.P_WAIT, octoshape, [octoshape, "-url:" + url]) return if dump: myspawnvp(os.P_WAIT, mplayer, [mplayer, "-cache", "256", playlist, url, "-dumpstream", "-dumpfile", dumpfile]) return if "itvp" in url: fname = os.popen ("tempfile -d /tmp -p radio -s .asx").read() os.system("wget " + url + " -O " + fname ) myspawnvp(os.P_WAIT, mplayer, [mplayer] + ao + vo + ["-af", af, "-cache", "8192", "-cache-min", "1", "-playlist", fname[:-1] ]) else: myspawnvp(os.P_WAIT, mplayer, [mplayer] + ao + vo + ["-af", af, "-cache", "8192", "-cache-min", "1", playlist, url]) def play_channel(ch): global killpid if tunnel: if channels[ch][1] <> "": print "Tunneling via " + server + " to " + channels[ch][1] killpid = os.spawnlp(os.P_NOWAIT, "ssh", "ssh", "-N", channels[ch][1], server) print "Waiting for the connection to be established..." time.sleep(5) while True: play_url(channels[ch][2]) if not options.loop: break else: while True: play_url(channels[ch][0]) if not options.loop: break sys.exit(); def show_channels(): def sepwrite(s): sys.stderr.write (s+"("+channels[s][3]+") - " +channels[s][4] +"\n") sys.stderr.write('Available channels:\n') names.sort() map (sepwrite, names) sys.stderr.write ('\n') if (options.server != None): tunnel = True server = options.server if (options.ao != None): ao = ["-ao", options.ao] if (options.vo != None): vo = ["-vo", options.vo] if (options.af != None): af = options.af if (options.dumpfile != None): dump = True dumpfile = options.dumpfile if (options.list_channels): show_channels() sys.exit() if len(args) != 1: parser.error("incorrect number of arguments") if not channels.has_key( args[0] ): sys.stderr.write ('Unknown channel: ' + sys.argv[0] + '\n') show_channels() sys.exit() # signal.signal(signal.SIGINT,signal.SIG_IGN) try: try: play_channel(sys.argv[-1]) finally: if killpid>0: sys.stderr.write ("Killing child ssh process...") os.kill(killpid,signal.SIGTERM) sys.stderr.write ("killed.\n") except KeyboardInterrupt: sys.stderr.write("\n*** Interrupted ***\n")