From d96d22381dfeca3c3dce34dfadb0e4965811d86d Mon Sep 17 00:00:00 2001 From: shibaisdog Date: Mon, 18 Nov 2024 17:48:50 +0900 Subject: [PATCH] load playlist You can load playlist songs --- requirements.txt | 3 ++- setting.json | 3 +++ src/down/download.py | 14 +++++++++++++- src/gui.py | 34 ++++++++++++++++++++++++++++++++-- src/utils/json.py | 19 +++++++++++++++++++ src/win/setting.py | 26 ++++++++++++++++++++++++-- 6 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 setting.json create mode 100644 src/utils/json.py diff --git a/requirements.txt b/requirements.txt index ee993a7..2e80ab9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ chardet == 5.2.0 pytubefix == 7.1rc2 pyvidplayer2 == 0.9.24 opencv-python == 4.6.0.66 -moviepy == 1.0.3 \ No newline at end of file +moviepy == 1.0.3 +yt_dlp == 2024.8.6 \ No newline at end of file diff --git a/setting.json b/setting.json new file mode 100644 index 0000000..8c2348f --- /dev/null +++ b/setting.json @@ -0,0 +1,3 @@ +{ + "volume": 10 +} \ No newline at end of file diff --git a/src/down/download.py b/src/down/download.py index 9e95c60..306a8f3 100644 --- a/src/down/download.py +++ b/src/down/download.py @@ -1,4 +1,4 @@ -import os,pygame,shutil +import os,pygame,shutil,yt_dlp from pytubefix import YouTube,Search from pytubefix.cli import on_progress #################################### @@ -34,6 +34,18 @@ def search(q:str,result:int): list = Search(query=q) return list.videos +def get_playlist_video(playlist_url): + ydl_opts = { + 'extract_flat': True, + 'force_generic_extractor': True, + } + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + result = ydl.extract_info(playlist_url, download=False) + if 'entries' in result: + return [entry['url'] for entry in result['entries']] + else: + return [] + def search_infos(videos): res = [] for video in videos: diff --git a/src/gui.py b/src/gui.py index bdb711b..4bce77e 100644 --- a/src/gui.py +++ b/src/gui.py @@ -30,6 +30,9 @@ class VideoState: def is_url(url: str) -> bool: match = re.search(src.win.setting.SEARCH_PATTERN, url) return bool(match) +def is_playlist(url: str) -> bool: + match = re.search(src.win.setting.PLAYLIST_SEARCH_PATTERN, url) + return bool(match) def frame_to_ascii(frame, width=100): """ @@ -83,7 +86,7 @@ def handle_key_event(key: str) -> None: """ if not key: return - + if key == "r": src.win.screen.vid.restart() state.msg_text = "Restarted" @@ -99,7 +102,7 @@ def handle_key_event(key: str) -> None: elif key in ["up", "down"]: volume_delta = 10 if key == "up" else -10 if 0 <= src.win.setting.volume + volume_delta <= 100: - src.win.setting.volume += volume_delta + src.win.setting.change_setting_data('volume',src.win.setting.volume + volume_delta) src.win.screen.vid.set_volume(src.win.setting.volume/100) state.msg_text = f"Volume: {src.win.setting.volume}%" elif key in ["right", "left"]: @@ -290,6 +293,33 @@ def wait(): src.win.screen.win.blit(text_surface, text_rect) pygame.display.update() if key == "enter" or key == "return": + # TEST URL 'https://youtube.com/playlist?list=PLWe0uF1Zfq3K4ao8lvh2fM3NDqBAxhdaZ&si=JO4TZBYAokbwWzHe' + if is_playlist(state.search): + video_urls = download.get_playlist_video(state.search) + src.win.setting.video_list.extend(video_urls) + trys = 0 + while len(src.win.setting.video_list) != 0: + try: + run(src.win.setting.video_list[0]) + src.win.setting.video_list.remove(src.win.setting.video_list[0]) + except Exception as e: + if src.win.screen.vid == None: + src.win.screen.reset((state.search_width, state.search_height)) + else: + src.win.screen.reset((src.win.screen.vid.current_size[0],src.win.screen.vid.current_size[1]+5), vid=True) + if trys >= 10: + print("fail") + break + print(f"An error occurred during playback. Trying again... ({trys}/10) > \n{e}") + text_surface = src.win.screen.font.render(f"An error occurred during playback. Trying again... ({trys}/10) >", True, (255,255,255)) + text_surface_2 = src.win.screen.font.render(f"{e}", True, (255,255,255)) + text_rect = text_surface.get_rect(center=(src.win.screen.win.get_size()[0]/2,src.win.screen.win.get_size()[1]/2)) + text_rect_2 = text_surface_2.get_rect(center=(src.win.screen.win.get_size()[0]/2,src.win.screen.win.get_size()[1]/2+30)) + src.win.screen.win.blit(text_surface, text_rect) + src.win.screen.win.blit(text_surface_2, text_rect_2) + pygame.display.flip() + time.sleep(0.5) + trys += 1 if is_url(state.search): a = state.search state.search = "" diff --git a/src/utils/json.py b/src/utils/json.py new file mode 100644 index 0000000..97caacb --- /dev/null +++ b/src/utils/json.py @@ -0,0 +1,19 @@ +import json + +def read(file_path): + """read json file""" + try: + with open(file_path, 'r', encoding='utf-8') as file: + return json.load(file) + except FileNotFoundError: + return None + except json.JSONDecodeError: + return None + +def write(file_path, data): + """write json file""" + try: + with open(file_path, 'w', encoding='utf-8') as file: + json.dump(data, file, ensure_ascii=False, indent=4) + except Exception as e: + print(f"Error: 파일 저장 중 오류가 발생했습니다. {e}") \ No newline at end of file diff --git a/src/win/setting.py b/src/win/setting.py index 1193a0f..e7e9d2d 100644 --- a/src/win/setting.py +++ b/src/win/setting.py @@ -1,10 +1,32 @@ -volume = 10 +import src.utils.json as json +json_file_path = "./setting.json" +def init_file(): + data = {} + data['volume'] = 10 + return data +def change_setting_data(key:str,value): + data = json.read(json_file_path) + if data == None: + data = init_file() + data[key] = value + json.write(json_file_path,data) + reload_setting_file() +def reload_setting_file(): + global volume + data = json.read(json_file_path) + if data == None: + data = init_file() + json.write(json_file_path,data) + volume = data['volume'] +volume = None loop = False video_list = [] SEARCH_PATTERN = r"(?:v=|\/)([0-9A-Za-z_-]{11}).*" +PLAYLIST_SEARCH_PATTERN = r"(?:list=)([A-Za-z0-9_-]{34})" MESSAGE_DISPLAY_TIME = 2.0 ASCII_CHARS = ["$", "@", "B", "%", "8", "&", "W", "M", "#", "*", "o", "a", "h", "k", "b", "d", "p", "q", "w", "m", "Z", "O", "0", "Q", "L", "C", "J", "U", "Y", "X", "z", "c", "v", "u", "n", "x", "r", "j", "f", "t", "/", "\\", "|", "(", ")", "1", "{", "}", "[", "]", "?", "-", "_", "+", "~", "<", ">", "i", "!", "l", "I", ";", ":", ",", - "\"", "^", "`", "'", ".", " "] \ No newline at end of file + "\"", "^", "`", "'", ".", " "] +reload_setting_file() \ No newline at end of file