Skip to content

Commit

Permalink
Feature/fix download hander failed (#9476)
Browse files Browse the repository at this point in the history
* Check for path, before trying to postprocess
* Added logging

* Do not even attempt postprocess when no destination path available.

* Fix manual-post-process.vue:
* processMethod emtpy.
* processMethod and Path are shown, but not send through api.

* Also PP resource when there is no path.

* add logging

* proc_type shouldn't be cast to bool

* Handle getting no response from client

* Clean up comment

* Update all history records by info_hash.

* Fix bug in walk_path.

* Remove log
  • Loading branch information
p0psicles authored Apr 27, 2021
1 parent db8c24d commit 8dfa74c
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 39 deletions.
3 changes: 3 additions & 0 deletions medusa/clients/torrent/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,9 @@ def test_authentication(self):
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL):
return False, 'Error: Invalid {name} host'.format(name=self.name)

if not self.response:
return False, 'Unable to connect to {name}'.format(name=self.name)

if self.response.status_code == 401:
return False, 'Error: Invalid {name} Username or Password, check your config!'.format(name=self.name)

Expand Down
70 changes: 40 additions & 30 deletions medusa/process_tv.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ def update_resource(self, status):
"""
main_db_con = db.DBConnection()
main_db_con.action(
'UPDATE history set client_status = ? '
'WHERE date = (select max(date) from history where info_hash = ?)',
'UPDATE history set client_status = ? WHERE info_hash = ?',
[status.status, self.info_hash]
)
log.info('Updated history with resource path: {path} and resource: {resource} with new status {status}', {
Expand All @@ -87,8 +86,8 @@ def update_resource(self, status):
'status': status
})

def update_history(self, process_results):
"""Update main.history table with process results."""
def update_history_processed(self, process_results):
"""Update the history table when we have a processed path + resource."""
from medusa.schedulers.download_handler import ClientStatus
status = ClientStatus()

Expand All @@ -99,7 +98,7 @@ def update_history(self, process_results):

# If succeeded store Postprocessed + Completed. (384)
# If failed store Postprocessed + Failed. (272)
if process_results.result:
if process_results.result and not process_results.failed:
status.add_status_string('Completed')
self.success = True
else:
Expand All @@ -112,44 +111,55 @@ def update_history(self, process_results):
'resource': self.resource_name
})

def process_path(self):
"""Process for when we have a valid path."""
process_method = self.process_method or app.PROCESS_METHOD

process_results = ProcessResult(self.path, process_method, failed=self.failed)
process_results.process(
resource_name=self.resource_name,
force=self.force,
is_priority=self.is_priority,
delete_on=self.delete_on,
proc_type=self.proc_type,
ignore_subs=self.ignore_subs
)

# A user might want to use advanced post-processing, but opt-out of failed download handling.
if (app.USE_FAILED_DOWNLOADS and (process_results.failed or (not process_results.succeeded and self.resource_name))):
process_results.process_failed(self.path)

# In case we have an info_hash or (nzbid), update the history table with the pp results.
if self.info_hash:
self.update_history_processed(process_results)

return process_results

def run(self):
"""Run postprocess queueitem thread."""
generic_queue.QueueItem.run(self)
self.started = True

try:
log.info('Beginning postprocessing for path {path}', {'path': self.path})
log.info('Beginning postprocessing for path {path} and resource {resource}', {
'path': self.path, 'resource': self.resource_name
})

# Push an update to any open Web UIs through the WebSocket
ws.Message('QueueItemUpdate', self.to_json).push()

path = self.path or app.TV_DOWNLOAD_DIR
process_method = self.process_method or app.PROCESS_METHOD

process_results = ProcessResult(path, process_method, failed=self.failed)
process_results.process(
resource_name=self.resource_name,
force=self.force,
is_priority=self.is_priority,
delete_on=self.delete_on,
proc_type=self.proc_type,
ignore_subs=self.ignore_subs
)
if not self.path and self.resource_name:
# We don't have a path, but do have a resource name. If this is a failed download.
# Let's use the TV_DOWNLOAD_DIR as path combined with the resource_name.
self.path = app.TV_DOWNLOAD_DIR

# A user might want to use advanced post-processing, but opt-out of failed download handling.
if app.USE_FAILED_DOWNLOADS \
and (process_results.failed or (not process_results.succeeded and self.resource_name)):
process_results.process_failed(path)

# In case we have an info_hash or (nzbid), update the history table with the pp results.
if self.info_hash:
self.update_history(process_results)
if self.path:
process_results = self.process_path()
if process_results._output:
self.to_json.update({'output': process_results._output})

log.info('Completed Postproccessing')

if process_results._output:
self.to_json.update({'output': process_results._output})

# Use success as a flag for a finished PP. PP it self can be succeeded or failed.
self.success = True

Expand Down Expand Up @@ -460,7 +470,7 @@ def _get_files(self, path):
# If resource_name is a file and not an NZB, process it directly
def walk_path(path_name):
topdown = True if self.directory == path_name else False
for root, dirs, files in os.walk(path, topdown=topdown):
for root, dirs, files in os.walk(path_name, topdown=topdown):
if files:
yield root, sorted(files)
if topdown:
Expand Down
22 changes: 19 additions & 3 deletions medusa/schedulers/download_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,30 @@ def _check_postprocess(self, client):
continue

log.debug(
'Found {client_type} (status {status}) on {client} with info_hash {info_hash}',
'Sending postprocess job for {client_type} with info_hash: {info_hash}'
'\nstatus: {status}\nclient: {client}'
'\ndestination: {destination}\nresource: {resource}',
{
'client_type': client_type,
'info_hash': history_result['info_hash'],
'status': status,
'client': app.TORRENT_METHOD if client_type == 'torrent' else app.NZB_METHOD,
'info_hash': history_result['info_hash']
'destination': status.destination,
'resource': status.resource or history_result['resource']
}
)

if not status.destination and not status.resource and history_result['resource']:
# We didn't get a destination, because probably it failed to start a download.
# For example when it already failed to get the nzb. But we have a resource name from the snatch.
# We'll use this, so that we can finish the postprocessing and possible failed download handling.
status.resource = history_result['resource']

if not status.destination and not status.resource:
log.warning('Not starting postprocessing for info_hash {info_hash}, need a destination path.',
{'info_hash': history_result['info_hash']})
continue

self._postprocess(
status.destination, history_result['info_hash'], status.resource,
failed=str(status) == 'Failed'
Expand Down Expand Up @@ -311,7 +327,7 @@ def _clean(self, client):
"""Update status in the history table for torrents/nzb's that can't be located anymore."""
client_type = 'torrent' if isinstance(client, GenericClient) else 'nzb'

# Make sure the client can be reached. As we don't want to change the state for downlaods
# Make sure the client can be reached. As we don't want to change the state for downloads
# because the client is temporary unavailable.
if not self._test_connection(client, client_type):
log.warning('The client cannot be reached or authentication is failing. Abandon cleanup.')
Expand Down
2 changes: 1 addition & 1 deletion medusa/server/api/v2/postprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def post(self, identifier=None):
is_priority = bool(data.get('is_priority', False))
delete_on = bool(data.get('delete_on', False))
failed = bool(data.get('failed', False))
proc_type = bool(data.get('proc_type', False))
proc_type = data.get('proc_type', '')
ignore_subs = bool(data.get('is_priority', False))

if not proc_dir:
Expand Down
6 changes: 5 additions & 1 deletion themes-default/slim/src/components/manual-post-process.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<div class="col-xs-12 col-lg-9">
<config-template label="Process Method to be used" label-for="process_method">
<select id="process_method" name="process_method" v-model="processMethod" class="form-control input-sm">
<select id="process_method" name="process_method" :value="postprocessing.processMethod" @update="processMethod = $event" class="form-control input-sm">
<option v-for="option in availableMethods" :value="option.value" :key="option.value">
{{option.text}}
</option>
Expand Down Expand Up @@ -69,6 +69,10 @@ export default {
ConfigTemplate,
ConfigToggleSlider
},
mounted() {
this.processMethod = this.postprocessing.processMethod;
this.path = this.postprocessing.showDownloadDir;
},
data() {
return {
processMethod: null,
Expand Down
Loading

0 comments on commit 8dfa74c

Please sign in to comment.