mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-26 20:52:52 +08:00
🎄 Sync 2026-09-29 23:49:35
This commit is contained in:
1 parent
2c45fa21e0
commit
a633bba059
4 files changed
-480
No files matched your search
@@ -1,85 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
ROOT_DIR="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)"
|
||||
OUT_DIR="${ROOT_DIR}/clashoo/files/usr/share/clashoo/nftables"
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
V2DAT_BIN="${V2DAT_BIN:-}"
|
||||
GEOIP_DAT_URL="${GEOIP_DAT_URL:-https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat}"
|
||||
V2DAT_PKG="${V2DAT_PKG:-github.com/kenzok8/v2dat}"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$TMP_DIR"
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
ensure_v2dat() {
|
||||
if [ -n "$V2DAT_BIN" ] && [ -x "$V2DAT_BIN" ]; then
|
||||
return 0
|
||||
fi
|
||||
if command -v v2dat >/dev/null 2>&1; then
|
||||
V2DAT_BIN="$(command -v v2dat)"
|
||||
return 0
|
||||
fi
|
||||
export GOBIN="${TMP_DIR}/bin"
|
||||
mkdir -p "$GOBIN"
|
||||
go install "${V2DAT_PKG}@latest"
|
||||
V2DAT_BIN="${GOBIN}/v2dat"
|
||||
}
|
||||
|
||||
render_nft_set() {
|
||||
local family="$1"
|
||||
local input_file="$2"
|
||||
local output_file="$3"
|
||||
local set_name="$4"
|
||||
|
||||
awk -v set_name="$set_name" -v set_type="$family" '
|
||||
BEGIN {
|
||||
print "set " set_name " {"
|
||||
print "\ttype " set_type ";"
|
||||
print "\tflags interval;"
|
||||
print "\tauto-merge;"
|
||||
print "\telements = {"
|
||||
first = 1
|
||||
}
|
||||
!/^[[:space:]]*$/ && !/^[[:space:]]*#/ {
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", $0)
|
||||
if ($0 == "")
|
||||
next
|
||||
if (!first)
|
||||
print ","
|
||||
printf "\t\t%s", $0
|
||||
first = 0
|
||||
}
|
||||
END {
|
||||
if (!first)
|
||||
print ""
|
||||
print "\t}"
|
||||
print "}"
|
||||
}
|
||||
' "$input_file" > "$output_file"
|
||||
}
|
||||
|
||||
mkdir -p "$OUT_DIR" "${TMP_DIR}/out"
|
||||
ensure_v2dat
|
||||
|
||||
curl -fsSL "$GEOIP_DAT_URL" -o "${TMP_DIR}/geoip.dat"
|
||||
"$V2DAT_BIN" unpack geoip -o "${TMP_DIR}/out" -f cn "${TMP_DIR}/geoip.dat"
|
||||
|
||||
CN_TXT="$(find "${TMP_DIR}/out" -type f -name '*_cn.txt' | head -1)"
|
||||
[ -n "${CN_TXT}" ] && [ -f "${CN_TXT}" ] || {
|
||||
echo "failed to unpack CN CIDRs from geoip.dat" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
awk 'index($0, ":") == 0 { print }' "${CN_TXT}" > "${TMP_DIR}/cn_ipv4.txt"
|
||||
awk 'index($0, ":") != 0 { print }' "${CN_TXT}" > "${TMP_DIR}/cn_ipv6.txt"
|
||||
|
||||
render_nft_set ipv4_addr "${TMP_DIR}/cn_ipv4.txt" "${OUT_DIR}/geoip_cn.nft" clashoo_china
|
||||
render_nft_set ipv6_addr "${TMP_DIR}/cn_ipv6.txt" "${OUT_DIR}/geoip6_cn.nft" clashoo_china6
|
||||
|
||||
echo "generated:"
|
||||
echo " ${OUT_DIR}/geoip_cn.nft"
|
||||
echo " ${OUT_DIR}/geoip6_cn.nft"
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
ROOT_DIR="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)"
|
||||
RULESET_DIR="${ROOT_DIR}/clashoo/files/usr/share/clashoo/ruleset"
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
GEOSITE_BASE="${GEOSITE_BASE:-https://cdn.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite}"
|
||||
GEOIP_BASE="${GEOIP_BASE:-https://cdn.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip}"
|
||||
# mihomo .mrs lives on the meta branch (binary, not .srs)
|
||||
META_GEOSITE_BASE="${META_GEOSITE_BASE:-https://cdn.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@meta/geo/geosite}"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$TMP_DIR"
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
fetch_ruleset() {
|
||||
tag="$1"
|
||||
base="$2"
|
||||
remote_name="${3:-$tag}"
|
||||
url="${base}/${remote_name}.srs"
|
||||
tmp_file="${TMP_DIR}/${tag}.srs"
|
||||
out_file="${RULESET_DIR}/${tag}.srs"
|
||||
|
||||
echo "fetch ${tag}.srs"
|
||||
curl -fsSL --retry 3 --retry-delay 2 "$url" -o "$tmp_file"
|
||||
[ -s "$tmp_file" ] || {
|
||||
echo "empty ruleset: $url" >&2
|
||||
exit 1
|
||||
}
|
||||
mv "$tmp_file" "$out_file"
|
||||
}
|
||||
|
||||
mkdir -p "$RULESET_DIR"
|
||||
rm -f "${RULESET_DIR}"/*.srs
|
||||
|
||||
# Minimal built-in set:
|
||||
# - geolocation-!cn: required by fake-ip DNS and broad non-CN routing.
|
||||
# - geosite-cn: local alias for subscription tags geolocation-cn/cn.
|
||||
# - cn-ip/private-ip: keep China/private IP direct without remote downloads.
|
||||
fetch_ruleset "geolocation-!cn" "$GEOSITE_BASE"
|
||||
fetch_ruleset "geosite-cn" "$GEOSITE_BASE" geolocation-cn
|
||||
fetch_ruleset "private-ip" "$GEOIP_BASE" private
|
||||
fetch_ruleset "cn-ip" "$GEOIP_BASE" cn
|
||||
|
||||
# mihomo cn.mrs replaces geosite:cn in fake-ip-filter so the core skips geosite.dat
|
||||
echo "fetch cn.mrs"
|
||||
curl -fsSL --retry 3 --retry-delay 2 "${META_GEOSITE_BASE}/cn.mrs" -o "${TMP_DIR}/cn.mrs"
|
||||
[ -s "${TMP_DIR}/cn.mrs" ] || {
|
||||
echo "empty ruleset: ${META_GEOSITE_BASE}/cn.mrs" >&2
|
||||
exit 1
|
||||
}
|
||||
mv "${TMP_DIR}/cn.mrs" "${RULESET_DIR}/cn.mrs"
|
||||
|
||||
echo "generated sing-box rule sets in ${RULESET_DIR}"
|
||||
@@ -1,281 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
FEED_BASE_URL="https://down.dllkids.xyz/openwrt-feed/clashoo"
|
||||
GITHUB_API_URL="https://api.github.com/repos/kenzok8/openwrt-clashoo/releases/latest"
|
||||
GITHUB_PROXY_PREFIX="${GITHUB_PROXY_PREFIX:-https://ghfast.top/}"
|
||||
TMP_DIR="/tmp/clashoo-install"
|
||||
|
||||
fetch_text() {
|
||||
url="$1"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL "$url"
|
||||
return $?
|
||||
fi
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -qO- "$url"
|
||||
return $?
|
||||
fi
|
||||
return 127
|
||||
}
|
||||
|
||||
download_file() {
|
||||
url="$1"
|
||||
out="$2"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fL "$url" -o "$out"
|
||||
return $?
|
||||
fi
|
||||
wget -qO "$out" "$url"
|
||||
}
|
||||
|
||||
download_url() {
|
||||
url="$1"
|
||||
case "$url" in
|
||||
https://github.com/*)
|
||||
printf '%s%s\n' "$GITHUB_PROXY_PREFIX" "$url"
|
||||
;;
|
||||
*)
|
||||
printf '%s\n' "$url"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
detect_manager() {
|
||||
if command -v opkg >/dev/null 2>&1; then
|
||||
echo opkg
|
||||
return
|
||||
fi
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
echo apk
|
||||
return
|
||||
fi
|
||||
echo "unsupported"
|
||||
}
|
||||
|
||||
detect_arch() {
|
||||
pm="$1"
|
||||
if [ "$pm" = "opkg" ]; then
|
||||
opkg print-architecture | awk '/^arch / {print $2}' | tail -n 1
|
||||
return
|
||||
fi
|
||||
# apk --print-arch 只回 CPU family(如 aarch64),丢掉 subtarget 后缀;
|
||||
# feed/release 产物用完整 target arch(aarch64_cortex-a53),优先读 DISTRIB_ARCH
|
||||
distrib_arch="$(sed -n "s/^DISTRIB_ARCH=['\"]\([^'\"]*\)['\"].*/\1/p" /etc/openwrt_release 2>/dev/null | head -n 1)"
|
||||
if [ -n "$distrib_arch" ]; then
|
||||
printf '%s\n' "$distrib_arch"
|
||||
else
|
||||
apk --print-arch
|
||||
fi
|
||||
}
|
||||
|
||||
detect_sdk() {
|
||||
if [ ! -r /etc/openwrt_release ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
release="$(sed -n "s/^DISTRIB_RELEASE=['\"]\\([^'\"]*\\)['\"]$/\\1/p" /etc/openwrt_release | head -n 1)"
|
||||
[ -n "$release" ] || return 1
|
||||
|
||||
sdk="$(printf '%s\n' "$release" | grep -Eo '[0-9]+\.[0-9]+' | head -n 1)"
|
||||
[ -n "$sdk" ] || return 1
|
||||
printf '%s\n' "$sdk"
|
||||
}
|
||||
|
||||
find_feed_filename() {
|
||||
package_name="$1"
|
||||
packages_text="$2"
|
||||
printf '%s\n' "$packages_text" | awk -v pkg="$package_name" '
|
||||
$0 == "Package: " pkg {
|
||||
in_pkg = 1
|
||||
next
|
||||
}
|
||||
in_pkg && /^Filename: / {
|
||||
sub(/^Filename: /, "")
|
||||
print
|
||||
exit
|
||||
}
|
||||
in_pkg && /^$/ {
|
||||
in_pkg = 0
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
find_manifest_value() {
|
||||
key="$1"
|
||||
manifest_text="$2"
|
||||
printf '%s\n' "$manifest_text" | sed -n "s/^${key}=//p" | head -n 1
|
||||
}
|
||||
|
||||
append_unique_word() {
|
||||
value="$1"
|
||||
list="$2"
|
||||
[ -n "$value" ] || {
|
||||
printf '%s\n' "$list"
|
||||
return
|
||||
}
|
||||
case " $list " in
|
||||
*" $value "*) ;;
|
||||
*) list="${list}${list:+ }${value}" ;;
|
||||
esac
|
||||
printf '%s\n' "$list"
|
||||
}
|
||||
|
||||
build_sdk_candidates() {
|
||||
pm="$1"
|
||||
candidates=""
|
||||
detected_sdk="$(detect_sdk || true)"
|
||||
candidates="$(append_unique_word "$detected_sdk" "$candidates")"
|
||||
|
||||
if [ "$pm" = "opkg" ]; then
|
||||
for sdk in 24.10 23.05 22.03 21.02; do
|
||||
candidates="$(append_unique_word "$sdk" "$candidates")"
|
||||
done
|
||||
else
|
||||
for sdk in 25.12 24.10; do
|
||||
candidates="$(append_unique_word "$sdk" "$candidates")"
|
||||
done
|
||||
fi
|
||||
|
||||
printf '%s\n' "$candidates"
|
||||
}
|
||||
|
||||
# Feed 结构:<base>/<sdk>/<arch>/<files> —— 与 dllkids setup.sh 对齐,不嵌 feedname 子目录
|
||||
feed_base_for() {
|
||||
printf '%s/%s/%s' "$FEED_BASE_URL" "$1" "$2"
|
||||
}
|
||||
|
||||
load_manifest_urls() {
|
||||
sdk="$1"
|
||||
arch="$2"
|
||||
base="$(feed_base_for "$sdk" "$arch")"
|
||||
manifest_url="${base}/manifest-clashoo.txt"
|
||||
manifest_text="$(fetch_text "$manifest_url" || true)"
|
||||
[ -n "$manifest_text" ] || return 1
|
||||
|
||||
core_file="$(find_manifest_value "core" "$manifest_text")"
|
||||
luci_file="$(find_manifest_value "luci" "$manifest_text")"
|
||||
i18n_file="$(find_manifest_value "i18n" "$manifest_text")"
|
||||
|
||||
[ -n "$core_file" ] || return 1
|
||||
[ -n "$luci_file" ] || return 1
|
||||
|
||||
CORE_URL="${base}/${core_file}"
|
||||
LUCI_URL="${base}/${luci_file}"
|
||||
I18N_URL=""
|
||||
[ -n "$i18n_file" ] && I18N_URL="${base}/${i18n_file}"
|
||||
return 0
|
||||
}
|
||||
|
||||
load_opkg_feed_urls() {
|
||||
sdk="$1"
|
||||
arch="$2"
|
||||
base="$(feed_base_for "$sdk" "$arch")"
|
||||
packages_url="${base}/Packages.gz"
|
||||
packages_text="$(fetch_text "$packages_url" || true)"
|
||||
if ! printf '%s' "$packages_text" | grep -q '^Package: '; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
core_file="$(find_feed_filename "clashoo" "$packages_text")"
|
||||
luci_file="$(find_feed_filename "luci-app-clashoo" "$packages_text")"
|
||||
i18n_file="$(find_feed_filename "luci-i18n-clashoo-zh-cn" "$packages_text")"
|
||||
|
||||
[ -n "$core_file" ] || return 1
|
||||
[ -n "$luci_file" ] || return 1
|
||||
|
||||
CORE_URL="${base}/${core_file}"
|
||||
LUCI_URL="${base}/${luci_file}"
|
||||
I18N_URL=""
|
||||
[ -n "$i18n_file" ] && I18N_URL="${base}/${i18n_file}"
|
||||
return 0
|
||||
}
|
||||
|
||||
load_github_urls() {
|
||||
arch="$1"
|
||||
ext="$2"
|
||||
payload="$(fetch_text "$GITHUB_API_URL" || true)"
|
||||
[ -n "$payload" ] || return 1
|
||||
|
||||
urls="$(printf '%s\n' "$payload" | sed -n 's/.*"browser_download_url":[[:space:]]*"\([^"]*\)".*/\1/p')"
|
||||
[ -n "$urls" ] || return 1
|
||||
|
||||
if [ "$ext" = "apk" ]; then
|
||||
CORE_URL="$(printf '%s\n' "$urls" | grep -E '/clashoo-[^-]+.*-r[0-9]+-'"$arch"'\.apk$' | head -n 1)"
|
||||
LUCI_URL="$(printf '%s\n' "$urls" | grep -E '/luci-app-clashoo-[^-]+.*-r[0-9]+-('"$arch"'|all)\.apk$' | head -n 1)"
|
||||
I18N_URL="$(printf '%s\n' "$urls" | grep -E '/luci-i18n-clashoo-zh-cn-[^-]+.*-r[0-9]+-('"$arch"'|all)\.apk$' | head -n 1)"
|
||||
else
|
||||
CORE_URL="$(printf '%s\n' "$urls" | grep -E '/clashoo_.*_'"$arch"'\.ipk$' | head -n 1)"
|
||||
LUCI_URL="$(printf '%s\n' "$urls" | grep -E '/luci-app-clashoo_.*_all\.ipk$' | head -n 1)"
|
||||
I18N_URL="$(printf '%s\n' "$urls" | grep -E '/luci-i18n-clashoo-zh-cn_.*_all\.ipk$' | head -n 1)"
|
||||
fi
|
||||
|
||||
[ -n "$CORE_URL" ] || return 1
|
||||
[ -n "$LUCI_URL" ] || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
PM="$(detect_manager)"
|
||||
if [ "$PM" = "unsupported" ]; then
|
||||
echo "No supported package manager found (opkg/apk)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCH="$(detect_arch "$PM")"
|
||||
[ -n "$ARCH" ] || { echo "Cannot detect architecture"; exit 1; }
|
||||
|
||||
SDK_CANDIDATES="$(build_sdk_candidates "$PM")"
|
||||
|
||||
EXT="ipk"
|
||||
[ "$PM" = "apk" ] && EXT="apk"
|
||||
|
||||
CORE_URL=""
|
||||
LUCI_URL=""
|
||||
I18N_URL=""
|
||||
|
||||
if [ -n "$SDK_CANDIDATES" ]; then
|
||||
for SDK in $SDK_CANDIDATES; do
|
||||
if load_manifest_urls "$SDK" "$ARCH"; then
|
||||
echo "Using R2 feed manifest: ${SDK}/${ARCH}"
|
||||
break
|
||||
fi
|
||||
if [ "$PM" = "opkg" ] && load_opkg_feed_urls "$SDK" "$ARCH"; then
|
||||
echo "Using R2 feed: ${SDK}/${ARCH}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$CORE_URL" ] || [ -z "$LUCI_URL" ]; then
|
||||
if load_github_urls "$ARCH" "$EXT"; then
|
||||
echo "Using GitHub latest release"
|
||||
else
|
||||
echo "Cannot find required packages for arch: $ARCH"
|
||||
echo "Detected package manager: $PM"
|
||||
echo "Tried SDKs: $SDK_CANDIDATES"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf "$TMP_DIR"
|
||||
mkdir -p "$TMP_DIR"
|
||||
|
||||
echo "Downloading packages..."
|
||||
download_file "$(download_url "$CORE_URL")" "$TMP_DIR/core.${EXT}"
|
||||
download_file "$(download_url "$LUCI_URL")" "$TMP_DIR/luci.${EXT}"
|
||||
if [ -n "$I18N_URL" ]; then
|
||||
download_file "$(download_url "$I18N_URL")" "$TMP_DIR/i18n.${EXT}"
|
||||
fi
|
||||
|
||||
echo "Installing packages with $PM..."
|
||||
if [ "$PM" = "opkg" ]; then
|
||||
# Refresh package lists so deps (yq, coreutils-nohup, kmod-*) resolve on fresh systems
|
||||
opkg update || echo "Warning: opkg update failed, dependency resolution may break"
|
||||
opkg install "$TMP_DIR/core.${EXT}" "$TMP_DIR/luci.${EXT}" ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"}
|
||||
else
|
||||
apk update || echo "Warning: apk update failed, dependency resolution may break"
|
||||
apk add --allow-untrusted "$TMP_DIR/core.${EXT}" "$TMP_DIR/luci.${EXT}" ${I18N_URL:+"$TMP_DIR/i18n.${EXT}"}
|
||||
fi
|
||||
|
||||
echo "Install complete."
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
echo "Stopping clashoo service..."
|
||||
/etc/init.d/clashoo stop >/dev/null 2>&1 || true
|
||||
/etc/init.d/clashoo disable >/dev/null 2>&1 || true
|
||||
|
||||
core_still_installed() {
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
apk list -I 2>/dev/null | grep -q "^clashoo-[0-9]"
|
||||
elif command -v opkg >/dev/null 2>&1; then
|
||||
opkg list-installed 2>/dev/null | grep -q "^clashoo "
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
if command -v opkg >/dev/null 2>&1; then
|
||||
echo "Removing packages with opkg..."
|
||||
opkg remove luci-i18n-clashoo-zh-cn luci-app-clashoo clashoo >/dev/null 2>&1 || true
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
echo "Removing packages with apk..."
|
||||
apk del luci-i18n-clashoo-zh-cn luci-app-clashoo clashoo >/dev/null 2>&1 || true
|
||||
else
|
||||
echo "No supported package manager found (opkg/apk), skip package removal."
|
||||
fi
|
||||
|
||||
# Always safe: purely runtime/temp files, never owned by the package manager.
|
||||
echo "Cleaning runtime temp files..."
|
||||
rm -rf /tmp/clashoo /tmp/clashoo-install /tmp/clashoo_* /tmp/luci* 2>/dev/null || true
|
||||
|
||||
# CRITICAL: only delete package-owned files (config / init.d / dirs) when the
|
||||
# core package was actually removed. If it's still installed - e.g. nikki, which
|
||||
# depends on the clashoo-provided `mihomo`, blocks `apk del clashoo` - deleting
|
||||
# these behind the package manager's back corrupts apk's state: the db keeps
|
||||
# owning files that no longer exist, so a later same-version reinstall only
|
||||
# writes `.apk-new` and never restores them, leaving the UI broken
|
||||
# ("kernel not installed" / start stuck). Leave them in place instead.
|
||||
if core_still_installed; then
|
||||
echo "WARNING: 'clashoo' is still installed because other packages depend on it"
|
||||
echo " (e.g. nikki depends on the clashoo-provided 'mihomo')."
|
||||
echo " Kept /etc/config/clashoo, /etc/init.d/clashoo and /etc/clashoo intact"
|
||||
echo " to avoid corrupting package state. Remove nikki first for a full"
|
||||
echo " uninstall, or just reinstall clashoo to refresh it."
|
||||
else
|
||||
echo "Cleaning package files..."
|
||||
rm -rf /etc/clashoo /usr/share/clashoo /usr/share/clashbackup 2>/dev/null || true
|
||||
rm -f /etc/init.d/clashoo /etc/config/clashoo 2>/dev/null || true
|
||||
fi
|
||||
|
||||
/etc/init.d/rpcd restart >/dev/null 2>&1 || true
|
||||
/etc/init.d/uhttpd restart >/dev/null 2>&1 || true
|
||||
/etc/init.d/dnsmasq restart >/dev/null 2>&1 || true
|
||||
/etc/init.d/firewall restart >/dev/null 2>&1 || true
|
||||
|
||||
echo "Uninstall & reset complete."
|
||||
Reference in new issue
Block a user