PT-depiler
Copilot instructions2.7k starsChanged 7 days agoMITView on GitHub
PT-depiler is a browser extension (Manifest v3) for enhancing Private Tracker (PT) site usability: multi-site search, torrent / user-info management, and downloader integration. Stack: Vue 3 + TypeScript + Vuetify. ⚠️ Do not import the @ptd/site barrel into the service worker or the content-script bootstrap: it pulls the whole definitions graph. Use deep imports (@ptd/site/utils/html.ts, @ptd/site/types/base.ts, …) there.
We split this copilot-instructions.md into the rules it gives an agent
10 rules. About 0 are common, 2 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 50
Prefer letting the handler answer the question instead of shipping data to the caller: matchSocialPage / matchSitePage exist so that …
- Very specific: line 59
When factoring filters into a reusable const, annotate it (satisfies IElementQuery / TQueryFilter[]).
- Very specific: line 60
Prefer the shared named filters for parsing.
- Distinctive: line 64
Prefer local assets over remote URLs and inline data URIs.
- Very specific: line 70
Prefer ref() / reactive() / computed() over the Options API.
- Very specific: line 101
every TPatterns string compiles as a RegExp
- Very specific: line 116
Add src/packages/site/definitions/<id>.ts with siteMetadata (id = file name, urls, version per the engine convention in types/site.ts, …
- Very specific: line 118
Verify with pnpm check:site-definition src/packages/site/definitions/<id>.ts and then pnpm check.
- Very specific: line 127
Use chrome.* APIs with feature detection.
- Distinctive: line 128
Keep service-worker and background-page entry points separate (see the manifest section).
≈ “Common” is an estimate: at least 1 in 5 of the 3,669 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
PT-depiler AI Coding Agent Instructions
Project Overview
PT-depiler is a browser extension (Manifest v3) for enhancing Private Tracker (PT) site usability: multi-site search, torrent / user-info management, and downloader integration. Stack: Vue 3 + TypeScript + Vuetify.
- Toolchain: pnpm (>=12), Node >=23.7, TypeScript ~6.0, Vite 6.
- ~400 tracker engines' worth of site definitions ship in-tree under
src/packages/site/definitions/.
Architecture & Key Components
Web Extension Structure (src/entries/)
- Background service worker —
background/main.ts: ownschrome.*side effects (context menus, downloads, cookies, DNR rules, alarms) and theextStoragemessage handlers. - Content script —
content-script/index.ts: deliberately tiny. It only decides whether the current page belongs to an added site, then dynamically imports the real app (assets/cs-app.js, a separate multi-page ESM entry, see thecs-app-entryplugin invite.config.ts). Keep this bootstrap free of heavy imports (Vue / Vuetify /@ptd/site), otherwise every visited page pays for them. - Options page —
options/: the Vue 3 SPA. - Offscreen document —
offscreen/: owns IndexedDB and the scanning / social helpers; background and options reach it over messages. - Shared —
shared/: types and helpers used by several entries.
Module System (src/packages/)
- Site
@ptd/site— site definitions, engine schemas, metadata and scraping - Downloader
@ptd/downloader— qBittorrent, Transmission, Deluge, Aria2, Flood, ruTorrent, uTorrent, Synology Download Station - BackupServer
@ptd/backupServer— WebDAV, S3, Backblaze B2, Dropbox, Google Drive, Gist, CookieCloud, OWSS - MediaServer
@ptd/mediaServer— Jellyfin, Plex, Emby, fnOS - Social
@ptd/social— Douban, IMDb, TMDb, AniDB, Bangumi, TVmaze lookups
⚠️ Do not import the @ptd/site barrel into the service worker or the content-script bootstrap: it pulls the whole definitions graph. Use deep imports (@ptd/site/utils/html.ts, @ptd/site/types/base.ts, …) there.
Storage & State Management
- Extension storage:
@webext-core/storage, wrapped bysrc/entries/storage.ts. Keys:config,metadata,userInfo,searchResultSnapshot,keepUploadTask. Pinia stores persist throughpinia-plugin-state-persistence. - IndexedDB:
idb, databaseptd(v3), created only in the offscreen document (offscreen/adapter/indexdb.ts):social_information,download_history,favicon(siteId → icon path). Other contexts must go through messages. - ⚠️ The
metadata/userInfostores are large. Avoid reading a whole store in per-page code paths (getExtStorage("metadata")structured-clones the entire store) and avoid read-modify-write of a whole store when a narrower update is possible.
Development Patterns
Path Aliases (tsconfig.json)
"~/*": ["src/*"] // Root source files
"@/*": ["src/entries/*"] // Extension entries
"@ptd/*": ["src/packages/*"] // Modular packagesMessage Passing
- Declare every message in the
ProtocolMapinsrc/entries/messages.ts, and register exactly oneonMessage(...)handler for it — a declared message without a handler fails silently at runtime. Handlers live inbackground/utils/*oroffscreen/utils/*. - Pattern:
onMessage("messageType", handler)/sendMessage("messageType", data). - Prefer letting the handler answer the question instead of shipping data to the caller:
matchSocialPage/matchSitePageexist so that neither the social package nor the (large) metadata store ever reaches the content-script bootstrap.
Site Integration
- Engine schemas in
src/packages/site/schemas/:AbstractBittorrentSite,AbstractPrivateSite, plusNexusPHP,Unit3D,Gazelle,GazelleJSONAPI,AvistazNetwork,Luminance,Rartracker,TCG. - Site definitions in
src/packages/site/definitions/<id>.tsexportsiteMetadata(types insite/types/site.ts). The file name must equalsiteMetadata.id— the loader uses the file name assiteId. - Engine default metadata: every schema exports
SchemaMetadatatyped asTSchemaMetadata<键集>(site/types/site.ts) — enumerate the keys the engine always provides (Required<Pick<ISiteMetadata, K>>). Reading those keys then needs no!, while their values keep the declared types: definitions legitimately read optional members the engine never sets (noLoginAssert,requestConfig.params, …), which a narrowed literal type would reject. - Selector-based scraping:
IElementQuery(selector/attr/filters/switchFilters/elementProcess), parsed with Sizzle. filters: [{ name, args }]names must exist indefinedFilters(site/utils/filter.ts).runQueryFilters()silently skips unknown names, so a typo yields wrong values and nothing else. Two layers guard this:filter.tsdeclares its table withsatisfies Record<string, TQueryFilterFn>(soTDefinedFilterNamestays a real string-literal union and vue-tsc rejects bad names in typed positions), andpnpm check'scheckFilters()catches what the compiler cannot see (names behind ananyboundary, dynamically built configs).- When factoring filters into a reusable const, annotate it (
satisfies IElementQuery/TQueryFilter[]). Without a type annotationnamewidens tostringand the compile-time half of that guard stops protecting you. - Prefer the shared named filters for parsing; site-specific arithmetic is fine as an inline
(query) => ….
- When factoring filters into a reusable const, annotate it (
- Adult sites (tags containing 成人 / XXX / Adult) must keep
urls/legacyUrls/trackerUrlsin rot13 (restored at load time), and must not repeat their own domain in plaintext anywhere else — derive fromthis.url, or use a local asset. - Site icons:
public/icons/site/<id>.png|.ico|.svg. An explicitfavicon: "./x"in the metadata wins; otherwise lookup order is<id>.png→<id>.ico→<id>.svg.- Never rename an icon file. The resolved path string is cached per siteId in IndexedDB, so renaming 404s for existing users with no automatic recovery.
- Prefer local assets over remote URLs and inline data URIs; keep icons ≤256×256 (they render at 14–36 px; ≤128 is plenty).
- Overridable hooks live in
AbstractBittorrentSite:getSearchResult(),transformSearchPage(),transformListPage(),transformDetailPage(),getTorrentDownloadLink(),getTorrentDownloadRequestConfig(),getFieldData(),findElementsBySelectors(),parseWholeTorrentFromRow(),fixParsedTorrent().
Vue 3 Composition API
- Use
<script setup>consistently. - Prefer
ref()/reactive()/computed()over the Options API. - Vuetify 4 components with CSS utility classes; all user-facing strings go through vue-i18n.
Build & Development
Key Commands
pnpm dev # Vite dev server (HMR for the options page and cs-app)
pnpm build:dist # Build Chrome extension → dist-chrome/
pnpm build:dist-firefox # Build Firefox addon → dist-firefox/ (TARGET=firefox)
pnpm build:watch # Unminified watch build
pnpm check # vue-tsc --noEmit && tsx vite/scripts/checkSiteDefinition.ts && tsx vite/scripts/checkMdiIcons.ts
pnpm check:site-definition # Site-definition checks only (optionally with file paths)
pnpm check:mdi-icons # MDI icon names used in src/ vs the full font in public/lib/mdi
pnpm format # prettierManifest & Browser Targets
- There is no
manifest.jsonfile: the manifest is built inline invite.config.ts(manifest: () => ({ … })) and consumed byvite-plugin-web-extension. Keys prefixed{{chrome}}./{{firefox}}.are kept only in the matching build. - Chrome uses
background.service_worker→background/main.ts; Firefox usesbackground.page→background/firefox_main.html. That page entry is deliberate: an IIFEscriptsentry cannot code-split, would inline the offscreen dependency graph, and would duplicate the options vendor chunk. transformManifestremoves the CSS that the plugin would otherwise push intocontent_scripts.- Build-time
defines include__RESOURCE_SITE_ICONS__(icon file list) and version/commit metadata; the light site index is generated byvite/plugin/generateSiteIndex.ts, web-extension locales byvite/plugin/generateWebextLocales.ts. - Version/commit metadata comes from
vite/utils/gitInfo.ts, which shells out togit. It degrades instead of failing when git is missing or the directory has no.git(e.g. building from a GitHub source zip): it falls back toGITHUB_SHA/GITHUB_REF_NAME, then to placeholders (0.0.6.0,unknown).
Testing & Quality
- There is no unit-test framework in this repository — do not add test files expecting a runner. Verification is
pnpm checkplus a realpnpm build:dist. pnpm checkrunsvite/scripts/checkSiteDefinition.ts, which statically validates every definition and schema:- structure (id ↔ file name, duplicate
categorykeys, non-increasinglevelRequirementsids, non-URLurls, …) - every
TPatternsstring compiles as aRegExp - filter names (
filters/switchFiltersentries must exist indefinedFilters) - favicon usage (remote/data-URI favicons are flagged,
favicon: "./x"must resolve, local icons must not exceed 256×256) - the indexed-metadata contract (
INDEXED_METADATA_FIELDS↔pickSiteMetadataIndexEntry())
Errors fail the command; warnings and notes do not.
- structure (id ↔ file name, duplicate
- CI (
.github/workflows/action_build.yml) runspnpm check— blocking on pull requests,continue-on-erroronpushevents. Treat it as your own gate locally rather than relying on CI. - Prettier: 120 columns, semicolons, trailing commas, LF. Husky + lint-staged run Prettier on staged files.
Common Patterns
Adding New Site Support
- Pick the engine — override hooks on an existing schema, or add a new schema in
src/packages/site/schemas/. - Add
src/packages/site/definitions/<id>.tswithsiteMetadata(id= file name,urls,versionper the engine convention intypes/site.ts,category,search,userInfo,levelRequirements). - Override only what the engine's selectors cannot express.
- Verify with
pnpm check:site-definition src/packages/site/definitions/<id>.tsand thenpnpm check.
File Downloads
- Export a file with
downloadBlob()from@/options/utils.ts: it wraps theBlobinURL.createObjectURL()and callschrome.downloads.download()directly — options pages are extension pages with thedownloadspermission, so there is no reason to round-trip throughsendMessage("downloadFile")(and content scripts have nochrome.downloadsat all). It revokes the object URL once the download reachescomplete/interrupted. - The downloads API validates
filenamestrictly (a:in a timestamped name is rejected withInvalid filename), unlike<a download>, which silently sanitizes. So names go throughsanitizeFilename()(@ptd/utils/filename.ts) first. Do not reintroducefile-saver.
Cross-Browser Compatibility
- Use
chrome.*APIs with feature detection; the Firefox build maps what it can. - Keep service-worker and background-page entry points separate (see the manifest section).
- Conditional permissions belong in the inline manifest.
Error Handling
- Degrade gracefully on network failures instead of throwing away a whole page of results.
- Surface user-facing errors through i18n.
- Background job scheduling goes through
@webext-core/job-scheduler.
Key Dependencies
- Vue ecosystem: Vue 3.5, Vuetify 4, Vue Router 5, Pinia 4 (+
pinia-plugin-state-persistence), Vue I18n 11,@vueuse/core/@vueuse/components - Extension framework:
@webext-core/{messaging,storage,job-scheduler},vite-plugin-web-extension - HTTP & DOM: axios, sizzle,
parse-torrent,search-query-parser - Data:
idb,fflate(zip —jszipis no longer a dependency),webdav - Charts & graphics:
echarts+vue-echarts,konva+vue-konva - Crypto & utilities:
@noble/hashes,@noble/ciphers,es-toolkit,date-fns,nanoid,p-queue,filesize,url-join,valid-filename
This is a sophisticated multi-platform extension requiring careful attention to web extension APIs, cross-site scripting, and torrent ecosystem integrations.
Trending
Quiet since September.thin dataabout the whole repository
Who's talking about pt-plugins/PT-depiler
- iorate/wepub“Fail in Microsoft Edge publish”GitHub · Sep 17, 2026
- madwind/flexget_qbittorrent_mod“Remove dead sites”GitHub · May 13, 2026
The biggest 2 of 2 mentions linking to the repository that our crawl found. Each line is their own headline.
Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.
Of the Copilot instructions files we read, the 2,297 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

