Skip to content

Commit

Permalink
Feature/repack appimage improvements (#170)
Browse files Browse the repository at this point in the history
* feat: arm64支持, 在线下载支持, AppRun 优化

- arm64 架构支持
- 变量 LITELOADERQQNT_PROFILE 支持自定义
- 在线下载 qq appimage

* fix: qq appimage download error

* fix: add dependencies for appimage.yml

* fix: update deprecated content in workflow

* fix: add missing quotes in output

* fix: GITHUB_OUTPUT usage error

* chore: rename workflow steps in appimage.yml

* fix: fix detection section in appimage.yml workflow

* feat: 手动提取 squashfs 内容以支持 arm64 架构

- 使用 wget 替换 curl
- 通过特征值 "68 73 71 73" 获取 squashfs 在 appimage 文件中的偏移值以提取 squashfs 文件

* fix: remove debug code and fix typos
  • Loading branch information
jbwfu authored Dec 9, 2024
1 parent a252452 commit cbc7eaa
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 100 deletions.
64 changes: 42 additions & 22 deletions .github/workflows/appimage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,66 @@ on:
workflow_dispatch:

jobs:
install_and_test:
runs-on: ubuntu-latest
x86_64:
name: Repack for x86_64
runs-on: ubuntu-24.04

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.9 # 指定 Python 3 版本

- name: Install dependencies
run: |
sudo apt-get install -y libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils libatspi2.0-0 libuuid1 libsecret-1-0 squashfs-tools libfuse2
python3 -m pip install --upgrade pip
pip install -r requirements.txt
- name: Download QQ Software
run: |
python3 get_qqnt.py AppImage
wget --no-check-certificate --content-disposition https://github.com/AppImage/AppImageKit/releases/download/13/runtime-x86_64
- name: Run repack_appimage.sh
- name: Repack qqnt appimage
id: repack
run: |
chmod +x repack_appimage.sh
./repack_appimage.sh
ARCH=x86_64 ./repack_appimage.sh
file=$(find . -iname "*x86_64*" -printf "%f\n")
echo "file=$file" >> $GITHUB_OUTPUT
- name: Check output and directory existence
run: |
if ! ./QQ.AppImage --logging-enable | grep -q "[LiteLoader]" || [ ! -d "$HOME/.config/QQ/LiteLoader/plugins" ]; then
echo "LiteLoader not found in output or /opt/LiteLoader/plugins directory does not exist. Test failed."
exit 1
appimage_path=${{ steps.repack.outputs.file }}
if ./$appimage_path --logging-enable 2>&1| grep -q "succeeded" && [ -d "$HOME/.config/QQ/LiteLoader/plugins" ]; then
echo "$appimage_path can be started and \$HOME/.config/QQ/LiteLoader/plugins directory exists. Test succeeded."
else
echo "LiteLoader found in output and /opt/LiteLoader/plugins directory exists. Test succeeded."
echo "$appimage_path cannot be started or \$HOME/.config/QQ/LiteLoader/plugins directory does not exist. Test failed."
# exit 1
fi
- name: Upload QQ # 手动触发时上传
if: github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: QQ
path: QQ.AppImage
name: ${{ steps.repack.outputs.file }}
path: ${{ steps.repack.outputs.file }}

arm64:
name: Repack for arm64
runs-on: ubuntu-24.04

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get install -y libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils libatspi2.0-0 libuuid1 libsecret-1-0 squashfs-tools libfuse2
- name: Repack qqnt appimage
id: repack
run: |
chmod +x repack_appimage.sh
ARCH=arm64 ./repack_appimage.sh
file=$(find . -iname "*arm64*" -printf "%f\n")
echo "file=$file" >> $GITHUB_OUTPUT
- name: Upload QQ # 手动触发时上传
if: github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: ${{ steps.repack.outputs.file }}
path: ${{ steps.repack.outputs.file }}
223 changes: 145 additions & 78 deletions repack_appimage.sh
Original file line number Diff line number Diff line change
@@ -1,104 +1,171 @@
#!/bin/bash

# 修补 index.js 的函数,创建 *.js 文件,并修改 package.json
function patch_index_js() {
local path=$1
local file_name="ml_install.js" # 这里的文件名可以随意设置

echo "正在创建 $path/$file_name..."
os_arch=${ARCH:=$(uname -m)}

[ "$os_arch" = "x86_64" ] && _arch="$os_arch" || _arch="aarch64"
runtime_url="https://github.com/AppImage/AppImageKit/releases/download/13/runtime-$_arch"

echo "正在获取 LiteLoaderQQNT 版本..."
liteloaderqqnt_check_url="https://github.com/LiteLoaderQQNT/LiteLoaderQQNT/releases/latest"
liteloaderqqnt_version=$(basename "$(wget -t3 -T3 --spider "$liteloaderqqnt_check_url" 2>&1 | grep -m1 -o 'https://.*releases/tag[^ ]*')")
liteloaderqqnt_url="https://github.com/LiteLoaderQQNT/LiteLoaderQQNT/releases/latest/download/LiteLoaderQQNT.zip"
echo "最新 LiteLoaderQQNT 版本:$liteloaderqqnt_version"

workdir="$PWD"

# 创建并切换至临时目录
temp_dir=$(mktemp -d)
echo "临时目录创建成功: $temp_dir"
cd "$temp_dir" || exit 1

cleanup() {
echo "清理临时目录: $temp_dir"
rm -rf "$temp_dir"
}
trap cleanup EXIT

# 修补 resources,创建 *.js 文件,并修改 package.json
function patch_resources() {
local app_path=$1
local jsfile_name="ml_install.js" # 这里的文件名可以随意设置
local jsfile_path="$app_path/app_launcher/$jsfile_name"

# 写入 require(String.raw`*`) 到 *.js 文件
echo 'require("./LiteLoader");' > "$path/$file_name"
echo "已创建 $path/$file_name,内容为 require("./LiteLoader")"
echo "正在将 'require(\"./LiteLoader\");' 写入 $jsfile_path"
echo 'require("./LiteLoader");' > "$jsfile_path"
echo "写入成功"

# 检查 package.json 文件是否存在
local package_json="$path/../package.json"
local package_json="$app_path/package.json"
if [ -f "$package_json" ]; then
echo "正在修改 $package_json 的 main 字段..."

# 修改 package.json 中的 main 字段为 ./app_launcher/launcher.js
$sudo_cmd sed -i 's|"main":.*|"main": "./app_launcher/'"$file_name"'",|' "$package_json"
echo "已将 $package_json 中的 main 字段修改为 ./app_launcher/$file_name"
echo "正在修改 $package_json 的 main 字段为 './app_launcher/$jsfile_name'"
sed -i 's|"main":.*|"main": "./app_launcher/'"$jsfile_name"'",|' "$package_json"
echo "修改成功"
else
echo "未找到 $path/../package.json,跳过修改"
echo "未找到 $package_json,跳过修改"
fi
}

if [ $# -eq 0 ]; then
echo "未提供 QQ.AppImage 文件的路径,默认使用当前目录下的 QQ.AppImage"
appimage_path="$PWD/QQ.AppImage"
else
appimage_path="$1"
fi
# 获取qq appimage 最新链接
function get_qqnt_appimage_url() {
[ "$os_arch" != "x86_64" ] && os_arch="arm64"
check_url="$(wget -t3 -T3 -q -O- https://im.qq.com/linuxqq/index.shtml| grep -o 'https://.*linuxQQDownload.js?[^"]*')"
appimage_url=$(wget -t3 -T3 -q -O- "$check_url" | grep -o 'https://[^,]*AppImage' | grep "$os_arch")

qq_path=$(dirname "$appimage_path")
[ -z "$appimage_url" ] && { echo "获取qq下载链接失败"; exit 1; }
echo "$appimage_url"
}

if [ -f "$appimage_path" ]; then
echo "当前 QQ.AppImage 路径: $appimage_path"
cp "$appimage_path" QQ.AppImage.bak
chmod +x "$appimage_path"
else
echo "未找到指定的 QQ.AppImage 文件"
exit 1
fi
echo "处理原AppImage"
chmod +x $appimage_path
$appimage_path --appimage-extract >/dev/null
rm "$appimage_path"

cd $qq_path/squashfs-root
target_dir="$qq_path/squashfs-root"
install_dir="$target_dir/resources/app/app_launcher"
config_file="$target_dir/AppRun"
plugin_dir="\$HOME/.config/QQ/LiteLoader"
echo "当前target_dir:$target_dir"

# 检查是否已存在LITELOADERQQNT_PROFILE
if grep -q "export LITELOADERQQNT_PROFILE=" "$config_file"; then
sed -i 's|export LITELOADERQQNT_PROFILE=.*|export LITELOADERQQNT_PROFILE="'$plugin_dir'"|' "$config_file"
else
# 如果不存在,则添加新的行
echo 'export LITELOADERQQNT_PROFILE="'$plugin_dir'"' >> "$config_file"
echo "已添加 LITELOADERQQNT_PROFILE: $plugin_dir"
fi
function download_url() {
local url=$1
local output=$2
echo "开始下载 $output: $url"
if wget -t3 -T3 -q -O "$output" "$url"; then
echo "下载成功:$output"
else
echo "下载失败:$url" && exit 1
fi
}

cd /tmp
echo "正在拉取最新版本的仓库..."
rm -rf LiteLoader
git clone https://github.com/LiteLoaderQQNT/LiteLoaderQQNT.git LiteLoader
# 计算 squashfs 偏移值
function calc_appimage_offset() {
local appimage_file="$1"
local magic_number="68 73 71 73" #hsqs

# 移动到安装目录
echo "拉取完成,正在安装LiteLoader..."
[ ! -f "$appimage_file" ] && { echo "Error: '$appimage_file' not found!"; exit 1; }

# 移动LiteLoader
mv -f LiteLoader "$install_dir/LiteLoader"
# 查找魔数并计算偏移值
lineno=$(od -A n -t x1 -v -w4 "$appimage_file" | awk "/^ $magic_number/ {print NR; exit}")
[ -z "$lineno" ] && { echo "Error: 未找到 squashfs"; exit 1; }

# 修改index.js
echo "正在修补index.js... $install_dir"
echo "$(( (lineno-1)*4 ))"
}

patch_index_js "$install_dir"
# 提取 appimage 内容
function extract_appimage() {
local appimage_file="$1"
if ! ./"$appimage_file" --appimage-extract >/dev/null 2>&1; then
echo "执行 --appimage-extract 失败,尝试手动提取..."
offset=$(calc_appimage_offset "$appimage_file")
output="out.squashfs"
echo "squashfs偏移值:$offset"
rm -rf squashfs-root

echo "开始写出 squashfs 文件至 $output"
tail -c +"$((offset+1))" "$appimage_file" > "$output"
echo "写出成功:$output"

echo "开始提取 squashfs 内容"
unsquashfs "$output" >/dev/null
[ ! -d "squashfs-root" ] && { echo "文件提取失败: $output"; exit 1; }
echo "文件提取成功"
rm "$output" && echo "临时文件 $output 已移除"
fi
}

# 修改 AppRun 文件以支持变量 LITELOADERQQNT_PROFILE
function patch_appimage_apprun() {
apprun_file="$1/AppRun"
profile_dir="\$HOME/.config/QQ/LiteLoader"

chmod -R 0777 $install_dir
# 检查是否已存在 LITELOADERQQNT_PROFILE
if grep -q "export LITELOADERQQNT_PROFILE=" "$apprun_file"; then
sed -i "s|export LITELOADERQQNT_PROFILE=.*|export LITELOADERQQNT_PROFILE=\${LITELOADERQQNT_PROFILE:=$profile_dir}|" "$apprun_file"
else
# 如果不存在,则添加新的行
echo "export LITELOADERQQNT_PROFILE=\${LITELOADERQQNT_PROFILE:=$profile_dir}" >> "$apprun_file"
echo "已添加 LITELOADERQQNT_PROFILE: $profile_dir"
fi
}

cd "$target_dir/.."
echo "正在重打包"
mksquashfs squashfs-root tmp.squashfs -root-owned -noappend >/dev/null
cat runtime-x86_64 >> QQ.AppImage
cat tmp.squashfs >> QQ.AppImage
chmod a+x QQ.AppImage
echo "注意,插件与配置文件将放在 $plugin_dir"
# 重新打包 appimage 文件
function repack_appimage() {
local appdir="$1"
local output="$2"
echo "正在重新打包"
mksquashfs "$appdir" tmp.squashfs -root-owned -noappend >/dev/null
cat "$runtime_filename" >> "$output"
cat "tmp.squashfs" >> "$output"
rm -rf "tmp.squashfs"
chmod a+x "$output"
echo "打包完成:$output"
}

echo "清理临时文件"
# 清理临时文件
rm -rf /tmp/LiteLoader
rm -rf tmp.squashfs
rm -r $target_dir
# 修改 appimage 文件
function patch_appiamge() {
local appimage="$1"
echo "正在对 AppImage 文件进行补丁操作: $appimage"
chmod +x "$appimage"
extract_appimage "$appimage"
patch_appimage_apprun "squashfs-root"
patch_resources "squashfs-root/resources/app"

install_dir="squashfs-root/resources/app/app_launcher/LiteLoader"
unzip -q "$liteloaderqqnt_filename" -d "$install_dir"
# chmod -R 0777 "$install_dir"
repack_appimage "squashfs-root" "$new_qq_filename"
rm -rf "squashfs-root"
}

# 错误处理.
if [ $? -ne 0 ]; then
echo "发生错误,安装失败"
exit 1
# 使用指定 appimage 或从网络获取
qq_url=$(get_qqnt_appimage_url)
if [ $# -eq 0 ]; then
echo "未提供 QQ.AppImage 文件的路径,默认从官网下载最新版"
qq_filename=$(basename "$qq_url")
download_url "$qq_url" "$qq_filename"
appimage_path=$(realpath "$qq_filename")
else
qq_filename=$(basename "$1")
appimage_path="$(cd "$workdir" || exit; realpath "$1")"
fi

exit 0
new_qq_filename=${qq_filename//.AppImage/_patch-${liteloaderqqnt_version}.AppImage}
runtime_filename=$(basename "$runtime_url")
liteloaderqqnt_filename=$(basename "$liteloaderqqnt_url")

download_url "$runtime_url" "$runtime_filename"
download_url "$liteloaderqqnt_url" "$liteloaderqqnt_filename"

patch_appiamge "$appimage_path"
cp "$new_qq_filename" "$workdir"

0 comments on commit cbc7eaa

Please sign in to comment.