From 8b24e294bf8143eee988f24bedc981386e70d7e7 Mon Sep 17 00:00:00 2001 From: Thisal Dilmith <93121062+Thisal-D@users.noreply.github.com> Date: Sat, 30 Nov 2024 03:58:35 +0530 Subject: [PATCH 1/2] Add files via upload --- PROJECT_STRUCTURE.md | 2 +- app.py | 40 ++++++++++++- contributors.txt | 3 +- data/appearance.json | 8 +-- data/general.json | 2 +- data/info.json | 2 +- data/languages/en.json | 3 +- data/languages/si.json | 3 +- data/languages/zh.json | 3 +- main.py | 11 +++- utils/__init__.py | 2 +- utils/data_retrive_utility.py | 67 ++++++++++++++++++++++ widgets/core_widgets/alert_window.py | 17 +++++- widgets/setting_panels/about_panel.py | 13 +++-- widgets/setting_panels/appearance_panel.py | 4 +- 15 files changed, 156 insertions(+), 24 deletions(-) create mode 100644 utils/data_retrive_utility.py diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md index 2f625e1..d4f2bf7 100644 --- a/PROJECT_STRUCTURE.md +++ b/PROJECT_STRUCTURE.md @@ -33,7 +33,7 @@ project_folder/
    │        ├── \_\_init\_\_.py
    │        ├── download_info_utility.py
    │        ├── file_utility.py
-    │        ├── git_hub_utility.py
+    │        ├── data_retrive_utility.py
    │        ├── gui_utils.py
    │        ├── image_utility.py
    │        ├── json_utility.py
diff --git a/app.py b/app.py index cc5c6a8..9fed86c 100644 --- a/app.py +++ b/app.py @@ -3,6 +3,7 @@ import tkinter as tk import threading import time +import webbrowser from typing import Literal import pyautogui from widgets import ( @@ -28,7 +29,9 @@ GeneralSettings, ) from utils import ( - FileUtility + FileUtility, + DataRetriveUtility, + GuiUtils ) @@ -1441,6 +1444,7 @@ def show_close_confirmation_dialog(self) -> None: ok_button_callback=self.on_app_closing, cancel_button_callback=self.cancel_app_closing, callback=self.cancel_app_closing, + wait_for_previous=True, width=int(450 * scale), height=int(130 * scale), ) @@ -1477,3 +1481,37 @@ def clear_temporally_saved_files(self) -> None: Clears temporarily saved files, such as thumbnails. """ FileUtility.delete_files("temp\\thumbnails", ["this directory is necessary"]) + + def open_update_download_page(self) -> None: + """ + Open website for download latest version + """ + webbrowser.open("https://sourceforge.net/projects/pytube-downloader/files/latest/download") + + def check_for_updates(self) -> None: + """ + Update the version of the application. + """ + # Check the app is updated or not + latest_version = DataRetriveUtility.get_latest_version() + current_version = DataRetriveUtility.get_current_version() + scale = AppearanceSettings.settings["scale_r"] + if latest_version is not None: + if latest_version != current_version: + AlertWindow( + master=self, + alert_msg="update_alert", + ok_button_display=True, + ok_button_callback=self.open_update_download_page, + cancel_button_display=True, + wait_for_previous=True, + width=int(450 * scale), + height=int(130 * scale) + ) + + def run_update_check(self): + """ + Run the update check in a separate thread. + """ + self.update_check_thread = threading.Thread(target=self.check_for_updates, daemon=True) + self.update_check_thread.start() diff --git a/contributors.txt b/contributors.txt index 4ccd47f..7bbe079 100644 --- a/contributors.txt +++ b/contributors.txt @@ -1,5 +1,4 @@ -CONTRIBUTORS INFO https://github.com/Thisal-D@%@Thisal Dilmith https://github.com/childeyouyu@%@youyu https://github.com/Navindu21@%@Navindu Pahasara -https://github.com/sooryasuraweera@%@Soorya Suraweera +https://github.com/sooryasuraweera@%@Soorya Suraweera \ No newline at end of file diff --git a/data/appearance.json b/data/appearance.json index 861bfb2..f366277 100644 --- a/data/appearance.json +++ b/data/appearance.json @@ -34,7 +34,7 @@ ] } }, - "opacity": 100.0, + "opacity": 100, "opacity_r": 1.0, "radio_btn": { "text_color": { @@ -51,8 +51,8 @@ "root": { "accent_color": { "default": true, - "hover": "#903efb", - "normal": "#7a14ff" + "hover": "#5f4ff1", + "normal": "#412ff0" }, "fg_color": { "hover": [ @@ -258,4 +258,4 @@ ] } } -} +} \ No newline at end of file diff --git a/data/general.json b/data/general.json index 5bcafa8..a654746 100644 --- a/data/general.json +++ b/data/general.json @@ -16,4 +16,4 @@ "reload_automatically": false, "update_delay": 0.5, "window_geometry": "900x500+0+0" -} +} \ No newline at end of file diff --git a/data/info.json b/data/info.json index bd51842..d357ded 100644 --- a/data/info.json +++ b/data/info.json @@ -3,4 +3,4 @@ "name": "PyTube Downloader", "site": "https://github.com/Thisal-D/PyTube-Downloader", "version": "2.0.2" -} +} \ No newline at end of file diff --git a/data/languages/en.json b/data/languages/en.json index 718a1de..0e16037 100644 --- a/data/languages/en.json +++ b/data/languages/en.json @@ -85,5 +85,6 @@ "quick_exit": "Quick Exit", "force_exit": "Force Exit", "minimize_to_tray": "Minimize To Tray", - "reset": "Reset" + "reset": "Reset", + "update_alert": "A new update is available! \nVisit the official website to download the \nlatest version." } diff --git a/data/languages/si.json b/data/languages/si.json index 3cdeaa2..f44586b 100644 --- a/data/languages/si.json +++ b/data/languages/si.json @@ -85,6 +85,7 @@ "quick_exit": "ඉක්මන් පිටවීම", "force_exit": "පිටවීම", "minimize_to_tray": "ට්‍රේ එකට Minimize කරන්න", - "reset": "නෑවත සකසන්න" + "reset": "නෑවත සකසන්න", + "update_alert": "නව අනුවාදයක් තිබේ!\nනවතම අනුවාදය බාගැනීමට කරුණාකර \nනිල වෙබ් අඩවියට පිවිසෙන්න." } \ No newline at end of file diff --git a/data/languages/zh.json b/data/languages/zh.json index 1912015..7dd537a 100644 --- a/data/languages/zh.json +++ b/data/languages/zh.json @@ -85,5 +85,6 @@ "quick_exit": "快速退出", "force_exit": "强制退出", "minimize_to_tray": "最小化到托盘", - "reset": "重置" + "reset": "重置", + "update_alert": "有新版本可用!\n请访问官方网站下载最新版本。" } diff --git a/main.py b/main.py index d6b9404..89a7e3d 100644 --- a/main.py +++ b/main.py @@ -13,7 +13,9 @@ LanguageManager, VideoCountTracker ) -from utils import FileUtility +from utils import ( + FileUtility +) # Initialize app. @@ -80,5 +82,10 @@ app.bind_widgets_events() # bind shortcut keys app.bind_keyboard_shortcuts() -# just rut the app +# Check app updates +app.run_update_check() +# just run the app app.run() + +# Codes under here will only execute when the app is closed + \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py index 2add71e..b35ddc4 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,6 +1,6 @@ from .download_info_utility import DownloadInfoUtility from .file_utility import FileUtility -from .git_hub_utility import GitHubUtility +from .data_retrive_utility import DataRetriveUtility from .json_utility import JsonUtility from .image_utility import ImageUtility from .settings_validate_utility import SettingsValidateUtility diff --git a/utils/data_retrive_utility.py b/utils/data_retrive_utility.py new file mode 100644 index 0000000..bb52a48 --- /dev/null +++ b/utils/data_retrive_utility.py @@ -0,0 +1,67 @@ +from urllib import request +import requests +from typing import List, Dict +from .json_utility import JsonUtility + + +class DataRetriveUtility: + CONTRIBUTORS_TEXT_URL = "https://raw.githubusercontent.com/Thisal-D/PyTube-Downloader/main/contributors.txt" + VERSION_FILE_URL = "https://raw.githubusercontent.com/Thisal-D/PyTube-Downloader/main/VERSION" + + @staticmethod + def get_contributors_data() -> List[Dict]: + """ + Retrieve contributors data from a GitHub repository. + + Returns: + list: A list of dictionaries containing contributor information. + """ + contributors = [] + try: + data = requests.get(DataRetriveUtility.CONTRIBUTORS_TEXT_URL).text + for contributor_data in data.split("\n"): + try: + profile_url, username = contributor_data.split("@%@") + contributors.append({ + "profile_url": profile_url, + "user_name": username, + }) + except Exception as error: + print(f"data_retrive_utility.py L54 : {error}") + except Exception as error: + print(f"data_retrive_utility.py L43 : {error}") + return None + + return contributors + + @staticmethod + def get_latest_version(): + """ + Retrieve latest version from a GitHub repository. + + Returns: + string: The latest version number. + """ + try: + data = requests.get(DataRetriveUtility.VERSION_FILE_URL).text.strip() + # Extract the version number from the string "VERSION = '2.0.2'" + # Split at "=" and remove extra characters like spaces and quotes + version = data.split('=')[1].strip().strip("'") + + except Exception as error: + print(f"data_retrive_utility.py L43 : {error}") + return None + + return version + + def get_current_version(): + """ + Read current version from info.json file. + + return: + string: current version + """ + version = JsonUtility.read_from_file("data\\info.json")["version"] + return version + + \ No newline at end of file diff --git a/widgets/core_widgets/alert_window.py b/widgets/core_widgets/alert_window.py index a50c831..adc71b6 100644 --- a/widgets/core_widgets/alert_window.py +++ b/widgets/core_widgets/alert_window.py @@ -1,11 +1,16 @@ import customtkinter as ctk +import time from PIL import Image from typing import Callable from settings import AppearanceSettings from services import LanguageManager - class AlertWindow(ctk.CTkToplevel): + """ + Use to track any alert windows running or not + """ + Running = False + def __init__( self, master: ctk.CTk = None, @@ -15,6 +20,7 @@ def __init__( cancel_button_display: bool = None, cancel_button_callback: Callable = None, callback: Callable = None, + wait_for_previous: bool = False, width: int = 400, height: int = 200): @@ -24,6 +30,14 @@ def __init__( width=width, height=height) + # If ensure_previous_closed is true, wait until the previous alert window is closed + if wait_for_previous: + while AlertWindow.Running : + time.sleep(0.5) + + # Start the alert window + AlertWindow.Running = True + scale = AppearanceSettings.settings["scale_r"] self.master: ctk.CTk = master @@ -106,6 +120,7 @@ def on_closing(self): self.unbind("") self.master.unbind("") self.destroy() + AlertWindow.Running = False if self.callback is not None: self.callback() diff --git a/widgets/setting_panels/about_panel.py b/widgets/setting_panels/about_panel.py index 30a434e..756b40c 100644 --- a/widgets/setting_panels/about_panel.py +++ b/widgets/setting_panels/about_panel.py @@ -6,7 +6,7 @@ import customtkinter as ctk from PIL import Image from utils import ( - GitHubUtility, + DataRetriveUtility, JsonUtility, FileUtility, ImageUtility, @@ -100,13 +100,14 @@ def __init__( scrollbar_fg_color=AppearanceSettings.settings["root"]["fg_color"]["normal"], fg_color=AppearanceSettings.settings["root"]["fg_color"]["normal"] ) - + self.disclaimer_label = ctk.CTkLabel( master=self, justify="left", text="", text_color=AppearanceSettings.settings["settings_panel"]["warning_color"]["normal"] ) + self.contribute_data_retrieve_status = None self.app_info: Dict = JsonUtility.read_from_file("data\\info.json") self.place_widgets() @@ -144,7 +145,7 @@ def configure_contributors_info(self): self.app_info["contributors"] = {} # retrieve contributors data from GitHub repo as list[dict] - contributors_data = GitHubUtility.get_contributors_data() + contributors_data = DataRetriveUtility.get_contributors_data() # if it success -> return Dict # if it fails -> return None if contributors_data is not None: @@ -280,13 +281,14 @@ def place_widgets(self): self.contributors_title_label.grid(row=3, column=0, padx=(100, 0), pady=(pady, 0), sticky="nw") self.dash4_label.grid(row=3, column=1, padx=(30, 30), pady=(pady, 0), sticky="nw") self.contributors_status_label.grid(row=3, column=2, pady=(pady, 0), sticky="w") + self.disclaimer_label.place(x=100, rely=1, y=-60 * scale) def set_widgets_sizes(self): scale = AppearanceSettings.settings["scale_r"] self.contributors_frame.configure(height=200 * scale, width=500 * scale) self.contributors_frame._scrollbar.grid_forget() - + def set_widgets_texts(self): self.name_title_label.configure(text=LanguageManager.data["name"]) self.version_title_label.configure(text=LanguageManager.data["version"]) @@ -297,6 +299,7 @@ def set_widgets_texts(self): elif self.contribute_data_retrieve_status is None: self.contributors_status_label.configure(text=LanguageManager.data["loading"]) self.disclaimer_label.configure(text=" " + LanguageManager.data["disclaimer"]) + def update_widgets_text(self): self.set_widgets_texts() @@ -320,5 +323,5 @@ def set_widgets_fonts(self): self.dash4_label.configure(font=title_font) self.contributors_status_label.configure(font=title_font) - value_font = ("Segoe UI", 13 * scale, "normal") + value_font = ("Segoe UI", int(13 * scale), "normal") self.disclaimer_label.configure(font=value_font) diff --git a/widgets/setting_panels/appearance_panel.py b/widgets/setting_panels/appearance_panel.py index 57f003b..1602981 100644 --- a/widgets/setting_panels/appearance_panel.py +++ b/widgets/setting_panels/appearance_panel.py @@ -201,8 +201,8 @@ def cancel_scale_settings_resetting(self): self.scale_value_label.configure(text=f"{AppearanceSettings.settings["scale"]} %") def reset_settings(self): - self.apply_theme_mode("Dark") - self.theme_combo_box.set("Dark") + self.apply_theme_mode(self.theme_combo_box.cget("values")[0]) + self.theme_combo_box.set(self.theme_combo_box.cget("values")[0]) if not self.accent_color_buttons[0].pressed: self.accent_color_buttons[0].on_mouse_enter_self('event') From 050b4fb07891e6413a381698b08c8a23c1bcac66 Mon Sep 17 00:00:00 2001 From: Thisal Dilmith <93121062+Thisal-D@users.noreply.github.com> Date: Sat, 30 Nov 2024 04:01:09 +0530 Subject: [PATCH 2/2] Update app.py --- app.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app.py b/app.py index 9fed86c..d66785b 100644 --- a/app.py +++ b/app.py @@ -30,8 +30,7 @@ ) from utils import ( FileUtility, - DataRetriveUtility, - GuiUtils + DataRetriveUtility )