1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: directory browser for internet radio / audio streams
# depends: gtk, pygtk, xml.dom.minidom, threading, lxml, pyquery, kronos
# version: 2.0.9.6
# author: mario salzer
# license: public domain
# url: http://freshmeat.net/projects/streamtuner2
# config: <env name="http_proxy" value="" description="proxy for HTTP access" /> <env name="XDG_CONFIG_HOME" description="relocates user .config subdirectory" />
# category: multimedia
#
# |
|
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: directory browser for internet radio / audio streams
# depends: gtk, pygtk, xml.dom.minidom, threading, lxml, pyquery, kronos
# version: 2.0.9.7
# author: mario salzer
# license: public domain
# url: http://freshmeat.net/projects/streamtuner2
# config: <env name="http_proxy" value="" description="proxy for HTTP access" /> <env name="XDG_CONFIG_HOME" description="relocates user .config subdirectory" />
# category: multimedia
#
# |
|
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 |
# standard modules
import sys
import os, os.path
import re
import copy
import urllib
# threading or processing module
try:
from processing import Process as Thread
except:
from threading import Thread
Thread.stop = lambda self: None
# add library path
sys.path.insert(0, "/usr/share/streamtuner2") # pre-defined directory for modules
sys.path.insert(0, ".") # pre-defined directory for modules
# gtk modules
from mygtk import pygtk, gtk, gobject, ui_file, mygtk, ver as GTK_VER
# custom modules
from config import conf # initializes itself, so all conf.vars are available right away
from config import __print__, dbg
import ahttp
import action # needs workaround... (action.main=main)
from channels import *
import favicon
#from pq import pq
# this represents the main window
# and also contains most application behaviour
main = None
class StreamTunerTwo(gtk.Builder): |
<
<
|
<
| 76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 |
# standard modules
import sys
import os, os.path
import re
# threading or processing module
try:
from processing import Process as Thread
except:
from threading import Thread
Thread.stop = lambda self: None
# add library path
sys.path.insert(0, "/usr/share/streamtuner2") # pre-defined directory for modules
sys.path.insert(0, ".") # development module path
# gtk modules
from mygtk import pygtk, gtk, gobject, ui_file, mygtk, ver as GTK_VER
# custom modules
from config import conf # initializes itself, so all conf.vars are available right away
from config import __print__, dbg
import ahttp
import action # needs workaround... (action.main=main)
from channels import *
import favicon
# this represents the main window
# and also contains most application behaviour
main = None
class StreamTunerTwo(gtk.Builder): |
|
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576 | # right click in streams/stations TreeView
def station_context_menu(treeview, event):
# right-click ?
if event.button >= 3:
path = treeview.get_path_at_pos(int(event.x), int(event.y))[0]
treeview.grab_focus()
treeview.set_cursor(path, None, False)
if GTK_VER == 2:
main.streamactions.popup(None, None, None, event.button, event.time)
else:
main.streamactions.popup(None, None, None, None, event.button, event.time)
return None
# we need to pass on to normal left-button signal handler
else:
return False
# this works better as callback function than as class - because of False/Object result for event trigger
|
<
|
<
>
|
>
>
| 556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574 | # right click in streams/stations TreeView
def station_context_menu(treeview, event):
# right-click ?
if event.button >= 3:
path = treeview.get_path_at_pos(int(event.x), int(event.y))[0]
treeview.grab_focus()
treeview.set_cursor(path, None, False)
main.streamactions.popup(
parent_menu_shell=None, parent_menu_item=None, func=None,
button=event.button, activate_time=event.time,
data=None
)
return None
# we need to pass on to normal left-button signal handler
else:
return False
# this works better as callback function than as class - because of False/Object result for event trigger
|
|
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788 | def hide(self, *args):
self.win_config.hide()
return True
# set/load values between gtk window and conf. dict
def apply(self, config, prefix="config_", save=0):
for key,val in config.iteritems():
# map non-alphanumeric chars from config{} to underscores in according gtk widget names
id = re.sub("[^\w]", "_", key)
w = main.get_widget(prefix + id)
__print__(dbg.CONF, "config", ("save" if save else "load"), prefix+id, w, val)
# recurse into dictionaries, transform: conf.play.audio/mp3 => conf.play_audio_mp3
if (type(val) == dict):
self.apply(val, prefix + id + "_", save) |
|
| 772
773
774
775
776
777
778
779
780
781
782
783
784
785
786 | def hide(self, *args):
self.win_config.hide()
return True
# set/load values between gtk window and conf. dict
def apply(self, config, prefix="config_", save=0):
for key,val in config.items():
# map non-alphanumeric chars from config{} to underscores in according gtk widget names
id = re.sub("[^\w]", "_", key)
w = main.get_widget(prefix + id)
__print__(dbg.CONF, "config", ("save" if save else "load"), prefix+id, w, val)
# recurse into dictionaries, transform: conf.play.audio/mp3 => conf.play_audio_mp3
if (type(val) == dict):
self.apply(val, prefix + id + "_", save) |
|
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844 |
# add configuration setting definitions from plugins
once = 0
def add_plugins(self):
if self.once:
return
for name,enabled in conf.plugins.iteritems():
# add plugin load entry
if name:
label = ("enable ⎗ %s channel" if self.channels.get(name) else "use ⎗ %s plugin")
cb = gtk.ToggleButton(label=label % name)
self.add_( "config_plugins_"+name, cb )#, label=None, color="#ddd" )
|
|
| 828
829
830
831
832
833
834
835
836
837
838
839
840
841
842 |
# add configuration setting definitions from plugins
once = 0
def add_plugins(self):
if self.once:
return
for name,enabled in conf.plugins.items():
# add plugin load entry
if name:
label = ("enable ⎗ %s channel" if self.channels.get(name) else "use ⎗ %s plugin")
cb = gtk.ToggleButton(label=label % name)
self.add_( "config_plugins_"+name, cb )#, label=None, color="#ddd" )
|
|
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064 | # First we'll generate a list of current bookmark stream urls, and then
# remove all but those from the currently UPDATED_channel + category.
# This step is most likely redundant, but prevents accidently re-rewriting
# stations that are in two channels (=duplicates with different PLS urls).
check = {"http//": "[row]"}
check = dict((row["url"],row) for row in fav)
# walk through all channels/streams
for chname,channel in main.channels.iteritems():
for cat,streams in channel.streams.iteritems():
# keep the potentially changed rows
if (chname == updated_channel) and (cat == updated_category):
freshened_streams = streams
# remove unchanged urls/rows
else: |
|
|
| 1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062 | # First we'll generate a list of current bookmark stream urls, and then
# remove all but those from the currently UPDATED_channel + category.
# This step is most likely redundant, but prevents accidently re-rewriting
# stations that are in two channels (=duplicates with different PLS urls).
check = {"http//": "[row]"}
check = dict((row["url"],row) for row in fav)
# walk through all channels/streams
for chname,channel in main.channels.items():
for cat,streams in channel.streams.items():
# keep the potentially changed rows
if (chname == updated_channel) and (cat == updated_category):
freshened_streams = streams
# remove unchanged urls/rows
else: |
|