Init
This commit is contained in:
parent
5a846d328d
commit
cdd0e4070d
15 changed files with 864 additions and 0 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
@ -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/
|
3
build.bat
Executable file
3
build.bat
Executable file
|
@ -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
|
2
build.sh
Executable file
2
build.sh
Executable file
|
@ -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
|
34
dwnld.sh
Executable file
34
dwnld.sh
Executable file
|
@ -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
|
||||||
|
|
29
install-linux.sh
Executable file
29
install-linux.sh
Executable file
|
@ -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
|
13
install-windows.txt
Executable file
13
install-windows.txt
Executable file
|
@ -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
|
3
run.bat
Normal file
3
run.bat
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
python3 ./src/main.py
|
||||||
|
:: --clean-cache=all --disable-console --windows-icon-from-ico=./data/icon.ico
|
||||||
|
pause
|
1
run.sh
Executable file
1
run.sh
Executable file
|
@ -0,0 +1 @@
|
||||||
|
python3 ./src/main.py
|
29
src/donwload_sourceforege.py
Normal file
29
src/donwload_sourceforege.py
Normal file
|
@ -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)
|
80
src/download_github.py
Normal file
80
src/download_github.py
Normal file
|
@ -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}")
|
119
src/download_gitlab.py
Normal file
119
src/download_gitlab.py
Normal file
|
@ -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)
|
71
src/download_main.py
Normal file
71
src/download_main.py
Normal file
|
@ -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()
|
212
src/gui_main.py
Normal file
212
src/gui_main.py
Normal file
|
@ -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()
|
110
src/json_main.py
Normal file
110
src/json_main.py
Normal file
|
@ -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.")
|
143
src/main.py
Normal file
143
src/main.py
Normal file
|
@ -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()
|
Reference in a new issue