class MockTest(unittest.TestCase): def setUp(self): self.parser = Parser() def test_current_season(self): with HTTMock(current_season_mock): current = self.parser.current_shows self.assertEqual(list(current), ["Test 1", "Test 2", "Test 3", "Test 4"]) def test_shows_list(self): with HTTMock(shows_mock): shows = self.parser.shows self.assertEqual( shows, { 'Test 1': 'test-1', 'Test 2': 'test-2', 'Test 3': 'test-3', 'Test 4': 'test-4' }) def test_get_episodes(self): with HTTMock(api_mock): episodes = self.parser.get_episodes("test", limit=4) self.assertEqual(len(episodes), 4) batch = self.parser.get_batches("test") self.assertEqual(batch[0]["title"].lower(), "one-punch man") def test_show_id(self): with HTTMock(showid_mock): showid = self.parser._get_show_id("doesn't matter") self.assertTrue(showid, 123456789)
def test_get_batches(): parser = Parser() title = "Kateikyoushi Hitman Reborn!" batches = parser.get_batches(title) assert len(batches) == 2 for batch in batches: assert batch["title"] == title has_magnet = [] for resolution in "480", "720", "1080": assert resolution in batch has_magnet.append("Magnet" in batch[resolution]) assert has_magnet == sorted(has_magnet, reverse=True) assert has_magnet[0]
def subscribe_to(show, episode): """ subscribe to a show at and set progress to specified episodes :param show: the search term for the name of the show, it can be an approximation :param episode: the initial episode to set the show. defaults to 0 (as if no episodes were watched). :return: returns a tuple - first element indicates the success status, the second one is the exact name of the show. """ config = ConfigManager() title = Parser().get_episodes(show)[0]["title"] if title.lower() in config.conf["subscriptions"]: return False, title config.conf["subscriptions"][title.lower()] = episode with open(os.path.join(config.dir, config.file), "w") as f: config.conf.write(f) return True, title
def test_get_proper_title(): with HTTMock(shows_mock): parser = Parser() reasonable_titles = [ "Test 1", # exact match "test 1", # almost same "tast 1", # typo ] for title in reasonable_titles: proper_title = parser.get_proper_title(title) assert proper_title == "Test 1" incorrect_titles = [ "", # blank "random", # non-matching text "123" ] for title in incorrect_titles: assert parser.get_proper_title(title, min_threshold=70) == "" assert parser.get_proper_title("Hello $amp; World") == "Hello & World"
def test_get_shows(): with HTTMock(shows_mock): parser = Parser() assert parser.shows == parser.current_shows assert parser.shows == { 'Test 1': 'test-1', 'Test 2': 'test-2', 'Test 3': 'test-3', 'Test 4': 'test-4', "Hello & World": "hello&world" }
def test_get_episodes(): # without mocking, we'll do live testing on the website. parser = Parser() for limit in 0, 3, 12, 24, 28: title = parser.get_proper_title("one piece") showid = parser._get_show_id(title) shows_html = parser._get_html(showid, limit, "show") episodes = list(parser._parse_html(shows_html)) assert len(episodes) == 12 * round(limit / 12) proper_get_episodes = parser.get_episodes("one piece", limit=limit) for index, episode in enumerate(proper_get_episodes): episode.pop("title") proper = episode.keys() non_proper = episodes[index].keys() error_msg = f"proper: {proper} \nnon proper: {non_proper}" assert episode == episodes[index], error_msg
def test_show_id(): parser = Parser() assert parser._get_show_id("no way this will ever be an anime") == -1
subprocess.check_call(passValues) # don't forget to uncomment! print("Download Completed !") Video = GetVideoDirAndConvert(showName, str(episode)) SaveToDatabase(seriesID, showName, episode, cursor, Video, Database) while True: Database = mysql.connector.connect(host="127.0.0.1", user="******", passwd="python", database="streaming") p = Parser() config = ConfigManager() cursor = Database.cursor() cursor.execute("Select * FROM DownloadList") results = cursor.fetchall() for result in results: print(result[1]) Id = (result[1], ) sql = "Select * FROM series WHERE id = '%s'" cursor.execute(sql, Id) Series = cursor.fetchone() DownloadShow(Series[0], Series[1], cursor, Database) if Series[4] == "Finished Airing": sql = "DELETE FROM DownloadList WHERE SeriesID ='%s'"
def setUp(self): self.parser = Parser()
def main(): argparser = argparse.ArgumentParser(description="horrible script for downloading anime") argparser.add_argument("-d", "--download", help="download a specific anime", type=str) argparser.add_argument("-o", "--output", help="directory to which it will download the files", type=str) argparser.add_argument("-e", "--episodes", help="specify specific episodes to download", type=str) argparser.add_argument("-l", "--list", help="display list of available episodes", action="store_true") argparser.add_argument("-r", "--resolution", help="specify resolution quality", type=str) argparser.add_argument("--subscribe", help="add a show to the config file", type=str) argparser.add_argument("--batch", help="search for batches as well as regular files", action="store_true") argparser.add_argument("-q", "--quiet", help="set quiet mode on", action="store_true") argparser.add_argument("-lc", "--list-current", help="list all currently airing shows", action="store_true") argparser.add_argument("-c", "--config", help="config file location", type=str) argparser.add_argument("--noconfirm", help="Bypass any and all “Are you sure?” messages.", action="store_true") args = argparser.parse_args() logger = logging.getLogger("info") if not args.config: config = ConfigManager() else: path, file = os.path.split(args.config) if file: config = ConfigManager(conf_dir=path, file=file) elif path: config = ConfigManager(conf_dir=path) else: config = ConfigManager() parser = Parser() if args.subscribe: episode_number = args.episodes if args.episodes else "0" title = parser.get_proper_title(args.subscribe) success, show = config.add_entry(title, episode_number) if success: print(f"Successfully subscribed to: \"{show.lower()}\"") print(f"Latest watched episode is - {episode_number}") else: print(f"You're already subscribed to \"{show}\", omitting changes...") exit(0) if args.list: print("\n".join(parser.shows.keys())) exit(0) if args.list_current: print("\n".join(parser.current_shows.keys())) exit(0) clear() if args.output: config.download_dir = args.output if args.resolution: config.quality = args.resolution qualities = config.quality.split(",") if not valid_qualities(qualities): print("Bad resolution specified, aborting...") exit(1) if args.download: title = parser.get_proper_title(args.download) if not args.quiet: print(f"{fg(3)}FETCHING:{fg.rs} {title}") episodes = parser.get_episodes(args.download, batches=args.batch) def should_download(episode): if not args.episodes: return True return episode_filter(float(episode["episode"]), args.episodes) filtered_episodes = list(filter(should_download, episodes)) if not args.quiet: clear() dots = "." * (50 - len(title)) found_str = f"FOUND ({len(filtered_episodes)})" print(f"{fg(3)}FETCHING: {fg.rs}{title}{dots}{fg(10)}{found_str}{fg.rs}") episodes_len = len(filtered_episodes) * len(qualities) print(f'{fg(2)}\nFound {episodes_len} file{"s" if episodes_len > 1 else ""} to download:\n{fg.rs}') for episode in filtered_episodes: for quality in qualities: print(f'{title} - {episode["episode"]} [{quality}p].mkv') if not args.noconfirm and not args.quiet: inp = input(f'{fg(3)}\nwould you like to proceed? [Y/n] {fg.rs}') if inp not in ('', 'Y', 'y', 'yes', 'Yes'): print(fg(1) + 'aborting download\n' + fg.rs) exit(1) for episode in filtered_episodes: download(episode, qualities, config.download_dir) config.update_entry(title, episode["episode"]) exit(0) manager = Manager() initial_downloads_dict = {parser.get_proper_title(title): None for title in config.subscriptions.keys()} downloads = manager.dict(initial_downloads_dict) printing_lock = Lock() procs = [] method = "batches" if args.batch else "show" if not args.quiet: clear() for title in initial_downloads_dict.keys(): print(f"{fg(3)}FETCHING:{fg.rs} {title}") for entry in config.subscriptions.items(): proc = Process( target=fetch_episodes, args=(entry, downloads, printing_lock, parser, args.batch, args.quiet) ) proc.start() procs.append(proc) for proc in procs: proc.join() downloads_list = [] for episodes in downloads.values(): for episode in episodes: downloads_list.append(episode) if downloads_list == []: if not args.quiet: print(fg(1) + 'No new episodes were found. Exiting ' + fg.rs) logger.info("No new episodes were found. Exiting ") exit(0) logger.info("found the following files:") if not args.quiet: episodes_len = len(downloads_list) * len(qualities) print(f'{fg(2)}\nFound {episodes_len} file{"s" if episodes_len > 1 else ""} to download:\n{fg.rs}') for episode in downloads_list: for quality in qualities: if not args.quiet: print(f'{episode["title"]} - {episode["episode"]} [{quality}p].mkv') logger.info(f'{episode["title"]} - {episode["episode"]} [{quality}p].mkv') if not args.noconfirm and not args.quiet: inp = input(f'{fg(3)}\nwould you like to proceed? [Y/n] {fg.rs}') if inp not in ('', 'Y', 'y', 'yes', 'Yes'): print(fg(1) + 'aborting download\n' + fg.rs) logger.info("user has aboorted the download") exit(1) for episode in downloads_list: download(episode, qualities, config.download_dir) config.update_entry(episode["title"], episode["episode"]) logger.info(f'updated entry: {episode["title"]} - {episode["episode"]}') exit(0)
#!/usr/bin/env python3 from HorribleDownloader import Parser, ConfigManager import json print ("Hello World") p = Parser() config = ConfigManager() episodes = p.get_episodes("Hibike! Euphonium") print(episodes[0]['1080']['Magnet']); #print(episodes[0]); #s = episodes[0].replace("'", '"') #y = json.loads[s]; #print(y["episode"]); #for x in episodes: # s = "["+str(x)+"]"; # s = str.replace("'", '"') # y = json.loads(s); # print(y["episde"]); # print("\n");
def cli(): try: parser = argparse.ArgumentParser( description='horrible script for downloading anime') parser.add_argument('-d', '--download', help="download a specific anime", type=str) parser.add_argument( '-o', '--output', help="directory to which it will download the files", type=str) parser.add_argument('-e', '--episodes', help="specify specific episodes to download", type=str) parser.add_argument('-l', '--list', help="display list of available episodes", action="store_true") parser.add_argument('-r', '--resolution', help="specify resolution quality", type=str) parser.add_argument('--subscribe', help="add a show to the config file", type=str) parser.add_argument('--batch', help="search for batches as well as regular files", action="store_true") parser.add_argument('-q', '--quiet', help="set quiet mode on", action="store_true") parser.add_argument('-lc', '--list-current', help="list all currently airing shows", action="store_true") args = parser.parse_args() if args.subscribe: episode_number = args.episodes if args.episodes else "0" status, show = subscribe_to(args.subscribe, episode_number) if status: print(f"Successfully subscribed to: \"{show.lower()}\"") print(f"Latest watched episode is - {episode_number}") else: print( f"You're already subscribed to \"{show}\", omitting changes..." ) exit(0) if args.list: shows = list(Parser().shows.keys()) print("\n".join(shows)) exit(0) if args.list_current: shows = list(Parser().current_shows) print("\n".join(shows)) exit(0) main(args) except KeyboardInterrupt: print(f"{fg(1)}\nAborting download...{fg.rs}")
def main(args): clear() CONFIG = ConfigManager() PARSER = Parser() # change to custom download dir if user has specified if args.output: CONFIG.download_dir = args.output QUALITIES = (CONFIG.quality if not args.resolution else args.resolution).split(",") # validating qualities object to fit format: if not verify_quality(QUALITIES): print("Bad resolution specified, aborting...") exit(1) downloads = [] if args.download: # we want to set the correct title title = Parser().get_episodes(args.download)[0]["title"] downloads = multiprocessing.Manager().dict() procs = [] l = multiprocessing.Lock() # all the variables set, lets start with the iterations: for show, last_watched in [(title, 0)] if args.download else CONFIG.subscriptions: proc = multiprocessing.Process(target=fetch_episodes, args=(PARSER, show, last_watched, downloads, args, l)) proc.start() procs.append(proc) for proc in procs: proc.join() downloads_flat = flatten_dict(downloads) # after we iterated on all of the shows we have a list of stuff to download. # but first we must check the list if it contains data: if not downloads_flat: if args.download: # we want to display a different message in each case. print(fg(1) + "Couldn't find specified anime. Exiting" + fg.rs) else: print(fg(1) + 'No new episodes were found. Exiting ' + fg.rs) exit(1) # arguably should be exit code 0 # summerizing info about the download reprint_results(downloads, QUALITIES) inp = input( f'{fg(3)}\nwould you like to re-arrange the downloads? (Return for default) {fg.rs}' ) if inp is "": # continue as usually. pass elif inp in ("Y", "y", "yes", "Yes"): # do the re-arrangment print( "press SPACE to toggle select a show, use UP/DOWN to arrange, when done - press RETURN" ) # set some helpful variables shows_download_keys = downloads.keys() current_index = 0 selected = False while True: # printing all of the info from before, to reset the new data reprint_results(downloads, QUALITIES) print( f'{fg(3)}\nwould you like to re-arrange the downloads? (Return for default) {fg.rs}', inp) print( "press SPACE to toggle select a show, use UP/DOWN to arrange, when done - press RETURN" ) for i, show in enumerate( shows_download_keys ): # here we set the colors of the new data if i == current_index: if selected: print(f"{fg(12)}{i+1}. {show}{fg.rs}") else: print(f"{fg(3)}{i+1}. {fg.rs}{show}") else: print(f"{i+1}. {show}") keypress = getKey() if keypress == " ": # SPACE selected = not selected elif keypress in ("up", "down"): # ARROWS (ANY) # this has to be done no matter which arrow key is pressed: if selected: removed = shows_download_keys.pop(current_index) # this is how it works to detect the individual arrows. # https://www.daniweb.com/posts/jump/1087957 if keypress == "up": # UP if current_index > 0: current_index -= 1 elif keypress == "down": # DOWN if current_index < len(shows_download_keys) - ( 0 if selected else 1): current_index += 1 # once we know what key was pressed, we need to return the value we removed if selected: shows_download_keys.insert(current_index, removed) elif keypress == "\r": # RETURN for show in shows_download_keys: downloads[show] = downloads.pop(show) downloads_flat = flatten_dict(downloads) print( f"{fg(3)}The download order will be as follows:{fg.rs}\n") for episode in downloads_flat: for quality in QUALITIES: print( f'{episode["title"]} - {episode["episode"]} [{quality}p].mkv' ) break else: print(fg(1) + 'aborting download\n' + fg.rs) exit(1) #l et the downloads begin! abs_path = os.path.expanduser(CONFIG.download_dir) for episode_obj in downloads_flat: download(episode_obj, QUALITIES, abs_path) if not args.download: CONFIG.conf["subscriptions"][episode_obj["title"].lower( )] = episode_obj["episode"].lstrip("0") with open(os.path.join(CONFIG.dir, CONFIG.file), "w") as f: CONFIG.conf.write(f)