Prevents modifying the config if its already being modified.

Co-authored-by: Arjix <53124886+ArjixGamer@users.noreply.github.com>
master
Arjix 2021-10-16 14:03:07 +03:00 committed by GitHub
parent a4f3eeee51
commit 913e6bc842
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 149 additions and 30 deletions

View File

@ -1,7 +1,11 @@
import click
from anime_downloader.util import is_running
if is_running(regex=r'python|anime|config', expected_matches=3):
raise Exception('Another instance of "anime config" is already running!')
import os
import click
from tabulate import tabulate
from anime_downloader.config import APP_DIR, Config
from anime_downloader.config import APP_DIR, Config # noqa
data = Config._CONFIG
@ -20,7 +24,7 @@ def traverse_json(data, previous=''):
click.echo(create_table(keys, previous))
val = click.prompt("Select Option", type=int, default=1) - 1
if type(data[keys[val]]) == dict:
if isinstance(data[keys[val]], dict):
traverse_json(data[keys[val]], keys[val])
else:
click.echo(f"Current value: {data[keys[val]]}")
@ -32,8 +36,9 @@ def traverse_json(data, previous=''):
except (SyntaxError, NameError) as e:
pass
if type(newVal) != type(data[keys[val]]):
choice = click.confirm(f"{newVal} appears to be of an incorrect type. Continue")
if not isinstance(newVal, type(data[keys[val]])):
choice = click.confirm(
f"{newVal} appears to be of an incorrect type. Continue")
if not choice:
exit()
@ -41,7 +46,8 @@ def traverse_json(data, previous=''):
try:
newVal = type(data[keys[val]])(newVal)
except TypeError:
click.echo(f"'{newVal}' could not be converted to the correct type")
click.echo(
f"'{newVal}' could not be converted to the correct type")
exit()
data[keys[val]] = newVal

View File

@ -73,7 +73,8 @@ sitenames = [v[1] for v in ALL_ANIME_SITES]
'--choice', '-c', type=int,
help='Choice to start downloading given anime number '
)
@click.option("--skip-fillers", is_flag=True, help="Skip downloading of fillers.")
@click.option("--skip-fillers", is_flag=True,
help="Skip downloading of fillers.")
@click.option(
"--speed-limit",
type=str,
@ -149,16 +150,18 @@ def command(ctx, anime_url, episode_range, url, player, skip_download, quality,
if skip_fillers and fillers:
if episode.ep_no in fillers:
logger.info(
"Skipping episode {} because it is a filler.".format(episode.ep_no))
"Skipping episode {} because it is a filler.".format(
episode.ep_no))
continue
if url:
util.print_episodeurl(episode)
if player:
episode_range = f"0:{len(animes)}" if not episode_range else episode_range
util.play_episode(
episode, player=player, title=f'{anime.title} - Episode {episode.ep_no}', episodes=episode_range)
episode,
player=player,
title=f'{anime.title} - Episode {episode.ep_no}')
if not skip_download:
if external_downloader:

View File

@ -50,7 +50,8 @@ sitenames = [v[1] for v in ALL_ANIME_SITES]
@click.option(
'--download-metadata', '-dm', is_flag=True,
help='Download additional metadata')
@click.option("--skip-fillers", is_flag=True, help="Skip downloading of fillers.")
@click.option("--skip-fillers", is_flag=True,
help="Skip downloading of fillers.")
@click.pass_context
def command(ctx, anime_url, episode_range, player,
force_download, provider,
@ -94,11 +95,13 @@ def command(ctx, anime_url, episode_range, player,
raise exceptions.NotFoundError('No episodes found within index.')
# Stores the choices for each provider, to prevent re-prompting search.
# As the current setup runs episode wise without this a 12 episode series would give 12+ prompts.
# As the current setup runs episode wise without this a 12 episode series
# would give 12+ prompts.
choice_dict = {}
# Doesn't work on nyaa since it only returns one episode.
for episode_range in range(int(episode_range_split[0]), int(episode_range_split[-1]) + 1):
for episode_range in range(int(episode_range_split[0]), int(
episode_range_split[-1]) + 1):
# Exits if all providers are skipped.
if [choice_dict[i] for i in choice_dict] == [0] * len(providers):
logger.info('All providers skipped, exiting')
@ -115,7 +118,8 @@ def command(ctx, anime_url, episode_range, player,
# To make the downloads use the correct name if URL:s are used.
real_provider = cls.sitename if cls else provider
# This will allow for animeinfo metadata in filename and one filename for multiple providers.
# This will allow for animeinfo metadata in filename and one
# filename for multiple providers.
rep_dict = {
'animeinfo_anime_title': util.slugify(info.title),
'provider': util.slugify(real_provider),
@ -128,11 +132,13 @@ def command(ctx, anime_url, episode_range, player,
disable_ssl = False
session.get_session().verify = not disable_ssl
# This is just to make choices in providers presistent between searches.
# This is just to make choices in providers presistent between
# searches.
choice_provider = choice_dict.get(provider)
if not cls:
_anime_url, choice_provider = util.search(anime_url, provider, val=choice_provider, season_info=info, ratio=ratio)
_anime_url, choice_provider = util.search(
anime_url, provider, val=choice_provider, season_info=info, ratio=ratio)
choice_dict[provider] = choice_provider
if choice_provider == 0 or not _anime_url:
logger.info('Skipped')
@ -145,7 +151,7 @@ def command(ctx, anime_url, episode_range, player,
fallback_qualities=fallback_qualities)
# I have yet to investigate all errors this can output
# No sources found gives error which exits the script
except:
except BaseException:
continue
logger.debug('Found anime: {}'.format(anime.title))
@ -153,7 +159,8 @@ def command(ctx, anime_url, episode_range, player,
try:
animes = util.parse_ep_str(anime, str(episode_range))
except RuntimeError:
logger.error('No episode found with index {}'.format(episode_range))
logger.error(
'No episode found with index {}'.format(episode_range))
continue
except:
logger.error('Unknown provider error')
@ -167,23 +174,31 @@ def command(ctx, anime_url, episode_range, player,
skip_download = True
if download_dir and not skip_download:
logger.info('Downloading to {}'.format(os.path.abspath(download_dir)))
logger.info(
'Downloading to {}'.format(
os.path.abspath(download_dir)))
if skip_fillers:
fillers = util.get_filler_episodes(query)
for episode in animes:
if skip_fillers and fillers:
if episode.ep_no in fillers:
logger.info("Skipping episode {} because it is a filler.".format(episode.ep_no))
logger.info(
"Skipping episode {} because it is a filler.".format(
episode.ep_no))
continue
if download_metadata:
util.download_metadata(fixed_file_format, info.metadata, episode)
util.download_metadata(
fixed_file_format, info.metadata, episode)
if url:
util.print_episodeurl(episode)
if player:
util.play_episode(episode, player=player, title=f'{anime.title} - Episode {episode.ep_no}')
util.play_episode(
episode,
player=player,
title=f'{anime.title} - Episode {episode.ep_no}')
if not skip_download:
if external_downloader:

View File

@ -1,3 +1,8 @@
from anime_downloader.util import is_running
if is_running(regex=r'python|anime|watch', expected_matches=3):
raise Exception('Another instance of "anime watch" is already running!')
import click
import logging
import sys
@ -90,17 +95,21 @@ def command(anime_name, new, update_all, _list, quality, remove,
watcher.update_anime(anime)
if mal_import:
PATH = anime_name # Hack, but needed to prompt the user. Uses the anime name as parameter.
# Hack, but needed to prompt the user. Uses the anime name as
# parameter.
PATH = anime_name
if PATH:
query = PATH
else:
query = click.prompt('Enter the file path for the MAL .xml file', type=str)
query = click.prompt(
'Enter the file path for the MAL .xml file', type=str)
if query.endswith('.xml'):
watcher._import_from_MAL(query)
sys.exit(0)
else:
logging.error("Either the file selected was not an .xml or no file was selected.")
logging.error(
"Either the file selected was not an .xml or no file was selected.")
sys.exit(1)
# Defaults the command to anime watch -l all.
@ -128,13 +137,15 @@ def command(anime_name, new, update_all, _list, quality, remove,
def command_parser(command):
# Returns<kUp> a list of the commands
# new "no neverland" --provider vidstream > ['new', '--provider', 'no neverland', 'vidstream']
# new "no neverland" --provider vidstream > ['new', '--provider', 'no
# neverland', 'vidstream']
# Better than split(' ') because it accounts for quoutes.
# Group 3 for quoted command
command_regex = r'(("|\')(.*?)("|\')|.*?\s)'
matches = re.findall(command_regex, command + " ")
commands = [i[0].strip('"').strip("'").strip() for i in matches if i[0].strip()]
commands = [i[0].strip('"').strip("'").strip()
for i in matches if i[0].strip()]
return commands
@ -159,8 +170,10 @@ def list_animes(watcher, quality, download_dir, imp=None, _filter=None):
watcher.new(url)
if key == 'swap':
if vals[0] in ['all', 'watching', 'completed', 'planned', 'dropped', 'hold']:
return list_animes(watcher, quality, download_dir, imp=imp, _filter=vals[0])
if vals[0] in ['all', 'watching', 'completed',
'planned', 'dropped', 'hold']:
return list_animes(
watcher, quality, download_dir, imp=imp, _filter=vals[0])
return list_animes(watcher, quality, download_dir, imp=imp)
else:
@ -272,7 +285,8 @@ def list_animes(watcher, quality, download_dir, imp=None, _filter=None):
watcher.update(anime)
elif key == 'watch_status':
if val in ['watching', 'completed', 'dropped', 'planned', 'all']:
if val in ['watching', 'completed',
'dropped', 'planned', 'all']:
colours = {
'watching': 'cyan',
'completed': 'green',

View File

@ -493,3 +493,84 @@ class ClickListOption(click.Option):
return ast.literal_eval(value)
except:
raise click.BadParameter(value)
class Process:
def __init__(self, name, cmdline, pid):
self.name = name
self.pid = pid
self.cmdline = cmdline
def __str__(self):
return str({
'name': self.name,
'pid': self.pid,
'cmdline': self.cmdline
})
def getAllProcesses_Win32():
placeholder = list()
out = os.popen('WMIC path win32_process get Caption,Processid,Commandline').read(
).split('\n')[::2][1:]
for line in out:
f = line.split()
if f:
if len(f) > 2:
placeholder.append(
Process(name=f[0], cmdline=f[1:-1], pid=int(f[-1])))
else:
placeholder.append(
Process(name=f[0], cmdline=None, pid=int(f[-1])))
return placeholder
def getAllProcesses_unix():
if sys.platform.startswith('darwin'):
cmd = 'ps -Ao user,pid,%cpu,%mem,vsz,rss,tt,stat,start,time,command'
return []
elif sys.startswith('linux'):
cmd = 'ps aux'
out = os.popen(cmd).read()
out = out.split('\n')[1:]
placeholder = list()
for line in out:
try:
line_list = line.lower().split()
PID = line_list[1]
NAME = line_list[10:][0]
CMD = line_list[10:]
placeholder.append(Process(name=NAME, cmdline=CMD, pid=PID))
except IndexError:
continue
return placeholder
def get_all_processes():
if sys.platform.startswith('win'):
return getAllProcesses_Win32()
else:
return getAllProcesses_unix()
def is_running(regex, expected_matches):
"""
Iterates through all the processes that are running
and returns a boolean if a process matches the regex passed
and the groups matched are equal to or more than the expected_matches.
"""
already_running = False
dict_pids = {
p.pid: [p.name, p.cmdline]
for p in get_all_processes()
}
if os.getpid() in dict_pids:
del dict_pids[os.getpid()]
for key, value in dict_pids.items():
if value[1]:
list_of_matches = re.findall(regex, ' '.join(value[1]))
if list_of_matches and len(list_of_matches) >= expected_matches:
already_running = True
return already_running