JavaScript プラグイン
この仕様は、オンラインのソースから Mankai に漫画を提供するプラグインの JSON 形式と JavaScript API を説明します。
JavaScript プラグインは読み取り専用のソースです。アプリは URL または貼り付けられた JSON からマニフェストを読み込み、非表示の WebKit Web ビューでコールバックスクリプトを実行します。
マニフェスト
「マニフェスト」のセクションマニフェストは JSON オブジェクトです。デコーダーが必須とするフィールドは id だけですが、利用する操作に必要なコールバックスクリプトも用意する必要があります。
type ScriptName = | 'isOnline' | 'getSuggestion' | 'search' | 'getList' | 'getMangas' | 'getMangaUpdates' | 'getDetailedManga' | 'getChapter' | 'getImage'
type PluginCapability = | 'onlineCheck' | 'suggestions' | 'list' | 'listByGenre' | 'listByStatus' | 'search' | 'searchByGenre' | 'searchByStatus' | 'searchByAuthor' | 'mangaDetails' | 'batchMangas' | 'mangaUpdates' | 'chapter' | 'image'
interface JsPluginManifest { id: string name?: string version?: string description?: string authors?: string[] repository?: string updatesUrl?: string availableGenres?: Genre[] scripts?: Record<ScriptName, string> configs?: Config[] getImageHeaders?: Record<string, string> cooldown?: Cooldown capabilities?: PluginCapability[]}メタデータのフィールド
「メタデータのフィールド」のセクション| フィールド | 型 | 説明 |
|---|---|---|
id |
string |
変更されない、全体で一意なプラグイン識別子です。永続ストレージの保存範囲の識別にも使います。 |
name |
string |
表示名です。省略すると ID を使います。 |
version |
string |
アプリに表示され、更新の比較に使われるプラグインのバージョンです。 |
description |
string |
ソース設定に表示する短い説明です。 |
authors |
string[] |
プラグインの作者です。既定値は [] です。 |
repository |
string |
ソースコードまたはプロジェクトの URL です。 |
updatesUrl |
string |
更新確認に使うマニフェストの URL です。 |
availableGenres |
Genre[] |
ソースが対応するジャンルです。既定値は [] です。 |
scripts |
Record<string, string> |
下記のスクリプト名をキーとする JavaScript ソースです。未知のキーは無視されます。 |
configs |
Config[] |
ユーザーが変更でき、スクリプトから参照できる設定です。既定値は [] です。 |
getImageHeaders |
Record<string, string> |
指定すると、Mankai はすべての画像 URL をこのヘッダー付きのネイティブリクエストで取得し、getImage スクリプトを呼び出しません。 |
cooldown |
Cooldown |
任意のリクエスト間隔と画像の同時取得数の制限です。 |
capabilities |
PluginCapability[] |
プラグインが対応する操作です。既定では mangaUpdates 以外のすべての機能が有効です。 |
スクリプトの形式
「スクリプトの形式」のセクション各スクリプトの値は、関数とエクスポートマーカーを含む文字列です。
async function isOnline() { const response = await fetch('https://example.com/') return response.ok}
export{isOnline as default};マーカーは export{functionName as default}; の形式にする必要があります。Mankai は実行前にマーカーを取り除き、指定された名前の関数を呼び出します。関数は同期でも非同期でも構いません。Mankai は結果を待機します。スクリプトには、エクスポートする関数に加えて補助関数を含めることもできます。
コールバックスクリプト
「コールバックスクリプト」のセクション任意の capabilities フィールドには、以下の値を指定できます。
onlineCheck, suggestions, list, listByGenre, listByStatus, search, searchByGenre, searchByStatus, searchByAuthor, mangaDetails, batchMangas, mangaUpdates, chapter, imageキーと関数シグネチャは次のとおりです。
| キー | 関数シグネチャ | 戻り値 |
|---|---|---|
isOnline |
isOnline() |
boolean |
getSuggestion |
getSuggestion(query) |
string[] |
search |
search(query, page, genre, status, isAuthor) |
Manga[] |
getList |
getList(page, genre, status) |
Manga[] |
getMangas |
getMangas(ids) |
Manga[] |
getMangaUpdates |
getMangaUpdates(mangas) |
メタデータの差分と更新フラグを持つ MangaUpdate[] |
getDetailedManga |
getDetailedManga(id) |
DetailedManga |
getChapter |
getChapter(manga, chapter) |
画像 URL の string[] |
getImage |
getImage(url) |
Base64 画像データ、または画像プロキシリクエストのオブジェクト |
各引数と戻り値の詳細を以下に説明します。
isOnline
「isOnline」のセクションソースに接続でき、利用可能な場合は true、それ以外は false を返します。例外を投げた場合や、真偽値以外を返した場合は、プラグイン呼び出しの失敗として扱われます。
getSuggestion(query)
「getSuggestion(query)」のセクション検索候補として使える文字列の配列を返します。マニフェストのキーは単数形の getSuggestion です。
async function getSuggestion(query) { const response = await fetch( `https://example.com/suggestions?q=${encodeURIComponent(query)}`, ) if (!response.ok) return [] return await response.json()}
export{getSuggestion as default};search(query, page, genre, status, isAuthor)
「search(query, page, genre, status, isAuthor)」のセクションタイトルまたは作者で漫画を検索します。page は 1 から始まるページ番号です。genre はジャンルにある文字列のいずれかで、status は状態にある数値のいずれかです。isAuthor が true の場合は、タイトル欄ではなく作者欄を検索します。簡易情報を持つ Manga オブジェクトの配列を返します。
getList(page, genre, status)
「getList(page, genre, status)」のセクションソースからページ単位の一覧を返します。page、genre、status の引数は search と同じです。
getMangas(ids)
「getMangas(ids)」のセクション指定された文字列 ID に対応する、漫画の簡易オブジェクトの配列を返します。一部の ID がソースに存在しなくなっている場合は、要求数より少ない項目を返しても構いません。
getMangaUpdates(mangas)
「getMangaUpdates(mangas)」のセクション各リクエスト項目には、漫画の ID と、Mankai が現在把握している最新チャプターが含まれます。このコールバックで、プラグイン側から更新動作を制御できます。Mankai の標準の一括比較を使う場合は、mangaUpdates 機能を指定しないでください。
interface MangaUpdateRequest { id: string latestChapter: Chapter}MangaUpdate[] を返します。各結果には id と updates が必要です。保存済みの漫画を更新ありとするかどうかは、updates フラグだけで決まります。メタデータは、updates が false の結果も含め、返されたすべての結果で更新されます。
interface MangaUpdate extends Manga { updates: boolean}async function getMangaUpdates(mangas) { const response = await fetch('https://example.com/manga/updates', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(mangas), }) if (!response.ok) return [] return await response.json()}
export{getMangaUpdates as default};たとえば { id: "completed-series", updates: false, status: 2 } を返すと、未読の更新として表示せずに状態を更新できます。
getDetailedManga(id)
「getDetailedManga(id)」のセクション完全な DetailedManga オブジェクトを返します。Mankai は戻り値を JSON にシリアライズしてからデコードするため、JSON 文字列ではなく JavaScript オブジェクトを返してください。
getChapter(manga, chapter)
「getChapter(manga, chapter)」のセクションchapter の画像 URL を表示順に返します。manga は getDetailedManga が返した完全なオブジェクトで、chapter は選択されたチャプターのオブジェクトです。Mankai は後から各画像 URL を getImage に渡すため、画像 URL は絶対 URL にしてください。
async function getChapter(manga, chapter) { const response = await fetch( `https://example.com/manga/${encodeURIComponent(manga.id)}/chapter/${encodeURIComponent(chapter.id)}`, ) if (!response.ok) return [] return await response.json()}
export{getChapter as default};getImage(url)
「getImage(url)」のセクションgetImageHeaders がない場合、Mankai は表紙とチャプターのページに対してこのスクリプトを呼び出します。次のいずれかを返せます。
-
画像のバイト列を Base64 でエンコードした文字列です。
data:image/...;base64,の接頭辞は含めないでください。 -
Mankai にネイティブリクエストを指示するオブジェクトです。
interface ImageProxyRequest {url: stringheaders: Record<string, string>}
例を示します。
async function getImage(url) { return { url, headers: { Referer: 'https://example.com/', 'User-Agent': 'Mozilla/5.0', }, }}
export{getImage as default};マニフェストに getImageHeaders がある場合は、すべての画像 URL に対して同等のネイティブリクエストが自動的に行われます。
{ "getImageHeaders": { "Referer": "https://example.com/", "User-Agent": "Mozilla/5.0" }}データ型
「データ型」のセクションコールバックの戻り値は、以下の形式に対応しています。任意のプロパティは省略できます。
interface Chapter { id: string title?: string locked?: boolean}
interface Manga { id: string title?: string cover?: string status?: Status latestChapter?: Chapter meta?: string}
interface ChapterGroup { id?: string title: string chapters: Chapter[]}
interface DetailedManga { id: string title?: string cover?: string status?: Status readingDirection?: ReadingDirection latestChapter?: Chapter description?: string externalLink?: string updatedAt?: number // Unix timestamp in milliseconds authors?: string[] genres?: Genre[] chapters?: ChapterGroup[] remarks?: string meta?: string}ジャンル
「ジャンル」のセクションMankai が認識する文字列は次のとおりです。
all, action, romance, yuri, boysLove, otokonoko, schoolLife, adventure,harem, speculativeFiction, war, suspense, fanFiction, comedy, magic, horror,historical, sports, mature, mecha| 名前 | 値 |
|---|---|
any |
0 |
onGoing |
1 |
completed |
2 |
閲覧方向
「閲覧方向」のセクション| 名前 | 値 |
|---|---|
leftToRight |
1 |
rightToLeft |
2 |
vertical |
3 |
実行環境の補助関数
「実行環境の補助関数」のセクションMankai はすべてのコールバックスクリプトに、以下の補助関数を注入します。
fetch(url, options)
「fetch(url, options)」のセクション実行環境は、ネイティブのネットワーク処理を使う fetch を提供します。対応するリクエストオプションは次のとおりです。
interface FetchOptions { method?: string // Defaults to "GET" headers?: Record<string, string> | Headers body?: string}返されるレスポンスには、以下のプロパティとメソッドがあります。
interface FetchResponse { ok: boolean status: number statusText: string url: string headers: Headers text(): Promise<string> json(): Promise<any> blob(): Promise<Blob> arrayBuffer(): Promise<ArrayBuffer>}console.log(...values)
「console.log(...values)」のセクションconsole.log の出力先は Mankai の JavaScript プラグインログに変更されています。開発中のプラグインの問題を調べる際に使えます。
console.log('searching', query)s2t(text) と t2s(text)
「s2t(text) と t2s(text)」のセクションこれらの非同期補助関数は、OpenCC を使って中国語の文字を変換します。
const traditional = await s2t('简体转繁体')const simplified = await t2s('繁體轉簡體')s2t は簡体字から繁体字に変換し、t2s はその逆に変換します。
getConfigs()
「getConfigs()」のセクションマニフェストで宣言された設定の現在値を、配列で返します。
interface ConfigValue { key: string value: unknown}例を示します。
function configValue(key) { return getConfigs().find((config) => config.key === key)?.value}
const username = configValue('username')永続ストレージ
「永続ストレージ」のセクション以下の補助関数は、プラグインの id ごとに分離されたキーバリューストアに文字列を保存します。
getValue(key: string): Promise<string | null>;setValue(key: string, value: string): Promise<void>;removeValue(key: string): Promise<boolean>;3 つの補助関数すべてに await を使ってください。値はアプリの再起動やプラグインの更新後も保持され、プラグインを削除すると取り除かれます。
const token = await getValue('token')if (!token) { await setValue('token', 'new-token')}await removeValue('temporary-value')設定項目は次の形式です。
interface Config { key: string name: string description?: string type: 'text' | 'password' | 'number' | 'slider' | 'boolean' | 'select' | 'color' defaultValue: unknown options?: string[] min?: number max?: number step?: number supportsOpacity?: boolean}options は select の設定で使います。min、max、step は slider の範囲と刻み幅を設定します。アプリは各設定を defaultValue で初期化し、ソース設定で行った変更を保存して、現在値を getConfigs() から公開します。
例を示します。
{ "configs": [ { "key": "language", "name": "Language", "description": "Language used when requesting titles.", "type": "select", "defaultValue": "en", "options": ["en", "zh-Hans", "zh-Hant"] }, { "key": "imageQuality", "name": "Image quality", "type": "slider", "defaultValue": 80, "min": 10, "max": 100, "step": 5 }, { "key": "includeMature", "name": "Include mature content", "type": "boolean", "defaultValue": false } ]}リクエスト間隔と同時実行数
「リクエスト間隔と同時実行数」のセクション間隔の値はミリ秒単位です。
interface Cooldown { default?: number getImage?: number getImageConcurrency?: number}| フィールド | 説明 |
|---|---|
default |
検索、一覧、詳細、チャプターの取得など、画像以外の操作の最小間隔です。 |
getImage |
画像リクエストの最小間隔です。画像はほかの操作とは別にスケジュールされます。 |
getImageConcurrency |
同時に処理できる画像リクエストの最大数です。1 未満の値では制限を設定しません。 |
これらのフィールドを使い、ソースのレート制限を守ってください。例を示します。
{ "cooldown": { "default": 500, "getImage": 100, "getImageConcurrency": 2 }}