| name | legado-source |
| description | This skill should be used when creating or debugging book sources (书源) for Legado Tauri application. It provides specialized workflows for converting website URLs or Legado Android JSON configurations into executable JavaScript book source files. Triggered when users need to create novel, comic, or video book sources, debug existing sources, or query Legado-specific knowledge about CSS selectors, rule formats, and JS API structures. |
Legado 书源开发助手
Overview
This skill enables CodeBuddy to act as a Legado Tauri Book Source Assistant, helping users create executable JavaScript book sources for the Legado Tauri reading application. It follows a progressive disclosure workflow that reveals documentation in stages, avoiding context overflow from loading all APIs at once.
Core Principles
Run Environment: Boa JS Engine
Hard Prohibitions:
- Arrow functions /
class / browser DOM (document / window) / XMLHttpRequest
Core Rules:
- All network requests and HTML parsing via
legado.* host API
- HTTP host APIs are async Promises, use
async / await
- Crypto/hash APIs in Tauri version are sync (direct call, no
await); HarmonyOS version uses async
- Built-in browser compatibility layer:
fetch / Headers / Request / Response / URLSearchParams / FormData
- Use conservative syntax:
var + regular functions
Phase 1: Environment Constraints (Mandatory)
CLI Location
Default path: src-tauri\target\x86_64-pc-windows-msvc\release\legado_tauri.exe
Search or replace path as needed.
File Skeleton
var BASE = 'https://main-site-domain';
async function search(keyword, page) { }
async function bookInfo(bookUrl) { }
async function chapterList(tocUrl) { }
async function chapterContent(chapterUrl) { }
async function explore(page, category) { }
Phase 2: Determine Book Source Type
Before coding, determine the type:
| Type | @type | Characteristics | chapterContent Return |
|---|
| Novel | novel (default) | Text content, chapters are text paragraphs | Plain text string |
| Comic | comic | Image content, chapters return image URL arrays | JSON.stringify(imageUrls) |
| Video | video | Video content, chapters return play URLs | URL or JSON object |
| Music | music | Audio content | URL or JSON object |
Set @type accordingly before implementation.
Phase 3: Progressive Module Implementation
Workflow Order
explore → bookInfo → chapterList → chapterContent → search
Each module follows this loop:
Probe current module → Implement immediately → Test with CLI → Fix based on logs → Next module
CLI Test Commands
Use PowerShell (do NOT use 2>&1 which causes encoding issues):
# Explore (Discovery Page)
legado_tauri cli booksource-test ./booksources/书源名.js explore
legado_tauri cli booksource-test ./booksources/书源名.js explore 分类名 1
# Book Details
legado_tauri cli booksource-test ./booksources/书源名.js info <bookUrl>
# Chapter List
legado_tauri cli booksource-test ./booksources/书源名.js toc <tocUrl>
# Chapter Content
legado_tauri cli booksource-test ./booksources/书源名.js content <chapterUrl>
# Search
legado_tauri cli booksource-test ./booksources/书源名.js search <keyword>
# All (final test)
legado_tauri cli booksource-test ./booksources/书源名.js all <keyword>
# Direct JS eval (PREFERRED for probing sites)
legado_tauri cli booksource-eval ./booksources/书源名.js "search('keyword', 1).then(function(list){ return list.length; })"
# Verbose logging
legado_tauri --verbose cli booksource-eval ./booksources/书源名.js "search('keyword', 1)"
Module A: explore (Discovery Page)
Required APIs:
| API | Description |
|---|
legado.http.get(url, headers?) | GET request, returns response text |
legado.dom.parse(html) | Parse HTML → document handle |
legado.dom.selectAll(handle, sel) | CSS select all → handle array |
legado.dom.text(el) | Get element text |
legado.dom.attr(el, name) | Get attribute value |
legado.dom.selectText(handle, sel) | Shortcut: first match text |
legado.dom.selectAllTexts(handle, sel) | Shortcut: all texts array |
legado.dom.selectAllAttrs(handle, sel, attr) | Shortcut: all attribute values |
legado.log(msg) | Log (MUST use in every function) |
Implementation:
- Return category name array when
category === 'GETALL' or no match
- Return
BookItem[] when category matched
- Only extract fields available on list page (don't request detail pages)
- Skip if site doesn't support discovery
Module B: bookInfo (Book Details)
Use same HTTP + DOM APIs from Module A.
Implementation:
- Return comprehensive book info object
- Prefer OGP meta tags (
og:title, og:image)
tocUrl defaults to bookUrl
Module C: chapterList (Chapter List)
Additional API:
| API | Description | When Needed |
|---|
await legado.http.batchGet(urls) | Batch GET, returns BatchResult[] | Pagination with <select> |
Implementation:
- MUST return in forward order (Chapter 1 first)
- Deduplicate and filter irrelevant links
- Pagination: use
batchGet for <select>; use MAX_PAGES for "next page" to prevent infinite loops
Module D: chapterContent (Chapter Content)
Additional APIs:
| API | Description | When Needed |
|---|
legado.dom.remove(handle, sel) | Remove matched elements | Remove ad nodes |
legado.dom.html(el) | Get innerHTML | Preserve HTML tags |
Type Differences:
| Type | chapterContent Returns |
|---|
| Novel | Cleaned plain text string |
| Comic | JSON.stringify(['url1', 'url2', ...]) |
| Video | Direct URL or JSON with {url, type, headers, m3u8Content} |
Module E: search (Search - Implement Last)
Additional APIs:
| API | Description | When Needed |
|---|
legado.http.post(url, body, headers?) | POST request | Form-based search |
legado.urlEncodeCharset(str, charset) | Encoding conversion | GBK sites |
Implementation:
- UTF-8:
encodeURIComponent
- GBK:
legado.urlEncodeCharset
- Return
[] for empty results
Phase 4: Advanced APIs (On Demand)
Browser Probe (Dynamic Pages)
Use when pages require JS rendering, login, HttpOnly Cookie, or Cloudflare protection:
var result = legado.browser.run(url, 'return document.title', { visible: false });
var id = legado.browser.acquire('main');
legado.browser.navigate(id, url);
var html = legado.browser.html(id);
Image Hooks (Comics)
prepareImage — Before Download (URL Rewrite / Header Injection)
function prepareImage(url, pageIndex) {
return {
headers: {
'Referer': BASE + '/',
'Origin': BASE
}
};
}
processImage — After Download (Image Decryption / Stitching)
function processImage(base64Data, pageIndex, imageUrl) {
var img = legado.image.decode(base64Data);
var result = legado.image.encode(dest, 'jpg');
legado.image.free(img);
return result;
}
Crypto / Decrypt
var decrypted = legado.aesDecrypt(ciphertext, key, iv, 'CBC');
var decoded = legado.base64Decode(encoded);
Script Config Persistence
legado.config.write('my-source', 'token', tokenValue);
var token = legado.config.read('my-source', 'token');
Phase 5: Completion
Full Test
legado_tauri cli booksource-test ./booksources/书源名.js all <keyword>
TEST Function
async function TEST(type) {
if (type === '__list__') return ['search', 'explore'];
if (type === 'search') {
var r = await search('keyword', 1);
if (!r || r.length < 1) return { passed: false, message: 'No results' };
return { passed: true, message: 'Search returned ' + r.length + ' items' };
}
if (type === 'explore') {
var b = await explore(1, 'category');
if (!b || b.length < 1) return { passed: false, message: 'Empty explore' };
return { passed: true, message: 'Explore returned ' + b.length + ' items' };
}
return { passed: false, message: 'Unknown: ' + type };
}
Completion Criteria
Output & Context Control
- Default output: complete JS file for current module
- Minimal process explanation: current module → test result → key fixes
- Prohibited: long pre-analysis, excessive HTML dumps, candidate selector lists, unnecessary tutorials
- When context near full: complete current module loop first, keep only conclusions
Data Structures
BookItem
{ name, author, bookUrl, coverUrl, kind, lastChapter, latestChapter, latestChapterUrl, wordCount, chapterCount, updateTime, status }
ChapterInfo
{ name, url, group? }
Resources
See references/api_reference.md for detailed API documentation.
External Documentation Links