rhythmbox-radio-browser-2.3.1/0000755000175000017500000000000011470615004015640 5ustar seglerseglerrhythmbox-radio-browser-2.3.1/Makefile0000644000175000017500000000052111470615004017276 0ustar seglerseglerDESTDIR= SUBDIR=/usr/lib/rhythmbox/plugins/radio-browser/ LOCALEDIR=/usr/share/locale/ all: clean: - rm *.pyc install: install -d $(DESTDIR)$(SUBDIR) install -m 644 *.py $(DESTDIR)$(SUBDIR) install -m 644 *.png $(DESTDIR)$(SUBDIR) install -m 644 radio-browser.rb-plugin $(DESTDIR)$(SUBDIR) cd po;./lang.sh $(DESTDIR)$(LOCALEDIR) rhythmbox-radio-browser-2.3.1/shoutcast_handler.py0000644000175000017500000001055511470615004021732 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import os import urllib import urllib2 import xml.sax.handler from radio_station import RadioStation from feed import Feed class ShoutcastRadioStation(RadioStation): def updateRealURL(self): self.listen_urls = [] try: # download from "http://www.shoutcast.com"+self.tunein+"?id="+shoutcast_id url = "http://www.shoutcast.com"+self.tunein+"?id="+self.listen_id remote = urllib2.urlopen(url) data = remote.read() remote.close() lines = data.splitlines() for line in lines: if line.startswith("File"): self.listen_urls.append(line.split("=")[1]) print "new link:"+line.split("=")[1] self.askUserAboutUrls() except: return def getRealURL(self): if self.listen_url == "": self.updateRealURL() if self.listen_url == "": return None else: return self.listen_url class ShoutcastHandler(xml.sax.handler.ContentHandler): def __init__(self): self.genres = [] self.entries = [] def startElement(self, name, attributes): if name == "genre": self.genres.append(attributes.get("name")) if name == "tunein": self.tunein = attributes.get("base") if name == "station": self.entry = ShoutcastRadioStation() self.entry.tunein = self.tunein self.entry.type = "Shoutcast" self.entry.server_name = attributes.get("name") self.entry.genre = attributes.get("genre").lower() self.entry.genre = ",".join(self.entry.genre.split(" ")) self.entry.current_song = attributes.get("ct") self.entry.bitrate = attributes.get("br") self.entry.listen_id = attributes.get("id") self.entry.listeners = attributes.get("lc") self.entry.server_type = attributes.get("mt") try: self.entry.homepage = "http://shoutcast.com/directory/search_results.jsp?searchCrit=simple&s="+urllib.quote_plus(self.entry.server_name.replace("- [SHOUTcast.com]","").strip()) except: self.entry.homepage = "" self.entries.append(self.entry) class FeedShoutcast(Feed): def __init__(self,cache_dir,status_change_handler): Feed.__init__(self) print "init shoutcast feed" self.handler = ShoutcastHandler() self.cache_dir = cache_dir self.filename = os.path.join(self.cache_dir, "shoutcast-genre.xml") self.uri = "http://www.shoutcast.com/sbin/newxml.phtml" self.status_change_handler = status_change_handler def name(self): return "Shoutcast" def getHomepage(self): return "http://shoutcast.com/" def genres(self): if not self.loaded: if not os.path.isfile(self.filename): self.download() self.load() self.loaded = True return self.handler.genres def entries(self): entry_list = [] genres = self.genres() for genre in genres: entry = FeedSubShoutcast(self.cache_dir,self.status_change_handler,genre) entry_list.append(entry) return entry_list def search(self,term): searchUrl = "http://www.shoutcast.com/sbin/newxml.phtml?%s" % urllib.urlencode({"search":term}) data = self.downloadFile(searchUrl) handler = ShoutcastHandler() if data != None: xml.sax.parseString(data,handler) return handler.entries return None class FeedSubShoutcast(Feed): def __init__(self,cache_dir,status_change_handler,genre): Feed.__init__(self) self.handler = ShoutcastHandler() self.cache_dir = cache_dir self.filename = os.path.join(self.cache_dir, "shoutcast-"+genre+".xml") self.uri = "http://www.shoutcast.com/sbin/newxml.phtml?%s" % urllib.urlencode({"genre":genre}) self.status_change_handler = status_change_handler self.genre = genre self.setAutoDownload(False) self.setUpdateChecking(False) def name(self): return "Shoutcast Genre "+self.genre def getHomepage(self): return "http://shoutcast.com/" rhythmbox-radio-browser-2.3.1/record_process.py0000644000175000017500000001664111470615004021236 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import threading import gobject import subprocess import gtk import os from datetime import datetime import xml.sax.saxutils from radio_station import RadioStation class RecordProcess(threading.Thread,gtk.VBox): def __init__(self,station,outputpath,play_cb,shell): # init base classes threading.Thread.__init__(self) gtk.VBox.__init__(self) # make shortcuts title = station.server_name uri = station.getRealURL() self.relay_port = "" self.server_name = "" self.bitrate = "" self.song_info = "" self.stream_name = "" self.filesize = "" self.song_start = datetime.now() self.play_cb = play_cb self.outputpath = outputpath self.shell = shell # prepare streamripper commandline = ["streamripper",uri,"-d",outputpath,"-r","-o","larger"] self.process = subprocess.Popen(commandline,stdout=subprocess.PIPE) # infobox left = gtk.Table(12,2) left.set_col_spacing(0,10) self.info_box = left right = gtk.VBox() play_button = gtk.Button(stock=gtk.STOCK_MEDIA_PLAY,label="") right.pack_start(play_button) stop_button = gtk.Button(stock=gtk.STOCK_STOP,label="") right.pack_start(stop_button) box = gtk.HBox() box.pack_start(left) box.pack_start(right,False) decorated_box = gtk.Frame(_("Ripping stream")) decorated_box.add(box) play_button.connect("clicked",self.record_play_button_handler,uri) stop_button.connect("clicked",self.record_stop_button_handler) # song list self.songlist = gtk.TreeView() self.songlist.connect('row-activated', self.open_file) self.songlist_store = gtk.TreeStore(int,str,str) self.songlist_store.set_sort_column_id(0,gtk.SORT_DESCENDING) self.songlist.set_model(self.songlist_store) column_time_cell = gtk.CellRendererText() column_time_cell.set_property('xalign', 0.0) column_time = gtk.TreeViewColumn(_("Time"),column_time_cell) column_time.set_cell_data_func(column_time_cell,self.display_cb) self.songlist.append_column(column_time) column_title = gtk.TreeViewColumn(_("Title"),gtk.CellRendererText(),text=1) self.songlist.append_column(column_title) column_size_cell = gtk.CellRendererText() column_size_cell.set_property('xalign', 1.0) column_size = gtk.TreeViewColumn(_("Filesize"),column_size_cell,text=2) column_size.set_alignment(1.0) self.songlist.append_column(column_size) tree_view_container = gtk.ScrolledWindow() tree_view_container.set_shadow_type(gtk.SHADOW_IN) tree_view_container.add(self.songlist) tree_view_container.set_property("hscrollbar-policy", gtk.POLICY_AUTOMATIC) self.pack_start(decorated_box,False) self.pack_start(tree_view_container) self.show_all() def open_file(self, treeview, path, column): model = treeview.get_model() iter = model.get_iter(path) filename = os.path.join(os.path.join(self.outputpath, self.stream_name),model.get_value(iter, 1)) #self.shell.add_to_queue("file:/"+filename) #self.shell.load_uri("file:/"+filename,True) t = threading.Thread(target = self.play,args = (filename,)) t.setDaemon(True) t.start() return def display_cb(self,column,cell,model,iter): seconds = model.get_value(iter,0) cell.set_property("text",datetime.fromtimestamp(seconds).strftime("%x %X")) def play(self,filename): print filename subprocess.call(["rhythmbox",filename]) def refillList(self): self.songlist.set_model() self.songlist_store.clear() path = os.path.join(self.outputpath,self.stream_name) if os.path.isdir(path): for filename in os.listdir(path): filepath = os.path.join(path,filename) if os.path.isfile(filepath): self.songlist_store.append(None,(int(os.path.getmtime(filepath)),filename,str(os.path.getsize(filepath)/1024)+" kB")) self.songlist.set_model(self.songlist_store) def set_info_box(self): self.added_lines = 0 def add_label(title,value): if not value == "": label = gtk.Label() if value.startswith("http://"): label.set_markup(""+value+"") else: label.set_markup(xml.sax.saxutils.escape(value)) label.set_selectable(True) label.set_alignment(0, 0) title_label = gtk.Label() title_label.set_alignment(1, 0) title_label.set_markup(""+xml.sax.saxutils.escape(title)+"") self.info_box.attach(title_label,0,1,self.added_lines,self.added_lines+1) self.info_box.attach(label,1,2,self.added_lines,self.added_lines+1) self.added_lines += 1 for widget in self.info_box.get_children(): self.info_box.remove(widget) add_label(_("Server"),self.server_name) add_label(_("Stream"),self.stream_name) add_label(_("Current song"),self.song_info) playing_time = datetime.now()-self.song_start add_label(_("Playing time"),"{0:02d}:{1:02d}".format(playing_time.seconds/60,playing_time.seconds%60)) add_label(_("Filesize"),self.filesize) add_label(_("Bitrate"),self.bitrate) add_label(_("Relay port"),str(self.relay_port)) self.info_box.show_all() return False def run(self): pout = self.process.stdout while self.process.poll()==None: line = "" while True: try: char = pout.read(1) except: print "exception" break if char == None or char == "": break if char == "\n": break if char == "\r": break line = line+char #print "STREAMRIPPER:"+line if line.startswith("relay port"): self.relay_port = line.split(":")[1].strip() if line.startswith("stream"): self.stream_name = line.split(":")[1].strip() # refillList depends on stream_name self.refillList() if line.startswith("server name"): self.server_name = line.split(":")[1].strip() if line.startswith("declared bitrate"): self.bitrate = line.split(":")[1].strip() if line.startswith("[ripping") or line.startswith("[skipping"): song = line[17:len(line)-10] # add old song to list, after recording title changed to new song if self.song_info != song: #if self.song_info != "": # self.songlist_store.append((str(self.song_start.strftime("%x %X")),self.song_info,self.filesize)) self.song_info = song self.song_start = datetime.now() self.refillList() self.filesize = line[len(line)-8:len(line)-1].strip() gobject.idle_add(self.set_info_box) print "thread closed" gtk.gdk.threads_enter() self.get_parent().set_current_page(0) self.get_parent().remove(self) gtk.gdk.threads_leave() def stop(self): if self.process.poll() is None: self.process.terminate() def record_play_button_handler(self,button,uri): station = RadioStation() station.server_name = self.stream_name station.listen_url = "http://127.0.0.1:"+self.relay_port station.type = "local" self.play_cb(station) def record_stop_button_handler(self,button): self.process.terminate() rhythmbox-radio-browser-2.3.1/local_handler.py0000644000175000017500000000540011470615004021000 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import os import xml.sax.handler from radio_station import RadioStation from feed import Feed class LocalHandler(xml.sax.handler.ContentHandler): def __init__(self): self.countries = [] self.categories = [] self.entries = [] self.current_category = None def startElement(self, name, attributes): if name == "country": self.countries.append(attributes.get("name")) self.current_country = attributes.get("name") if name == "category": self.categories.append(attributes.get("name")) self.current_category = attributes.get("name") if name == "station": self.entry = RadioStation() self.entry.type = "Local" self.entry.server_name = attributes.get("name") self.entry.genre = attributes.get("genre") self.entry.listen_url = attributes.get("address") self.entry.bitrate = attributes.get("bitrate") if self.entry.bitrate is None: self.entry.bitrate = "" self.entry.homepage = attributes.get("homepage") self.entry.icon_src = attributes.get("favicon") if self.entry.icon_src is None: self.entry.icon_src = "" if self.current_category is not None: self.entry.country = self.current_country+"/"+self.current_category else: self.entry.country = self.current_country self.entries.append(self.entry) def endElement(self, name): if name == "category": self.current_category = None class FeedLocal(Feed): def __init__(self,cache_dir,status_change_handler): Feed.__init__(self) print "init local feed" self.handler = LocalHandler() self.cache_dir = cache_dir self.filename = os.path.join(self.cache_dir, "local.xml") self.uri = "http://www.programmierecke.net/programmed/local.xml" self.status_change_handler = status_change_handler def name(self): return "Local" def getHomepage(self): return "http://www.radio-browser.info" def search(self, term): foundEntries = [] for entry in self.entries(): if entry.server_name.lower().find(term.lower()) >= 0: foundEntries.append(entry) return foundEntries rhythmbox-radio-browser-2.3.1/radiotime_handler.py0000644000175000017500000001173611470615004021674 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import os import urllib import urllib2 import xml.sax.handler from radio_station import RadioStation from feed import Feed class RadioTimeRadioStation(RadioStation): def updateRealURL(self): self.listen_urls = [] try: url = "http://opml.radiotime.com/Tune.ashx?id="+self.listen_id print "tunein:"+url remote = urllib2.urlopen(url) data = remote.read() remote.close() lines = data.splitlines() for line in lines: if not line.startswith("#"): self.listen_urls.append(line) print "new link:"+line self.askUserAboutUrls() except: return def getRealURL(self): if self.listen_url == "": self.updateRealURL() if self.listen_url == "": return None else: return self.listen_url class RadioTimeHandler(xml.sax.handler.ContentHandler): def __init__(self): self.genres = {} self.entries = [] def startElement(self, name, attributes): if name == "outline": if attributes.get("type") == "audio": self.entry = RadioTimeRadioStation() self.entry.type = "RadioTime" self.entry.server_name = attributes.get("text") self.entry.bitrate = attributes.get("bitrate") self.entry.reliability = attributes.get("reliability") self.entry.listen_id = attributes.get("guide_id") self.entry.genre = "" self.entry.genre_id = attributes.get("genre_id") self.entry.icon_src = attributes.get("image") self.entry.server_type = attributes.get("formats") self.entry.homepage = "" self.entries.append(self.entry) if attributes.get("type") == "link": try: self.entry = FeedRadioTime(self.cache_dir,self.status_change_handler) self.entry.uri = attributes.get("URL") self.entry._name = attributes.get("text") self.entry.filename = os.path.join(self.cache_dir,"radiotime-%s.xml" % attributes.get("guide_id")) self.entry.setAutoDownload(False) self.entries.append(self.entry) except: pass if attributes.get("type") == "text": self.genres[attributes.get("guide_id")] = attributes.get("text") RadioTimeGenreList = None class FeedRadioTime(Feed): def __init__(self,cache_dir,status_change_handler): Feed.__init__(self) self.handler = RadioTimeHandler() self.handler.cache_dir = cache_dir self.handler.status_change_handler = status_change_handler self.cache_dir = cache_dir self.status_change_handler = status_change_handler self.filename = os.path.join(self.cache_dir, "radiotime.xml") self.uri = "http://opml.radiotime.com/Browse.ashx?%s" % urllib.urlencode({"id":"r0","formats":"ogg,mp3,aac,wma"}) self._name = "RadioTime" self.setUpdateChecking(False) def loadGenreList(self): global RadioTimeGenreList print "load genre list" url = "http://opml.radiotime.com/Describe.ashx?c=genres" handler = RadioTimeHandler() RadioTimeGenreList = {} try: remote = urllib2.urlopen(url) xmlData = remote.read() remote.close() except Exception, e: print "could not load genre list" print str(e) return try: xml.sax.parseString(xmlData,handler) RadioTimeGenreList = handler.genres except: print "parse failed of "+xmlData def entries(self): items = Feed.entries(self) if RadioTimeGenreList == None: self.loadGenreList() for item in items: if isinstance(item,RadioTimeRadioStation): #print "search for '"+item.genre_id+"'" if item.genre_id in RadioTimeGenreList: #print "found it!" item.genre = RadioTimeGenreList[item.genre_id] return items def name(self): return self._name def getHomepage(self): return "http://radiotime.com/" def search(self,term): searchUrl = "http://opml.radiotime.com/Search.ashx?%s" % urllib.urlencode({"query":term,"formats":"ogg,mp3,aac,wma"}) print("url:"+searchUrl) data = self.downloadFile(searchUrl) handler = RadioTimeHandler() if data != None: xml.sax.parseString(data,handler) return handler.entries return None class FeedRadioTimeLocal(FeedRadioTime): def __init__(self,cache_dir,status_change_handler): FeedRadioTime.__init__(self,cache_dir,status_change_handler) self.uri = "http://opml.radiotime.com/Browse.ashx?%s" % urllib.urlencode({"c":"local","formats":"ogg,mp3,aac,wma"}) self._name = "RadioTime Local" self.filename = os.path.join(self.cache_dir, "radiotime-local.xml") rhythmbox-radio-browser-2.3.1/xiph-logo.png0000644000175000017500000000364511470615004020264 0ustar seglerseglerPNG  IHDRHJ%LsRGBbKGD pHYs  tIME&"ItEXtCommentCreated with GIMPWIDATxklSn!ˍKhe UE5ۚIc(MbhVPh:ABiCʀ* dII۱_>9%v|,sl?y}||IH$pt--sP $J wwa0ȷ]٠Agx8rHF霴w^\6;O?,h pRΝ;׻3ie@" gFGFGUb[Vn$>PaH+T}[oCyyy,m@h[pAD12\]W7/2:=No ;x0xoo*U3I!U48 nUW0퀂^١ L\wQ:::*&lHUK*sܱr1?-f6 !?߿¯vq],'}bF‘oBmm $=6VRk61e 1y3A#c@!ZXC.b4Nx߼Rx@J3.۬|}hprVX^RHUE83dor7VdMcȱb-ϯW1-)2з4nl 'mjzdPB6ZsE{jNnݽIOHȤSיސ j޶@JP3jyۚr\kC5"׆j+Qƪk)5ھ,{@5܈zzM*͸T~S9s@_yRW*ʜ&j6KPF7eNz@Z]hEɼ*af%* RmEokެRmMPUhMJe|g)y*t*R﹀ڃ@ >efy c słQ>PVZ@A, 9w MhP"_.}r+hF%{fY8ZC,>(hשYjN " kδ} u_41LۓߤqD3I8O LC_' 0.n(b6S 3gv|MQ>xZoٲykYaR, (8 Kybk4=.0OF4F3x[ /㞒t!I/`ݜ{ldx pcI;{$biDD,`kbJ H!Dn^B y޿,젱>3@(׉T: 4T|p=?86m "dxoďX5z) 84 Fo 1 "E(47Zh5\`w%m@IENDB`rhythmbox-radio-browser-2.3.1/radio-browser.rb-plugin.in0000644000175000017500000000207211470615004022646 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . [RB Plugin] Loader=python Module=radio-browser IAge=1 _Name=Internet radio station browser _Description=Shows icecast and shoutcast radio stations on a tab. Authors=segler_alex@web.de Copyright=Copyright © 2009 segler_alex Website=http://programmierecke.net Icon=radio-browser.png rhythmbox-radio-browser-2.3.1/CHANGELOG0000644000175000017500000000265411470615004017061 0ustar seglerseglerChanges in 2.3.1: ================= * added stream chooser dialog if station has multiple streams urls * some bugfixes * updated translations Changes in 2.3: =============== * new search tab * moved board to new server: http://www.radio-browser.info * start page has resizer-handle now * translation updates * some bugfixes Changes in 2.2: =============== * added new tab, that displays favourites for faster access on program start Changes in 2.1: =============== * gio library dependency is not needed any more * new source radiotime * translation updates Changes in 2.0: =============== * more translations * recording streams creates a new tab for each recording * recently played entries get removed after a configurable time * streamripper overwrites the older file if the newer one with the same title is bigger * display station count in each subtree * group bitrate by steps of 32 and bigger ones than 512 to invalid Changes in 1.9: =============== * new view to display search(filter) results * rewrite of some parts -> more stability * new icon set * automatic update of some feeds(icecast, local), if local copy is at least 1 day older than server version * station click hitlist on http://segler.bplaced.net * new install scrypt, for per user install * special sorting (by bitrate, genre, streamtype, country) for each feed * removed right click in tree in favour of buttons in infobox * added german translation * more error dialogs rhythmbox-radio-browser-2.3.1/icecast_handler.py0000644000175000017500000000507311470615004021327 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import os import xml.sax.handler from radio_station import RadioStation from feed import Feed class IcecastHandler(xml.sax.handler.ContentHandler): def __init__(self): self.entries = [] def startElement(self, name, attributes): self.currentEntry = name; if name == "entry": self.entry = RadioStation() self.entry.type = "Icecast" def characters(self, data): if self.currentEntry == "server_name": self.entry.server_name += data elif self.currentEntry == "listen_url": self.entry.listen_url += data elif self.currentEntry == "genre": self.entry.genre += data elif self.currentEntry == "current_song": self.entry.current_song += data elif self.currentEntry == "bitrate": self.entry.bitrate += data elif self.currentEntry == "server_type": self.entry.server_type += data def endElement(self, name): if name == "entry": try: self.entry.homepage = "http://dir.xiph.org/search?search="+urllib.quote_plus(self.entry.server_name) except: self.entry.homepage = "" self.entry.genre = ",".join(self.entry.genre.split(" ")) self.entries.append(self.entry) self.currentEntry = "" class FeedIcecast(Feed): def __init__(self,cache_dir,status_change_handler): Feed.__init__(self) print "init icecast feed" self.handler = IcecastHandler() self.cache_dir = cache_dir self.filename = os.path.join(self.cache_dir, "icecast.xml") self.uri = "http://dir.xiph.org/yp.xml" self.status_change_handler = status_change_handler def name(self): return "Icecast" def getDescription(self): return "" def getHomepage(self): return "http://dir.xiph.org" def search(self, term): foundEntries = [] for entry in self.entries(): if entry.server_name.lower().find(term.lower()) >= 0: foundEntries.append(entry) return foundEntries rhythmbox-radio-browser-2.3.1/radio-browser.rb-plugin0000644000175000017500000000347611470615004022252 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . [RB Plugin] Loader=python Module=radio-browser IAge=1 Name=Internet radio station browser Name[de]=Internetradio Verzeichnis Name[el]=Internet radio station browser Name[es]=Explorador de estaciones de radio Name[fr]=Navigateur de webradios Name[pt_BR]=Navegador de estações de rádio Name[ru]=Навигатор интернет-радиостанций Description=Shows icecast and shoutcast radio stations on a tab. Description[de]=Zeigt Icecast und Shoutcast Radiostationen auf einem Tab an. Description[el]=Εμφανίζει ραδιοφωνικούς σταθμούς, icecast και shoutcast, σε μια καρτέλα. Description[es]=Muestra estaciones de radio Icecast y Shoutcast Description[fr]=Montrer les webradios Icecast et Shoutcast dans un onglet Description[pt_BR]=Exibe estações de icecast e shoutcast em uma aba. Description[ru]=Показывать icecast и shoutcast радиостанции… Authors=segler_alex@web.de Copyright=Copyright © 2009 segler_alex Website=http://programmierecke.net Icon=radio-browser.png rhythmbox-radio-browser-2.3.1/note.png0000644000175000017500000000522211470615004017314 0ustar seglerseglerPNG  IHDRHJ%LsRGBbKGD pHYs  tIME5' tEXtCommentCreated with GIMPW IDATxyl?3{c]s8AVڪ`5-ik*BjQ(IB U i.GAUH :s'ܱ{oێݯ42y߼7~,wm^-۶}2Qh],]$ntH$$Iy$M[$IxkժUs`?*YdV.)}q\.WJqg:`֮]˷~9!I (DzeChsuhsudbqR6-nl-sCh߀~8ob޽deep,_["Gi|adſ? :Z!cyy6}<)h4tyOV"]jz|fx%˦'_@-+6GFdk.^zwٳ;a81{P'=ϦM;u+g1> CxS |vn>z/֬a}5iRr.p8}HLyqP@} ـ&`M}- DUk T9WO]&|B!x 4`GM}z=>g%5XAq+p޲߰qrm,b溹IFऀp$@ US"Agus,@9JKiV]S_%u EhstToON)r19K pM o[jlg<7)yUggn H_7( &8'44 2XW,?%ȸi3_0&Z?^`X oҫZ?/5Tb1TS_k L +fыǓrpUqN@\n\]6W8 $e/,L >@ W>P>?,bk ҙ_P8_PΤP^U#El 豲(!eDmP@jqʟ3p64v҈f9TM9rFHd,Bi (X=H!1(yl (35#P(5^\dX@>Up^oTᱹQTI;ܐTܞ) (wFoUڠ.@yln{Kϗj*?acΣ=^Ed)ܻ0>N7aPcM37^fX% FfrJ8Ra17RZ$(7$>'~1L\w;.Hi>A-Oh?d@9JPAbSm͝,m?ZZ.EwSDKqx)G$1}q:@[S_ܟNqW_Ųdh46!GR~1ׇJ%Լ sCpXQH( Pz'&)yi&K0g@@~Izrܳި,-0] G֤/P.s ^;~?<`174 le쩌9MBGL%3wJޠD%gn{VsMimKDΙ[@'a@N[3k]:l-!,%9a@.dhH+O^Hkԓ^xvG< J#--Mr h82y ?IL7hPAh\vڋVFݱc8a,9Q |Xh233 ƛ0bPLaP67.݄. рC*,Ǐ5f &Պ4l(i9xΣc|>]bh$,O6#LF{m-#gĴ 22YQyf]-#ĶԚu(<pжoV\^dr>(38]eӍ}Q,ɤAOg "p>P>(M\~N[~8@\><ծ8@\>rȏ`~ncuDcup}HC15uy-'O:  1YFCA/Gn%,[8Hc8jw"'ZtRDK6XZ"v;7ѐ9͛΢JfD*V3ϵ5NENGc+^eo,dڰPAT$A0`yzHyxwӫ ҇ACs8#r啑PǹUϻ Ra M *iM#nj#$R(it_y$Us5Euu<ɀ5SVOۏz|}UHgɀe_0Iy銫giQW+/pr;/?4(qهTJ -oFץNpp+P1 n?T5|'zov] ׵kװcY5 { h?t;n;%0#J_\9AHKfH!7pfݷP 6Vm 8%j;)IENDB`rhythmbox-radio-browser-2.3.1/feed.py0000644000175000017500000001240511470615004017117 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import os import urllib2 import httplib from urlparse import urlparse import datetime import locale import xml.sax.handler from radio_station import RadioStation class FeedAction: def __init__(self,feed,name,func): self.feed = feed self.name = name self.func = func def call(self,source): self.func(source) class FeedStationAction: def __init__(self,feed,name,func): self.feed = feed self.name = name self.func = func def call(self,source,station): self.func(source,station) class Feed: def __init__(self): self.loaded = False self.AutoDownload = True self.UpdateChecking = True self.FileSize = 0 self.remote_mod = datetime.datetime.now() def getSource(self): return self.uri def getDescription(self): return "" def getHomepage(self): return "" def setAutoDownload(self,autodownload): self.AutoDownload = autodownload def setUpdateChecking(self,updatechecking): self.UpdateChecking = updatechecking def copy_callback(self,current,total): self.status_change_handler(self.uri,current,total) def download(self): print "downloading "+self.uri try: os.remove(self.filename) except: pass try: remotefile = urllib2.urlopen(self.uri) chunksize = 100 data = "" current = 0 while True: chunk = remotefile.read(chunksize) current += chunksize self.copy_callback(current,self.FileSize) if chunk == "": break if chunk == None: break data += chunk localfile = open(self.filename,"w") localfile.write(data) localfile.close() except Exception, e: print "download failed exception" print e return False return True def getRemoteFileInfo(self): try: urlparts = urlparse(self.uri) conn = httplib.HTTPConnection(urlparts.netloc) conn.request("HEAD", urlparts.path) res = conn.getresponse() for key,value in res.getheaders(): if key == "last-modified": print key+":"+value oldlocale = locale.setlocale(locale.LC_ALL) locale.setlocale(locale.LC_ALL,"C") self.remote_mod = datetime.datetime.strptime(value,'%a, %d %b %Y %H:%M:%S %Z') locale.setlocale(locale.LC_ALL,oldlocale) if key == "content-length": print key+":"+value self.FileSize = int(value) except Exception, e: print "could not check remote file for modification time:"+self.uri print e return # only download if necessary def update(self): download = False local_mod = datetime.datetime.min try: local_mod = datetime.datetime.fromtimestamp(os.path.getmtime(self.filename)) except: print "could not load local file:"+self.filename download = True self.getRemoteFileInfo() if self.remote_mod > local_mod: print "Local file older than 1 day: remote("+str(self.remote_mod)+") local("+str(local_mod)+")" # change date is different -> download download = True if download: self.download() def load(self): print "loading "+self.filename try: xml.sax.parse(self.filename,self.handler) except: print "parse failed of "+self.filename def genres(self): if not os.path.isfile(self.filename) and not self.AutoDownload: return [] if not self.loaded: if self.UpdateChecking: self.update() if not os.path.isfile(self.filename): download() self.load() self.loaded = True list = [] for station in self.handler.entries: if station.genre is not None: for genre in station.genre.split(","): tmp = genre.strip().lower() if tmp not in list: list.append(tmp) return list def entries(self): if not os.path.isfile(self.filename) and not self.AutoDownload: return [] if not self.loaded: if self.UpdateChecking: self.update() if not os.path.isfile(self.filename): download() self.load() self.loaded = True return self.handler.entries def force_redownload(self): self.handler.entries = [] self.loaded = False try: os.remove(self.filename) except: pass pass def get_feed_actions(self): actions = [] return actions def get_station_actions(self): actions = [] return actions #def search(self,term,queue): # print "not implemented in this feed" # return None def downloadFile(self,url): try: remotefile = urllib2.urlopen(url) chunksize = 100 data = "" current = 0 while True: chunk = remotefile.read(chunksize) current += chunksize if chunk == "": break if chunk == None: break data += chunk remotefile.close() return data except Exception, e: print "download failed exception" print e return None rhythmbox-radio-browser-2.3.1/board_handler.py0000644000175000017500000002075511470615004021007 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import os import urllib import gtk import xml.sax.handler from radio_station import RadioStation from feed import Feed from feed import FeedAction from feed import FeedStationAction class BoardHandler(xml.sax.handler.ContentHandler): def __init__(self): self.entries = [] self.languages = [] self.countries = [] def startElement(self, name, attributes): if name == "station": self.entry = RadioStation() self.entry.type = "Board" self.entry.id = attributes.get("id") self.entry.server_name = attributes.get("name") self.entry.genre = attributes.get("tags") if (self.entry.genre == None): self.entry.genre = "" self.entry.genre = ",".join(self.entry.genre.split(" ")) self.entry.listen_url = attributes.get("url") self.entry.language = attributes.get("language") self.entry.country = attributes.get("country") self.entry.votes = attributes.get("votes") self.entry.negativevotes = attributes.get("negativevotes") self.entry.homepage = attributes.get("homepage") self.entry.icon_src = attributes.get("favicon") try: self.entry.clickcount = attributes.get("clickcount") except: self.entry.clickcount = 0 self.entries.append(self.entry) if self.entry.country.title() not in self.countries: self.countries.append(self.entry.country.title()) if self.entry.language.title() not in self.languages: self.languages.append(self.entry.language.title()) class PostStationDialog(gtk.Dialog): def __init__(self): super(PostStationDialog,self).__init__() title_label = gtk.Label() title_label.set_markup(""+_("Post new station")+"") self.get_content_area().pack_start(title_label) self.add_button(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL) self.add_button(gtk.STOCK_OK,gtk.RESPONSE_OK) table = gtk.Table(3,8) table.attach(gtk.Label(_("Examples")),2,3,0,1) table.attach(gtk.Label(_("Name")),0,1,1,2) self.StationName = gtk.Entry() table.attach(self.StationName,1,2,1,2) table.attach(gtk.Label(_("My Station")),2,3,1,2) table.attach(gtk.Label(_("URL")),0,1,2,3) self.StationUrl = gtk.Entry() table.attach(self.StationUrl,1,2,2,3) table.attach(gtk.Label(_("http://listen.to.my/station.pls")),2,3,2,3) table.attach(gtk.Label(_("Homepage URL")),0,1,3,4) self.StationHomepage = gtk.Entry() table.attach(self.StationHomepage,1,2,3,4) table.attach(gtk.Label(_("http://very.cool.site")),2,3,3,4) table.attach(gtk.Label(_("Favicon URL")),0,1,4,5) self.StationFavicon = gtk.Entry() table.attach(self.StationFavicon,1,2,4,5) table.attach(gtk.Label(_("http://very.cool.site/favicon.ico")),2,3,4,5) table.attach(gtk.Label(_("Country")),0,1,5,6) self.StationCountry = gtk.ComboBoxEntry() table.attach(self.StationCountry,1,2,5,6) table.attach(gtk.Label(_("Utopia")),2,3,5,6) table.attach(gtk.Label(_("Language")),0,1,6,7) self.StationLanguage = gtk.ComboBoxEntry() table.attach(self.StationLanguage,1,2,6,7) table.attach(gtk.Label(_("Esperanto")),2,3,6,7) table.attach(gtk.Label(_("Tags")),0,1,7,8) self.StationTags = gtk.Entry() table.attach(self.StationTags,1,2,7,8) table.attach(gtk.Label(_("Classical Jazz Talk")),2,3,7,8) self.get_content_area().pack_start(table,False) self.set_title(_("Post new station")) self.set_resizable(False) self.set_position(gtk.WIN_POS_CENTER) self.show_all() class FeedBoard(Feed): def __init__(self,cache_dir,status_change_handler): Feed.__init__(self) print "init board feed" self.handler = BoardHandler() self.cache_dir = cache_dir self.filename = os.path.join(self.cache_dir, "board.xml") self.uri = "http://www.radio-browser.info/xml.php" self.status_change_handler = status_change_handler def name(self): return "Board" def search(self, term): foundEntries = [] for entry in self.entries(): if entry.server_name.lower().find(term.lower()) >= 0: foundEntries.append(entry) return foundEntries """ vote for station on board """ def vote_station(self,source,station): message = gtk.MessageDialog(message_format=_("Vote for station"),buttons=gtk.BUTTONS_YES_NO,type=gtk.MESSAGE_QUESTION) message.format_secondary_text(_("Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station.")) response = message.run() if response == gtk.RESPONSE_YES: params = urllib.urlencode({'action': 'vote','id': station.id}) f = urllib.urlopen("http://www.radio-browser.info/?%s" % params) f.read() source.refill_list() message.destroy() """ mark station as bad on board """ def bad_station(self,source,station): message = gtk.MessageDialog(message_format=_("Mark station as broken"),buttons=gtk.BUTTONS_YES_NO,type=gtk.MESSAGE_WARNING) message.format_secondary_text(_("Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://www.radio-browser.info/")) response = message.run() if response == gtk.RESPONSE_YES: params = urllib.urlencode({'action': 'negativevote','id': station.id}) f = urllib.urlopen("http://www.radio-browser.info/?%s" % params) f.read() source.refill_list() message.destroy() """ post new station to board """ def post_new_station(self,source): dialog = PostStationDialog() LanguageList = gtk.ListStore(str) for language in self.handler.languages: LanguageList.append([language]) LanguageList.set_sort_column_id(0,gtk.SORT_ASCENDING) dialog.StationLanguage.set_model(LanguageList) dialog.StationLanguage.set_text_column(0) CountryList = gtk.ListStore(str) for country in self.handler.countries: CountryList.append([country]) CountryList.set_sort_column_id(0,gtk.SORT_ASCENDING) dialog.StationCountry.set_model(CountryList) dialog.StationCountry.set_text_column(0) while True: def show_message(message): info_dialog = gtk.MessageDialog(parent=dialog,buttons=gtk.BUTTONS_OK,message_format=message) info_dialog.run() info_dialog.destroy() response = dialog.run() if response == gtk.RESPONSE_CANCEL: break if response == gtk.RESPONSE_OK: Name = dialog.StationName.get_text().strip() URL = dialog.StationUrl.get_text().strip() Homepage = dialog.StationHomepage.get_text().strip() Favicon = dialog.StationFavicon.get_text().strip() Tags = dialog.StationTags.get_text().strip() Country = dialog.StationCountry.get_child().get_text().strip() Language = dialog.StationLanguage.get_child().get_text().strip() if Name == "" or URL == "": show_message(_("Name and URL are necessary")) continue if not (URL.lower().startswith("http://") or URL.lower().startswith("mms://")): show_message(_("URL needs to start with http:// or mms://")) continue if Homepage != "": if not Homepage.lower().startswith("http://"): show_message(_("Homepage URL needs to start with http://")) continue if Favicon != "": if not Favicon.lower().startswith("http://"): show_message(_("Favicon URL needs to start with http://")) continue params = urllib.urlencode({'action': 'add','name': Name, 'url': URL, 'homepage': Homepage,'favicon': Favicon, 'tags': Tags,'language': Language, 'country':Country}) f = urllib.urlopen("http://www.radio-browser.info/?%s" % params) f.read() show_message(_("Station successfully posted")) source.refill_list() break dialog.destroy() def get_feed_actions(self): actions = [] actions.append(FeedAction(self,_("Post new station"),self.post_new_station)) return actions def get_station_actions(self): actions = [] actions.append(FeedStationAction(self,_("Vote for station"),self.vote_station)) actions.append(FeedStationAction(self,_("Station is broken"),self.bad_station)) return actions rhythmbox-radio-browser-2.3.1/po/0000755000175000017500000000000011470615004016256 5ustar seglerseglerrhythmbox-radio-browser-2.3.1/po/update.sh0000755000175000017500000000042011470615004020073 0ustar seglersegler#!/bin/sh # update package.pot echo "update package.pot" intltool-update -p -g package # update translations from webtranslateit /var/lib/gems/1.8/bin/wti pull # update radio-browser.rb-plugin intltool-merge -d . ../radio-browser.rb-plugin.in ../radio-browser.rb-plugin rhythmbox-radio-browser-2.3.1/po/POTFILES.in0000644000175000017500000000034111470615004020031 0ustar seglerseglerboard_handler.py feed.py icecast_handler.py local_handler.py radio-browser.py radio_browser_source.py radio_station.py radiotime_handler.py record_process.py shoutcast_handler.py [type: gettext/ini]radio-browser.rb-plugin.in rhythmbox-radio-browser-2.3.1/po/config/0000755000175000017500000000000011470615004017523 5ustar seglerseglerrhythmbox-radio-browser-2.3.1/po/config/translation.yml0000644000175000017500000000055411470615004022610 0ustar seglerseglerapi_key: 76aae83a47d53d28c2297f4ca498a99b32388338 # Optional: locales not to sync with Web Translate It. # eg. [:en, :fr] or just 'en' # ignore_locales: 'en' # Optional, only used by wti server # before_pull: "echo 'some unix command'" # Command executed before pulling files # after_pull: "touch tmp/restart.txt" # Command executed after pulling files rhythmbox-radio-browser-2.3.1/po/ru.po0000644000175000017500000002576611470615004017264 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-09-11 16:29:52 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: Russian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "Добавлена в список недавно звучавших" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Битрейт" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "В закладки" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Закладки" #: ../radio-browser.py msgid "Browser" msgstr "Навигатор" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "По битрейту" #: ../radio_browser_source.py msgid "By Country" msgstr "По странам" #: ../radio_browser_source.py msgid "By Genres" msgstr "По стилям" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "По формату потока" #: ../board_handler.py msgid "Classical Jazz Talk" msgstr "Classical Jazz Talk" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Очистить кэш иконок" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "Невозможно скачать ленту. Пожалуйста, попробуйте позже." #: ../radio_browser_source.py msgid "Could not download station information" msgstr "Невозможно скачать информацию о станции" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "Невозможно скачать информацию о станции с сервера shoutcast. Пожалуйста, попробуйте позже." #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "Страна" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Сейчас слушателей" #: ../record_process.py msgid "Current song" msgstr "Текущая композиция" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Композиция (на момент обновления)" #: ../radio_browser_source.py msgid "Description" msgstr "Описание" #: ../board_handler.py msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://segler.bplaced.net/" msgstr "Вы действительно хотите отметить станцию как не работающую? Со временем она будет удалена если достаточно людей так её отметят! Подробнее можно узнать на сайте: http://segler.bplaced.net/" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "Вы действительно хотите проголосовать за станцию? Это значит, что вам она нравится и вы хотите сообщить другим людям, что это хорошая станция." #: ../radio_browser_source.py msgid "Download" msgstr "Скачать" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "Скачивание ленты %(name)s с %(url)s. %…" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "Формат" #: ../board_handler.py msgid "Esperanto" msgstr "Esperanto" #: ../board_handler.py msgid "Examples" msgstr "Примеры" #: ../board_handler.py msgid "Favicon URL" msgstr "Адрес иконки" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "Путь к иконке должен начинаться с http://" #: ../radio_browser_source.py msgid "Feed" msgstr "Лента" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Не удалось скачать ленту" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Домашняя страница" #: ../radio_browser_source.py msgid "Feed source" msgstr "Источник" #: ../record_process.py msgid "Filesize" msgstr "Размер файла" #: ../radio_browser_source.py msgid "Filter" msgstr "Фильтр" #: ../radio_browser_source.py msgid "Genre" msgstr "Стиль" #: ../radio_browser_source.py msgid "Homepage" msgstr "Домашняя страница" #: ../board_handler.py msgid "Homepage URL" msgstr "Адрес домашней страницы" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "Адрес домашней страницы должен начинаться с http://" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "Вставка ленты %(name)s (%(itemcount)d элементов) в дерево…" #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "Навигатор интернет-радиостанций" #: ../radio_browser_source.py msgid "Invalid" msgstr "Недействительный" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Язык" #: ../radio_browser_source.py msgid "Last update" msgstr "Последнее обновление" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "Загрузка %(url)s" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "Загрузка ленты %(name)s" #: ../board_handler.py msgid "Mark station as broken" msgstr "Пометить станцию как неработающую" #: ../board_handler.py msgid "My Station" msgstr "Моя станция" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Название" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Имя и адрес обязательны" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Отрицательные отзывы" #: ../radio_browser_source.py msgid "No local copy" msgstr "Не скачивался" #: ../radio_browser_source.py msgid "Nothing" msgstr "Ничего" #: ../radio_browser_source.py msgid "Play" msgstr "Воспроизвести" #: ../record_process.py msgid "Playing time" msgstr "Время воспроизведения" #: ../board_handler.py msgid "Post new station" msgstr "Добавить новую станцию" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Настройки Радио Навигатора" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "Радиостанции" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Список радиостанций" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Недавно звучавшие" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "Удалять из недавно звучавших через (сутки)" #: ../radio_browser_source.py msgid "Record" msgstr "Записать" #: ../radio_browser_source.py msgid "Redownload" msgstr "Скачать заново" #: ../record_process.py msgid "Relay port" msgstr "Порт" #: ../record_process.py msgid "Ripping stream" msgstr "Захват потока" #: ../record_process.py msgid "Server" msgstr "Сервер" #: ../radio_browser_source.py msgid "Server type" msgstr "Тип" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "Показывать icecast и shoutcast радиостанции…" #: ../radio_browser_source.py msgid "Source feed" msgstr "Источник" #: ../board_handler.py msgid "Station is broken" msgstr "Станция не работает" #: ../board_handler.py msgid "Station successfully posted" msgstr "Станция успешно добавлена" #: ../record_process.py msgid "Stream" msgstr "Поток" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "Адрес потока" #: ../radio-browser.py msgid "Streamripper output path" msgstr "Путь к выходному файлу streamripper'а" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Тэги" #: ../record_process.py msgid "Time" msgstr "Время" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Название" #: ../radio_browser_source.py msgid "Try" msgstr "Попытка" #: ../radio-browser.py msgid "Trys to download file" msgstr "Число попыток скачивания файла" #: ../board_handler.py msgid "URL" msgstr "Адрес" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "Адрес должен начинаться с http:// или mms://" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Удалить закладку" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Обновить список радиостанций" #: ../board_handler.py msgid "Utopia" msgstr "Utopia" #: ../board_handler.py msgid "Vote for station" msgstr "Проголосовать за станцию" #: ../radio_browser_source.py msgid "Votes" msgstr "Отзывы" #: ../radio_browser_source.py msgid "downloading station information" msgstr "скачивание информации о станции" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "http://listen.to.my/station.pls" #: ../board_handler.py msgid "http://very.cool.site" msgstr "http://very.cool.site" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr "http://very.cool.site/favicon.ico" rhythmbox-radio-browser-2.3.1/po/bg.po0000644000175000017500000002414711470615004017216 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-09-11 16:29:52 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: Bulgarian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Битрейт" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "Постави в Отметки" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Отметки" #: ../radio-browser.py msgid "Browser" msgstr "Браузър" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "По битрейт" #: ../radio_browser_source.py msgid "By Country" msgstr "По Държава" #: ../radio_browser_source.py msgid "By Genres" msgstr "По Стилове" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "По тип на стрийма" #: ../board_handler.py msgid "Classical Jazz Talk" msgstr "Класически Джаз разговор" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Изчистване на кеш на иконите" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "Не може да се свали хранилището. Моля опитайте по-късно" #: ../radio_browser_source.py msgid "Could not download station information" msgstr "Не може да се свали информация за станцията" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "" #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "Държава" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Текущи слушатели" #: ../record_process.py msgid "Current song" msgstr "Текуща песен" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Текуща песен (при последното опресняване)" #: ../radio_browser_source.py msgid "Description" msgstr "Описание" #: ../board_handler.py msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://segler.bplaced.net/" msgstr "" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "" #: ../radio_browser_source.py msgid "Download" msgstr "Свали" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "Тип на вписването" #: ../board_handler.py msgid "Esperanto" msgstr "Есперанто" #: ../board_handler.py msgid "Examples" msgstr "Примери" #: ../board_handler.py msgid "Favicon URL" msgstr "Favicon URL адрес" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "Адреса на Favicon трябва да започва с http://" #: ../radio_browser_source.py msgid "Feed" msgstr "Хранилище" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Свалянето на хранилището се провали" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Страница на хранилището" #: ../radio_browser_source.py msgid "Feed source" msgstr "Хранилище на източника" #: ../record_process.py msgid "Filesize" msgstr "Размер на файла" #: ../radio_browser_source.py msgid "Filter" msgstr "Филтър" #: ../radio_browser_source.py msgid "Genre" msgstr "Стил" #: ../radio_browser_source.py msgid "Homepage" msgstr "Официален сайт" #: ../board_handler.py msgid "Homepage URL" msgstr "Адрес на домашната страница" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "URL на домашната страница трябва да започва със http:// or mms://" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "" #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "" #: ../radio_browser_source.py msgid "Invalid" msgstr "" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Език" #: ../radio_browser_source.py msgid "Last update" msgstr "Последено обновяване" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "" #: ../board_handler.py msgid "Mark station as broken" msgstr "Маркирай станцията като повредена" #: ../board_handler.py msgid "My Station" msgstr "Моята станция" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Име" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Нужни са име и URL адрес" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Негативни гласове" #: ../radio_browser_source.py msgid "No local copy" msgstr "Няма локално копие" #: ../radio_browser_source.py msgid "Nothing" msgstr "Нищо" #: ../radio_browser_source.py msgid "Play" msgstr "Възпроизвеждане" #: ../record_process.py msgid "Playing time" msgstr "Продължителност на свирене" #: ../board_handler.py msgid "Post new station" msgstr "Пусни нова станция" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Настройка на радио браузъра" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "Радио браузър" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Списък с радиостанции" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Наскоро слушани" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "До премахването на скоро слушаните остават (дни)" #: ../radio_browser_source.py msgid "Record" msgstr "Запис" #: ../radio_browser_source.py msgid "Redownload" msgstr "Свали отново" #: ../record_process.py msgid "Relay port" msgstr "Сменяне на порта" #: ../record_process.py msgid "Ripping stream" msgstr "Декодиране на потока" #: ../record_process.py msgid "Server" msgstr "Сървър" #: ../radio_browser_source.py msgid "Server type" msgstr "Тип на сървъра" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "" #: ../radio_browser_source.py msgid "Source feed" msgstr "Източник на хранилището" #: ../board_handler.py msgid "Station is broken" msgstr "Станцията е повредена" #: ../board_handler.py msgid "Station successfully posted" msgstr "Станцияте е публикувана успешно" #: ../record_process.py msgid "Stream" msgstr "Поток" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "URL на стрийма" #: ../radio-browser.py msgid "Streamripper output path" msgstr "Изходен път на Стриймрипър" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Етикет" #: ../record_process.py msgid "Time" msgstr "Време" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Заглавие" #: ../radio_browser_source.py msgid "Try" msgstr "Опитай" #: ../radio-browser.py msgid "Trys to download file" msgstr "Опитва се да свали файл" #: ../board_handler.py msgid "URL" msgstr "URL адрес" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "URL адреса трябва да започва със http:// or mms://" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Премахни от Отметки" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Обновяване на радио листата" #: ../board_handler.py msgid "Utopia" msgstr "Утопия" #: ../board_handler.py msgid "Vote for station" msgstr "Гласувай за станция" #: ../radio_browser_source.py msgid "Votes" msgstr "Брой гласове" #: ../radio_browser_source.py msgid "downloading station information" msgstr "Сваляне на информация за станцията" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "http://listen.to.my/station.pls" #: ../board_handler.py msgid "http://very.cool.site" msgstr "http://very.cool.site" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr "http://very.cool.site/favicon.ico" rhythmbox-radio-browser-2.3.1/po/es.po0000644000175000017500000002345711470615004017240 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-09-12 12:30:32 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: Spanish; Castilian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Tasa de bits" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "Añadir a marcadores" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Marcadores" #: ../radio-browser.py msgid "Browser" msgstr "Navegador" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "Por Tasa de bits" #: ../radio_browser_source.py msgid "By Country" msgstr "Por País" #: ../radio_browser_source.py msgid "By Genres" msgstr "Por Géneros" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "" msgid "Classical Jazz Talk" msgstr "Charla de Jazz Clásico" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Purgar caché de iconos" #: ../radio_browser_source.py msgid "Click statistics (Last 30 days)" msgstr "" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "La subscripción no pudo ser descargada. Por favor intente de nuevo más tarde." #: ../radio_browser_source.py msgid "Could not download station information" msgstr "No se pudo descargar la información de la estación" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "No se pudo descargar la información de la estación desde el servidor de shoutcast. Por favor inténtelo más tarde." #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "Pais" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Número de oyentes" #: ../record_process.py msgid "Current song" msgstr "Canción actual" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Canción actual" #: ../radio_browser_source.py msgid "Description" msgstr "Descripción" msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://segler.bplaced.net/" msgstr "¿Está seguro de que desea marcar esta estación como inválida? Sólo será borrada si suficientes personas hacen lo mismo. Más información al respecto en la página del feed. http://segler.bplaced.net" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "Realmente desea votar por esta estación? Esto significa que es de su agrado, desea que más gente la conozca y que es una estación recomendable." #: ../radio_browser_source.py msgid "Download" msgstr "Descargar" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "" #: ../board_handler.py msgid "Esperanto" msgstr "Esperanto" #: ../board_handler.py msgid "Examples" msgstr "Ejemplos" #: ../board_handler.py msgid "Favicon URL" msgstr "Dirección web del favicon" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "Dirección web del favicon debe comenzar con http://" #: ../radio_browser_source.py #: ../radio_browser_source.py msgid "Favourites" msgstr "" #: ../radio_browser_source.py msgid "Feed" msgstr "Subscripción" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Descarga de la subscripción falló" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Página principal de la subscripción" #: ../radio_browser_source.py msgid "Feed source" msgstr "Origen de la subscripción" #: ../record_process.py msgid "Filesize" msgstr "Tamaño de fichero" #: ../radio_browser_source.py msgid "Filter" msgstr "Filtro" #: ../radio_browser_source.py msgid "Genre" msgstr "Género" #: ../radio_browser_source.py msgid "Homepage" msgstr "Página principal" #: ../board_handler.py msgid "Homepage URL" msgstr "Dirección web de la página principal" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "Dirección web de la página principal debe comenzar con http://" #: ../radio_browser_source.py msgid "Info box" msgstr "" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "" #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "Explorador de estaciones de radio" #: ../radio_browser_source.py msgid "Invalid" msgstr "Inválido" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Idioma" #: ../radio_browser_source.py msgid "Last update" msgstr "Última actualización" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "" #: ../board_handler.py msgid "Mark station as broken" msgstr "Marcar estación como inválida" #: ../board_handler.py msgid "My Station" msgstr "Mi estación" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Nombre" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Nombre y dirección web son necesarios" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Votos negativos" #: ../radio_browser_source.py msgid "No local copy" msgstr "Copia no disponible" #: ../radio_browser_source.py msgid "Nothing" msgstr "Nada" #: ../radio_browser_source.py msgid "Play" msgstr "Reproducir" #: ../record_process.py msgid "Playing time" msgstr "Tiempo de reproducción" #: ../board_handler.py msgid "Post new station" msgstr "Enviar nueva estación" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Configuración del explorador de estaciones" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "Explorador de estaciones" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Lista de estaciones" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Escuchadas recientemente" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "Días que permanecerán las estaciones recientemente reproducidas" #: ../radio_browser_source.py msgid "Record" msgstr "Grabar" #: ../radio_browser_source.py msgid "Redownload" msgstr "Descargar de nuevo" #: ../record_process.py msgid "Relay port" msgstr "" msgid "Ripping stream" msgstr "Hacer rip desde fuente stream" #: ../record_process.py msgid "Server" msgstr "Servidor" #: ../radio_browser_source.py msgid "Server type" msgstr "Tipo de servidor" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "Muestra estaciones de radio Icecast y Shoutcast" #: ../radio_browser_source.py msgid "Source feed" msgstr "Subscripción de origen" #: ../board_handler.py msgid "Station is broken" msgstr "Estación es inválida" #: ../board_handler.py msgid "Station successfully posted" msgstr "Estación exitosamente enviada" #: ../record_process.py msgid "Stream" msgstr "" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "" #: ../radio-browser.py msgid "Streamripper output path" msgstr "" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Etiquetas" #: ../record_process.py msgid "Time" msgstr "Hora" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Título" #: ../radio_browser_source.py msgid "Try" msgstr "Intento" #: ../radio-browser.py msgid "Trys to download file" msgstr "Número de intentos para descargar archivo" #: ../board_handler.py msgid "URL" msgstr "Dirección web" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "Dirección web debe comenzar con http:// o mms://" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Quitar de marcadores" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Actualizar lista de estaciones" #: ../board_handler.py msgid "Utopia" msgstr "Utopia" #: ../board_handler.py msgid "Vote for station" msgstr "Votar por estaciones" #: ../radio_browser_source.py msgid "Votes" msgstr "Votos" #: ../radio_browser_source.py msgid "downloading station information" msgstr "Descargando información de la estación" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "http://escucha.mi/estación.pls" #: ../board_handler.py msgid "http://very.cool.site" msgstr "http://sitio.muy.interesante" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr "http://sitio.muy.interesante/favicon.ico"rhythmbox-radio-browser-2.3.1/po/de.po0000644000175000017500000002336311470615004017215 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-09-12 12:30:32 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: German\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "Hinzugefügt zu 'Kürzlich gehört' am" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Bitrate" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "Lesezeichen setzen" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Lesezeichen" #: ../radio-browser.py msgid "Browser" msgstr "Browser" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "Nach Bitrate" #: ../radio_browser_source.py msgid "By Country" msgstr "Nach Ländern" #: ../radio_browser_source.py msgid "By Genres" msgstr "Nach Genre" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "Nach Streamtyp" #: ../board_handler.py msgid "Classical Jazz Talk" msgstr "Klassik Jazz Sprache" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Lösche Icon Zwischenspeicher" msgid "Click statistics (Last 30 days)" msgstr "Klickstatistik (Letzten 30 Tage)" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "Konnte Quelle nicht herunterladen. Bitte versuchen sie es später noch einmal" #: ../radio_browser_source.py msgid "Could not download station information" msgstr "Stationsinformationen konnten nicht heruntergeladen werden" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "Konnte Senderinformationen nicht vom Shoutcast Verzeichnisserver herunterladen. Bitte versuchen sie es später noch einmal." #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "Land" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Aktuelle Zuhörer" #: ../record_process.py msgid "Current song" msgstr "Aktueller Song" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Aktueller Song (beim letzten Update)" #: ../radio_browser_source.py msgid "Description" msgstr "Beschreibung" #: ../board_handler.py msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://segler.bplaced.net/" msgstr "Wollen sie diesen Sender wirklich als 'nicht benutzbar' markieren? Er wird möglicherweise gelöscht, wenn genug leute dies tun! Mehr Informationen dazu finden sie auf der Homepage:\nhttp://segler.bplaced.net/" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "Wollen sie wirklich für diesen Sender abstimmen? Das bedeutet, das sie ihn mögen und den Leuten mitteilen möchten, dass es sich um einen guten Sender handelt" #: ../radio_browser_source.py msgid "Download" msgstr "Download" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "Lade %(name)s von %(url)s. %(try)d/%(trys)d" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "Typ des Eintrags" #: ../board_handler.py msgid "Esperanto" msgstr "Esperanto" #: ../board_handler.py msgid "Examples" msgstr "Beispiele" #: ../board_handler.py msgid "Favicon URL" msgstr "Favicon URL" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "Favicon URL muss mit http:// beginnen" msgid "Favourites" msgstr "Favouriten" #: ../radio_browser_source.py msgid "Feed" msgstr "Quelle" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Quellendownload fehlgeschlagen" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Homepage der Quelle" #: ../radio_browser_source.py msgid "Feed source" msgstr "Quellenadresse" #: ../record_process.py msgid "Filesize" msgstr "Dateigröße" #: ../radio_browser_source.py msgid "Filter" msgstr "Filter" #: ../radio_browser_source.py msgid "Genre" msgstr "Genre" #: ../radio_browser_source.py msgid "Homepage" msgstr "Homepage" #: ../board_handler.py msgid "Homepage URL" msgstr "Homepage URL" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "Homepage URL muss mit http:// beginnen" msgid "Info box" msgstr "Infobox" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "Integriere Quelle %(name)s (%(itemcount)d Elemente) in den Baum..." #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "Internetradio Verzeichnis" #: ../radio_browser_source.py msgid "Invalid" msgstr "ungültig" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Sprache" #: ../radio_browser_source.py msgid "Last update" msgstr "Letztes Update" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "Lade %(url)s" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "Lade Quelle %(name)s" #: ../board_handler.py msgid "Mark station as broken" msgstr "Markiere Station als nicht benutzbar" #: ../board_handler.py msgid "My Station" msgstr "Meine Station" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Name" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Name und URL werden benötigt" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Negative Stimmen" #: ../radio_browser_source.py msgid "No local copy" msgstr "Keine lokale Kopie" #: ../radio_browser_source.py msgid "Nothing" msgstr "Nichts" #: ../radio_browser_source.py msgid "Play" msgstr "Abspielen" #: ../record_process.py msgid "Playing time" msgstr "Spielzeit" #: ../board_handler.py msgid "Post new station" msgstr "Veröffentliche neue Station" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Radio Browser Einstellungen" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "Radio browser" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Liste der Radiostationen" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Kürzlich gehört" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "Löschzeit von 'Zuletzt gehört' (in Tagen)" #: ../radio_browser_source.py msgid "Record" msgstr "Aufnehmen" #: ../radio_browser_source.py msgid "Redownload" msgstr "Neudownload" #: ../record_process.py msgid "Relay port" msgstr "Horcht auf Port" #: ../record_process.py msgid "Ripping stream" msgstr "Speichere Stream" #: ../record_process.py msgid "Server" msgstr "Server" #: ../radio_browser_source.py msgid "Server type" msgstr "Server Typ" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "Zeigt Icecast und Shoutcast Radiostationen auf einem Tab an." #: ../radio_browser_source.py msgid "Source feed" msgstr "Quelle" #: ../board_handler.py msgid "Station is broken" msgstr "Station ist nicht benutzbar" #: ../board_handler.py msgid "Station successfully posted" msgstr "Station wurde erfolgreich veröffentlicht" #: ../record_process.py msgid "Stream" msgstr "Stream" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "Stream URL" #: ../radio-browser.py msgid "Streamripper output path" msgstr "Ausgabeverzeichnis von Streamripper" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Markierungen" #: ../record_process.py msgid "Time" msgstr "Zeit" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Titel" #: ../radio_browser_source.py msgid "Try" msgstr "Versuch" #: ../radio-browser.py msgid "Trys to download file" msgstr "Anzahl der Downloadversuche" #: ../board_handler.py msgid "URL" msgstr "URL" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "URL muss entweder mit http:// oder mms:// beginnen" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Lesezeichen löschen" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Erneuere Radiostationsliste" #: ../board_handler.py msgid "Utopia" msgstr "Utopia" #: ../board_handler.py msgid "Vote for station" msgstr "Stimme für Station" #: ../radio_browser_source.py msgid "Votes" msgstr "Stimmen" #: ../radio_browser_source.py msgid "downloading station information" msgstr "lade Stationsinformationen herunter" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "" #: ../board_handler.py msgid "http://very.cool.site" msgstr "" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr ""rhythmbox-radio-browser-2.3.1/po/fr.po0000644000175000017500000002367611470615004017243 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-09-12 12:30:32 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: French\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "Ajouté comme récemment joué à" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Débit" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "Marquer" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Marque-pages" #: ../radio-browser.py msgid "Browser" msgstr "Navigateur" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "Par débit" #: ../radio_browser_source.py msgid "By Country" msgstr "Par pays" #: ../radio_browser_source.py msgid "By Genres" msgstr "Par genre" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "Par type de flux" #: ../board_handler.py msgid "Classical Jazz Talk" msgstr "Discussion Jazz Classique" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Vider la cache des icônes" msgid "Click statistics (Last 30 days)" msgstr "Cliquez pour voir les statistiques (30 derniers jours)" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "Ne peut télécharger le flux. Veuillez réessayer plus tard." #: ../radio_browser_source.py msgid "Could not download station information" msgstr "Ne peut télécharger les informations de la station" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "Ne peut télécharger les informations de la station depuis le serveur Shoutcast. Veuillez réessayer plus tard." #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "Pays" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Auditeurs actuels" #: ../record_process.py msgid "Current song" msgstr "Chanson actuelle" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Chanson actuelle (dernière MÀJ)" #: ../radio_browser_source.py msgid "Description" msgstr "Description" msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://segler.bplaced.net/" msgstr "Voulez-vous réellement marquer cette station comme non-fonctionnelle? Elle sera finalement supprimée si assez de personnes la reportent comme telle! Plus d'informations à cet effet sur la page d'accueil des flux: http://segler.bplaced.net/" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "Voulez-vous réellement voter pour cette station? Cela veut dire que vous l'appréciez et que vous voulez la faire connaitre à plus de monde." #: ../radio_browser_source.py msgid "Download" msgstr "Télécharger" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "Télécharge le flux %(name)s depuis %(url)s. %(try)d/%(trys)d" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "Type d'entrée" #: ../board_handler.py msgid "Esperanto" msgstr "Espéranto" #: ../board_handler.py msgid "Examples" msgstr "Exemples" #: ../board_handler.py msgid "Favicon URL" msgstr "URL de la favicon" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "L'URL de la favicon doit débuter par http://" msgid "Favourites" msgstr "Favoris" #: ../radio_browser_source.py msgid "Feed" msgstr "Flux" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Téléchargement du flux échoué" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Page d'accueil du flux" #: ../radio_browser_source.py msgid "Feed source" msgstr "Source du flux" #: ../record_process.py msgid "Filesize" msgstr "Taille du fichier" #: ../radio_browser_source.py msgid "Filter" msgstr "Filtre" #: ../radio_browser_source.py msgid "Genre" msgstr "Genre" #: ../radio_browser_source.py msgid "Homepage" msgstr "Page d'accueil" #: ../board_handler.py msgid "Homepage URL" msgstr "URL de la page d'accueil" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "L'URL de la page d'accueil doit débuter par http://" msgid "Info box" msgstr "Boîte d'information" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "Intègre le flux %(name)s (%(itemcount)d éléments) dans l'arbre" #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "Navigateur de webradios" #: ../radio_browser_source.py msgid "Invalid" msgstr "Invalide" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Langue" #: ../radio_browser_source.py msgid "Last update" msgstr "Dernière mise-à-jour" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "Charge %(url)s" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "Charge le flux %(name)s" #: ../board_handler.py msgid "Mark station as broken" msgstr "Marquer cette station comme non-fonctionnelle" #: ../board_handler.py msgid "My Station" msgstr "Ma station" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Nom" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Le nom et l'URL sont nécessaires" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Votes négatifs" #: ../radio_browser_source.py msgid "No local copy" msgstr "Pas de copie locale" #: ../radio_browser_source.py msgid "Nothing" msgstr "Aucune action" #: ../radio_browser_source.py msgid "Play" msgstr "Lecture" #: ../record_process.py msgid "Playing time" msgstr "Temps de lecture" #: ../board_handler.py msgid "Post new station" msgstr "Publier nouvelle station" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Configuration du navigateur radio" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "Navigateur radio" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Liste des stations radio" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Récemment écouté" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "Jours avant suppression des fichiers récemment écoutés" #: ../radio_browser_source.py msgid "Record" msgstr "Enregistrement" #: ../radio_browser_source.py msgid "Redownload" msgstr "Télécharger de nouveau" #: ../record_process.py msgid "Relay port" msgstr "Port de relais" #: ../record_process.py msgid "Ripping stream" msgstr "Extraction du flux" #: ../record_process.py msgid "Server" msgstr "Serveur" #: ../radio_browser_source.py msgid "Server type" msgstr "Type de serveur" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "Montrer les webradios Icecast et Shoutcast dans un onglet" #: ../radio_browser_source.py msgid "Source feed" msgstr "Alimentation du flux" #: ../board_handler.py msgid "Station is broken" msgstr "Station non fonctionnelle" #: ../board_handler.py msgid "Station successfully posted" msgstr "Station publiée avec succès" #: ../record_process.py msgid "Stream" msgstr "Flux" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "URL du flux" #: ../radio-browser.py msgid "Streamripper output path" msgstr "Répertoire d'extraction Streamripper" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Balise" #: ../record_process.py msgid "Time" msgstr "Durée" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Titre" #: ../radio_browser_source.py msgid "Try" msgstr "Essai" msgid "Trys to download file" msgstr "Essais de téléchargement du fichier" #: ../board_handler.py msgid "URL" msgstr "URL" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "L'URL doit débuter par http:// ou mms://" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Enlever le marquage" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Mise-à-jour de la liste des stations" #: ../board_handler.py msgid "Utopia" msgstr "Utopia" #: ../board_handler.py msgid "Vote for station" msgstr "Voter pour cette station" #: ../radio_browser_source.py msgid "Votes" msgstr "Votes" #: ../radio_browser_source.py msgid "downloading station information" msgstr "téléchargement des informations de la station" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "http://ecoutez.ma/station.pls" #: ../board_handler.py msgid "http://very.cool.site" msgstr "http://site.tres.sympa" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr "http://site.tres.sympa/favicon.ico"rhythmbox-radio-browser-2.3.1/po/package.pot0000644000175000017500000001770411470615004020406 0ustar seglersegler# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-11-17 00:40+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: ../board_handler.py:67 ../board_handler.py:113 ../board_handler.py:230 msgid "Post new station" msgstr "" #: ../board_handler.py:74 msgid "Examples" msgstr "" #: ../board_handler.py:76 ../radio_browser_source.py:657 msgid "Name" msgstr "" #: ../board_handler.py:79 msgid "My Station" msgstr "" #: ../board_handler.py:81 msgid "URL" msgstr "" #: ../board_handler.py:84 msgid "http://listen.to.my/station.pls" msgstr "" #: ../board_handler.py:86 msgid "Homepage URL" msgstr "" #: ../board_handler.py:89 msgid "http://very.cool.site" msgstr "" #: ../board_handler.py:91 msgid "Favicon URL" msgstr "" #: ../board_handler.py:94 msgid "http://very.cool.site/favicon.ico" msgstr "" #: ../board_handler.py:96 ../radio_browser_source.py:665 msgid "Country" msgstr "" #: ../board_handler.py:99 msgid "Utopia" msgstr "" #: ../board_handler.py:101 ../radio_browser_source.py:664 msgid "Language" msgstr "" #: ../board_handler.py:104 msgid "Esperanto" msgstr "" #: ../board_handler.py:106 ../radio_browser_source.py:658 msgid "Tags" msgstr "" #: ../board_handler.py:109 msgid "Classical Jazz Talk" msgstr "" #: ../board_handler.py:142 ../board_handler.py:235 msgid "Vote for station" msgstr "" #: ../board_handler.py:143 msgid "" "Do you really want to vote for this station? It means, that you like it, and " "you want more people to know, that this is a good station." msgstr "" #: ../board_handler.py:154 msgid "Mark station as broken" msgstr "" #: ../board_handler.py:155 msgid "" "Do you really want to mark this radio station as broken? It will eventually " "get deleted if enough people do that! More information on that on the feeds " "homepage: http://www.radio-browser.info/" msgstr "" #: ../board_handler.py:201 msgid "Name and URL are necessary" msgstr "" #: ../board_handler.py:205 msgid "URL needs to start with http:// or mms://" msgstr "" #: ../board_handler.py:210 msgid "Homepage URL needs to start with http://" msgstr "" #: ../board_handler.py:215 msgid "Favicon URL needs to start with http://" msgstr "" #: ../board_handler.py:222 msgid "Station successfully posted" msgstr "" #: ../board_handler.py:236 msgid "Station is broken" msgstr "" #: ../radio-browser.py:42 msgid "Trys to download file" msgstr "" #: ../radio-browser.py:43 msgid "Recently played removal time(days)" msgstr "" #: ../radio-browser.py:44 msgid "Streamripper output path" msgstr "" #: ../radio-browser.py:63 msgid "Browser" msgstr "" #: ../radio-browser.py:69 msgid "Radio Browser Configuration" msgstr "" #: ../radio-browser.py:121 msgid "Radio browser" msgstr "" #. add "update-all" action to the toolbar #: ../radio-browser.py:136 msgid "Update radio station list" msgstr "" #: ../radio-browser.py:140 msgid "Clear icon cache" msgstr "" #: ../radio_browser_source.py:83 msgid "Nothing" msgstr "" #: ../radio_browser_source.py:88 #, python-format msgid "Loading %(url)s" msgstr "" #. create the view #. "Title",gtk.CellRendererText(),text=0) #: ../radio_browser_source.py:146 ../radio_browser_source.py:235 #: ../record_process.py:86 msgid "Title" msgstr "" #: ../radio_browser_source.py:203 msgid "Filter" msgstr "" #: ../radio_browser_source.py:205 msgid "Genre" msgstr "" #: ../radio_browser_source.py:207 ../radio_browser_source.py:659 #: ../record_process.py:165 msgid "Bitrate" msgstr "" #: ../radio_browser_source.py:220 ../radio_browser_source.py:248 msgid "Search" msgstr "" #: ../radio_browser_source.py:247 ../radio_browser_source.py:510 msgid "Favourites" msgstr "" #: ../radio_browser_source.py:249 msgid "Radiostation list" msgstr "" #: ../radio_browser_source.py:287 #, python-format msgid "Searching for : '%s'" msgstr "" #: ../radio_browser_source.py:443 msgid "Click statistics (Last 30 days)" msgstr "" #. add recently played list #: ../radio_browser_source.py:455 ../radio_browser_source.py:1305 msgid "Recently played" msgstr "" #: ../radio_browser_source.py:641 msgid "Entry type" msgstr "" #: ../radio_browser_source.py:641 msgid "Feed" msgstr "" #: ../radio_browser_source.py:643 msgid "Description" msgstr "" #: ../radio_browser_source.py:644 msgid "Feed homepage" msgstr "" #: ../radio_browser_source.py:645 msgid "Feed source" msgstr "" #: ../radio_browser_source.py:651 msgid "No local copy" msgstr "" #: ../radio_browser_source.py:652 msgid "Last update" msgstr "" #: ../radio_browser_source.py:656 msgid "Source feed" msgstr "" #: ../radio_browser_source.py:660 msgid "Server type" msgstr "" #: ../radio_browser_source.py:661 msgid "Homepage" msgstr "" #: ../radio_browser_source.py:662 msgid "Current song (on last refresh)" msgstr "" #: ../radio_browser_source.py:663 msgid "Current listeners" msgstr "" #: ../radio_browser_source.py:666 msgid "Votes" msgstr "" #: ../radio_browser_source.py:667 msgid "Negative votes" msgstr "" #: ../radio_browser_source.py:668 msgid "Stream URL" msgstr "" #: ../radio_browser_source.py:671 msgid "Added to recently played at" msgstr "" #: ../radio_browser_source.py:687 ../radio_browser_source.py:756 msgid "Unbookmark" msgstr "" #: ../radio_browser_source.py:701 ../radio_browser_source.py:754 msgid "Bookmark" msgstr "" #: ../radio_browser_source.py:721 msgid "Redownload" msgstr "" #: ../radio_browser_source.py:724 msgid "Download" msgstr "" #: ../radio_browser_source.py:734 msgid "Play" msgstr "" #: ../radio_browser_source.py:746 msgid "Record" msgstr "" #: ../radio_browser_source.py:771 msgid "Info box" msgstr "" #: ../radio_browser_source.py:987 msgid "downloading station information" msgstr "" #: ../radio_browser_source.py:987 msgid "Try" msgstr "" #: ../radio_browser_source.py:999 msgid "Could not download station information" msgstr "" #: ../radio_browser_source.py:1000 msgid "" "Could not download station information from shoutcast directory server. " "Please try again later." msgstr "" #: ../radio_browser_source.py:1098 #, python-format msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "" #: ../radio_browser_source.py:1111 msgid "Feed download failed" msgstr "" #: ../radio_browser_source.py:1112 msgid "Could not download feed. Please try again later." msgstr "" #: ../radio_browser_source.py:1171 #, python-format msgid "Loading feed %(name)s" msgstr "" #: ../radio_browser_source.py:1190 #, python-format msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "" #: ../radio_browser_source.py:1217 msgid "By Genres" msgstr "" #: ../radio_browser_source.py:1218 msgid "By Country" msgstr "" #: ../radio_browser_source.py:1219 msgid "By Streamtype" msgstr "" #: ../radio_browser_source.py:1220 msgid "By Bitrate" msgstr "" #: ../radio_browser_source.py:1253 msgid "Invalid" msgstr "" #. add bookmarks #: ../radio_browser_source.py:1317 msgid "Bookmarks" msgstr "" #: ../radio_station.py:55 msgid "Select stream URL please" msgstr "" #: ../radio_station.py:58 msgid "Url" msgstr "" #: ../record_process.py:67 msgid "Ripping stream" msgstr "" #: ../record_process.py:82 msgid "Time" msgstr "" #: ../record_process.py:91 ../record_process.py:164 msgid "Filesize" msgstr "" #: ../record_process.py:159 msgid "Server" msgstr "" #: ../record_process.py:160 msgid "Stream" msgstr "" #: ../record_process.py:161 msgid "Current song" msgstr "" #: ../record_process.py:163 msgid "Playing time" msgstr "" #: ../record_process.py:166 msgid "Relay port" msgstr "" #: ../radio-browser.rb-plugin.in.h:1 msgid "Internet radio station browser" msgstr "" #: ../radio-browser.rb-plugin.in.h:2 msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "" rhythmbox-radio-browser-2.3.1/po/el.po0000600000175000017500000002763711470615004017225 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-11-16 20:08:09 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: Greek\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "Προστέθηκε στα πρόσφατα αναπαραχθέντα την" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Bitrate" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "Σελιδοδείκτης" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Σελιδοδείκτες" #: ../radio-browser.py msgid "Browser" msgstr "Περιηγητής" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "Κατά Bitrate" #: ../radio_browser_source.py msgid "By Country" msgstr "Κατά Χώρα" #: ../radio_browser_source.py msgid "By Genres" msgstr "Κατά Τεχνοτροπία" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "Κατά Τύπο Ροής" #: ../board_handler.py msgid "Classical Jazz Talk" msgstr "Κλασσική Jazz Ομιλία" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Άδειασμα της προσωρινής μνήμης εικονιδίων" #: ../radio_browser_source.py msgid "Click statistics (Last 30 days)" msgstr "Στατιστικά (Τελευταίες 30 μέρες)" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "Δεν μπορώ να κατεβάσω τη τροφοδοσία. Παρακαλώ προσπαθείστε αργότερα." #: ../radio_browser_source.py msgid "Could not download station information" msgstr "Δεν μπόρεσα να κατεβάσω πληροφορίες για το σταθμό" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "Δεν μπορώ να κατεβάσω τις πληροφορίες για το σταθμό από τον εξυπηρετητή shoutcast. Παρακαλώ δοκιμάστε αργότερα" #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "Χώρα" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Ποιοι ακούν τώρα" #: ../record_process.py msgid "Current song" msgstr "Τρέχον τραγούδι" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Τρέχον τραγούδι (μετά από την τελευταία ανανέωση)" #: ../radio_browser_source.py msgid "Description" msgstr "Περιγραφή" #: ../board_handler.py msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://www.radio-browser.info/" msgstr "Θέλετε πραγματικά να σημειώσετε αυτόν το σταθμό; Θα διαγραφεί αν αρκετοί χρήστες κάνουν αυτή την ενέργεια! Περισσότερες πληροφορίες γι' αυτό στην ιστοσελίδα: http://segler.bplaced.net/" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "Θέλετε πραγματικά να ψηφίσετε αυτόν το Σταθμό; Αυτό σημαίνει ότ σας αρέσει και θέλετε να ξέρουν περισσότεροι άνθρωποι, ότι είναι καλός." #: ../radio_browser_source.py msgid "Download" msgstr "Κατέβασμα" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "Κατέβασμα τροφοδοσίας %(name)s από %(url)s. %(try)d/%(trys)d" #: ../radio_browser_source.py msgid "downloading station information" msgstr "Κατέβασμα πληροφοριών σταθμού" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "Τύπος Εισόδου" #: ../board_handler.py msgid "Esperanto" msgstr "Εσπεράντο" #: ../board_handler.py msgid "Examples" msgstr "Παραδείγματα" #: ../board_handler.py msgid "Favicon URL" msgstr "URL Εικονιδίου" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "Το URL του εικονιδίου πρέπει να αρχίζει με http://" #: ../radio_browser_source.py #: ../radio_browser_source.py msgid "Favourites" msgstr "Αγαπημένα" #: ../radio_browser_source.py msgid "Feed" msgstr "Τροφοδοσία" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Το κατέβασμα τροφοδοσίας απέτυχε" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Ιστοσελίδα τροφοδοσίας" #: ../radio_browser_source.py msgid "Feed source" msgstr "Πηγή τροφοδοσίας" #: ../record_process.py msgid "Filesize" msgstr "Μέγεθος αρχείου" #: ../radio_browser_source.py msgid "Filter" msgstr "Φίλτρο" #: ../radio_browser_source.py msgid "Genre" msgstr "Τεχνοτροπία" #: ../radio_browser_source.py msgid "Homepage" msgstr "Αρχική Σελίδα" #: ../board_handler.py msgid "Homepage URL" msgstr "Αρχική Σελίδα" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "Το URL της αρχικής σελίδας πρέπει να ξεκινά με http://" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "http://listen.to.my/station.pls" #: ../board_handler.py msgid "http://very.cool.site" msgstr "http://very.cool.site" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr "http://very.cool.site/favicon.ico" #: ../radio_browser_source.py msgid "Info box" msgstr "Τμήμα Πληροφοριών" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "Ελεγχος αρτιότητας τροφοδοσίας %(name)s (%(itemcount)d αντικείμενα) στο δέντρο..." #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "Internet radio station browser" #: ../radio_browser_source.py msgid "Invalid" msgstr "Μη έγκυρο" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Γλώσσα" #: ../radio_browser_source.py msgid "Last update" msgstr "Τελευταία ενημέρωση" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "Φόρτωση %(url)s" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "Φόρτωμα ροής %(name)s" #: ../board_handler.py msgid "Mark station as broken" msgstr "Σήμανση σταθμού ως σπασμένου" #: ../board_handler.py msgid "My Station" msgstr "Ο Σταθμός μου" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Όνομα" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Όνομα και URL είναι υποχρεωτικά" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Αρνητικοί ψήφοι" #: ../radio_browser_source.py msgid "No local copy" msgstr "Όχι τοπικό αντίγραφο" #: ../radio_browser_source.py msgid "Nothing" msgstr "Τίποτα" #: ../radio_browser_source.py msgid "Play" msgstr "Αναπαραγωγή" #: ../record_process.py msgid "Playing time" msgstr "Διάρκεια" #: ../board_handler.py msgid "Post new station" msgstr "Αποστολή νέου σταθμού" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "Radio browser" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Ρύθμιση του Radio Browser" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Λίστα Ραδιοφωνικών Σταθμών" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Πρόσφατα αναπαραχθέντα" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "Χρόνος αφαίρεσης πρόσφατα αναπαραχθέντων. (ημέρες)" #: ../radio_browser_source.py msgid "Record" msgstr "Εγγραφή" #: ../radio_browser_source.py msgid "Redownload" msgstr "Επανάληψη κατεβάσματος" msgid "Relay port" msgstr "Θύρα αναμετάδοσης" #: ../record_process.py msgid "Ripping stream" msgstr "Μετατροπή ροής" #: ../radio_browser_source.py #: ../radio_browser_source.py msgid "Search" msgstr "Εύρεση" #: ../radio_browser_source.py msgid "Searching for : '%s'" msgstr "Ψάχνω για : '%s'" #: ../record_process.py msgid "Server" msgstr "Εξυπηρετητής" #: ../radio_browser_source.py msgid "Server type" msgstr "Τύπος Εξυπηρετητή" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "Εμφανίζει ραδιοφωνικούς σταθμούς, icecast και shoutcast, σε μια καρτέλα." #: ../radio_browser_source.py msgid "Source feed" msgstr "Τύπος Τροφοδοσίας" #: ../board_handler.py msgid "Station is broken" msgstr "Ο Σταθμός δεν υπάρχει" #: ../board_handler.py msgid "Station successfully posted" msgstr "Ο σταθμός καταχωρήθηκε επιτυχώς" #: ../record_process.py msgid "Stream" msgstr "Ροή" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "URL ροής" #: ../radio-browser.py msgid "Streamripper output path" msgstr "Διαδρομή εγγραφής ροής" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Σημειώσεις" #: ../record_process.py msgid "Time" msgstr "Χρόνος" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Τίτλος" #: ../radio_browser_source.py msgid "Try" msgstr "Δοκιμή" #: ../radio-browser.py msgid "Trys to download file" msgstr "Προσπάθειες για κατέβασμα αρχείου" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Αφαίρεση από τους σελιδοδείκτες" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Ενημέρωση της λίστας ραδιοφωνικών σταθμών" #: ../board_handler.py msgid "URL" msgstr "URL" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "Το URL πρέπει να ξεκινά με http:// ή mms://" #: ../board_handler.py msgid "Utopia" msgstr "Ουτοπία" #: ../board_handler.py msgid "Vote for station" msgstr "Ψηφίστε για το Σταθμό" #: ../radio_browser_source.py msgid "Votes" msgstr "Ψήφοι"rhythmbox-radio-browser-2.3.1/po/pt_BR.po0000644000175000017500000002334111470615004017627 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-09-12 12:30:32 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: Portuguese, Brazil\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "Adicionada recentemente tocada em" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Bitrate" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "Marcar" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Marcadores" #: ../radio-browser.py msgid "Browser" msgstr "Navegador" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "Por Bitrate" #: ../radio_browser_source.py msgid "By Country" msgstr "Por País" #: ../radio_browser_source.py msgid "By Genres" msgstr "Por Gêneros" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "Por Tipo de Stream" #: ../board_handler.py msgid "Classical Jazz Talk" msgstr "Classical Jazz Talk" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Limpar ícones da cache" msgid "Click statistics (Last 30 days)" msgstr "Clique para ver as estatísticas (Últimos 30 dias)" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "Incapaz de baixar o feed. Por favor tente depois." #: ../radio_browser_source.py msgid "Could not download station information" msgstr "Incapaz de baixar informação da estação" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "Incapaz de baixar informação da estação a partir deste servidor shoutcast. Por favor tente mais tarde." #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "País" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Ouvintes atuais" #: ../record_process.py msgid "Current song" msgstr "Música atual" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Música atual (da última atualização)" #: ../radio_browser_source.py msgid "Description" msgstr "Descrição" #: ../board_handler.py msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://segler.bplaced.net/" msgstr "Você realmente quer marca esta rádio como quebrada? Isso acabará deletando-a se muitas pessoas fizerem isso! Mais informações acesse: http://segler.bplaced.net/" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "Você realmente quer votar nesta estação? Isso significa que você gosta dela, e quer que as pessoas saibam que é uma boa rádio." #: ../radio_browser_source.py msgid "Download" msgstr "Baixar" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "Baixando feed %(name)s de %(url)s. %(try)d/%(trys)d" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "Tipo de entrada" #: ../board_handler.py msgid "Esperanto" msgstr "Esperanto" #: ../board_handler.py msgid "Examples" msgstr "Exemplos" #: ../board_handler.py msgid "Favicon URL" msgstr "URL do favicon" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "O URL do favicon precisa iniciar com http://" msgid "Favourites" msgstr "Favoritos" #: ../radio_browser_source.py msgid "Feed" msgstr "Feed" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Falha ao baixar o feed" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Página do Feed" #: ../radio_browser_source.py msgid "Feed source" msgstr "Caminho do Feed" #: ../record_process.py msgid "Filesize" msgstr "Tamanho" #: ../radio_browser_source.py msgid "Filter" msgstr "Filtro" #: ../radio_browser_source.py msgid "Genre" msgstr "Gênero" #: ../radio_browser_source.py msgid "Homepage" msgstr "Homepage" #: ../board_handler.py msgid "Homepage URL" msgstr "URL da Homepage" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "O URL da página precisa inciar com http://" msgid "Info box" msgstr "Caixa de informação" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "Integrando feed %(name)s (%(itemcount)d items) na árvore..." #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "Navegador de estações de rádio" #: ../radio_browser_source.py msgid "Invalid" msgstr "Inválido" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Idioma" #: ../radio_browser_source.py msgid "Last update" msgstr "Última atualização" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "Carregando %(url)s" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "Carregando feed %(name)s" #: ../board_handler.py msgid "Mark station as broken" msgstr "Marcar estação como quebrada" #: ../board_handler.py msgid "My Station" msgstr "Minha Estação" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Nome" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Nome e URL são necessários" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Votos negativos" #: ../radio_browser_source.py msgid "No local copy" msgstr "Nenhuma cópia local" #: ../radio_browser_source.py msgid "Nothing" msgstr "Nada" #: ../radio_browser_source.py msgid "Play" msgstr "Tocar" #: ../record_process.py msgid "Playing time" msgstr "Tempo de reprodução" #: ../board_handler.py msgid "Post new station" msgstr "Publicar nova estação" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Configuração do Radio Browser" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "Navegador de rádio" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Lista das estações de rádio" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Tocado recentemente" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "Apagar tempo das músicas tocadas recentemente (dias)" #: ../radio_browser_source.py msgid "Record" msgstr "Gravar" #: ../radio_browser_source.py msgid "Redownload" msgstr "Baixar denovo" #: ../record_process.py msgid "Relay port" msgstr "Porta" #: ../record_process.py msgid "Ripping stream" msgstr "Rippando stream" #: ../record_process.py msgid "Server" msgstr "Servidor" #: ../radio_browser_source.py msgid "Server type" msgstr "Tipo de áudio" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "Exibe estações de icecast e shoutcast em uma aba." #: ../radio_browser_source.py msgid "Source feed" msgstr "Fonte" #: ../board_handler.py msgid "Station is broken" msgstr "Estação quebrada" #: ../board_handler.py msgid "Station successfully posted" msgstr "Estação publicada com sucesso" #: ../record_process.py msgid "Stream" msgstr "Stream" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "URL do stream" #: ../radio-browser.py msgid "Streamripper output path" msgstr "Caminho de saída do Streamripper" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Tags" #: ../record_process.py msgid "Time" msgstr "Tempo" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Título" #: ../radio_browser_source.py msgid "Try" msgstr "Tente" #: ../radio-browser.py msgid "Trys to download file" msgstr "Tentativas para baixar arquivo" #: ../board_handler.py msgid "URL" msgstr "URL" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "O URL precisa iniciar com http:// ou mms://" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Desmarcar" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Atualizar lista de estações de rádio" #: ../board_handler.py msgid "Utopia" msgstr "Utopia" #: ../board_handler.py msgid "Vote for station" msgstr "Votar na estação" #: ../radio_browser_source.py msgid "Votes" msgstr "Votos" #: ../radio_browser_source.py msgid "downloading station information" msgstr "baixando informações da estação" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "http://escute.a.minha/radio.pls" #: ../board_handler.py msgid "http://very.cool.site" msgstr "http://site.muito.legal" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr "http://site.muito.legal/favicon.ico"rhythmbox-radio-browser-2.3.1/po/it.po0000644000175000017500000002226011470615004017234 0ustar seglerseglermsgid "" msgstr "" "Project-Id-Version: rhythmbox-radio-browser\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2010-03-29 19:18:35 UTC\n" "PO-Revision-Date: 2010-09-11 16:29:52 UTC\n" "Last-Translator: Web Translate It \n" "Language-Team: Italian\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Web Translate It\n" #: ../radio_browser_source.py msgid "Added to recently played at" msgstr "Aggiunta alle ascoltate di recente il" #: ../radio_browser_source.py #: ../record_process.py msgid "Bitrate" msgstr "Bitrate" #: ../radio_browser_source.py # Всё же это "В закладки", а то назначение кнопки не очевидно. msgid "Bookmark" msgstr "Segnalibri" #: ../radio_browser_source.py #. add bookmarks msgid "Bookmarks" msgstr "Segnalibri" #: ../radio-browser.py msgid "Browser" msgstr "" #: ../radio_browser_source.py msgid "By Bitrate" msgstr "per tipo di Bitrate" #: ../radio_browser_source.py msgid "By Country" msgstr "Per paese" #: ../radio_browser_source.py msgid "By Genres" msgstr "Per genere" #: ../radio_browser_source.py msgid "By Streamtype" msgstr "per tipo di stream" #: ../board_handler.py msgid "Classical Jazz Talk" msgstr "Classical Jazz Talk" #: ../radio-browser.py msgid "Clear icon cache" msgstr "Pulisci cache di icone" #: ../radio_browser_source.py msgid "Could not download feed. Please try again later." msgstr "Non e stato possibile di scarica il feed. Per favore riprovare più tardi" #: ../radio_browser_source.py msgid "Could not download station information" msgstr "Non e stato possibile scaricare informazioni sulla stazione radio" #: ../radio_browser_source.py msgid "Could not download station information from shoutcast directory server. Please try again later." msgstr "Non e stato possibile scaricare informazioni dalla directory shoutcast del server. Si prega di riprovare più tardi." #: ../board_handler.py #: ../radio_browser_source.py msgid "Country" msgstr "Paese" #: ../radio_browser_source.py msgid "Current listeners" msgstr "Attuali ascoltatori" #: ../record_process.py msgid "Current song" msgstr "Brano attuale" #: ../radio_browser_source.py msgid "Current song (on last refresh)" msgstr "Brano corrente" #: ../radio_browser_source.py msgid "Description" msgstr "Descrizione" #: ../board_handler.py msgid "Do you really want to mark this radio station as broken? It will eventually get deleted if enough people do that! More information on that on the feeds homepage: http://segler.bplaced.net/" msgstr "Vuoi veramente segnalare questa stazione come non funzionante? Se anche altre persone lo faranno allora eventualmente verrà eliminata! Trovi più informazioni nella homepage dei feed:\nhttp://segler.bplaced.net/" #: ../board_handler.py # "Вы" пишется с большой буквы только в официальных сообщениях и личной переписке для выделения уважительного отношения к собеседнику (весьма конкретному собеседнику). Во всех остальных случаях местоимение "вы" пишется со строчной. В данном случае написание с большой буквы не оправдано. msgid "Do you really want to vote for this station? It means, that you like it, and you want more people to know, that this is a good station." msgstr "Sei sicuro di voler votare questa stazione? Ciò significa che ti piace e vuoi che più persone sappiano che questa è una buona stazione." #: ../radio_browser_source.py msgid "Download" msgstr "Scarica" #: ../radio_browser_source.py msgid "Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d" msgstr "" #: ../radio_browser_source.py # audio/mpeg, например. msgid "Entry type" msgstr "Tipo di entrata" #: ../board_handler.py msgid "Esperanto" msgstr "Esperanto" #: ../board_handler.py msgid "Examples" msgstr "Esempi" #: ../board_handler.py msgid "Favicon URL" msgstr "Favicon URL" #: ../board_handler.py msgid "Favicon URL needs to start with http://" msgstr "La Favicon URL deve iniziare con http://" #: ../radio_browser_source.py msgid "Feed" msgstr "Feed" #: ../radio_browser_source.py msgid "Feed download failed" msgstr "Scarica feed fallito" #: ../radio_browser_source.py msgid "Feed homepage" msgstr "Feed pagina iniziale" #: ../radio_browser_source.py msgid "Feed source" msgstr "Sorgente feed" #: ../record_process.py msgid "Filesize" msgstr "Dimensione del file" #: ../radio_browser_source.py msgid "Filter" msgstr "Filtro" #: ../radio_browser_source.py msgid "Genre" msgstr "Genere" #: ../radio_browser_source.py msgid "Homepage" msgstr "Pagina iniziale" #: ../board_handler.py msgid "Homepage URL" msgstr "" #: ../board_handler.py msgid "Homepage URL needs to start with http://" msgstr "L' Homepage URL deve iniziare con http://" #: ../radio_browser_source.py msgid "Integrating feed %(name)s (%(itemcount)d items) into tree..." msgstr "" #: ../radio-browser.rb-plugin.in.h msgid "Internet radio station browser" msgstr "" #: ../radio_browser_source.py msgid "Invalid" msgstr "Non valido" #: ../board_handler.py #: ../radio_browser_source.py msgid "Language" msgstr "Lingua" #: ../radio_browser_source.py msgid "Last update" msgstr "Ultimo aggiornamento" #: ../radio_browser_source.py msgid "Loading %(url)s" msgstr "" #: ../radio_browser_source.py msgid "Loading feed %(name)s" msgstr "" #: ../board_handler.py msgid "Mark station as broken" msgstr "Segnala come non funzionante" #: ../board_handler.py msgid "My Station" msgstr "" #: ../board_handler.py #: ../radio_browser_source.py msgid "Name" msgstr "Nome" #: ../board_handler.py msgid "Name and URL are necessary" msgstr "Nome e URL sono necessari" #: ../radio_browser_source.py msgid "Negative votes" msgstr "Voti negativi" #: ../radio_browser_source.py msgid "No local copy" msgstr "Nessuna copia locale" #: ../radio_browser_source.py msgid "Nothing" msgstr "Niente" #: ../radio_browser_source.py msgid "Play" msgstr "Avvia" #: ../record_process.py msgid "Playing time" msgstr "" #: ../board_handler.py msgid "Post new station" msgstr "Pubblica una nuova stazione" #: ../radio-browser.py msgid "Radio Browser Configuration" msgstr "Configurazione di Radio Browser" #: ../radio-browser.py # Звучит как два не связанных слова. Может "Радиостанции" будет лучше? Не дословно, но хоть не разваливается на куски. msgid "Radio browser" msgstr "" #: ../radio_browser_source.py msgid "Radiostation list" msgstr "Lista delle stazioni radio" #: ../radio_browser_source.py #. add recently played list msgid "Recently played" msgstr "Ascoltate di recente" #: ../radio-browser.py msgid "Recently played removal time(days)" msgstr "" #: ../radio_browser_source.py msgid "Record" msgstr "Registra" #: ../radio_browser_source.py msgid "Redownload" msgstr "Riscarica" #: ../record_process.py msgid "Relay port" msgstr "Relay port" #: ../record_process.py msgid "Ripping stream" msgstr "sto registrando la trasmissione" #: ../record_process.py msgid "Server" msgstr "Server" #: ../radio_browser_source.py msgid "Server type" msgstr "Tipo di server" #: ../radio-browser.rb-plugin.in.h msgid "Shows icecast and shoutcast radio stations on a tab." msgstr "" #: ../radio_browser_source.py msgid "Source feed" msgstr "Sorgente Feed" #: ../board_handler.py msgid "Station is broken" msgstr "La stazione non funziona" #: ../board_handler.py msgid "Station successfully posted" msgstr "Stazione pubblicata con successo" #: ../record_process.py msgid "Stream" msgstr "Stream" #: ../radio_browser_source.py # Всё же URL-адрес понятнее, чем "путь потока". Куда он течёт? ж) msgid "Stream URL" msgstr "" #: ../radio-browser.py msgid "Streamripper output path" msgstr "" #: ../board_handler.py #: ../radio_browser_source.py msgid "Tags" msgstr "Tags" #: ../record_process.py msgid "Time" msgstr "Tempo" #: ../radio_browser_source.py #: ../record_process.py #. create the view"Title",gtk.CellRendererText(),text=0) msgid "Title" msgstr "Titolo" #: ../radio_browser_source.py msgid "Try" msgstr "" #: ../radio-browser.py msgid "Trys to download file" msgstr "Tentetivi di download del file" #: ../board_handler.py msgid "URL" msgstr "URL" #: ../board_handler.py msgid "URL needs to start with http:// or mms://" msgstr "L' URL deve iniziare con http:// o mms://" #: ../radio_browser_source.py msgid "Unbookmark" msgstr "Cancella segnalibri" #: ../radio-browser.py #. add "update-all" action to the toolbar msgid "Update radio station list" msgstr "Aggiorna la lista delle stazioni radio" #: ../board_handler.py msgid "Utopia" msgstr "Utopia" #: ../board_handler.py msgid "Vote for station" msgstr "Vota la stazione" #: ../radio_browser_source.py msgid "Votes" msgstr "Voti" #: ../radio_browser_source.py msgid "downloading station information" msgstr "Sto scaricando informazioni sulla stazione" #: ../board_handler.py msgid "http://listen.to.my/station.pls" msgstr "" #: ../board_handler.py msgid "http://very.cool.site" msgstr "" #: ../board_handler.py msgid "http://very.cool.site/favicon.ico" msgstr "" rhythmbox-radio-browser-2.3.1/po/lang.sh0000755000175000017500000000032011470615004017531 0ustar seglersegler#!/bin/sh echo "installing languages to $1" for i in *.po; do lang=`basename $i .po` echo "installing $lang" install -d $1$lang/LC_MESSAGES msgfmt -c $lang.po -o $1$lang/LC_MESSAGES/radio-browser.mo done rhythmbox-radio-browser-2.3.1/INSTALL0000644000175000017500000000047211470615004016674 0ustar seglerseglerPer User Install (Default) ========================== 1) just unpack archive (which you did, in order to get to read this :) 2) cd to it 3) ./install.sh 4) restart rhythmbox and activate plugin in options System Install ============== 1) unpack archive 2) make 3) restart rhythmbox and activate plugin in options rhythmbox-radio-browser-2.3.1/COPYING0000644000175000017500000010451311470615004016677 0ustar seglersegler GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . rhythmbox-radio-browser-2.3.1/install.sh0000755000175000017500000000023111470615004017641 0ustar seglersegler#!/bin/sh DESTDIR=~/.gnome2/rhythmbox/plugins/radio-browser install -d $DESTDIR cp *.py $DESTDIR cp *.png $DESTDIR cp radio-browser.rb-plugin $DESTDIR rhythmbox-radio-browser-2.3.1/radio-browser.png0000644000175000017500000000166311470615004021133 0ustar seglerseglerPNG  IHDRHJ%LsRGBbKGD pHYs  tIME%)#dtEXtCommentCreated with GIMPWIDATx=kAg T8.uI#CB`8R&`UTi 5QawcHaWjš(socv*qgޙ4@A~6 Lj| (* 퐘- ns / {˕/ݭgRp2Y%.((v IUHZkP(]`MY ۍIֵV6fob}FW1rظ/ ۋO]oV#q< }<こLvdO1ӐHԠaow yJ%&$>(Ev7RDXa󠬒`UtV91t^AؐL1LHFj\ 痝 {<B5k5}.p﮸mg=՗bunוzg< r62 *NFTu8<hęN0bV119\2)*#ƻ][O+HI; Pުy@ cr6ki e8Jy'Xcά9-n 7?ŭ㿿0fiaq6Xx~ jUّ5,$piYH.Ŋ>|BVHAi(ȀՍ">S;?Cx!GdCt͵u!x_0ZG4Z3񭨰i Q1 :3 a@RHf@R̖\Y((J91?IENDB`rhythmbox-radio-browser-2.3.1/radio-browser.py0000644000175000017500000001743711470615004021005 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import rb import rhythmdb import gobject import gconf import gtk import os from gettext import * from radio_browser_source import RadioBrowserSource gconf_keys = {'download_trys' : '/apps/rhythmbox/plugins/radio-browser/download_trys', 'outputpath': '/apps/rhythmbox/plugins/radio-browser/streamripper_outputpath', 'recently_played_purge_days': '/apps/rhythmbox/plugins/radio-browser/recently_played_purge_days' } class ConfigDialog (gtk.Dialog): def __init__(self,plugin): super(ConfigDialog,self).__init__() self.plugin = plugin self.add_button(gtk.STOCK_CLOSE,gtk.RESPONSE_CLOSE) table = gtk.Table(3,3) table.attach(gtk.Label(_("Trys to download file")),0,1,0,1) table.attach(gtk.Label(_("Recently played removal time(days)")),0,1,1,2) table.attach(gtk.Label(_("Streamripper output path")),0,1,2,3) self.spin_download_trys = gtk.SpinButton() self.spin_download_trys.set_adjustment(gtk.Adjustment(value=1,lower=1,upper=10,step_incr=1)) self.spin_download_trys.set_value(float(self.plugin.download_trys)) self.spin_download_trys.connect("changed",self.download_trys_changed) table.attach(self.spin_download_trys,1,2,0,1) self.spin_removaltime = gtk.SpinButton() self.spin_removaltime.set_adjustment(gtk.Adjustment(value=1,lower=1,upper=7,step_incr=1)) self.spin_removaltime.set_value(float(self.plugin.recently_played_purge_days)) self.spin_removaltime.connect("changed",self.removaltime_changed) table.attach(self.spin_removaltime,1,2,1,2) self.entry_outputpath = gtk.Entry() self.entry_outputpath.set_text(self.plugin.outputpath) self.entry_outputpath.connect("changed",self.outputpath_changed) table.attach(self.entry_outputpath,1,2,2,3) file_browser_button = gtk.Button(_("Browser")) file_browser_button.connect("clicked",self.on_file_browser) table.attach(file_browser_button,2,3,2,3) self.get_content_area().pack_start(table) self.set_title(_("Radio Browser Configuration")) self.set_resizable(False) self.set_position(gtk.WIN_POS_CENTER) self.show_all() def on_file_browser(self,button): filew = gtk.FileChooserDialog("File selection",action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_OK)) filew.set_filename(self.plugin.outputpath) if filew.run() == gtk.RESPONSE_OK: self.entry_outputpath.set_text(filew.get_filename()) filew.destroy() """ immediately change gconf values in config dialog after user changed download trys """ def download_trys_changed(self,spin): self.plugin.download_trys = str(self.spin_download_trys.get_value()) gconf.client_get_default().set_string(gconf_keys['download_trys'], self.plugin.download_trys) """ immediately change gconf values in config dialog after user changed removal days """ def removaltime_changed(self,spin): self.plugin.recently_played_purge_days = str(self.spin_removaltime.get_value()) gconf.client_get_default().set_string(gconf_keys['recently_played_purge_days'], self.plugin.recently_played_purge_days) """ immediately change gconf values in config dialog after user changed recorded music output directory """ def outputpath_changed(self,entry): self.plugin.outputpath = self.entry_outputpath.get_text() gconf.client_get_default().set_string(gconf_keys['outputpath'], self.plugin.outputpath) class RadioBrowserEntryType(rhythmdb.EntryType): def __init__(self): rhythmdb.EntryType.__init__(self, name='RadioBrowserEntryType') class RadioBrowserPlugin (rb.Plugin): def __init__(self): rb.Plugin.__init__(self) """ on plugin activation """ def activate(self, shell): # Get the translation file install('radio-browser') # register this source in rhythmbox db = shell.props.db try: entry_type = RadioBrowserEntryType() db.register_entry_type(entry_type) except NotImplementedError: entry_type = db.entry_register_type("RadioBrowserEntryType") entry_type.category = rhythmdb.ENTRY_STREAM group = rb.rb_source_group_get_by_name ("library") self.source = gobject.new (RadioBrowserSource, shell=shell, name=_("Radio browser"), entry_type=entry_type,source_group=group,plugin=self) shell.append_source(self.source, None) shell.register_entry_type_for_source(self.source, entry_type) gobject.type_register(RadioBrowserSource) # load plugin icon width, height = gtk.icon_size_lookup(gtk.ICON_SIZE_LARGE_TOOLBAR) filepath = self.find_file("radio-browser.png") if filepath: icon = gtk.gdk.pixbuf_new_from_file_at_size(filepath, width, height) self.source.set_property( "icon", icon) self.actiongroup = gtk.ActionGroup('RadioBrowserActionGroup') # add "update-all" action to the toolbar action = gtk.Action('UpdateList', None, _("Update radio station list"), gtk.STOCK_GO_DOWN) action.connect('activate', lambda a: shell.get_property("selected-source").update_button_clicked()) self.actiongroup.add_action(action) action = gtk.Action('ClearIconCache', None, _("Clear icon cache"), gtk.STOCK_CLEAR) action.connect('activate', lambda a: shell.get_property("selected-source").clear_iconcache_button_clicked()) self.actiongroup.add_action(action) uim = shell.get_ui_manager () uim.insert_action_group (self.actiongroup) uim.ensure_update() # try reading gconf entries and set default values if not readable self.download_trys = gconf.client_get_default().get_string(gconf_keys['download_trys']) if not self.download_trys: self.download_trys = "3" gconf.client_get_default().set_string(gconf_keys['download_trys'], self.download_trys) self.recently_played_purge_days = gconf.client_get_default().get_string(gconf_keys['recently_played_purge_days']) if not self.recently_played_purge_days: self.recently_played_purge_days = "3" gconf.client_get_default().set_string(gconf_keys['recently_played_purge_days'], self.recently_played_purge_days) # set the output path of recorded music to xdg standard directory for music self.outputpath = gconf.client_get_default().get_string(gconf_keys['outputpath']) if not self.outputpath: self.outputpath = os.path.expanduser("~") # try to read xdg music dir try: f = open(self.outputpath+"/.config/user-dirs.dirs","r") except IOError: print "xdg user dir file not found" else: for line in f: if line.startswith("XDG_MUSIC_DIR"): self.outputpath = os.path.expandvars(line.split("=")[1].strip().strip('"')) print self.outputpath f.close() gconf.client_get_default().set_string(gconf_keys['outputpath'], self.outputpath) """ build plugin configuration dialog """ def create_configure_dialog(self, dialog=None): if not dialog: dialog = ConfigDialog(self) dialog.connect("response",self.dialog_response) dialog.present() return dialog def dialog_response(self,dialog,response): dialog.hide() """ on plugin deactivation """ def deactivate(self, shell): uim = shell.get_ui_manager () uim.remove_action_group(self.actiongroup) self.actiongroup = None self.source.delete_thyself() self.source = None rhythmbox-radio-browser-2.3.1/radio_browser_source.py0000644000175000017500000013272311470615004022443 0ustar seglersegler# This file is part of Radio-Browser-Plugin for Rhythmbox. # # Copyright (C) 2009 # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import rb import rhythmdb import gobject import httplib import gtk import gconf import os import subprocess import threading import hashlib import urllib import webbrowser import Queue import pickle import datetime import math import urllib2 import xml.sax.saxutils from radio_station import RadioStation from record_process import RecordProcess from feed import Feed from local_handler import FeedLocal from icecast_handler import FeedIcecast from shoutcast_handler import FeedShoutcast from shoutcast_handler import ShoutcastRadioStation from board_handler import FeedBoard from board_handler import BoardHandler from radiotime_handler import FeedRadioTime from radiotime_handler import FeedRadioTimeLocal #TODO: should not be defined here, but I don't know where to get it from. HELP: much apreciated RB_METADATA_FIELD_TITLE = 0 RB_METADATA_FIELD_GENRE = 4 RB_METADATA_FIELD_BITRATE = 20 BOARD_ROOT = "http://www.radio-browser.info/" RECENTLY_USED_FILENAME = "recently2.bin" BOOKMARKS_FILENAME = "bookmarks.bin" class RadioBrowserSource(rb.StreamingSource): __gproperties__ = { 'plugin': (rb.Plugin, 'plugin', 'plugin', gobject.PARAM_WRITABLE|gobject.PARAM_CONSTRUCT_ONLY), } def __init__(self): self.hasActivated = False rb.StreamingSource.__init__(self,name="RadioBrowserPlugin") def do_set_property(self, property, value): if property.name == 'plugin': self.plugin = value """ return list of actions that should be displayed in toolbar """ def do_impl_get_ui_actions(self): return ["UpdateList","ClearIconCache"] def do_impl_get_status(self): if self.updating: progress = -1.0 if self.load_total_size > 0: progress = min (float(self.load_current_size) / self.load_total_size, 1.0) return (self.load_status,None,progress) else: return (_("Nothing"),None,2.0) def update_download_status(self,filename,current, total): self.load_current_size = current self.load_total_size = total self.load_status = _("Loading %(url)s") % {'url':filename} gtk.gdk.threads_enter() self.notify_status_changed() gtk.gdk.threads_leave() """ on source actiavation, e.g. double click on source or playing something in this source """ def do_impl_activate(self): # first time of activation -> add graphical stuff if not self.hasActivated: self.shell = self.get_property('shell') self.db = self.shell.get_property('db') self.entry_type = self.get_property('entry-type') self.hasActivated = True # add listener for stream infos sp = self.shell.get_player () #sp.connect ('playing-song-changed',self.playing_entry_changed) #sp.connect ('playing-changed',self.playing_changed) #sp.connect ('playing-song-property-changed',self.playing_song_property_changed) sp.props.player.connect("info",self.info_available) # create cache dir self.cache_dir = rb.find_user_cache_file("radio-browser") if os.path.exists(self.cache_dir) is False: os.makedirs(self.cache_dir, 0700) self.icon_cache_dir = os.path.join(self.cache_dir,"icons") if os.path.exists(self.icon_cache_dir) is False: os.makedirs(self.icon_cache_dir,0700) self.updating = False self.load_current_size = 0 self.load_total_size = 0 self.load_status = "" # create the model for the view self.filter_entry = gtk.Entry() self.filter_entry.connect("changed",self.filter_entry_changed) self.filter_entry_bitrate = gtk.SpinButton() self.filter_entry_bitrate.set_range(32,512) self.filter_entry_bitrate.set_value(64) self.filter_entry_bitrate.set_increments(32,32) self.filter_entry_bitrate.connect("changed",self.filter_entry_changed) self.filter_entry_genre = gtk.Entry() #cell = gtk.CellRendererText() #self.filter_entry_genre.pack_start(cell, True) #self.filter_entry_genre.add_attribute(cell, 'text', 0) self.filter_entry_genre.connect("changed",self.filter_entry_changed) self.tree_store = gtk.TreeStore(str,object) self.sorted_list_store = gtk.TreeModelSort(self.tree_store) #self.filtered_list_store = self.sorted_list_store.filter_new() #self.filtered_list_store.set_visible_func(self.list_store_visible_func) self.tree_view = gtk.TreeView(self.sorted_list_store) # create the view column_title = gtk.TreeViewColumn()#"Title",gtk.CellRendererText(),text=0) column_title.set_title(_("Title")) renderer = gtk.CellRendererPixbuf() column_title.pack_start(renderer, expand=False) column_title.set_cell_data_func(renderer,self.model_data_func,"image") renderer = gtk.CellRendererText() column_title.pack_start(renderer, expand=True) column_title.add_attribute(renderer, 'text', 0) column_title.set_resizable(True) column_title.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column_title.set_fixed_width(100) column_title.set_expand(True) self.tree_view.append_column(column_title) """column_genre = gtk.TreeViewColumn("Tags",gtk.CellRendererText(),text=1) column_genre.set_resizable(True) column_genre.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column_genre.set_fixed_width(100) self.tree_view.append_column(column_genre) column_bitrate = gtk.TreeViewColumn("Bitrate",gtk.CellRendererText(),text=2) column_bitrate.set_resizable(True) column_bitrate.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column_bitrate.set_fixed_width(100) self.tree_view.append_column(column_bitrate)""" self.info_box_tree = gtk.HBox() # add some more listeners for tree view... # - row double click self.tree_view.connect("row-activated",self.row_activated_handler) # - selection change self.tree_view.connect("cursor-changed",self.treeview_cursor_changed_handler,self.info_box_tree) # create icon view self.icon_view = gtk.IconView() self.icon_view.set_text_column(0) self.icon_view.set_pixbuf_column(2) self.icon_view.set_item_width(150) self.icon_view.set_selection_mode(gtk.SELECTION_SINGLE) self.icon_view.connect("item-activated", self.on_item_activated_icon_view) self.icon_view.connect("selection-changed", self.on_selection_changed_icon_view) self.tree_view_container = gtk.ScrolledWindow() self.tree_view_container.set_shadow_type(gtk.SHADOW_IN) self.tree_view_container.add(self.tree_view) self.tree_view_container.set_property("hscrollbar-policy", gtk.POLICY_AUTOMATIC) self.icon_view_container = gtk.ScrolledWindow() self.icon_view_container.set_shadow_type(gtk.SHADOW_IN) self.icon_view_container.add(self.icon_view) self.icon_view_container.set_property("hscrollbar-policy", gtk.POLICY_AUTOMATIC) self.view = gtk.HBox() self.view.pack_start(self.tree_view_container) self.view.pack_start(self.icon_view_container) filterbox = gtk.HBox() filterbox.pack_start(gtk.Label(_("Filter")+":"),False) filterbox.pack_start(self.filter_entry) filterbox.pack_start(gtk.Label(_("Genre")+":"),False) filterbox.pack_start(self.filter_entry_genre,False) filterbox.pack_start(gtk.Label(_("Bitrate")+":"),False) filterbox.pack_start(self.filter_entry_bitrate,False) self.start_box = gtk.HPaned() # prepare search tab self.info_box_search = gtk.HBox() self.search_box = gtk.VBox() self.search_entry = gtk.Entry() #self.search_entry.connect("changed",self.filter_entry_changed) def searchButtonClick(widget): self.doSearch(self.search_entry.get_text()) searchbutton = gtk.Button(_("Search")) searchbutton.connect("clicked",searchButtonClick) search_input_box = gtk.HBox() search_input_box.pack_start(self.search_entry) search_input_box.pack_start(searchbutton,False) self.result_box = gtk.TreeView() self.result_box.connect("row-activated",self.row_activated_handler) self.result_box.connect("cursor-changed",self.treeview_cursor_changed_handler,self.info_box_search) self.result_box_container = gtk.ScrolledWindow() self.result_box_container.set_shadow_type(gtk.SHADOW_IN) self.result_box_container.add(self.result_box) self.result_box_container.set_property("hscrollbar-policy", gtk.POLICY_AUTOMATIC) self.result_box.append_column(gtk.TreeViewColumn(_("Title"),gtk.CellRendererText(),text=0)) self.search_box.pack_start(search_input_box,False) self.search_box.pack_start(self.result_box_container) self.search_box.pack_start(self.info_box_search,False) stations_box = gtk.VBox() stations_box.pack_start(filterbox,False) stations_box.pack_start(self.view) stations_box.pack_start(self.info_box_tree,False) self.notebook = gtk.Notebook() self.notebook.append_page(self.start_box,gtk.Label(_("Favourites"))) self.notebook.append_page(self.search_box,gtk.Label(_("Search"))) self.notebook.append_page(stations_box,gtk.Label(_("Radiostation list"))) self.notebook.set_scrollable(True) self.notebook.connect("switch-page",self.event_page_switch) self.pack_start(self.notebook) self.notebook.show_all() self.icon_view_container.hide_all() # initialize lists for recording streams and icon cache self.recording_streams = {} self.icon_cache = {} # start icon downloader thread # use queue for communication with thread # enqueued addresses will get downloaded self.icon_download_queue = Queue.Queue() self.icon_download_thread = threading.Thread(target = self.icon_download_worker) self.icon_download_thread.setDaemon(True) self.icon_download_thread.start() # first time filling of the model self.main_list_filled = False # enable images on buttons settings = gtk.settings_get_default() settings.set_property("gtk-button-images",True) rb.BrowserSource.do_impl_activate (self) def searchEngines(self): yield FeedLocal(self.cache_dir,self.update_download_status) yield FeedIcecast(self.cache_dir,self.update_download_status) yield FeedBoard(self.cache_dir,self.update_download_status) yield FeedShoutcast(self.cache_dir,self.update_download_status) yield FeedRadioTime(self.cache_dir,self.update_download_status) def doSearch(self, term): search_model = gtk.ListStore(str) search_model.append((_("Searching for : '%s'") % term,)) # unset model self.result_box.set_model(search_model) # start thread search_thread = threading.Thread(target = self.doSearchThread, args = (term,)) search_thread.start() def doSearchThread(self,term): results = {} self.station_actions = {} # check each engine for search method for feed in self.searchEngines(): try: feed.search except: print "no search support in : "+feed.name() continue # call search method try: self.station_actions[feed.name()] = feed.get_station_actions() result = feed.search(term) results[feed.name()] = result except Exception,e: print "error with source:"+feed.name() print "error:"+str(e) gtk.gdk.threads_enter() # create new model new_model = gtk.TreeStore(str,object) # add entries to model for name in results.keys(): result = results[name] source_parent = new_model.append(None,(name+" ("+str(len(result))+")",None)) for entry in result: new_model.append(source_parent,(entry.server_name,entry)) # set model of result_box new_model.set_sort_column_id(0,gtk.SORT_ASCENDING) self.result_box.set_model(new_model) gtk.gdk.threads_leave() def download_click_statistic(self): # download statistics statisticsStr = "" try: remotefile = urllib2.urlopen("http://www.radio-browser.info/topclick.php?limit=10") statisticsStr = remotefile.read() except Exception, e: print "download failed exception" print e return # parse statistics self.statistics_handler = BoardHandler() xml.sax.parseString(statisticsStr,self.statistics_handler) # fill statistics box self.refill_statistics(thread=True) def shortStr(self,longstring,maxlen): if len(longstring) > maxlen: short_value = longstring[0:maxlen-3]+"..." else: short_value = longstring return short_value def refill_statistics(self, thread=False): # check if already downloaded try: self.statistics_handler except: transmit_thread = threading.Thread(target = self.download_click_statistic) transmit_thread.start() return def button_click(widget,name,station): self.play_uri(station) def button_add_click(widget,name,station): data = self.load_from_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME)) if data is None: data = {} if station.server_name not in data: data[station.server_name] = station self.save_to_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME),data) self.refill_favourites() if thread: gtk.gdk.threads_enter() for entry in self.statistics_handler.entries: button = gtk.Button(self.shortStr(entry.server_name,30)+" ("+entry.clickcount+")") button.connect("clicked",button_click,entry.server_name,entry) button_add = gtk.Button() img = gtk.Image() img.set_from_stock(gtk.STOCK_GO_FORWARD,gtk.ICON_SIZE_BUTTON) button_add.set_image(img) button_add.connect("clicked",button_add_click,entry.server_name,entry) line = gtk.HBox() line.pack_start(button) line.pack_start(button_add,expand=False) self.statistics_box.pack_start(line,expand=False) line.show_all() self.statistics_box_parent.show_all() if thread: gtk.gdk.threads_leave() def refill_favourites(self): print "refill favourites" width, height = gtk.icon_size_lookup(gtk.ICON_SIZE_BUTTON) # remove all old information in infobox for widget in self.start_box.get_children(): self.start_box.remove(widget) def button_click(widget,name,station): self.play_uri(station) def button_record_click(widget,name,station): self.record_uri(station) def button_add_click(widget,name,station): data = self.load_from_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME)) if data is None: data = {} if station.server_name not in data: data[station.server_name] = station self.save_to_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME),data) self.refill_favourites() def button_delete_click(widget,name,station): data = self.load_from_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME)) if data is None: data = {} if station.server_name in data: del data[station.server_name] self.save_to_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME),data) self.refill_favourites() left_box = gtk.VBox() left_box.show() # add click statistics list self.statistics_box = gtk.VBox() scrolled_box = gtk.ScrolledWindow() scrolled_box.add_with_viewport(self.statistics_box) scrolled_box.set_property("hscrollbar-policy", gtk.POLICY_AUTOMATIC) decorated_box = gtk.Frame(_("Click statistics (Last 30 days)")) decorated_box.add(scrolled_box) self.statistics_box_parent = decorated_box left_box.pack_start(decorated_box) self.refill_statistics() # add recently played list recently_box = gtk.VBox() scrolled_box = gtk.ScrolledWindow() scrolled_box.add_with_viewport(recently_box) scrolled_box.set_property("hscrollbar-policy", gtk.POLICY_AUTOMATIC) decorated_box = gtk.Frame(_("Recently played")) decorated_box.add(scrolled_box) left_box.pack_start(decorated_box) self.start_box.pack1(left_box) data = self.load_from_file(os.path.join(self.cache_dir,RECENTLY_USED_FILENAME)) if data is None: data = {} dataNew = {} sortedkeys = sorted(data.keys()) for name in sortedkeys: station = data[name] if datetime.datetime.now()-station.PlayTime <= datetime.timedelta(days=float(self.plugin.recently_played_purge_days)): if len(name) > 53: short_value = name[0:50]+"..." else: short_value = name button = gtk.Button(short_value) button.connect("clicked",button_click,name,station) button_add = gtk.Button() img = gtk.Image() img.set_from_stock(gtk.STOCK_GO_FORWARD,gtk.ICON_SIZE_BUTTON) button_add.set_image(img) button_add.connect("clicked",button_add_click,name,station) line = gtk.HBox() line.pack_start(button) line.pack_start(button_add,expand=False) recently_box.pack_start(line, expand=False) dataNew[name] = station try: if station.icon_src != "": hash_src = hashlib.md5(station.icon_src).hexdigest() filepath = os.path.join(self.icon_cache_dir, hash_src) if os.path.exists(filepath): buffer = gtk.gdk.pixbuf_new_from_file_at_size(filepath,width,height) img = gtk.Image() img.set_from_pixbuf(buffer) img.show() button.set_image(img) except: print "could not set image for station:"+str(station.server_name) if len(sortedkeys)>0: decorated_box.show_all() self.save_to_file(os.path.join(self.cache_dir,RECENTLY_USED_FILENAME),dataNew) # add bookmarks favourites_box = gtk.VBox() scrolled_box = gtk.ScrolledWindow() scrolled_box.add_with_viewport(favourites_box) scrolled_box.set_property("hscrollbar-policy", gtk.POLICY_AUTOMATIC) decorated_box = gtk.Frame(_("Favourites")) decorated_box.add(scrolled_box) self.start_box.pack2(decorated_box) data = self.load_from_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME)) if data is None: data = {} sortedkeys = sorted(data.keys()) for name in sortedkeys: line = gtk.HBox() station = data[name] if len(name) > 53: short_value = name[0:50]+"..." else: short_value = name button = gtk.Button(short_value) button.connect("clicked",button_click,name,station) button_delete = gtk.Button() img = gtk.Image() img.set_from_stock(gtk.STOCK_DELETE,gtk.ICON_SIZE_BUTTON) button_delete.set_image(img) button_delete.connect("clicked",button_delete_click,name,station) button_record = gtk.Button() img = gtk.Image() img.set_from_stock(gtk.STOCK_MEDIA_RECORD,gtk.ICON_SIZE_BUTTON) button_record.set_image(img) button_record.connect("clicked",button_record_click,name,station) line.pack_start(button) line.pack_start(button_record,expand=False) line.pack_start(button_delete,expand=False) favourites_box.pack_start(line, expand=False) try: if station.icon_src != "": hash_src = hashlib.md5(station.icon_src).hexdigest() filepath = os.path.join(self.icon_cache_dir, hash_src) if os.path.exists(filepath): buffer = gtk.gdk.pixbuf_new_from_file_at_size(filepath,width,height) img = gtk.Image() img.set_from_pixbuf(buffer) img.show() button.set_image(img) except: print "could not set image for station:"+str(station.server_name) if (len(sortedkeys) > 0): decorated_box.show_all() """ handler for page switches in the main notebook """ def event_page_switch(self,notebook,page,page_num): if page_num == 0: # update favourites each time user selects it self.refill_favourites() if page_num == 1: pass if page_num == 2: if not self.main_list_filled: # fill the list only the first time, the user selects the main tab self.main_list_filled = True self.refill_list() """ listener on double click in search view """ def on_item_activated_icon_view(self,widget,item): model = widget.get_model() station = model[item][1] self.play_uri(station) """ listener on selection change in search view """ def on_selection_changed_icon_view(self,widget): model = widget.get_model() items = widget.get_selected_items() if len(items) == 1: obj = model[items[0]][1] self.update_info_box(obj) """ listener for selection changes """ def treeview_cursor_changed_handler(self,treeview,info_box): # get selected item selection = treeview.get_selection() model,iter = selection.get_selected() # if some item is selected if not iter == None: obj = model.get_value(iter,1) self.update_info_box(obj,info_box) def update_info_box(self,obj,info_box): # remove all old information in infobox for widget in info_box.get_children(): info_box.remove(widget) # create new infobox info_container = gtk.Table(12,2) info_container.set_col_spacing(0,10) self.info_box_added_rows = 0 # convinience method for adding new labels to infobox def add_label(title,value,shorten=True): if value == None: return if not value == "": if shorten: if len(value) > 53: short_value = value[0:50]+"..." else: short_value = value else: short_value = value label = gtk.Label() label.set_line_wrap(True) if value.startswith("http://") or value.startswith("mailto:"): label.set_markup(""+xml.sax.saxutils.escape(short_value)+"") else: label.set_markup(xml.sax.saxutils.escape(short_value)) label.set_selectable(True) label.set_alignment(0, 0) title_label = gtk.Label(title) title_label.set_alignment(1, 0) title_label.set_markup(""+xml.sax.saxutils.escape(title)+"") info_container.attach(title_label,0,1,self.info_box_added_rows,self.info_box_added_rows+1) info_container.attach(label,1,2,self.info_box_added_rows,self.info_box_added_rows+1) self.info_box_added_rows = self.info_box_added_rows+1 if isinstance(obj,Feed): feed = obj add_label(_("Entry type"),_("Feed")) add_label(_("Description"),feed.getDescription(),False) add_label(_("Feed homepage"),feed.getHomepage()) add_label(_("Feed source"),feed.getSource()) try: t = os.path.getmtime(feed.filename) timestr = datetime.datetime.fromtimestamp(t).strftime("%x %X") except: timestr = _("No local copy") add_label(_("Last update"),timestr) if isinstance(obj,RadioStation): station = obj add_label(_("Source feed"),station.type) add_label(_("Name"),station.server_name) add_label(_("Tags"),station.genre) add_label(_("Bitrate"),station.bitrate) add_label(_("Server type"),station.server_type) add_label(_("Homepage"),station.homepage) add_label(_("Current song (on last refresh)"),station.current_song) add_label(_("Current listeners"),station.listeners) add_label(_("Language"),station.language) add_label(_("Country"),station.country) add_label(_("Votes"),station.votes) add_label(_("Negative votes"),station.negativevotes) add_label(_("Stream URL"),station.listen_url) try: PlayTime = station.PlayTime.strftime("%x %X") add_label(_("Added to recently played at"),PlayTime) except: pass button_box = gtk.VBox() def button_play_handler(widget,station): self.play_uri(station) def button_bookmark_handler(widget,station): data = self.load_from_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME)) if data is None: data = {} if station.server_name not in data: self.tree_store.append(self.bookmarks_iter,(station.server_name,station)) data[station.server_name] = station widget.set_label(_("Unbookmark")) else: iter = self.tree_store.iter_children(self.bookmarks_iter) while True: title = self.tree_store.get_value(iter,0) if title == station.server_name: self.tree_store.remove(iter) break iter = self.tree_store.iter_next(iter) if iter == None: break del data[station.server_name] widget.set_label(_("Bookmark")) self.save_to_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME),data) def button_record_handler(widget,station): self.record_uri(station) def button_download_handler(widget,feed): transmit_thread = threading.Thread(target = self.download_feed,args = (feed,)) transmit_thread.setDaemon(True) transmit_thread.start() def button_action_handler(widget,action): action.call(self) def button_station_action_handler(widget,action,station): action.call(self,station) if isinstance(obj,Feed): feed = obj if os.path.isfile(feed.filename): button = gtk.Button(_("Redownload")) button.connect("clicked", button_download_handler, feed) else: button = gtk.Button(_("Download")) button.connect("clicked", button_download_handler, feed) button_box.pack_start(button,False) for action in feed.get_feed_actions(): button = gtk.Button(action.name) button.connect("clicked",button_action_handler,action) button_box.pack_start(button,False) if isinstance(obj,RadioStation): button = gtk.Button(_("Play")) button.connect("clicked", button_play_handler, obj) button_box.pack_start(button,False) # check for streamripper, before displaying record button try: process = subprocess.Popen("streamripper",stdout=subprocess.PIPE) process.communicate() process.wait() except(OSError): print "streamripper not found" else: button = gtk.Button(_("Record")) button.connect("clicked", button_record_handler, obj) button_box.pack_start(button,False) data = self.load_from_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME)) if data is None: data = {} if station.server_name not in data: button = gtk.Button(_("Bookmark")) else: button = gtk.Button(_("Unbookmark")) button.connect("clicked", button_bookmark_handler, obj) button_box.pack_start(button,False) if station.type in self.station_actions.keys(): actions = self.station_actions[station.type] for action in actions: button = gtk.Button(action.name) button.connect("clicked", button_station_action_handler, action,obj) button_box.pack_start(button,False) sub_info_box = gtk.HBox() sub_info_box.pack_start(info_container) sub_info_box.pack_start(button_box,False) decorated_info_box = gtk.Frame(_("Info box")) decorated_info_box.add(sub_info_box) info_box.pack_start(decorated_info_box) info_box.show_all() """ icon download worker thread function """ def icon_download_worker(self): while True: filepath,src = self.icon_download_queue.get() if os.path.exists(filepath) is False: if src.lower().startswith("http://"): try: urllib.urlretrieve(src,filepath) except: pass self.icon_download_queue.task_done() """ tries to load icon from disk and if found it saves it in cache returns it """ def get_icon_pixbuf(self,filepath,return_value_not_found=None): if os.path.exists(filepath): width, height = gtk.icon_size_lookup(gtk.ICON_SIZE_BUTTON) if filepath in self.icon_cache: return self.icon_cache[filepath] else: try: icon = gtk.gdk.pixbuf_new_from_file_at_size(filepath,width,height) except: icon = return_value_not_found self.icon_cache[filepath] = icon return icon return return_value_not_found """ data display function for tree view """ def model_data_func(self,column,cell,model,iter,infostr): obj = model.get_value(iter,1) self.clef_icon = self.get_icon_pixbuf(self.plugin.find_file("note.png")) if infostr == "image": icon = None if isinstance(obj,RadioStation): station = obj # default icon icon = self.clef_icon # icons for special feeds if station.type == "Shoutcast": icon = self.get_icon_pixbuf(self.plugin.find_file("shoutcast-logo.png")) if station.type == "Icecast": icon = self.get_icon_pixbuf(self.plugin.find_file("xiph-logo.png")) if station.type == "Local": icon = self.get_icon_pixbuf(self.plugin.find_file("local-logo.png")) # most special icons, if the station has one for itsself if station.icon_src != "": hash_src = hashlib.md5(station.icon_src).hexdigest() filepath = os.path.join(self.icon_cache_dir, hash_src) if os.path.exists(filepath): icon = self.get_icon_pixbuf(filepath,self.clef_icon) else: # load icon self.icon_download_queue.put([filepath,station.icon_src]) if icon is None: cell.set_property("stock-id",gtk.STOCK_DIRECTORY) else: cell.set_property("pixbuf",icon) """ transmits station information to board """ def transmit_station(self,station): params = urllib.urlencode({'action':'clicked','name': station.server_name,'url': station.getRealURL(),'source':station.type}) f = urllib.urlopen(BOARD_ROOT+"?%s" % params) f.read() print "Transmit station '"+str(station.server_name)+"' OK" """ transmits title information to board """ """def transmit_title(self,title): params = urllib.urlencode({'action':'streaming','name': self.station.server_name,'url': self.station.getRealURL(),'source':self.station.type,'title':title}) f = urllib.urlopen(BOARD_ROOT+"?%s" % params) f.read() print "Transmit title '"+str(title)+"' OK" """ """ stream information listener """ def info_available(self,player,uri,field,value): if field == RB_METADATA_FIELD_TITLE: self.title = value self.set_streaming_title(self.title) #transmit_thread = threading.Thread(target = self.transmit_title,args = (value,)) #transmit_thread.setDaemon(True) #transmit_thread.start() #print "setting title to:"+value elif field == RB_METADATA_FIELD_GENRE: self.genre = value ## causes warning: RhythmDB-WARNING **: trying to sync properties of non-editable file #self.shell.props.db.set(self.entry, rhythmdb.PROP_GENRE, value) #self.shell.props.db.commit() #print "setting genre to:"+value elif field == RB_METADATA_FIELD_BITRATE: ## causes warning: RhythmDB-WARNING **: trying to sync properties of non-editable file #self.shell.props.db.set(self.entry, rhythmdb.PROP_BITRATE, value/1000) #self.shell.props.db.commit() #print "setting bitrate to:"+str(value/1000) pass else: print "Server sent unknown info '"+str(field)+"':'"+str(value)+"'" # def playing_changed (self, sp, playing): # print "playing changed" # def playing_entry_changed (self, sp, entry): # print "playing entry changed" # def playing_song_property_changed (self, sp, uri, property, old, new): # print "property changed "+str(new) def record_uri(self,station): play_thread = threading.Thread(target = self.play_uri_,args = (station,True)) play_thread.setDaemon(True) play_thread.start() """ listener for filter entry change """ def filter_entry_changed(self,gtk_entry): if self.filter_entry.get_text() == "" and self.filter_entry_genre.get_text() == "": self.tree_view_container.show_all() self.icon_view_container.hide_all() else: self.tree_view_container.hide_all() self.icon_view_container.show_all() self.icon_view.set_model() self.filtered_icon_view_store.refilter() self.icon_view.set_model(self.filtered_icon_view_store) self.notify_status_changed() """ callback for item filtering """ def list_store_visible_func(self,model,iter): # returns true if the row should be visible if len(model) == 0: return True obj = model.get_value(iter,1) if isinstance(obj,RadioStation): station = obj try: bitrate = int(station.bitrate) min_bitrate = int(float(self.filter_entry_bitrate.get_value())) if bitrate < min_bitrate: return False except: pass filter_string = self.filter_entry.get_text().lower() if filter_string != "": if station.server_name.lower().find(filter_string) < 0: return False filter_string = self.filter_entry_genre.get_text().lower() if filter_string != "": genre = station.genre if genre is None: genre = "" if genre.lower().find(filter_string) < 0: return False return True else: return True """ handler for update toolbar button """ def update_button_clicked(self): if not self.updating: # delete cache files files = os.listdir(self.cache_dir) for filename in files: if filename.endswith("xml"): filepath = os.path.join(self.cache_dir, filename) os.unlink(filepath) # start filling again self.refill_list() def clear_iconcache_button_clicked(self): if not self.updating: # delete cache files files = os.listdir(self.icon_cache_dir) for filename in files: filepath = os.path.join(self.icon_cache_dir, filename) os.unlink(filepath) # delete internal cache self.icon_cache = {} # start filling again self.refill_list() pass """ starts playback of the station """ def play_uri(self,station): station.updateRealURL() play_thread = threading.Thread(target = self.play_uri_,args = (station,)) play_thread.setDaemon(True) play_thread.start() def play_uri_(self,station,record=False): # do not play while downloading if self.updating: return # try downloading station information tryno = 0 self.updating = True while True: tryno += 1 gtk.gdk.threads_enter() self.load_status = _("downloading station information")+" '"+station.server_name+"', "+_("Try")+":"+str(tryno)+"/"+str(math.floor(float(self.plugin.download_trys))) self.load_total_size = 0 self.notify_status_changed() gtk.gdk.threads_leave() if station.getRealURL() is not None: break if tryno >= float(self.plugin.download_trys): gtk.gdk.threads_enter() self.load_status = "" self.updating = False self.notify_status_changed() message = gtk.MessageDialog(message_format=_("Could not download station information"),buttons=gtk.BUTTONS_OK,type=gtk.MESSAGE_ERROR) message.format_secondary_text(_("Could not download station information from shoutcast directory server. Please try again later.")) response = message.run() message.destroy() gtk.gdk.threads_leave() return if not station.listen_url.startswith("http://127.0.0.1"): # add to recently played data = self.load_from_file(os.path.join(self.cache_dir,RECENTLY_USED_FILENAME)) if data is None: data = {} if station.server_name not in data: try: self.tree_store.append(self.recently_iter,(station.server_name,station)) except: pass data[station.server_name] = station data[station.server_name].PlayTime = datetime.datetime.now() else: data[station.server_name].PlayTime = datetime.datetime.now() self.save_to_file(os.path.join(self.cache_dir,RECENTLY_USED_FILENAME),data) gtk.gdk.threads_enter() self.load_status = "" self.updating = False self.notify_status_changed() if record: def short_name(name): maxlen = 30 if len(name) > maxlen: return name[0:maxlen-3]+"..." else: return name uri = station.getRealURL() # do not record the same stream twice if uri in self.recording_streams: if self.recording_streams[uri].process.poll() is None: return self.recording_streams[uri] = RecordProcess(station,self.plugin.outputpath,self.play_uri,self.shell) self.notebook.append_page(self.recording_streams[uri],gtk.Label(short_name(station.server_name))) self.recording_streams[uri].start() self.notebook.set_current_page(self.notebook.page_num(self.recording_streams[uri])) else: # get player player = self.shell.get_player() player.stop() # create new entry to play self.entry = self.shell.props.db.entry_lookup_by_location(station.getRealURL()) if self.entry == None: #self.shell.props.db.entry_delete(self.entry) self.entry = self.shell.props.db.entry_new(self.entry_type, station.getRealURL()) self.shell.props.db.set(self.entry, rhythmdb.PROP_TITLE, station.server_name) self.shell.props.db.commit() #shell.load_uri(uri,False) # start playback player.play_entry(self.entry,self) gtk.gdk.threads_leave() # transmit station click to station board (statistic) """ transmit_thread = threading.Thread(target = self.transmit_station,args = (station,)) transmit_thread.setDaemon(True) transmit_thread.start() """ handler for double clicks in tree view """ def row_activated_handler(self,treeview,path,column): model = treeview.get_model() myiter = model.get_iter(path) obj = model.get_value(myiter,1) if obj == None: return if isinstance(obj,RadioStation): station = obj if station is not None: self.play_uri(station) if isinstance(obj,Feed): feed = obj transmit_thread = threading.Thread(target = self.download_feed,args = (feed,)) transmit_thread.setDaemon(True) transmit_thread.start() def download_feed(self,feed): tryno = 0 self.updating = True while True: tryno += 1 gtk.gdk.threads_enter() self.load_status = _("Downloading feed %(name)s from %(url)s. %(try)d/%(trys)d") % {'name':feed.name(), 'url':feed.uri, 'try':tryno, 'trys':(math.floor(float(self.plugin.download_trys)))} self.load_total_size = 0 self.notify_status_changed() gtk.gdk.threads_leave() if feed.download(): break if tryno >= float(self.plugin.download_trys): gtk.gdk.threads_enter() self.load_status = "" self.updating = False self.notify_status_changed() message = gtk.MessageDialog(message_format=_("Feed download failed"),buttons=gtk.BUTTONS_OK,type=gtk.MESSAGE_ERROR) message.format_secondary_text(_("Could not download feed. Please try again later.")) response = message.run() message.destroy() gtk.gdk.threads_leave() return self.refill_list() def do_impl_delete_thyself(self): if self.hasActivated: # kill all running records for uri in self.recording_streams.keys(): self.recording_streams[uri].stop() self.shell = False def engines(self): yield FeedLocal(self.cache_dir,self.update_download_status) yield FeedIcecast(self.cache_dir,self.update_download_status) yield FeedBoard(self.cache_dir,self.update_download_status) yield FeedShoutcast(self.cache_dir,self.update_download_status) yield FeedRadioTime(self.cache_dir,self.update_download_status) yield FeedRadioTimeLocal(self.cache_dir,self.update_download_status) def get_stock_icon(self, name): theme = gtk.icon_theme_get_default() return theme.load_icon(name, 48, 0) def load_icon_file(self,filepath,value_not_found): icon = value_not_found try: icon = gtk.gdk.pixbuf_new_from_file_at_size(filepath,72,72) except: icon = value_not_found return icon def get_station_icon(self,station,default_icon): # default icon icon = default_icon # most special icons, if the station has one for itsself if station.icon_src != "": if station.icon_src is not None: hash_src = hashlib.md5(station.icon_src).hexdigest() filepath = os.path.join(self.icon_cache_dir, hash_src) if os.path.exists(filepath): icon = self.load_icon_file(filepath,icon) else: # load icon self.icon_download_queue.put([filepath,station.icon_src]) return icon def insert_feed(self,feed,parent): # preload most used icons note_icon = self.load_icon_file(self.plugin.find_file("note.png"),None) shoutcast_icon = self.load_icon_file(self.plugin.find_file("shoutcast-logo.png"),None) xiph_icon = self.load_icon_file(self.plugin.find_file("xiph-logo.png"),None) local_icon = self.load_icon_file(self.plugin.find_file("local-logo.png"),None) gtk.gdk.threads_enter() self.load_status = _("Loading feed %(name)s") % {'name':feed.name(),} self.load_total_size = 0 self.notify_status_changed() gtk.gdk.threads_leave() # create main feed root item current_iter = self.tree_store.append(parent,(feed.name(),feed)) # initialize dicts for iters genres = {} countries = {} subcountries = {} streamtypes = {} bitrates = {} # load entries entries = feed.entries() gtk.gdk.threads_enter() self.load_status = _("Integrating feed %(name)s (%(itemcount)d items) into tree...") % {'name':feed.name(),'itemcount':len(entries)} self.notify_status_changed() gtk.gdk.threads_leave() def short_name(name): maxlen = 50 if len(name) > maxlen: return name[0:maxlen-3]+"..." else: return name self.load_total_size = len(entries) self.load_current_size = 0 stations_count = 0 for obj in entries: if isinstance(obj,Feed): sub_feed = obj # add sub feed to treeview stations_count += self.insert_feed(sub_feed,current_iter) elif isinstance(obj,RadioStation): stations_count += 1 station = obj # add subitems for sorting, if there are stations if self.load_current_size == 0: genre_iter = self.tree_store.append(current_iter,(_("By Genres"),None)) country_iter = self.tree_store.append(current_iter,(_("By Country"),None)) streamtype_iter = self.tree_store.append(current_iter,(_("By Streamtype"),None)) bitrate_iter = self.tree_store.append(current_iter,(_("By Bitrate"),None)) # display status info in statusbar self.load_current_size += 1 gtk.gdk.threads_enter() if self.load_current_size % 50 == 0: self.notify_status_changed() gtk.gdk.threads_leave() # default icon icon = note_icon # icons for special feeds if station.type == "Shoutcast": icon = shoutcast_icon if station.type == "Icecast": icon = xiph_icon if station.type == "Local": icon = local_icon # add new station to liststore of search-view too self.icon_view_store.append((short_name(station.server_name),station,self.get_station_icon(station,icon))) # add station to treeview, by streamtype if station.server_type not in streamtypes: streamtypes[station.server_type] = self.tree_store.append(streamtype_iter,(station.server_type,None)) self.tree_store.append(streamtypes[station.server_type],(station.server_name,station)) # add station to treeview, by bitrate br = station.bitrate try: br_int = int(br) br = str((((br_int-1)/32)+1)*32) if br_int > 512: br = _("Invalid") except: pass if br not in bitrates: bitrates[br] = self.tree_store.append(bitrate_iter,(br,None)) self.tree_store.append(bitrates[br],(station.server_name,station)) # add station to treeview, by genre if station.genre is not None: for genre in station.genre.split(","): genre = genre.strip().lower() if genre not in genres: genres[genre] = self.tree_store.append(genre_iter,(genre,None)) self.genre_list[genre] = 1 self.tree_store.append(genres[genre],(station.server_name,station)) # add station to treeview, by country country_arr = station.country.split("/") if country_arr[0] not in countries: countries[country_arr[0]] = self.tree_store.append(country_iter,(country_arr[0],None)) if len(country_arr) == 2: if station.country not in subcountries: subcountries[station.country] = self.tree_store.append(countries[country_arr[0]],(country_arr[1],None)) self.tree_store.append(subcountries[station.country],(station.server_name,station)) else: self.tree_store.append(countries[country_arr[0]],(station.server_name,station)) else: print "ERROR: unknown class type in feed" self.tree_store.set_value(current_iter,0,feed.name()+" ("+str(stations_count)+")") return stations_count def refill_list_worker(self): print "refill list worker" self.station_actions = {} self.tree_view.set_model() self.icon_view.set_model() #self.filter_entry_genre.set_model() self.updating = True # deactivate sorting self.icon_view_store = gtk.ListStore(str,object,gtk.gdk.Pixbuf) self.sorted_list_store.reset_default_sort_func() # delete old entries self.tree_store.clear() self.icon_view_store.clear() # add recently played list self.recently_iter = self.tree_store.append(None,(_("Recently played"),None)) data = self.load_from_file(os.path.join(self.cache_dir,RECENTLY_USED_FILENAME)) if data is None: data = {} dataNew = {} for name,station in data.items(): if datetime.datetime.now()-station.PlayTime <= datetime.timedelta(days=float(self.plugin.recently_played_purge_days)): self.tree_store.append(self.recently_iter,(name,station)) dataNew[name] = station self.save_to_file(os.path.join(self.cache_dir,RECENTLY_USED_FILENAME),dataNew) # add bookmarks self.bookmarks_iter = self.tree_store.append(None,(_("Bookmarks"),None)) data = self.load_from_file(os.path.join(self.cache_dir,BOOKMARKS_FILENAME)) if data is None: data = {} for name,station in data.items(): self.tree_store.append(self.bookmarks_iter,(name,station)) # initialize genre dict for genre filter combobox self.genre_list = {} for feed in self.engines(): try: self.station_actions[feed.name()] = feed.get_station_actions() self.insert_feed(feed,None) except Exception,e: print "error with source:"+feed.name() print "error:"+str(e) self.genre_liststore = gtk.ListStore(gobject.TYPE_STRING) self.genre_liststore.append(("",)) for key in self.genre_list.keys(): self.genre_liststore.append((key,)) self.genre_liststore.set_sort_column_id(0,gtk.SORT_ASCENDING) completion = gtk.EntryCompletion() completion.set_text_column(0) completion.set_model(self.genre_liststore) self.filter_entry_genre.set_completion(completion) # activate sorting self.sorted_list_store.set_sort_column_id(0,gtk.SORT_ASCENDING) self.icon_view_store.set_sort_column_id(0,gtk.SORT_ASCENDING) # connect model to view self.filtered_icon_view_store = self.icon_view_store.filter_new() self.filtered_icon_view_store.set_visible_func(self.list_store_visible_func) self.tree_view.set_model(self.sorted_list_store) self.icon_view.set_model(self.filtered_icon_view_store) gtk.gdk.threads_enter() self.updating = False self.notify_status_changed() gtk.gdk.threads_leave() def refill_list(self): print "refill list" self.list_download_thread = threading.Thread(target = self.refill_list_worker) self.list_download_thread.setDaemon(True) self.list_download_thread.start() def load_from_file(self,filename): if not os.path.isfile(filename): return None try: f = open(filename,"r") p = pickle.Unpickler(f) data = p.load() f.close() return data except: print "load file did not work:"+filename return None def save_to_file(self,filename,obj): f = open(filename,"w") p = pickle.Pickler(f) p.dump(obj) f.close() rhythmbox-radio-browser-2.3.1/local-logo.png0000644000175000017500000000371211470615004020401 0ustar seglerseglerPNG  IHDRHJ%LsRGBbKGD pHYs  tIME'#XjtEXtCommentCreated with GIMPW%IDATx{lSUǿynmhaԽO 1#L?d&"B sh08c`1cs[mFz^Is;`>47Kdh%0tӃ=Rkgg픭{v:tHPI.meWVN7nV8xPA Q]] ؾ}/T4P4H7\ tjPgyNM'؈43 i+Wܹ$P0O &Ck" 4$ݞe;w$2fQ 0eWb0o#BJ/0#ܟ W@h o\;rjkkԄ,C7PHY3QWW7T:W@e? eq8^|v-Ǥ%Òŋ7I7O*Aew/aHt׭l (RYI1~j;Io@px@ͤ0iF @OtqiYx{MP8RU1H)[@lu A:([@A:?ϜUp6+wPh}7^=s˞r:ݨ2O%K81ȭSwM xT$&gC^YPs'1HPt 3pe \~̟aG6jՀˋW_@eIGc:> # # Radio-Browser-Plugin 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 3 of the License, or # (at your option) any later version. # # Radio-Browser-Plugin 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 Radio-Browser-Plugin. If not, see . import gtk class RadioStation: def __init__(self): self.listen_url = "" self.listen_urls = [] self.server_name = "" self.genre = "" self.bitrate = "" self.current_song = "" self.type = "" self.icon_src = "" self.homepage = "" self.listeners = "" self.server_type = "" self.language = "" self.country = "" self.votes = "" self.negativevotes = "" self.id = "" def getRealURL(self): return self.listen_url def updateRealURL(self): pass def askUserAboutUrls(self): try: if len(self.listen_urls) == 0: self.listen_url = "" return if len(self.listen_urls) == 1: self.listen_url = self.listen_urls[0] return gtk.gdk.threads_enter() dialog = gtk.Dialog(_("Select stream URL please"),flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) urlListView = gtk.TreeView() urlListView.append_column(gtk.TreeViewColumn(_("Url"),gtk.CellRendererText(),text=0)) urlListStore = gtk.ListStore(str) iter = None for url in self.listen_urls: newiter = urlListStore.append((url,)) if iter == None: iter = newiter if url.lower().startswith("http://") and not url.lower().endswith("asx"): iter = newiter urlListView.set_model(urlListStore) treeselection = urlListView.get_selection() treeselection.set_mode(gtk.SELECTION_SINGLE) treeselection.select_iter(iter) contentarea = dialog.get_content_area() contentarea.pack_start(urlListView) contentarea.show_all() dialog.run() dialog.hide_all() (model, iter) = treeselection.get_selected() self.listen_url = model.get_value(iter,0) gtk.gdk.threads_leave() print "choosen link:"+self.listen_url except Exception,e: print e