У меня есть несколько серийных локально скачанных (я знаю, что пиратство не круто) и единственная причина, по которой я не смог посмотреть их до сих пор, мне слишком скучно наблюдать за ними один за другим и отслеживать Один я в последний раз смотрел.
Итак, я подумал, я могу написать сценарий Python, который сделает все это для меня, и все, что мне придется сделать, это запускать его, и это будет делать остальные. (Да, я знаю Netflix делает это Но тогда эти серии были недоступны на Netflix).
После многих мозгового штурма я пришел со следующим процессом, который я бы реализовал, чтобы сделать вышеуказанное.
Процесс
- Если серия еще не кэширована, кэлит это (объяснит это позже)
- Получить последний поигранный эпизод
- Позвоните внешнему игроку, как
MPV.
1. Кэширование
Итак, вот сделка. Серия, которую мы сохраняем локально загруженные, хранятся в следующем формате
├── TAAHM │ ├── Season 01 │ │ ├── Two And A Half Men Season 01 Episode 01 - Pilot - Most Chicks Wont Eat Veal.avi │ │ ├── Two And A Half Men Season 01 Episode 02 - Big Flappy Bastards.avi │ │ ├── Two And A Half Men Season 01 Episode 03 - Go East on Sunset Until You Reach the Gates of Hell.avi │ │ ├── Two And A Half Men Season 01 Episode 04 - If I Can't Write My Chocolate Song, I'm Going to Take a Nap.avi │ │ ├── Two And A Half Men Season 01 Episode 05 - The Last Thing You Want to Do Is Wind Up with a Hump.avi │ │ ├── Two And A Half Men Season 01 Episode 06 - Did You Check with the Captain of the Flying Monkeys.avi │ │ ├── Two And A Half Men Season 01 Episode 07 - If They Do Go Either Way, They're Usually Fake.avi │ │ ├── Two And A Half Men Season 01 Episode 08 - Twenty-Five Little Pre-pubers Without a Snoot-ful.avi │ │ ├── Two And A Half Men Season 01 Episode 09 - Phase One, Complete.avi │ │ ├── ..... │ ├── Season 02 │ │ ├── ......
Итак, во-первых, во-первых, нам нужно определить функцию, которая может рекурсивно выяснить все сезоны и эпизоды.
Однако есть поймать, мы не можем просто рекурсивно пройти через все файлы, нам также нужно извлечь из них номера сезона и эпизода и придется отсортировать их на основе этого и хранить их соответственно.
Только тогда мы сможем кэшировать их, чтобы в следующий раз мы сможем просто найти кэшированные данные и пропустить эту часть.
Давайте напишем (некоторые) функции (ы) для извлечения данных
def _get_all_match(self, values, keyword): """Get all the possible matches of the keyword passed in the list.""" matched_list = {} for value in values: # Try to extract the season number, if it's not present # skip the dir season_name = value.name.lower() result = re.search( '{}({})?[\ \.]?[0-9]?[0-9]'.format(keyword[0], keyword[1:]), season_name ) if result is not None: result = result.group(0) else: continue season_number = re.sub( '{}({})?'.format(keyword[0], keyword[1:]), '', result ).replace(" ", "") matched_list[int(season_number)] = value.as_posix() return matched_list
Что эта функция делает, предпринимает некоторые значения и принимает ключевое слово.
Я сделал функцию Generic так, чтобы она могла получить сочетание эпизода, а также в сезон с той же логикой.
Например:
Если мы хотим найти все эпизоды в сезон.
Мы будем соответствовать каждому имени файла с рисунком Regex.
Если мы хотим найти для эпизода, то это может быть либо E01 или Episode01 или E12 или E1 Отказ
Увидеть что-нибудь подобное в вышесказанном?
Хорошо, в каждом из них начало письмо е и эпизод Часть не является обязательной, но опять необходимо, должно быть два числа, следующие за этими буквами, и в числах первая необязательна (В 01, 0 может не присутствовать все время), но требуется второй.
Таким образом, мы придумаем следующее Regex
'e(pisode)?[\ \.]?[0-9]?[0-9]'
Но опять же в случае сезона это будет
's(eason)?[\ \.]?[0-9]?[0-9]'
Мы преобразуем строки ниже, чтобы быть на безопасной стороне.
После того, как наша логика готова, мы можем просто определить две функции, которые соответственно вызывают эту функцию для эпизода и сезонов.
def _process_parent(self): """Process the parent directory and extract all the Seasons.""" season_list = [] for season in self.parent_dir.iterdir(): if season.is_dir(): season_list.append(season) return OrderedDict(sorted( self._get_all_match(season_list, "season") .items() ))
Здесь мы используем ЗаказДикт Потому что нам нужны сезоны в правильном порядке возрастающих чисел.
Сериализация данных
У нас есть еще одна проблема. Мы не можем просто хранить такие данные в файле JSON и вызовите его кэшированным.
Если мы сделаем вышеизложенное, нам придется снова найти следующий сезон/эпизод, и повторяя все данные (кэшированные).
Так вот вот что мы можем сделать.
Мы будем ссылаться на каждый сезон, используя номер сезона и каждый эпизод с его номером эпизода.
Мы храним данные в следующем формате
"3": { "1": "/home/deepjyoti30/Downloads/TAAHM/Two and a Half Men Season 3 720p MaRS/Two.and.a.Half.Men.S03E01.720p.WEB-DL-MaRS.mkv", "2": "/home/deepjyoti30/Downloads/TAAHM/Two and a Half Men Season 3 720p MaRS/Two.and.a.Half.Men.S03E02.720p.WEB-DL-MaRS.mkv", "3": "/home/deepjyoti30/Downloads/TAAHM/Two and a Half Men Season 3 720p MaRS/Two.and.a.Half.Men.S03E03.720p.WEB-DL-MaRS.mkv", "4": "/home/deepjyoti30/Downloads/TAAHM/Two and a Half Men Season 3 720p MaRS/Two.and.a.Half.Men.S03E04.720p.WEB-DL-MaRS.mkv", "5": "/home/deepjyoti30/Downloads/TAAHM/Two and a Half Men Season 3 720p MaRS/Two.and.a.Half.Men.S03E05.720p.WEB-DL-MaRS.mkv",
Мы можем сериализовать данные по следующей функции
def _serialize_data(self, series_data): """Serialize the data.""" serialized_data = {} for season_number, season_data in series_data.items(): for episode_number in range(0, len(season_data)): data_value = season_data[str(episode_number + 1)] if len(season_number) < 2: season_number = "0" + season_number if episode_number < 9: episode_number = "0" + str(episode_number + 1) else: episode_number = str(episode_number + 1) data_key = "{}{}".format(season_number, episode_number) serialized_data[data_key] = data_value return serialized_data
Мы также будем хранить текущий воспроизводимый эпизод в другом файле, который мы будем читать в начале сценария каждый раз.
Теперь, когда у нас есть данные, кэшированные последовательно, вот как сценарий выполняется после этой части
- Он загрузит кэшированные (сериализованные) данные.
- Он прочитал текущий эпизод
- Он будет воспроизводить текущий эпизод и подождать, пока внешний проигрыватель не возвращается
- Прочитайте следующий эпизод в сериализованных данных.
Например:
Если текущий эпизод 0106 Мы будем играть текущую и то, что сделано, мы просто получим следующий номер из файла JSON и снова позвоните в функцию проигрывателя.
2. Получить последний сыгранный
Это простая часть. Мы можем просто прочитать файл, который у нас есть последний игровой эпизод, хранящийся в.
Я храним файлы в ~/.cache каталог.
Кроме того, файл, содержащий текущий эпизод, имеет имя AS .Текущий и тот, который содержащий сериализованные данные, это .ряд
Мы можем прочитать данные, используя следующую функцию
# Read the JSON data with open(, 'r') as RSTREAM: data = json.load(RSTREAM) # Read the current episode current_epi = open( , 'r').read().replace("\n", "")
Вот как мы будем играть в файл
def _play(self, episode): """Play the passed episode.""" starting_epi = episode for it in self._cached_data: try: if it < starting_epi: continue print("[*] Playing {}".format(it)) self._save_current(it) self._mpv(self._cached_data[it]) except KeyboardInterrupt: print("[*] You watched till {}".format(it)) exit(0)
Мы обнаруживаем прерывание клавиатуры для выхода из скрипта.
3. Позвоните внешнему игроку
Я использую подпрокат Модуль, чтобы вызвать внешний проигрыватель.
Я использую MPV Поскольку он имеет встроенный вариант для возобновления воспроизведения на последней остановленной позиции.
Вот как мы позвоним игроку
def _mpv(self, path): """Call MPV and pass the path to play.""" call([ 'mpv', '--really-quiet', '--save-position-on-quit', '--resume-playback', path ])
Мы называем игроком с тремя аргументами, один – сохранить минимальный срок.
Другие два довольно явно объясняют.
Один из них заставит игрока сохранить позицию воспроизведения на выходе, а другой будет возобновить его с последней сохраненной точки.
Вывод
Первое первое, пиратство не круто.
Но затем Netflix просто не дает нам несколько серий, которые мы хотим посмотреть очень плохо, а когда это произойдет, получите серию из где-то а затем используйте этот скрипт, чтобы автоматизировать все.
Просто чтобы сделать все более простые, я также добавил функциональность, что путь к серии передается в качестве аргумента для скрипта.
Просто используйте Sys модуль для этого.
Хотя из-за вышеупомянутых, нам нужно добавить дополнительные проверки, чтобы посмотреть, являются ли пути действительны и прочее.
Весь скрипт можно найти здесь
Спасибо за чтение!
Я также пишу о технических вещах на моей личной странице. Считайте, что проверка постов там.
Оригинал: “https://dev.to/deepjyoti30/automate-watching-a-local-series-in-python-1aai”