diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ef28a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +config.json +__pycache__/ +update/ +build/ +*.spec +*.bin +*.build +dist +data/config.json +*.dist +*.onefile-build +downloaded_files/ +my_app_github/ +my_app_gitlab/ +data-backup/ \ No newline at end of file diff --git a/build.bat b/build.bat new file mode 100755 index 0000000..03b6ebc --- /dev/null +++ b/build.bat @@ -0,0 +1,3 @@ +nuitka3 ./src/main.py --clean-cache=all --onefile --run --output-dir=./build --enable-plugin=tk-inter +:: --clean-cache=all --disable-console --windows-icon-from-ico=./data/icon.ico +pause \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..bae3388 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +nuitka3 ./src/main.py --linux-onefile-icon=./data/icon.png --onefile --output-dir=./build --run +#--disable-console --linux-icon=./data/icon.png --output-dir=./build --clean-cache=all #--include-plugin-directory=./src/ --run --disable-console --linux-icon=./data/icon.png --output-dir=./build #--clean-cache=all --recompile-c-only #--windows-icon-from-ico=./data/icon.ico --disable-console --linux-icon=./data/icon.png --onefile --output-dir=./build \ No newline at end of file diff --git a/dwnld.sh b/dwnld.sh new file mode 100755 index 0000000..979428e --- /dev/null +++ b/dwnld.sh @@ -0,0 +1,34 @@ +#!/bin/sh +set -e + +display_usage() { + echo "Downloads all of a SourceForge project's files." + echo -e "\nUsage: ./sourceforge-file-download.sh [project name]\n" +} + +if [ $# -eq 0 ] +then + display_usage + exit 1 +fi + +project=$1 +echo "Downloading $project's files" + +# download all the pages on which direct download links are +# be nice, sleep a second +wget -w 1 -np -m -A download https://sourceforge.net/projects/$project/files/ + +# find the files (ignore "latest" link, that should be included as another URL already) +find sourceforge.net/ | sed "s#.*${project}/files/##" | grep download$ | grep -v "latest/download" | sed -e "s#^#https://master.dl.sourceforge.net/project/${project}/#" -e "s#/download#?viasf=1#" > urllist + +# download each of the extracted URLs, put into $projectname/ +while read url; do wget --content-disposition -x -nH --cut-dirs=1 "${url}"; done < urllist + +# remove ?viasf=1 suffix +find . -name '*?viasf=1' -print0 | xargs -0 rename --verbose "?viasf=1" "" + +# remove temporary files, unless you want to keep them for some reason +rm -ri sourceforge.net/ +rm -i urllist + diff --git a/install-linux.sh b/install-linux.sh new file mode 100755 index 0000000..f90e065 --- /dev/null +++ b/install-linux.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# This script installs required dependencies on Linux + +# Update package lists and install Python3 +sudo apt update -y +sudo apt install python3 -y + +# Install Python3 pip +sudo apt install python3-pip -y + +# Install GTK4 package +sudo apt install libgtk-4-dev -y + +# Install PatchELF for Nuitka (if needed) +sudo apt install patchelf -y + +# Install Nuitka +pip3 install nuitka + +# Install additional Python packages +pip3 install requests +sudo apt install libgirepository1.0-dev -y +sudo apt install python3-cairo-dev -y +pip3 install PyGObject # Install PyGObject for Gtk support +pip3 install pillow # Install Pillow for image manipulation +pip3 install setuptools # Install setuptools for packaging + +# Install ccache for faster re-compiling +sudo apt install ccache -y diff --git a/install-windows.txt b/install-windows.txt new file mode 100755 index 0000000..b66c8d2 --- /dev/null +++ b/install-windows.txt @@ -0,0 +1,13 @@ +# install msys2 + +# update msys2 + +# install python && pip in msys2 + +# install GTK4 according to GTK website + +# install nuitka (in msys2) + +# add python (usually: C:\msys2\bin) to system variable PATH + +# restart computer, and if done well you should be able to build and run this app \ No newline at end of file diff --git a/run.bat b/run.bat new file mode 100644 index 0000000..cd12ee0 --- /dev/null +++ b/run.bat @@ -0,0 +1,3 @@ +python3 ./src/main.py +:: --clean-cache=all --disable-console --windows-icon-from-ico=./data/icon.ico +pause \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..97b767a --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +python3 ./src/main.py \ No newline at end of file diff --git a/src/donwload_sourceforege.py b/src/donwload_sourceforege.py new file mode 100644 index 0000000..7024cbf --- /dev/null +++ b/src/donwload_sourceforege.py @@ -0,0 +1,29 @@ +import requests +from tqdm import tqdm + +# not exactly ideal solution + +def download_from_sourceforge(api_url, file_path): + response = requests.get(api_url, stream=True) + + if response.status_code == 200: + total_size = int(response.headers.get('content-length', 0)) + block_size = 1024 # 1 KB + progress_bar = tqdm(total=total_size, unit='B', unit_scale=True) + + with open(file_path, 'wb') as file: + for data in response.iter_content(block_size): + progress_bar.update(len(data)) + file.write(data) + + progress_bar.close() + + print("Download completed successfully.") + else: + print(f"Failed to download. Status code: {response.status_code}") + +# Example usage with the provided link +sourceforge_api_url = "https://downloads.sourceforge.net/project/sevenzip/7-Zip/19.00/7z1900-x64.exe" +download_path = "7z1900-x64.exe" + +download_from_sourceforge(sourceforge_api_url, download_path) diff --git a/src/download_github.py b/src/download_github.py new file mode 100644 index 0000000..d12f351 --- /dev/null +++ b/src/download_github.py @@ -0,0 +1,80 @@ +import os +import requests +from tqdm import tqdm + +def fetch_release_version(url): + try: + response = requests.get(url) + response.raise_for_status() + return response.json()['tag_name'] + except requests.exceptions.RequestException as e: + print(f"Error fetching release version: {str(e)}") + return None + +def download_from_github(url, destination, progress_bar, version): + # Get the latest release information + api_url = f"{url}/releases/latest" + response = requests.get(api_url) + response.raise_for_status() + release_info = response.json() + + latest_version = release_info["tag_name"] + + # Check if the latest version is different from the current version + if latest_version != version: + # Get the asset URL for the first asset in the release (you may modify this based on your needs) + asset_url = release_info["assets"][0]["browser_download_url"] + + # Download the asset with a progress bar + response = requests.get(asset_url, stream=True) + response.raise_for_status() + + # Calculate the total file size for the progress bar + total_size = int(response.headers.get('content-length', 0)) + + # Create the destination directory if it doesn't exist + os.makedirs(destination, exist_ok=True) + + # Define the file path for the downloaded asset + file_path = os.path.join(destination, os.path.basename(asset_url)) + + with open(file_path, 'wb') as file, tqdm( + desc="Downloading", + total=total_size, + unit="B", + unit_scale=True, + unit_divisor=1024, + disable=not progress_bar, + ) as bar: + for data in response.iter_content(chunk_size=1024): + bar.update(len(data)) + file.write(data) + + print("Download complete.") + return latest_version + else: + print("You already have the latest version.") + return version + +def download_from_url(url, destination, progress_bar, version): + if "github.com" in url: + return download_from_github(url, destination, progress_bar, version) + elif "sourceforge.net" in url: + return download_from_sourceforge(url, destination, progress_bar) + elif "gitlab.com" in url: + return download_from_gitlab(url, destination, progress_bar) + elif "gitea.com" in url: + return download_from_gitea(url, destination, progress_bar) + else: + print("Unsupported platform") + return None + +####################### + +# # Example usage: +# github_url = "https://api.github.com/repos/emoacht/Monitorian" +# destination_folder = "./downloaded_files" +# current_version = "v1.0.0" + +# new_version = download_from_github(github_url, destination_folder, True, current_version) +# print(f"Updated to version: {new_version}") diff --git a/src/download_gitlab.py b/src/download_gitlab.py new file mode 100644 index 0000000..ddd703e --- /dev/null +++ b/src/download_gitlab.py @@ -0,0 +1,119 @@ +import requests +from tqdm import tqdm +import os +import zipfile + +def download_release_from_gitlab(api_url, project_id, token, destination, progress_bar, version): + # Get the latest release information + response = requests.get(f"{api_url}/projects/{project_id}/releases", headers={"PRIVATE-TOKEN": token}) + response.raise_for_status() + + releases = response.json() + + # Check if there are any releases + if not releases: + return None + + # Assuming releases are sorted by creation date, so the latest release is the first one + latest_release = releases[0] + latest_version = latest_release["tag_name"] + + # Check if the latest version is different from the current version + if latest_version != version: + # Get the asset URL for the first asset in the release (you may modify this based on your needs) + asset_url = latest_release["assets"]["sources"][0]["url"] + + # Download the asset with a progress bar + response = requests.get(asset_url, stream=True, headers={"PRIVATE-TOKEN": token}) + response.raise_for_status() + + # Calculate the total file size for the progress bar + total_size = int(response.headers.get('content-length', 0)) + + # Create the destination directory if it doesn't exist + os.makedirs(destination, exist_ok=True) + + # Define the file path for the downloaded asset + file_path = os.path.join(destination, os.path.basename(asset_url)) + + with open(file_path, 'wb') as file, tqdm( + desc="Downloading", + total=total_size, + unit="B", + unit_scale=True, + unit_divisor=1024, + disable=not progress_bar, + ) as bar: + for data in response.iter_content(chunk_size=1024): + bar.update(len(data)) + file.write(data) + + print("Download complete.") + return latest_version + else: + print("You already have the latest version.") + return version + +def download_source_from_gitlab(api_url, project_id, token, destination, progress_bar): + # Construct the source code repository URL based on the project ID + repository_url = f"{api_url}/projects/{project_id}/repository/archive.zip" + + # Download the source code as a ZIP file + response = requests.get(repository_url, stream=True, headers={"PRIVATE-TOKEN": token}) + response.raise_for_status() + + # Create the destination directory if it doesn't exist + os.makedirs(destination, exist_ok=True) + + # Define the file path for the downloaded ZIP file + zip_file_path = os.path.join(destination, "source_code.zip") + + with open(zip_file_path, 'wb') as file, tqdm( + desc="Downloading Source Code", + unit="B", + unit_scale=True, + unit_divisor=1024, + disable=not progress_bar, + ) as bar: + for data in response.iter_content(chunk_size=1024): + bar.update(len(data)) + file.write(data) + + print("Download complete.") + + # Extract the ZIP file + extract_folder = os.path.join(destination, "source_code") + with zipfile.ZipFile(zip_file_path, 'r') as zip_ref: + zip_ref.extractall(extract_folder) + + # Remove the ZIP file + os.remove(zip_file_path) + + return extract_folder + +def download_and_update(api_url, project_id, private_token, destination_folder, progress_bar, current_version): + try: + new_version = download_release_from_gitlab(api_url, project_id, private_token, destination_folder, progress_bar, current_version) + if new_version: + print(f"Updated to version: {new_version}") + else: + print("No releases found. Downloading source code instead.") + source_code_folder = download_source_from_gitlab(api_url, project_id, private_token, destination_folder, progress_bar) + print(f"Source code downloaded to: {source_code_folder}") + except requests.exceptions.HTTPError as e: + if e.response.status_code == 404: + print("No releases found. Downloading source code instead.") + source_code_folder = download_source_from_gitlab(api_url, project_id, private_token, destination_folder, progress_bar) + print(f"Source code downloaded to: {source_code_folder}") + else: + raise # Re-raise the exception if it's not a 404 error + +# ####################################### +# # Example usage: +# gitlab_api_url = "https://gitlab.com/api/v4" +# project_id = 5774889 # Use the project ID directly +# private_token = "" # No private token needed for public projects +# destination_folder = "./downloaded_files" +# current_version = "v1.0.0" + +# download_and_update(gitlab_api_url, project_id, private_token, destination_folder, True, current_version) diff --git a/src/download_main.py b/src/download_main.py new file mode 100644 index 0000000..a476223 --- /dev/null +++ b/src/download_main.py @@ -0,0 +1,71 @@ +import os +from tqdm import tqdm # You might need to install this package using pip if not already installed + +import json +import json_main +import download_gitlab +import download_github + +data_location = "./data/" + +# Ensure that the directory structure exists, once again +if not os.path.exists(data_location): + os.makedirs(data_location) + +# Check if config.json exists and create it with default values if not +if not os.path.isfile(data_location+"config.json"): + default_data = { + "first_run": "false", + "packages": [] + } + with open(data_location+"config.json", "w") as json_file: + json.dump(default_data, json_file, indent=4) + +# Placeholder functions for SourceForge and Gitea +def download_from_sourceforge(url, destination, progress_bar, version): + # Placeholder function for downloading from SourceForge + print("Sourceforge not supported yet") + +def download_from_gitea(api_url, project_id, token, destination, progress_bar, version): + # Placeholder function for downloading from Gitea + print("Gita not supported, yet") + +# Function to install all packages +def install_all_packages(progress_bar, progress_label): + try: + with open(data_location+"config.json", 'r') as file: + data = json.load(file) + packages = data.get("packages", []) + total_packages = len(packages) + + for index, package in enumerate(packages, start=1): + app_name, app_data = package.popitem() + source_info = app_data.get("source", {}) + source_type = source_info.get("source_type", "") + version = app_data.get("version", "") + + try: + progress_label.set_text(f"Downloading {app_name}") + progress_value = index / total_packages/2 + progress_bar.set_fraction(progress_value) + + if source_type == "github": + download_github.download_from_github(source_info["github_url"], app_name, tqdm, version) + elif source_type == "gitlab": + download_gitlab.download_and_update(source_info["gitlab_api_url"], source_info["project_id"], + source_info["private_token"], app_name, tqdm, version) + # Add other source types as needed + else: + progress_label.set_text(f"Unsupported source type for {app_name}: {source_type}") + print(f"Unsupported source type for {app_name}: {source_type}") + except Exception as e: + progress_label.set_text(f"Error processing {app_name}: {e}") + print(f"Error processing {app_name}: {e}") + except FileNotFoundError: + progress_label.set_text(f"Config file not found.") + print("Config file not found.") + + +# Check if the script is executed directly +if __name__ == "__main__": + install_all_packages() \ No newline at end of file diff --git a/src/gui_main.py b/src/gui_main.py new file mode 100644 index 0000000..fd10b3b --- /dev/null +++ b/src/gui_main.py @@ -0,0 +1,212 @@ +import gi +gi.require_version('Gtk', '4.0') +from gi.repository import Gtk, Gio, GLib, GdkPixbuf +import threading + +import download_main + +number_of_tabs = 4 + +class InstallerGUI: + def __init__(self): + self.app = Gtk.Application(application_id="org.example.customizableapp", + flags=Gio.ApplicationFlags.FLAGS_NONE) + self.app.connect("activate", self.activate) + + def run(self): + self.app.run() + + def activate(self, app): + app_window = MainWindow(application=app) + app_window.present() + +class UpdaterGUI(Gtk.Box): + def __init__(self): + super().__init__(orientation=Gtk.Orientation.VERTICAL) + + # Create a progress bar and a label + self.progress_bar = Gtk.ProgressBar() + self.progress_label = Gtk.Label() + + # # Set up the layout + # logo_path = "./data/icon.png" + # logo_pixbuf = GdkPixbuf.Pixbuf.new_from_file(logo_path) + # logo_image = Gtk.Image.new_from_pixbuf(logo_pixbuf) + + # self.append(logo_image) + self.append(self.progress_bar) + self.append(self.progress_label) + + # Connect to the "realize" signal to run the function when the widget becomes visible + self.connect("realize", self.on_realize) + + def on_realize(self, widget): + # Run the install_all_packages function in a separate thread when the widget becomes visible + threading.Thread(target=self.run_installation).start() + + def run_installation(self): + # Pass the progress bar and label to the install_all_packages function + download_main.install_all_packages(self.progress_bar, self.progress_label) + # Glib.idle_add() ? + + +class CustomizationTab(Gtk.Box): + def __init__(self, button_box): + super().__init__(orientation=Gtk.Orientation.VERTICAL, spacing=6) + self.create_ui(button_box) + + def create_ui(self, button_box): + # Add elements for customization tab in the future + + # Add back and next buttons at the bottom + self.bottom_buttons(button_box) + + def bottom_buttons(self, button_box): + self.append(Gtk.Box(hexpand=True, vexpand=True)) # Expandable empty box to push buttons to the bottom + self.append(button_box) + +class MainWindow(Gtk.ApplicationWindow): + def __init__(self, application, **kwargs): + super().__init__(application=application, **kwargs) + + # # Set Adwaita theme + # settings = Gtk.Settings.get_default() + # settings.set_property("gtk-application-prefer-dark-theme", True) + # settings.set_property("gtk-theme-name", "Adwaita") + + self.set_default_size(600, 400) + self.set_title("Spitfire Installer Nightly") + + self.child_names = ["Main", "Customization", "Tab 2", "Tab 3", "Tab 4","UpdaterGUI"] + + self.stack = Gtk.Stack(transition_type=Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) + self.stack.set_transition_duration(1000) # Set the duration of the transition in milliseconds + + # Create a HeaderBar + header_bar = Gtk.HeaderBar() + header_bar.set_show_title_buttons(True) + self.set_titlebar(header_bar) + + # First tab + self.add_first_tab() + + # Second tab (Customization tab) + button_box = self.create_button_box(0) + self.customization_tab = CustomizationTab(button_box) + self.stack.add_titled(self.customization_tab, "Customization", "Customization") + + # Third to Fifth tabs (empty for now) + for i in range(3): + self.add_tab(i + 1) + + # Last tab (Installer tab) + self.updater_tab = UpdaterGUI() + self.stack.add_titled(self.updater_tab, "UpdaterGUI", "UpdaterGUI") + + self.set_child(self.stack) + + self.show() + + def create_button_box(self, current_tab): + button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6) + left_button = Gtk.Button(label="Back") + left_button.connect("clicked", self.on_back_clicked) + + right_button = Gtk.Button(label="Next") + right_button.connect("clicked", self.on_next_clicked) + + label = Gtk.Label(label=f"{current_tab + 1} / {number_of_tabs}") # Display current tab number + label.set_halign(Gtk.Align.CENTER) # Center-align the label + + # Add an empty box to act as a flexible space + button_box.append(Gtk.Box(hexpand=True)) + + # Add left button, label, and right button to the button box + button_box.append(left_button) + button_box.append(label) + button_box.append(right_button) + + return button_box + + def add_first_tab(self): + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) + self.stack.add_titled(box, "Main", "Main") + + label = Gtk.Label(label=f"\nThis is an experimental (Nightly) build.") + box.append(label) + + empty_space = Gtk.Box(vexpand=True) + box.append(empty_space) # Expandable empty box to push buttons to the bottom + + skip_button = Gtk.Button(label="Install") + skip_button.connect("clicked", self.on_skip_clicked) + box.append(skip_button) # Use append to add child widgets + + customize_button = Gtk.Button(label="Customize") + customize_button.connect("clicked", self.on_next_clicked) + box.append(customize_button) # Use append to add child widget + + empty_space = Gtk.Box(vexpand=True) + box.append(empty_space) # Expandable empty box to push buttons to the bottom + + def add_tab(self, current_tab): + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) + self.stack.add_titled(box, f"Tab {current_tab + 1}", f"Tab {current_tab + 1}") + + # Add back and next buttons at the bottom + self.bottom_buttons(box, current_tab) + + def bottom_buttons(self, box, current_tab): + button_box = self.create_button_box(current_tab) + box.append(Gtk.Box(hexpand=True, vexpand=True)) # Expandable empty box to push buttons to the bottom + box.append(button_box) + + def on_skip_clicked(self, button): + current_page_name = "UpdaterGUI" + current_page_index = self.child_names.index(current_page_name) + next_page_index = number_of_tabs+1 + + if next_page_index < len(self.child_names): + next_page_name = self.child_names[next_page_index] + next_page = self.stack.get_child_by_name(next_page_name) + self.stack.set_visible_child(next_page) + + def on_next_clicked(self, button): + current_page_name = self.stack.get_visible_child_name() + current_page_index = self.child_names.index(current_page_name) + next_page_index = current_page_index + 1 + + if next_page_index < len(self.child_names): + next_page_name = self.child_names[next_page_index] + next_page = self.stack.get_child_by_name(next_page_name) + self.stack.set_visible_child(next_page) + + def on_back_clicked(self, button): + current_page_name = self.stack.get_visible_child_name() + current_page_index = self.child_names.index(current_page_name) + prev_page_index = current_page_index - 1 + + if prev_page_index >= 0: + prev_page_name = self.child_names[prev_page_index] + prev_page = self.stack.get_child_by_name(prev_page_name) + self.stack.set_visible_child(prev_page) + + def update_logo_and_title(self, page_name): + # Update title label text + self.title_label.set_label(page_name) + + # Update logo image based on the page name + logo_path = f"./data/{page_name.lower()}_icon.png" # Assuming you have different icons for each page + logo_pixbuf = GdkPixbuf.Pixbuf.new_from_file(logo_path) + self.logo_and_title_box.get_children()[0].set_from_pixbuf(logo_pixbuf) + +# Make the MainWindow class callable as a function +def run_installer(): + app = Gtk.Application(application_id="org.example.customizableapp", + flags=Gio.ApplicationFlags.FLAGS_NONE) + app.connect("activate", lambda app: MainWindow(application=app)) + app.run() + +# # Run the installer when this script is executed directly +# if __name__ == "__main__": +# run_installer() \ No newline at end of file diff --git a/src/json_main.py b/src/json_main.py new file mode 100644 index 0000000..d3f1b0c --- /dev/null +++ b/src/json_main.py @@ -0,0 +1,110 @@ +import json +import os + +data_location = "./data/config.json" + +def save_first_run(var): + with open(data_location, "r") as json_file: + data = json.load(json_file) + data["first_run"] = var + with open(data_location, "w") as json_file: + json.dump(data, json_file, indent=4) + + +def get_first_run(): + with open(data_location, "r") as json_file: + data = json.load(json_file) + return data["first_run"] + +# Save variable app to .json file with version, source, and source_type as variables +def save_package(version, app, source_type, source_info, package_type): + try: + with open(data_location, 'r') as file: + data = json.load(file) + except FileNotFoundError: + # If the file doesn't exist, create an empty dictionary + data = {"packages": []} + + # Create or update the category for the given app + app_data = { + "version": version, + "source": { + "source_type": source_type, + **source_info + }, + "state": "not installed", + "type": package_type + } + + data["packages"].append({app: app_data}) + + with open(data_location, 'w') as file: + json.dump(data, file, indent=2) + +# This function will get the package information for the given app. +# If the app is not in .json, return an empty dictionary. +def get_package(app): + try: + with open(data_location, 'r') as file: + data = json.load(file) + for package in data.get("packages", []): + if app in package: + return package[app] + except FileNotFoundError: + return {} + + + +# ###################### +# # save package test + +# # Example usage: +# # Define source information for GitHub +# github_source_info = { +# "github_url": "https://api.github.com/repos/emoacht/Monitorian" +# } + +# # Define source information for GitLab +# gitlab_source_info = { +# "gitlab_api_url": "https://gitlab.com/api/v4", +# "project_id": 5774889, +# "private_token": "" # No private token needed for public projects +# } + +# # Define source information for Gitea +# gitea_source_info = { +# # Add gitea-specific information here +# } + +# # Define source information for SourceForge +# sourceforge_source_info = { +# # Add sourceforge-specific information here +# } + +# # Save package information for GitHub +# save_package("1.0", "my_app_github", "github", github_source_info, "addon") + +# # Save package information for GitLab +# save_package("1.0", "my_app_gitlab", "gitlab", gitlab_source_info, "skin") + +# # Save package information for Gitea +# save_package("1.0", "my_app_gitea", "gitea", gitea_source_info, "config") + +# # Save package information for SourceForge +# save_package("1.0", "my_app_sourceforge", "sourceforge", sourceforge_source_info, "panel") + + +# ######################### +# # get package test + +# # Get package information for GitHub +# package_info = get_package("my_app_github") + +# # Example of accessing package information +# if package_info: +# print(f"Your package version is: {package_info['version']}") +# print(f"Your package source type is: {package_info['source']['source_type']}") +# print(f"Your package state is: {package_info['state']}") +# print(f"Your package type is: {package_info['type']}") +# else: +# print("Package not found.") \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..0e8782a --- /dev/null +++ b/src/main.py @@ -0,0 +1,143 @@ +import sys + +if sys.platform == 'win32': + import os + import tkinter as tk + from tkinter import ttk + from urllib.request import urlopen + import zipfile + import certifi + import ssl + import subprocess + import tempfile + +def get_temp_folder(): + # Get the current user's temporary directory + temp_dir = tempfile.gettempdir() + + # Create a subdirectory inside the temporary directory + user_temp_folder = os.path.join(temp_dir, 'my_temp_folder') + + # Create the directory if it doesn't exist + if not os.path.exists(user_temp_folder): + os.makedirs(user_temp_folder) + + return user_temp_folder + +def download_file(url, destination, progress_callback=None): + context = ssl.create_default_context(cafile=certifi.where()) + + with urlopen(url, context=context) as response, open(destination, 'wb') as out_file: + total_size = int(response.headers.get('content-length', 0)) + block_size = 1024 + current_size = 0 + while True: + buffer = response.read(block_size) + if not buffer: + break + out_file.write(buffer) + current_size += len(buffer) + if progress_callback: + progress_callback(current_size, total_size) + +def extract_zip(zip_file, extract_path): + with zipfile.ZipFile(zip_file, 'r') as zip_ref: + zip_ref.extractall(extract_path) + +def download_gtk_dlls(download_path, dll_url, dll_files, progress_callback=None): + + for dll_file in dll_files: + file_url = dll_url + dll_file + + # Check if the file already exists, if not, download it + if not os.path.exists(os.path.join(download_path, dll_file)): + download_file(file_url, os.path.join(download_path, dll_file), progress_callback) + + # Check if the downloaded file is a zip file, extract it, and remove the zip file + if dll_file.endswith('.zip'): + extract_path = os.path.join(download_path, dll_file.replace('.zip', '')) + extract_zip(os.path.join(download_path, dll_file), extract_path) + os.remove(os.path.join(download_path, dll_file)) + +def set_path_variable(download_path): + + current = subprocess.run("echo %Path%", stdout=subprocess.PIPE, shell=True, text=True) + + output_string = str(current.stdout).strip() + ';' + download_path + + # Split the output_string into individual elements + elements = output_string.split(';') + + # Remove duplicates + unique_elements = list(set(elements)) + + # Join the unique elements back together + output_string_unique = ';'.join(unique_elements) + + # Refresh the system environment variables + subprocess.run("SETX Path " + output_string_unique, shell=True) + + print(f"Added PATH: {output_string_unique}") + +def main(): + # Skips entier program if is a different system than windows + if sys.platform != 'win32': + from gui_main import run_installer + run_installer() + return + + # Replace this with the desired download path + download_path = get_temp_folder() + + dll_url = 'https://downloads.sourceforge.net/project/spitfire-browser/nightly/components/GTK4/' + + # Check if all required files are already present + dll_files = [ + 'libs.zip' + # Add more files as needed + ] + + all_files_exist = all(os.path.exists(os.path.join(download_path, filename)) for filename in dll_files) + + if not all_files_exist: + # Create a simple GUI window if files are not present + root = tk.Tk() + root.title("Preparing for first start") + root.geometry("300x100") + + progress_var = tk.DoubleVar() + progress = ttk.Progressbar(root, variable=progress_var, length=200) + progress.grid(row=0, column=0, padx=20, pady=20) + + def update_progress_bar(current_size, total_size): + progress_value = (current_size / total_size) * 100 + progress_var.set(progress_value) + root.update_idletasks() + + def start_download(): + # Download GTK4 DLLs if they are not already present + download_gtk_dlls(download_path, dll_url, dll_files, update_progress_bar) + + # Set PATH variable and refresh environment variables + if sys.platform == 'win32': + set_path_variable(download_path) + + # Destroy the GUI window + root.destroy() + + # Run your main application function + from gui_main import run_installer + run_installer() + + # Schedule the start_download function to run after 100 milliseconds + root.after(100, start_download) + + # Start the Tkinter event loop + root.mainloop() + else: + # Run installer directly if all files are present + from gui_main import run_installer + run_installer() + +if __name__ == "__main__": + main()