anidl/adl.py
2022-06-29 13:11:58 +02:00

563 lines
19 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
import os
import subprocess
import sys
import argparse
import signal
# required files
CURRENT_DIR = os.getcwd()
VERSION = "1.0"
if sys.platform == "win32":
CONFIG_FILE_PATH = os.path.join('C:\\', 'Users', str(
os.getlogin()), 'Documents', 'Adl', 'config.json')
DEFAULT_DOWNLOAD_LOCATION = os.path.join(
'C:\\', 'Users', str(os.getlogin()), 'Videos', 'Anime')
CLEAR = 'cls'
else:
CONFIG_FILE_PATH = os.path.join(
'/home', str(os.getlogin()), '.config', 'adl', 'config.json')
DEFAULT_DOWNLOAD_LOCATION = os.path.join(
'/home', str(os.getlogin()), 'Videos', 'Anime')
CLEAR = 'clear'
PROBLEMATIC_TITLES = ['Komi-san wa, Komyushou desu ',
'SK∞']
GOOD_TITLES = ['Komi-san wa, Komyushou desu.',
'SK∞']
CHOOSE_EPISODE='''Enter lowercase or uppercase to issue command:
N - Next episode (default, press <ENTER>)
L - from current to Last known:
A - All available, from episode 1
I - custom Interval (range) of episodes
0-9 - Plus n episodes relative to last seen (type number)
R - Rewatch/redownload current episode in list
C - Custom episode
U - Update entry chosen instead of streaming
S - Skip. Choose another show.
'''
CHOOSE_EPISODE_SPECIFIC_SHOW='''Enter lowercase or uppercase to issue command:
A - All available, from episode 1
I - custom Interval (range) of episodes
C - Custom episode
S - Skip. Exit adl.
'''
# exit function
def exit_adl():
sys.exit()
def interupt_command(signum, frame):
exit_adl()
# colored print
def color_print(text):
print(f"\033[0;36m{text } \033[0m")
# colored watch primpt
def watch_prompt(title, episode, msg):
print(
f"Now {msg} \033[0;34m{title}\033[0m, episode \033[0;34m{str(episode)} \033[0m")
# colored input
def color_prommpt(text):
return input(f"\033[0;34m{text}\033[0m")
# retrieve new list
def retrieve_list(account):
color_print(f"Running trackma retrieve for account {account}...")
subprocess.run(["trackma", "-a", account, "retrieve"])
subprocess.run(CLEAR)
# retrieve updated list
def retrieve_list_update(account):
color_print(
f"Running trackma retrieve for account {account} to get the updated list...")
subprocess.run(["trackma", "-a", account, "retrieve"])
subprocess.run(CLEAR)
# load list
def load_list(account):
alist = subprocess.run(["trackma", "-a", account, "list"],
stdout=subprocess.PIPE).stdout.decode('utf-8').splitlines()
alist.pop(0)
alist = alist[: len(alist) - 2]
alist = "\n".join(alist)
return alist
# exit prompt
def exit_ask():
while True:
subprocess.run(CLEAR)
choice = color_prommpt("Want to watch another anime? [Y/n]: ")
if choice == "N" or choice == "n":
exit_adl()
elif choice == "Y" or choice == "y" or choice == "":
return
# check for problematic title
def check_title(title):
if title in PROBLEMATIC_TITLES:
title = GOOD_TITLES[PROBLEMATIC_TITLES.index(
title)].encode('utf-8')
title = title.decode('utf-8')
return title
# get chosen anime info
def get_info(choice):
# get index
index = int(choice[4:7])
# get title
title = str(choice[9:-19])
title = title.replace('.', '')
title = check_title(title)
# get episode
episode = int(choice[-19:-15])
# get score
score = int(choice[-10:-5])
return index, title, episode, score
# watch animes
def watch(title, episode, download, provider, download_location):
cmd = ['animdl']
if download:
cmd.append('download')
if os.path.isdir(download_location):
os.chdir(download_location)
else:
os.mkdir(download_location)
os.chdir(download_location)
else:
cmd.append('stream')
cmd.append(f'{provider}:{title}')
cmd.append('-r')
cmd.append(episode)
subprocess.run(cmd)
if download:
os.chdir(CURRENT_DIR)
# next episode
def next_episode(title, episode, msg, download, provider, download_location):
if not download:
watch_next = True
while watch_next:
episode = episode + 1
watch_prompt(title, str(episode), msg)
watch(title, str(episode), download, provider, download_location)
while True:
color_print(f"Current watched episode: {str(episode)}")
yn = color_prommpt("Wanna watch next episode? [Y/n]: ")
if yn == "Y" or yn == "y" or yn == "":
break
elif yn == "N" or yn == "n":
watch_next = False
break
else:
episode = episode + 1
watch_prompt(title, str(episode), msg)
watch(title, str(episode), download, provider, download_location)
# all from last watched
def all_from_last(title, episode, msg, download, provider, download_location):
watch_prompt(title, f"{str(episode)} all left episodes", msg)
watch(title, f'{str(episode + 1)}:', download, provider, download_location)
# all episode
def all_episodes(title, msg, download, provider, download_location):
watch_prompt(title, "all", msg)
watch(title, '1:', download, provider, download_location)
# watch from custom range
def custom_episode_range(title, msg, download, provider, download_location):
begginig = color_prommpt("Beggining of interval?: ")
end = color_prommpt("End of interval?: ")
watch_prompt(title, f"{begginig} to {end}", msg)
watch(title, f"{begginig}:{end}", download, provider, download_location)
# add to last watched m
def next_plus_n(title, episode, action, msg, download, provider, download_location):
watch_prompt(title, str(episode + int(action)), msg)
watch(title, str(episode + int(action)),
download, provider, download_location)
# rewatch current episode
def rewatch_episode(title, episode, msg, download, provider, download_location):
watch_prompt(title, str(episode), msg)
watch(title, str(episode), download, provider, download_location)
# watch custom episode
def custom_episode(title, msg, download, provider, download_location):
episode = color_prommpt("Enter custom episode: ")
watch_prompt(title, episode, msg)
watch(title, episode, download, provider, download_location)
# update title
def update_title(index, title, episode, account):
color_print(f"Current episode for {title} is {str(episode)}")
custom = color_prommpt("Enter updated episode number: ")
if custom != "":
subprocess.run(['trackma', '-a', account,
'update', str(index), custom])
subprocess.run(['trackma', '-a', account, 'send'])
retrieve_list_update(account)
else:
color_print("Skipping updating...")
# update score
def update_score(index, title, score, account):
color_print(f"Current score for {title} is {score}")
custom = color_prommpt("Enter updated score: ")
if custom != "":
subprocess.run(['trackma', '-a', account, 'score', str(index), custom])
subprocess.run(['trackma', '-a', account, 'send'])
retrieve_list_update(account)
else:
color_print("Skipping updating...")
# update question
def update_question(index, title, episode, score, account):
while True:
color_print("Skipping watching episodes. Modifing entry.")
choice = color_prommpt("Update episode number or update score [E/s]: ")
if choice == "e" or choice == "E" or choice == "":
update_title(index, title, episode, account)
break
elif choice == "s" or choice == "S":
update_score(index, title, score, account)
break
# ask if you wanna continus watching
def wanna_continu_watch(download):
while True:
if not download:
yn = color_prommpt("Wanna continue watching? [Y/n]: ")
else:
yn = color_prommpt("Wanna continue downloading? [Y/n]: ")
if yn == "y" or yn == "Y" or yn == "":
return True
elif yn == "n" or yn == "N":
return False
# ask if you wanna update title meta after watch
def wanna_update_title_after_watch(index, title, episode, score, download, account):
if not download:
while True:
yn = color_prommpt(
"Wanna update episode number or update score of watched anime? [N/e/s]: ")
if yn == "E" or yn == "e":
update_title(index, title, episode, account)
break
elif yn == "S" or yn == "s":
update_score(index, title, score, account)
break
elif yn == "N" or yn == "n" or yn == "":
break
# choose what to do with episode
def choose_episode():
subprocess.run(CLEAR)
color_print(CHOOSE_EPISODE)
return color_prommpt("Your choice? [N/l/a/i/0-9/r/c/u/s]: ")
def choose_episode_specific_show():
subprocess.run(CLEAR)
color_print(CHOOSE_EPISODE_SPECIFIC_SHOW)
return color_prommpt("Your choice? [A/i/c/s]: ")
def argument_and_config_parser():
# config
config = {}
ConfigExists = False
# print(CONFIG_FILE_PATH)
# sys.exit()
if os.path.exists(CONFIG_FILE_PATH):
config_content = open(CONFIG_FILE_PATH, encoding='utf-8-sig').read()
config = eval(config_content)
ConfigExists = True
# argument parser
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--provider", required=False,
help="Define provider used for streaming (check \033[0;36m$anime dl --help\033[0m for providers list)")
ap.add_argument("-s", "--show", required=False,
help='Watch custom show. Ep nr optional, careful with the quotes. Ex: \033[0;36m$adl -s "gegege 2018"\033[0m')
ap.add_argument("-n", "--number", required=False,
help='Specify episode number that will be used with "-s / --show" option. Ex: \033[0;36m$adl -s "gegege 2018" -n "4"\033[0m')
ap.add_argument("-a", "--account", required=False,
help="By default trackma will use account 1. Use '-a 2' for example to change trackma account")
ap.add_argument("-d", "--download", required=False, type=bool, nargs='?', const=True, default=False,
help="Download instead of streaming")
ap.add_argument("-l", "--download-location", required=False,
help="Define downloads location, Default location is in 'User folder/Videos/Anime'")
ap.add_argument("-t", "--test-providers", required=False, type=bool, nargs='?', const=True, default=False,
help="Check the state of possible providers")
ap.add_argument("-v", "--version", required=False, nargs='?', const=True,
help="Display version and exit")
args = vars(ap.parse_args())
# print the version
if args["version"]:
print(f"Py-adl version {VERSION}")
sys.exit()
# check if providers are working
if args["test_providers"]:
subprocess.run(["animdl", "test"])
sys.exit()
# get provider
if args['provider']:
provider = str(args["provider"])
elif ConfigExists and 'provider' in config and config['provider']:
provider = str(config["provider"])
else:
provider = "zoro"
# get show
if args['show']:
show = str(args["show"])
else:
show = ""
# get episode
if args['number']:
if args['number'] and args['show']:
episode = int(args['number'])
else:
print("You need to also specify a show name to use this option")
sys.exit()
else:
episode = 0
# get account
if args['account']:
account = str(int(args["account"]) - 1) # take the account from input
elif ConfigExists and 'account' in config and config["account"]:
# take the account from config
account = str(int(config["account"]) - 1)
else:
account = "0" # default account
# enable downloading
if args["download"]:
download = True # enable downloading
msg = "downloading" # download message
else:
download = False # specify whether to download or not
msg = "watching" # msg for the watch prompt
if not download and args["download_location"]:
color_print("You need to be downloading to use this option!")
exit_adl()
elif download and args["download_location"]:
download_location = str(args["download_location"])
else:
download_location = DEFAULT_DOWNLOAD_LOCATION
return (provider, show, episode, account, download, msg, download_location)
def specific_show_loop(show, msg, download, provider, download_location):
while True:
# choose what to do with the choosen anime
action = choose_episode_specific_show()
if action == "a" or action == "A" or action == "":
all_episodes(show, msg, download, provider, download_location)
exit_adl()
# custom range of episodes
elif action == "i" or action == "I":
custom_episode_range(show, msg, download,
provider, download_location)
if wanna_continu_watch(download):
continue
else:
exit_adl()
# watch custom episode
elif action == "c" or action == "C":
custom_episode(show, msg, download, provider, download_location)
if wanna_continu_watch(download):
continue
else:
exit_adl()
# skip the anime
elif action == "s" or action == "S":
exit_adl()
def main_loop(retrieve, account, msg, download, provider, download_location):
# main loop
while True:
# retrieving the list on start
if retrieve:
retrieve_list(account)
retrieve = False
# get the list of anime
alist = load_list(account)
# get choice from fzf
choice = subprocess.run(["fzf", "--ansi", "--unicode", "--reverse", "--prompt",
"Choose anime to watch: "], input=alist, stdout=subprocess.PIPE, encoding='utf-8').stdout
if choice:
# get needed info
index, title, episode, score = get_info(choice)
# the watch loop
while True:
# choose what to do with the choosen anime
action = choose_episode()
# watch next episode
if action == "n" or action == "N" or action == "":
next_episode(title, episode, msg, download,
provider, download_location)
wanna_update_title_after_watch(
index, title, episode, score, download, account)
exit_ask()
break
# watch all left episodes
elif action == "l" or action == "L":
all_from_last(title, episode, msg, download,
provider, download_location)
wanna_update_title_after_watch(
index, title, episode, score, download, account)
exit_ask()
break
# watch every episode available
elif action == "a" or action == "A":
all_episodes(title, msg, download,
provider, download_location)
wanna_update_title_after_watch(
index, title, episode, score, download, account)
exit_ask()
break
# custom range of episodes
elif action == "i" or action == "I":
custom_episode_range(
title, msg, download, provider, download_location)
if wanna_continu_watch(download):
continue
else:
wanna_update_title_after_watch(
index, title, episode, score, download, account)
exit_ask()
break
# something?
elif action == "1" or action == "2" or action == "3" or action == "4" or action == "5" or action == "6" or action == "7" or action == "8" or action == "9":
next_plus_n(title, episode, action, msg,
download, provider, download_location)
if wanna_continu_watch(download):
continue
else:
wanna_update_title_after_watch(
index, title, episode, score, download, account)
exit_ask()
break
# rewatch current episode
elif action == "r" or action == "R":
rewatch_episode(title, episode, msg, download,
provider, download_location)
if wanna_continu_watch(download):
continue
else:
wanna_update_title_after_watch(
index, title, episode, score, download, account)
exit_ask()
break
# watch custom episode
elif action == "c" or action == "C":
custom_episode(title, msg, download,
provider, download_location)
if wanna_continu_watch(download):
continue
else:
wanna_update_title_after_watch(
index, title, episode, score, download, account)
exit_ask()
break
# update anime meta
elif action == "u" or action == "U":
update_question(index, title, episode, score, account)
exit_ask()
break
# skip the anime
elif action == "s" or action == "S":
break
else:
exit_ask()
def main():
signal.signal(signal.SIGINT, interupt_command)
# print("Inside")
# setup env variables for better readability of outputs
os.environ['LINES'] = '25'
os.environ['COLUMNS'] = '120'
os.environ['PYTHONIOENCODING'] = 'utf-8'
# get argument and config parameters
(provider, show, episode, account, download, msg,
download_location) = argument_and_config_parser()
# retrieve the trackma list on run
retrieve = True
if not show == "" and not episode == 0:
# watching just a specific show and episode only
watch(show, str(episode), download, provider, download_location)
elif not show == "":
# choose want to do with a specific show
specific_show_loop(show, msg, download, provider, download_location)
else:
# main loop that connets with your list with trackma
main_loop(retrieve, account, msg, download,
provider, download_location)
exit_adl()
# run only if runned directly
if __name__ == "__main__":
main()