mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-21 05:43:16 -07:00
Merge pull request #1408 from clinton-hall/fix/unvendor
Move vendored packages in `core` to `libs`
This commit is contained in:
commit
014852c683
26 changed files with 349 additions and 408 deletions
|
@ -1,123 +0,0 @@
|
||||||
# coding=utf-8
|
|
||||||
# Linktastic Module
|
|
||||||
# - A python2/3 compatible module that can create hardlinks/symlinks on windows-based systems
|
|
||||||
#
|
|
||||||
# Linktastic is distributed under the MIT License. The follow are the terms and conditions of using Linktastic.
|
|
||||||
#
|
|
||||||
# The MIT License (MIT)
|
|
||||||
# Copyright (c) 2012 Solipsis Development
|
|
||||||
#
|
|
||||||
# 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 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.
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
from subprocess import CalledProcessError
|
|
||||||
import os
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
info = subprocess.STARTUPINFO()
|
|
||||||
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
||||||
|
|
||||||
|
|
||||||
# Prevent spaces from messing with us!
|
|
||||||
def _escape_param(param):
|
|
||||||
return '"{0}"'.format(param)
|
|
||||||
|
|
||||||
|
|
||||||
# Private function to create link on nt-based systems
|
|
||||||
def _link_windows(src, dest):
|
|
||||||
try:
|
|
||||||
subprocess.check_output(
|
|
||||||
'cmd /C mklink /H {0} {1}'.format(_escape_param(dest), _escape_param(src)),
|
|
||||||
stderr=subprocess.STDOUT, startupinfo=info)
|
|
||||||
except CalledProcessError as err:
|
|
||||||
|
|
||||||
raise IOError(err.output.decode('utf-8'))
|
|
||||||
|
|
||||||
# TODO, find out what kind of messages Windows sends us from mklink
|
|
||||||
# print(stdout)
|
|
||||||
# assume if they ret-coded 0 we're good
|
|
||||||
|
|
||||||
|
|
||||||
def _symlink_windows(src, dest):
|
|
||||||
try:
|
|
||||||
subprocess.check_output(
|
|
||||||
'cmd /C mklink {0} {1}'.format(_escape_param(dest), _escape_param(src)),
|
|
||||||
stderr=subprocess.STDOUT, startupinfo=info)
|
|
||||||
except CalledProcessError as err:
|
|
||||||
raise IOError(err.output.decode('utf-8'))
|
|
||||||
|
|
||||||
# TODO, find out what kind of messages Windows sends us from mklink
|
|
||||||
# print(stdout)
|
|
||||||
# assume if they ret-coded 0 we're good
|
|
||||||
|
|
||||||
|
|
||||||
def _dirlink_windows(src, dest):
|
|
||||||
try:
|
|
||||||
subprocess.check_output(
|
|
||||||
'cmd /C mklink /J {0} {1}'.format(_escape_param(dest), _escape_param(src)),
|
|
||||||
stderr=subprocess.STDOUT, startupinfo=info)
|
|
||||||
except CalledProcessError as err:
|
|
||||||
raise IOError(err.output.decode('utf-8'))
|
|
||||||
|
|
||||||
# TODO, find out what kind of messages Windows sends us from mklink
|
|
||||||
# print(stdout)
|
|
||||||
# assume if they ret-coded 0 we're good
|
|
||||||
|
|
||||||
|
|
||||||
def _junctionlink_windows(src, dest):
|
|
||||||
try:
|
|
||||||
subprocess.check_output(
|
|
||||||
'cmd /C mklink /D {0} {1}'.format(_escape_param(dest), _escape_param(src)),
|
|
||||||
stderr=subprocess.STDOUT, startupinfo=info)
|
|
||||||
except CalledProcessError as err:
|
|
||||||
raise IOError(err.output.decode('utf-8'))
|
|
||||||
|
|
||||||
# TODO, find out what kind of messages Windows sends us from mklink
|
|
||||||
# print(stdout)
|
|
||||||
# assume if they ret-coded 0 we're good
|
|
||||||
|
|
||||||
|
|
||||||
# Create a hard link to src named as dest
|
|
||||||
# This version of link, unlike os.link, supports nt systems as well
|
|
||||||
def link(src, dest):
|
|
||||||
if os.name == 'nt':
|
|
||||||
_link_windows(src, dest)
|
|
||||||
else:
|
|
||||||
os.link(src, dest)
|
|
||||||
|
|
||||||
|
|
||||||
# Create a symlink to src named as dest, but don't fail if you're on nt
|
|
||||||
def symlink(src, dest):
|
|
||||||
if os.name == 'nt':
|
|
||||||
_symlink_windows(src, dest)
|
|
||||||
else:
|
|
||||||
os.symlink(src, dest)
|
|
||||||
|
|
||||||
|
|
||||||
# Create a symlink to src named as dest, but don't fail if you're on nt
|
|
||||||
def dirlink(src, dest):
|
|
||||||
if os.name == 'nt':
|
|
||||||
_dirlink_windows(src, dest)
|
|
||||||
else:
|
|
||||||
os.symlink(src, dest)
|
|
||||||
|
|
||||||
|
|
||||||
# Create a symlink to src named as dest, but don't fail if you're on nt
|
|
||||||
def junctionlink(src, dest):
|
|
||||||
if os.name == 'nt':
|
|
||||||
_junctionlink_windows(src, dest)
|
|
||||||
else:
|
|
||||||
os.symlink(src, dest)
|
|
|
@ -14,19 +14,19 @@ import time
|
||||||
|
|
||||||
import beets
|
import beets
|
||||||
import guessit
|
import guessit
|
||||||
|
import linktastic
|
||||||
import requests
|
import requests
|
||||||
import subliminal
|
import subliminal
|
||||||
from babelfish import Language
|
from babelfish import Language
|
||||||
|
from qbittorrent import Client as qBittorrentClient
|
||||||
from six import text_type
|
from six import text_type
|
||||||
|
from synchronousdeluge.client import DelugeClient
|
||||||
|
from transmissionrpc.client import Client as TransmissionClient
|
||||||
|
from utorrent.client import UTorrentClient
|
||||||
|
|
||||||
import core
|
import core
|
||||||
from core import logger, nzbToMediaDB
|
from core import logger, nzbToMediaDB
|
||||||
from core.extractor import extractor
|
from core.extractor import extractor
|
||||||
from core.linktastic import linktastic
|
|
||||||
from core.qbittorrent.client import Client as qBittorrentClient
|
|
||||||
from core.synchronousdeluge.client import DelugeClient
|
|
||||||
from core.transmissionrpc.client import Client as TransmissionClient
|
|
||||||
from core.utorrent.client import UTorrentClient
|
|
||||||
|
|
||||||
requests.packages.urllib3.disable_warnings()
|
requests.packages.urllib3.disable_warnings()
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
# coding=utf-8
|
|
|
@ -1,18 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
|
||||||
# Licensed under the MIT license.
|
|
||||||
|
|
||||||
from core.transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT, PRIORITY, RATIO_LIMIT, LOGGER
|
|
||||||
from core.transmissionrpc.error import TransmissionError, HTTPHandlerError
|
|
||||||
from core.transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler
|
|
||||||
from core.transmissionrpc.torrent import Torrent
|
|
||||||
from core.transmissionrpc.session import Session
|
|
||||||
from core.transmissionrpc.client import Client
|
|
||||||
from core.transmissionrpc.utils import add_stdout_logger, add_file_logger
|
|
||||||
|
|
||||||
__author__ = 'Erik Svensson <erik.public@gmail.com>'
|
|
||||||
__version_major__ = 0
|
|
||||||
__version_minor__ = 11
|
|
||||||
__version__ = '{0}.{1}'.format(__version_major__, __version_minor__)
|
|
||||||
__copyright__ = 'Copyright (c) 2008-2013 Erik Svensson'
|
|
||||||
__license__ = 'MIT'
|
|
|
@ -1 +0,0 @@
|
||||||
# coding=utf-8
|
|
75
libs/linktastic.py
Normal file
75
libs/linktastic.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# Linktastic Module
|
||||||
|
# - A python2/3 compatible module that can create hardlinks/symlinks on windows-based systems
|
||||||
|
#
|
||||||
|
# Linktastic is distributed under the MIT License. The follow are the terms and conditions of using Linktastic.
|
||||||
|
#
|
||||||
|
# The MIT License (MIT)
|
||||||
|
# Copyright (c) 2012 Solipsis Development
|
||||||
|
#
|
||||||
|
# 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 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.
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
from subprocess import CalledProcessError
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# Prevent spaces from messing with us!
|
||||||
|
def _escape_param(param):
|
||||||
|
return '"%s"' % param
|
||||||
|
|
||||||
|
|
||||||
|
# Private function to create link on nt-based systems
|
||||||
|
def _link_windows(src, dest):
|
||||||
|
try:
|
||||||
|
subprocess.check_output(
|
||||||
|
'cmd /C mklink /H %s %s' % (_escape_param(dest), _escape_param(src)),
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
except CalledProcessError as err:
|
||||||
|
raise IOError(err.output.decode('utf-8'))
|
||||||
|
|
||||||
|
# TODO, find out what kind of messages Windows sends us from mklink
|
||||||
|
# print(stdout)
|
||||||
|
# assume if they ret-coded 0 we're good
|
||||||
|
|
||||||
|
|
||||||
|
def _symlink_windows(src, dest):
|
||||||
|
try:
|
||||||
|
subprocess.check_output(
|
||||||
|
'cmd /C mklink %s %s' % (_escape_param(dest), _escape_param(src)),
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
except CalledProcessError as err:
|
||||||
|
raise IOError(err.output.decode('utf-8'))
|
||||||
|
|
||||||
|
# TODO, find out what kind of messages Windows sends us from mklink
|
||||||
|
# print(stdout)
|
||||||
|
# assume if they ret-coded 0 we're good
|
||||||
|
|
||||||
|
|
||||||
|
# Create a hard link to src named as dest
|
||||||
|
# This version of link, unlike os.link, supports nt systems as well
|
||||||
|
def link(src, dest):
|
||||||
|
if os.name == 'nt':
|
||||||
|
_link_windows(src, dest)
|
||||||
|
else:
|
||||||
|
os.link(src, dest)
|
||||||
|
|
||||||
|
|
||||||
|
# Create a symlink to src named as dest, but don't fail if you're on nt
|
||||||
|
def symlink(src, dest):
|
||||||
|
if os.name == 'nt':
|
||||||
|
_symlink_windows(src, dest)
|
||||||
|
else:
|
||||||
|
os.symlink(src, dest)
|
1
libs/qbittorrent/__init__.py
Normal file
1
libs/qbittorrent/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from qbittorrent.client import Client
|
12
libs/rencode/__init__.py
Normal file
12
libs/rencode/__init__.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
try:
|
||||||
|
from rencode._rencode import *
|
||||||
|
from rencode._rencode import __version__
|
||||||
|
except ImportError:
|
||||||
|
import rencode.rencode_orig
|
||||||
|
prev_all = rencode.rencode_orig.__all__[:]
|
||||||
|
del rencode.rencode_orig.__all__
|
||||||
|
from rencode.rencode_orig import *
|
||||||
|
from rencode.rencode_orig import __version__
|
||||||
|
rencode.rencode_orig.__all__ = prev_all
|
||||||
|
|
||||||
|
__all__ = ['dumps', 'loads']
|
|
@ -1,34 +1,3 @@
|
||||||
# coding=utf-8
|
|
||||||
"""
|
|
||||||
rencode -- Web safe object pickling/unpickling.
|
|
||||||
|
|
||||||
Public domain, Connelly Barnes 2006-2007.
|
|
||||||
|
|
||||||
The rencode module is a modified version of bencode from the
|
|
||||||
BitTorrent project. For complex, heterogeneous data structures with
|
|
||||||
many small elements, r-encodings take up significantly less space than
|
|
||||||
b-encodings:
|
|
||||||
|
|
||||||
>>> len(rencode.dumps({'a': 0, 'b': [1, 2], 'c': 99}))
|
|
||||||
13
|
|
||||||
>>> len(bencode.bencode({'a': 0, 'b': [1, 2], 'c': 99}))
|
|
||||||
26
|
|
||||||
|
|
||||||
The rencode format is not standardized, and may change with different
|
|
||||||
rencode module versions, so you should check that you are using the
|
|
||||||
same rencode version throughout your project.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import struct
|
|
||||||
from threading import Lock
|
|
||||||
from six import PY3
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
long = int
|
|
||||||
|
|
||||||
__version__ = '1.0.1'
|
|
||||||
__all__ = ['dumps', 'loads']
|
|
||||||
|
|
||||||
# Original bencode module by Petru Paler, et al.
|
# Original bencode module by Petru Paler, et al.
|
||||||
#
|
#
|
||||||
# Modifications by Connelly Barnes:
|
# Modifications by Connelly Barnes:
|
||||||
|
@ -68,6 +37,45 @@ __all__ = ['dumps', 'loads']
|
||||||
#
|
#
|
||||||
# (The rencode module is licensed under the above license as well).
|
# (The rencode module is licensed under the above license as well).
|
||||||
#
|
#
|
||||||
|
# pylint: disable=redefined-builtin
|
||||||
|
|
||||||
|
"""
|
||||||
|
rencode -- Web safe object pickling/unpickling.
|
||||||
|
|
||||||
|
Public domain, Connelly Barnes 2006-2007.
|
||||||
|
|
||||||
|
The rencode module is a modified version of bencode from the
|
||||||
|
BitTorrent project. For complex, heterogeneous data structures with
|
||||||
|
many small elements, r-encodings take up significantly less space than
|
||||||
|
b-encodings:
|
||||||
|
|
||||||
|
>>> len(rencode.dumps({'a':0, 'b':[1,2], 'c':99}))
|
||||||
|
13
|
||||||
|
>>> len(bencode.bencode({'a':0, 'b':[1,2], 'c':99}))
|
||||||
|
26
|
||||||
|
|
||||||
|
The rencode format is not standardized, and may change with different
|
||||||
|
rencode module versions, so you should check that you are using the
|
||||||
|
same rencode version throughout your project.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
from threading import Lock
|
||||||
|
|
||||||
|
__version__ = ("Python", 1, 0, 6)
|
||||||
|
__all__ = ('dumps', 'loads')
|
||||||
|
|
||||||
|
py3 = sys.version_info[0] >= 3
|
||||||
|
if py3:
|
||||||
|
long = int
|
||||||
|
unicode = str
|
||||||
|
|
||||||
|
def int2byte(c):
|
||||||
|
return bytes([c])
|
||||||
|
else:
|
||||||
|
def int2byte(c):
|
||||||
|
return chr(c)
|
||||||
|
|
||||||
# Default number of bits for serialized floats, either 32 or 64 (also a parameter for dumps()).
|
# Default number of bits for serialized floats, either 32 or 64 (also a parameter for dumps()).
|
||||||
DEFAULT_FLOAT_BITS = 32
|
DEFAULT_FLOAT_BITS = 32
|
||||||
|
@ -77,19 +85,19 @@ MAX_INT_LENGTH = 64
|
||||||
|
|
||||||
# The bencode 'typecodes' such as i, d, etc have been extended and
|
# The bencode 'typecodes' such as i, d, etc have been extended and
|
||||||
# relocated on the base-256 character set.
|
# relocated on the base-256 character set.
|
||||||
CHR_LIST = chr(59)
|
CHR_LIST = int2byte(59)
|
||||||
CHR_DICT = chr(60)
|
CHR_DICT = int2byte(60)
|
||||||
CHR_INT = chr(61)
|
CHR_INT = int2byte(61)
|
||||||
CHR_INT1 = chr(62)
|
CHR_INT1 = int2byte(62)
|
||||||
CHR_INT2 = chr(63)
|
CHR_INT2 = int2byte(63)
|
||||||
CHR_INT4 = chr(64)
|
CHR_INT4 = int2byte(64)
|
||||||
CHR_INT8 = chr(65)
|
CHR_INT8 = int2byte(65)
|
||||||
CHR_FLOAT32 = chr(66)
|
CHR_FLOAT32 = int2byte(66)
|
||||||
CHR_FLOAT64 = chr(44)
|
CHR_FLOAT64 = int2byte(44)
|
||||||
CHR_TRUE = chr(67)
|
CHR_TRUE = int2byte(67)
|
||||||
CHR_FALSE = chr(68)
|
CHR_FALSE = int2byte(68)
|
||||||
CHR_NONE = chr(69)
|
CHR_NONE = int2byte(69)
|
||||||
CHR_TERM = chr(127)
|
CHR_TERM = int2byte(127)
|
||||||
|
|
||||||
# Positive integers with value embedded in typecode.
|
# Positive integers with value embedded in typecode.
|
||||||
INT_POS_FIXED_START = 0
|
INT_POS_FIXED_START = 0
|
||||||
|
@ -111,6 +119,9 @@ STR_FIXED_COUNT = 64
|
||||||
LIST_FIXED_START = STR_FIXED_START + STR_FIXED_COUNT
|
LIST_FIXED_START = STR_FIXED_START + STR_FIXED_COUNT
|
||||||
LIST_FIXED_COUNT = 64
|
LIST_FIXED_COUNT = 64
|
||||||
|
|
||||||
|
# Whether strings should be decoded when loading
|
||||||
|
_decode_utf8 = False
|
||||||
|
|
||||||
|
|
||||||
def decode_int(x, f):
|
def decode_int(x, f):
|
||||||
f += 1
|
f += 1
|
||||||
|
@ -121,48 +132,49 @@ def decode_int(x, f):
|
||||||
n = int(x[f:newf])
|
n = int(x[f:newf])
|
||||||
except (OverflowError, ValueError):
|
except (OverflowError, ValueError):
|
||||||
n = long(x[f:newf])
|
n = long(x[f:newf])
|
||||||
if x[f] == '-':
|
if x[f:f + 1] == '-':
|
||||||
if x[f + 1] == '0':
|
if x[f + 1:f + 2] == '0':
|
||||||
raise ValueError
|
raise ValueError
|
||||||
elif x[f] == '0' and newf != f + 1:
|
elif x[f:f + 1] == '0' and newf != f + 1:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
return n, newf + 1
|
return (n, newf + 1)
|
||||||
|
|
||||||
|
|
||||||
def decode_intb(x, f):
|
def decode_intb(x, f):
|
||||||
f += 1
|
f += 1
|
||||||
return struct.unpack('!b', x[f:f + 1])[0], f + 1
|
return (struct.unpack('!b', x[f:f + 1])[0], f + 1)
|
||||||
|
|
||||||
|
|
||||||
def decode_inth(x, f):
|
def decode_inth(x, f):
|
||||||
f += 1
|
f += 1
|
||||||
return struct.unpack('!h', x[f:f + 2])[0], f + 2
|
return (struct.unpack('!h', x[f:f + 2])[0], f + 2)
|
||||||
|
|
||||||
|
|
||||||
def decode_intl(x, f):
|
def decode_intl(x, f):
|
||||||
f += 1
|
f += 1
|
||||||
return struct.unpack('!l', x[f:f + 4])[0], f + 4
|
|
||||||
|
return (struct.unpack('!l', x[f:f + 4])[0], f + 4)
|
||||||
|
|
||||||
|
|
||||||
def decode_intq(x, f):
|
def decode_intq(x, f):
|
||||||
f += 1
|
f += 1
|
||||||
return struct.unpack('!q', x[f:f + 8])[0], f + 8
|
return (struct.unpack('!q', x[f:f + 8])[0], f + 8)
|
||||||
|
|
||||||
|
|
||||||
def decode_float32(x, f):
|
def decode_float32(x, f):
|
||||||
f += 1
|
f += 1
|
||||||
n = struct.unpack('!f', x[f:f + 4])[0]
|
n = struct.unpack('!f', x[f:f + 4])[0]
|
||||||
return n, f + 4
|
return (n, f + 4)
|
||||||
|
|
||||||
|
|
||||||
def decode_float64(x, f):
|
def decode_float64(x, f):
|
||||||
f += 1
|
f += 1
|
||||||
n = struct.unpack('!d', x[f:f + 8])[0]
|
n = struct.unpack('!d', x[f:f + 8])[0]
|
||||||
return n, f + 8
|
return (n, f + 8)
|
||||||
|
|
||||||
|
|
||||||
def decode_string(x, f):
|
def decode_string(x, f):
|
||||||
colon = x.index(':', f)
|
colon = x.index(b':', f)
|
||||||
try:
|
try:
|
||||||
n = int(x[f:colon])
|
n = int(x[f:colon])
|
||||||
except (OverflowError, ValueError):
|
except (OverflowError, ValueError):
|
||||||
|
@ -171,86 +183,73 @@ def decode_string(x, f):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
colon += 1
|
colon += 1
|
||||||
s = x[colon:colon + n]
|
s = x[colon:colon + n]
|
||||||
try:
|
if _decode_utf8:
|
||||||
t = s.decode("utf8")
|
s = s.decode('utf8')
|
||||||
if len(t) != len(s):
|
return (s, colon + n)
|
||||||
s = t
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
pass
|
|
||||||
return s, colon + n
|
|
||||||
|
|
||||||
|
|
||||||
def decode_list(x, f):
|
def decode_list(x, f):
|
||||||
r, f = [], f + 1
|
r, f = [], f + 1
|
||||||
while x[f] != CHR_TERM:
|
while x[f:f + 1] != CHR_TERM:
|
||||||
v, f = decode_func[x[f]](x, f)
|
v, f = decode_func[x[f:f + 1]](x, f)
|
||||||
r.append(v)
|
r.append(v)
|
||||||
return tuple(r), f + 1
|
return (tuple(r), f + 1)
|
||||||
|
|
||||||
|
|
||||||
def decode_dict(x, f):
|
def decode_dict(x, f):
|
||||||
r, f = {}, f + 1
|
r, f = {}, f + 1
|
||||||
while x[f] != CHR_TERM:
|
while x[f:f + 1] != CHR_TERM:
|
||||||
k, f = decode_func[x[f]](x, f)
|
k, f = decode_func[x[f:f + 1]](x, f)
|
||||||
r[k], f = decode_func[x[f]](x, f)
|
r[k], f = decode_func[x[f:f + 1]](x, f)
|
||||||
return r, f + 1
|
return (r, f + 1)
|
||||||
|
|
||||||
|
|
||||||
def decode_true(x, f):
|
def decode_true(x, f):
|
||||||
return True, f + 1
|
return (True, f + 1)
|
||||||
|
|
||||||
|
|
||||||
def decode_false(x, f):
|
def decode_false(x, f):
|
||||||
return False, f + 1
|
return (False, f + 1)
|
||||||
|
|
||||||
|
|
||||||
def decode_none(x, f):
|
def decode_none(x, f):
|
||||||
return None, f + 1
|
return (None, f + 1)
|
||||||
|
|
||||||
|
decode_func = {}
|
||||||
decode_func = {
|
decode_func[b'0'] = decode_string
|
||||||
'0': decode_string,
|
decode_func[b'1'] = decode_string
|
||||||
'1': decode_string,
|
decode_func[b'2'] = decode_string
|
||||||
'2': decode_string,
|
decode_func[b'3'] = decode_string
|
||||||
'3': decode_string,
|
decode_func[b'4'] = decode_string
|
||||||
'4': decode_string,
|
decode_func[b'5'] = decode_string
|
||||||
'5': decode_string,
|
decode_func[b'6'] = decode_string
|
||||||
'6': decode_string,
|
decode_func[b'7'] = decode_string
|
||||||
'7': decode_string,
|
decode_func[b'8'] = decode_string
|
||||||
'8': decode_string,
|
decode_func[b'9'] = decode_string
|
||||||
'9': decode_string,
|
decode_func[CHR_LIST] = decode_list
|
||||||
CHR_LIST: decode_list,
|
decode_func[CHR_DICT] = decode_dict
|
||||||
CHR_DICT: decode_dict,
|
decode_func[CHR_INT] = decode_int
|
||||||
CHR_INT: decode_int,
|
decode_func[CHR_INT1] = decode_intb
|
||||||
CHR_INT1: decode_intb,
|
decode_func[CHR_INT2] = decode_inth
|
||||||
CHR_INT2: decode_inth,
|
decode_func[CHR_INT4] = decode_intl
|
||||||
CHR_INT4: decode_intl,
|
decode_func[CHR_INT8] = decode_intq
|
||||||
CHR_INT8: decode_intq,
|
decode_func[CHR_FLOAT32] = decode_float32
|
||||||
CHR_FLOAT32: decode_float32,
|
decode_func[CHR_FLOAT64] = decode_float64
|
||||||
CHR_FLOAT64: decode_float64,
|
decode_func[CHR_TRUE] = decode_true
|
||||||
CHR_TRUE: decode_true,
|
decode_func[CHR_FALSE] = decode_false
|
||||||
CHR_FALSE: decode_false,
|
decode_func[CHR_NONE] = decode_none
|
||||||
CHR_NONE: decode_none,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def make_fixed_length_string_decoders():
|
def make_fixed_length_string_decoders():
|
||||||
def make_decoder(slen):
|
def make_decoder(slen):
|
||||||
def f(x, f):
|
def f(x, f):
|
||||||
s = x[f + 1:f + 1 + slen]
|
s = x[f + 1:f + 1 + slen]
|
||||||
try:
|
if _decode_utf8:
|
||||||
t = s.decode("utf8")
|
s = s.decode("utf8")
|
||||||
if len(t) != len(s):
|
return (s, f + 1 + slen)
|
||||||
s = t
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
pass
|
|
||||||
return s, f + 1 + slen
|
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
for i in range(STR_FIXED_COUNT):
|
for i in range(STR_FIXED_COUNT):
|
||||||
decode_func[chr(STR_FIXED_START + i)] = make_decoder(i)
|
decode_func[int2byte(STR_FIXED_START + i)] = make_decoder(i)
|
||||||
|
|
||||||
|
|
||||||
make_fixed_length_string_decoders()
|
make_fixed_length_string_decoders()
|
||||||
|
|
||||||
|
@ -259,16 +258,13 @@ def make_fixed_length_list_decoders():
|
||||||
def make_decoder(slen):
|
def make_decoder(slen):
|
||||||
def f(x, f):
|
def f(x, f):
|
||||||
r, f = [], f + 1
|
r, f = [], f + 1
|
||||||
for i in range(slen):
|
for _ in range(slen):
|
||||||
v, f = decode_func[x[f]](x, f)
|
v, f = decode_func[x[f:f + 1]](x, f)
|
||||||
r.append(v)
|
r.append(v)
|
||||||
return tuple(r), f
|
return (tuple(r), f)
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
for i in range(LIST_FIXED_COUNT):
|
for i in range(LIST_FIXED_COUNT):
|
||||||
decode_func[chr(LIST_FIXED_START + i)] = make_decoder(i)
|
decode_func[int2byte(LIST_FIXED_START + i)] = make_decoder(i)
|
||||||
|
|
||||||
|
|
||||||
make_fixed_length_list_decoders()
|
make_fixed_length_list_decoders()
|
||||||
|
|
||||||
|
@ -276,15 +272,12 @@ make_fixed_length_list_decoders()
|
||||||
def make_fixed_length_int_decoders():
|
def make_fixed_length_int_decoders():
|
||||||
def make_decoder(j):
|
def make_decoder(j):
|
||||||
def f(x, f):
|
def f(x, f):
|
||||||
return j, f + 1
|
return (j, f + 1)
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
for i in range(INT_POS_FIXED_COUNT):
|
for i in range(INT_POS_FIXED_COUNT):
|
||||||
decode_func[chr(INT_POS_FIXED_START + i)] = make_decoder(i)
|
decode_func[int2byte(INT_POS_FIXED_START + i)] = make_decoder(i)
|
||||||
for i in range(INT_NEG_FIXED_COUNT):
|
for i in range(INT_NEG_FIXED_COUNT):
|
||||||
decode_func[chr(INT_NEG_FIXED_START + i)] = make_decoder(-1 - i)
|
decode_func[int2byte(INT_NEG_FIXED_START + i)] = make_decoder(-1 - i)
|
||||||
|
|
||||||
|
|
||||||
make_fixed_length_int_decoders()
|
make_fixed_length_int_decoders()
|
||||||
|
|
||||||
|
@ -293,31 +286,22 @@ def make_fixed_length_dict_decoders():
|
||||||
def make_decoder(slen):
|
def make_decoder(slen):
|
||||||
def f(x, f):
|
def f(x, f):
|
||||||
r, f = {}, f + 1
|
r, f = {}, f + 1
|
||||||
for j in range(slen):
|
for _ in range(slen):
|
||||||
k, f = decode_func[x[f]](x, f)
|
k, f = decode_func[x[f:f + 1]](x, f)
|
||||||
r[k], f = decode_func[x[f]](x, f)
|
r[k], f = decode_func[x[f:f + 1]](x, f)
|
||||||
return r, f
|
return (r, f)
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
for i in range(DICT_FIXED_COUNT):
|
for i in range(DICT_FIXED_COUNT):
|
||||||
decode_func[chr(DICT_FIXED_START + i)] = make_decoder(i)
|
decode_func[int2byte(DICT_FIXED_START + i)] = make_decoder(i)
|
||||||
|
|
||||||
|
|
||||||
make_fixed_length_dict_decoders()
|
make_fixed_length_dict_decoders()
|
||||||
|
|
||||||
|
|
||||||
def encode_dict(x, r):
|
def loads(x, decode_utf8=False):
|
||||||
r.append(CHR_DICT)
|
global _decode_utf8
|
||||||
for k, v in x.items():
|
_decode_utf8 = decode_utf8
|
||||||
encode_func[type(k)](k, r)
|
|
||||||
encode_func[type(v)](v, r)
|
|
||||||
r.append(CHR_TERM)
|
|
||||||
|
|
||||||
|
|
||||||
def loads(x):
|
|
||||||
try:
|
try:
|
||||||
r, l = decode_func[x[0]](x, 0)
|
r, l = decode_func[x[0:1]](x, 0)
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
if l != len(x):
|
if l != len(x):
|
||||||
|
@ -325,14 +309,11 @@ def loads(x):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
from types import StringType, IntType, LongType, DictType, ListType, TupleType, FloatType, NoneType, UnicodeType
|
|
||||||
|
|
||||||
|
|
||||||
def encode_int(x, r):
|
def encode_int(x, r):
|
||||||
if 0 <= x < INT_POS_FIXED_COUNT:
|
if 0 <= x < INT_POS_FIXED_COUNT:
|
||||||
r.append(chr(INT_POS_FIXED_START + x))
|
r.append(int2byte(INT_POS_FIXED_START + x))
|
||||||
elif -INT_NEG_FIXED_COUNT <= x < 0:
|
elif -INT_NEG_FIXED_COUNT <= x < 0:
|
||||||
r.append(chr(INT_NEG_FIXED_START - 1 - x))
|
r.append(int2byte(INT_NEG_FIXED_START - 1 - x))
|
||||||
elif -128 <= x < 128:
|
elif -128 <= x < 128:
|
||||||
r.extend((CHR_INT1, struct.pack('!b', x)))
|
r.extend((CHR_INT1, struct.pack('!b', x)))
|
||||||
elif -32768 <= x < 32768:
|
elif -32768 <= x < 32768:
|
||||||
|
@ -343,6 +324,9 @@ def encode_int(x, r):
|
||||||
r.extend((CHR_INT8, struct.pack('!q', x)))
|
r.extend((CHR_INT8, struct.pack('!q', x)))
|
||||||
else:
|
else:
|
||||||
s = str(x)
|
s = str(x)
|
||||||
|
if py3:
|
||||||
|
s = bytes(s, "ascii")
|
||||||
|
|
||||||
if len(s) >= MAX_INT_LENGTH:
|
if len(s) >= MAX_INT_LENGTH:
|
||||||
raise ValueError('overflow')
|
raise ValueError('overflow')
|
||||||
r.extend((CHR_INT, s, CHR_TERM))
|
r.extend((CHR_INT, s, CHR_TERM))
|
||||||
|
@ -357,18 +341,21 @@ def encode_float64(x, r):
|
||||||
|
|
||||||
|
|
||||||
def encode_bool(x, r):
|
def encode_bool(x, r):
|
||||||
r.extend({False: CHR_FALSE, True: CHR_TRUE}[bool(x)])
|
r.append({False: CHR_FALSE, True: CHR_TRUE}[bool(x)])
|
||||||
|
|
||||||
|
|
||||||
def encode_none(x, r):
|
def encode_none(x, r):
|
||||||
r.extend(CHR_NONE)
|
r.append(CHR_NONE)
|
||||||
|
|
||||||
|
|
||||||
def encode_string(x, r):
|
def encode_string(x, r):
|
||||||
if len(x) < STR_FIXED_COUNT:
|
if len(x) < STR_FIXED_COUNT:
|
||||||
r.extend((chr(STR_FIXED_START + len(x)), x))
|
r.extend((int2byte(STR_FIXED_START + len(x)), x))
|
||||||
else:
|
else:
|
||||||
r.extend((str(len(x)), ':', x))
|
s = str(len(x))
|
||||||
|
if py3:
|
||||||
|
s = bytes(s, "ascii")
|
||||||
|
r.extend((s, b':', x))
|
||||||
|
|
||||||
|
|
||||||
def encode_unicode(x, r):
|
def encode_unicode(x, r):
|
||||||
|
@ -377,7 +364,7 @@ def encode_unicode(x, r):
|
||||||
|
|
||||||
def encode_list(x, r):
|
def encode_list(x, r):
|
||||||
if len(x) < LIST_FIXED_COUNT:
|
if len(x) < LIST_FIXED_COUNT:
|
||||||
r.append(chr(LIST_FIXED_START + len(x)))
|
r.append(int2byte(LIST_FIXED_START + len(x)))
|
||||||
for i in x:
|
for i in x:
|
||||||
encode_func[type(i)](i, r)
|
encode_func[type(i)](i, r)
|
||||||
else:
|
else:
|
||||||
|
@ -389,7 +376,7 @@ def encode_list(x, r):
|
||||||
|
|
||||||
def encode_dict(x, r):
|
def encode_dict(x, r):
|
||||||
if len(x) < DICT_FIXED_COUNT:
|
if len(x) < DICT_FIXED_COUNT:
|
||||||
r.append(chr(DICT_FIXED_START + len(x)))
|
r.append(int2byte(DICT_FIXED_START + len(x)))
|
||||||
for k, v in x.items():
|
for k, v in x.items():
|
||||||
encode_func[type(k)](k, r)
|
encode_func[type(k)](k, r)
|
||||||
encode_func[type(v)](v, r)
|
encode_func[type(v)](v, r)
|
||||||
|
@ -400,27 +387,19 @@ def encode_dict(x, r):
|
||||||
encode_func[type(v)](v, r)
|
encode_func[type(v)](v, r)
|
||||||
r.append(CHR_TERM)
|
r.append(CHR_TERM)
|
||||||
|
|
||||||
|
encode_func = {}
|
||||||
encode_func = {
|
encode_func[int] = encode_int
|
||||||
IntType: encode_int,
|
encode_func[long] = encode_int
|
||||||
LongType: encode_int,
|
encode_func[bytes] = encode_string
|
||||||
StringType: encode_string,
|
encode_func[list] = encode_list
|
||||||
ListType: encode_list,
|
encode_func[tuple] = encode_list
|
||||||
TupleType: encode_list,
|
encode_func[dict] = encode_dict
|
||||||
DictType: encode_dict,
|
encode_func[type(None)] = encode_none
|
||||||
NoneType: encode_none,
|
encode_func[unicode] = encode_unicode
|
||||||
UnicodeType: encode_unicode,
|
encode_func[bool] = encode_bool
|
||||||
}
|
|
||||||
|
|
||||||
lock = Lock()
|
lock = Lock()
|
||||||
|
|
||||||
try:
|
|
||||||
from types import BooleanType
|
|
||||||
|
|
||||||
encode_func[BooleanType] = encode_bool
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def dumps(x, float_bits=DEFAULT_FLOAT_BITS):
|
def dumps(x, float_bits=DEFAULT_FLOAT_BITS):
|
||||||
"""
|
"""
|
||||||
|
@ -428,60 +407,55 @@ def dumps(x, float_bits=DEFAULT_FLOAT_BITS):
|
||||||
|
|
||||||
Here float_bits is either 32 or 64.
|
Here float_bits is either 32 or 64.
|
||||||
"""
|
"""
|
||||||
lock.acquire()
|
with lock:
|
||||||
try:
|
|
||||||
if float_bits == 32:
|
if float_bits == 32:
|
||||||
encode_func[FloatType] = encode_float32
|
encode_func[float] = encode_float32
|
||||||
elif float_bits == 64:
|
elif float_bits == 64:
|
||||||
encode_func[FloatType] = encode_float64
|
encode_func[float] = encode_float64
|
||||||
else:
|
else:
|
||||||
raise ValueError('Float bits ({0:d}) is not 32 or 64'.format(float_bits))
|
raise ValueError('Float bits (%d) is not 32 or 64' % float_bits)
|
||||||
r = []
|
r = []
|
||||||
encode_func[type(x)](x, r)
|
encode_func[type(x)](x, r)
|
||||||
finally:
|
return b''.join(r)
|
||||||
lock.release()
|
|
||||||
return ''.join(r)
|
|
||||||
|
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
f1 = struct.unpack('!f', struct.pack('!f', 25.5))[0]
|
f1 = struct.unpack('!f', struct.pack('!f', 25.5))[0]
|
||||||
f2 = struct.unpack('!f', struct.pack('!f', 29.3))[0]
|
f2 = struct.unpack('!f', struct.pack('!f', 29.3))[0]
|
||||||
f3 = struct.unpack('!f', struct.pack('!f', -0.6))[0]
|
f3 = struct.unpack('!f', struct.pack('!f', -0.6))[0]
|
||||||
L = (({'a': 15, 'bb': f1, 'ccc': f2, '': (f3, (), False, True, '')}, ('a', 10 ** 20), tuple(range(-100000, 100000)),
|
ld = (({b'a': 15, b'bb': f1, b'ccc': f2, b'': (f3, (), False, True, b'')}, (b'a', 10**20),
|
||||||
'b' * 31, 'b' * 62, 'b' * 64, 2 ** 30, 2 ** 33, 2 ** 62, 2 ** 64, 2 ** 30, 2 ** 33, 2 ** 62, 2 ** 64, False,
|
tuple(range(-100000, 100000)), b'b' * 31, b'b' * 62, b'b' * 64, 2**30, 2**33, 2**62,
|
||||||
False, True, -1, 2, 0),)
|
2**64, 2**30, 2**33, 2**62, 2**64, False, False, True, -1, 2, 0),)
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
d = dict(zip(range(-100000, 100000), range(-100000, 100000)))
|
d = dict(zip(range(-100000, 100000), range(-100000, 100000)))
|
||||||
d.update({'a': 20, 20: 40, 40: 41, f1: f2, f2: f3, f3: False, False: True, True: False})
|
d.update({b'a': 20, 20: 40, 40: 41, f1: f2, f2: f3, f3: False, False: True, True: False})
|
||||||
L = (d, {}, {5: 6}, {7: 7, True: 8}, {9: 10, 22: 39, 49: 50, 44: ''})
|
ld = (d, {}, {5: 6}, {7: 7, True: 8}, {9: 10, 22: 39, 49: 50, 44: b''})
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
L = ('', 'a' * 10, 'a' * 100, 'a' * 1000, 'a' * 10000, 'a' * 100000, 'a' * 1000000, 'a' * 10000000)
|
ld = (b'', b'a' * 10, b'a' * 100, b'a' * 1000, b'a' * 10000, b'a' * 100000, b'a' * 1000000, b'a' * 10000000)
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
L = tuple([dict(zip(range(n), range(n))) for n in range(100)]) + ('b',)
|
ld = tuple([dict(zip(range(n), range(n))) for n in range(100)]) + (b'b',)
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
L = tuple([dict(zip(range(n), range(-n, 0))) for n in range(100)]) + ('b',)
|
ld = tuple([dict(zip(range(n), range(-n, 0))) for n in range(100)]) + (b'b',)
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
L = tuple([tuple(range(n)) for n in range(100)]) + ('b',)
|
ld = tuple([tuple(range(n)) for n in range(100)]) + (b'b',)
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
L = tuple(['a' * n for n in range(1000)]) + ('b',)
|
ld = tuple([b'a' * n for n in range(1000)]) + (b'b',)
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
L = tuple(['a' * n for n in range(1000)]) + (None, True, None)
|
ld = tuple([b'a' * n for n in range(1000)]) + (None, True, None)
|
||||||
assert loads(dumps(L)) == L
|
assert loads(dumps(ld)) == ld
|
||||||
assert loads(dumps(None)) is None
|
assert loads(dumps(None)) is None
|
||||||
assert loads(dumps({None: None})) == {None: None}
|
assert loads(dumps({None: None})) == {None: None}
|
||||||
assert 1e-10 < abs(loads(dumps(1.1)) - 1.1) < 1e-6
|
assert 1e-10 < abs(loads(dumps(1.1)) - 1.1) < 1e-6
|
||||||
assert 1e-10 < abs(loads(dumps(1.1, 32)) - 1.1) < 1e-6
|
assert 1e-10 < abs(loads(dumps(1.1, 32)) - 1.1) < 1e-6
|
||||||
assert abs(loads(dumps(1.1, 64)) - 1.1) < 1e-12
|
assert abs(loads(dumps(1.1, 64)) - 1.1) < 1e-12
|
||||||
assert loads(dumps(u"Hello World!!"))
|
assert loads(dumps("Hello World!!"), decode_utf8=True)
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import psyco
|
import psyco
|
||||||
|
|
||||||
psyco.bind(dumps)
|
psyco.bind(dumps)
|
||||||
psyco.bind(loads)
|
psyco.bind(loads)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test()
|
test()
|
|
@ -15,7 +15,7 @@ Example usage:
|
||||||
download_location = client.core.get_config_value("download_location").get()
|
download_location = client.core.get_config_value("download_location").get()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from core.synchronousdeluge.exceptions import DelugeRPCError
|
from .exceptions import DelugeRPCError
|
||||||
|
|
||||||
|
|
||||||
__title__ = "synchronous-deluge"
|
__title__ = "synchronous-deluge"
|
|
@ -1,9 +1,10 @@
|
||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from itertools import imap
|
|
||||||
|
from six.moves import map as imap
|
||||||
|
|
||||||
from .exceptions import DelugeRPCError
|
from .exceptions import DelugeRPCError
|
||||||
from .protocol import DelugeRPCRequest, DelugeRPCResponse
|
from .protocol import DelugeRPCRequest, DelugeRPCResponse
|
||||||
from .transfer import DelugeTransfer
|
from .transfer import DelugeTransfer
|
|
@ -1,5 +1,4 @@
|
||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
__all__ = ["DelugeRPCError"]
|
|
||||||
|
|
||||||
|
|
||||||
class DelugeRPCError(Exception):
|
class DelugeRPCError(Exception):
|
|
@ -1,5 +1,4 @@
|
||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
__all__ = ["DelugeRPCRequest", "DelugeRPCResponse"]
|
|
||||||
|
|
||||||
|
|
||||||
class DelugeRPCRequest(object):
|
class DelugeRPCRequest(object):
|
|
@ -1,10 +1,10 @@
|
||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
import zlib
|
|
||||||
import struct
|
|
||||||
import socket
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
|
import struct
|
||||||
|
import zlib
|
||||||
|
|
||||||
from core.synchronousdeluge import rencode
|
import rencode
|
||||||
|
|
||||||
__all__ = ["DelugeTransfer"]
|
__all__ = ["DelugeTransfer"]
|
||||||
|
|
18
libs/transmissionrpc/__init__.py
Normal file
18
libs/transmissionrpc/__init__.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
||||||
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
|
from transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT, PRIORITY, RATIO_LIMIT, LOGGER
|
||||||
|
from transmissionrpc.error import TransmissionError, HTTPHandlerError
|
||||||
|
from transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler
|
||||||
|
from transmissionrpc.torrent import Torrent
|
||||||
|
from transmissionrpc.session import Session
|
||||||
|
from transmissionrpc.client import Client
|
||||||
|
from transmissionrpc.utils import add_stdout_logger, add_file_logger
|
||||||
|
|
||||||
|
__author__ = 'Erik Svensson <erik.public@gmail.com>'
|
||||||
|
__version_major__ = 0
|
||||||
|
__version_minor__ = 11
|
||||||
|
__version__ = '{0}.{1}'.format(__version_major__, __version_minor__)
|
||||||
|
__copyright__ = 'Copyright (c) 2008-2013 Erik Svensson'
|
||||||
|
__license__ = 'MIT'
|
|
@ -2,24 +2,24 @@
|
||||||
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import re
|
|
||||||
import time
|
|
||||||
import operator
|
|
||||||
import warnings
|
|
||||||
import os
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
|
import operator
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import warnings
|
||||||
|
|
||||||
from six import PY3, integer_types, string_types, iteritems
|
from six import PY3, integer_types, iteritems, string_types
|
||||||
from six.moves.urllib_parse import urlparse
|
from six.moves.urllib_parse import urlparse
|
||||||
from six.moves.urllib_request import urlopen
|
from six.moves.urllib_request import urlopen
|
||||||
|
|
||||||
from core.transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT
|
from .constants import DEFAULT_PORT, DEFAULT_TIMEOUT
|
||||||
from core.transmissionrpc.error import TransmissionError, HTTPHandlerError
|
from .error import HTTPHandlerError, TransmissionError
|
||||||
from core.transmissionrpc.utils import LOGGER, get_arguments, make_rpc_name, argument_value_convert, rpc_bool
|
from .httphandler import DefaultHTTPHandler
|
||||||
from core.transmissionrpc.httphandler import DefaultHTTPHandler
|
from .session import Session
|
||||||
from core.transmissionrpc.torrent import Torrent
|
from .torrent import Torrent
|
||||||
from core.transmissionrpc.session import Session
|
from .utils import LOGGER, argument_value_convert, get_arguments, make_rpc_name, rpc_bool
|
||||||
|
|
||||||
|
|
||||||
def debug_httperror(error):
|
def debug_httperror(error):
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
from six import string_types, integer_types
|
from six import integer_types, string_types
|
||||||
|
|
||||||
|
|
||||||
class TransmissionError(Exception):
|
class TransmissionError(Exception):
|
|
@ -4,15 +4,17 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from six.moves.urllib_request import (
|
|
||||||
build_opener, install_opener,
|
|
||||||
HTTPBasicAuthHandler, HTTPDigestAuthHandler, HTTPPasswordMgrWithDefaultRealm,
|
|
||||||
Request,
|
|
||||||
)
|
|
||||||
from six.moves.urllib_error import HTTPError, URLError
|
|
||||||
from six.moves.http_client import BadStatusLine
|
from six.moves.http_client import BadStatusLine
|
||||||
|
from six.moves.urllib_error import HTTPError, URLError
|
||||||
|
from six.moves.urllib_request import (
|
||||||
|
HTTPBasicAuthHandler,
|
||||||
|
HTTPDigestAuthHandler,
|
||||||
|
HTTPPasswordMgrWithDefaultRealm,
|
||||||
|
Request,
|
||||||
|
build_opener,
|
||||||
|
)
|
||||||
|
|
||||||
from core.transmissionrpc.error import HTTPHandlerError
|
from .error import HTTPHandlerError
|
||||||
|
|
||||||
|
|
||||||
class HTTPHandler(object):
|
class HTTPHandler(object):
|
|
@ -2,9 +2,9 @@
|
||||||
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
from six import iteritems, integer_types
|
from six import integer_types, iteritems
|
||||||
|
|
||||||
from core.transmissionrpc.utils import Field
|
from .utils import Field
|
||||||
|
|
||||||
|
|
||||||
class Session(object):
|
class Session(object):
|
|
@ -2,13 +2,13 @@
|
||||||
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import sys
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
from six import integer_types, string_types, text_type, iteritems
|
from six import integer_types, iteritems, string_types, text_type
|
||||||
|
|
||||||
from core.transmissionrpc.constants import PRIORITY, RATIO_LIMIT, IDLE_LIMIT
|
from .constants import IDLE_LIMIT, PRIORITY, RATIO_LIMIT
|
||||||
from core.transmissionrpc.utils import Field, format_timedelta
|
from .utils import Field, format_timedelta
|
||||||
|
|
||||||
|
|
||||||
def get_status_old(code):
|
def get_status_old(code):
|
|
@ -2,7 +2,6 @@
|
||||||
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2013 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import constants
|
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
@ -10,7 +9,8 @@ from collections import namedtuple
|
||||||
|
|
||||||
from six import iteritems, string_types
|
from six import iteritems, string_types
|
||||||
|
|
||||||
from constants import LOGGER
|
from . import constants
|
||||||
|
from .constants import LOGGER
|
||||||
|
|
||||||
UNITS = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
|
UNITS = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
# coding=utf8
|
# coding=utf8
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
import urlparse
|
|
||||||
import cookielib
|
|
||||||
import re
|
import re
|
||||||
import StringIO
|
import urllib
|
||||||
|
|
||||||
|
from six import StringIO
|
||||||
|
from six.moves.http_cookiejar import CookieJar
|
||||||
|
from six.moves.urllib.request import (
|
||||||
|
HTTPBasicAuthHandler,
|
||||||
|
HTTPCookieProcessor,
|
||||||
|
Request,
|
||||||
|
build_opener,
|
||||||
|
install_opener,
|
||||||
|
)
|
||||||
|
from six.moves.urllib_parse import urljoin
|
||||||
|
|
||||||
|
from .upload import MultiPartForm
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
|
|
||||||
from upload import MultiPartForm
|
|
||||||
|
|
||||||
class UTorrentClient(object):
|
class UTorrentClient(object):
|
||||||
|
|
||||||
def __init__(self, base_url, username, password):
|
def __init__(self, base_url, username, password):
|
||||||
|
@ -25,23 +33,23 @@ class UTorrentClient(object):
|
||||||
def _make_opener(self, realm, base_url, username, password):
|
def _make_opener(self, realm, base_url, username, password):
|
||||||
'''uTorrent API need HTTP Basic Auth and cookie support for token verify.'''
|
'''uTorrent API need HTTP Basic Auth and cookie support for token verify.'''
|
||||||
|
|
||||||
auth_handler = urllib2.HTTPBasicAuthHandler()
|
auth_handler = HTTPBasicAuthHandler()
|
||||||
auth_handler.add_password(realm=realm,
|
auth_handler.add_password(realm=realm,
|
||||||
uri=base_url,
|
uri=base_url,
|
||||||
user=username,
|
user=username,
|
||||||
passwd=password)
|
passwd=password)
|
||||||
opener = urllib2.build_opener(auth_handler)
|
opener = build_opener(auth_handler)
|
||||||
urllib2.install_opener(opener)
|
install_opener(opener)
|
||||||
|
|
||||||
cookie_jar = cookielib.CookieJar()
|
cookie_jar = CookieJar()
|
||||||
cookie_handler = urllib2.HTTPCookieProcessor(cookie_jar)
|
cookie_handler = HTTPCookieProcessor(cookie_jar)
|
||||||
|
|
||||||
handlers = [auth_handler, cookie_handler]
|
handlers = [auth_handler, cookie_handler]
|
||||||
opener = urllib2.build_opener(*handlers)
|
opener = build_opener(*handlers)
|
||||||
return opener
|
return opener
|
||||||
|
|
||||||
def _get_token(self):
|
def _get_token(self):
|
||||||
url = urlparse.urljoin(self.base_url, 'token.html')
|
url = urljoin(self.base_url, 'token.html')
|
||||||
response = self.opener.open(url)
|
response = self.opener.open(url)
|
||||||
token_re = "<div id='token' style='display:none;'>([^<>]+)</div>"
|
token_re = "<div id='token' style='display:none;'>([^<>]+)</div>"
|
||||||
match = re.search(token_re, response.read())
|
match = re.search(token_re, response.read())
|
||||||
|
@ -131,7 +139,7 @@ class UTorrentClient(object):
|
||||||
def _action(self, params, body=None, content_type=None):
|
def _action(self, params, body=None, content_type=None):
|
||||||
#about token, see https://github.com/bittorrent/webui/wiki/TokenSystem
|
#about token, see https://github.com/bittorrent/webui/wiki/TokenSystem
|
||||||
url = self.base_url + '?token=' + self.token + '&' + urllib.urlencode(params)
|
url = self.base_url + '?token=' + self.token + '&' + urllib.urlencode(params)
|
||||||
request = urllib2.Request(url)
|
request = Request(url)
|
||||||
|
|
||||||
if body:
|
if body:
|
||||||
request.add_data(body)
|
request.add_data(body)
|
||||||
|
@ -139,8 +147,5 @@ class UTorrentClient(object):
|
||||||
if content_type:
|
if content_type:
|
||||||
request.add_header('Content-type', content_type)
|
request.add_header('Content-type', content_type)
|
||||||
|
|
||||||
try:
|
|
||||||
response = self.opener.open(request)
|
response = self.opener.open(request)
|
||||||
return response.code, json.loads(response.read())
|
return response.code, json.loads(response.read())
|
||||||
except urllib2.HTTPError,e:
|
|
||||||
raise
|
|
|
@ -2,11 +2,9 @@
|
||||||
# code copied from http://www.doughellmann.com/PyMOTW/urllib2/
|
# code copied from http://www.doughellmann.com/PyMOTW/urllib2/
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import mimetools
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from cStringIO import StringIO
|
from email.generator import _make_boundary as choose_boundary
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
|
|
||||||
class MultiPartForm(object):
|
class MultiPartForm(object):
|
||||||
"""Accumulate the data to be used when posting a form."""
|
"""Accumulate the data to be used when posting a form."""
|
||||||
|
@ -14,7 +12,7 @@ class MultiPartForm(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.form_fields = []
|
self.form_fields = []
|
||||||
self.files = []
|
self.files = []
|
||||||
self.boundary = mimetools.choose_boundary()
|
self.boundary = choose_boundary()
|
||||||
return
|
return
|
||||||
|
|
||||||
def get_content_type(self):
|
def get_content_type(self):
|
Loading…
Add table
Add a link
Reference in a new issue