1 Commits

Author SHA1 Message Date
snyk-bot
2a2fa1a9b5 fix: requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-WEBSOCKETS-1582792
2021-11-14 05:26:14 +00:00
12 changed files with 279 additions and 509 deletions

View File

@@ -1,90 +0,0 @@
---
kind: pipeline
type: docker
name: Build and test amd64
platform:
os: linux
arch: amd64
steps:
- name: Build source
image: python:3.10
commands:
- make build
- name: Install
image: python:3.10
commands:
- make dist
- pip3 install -r requirements.txt
- pip3 install dist/*.whl
# - pipenv install pytest
# - name: Run tests
# image: python:3.10
# commands:
# pipenv run pytest
---
kind: pipeline
type: docker
name: Publish package to PyPi
platform:
os: linux
arch: amd64
steps:
- name: Newer version to publish?
image: python:3.10
commands:
- pip3 install delugeClient-kevin -q -q
- bash publish_version?.sh
- name: PyPi verify
image: python:3.10
commands:
- make dist
- pip3 install twine
- twine check dist/*
- name: PyPi test publish
image: python:3.10
environment:
TWINE_USERNAME:
from_secret: TWINE_USERNAME
TWINE_PASSWORD:
from_secret: TWINE_TEST_PASSWORD
commands:
- make dist
- pip3 install twine
- twine upload --repository-url https://test.pypi.org/legacy/ dist/*
- name: PyPi publish
image: python:3.10
environment:
TWINE_USERNAME:
from_secret: TWINE_USERNAME
TWINE_PASSWORD:
from_secret: TWINE_PASSWORD
commands:
- make dist
- pip3 install twine
- twine upload dist/*
depends_on:
- Build and test amd64
trigger:
branch:
- master
event:
exclude:
- pull_request
---
kind: signature
hmac: 60604a21f35e11d078d5d381bbea8e25b903175c018ba9e6f4a4379285e89883
...

View File

@@ -1,22 +0,0 @@
.PHONY: clean
binaries=dist build
install:
python3 setup.py install
build:
python3 setup.py build
tarball:
python3 setup.py sdist
wheel:
python3 setup.py bdist_wheel
dist: tarball wheel
upload: clean dist
twine upload dist/*
clean:
rm -rf $(binaries)

124
README.md
View File

@@ -4,20 +4,26 @@
<h4 align="center"> A easy to use Deluge CLI that can connect to Deluge RPC (even over ssh) written entirely in python.</h4>
| Tested version | PyPi package | License |
|:--------|:------|:------|
| [![PyVersion](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/) | [![PyPI](https://img.shields.io/pypi/v/delugeClient_kevin)](https://pypi.org/project/delugeClient_kevin/) |[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
| Drone CI | Known vulnerabilities |
|:--------|:------|
| [![Build Status](https://drone.schleppe.cloud/api/badges/KevinMidboe/delugeClient/status.svg)](https://drone.schleppe.cloud/KevinMidboe/delugeClient) | [![Known Vulnerabilities](https://snyk.io/test/github/kevinmidboe/delugeClient/badge.svg?targetFile=requirements.txt)](https://snyk.io/test/github/kevinmidboe/delugeClient?targetFile=requirements.txt)
<p align="center">
<a href="https://pypi.org/project/delugeClient-kevin/">
<img src="https://img.shields.io/pypi/v/delugeClient-kevin" />
</a>
<a href="https://snyk.io/test/github/kevinmidboe/delugeclient?targetFile=requirements.txt">
<img src="https://snyk.io/test/github/kevinmidboe/delugeclient/badge.svg?targetFile=requirements.txt" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/kevinmidboe/delugeclient?targetFile=requirements.txt" style="max-width:100%;">
</a>
<a href="https://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="">
</a>
</p>
<p align="center">
<a href="#abstract">Abstract</a>
<a href="#install">Install</a>
<a href="#usage">Usage</a>
<a href="#setup_virtualenv">Setup Virtual Environment</a>
<a href="#setup_virtualenv">Setup virtualenv</a>
<a href="#configure">Configure</a>
<a href="#installation">Install dependencies</a>
<a href="#usage">Usage</a>
<a href="#running">Running</a>
<a href="#contributing">Contributing</a>
</p>
@@ -25,51 +31,6 @@
## <a name="abstract"></a> Abstract
Create a deluge python client for interfacing with deluge for common tasks like listing, adding, removing and setting download directory for torrents.
## <a name="install"></a> Install
Install from source:
```bash
python3 setup.py install
```
Install from pip:
```bash
pip3 install delugeClient-kevin
```
## <a name="usage"></a> Usage
View delugeClient cli options with `delugeclient --help`:
```
Usage: python -m delugeclient [OPTIONS] COMMAND [ARGS]...
╭─ Options ───────────────────────────────────────────────────────────────╮
│ --debug Set log level to debug │
│ --info Set log level to info │
│ --warning Set log level to warning │
│ --error Set log level to error │
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell │
│ --help Show this message and exit. │
╰─────────────────────────────────────────────────────────────────────────╯
╭─ Commands ──────────────────────────────────────────────────────────────╮
│ add Add magnet torrent │
│ disk Get free disk space │
│ get Get torrent by id or hash │
│ ls List all torrents │
│ remove Remove torrent by id or hash │
│ rm Remove torrent by name │
│ search Search for string segment in torrent name │
│ toggle Toggle torrent download state │
│ version Print package version │
╰─────────────────────────────────────────────────────────────────────────╯
```
### Running from source
Run from source for fun or during development using module flag:
```
python3 -m delugeClient --help
```
## <a name="setup_virtualenv"></a> Setup Virtual Environment
Virtual environment allows us to create a local environment for the requirements needed. Because pip does not download packages already downloaded to your system, we can use virtualenv to save our packages in the project folder.
@@ -83,7 +44,7 @@ To install virtualenv, simply run:
```
### Virtualenv setup
### Usage
After you have downloaded this project go to it in your terminal by going to the folder you downloaded and typing the following:
@@ -94,12 +55,14 @@ After you have downloaded this project go to it in your terminal by going to the
The to setup a virtual environment enter this:
```
$ virtualenv -p python3.10 env
$ virtualenv -p python3.6 env
```
> If you get an error now it might be because you don't have python3.10, please make sure you have python version 3.10 if else you can download it from [here](https://www.python.org/downloads/)
> If you get an error now it might be because you don't have python3.6, please make sure you have python version 3.6 if else you can download it from [here](https://www.python.org/downloads/)
First we navigate to the folder we downloaded.
Then we use the ```virtualenv``` command to create a ```env``` subdirectory in our project. This is where pip will download everything to and where we can add other specific python versions. Then we need to *activate* our virtual environment by doing:
```
@@ -136,6 +99,51 @@ Then you need to change the HOST and PORT to reflect the address for your deluge
$ cat /home/USER/.config/deluge/auth
```
## <a name="install"></a> Install Required Dependencies
Now that we have our virutalenv set up and activated we want to install all the necessary packages listed in `requirements.txt`. To install it's dependencies do the following:
```
$ pip install -r requirements.txt
```
Now we have our neccessary packages installed!
## <a name="usage"></a> Usage
```
Custom delugeRPC client
Usage:
deluge_cli add MAGNET [DIR] [--debug | --warning | --error]
deluge_cli get TORRENT
deluge_cli ls [--downloading | --seeding | --paused]
deluge_cli toggle TORRENT
deluge_cli rm TORRENT [--debug | --warning | --error]
deluge_cli (-h | --help)
deluge_cli --version
Arguments:
MAGNET Magnet link to add
DIR Directory to save to
TORRENT A selected torrent
Options:
-h --help Show this screen
--version Show version
--debug Print all debug log
--warning Print only logged warnings
--error Print error messages (Error/Warning)
```
### <a name="running"></a> Running
To interface with deluged :
```
$ ./deluge_cli.py ls
```
## <a name="contributing"></a> Contributing
- Fork it!
- Create your feature branch: git checkout -b my-new-feature

View File

@@ -1,24 +1,22 @@
#!/usr/bin/env python3.10
# -*- encoding: utf-8 -*-
import os
from sys import path
from os.path import dirname, join, abspath
SCRIPT_DIR = dirname(abspath(__file__))
path.append(dirname(SCRIPT_DIR))
path.append(os.path.dirname(__file__))
__version__=0.1
import logging
from delugeClient.utils import BASE_DIR
from delugeClient.deluge import Deluge
def addHandler(handler):
handler.setFormatter(formatter)
logger.addHandler(handler)
from delugeUtils import BASE_DIR
logger = logging.getLogger('deluge_cli')
logger.setLevel(logging.DEBUG)
fh = logging.FileHandler(join(BASE_DIR, 'deluge_cli.log'))
formatter = logging.Formatter('%(asctime)s| %(levelname)s | %(message)s')
fh = logging.FileHandler(os.path.join(BASE_DIR, 'deluge_cli.log'))
fh.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
addHandler(fh)
formatter = logging.Formatter('%(asctime)s %(levelname)8s %(name)s | %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.addHandler(ch)

View File

@@ -1,176 +1,148 @@
#!/usr/bin/env python3.10
#!/usr/bin/env python3.6
"""Custom delugeRPC client
Usage:
deluge_cli add MAGNET [DIR] [--json | --debug | --warning | --error]
deluge_cli search NAME [--json]
deluge_cli get TORRENT [--json | --debug | --warning | --error]
deluge_cli ls [--downloading | --seeding | --paused | --json]
deluge_cli toggle TORRENT
deluge_cli progress [--json]
deluge_cli rm NAME [--destroy] [--debug | --warning | --error]
deluge_cli (-h | --help)
deluge_cli --version
Arguments:
MAGNET Magnet link to add
DIR Directory to save to
TORRENT A selected torrent
Options:
-h --help Show this screen
--version Show version
--print Print response from commands
--json Print response as JSON
--debug Print all debug log
--warning Print only logged warnings
--error Print error messages (Error/Warning)
"""
import os
import sys
import signal
import logging
import typer
from docopt import docopt
from pprint import pprint
from delugeClient.deluge import Deluge
from delugeClient.utils import ColorizeFilter, BASE_DIR, validHash, convertFilesize
from delugeClient.__version__ import __version__
from delugeClient.__init__ import addHandler
from deluge import Deluge
from utils import ColorizeFilter, BASE_DIR
from __init__ import __version__
ch = logging.StreamHandler()
ch.addFilter(ColorizeFilter())
addHandler(ch)
logger = logging.getLogger('deluge_cli')
logger.setLevel(logging.DEBUG)
app = typer.Typer()
deluge = None
fh = logging.FileHandler(os.path.join(BASE_DIR, 'deluge_cli.log'))
fh.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
formatter = logging.Formatter('%(asctime)s %(levelname)8s %(name)s | %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.addHandler(ch)
logger.addFilter(ColorizeFilter())
def signal_handler(signal, frame):
"""
Handle exit by Keyboardinterrupt
"""
global deluge
del deluge
logger.info('\nGood bye!')
sys.exit(1)
sys.exit(0)
def handleKeyboardInterrupt():
def main():
"""
Main function, parse the input
"""
signal.signal(signal.SIGINT, signal_handler)
def printResponse(response, json=False):
arguments = docopt(__doc__, version=__version__)
# Set logging level for streamHandler
if arguments['--debug']:
ch.setLevel(logging.DEBUG)
elif arguments['--warning']:
ch.setLevel(logging.WARNING)
elif arguments['--error']:
ch.setLevel(logging.ERROR)
logger.info('Deluge client')
logger.debug(arguments)
# Get config settings
deluge = Deluge()
_id = arguments['TORRENT']
query = arguments['NAME']
magnet = arguments['MAGNET']
name = arguments['NAME']
_filter = [ a[2:] for a in ['--downloading', '--seeding', '--paused'] if arguments[a] ]
response = None
if arguments['add']:
logger.info('Add cmd selected with link {}'.format(magnet))
response = deluge.add(magnet)
if response is not None:
logger.info('Successfully added torrent.\nResponse from deluge: {}'.format(response))
else:
logger.warning('Add response returned empty: {}'.format(response))
elif arguments['search']:
logger.info('Search cmd selected for query: {}'.format(query))
response = deluge.search(query)
if response is not None or response != '[]':
logger.info('Search found {} torrents'.format(len(response)))
else:
logger.info('Empty response for search query.')
elif arguments['progress']:
logger.info('Progress cmd selected.')
response = deluge.progress()
elif arguments['get']:
logger.info('Get cmd selected for id: {}'.format(_id))
response = deluge.get(_id)
elif arguments['ls']:
logger.info('List cmd selected')
response = deluge.get_all(_filter=_filter)
elif arguments['toggle']:
logger.info('Toggling id: {}'.format(_id))
deluge.togglePaused(_id)
elif arguments['rm']:
destroy = arguments['--destroy']
logger.info('Remove by name: {}.'.format(name))
if destroy:
logger.info('Destroy set, removing files')
deluge.remove(name, destroy)
try:
if json:
if isinstance(response, list):
if arguments['--json']:
if len(response) > 1:
print('[{}]'.format(','.join([t.toJSON() for t in response])))
else:
print(response.toJSON())
elif isinstance(response, list):
for el in response:
print(el)
elif response:
print(response)
print(response[0].toJSON())
except KeyError as error:
logger.error('Unexpected error while trying to print')
raise error
@app.command()
def add(magnet: str, json: bool = typer.Option(False, help="Print as json")):
'''
Add magnet torrent
'''
logger.info('Add command selected')
logger.debug(magnet)
response = deluge.add(magnet)
if validHash(response):
torrent = deluge.get(response)
printResponse(torrent, json)
else:
logger.info('Unable to add torrent')
@app.command()
def ls(json: bool = typer.Option(False, help="Print as json")):
'''
List all torrents
'''
logger.info('List command selected')
response = deluge.get_all()
if response is None:
logger.info('No torrents found')
return
printResponse(response, json)
@app.command()
def get(id: str, json: bool = typer.Option(False, help="Print as json")):
'''
Get torrent by id or hash
'''
logger.info('Get command selected for id: {}'.format(id))
if not validHash(id):
return logger.info("Id is not valid")
response = deluge.get(id)
printResponse(response, json)
@app.command()
def toggle(id: str):
'''
Toggle torrent download state
'''
logger.info('Toggle command selected for id: {}'.format(id))
if not validHash(id):
return logger.info("Id is not valid")
deluge.toggle(id)
torrent = deluge.get(id)
printResponse(torrent)
@app.command()
def search(query: str, json: bool = typer.Option(False, help="Print as json")):
'''
Search for string segment in torrent name
'''
logger.info('Search command selected with query: {}'.format(query))
response = deluge.search(query)
printResponse(response, json)
@app.command()
def rm(name: str, destroy: bool = typer.Option(False, help="Remove torrent by name")):
'''
Remove torrent by name
'''
logger.info('Removing torrent with name: {}, destroy flag: {}'.format(name, destroy))
response = deluge.removeByName(name, destroy)
@app.command()
def remove(id: str, destroy: bool = typer.Option(False, help="Remove torrent by id")):
'''
Remove torrent by id or hash
'''
logger.info('Removing torrent with id: {}, destroy flag: {}'.format(id, destroy))
if not validHash(id):
return logger.info("Id is not valid")
response = deluge.remove(id, destroy)
@app.command()
def disk():
'''
Get free disk space
'''
response = deluge.freeSpace()
if response == None or not isinstance(response, int):
logger.error("Unable to get available disk space")
return
print(convertFilesize(response))
@app.command()
def version():
'''
Print package version
'''
print(__version__)
# Runs before any command
@app.callback()
def defaultOptions(debug: bool = typer.Option(False, '--debug', help='Set log level to debug'), info: bool = typer.Option(False, '--info', help='Set log level to info'), warning: bool = typer.Option(False, '--warning', help='Set log level to warning'), error: bool = typer.Option(False, '--error', help='Set log level to error')):
ch.setLevel(logging.INFO)
if '--json' in sys.argv:
ch.setLevel(logging.CRITICAL)
elif error == True:
ch.setLevel(logging.ERROR)
elif warning == True:
ch.setLevel(logging.WARNING)
elif info == True:
ch.setLevel(logging.INFO)
elif debug == True:
ch.setLevel(logging.DEBUG)
# Initiate deluge
global deluge
deluge = Deluge()
def main():
app()
del deluge
return response
if __name__ == '__main__':
handleKeyboardInterrupt()
main()
main()

View File

@@ -1,4 +0,0 @@
__version__ = '0.3.5'
if __name__ == '__main__':
print(__version__)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3.10
#!/usr/bin/env python3.6
import os
import re
@@ -7,11 +7,11 @@ import logging
import requests
import logging.config
from deluge_client import DelugeRPCClient, FailedToReconnectException
from sshtunnel import SSHTunnelForwarder, BaseSSHTunnelForwarderError
from deluge_client import DelugeRPCClient
from sshtunnel import SSHTunnelForwarder
from delugeUtils import getConfig, BASE_DIR
from delugeClient.utils import getConfig, BASE_DIR
from delugeClient.torrent import Torrent
from torrent import Torrent
logger = logging.getLogger('deluge_cli')
@@ -19,14 +19,6 @@ def split_words(string):
logger.debug('Splitting input: {} (type: {}) with split_words'.format(string, type(string)))
return re.findall(r"[\w\d']+", string.lower())
def responseToString(response=None):
try:
response = response.decode('utf-8')
except (UnicodeDecodeError, AttributeError):
pass
return response
class Deluge(object):
"""docstring for ClassName"""
def __init__(self):
@@ -41,19 +33,7 @@ class Deluge(object):
self.ssh_pkey = config['ssh']['pkey']
self.ssh_password = config['ssh']['password']
try:
self._connect()
except FailedToReconnectException:
logger.error("Unable to connect to deluge, make sure it's running")
sys.exit(1)
except ConnectionRefusedError:
logger.error("Unable to connect to deluge, make sure it's running")
sys.exit(1)
except BaseException as error:
logger.error("Unable to connect to deluge, make sure it's running")
if 'nodename nor servname provided' in str(error):
sys.exit(1)
raise error
self._connect()
def freeSpace(self):
return self.client.call('core.get_free_space')
@@ -65,74 +45,52 @@ class Deluge(object):
torrents.append(Torrent.fromDeluge(torrent))
return torrents
def establishSSHTunnel(self):
logger.debug('Checking if script on same server as deluge RPC')
if self.password is not None:
self.tunnel = SSHTunnelForwarder(self.ssh_host, ssh_username=self.ssh_user, ssh_password=self.ssh_password,
local_bind_address=('localhost', self.port), remote_bind_address=('localhost', self.port))
elif self.pkey is not None:
self.tunnel = SSHTunnelForwarder(self.ssh_host, ssh_username=self.ssh_user, ssh_pkey=self.ssh_pkey,
local_bind_address=('localhost', self.port), remote_bind_address=('localhost', self.port))
else:
logger.error("Either password or private key path must be set in config.")
return
try:
self.tunnel.start()
except BaseSSHTunnelForwarderError as sshError:
logger.warning("SSH host {} online, check your connection".format(self.ssh_host))
return
def _call(self, command, *args):
try:
return self.client.call(command, *args)
except ConnectionRefusedError as error:
logger.error("Unable to run command, connection to deluge seems to be offline")
except FailedToReconnectException as error:
logger.error("Unable to run command, reconnection to deluge failed")
def _connect(self):
logger.info('Checking if script on same server as deluge RPC')
if self.host != 'localhost' and self.host is not None:
self.establishSSHTunnel()
try:
if self.password:
self.tunnel = SSHTunnelForwarder(self.ssh_host, ssh_username=self.ssh_user, ssh_password=self.ssh_password,
local_bind_address=('localhost', self.port), remote_bind_address=('localhost', self.port))
elif self.pkey is not None:
self.tunnel = SSHTunnelForwarder(self.ssh_host, ssh_username=self.ssh_user, ssh_pkey=self.ssh_pkey,
local_bind_address=('localhost', self.port), remote_bind_address=('localhost', self.port))
except ValueError as error:
logger.error("Either password or private key path must be set in config.")
raise error
self.tunnel.start()
self.client = DelugeRPCClient(self.host, self.port, self.user, self.password)
self.client.connect()
def add(self, url):
response = None
logger.info('Adding magnet with url: {}.'.format(url))
if (url.startswith('magnet')):
response = self._call('core.add_torrent_magnet', url, {})
return self.client.call('core.add_torrent_magnet', url, {})
elif url.startswith('http'):
magnet = self.getMagnetFromFile(url)
response = self._call('core.add_torrent_magnet', magnet, {})
return responseToString(response)
return self.client.call('core.add_torrent_magnet', magnet, {})
def get_all(self, _filter=None):
response = None
if (type(_filter) is list and len(_filter)):
if ('seeding' in _filter):
response = self._call('core.get_torrents_status', {'state': 'Seeding'}, [])
response = self.client.call('core.get_torrents_status', {'state': 'Seeding'}, [])
elif ('downloading' in _filter):
response = self._call('core.get_torrents_status', {'state': 'Downloading'}, [])
response = self.client.call('core.get_torrents_status', {'state': 'Downloading'}, [])
elif ('paused' in _filter):
response = self._call('core.get_torrents_status', {'paused': 'true'}, [])
response = self.client.call('core.get_torrents_status', {'paused': 'true'}, [])
else:
response = self.client.call('core.get_torrents_status', {}, [])
if response == {}:
return None
return self.parseResponse(response)
def search(self, query):
allTorrents = self.get_all()
torrentNamesMatchingQuery = []
if len(allTorrents):
for torrent in allTorrents:
if query in torrent.name.lower():
if query in torrent.name:
torrentNamesMatchingQuery.append(torrent)
allTorrents = torrentNamesMatchingQuery
@@ -143,54 +101,34 @@ class Deluge(object):
return [ t for t in self.get_all() if (set(q_list) <= set(split_words(t.name))) ]
def get(self, id):
response = self._call('core.get_torrent_status', id, {})
if response == {}:
logger.warning('No torrent with id: {}'.format(id))
return None
response = self.client.call('core.get_torrent_status', id, {})
return Torrent.fromDeluge(response)
def toggle(self, id):
def togglePaused(self, id):
torrent = self.get(id)
if torrent is None:
return
if (torrent.paused):
response = self._call('core.resume_torrent', [id])
response = self.client.call('core.resume_torrent', [id])
else:
response = self._call('core.pause_torrent', [id])
response = self.client.call('core.pause_torrent', [id])
return response
return responseToString(response)
def removeByName(self, name, destroy=False):
def remove(self, name, destroy=False):
matches = list(filter(lambda t: t.name == name, self.get_all()))
logger.info('Matches for {}: {}'.format(name, matches))
if len(matches) > 1:
if (len(matches) > 1):
raise ValueError('Multiple files found matching key. Unable to remove.')
elif len(matches) == 1:
elif (len(matches) == 1):
torrent = matches[0]
response = self.remove(torrent.key, destroy)
logger.debug('Response rm: {}'.format(str(response)))
response = self.client.call('core.remove_torrent', torrent.key, destroy)
logger.info('Response: {}'.format(str(response)))
if response == False:
if (response == False):
raise AttributeError('Unable to remove torrent.')
return responseToString(response)
return response
else:
logger.error('ERROR. No torrent found with that name.')
def remove(self, id, destroy=False):
try:
response = self.client.call('core.remove_torrent', id, destroy)
logger.debug('Response from remove: {}'.format(str(response)))
return responseToString(response)
except BaseException as error:
if 'torrent_id not in session' in str(error):
logger.info('Unable to remove. No torrent with matching id')
return None
raise error
def filterOnValue(self, torrents, value):
filteredTorrents = []
for t in torrents:
@@ -202,14 +140,23 @@ class Deluge(object):
filteredTorrents.append(value_template)
return filteredTorrents
def __del__(self):
if hasattr(self, 'client') and self.client.connected:
logger.debug('Disconnected deluge rpc')
self.client.disconnect()
def progress(self):
attributes = ['progress', 'eta', 'state', 'finished']
all_torrents = self.get_all()
if hasattr(self, 'tunnel') and self.tunnel.is_active:
logger.debug('Closing ssh tunnel')
self.tunnel.stop(True)
torrents = []
for i, attribute in enumerate(attributes):
if i < 1:
torrents = self.filterOnValue(all_torrents, attribute)
continue
torrents = [dict(e, **v) for e,v in zip(torrents, self.filterOnValue(all_torrents, attribute))]
return torrents
def __del__(self):
if hasattr(self, 'tunnel'):
logger.info('Closing ssh tunnel')
self.tunnel.stop()
def getMagnetFromFile(self, url):
logger.info('File url found, fetching magnet.')

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3.10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: kevinmidboe
# @Date: 2018-04-17 19:55:38
@@ -50,7 +50,7 @@ def getConfig():
for key, value in requiredParameters:
if value == '':
logger.error('Missing value for variable: "{}" in config: \
"{}.'.format(key, user_config_dir))
"$HOME/.config/delugeClient/config.ini".'.format(key))
exit(1)
return config
@@ -60,7 +60,7 @@ class ColorizeFilter(logging.Filter):
Class for setting specific colors to levels of severity for log output
"""
color_by_level = {
10: 'cyan',
10: 'chartreuse_3b',
20: 'white',
30: 'orange_1',
40: 'red'
@@ -79,20 +79,3 @@ def convert(data):
if isinstance(data, tuple): return map(convert, data)
json_data = json.dumps(data)
return json_data
def validHash(hash: str):
try:
return hash and len(hash) == 40 and int(hash, 16)
except ValueError:
return False
import math
def convertFilesize(size_bytes):
if size_bytes == None or size_bytes == 0:
return "0B"
size_name = ("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB")
i = int(math.floor(math.log(size_bytes, 1024)))
p = math.pow(1024, i)
s = round(size_bytes / p, 2)
return "%s %s" % (s, size_name[i])

View File

@@ -2,7 +2,7 @@ import json
import logging
from distutils.util import strtobool
from delugeClient.utils import convert
from utils import convert
logger = logging.getLogger('deluge_cli')
@@ -44,5 +44,5 @@ class Torrent(object):
return json.dumps(torrentDict)
def __str__(self):
return "{} Progress: {}% ETA: {} State: {} Paused: {}".format(
self.name[:59].ljust(60), self.progress.rjust(5), self.eta.rjust(11), self.state.ljust(12), self.paused)
return "Name: {}, Progress: {}%, ETA: {}, State: {}, Paused: {}".format(
self.name, self.progress, self.eta, self.state, self.paused)

View File

@@ -1,19 +0,0 @@
#!/usr/bin/bash
PYPI_VERSION=$(pip3 show delugeClient-kevin | awk '$1 ~ /Version:/ { print $2 }')
SOURCE_VERSION=$(python3 delugeClient/__version__.py)
printf "Source version:\t\t %s\n" $SOURCE_VERSION
printf "Remote PyPi version:\t %s\n" $PYPI_VERSION
function version {
echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }';
}
if [ $(version $SOURCE_VERSION) -gt $(version $PYPI_VERSION) ]; then
echo "Soure is newer than remote, publishing!"
exit 0
else
echo "Source is same or oldre than remote, nothing to do."
exit 1
fi

View File

@@ -1,5 +1,6 @@
colored==1.4.4
colored==1.4.2
deluge-client==1.9.0
requests==2.28.1
docopt==0.6.2
requests==2.25.1
sshtunnel==0.4.0
typer==0.7.0
websockets==10.0

View File

@@ -1,43 +1,39 @@
#!/usr/bin/env python3.10
# -*- encoding: utf-8 -*-
from setuptools import setup, find_packages
from sys import path
from os.path import dirname
import delugeClient
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
exec(open('delugeClient/__version__.py').read())
setup(
name="delugeClient-kevin",
version=__version__,
packages=find_packages(),
package_data={
'delugeClient': ['default_config.ini'],
},
python_requires=">=3.10",
version=delugeClient.__version__,
author="KevinMidboe",
description="Deluge client with custom functions written in python",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/kevinmidboe/delugeClient",
install_requires=[
'colored>=1.4.4',
'deluge-client>=1.9.0',
'requests>=2.28.1',
'sshtunnel>=0.4.0',
'typer[all]>=0.7.0'
'colored==1.4.2',
'deluge-client==1.9.0',
'docopt==0.6.2',
'requests==2.25.1',
'sshtunnel==0.4.0',
'websockets==9.1'
],
classifiers=[
'Programming Language :: Python',
'Operating System :: OS Independent',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.6',
],
entry_points={
'console_scripts': [
'delugeclient = delugeClient.__main__:main',
],
}
},
packages=find_packages(),
package_data={
'delugeClient': ['default_config.ini'],
},
python_requires=">=3.6",
)