Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Nightkingale committed Sep 7, 2022
0 parents commit 4b11be7
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 0 deletions.
21 changes: 21 additions & 0 deletions LICENSE
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 NoahAbc12345

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
18 changes: 18 additions & 0 deletions README.md
@@ -0,0 +1,18 @@
# WUHB Packager

A Wii U homebrew packager for use with Aroma.

WUHB Packager is a graphical alternative to using the command-line to package homebrew files for the Aroma environment. It still relies on wuhbtool in order to work properly, however it may provide a much simpler way to package homebrew for those who prefer not to use command-line tools.

## Installation
A Windows executable will be bundled with each release. Linux users will need to use the Python script in the source code in order to run the program, but it should still function fine.
- It is crucial to have wuhbtool installed correctly, which comes in [wut-tools](https://github.com/devkitPro/wut-tools). Without this installed, the program will refuse to package any homebrew. Please refer to that repository for installation instructions.

## Usage
In order to use the program, you'll need to at least have the homebrew you'd like to package in RPX format.
- Besides the executable, you can also provide a `/content` directory (if necessary), a name, pictures, and more. None of this is required, but it's encouraged for your homebrew to be more recognizable on the Wii U Menu. If anything is missing, the program will alert you, but any warnings can be dismissed.
- When a homebrew executable has been provided, a button will be available that allows you to package the homebrew. Clicking it will ask where to save the resulting WUHB file, and anything that should be brought to your attention will show here.
- After the homebrew is packaged, the program will let you know with one final alert. You can now use and distribute the WUHB file, exclusively for usage in the [Aroma environment](https://aroma.foryour.cafe/).

## Credits
A special thanks is in order for [GaryOderNichts](https://github.com/GaryOderNichts) for requesting this to be made, assisting me throughout development, and testing the program before release.
269 changes: 269 additions & 0 deletions packager.py
@@ -0,0 +1,269 @@
import os
import tkinter

from PIL import Image
from tkinter import filedialog, messagebox, Tk, ttk

# Define valid image file extensions.
file_extensions = [
("All Files", ".bmp .jpg .jpeg .png .tga"),
("BMP Files", ".bmp"),
("JPG Files", ".jpg .jpeg"),
("PNG Files", ".png"),
("TGA Files", ".tga"),
]

# Check to make sure RPX is provided before building.
def check_package_status():
if rpx_path.get():
package_wuhb_button.config(state="normal")
else:
package_wuhb_button.config(state="disabled")

# Locate a /content path if necessary.
def select_content_path():
folder_directory = filedialog.askdirectory()

if not folder_directory:
raise Exception("No file was selected!")

content_path.config(state="normal")
content_path.delete(0, "end")
content_path.insert(0, folder_directory)
content_path.config(state="readonly")

# Select the RPX file, the only necessary requirement.
def select_rpx_file():
file_directory = filedialog.askopenfilename(
filetypes=[("RPX Files", ".rpx")])

if not file_directory:
raise Exception("No file was selected!")

rpx_path.config(state="normal")
rpx_path.delete(0, "end")
rpx_path.insert(0, file_directory)
rpx_path.config(state="readonly")

check_package_status()

# Select the icon that shows up on the Wii U Menu.
def select_icon_file():
file_directory = filedialog.askopenfilename(filetypes=file_extensions)

if not file_directory:
raise Exception("No file was selected!")
else:
application_image = Image.open(file_directory)
if application_image.size != (128, 128):
messagebox.showwarning("WUHB Packager",
"The picture you selected is not the right dimension!")

icon_path.config(state="normal")
icon_path.delete(0, "end")
icon_path.insert(0, file_directory)
icon_path.config(state="readonly")

# Select the splash screen image for the television.
def select_tv_splash_file():
file_directory = filedialog.askopenfilename(filetypes=file_extensions)

if not file_directory:
raise Exception("No file was selected!")
else:
application_image = Image.open(file_directory)
if application_image.size != (1280, 720):
messagebox.showwarning("WUHB Packager",
"The picture you selected is not the right dimension!")

tv_splash_path.config(state="normal")
tv_splash_path.delete(0, "end")
tv_splash_path.insert(0, file_directory)
tv_splash_path.config(state="readonly")

# Select the splash screen image for the Wii U GamePad.
def select_drc_splash_file():
file_directory = filedialog.askopenfilename(filetypes=file_extensions)

if not file_directory:
raise Exception("No file was selected!")
else:
application_image = Image.open(file_directory)
if application_image.size != (854, 480):
messagebox.showwarning("WUHB Packager",
"The picture you selected is not the right dimension!")

drc_splash_path.config(state="normal")
drc_splash_path.delete(0, "end")
drc_splash_path.insert(0, file_directory)
drc_splash_path.config(state="readonly")

# Where all the core functions happen, packaging to a WUHB.
def package_wuhb_file():
rpx = rpx_path.get()
content = content_path.get()
name = long_name_path.get()
short_name = short_name_path.get()
author = author_path.get()
icon = icon_path.get()
tv_image = tv_splash_path.get()
drc_image = drc_splash_path.get()

wuhb = filedialog.asksaveasfilename(
filetypes=[("WUHB Files", ".wuhb")], defaultextension=".wuhb")

if not wuhb:
raise Exception("No file was selected!")

if not name or not short_name or not author:
answer = messagebox.askyesno(title="Missing Metadata",
message="One or more fields of metadata are empty. Instead, any missing "
+ "information will be auto-filled with dummy text. Is this okay?")

if not answer:
raise Exception("No metadata was given!")

if not icon or not tv_image or not drc_image:
answer = messagebox.askyesno(title="Missing Image Files",
message="One or more image files are missing. Instead, dummy image "
+ "files will be used during packaging. Is this okay?")

if not answer:
raise Exception("No images were selected!")

if os.name == "nt":
# Confirmed that the user is running Windows.
command = "C:\\devkitPro\\tools\\bin\wuhbtool.exe"
elif os.name == "posix":
# Confirmed that the user is running Linux.
command = "/opt/devkitpro/tools/bin/wuhbtool"
else:
# The user is using an operating system that probably isn't supported.
messagebox.showerror("WUHB Packager", "An application cannot be packaged on"
+ "this system. Please run this on a Linux or Windows operating system.")

if not os.path.exists(command):
# wuhbtool might not be installed or configured correctly.
messagebox.showerror("WUHB Packager", "You must have wuhbtool installed"
+ " properly in order to package an application.")
raise Exception("wuhbtool is not installed or configured properly!")

command += f" \"{rpx}\" \"{wuhb}\""

if content:
# Check for optional /content folder.
command += f' --content="{content}"'
if name:
# Check for optional application name.
command += f' --name "{name}"'
if short_name:
# Check for optional application short name.
command += f' --short-name "{short_name}"'
if author:
# Check for optional application author.
command += f' --author "{author}"'
if icon:
# Check for optional icon image.
command += f' --icon="{icon}"'
if tv_image:
# Check for optional television splash image.
command += f' --tv-image="{tv_image}"'
if drc_image:
# Check for optional Wii U GamePad splash image.
command += f' --drc-image="{drc_image}"'

# Disable the package button, run the command, and inform when finished.
package_wuhb_button.config(text=f"Processing Package", state="disabled")

os.system(command)
messagebox.showinfo("WUHB Packager", f"The application was packaged successfully!")
package_wuhb_button.config(text=f"Package WUHB File", state="normal")

# Create the Tkinter window and assets.
main_window = Tk()
main_window.title("WUHB Packager")
main_window.resizable(False, False)
# /content path selection panel.
content_label = tkinter.Label(main_window, text="Path to /content Directory")
content_label.grid(column=0, row=1)
content_path = tkinter.Entry(main_window, state="readonly", width=40, border=5)
content_path.grid(column=0, row=2)
pick_content_path = tkinter.Button(main_window, text="Select Path to /content Directory",
border=5, command=select_content_path)
pick_content_path.grid(column=0, row=3)
pick_content_path.config(height=1, width=35)
# Program title panel.
title_label = tkinter.Label(main_window, text="WUHB Packager", width=40)
title_label.grid(column=1, row=2)
# RPX file selection panel.
rpx_label = tkinter.Label(main_window, text="Path to RPX file")
rpx_label.grid(column=2, row=1)
rpx_path = tkinter.Entry(main_window, state="readonly", width=40, border=5)
rpx_path.grid(column=2, row=2)
pick_rpx_file = tkinter.Button(main_window, text="Select RPX File",
border=5, command=select_rpx_file)
pick_rpx_file.grid(column=2, row=3)
pick_rpx_file.config(height=1, width=35)
# Application name entry panel.
long_name_label = tkinter.Label(main_window, text="Long Application Name")
long_name_label.grid(column=0, row=5)
long_name_path = tkinter.Entry(main_window, state="normal", width=40, border=5)
long_name_path.grid(column=0, row=6)
# Application short name entry panel.
short_name_label = tkinter.Label(main_window, text="Short Application Name")
short_name_label.grid(column=1, row=5)
short_name_path = tkinter.Entry(main_window, state="normal", width=40, border=5)
short_name_path.grid(column=1, row=6)
# Application author entry panel.
author_label = tkinter.Label(main_window, text="Application Author")
author_label.grid(column=2, row=5)
author_path = tkinter.Entry(main_window, state="normal", width=40, border=5)
author_path.grid(column=2, row=6)
# Application icon selection panel.
icon_label = tkinter.Label(main_window, text="Application Icon (128x128)")
icon_label.grid(column=0, row=8)
icon_path = tkinter.Entry(main_window, state="readonly", width=40, border=5)
icon_path.grid(column=0, row=9)
pick_icon_file = tkinter.Button(main_window, text="Select Application Icon",
border=5, command=select_icon_file)
pick_icon_file.grid(column=0, row=10)
pick_icon_file.config(height=1, width=35)
# Television splash image selection panel.
tv_splash_label = tkinter.Label(main_window, text="TV Splash Screen Image (1280x720)")
tv_splash_label.grid(column=1, row=8)
tv_splash_path = tkinter.Entry(main_window, state="readonly", width=40, border=5)
tv_splash_path.grid(column=1, row=9)
pick_tv_splash_file = tkinter.Button(main_window, text="Select TV Splash Screen Image",
border=5, command=select_tv_splash_file)
pick_tv_splash_file.grid(column=1, row=10)
pick_tv_splash_file.config(height=1, width=35)
# Wii U GamePad splash image selection panel.
drc_splash_label = tkinter.Label(main_window, text="DRC Splash Screen Image (854x480)")
drc_splash_label.grid(column=2, row=8)
drc_splash_path = tkinter.Entry(
main_window, state="readonly", width=40, border=5)
drc_splash_path.grid(column=2, row=9)
pick_drc_splash_file = tkinter.Button(main_window, text="Select DRC Splash Screen Image",
border=5, command=select_drc_splash_file)
pick_drc_splash_file.grid(column=2, row=10)
pick_drc_splash_file.config(height=1, width=35)
# Line seperator to put the packaging button away from the rest.
button_separator = ttk.Separator(main_window, orient="horizontal")
button_separator.grid(column=1, row=11, sticky="ew", pady=10)
# Button that will activate the function to package to WUHB.
package_wuhb_button = tkinter.Button(main_window, text="Package WUHB File",
border=5, command=package_wuhb_file)
package_wuhb_button.grid(column=1, row=12)
package_wuhb_button.config(height=2, width=35)
# Line seperator to put the credits line away from the rest.
button_separator = ttk.Separator(main_window, orient="horizontal")
button_separator.grid(column=1, row=13, sticky="ew", pady=10)
# Credits line to show who made the application.
credit_label = tkinter.Label(
main_window, text="Created by NoahAbc12345", width=40)
credit_label.grid(column=1, row=14)

# Make sure packaging button is disabled on start-up.
check_package_status()

main_window.mainloop()

0 comments on commit 4b11be7

Please sign in to comment.