Skip to content

Build: upload > /product/media #2

Build: upload > /product/media

Build: upload > /product/media #2

Workflow file for this run

name: Build Custom Module
# To run this workflow
# 1. Fork this repo
# 2. Choose a device template or add custom files to the 'upload' folder
# 3. Run and download the module
run-name: "Build: ${{ inputs.source == 'template' && format('{0}/{1}', inputs.device, inputs.theme) || 'upload' }} > ${{ inputs.target_location }}"
on:
workflow_dispatch:
inputs:
source:
description: 'Source'
required: true
default: 'upload'
type: choice
options:
- 'upload'
- 'template'
device:
description: 'Device model (only applies when source is template)'
required: false
default: 'liuqin'
type: choice
options:
- 'liuqin'
theme:
description: 'Theme (only applies when source is template)'
required: false
default: 'HyperOS'
type: choice
options:
- 'HyperOS'
- 'MIUI'
- 'MIUI_inverted'
target_location:
description: 'Where to place bootanimation files in the system'
required: true
default: '/product/media'
type: choice
options:
- '/product/media'
- '/system/media'
- '/system_ext/media'
jobs:
build-module:
runs-on: ubuntu-latest
name: Build Module
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Download latest release module
id: download_release
run: |
echo "Fetching latest release info from update.json..."
# Read update.json to get the download URL
if [ ! -f "update.json" ]; then
echo "Error: update.json not found!"
exit 1
fi
ZIP_URL=$(jq -r '.zipUrl' update.json)
VERSION=$(jq -r '.version' update.json)
if [ -z "$ZIP_URL" ] || [ "$ZIP_URL" = "null" ]; then
echo "Error: No zipUrl found in update.json!"
exit 1
fi
echo "Version: $VERSION"
echo "Download URL: $ZIP_URL"
echo "version=$VERSION" >> $GITHUB_OUTPUT
# Download the module zip
mkdir -p release_download
cd release_download
echo "Downloading module..."
curl -L -o module.zip "$ZIP_URL"
if [ ! -f "module.zip" ]; then
echo "Error: Failed to download module!"
exit 1
fi
echo "Downloaded: module.zip"
# Extract the module
mkdir -p ../build/module
unzip -o "module.zip" -d ../build/module
echo "Module extracted successfully"
# Show module info
if [ -f "../build/module/module.prop" ]; then
echo ""
echo "Module info:"
cat ../build/module/module.prop
fi
- name: Prepare bootanimation files
id: prepare_files
run: |
mkdir -p bootanimations
SOURCE="${{ github.event.inputs.source }}"
# Default to upload if not specified
if [ -z "$SOURCE" ]; then
SOURCE="upload"
fi
echo "Source: $SOURCE"
if [ "$SOURCE" = "template" ]; then
# Build template path from device and theme inputs
DEVICE="${{ github.event.inputs.device }}"
THEME="${{ github.event.inputs.theme }}"
# Use defaults if not specified
DEVICE="${DEVICE:-liuqin}"
THEME="${THEME:-HyperOS}"
TEMPLATE_DIR="templates/$DEVICE/$THEME"
echo "Using template: $DEVICE/$THEME"
if [ ! -d "$TEMPLATE_DIR" ]; then
echo "Error: Template directory not found: $TEMPLATE_DIR"
echo ""
echo "Available templates:"
find templates -type d -mindepth 2 -maxdepth 2 2>/dev/null || echo " (none)"
exit 1
fi
# Copy template files to bootanimations
cp "$TEMPLATE_DIR"/*.zip bootanimations/ 2>/dev/null || {
echo "Error: No bootanimation files found in template: $TEMPLATE_DIR"
exit 1
}
echo "Copied template files:"
ls -la bootanimations/
else
# Use upload folder
echo "Using upload folder"
if [ -d "upload" ] && ls upload/*.zip 1> /dev/null 2>&1; then
cp upload/*.zip bootanimations/
echo "Copied files from upload folder:"
ls -la bootanimations/
else
echo "Error: No bootanimation files found in upload folder!"
echo ""
echo "To use this workflow:"
echo "1. Add your bootanimation.zip files to the 'upload' folder"
echo "2. Commit and push the changes"
echo "3. Run this workflow again"
echo ""
echo "OR select 'template' as source and choose a device/system."
echo ""
echo "File naming convention:"
echo " - bootanimation.zip (main boot animation)"
echo " - bootanimation01.zip (alternative 1)"
echo " - bootanimation02.zip (alternative 2)"
echo " - etc."
exit 1
fi
fi
- name: Validate bootanimation files
run: |
echo "Validating bootanimation files..."
echo ""
errors=0
warnings=0
for file in bootanimations/*.zip; do
if [ -f "$file" ]; then
filename=$(basename "$file")
filesize=$(du -h "$file" | cut -f1)
echo "Checking: $filename ($filesize)"
# Validate ZIP integrity
if ! unzip -t "$file" > /dev/null 2>&1; then
echo " [ERROR] Invalid ZIP file!"
errors=$((errors + 1))
continue
fi
# Check for desc.txt
if unzip -l "$file" 2>/dev/null | grep -q "desc.txt"; then
echo " [OK] desc.txt found"
else
echo " [WARN] desc.txt not found"
warnings=$((warnings + 1))
fi
# Check for part0/
if unzip -l "$file" 2>/dev/null | grep -q "part0/"; then
echo " [OK] part0/ found"
else
echo " [WARN] part0/ not found"
warnings=$((warnings + 1))
fi
echo ""
fi
done
if [ $errors -gt 0 ]; then
echo "Validation failed with $errors error(s)"
exit 1
fi
if [ $warnings -gt 0 ]; then
echo "Validation completed with $warnings warning(s)"
else
echo "All files validated successfully"
fi
- name: Prepare module structure
run: |
echo "Preparing module structure..."
# Determine target location
TARGET_LOCATION="${{ github.event.inputs.target_location }}"
if [ -z "$TARGET_LOCATION" ]; then
TARGET_LOCATION="/product/media"
fi
MODULE_TARGET="system$TARGET_LOCATION"
echo "Target location: $TARGET_LOCATION"
echo "Module path: $MODULE_TARGET"
# Remove all existing media directories to avoid conflicts
echo "Cleaning up existing media directories..."
MEDIA_DIRS=(
"build/module/system/product/media"
"build/module/system/system/media"
"build/module/system/system_ext/media"
"build/module/system/product/media/theme/default"
)
for dir in "${MEDIA_DIRS[@]}"; do
if [ -d "$dir" ]; then
# Check if this is the target or a parent of it
TARGET_DIR_FULL="build/module/$MODULE_TARGET"
if [[ "$TARGET_DIR_FULL" != "$dir"* ]]; then
echo " Removing: $dir"
rm -rf "$dir"
fi
fi
done
# Create target directory with system/ prefix for Magisk
TARGET_DIR="build/module/$MODULE_TARGET"
mkdir -p "$TARGET_DIR"
# Clean any existing bootanimation files from the downloaded module
find build/module -name "bootanimation*.zip" -type f -delete 2>/dev/null || true
echo "Target location: $TARGET_LOCATION"
echo "target_dir=$TARGET_DIR" >> $GITHUB_ENV
echo "target_location=$TARGET_LOCATION" >> $GITHUB_ENV
- name: Copy bootanimation files
run: |
echo "Copying bootanimation files..."
for file in bootanimations/*.zip; do
if [ -f "$file" ]; then
filename=$(basename "$file")
echo " -> $filename"
cp "$file" "${{ env.target_dir }}/"
fi
done
echo ""
echo "Files copied to module:"
ls -la "${{ env.target_dir }}/"
- name: Get module info
id: module_info
run: |
PROP_FILE="build/module/module.prop"
MODULE_ID=$(grep "^id=" "$PROP_FILE" | cut -d= -f2 | tr -d '\r')
MODULE_NAME=$(grep "^name=" "$PROP_FILE" | cut -d= -f2 | tr -d '\r')
MODULE_VERSION=$(grep "^version=" "$PROP_FILE" | cut -d= -f2 | tr -d '\r')
MODULE_AUTHOR=$(grep "^author=" "$PROP_FILE" | cut -d= -f2 | tr -d '\r')
echo "module_id=$MODULE_ID" >> $GITHUB_OUTPUT
echo "module_name=$MODULE_NAME" >> $GITHUB_OUTPUT
echo "module_version=$MODULE_VERSION" >> $GITHUB_OUTPUT
echo "module_author=$MODULE_AUTHOR" >> $GITHUB_OUTPUT
echo "Module info:"
echo " ID: $MODULE_ID"
echo " Name: $MODULE_NAME"
echo " Version: $MODULE_VERSION"
echo " Author: $MODULE_AUTHOR"
- name: Prepare module artifact
id: prepare_artifact
run: |
MODULE_ID="${{ steps.module_info.outputs.module_id }}"
MODULE_VERSION="${{ steps.module_info.outputs.module_version }}"
# Create a unique artifact name with target location
TARGET_SHORT=$(echo "${{ env.target_location }}" | sed 's|^/||' | tr '/' '-')
ARTIFACT_NAME="${MODULE_ID}-${MODULE_VERSION}-${TARGET_SHORT}"
# Calculate module size
MODULE_SIZE=$(du -sh build/module | cut -f1)
echo "artifact_name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
echo "module_size=$MODULE_SIZE" >> $GITHUB_OUTPUT
echo ""
echo "Module prepared: $ARTIFACT_NAME ($MODULE_SIZE)"
echo ""
echo "Module contents:"
ls -laR build/module
- name: Upload module artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.prepare_artifact.outputs.artifact_name }}
path: build/module
retention-days: 90
- name: Generate build summary
run: |
SOURCE="${{ github.event.inputs.source }}"
if [ -z "$SOURCE" ]; then
SOURCE="upload"
fi
# Build source description
if [ "$SOURCE" = "template" ]; then
DEVICE="${{ github.event.inputs.device }}"
THEME="${{ github.event.inputs.theme }}"
SOURCE_DESC="template: $DEVICE/$THEME"
else
SOURCE_DESC="upload"
fi
cat << EOF >> $GITHUB_STEP_SUMMARY
# Module Built Successfully
## Module Details
| Property | Value |
|----------|-------|
| **Artifact** | \`${{ steps.prepare_artifact.outputs.artifact_name }}.zip\` |
| **Size** | ${{ steps.prepare_artifact.outputs.module_size }} |
| **Base Release** | ${{ steps.download_release.outputs.version }} |
| **Source** | $SOURCE_DESC |
| **Name** | ${{ steps.module_info.outputs.module_name }} |
| **Version** | ${{ steps.module_info.outputs.module_version }} |
| **Author** | ${{ steps.module_info.outputs.module_author }} |
| **Target** | \`${{ env.target_location }}\` |
## Included Bootanimations
EOF
for file in "${{ env.target_dir }}"/*.zip; do
if [ -f "$file" ]; then
filename=$(basename "$file")
size=$(du -h "$file" | cut -f1)
echo "- \`$filename\` ($size)" >> $GITHUB_STEP_SUMMARY
fi
done
cat << 'EOF' >> $GITHUB_STEP_SUMMARY
## Download & Installation
1. Scroll down to the **Artifacts** section below
2. Click on the artifact to download the module ZIP
3. Flash the downloaded ZIP directly using:
- **Magisk Manager** → Modules → Install from storage
- **KernelSU** → Module → Install
- **APatch** → Module → Install
4. Reboot your device
## Notes
- The module will replace the boot animation on your device
- A backup of the original animation will be created during installation
- You can uninstall the module to restore the original animation
EOF