Update to support V2

Hopefully?
This commit is contained in:
d8ahazard
2019-10-23 11:37:58 -05:00
parent 1bef5756cf
commit 2424b7750a
10 changed files with 279 additions and 360 deletions

3
.gitignore vendored
View File

@@ -1,10 +1,11 @@
.DS_Store .DS_Store
.AppleDouble .AppleDouble
.LSOverride .LSOverride
.idea
# Icon must end with two \r # Icon must end with two \r
Icon Icon
# Thumbnails # Thumbnails
._* ._*

View File

@@ -1,52 +1,25 @@
# # -*- coding: utf-8 -*-
# setup.py
# #
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2015 Chris Yereaztian <chris.yereaztian@gmail.com>
# #
# Basic plugin template created by: # Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com> # Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# # the additional special exception to link portions of this program with the OpenSSL library.
# You may redistribute it and/or modify it under the terms of the # See LICENSE for more details.
# 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.
#
# #
from setuptools import setup from setuptools import find_packages, setup
__plugin_name__ = "SimpleExtractor" __plugin_name__ = 'SimpleExtractor'
__author__ = "Chris Yereaztian" __author__ = 'Digitalhigh'
__author_email__ = "chris.yereaztian@gmail.com" __author_email__ = 'donate.to.digitalhigh@gmail.com'
__version__ = "0.4.1" __version__ = '0.7'
__url__ = "github.com/cvarta/deluge-extractor" __url__ = 'github.com/d8ahazard/deluge-extractor'
__license__ = "GPLv3" __license__ = 'GPLv3'
__description__ = "Extract files upon torrent completion" __description__ = 'Extract files upon torrent completion'
__long_description__ = """ __long_description__ = """
Extract files upon torrent completion Extract files upon torrent completion
@@ -57,7 +30,7 @@ Windows support: .rar, .zip, .tar, .7z, .xz, .lzma
Note: Will not extract with 'Move Completed' enabled Note: Will not extract with 'Move Completed' enabled
""" """
__pkg_data__ = {__plugin_name__.lower(): ["template/*", "data/*"]} __pkg_data__ = {'deluge_' + __plugin_name__.lower(): ['data/*']}
setup( setup(
name=__plugin_name__, name=__plugin_name__,
@@ -68,16 +41,15 @@ setup(
url=__url__, url=__url__,
license=__license__, license=__license__,
long_description=__long_description__ if __long_description__ else __description__, long_description=__long_description__ if __long_description__ else __description__,
packages=find_packages(),
packages=[__plugin_name__.lower()], package_data=__pkg_data__,
package_data = __pkg_data__,
entry_points=""" entry_points="""
[deluge.plugin.core] [deluge.plugin.core]
%s = %s:CorePlugin %s = deluge_%s:CorePlugin
[deluge.plugin.gtkui] [deluge.plugin.gtk3ui]
%s = %s:GtkUIPlugin %s = deluge_%s:GtkUIPlugin
[deluge.plugin.web] [deluge.plugin.web]
%s = %s:WebUIPlugin %s = deluge_%s:WebUIPlugin
""" % ((__plugin_name__, __plugin_name__.lower())*3) """
% ((__plugin_name__, __plugin_name__.lower()) * 3),
) )

View File

@@ -39,6 +39,7 @@
# #
from deluge.plugins.init import PluginInitBase from deluge.plugins.init import PluginInitBase
from __future__ import unicode_literals
class CorePlugin(PluginInitBase): class CorePlugin(PluginInitBase):
def __init__(self, plugin_name): def __init__(self, plugin_name):

View File

@@ -1,39 +1,23 @@
# -*- coding: utf-8 -*-
# #
# common.py # Basic plugin template created by:
# # Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> # 2007-2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2015 Chris Yereaztian <chris.yereaztian@gmail.com> # 2009 Damien Churchill <damoxc@gmail.com>
# # 2010 Pedro Algarvio <pedro@algarvio.me>
# Deluge is free software. # 2017 Calum Lind <calumlind+deluge@gmail.com>
#
# 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.
# #
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
# #
from __future__ import unicode_literals
import os.path
from pkg_resources import resource_filename
def get_resource(filename): def get_resource(filename):
import pkg_resources, os return resource_filename(__package__, os.path.join('data', filename))
return pkg_resources.resource_filename("simpleextractor", os.path.join("data", filename))

View File

@@ -1,60 +1,34 @@
# # -*- coding: utf-8 -*-
# core.py
# #
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2015 Chris Yereaztian <chris.yereaztian@gmail.com>
# #
# Basic plugin template created by: # Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com> # Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# # the additional special exception to link portions of this program with the OpenSSL library.
# You may redistribute it and/or modify it under the terms of the # See LICENSE for more details.
# 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.
#
# #
from __future__ import unicode_literals
import errno
import logging
import os import os
from twisted.internet.utils import getProcessValue from twisted.internet.utils import getProcessOutputAndValue
from twisted.python.procutils import which
from deluge.log import LOG as log
from deluge.plugins.pluginbase import CorePluginBase
import deluge.component as component import deluge.component as component
import deluge.configmanager import deluge.configmanager
from deluge.core.rpcserver import export
from deluge.common import windows_check from deluge.common import windows_check
from extractor.which import which from deluge.core.rpcserver import export
from deluge.plugins.pluginbase import CorePluginBase
DEFAULT_PREFS = { log = logging.getLogger(__name__)
"extract_path": "",
"use_name_folder": False, DEFAULT_PREFS = {'extract_path': '', 'use_name_folder': True, 'in_place_extraction': True}
"in_place_extraction": True
}
if windows_check(): if windows_check():
win_7z_exes = [ win_7z_exes = [
@@ -63,69 +37,84 @@ if windows_check():
'C:\\Program Files (x86)\\7-Zip\\7z.exe', 'C:\\Program Files (x86)\\7-Zip\\7z.exe',
] ]
import _winreg
try: try:
hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\7-Zip") import winreg
except ImportError:
import _winreg as winreg # For Python 2.
try:
hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Software\\7-Zip')
except WindowsError: except WindowsError:
pass pass
else: else:
win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, "Path")[0], "7z.exe") win_7z_path = os.path.join(winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe')
_winreg.CloseKey(hkey) winreg.CloseKey(hkey)
win_7z_exes.insert(1, win_7z_path) win_7z_exes.insert(1, win_7z_path)
switch_7z = "x -y" switch_7z = 'x -y'
## Future suport: # Future suport:
## 7-zip cannot extract tar.* with single command. # 7-zip cannot extract tar.* with single command.
# ".tar.gz", ".tgz", # ".tar.gz", ".tgz",
# ".tar.bz2", ".tbz", # ".tar.bz2", ".tbz",
# ".tar.lzma", ".tlz", # ".tar.lzma", ".tlz",
# ".tar.xz", ".txz", # ".tar.xz", ".txz",
exts_7z = [ exts_7z = ['.rar', '.zip', '.tar', '.7z', '.xz', '.lzma']
".rar", ".zip", ".tar",
".7z", ".xz", ".lzma",
]
for win_7z_exe in win_7z_exes: for win_7z_exe in win_7z_exes:
if which(win_7z_exe): if which(win_7z_exe):
EXTRACT_COMMANDS = dict.fromkeys(exts_7z, [win_7z_exe, switch_7z]) EXTRACT_COMMANDS = dict.fromkeys(exts_7z, [win_7z_exe, switch_7z])
break break
else: else:
required_cmds=["unrar", "unzip", "tar", "unxz", "unlzma", "7zr", "bunzip2"] required_cmds = ['unrar', 'unzip', 'tar', 'unxz', 'unlzma', '7zr', 'bunzip2']
## Possible future suport: # Possible future suport:
# gunzip: gz (cmd will delete original archive) # gunzip: gz (cmd will delete original archive)
## the following do not extract to dest dir # the following do not extract to dest dir
# ".xz": ["xz", "-d --keep"], # ".xz": ["xz", "-d --keep"],
# ".lzma": ["xz", "-d --format=lzma --keep"], # ".lzma": ["xz", "-d --format=lzma --keep"],
# ".bz2": ["bzip2", "-d --keep"], # ".bz2": ["bzip2", "-d --keep"],
EXTRACT_COMMANDS = { EXTRACT_COMMANDS = {
".rar": ["unrar", "x -o+ -y"], '.rar': ['unrar', 'x -o+ -y'],
".tar": ["tar", "-xf"], '.tar': ['tar', '-xf'],
".zip": ["unzip", ""], '.zip': ['unzip', ''],
".tar.gz": ["tar", "-xzf"], ".tgz": ["tar", "-xzf"], '.tar.gz': ['tar', '-xzf'],
".tar.bz2": ["tar", "-xjf"], ".tbz": ["tar", "-xjf"], '.tgz': ['tar', '-xzf'],
".tar.lzma": ["tar", "--lzma -xf"], ".tlz": ["tar", "--lzma -xf"], '.tar.bz2': ['tar', '-xjf'],
".tar.xz": ["tar", "--xz -xf"], ".txz": ["tar", "--xz -xf"], '.tbz': ['tar', '-xjf'],
".7z": ["7zr", "x"], '.tar.lzma': ['tar', '--lzma -xf'],
'.tlz': ['tar', '--lzma -xf'],
'.tar.xz': ['tar', '--xz -xf'],
'.txz': ['tar', '--xz -xf'],
'.7z': ['7zr', 'x'],
} }
# Test command exists and if not, remove. # Test command exists and if not, remove.
for cmd in required_cmds: for command in required_cmds:
if not which(cmd): if not which(command):
for k,v in EXTRACT_COMMANDS.items(): for k, v in list(EXTRACT_COMMANDS.items()):
if cmd in v[0]: if command in v[0]:
log.warning("EXTRACTOR: %s not found, disabling support for %s", cmd, k) log.warning('%s not found, disabling support for %s', command, k)
del EXTRACT_COMMANDS[k] del EXTRACT_COMMANDS[k]
if not EXTRACT_COMMANDS: if not EXTRACT_COMMANDS:
raise Exception("EXTRACTOR: No archive extracting programs found, plugin will be disabled") raise Exception('No archive extracting programs found, plugin will be disabled')
class Core(CorePluginBase): class Core(CorePluginBase):
def enable(self): def enable(self):
self.config = deluge.configmanager.ConfigManager("simpleextractor.conf", DEFAULT_PREFS) self.config = deluge.configmanager.ConfigManager(
if not self.config["extract_path"]: 'extractor.conf', DEFAULT_PREFS
self.config["extract_path"] = deluge.configmanager.ConfigManager("core.conf")["download_location"] )
component.get("EventManager").register_event_handler("TorrentFinishedEvent", self._on_torrent_finished) if not self.config['extract_path']:
self.config['extract_path'] = deluge.configmanager.ConfigManager(
'core.conf'
)['download_location']
component.get('EventManager').register_event_handler(
'TorrentFinishedEvent', self._on_torrent_finished
)
def disable(self): def disable(self):
component.get("EventManager").deregister_event_handler("TorrentFinishedEvent", self._on_torrent_finished) component.get('EventManager').deregister_event_handler(
'TorrentFinishedEvent', self._on_torrent_finished
)
def update(self): def update(self):
pass pass
@@ -134,28 +123,31 @@ class Core(CorePluginBase):
""" """
This is called when a torrent finishes and checks if any files to extract. This is called when a torrent finishes and checks if any files to extract.
""" """
tid = component.get("TorrentManager").torrents[torrent_id] tid = component.get('TorrentManager').torrents[torrent_id]
tid_status = tid.get_status(["save_path", "name"]) tid_status = tid.get_status(['download_location', 'name'])
files = tid.get_files() files = tid.get_files()
for f in files: for f in files:
file_root, file_ext = os.path.splitext(f["path"]) file_root, file_ext = os.path.splitext(f['path'])
file_ext_sec = os.path.splitext(file_root)[1] file_ext_sec = os.path.splitext(file_root)[1]
if file_ext_sec and file_ext_sec + file_ext in EXTRACT_COMMANDS: if file_ext_sec and file_ext_sec + file_ext in EXTRACT_COMMANDS:
file_ext = file_ext_sec + file_ext file_ext = file_ext_sec + file_ext
elif file_ext not in EXTRACT_COMMANDS or file_ext_sec == '.tar': elif file_ext not in EXTRACT_COMMANDS or file_ext_sec == '.tar':
log.warning("EXTRACTOR: Can't extract file with unknown file type: %s" % f["path"]) log.debug('Cannot extract file with unknown file type: %s', f['path'])
continue continue
elif file_ext == '.rar' and 'part' in file_ext_sec:
part_num = file_ext_sec.split('part')[1]
if part_num.isdigit() and int(part_num) != 1:
log.debug('Skipping remaining multi-part rar files: %s', f['path'])
continue
cmd = EXTRACT_COMMANDS[file_ext] cmd = EXTRACT_COMMANDS[file_ext]
fpath = os.path.join(
# Now that we have the cmd, lets run it to extract the files tid_status['download_location'], os.path.normpath(f['path'])
fpath = os.path.join(tid_status["save_path"], os.path.normpath(f["path"])) )
dest = os.path.normpath(self.config['extract_path'])
# Get the destination path if self.config['use_name_folder']:
dest = os.path.normpath(self.config["extract_path"]) dest = os.path.join(dest, tid_status['name'])
if self.config["use_name_folder"]:
name = tid_status["name"]
dest = os.path.join(dest, name)
# Override destination if in_place_extraction is set # Override destination if in_place_extraction is set
if self.config["in_place_extraction"]: if self.config["in_place_extraction"]:
@@ -167,32 +159,42 @@ class Core(CorePluginBase):
if not os.path.exists(dest): if not os.path.exists(dest):
try: try:
os.makedirs(dest) os.makedirs(dest)
except Exception, e: except OSError as ex:
log.error("EXTRACTOR: Error creating destination folder: %s", e) if not (ex.errno == errno.EEXIST and os.path.isdir(dest)):
return log.error('Error creating destination folder: %s', ex)
break
def on_extract_success(result, torrent_id, fpath): def on_extract(result, torrent_id, fpath):
# XXX: Emit an event # Check command exit code.
log.info("EXTRACTOR: Extract successful: %s (%s)", fpath, torrent_id) if not result[2]:
log.info('Extract successful: %s (%s)', fpath, torrent_id)
else:
log.error(
'Extract failed: %s (%s) %s', fpath, torrent_id, result[1]
)
def on_extract_failed(result, torrent_id, fpath): # Run the command and add callback.
# XXX: Emit an event log.debug(
log.error("EXTRACTOR: Extract failed: %s (%s)", fpath, torrent_id) 'Extracting %s from %s with %s %s to %s',
fpath,
# Run the command and add some callbacks torrent_id,
log.debug("EXTRACTOR: Extracting %s with %s %s to %s", fpath, cmd[0], cmd[1], dest) cmd[0],
d = getProcessValue(cmd[0], cmd[1].split() + [str(fpath)], {}, str(dest)) cmd[1],
d.addCallback(on_extract_success, torrent_id, fpath) dest,
d.addErrback(on_extract_failed, torrent_id, fpath) )
d = getProcessOutputAndValue(
cmd[0], cmd[1].split() + [str(fpath)], os.environ, str(dest)
)
d.addCallback(on_extract, torrent_id, fpath)
@export @export
def set_config(self, config): def set_config(self, config):
"sets the config dictionary" """Sets the config dictionary."""
for key in config.keys(): for key in config:
self.config[key] = config[key] self.config[key] = config[key]
self.config.save() self.config.save()
@export @export
def get_config(self): def get_config(self):
"returns the config dictionary" """Returns the config dictionary."""
return self.config.config return self.config.config

View File

@@ -2,7 +2,7 @@
* simpleextractor.js * simpleextractor.js
* *
* Copyright (c) Damien Churchill 2010 <damoxc@gmail.com> * Copyright (c) Damien Churchill 2010 <damoxc@gmail.com>
* Copyright (C) 2015 Chris Yereaztian <chris.yereaztian@gmail.com> * Copyright (C) Digitalhigh 2019 <donate.to.digitalhigh@gmail.com>
* *
* This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with * This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
* the additional special exception to link portions of this program with the OpenSSL library. * the additional special exception to link portions of this program with the OpenSSL library.

View File

@@ -1,31 +1,42 @@
<?xml version="1.0"?> <?xml version="1.0" encoding="UTF-8"?>
<glade-interface> <!-- Generated with glade 3.22.1 -->
<!-- interface-requires gtk+ 2.6 --> <interface>
<!-- interface-naming-policy toplevel-contextual --> <requires lib="gtk+" version="3.0"/>
<widget class="GtkWindow" id="window1"> <object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child> <child>
<widget class="GtkVBox" id="extractor_prefs_box"> <placeholder/>
</child>
<child>
<object class="GtkBox" id="extractor_prefs_box">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<property name="orientation">vertical</property>
<child> <child>
<widget class="GtkFrame" id="frame1"> <object class="GtkFrame" id="frame1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property> <property name="label_xalign">0</property>
<property name="shadow_type">none</property> <property name="shadow_type">none</property>
<child> <child>
<widget class="GtkVBox" id="vbox1"> <object class="GtkBox" id="vbox1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">5</property> <property name="border_width">5</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<property name="orientation">vertical</property>
<child> <child>
<widget class="GtkHBox" id="hbox1"> <object class="GtkBox" id="hbox1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property> <property name="spacing">5</property>
<child> <child>
<widget class="GtkLabel" id="label2"> <object class="GtkLabel" id="label2">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Extract to:</property> <property name="label" translatable="yes">Extract to:</property>
</widget> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
@@ -33,31 +44,41 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkHBox" id="hbox2"> <object class="GtkBox" id="hbox2">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property>
<child> <child>
<widget class="GtkFileChooserButton" id="folderchooser_path"> <object class="GtkFileChooserButton" id="folderchooser_path">
<property name="can_focus">False</property>
<property name="action">select-folder</property> <property name="action">select-folder</property>
<property name="title" translatable="yes">Select A Folder</property> <property name="title" translatable="yes">Select A Folder</property>
</widget> </object>
<packing> <packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkEntry" id="entry_path"> <object class="GtkEntry" id="entry_path">
<property name="can_focus">True</property> <property name="can_focus">True</property>
</widget> <property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
</object>
<packing> <packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
</widget> </object>
<packing> <packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
</widget> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
@@ -65,53 +86,38 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkCheckButton" id="chk_use_name"> <object class="GtkCheckButton" id="chk_use_name">
<property name="label" translatable="yes">Create torrent name sub-folder</property> <property name="label" translatable="yes">Create torrent name sub-folder</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="tooltip" translatable="yes">This option will create a sub-folder using the torrent's name within the selected extract folder and put the extracted files there.</property> <property name="tooltip_text" translatable="yes">This option will create a sub-folder using the torrent's name within the selected extract folder and put the extracted files there.</property>
<property name="draw_indicator">True</property> <property name="draw_indicator">True</property>
</widget> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child> </object>
<widget class="GtkCheckButton" id="chk_in_place_extraction">
<property name="label" translatable="yes">Extract torrent in place</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip" translatable="yes">This option will extract the torrent in place.</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child> </child>
</widget> <child type="label">
</child> <object class="GtkLabel" id="label1">
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</widget> </object>
<packing>
<property name="type">label_item</property>
</packing>
</child> </child>
</widget> </object>
<packing> <packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
</widget> </object>
</child> </child>
</widget> </object>
</glade-interface> </interface>

View File

@@ -1,98 +1,98 @@
# # -*- coding: utf-8 -*-
# gtkui.py
# #
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# Copyright (C) 2015 Chris Yereaztian <chris.yereaztian@gmail.com>
# #
# Basic plugin template created by: # Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com> # Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# # the additional special exception to link portions of this program with the OpenSSL library.
# You may redistribute it and/or modify it under the terms of the # See LICENSE for more details.
# 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 from __future__ import unicode_literals
from deluge.log import LOG as log import logging
from deluge.ui.client import client
from deluge.plugins.pluginbase import GtkPluginBase import gi # isort:skip (Required before Gtk import).
gi.require_version('Gtk', '3.0') # NOQA: E402
# isort:imports-thirdparty
from gi.repository import Gtk
# isort:imports-firstparty
import deluge.component as component import deluge.component as component
import deluge.common from deluge.plugins.pluginbase import Gtk3PluginBase
from deluge.ui.client import client
from common import get_resource # isort:imports-localfolder
from .common import get_resource
class GtkUI(GtkPluginBase): log = logging.getLogger(__name__)
class GtkUI(Gtk3PluginBase):
def enable(self): def enable(self):
self.glade = gtk.glade.XML(get_resource("simpleextractor_prefs.glade")) self.builder = Gtk.Builder()
self.builder.add_from_file(get_resource('extractor_prefs.ui'))
component.get("Preferences").add_page(_("SimpleExtractor"), self.glade.get_widget("extractor_prefs_box")) component.get('Preferences').add_page(
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs) _('Extractor'), self.builder.get_object('extractor_prefs_box')
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs) )
component.get('PluginManager').register_hook(
'on_apply_prefs', self.on_apply_prefs
)
component.get('PluginManager').register_hook(
'on_show_prefs', self.on_show_prefs
)
self.on_show_prefs() self.on_show_prefs()
def disable(self): def disable(self):
component.get("Preferences").remove_page(_("Extractor")) component.get('Preferences').remove_page(_('Extractor'))
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs) component.get('PluginManager').deregister_hook(
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs) 'on_apply_prefs', self.on_apply_prefs
del self.glade )
component.get('PluginManager').deregister_hook(
'on_show_prefs', self.on_show_prefs
)
del self.builder
def on_apply_prefs(self): def on_apply_prefs(self):
log.debug("applying prefs for Extractor") log.debug('applying prefs for Extractor')
if client.is_localhost(): if client.is_localhost():
path = self.glade.get_widget("folderchooser_path").get_filename() path = self.builder.get_object('folderchooser_path').get_filename()
else: else:
path = self.glade.get_widget("entry_path").get_text() path = self.builder.get_object('entry_path').get_text()
config = { config = {
"extract_path": path, 'extract_path': path,
"use_name_folder": self.glade.get_widget("chk_use_name").get_active(), 'use_name_folder': self.builder.get_object('chk_use_name').get_active(),
"in_place_extraction": self.glade.get_widget("chk_in_place_extraction").get_active() 'in_place_extraction': self.builder.get_object("chk_in_place_extraction").get_active()
} }
client.extractor.set_config(config) client.extractor.set_config(config)
def on_show_prefs(self): def on_show_prefs(self):
if client.is_localhost(): if client.is_localhost():
self.glade.get_widget("folderchooser_path").show() self.builder.get_object('folderchooser_path').show()
self.glade.get_widget("entry_path").hide() self.builder.get_object('entry_path').hide()
else: else:
self.glade.get_widget("folderchooser_path").hide() self.builder.get_object('folderchooser_path').hide()
self.glade.get_widget("entry_path").show() self.builder.get_object('entry_path').show()
def on_get_config(config): def on_get_config(config):
if client.is_localhost(): if client.is_localhost():
self.glade.get_widget("folderchooser_path").set_current_folder(config["extract_path"]) self.builder.get_object('folderchooser_path').set_current_folder(
config['extract_path']
)
else: else:
self.glade.get_widget("entry_path").set_text(config["extract_path"]) self.builder.get_object('entry_path').set_text(config['extract_path'])
self.glade.get_widget("chk_use_name").set_active(config["use_name_folder"]) self.builder.get_object('chk_use_name').set_active(
self.glade.get_widget("chk_in_place_extraction").set_active(config["in_place_extraction"]) config['use_name_folder']
)
self.builder.get_object('chk_in_place_extraction').set_active(config['in_place_extraction'])
client.extractor.get_config().addCallback(on_get_config) client.extractor.get_config().addCallback(on_get_config)

View File

@@ -1,5 +1,4 @@
# # -*- coding: utf-8 -*-
# webui.py
# #
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# #
@@ -7,49 +6,23 @@
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com> # Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com> # Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# # the additional special exception to link portions of this program with the OpenSSL library.
# You may redistribute it and/or modify it under the terms of the # See LICENSE for more details.
# 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.
#
# #
from deluge.log import LOG as log from __future__ import unicode_literals
from deluge.ui.client import client
from deluge import component import logging
from deluge.plugins.pluginbase import WebPluginBase from deluge.plugins.pluginbase import WebPluginBase
from common import get_resource from .common import get_resource
log = logging.getLogger(__name__)
class WebUI(WebPluginBase): class WebUI(WebPluginBase):
def enable(self):
pass
def disable(self): scripts = [get_resource('simpleextractor.js')]
pass
scripts = [get_resource("simpleextractor.js")]
debug_scripts = scripts debug_scripts = scripts

View File

@@ -1,20 +0,0 @@
"""
which.py : Same as the Unix "which" command: tests if an executable exists and returns name
"""
def which(program):
# Author Credit: Jay @ http://stackoverflow.com/a/377028
import os
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None