尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗
| Doc | Read it when |
|---|---|
docs/agent-guide.md | Start here. Complete tour of what the project does, how every pipeline stage works internally, and the invariants that silently break output. |
PROJECT.md | Adding a site: selector discovery, SPA/Cloudflare strategies, testing protocol. |
docs/development.md | Local dev setup, Docker image, workflow. |
docs/research.md | Background on RSSHub / rss-proxy and the ideas borrowed from them. |
AGENTS.md | Conventions for AI agents working in this repo. |
All feeds are listed on the index page,
grouped by category and language — that page and the OPML below are generated
from config/sites.yaml, so they are always current. The index page and the
reader are behind a password; the feeds themselves and feeds.opml are public,
because an RSS reader fetches them with nowhere to type one (see Security).
📥 Download OPML — import into Inoreader or any RSS reader, pre‑sorted into folders.
Feeds are enriched with TMDb posters, years, IMDb links, and YouTube trailer links. Each run regenerates in place: a source that fails transiently keeps its last published feed, and only a source the engine declares gone is dropped, after one retry pass.
Recent additions (migrated from PolitePaul): xfilme.ro (Filme + Episodes), XCinema.ro (Filme) and PortalulTauTV.info — all RO feeds, scraped directly with the http method.
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Install Playwright browser
python -m playwright install chromium
# Full pipeline
PYTHONPATH=. python scripts/generate_feeds.py
PYTHONPATH=. python scripts/enrich_feeds.py
PYTHONPATH=. python scripts/fix_feeds.py
PYTHONPATH=. python scripts/generate_index.py
# Just one site (matches `name` or the feed_file, with or without .xml;
# repeatable). Handy when iterating on one scraper.
PYTHONPATH=. python -m core.cli generate --site showrss
# One feed through the WHOLE flow (get -> enrich -> process). Order matters:
# generating rewrites the feed from the site's own RSS, which discards the
# article bodies enrichment added. Ends with a per-item body-length report.
./start.sh one gabriel-ursan
./start.sh one ghacks thehackernews
# Serve locally (static files only — the generated index/feeds, no UI)
./scripts/serve.sh
# Local Inoreader-style feed review UI (reads feeds/*.xml directly)
./scripts/start_reader.sh # opens http://localhost:8080/reader
Generated feeds are committed only by GitHub Actions: the update.yml
workflow rebuilds feeds/ in place (generate_feeds.py → enrich_feeds.py →
fix_feeds.py → generate_index.py) and pushes feeds/*.xml + feeds.opml
back to main so raw.githubusercontent.com serves the latest copy. Each run
updates the committed feeds rather than replacing the whole set, so a source
that fails transiently keeps its last published feed. Never commit a feed by
hand — local feeds/, index.html and feeds.opml are gitignored, and a local
run writes them to the working tree only.
scripts/local_reader.py serves an Inoreader-like review UI on
http://localhost:8080/reader. It reads the generated feeds/*.xml directly —
no TMDb key, no network scraping, no CI dependency — and groups feeds into
categories (Movies, Episodes, Torrents, …).
./scripts/start_reader.sh # colored control menu
./scripts/start_reader.sh status # one-shot: start|stop|restart|status|logs|open
./scripts/start_reader.sh regen # regenerate all feeds locally (long)
PORT=9000 ./scripts/start_reader.sh start # pick a different port
Menu item 7) (or regen) runs the same pipeline GitHub Actions uses —
generate_feeds.py → enrich_feeds.py → fix_feeds.py → generate_index.py
— so the reader can show freshly-generated feeds without CI. Drop a gitignored
.env in the repo root (TMDB_API_KEY=…) and the enrich step opens as well (the
script sources it automatically; without it that step is skipped).
The menu (or the one-shot actions) replaces the manual
pkill …; setsid nohup python3 …local_reader.py … incantation — it starts the
reader detached, verifies it is serving, and keeps a live log at /tmp/rss-reader.log.
Features: folder tree with unread counters, article list, read/unread state
(localStorage), search, and a Refresh button that re-parses the local feed
files. Use it to sanity-check feeds after generation before pushing.
player/ page, which passes tmdb/imdb/type, the season+episode parsed from the title, the resolved epguides slug and a year‑folded title. The page loads the embed servers, EpGuides (for TV) and TMDB in one iframe — an episode goes straight to its TMDb episode page — while IMDb and Trailer sit beside them as ↗ new‑tab links, because neither site will render inside a third‑party frame. The eight embed servers that read a TMDb id come first; VidSrc and VidAPI read an IMDb id, so they sit at the end of the row and are left out altogether when a title has no IMDb id to give them. The page also has a manual lookup row — TMDb id, IMDb id, Movie/TV, and Season/episode once TV is chosen — prefilled from the current URL and submitting new parameters, so any title can be played by id without going through a feed. When the frame is showing a TMDb page, that row gains a TMDb page box and a Get the TMDb id button: paste in (or copy, and leave the box empty) the address of the TMDb page you were reading, and the button clears the lookup and fills TMDb id, Movie/TV, season and episode from it — the player cannot read the frame's own address, so the page URL has to come from you./ — per‑feed health, last update, item countconfig/sites.yaml; no code changes neededGitHub Actions (cron @:19 hourly)
└─ GenerationEngine
├─ Fetcher (http → cloudscraper → Playwright fallback)
├─ Parser (elementpath XPath 2.0 → lxml XPath 1.0)
│ └─ category_selector — extract page‑level category classes
├─ DedupStore (URL‑based dedup, 500 URLs/site cap)
├─ Feed writer (feedgen — RSS 2.0)
├─ _fetch_extra_pages — multi‑page pagination
└─ _filter_items — blocked_categories + title_filter_patterns
config/sites.yaml — master site list (XPath selectors, fetch method, category, kind, blocked_categories, pages, enabled)core/config.py — SiteConfig dataclass: category_selector, blocked_categories, title_filter_patterns, pages, enabledcore/engine.py — orchestration: shuffle, stagger, timeout (240s), concurrent (6 sites), multi‑page fetchscraper/fetcher.py — 3‑strategy fetch chain with anti‑detection and browser challenge retryscraper/parser.py — XPath 2.0 parsing via elementpath, falls back to lxml XPath 1.0; category extractioncore/feed.py — RSS 2.0 generation with WebSub hub, syndication tags, TMDb poster sizingcore/tmdb.py — rate‑limited TMDb API client with in‑memory cache; search_movie(title) / search_tv(title) fallbacksscripts/enrich_feeds.py — enrichment orchestrator; routes each feed by its site category to a mode (streaming / article / none), overridable per site with enhance_modescripts/enrichers/streaming_enricher.py — streaming mode: TMDb ID lookup, title‑based year search, poster enrichment; cleans torrent‑style titles for TMDB search (TV episodes via /search/tv); injects IMDb + YouTube trailer search links, EpGuides series links and the ▶ Play link to the player/ pagescripts/enrichers/article_enricher.py + scripts/enrichers/ad_remover.py — article mode: fetch the full article body, strip ads/boilerplate, keep a featured imagescripts/fix_feeds.py — post‑processing: year formatting, poster style, per‑site chrome removal, magnet Download linksscripts/refresh_feed.py — runs get → enrich → process for named feeds only (./start.sh one <site>), then reports each item's body-text length so a truncated article is obvious| Field | Required | Description |
|---|---|---|
name | Yes | Unique site key (YAML key) |
url | Yes | Full page URL to scrape |
method | Yes | Fetch method: http, cloudscraper, playwright, or rss |
item_selector | Yes* | XPath 2.0 expression to select each listing item |
title_selector | Yes* | XPath for item title (relative to item) |
link_selector | Yes* | XPath for item link (relative to item) |
feed_file | No | Output filename (default: {name}.xml) |
enabled | No | false skips the site during generation while keeping its config (default: true). Use it to park duplicate or fallback feeds. Disabled sites are excluded from index.html/feeds.opml and from enrichment, and --site <name> reports them as unmatched. |
category | No | Feed category (movies, episodes, torrents, cinema, releases, blogs, news, cyber, tech, education, economy, local). Determines enrichment mode. |
kind | No | Content type: movie or series. When series, items route to TMDb TV search and receive EpGuides links. If unset, title-based heuristics (SxxEyy markers) are used. |
language | No | Language code (ro or en, default: ro) |
max_items | No | Maximum items per feed |
display_name | No | Human-readable feed title |
*Required for http, cloudscraper, and playwright methods. Native RSS/Atom feeds (method: rss) don't need XPath selectors.
| Source Category | Enrichment Mode | Description |
|---|---|---|
movies, episodes, cinema, torrents, releases | streaming | TMDb posters, years, IMDb links, trailer links, EpGuides |
blogs, news, cyber, tech, education, economy, local | article | Full article content extraction with ad removal |
| any | none | No enrichment (pass through) |
Use enhance_mode: none to skip enrichment for individual sites.
Edit config/sites.yaml, then run PYTHONPATH=. python scripts/generate_index.py to rebuild index.html and feeds.opml automatically.
For new sites, use the interactive onboarding:
PYTHONPATH=. python scripts/onboard_site.py
.github/workflows/update.yml — runs hourly + on push + manual dispatch:
index.html + feeds.opml--theirs for feeds)Secrets needed: TMDB_API_KEY, RSS_GENERATOR_PROXY_URL
(optional: TMDB_API_KEY2 for rate-limit failover, OMDB_API_KEY for the
IMDb/OMDb fallback when TMDb search misses)
Enable Settings → Actions → General → Workflow permissions: Read and write and set Settings → Pages → Source to GitHub Actions.
.github/workflows/lint.yml runs ruff on every PR and push to main. Rules are configured in pyproject.toml ([tool.ruff]); run locally with:
pip install ruff
ruff check .
index.html and reader.html are gated by a client-side password check
(scripts/pages_gate.py). The password lives in .pages_pass.txt, which is
gitignored and local only; what the repository and the deployed page carry
is a PBKDF2-HMAC-SHA256 verifier (random salt + 600 000 iterations) in
config/pages-gate.json. Rotate with python scripts/pages_gate.py --set-password,
and confirm the two halves agree with --check.
This is a speed bump, not access control. GitHub Pages serves static bytes: the
page's own markup is public, and anyone can defeat the prompt from a console.
It keeps casual visitors out of the two UI pages. feeds/*.xml and
feeds.opml stay public on purpose — they are what an RSS reader fetches.
Real access control would need a host that authenticates the request
(Cloudflare Access in front of Pages, or a private deployment).
Automated secret scanning runs on every push, PR, manual dispatch, and daily
schedule via .github/workflows/secret-scan.yml.
See SECURITY.md for reporting.
Detailed architecture and development reference:
PROJECT.md
enhance_mode |
| No |
Override enrichment mode: streaming (TMDb posters), article (full content), or none. Defaults to category-based mode. |
detail_article_selector | No | XPath for extracting full article content from detail pages (for article enrichment). |
ad_selectors | No | CSS selectors for removing ads/boilerplate during article enrichment. Default: .ad, .ad-container, .advertisement, #sidebar, .sidebar, .social-share, .comments, .related-posts. |
removals | No | Named chrome-removal modules applied to article bodies (e.g. comments, head-meta, blank-embeds). The catalogue is in docs/agent-guide.md. |
keep_titles | No | Publish titles exactly as scraped — no TMDb title replacement and no appended year (default: false). Use it for torrent feeds whose names already carry the year and release tags. |
player_servers | No | Ordered list of streaming embed server ids for this feed. A feed publishes only the single ▶ Play link into the player/ page (season/episode, epguides slug and a year‑folded title travel in its query string); the page keeps its own server list and renders one iframe button per server, so this option no longer changes feed output — it is kept for scripts/e2e_player_servers.py, which exercises each server against a live TMDb key. None (default) = per‑category default (cinesrc + vidsrc + vidlink + 2embed + medmedia03 + vidapi for torrents/releases, none for other categories); [] = disabled, currently equivalent to the default for what reaches the feed. Known ids: cinesrc, vidsrc, vidsrc_buzz, vidlink, vembed, vidnest, vidfast, 2embed, medmedia03, vidapi. See scripts/enrichers/player_servers.py. |