feat: initial release v0.0.1

This commit is contained in:
Nikita 2026-10-24 16:30:48 +05:00
commit d1c2d4e62f
166 changed files with 26724 additions and 0 deletions

11
.cargo/config.toml Normal file
View file

@ -0,0 +1,11 @@
[target.aarch64-linux-android]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]
[target.armv7-linux-androideabi]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]
[target.x86_64-linux-android]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]
[target.i686-linux-android]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]

180
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,180 @@
name: Release Build & Auto-Updater
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Target Release Tag (e.g. v0.1.5)'
required: false
default: 'v0.1.5'
jobs:
release:
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- platform: 'macos-latest'
target: 'aarch64-apple-darwin'
- platform: 'windows-latest'
target: 'x86_64-pc-windows-msvc'
- platform: 'ubuntu-22.04'
target: 'x86_64-unknown-linux-gnu'
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Linux build dependencies
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev rpm
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Setup Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
- name: Install dependencies
run: npm install
- name: Build Tauri and publish Release
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY || 'dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5VUF0UnlMZjR6bE4vUUFIbnQ0MDdjQ01xSXBHUVVMZ0k2OURzMEhrbkZwNEFBQkFBQUFBQUFBQUFBQUlBQUFBQU1GZmxKUFZFcGJXSW1LUlRvVXN6SjJSV1FYMnhYQldjOFRtTE4rRkRSUGEvM0xDVFZPOVovL3Q1N3Rmdi9PUG9XOWxGdHM5bjFNc3BKZCtCWHdkWDVsNW9LaHhZNXpFbFNSYkNkeXFLQmRuNmNyeHA0Rlp4UVhSUENPUFJrUnVCandLd2ZBSy95V2M9Cg==' }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ''
with:
tagName: ${{ inputs.tag || github.ref_name }}
releaseName: 'Home Autli Server ${{ inputs.tag || github.ref_name }}'
releaseBody: 'Автоматический релиз для Android (.apk), Linux (.deb, .rpm, .AppImage), Windows (.exe) и macOS (.dmg).'
releaseDraft: false
prerelease: false
args: ${{ matrix.target && format('--target {0}', matrix.target) || '' }}
release-android:
needs: release
if: always() && (needs.release.result == 'success' || needs.release.result == 'skipped')
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Setup Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-linux-android,armv7-linux-androideabi
- name: Setup Android NDK
run: |
echo "ANDROID_HOME=$ANDROID_SDK_ROOT" >> $GITHUB_ENV
if [ -d "$ANDROID_SDK_ROOT/ndk/26.1.10909125" ]; then
NDK_PATH="$ANDROID_SDK_ROOT/ndk/26.1.10909125"
else
NDK_LATEST=$(ls -d $ANDROID_SDK_ROOT/ndk/* 2>/dev/null | tail -n 1 || true)
if [ -n "$NDK_LATEST" ]; then
NDK_PATH="$NDK_LATEST"
else
echo "y" | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager "ndk;26.1.10909125"
NDK_PATH="$ANDROID_SDK_ROOT/ndk/26.1.10909125"
fi
fi
echo "NDK_HOME=$NDK_PATH" >> $GITHUB_ENV
TOOLCHAIN="$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64"
echo "TOOLCHAIN=$TOOLCHAIN" >> $GITHUB_ENV
echo "$TOOLCHAIN/bin" >> $GITHUB_PATH
# Create symlinks for legacy GNU binutils expected by OpenSSL makefile
for prefix in aarch64-linux-android arm-linux-androideabi armv7a-linux-androideabi; do
sudo ln -sf "$TOOLCHAIN/bin/llvm-ar" "/usr/local/bin/${prefix}-ar"
sudo ln -sf "$TOOLCHAIN/bin/llvm-ranlib" "/usr/local/bin/${prefix}-ranlib"
sudo ln -sf "$TOOLCHAIN/bin/llvm-nm" "/usr/local/bin/${prefix}-nm"
sudo ln -sf "$TOOLCHAIN/bin/llvm-as" "/usr/local/bin/${prefix}-as"
sudo ln -sf "$TOOLCHAIN/bin/llvm-strip" "/usr/local/bin/${prefix}-strip"
sudo ln -sf "$TOOLCHAIN/bin/llvm-ar" "$TOOLCHAIN/bin/${prefix}-ar"
sudo ln -sf "$TOOLCHAIN/bin/llvm-ranlib" "$TOOLCHAIN/bin/${prefix}-ranlib"
sudo ln -sf "$TOOLCHAIN/bin/llvm-nm" "$TOOLCHAIN/bin/${prefix}-nm"
sudo ln -sf "$TOOLCHAIN/bin/llvm-as" "$TOOLCHAIN/bin/${prefix}-as"
sudo ln -sf "$TOOLCHAIN/bin/llvm-strip" "$TOOLCHAIN/bin/${prefix}-strip"
done
- name: Install dependencies
run: npm install
- name: Build Android APK
run: npm run tauri -- android build --apk --target aarch64 armv7
env:
NDK_HOME: ${{ env.NDK_HOME }}
OPENSSL_STATIC: "1"
AR_aarch64_linux_android: llvm-ar
RANLIB_aarch64_linux_android: llvm-ranlib
AR_armv7_linux_androideabi: llvm-ar
RANLIB_armv7_linux_androideabi: llvm-ranlib
- name: Upload APK to GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
RELEASE_TAG="${{ inputs.tag || github.ref_name }}"
echo "Target Release Tag is: $RELEASE_TAG"
mkdir -p dist-apk
for apk in $(find src-tauri/gen/android/app/build/outputs/apk -type f -name "*.apk"); do
filename=$(basename "$apk")
echo "Found APK: $apk ($filename)"
cp "$apk" "dist-apk/Home.Autli.Server_${RELEASE_TAG}_${filename}"
if [[ "$filename" == *"universal"* ]] || [[ "$filename" == *"release"* ]]; then
cp "$apk" "dist-apk/Home.Autli.Server_${RELEASE_TAG}.apk"
fi
done
if [ ! -f "dist-apk/Home.Autli.Server_${RELEASE_TAG}.apk" ]; then
first_apk=$(find dist-apk -type f -name "*.apk" | head -n 1)
if [ -n "$first_apk" ]; then
cp "$first_apk" "dist-apk/Home.Autli.Server_${RELEASE_TAG}.apk"
fi
fi
echo "Uploading APK assets to GitHub release $RELEASE_TAG..."
if ! gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release create "$RELEASE_TAG" --title "Home Autli Server $RELEASE_TAG" --notes "Release $RELEASE_TAG"
fi
gh release upload "$RELEASE_TAG" dist-apk/*.apk --clobber

30
.gitignore vendored Normal file
View file

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Environment variables (NEVER commit any .env file to GitHub!)
.env*
# Tauri update private signing key (KEEP SECRET!)
src-tauri/*.key

3
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
}

31
PKGBUILD Normal file
View file

@ -0,0 +1,31 @@
# Maintainer: autli5 <https://github.com/autli5>
pkgname=home-autli-server-bin
pkgver=0.1.5
pkgrel=1
pkgdesc="Home Autli Server (HAS) - Кинотеатр (Full HD + Русская озвучка) и Облачное хранилище"
arch=('x86_64')
url="https://github.com/autli5/has"
license=('custom')
depends=('webkit2gtk-4.1' 'libappindicator-gtk3' 'librsvg' 'openssl' 'hicolor-icon-theme')
options=(!strip)
source=(
"https://github.com/autli5/has/releases/download/v${pkgver}/home-autli-server_${pkgver}_amd64.deb"
"https://raw.githubusercontent.com/autli5/has/main/public/logo.png"
)
sha256sums=(
'SKIP'
'SKIP'
)
package() {
# Распаковываем DEB пакет
tar -xf data.tar.* -C "${pkgdir}/"
# Устанавливаем логотип
install -Dm644 "${srcdir}/logo.png" "${pkgdir}/usr/share/icons/hicolor/512x512/apps/has.png"
# Создаем симлинк для быстрого запуска через 'has' в терминале
mkdir -p "${pkgdir}/usr/bin"
ln -sf "/usr/bin/home-autli-server" "${pkgdir}/usr/bin/has"
}

90
README.md Normal file
View file

@ -0,0 +1,90 @@
# Home Autli Server (HAS) 🚀
> **Личный облачный сервер, Кинотеатр Full HD с полной русской озвучкой (дубляж) и защищенное хранилище данных.**
[![Release Build & Auto-Updater](https://github.com/autli5/has/actions/workflows/release.yml/badge.svg)](https://github.com/autli5/has/actions/workflows/release.yml)
[![Version](https://img.shields.io/badge/version-v0.1.5-blue.svg)](https://github.com/autli5/has/releases/latest)
[![Platforms](https://img.shields.io/badge/platforms-Linux%20%7C%20Windows%20%7C%20macOS-success.svg)](https://github.com/autli5/has/releases/latest)
---
## ⚡ Быстрая установка на Linux через Терминал
Поддерживаются любые дистрибутивы: **Ubuntu, Debian, Fedora, Arch Linux, CachyOS, Manjaro, Linux Mint, Pop!_OS** и другие.
Выполните одну команду в терминале:
```bash
curl -fsSL https://raw.githubusercontent.com/autli5/has/main/install.sh | bash
```
*или через `wget`:*
```bash
wget -qO- https://raw.githubusercontent.com/autli5/has/main/install.sh | bash
```
Установщик сам определит ваш дистрибутив (Debian, Ubuntu, Fedora, Arch, CachyOS), скачает подходящий пакет (`.deb`, `.rpm` или `.AppImage`), установит необходимые зависимости и создаст ярлык в меню приложений.
Запуск из терминала:
```bash
has
```
---
## 📦 Ручная установка по дистрибутивам
### 🐧 Ubuntu / Debian / Linux Mint / Pop!_OS (`.deb`)
```bash
# 1. Скачивание последнего пакета .deb
curl -s https://api.github.com/repos/autli5/has/releases/latest | grep "browser_download_url.*amd64.deb" | cut -d : -f 2,3 | tr -d \" | wget -qi -
# 2. Установка через dpkg
sudo dpkg -i home-autli-server_*_amd64.deb || sudo apt-get install -f -y
```
### 🎩 Fedora / RHEL / CentOS (`.rpm`)
```bash
# 1. Скачивание пакета .rpm
curl -s https://api.github.com/repos/autli5/has/releases/latest | grep "browser_download_url.*x86_64.rpm" | cut -d : -f 2,3 | tr -d \" | wget -qi -
# 2. Установка через dnf
sudo dnf install -y ./home-autli-server-*.rpm
```
### 🏹 Arch Linux / CachyOS / Manjaro / EndeavourOS
#### Вариант A: Через `install.sh` (Рекомендуется)
```bash
curl -fsSL https://raw.githubusercontent.com/autli5/has/main/install.sh | bash -s -- --arch
```
#### Вариант B: Через `PKGBUILD`
```bash
git clone https://github.com/autli5/has.git
cd has
makepkg -si
```
---
## 💻 Другие операционные системы
- **🍏 macOS (Apple Silicon & Intel):** Скачайте `.dmg` из [последнего релиза](https://github.com/autli5/has/releases/latest).
- **🪟 Windows 10/11 (64-bit):** Скачайте `.exe` установщик из [последнего релиза](https://github.com/autli5/has/releases/latest).
---
## ✨ Основные возможности приложения
- 🎬 **Кинотеатр нового поколения:**
- Огромный каталог фильмов, сериалов и аниме без региональных блокировок.
- **100% Русская озвучка / Дубляж по умолчанию:** Smotrim, Embess, Alloha (Red Head Sound, Flarrow Films, СНГ-дубляж).
- Студийные озвучки для аниме: **Studio Band, AniLibria, AniDUB, SHIZA Project**.
- Полноэкранный режим с поддержкой звука и выбором серий прямо в плеере.
- 📁 **Облачное хранилище файлов:** Загрузка, папки, превью и мгновенная синхронизация.
- 👤 **Профиль пользователя:** Настройка темы, персонализация и управление аккаунтом.
- 🔄 **Авто-обновления:** Встроенный механизм проверки и загрузки новых версий (Tauri Updater).

16
index.html Normal file
View file

@ -0,0 +1,16 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<title>has</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

241
install.sh Executable file
View file

@ -0,0 +1,241 @@
#!/usr/bin/env bash
# ==============================================================================
# Home Autli Server (HAS) - Универсальный установщик для Linux через терминал
# Поддерживает: Ubuntu, Debian, Fedora, Arch Linux, CachyOS, Manjaro и др.
#
# Быстрый запуск одной командой в терминале:
# curl -fsSL https://raw.githubusercontent.com/autli5/has/main/install.sh | bash
# или
# wget -qO- https://raw.githubusercontent.com/autli5/has/main/install.sh | bash
# ==============================================================================
set -e
REPO="autli5/has"
APP_NAME="Home Autli Server"
BIN_NAME="has"
# Цвета для вывода в терминале
BOLD="\033[1m"
GREEN="\033[0;32m"
BLUE="\033[0;34m"
CYAN="\033[0;36m"
YELLOW="\033[1;33m"
RED="\033[0;31m"
RESET="\033[0m"
echo -e "${CYAN}${BOLD}"
echo "=========================================================="
echo " 🚀 Установка Home Autli Server (HAS) для Linux "
echo " Кинотеатр (Full HD + Русская озвучка) и Облако "
echo " Поддержка: Ubuntu, Debian, Fedora, Arch, CachyOS "
echo "=========================================================="
echo -e "${RESET}"
# 1. Проверка архитектуры системы
ARCH=$(uname -m)
if [ "$ARCH" != "x86_64" ] && [ "$ARCH" != "aarch64" ]; then
echo -e "${RED}Ошибка: архитектура $ARCH не поддерживается.${RESET}"
exit 1
fi
# 2. Определение дистрибутива Linux
PKG_TYPE=""
for arg in "$@"; do
case "$arg" in
--deb) PKG_TYPE="deb" ;;
--rpm) PKG_TYPE="rpm" ;;
--arch|--cachyos) PKG_TYPE="arch" ;;
--appimage) PKG_TYPE="appimage" ;;
esac
done
if [ -z "$PKG_TYPE" ]; then
if [ -f /etc/os-release ]; then
. /etc/os-release
DISTRO_ID="${ID:-linux}"
DISTRO_LIKE="${ID_LIKE:-}"
case "$DISTRO_ID $DISTRO_LIKE" in
*ubuntu*|*debian*|*linuxmint*|*pop*|*elementary*|*zorin*|*kali*)
PKG_TYPE="deb"
echo -e "${BLUE}ℹ️ Обнаружен дистрибутив Debian / Ubuntu (${DISTRO_ID}). Формат: .deb${RESET}"
;;
*fedora*|*rhel*|*centos*|*rocky*|*almalinux*)
PKG_TYPE="rpm"
echo -e "${BLUE}ℹ️ Обнаружен дистрибутив Fedora / Red Hat (${DISTRO_ID}). Формат: .rpm${RESET}"
;;
*arch*|*cachyos*|*cachy*|*manjaro*|*endeavouros*|*artix*)
PKG_TYPE="arch"
echo -e "${BLUE}ℹ️ Обнаружен дистрибутив Arch Linux / CachyOS (${DISTRO_ID}).${RESET}"
;;
*)
PKG_TYPE="appimage"
echo -e "${BLUE}ℹ️ Обнаружен дистрибутив Linux (${DISTRO_ID}). Формат: .AppImage${RESET}"
;;
esac
else
PKG_TYPE="appimage"
echo -e "${YELLOW}⚠️ Не удалось определить дистрибутив. Будет использован универсальный AppImage.${RESET}"
fi
fi
# 3. Получение последней версии из GitHub Releases
echo -e "${CYAN}🔍 Поиск последней версии в GitHub (${REPO})...${RESET}"
RELEASE_JSON=$(curl -s "https://api.github.com/repos/${REPO}/releases/latest" || true)
TAG_NAME=$(echo "$RELEASE_JSON" | grep -m1 '"tag_name":' | cut -d '"' -f 4 || true)
if [ -z "$TAG_NAME" ]; then
TAG_NAME="v0.1.5"
echo -e "${YELLOW}⚠️ Использована версия по умолчанию: ${TAG_NAME}${RESET}"
else
echo -e "${GREEN}✓ Найдена версия: ${TAG_NAME}${RESET}"
fi
# 4. Поиск прямой ссылки на скачивание нужного пакета
DOWNLOAD_URL=""
case "$PKG_TYPE" in
deb)
DOWNLOAD_URL=$(echo "$RELEASE_JSON" | grep -o 'https://[^"]*\.deb' | head -n 1 || true)
;;
rpm)
DOWNLOAD_URL=$(echo "$RELEASE_JSON" | grep -o 'https://[^"]*\.rpm' | head -n 1 || true)
;;
arch|appimage)
DOWNLOAD_URL=$(echo "$RELEASE_JSON" | grep -o 'https://[^"]*\.AppImage' | head -n 1 || true)
;;
esac
# Запасные прямые URL если GitHub API не вернул ссылки в JSON
if [ -z "$DOWNLOAD_URL" ]; then
case "$PKG_TYPE" in
deb)
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${TAG_NAME}/home-autli-server_${TAG_NAME#v}_amd64.deb"
;;
rpm)
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${TAG_NAME}/home-autli-server-${TAG_NAME#v}-1.x86_64.rpm"
;;
arch|appimage)
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${TAG_NAME}/home-autli-server_${TAG_NAME#v}_amd64.AppImage"
;;
esac
fi
TMP_DIR=$(mktemp -d /tmp/has-install.XXXXXX)
trap 'rm -rf "$TMP_DIR"' EXIT
FILE_NAME=$(basename "$DOWNLOAD_URL")
TMP_FILE="$TMP_DIR/$FILE_NAME"
echo -e "${CYAN}⬇️ Скачивание пакета (${FILE_NAME})...${RESET}"
if command -v curl &>/dev/null; then
curl -fL --progress-bar "$DOWNLOAD_URL" -o "$TMP_FILE"
elif command -v wget &>/dev/null; then
wget -q --show-progress "$DOWNLOAD_URL" -O "$TMP_FILE"
else
echo -e "${RED}Ошибка: необходимо установить curl или wget.${RESET}"
exit 1
fi
echo -e "${GREEN}✓ Файл успешно загружен.${RESET}"
# 5. Установка пакета в систему
echo -e "${CYAN}⚙️ Установка ${APP_NAME}...${RESET}"
case "$PKG_TYPE" in
deb)
echo -e "${BLUE}Выполняется установка .deb через dpkg / apt...${RESET}"
if sudo dpkg -i "$TMP_FILE"; then
echo -e "${GREEN}✓ Пакет установлен.${RESET}"
else
echo -e "${YELLOW}Доустановка недостающих зависимостей...${RESET}"
sudo apt-get update -qq
sudo apt-get install -f -y
fi
;;
rpm)
echo -e "${BLUE}Выполняется установка .rpm через dnf / rpm...${RESET}"
if command -v dnf &>/dev/null; then
sudo dnf install -y "$TMP_FILE"
elif command -v yum &>/dev/null; then
sudo yum localinstall -y "$TMP_FILE"
else
sudo rpm -Uvh --replacepkgs "$TMP_FILE"
fi
;;
arch)
echo -e "${BLUE}Настройка для Arch Linux / CachyOS...${RESET}"
# Проверка и установка зависимостей через pacman при необходимости
if command -v pacman &>/dev/null; then
echo -e "${CYAN}Проверка зависимостей (webkit2gtk-4.1, libappindicator-gtk3)...${RESET}"
sudo pacman -S --needed --noconfirm webkit2gtk-4.1 libappindicator-gtk3 librsvg || true
fi
chmod +x "$TMP_FILE"
INSTALL_BIN="$HOME/.local/bin"
mkdir -p "$INSTALL_BIN"
mv "$TMP_FILE" "$INSTALL_BIN/$BIN_NAME"
# Скачивание логотипа HAS для меню CachyOS / Arch
ICON_DIR="$HOME/.local/share/icons/hicolor/512x512/apps"
mkdir -p "$ICON_DIR"
curl -sL "https://raw.githubusercontent.com/${REPO}/main/public/logo.png" -o "$ICON_DIR/has.png" 2>/dev/null || true
# Создание .desktop файла для меню приложений (KDE Plasma, GNOME, Hyprland, XFCE)
DESKTOP_DIR="$HOME/.local/share/applications"
mkdir -p "$DESKTOP_DIR"
cat <<EOF > "$DESKTOP_DIR/home-autli-server.desktop"
[Desktop Entry]
Name=Home Autli Server
Comment=Личный сервер, Кинотеатр (Full HD + Русская озвучка) и Облако
Exec=$INSTALL_BIN/$BIN_NAME
Icon=$ICON_DIR/has.png
Terminal=false
Type=Application
Categories=AudioVideo;Player;Network;Utility;
StartupWMClass=home-autli-server
EOF
chmod +x "$DESKTOP_DIR/home-autli-server.desktop"
echo -e "${GREEN}✓ Исполняемый файл установлен в $INSTALL_BIN/$BIN_NAME${RESET}"
echo -e "${GREEN}✓ Ярлык добавлен в меню приложений Arch / CachyOS.${RESET}"
;;
appimage)
echo -e "${BLUE}Настройка переносимого AppImage...${RESET}"
chmod +x "$TMP_FILE"
INSTALL_BIN="$HOME/.local/bin"
mkdir -p "$INSTALL_BIN"
mv "$TMP_FILE" "$INSTALL_BIN/$BIN_NAME"
ICON_DIR="$HOME/.local/share/icons"
mkdir -p "$ICON_DIR"
curl -sL "https://raw.githubusercontent.com/${REPO}/main/public/logo.png" -o "$ICON_DIR/has.png" 2>/dev/null || true
DESKTOP_DIR="$HOME/.local/share/applications"
mkdir -p "$DESKTOP_DIR"
cat <<EOF > "$DESKTOP_DIR/home-autli-server.desktop"
[Desktop Entry]
Name=Home Autli Server
Comment=Личный сервер, Кинотеатр и Хранилище
Exec=$INSTALL_BIN/$BIN_NAME
Icon=$ICON_DIR/has.png
Terminal=false
Type=Application
Categories=AudioVideo;Player;Network;Utility;
StartupWMClass=home-autli-server
EOF
chmod +x "$DESKTOP_DIR/home-autli-server.desktop"
echo -e "${GREEN}✓ Исполняемый файл установлен в $INSTALL_BIN/$BIN_NAME${RESET}"
echo -e "${GREEN}✓ Ярлык добавлен в меню приложений.${RESET}"
;;
esac
echo ""
echo -e "${GREEN}${BOLD}==========================================================${RESET}"
echo -e "${GREEN}${BOLD} 🎉 ${APP_NAME} успешно установлен на ваш Linux! ${RESET}"
echo -e "${GREEN}${BOLD}==========================================================${RESET}"
echo ""
echo -e "Вы можете запустить приложение:"
echo -e " 1. Из меню приложений вашего рабочего стола: ${BOLD}Home Autli Server${RESET}"
echo -e " 2. Или прямо в терминале командой: ${CYAN}${BOLD}has${RESET}"
echo ""

1215
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

31
package.json Normal file
View file

@ -0,0 +1,31 @@
{
"name": "has",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"tauri": "tauri",
"android": "./scripts/run-android.sh dev",
"android:build": "./scripts/run-android.sh build --apk"
},
"dependencies": {
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-process": "^2.4.0",
"@tauri-apps/plugin-updater": "^2.13.3",
"hls.js": "^1.7.3",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@tauri-apps/cli": "^2",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^6.0.2",
"typescript": "~6.0.3",
"vite": "^8.0.16"
}
}

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

6
public/tauri.svg Normal file
View file

@ -0,0 +1,6 @@
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
<ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

1
public/vite.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

26
scripts/run-android.sh Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$DIR"
export ANDROID_HOME="${ANDROID_HOME:-$HOME/Library/Android/sdk}"
if [ -z "$NDK_HOME" ]; then
if [ -d "$ANDROID_HOME/ndk/27.2.12479018" ]; then
export NDK_HOME="$ANDROID_HOME/ndk/27.2.12479018"
elif [ -d "$ANDROID_HOME/ndk" ]; then
export NDK_HOME="$(ls -d "$ANDROID_HOME/ndk/"* 2>/dev/null | tail -n 1)"
fi
fi
if [ -n "$NDK_HOME" ] && [ -d "$NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin" ]; then
TOOLCHAIN_BIN="$NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin"
export PATH="$TOOLCHAIN_BIN:/usr/local/bin:/opt/homebrew/bin:$PATH"
fi
export OPENSSL_STATIC=1
export AR_aarch64_linux_android=llvm-ar
export RANLIB_aarch64_linux_android=llvm-ranlib
export RUSTFLAGS="-C link-arg=-Wl,-z,max-page-size=16384 ${RUSTFLAGS:-}"
exec npx tauri android "$@"

191
scripts/server-anti-ddos.sh Executable file
View file

@ -0,0 +1,191 @@
#!/bin/bash
# ==============================================================================
# HAS Server Anti-DDoS & Port 5432 Protection Setup Script
# ==============================================================================
# This script hardens Ubuntu server against:
# 1. TCP SYN Flood & Connection Exhaustion DDoS
# 2. Port 5432 Port Scanning, Connection Floods & Slowloris
# 3. PostgreSQL Brute-Force & Credential Stuffing
# 4. Kernel Socket & Memory Exhaustion Attacks
# ==============================================================================
set -e
# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
echo -e "${BLUE}====================================================================${NC}"
echo -e "${BLUE} HAS SERVER ANTI-DDOS & PORT 5432 HARDENING SETUP ${NC}"
echo -e "${BLUE}====================================================================${NC}"
# 1. Check Root
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}❌ Пожалуйста, запустите скрипт с правами суперпользователя: sudo bash $0${NC}"
exit 1
fi
echo -e "\n${YELLOW}>>> 1/5. Настройка ядра Linux против SYN Flood и DoS атак...${NC}"
SYSCTL_CONF="/etc/sysctl.d/99-has-anti-ddos.conf"
cat << 'EOF' > "$SYSCTL_CONF"
# --- HAS Anti-DDoS Kernel Protection ---
# 1. SYN Flood Protection (Cryptographic SYN cookies when queue is under attack)
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 3
# 2. Fast timeout for abandoned and dead connections (Anti-Slowloris)
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 30
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 3
# 3. Socket reuse & connection scaling
net.ipv4.tcp_tw_reuse = 1
net.core.somaxconn = 4096
net.core.netdev_max_backlog = 5000
net.ipv4.ip_local_port_range = 1024 65535
# 4. Anti-Spoofing & Broadcast ICMP flood protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
EOF
sysctl -p "$SYSCTL_CONF" >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1
echo -e "${GREEN}✓ Параметры ядра sysctl применены: SYN-cookies включены, таймауты сброшены.${NC}"
# 2. Iptables Rate-Limiting & Connection Limits on Port 5432
echo -e "\n${YELLOW}>>> 2/5. Настройка фаервола iptables на порту 5432...${NC}"
# Ensure iptables-persistent is installed
if ! command -v iptables &> /dev/null; then
apt-get update -y && apt-get install -y iptables
fi
export DEBIAN_FRONTEND=noninteractive
apt-get install -y iptables-persistent netfilter-persistent >/dev/null 2>&1 || true
# Remove older duplicate HAS rules if any
iptables -D INPUT -p tcp --dport 5432 -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT --reject-with tcp-reset 2>/dev/null || true
iptables -D INPUT -p tcp --dport 5432 -m state --state NEW -m recent --update --seconds 10 --hitcount 20 --name HAS_PG_RATE -j DROP 2>/dev/null || true
iptables -D INPUT -p tcp --dport 5432 -m state --state NEW -m recent --set --name HAS_PG_RATE 2>/dev/null || true
iptables -D INPUT -p tcp --dport 5432 --syn -m limit --limit 30/s --limit-burst 60 -j ACCEPT 2>/dev/null || true
# RULE A: Limit max concurrent connections per single IP to 10
# (Real app uses 1-3 connections; botnet opening 50+ sockets gets immediate TCP RST)
iptables -I INPUT -p tcp --dport 5432 -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT --reject-with tcp-reset
# RULE B: Rate-limit new connections (Anti-Scan / Anti-Burst Flood)
# (Max 20 new connections per 10 seconds per IP, rest are dropped silently)
iptables -I INPUT -p tcp --dport 5432 -m state --state NEW -m recent --update --seconds 10 --hitcount 20 --name HAS_PG_RATE -j DROP
iptables -I INPUT -p tcp --dport 5432 -m state --state NEW -m recent --set --name HAS_PG_RATE
# RULE C: SYN flood packet rate limiting
iptables -I INPUT -p tcp --dport 5432 --syn -m limit --limit 30/s --limit-burst 60 -j ACCEPT
# Save iptables rules to persist across reboot
if command -v netfilter-persistent &> /dev/null; then
netfilter-persistent save >/dev/null 2>&1 || true
fi
mkdir -p /etc/iptables
iptables-save > /etc/iptables/rules.v4 2>/dev/null || true
echo -e "${GREEN}✓ Iptables настроен: макс. 10 подключений на 1 IP, лимит новых сессий (20/10с), защита от SYN-flood.${NC}"
# 3. Hardening PostgreSQL Server (postgresql.conf)
echo -e "\n${YELLOW}>>> 3/5. Оптимизация параметров безопасности PostgreSQL...${NC}"
PG_CONF=""
for p in "/www/server/pgsql/data/postgresql.conf" $(find /etc/postgresql -name postgresql.conf 2>/dev/null); do
if [ -f "$p" ]; then
PG_CONF="$p"
break
fi
done
if [ -n "$PG_CONF" ] && [ -f "$PG_CONF" ]; then
echo -e "Найден конфигурационный файл: ${BLUE}$PG_CONF${NC}"
cp "$PG_CONF" "${PG_CONF}.bak_$(date +%Y%m%d%H%M%S)"
# Anti-Slowloris: reduce authentication timeout from 60s to 5s
sed -i "s/^#\?authentication_timeout\s*=.*/authentication_timeout = 5s/" "$PG_CONF"
# Fast keepalive for dead client connections
sed -i "s/^#\?tcp_keepalives_idle\s*=.*/tcp_keepalives_idle = 15/" "$PG_CONF"
sed -i "s/^#\?tcp_keepalives_interval\s*=.*/tcp_keepalives_interval = 5/" "$PG_CONF"
sed -i "s/^#\?tcp_keepalives_count\s*=.*/tcp_keepalives_count = 3/" "$PG_CONF"
# Connection limits & admin reservation
sed -i "s/^#\?max_connections\s*=.*/max_connections = 120/" "$PG_CONF"
sed -i "s/^#\?superuser_reserved_connections\s*=.*/superuser_reserved_connections = 5/" "$PG_CONF"
# Reload PostgreSQL configuration without downtime
if [ -f "/www/server/pgsql/bin/pg_ctl" ]; then
su - postgres -c "/www/server/pgsql/bin/pg_ctl -D /www/server/pgsql/data reload" >/dev/null 2>&1 || true
elif [ -f "/etc/init.d/pgsql" ]; then
/etc/init.d/pgsql reload >/dev/null 2>&1 || true
else
systemctl reload postgresql >/dev/null 2>&1 || true
fi
echo -e "${GREEN}✓ PostgreSQL обновлен: authentication_timeout=5s (Anti-Slowloris), keepalive=15s, резерв для админа.${NC}"
else
echo -e "${YELLOW}⚠️ Файл postgresql.conf не найден автоматически, пропуск обновления параметров PG.${NC}"
fi
# 4. Setup Fail2Ban against Brute-Force & Malicious Scanners
echo -e "\n${YELLOW}>>> 4/5. Настройка Fail2ban для автоматической блокировки атакующих ботов...${NC}"
apt-get update -y >/dev/null 2>&1 || true
apt-get install -y fail2ban >/dev/null 2>&1 || true
if command -v fail2ban-client &> /dev/null; then
mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d
cat << 'EOF' > /etc/fail2ban/filter.d/postgresql-has.conf
[Definition]
failregex = ^.*FATAL:\s+password authentication failed for user.*host=<HOST>.*$
^.*FATAL:\s+no pg_hba.conf entry for host "<HOST>".*$
ignoreregex =
EOF
PG_LOG="/www/server/pgsql/data/server.log"
if [ ! -f "$PG_LOG" ]; then
PG_LOG="/var/log/postgresql/postgresql-*.log"
fi
cat << EOF > /etc/fail2ban/jail.d/postgresql-has.local
[postgresql-has]
enabled = true
port = 5432
filter = postgresql-has
logpath = $PG_LOG
maxretry = 5
findtime = 600
bantime = 86400
EOF
systemctl restart fail2ban >/dev/null 2>&1 || service fail2ban restart >/dev/null 2>&1 || true
echo -e "${GREEN}✓ Fail2ban активирован: автобан на 24 часа при 5 неудачных попытках авторизации.${NC}"
else
echo -e "${YELLOW}⚠️ Fail2ban не удалось установить автоматически.${NC}"
fi
# 5. Verification & Status Output
echo -e "\n${BLUE}====================================================================${NC}"
echo -e "${GREEN}🎉 НАСТРОЙКА ЗАЩИТЫ УСПЕШНО ЗАВЕРШЕНА!${NC}"
echo -e "${BLUE}====================================================================${NC}"
echo -e "Активные правила iptables на порту 5432:"
iptables -L INPUT -v -n --line-numbers | grep -E "5432|dpt" || true
echo -e "\n${YELLOW}Полезные команды для мониторинга сервера:${NC}"
echo -e "1. Просмотр заблокированных ботов в Fail2ban: ${GREEN}fail2ban-client status postgresql-has${NC}"
echo -e "2. Просмотр счетчика отброшенных пакетов: ${GREEN}iptables -L INPUT -v -n | grep 5432${NC}"
echo -e "3. Просмотр активных соединений с базой: ${GREEN}ss -nt state established '( sport = :5432 )'${NC}"
echo -e "4. Разблокировать ошибочно забаненный IP: ${GREEN}fail2ban-client set postgresql-has unbanip <IP>${NC}"
echo -e "${BLUE}====================================================================${NC}"

26
scripts/setup-android-env.sh Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
ANDROID_HOME="${ANDROID_HOME:-$HOME/Library/Android/sdk}"
if [ -z "$NDK_HOME" ]; then
if [ -d "$ANDROID_HOME/ndk/27.2.12479018" ]; then
NDK_HOME="$ANDROID_HOME/ndk/27.2.12479018"
elif [ -d "$ANDROID_HOME/ndk" ]; then
NDK_HOME="$(ls -d "$ANDROID_HOME/ndk/"* 2>/dev/null | tail -n 1)"
fi
fi
if [ -n "$NDK_HOME" ] && [ -d "$NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin" ]; then
TOOLCHAIN_BIN="$NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin"
echo "Setting up GNU binutils symlinks in $TOOLCHAIN_BIN..."
for prefix in aarch64-linux-android arm-linux-androideabi armv7a-linux-androideabi x86_64-linux-android i686-linux-android; do
[ -f "$TOOLCHAIN_BIN/llvm-ar" ] && ln -sf "$TOOLCHAIN_BIN/llvm-ar" "$TOOLCHAIN_BIN/${prefix}-ar"
[ -f "$TOOLCHAIN_BIN/llvm-ranlib" ] && ln -sf "$TOOLCHAIN_BIN/llvm-ranlib" "$TOOLCHAIN_BIN/${prefix}-ranlib"
[ -f "$TOOLCHAIN_BIN/llvm-nm" ] && ln -sf "$TOOLCHAIN_BIN/llvm-nm" "$TOOLCHAIN_BIN/${prefix}-nm"
[ -f "$TOOLCHAIN_BIN/llvm-as" ] && ln -sf "$TOOLCHAIN_BIN/llvm-as" "$TOOLCHAIN_BIN/${prefix}-as"
[ -f "$TOOLCHAIN_BIN/llvm-strip" ] && ln -sf "$TOOLCHAIN_BIN/llvm-strip" "$TOOLCHAIN_BIN/${prefix}-strip"
done
echo "Symlinks created successfully."
else
echo "NDK toolchain not found at $NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64/bin"
fi

View file

@ -0,0 +1,11 @@
[target.aarch64-linux-android]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]
[target.armv7-linux-androideabi]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]
[target.x86_64-linux-android]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]
[target.i686-linux-android]
rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=16384"]

7
src-tauri/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Generated by Tauri
# will have schema files for capabilities auto-completion
/gen/schemas

5838
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

50
src-tauri/Cargo.toml Normal file
View file

@ -0,0 +1,50 @@
[package]
name = "has"
version = "0.0.1"
description = "has"
authors = ["autli"]
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
name = "has_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-opener = "2"
tauri-plugin-updater = "2"
tauri-plugin-process = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
tokio-postgres = { version = "0.7", features = ["with-chrono-0_4"] }
native-tls = { version = "0.2", features = ["vendored"] }
openssl = { version = "0.10", features = ["vendored"] }
tokio-native-tls = "0.3"
postgres-native-tls = "0.5"
dotenvy = "0.15"
bcrypt = "0.17"
sha2 = "0.10"
hex = "0.4"
base64 = "0.22"
chrono = { version = "0.4", default-features = false, features = ["clock"] }
reqwest = { version = "0.12", default-features = false, features = ["json", "default-tls"] }
rustls = { version = "0.23", default-features = false, features = ["ring"] }
# Read the optimization guideline for more details: https://tauri.app/concept/size/#cargo-configuration
[profile.release]
codegen-units = 1
lto = true
opt-level = 3
panic = "abort"
strip = true

3
src-tauri/build.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

View file

@ -0,0 +1,12 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"opener:default",
"updater:default",
"process:default"
]
}

View file

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false

20
src-tauri/gen/android/.gitignore vendored Normal file
View file

@ -0,0 +1,20 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
build
/captures
.externalNativeBuild
.cxx
local.properties
key.properties
keystore.properties
/.tauri
/tauri.settings.gradle

6
src-tauri/gen/android/app/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
/src/main/**/generated
/src/main/jniLibs/**/*.so
/src/main/assets/tauri.conf.json
/tauri.build.gradle.kts
/proguard-tauri.pro
/tauri.properties

View file

@ -0,0 +1,84 @@
import java.util.Properties
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("rust")
}
val tauriProperties = Properties().apply {
val propFile = file("tauri.properties")
if (propFile.exists()) {
propFile.inputStream().use { load(it) }
}
}
android {
compileSdk = 37
namespace = "com.has.tauri_app"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.has.tauri_app"
minSdk = 24
targetSdk = 37
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packaging {
jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
signingConfig = signingConfigs.getByName("debug")
optimization {
enable = true
}
proguardFiles(
*fileTree(".") {
include("**/*.pro")
exclude("build/**")
}.files.toTypedArray()
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildFeatures {
buildConfig = true
}
}
kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_1_8
}
}
rust {
rootDirRel = "../../../"
}
dependencies {
implementation("androidx.webkit:webkit:1.14.0")
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("androidx.activity:activity-ktx:1.10.1")
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.lifecycle:lifecycle-process:2.10.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
}
apply(from = file("tauri.build.gradle.kts"))

View file

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<!-- AndroidTV support -->
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.tauri_app"
android:usesCleartextTraffic="${usesCleartextTraffic}">
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:launchMode="singleTask"
android:label="@string/main_activity_title"
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- AndroidTV support -->
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View file

@ -0,0 +1,11 @@
package com.has.tauri_app
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
class MainActivity : TauriActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
}
}

View file

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View file

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -0,0 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.tauri_app" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View file

@ -0,0 +1,4 @@
<resources>
<string name="app_name">"Home Autli Server"</string>
<string name="main_activity_title">"Home Autli Server"</string>
</resources>

View file

@ -0,0 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.tauri_app" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="." />
<cache-path name="my_cache_images" path="." />
</paths>

View file

@ -0,0 +1,22 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:9.4.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.10")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
tasks.register("clean").configure {
delete("build")
}

View file

@ -0,0 +1,23 @@
plugins {
`kotlin-dsl`
}
gradlePlugin {
plugins {
create("pluginsForCoolKids") {
id = "rust"
implementationClass = "RustPlugin"
}
}
}
repositories {
google()
mavenCentral()
}
dependencies {
compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:9.4.1")
}

View file

@ -0,0 +1,99 @@
import java.io.File
import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import javax.inject.Inject
import org.gradle.process.ExecOperations
abstract class BuildTask : DefaultTask() {
@get:Inject
abstract val execOperations: ExecOperations
@Input
var rootDirRel: String? = null
@Input
var projectDir: String? = null
@Input
var target: String? = null
@Input
var release: Boolean? = null
@TaskAction
fun assemble() {
val candidates = listOf(
"/usr/local/bin/npm",
"/opt/homebrew/bin/npm",
System.getProperty("user.home") + "/.nvm/versions/node/$(node -v)/bin/npm",
"npm"
)
val executable = candidates.firstOrNull { File(it).exists() } ?: "npm"
try {
runTauriCli(executable)
} catch (e: Exception) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
// Try different Windows-specific extensions
val fallbacks = listOf(
"$executable.exe",
"$executable.cmd",
"$executable.bat",
)
var lastException: Exception = e
for (fallback in fallbacks) {
try {
runTauriCli(fallback)
return
} catch (fallbackException: Exception) {
lastException = fallbackException
}
}
throw lastException
} else {
throw e;
}
}
}
fun runTauriCli(executable: String) {
val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null")
val target = target ?: throw GradleException("target cannot be null")
val release = release ?: throw GradleException("release cannot be null")
val args = listOf("run", "--", "tauri", "android", "android-studio-script");
val userHome = System.getProperty("user.home")
val androidSdk = File(userHome, "Library/Android/sdk")
val ndkDir = File(androidSdk, "ndk/27.2.12479018")
val toolchainBin = File(ndkDir, "toolchains/llvm/prebuilt/darwin-x86_64/bin")
execOperations.exec {
workingDir(File(projectDir, rootDirRel))
executable(executable)
args(args)
if (androidSdk.exists()) {
environment("ANDROID_HOME", androidSdk.absolutePath)
}
if (ndkDir.exists()) {
environment("NDK_HOME", ndkDir.absolutePath)
}
val existingPath = System.getenv("PATH") ?: "/usr/bin:/bin:/usr/sbin:/sbin"
val fullPath = "${toolchainBin.absolutePath}:/usr/local/bin:/opt/homebrew/bin:$existingPath"
environment("PATH", fullPath)
environment("OPENSSL_STATIC", "1")
environment("AR_aarch64_linux_android", "llvm-ar")
environment("RANLIB_aarch64_linux_android", "llvm-ranlib")
environment("RUSTFLAGS", "-C link-arg=-Wl,-z,max-page-size=16384")
if (logger.isEnabled(LogLevel.DEBUG)) {
args("-vv")
} else if (logger.isEnabled(LogLevel.INFO)) {
args("-v")
}
if (release) {
args("--release")
}
args(listOf("--target", target))
}.assertNormalExitValue()
}
}

View file

@ -0,0 +1,86 @@
import com.android.build.api.dsl.ApplicationExtension
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
const val TASK_GROUP = "rust"
open class Config {
lateinit var rootDirRel: String
}
open class RustPlugin : Plugin<Project> {
private lateinit var config: Config
override fun apply(project: Project) = with(project) {
config = extensions.create("rust", Config::class.java)
val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64");
val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList
val defaultArchList = listOf("arm64", "arm", "x86", "x86_64");
val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList
val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64")
extensions.configure<ApplicationExtension> {
@Suppress("UnstableApiUsage")
flavorDimensions.add("abi")
productFlavors {
create("universal") {
dimension = "abi"
ndk {
abiFilters += abiList
}
}
defaultArchList.forEachIndexed { index, arch ->
create(arch) {
dimension = "abi"
ndk {
abiFilters.add(defaultAbiList[index])
}
}
}
}
}
afterEvaluate {
for (profile in listOf("debug", "release")) {
val profileCapitalized = profile.replaceFirstChar { it.uppercase() }
val buildTask = tasks.maybeCreate(
"rustBuildUniversal$profileCapitalized",
DefaultTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for all targets"
}
tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask)
for (targetPair in targetsList.withIndex()) {
val targetName = targetPair.value
val targetArch = archList[targetPair.index]
val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() }
val targetBuildTask = project.tasks.register(
"rustBuild$targetArchCapitalized$profileCapitalized",
BuildTask::class.java
) {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for $targetArch"
rootDirRel = config.rootDirRel
projectDir = project.projectDir.path
target = targetName
release = profile == "release"
}
buildTask.dependsOn(targetBuildTask)
tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn(
targetBuildTask
)
}
}
}
}
}

View file

@ -0,0 +1,26 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.configuration-cache=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Our old plugin template had a bug that caused missing `consumer-rules.pro` files
# so we have to disable it for now.
# See https://github.com/tauri-apps/tauri/pull/15828#issuecomment-5199937796
android.proguard.failOnMissingFiles=false
# Keeping Gradle 9 compatible with current plugins
# TODO: Remove this in v3
android.builtInKotlin=false
android.newDsl=false

View file

@ -0,0 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c2dd35c9d0aaf0ba6ad0791320f99dfc/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/e5810bd7fd1f8a586644409d395a7e55/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/cf726b4a1c84b50457225f9bba6d7650/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fa1e318c287360478e3c83a9a3ef1007/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/7b3c4877c0749019e6805bb61e421497/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/d76df094a9cbbabd3b08251f9e61444a/redirect
toolchainVersion=25

Binary file not shown.

View file

@ -0,0 +1,6 @@
#Tue May 10 19:22:52 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

248
src-tauri/gen/android/gradlew vendored Executable file
View file

@ -0,0 +1,248 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# gradlew start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh gradlew
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

82
src-tauri/gen/android/gradlew.bat vendored Normal file
View file

@ -0,0 +1,82 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem gradlew startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
@rem Execute gradlew
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%

View file

@ -0,0 +1,3 @@
include ':app'
apply from: 'tauri.settings.gradle'

View file

@ -0,0 +1 @@
dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDNEQUVFQTk4QkE5REVFNjMKUldSajdwMjZtT3F1UGFzWUFIcjNNcjRUdnlGKzBzUGxTZ3BOTGFWcGRwN2pCd1JJTnRXbTE2d3EK

BIN
src-tauri/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
src-tauri/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
src-tauri/icons/64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<background android:drawable="@color/ic_launcher_background"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

BIN
src-tauri/icons/icon.icns Normal file

Binary file not shown.

BIN
src-tauri/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
src-tauri/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Some files were not shown because too many files have changed in this diff Show more