# Contributing This guide have some instructions and tips on how to create a new Mangayomi extension on JavaScript extension. ## Prerequisites Before starting please have installed the recent desktop version of the mangayomi application preferably or if you want with a tablet too. ### Writing your extension 1. Open the app. 2. Go to extension tab : ![1](https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/screenshots/1.png) 3. then click `+` and you will see : ![2](https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/screenshots/2.png) 4. Fill in the fields with your new source that you would like to create, ![3](https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/screenshots/3.png) NB: only the `ApiUrl` field is optional then click on save 5. you will see your new source in the extension list ![4](https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/screenshots/4.png) click to open settings 6. After click on edit code ![5](https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/screenshots/5.png) 7. Finally you can now write the extension ![6](https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/screenshots/6.png) - This page contains three parts: - Code editor: where you will write your code - Fecth result: where you will test the different implemented methods by having a result in the expected format - Console: which will show you the logs Once extension is ready you can relocate your code into `mangayomi-extension` project in a `src` or `multisrc` package and create a Pull Request. ### Source | Field | Description | | ----- | ----------- | | `name` | Name displayed in the "Sources" tab in Mangayomi. | | `baseUrl` | Base URL of the source without any trailing slashes. | | `apiUrl` | (Optional, defaults is empty) Api URL of the source with trailing slashes. | | `lang` | An ISO 639-1 compliant language code (two letters in lower case in most cases, but can also include the country/dialect part by using a simple dash character). | | `id` | Identifier of your source, automatically set in `Source`. It should only be manually overriden if you need to copy an existing autogenerated ID. | | `isManga` | (Optional, defaults to `true`) specify source type (false for anime and true for manga)| | `dateFormat` | (Optional, defaults is empty) | | `iconUrl` | The extension icon URL | | `version` | The extension version code. This must be incremented with any change to the code. | | `dateFormatLocale` | (Optional, defaults is empty) | | `isNsfw` | (Optional, defaults to `false`) Flag to indicate that a source contains NSFW content. | ### Extension call flow #### Popular manga a.k.a. the Browse source entry point in the app (invoked by tapping on the source name). - The app calls `getPopular` which should return a JSON ```bash { 'list': array of {'url':string,'name':string,'link':string}, hasNextPage: Boolean } ``` - This method supports pagination. When user scrolls the manga list and more results must be fetched, the app calls it again with increasing `page` values(starting with `page=1`). This continues while `hasNextPage` is passed as `true` and `list` is not empty. #### Latest manga a.k.a. the Latest source entry point in the app (invoked by tapping on the "Latest" button beside the source name). - Similar to popular manga, but should be fetching the latest entries from a source. #### Search manga - When the user searches inside the app, `search` will be called and the rest of the flow is similar to what happens with `getPopular`. - `getFilterList` will be called to get all filters and filter types. #### Manga Details - When user taps on an manga, `getDetail` will be called and the results will be cached. - `getDetail` is called to update an manga's details from when it was initialized earlier. - `title` is a string containing title. - `description` is a string containing description. - `author` is a string containing author. - `genre` contain array of all genres. - `status` is an "integer" value. You can refer to this example to see the correspondence: ```bash 0=>"ongoing", 1=>"complete", 2=>"hiatus", 3=>"canceled", 4=>"publishingFinished", 5=>unknow ``` - `chapters` or `episodes` contain all of all manga chapters or anime episodes. - `name` is a string containing a chapter name. - `url` is a string containing a chapter url. - `scanlator` is a string containing a chapter scanlator. - `dateUpload` is a string containing date **expressed in millisecondsSinceEpoch**. - If you don't pass `dateUpload` and leave it null, the app will use the default date instead, but it's recommended to always fill it if it's available. #### Chapter pages - When user opens an chapter, `getPageList` will be called and it will return an array of string or an array of map like `{ url:string,headers:map }` that are used by the reader. #### Episode Videos - When user opens an episode, `getVideoList` will be called and it will return a ```bash array of {'url':string,'originalUrl':string,'quality':string} ``` that are used by the player. ## Example sources that can help you understand how to create your source - [Example](https://github.com/kodjodevf/mangayomi-extensions/blob/main/javascript/anime/src/de/aniworld.js) of HTML parsing using HTML DOM selector. - [Example](https://github.com/kodjodevf/mangayomi-extensions/blob/main/javascript/anime/src/en/allanime.js) of Json API usage. ## Some functions already available and usable ### http client Return Response ```bash - Simple request const client = new Client(); const res = await client.get("http://example.com"); console.log(res.body); - With headers const client = new Client(); const res = await client.get("http://example.com",{"Referer": "http://example.com"}); console.log(res.body); - With body const client = new Client(); const res = await client.post("http://example.com",{"Referer": "http://example.com"},{'name':'test'}); console.log(res.body); ``` ### HTML DOM selector Example: ```bash const htmlString = `
author
div head
1 2 3 4 one two three four
end
` const document = new Document(htmlString); console.log(document.selectFirst("a").attr("href")); // https://github.com/kodjodevf console.log(document.selectFirst("td").text); // 1 ``` See [`dom_selector`](https://github.com/kodjodevf/mangayomi/blob/main/lib/eval/javascript/dom_selector.dart) to see available methods. ### String utils - this.substringAfter(`string: pattern`) - this.substringAfterLast(`string: pattern`) - this.substringBefore(`string: pattern`) - this.substringBeforeLast(`string: pattern`) - this.substringBetween(`string: left`, `string: right`) ### Crypto utils - unpackJs(`string: code`); - deobfuscateJsPassword(`string: inputString`) - encryptAESCryptoJS(`string: plainText`, `string: passphrase`) - decryptAESCryptoJS(`string: encrypted`, `string: passphrase`) - cryptoHandler(`string: text`, `string: iv`, `string: secretKeyString`, `Boolean: encrypt`) ## Help If you need a help or have some questions, ask a community in our [Discord server](https://discord.com/invite/EjfBuYahsP).