├── .gitignore ├── libuosdevicea.Makefile ├── wechat-universal.install ├── wechat-license ├── wechat-universal.desktop ├── libuosdevicea.c ├── .SRCINFO ├── fetch_tencent_wechat_release.sh ├── PKGBUILD ├── fetch_uos_wechat_release.py └── wechat-universal.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /*.pkg.tar* 2 | /*.deb 3 | /pkg 4 | /src 5 | /.venv -------------------------------------------------------------------------------- /libuosdevicea.Makefile: -------------------------------------------------------------------------------- 1 | NAME := libuosdevicea 2 | SONAME := ${NAME}.so 3 | STRIP ?= strip 4 | 5 | ${SONAME}: ${SONAME}.unstripped 6 | ${STRIP} $< -o $@ 7 | 8 | ${SONAME}.unstripped: ${NAME}.c 9 | ${CC} ${CFLAGS} ${LDFLAGS} -fPIC -shared $< -o $@ 10 | 11 | -------------------------------------------------------------------------------- /wechat-universal.install: -------------------------------------------------------------------------------- 1 | post_install() { 2 | if [[ "$LANG" == "zh_CN.UTF-8" ]]; then 3 | echo '>> 注意!升级至4.0版本后,环境变量已统一至WECHAT_ 前缀' 4 | echo '>> 执行 `wechat-universal --help` 来查看相关帮助信息' 5 | else 6 | echo '>> Warning! After updating to v4.0, all environment variables are unified to be prefixed with WECHAT_' 7 | echo '>> Run `wechat-universal --help` to check for the help message' 8 | fi 9 | } 10 | -------------------------------------------------------------------------------- /wechat-license: -------------------------------------------------------------------------------- 1 | This package is subject to both Weixin End-User License Agreement (for Chinese users) and WECHAT – TERMS OF SERVICE (for non-Chinese users). 2 | Full text for Weixin End-User License Agreement available at: 3 | https://weixin.qq.com/cgi-bin/readtemplate?uin=&stype=&promote=&fr=&lang=zh_CN&ADTAG=&check=false&nav=faq&t=weixin_agreement&s=default 4 | Full text for WECHAT – TERMS OF SERVICE available at: 5 | https://www.wechat.com/en/service_terms.html -------------------------------------------------------------------------------- /wechat-universal.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Comment=WeChat Universal 3 | Comment[zh_CN]= 4 | TryExec=/usr/lib/wechat-universal/start.sh 5 | Exec=/usr/lib/wechat-universal/start.sh %u 6 | Icon=wechat-universal 7 | Name=WeChat (Universal) 8 | Name[zh_CN]=微信 Universal 9 | Categories=Network;InstantMessaging;Chat; 10 | Terminal=false 11 | Type=Application 12 | Keywords=wechat;weixin;we;w; 13 | Keywords[zh_CN]=微;微信;wechat;weixin;we; 14 | StartupWMClass=wechat 15 | X-GNOME-SingleWindow=true 16 | SingleMainWindow=true 17 | Actions=quit; 18 | 19 | [Desktop Action quit] 20 | Name=Quit WeChat 21 | Name[zh_CN]=退出 22 | Exec=/usr/lib/wechat-universal/stop.sh 23 | Icon=application-exit 24 | -------------------------------------------------------------------------------- /libuosdevicea.c: -------------------------------------------------------------------------------- 1 | /* 2 | * licensestub - compat layer for libuosdevicea 3 | * Copyright (C) 2024 Zephyr Lykos 4 | * Copyright (C) 2024 Guoxin "7Ji" Pu 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | */ 21 | #define _GNU_SOURCE 22 | 23 | #include 24 | 25 | #define declare_string_getter(suffix, constant) void uos_get_##suffix(char *const restrict out) { if (out) strcpy(out, constant); } 26 | 27 | declare_string_getter(mac, // MAC address with colon stripped 28 | "000000000000") 29 | declare_string_getter(hddsninfo, 30 | "SN") 31 | declare_string_getter(hwserial, // MD5 of hddsninfo 32 | "92666505ce75444ee14be2ebc2f10a60") 33 | declare_string_getter(mb_sn, // hardcoded 34 | "E50022008800015957007202c59a1a8-3981-2020-0810-204909000000") 35 | declare_string_getter(osver, 36 | "UnionTech OS Desktop") 37 | declare_string_getter(licensetoken, 38 | "djEsdjEsMSwyLDk5QUFFN0FBQVdRQjk5OFhKS0FIU1QyOTQsMTAsOTI2NjY1MDVjZTc1NDQ0ZWUxNGJlMmViYzJmMTBhNjAsQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE6ZjA3NjAwYzZkNmMyMDkyMDBkMzE5YzU2OThmNTc3MGRlYWY1NjAyZTY5MzUxZTczNjI2NjlhNzIyZTBkNTJiOTNhYzk0MmM3YTNkZTgxNjIxMmUwMDA1NTUwODg4N2NlMDQ4ODMyNTExY2JhNGFiMjdmYzlmZjMyYzFiNTYwNjMwZDI3ZDI2NmE5ZGIxZDQ0N2QxYjNlNTNlNTVlOTY1MmU5YTU4OGY0NWYzMTMwZDE0NDc4MTRhM2FmZjRlZGNmYmNkZjhjMmFiMDc5OWYwNGVmYmQ2NjdiNGYwYzEwNDhkYzExNjYwZWU1NTdlNTdmNzBlNjA1N2I0NThkMDgyOA==") 39 | 40 | int uos_is_active() { 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /.SRCINFO: -------------------------------------------------------------------------------- 1 | pkgbase = wechat-universal-bwrap 2 | pkgdesc = WeChat (Universal) with bwrap sandbox 3 | pkgver = 4.1.0.13 4 | pkgrel = 1 5 | url = https://linux.weixin.qq.com/ 6 | install = wechat-universal.install 7 | arch = x86_64 8 | arch = aarch64 9 | arch = loong64 10 | license = LicenseRef-wechat-license 11 | makedepends = patchelf 12 | depends = at-spi2-core 13 | depends = bubblewrap 14 | depends = flatpak-xdg-utils 15 | depends = jack 16 | depends = libpulse 17 | depends = libxcomposite 18 | depends = libxdamage 19 | depends = libxkbcommon-x11 20 | depends = libxrandr 21 | depends = mesa 22 | depends = nss 23 | depends = pango 24 | depends = xcb-util-image 25 | depends = xcb-util-keysyms 26 | depends = xcb-util-renderutil 27 | depends = xcb-util-wm 28 | depends = xdg-desktop-portal 29 | depends = xdg-user-dirs 30 | provides = wechat-universal 31 | conflicts = wechat-universal 32 | replaces = wechat-beta 33 | replaces = wechat-beta-bwrap 34 | noextract = wechat-universal-4.1.0.13-x86_64.deb 35 | noextract = wechat-universal-4.1.0.13-aarch64.deb 36 | noextract = wechat-universal-4.1.0.13-loong64.deb 37 | options = !strip 38 | options = !debug 39 | options = emptydirs 40 | source = wechat-universal.sh 41 | source = wechat-universal.desktop 42 | source = libuosdevicea.c 43 | source = libuosdevicea.Makefile 44 | source = wechat-license 45 | sha256sums = 05aa21a0b729b2184c5bb88c45fc832f15e957b81f711a59b19f33d60041cdb8 46 | sha256sums = 0563472cf2c74710d1fe999d397155f560d3ed817e04fd9c35077ccb648e1880 47 | sha256sums = fc3ce9eb8dee3ee149233ebdb844d3733b2b2a8664422d068cf39b7fb08138f8 48 | sha256sums = f05f6f907898740dab9833c1762e56dbc521db3c612dd86d2e2cd4b81eb257bf 49 | sha256sums = 898ebc397583d111db9a337e9d09aaee2f795fcd720e65cab5ce0e92efcd8f10 50 | source_x86_64 = wechat-universal-4.1.0.13-x86_64.deb::https://dldir1v6.qq.com/weixin/Universal/Linux/WeChatLinux_x86_64.deb 51 | sha256sums_x86_64 = 39858c484663f7739bb331acc05ba5d8a6eb4081323af129a6a27815fd3c0aa5 52 | source_aarch64 = wechat-universal-4.1.0.13-aarch64.deb::https://dldir1v6.qq.com/weixin/Universal/Linux/WeChatLinux_arm64.deb 53 | sha256sums_aarch64 = 5a872f2a1698546a28f4d7b55fb6d93d3c248f68d8de4ee0e04b90601fa9e1b8 54 | source_loong64 = wechat-universal-4.1.0.13-loong64.deb::https://dldir1v6.qq.com/weixin/Universal/Linux/WeChatLinux_LoongArch.deb 55 | sha256sums_loong64 = e7a20f6e95477197feabdc97bc45d153059d77182e5eb3ad0d908498997cfb33 56 | 57 | pkgname = wechat-universal-bwrap 58 | -------------------------------------------------------------------------------- /fetch_tencent_wechat_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Fetcher for tencent wechat release 3 | # Copyright (C) 2024-present Guoxin "7Ji" Pu 4 | 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as 7 | # published by the Free Software Foundation, either version 3 of the 8 | # License, or (at your option) any later version. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | # A full package URL looks like this: 20 | # https://dldir1v6.qq.com/weixin/Universal/Linux/WeChatLinux_x86_64.deb 21 | 22 | set -euo pipefail 23 | 24 | declare -A arches_tencent_from_archlinux=( 25 | ['x86_64']='x86_64' 26 | ['aarch64']='arm64' 27 | ['loong64']='LoongArch' 28 | ) 29 | 30 | name_prefix='wechat-universal-' 31 | url_prefix='https://dldir1v6.qq.com/weixin/Universal/Linux/WeChatLinux_' 32 | 33 | version_max=0 34 | body= 35 | declare -A names urls sha256sums 36 | 37 | for arch_archlinux in x86_64 aarch64 loong64; do 38 | url="${url_prefix}${arches_tencent_from_archlinux["${arch_archlinux}"]}.deb" 39 | name_temp="${name_prefix}unknown-${arch_archlinux}.deb.temp" 40 | curl -vLo "${name_temp}" "${url}" 41 | version=$( 42 | bsdtar -xOf "${name_temp}" ./control.tar.xz | 43 | xz -cdT0 | 44 | tar -xO ./control | 45 | sed -n 's/^Version: \+\(.\+\)$/\1/p' 46 | ) 47 | if vercmp "${version}" "${version_max}"; then 48 | version_max="${version}" 49 | fi 50 | sha256sum_deb=$(sha256sum "${name_temp}") 51 | name="${name_prefix}${version}-${arch_archlinux}.deb" 52 | mv "${name_temp}" "${name}" 53 | names["${arch_archlinux}"]="${name}" 54 | urls["${arch_archlinux}"]="${url}" 55 | sha256sums["${arch_archlinux}"]="${sha256sum_deb::64}" 56 | done 57 | 58 | echo "pkgver=${version_max}" 59 | for arch_archlinux in x86_64 aarch64 loong64; do 60 | printf "sources_%s=(\n '%s::%s'\n)\n" \ 61 | "${arch_archlinux}" "${names["${arch_archlinux}"]}" \ 62 | "${urls["${arch_archlinux}"]}" 63 | done 64 | for arch_archlinux in x86_64 aarch64 loong64; do 65 | printf "sha256sums_%s=(\n '%s'\n)\n" \ 66 | "${arch_archlinux}" "${sha256sums["${arch_archlinux}"]}" 67 | done -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: 7Ji 2 | # Maintainer: leaeasy 3 | # Contributor: devome 4 | 5 | _pkgname=wechat-universal 6 | pkgname=${_pkgname}-bwrap 7 | pkgver=4.1.0.13 8 | pkgrel=1 9 | pkgdesc="WeChat (Universal) with bwrap sandbox" 10 | arch=('x86_64' 'aarch64' 'loong64') 11 | url='https://linux.weixin.qq.com/' 12 | license=('LicenseRef-wechat-license') 13 | install="${_pkgname}".install 14 | provides=("${_pkgname}") 15 | conflicts=("${_pkgname}") 16 | replaces=('wechat-beta'{,-bwrap}) 17 | depends=( 18 | 'at-spi2-core' 19 | 'bubblewrap' 20 | 'flatpak-xdg-utils' 21 | 'jack' 22 | 'libpulse' 23 | 'libxcomposite' 24 | 'libxdamage' 25 | 'libxkbcommon-x11' 26 | 'libxrandr' 27 | 'mesa' 28 | 'nss' 29 | 'pango' 30 | 'xcb-util-image' 31 | 'xcb-util-keysyms' 32 | 'xcb-util-renderutil' 33 | 'xcb-util-wm' 34 | 'xdg-desktop-portal' 35 | 'xdg-user-dirs' 36 | ) 37 | makedepends=( 38 | 'patchelf' 39 | ) 40 | if [[ "${CARCH}" == loong64 ]]; then # This is needed instead of a plain declaration because AUR web would return all depends regardless of client's arch, AUR helpers would thus refuse to build the package on non-loong64 due to missing liblol 41 | depends_loong64=('liblol') 42 | fi 43 | options=(!strip !debug emptydirs) 44 | 45 | _lib_uos='libuosdevicea' 46 | 47 | source=( 48 | "${_pkgname}.sh" 49 | "${_pkgname}.desktop" 50 | "${_lib_uos}".{c,Makefile} 51 | 'wechat-license' 52 | ) 53 | 54 | _upstream_name='wechat' 55 | _deb_url_common='https://dldir1v6.qq.com/weixin/Universal/Linux/WeChatLinux_' 56 | _deb_prefix="${_pkgname}-${pkgver}-" 57 | 58 | source_x86_64=("${_deb_prefix}x86_64.deb::${_deb_url_common}x86_64.deb") 59 | source_aarch64=("${_deb_prefix}aarch64.deb::${_deb_url_common}arm64.deb") 60 | source_loong64=("${_deb_prefix}loong64.deb::${_deb_url_common}LoongArch.deb") 61 | 62 | noextract=("${_deb_prefix}"{x86_64,aarch64,loong64}.deb ) 63 | 64 | sha256sums=( 65 | '05aa21a0b729b2184c5bb88c45fc832f15e957b81f711a59b19f33d60041cdb8' 66 | '0563472cf2c74710d1fe999d397155f560d3ed817e04fd9c35077ccb648e1880' 67 | 'fc3ce9eb8dee3ee149233ebdb844d3733b2b2a8664422d068cf39b7fb08138f8' 68 | 'f05f6f907898740dab9833c1762e56dbc521db3c612dd86d2e2cd4b81eb257bf' 69 | '898ebc397583d111db9a337e9d09aaee2f795fcd720e65cab5ce0e92efcd8f10' 70 | ) 71 | 72 | sha256sums_x86_64=( 73 | '39858c484663f7739bb331acc05ba5d8a6eb4081323af129a6a27815fd3c0aa5' 74 | ) 75 | sha256sums_aarch64=( 76 | '5a872f2a1698546a28f4d7b55fb6d93d3c248f68d8de4ee0e04b90601fa9e1b8' 77 | ) 78 | sha256sums_loong64=( 79 | 'e7a20f6e95477197feabdc97bc45d153059d77182e5eb3ad0d908498997cfb33' 80 | ) 81 | 82 | prepare() { 83 | echo 'Extracting data from deb...' 84 | bsdtar --extract --to-stdout --file "${_deb_prefix}${CARCH}.deb" ./data.tar.xz | 85 | xz --to-stdout --decompress --threads 0 | 86 | tar --strip-components 2 --extract ./opt/"${_upstream_name}" ./usr/share/icons/hicolor 87 | 88 | mv share/icons/hicolor icons 89 | rm -rf share "${_upstream_name}"/libuosdevicea.so 90 | 91 | echo "Preparing to compile ${_lib_uos}.so..." 92 | mv "${_lib_uos}".Makefile Makefile 93 | 94 | echo 'Stripping executable permission of non-ELF files...' 95 | cd "${_upstream_name}" 96 | local _file 97 | find . -type f -perm /111 | while read _file; do 98 | if [[ $(file --brief "${_file}") == 'ELF '* ]]; then 99 | continue 100 | fi 101 | stat --printf ' %A => ' "${_file}" 102 | chmod u-x,g-x,o-x "${_file}" 103 | stat --format '%A %n' "${_file}" 104 | done 105 | 106 | echo 'Patching rpath...' 107 | patchelf --set-rpath '$ORIGIN' 'libwxtrans.so' 108 | echo " '\$ORIGIN' <= libwxtrans.so" 109 | cd vlc_plugins 110 | find . -type f | while read _file; do 111 | echo " '\$ORIGIN:\$ORIGIN/../..' <= vlc_plugins/${_file}" 112 | patchelf --set-rpath '$ORIGIN:$ORIGIN/../..' "${_file}" 113 | done 114 | } 115 | 116 | build() { 117 | echo "Building ${_lib_uos}.so stub by Zephyr Lykos..." 118 | make 119 | } 120 | 121 | package() { 122 | echo 'Popupating pkgdir with earlier extracted data...' 123 | mkdir -p "${pkgdir}"/opt 124 | cp -r --preserve=mode "${_upstream_name}" "${pkgdir}/opt/${_pkgname}" 125 | 126 | echo 'Installing icons...' 127 | for res in 16 32 48 64 128 256; do 128 | install -Dm644 \ 129 | "icons/${res}x${res}/apps/${_upstream_name}.png" \ 130 | "${pkgdir}/usr/share/icons/hicolor/${res}x${res}/apps/${_pkgname}.png" 131 | done 132 | 133 | local _wechat_root="${pkgdir}/usr/lib/${_pkgname}" 134 | 135 | echo 'Fixing licenses...' 136 | install -dm755 "${pkgdir}"/usr/lib/license # This is needed if /usr/lib/license/${_lib_uos}.so needs to be mounted in sandbox 137 | install -Dm755 {,"${_wechat_root}"/usr/lib/license/}"${_lib_uos}.so" 138 | echo 'DISTRIB_ID=uos' | 139 | install -Dm755 /dev/stdin "${_wechat_root}"/etc/lsb-release 140 | 141 | echo 'Installing scripts...' 142 | install -Dm755 wechat-universal.sh "${_wechat_root}"/common.sh 143 | ln -s common.sh "${_wechat_root}"/start.sh 144 | ln -s common.sh "${_wechat_root}"/stop.sh 145 | mkdir -p "${pkgdir}"/usr/bin 146 | ln -s ../lib/"${_pkgname}"/common.sh "${pkgdir}"/usr/bin/"${_pkgname}" 147 | 148 | echo 'Installing desktop files...' 149 | install -Dm644 "${_pkgname}.desktop" "${pkgdir}/usr/share/applications/${_pkgname}.desktop" 150 | 151 | echo 'Installing license...' 152 | install -Dm644 {,"${pkgdir}/usr/share/licenses/${_pkgname}/"}wechat-license 153 | } 154 | -------------------------------------------------------------------------------- /fetch_uos_wechat_release.py: -------------------------------------------------------------------------------- 1 | # Fetcher for UOS com.tencent.wechat release 2 | # Copyright (C) 2024-present Guoxin "7Ji" Pu 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as 6 | # published by the Free Software Foundation, either version 3 of the 7 | # License, or (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU Affero General Public License for more details. 13 | 14 | # You should have received a copy of the GNU Affero General Public License 15 | # along with this program. If not, see . 16 | 17 | 18 | # A full package URL looks like this: 19 | # https://home-store-packages.uniontech.com/appstore/pool/appstore/c/com.tencent.wechat/com.tencent.wechat_1.0.0.236_arm64.deb 20 | # For their safety, UOS mirrors verify client UAs for plain folder view across the whole site, except for exact file path 21 | # home, pro, etc are all just cnames that resolve to app-store-files 22 | # This is just like any other Debian mirrors: 23 | # https://mirrors.tuna.tsinghua.edu.cn/debian/pool/main/b/bash/bash_5.0-4_amd64.deb 24 | # Package list of a release from a debian mirror lives in a different folder like this: 25 | # https://mirrors.tuna.tsinghua.edu.cn/debian/dists/bullseye/main/binary-amd64/Packages.xz 26 | # Substitute the above and we get the following URL (eagle is the most recent release codename): 27 | # https://home-store-packages.uniontech.com/appstore/dists/eagle/appstore/binary-amd64/Packages.gz 28 | 29 | import requests 30 | import zlib 31 | import hashlib 32 | import os 33 | 34 | class Architecture: 35 | arch_uos: str 36 | arch_archlinux: str 37 | version: str 38 | url: str 39 | file: str 40 | sha256: str 41 | sha1: str 42 | md5: str 43 | 44 | def __init__(self, arch_uos: str, arch_archlinux: str): 45 | self.arch_uos = arch_uos 46 | self.arch_archlinux = arch_archlinux 47 | self.version = None 48 | self.url = None 49 | self.file = None 50 | self.size = None 51 | self.sha256 = None 52 | self.sha1 = None 53 | self.md5 = None 54 | 55 | def fetch(self, url_appstore: str, session: requests.Session): 56 | print(f"=> Fetching for architecture '{self.arch_uos}' (Uniontech OS) / '{self.arch_archlinux}' (Arch Linux)") 57 | url = f'{url_appstore}/dists/eagle/appstore/binary-{self.arch_uos}/Packages.gz' 58 | response = session.get(url, stream = True) 59 | if response.status_code != 200: 60 | raise Exception(f'Request code is {response.status_code}') 61 | decompressor = zlib.decompressobj(wbits = 31) 62 | data = bytearray() 63 | for chunk in response.iter_content(0x100000): 64 | data += decompressor.decompress(chunk) 65 | data += decompressor.flush() 66 | 67 | wechat = None 68 | for package in data.split(b'\n\n'): 69 | if package.startswith(b'Package: com.tencent.wechat\n'): 70 | wechat=package 71 | break 72 | if wechat is None: 73 | raise Exception(f"Failed to find package com.tencent.wechat for arch '{self.arch_uos}'") 74 | 75 | for line in package.split(b'\n'): 76 | if line.startswith(b'Version: '): 77 | self.version = line[9:].decode('utf-8') 78 | elif line.startswith(b'Filename: '): 79 | self.file = line[10:].decode('utf-8') 80 | elif line.startswith(b'Size: '): 81 | self.size = int(line[6:]) 82 | elif line.startswith(b'SHA256: '): 83 | self.sha256 = line[8:].decode('utf-8') 84 | elif line.startswith(b'SHA1: '): 85 | self.sha1 = line[6:].decode('utf-8') 86 | elif line.startswith(b'MD5sum: '): 87 | self.md5 = line[8:].decode('utf-8') 88 | if self.version is None: 89 | raise Exception("Failed to get version") 90 | if self.file is None: 91 | raise Exception(f"Failed to get remote filename") 92 | self.url = f"{url_appstore}/{self.file}" 93 | self.file = self.file.rsplit('/', 1)[-1] 94 | if self.size is None: 95 | raise Exception("Failed to get size") 96 | 97 | def cache(self, session: requests.Session): 98 | print(f"=> Caching for architecture '{self.arch_uos}' (Uniontech OS) / '{self.arch_archlinux}' (Arch Linux)") 99 | if os.path.exists(self.file): 100 | with open(self.file, "rb") as f: 101 | data = f.read() 102 | sha256 = hashlib.sha256(data).hexdigest() 103 | sha1 = hashlib.sha1(data).hexdigest() 104 | md5 = hashlib.md5(data).hexdigest() 105 | integ = True 106 | if sha256 != self.sha256: 107 | print(f"sha256 not right, local {sha256} != remote {self.sha256}") 108 | integ = False 109 | if sha1 != self.sha1: 110 | print(f"sha1 not right, local {sha1} != remote {self.sha1}") 111 | integ = False 112 | if md5 != self.md5: 113 | print(f"md5 not right, local {md5} != remote {self.md5}") 114 | integ = False 115 | if integ: 116 | print("All integ passed, no need to redownload") 117 | return 118 | os.remove(self.file) 119 | print("Some integ failed, re-downloading") 120 | 121 | response = session.get(self.url) 122 | if response.status_code != 200: 123 | raise Exception(f'Request code is {response.status_code}') 124 | sha256 = hashlib.sha256(response.content).hexdigest() 125 | sha1 = hashlib.sha1(response.content).hexdigest() 126 | md5 = hashlib.md5(response.content).hexdigest() 127 | integ = True 128 | if sha256 != self.sha256: 129 | print(f"sha256 not right, file {sha256} != repo {self.sha256}") 130 | integ = False 131 | if sha1 != self.sha1: 132 | print(f"sha1 not right, file {sha1} != repo {self.sha1}") 133 | integ = False 134 | if md5 != self.md5: 135 | print(f"md5 not right, file {md5} != repo {self.md5}") 136 | integ = False 137 | if not integ: 138 | print("Some integ passed, would not save it, try to re-cache") 139 | return 140 | print("All integ passed, saving it to disk") 141 | with open(self.file, "wb") as f: 142 | f.write(response.content) 143 | 144 | 145 | architectures=( 146 | Architecture('amd64', 'x86_64'), 147 | Architecture('arm64', 'aarch64'), 148 | Architecture('loongarch64', 'loong64') 149 | ) 150 | 151 | url_appstore='https://home-store-packages.uniontech.com/appstore' 152 | session = requests.Session() 153 | 154 | for architecture in architectures: 155 | architecture.fetch(url_appstore, session) 156 | for architecture in architectures: 157 | print(f"source_{architecture.arch_archlinux}=(\n\t'{architecture.url}'\n)") 158 | for architecture in architectures: 159 | print(f"sha256sums_{architecture.arch_archlinux}=(\n\t'{architecture.sha256}'\n)") 160 | for architecture in architectures: 161 | print(f"sha1sums_{architecture.arch_archlinux}=(\n\t'{architecture.sha1}'\n)") 162 | for architecture in architectures: 163 | print(f"md5sums_{architecture.arch_archlinux}=(\n\t'{architecture.md5}'\n)") 164 | 165 | print("Caching all files and verifying them...") 166 | for architecture in architectures: 167 | architecture.cache(session) 168 | -------------------------------------------------------------------------------- /wechat-universal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # wechat-universal.sh - wrapper for WeChat Universal 4 | # Copyright (C) 2024 Guoxin "7Ji" Pu 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | # 20 | 21 | dbus_call() { # $1: dest, $2: object path, $3: method 22 | local args=(dbus-send --session --dest="$1" --print-reply "${@:2}") 23 | echo "D-Bus calling with: ${args[@]}" >&2 24 | "${args[@]}" 25 | } 26 | 27 | # Based on: https://github.com/web1n/wechat-universal-flatpak/blob/91f5d0d246881077812881e800a22f5a02cea438/wechat.sh#L3 28 | notifier_get() { 29 | local dbus_item 30 | for dbus_item in $( 31 | dbus_call org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | 32 | sed -n 's/ string "\(org\.kde\.StatusNotifierItem.\+\)"/\1/p' 33 | ) 34 | do 35 | if dbus_call "${dbus_item}" \ 36 | /StatusNotifierItem \ 37 | org.freedesktop.DBus.Properties.Get \ 38 | string:org.kde.StatusNotifierItem \ 39 | string:Id | 40 | grep -q 'string "wechat"' 41 | then 42 | echo "${dbus_item}" 43 | return 44 | fi 45 | done 46 | } 47 | 48 | try_move_foreground() { 49 | # Try to find existing WeChat window first and display it, before actually opening a new one 50 | notifier_item=$(notifier_get) 51 | if [[ "${notifier_item}" ]]; then 52 | echo 'WeChat is already running, moving it to foreground' 53 | # Based on: https://github.com/web1n/wechat-universal-flatpak/blob/91f5d0d246881077812881e800a22f5a02cea438/wechat.sh#L25 54 | dbus_call "${notifier_item}" \ 55 | /StatusNotifierItem \ 56 | org.kde.StatusNotifierItem.Activate \ 57 | int32:0 \ 58 | int32:0 59 | return $? 60 | fi 61 | return 1 62 | } 63 | 64 | try_start() { 65 | # Data folder setup 66 | # If user has declared a custom data dir, no need to query xdg for documents dir, but always resolve that to absolute path 67 | if [[ "${WECHAT_DATA_DIR}" ]]; then 68 | WECHAT_DATA_DIR=$(readlink -f -- "${WECHAT_DATA_DIR}") 69 | else 70 | XDG_DOCUMENTS_DIR="${XDG_DOCUMENTS_DIR:-$(xdg-user-dir DOCUMENTS)}" 71 | if [[ -z "${XDG_DOCUMENTS_DIR}" ]]; then 72 | echo 'Error: Failed to get XDG_DOCUMENTS_DIR, refuse to continue' 73 | exit 1 74 | fi 75 | WECHAT_DATA_DIR="${XDG_DOCUMENTS_DIR}/WeChat_Data" 76 | fi 77 | echo "Using '${WECHAT_DATA_DIR}' as Wechat Data folder" 78 | WECHAT_FILES_DIR="${WECHAT_DATA_DIR}/xwechat_files" 79 | WECHAT_HOME_DIR="${WECHAT_DATA_DIR}/home" 80 | 81 | # Runtime folder setup 82 | XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-$(xdg-user-dir RUNTIME)}" 83 | if [[ -z "${XDG_RUNTIME_DIR}" ]]; then 84 | echo 'Error: Failed to get XDG_RUNTIME_DIR, refuse to continue' 85 | exit 1 86 | fi 87 | if [[ -z "${XAUTHORITY}" ]]; then 88 | echo 'Warning: No XAUTHORITY set, runnning in no-X environment? Generating it' 89 | export XAUTHORITY=$(mktemp "${XDG_RUNTIME_DIR}"/xauth_XXXXXX) 90 | echo "Info: Generated XAUTHORITY at '${XAUTHORITY}'" 91 | fi 92 | 93 | # wechat-universal only supports xcb 94 | export QT_QPA_PLATFORM=xcb \ 95 | QT_AUTO_SCREEN_SCALE_FACTOR=1 \ 96 | PATH="/sandbox:${PATH}" 97 | 98 | if [[ -z "${WECHAT_IME_WORKAROUND}" || "${WECHAT_IME_WORKAROUND}" == 'auto' ]]; then 99 | case "${XMODIFIERS}" in 100 | *@im=fcitx*) 101 | WECHAT_IME_WORKAROUND='fcitx' 102 | ;; 103 | *@im=ibus*) 104 | WECHAT_IME_WORKAROUND='ibus' 105 | ;; 106 | esac 107 | fi 108 | 109 | case "${WECHAT_IME_WORKAROUND}" in 110 | fcitx) 111 | echo "IME workaround for fcitx applied" 112 | export QT_IM_MODULE=fcitx \ 113 | GTK_IM_MODULE=fcitx 114 | ;; 115 | ibus) 116 | echo "IME workaround for ibus applied" 117 | export QT_IM_MODULE=ibus \ 118 | GTK_IM_MODULE=ibus \ 119 | IBUS_USE_PORTAL=1 120 | ;; 121 | esac 122 | 123 | BWRAP_DEV_BINDS=() 124 | for DEV_NODE in /dev/{nvidia{-uvm,ctl,*[0-9]},video*[0-9]}; do 125 | [[ -e "${DEV_NODE}" ]] && BWRAP_DEV_BINDS+=(--dev-bind "${DEV_NODE}"{,}) 126 | done 127 | 128 | # Custom exposed folders 129 | # echo "Hint: Custom binds could either be declared in '~/.config/wechat-universal/binds.list', each line a path, absolute or relative to your HOME; or as argument \`--bind [custom bind]\`" 130 | BWRAP_CUSTOM_BINDS=() 131 | if [[ -f "${WECHAT_CUSTOM_BINDS_CONFIG}" ]]; then 132 | mapfile -t WECHAT_CUSTOM_BINDS_PRESISTENT < "${WECHAT_CUSTOM_BINDS_CONFIG}" 133 | fi 134 | cd ~ # 7Ji: two chdir.3 should be cheaper than a lot of per-dir calculation 135 | for WECHAT_CUSTOM_BIND in "${WECHAT_CUSTOM_BINDS_RUNTIME[@]}" "${WECHAT_CUSTOM_BINDS_PRESISTENT[@]}"; do 136 | WECHAT_CUSTOM_BIND=$(readlink -f -- "${WECHAT_CUSTOM_BIND}") 137 | echo "Custom bind: '${WECHAT_CUSTOM_BIND}'" 138 | BWRAP_CUSTOM_BINDS+=(--bind "${WECHAT_CUSTOM_BIND}"{,}) 139 | done 140 | cd - > /dev/null 141 | 142 | DBUS_SESSION_BUS_PATH='' 143 | if [[ "${DBUS_SESSION_BUS_ADDRESS}" ]]; then 144 | DBUS_SESSION_BUS_PATH=$(echo "${DBUS_SESSION_BUS_ADDRESS}" | sed 's/^unix:\(.\+=.\+\)\?path=\(.\+\)\(,.\+=.\+\|$\)/\2/') 145 | fi 146 | if [[ -z "${DBUS_SESSION_BUS_PATH}" ]]; then 147 | DBUS_SESSION_BUS_PATH="${XDG_RUNTIME_DIR}/bus" 148 | echo "Failed to extract \$DBUS_SESSION_BUS_ADDRESS from \$DBUS_SESSION_BUS_ADDRESS (${DBUS_SESSION_BUS_ADDRESS}), using fallback ${DBUS_SESSION_BUS_PATH}" 149 | fi 150 | 151 | mkdir -p "${WECHAT_FILES_DIR}" "${WECHAT_HOME_DIR}" 152 | ln -snf "${WECHAT_FILES_DIR}" "${WECHAT_HOME_DIR}/xwechat_files" 153 | 154 | if [[ "${WECHAT_MULTIPLE_INSTANCE}" ]];then 155 | BWRAP_ARGS=( 156 | --unshare-user-try 157 | --unshare-ipc 158 | --unshare-uts 159 | --unshare-cgroup-try 160 | ) 161 | else 162 | BWRAP_ARGS=( 163 | # Drop privileges 164 | --unshare-all 165 | ) 166 | fi 167 | 168 | BWRAP_ARGS+=( 169 | --share-net 170 | --cap-drop ALL 171 | --die-with-parent 172 | 173 | # /usr 174 | --ro-bind /usr{,} 175 | --symlink usr/lib /lib 176 | --symlink usr/lib /lib64 177 | --symlink usr/bin /bin 178 | --symlink usr/bin /sbin 179 | --bind /usr/bin/{true,lsblk} 180 | 181 | # /sandbox 182 | --ro-bind /{usr/lib/flatpak-xdg-utils,sandbox}/xdg-open 183 | --ro-bind /usr/lib/wechat-universal/common.sh /sandbox/dde-file-manager 184 | 185 | # /dev 186 | --dev /dev 187 | --dev-bind /dev/dri{,} 188 | --tmpfs /dev/shm 189 | 190 | # /proc 191 | --proc /proc 192 | 193 | # /etc 194 | --ro-bind /etc/machine-id{,} 195 | --ro-bind /etc/passwd{,} 196 | --ro-bind /etc/nsswitch.conf{,} 197 | --ro-bind /etc/resolv.conf{,} 198 | --ro-bind /etc/localtime{,} 199 | --ro-bind-try /etc/fonts{,} 200 | 201 | # /sys 202 | --dir /sys/dev # hack for Intel / AMD graphics, mesa calling virtual nodes needs /sys/dev being 0755 203 | --ro-bind /sys/dev/char{,} 204 | --ro-bind /sys/devices{,} 205 | 206 | # /tmp 207 | --tmpfs /tmp 208 | --ro-bind-try /tmp/.X11-unix{,} # haayuya suggested this fix on Hyprland: [1] https://aur.archlinux.org/packages/wechat-universal-bwrap#comment-1046129 [2] https://github.com/hyprwm/Hyprland/pull/8874 209 | 210 | # /opt 211 | --ro-bind /opt/wechat-universal{,} 212 | --ro-bind-try /opt/lol{,} # Loong Old World (WeChat) on Loong New World (LoongArchLinux) 213 | 214 | # license fixups in various places 215 | --ro-bind {/usr/lib/wechat-universal,}/usr/lib/license 216 | --ro-bind {/usr/lib/wechat-universal,}/etc/lsb-release 217 | 218 | # /home 219 | --bind "${WECHAT_HOME_DIR}" "${HOME}" 220 | --bind "${WECHAT_FILES_DIR}"{,} 221 | --bind-try "${HOME}/.pki"{,} 222 | --ro-bind-try "${HOME}/.fontconfig"{,} 223 | --ro-bind-try "${HOME}/.fonts"{,} 224 | --ro-bind-try "${HOME}/.config/fontconfig"{,} 225 | --ro-bind-try "${HOME}/.local/share/fonts"{,} 226 | --ro-bind-try "${HOME}/.icons"{,} 227 | --ro-bind-try "${HOME}/.local/share/icons"{,} 228 | 229 | # /run 230 | --dev-bind /run/dbus{,} 231 | --ro-bind-try /run/systemd/userdb{,} 232 | --ro-bind-try "${XAUTHORITY}"{,} 233 | --ro-bind "${DBUS_SESSION_BUS_PATH}"{,} 234 | --ro-bind "${XDG_RUNTIME_DIR}/pulse"{,} 235 | ) 236 | 237 | case "${WECHAT_MULTIPLE_INSTANCE}" in 238 | '') 239 | # Single 240 | : 241 | ;; 242 | 'auto') 243 | # Multiple: tmpfs throwaway 244 | echo "Multiple instance: using throwaway tmpfs data dir" 245 | BWRAP_ARGS+=( 246 | --tmpfs "${HOME}/.xwechat" 247 | --tmpfs "${WECHAT_FILES_DIR}/all_users" 248 | --tmpfs "${WECHAT_FILES_DIR}/WMPF" 249 | ) 250 | ;; 251 | *) 252 | # Multiple: persistent 253 | local INSTANCE_DATA_DIR=$(echo -n "${WECHAT_MULTIPLE_INSTANCE}" | md5sum) 254 | INSTANCE_DATA_DIR="${INSTANCE_DATA_DIR::32}" 255 | echo "Multiple instance: name '${WECHAT_MULTIPLE_INSTANCE}' => id '${INSTANCE_DATA_DIR}'" 256 | INSTANCE_DATA_DIR="${WECHAT_HOME_DIR}/.multi_xwechat_instance/${INSTANCE_DATA_DIR}" 257 | echo "Multiple instance: data dir is at '${INSTANCE_DATA_DIR}'" 258 | mkdir -p "${INSTANCE_DATA_DIR}"/{.xwechat,xwechat_files/all_users/config,xwechat_files/WMPF} 259 | BWRAP_ARGS+=( 260 | --bind "${INSTANCE_DATA_DIR}/.xwechat" "${HOME}/.xwechat" 261 | --bind "${INSTANCE_DATA_DIR}/xwechat_files/all_users" "${WECHAT_FILES_DIR}/all_users" 262 | --bind "${INSTANCE_DATA_DIR}/xwechat_files/WMPF" "${WECHAT_FILES_DIR}/WMPF" 263 | ) 264 | ;; 265 | esac 266 | 267 | exec bwrap "${BWRAP_ARGS[@]}" "${BWRAP_CUSTOM_BINDS[@]}" "${BWRAP_DEV_BINDS[@]}" /opt/wechat-universal/wechat "$@" 268 | echo "Error: Failed to exec bwrap, rerun this script with 'bash -x $0' to show the full command history" 269 | return 1 270 | } 271 | 272 | applet_start() { 273 | IFS=':' read -r -a WECHAT_CUSTOM_BINDS_RUNTIME <<< "${WECHAT_CUSTOM_BINDS}" 274 | if [[ -z "${WECHAT_CUSTOM_BINDS_CONFIG}" && ! -v WECHAT_CUSTOM_BINDS_CONFIG ]]; then 275 | WECHAT_CUSTOM_BINDS_CONFIG=~/.config/wechat-universal/binds.list 276 | fi 277 | # Parsing arguments, for any option, argument > environment 278 | while (( $# )); do 279 | case "$1" in 280 | '--data') 281 | WECHAT_DATA_DIR="$2" 282 | shift 283 | ;; 284 | '--bind') 285 | WECHAT_CUSTOM_BINDS_RUNTIME+=("$2") 286 | shift 287 | ;; 288 | '--binds-config') 289 | WECHAT_CUSTOM_BINDS_CONFIG="$2" 290 | shift 291 | ;; 292 | '--ime') 293 | WECHAT_IME_WORKAROUND="$2" 294 | shift 295 | ;; 296 | '--no-callout') 297 | WECHAT_NO_CALLOUT='yes' 298 | ;; 299 | '--multiple') 300 | WECHAT_NO_CALLOUT='yes' 301 | case "$2" in 302 | ''|'auto') 303 | WECHAT_MULTIPLE_INSTANCE='auto' 304 | shift 305 | ;; 306 | --*) 307 | WECHAT_MULTIPLE_INSTANCE='auto' 308 | ;; 309 | *) 310 | WECHAT_MULTIPLE_INSTANCE="$2" 311 | shift 312 | ;; 313 | esac 314 | ;; 315 | '--help') 316 | if [[ "${LANG}" == zh_CN* ]]; then 317 | echo "$0 (--data [微信数据文件夹]) (--bind [自定义绑定挂载] (--bind ...))) (--ime [输入法]) (--help)" 318 | echo 319 | printf ' --%s\t%s\n' \ 320 | 'data [微信数据文件夹]' '微信数据文件夹的路径,绝对路径,或相对于用户HOME的相对路径。 默认:~/文档/Wechat_Data;环境变量: WECHAT_DATA_DIR' \ 321 | 'bind [自定义绑定挂载]' '自定义的绑定挂载,可被声明多次,绝对路径,或相对于用户HOME的相对路径。环境变量: WECHAT_CUSTOM_BINDS, (用冒号:分隔,与PATH相似)' \ 322 | 'binds-config [文件]' '以每行一个的方式列明应被绑定挂载的路径的纯文本配置文件,每行定义与--bind一致。默认:~/.config/wechat-universal/binds.list;环境变量:WECHAT_CUSTOM_BINDS_CONFIG' \ 323 | 'ime [输入法名称或特殊值]' '应用输入法对应环境变量修改,可支持:fcitx (不论是否为5), ibus,特殊值:none不应用,auto自动判断。默认: auto;环境变量: WECHAT_IME_WORKAROUND'\ 324 | 'no-callout ' '不要试图呼出已经在运行的微信实例。默认: 不设置;环境变量: WECHAT_NO_CALLOUT'\ 325 | 'multiple [name] ' '创建全新的微信实例,命名为[name],即使微信已在运行,从而进行多开;强制启用--no-callout。特殊值:留空(仅参数)或auto生成一次性tmpfs数据文件夹;环境变量: WECHAT_MULTIPLE_INSTANCE'\ 326 | 'help' '' 327 | echo 328 | echo "命令行参数比环境变量优先级更高,如果命令行参数与环境变量皆为空,则使用默认值" 329 | else 330 | echo "$0 (--data [wechat data]) (--bind [custom bind] (--bind ...))) (--ime [ime]) (--help)" 331 | echo 332 | printf ' --%s\t%s\n' \ 333 | 'data [wechat data]' 'Path to Wechat_Data folder, absolute or relative to user home, default: ~/Documents/Wechat_Data, as environment: WECHAT_DATA_DIR' \ 334 | 'bind [custom bind]' 'Custom bindings, could be specified multiple times, absolute or relative to user home, as environment: WECHAT_CUSTOM_BINDS (colon ":" seperated like PATH)' \ 335 | 'binds-config [file]' 'Path to text file that contains one --bind value per line, default: ~/.config/wechat-universal/binds.list, as environment: WECHAT_CUSTOM_BINDS_CONFIG'\ 336 | 'ime [input method]' 'Apply IME-specific workaround, support: fcitx (also for 5), ibus, default: auto, as environment: WECHAT_IME_WORKAROUND'\ 337 | 'no-callout ' 'do not try to call out an already running WeChat instance. default: not set, as environment: WECHAT_NO_CALLOUT'\ 338 | 'multiple [name]' 'Create a new, individual instance even if WeChat is already running, naming it as [name], useful when you want to keep multiple WeChat accounts online on a single host, enables --no-callout implicitly. special: (leave empty as argument or) auto, to generate the data dir in a throwaway tmpfs. default: not set, as environment: WECHAT_MULTIPLE_INSTANCE'\ 339 | 'help' '' 340 | echo 341 | echo "Arguments take priority over environment, if both argument and environment are empty, the default value would be used" 342 | fi 343 | return 0 344 | ;; 345 | *) 346 | echo "Unknown option: $1, pass --help to read help message" 347 | return 1 348 | ;; 349 | esac 350 | shift 351 | done 352 | if [[ -z "${WECHAT_NO_CALLOUT}" ]] && try_move_foreground; then 353 | return 0 354 | else 355 | try_start "$@" 356 | return $? 357 | fi 358 | } 359 | 360 | applet_stop() { 361 | notifier_item=$(notifier_get) 362 | [[ -z "${notifier_item}" ]] && return 363 | echo 'Stopping running WeChat instance' 364 | # Based on: https://github.com/web1n/wechat-universal-flatpak/blob/91f5d0d246881077812881e800a22f5a02cea438/wechat.sh#L35 365 | dbus_call "${notifier_item}" \ 366 | /MenuBar \ 367 | com.canonical.dbusmenu.Event \ 368 | int32:1 \ 369 | string:clicked \ 370 | variant:string:'Quit WeChat' \ 371 | uint32:0 372 | } 373 | 374 | applet_dde() { 375 | local item= 376 | while (( $# )); do 377 | case "$1" in 378 | '--show-item') 379 | item="$2" 380 | shift 381 | ;; 382 | esac 383 | shift 384 | done 385 | if [[ "${item}" ]]; then 386 | local path object target 387 | path=$(readlink -f -- "${item}") # Resolve this to absolute path that's same across host / guest 388 | echo "Fake deepin file manager: dbus-send to open '${path}' in file manager" 389 | if [[ -d "${path}" ]]; then 390 | # WeChat pass both files and folders in the same way, if we use ShowItems for folders, 391 | # it would open that folder's parent folder, which is not right. 392 | object=ShowFolders 393 | target=folders 394 | else 395 | object=ShowItems 396 | target=items 397 | fi 398 | exec dbus-send --print-reply --dest=org.freedesktop.FileManager1 \ 399 | /org/freedesktop/FileManager1 \ 400 | org.freedesktop.FileManager1."${object}" \ 401 | array:string:"file://${path}" \ 402 | string:fake-dde-file-manager-show-"${target}" 403 | # We should not fall to here, but add a fallback anyway 404 | echo "Fake deepin file manager: fallback: xdg-open to show '${path}' in file manager" 405 | exec xdg-open "${path}" 406 | else 407 | echo "Fake deepin file manager: xdg-open with args $@" 408 | exec xdg-open "$@" 409 | fi 410 | # At this stage, it's either: dbus-send not found, or xdg-open not found, this should not happen 411 | # In whatever case, bail out 412 | echo "Fake deepin file manager: could not open any thing, original args: $@" 413 | return 1 414 | } 415 | 416 | applet="${0##*/}" 417 | case "${applet}" in 418 | 'stop.sh'|'stop') 419 | applet_stop "$@" 420 | ;; 421 | 'start.sh'|'start'|'wechat-universal.sh'|'wechat-universal') 422 | applet_start "$@" 423 | ;; 424 | 'dde-file-manager') 425 | applet_dde "$@" 426 | ;; 427 | *) 428 | echo "Unknown applet '${applet}', allowed: start.sh (alias start, wechat-universal, wechat-universal.sh), stop.sh (alias stop)" 429 | false 430 | ;; 431 | esac 432 | exit $? 433 | --------------------------------------------------------------------------------