2015-01-22 19:41:44 +01:00
|
|
|
#
|
|
|
|
|
# gtkui.py
|
|
|
|
|
#
|
|
|
|
|
# Copyright (C) 2009 John Doee <johndoee@tidalstream.org>
|
|
|
|
|
#
|
|
|
|
|
# Basic plugin template created by:
|
|
|
|
|
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
|
|
|
|
|
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
|
|
|
|
|
# Copyright (C) 2009 Damien Churchill <damoxc@gmail.com>
|
|
|
|
|
#
|
|
|
|
|
# Deluge is free software.
|
|
|
|
|
#
|
|
|
|
|
# You may 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.
|
|
|
|
|
#
|
|
|
|
|
# deluge 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 deluge. If not, write to:
|
|
|
|
|
# The Free Software Foundation, Inc.,
|
|
|
|
|
# 51 Franklin Street, Fifth Floor
|
|
|
|
|
# Boston, MA 02110-1301, USA.
|
|
|
|
|
#
|
|
|
|
|
# In addition, as a special exception, the copyright holders give
|
|
|
|
|
# permission to link the code of portions of this program with the OpenSSL
|
|
|
|
|
# library.
|
|
|
|
|
# You must obey the GNU General Public License in all respects for all of
|
|
|
|
|
# the code used other than OpenSSL. If you modify file(s) with this
|
|
|
|
|
# exception, you may extend this exception to your version of the file(s),
|
|
|
|
|
# but you are not obligated to do so. If you do not wish to do so, delete
|
|
|
|
|
# this exception statement from your version. If you delete this exception
|
|
|
|
|
# statement from all source files in the program, then also delete it here.
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
import gtk
|
2017-08-18 17:01:16 +02:00
|
|
|
import os
|
|
|
|
|
import subprocess
|
|
|
|
|
import sys
|
2015-01-22 19:41:44 +01:00
|
|
|
|
|
|
|
|
from deluge.log import LOG as log
|
|
|
|
|
from deluge.ui.client import client
|
|
|
|
|
from deluge.ui.gtkui import dialogs
|
|
|
|
|
from deluge.plugins.pluginbase import GtkPluginBase
|
|
|
|
|
import deluge.component as component
|
|
|
|
|
import deluge.common
|
|
|
|
|
|
2017-12-17 19:38:53 +01:00
|
|
|
from twisted.internet import defer, threads
|
2015-11-17 22:41:14 +01:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
from common import get_resource
|
|
|
|
|
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2017-08-18 17:01:16 +02:00
|
|
|
def execute_url(url):
|
|
|
|
|
if sys.platform == 'win32':
|
|
|
|
|
os.startfile(url)
|
|
|
|
|
elif sys.platform == 'darwin':
|
|
|
|
|
subprocess.Popen(['open', url])
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
subprocess.Popen(['xdg-open', url])
|
|
|
|
|
except OSError:
|
|
|
|
|
print 'Unable to open URL %s' % (url, )
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-11-17 22:41:14 +01:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
class GtkUI(GtkPluginBase):
|
2018-02-20 17:43:23 +01:00
|
|
|
def get_widget(self, widget_name):
|
|
|
|
|
main_window = component.get("MainWindow")
|
|
|
|
|
if hasattr(main_window, 'main_glade'):
|
|
|
|
|
return main_window.main_glade.get_widget(widget_name)
|
|
|
|
|
else:
|
|
|
|
|
return main_window.main_builder.get_object(widget_name)
|
|
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
def enable(self):
|
|
|
|
|
self.glade = gtk.glade.XML(get_resource("config.glade"))
|
|
|
|
|
|
|
|
|
|
component.get("Preferences").add_page("Streaming", self.glade.get_widget("prefs_box"))
|
|
|
|
|
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
|
|
|
|
|
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2018-02-20 17:43:23 +01:00
|
|
|
file_menu = self.get_widget('menu_file_tab')
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
self.sep = gtk.SeparatorMenuItem()
|
|
|
|
|
self.item = gtk.MenuItem(_("_Stream this file"))
|
|
|
|
|
self.item.connect("activate", self.on_menuitem_stream)
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
file_menu.append(self.sep)
|
|
|
|
|
file_menu.append(self.item)
|
|
|
|
|
|
|
|
|
|
self.sep.show()
|
|
|
|
|
self.item.show()
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-11-21 19:05:01 +01:00
|
|
|
torrentmenu = component.get("MenuBar").torrentmenu
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-11-21 19:05:01 +01:00
|
|
|
self.sep_torrentmenu = gtk.SeparatorMenuItem()
|
|
|
|
|
self.item_torrentmenu = gtk.MenuItem(_("_Stream this torrent"))
|
|
|
|
|
self.item_torrentmenu.connect("activate", self.on_torrentmenu_menuitem_stream)
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-11-21 19:05:01 +01:00
|
|
|
torrentmenu.append(self.sep_torrentmenu)
|
|
|
|
|
torrentmenu.append(self.item_torrentmenu)
|
|
|
|
|
|
|
|
|
|
self.sep_torrentmenu.show()
|
|
|
|
|
self.item_torrentmenu.show()
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
def disable(self):
|
|
|
|
|
component.get("Preferences").remove_page("Streaming")
|
|
|
|
|
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
|
|
|
|
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2018-02-20 17:43:23 +01:00
|
|
|
file_menu = self.get_widget('menu_file_tab')
|
2015-01-22 19:41:44 +01:00
|
|
|
|
|
|
|
|
file_menu.remove(self.item)
|
|
|
|
|
file_menu.remove(self.sep)
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-11-21 19:05:01 +01:00
|
|
|
torrentmenu = component.get("MenuBar").torrentmenu
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-11-21 20:29:42 +01:00
|
|
|
torrentmenu.remove(self.item_torrentmenu)
|
|
|
|
|
torrentmenu.remove(self.sep_torrentmenu)
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
@defer.inlineCallbacks
|
2015-01-22 19:41:44 +01:00
|
|
|
def on_apply_prefs(self):
|
|
|
|
|
log.debug("applying prefs for Streaming")
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
if self.glade.get_widget("input_serve_standalone").get_active():
|
|
|
|
|
serve_method = 'standalone'
|
|
|
|
|
elif self.glade.get_widget("input_serve_webui").get_active():
|
|
|
|
|
serve_method = 'webui'
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
if self.glade.get_widget("input_ssl_cert_daemon").get_active():
|
|
|
|
|
ssl_source = 'daemon'
|
|
|
|
|
elif self.glade.get_widget("input_ssl_cert_custom").get_active():
|
|
|
|
|
ssl_source = 'custom'
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
config = {
|
|
|
|
|
"ip": self.glade.get_widget("input_ip").get_text(),
|
|
|
|
|
"port": int(self.glade.get_widget("input_port").get_text()),
|
2015-11-17 22:41:14 +01:00
|
|
|
"use_stream_urls": self.glade.get_widget("input_use_stream_urls").get_active(),
|
|
|
|
|
"auto_open_stream_urls": self.glade.get_widget("input_auto_open_stream_urls").get_active(),
|
2015-01-22 19:41:44 +01:00
|
|
|
"allow_remote": self.glade.get_widget("input_allow_remote").get_active(),
|
2016-09-07 20:00:49 +02:00
|
|
|
"download_only_streamed": self.glade.get_widget("input_download_only_streamed").get_active(),
|
|
|
|
|
"use_ssl": self.glade.get_widget("input_use_ssl").get_active(),
|
2015-03-16 22:21:00 +01:00
|
|
|
"remote_username": self.glade.get_widget("input_remote_username").get_text(),
|
|
|
|
|
"remote_password": self.glade.get_widget("input_remote_password").get_text(),
|
2016-09-07 20:00:49 +02:00
|
|
|
"ssl_priv_key_path": self.glade.get_widget("input_ssl_priv_key_path").get_text(),
|
|
|
|
|
"ssl_cert_path": self.glade.get_widget("input_ssl_cert_path").get_text(),
|
|
|
|
|
"serve_method": serve_method,
|
|
|
|
|
"ssl_source": ssl_source,
|
2015-01-22 19:41:44 +01:00
|
|
|
}
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
result = yield client.streaming.set_config(config)
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
if result:
|
|
|
|
|
message_type, message_class, message = result
|
|
|
|
|
if message_type == 'error':
|
|
|
|
|
topic = 'Unknown error type'
|
|
|
|
|
if message_class == 'ssl':
|
|
|
|
|
topic = 'SSL Failed'
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
dialogs.ErrorDialog(topic, message).run()
|
2015-01-22 19:41:44 +01:00
|
|
|
|
|
|
|
|
def on_show_prefs(self):
|
|
|
|
|
client.streaming.get_config().addCallback(self.cb_get_config)
|
|
|
|
|
|
|
|
|
|
def cb_get_config(self, config):
|
|
|
|
|
"callback for on show_prefs"
|
|
|
|
|
self.glade.get_widget("input_ip").set_text(config["ip"])
|
|
|
|
|
self.glade.get_widget("input_port").set_text(str(config["port"]))
|
2015-11-17 22:41:14 +01:00
|
|
|
self.glade.get_widget("input_use_stream_urls").set_active(config["use_stream_urls"])
|
|
|
|
|
self.glade.get_widget("input_auto_open_stream_urls").set_active(config["auto_open_stream_urls"])
|
2015-01-22 19:41:44 +01:00
|
|
|
self.glade.get_widget("input_allow_remote").set_active(config["allow_remote"])
|
2016-09-07 20:00:49 +02:00
|
|
|
self.glade.get_widget("input_use_ssl").set_active(config["use_ssl"])
|
|
|
|
|
self.glade.get_widget("input_download_only_streamed").set_active(config["download_only_streamed"])
|
2015-03-16 22:21:00 +01:00
|
|
|
self.glade.get_widget("input_remote_username").set_text(config["remote_username"])
|
|
|
|
|
self.glade.get_widget("input_remote_password").set_text(config["remote_password"])
|
2016-09-07 20:00:49 +02:00
|
|
|
self.glade.get_widget("input_ssl_priv_key_path").set_text(config["ssl_priv_key_path"])
|
|
|
|
|
self.glade.get_widget("input_ssl_cert_path").set_text(config["ssl_cert_path"])
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
self.glade.get_widget("input_serve_standalone").set_active(config["serve_method"] == "standalone")
|
|
|
|
|
self.glade.get_widget("input_serve_webui").set_active(config["serve_method"] == "webui")
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2016-09-07 20:00:49 +02:00
|
|
|
self.glade.get_widget("input_ssl_cert_daemon").set_active(config["ssl_source"] == "daemon")
|
|
|
|
|
self.glade.get_widget("input_ssl_cert_custom").set_active(config["ssl_source"] == "custom")
|
2015-01-22 19:41:44 +01:00
|
|
|
|
2017-08-12 13:27:32 +02:00
|
|
|
api_url = 'http%s://%s:%s/streaming/stream' % (('s' if config["use_ssl"] else ''), config["ip"], config["port"])
|
|
|
|
|
self.glade.get_widget("output_remote_url").set_text(api_url)
|
|
|
|
|
|
2015-11-17 22:41:14 +01:00
|
|
|
def stream_ready(self, result):
|
|
|
|
|
if result['status'] == 'success':
|
|
|
|
|
if result.get('use_stream_urls', False):
|
|
|
|
|
url = "stream+%s" % result['url']
|
|
|
|
|
if result.get('auto_open_stream_urls', False):
|
2017-08-18 17:01:16 +02:00
|
|
|
threads.deferToThread(execute_url, url)
|
2015-11-17 22:41:14 +01:00
|
|
|
else:
|
2017-08-18 17:01:16 +02:00
|
|
|
def on_dialog_callback(response):
|
|
|
|
|
if response == gtk.RESPONSE_YES:
|
|
|
|
|
threads.deferToThread(execute_url, url)
|
|
|
|
|
|
|
|
|
|
dialogs.YesNoDialog('Stream ready', 'Do you want to play the video?').run().addCallback(on_dialog_callback)
|
2015-11-17 22:41:14 +01:00
|
|
|
else:
|
|
|
|
|
dialogs.ErrorDialog('Stream ready', 'Copy the link into a media player', details=result['url']).run()
|
|
|
|
|
else:
|
|
|
|
|
dialogs.ErrorDialog('Stream failed', 'Was unable to prepare the stream', details=result).run()
|
|
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
def on_menuitem_stream(self, data=None):
|
|
|
|
|
torrent_id = component.get("TorrentView").get_selected_torrents()[0]
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
ft = component.get("TorrentDetails").tabs['Files']
|
|
|
|
|
paths = ft.listview.get_selection().get_selected_rows()[1]
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
selected = []
|
|
|
|
|
for path in paths:
|
|
|
|
|
selected.append(ft.treestore.get_iter(path))
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-01-22 19:41:44 +01:00
|
|
|
for select in selected:
|
|
|
|
|
path = ft.get_file_path(select)
|
2015-11-22 16:20:37 +01:00
|
|
|
client.streaming.stream_torrent(infohash=torrent_id, filepath_or_index=path, includes_name=True).addCallback(self.stream_ready)
|
2015-11-17 22:41:14 +01:00
|
|
|
break
|
2017-08-12 13:27:32 +02:00
|
|
|
|
2015-11-21 19:05:01 +01:00
|
|
|
def on_torrentmenu_menuitem_stream(self, data=None):
|
|
|
|
|
torrent_id = component.get("TorrentView").get_selected_torrents()[0]
|
|
|
|
|
client.streaming.stream_torrent(infohash=torrent_id).addCallback(self.stream_ready)
|