Qbittorrent

- Postprocessing get folder from hash
- Postprocessing allow for single file
- Rutracker fix up
This commit is contained in:
Ade
2017-04-04 20:24:26 +12:00
parent 5bb6ec04a9
commit de15f6b632
7 changed files with 145 additions and 63 deletions

View File

@@ -306,9 +306,10 @@ def initialize_scheduler():
minutes=minutes)
# Remove Torrent + data if Post Processed and finished Seeding
minutes = CONFIG.TORRENT_REMOVAL_INTERVAL
schedule_job(torrentfinished.checkTorrentFinished, 'Torrent removal check', hours=0,
minutes=minutes)
if headphones.CONFIG.TORRENT_DOWNLOADER != 0:
minutes = CONFIG.TORRENT_REMOVAL_INTERVAL
schedule_job(torrentfinished.checkTorrentFinished, 'Torrent removal check', hours=0,
minutes=minutes)
# Start scheduler
if start_jobs and len(SCHED.get_jobs()):
@@ -376,7 +377,7 @@ def dbcheck():
c.execute(
'CREATE TABLE IF NOT EXISTS alltracks (ArtistID TEXT, ArtistName TEXT, AlbumTitle TEXT, AlbumASIN TEXT, AlbumID TEXT, TrackTitle TEXT, TrackDuration, TrackID TEXT, TrackNumber INTEGER, Location TEXT, BitRate INTEGER, CleanName TEXT, Format TEXT, ReleaseID TEXT)')
c.execute(
'CREATE TABLE IF NOT EXISTS snatched (AlbumID TEXT, Title TEXT, Size INTEGER, URL TEXT, DateAdded TEXT, Status TEXT, FolderName TEXT, Kind TEXT)')
'CREATE TABLE IF NOT EXISTS snatched (AlbumID TEXT, Title TEXT, Size INTEGER, URL TEXT, DateAdded TEXT, Status TEXT, FolderName TEXT, Kind TEXT, TorrentHash TEXT)')
# Matched is a temporary value used to see if there was a match found in
# alltracks
c.execute(
@@ -613,6 +614,12 @@ def dbcheck():
except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN MetaCritic TEXT DEFAULT NULL')
try:
c.execute('SELECT TorrentHash from snatched')
except sqlite3.OperationalError:
c.execute('ALTER TABLE snatched ADD COLUMN TorrentHash TEXT')
c.execute('UPDATE snatched SET TorrentHash = FolderName WHERE Status LIKE "Seed_%"')
conn.commit()
c.close()

View File

@@ -623,7 +623,7 @@ def get_downloaded_track_list(albumpath):
return downloaded_track_list
def preserve_torrent_directory(albumpath, forced=False):
def preserve_torrent_directory(albumpath, forced=False, single=False):
"""
Copy torrent directory to temp headphones_ directory to keep files for seeding.
"""
@@ -639,7 +639,11 @@ def preserve_torrent_directory(albumpath, forced=False):
headphones.SYS_ENCODING, 'replace'))
try:
prefix = "headphones_" + os.path.basename(os.path.normpath(albumpath)) + "_"
file_name = os.path.basename(os.path.normpath(albumpath))
if not single:
prefix = "headphones_" + file_name + "_"
else:
prefix = "headphones_" + os.path.splitext(file_name)[0] + "_"
new_folder = tempfile.mkdtemp(prefix=prefix, dir=tempdir)
except Exception as e:
logger.error("Cannot create temp directory: " + tempdir.decode(
@@ -665,7 +669,11 @@ def preserve_torrent_directory(albumpath, forced=False):
try:
subdir = os.path.join(new_folder, "headphones")
logger.info("Copying files to " + subdir.decode(headphones.SYS_ENCODING, 'replace'))
shutil.copytree(albumpath, subdir)
if not single:
shutil.copytree(albumpath, subdir)
else:
os.makedirs(subdir)
shutil.copy(albumpath, subdir)
# Update the album path with the new location
return subdir
except Exception as e:

View File

@@ -43,6 +43,8 @@ def checkFolder():
for album in snatched:
if album['FolderName']:
folder_name = album['FolderName']
single = False
if album['Kind'] == 'nzb':
download_dir = headphones.CONFIG.DOWNLOAD_DIR
else:
@@ -51,21 +53,29 @@ def checkFolder():
else:
download_dir = headphones.CONFIG.DOWNLOAD_TORRENT_DIR
album_path = os.path.join(download_dir, album['FolderName']).encode(
headphones.SYS_ENCODING, 'replace')
logger.debug("Checking if %s exists" % album_path)
# Qbittorrent - get folder from torrent hash
if album['TorrentHash']:
if headphones.CONFIG.TORRENT_DOWNLOADER == 4:
folder_name, single = qbittorrent.getFolder(album['TorrentHash'])
if not folder_name:
logger.debug("Could not get folder name from torrent hash for " + album['Title'])
if os.path.exists(album_path):
logger.info('Found "' + album['FolderName'] + '" in ' + album[
'Kind'] + ' download folder. Verifying....')
verify(album['AlbumID'], album_path, album['Kind'])
if folder_name:
album_path = os.path.join(download_dir, folder_name).encode(
headphones.SYS_ENCODING, 'replace')
logger.debug("Checking if %s exists" % album_path)
if os.path.exists(album_path):
logger.info('Found "' + folder_name + '" in ' + album[
'Kind'] + ' download folder. Verifying....')
verify(album['AlbumID'], album_path, album['Kind'],single=single)
else:
logger.info("No folder name found for " + album['Title'])
logger.debug("Checking download folder finished.")
def verify(albumid, albumpath, Kind=None, forced=False, keep_original_folder=False):
def verify(albumid, albumpath, Kind=None, forced=False, keep_original_folder=False, single=False):
myDB = db.DBConnection()
release = myDB.action('SELECT * from albums WHERE AlbumID=?', [albumid]).fetchone()
tracks = myDB.select('SELECT * from tracks WHERE AlbumID=?', [albumid])
@@ -206,6 +216,10 @@ def verify(albumid, albumpath, Kind=None, forced=False, keep_original_folder=Fal
'replace') + " isn't complete yet. Will try again on the next run")
return
# Force single file through
if single and not downloaded_track_list:
downloaded_track_list.append(albumpath)
# Check to see if we're preserving the torrent dir
if (headphones.CONFIG.KEEP_TORRENT_FILES and Kind == "torrent") or headphones.CONFIG.KEEP_ORIGINAL_FOLDER:
keep_original_folder = True
@@ -263,7 +277,7 @@ def verify(albumid, albumpath, Kind=None, forced=False, keep_original_folder=Fal
if metaartist == dbartist and metaalbum == dbalbum:
doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, Kind,
keep_original_folder, forced)
keep_original_folder, forced, single)
return
# test #2: filenames
@@ -282,7 +296,7 @@ def verify(albumid, albumpath, Kind=None, forced=False, keep_original_folder=Fal
if dbtrack in filetrack:
doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, Kind,
keep_original_folder, forced)
keep_original_folder, forced, single)
return
# test #3: number of songs and duration
@@ -315,7 +329,7 @@ def verify(albumid, albumpath, Kind=None, forced=False, keep_original_folder=Fal
delta = abs(downloaded_track_duration - db_track_duration)
if delta < 240:
doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, Kind,
keep_original_folder, forced)
keep_original_folder, forced, single)
return
logger.warn(u'Could not identify album: %s. It may not be the intended album.',
@@ -337,13 +351,13 @@ def markAsUnprocessed(albumid, albumpath, keep_original_folder=False):
def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, Kind=None,
keep_original_folder=False, forced=False):
keep_original_folder=False, forced=False, single=False):
logger.info('Starting post-processing for: %s - %s' % (release['ArtistName'], release['AlbumTitle']))
new_folder = None
# Preserve the torrent dir
if keep_original_folder:
temp_path = helpers.preserve_torrent_directory(albumpath, forced)
if keep_original_folder or single:
temp_path = helpers.preserve_torrent_directory(albumpath, forced, single)
if not temp_path:
markAsUnprocessed(albumid, albumpath, keep_original_folder)
return
@@ -467,7 +481,7 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
'SELECT * from snatched WHERE Status="Seed_Snatched" and AlbumID=?',
[albumid]).fetchone()
if seed_snatched:
hash = seed_snatched['FolderName']
hash = seed_snatched['TorrentHash']
torrent_removed = False
logger.info(u'%s - %s. Checking if torrent has finished seeding and can be removed' % (
release['ArtistName'], release['AlbumTitle']))

View File

@@ -21,6 +21,7 @@ import time
import mimetypes
import random
import string
import os
import headphones
@@ -197,25 +198,47 @@ def addFile(data):
return qbclient._command('command/upload', filelist=files)
def getFolder(hash):
logger.debug('getFolder(%s)' % hash)
def getName(hash):
logger.debug('getName(%s)' % hash)
qbclient = qbittorrentclient()
tries = 1
while tries <= 10:
status, torrentList = qbclient._get_list()
for torrent in torrentList:
if torrent['hash'].upper() == hash.upper():
if torrent['state'] == 'metaDL':
tries += 1
time.sleep(6)
else:
return torrent['name']
while tries <= 5:
status, torrentlist = qbclient._get_list()
for torrent in torrentlist:
if torrent['hash'].lower() == hash.lower():
return torrent['name']
tries += 1
time.sleep(1)
return None
def getFolder(hash):
logger.debug('getFolder(%s)' % hash)
torrent_folder = None
single_file = False
qbclient = qbittorrentclient()
try:
status, torrent_files = qbclient.getfiles(hash.lower())
if torrent_files:
if len(torrent_files) == 1:
torrent_folder = torrent_files[0]['name']
single_file = True
else:
torrent_folder = os.path.split(torrent_files[0]['name'])[0]
single_file = False
except:
torrent_folder = None
single_file = False
return torrent_folder, single_file
_BOUNDARY_CHARS = string.digits + string.ascii_letters

View File

@@ -6,6 +6,7 @@ from urlparse import urlparse
import re
import requests as requests
#from requests.auth import HTTPDigestAuth
from bs4 import BeautifulSoup
import headphones
@@ -216,3 +217,34 @@ class Rutracker(object):
self.session.post(url, params={'action': 'add-file'}, files=files)
except Exception as e:
logger.exception('Error adding file to utorrent %s', e)
# TODO get this working in qbittorrent.py
def qbittorrent_add_file(self, data):
host = headphones.CONFIG.QBITTORRENT_HOST
if not host.startswith('http'):
host = 'http://' + host
if host.endswith('/'):
host = host[:-1]
if host.endswith('/gui'):
host = host[:-4]
base_url = host
#self.session.auth = HTTPDigestAuth(headphones.CONFIG.QBITTORRENT_USERNAME, headphones.CONFIG.QBITTORRENT_PASSWORD)
url = base_url + '/login'
r = self.session.post(url, data={'username': headphones.CONFIG.QBITTORRENT_USERNAME,
'password': headphones.CONFIG.QBITTORRENT_PASSWORD})
url = base_url + '/command/upload'
args = {'savepath': headphones.CONFIG.DOWNLOAD_TORRENT_DIR}
if headphones.CONFIG.QBITTORRENT_LABEL:
args['category'] = headphones.CONFIG.QBITTORRENT_LABEL
torrent_files = {'torrents': data}
try:
self.session.post(url, data=args, files=torrent_files)
except Exception as e:
logger.exception('Error adding file to qbittorrent %s', e)

View File

@@ -1018,36 +1018,37 @@ def send_to_downloader(data, bestqual, album):
# Add torrent
if bestqual[3] == 'rutracker.org':
qbittorrent.addFile(data)
ruobj.qbittorrent_add_file(data)
else:
qbittorrent.addTorrent(bestqual[2])
# Get hash
torrentid = calculate_torrent_hash(bestqual[2], data)
torrentid = torrentid.lower()
if not torrentid:
logger.error('Torrent id could not be determined')
return
# Get folder
folder_name = qbittorrent.getFolder(torrentid)
# Get name
folder_name = qbittorrent.getName(torrentid)
if folder_name:
logger.info('Torrent folder name: %s' % folder_name)
logger.info('Torrent name: %s' % folder_name)
else:
logger.error('Torrent folder name could not be determined')
logger.error('Torrent name could not be determined')
return
myDB = db.DBConnection()
myDB.action('UPDATE albums SET status = "Snatched" WHERE AlbumID=?', [album['AlbumID']])
myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)',
myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?, ?)',
[album['AlbumID'], bestqual[0], bestqual[1], bestqual[2], "Snatched", folder_name,
kind])
kind, torrentid])
# Store the torrent id so we can check later if it's finished seeding and can be removed
if seed_ratio is not None and seed_ratio != 0 and torrentid:
myDB.action(
'INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)',
[album['AlbumID'], bestqual[0], bestqual[1], bestqual[2], "Seed_Snatched", torrentid,
kind])
'INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?, ?)',
[album['AlbumID'], bestqual[0], bestqual[1], bestqual[2], "Seed_Snatched", folder_name,
kind, torrentid])
# notify
artist = album[1]

View File

@@ -18,8 +18,6 @@ import threading
from headphones import db, utorrent, transmission, deluge, qbittorrent, logger
import headphones
postprocessor_lock = threading.Lock()
def checkTorrentFinished():
"""
@@ -28,26 +26,25 @@ def checkTorrentFinished():
logger.info("Checking if any torrents have finished seeding and can be removed")
with postprocessor_lock:
myDB = db.DBConnection()
results = myDB.select('SELECT * from snatched WHERE Status="Seed_Processed"')
myDB = db.DBConnection()
results = myDB.select('SELECT * from snatched WHERE Status="Seed_Processed"')
for album in results:
hash = album['FolderName']
albumid = album['AlbumID']
torrent_removed = False
for album in results:
hash = album['TorrentHash']
albumid = album['AlbumID']
torrent_removed = False
if headphones.CONFIG.TORRENT_DOWNLOADER == 1:
torrent_removed = transmission.removeTorrent(hash, True)
elif headphones.CONFIG.TORRENT_DOWNLOADER == 2:
torrent_removed = utorrent.removeTorrent(hash, True)
elif headphones.CONFIG.TORRENT_DOWNLOADER == 3:
torrent_removed = deluge.removeTorrent(hash, True)
else:
torrent_removed = qbittorrent.removeTorrent(hash, True)
if headphones.CONFIG.TORRENT_DOWNLOADER == 1:
torrent_removed = transmission.removeTorrent(hash, True)
elif headphones.CONFIG.TORRENT_DOWNLOADER == 2:
torrent_removed = utorrent.removeTorrent(hash, True)
elif headphones.CONFIG.TORRENT_DOWNLOADER == 3:
torrent_removed = deluge.removeTorrent(hash, True)
else:
torrent_removed = qbittorrent.removeTorrent(hash, True)
if torrent_removed:
myDB.action('DELETE from snatched WHERE status = "Seed_Processed" and AlbumID=?',
[albumid])
if torrent_removed:
myDB.action('DELETE from snatched WHERE status = "Seed_Processed" and AlbumID=?',
[albumid])
logger.info("Checking finished torrents completed")