From a5152dae76b124a0e2d955b6d51a3b324a05aa9b Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 1 Oct 2025 16:31:11 +0000 Subject: [PATCH] Restore files after forced sync --- .github/workflows/sync-build.yml | 121 ++++++++++++++ .github/workflows/update_domains.yml | 37 +++++ Dockerfiles/Dockerfile-auto-update | 4 +- Dockerfiles/Dockerfile-auto-update-no-config | 4 +- Dockerfiles/Dockerfile-es | 4 +- config.json | 30 ++-- update_domains.py | 159 +++++++++++++++++++ 7 files changed, 338 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/sync-build.yml create mode 100644 .github/workflows/update_domains.yml create mode 100644 update_domains.py diff --git a/.github/workflows/sync-build.yml b/.github/workflows/sync-build.yml new file mode 100644 index 0000000..6c92e20 --- /dev/null +++ b/.github/workflows/sync-build.yml @@ -0,0 +1,121 @@ +name: Conditional Sync Upstream, Build, and Push Docker Image + +on: + schedule: + - cron: '0 * * * *' # ogni ora + workflow_dispatch: + push: + branches: [main] + +jobs: + sync-build-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Backup files and force sync upstream + id: sync + run: | + git config user.name "github-actions" + git config user.email "actions@github.com" + + git remote get-url upstream || git remote add upstream https://github.com/UrloMythus/MammaMia.git + git fetch upstream + + # Controlla se ci sono differenze PRIMA del reset + if git diff --quiet HEAD upstream/main; then + echo "Repository already up to date" + echo "no_change=true" >> $GITHUB_OUTPUT + else + echo "Changes detected, proceeding with sync and build" + + backup_dir=".git/backup_files" + mkdir -p "$backup_dir/.github/workflows" + mkdir -p "$backup_dir/Dockerfiles" + + if [ -f config.json ]; then + cp config.json "$backup_dir/config.json" + else + echo "⚠️ config.json non trovato, skipping backup" + fi + + if [ -f update_domains.py ]; then + cp update_domains.py "$backup_dir/update_domains.py" + else + echo "⚠️ update_domains.py non trovato, skipping backup" + fi + + if [ -d .github/workflows ]; then + cp -r .github/workflows/* "$backup_dir/.github/workflows/" || echo "⚠️ No workflows to backup" + else + echo "⚠️ Cartella .github/workflows non trovata, skipping backup" + fi + + if [ -d Dockerfiles ]; then + cp -r Dockerfiles/* "$backup_dir/Dockerfiles/" || echo "⚠️ No Dockerfiles to backup" + else + echo "⚠️ Cartella Dockerfiles non trovata, skipping backup" + fi + + git checkout main || git checkout -b main + git reset --hard upstream/main + + if [ -f "$backup_dir/config.json" ]; then + cp "$backup_dir/config.json" config.json + else + echo "⚠️ File config.json non trovato nel backup, skipping restore" + fi + + if [ -f "$backup_dir/update_domains.py" ]; then + cp "$backup_dir/update_domains.py" update_domains.py + else + echo "⚠️ File update_domains.py non trovato nel backup, skipping restore" + fi + + mkdir -p .github/workflows + if [ -d "$backup_dir/.github/workflows" ]; then + cp -r "$backup_dir/.github/workflows/"* .github/workflows/ || echo "⚠️ No workflows to restore" + else + echo "⚠️ Backup workflows folder mancante, skipping restore" + fi + + mkdir -p Dockerfiles + if [ -d "$backup_dir/Dockerfiles" ]; then + cp -r "$backup_dir/Dockerfiles/"* Dockerfiles/ || echo "⚠️ No Dockerfiles to restore" + else + echo "⚠️ Backup Dockerfiles folder mancante, skipping restore" + fi + + git add . + git commit -m "Restore files after forced sync" || echo "No changes needed" + git push origin main --force + echo "no_change=false" >> $GITHUB_OUTPUT + + rm -rf "$backup_dir" + fi + + - name: Check if build is needed + run: echo "Changes detected, proceed with build." + if: steps.sync.outputs.no_change == 'false' + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + if: steps.sync.outputs.no_change == 'false' + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + if: steps.sync.outputs.no_change == 'false' + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + push: true + tags: dula117/mammamia:latest + if: steps.sync.outputs.no_change == 'false' diff --git a/.github/workflows/update_domains.yml b/.github/workflows/update_domains.yml new file mode 100644 index 0000000..e5d5c98 --- /dev/null +++ b/.github/workflows/update_domains.yml @@ -0,0 +1,37 @@ +name: Update Domains + +on: + schedule: + - cron: "0 20 * * *" # Esegui alle 20:00 ogni giorno + workflow_dispatch: # Permette di avviare manualmente il workflow + +jobs: + update-domains: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + pip install requests + + - name: Update domains in config.json + run: | + python update_domains.py + + - name: Commit and push changes + run: | + git config --global user.email "your-email@example.com" + git config --global user.name "Your Name" + git add config.json + git commit -m "Aggiornamento domini in config.json" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfiles/Dockerfile-auto-update b/Dockerfiles/Dockerfile-auto-update index 984f3e4..9566eb4 100644 --- a/Dockerfiles/Dockerfile-auto-update +++ b/Dockerfiles/Dockerfile-auto-update @@ -8,7 +8,7 @@ WORKDIR /app RUN apt-get update && apt-get install -y git # Clone the repository -RUN git clone https://github.com/UrloMythus/MammaMia.git . +RUN git clone https://github.com/vitouchiha/MammaMia.git . # Copy the local config.json file to the container COPY config.json /app/config.json @@ -20,4 +20,4 @@ RUN pip install --no-cache-dir -r requirements.txt EXPOSE 8080 # Run run.py when the container launches -ENTRYPOINT ["python", "run.py"] \ No newline at end of file +ENTRYPOINT ["python", "run.py"] diff --git a/Dockerfiles/Dockerfile-auto-update-no-config b/Dockerfiles/Dockerfile-auto-update-no-config index d9f97ee..bcbb4c9 100644 --- a/Dockerfiles/Dockerfile-auto-update-no-config +++ b/Dockerfiles/Dockerfile-auto-update-no-config @@ -8,7 +8,7 @@ WORKDIR /app RUN apt-get update && apt-get install -y git # Clone the repository -RUN git clone https://github.com/UrloMythus/MammaMia.git . +RUN git clone https://github.com/vitouchiha/MammaMia.git . # Install any needed packages specified in requirements.txt @@ -18,4 +18,4 @@ RUN pip install --no-cache-dir -r requirements.txt EXPOSE 8080 # Run run.py when the container launches -ENTRYPOINT ["python", "run.py"] \ No newline at end of file +ENTRYPOINT ["python", "run.py"] diff --git a/Dockerfiles/Dockerfile-es b/Dockerfiles/Dockerfile-es index 97d69f5..e5cec3c 100644 --- a/Dockerfiles/Dockerfile-es +++ b/Dockerfiles/Dockerfile-es @@ -7,7 +7,7 @@ RUN apt-get update && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -RUN git clone https://github.com/UrloMythus/MammaMia.git . +RUN git clone https://github.com/vitouchiha/MammaMia.git . RUN pip install --no-cache-dir -r requirements.txt @@ -15,4 +15,4 @@ RUN pip install --no-cache-dir pytesseract EXPOSE 8080 -ENTRYPOINT ["python", "run.py"] \ No newline at end of file +ENTRYPOINT ["python", "run.py"] diff --git a/config.json b/config.json index 60a1f96..ef541fb 100644 --- a/config.json +++ b/config.json @@ -9,51 +9,51 @@ "enabled": "1" }, "StreamingWatch":{ - "url":"https://www.streamingwatch.org", + "url": "https://www.streamingwatch.org", "SW_PROXY": "0", "SW_ForwardProxy": "0", "enabled":"1" }, "CB01":{ - "url":"https://cb01.uno", - "CB_PROXY":"0", + "url": "https://cb01net.xyz", + "CB_PROXY":"1", "CB_ForwardProxy":"0", "MX_ForwardProxy":"0", "MX_PROXY":"0", "enabled":"1" }, "Guardaserie":{ - "url":"https://guardaserie.qpon", + "url": "https://guardaserietv.help", "enabled":"1", "GS_ForwardProxy":"0", - "GS_PROXY":"0" + "GS_PROXY":"1" }, "GuardaHD":{ - "url":"https://mostraguarda.stream", + "url": "https://mostraguarda.stream", "enabled":"1", "GH_ForwardProxy":"0", - "GH_PROXY":"0" + "GH_PROXY":"1" }, "Eurostreaming":{ - "url": "https://eurostreaming.garden", + "url": "https://eurostreaming.dating", "enabled": "1", "ES_ForwardProxy": "0", - "ES_PROXY": "0" + "ES_PROXY": "1" }, "Guardaflix":{ "url": "https://guardaflix.live", "enabled": "1", "GF_ForwardProxy": "0", - "GF_PROXY": "0" + "GF_PROXY": "1" }, "Guardoserie":{ - "url": "https://guardoserie.live", + "url": "https://guardoserie.monster", "enabled": "1", "GO_ForwardProxy": "0", - "GO_PROXY": "0" + "GO_PROXY": "1" }, "AnimeWorld":{ - "url":"https://www.animeworld.so", + "url": "https://www.animeworld.ac", "enabled":"1", "AW_ForwardProxy":"0", "AW_PROXY":"0" @@ -63,8 +63,8 @@ "load_env": "0", "HOST": "0.0.0.0", "PORT": 8080, - "Name": "MammaMia", - "Icon": "🍕️", + "Name": "Nello", + "Icon": "🐶", "level": "info", "Global_Proxy": "0" } diff --git a/update_domains.py b/update_domains.py new file mode 100644 index 0000000..46955f1 --- /dev/null +++ b/update_domains.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +Merge remote URLs into local config.json, replacing ONLY the "url" lines. +- Scarica config.json remoto (raw GitHub). +- Per ogni sito in "Siti", segue i redirect e trova l'URL finale. +- Apre il config.json locale come testo, trova le righe "url" relative ai siti + e sostituisce SOLO il valore dentro le virgolette, preservando tutto il resto. +- Crea un backup del config.json locale prima di sovrascriverlo. +""" +from pathlib import Path +from datetime import datetime +import shutil +import re +import requests +import urllib3 +from urllib.parse import urlparse + +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +# --- CONFIGURAZIONE --- +REMOTE_RAW_URL = "https://raw.githubusercontent.com/UrloMythus/MammaMia/main/config.json" +LOCAL_CONFIG_PATH = Path("config.json") +HEADERS = {"User-Agent": "Mozilla/5.0 (compatible; DomainMerger/1.0)"} +REQUEST_TIMEOUT = 12 +# ----------------------- + +def backup_file(path: Path) -> Path | None: + if not path.exists(): + return None + ts = datetime.now().strftime("%Y%m%d_%H%M%S") + bak = path.with_name(f"{path.name}.bak_{ts}") + shutil.copy2(path, bak) + return bak + +def normalize_url(u: str) -> str: + parsed = urlparse(u) + scheme = parsed.scheme if parsed.scheme else "https" + netloc = parsed.netloc or parsed.path + return f"{scheme}://{netloc}" + +def follow_redirect(url: str) -> str | None: + if not url.startswith(("http://", "https://")): + test = "http://" + url + else: + test = url + try: + r = requests.get(test, allow_redirects=True, headers=HEADERS, + timeout=REQUEST_TIMEOUT, verify=False) + return normalize_url(r.url) + except requests.RequestException as e: + print(f"⚠️ Redirect fallito per '{url}': {e}") + return None + +def load_remote_urls(remote_raw_url: str) -> dict: + """Scarica il JSON remoto e ritorna mappa site_key -> url (o None se mancante).""" + try: + r = requests.get(remote_raw_url, headers=HEADERS, timeout=REQUEST_TIMEOUT) + r.raise_for_status() + remote_json = r.json() + except Exception as e: + raise RuntimeError(f"Impossibile scaricare/parsing remote config: {e}") + + siti = remote_json.get("Siti", {}) + result = {} + for site_key, site_info in siti.items(): + url = site_info.get("url") + if url: + result[site_key] = url + return result + +def merge_remote_into_local(remote_map: dict, local_path: Path): + if not local_path.exists(): + raise FileNotFoundError(f"File locale non trovato: {local_path}") + + # backup + bak = backup_file(local_path) + if bak: + print(f"📦 Backup creato: {bak.name}") + + text = local_path.read_text(encoding="utf-8") + lines = text.splitlines() + + # regex: match apertura blocco sito es. "CB01":{ + site_open_re = re.compile(r'^\s*"(?P[^"]+)"\s*:\s*\{\s*$') + + # regex per trovare esattamente la riga "url": "valore" preservando indentazione e virgola finale + url_line_re = re.compile(r'^(\s*)"url"\s*:\s*"([^"]*)"( *)(,?)\s*$') + + current_site = None + updated_lines = [] + changes = [] + + for idx, line in enumerate(lines): + site_match = site_open_re.match(line) + if site_match: + current_site = site_match.group("site") + updated_lines.append(line) + continue + + url_match = url_line_re.match(line) + if url_match: + indent = url_match.group(1) + old_value = url_match.group(2) + trailing_space = url_match.group(3) or "" + trailing_comma = url_match.group(4) or "" + site_key = current_site or "unknown" + + # se il sito esiste nella mappa remota, proviamo ad aggiornare + remote_url = remote_map.get(site_key) + if remote_url: + final_url = follow_redirect(remote_url) + if final_url and final_url != normalize_url(old_value): + # sostituisco solo la parte tra virgolette + new_line = f'{indent}"url": "{final_url}"{trailing_space}{trailing_comma}' + updated_lines.append(new_line) + changes.append((site_key, old_value, final_url)) + print(f"✅ {site_key}: {old_value} → {final_url}") + else: + # nessuna modifica (redirect fallito o identico) + updated_lines.append(line) + print(f"ℹ️ {site_key}: nessuna modifica per '{old_value}'") + else: + # il sito non è nella lista remota: non tocchiamo la riga + updated_lines.append(line) + print(f"ℹ️ {site_key}: nessun URL remoto per questo sito, riga lasciata invariata") + continue + + # linea normale + updated_lines.append(line) + + # Scrivo solo se ci sono cambiamenti (ma anche se non ci sono, sovrascrivo per coerenza) + new_text = "\n".join(updated_lines) + # preserva newline finale se il file originale ce l'aveva + if text.endswith("\n") and not new_text.endswith("\n"): + new_text += "\n" + + local_path.write_text(new_text, encoding="utf-8") + print("💾 Merge completato: solo le righe 'url' del file locale sono state eventualmente aggiornate.") + if not changes: + print("🔎 Nessun cambiamento effettuato.") + else: + print("📄 Riepilogo modifiche:") + for s, old, new in changes: + print(f" - {s}: {old} → {new}") + +def main(): + try: + remote_map = load_remote_urls(REMOTE_RAW_URL) + except Exception as e: + print(f"❌ Errore: {e}") + return + + try: + merge_remote_into_local(remote_map, LOCAL_CONFIG_PATH) + except Exception as e: + print(f"❌ Errore durante il merge: {e}") + +if __name__ == "__main__": + main()