Skip to content

Merge pull request #20 from JRailgun/patch-6 #41

Merge pull request #20 from JRailgun/patch-6

Merge pull request #20 from JRailgun/patch-6 #41

name: Convert TXT to MRS
on:
push:
branches: [main]
paths:
- "*.txt"
workflow_dispatch:
jobs:
convert:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download mihomo
shell: bash
run: |
set -euo pipefail
VERSION="$(curl -fsSL https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt)"
echo "Downloading mihomo version: $VERSION"
curl -fsSL -o mihomo.gz "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/mihomo-linux-amd64-${VERSION}.gz"
gzip -d mihomo.gz
chmod +x mihomo
- name: Sort and convert files
shell: bash
run: |
set -euo pipefail
# Optional sorter for domain files in your repo; non-fatal for ip lists
for f in *.txt; do
[ -f "$f" ] || continue
python3 .github/scripts/sort_domains.py "$f" || true
done
# Build normalized input and detect type
cat > /tmp/prepare_rules.py <<'PY'
import ipaddress
import re
import sys
from pathlib import Path
src = Path(sys.argv[1])
dst = Path(sys.argv[2])
lines = src.read_text(encoding="utf-8", errors="ignore").splitlines()
out = []
for raw in lines:
s = raw.strip().replace("\r", "")
if not s:
continue
# remove comments
s = re.sub(r"\s+#.*$", "", s).strip()
if not s:
continue
# yaml header
if s.lower() == "payload:":
continue
# yaml item prefix "- "
s = re.sub(r"^\s*-\s*", "", s).strip()
# strip quotes
if (s.startswith('"') and s.endswith('"')) or (s.startswith("'") and s.endswith("'")):
s = s[1:-1].strip()
if s:
out.append(s)
if not out:
print("EMPTY")
dst.write_text("", encoding="utf-8")
sys.exit(0)
ip_like = 0
final_ip = []
final_domain = []
for s in out:
try:
if "/" in s:
n = ipaddress.ip_network(s, strict=False)
ip_like += 1
final_ip.append(str(n))
else:
ip = ipaddress.ip_address(s)
ip_like += 1
final_ip.append(f"{ip}/32" if ip.version == 4 else f"{ip}/128")
except ValueError:
final_domain.append(s)
# If mostly IP/CIDR -> ipcidr, else domain
ratio = ip_like / len(out)
if ratio >= 0.90:
rule_type = "ipcidr"
final = final_ip
else:
rule_type = "domain"
final = final_domain if final_domain else out
# dedupe keep order
seen = set()
uniq = []
for x in final:
if x not in seen:
seen.add(x)
uniq.append(x)
dst.write_text("\n".join(uniq) + ("\n" if uniq else ""), encoding="utf-8")
print(rule_type)
PY
SKIP_FILES="processes.txt"
for txt_file in *.txt; do
[ -f "$txt_file" ] || continue
if echo "$SKIP_FILES" | grep -qw "$txt_file"; then
echo "Skipping $txt_file"
continue
fi
base_name="${txt_file%.txt}"
mrs_input="$(mktemp)"
RULE_TYPE="$(python3 /tmp/prepare_rules.py "$txt_file" "$mrs_input")"
if [ "$RULE_TYPE" = "EMPTY" ] || [ ! -s "$mrs_input" ]; then
echo "Warning: No rules in $txt_file"
rm -f "$mrs_input"
continue
fi
echo "Detected type for $txt_file: $RULE_TYPE"
head -10 "$mrs_input" || true
./mihomo convert-ruleset "$RULE_TYPE" text "$mrs_input" "${base_name}.mrs"
if [ ! -f "${base_name}.mrs" ]; then
echo "Error: ${base_name}.mrs was not created"
rm -f "$mrs_input"
exit 1
fi
if [ "$RULE_TYPE" = "ipcidr" ]; then
size="$(wc -c < "${base_name}.mrs")"
if [ "$size" -lt 100 ]; then
echo "Error: ${base_name}.mrs too small (${size} bytes)"
rm -f "$mrs_input"
exit 1
fi
fi
rm -f "$mrs_input"
echo "Converted: $txt_file -> ${base_name}.mrs ($RULE_TYPE)"
done
- name: Commit changes
shell: bash
run: |
set -euo pipefail
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
shopt -s nullglob
files=( *.txt *.mrs )
if [ ${#files[@]} -eq 0 ]; then
echo "No txt/mrs files to add"
exit 0
fi
git add "${files[@]}"
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "Auto-convert TXT to MRS (domain + IPv4/IPv6 CIDR)"
git push
fi