@ashdev/codex-plugin-release-tsundoku 1.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -0
- package/dist/index.js +1161 -0
- package/dist/index.js.map +7 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @ashdev/codex-plugin-release-tsundoku
|
|
2
|
+
|
|
3
|
+
A Codex release-source plugin that announces new volume and chapter coverage
|
|
4
|
+
for your tracked series using a [Tsundoku](https://github.com/AshDevFr) instance's
|
|
5
|
+
incremental series feed. **Notification-only** — Codex does not download anything.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **External-ID matching by weighted voting, no title fuzzing.** Series are
|
|
10
|
+
matched to your Codex catalog by provider IDs (MangaBaka, AniList, MAL,
|
|
11
|
+
MangaUpdates, Kitsu, Shikimori, Anime-Planet, Anime News Network). Because
|
|
12
|
+
some providers occasionally share/merge IDs across distinct series, each
|
|
13
|
+
shared ID *votes*: an agreeing ID adds its weight (MangaBaka 3, AniList 2,
|
|
14
|
+
rest 1), a disagreeing one subtracts it, and a series matches only when
|
|
15
|
+
agreement wins. So a trusted disagreement (different MangaBaka IDs) overrides
|
|
16
|
+
a sloppy agreement (a shared MAL ID), and genuinely ambiguous ties are
|
|
17
|
+
skipped rather than mis-attributed.
|
|
18
|
+
- **Filtered feed, no stored cursor.** Each poll `POST`s your tracked series'
|
|
19
|
+
`provider:externalId` set to Tsundoku's filtered `/api/v1/series/feed`, so the
|
|
20
|
+
response contains only your series (not the whole catalog). There's no
|
|
21
|
+
persisted cursor — every poll re-evaluates your tracked set's current
|
|
22
|
+
coverage and lets Codex dedup unchanged releases. Newly tracked series are
|
|
23
|
+
picked up automatically and untracked ones drop out, with no bookkeeping.
|
|
24
|
+
- **Volume- and chapter-aware.** The feed's merged, gap-preserving coverage
|
|
25
|
+
spans map directly onto Codex's release model.
|
|
26
|
+
|
|
27
|
+
## Authentication
|
|
28
|
+
|
|
29
|
+
None. The Tsundoku feed endpoint is public; you only need to point the plugin at
|
|
30
|
+
your instance with `baseUrl`.
|
|
31
|
+
|
|
32
|
+
## Admin Setup
|
|
33
|
+
|
|
34
|
+
### Adding the Plugin to Codex
|
|
35
|
+
|
|
36
|
+
Add the plugin from **Settings → Plugins** (it appears in the official plugin
|
|
37
|
+
gallery as "Tsundoku Releases"), or configure it manually:
|
|
38
|
+
|
|
39
|
+
- **Command:** `npx`
|
|
40
|
+
- **Args:**
|
|
41
|
+
```
|
|
42
|
+
-y
|
|
43
|
+
@ashdev/codex-plugin-release-tsundoku
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Set `baseUrl` to your Tsundoku instance (e.g. `https://tsundoku.example.com`)
|
|
47
|
+
and save. The plugin auto-registers a single source row ("Tsundoku Releases") in
|
|
48
|
+
**Settings → Release tracking**, where you can disable it, change the poll
|
|
49
|
+
interval, or trigger an immediate poll.
|
|
50
|
+
|
|
51
|
+
### Linking Series to Tsundoku
|
|
52
|
+
|
|
53
|
+
A series is matched whenever it carries at least one external ID that Tsundoku
|
|
54
|
+
also knows. Populate these by running a metadata refresh (e.g. the MangaBaka
|
|
55
|
+
metadata plugin) or by pasting an ID into the series' tracking panel. Supported
|
|
56
|
+
providers, in match-priority order:
|
|
57
|
+
|
|
58
|
+
`mangabaka`, `anilist`, `mal`, `mangaupdates`, `kitsu`, `shikimori`,
|
|
59
|
+
`anime_planet`, `anime_news_network`.
|
|
60
|
+
|
|
61
|
+
## Configuration
|
|
62
|
+
|
|
63
|
+
| Field | Required | Default | Description |
|
|
64
|
+
| ------------------ | -------- | ------- | ------------------------------------------------------------------------ |
|
|
65
|
+
| `baseUrl` | yes | — | Tsundoku instance base URL. The plugin appends `/api/v1/series/feed`. |
|
|
66
|
+
| `defaultLanguage` | no | `en` | ISO 639-1 tag stamped on every announcement (the feed carries none). |
|
|
67
|
+
| `pageLimit` | no | `100` | Items per feed page (1–500). |
|
|
68
|
+
| `requestTimeoutMs` | no | `10000` | Per-page fetch timeout in milliseconds. |
|
|
69
|
+
|
|
70
|
+
## How It Works
|
|
71
|
+
|
|
72
|
+
On each poll the plugin:
|
|
73
|
+
|
|
74
|
+
1. Builds a match context from your tracked series via the host's
|
|
75
|
+
`releases/list_tracked`, and derives the `provider:externalId` filter set.
|
|
76
|
+
2. `POST`s that filter to `/api/v1/series/feed`, paginating through the response
|
|
77
|
+
(cursor used only within the poll; nothing is persisted). The response is
|
|
78
|
+
narrowed to your tracked series.
|
|
79
|
+
3. Matches each returned item to a tracked series by weighted external-ID voting
|
|
80
|
+
(see Features); on a confident match it records a release candidate whose
|
|
81
|
+
`volumes`/`chapters` mirror the item's coverage and whose confidence reflects
|
|
82
|
+
the vote. When several feed entries map to the same Codex series, only the
|
|
83
|
+
best-scoring one is recorded (ambiguous ties are skipped).
|
|
84
|
+
4. Reports counters back to the host; the host applies its own threshold,
|
|
85
|
+
auto-ignore (for coverage you already own), and dedup.
|
|
86
|
+
|
|
87
|
+
The candidate's dedup key is the coverage high-water mark
|
|
88
|
+
(`tsundoku:{seriesId}:v{highestVolume}:c{highestChapter}`), so a new
|
|
89
|
+
announcement fires only when the frontier advances; re-delivery of the same
|
|
90
|
+
coverage dedups host-side. Because each poll re-evaluates the full tracked set,
|
|
91
|
+
**newly tracked series are backfilled on the next poll** and untracked ones stop
|
|
92
|
+
without any cursor bookkeeping.
|
|
93
|
+
|
|
94
|
+
If the very first feed page can't be fetched (e.g. `baseUrl` is wrong or the
|
|
95
|
+
instance is unreachable), the poll fails and the source shows `last_error` in
|
|
96
|
+
**Settings → Release tracking** rather than silently reporting "0 items". In
|
|
97
|
+
Docker, remember the plugin runs inside the worker container: use a URL the
|
|
98
|
+
container can resolve (e.g. `http://host.docker.internal:<port>`), not
|
|
99
|
+
`http://localhost:<port>`.
|
|
100
|
+
|
|
101
|
+
### Limitations
|
|
102
|
+
|
|
103
|
+
- **Default language.** Tsundoku tracks official release coverage and carries no
|
|
104
|
+
language, so every candidate uses `defaultLanguage` (`en` unless overridden).
|
|
105
|
+
Per-series language preferences still gate the high-water mark host-side.
|
|
106
|
+
- **Full re-walk each poll.** Each poll re-fetches the current coverage of your
|
|
107
|
+
whole tracked set (filtered server-side, so only your series). Cheap at
|
|
108
|
+
typical sizes and polled a few times a day; if it ever needs to scale, an
|
|
109
|
+
incremental cursor could be reintroduced (with explicit invalidation on
|
|
110
|
+
track/untrack).
|
|
111
|
+
- **High-water dedup.** A filled interior gap that doesn't move the highest
|
|
112
|
+
volume/chapter won't re-announce.
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Install dependencies
|
|
118
|
+
npm install
|
|
119
|
+
|
|
120
|
+
# Build the plugin
|
|
121
|
+
npm run build
|
|
122
|
+
|
|
123
|
+
# Type check
|
|
124
|
+
npm run typecheck
|
|
125
|
+
|
|
126
|
+
# Run tests
|
|
127
|
+
npm run test
|
|
128
|
+
|
|
129
|
+
# Lint
|
|
130
|
+
npm run lint
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Project Structure
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
src/
|
|
137
|
+
├── index.ts # Plugin lifecycle, config, source registration, poll loop
|
|
138
|
+
├── manifest.ts # Capability + config schema + supported providers
|
|
139
|
+
├── fetcher.ts # Feed wire types + paginated fetchFeedPage
|
|
140
|
+
├── matcher.ts # Weighted-vote external-ID matching + cross-item resolution
|
|
141
|
+
└── candidate.ts # Feed item → ReleaseCandidate mapping
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|