inital commit
This commit is contained in:
commit
6eeb10c4fc
|
@ -0,0 +1,131 @@
|
||||||
|
# ---> Python
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
MIT License Copyright (c) <year> <copyright holders>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||||
|
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,3 @@
|
||||||
|
# premiere-deluge-plugin
|
||||||
|
|
||||||
|
Broadcast Torrents in a premiere way!
|
|
@ -0,0 +1,19 @@
|
||||||
|
from deluge.plugins.init import PluginInitBase
|
||||||
|
|
||||||
|
class CorePlugin(PluginInitBase):
|
||||||
|
def __init__(self, plugin_name):
|
||||||
|
from core import Core as _plugin_cls
|
||||||
|
self._plugin_cls = _plugin_cls
|
||||||
|
super(CorePlugin, self).__init__(plugin_name)
|
||||||
|
|
||||||
|
class GtkUIPlugin(PluginInitBase):
|
||||||
|
def __init__(self, plugin_name):
|
||||||
|
from gtkui import GtkUI as _plugin_cls
|
||||||
|
self._plugin_cls = _plugin_cls
|
||||||
|
super(GtkUIPlugin, self).__init__(plugin_name)
|
||||||
|
|
||||||
|
class WebUIPlugin(PluginInitBase):
|
||||||
|
def __init__(self, plugin_name):
|
||||||
|
from webui import WebUI as _plugin_cls
|
||||||
|
self._plugin_cls = _plugin_cls
|
||||||
|
super(WebUIPlugin, self).__init__(plugin_name)
|
|
@ -0,0 +1,3 @@
|
||||||
|
def get_resource(filename):
|
||||||
|
import pkg_resources, os
|
||||||
|
return pkg_resources.resource_filename("premiere", os.path.join("data", filename))
|
|
@ -0,0 +1,68 @@
|
||||||
|
from deluge.plugins.pluginbase import CorePluginBase
|
||||||
|
import deluge.component as component
|
||||||
|
from deluge.core.rpcserver import export
|
||||||
|
|
||||||
|
from twisted.internet.task import LoopingCall, deferLater
|
||||||
|
from twisted.internet import reactor
|
||||||
|
|
||||||
|
|
||||||
|
class Core(CorePluginBase):
|
||||||
|
def enable(self):
|
||||||
|
self.loop = None
|
||||||
|
self.premiere_torrents = {}
|
||||||
|
deferLater(reactor, 5, self.enable_loop)
|
||||||
|
|
||||||
|
def enable_loop(self):
|
||||||
|
self.loop = LoopingCall(self.premiere_loop)
|
||||||
|
self.loop.start(10)
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
if self.loop and self.loop.running:
|
||||||
|
self.loop.stop()
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@export
|
||||||
|
def add_premiere_torrent(self, torr):
|
||||||
|
self.premiere_torrents[torr] = True
|
||||||
|
tor_handle = component.get("TorrentManager").torrents[torr].handle
|
||||||
|
for i in range(1, tor_handle.get_torrent_info().num_pieces()+1):
|
||||||
|
tor_handle.set_piece_premiere(i, True)
|
||||||
|
|
||||||
|
@export
|
||||||
|
def del_premiere_torrent(self, torr):
|
||||||
|
if self.is_premiere_torrent(torr):
|
||||||
|
del self.premiere_torrents[torr]
|
||||||
|
tor = component.get("TorrentManager").torrents[torr].handle
|
||||||
|
if not tor:
|
||||||
|
return
|
||||||
|
tor_handle = tor.handle
|
||||||
|
for i in range(tor_handle.get_torrent_info().num_pieces()+1):
|
||||||
|
tor_handle.set_piece_premiere(i, False)
|
||||||
|
|
||||||
|
@export
|
||||||
|
def is_premiere_torrent(self, torr):
|
||||||
|
return torr in self.premiere_torrents
|
||||||
|
|
||||||
|
@export
|
||||||
|
def get_premiere_torrents(self):
|
||||||
|
return self.premiere_torrents
|
||||||
|
|
||||||
|
def premiere_loop(self):
|
||||||
|
torrents = self.get_premiere_torrents()
|
||||||
|
for t in torrents:
|
||||||
|
tor = component.get("TorrentManager").torrents.get(t)
|
||||||
|
if not tor:
|
||||||
|
self.del_premiere_torrent(t)
|
||||||
|
continue
|
||||||
|
if tor.status.state == tor.status.seeding:
|
||||||
|
tor = tor.handle
|
||||||
|
if not tor.get_peer_info():
|
||||||
|
continue
|
||||||
|
if not all(len(p.pieces) > 0 and p.pieces[0] for p in tor.get_peer_info()):
|
||||||
|
tor.force_reannounce()
|
||||||
|
tor.set_piece_premiere(0, False)
|
||||||
|
for i in range(0, tor.get_torrent_info().num_pieces()+1):
|
||||||
|
if all(len(p.pieces) > i and p.pieces[i] for p in tor.get_peer_info()) and tor.is_piece_premiere(i+1):
|
||||||
|
tor.set_piece_premiere(i+1, False)
|
|
@ -0,0 +1,42 @@
|
||||||
|
Ext.namespace('Deluge.premiere');
|
||||||
|
Deluge.premiere.PremierePlugin = Ext.extend(Deluge.Plugin, {
|
||||||
|
name: "Premiere",
|
||||||
|
|
||||||
|
onDisable: function() {
|
||||||
|
deluge.menus.torrent.remove(this.ci);
|
||||||
|
},
|
||||||
|
|
||||||
|
onEnable: function() {
|
||||||
|
this.ci = deluge.menus.torrent.add(new Ext.menu.CheckItem({
|
||||||
|
text: "Premiere Mode",
|
||||||
|
checkHandler: this.onTogglePremiere,
|
||||||
|
scope: this
|
||||||
|
}));
|
||||||
|
deluge.menus.torrent.on('show', this.onMenuShow, this, {stopEvent : true});
|
||||||
|
},
|
||||||
|
|
||||||
|
onMenuShow: function() {
|
||||||
|
var tid = deluge.torrents.getSelectedIds()[0];
|
||||||
|
deluge.client.premiere.is_premiere_torrent(tid, {
|
||||||
|
success: function (is_prem) {
|
||||||
|
this.ci.setChecked(is_prem, true);
|
||||||
|
},
|
||||||
|
scope: this
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onTogglePremiere: function(item, checked) {
|
||||||
|
var ids = deluge.torrents.getSelectedIds();
|
||||||
|
if (checked) {
|
||||||
|
for (var i = 0; i < ids.length; i++) {
|
||||||
|
deluge.client.premiere.add_premiere_torrent(ids[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < ids.length; i++) {
|
||||||
|
deluge.client.premiere.del_premiere_torrent(ids[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Deluge.registerPlugin('Premiere', Deluge.premiere.PremierePlugin);
|
|
@ -0,0 +1,37 @@
|
||||||
|
import gtk
|
||||||
|
|
||||||
|
from deluge.log import LOG as log
|
||||||
|
from deluge.ui.client import client
|
||||||
|
from deluge.plugins.pluginbase import GtkPluginBase
|
||||||
|
import deluge.component as component
|
||||||
|
import deluge.common
|
||||||
|
|
||||||
|
from common import get_resource
|
||||||
|
|
||||||
|
class GtkUI(GtkPluginBase):
|
||||||
|
def enable(self):
|
||||||
|
torrentmenu = component.get("MenuBar").torrentmenu_glade.get_widget("torrent_menu")
|
||||||
|
|
||||||
|
self.sep = gtk.SeparatorMenuItem()
|
||||||
|
self.item = gtk.CheckMenuItem(_("_Premiere Mode"))
|
||||||
|
self.item.connect("toggled", self.on_checkbox_toggle)
|
||||||
|
|
||||||
|
torrentmenu.append(self.sep)
|
||||||
|
torrentmenu.append(self.item)
|
||||||
|
|
||||||
|
self.sep.show()
|
||||||
|
self.item.show()
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
torrentmenu = component.get("MenuBar").torrentmenu_glade.get_widget("torrent_menu")
|
||||||
|
torrentmenu.remove(self.item)
|
||||||
|
torrentmenu.remove(self.sep)
|
||||||
|
|
||||||
|
def on_checkbox_toggle(self, checkbox):
|
||||||
|
ids = component.get("TorrentView").get_selected_torrents()
|
||||||
|
if checkbox.active:
|
||||||
|
for torrent_id in ids:
|
||||||
|
client.premiere.add_premiere_torrent(torrent_id)
|
||||||
|
else:
|
||||||
|
for torrent_id in ids:
|
||||||
|
client.premiere.del_premiere_torrent(torrent_id)
|
|
@ -0,0 +1,5 @@
|
||||||
|
from deluge.plugins.pluginbase import WebPluginBase
|
||||||
|
from common import get_resource
|
||||||
|
|
||||||
|
class WebUI(WebPluginBase):
|
||||||
|
scripts = [get_resource("premiere.js")]
|
|
@ -0,0 +1,36 @@
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
__plugin_name__ = "Premiere"
|
||||||
|
__version__ = "0.5"
|
||||||
|
__description__ = "Enable putting torrents into 'premiere mode' to be broadcast sequentially."
|
||||||
|
__long_description__ = """
|
||||||
|
Premiere Plugin
|
||||||
|
|
||||||
|
Setting a torrent to premiere mode causes all of its pieces to become
|
||||||
|
unavailble to peers except the first piece. After all peers in the swarm
|
||||||
|
have completely downloaded the first piece, the second piece gets announced
|
||||||
|
as available and peers may download it. This continues on until the last piece.
|
||||||
|
|
||||||
|
This plugin requires a forked version of libtorrent that supports setting pieces
|
||||||
|
into premiere mode.
|
||||||
|
"""
|
||||||
|
__pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]}
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name=__plugin_name__,
|
||||||
|
version=__version__,
|
||||||
|
description=__description__,
|
||||||
|
long_description=__long_description__ if __long_description__ else __description__,
|
||||||
|
|
||||||
|
packages=[__plugin_name__.lower()],
|
||||||
|
package_data = __pkg_data__,
|
||||||
|
|
||||||
|
entry_points="""
|
||||||
|
[deluge.plugin.core]
|
||||||
|
%s = %s:CorePlugin
|
||||||
|
[deluge.plugin.gtkui]
|
||||||
|
%s = %s:GtkUIPlugin
|
||||||
|
[deluge.plugin.web]
|
||||||
|
%s = %s:WebUIPlugin
|
||||||
|
""" % ((__plugin_name__, __plugin_name__.lower())*3)
|
||||||
|
)
|
Loading…
Reference in New Issue