Skip to content

Commit

Permalink
Merge pull request #10016 from pymedusa/release/release-0.5.19
Browse files Browse the repository at this point in the history
Release/release 0.5.19
  • Loading branch information
medariox authored Oct 31, 2021
2 parents 21e350c + 8ad3012 commit 6f25e86
Show file tree
Hide file tree
Showing 227 changed files with 7,905 additions and 10,508 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/docker-image-master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ jobs:
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
- name: Build the Docker image
run: docker build . --file Dockerfile --tag pymedusa/medusa:master
run: docker build . --file Dockerfile --tag pymedusa/medusa:master --tag pymedusa/medusa:latest
- name: Docker push
run: docker push pymedusa/medusa:master
run: docker push pymedusa/medusa --all-tags
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## 0.5.19 (31-10-2021)

#### New Features
- Added separate configs for the process methods (copy, move, etc) for torrent and nzb. (only usuable with the download handler) ([9932](https://github.com/pymedusa/Medusa/pull/9932))
- Added setting for the default client path that will be protected (can't be deleted) during post-processing ([9954](https://github.com/pymedusa/Medusa/pull/9954))

#### Fixes
- Correctly delete folders with files for move method or if explicitly wanted ([9950](https://github.com/pymedusa/Medusa/pull/9950))
- Fixed link to the overview of snatched episodes at the bottom of the pages ([9954](https://github.com/pymedusa/Medusa/pull/9954))
- Prevent duplicate searches for Torznab
- Catch exceptions during shutdown and always delete PID file
- Fix scene season searches

-----

## 0.5.18 (14-09-2021)

#### Improvements
Expand All @@ -6,7 +21,7 @@

#### Fixes
- Fix prowlarr provider id's being obfuscated in logs because of a bad log level. ([9857](https://github.com/pymedusa/Medusa/pull/9857))
- Fix postprocessing specials. ([9812](https://github.com/pymedusa/Medusa/pull/9812))
- Fix postprocessing specials. ([9812](https://github.com/pymedusa/Medusa/pull/9812))
- Fix storing a negative value in the UI as a search delay value ([9822](https://github.com/pymedusa/Medusa/pull/9822))

-----
Expand Down
25 changes: 20 additions & 5 deletions medusa/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ def initialize(self, console_logging=True):
app.TORRENT_DIR = check_setting_str(app.CFG, 'Blackhole', 'torrent_dir', '')

app.TV_DOWNLOAD_DIR = check_setting_str(app.CFG, 'General', 'tv_download_dir', '')
app.DEFAULT_CLIENT_PATH = check_setting_str(app.CFG, 'General', 'default_client_path', '')
app.PROCESS_AUTOMATICALLY = bool(check_setting_int(app.CFG, 'General', 'process_automatically', 0))
app.NO_DELETE = bool(check_setting_int(app.CFG, 'General', 'no_delete', 0))
app.UNPACK = bool(check_setting_int(app.CFG, 'General', 'unpack', 0))
Expand All @@ -679,6 +680,11 @@ def initialize(self, console_logging=True):
app.FILE_TIMESTAMP_TIMEZONE = check_setting_str(app.CFG, 'General', 'file_timestamp_timezone', 'network')
app.KEEP_PROCESSED_DIR = bool(check_setting_int(app.CFG, 'General', 'keep_processed_dir', 1))
app.PROCESS_METHOD = check_setting_str(app.CFG, 'General', 'process_method', 'copy' if app.KEEP_PROCESSED_DIR else 'move')

app.USE_SPECIFIC_PROCESS_METHOD = bool(check_setting_int(app.CFG, 'General', 'use_specific_process_method', 0))
app.PROCESS_METHOD_TORRENT = check_setting_str(app.CFG, 'General', 'process_method', 'copy' if app.KEEP_PROCESSED_DIR else 'move')
app.PROCESS_METHOD_NZB = check_setting_str(app.CFG, 'General', 'process_method', 'copy' if app.KEEP_PROCESSED_DIR else 'move')

app.DELRARCONTENTS = bool(check_setting_int(app.CFG, 'General', 'del_rar_contents', 0))
app.MOVE_ASSOCIATED_FILES = bool(check_setting_int(app.CFG, 'General', 'move_associated_files', 0))
app.POSTPONE_IF_SYNC_FILES = bool(check_setting_int(app.CFG, 'General', 'postpone_if_sync_files', 1))
Expand Down Expand Up @@ -1108,7 +1114,7 @@ def initialize(self, console_logging=True):
load_provider_setting(app.CFG, provider, 'bool', 'enable_backlog', provider.supports_backlog)
load_provider_setting(app.CFG, provider, 'bool', 'enable_manualsearch', 1)
load_provider_setting(app.CFG, provider, 'bool', 'enable_search_delay', 0)
load_provider_setting(app.CFG, provider, 'int', 'search_delay', 480)
load_provider_setting(app.CFG, provider, 'float', 'search_delay', 480)

if provider.provider_type == GenericProvider.TORRENT:
load_provider_setting(app.CFG, provider, 'string', 'custom_url', '', censor_log='low')
Expand All @@ -1117,6 +1123,7 @@ def initialize(self, console_logging=True):
load_provider_setting(app.CFG, provider, 'string', 'password', '', censor_log='low')
load_provider_setting(app.CFG, provider, 'string', 'passkey', '', censor_log='low')
load_provider_setting(app.CFG, provider, 'string', 'pin', '', censor_log='low')
load_provider_setting(app.CFG, provider, 'string', 'pid', '', censor_log='low')
load_provider_setting(app.CFG, provider, 'string', 'sorting', 'seeders')
load_provider_setting(app.CFG, provider, 'string', 'options', '')
load_provider_setting(app.CFG, provider, 'float', 'ratio', -1)
Expand Down Expand Up @@ -1508,7 +1515,6 @@ def halt():
app.show_update_scheduler,
app.episode_update_scheduler,
app.version_check_scheduler,
app.generic_update_scheduler,
app.show_queue_scheduler,
app.search_queue_scheduler,
app.forced_search_queue_scheduler,
Expand Down Expand Up @@ -1685,8 +1691,12 @@ def save_config():
new_config['General']['cache_dir'] = app.ACTUAL_CACHE_DIR if app.ACTUAL_CACHE_DIR else 'cache'
new_config['General']['root_dirs'] = app.ROOT_DIRS if app.ROOT_DIRS else []
new_config['General']['tv_download_dir'] = app.TV_DOWNLOAD_DIR
new_config['General']['default_client_path'] = app.DEFAULT_CLIENT_PATH
new_config['General']['keep_processed_dir'] = int(app.KEEP_PROCESSED_DIR)
new_config['General']['process_method'] = app.PROCESS_METHOD
new_config['General']['use_specific_process_method'] = int(app.USE_SPECIFIC_PROCESS_METHOD)
new_config['General']['process_method_torrent'] = app.PROCESS_METHOD_TORRENT
new_config['General']['process_method_nzb'] = app.PROCESS_METHOD_NZB
new_config['General']['del_rar_contents'] = int(app.DELRARCONTENTS)
new_config['General']['move_associated_files'] = int(app.MOVE_ASSOCIATED_FILES)
new_config['General']['sync_files'] = app.SYNC_FILES
Expand Down Expand Up @@ -1759,7 +1769,7 @@ def save_config():
'password',
],
GenericProvider.TORRENT: [
'custom_url', 'digest', 'hash', 'passkey', 'pin', 'confirmed', 'ranked', 'engrelease',
'custom_url', 'digest', 'hash', 'passkey', 'pin', 'pid', 'confirmed', 'ranked', 'engrelease',
'onlyspasearch', 'sorting', 'ratio', 'minseed', 'minleech', 'options', 'freeleech',
'cat', 'subtitle', 'cookies', 'title_tag', 'cap_tv_search',
],
Expand Down Expand Up @@ -2267,7 +2277,8 @@ def remove_pid_file(pid_file):
try:
if os.path.exists(pid_file):
os.remove(pid_file)
except EnvironmentError:
except EnvironmentError as error:
exception_handler.handle(error)
return False

return True
Expand Down Expand Up @@ -2333,10 +2344,14 @@ def shutdown(self, event):

self.clear_cache() # Clean cache

except Exception as error:
exception_handler.handle(error, 'Something went wrong during shutdown')

finally:
# if run as daemon delete the pid file
if self.run_as_daemon and self.create_pid:
self.remove_pid_file(self.pid_file)
finally:

if event == Events.SystemEvent.RESTART:
self.restart()

Expand Down
22 changes: 22 additions & 0 deletions medusa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,17 @@ def __init__(self):
self.NO_DELETE = False
self.KEEP_PROCESSED_DIR = False
self.PROCESS_METHOD = None
# The process methods for torrent and nzb are used by the download handler.
self.USE_SPECIFIC_PROCESS_METHOD = False
self.PROCESS_METHOD_TORRENT = None
self.PROCESS_METHOD_NZB = None
self.DELRARCONTENTS = False
self.MOVE_ASSOCIATED_FILES = False
self.POSTPONE_IF_SYNC_FILES = True
self.POSTPONE_IF_NO_SUBS = False
self.NFO_RENAME = True
self._TV_DOWNLOAD_DIR = None
self.DEFAULT_CLIENT_PATH = None
self.UNPACK = False
self.SKIP_REMOVED_FILES = False
self.ALLOWED_EXTENSIONS = ['srt', 'nfo', 'sub', 'idx']
Expand Down Expand Up @@ -1022,6 +1027,23 @@ def SUBTITLES_FINDER_FREQUENCY(self, value):
"""Change SUBTITLES_FINDER_FREQUENCY."""
self.handle_prop('SUBTITLES_FINDER_FREQUENCY', value)

@property
def SUBTITLE_SERVICES(self):
"""Return a list of subtitle services."""
from medusa.subtitles import sorted_service_list
return sorted_service_list()

@SUBTITLE_SERVICES.setter
def SUBTITLE_SERVICES(self, value):
"""
Save subtitle services.
The order of available subtitle services and the enabled/disabled providers
are fleshed out when saving this app property.
"""
self.SUBTITLES_SERVICES_LIST = [prov['name'] for prov in value]
self.SUBTITLES_SERVICES_ENABLED = [int(prov['enabled']) for prov in value]


app = MedusaApp()
for app_key, app_value in app.__dict__.items():
Expand Down
3 changes: 2 additions & 1 deletion medusa/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
log.logger.addHandler(logging.NullHandler())

INSTANCE_ID = text_type(uuid.uuid1())
VERSION = '0.5.18'
VERSION = '0.5.19'

USER_AGENT = 'Medusa/{version} ({system}; {release}; {instance})'.format(
version=VERSION, system=platform.system(), release=platform.release(),
instance=INSTANCE_ID)
Expand Down
5 changes: 4 additions & 1 deletion medusa/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,10 @@ def real_path(path):
The resulting path will have no symbolic link, '/./' or '/../' components.
"""
return os.path.normpath(os.path.normpath(os.path.realpath(path)))
if path is None:
return ''

return os.path.normpath(os.path.normcase(os.path.realpath(path)))


def validate_show(show, season=None, episode=None):
Expand Down
39 changes: 8 additions & 31 deletions medusa/name_parser/rules/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
from rebulk.rebulk import Rebulk
from rebulk.rules import AppendMatch, RemoveMatch, RenameMatch, Rule

import six
from six.moves import range

log = logging.getLogger(__name__)
Expand All @@ -53,10 +52,7 @@ class BlacklistedReleaseGroup(Rule):

priority = POST_PROCESS
consequence = RemoveMatch
if six.PY3:
blacklist = ('private', 'req', 'no.rar', 'season')
else:
blacklist = (b'private', b'req', b'no.rar', b'season')
blacklist = ('private', 'req', 'no.rar', 'season')

def when(self, matches, context):
"""Evaluate the rule.
Expand Down Expand Up @@ -332,12 +328,8 @@ def when(self, matches, context):
for alternative_title in alternative_titles:
holes = matches.holes(start=previous.end, end=alternative_title.start)
# if the separator is a dash, add an extra space before and after
if six.PY3:
separators = [' ' + h.value + ' ' if h.value == '-' else h.value for h in holes]
separator = ' '.join(separators) if separators else ' '
else:
separators = [b' ' + h.value + b' ' if h.value == b'-' else h.value for h in holes]
separator = b' '.join(separators) if separators else b' '
separators = [' ' + h.value + ' ' if h.value == '-' else h.value for h in holes]
separator = ' '.join(separators) if separators else ' '
alias.value += separator + alternative_title.value

previous = alternative_title
Expand Down Expand Up @@ -424,10 +416,7 @@ def when(self, matches, context):
if next_match:
alias = copy.copy(title)
alias.name = 'alias'
if six.PY3:
alias.value = alias.value + ' ' + re.sub(r'\W*', '', after_title.raw)
else:
alias.value = alias.value + b' ' + re.sub(r'\W*', b'', after_title.raw)
alias.value = alias.value + ' ' + re.sub(r'\W*', '', after_title.raw)
alias.end = after_title.end
alias.raw_end = after_title.raw_end
return [alias]
Expand Down Expand Up @@ -581,10 +570,7 @@ def when(self, matches, context):
# adjust title to append the series name.
# Only the season.parent contains the S prefix in its value
new_title = copy.copy(title)
if six.PY3:
new_title.value = ' '.join([title.value, season.parent.value])
else:
new_title.value = b' '.join([title.value, season.parent.value])
new_title.value = ' '.join([title.value, season.parent.value])
new_title.end = season.end

# other fileparts might have the same season to be removed from the matches
Expand Down Expand Up @@ -698,10 +684,7 @@ def when(self, matches, context):
for i, episode in enumerate(episodes):
if i == 0:
new_title = copy.copy(title)
if six.PY3:
new_title.value = ' '.join([title.value, str(episode.value)])
else:
new_title.value = b' '.join([title.value, str(episode.value)])
new_title.value = ' '.join([title.value, str(episode.value)])
new_title.end = episode.end

to_remove.append(title)
Expand Down Expand Up @@ -1704,18 +1687,12 @@ def when(self, matches, context):
for release_group in release_groups:
value = release_group.value
for regex in self.regexes:
if six.PY3:
value = regex.sub(' ', value).strip()
else:
value = regex.sub(b' ', value).strip()
value = regex.sub(' ', value).strip()
if not value:
break

if value and matches.tagged('scene') and not matches.next(release_group):
if six.PY3:
value = value.split('-')[0]
else:
value = value.split(b'-')[0]
value = value.split('-')[0]

if release_group.value != value:
to_remove.append(release_group)
Expand Down
48 changes: 31 additions & 17 deletions medusa/process_tv.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class PostProcessQueueItem(generic_queue.QueueItem):

def __init__(self, path=None, info_hash=None, resource_name=None, force=False,
is_priority=False, process_method=None, delete_on=False, failed=False,
proc_type='auto', ignore_subs=False, episodes=[]):
proc_type='auto', ignore_subs=False, episodes=[], client_type=None):
"""Initialize the class."""
generic_queue.QueueItem.__init__(self, u'Post Process')

Expand All @@ -47,13 +47,17 @@ def __init__(self, path=None, info_hash=None, resource_name=None, force=False,
self.resource_name = resource_name
self.force = force
self.is_priority = is_priority
self.process_method = process_method
self.delete_on = delete_on
self.failed = failed
self.proc_type = proc_type
self.ignore_subs = ignore_subs
self.episodes = episodes

# torrent or nzb. Pass info on what sort of download we're processing.
# We might need this when determining the PROCESS_METHOD.
self.client_type = client_type
self.process_method = self.get_process_method(process_method, client_type)

self.to_json.update({
'success': self.success,
'config': {
Expand All @@ -70,6 +74,20 @@ def __init__(self, path=None, info_hash=None, resource_name=None, force=False,
}
})

def get_process_method(self, process_method, client_type):
"""Determine the correct process method.
If client_type is provided (torrent/nzb) use that to get a
client specific process method.
"""
if process_method:
return process_method

if self.client_type and app.USE_SPECIFIC_PROCESS_METHOD:
return app.PROCESS_METHOD_NZB if client_type == 'nzb' else app.PROCESS_METHOD_TORRENT

return app.PROCESS_METHOD

def update_resource(self, status):
"""
Update the resource in db, depending on the postprocess result.
Expand Down Expand Up @@ -114,9 +132,7 @@ def update_history_processed(self, process_results):

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, episodes=self.episodes)
process_results = ProcessResult(self.path, self.process_method, failed=self.failed, episodes=self.episodes)
process_results.process(
resource_name=self.resource_name,
force=self.force,
Expand Down Expand Up @@ -266,7 +282,7 @@ def directory(self, path):
# If the client and the application are not on the same machine,
# translate the directory into a network directory
elif all([app.TV_DOWNLOAD_DIR, os.path.isdir(app.TV_DOWNLOAD_DIR),
os.path.normpath(path) == os.path.normpath(app.TV_DOWNLOAD_DIR)]):
helpers.real_path(path) == helpers.real_path(app.TV_DOWNLOAD_DIR)]):
directory = os.path.join(
app.TV_DOWNLOAD_DIR,
os.path.abspath(path).split(os.path.sep)[-1]
Expand Down Expand Up @@ -390,7 +406,7 @@ def process(self, resource_name=None, force=False, is_priority=None, delete_on=F
self.log_and_output('Missed file: {missed_file}', level=logging.WARNING, **{'missed_file': missed_file})

if all([app.USE_TORRENTS, app.TORRENT_SEED_LOCATION,
self.process_method in ('hardlink', 'symlink', 'reflink', 'copy')]):
self.process_method in ('hardlink', 'symlink', 'reflink', 'keeplink', 'copy')]):
for info_hash, release_names in list(iteritems(app.RECENTLY_POSTPROCESSED)):
if self.move_torrent(info_hash, release_names):
app.RECENTLY_POSTPROCESSED.pop(info_hash, None)
Expand All @@ -409,11 +425,8 @@ def _clean_up(self, path, proc_type, delete=False):
if self.unwanted_files:
self.delete_files(path, self.unwanted_files)

if all([not app.NO_DELETE or clean_folder, self.process_method in ('move', 'copy'),
os.path.normpath(path) != os.path.normpath(app.TV_DOWNLOAD_DIR)]):

check_empty = False if self.process_method == 'copy' else True
if self.delete_folder(path, check_empty=check_empty):
if not app.NO_DELETE:
if self.delete_folder(path, check_empty=False):
self.log_and_output('Deleted folder: {path}', level=logging.DEBUG, **{'path': path})

def should_process(self, path):
Expand Down Expand Up @@ -637,13 +650,14 @@ def delete_folder(folder, check_empty=True):
:return: True on success, False on failure
"""
# check if it's a folder
if not os.path.isdir(folder):
if not folder or not os.path.isdir(folder):
return False

# check if it isn't TV_DOWNLOAD_DIR
if app.TV_DOWNLOAD_DIR:
if helpers.real_path(folder) == helpers.real_path(app.TV_DOWNLOAD_DIR):
return False
# check if it's a protected folder
if helpers.real_path(folder) in (helpers.real_path(app.TV_DOWNLOAD_DIR),
helpers.real_path(app.DEFAULT_CLIENT_PATH),
helpers.real_path(app.TORRENT_PATH)):
return False

# check if it's empty folder when wanted checked
if check_empty:
Expand Down
Loading

0 comments on commit 6f25e86

Please sign in to comment.