summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuo Jinghua <sunmoon1997@gmail.com>2009-09-15 23:55:49 +0800
committerLuo Jinghua <sunmoon1997@gmail.com>2009-09-15 23:55:49 +0800
commit1a1a80bd23418de54976032b2a54de7c9670946a (patch)
tree5b90c51313d1f5843d522c01f0a6c701505a4304
parent0f393eff94c3c7a32502eccd5e210612703844d9 (diff)
totem, po: add a custom channel list
-rw-r--r--po/zh_CN.po87
-rw-r--r--totem/plugin/Makefile.am4
-rw-r--r--totem/plugin/channels.pls234
-rw-r--r--totem/plugin/sopcast.py288
-rw-r--r--totem/plugin/sopcast.ui189
5 files changed, 783 insertions, 19 deletions
diff --git a/po/zh_CN.po b/po/zh_CN.po
index a7a7827..69e1672 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -5,52 +5,104 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: totem-pps 0.0.17\n"
+"Project-Id-Version: totem-sopcast 0.0.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-09-13 11:17+0800\n"
-"PO-Revision-Date: 2009-09-06 12:21+0800\n"
+"POT-Creation-Date: 2009-09-15 23:44+0800\n"
+"PO-Revision-Date: 2009-09-15 23:45+0800\n"
"Last-Translator: Luo Jinghua <sunmoon1997@gmail.com>\n"
"Language-Team: Luo Jinghua <sunmoon1997@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../totem/plugin/sopcast.py:210 ../totem/plugin/sopcast.py:401
+#: ../totem/plugin/sopcast.py:215 ../totem/plugin/sopcast.py:691
msgid "Sopcast"
-msgstr ""
+msgstr "Sopcast"
-#: ../totem/plugin/sopcast.py:288
+#: ../totem/plugin/sopcast.py:377
msgid "Downloading channel list..."
msgstr "加载频道列表中..."
-#: ../totem/plugin/sopcast.py:368
+#: ../totem/plugin/sopcast.py:467 ../totem/plugin/sopcast.py:600
msgid "Name"
msgstr "名称"
-#: ../totem/plugin/sopcast.py:372
+#: ../totem/plugin/sopcast.py:471
msgid "Number"
msgstr "数量"
-#: ../totem/plugin/sopcast.py:401
+#: ../totem/plugin/sopcast.py:604
+msgid "Location"
+msgstr "位置"
+
+#: ../totem/plugin/sopcast.py:691
#, python-format
msgid ""
"Totem cannot play this type of media (%s) because you do not have the "
"appropriate plugins to handle it."
msgstr "Totem 无法播放此介质类型(%s),原因是您没有可处理该类型的适当插件。"
-#: ../totem/plugin/sopcast.py:402
+#: ../totem/plugin/sopcast.py:692
msgid ""
"Please install the necessary plugins and restart Totem to be able to play "
"this media."
msgstr "请按装必需的插件,然后重新启动 Totem,这样才能播放此介质。"
-#: ../totem/plugin/sopcast.py:404
+#: ../totem/plugin/sopcast.py:694
msgid "More information about media plugins"
msgstr "更多的关于媒体插件的信息"
#: ../totem/plugin/sopcast.ui.h:1
-msgid "Channels"
-msgstr "频道"
+msgid "Add a new station to the list"
+msgstr "新增一个电视"
+
+#: ../totem/plugin/sopcast.ui.h:2
+msgid "Add a station to station list"
+msgstr "添加一个电视节目到列表中"
+
+#: ../totem/plugin/sopcast.ui.h:3
+msgid "Add the station to list"
+msgstr "添加到电视列表(_A)"
+
+#: ../totem/plugin/sopcast.ui.h:4
+msgid "Channels(Personal)"
+msgstr "频道(个人的)"
+
+#: ../totem/plugin/sopcast.ui.h:5
+msgid "Channels(Sopcast)"
+msgstr "频道(Sopcast)"
+
+#: ../totem/plugin/sopcast.ui.h:6
+msgid "Copy the location to the clipboard"
+msgstr "复制位置到剪切板"
+
+#: ../totem/plugin/sopcast.ui.h:7
+msgid "Location:"
+msgstr "位置:"
+
+#: ../totem/plugin/sopcast.ui.h:8
+msgid "Name:"
+msgstr "名称:"
+
+#: ../totem/plugin/sopcast.ui.h:9
+msgid "Remove the station from list"
+msgstr "删除电视(_R)"
+
+#: ../totem/plugin/sopcast.ui.h:10
+msgid "_Add the station"
+msgstr "添加到电视列表(_A)"
+
+#: ../totem/plugin/sopcast.ui.h:11
+msgid "_Copy Location"
+msgstr "复制位置(_C)"
+
+#: ../totem/plugin/sopcast.ui.h:12
+msgid "_New station"
+msgstr "新增电视(_N)"
+
+#: ../totem/plugin/sopcast.ui.h:13
+msgid "_Remove the station"
+msgstr "删除电视(_R)"
#: ../totem/plugin/sopcast-config.ui.h:1
msgid "<b>Sopcast</b>"
@@ -84,3 +136,12 @@ msgstr "一个可以浏览 Sopcast 频道的插件"
#: ../totem/plugin/sopcast.totem-plugin.in.h:2
msgid "Sopcast browser"
msgstr "Sopcast 浏览器"
+
+#~ msgid "Stations(Custom)"
+#~ msgstr "电视(自定的)"
+
+#~ msgid "_Add to Station list"
+#~ msgstr "添加到电视列表中(_A)"
+
+#~ msgid "_Remove from Station list"
+#~ msgstr "从电视列表中删除(_R)"
diff --git a/totem/plugin/Makefile.am b/totem/plugin/Makefile.am
index 3997d92..89971bf 100644
--- a/totem/plugin/Makefile.am
+++ b/totem/plugin/Makefile.am
@@ -14,9 +14,9 @@ plugin_in_files = sopcast.totem-plugin.in
%.totem-plugin: %.totem-plugin.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
plugin_DATA = $(plugin_in_files:.totem-plugin.in=.totem-plugin) sopcast_translation.py
-ui_DATA = sopcast.ui sopcast-config.ui
+ui_DATA = sopcast.ui sopcast-config.ui channels.pls
-EXTRA_DIST = $(plugin_in_files) $(ui_DATA) sopcast.py sopcast_translation.py.in channelguide.py
+EXTRA_DIST = $(plugin_in_files) $(ui_DATA) sopcast.py sopcast_translation.py.in channelguide.py channels.pls
CLEANFILES = $(plugin_DATA) sopcast_translation.py
DISTCLEANFILES = $(plugin_DATA) sopcast_translation.py
diff --git a/totem/plugin/channels.pls b/totem/plugin/channels.pls
new file mode 100644
index 0000000..9922745
--- /dev/null
+++ b/totem/plugin/channels.pls
@@ -0,0 +1,234 @@
+[playlist]
+NumberOfEntries=116
+File1=mms://live.cctv.com/cctv_live1
+Title1=CCTV 1
+File2=mms://live.cctv.com/live12
+Title2=CCTV 2
+File3=mms://live.cctv.com/live13
+Title3=CCTV 3
+File4=mms://live.cctv.com/cctv_live4
+Title4=CCTV 4
+File5=mms://live.cctv.com/live15
+Title5=CCTV 5
+File6=mms://live.cctv.com/live16
+Title6=CCTV 6
+File7=mms://live.cctv.com/live17
+Title7=CCTV 7
+File8=mms://live.cctv.com/cctv_live9
+Title8=CCTV 9
+File9=mms://live.cctv.com/live20
+Title9=CCTV 10
+File10=mms://live.cctv.com/live21
+Title10=CCTV 11
+File11=mms://live.cctv.com/live22
+Title11=CCTV 12
+File12=mms://live.cctv.com/livenews
+Title12=CCTV 新闻
+File13=mms://live.cctv.com/livekids
+Title13=CCTV 少儿
+File14=mms://live.cctv.com/livemusic
+Title14=CCTV 音乐
+File15=mms://gouwu.live.cctv.com/livegouwu?cccode=cc1289
+Title15=CCTV 购物
+File16=mms://live.cctv.com/livefengyun
+Title16=CCTV 风云足球
+File17=mms://211.167.102.66/ch-04
+Title17=Bloomberg
+File18=mms://211.167.102.66/ch-11
+Title18=探索频道
+File19=mms://211.167.102.66/ch-19
+Title19=国家地理
+File20=mms://61.139.37.135/blsz
+Title20=法国时尚
+File21=mms://211.167.102.66/ch-14
+Title21=ESPN体育
+File22=mms://211.167.102.67/ch-17
+Title22=卫视体育
+File23=mms://61.139.37.135/starmovies
+Title23=好莱坞电影
+File24=mms://61.139.37.135/aoya
+Title24=Aoya电影
+File25=mms://211.156.249.76/yl100tv001
+Title25=高清影视
+File26=mms://195.244.137.207:81
+Title26=1 Music
+File27=mms://211.167.102.66/ch-03
+Title27=Channal [V]
+File28=mms://morrich.gekimedia.net/MainStream500
+Title28=SonyMusic
+File29=mms://living.chinabroadcast.cn/hqzx
+Title29=环球资讯
+File30=mms://211.167.102.66/ch-01
+Title30=凤凰资讯
+File31=mms://211.167.102.66/ch-02
+Title31=凤凰卫视
+File32=mms://61.139.37.135/xgxz
+Title32=香港新知
+File33=mms://211.167.102.66/ch-20
+Title33=AXN香港
+File34=mms://61.139.37.135/tvb8
+Title34=TVB电影
+File35=mms://211.167.102.66/ch-07
+Title35=TVB星河
+File36=mms://211.167.102.66/ch-08
+Title36=TVBS
+File37=mms://211.167.102.66/ch-05
+Title37=TVB8
+File38=mms://211.167.102.66/ch-15
+Title38=大爱
+File39=mms://211.167.102.66/ch-06
+Title39=华娱卫视
+File40=mms://211.167.102.66/ch-12
+Title40=东风卫视
+File41=mms://211.167.102.66/ch-13
+Title41=东森综合
+File42=mms://211.167.102.66/ch-18
+Title42=东森电影
+File43=mms://211.167.102.66/ch-16
+Title43=中天综合
+File44=mms://211.157.10.21/suntv
+Title44=阳光卫视
+File45=mms://61.139.37.135/star
+Title45=星空卫视
+File46=mms://61.139.37.135/dfws
+Title46=上海东方卫视
+File47=mms://211.167.102.66/ch-10
+Title47=上海体育
+File48=mms://mediasrv2.iptv.xmg.com.cn/tvhaixia
+Title48=厦门卫视
+File49=mms://mediasrv2.iptv.xmg.com.cn/tvxinwen
+Title49=厦门新闻
+File50=mms://mediasrv2.iptv.xmg.com.cn/tvjishi
+Title50=厦门纪实
+File51=mms://mediasrv2.iptv.xmg.com.cn/tvshenghuo
+Title51=厦门生活
+File52=mms://mediasrv2.iptv.xmg.com.cn/tvyingshi
+Title52=厦门影视
+File53=mms://61.175.162.21/ztv2
+Title53=浙江钱江在线
+File54=mms://61.175.162.21/ztv3
+Title54=浙江经视
+File55=mms://61.175.162.21/ztv4
+Title55=浙江教育科技
+File56=mms://61.175.162.21/ztv5
+Title56=浙江影视
+File57=mms://61.175.162.21/ztv8
+Title57=浙江少儿
+File58=mmsh://live.njbg.com.cn:88/NJTV01?MSWMExt=.asf
+Title58=南京新闻综合
+File59=mmsh://live.njbg.com.cn:88/NJTV03?MSWMExt=.asf
+Title59=南京娱乐
+File60=mmsh://live.njbg.com.cn:88/NJTV04?MSWMExt=.asf
+Title60=南京生活
+File61=mmsh://live.njbg.com.cn:88/NJTV05?MSWMExt=.asf
+Title61=南京科教
+File62=mmsh://live.njbg.com.cn:88/NJTV06?MSWMExt=.asf
+Title62=南京信息
+File63=mmsh://live.njbg.com.cn:88/NJTV18?MSWMExt=.asf
+Title63=南京十八
+File64=mms://218.3.205.21/xwzhpd
+Title64=徐州新闻综合
+File65=mms://218.3.205.21/jjshpd
+Title65=徐州经济生活
+File66=mms://218.3.205.21/wyyspd
+Title66=徐州文艺影视
+File67=mms://218.3.205.21/shzfpd
+Title67=徐州公共
+File68=mms://vod1.cztv.tv/cztv1
+Title68=常州新闻
+File69=mms://vod1.cztv.tv/cztv2
+Title69=常州都市
+File70=mms://vod1.cztv.tv/cztv3
+Title70=常州影视
+File71=mms://vod1.cztv.tv/cztv4
+Title71=常州公共
+File72=mmsh://61.159.229.233/yntv-1?MSWMExt=.asf
+Title72=云南卫视
+File73=mmsh://61.159.229.233/yntv-2?MSWMExt=.asf
+Title73=云南都市
+File74=mmsh://61.159.229.233/yntv-3?MSWMExt=.asf
+Title74=云南娱乐
+File75=mmsh://61.159.229.233/yntv-4?MSWMExt=.asf
+Title75=云南生活资讯
+File76=mmsh://61.159.229.233/yntv-6?MSWMExt=.asf
+Title76=云南公共
+File77=mms://61.139.37.135/HUNA
+Title77=湖南卫视
+File78=mms://218.6.174.207/sctv1
+Title78=四川卫视
+File79=mms://218.6.174.207/sctv2
+Title79=四川文化旅游
+File80=mms://218.6.174.207/sctv3
+Title80=四川经济
+File81=mms://218.6.174.207/sctv4
+Title81=四川4
+File82=mms://218.6.174.207/sctv5
+Title82=四川影视文艺
+File83=mms://218.6.174.207/sctv6
+Title83=四川6
+File84=mms://218.6.174.207/sctv7
+Title84=四川妇女儿童
+File85=mms://218.6.174.207/sctv9
+Title85=四川公共
+File86=mms://vod.chengdutv.com/news
+Title86=成都新闻综合
+File87=mms://vod.chengdutv.com/economy
+Title87=成都经济资讯
+File88=mms://vod.chengdutv.com/life
+Title88=成都都市生活
+File89=mms://vod.chengdutv.com/film
+Title89=成都影视文艺
+File90=mms://vod.chengdutv.com/common
+Title90=成都公共
+File91=mms://vod.chengdutv.com/child
+Title91=成都少儿
+File92=mms://live.cbg.cn/cqws
+Title92=重庆卫视
+File93=mms://live.cbg.cn/cqds
+Title93=重庆都市
+File94=mms://live.cbg.cn/cqss
+Title94=重庆时尚
+File95=mms://live.cbg.cn/cqgj
+Title95=重庆国际
+File96=mms://live.cbg.cn/cqkj
+Title96=重庆科教
+File97=mms://live.cbg.cn/gzcp
+Title97=重庆公众彩票
+File98=mms://live.cbg.cn/qmpd
+Title98=重庆汽摩
+File99=mms://live.cbg.cn/mlsz
+Title99=重庆魅力时装
+File100=mms://live2.ncnews.com.cn/sjb
+Title100=南昌电视台4
+File101=mms://202.96.114.251/lstv
+Title101=丽水新闻综合
+File102=mms://202.96.114.251/lstv2
+Title102=丽水经济生活
+File103=mms://61.136.113.41/nytv_1
+Title103=南阳1
+File104=mms://61.136.113.41/nytv_2
+Title104=南阳2
+File105=mms://219.144.186.195/station1
+Title105=西安1
+File106=mms://220.171.12.184/btzx
+Title106=新疆兵团-1
+File107=mms://202.107.35.51/live1
+Title107=辽宁卫视
+File108=mms://202.107.35.51/live2
+Title108=辽宁都市
+File109=mms://202.107.35.51/live3
+Title109=辽宁影视娱乐
+File110=mms://202.107.35.51/live4
+Title110=辽宁体育
+File111=mms://202.107.35.51/live5
+Title111=辽宁青少
+File112=mms://202.107.35.51/live6
+Title112=辽宁生活
+File113=mms://202.107.35.51/live7
+Title113=辽宁游戏竞技
+File114=mms://221.0.171.202/qtv
+Title114=青岛综合
+File115=mms://video.chinactv.com/ctv
+Title115=长春综合
+File116=mms://221.212.177.20/vod
+Title116=黑龙江卫视
diff --git a/totem/plugin/sopcast.py b/totem/plugin/sopcast.py
index 53f2a03..21e3e03 100644
--- a/totem/plugin/sopcast.py
+++ b/totem/plugin/sopcast.py
@@ -9,6 +9,7 @@ import time
import re
import os
import random
+import ConfigParser
import gettext
from xml.dom import minidom
@@ -45,7 +46,8 @@ def unescape_xml (data):
gconf_key = '/apps/totem/plugins/sctream'
sc_cache_dir = os.path.expanduser ('~/.local/share/totem/plugin/sopcast')
-
+sc_system_playlist = os.path.join (os.path.dirname (__file__), 'channels.pls')
+sc_playlist = os.path.join (sc_cache_dir, 'channels.pls')
sc_xmls_dir = os.path.join (sc_cache_dir, "xmls")
sc_images_dir = os.path.join (sc_cache_dir, "images")
@@ -124,6 +126,8 @@ class Sopcast (totem.Plugin):
self.channels += [ 'http://channel.sopcast.cn/gchlxml' ]
self.channels += [ 'http://people.freedesktop.org/~jinghua/sopcast/gchlxml' ]
self.channels_index = 0
+ self.source_id = 0
+ self.playlist = []
def update_translation (self, builder):
for obj in builder.get_objects ():
@@ -199,10 +203,12 @@ class Sopcast (totem.Plugin):
self.notebook = self.builder.get_object ("sc_notebook")
self.notebook.connect ("switch-page", self.on_notebook_page_changed)
- self.notebook_pages = ["channels"]
+ self.notebook_pages = ["channels", 'playlist']
self.current_treeview_name = "channels"
self.load_config ()
+ self.setup_popup_menu ()
self.setup_channels ()
+ self.setup_playlist ()
self.setup_config_dialog ()
self.vbox = self.builder.get_object ("sc_vbox")
@@ -249,6 +255,90 @@ class Sopcast (totem.Plugin):
time.sleep (0.001)
return True
+ def on_add_to_station_list (self, treeview):
+ treeview_name = self.current_treeview_name
+ treeview = self.treeview[treeview_name]
+ selection = treeview.get_selection ()
+ model = treeview.get_model ()
+ model, rows = selection.get_selected_rows ()
+
+ for row in rows:
+ iter = model.get_iter (row)
+ mrl = model.get_value (iter, 2)
+ print mrl
+
+ def on_remove_from_station_list (self, treeview):
+ treeview_name = self.current_treeview_name
+ assert treeview_name == 'playlist'
+
+ treeview = self.treeview[treeview_name]
+ selection = treeview.get_selection ()
+ model = treeview.get_model ()
+ model, rows = selection.get_selected_rows ()
+
+ for row in rows:
+ self.remove_from_playlist (row[0])
+
+ def on_copy_location (self, action):
+ treeview_name = self.current_treeview_name
+ treeview = self.treeview[treeview_name]
+ selection = treeview.get_selection ()
+ model = treeview.get_model ()
+ model, rows = selection.get_selected_rows ()
+ iter = model.get_iter (rows[0])
+ if treeview_name == 'channels':
+ mrl = model.get_value (iter, 2)
+ else:
+ mrl = model.get_value (iter, 1)
+
+ clip = gtk.Clipboard ()
+ clip.set_text (mrl)
+ clip = gtk.Clipboard (display = gtk.gdk.display_get_default(),
+ selection = "PRIMARY")
+ clip.set_text (mrl)
+
+ def on_add_station (self, action):
+ treeview_name = self.current_treeview_name
+ dialog = self.builder.get_object ('sopcast_add_station_dialog')
+ dialog.run ()
+
+ def on_add_station_dialog_delete (self, dialog, event):
+ dialog.hide ()
+ return True
+
+ def on_add_station_dialog_close (self, dialog):
+ dialog.hide ()
+
+ def on_add_station_dialog_response (self, dialog, response_id):
+ dialog.hide ()
+ if response_id == gtk.RESPONSE_DELETE_EVENT:
+ return
+ elif response_id == 1:
+ return
+
+ name = self.builder.get_object ('sopcast_add_station_name_entry').get_text ().strip ()
+ location = self.builder.get_object ('sopcast_add_station_location_entry').get_text ().strip ()
+ if not name or not location:
+ return
+ self.add_to_playlist (name, location)
+
+ def setup_popup_menu (self):
+ self.ui_manager = self.builder.get_object ('sopcast-ui-manager')
+ action_group = self.ui_manager.get_action_groups () [0]
+ action = action_group.get_action ("add-to-station-list")
+ action.connect ('activate', self.on_add_to_station_list)
+ action = action_group.get_action ("remove-from-station-list")
+ action.connect ('activate', self.on_remove_from_station_list)
+ action = action_group.get_action ("copy-location")
+ action.connect ('activate', self.on_copy_location)
+ action = action_group.get_action ("add-station")
+ action.connect ('activate', self.on_add_station)
+
+ dialog = self.builder.get_object ('sopcast_add_station_dialog')
+ dialog.connect ("response", self.on_add_station_dialog_response)
+ dialog.connect ("close", self.on_add_station_dialog_close)
+ dialog.connect ("delete-event", self.on_add_station_dialog_delete)
+
def on_channels_row_activated (self, treeview, path, view_column, data=None):
model, rows = treeview.get_selection ().get_selected_rows ()
row = rows[0]
@@ -393,6 +483,8 @@ class Sopcast (totem.Plugin):
treeview.set_model (self.liststore[treeview_name])
treeview.connect("row_activated", self.on_channels_row_activated)
+ treeview.connect ("popup-menu", self.on_treeview_popup_menu)
+ treeview.connect ("button-press-event", self.on_treeview_button_pressed)
self.channels_count = 0
self.channels_downloading = False
@@ -402,6 +494,198 @@ class Sopcast (totem.Plugin):
else:
self.download_channels ()
+ def load_playlist (self, path = sc_playlist):
+ parser = ConfigParser.ConfigParser ()
+ if not parser.read ([path]):
+ return []
+ if not parser.has_section ('playlist'):
+ return []
+ result = {}
+ for item in parser.items ('playlist'):
+ key = item[0]
+ if key[0:4] == 'file':
+ index = str(key[4:])
+ key = 'file'
+ elif key[0:5] == 'title':
+ index = str(key[5:])
+ key = 'title'
+ else:
+ continue
+ if index not in result.keys ():
+ result[index] = {}
+ result[index][key] = item[1]
+ #print item, key, index, result[index]
+
+ keys = result.keys ()
+ keys.sort ()
+ playlist = []
+ for i in range (len (keys)):
+ title = result[keys[i]]['title']
+ url = result[keys[i]]['file']
+ playlist.append ((title, url))
+
+ return playlist
+
+ def save_playlist (self, playlist):
+ if not playlist:
+ return False
+ parser = ConfigParser.RawConfigParser ()
+ parser.add_section ('playlist')
+ parser.set ('playlist', 'NumberOfEntries', str (len (playlist)))
+ for i in range (len (playlist)):
+ parser.set ('playlist', 'File' + str (i + 1), playlist[i][1])
+ parser.set ('playlist', 'Title' + str (i + 1), playlist[i][0])
+ fp = None
+ try:
+ fp = file (sc_playlist, 'wb')
+ except:
+ return False
+ parser.write (fp)
+ fp.close ()
+ return True
+
+ def show_playlist (self):
+ treeview_name = 'playlist'
+ treeview = self.liststore[treeview_name]
+ self.clear_pages (treeview_name)
+
+ for item in self.playlist:
+ iter = treeview.append (None)
+ treeview.set (iter,
+ 0, item[0],
+ 1, item[1])
+
+ def add_to_playlist (self, title, mrl):
+ treeview_name = 'playlist'
+ treeview = self.liststore[treeview_name]
+ if (title, mrl) in self.playlist:
+ return
+
+ self.playlist.append ((title, mrl))
+ self.save_playlist (self.playlist)
+
+ iter = treeview.append (None)
+ treeview.set (iter,
+ 0, title,
+ 1, mrl)
+
+ def remove_from_playlist (self, row):
+ treeview_name = 'playlist'
+ treeview = self.liststore[treeview_name]
+
+ del self.playlist[row]
+ self.save_playlist (self.playlist)
+
+ iter = treeview.get_iter (row)
+ treeview.remove (iter)
+
+ def on_playlist_row_activated (self, treeview, path, view_column, data=None):
+ model, rows = treeview.get_selection ().get_selected_rows ()
+ row = rows[0]
+
+ iter = model.get_iter (row)
+ title = model.get_value (iter, 0)
+ mrl = model.get_value (iter, 1)
+
+ if hasattr(self.totem, "add_to_playlist_and_play"):
+ self.totem.add_to_playlist_and_play (mrl, title, False)
+ else:
+ self.totem.action_remote (totem.REMOTE_COMMAND_REPLACE, mrl)
+
+ def setup_playlist (self):
+ treeview_name = 'playlist'
+ treeview = self.builder.get_object ("sc_treeview_" + treeview_name)
+ renderer = gtk.CellRendererText ()
+ renderer.set_property("xalign", 0.0)
+
+ column = gtk.TreeViewColumn(_("Name"), renderer, text = 0)
+ column.set_clickable(True)
+ treeview.append_column(column)
+
+ column = gtk.TreeViewColumn(_("Location"), renderer, text = 1)
+ treeview.append_column(column)
+
+ self.vadjust[treeview_name] = treeview.get_vadjustment ()
+ #self.vadjust[treeview_name].connect ("value-changed", self.on_playlist_value_changed)
+ vscroll = self.builder.get_object ("sc_scrolled_window_" + treeview_name).get_vscrollbar ()
+ #vscroll.connect ("button-press-event", self.on_playlist_button_press_event)
+ #vscroll.connect ("button-release-event", self.on_playlist_button_release_event)
+
+ self.liststore[treeview_name] = self.builder.get_object ("sc_liststore_" + treeview_name)
+ self.treeview[treeview_name] = treeview
+ treeview.set_model (self.liststore[treeview_name])
+
+ treeview.connect("row_activated", self.on_playlist_row_activated)
+ treeview.connect ("popup-menu", self.on_treeview_popup_menu)
+ treeview.connect ("button-press-event", self.on_treeview_button_pressed)
+ treeview.connect ("key-press-event", self.on_playlist_key_pressed)
+
+ selection = treeview.get_selection ()
+ selection.set_mode (gtk.SELECTION_MULTIPLE)
+
+ try:
+ self.playlist = self.load_playlist ()
+ if not self.playlist:
+ self.playlist = self.load_playlist (sc_system_playlist)
+ except Exception, e:
+ print 'Failed to load play list', e
+ self.playlist = []
+
+ self.show_playlist ()
+
+ def show_popup_menu (self, event = None):
+ treeview_name = self.current_treeview_name
+ treeview = self.treeview [treeview_name]
+ selection = treeview.get_selection ()
+
+ if event:
+ button = event.button
+ time = event.time
+ path = treeview.get_path_at_pos (int(event.x), int(event.y))
+ if not path or not selection.path_is_selected (path[0]):
+ selection.unselect_all ()
+ else:
+ time = gtk.get_current_event_time ()
+ button = None
+
+ count = selection.count_selected_rows ()
+ if not count:
+ return False
+
+ action_group = self.ui_manager.get_action_groups () [0]
+ action = action_group.get_action ("copy-location")
+ action.set_sensitive (count == 1)
+
+ action = action_group.get_action ("add-to-station-list")
+ action.set_sensitive (treeview_name == 'channels')
+
+ action = action_group.get_action ("remove-from-station-list")
+ action.set_sensitive (treeview_name == 'playlist')
+
+ action = action_group.get_action ("add-station")
+ action.set_sensitive (treeview_name == 'playlist')
+
+ menu = self.ui_manager.get_widget ("/sopcast-popup")
+ menu.select_first (False)
+ menu.popup (None, None, None, button, time)
+
+ return True
+
+ def on_treeview_popup_menu (self):
+ self.show_popup_menu ()
+
+ def on_treeview_button_pressed (self, widget, event, user_data = None):
+ if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
+ return self.show_popup_menu (event)
+ return False
+
+ def on_playlist_key_pressed (self, wiget, event, user_data = None):
+ if event.type == gtk.gdk.KEY_PRESS and \
+ gtk.gdk.keyval_name (event.keyval) == 'Delete':
+ self.on_remove_from_station_list (self.treeview['playlist'])
+ return True
+ return False
+
def on_notebook_page_changed (self, notebook, notebook_page, page_num):
self.current_treeview_name = self.notebook_pages[page_num]
diff --git a/totem/plugin/sopcast.ui b/totem/plugin/sopcast.ui
index 112f1cd..0c9f547 100644
--- a/totem/plugin/sopcast.ui
+++ b/totem/plugin/sopcast.ui
@@ -12,6 +12,14 @@
<column type="gchararray"/>
</columns>
</object>
+ <object class="GtkTreeStore" id="sc_liststore_playlist">
+ <columns>
+ <!-- column-name Title -->
+ <column type="gchararray"/>
+ <!-- column-name MRL -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
<object class="GtkVBox" id="sc_vbox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
@@ -93,9 +101,39 @@
<child type="tab">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
- <property name="label" translatable="yes">Channels</property>
+ <property name="label" translatable="yes">Channels(Sopcast)</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="sc_scrolled_window_playlist">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="sc_treeview_playlist">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">sc_liststore_playlist</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Channels(Personal)</property>
</object>
<packing>
+ <property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -114,5 +152,152 @@
</packing>
</child>
</object>
- <object class="GtkUIManager" id="sc-list-ui-manager"/>
+ <object class="GtkDialog" id="sopcast_add_station_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Add a station to station list</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <child>
+ <object class="GtkEntry" id="sopcast_add_station_name_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="sopcast_add_station_location_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="sopcast_add_station_name_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Name:</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="sopcast_add_station_location_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Location:</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="sopcast_add_station_ok_button">
+ <property name="label">gtk-ok</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="sopcast_add_station_cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">sopcast_add_station_ok_button</action-widget>
+ <action-widget response="1">sopcast_add_station_cancel_button</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkUIManager" id="sopcast-ui-manager">
+ <child>
+ <object class="GtkActionGroup" id="sopcast-action-group">
+ <child>
+ <object class="GtkAction" id="add-to-station-list">
+ <property name="label" translatable="yes">_Add the station</property>
+ <property name="tooltip" translatable="yes">Add the station to list</property>
+ <property name="stock-id">gtk-add</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="remove-from-station-list">
+ <property name="label" translatable="yes">_Remove the station</property>
+ <property name="tooltip" translatable="yes">Remove the station from list</property>
+ <property name="stock-id">gtk-remove</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="add-station">
+ <property name="label" translatable="yes">_New station</property>
+ <property name="tooltip" translatable="yes">Add a new station to the list</property>
+ <property name="stock-id">gtk-add</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="copy-location">
+ <property name="label" translatable="yes">_Copy Location</property>
+ <property name="tooltip" translatable="yes">Copy the location to the clipboard</property>
+ <property name="stock-id">gtk-copy</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <ui>
+ <popup name="sopcast-popup">
+ <menuitem name="add-to-station-list" action="add-to-station-list"/>
+ <menuitem name="remove-from-station-list" action="remove-from-station-list"/>
+ <menuitem name="add-station" action="add-station"/>
+ <menuitem name="copy-location" action="copy-location"/>
+ </popup>
+ </ui>
+ </object>
</interface>