feat: create autonomous Nivora package repository

Maintain a validated cross-distribution package catalog.
Automate upstream updates, isolated builds, diagnostics, and direct publication.
Build the official GitHub Desktop sources for Linux with working OAuth.
This commit is contained in:
Александр
2026-07-25 00:49:32 +10:00
commit f405ae2bcf
168 changed files with 8483 additions and 0 deletions
+236
View File
@@ -0,0 +1,236 @@
name='anidesk'
version='0.0.1-beta.7'
debian_version='0.0.1.beta.7'
release=5
summary='Unofficial Anixart desktop client'
summary_ru='Неофициальный desktop-клиент Anixart'
group='Video/Players'
desc='AniDesk is an unofficial Electron desktop client for Anixart with account support, a built-in video player and Anime4K WebGPU upscaling.'
desc_ru='AniDesk — неофициальный Electron desktop-клиент Anixart с поддержкой аккаунта, встроенным видеоплеером и Anime4K-апскейлом через WebGPU.'
homepage='https://github.com/theDesConnet/AniDesk'
maintainer='DesConnet, hack1exe <https://github.com/theDesConnet/AniDesk>'
architectures=('amd64')
license=('GPL-2.0-only')
provides=()
replaces=('anidesk')
conflicts=()
auto_reqprov_method="dirty"
auto_req=0
auto_prov=0
deps=()
deps_debian=('libgtk-3-0' 'libnotify4' 'libnss3' 'xdg-utils' 'libatspi2.0-0' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libasound2' 'libvulkan1' 'mesa-vulkan-drivers')
deps_ubuntu=("${deps_debian[@]}")
deps_fedora=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'mesa-libgbm' 'libxcb' 'alsa-lib' 'vulkan-loader' 'mesa-vulkan-drivers')
deps_arch=('gtk3' 'libnotify' 'nss' 'xdg-utils' 'at-spi2-core' 'libdrm' 'mesa' 'libxcb' 'alsa-lib' 'vulkan-icd-loader' 'vulkan-radeon')
deps_opensuse=('gtk3' 'libnotify4' 'mozilla-nss' 'xdg-utils' 'at-spi2-core' 'libdrm2' 'libgbm1' 'libxcb-dri3-0' 'libasound2' 'libvulkan1' 'Mesa-vulkan-device-select')
deps_altlinux=('libgtk+3' 'libnotify' 'libnss' 'xdg-utils' 'libat-spi2-core' 'libdrm' 'libgbm' 'libxcb' 'libalsa' 'libvulkan1' 'mesa-dri-drivers')
build_deps=('binutils')
build_deps_debian=('binutils' 'python3')
build_deps_ubuntu=("${build_deps_debian[@]}")
build_deps_fedora=('binutils' 'python3')
build_deps_arch=('binutils' 'python')
build_deps_opensuse=('binutils' 'python3')
build_deps_altlinux=('binutils' 'python3')
opt_deps=()
opt_deps_debian=('gnome-keyring' 'discord')
opt_deps_ubuntu=("${opt_deps_debian[@]}")
opt_deps_fedora=('gnome-keyring' 'discord')
opt_deps_arch=('gnome-keyring' 'discord')
opt_deps_opensuse=('gnome-keyring' 'discord')
opt_deps_altlinux=('gnome-keyring')
sources=(
"https://github.com/theDesConnet/AniDesk/releases/download/v${version}/anidesk_${debian_version}_amd64.deb?~archive=false&~name=anidesk.deb"
"local:///anidesk.png"
"local:///anidesk-wrapper"
"local:///LICENSE"
)
checksums=(
'sha256:70fc1207824757f7ddab63f9e210f31bb907ea43dee3d2827fe79c3ef00252b6'
'sha256:6d7791424bd7db712b121f7e66206289b1d31eb2a8ea998d9aeced2c7075dfe8'
'sha256:f58b9f720bd63ff49053f949dd3f0a738afc2aa2cee57fedbd2b73440c123721'
'sha256:892e6b268f44a850a102cc6367fec45853fe3556840d44a6106f08487553e6c4'
)
scripts=(
['postinstall']='postinstall.sh'
['postremove']='postremove.sh'
)
package() {
cd "${srcdir}"
mkdir -p "${srcdir}/extracted"
ar x anidesk.deb
tar -xf data.tar.* -C "${srcdir}/extracted"
install -dm755 "${pkgdir}/usr/lib"
cp -a "${srcdir}/extracted/usr/lib/anidesk" "${pkgdir}/usr/lib/"
chmod 0755 "${pkgdir}/usr/lib/anidesk/chrome-sandbox"
chmod 755 "${pkgdir}/usr/lib/anidesk/anidesk"
python3 - "${pkgdir}/usr/lib/anidesk/resources/app.asar" <<'PY'
import copy
import hashlib
import json
import struct
import sys
from pathlib import Path
asar_path = Path(sys.argv[1])
data = asar_path.read_bytes()
_, _, _, header_size = struct.unpack("<IIII", data[:16])
header = json.loads(data[16 : 16 + header_size])
base_offset = 16 + ((header_size + 3) & ~3)
def iter_files(node, prefix=""):
for name, entry in node.get("files", {}).items():
path_name = f"{prefix}{name}"
if "files" in entry:
yield from iter_files(entry, f"{path_name}/")
else:
yield path_name, entry
entries = []
for path_name, entry in iter_files(header):
if "offset" not in entry or "size" not in entry:
continue
offset = int(entry["offset"])
size = int(entry["size"])
content = data[base_offset + offset : base_offset + offset + size]
entries.append((path_name, content))
patched = {}
bundle_patch_applied = False
source_patch_applied = False
for path_name, content in entries:
if path_name == "public/build/bundle.js":
text = content.decode()
old = (
'onChangeCallback:(e,t)=>{x.set(t),set(o,!0),'
'baseSettings.restartRequired=!0}'
)
new = (
'onChangeCallback:(e,t)=>{get(n)!==t&&(x.set(t),set(o,!0),'
'baseSettings.restartRequired=!0,queueMicrotask(()=>location.reload()))}'
)
if old not in text:
raise SystemExit("AniDesk ASAR patch failed: endpoint dropdown marker not found")
patched[path_name] = text.replace(old, new, 1).encode()
bundle_patch_applied = True
elif path_name == "src/app/settings-pages/SettingsApp.svelte":
text = content.decode()
old = """ onChangeCallback={(e, v) => {
endpointUrlRaw.set(v);
restartRequired = true;
baseSettings.restartRequired = true;
}}
"""
new = """ onChangeCallback={(e, v) => {
if (endpointUrl === v) {
return;
}
endpointUrlRaw.set(v);
restartRequired = true;
baseSettings.restartRequired = true;
queueMicrotask(() => window.location.reload());
}}
"""
if old not in text:
raise SystemExit("AniDesk ASAR patch failed: endpoint source marker not found")
patched[path_name] = text.replace(old, new, 1).encode()
source_patch_applied = True
if not bundle_patch_applied:
raise SystemExit("AniDesk ASAR patch failed: runtime bundle was not patched")
if not source_patch_applied:
raise SystemExit("AniDesk ASAR patch failed: source view was not patched")
def rebuild(node, prefix="", offset_state=None, payload=None):
if offset_state is None:
offset_state = {"offset": 0}
if payload is None:
payload = []
new_node = copy.deepcopy(node)
for name, entry in list(new_node.get("files", {}).items()):
path_name = f"{prefix}{name}"
if "files" in entry:
new_node["files"][name] = rebuild(
entry, f"{path_name}/", offset_state, payload
)
continue
content = None
for candidate_path, candidate_content in entries:
if candidate_path == path_name:
content = patched.get(path_name, candidate_content)
break
if content is None:
continue
entry["size"] = len(content)
entry["offset"] = str(offset_state["offset"])
digest = hashlib.sha256(content).hexdigest()
entry["integrity"] = {
"algorithm": "SHA256",
"hash": digest,
"blockSize": 4194304,
"blocks": [digest],
}
offset_state["offset"] += len(content)
payload.append(content)
if prefix == "":
return new_node, payload
return new_node
new_header, payload = rebuild(header)
header_json = json.dumps(new_header, separators=(",", ":")).encode()
header_padded_size = (len(header_json) + 3) & ~3
asar_path.write_bytes(
struct.pack("<IIII", 4, header_padded_size + 8, header_padded_size + 4, len(header_json))
+ header_json
+ (b"\0" * (header_padded_size - len(header_json)))
+ b"".join(payload)
)
PY
install -dm755 "${pkgdir}/usr/bin"
install -Dm755 anidesk-wrapper "${pkgdir}/usr/bin/anidesk"
install -dm755 "${pkgdir}/usr/share"
cp -a "${srcdir}/extracted/usr/share/applications" "${pkgdir}/usr/share/"
cp -a "${srcdir}/extracted/usr/share/doc" "${pkgdir}/usr/share/"
cp -a "${srcdir}/extracted/usr/share/pixmaps" "${pkgdir}/usr/share/"
install -Dm644 anidesk.png "${pkgdir}/usr/share/pixmaps/anidesk.png"
install -dm755 "${pkgdir}/usr/share/icons/hicolor/256x256/apps"
install -Dm644 anidesk.png "${pkgdir}/usr/share/icons/hicolor/256x256/apps/anidesk.png"
install-license LICENSE "anidesk/LICENSE.nivora"
install-license "${srcdir}/extracted/usr/lib/anidesk/LICENSES.chromium.html" \
"anidesk/LICENSES.chromium.html"
install-license "${srcdir}/extracted/usr/share/doc/anidesk/copyright" \
"anidesk/LICENSE.electron"
}
files() {
files-find-binary
files-find-desktop
files-find-license
files-find \
"/usr/lib/anidesk/**/*" \
"/usr/share/doc/anidesk/*" \
"/usr/share/icons/hicolor/256x256/apps/anidesk.png" \
"/usr/share/pixmaps/anidesk.png"
}