diff --git a/.github/workflows/plugin-live-check.yml b/.github/workflows/plugin-live-check.yml index 2022e5363..5a40c003d 100644 --- a/.github/workflows/plugin-live-check.yml +++ b/.github/workflows/plugin-live-check.yml @@ -37,6 +37,7 @@ jobs: plugins/**/*.ts files_ignore: | plugins/**/*\[*\]*.ts + plugins/**/*.broken.ts plugins/multisrc/** - name: Determine Targets @@ -63,6 +64,9 @@ jobs: # Multisrc-generated files (plugins/**/*[...].ts) are excluded above. # They're produced from plugins/multisrc/*/template.ts + sources.json, # not hand-authored, so testing the generator is out of scope here. + # Parked broken sources (plugins/**/*.broken.ts) are excluded too: the + # `.broken.ts` suffix deliberately removes them from production + # compilation, so live-checking them can only fail by design. - name: Run Live Check id: live-check if: steps.targets.outputs.files != '' diff --git a/docs/testing.md b/docs/testing.md index 37136b95c..ea5ce6206 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -34,7 +34,8 @@ Each step reports one of three outcomes: ## CI -Any PR that touches a file under `plugins/**/*.ts` (excluding multisrc-generated files) runs this +Any PR that touches a file under `plugins/**/*.ts` (excluding multisrc-generated files and +parked `*.broken.ts` sources) runs this same check automatically against just the changed plugins, and posts the results as a job summary on the workflow run (visible from the PR's checks list, under the Actions tab) — not as a PR comment. The check only fails the PR on a genuine `FAIL` — `INCONCLUSIVE` results (a site being diff --git a/plugins/arabic/Markazriwayat.ts b/plugins/arabic/Markazriwayat.broken.ts similarity index 89% rename from plugins/arabic/Markazriwayat.ts rename to plugins/arabic/Markazriwayat.broken.ts index 4a0fe4e22..5648b586f 100644 --- a/plugins/arabic/Markazriwayat.ts +++ b/plugins/arabic/Markazriwayat.broken.ts @@ -1,3 +1,14 @@ +/** + * BROKEN - مركز الروايات (markazriwayat.com) serves no novel content on any route: + * a Cloudflare challenge answers direct requests, and the origin behind it only + * returns a "Coming Soon" placeholder with a theme 404 on every deeper path. + * There is nothing left to parse, so this source is excluded from production + * compilation by the `.broken.ts` suffix. + * + * Successor source: Galaxy Novels (galaxynovels.com) - announced by the same + * operators on their Coming Soon page as their affiliated site - is already + * available as the `galaxynovels` plugin. + */ import { load as parseHTML } from 'cheerio'; import { fetchApi } from '@libs/fetch'; import { Plugin } from '@/types/plugin'; @@ -12,7 +23,6 @@ class Markazriwayat implements Plugin.PluginBase { icon = 'src/ar/markazriwayat/icon.png'; site = 'https://markazriwayat.com/'; - filters = { order: { type: FilterTypes.Picker, @@ -82,15 +92,16 @@ class Markazriwayat implements Plugin.PluginBase { try { if (page > 1) return []; const apiUrl = `${this.site}wp-json/theam/v1/novel-search?term=${encodeURIComponent(searchTerm)}&per_page=20`; - const res = await fetchApi(apiUrl) + const res = await fetchApi(apiUrl); if (!res.ok) return []; const data = await res.json(); return (data.items || []).map( (item: { title: string; link: string; cover?: string }) => ({ - name: item.title, - path: item.link.replace(this.site, ''), - cover: item.cover || defaultCover, - })); + name: item.title, + path: item.link.replace(this.site, ''), + cover: item.cover || defaultCover, + }), + ); } catch { // Fallback: use library search HTML try { diff --git a/scripts/live-check-plugin.js b/scripts/live-check-plugin.js index 8f0977935..163524ba3 100644 --- a/scripts/live-check-plugin.js +++ b/scripts/live-check-plugin.js @@ -297,6 +297,17 @@ async function probeSiteReachability(site) { async function checkPlugin(pluginPath) { const result = { pluginPath, steps: [], loadError: null }; + // Parked broken sources are deliberately excluded from production + // compilation (see tsconfig.production.json) — live-checking them can + // only fail by design, so short-circuit to INCONCLUSIVE (never a FAIL). + if (pluginPath.endsWith('.broken.ts')) { + const step = makeStep('parkedBrokenSource'); + step.status = 'INCONCLUSIVE'; + step.detail = + 'Parked broken source (*.broken.ts): excluded from production compilation; live check skipped.'; + result.steps = [step]; + return result; + } let plugin; try { plugin = await loadPluginInstance(pluginPath);