diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/api/README.md | 24 | ||||
| -rw-r--r-- | docs/api/danbooru-help-api.html | 693 | ||||
| -rw-r--r-- | docs/api/gelbooru-howto-api.html | 124 | ||||
| -rw-r--r-- | docs/api/konachan-help-api.html | 1016 | ||||
| -rw-r--r-- | docs/api/safebooru-dapi-help.html | 159 | ||||
| -rw-r--r-- | docs/api/sakugabooru-help-api.html | 1009 | ||||
| -rw-r--r-- | docs/api/yandere-help-api.html | 1021 | ||||
| -rw-r--r-- | docs/plans/2026-02-23-held-posts-toggle-design.md | 29 | ||||
| -rw-r--r-- | docs/plans/2026-02-23-held-posts-toggle-implementation.md | 68 |
9 files changed, 4143 insertions, 0 deletions
diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 0000000..c6f3918 --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,24 @@ +# Supported Provider API Docs (Snapshot) + +These are local HTML snapshots of API documentation for providers currently supported by Sora. +Fetched on 2026-02-23 (US/Pacific) using `curl -L` with a browser user agent. + +## Sources + +- Danbooru: https://danbooru.donmai.us/wiki_pages/help:api + - Local copy: `docs/api/danbooru-help-api.html` +- Yande.re (Moebooru): https://yande.re/help/api + - Local copy: `docs/api/yandere-help-api.html` +- Konachan (Moebooru): https://konachan.com/help/api + - Local copy: `docs/api/konachan-help-api.html` +- Sakugabooru (Moebooru): https://sakugabooru.com/help/api + - Local copy: `docs/api/sakugabooru-help-api.html` +- Gelbooru: https://gelbooru.com/index.php?id=18780&page=wiki&s=view + - Local copy: `docs/api/gelbooru-howto-api.html` +- Safebooru (Gelbooru-family DAPI): https://safebooru.org/index.php?page=help&topic=dapi + - Local copy: `docs/api/safebooru-dapi-help.html` + +## Notes + +- These are point-in-time copies and may drift from live docs. +- Re-fetch when changing provider request/auth/pagination/sort behavior. diff --git a/docs/api/danbooru-help-api.html b/docs/api/danbooru-help-api.html new file mode 100644 index 0000000..b29b8a6 --- /dev/null +++ b/docs/api/danbooru-help-api.html @@ -0,0 +1,693 @@ + +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>Help:Api Wiki | Danbooru</title> + + <link href="/favicon.ico" rel="icon" sizes="16x16" type="image/x-icon"> + <link href="/favicon.svg" rel="icon" sizes="any" type="image/svg+xml"> + + <link rel="canonical" href="https://danbooru.donmai.us/wiki_pages/help:api"> + <link rel="search" type="application/opensearchdescription+xml" href="https://danbooru.donmai.us/opensearch.xml?version=2" title="Search posts"> + + <meta name="csrf-param" content="authenticity_token" /> +<meta name="csrf-token" content="Wd757suCDuPJkJeJoJJ4BfUD60F6oCEnq1a1x_r77o20vJwIAJqHKRQOnsImirN7pt7mMQ3tdRoCt8xOZ0u9NQ" /> + <meta name="viewport" content="width=device-width,initial-scale=1"> + + <meta name="autocomplete-tag-prefixes" content="["ch:","co:","gen:","char:","copy:","art:","meta:","general:","character:","copyright:","artist:"]"> + + <script src="/packs/js/runtime-0addf670eec96d42fec9.js"></script> +<script src="/packs/js/948-d14ebcdd294788cb0769.js"></script> +<script src="/packs/js/application-9bb4dec4c9ff73e2af93.js"></script> + + <link rel="stylesheet" href="/packs/css/application-f43c8e3d.css" /> + + + <meta name="description" content="Danbooru offers a REST-like API to make scripting easy. All you need is a way to GET, POST, PUT and DELETE to URLs. Responses are given in either XML or JSON..."> + <meta property="og:type" content="website"> + <meta property="og:site_name" content="Danbooru"> + <meta property="og:title" content="Help:Api Wiki | Danbooru"> + <meta property="og:description" content="Danbooru offers a REST-like API to make scripting easy. All you need is a way to GET, POST, PUT and DELETE to URLs. Responses are given in either XML or JSON..."> + <meta property="og:url" content="https://danbooru.donmai.us/wiki_pages/help:api"> + + <meta name="twitter:site" content="@danboorubot"> + + <meta name="twitter:title" content="Help:Api Wiki | Danbooru"> + <meta name="twitter:description" content="Danbooru offers a REST-like API to make scripting easy. All you need is a way to GET, POST, PUT and DELETE to URLs. Responses are given in either XML or JSON..."> + + <meta name="git-hash" content="a75d42dd4b6c1d97d8ab90e5a3da29a32eed393f"> + <meta name="theme-color" content="hsl(213, 100%, 50%)"> + + + +</head> + +<body lang="en" class="c-wiki-pages a-show flex flex-col" spellcheck="false" data-controller="wiki-pages" data-action="show" data-layout="sidebar" data-current-user-ip-addr="2601:1c2:e80:46d0:1da5:d038:8946:baaf" data-current-user-save-data="false" data-current-user-id="null" data-current-user-name="Anonymous" data-current-user-level="0" data-current-user-level-string="null" data-current-user-theme="auto" data-current-user-comment-threshold="-8" data-current-user-default-image-size="large" data-current-user-time-zone="Eastern Time (US & Canada)" data-current-user-per-page="20" data-current-user-is-banned="false" data-current-user-receive-email-notifications="false" data-current-user-new-post-navigation-layout="true" data-current-user-enable-private-favorites="false" data-current-user-show-deleted-children="false" data-current-user-disable-categorized-saved-searches="false" data-current-user-disable-tagged-filenames="false" data-current-user-disable-mobile-gestures="false" data-current-user-enable-safe-mode="false" data-current-user-enable-desktop-mode="false" data-current-user-disable-post-tooltips="false" data-current-user-requires-verification="false" data-current-user-is-verified="false" data-current-user-show-deleted-posts="false" data-current-user-is-approver="false" data-current-user-is-anonymous="true" data-current-user-is-member="false" data-current-user-is-gold="false" data-current-user-is-platinum="false" data-current-user-is-builder="false" data-current-user-is-moderator="false" data-current-user-is-contributor="false" data-current-user-is-admin="false" data-current-user-is-owner="false" data-current-user-is-restricted="false" data-cookie-news-ticker="null" data-cookie-hide-upgrade-account-notice="null" data-cookie-hide-verify-account-notice="null" data-cookie-hide-dmail-notice="null" data-cookie-dab="null" data-cookie-show-relationship-previews="null" data-cookie-post-preview-size="null" data-cookie-post-preview-show-votes="null" data-wiki-page-id="43568" data-wiki-page-created-at="2013-03-18T11:08:03.991640-04:00" data-wiki-page-updated-at="2025-12-06T02:16:25.205662-05:00" data-wiki-page-is-locked="false" data-wiki-page-is-deleted="false"> + + + <header id="top" class="md:space-y-0 mt-2" x-data="{ menuOpen: false }"> + <div class="flex items-center justify-between mx-8 sm:mx-2 text-xxl"> + <div id="app-name-header" class="inline-flex items-center gap-2"> + <a id="app-logo" href="/"><img class="h-9 hover:brightness-125" src="/packs/static/danbooru-logo-128x128-ea111b6658173e847734.png" /></a> + <a id="app-name" class="font-header font-bold leading-none" href="/">Danbooru</a> + </div> + + <a class="mobile-only cursor-pointer" x-on:click="menuOpen = !menuOpen"> + <svg class="icon svg-icon menu-icon block w-6" viewBox="0 0 448 512" x-show="!menuOpen"><use fill="currentColor" href="/packs/static/icons-b92dd088a6e3ca08e2bd.svg#bars" /></svg> + <svg class="icon svg-icon close-icon block w-6" viewBox="0 0 320 512" x-show="menuOpen" x-cloak="true"><use fill="currentColor" href="/packs/static/icons-b92dd088a6e3ca08e2bd.svg#xmark" /></svg> + </a> + </div> + + <nav id="nav" class="desktop-only mt-2" x-bind:class="{ 'desktop-only': !menuOpen }"> + <div id="main-menu" class="flex flex-wrap items-center px-5 sm:p-2"> + <a id="nav-login" class="py-1.5 px-3 font-bold" rel="nofollow" href="/login?url=%2Fwiki_pages%2Fhelp%3Aapi">Login</a> + + <a id="nav-posts" class="py-1.5 px-3 " href="/posts">Posts</a> + <a id="nav-comments" class="py-1.5 px-3 " href="/comments">Comments</a> + <a id="nav-notes" class="py-1.5 px-3 " href="/notes">Notes</a> + <a id="nav-artists" class="py-1.5 px-3 " href="/artists">Artists</a> + <a id="nav-tags" class="py-1.5 px-3 " href="/tags">Tags</a> + <a id="nav-pools" class="py-1.5 px-3 " href="/pools/gallery">Pools</a> + <a id="nav-wiki" class="py-1.5 px-3 current font-bold" href="/wiki_pages/help:home">Wiki</a> + <a id="nav-forum" class="py-1.5 px-3 " href="/forum_topics">Forum</a> + + + <a id="nav-more" class="py-1.5 px-3 " href="/static/site_map">More »</a> + </div> + + <div id="subnav-menu" class="flex flex-wrap items-center px-5 sm:p-2"> + <form autocomplete="off" novalidate="novalidate" class="simple_form search-form quick-search-form one-line-form py-1.5 px-3 md:w-180px w-full" action="/wiki_pages" accept-charset="UTF-8" method="get"><div class="input stacked-input string optional search_title_normalize"><input data-autocomplete="wiki-page" class="string optional" placeholder="Search wiki pages" type="text" name="search[title_normalize]" /></div><input type="hidden" name="redirect" value="true"></form> + <a id="subnav-search" class="py-1.5 px-3 " href="/wiki_pages">Search</a> + <a id="subnav-changes" class="py-1.5 px-3 " href="/wiki_page_versions">Changes</a> + <a id="subnav-help" class="py-1.5 px-3 " href="/wiki_pages/help:wiki">Help</a> + <span class="text-muted select-none">|</span> + <a id="subnav-posts" class="py-1.5 px-3 " href="/posts?tags=help%3Aapi">Posts (0)</a> + <a id="subnav-history" class="py-1.5 px-3 " href="/wiki_page_versions?search%5Bwiki_page_id%5D=43568">History</a> + + </div> + </nav> +</header> + + + <div id="page" class="relative flex-1 mx-8 mt-4 sm:mx-2 sm:mt-2"> + + + + + + + <div id="notice" + class="notice flex fixed top-2 left-2 right-2 p-2 mx-auto max-w-720px max-h-150px thin-scrollbar z-9999 shadow-lg sm:text-sm" + x-init="$root.notice = $data.notice" + x-data="{ notice: new Danbooru.Notice(null) }" + x-bind:class="notice.type === 'error' ? 'notice-error' : 'notice-info'" + x-show="notice.isOpen" + x-transition.opacity.400ms + x-cloak> + <span class="prose flex-1" x-html="notice.message"></span> + <a href="javascript:void(0)" id="close-notice-link" class="flex self-center text-lg" data-shortcut="esc" x-on:click="notice.close()"><svg class="icon svg-icon close-icon" viewBox="0 0 320 512"><use fill="currentColor" href="/packs/static/icons-b92dd088a6e3ca08e2bd.svg#xmark" /></svg></a> +</div> + + + + + + + + <div id="c-wiki-pages"> + <div id="a-show"> + + <div class="sidebar-container flex sm:flex-col gap-3"> + <aside id="sidebar" class="flex-0 break-words sm:order-2"> + <div + id="blacklist-box" + class="mb-4 card-outlined max-w-full sidebar-blacklist" + x-data="{ blacklist: new Danbooru.Blacklist($root) }" + x-init="blacklist.initialize(["guro","scat","furry -rating:g"])" + x-show="blacklist.visible" + x-cloak> + <div class="flex items-center gap-1 p-2" x-bind:class="{ 'border-b': !blacklist.collapsed }"> + <label class="flex items-center gap-1 font-header font-bold cursor-pointer select-none"> + <input type="checkbox" class="toggle-switch" x-model="blacklist.enabled" x-effect="$el.indeterminate = blacklist.partiallyEnabled" data-shortcut="b"> + Blacklisted + </label> + + <span class="whitespace-nowrap post-count" x-text="blacklist.blacklistedPostCount"></span> + <span class="flex items-center flex-grow-1 justify-end gap-1"> + <div class="popup-menu inline-flex items-center h-full" data-hide-on-click="true"> + <a class="popup-menu-button default-popup-menu-button" x-on:mousedown.prevent="true" href="javascript:void(0)"> + <svg class="icon svg-icon ellipsis-icon" viewBox="0 0 448 512"><use fill="currentColor" href="/packs/static/icons-b92dd088a6e3ca08e2bd.svg#ellipsis" /></svg> +</a> + <ul class="popup-menu-content"> + <li> <label class="flex items-center link-color cursor-pointer select-none" x-bind:class="blacklist.autocollapse && 'font-bold'" x-on:click.stop title="Whether enabling blacklists automatically closes the blacklist box"> + <input type="checkbox" x-model="blacklist.autocollapse" class="w-4 h-full mr-1"><span>Autoclose</span> + </label> +</li> + <li> <label class="flex items-center link-color cursor-pointer select-none" x-bind:class="blacklist.showAll && 'font-bold'" x-on:click.stop title="Show all rules, even those that don't match any posts"> + <input type="checkbox" x-model="blacklist.showAll" class="w-4 h-full mr-1"><span>Show all</span> + </label> +</li> + <li> <label class="flex items-center link-color cursor-pointer select-none" x-bind:class="blacklist.blurImages && 'font-bold'" x-on:click.stop title="Blur images instead of hiding them"> + <input type="checkbox" x-model="blacklist.blurImages" class="w-4 h-full mr-1"><span>Blur images</span> + </label> +</li> + <li> <a class="wiki-link flex items-center" target="_blank" href="/wiki_pages/help:blacklists"> + <svg class="icon svg-icon circle-question-icon" viewBox="0 0 512 512"><use fill="currentColor" href="/packs/static/icons-b92dd088a6e3ca08e2bd.svg#circle-question" /></svg><span>Help</span> +</a></li> + </ul> +</div> <a class="inactive-link contents" x-on:click.prevent="blacklist.collapsed = !blacklist.collapsed" href="javascript:void(0)"> + <svg class="icon svg-icon chevron-down-icon transition-transform" viewBox="0 0 448 512" x-bind:class="{ 'rotate-180' : blacklist.collapsed }"><use fill="currentColor" href="/packs/static/icons-b92dd088a6e3ca08e2bd.svg#chevron-down" /></svg> +</a> </span> + </div> + + <div class="thin-scrollbar max-h-360px p-2" x-show="!blacklist.collapsed" x-cloak> + <div class="flex items-center gap-1 h-full overflow-hidden " + x-data="{ rule: blacklist.rules[0] }" + x-bind:data-visible="rule.visible.toString()" + x-bind:data-enabled="rule.enabled.toString()" + x-show="rule.visible"> + <input type="checkbox" class="toggle-switch" x-model="rule.enabled"> + <a title="guro" class="truncate" tabindex="-1" x-bind:class="{ 'inactive-link': !rule.enabled }" x-on:click.prevent="rule.toggle()" href="/posts?tags=guro">guro</a> + <span class="whitespace-nowrap post-count" x-text="Alpine.raw(rule.posts).map(post => post.post.dataset.id).size"></span> + </div> + <div class="flex items-center gap-1 h-full overflow-hidden " + x-data="{ rule: blacklist.rules[1] }" + x-bind:data-visible="rule.visible.toString()" + x-bind:data-enabled="rule.enabled.toString()" + x-show="rule.visible"> + <input type="checkbox" class="toggle-switch" x-model="rule.enabled"> + <a title="scat" class="truncate" tabindex="-1" x-bind:class="{ 'inactive-link': !rule.enabled }" x-on:click.prevent="rule.toggle()" href="/posts?tags=scat">scat</a> + <span class="whitespace-nowrap post-count" x-text="Alpine.raw(rule.posts).map(post => post.post.dataset.id).size"></span> + </div> + <div class="flex items-center gap-1 h-full overflow-hidden " + x-data="{ rule: blacklist.rules[2] }" + x-bind:data-visible="rule.visible.toString()" + x-bind:data-enabled="rule.enabled.toString()" + x-show="rule.visible"> + <input type="checkbox" class="toggle-switch" x-model="rule.enabled"> + <a title="furry -rating:g" class="truncate" tabindex="-1" x-bind:class="{ 'inactive-link': !rule.enabled }" x-on:click.prevent="rule.toggle()" href="/posts?tags=furry+-rating%3Ag">furry -rating:g</a> + <span class="whitespace-nowrap post-count" x-text="Alpine.raw(rule.posts).map(post => post.post.dataset.id).size"></span> + </div> +</div></div> + + <section> + <h2>Recent Changes (<a href="/wiki_page_versions">all</a>)</h2> + <ul> + <li><a class="tag-type-3" href="/wiki_pages/garo_(tokusatsu_series)">garo (tokusatsu series)</a></li> + <li><a class="tag-type-0" href="/wiki_pages/eldritch_abomination">eldritch abomination</a></li> + <li><a class="tag-type-4" href="/wiki_pages/shunshun">shunshun</a></li> + <li><a class="tag-type-4" href="/wiki_pages/shunga_youkyu">shunga youkyu</a></li> + <li><a class="tag-type-0" href="/wiki_pages/change!_emu_wa_ojou_sama!%3F_(project_sekai)">change! emu wa ojou sama!? (project sekai)</a></li> + <li><a class="tag-type-0" href="/wiki_pages/noble_galerus">noble galerus</a></li> + <li><a class="tag-type-4" href="/wiki_pages/harukawa_shigure_(varia_kimagure)">harukawa shigure (varia kimagure)</a></li> + <li><a class="tag-type-4" href="/wiki_pages/iris_(seisenki_iris)">iris (seisenki iris)</a></li> + <li><a class="tag-type-0" href="/wiki_pages/do_you_want_to_pet_my_cat_(meme)">do you want to pet my cat (meme)</a></li> + <li><a class="tag-type-0" href="/wiki_pages/projectile_cum">projectile cum</a></li> + <li><a class="tag-type-4" href="/wiki_pages/cesario_(umamusume)">cesario (umamusume)</a></li> + <li><a class="tag-type-0" href="/wiki_pages/sex_machine">sex machine</a></li> + <li><a class="tag-type-0" href="/wiki_pages/spanking_machine">spanking machine</a></li> + <li><a class="tag-type-0" href="/wiki_pages/ball_busting_machine">ball busting machine</a></li> + <li><a class="tag-type-1" href="/wiki_pages/love_kitten">love kitten</a></li> + <li><a class="tag-type-3" href="/wiki_pages/x-com_(classic)">x-com (classic)</a></li> + <li><a class="tag-type-0" href="/wiki_pages/tucking_hair">tucking hair</a></li> + <li><a class="tag-type-0" href="/wiki_pages/hoyolab_sticker_redraw">hoyolab sticker redraw</a></li> + <li><a class="tag-type-4" href="/wiki_pages/magical_mirai_miku">magical mirai miku</a></li> + <li><a class="tag-type-4" href="/wiki_pages/oedaki_chika">oedaki chika</a></li> + <li><a class="tag-type-4" href="/wiki_pages/victoire_pisa_(umamusume)">victoire pisa (umamusume)</a></li> + <li><a class="tag-type-4" href="/wiki_pages/miura_azusa">miura azusa</a></li> + <li><a class="tag-type-4" href="/wiki_pages/futami_ami">futami ami</a></li> + <li><a class="tag-type-4" href="/wiki_pages/minase_iori">minase iori</a></li> + <li><a class="tag-type-4" href="/wiki_pages/reyla_(lamunation)">reyla (lamunation)</a></li> + </ul> +</section> + + + <h2>Options</h2> + + <ul> + + <li><a href="/wiki_page_versions?search%5Bwiki_page_id%5D=43568">Wiki History</a></li> + + <li><a href="/forum_posts?search%5Blinked_to%5D=help%3Aapi">Discussions</a></li> + + <li><a href="/wiki_pages?search%5Blinked_to%5D=help%3Aapi">What Links Here</a></li> + + </ul> + + </aside> + + <section id="content" class="flex-1 min-w-0 sm:order-1"> + <h1 id="wiki-page-title"> + <a href="/posts?tags=help%3Aapi">help:api</a> + + + </h1> + + + <div id="wiki-page-body" class="prose"> + <p>Danbooru offers a REST-like API to make scripting easy. All you need is a way to GET, POST, PUT and DELETE to URLs. Responses are given in either XML or JSON format.</p><h1>Testing</h1><p>API calls can be tested on <a rel="external nofollow noreferrer" class="dtext-link dtext-external-link" href="https://testbooru.donmai.us">https://testbooru.donmai.us</a>. Scripts should be tested there before using them on the main site.</p><h1>Basics</h1><p>HTTP defines four basic request methods: GET, POST, PUT and DELETE. You'll be using these methods to interact with the Danbooru API. Most API calls that change the state of the database (like creating, updating, or deleting something) require an HTTP POST, PUT or DELETE call. API calls that only retrieve data can typically be done with an HTTP GET call.</p><p>A URL is considered a resource and the HTTP methods are actions you perform on the resource. For example, GET <a class="dtext-link" href="/posts/23.json">/posts/23.json</a> returns a JSON representation of <a class="dtext-link dtext-id-link dtext-post-id-link" href="/posts/23">post #23</a>. GET <a class="dtext-link" href="/posts/23.xml">/posts/23.xml</a> returns an XML representation. PUT or PATCH /posts/6.json would update the resource, for example changing its tags.</p><p>Some resources require parameters. For example, you can find tags that start with the letter 'a' by calling GET <a class="dtext-link" href="/tags.json?search[name_matches]=a*">/tags.json?search[name_matches]=a*</a>. This will give you a JSON listing of all tags with names starting with an a.</p><p>For POST, PUT and DELETE requests you must pass these parameters along in the body instead of the query parameters. Body parameters may be encoded in one of two ways. The usual way is with key-values pairs using "Content-Type: application/x-www-form-urlencoded":</p><pre>curl -u "$login:$api_key" -X PUT "https://testbooru.donmai.us/posts/6.json" -d 'post[rating]=s&post[tag_string]=danboo'</pre><p>Parameters may also be encoded as JSON using "Content-Type: application/json":</p><pre>curl -u "$login:$api_key" -X PUT "https://testbooru.donmai.us/posts/6.json" -d '{ "post": { "rating": "s", "tag_string": "danboo" } }' -H "Content-Type: application/json" </pre><h1>Responses</h1><p>All API calls that change state will return a single element response (for XML calls). They are formatted like this:</p><pre><?xml version="1.0" encoding="UTF-8"?> +<response success="false" reason="duplicate"/></pre><p>For JSON responses, they'll look like this:</p><pre>{ "success": false, "reason": "duplicate" }</pre><p>While you can usually determine success or failure based on the response object, you can also figure out what happened based on the HTTP status code. In addition to the standard ones, Danbooru uses some custom status codes in the 4xx and 5xx range.</p><ul><li><strong>200 OK</strong>: Request was successful</li><li><strong>204 No Content</strong>: Request was successful (returned by create actions)</li><li><strong>400 Bad Request</strong>: The given parameters could not be parsed</li><li><strong>401 Unauthorized</strong>: Authentication failed</li><li><strong>403 Forbidden</strong>: Access denied (see <a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Ausers">help:users</a> for permissions information)</li><li><strong>404 Not Found</strong>: Not found</li><li><strong>410 Gone</strong>: Pagination limit (see <a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Ausers">help:users</a> for pagination limits)</li><li><strong>420 Invalid Record</strong>: Record could not be saved</li><li><strong>422 Locked</strong>: The resource is locked and cannot be modified</li><li><strong>423 Already Exists</strong>: Resource already exists</li><li><strong>424 Invalid Parameters</strong>: The given parameters were invalid</li><li><strong>429 User Throttled</strong>: User is throttled, try again later (see <a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Ausers">help:users</a> for API limits)</li><li><strong>500 Internal Server Error</strong>: A database timeout, or some unknown error occurred on the server</li><li><strong>502 Bad Gateway</strong>: Server cannot currently handle the request, try again later (returned during heavy load)</li><li><strong>503 Service Unavailable</strong>: Server cannot currently handle the request, try again later (returned during downbooru)</li></ul><h1>Authentication</h1><p>You will need an API key if you need to login using the API. You can generate an API key by visiting your <a class="dtext-link" href="/profile">user profile</a> and clicking the Generate API key button.</p><p>To authenticate with the API, pass the <code>login</code> and <code>api_key</code> URL parameters, where <code>login</code> is your username and <code>api_key</code> is your API key:</p><pre>https://danbooru.donmai.us/profile.json?login=your_username&api_key=your_api_key</pre><p>You can also authenticate using <a rel="external nofollow noreferrer" class="dtext-link dtext-external-link dtext-named-external-link" href="https://en.wikipedia.org/wiki/Basic_access_authentication">HTTP Basic Authentication</a>:</p><pre>curl "https://$username:[email protected]/profile.json" +curl --user "$username:$api_key" https://danbooru.donmai.us/profile.json</pre><p>Most HTTP libraries support HTTP basic authentication out of the box. If yours doesn't, you can generate the authentication header manually. The format is <code>Authentication: Basic $secret</code> where <code>$secret = base64($username + ":" + $api_key)</code>. In other words, concatenate your username and API key together, separated by a colon, then <a rel="external nofollow noreferrer" class="dtext-link dtext-external-link dtext-named-external-link" href="https://en.wikipedia.org/wiki/Base64">Base64</a> encode the result:</p><pre>curl --header "Authorization: Basic $(printf "%s" "$username:$api_key" | base64)" https://danbooru.donmai.us/profile.json</pre><p>If you are writing a user script for a browser, you do not need to embed an API key. You can rely on the user's session.</p><p>⚠️ <strong>IMPORTANT!</strong> Keep your API key secret. Treat it like a password. Gaining access to it allows full access to your account. Do not publicly post your API key or distribute it in scripts.</p><h1>Rate Limits</h1><p>There's a global rate limit on read requests of 10 requests per second regardless of account or endpoint.</p><p>Most kinds of update actions are rate limited according to user level:</p><ul><li>Basic users: 1 update/second</li><li>Gold users and above: 4 updates/second</li></ul><p>Each rate-limited endpoint has a burst pool, which lets a user make several consecutive updates before being rate limited. The rate at which the pool is recharged depends on the endpoint, but most follow the rates above.</p><p>The burst pool size, recharge rate, and current limits are returned as JSON in the <code>x-rate-limit</code> HTTP header. They can also be found at <a class="dtext-link" href="/rate_limits">/rate_limits</a>, which shows the limits as of the last API call (the page won't update until the API is used again).</p><p>Rate limits are shared between accounts and IP addresses: multiple accounts with the same IP address will share the same rate limit.</p><h1>Queries</h1><h4>Common Search Parameters</h4><p>All search endpoints support a common set of parameters:</p><ul><li><strong>page</strong> Returns the given page. Subject to maximum page limits (see <a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Ausers">help:users</a>).</li></ul><p> You can also use <code>b<id></code> and <code>a<id></code> to request results before <id> or after <id>, respectively.<br> E.g. to get a page of posts before <a class="dtext-link dtext-id-link dtext-post-id-link" href="/posts/999999">post #999999</a>, you'd make a request to <code>/posts.json?page=b999999</code>.</p><ul><li><strong>limit</strong> The number of results to return per page. The maximum limit is 200 for /posts.json and 1000 for everything else.</li><li><strong>search[id]</strong></li><li><strong>search[created_at]</strong></li><li><strong>search[updated_at]</strong></li><li><strong>search[order]=custom</strong> Returns results in the same order as given by <code>search[id]=3,2,1</code>.</li></ul><h5>Parameter Parsing</h5><p>Numeric search parameters support ranges:</p><ul><li><code>100</code></li><li><code>>100</code></li><li><code>>=100</code></li><li><code><100</code></li><li><code><=100</code></li><li><code>100,200,300</code></li><li><code>100..200</code> (inclusive)</li></ul><p>Date parameters also support ranges:</p><ul><li><code>2012-01-01</code></li><li><code>>2012-01-01</code></li><li><code>>=2012-01-01</code></li><li><code><2012-01-01</code></li><li><code><=2012-01-01</code></li><li><code>2012-01-01,2012-01-02</code></li><li><code>2012-01-01..2013-01-01</code> (inclusive)</li></ul><p>Boolean parameters accept any of the following values for true or false:</p><ul><li>True: true, t, yes, y, on, 1</li><li>False: false, f, no, n, off, 0</li></ul><p>Most string parameters support using asterisks (<code>*</code>) as wildcards. Wildcards can be escaped with <code>\*</code>. Literal backslashes can be escaped with <code>\\</code>.</p><h1>Versioned Types</h1><ul><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Aartists">API:Artists</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Aartist_commentaries">API:Artist commentaries</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Anotes">API:Notes</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Apools">API:Pools</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Aposts">API:Posts</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Awiki_pages">API:Wiki Pages</a></li></ul><h2>Type Versions</h2><ul><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Aartist_versions">API:Artist versions</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Aartist_commentary_versions">API:Artist commentary versions</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Anote_versions">API:Note versions</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Apool_versions">API:Pool versions</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Apost_versions">API:Post versions</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Awiki_page_versions">API:Wiki page versions</a></li></ul><h2>Non-versioned Types</h2><ul><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Abulk_update_requests">API:Bulk update requests</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Acomments">API:Comments</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Admails">API:Dmails</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Afavorite_groups">API:Favorite groups</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Aforum_posts">API:Forum posts</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Aforum_topics">API:Forum topics</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Apost_appeals">API:Post appeals</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Apost_flags">API:Post flags</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Atags">API:Tags</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Atag_aliases">API:Tag aliases</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Atag_implications">API:Tag implications</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Auploads">API:Uploads</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/api%3Ausers">API:Users</a></li></ul><h2>Other Functions</h2><details><summary>Related Tags</summary><div><h3>Show</h3><p>The base URL is GET /related_tag.json.</p><ul><li><strong>query</strong> REQUIRED The tag to find the related tags for.</li><li><strong>category</strong> If specified, show only tags of a specific category. Can be: general, artist, copyright, character, meta</li></ul></div></details><h1>List of API endpoints</h1><details><summary>API Endpoints</summary><div><pre>Verb URI Pattern Controller#Action +GET /posts/random(.:format) posts#random +GET /posts(.:format) posts#index +GET /posts/:id(.:format) posts#show +PATCH /posts/:id(.:format) posts#update +PUT /posts/:id(.:format) posts#update +DELETE /posts/:id(.:format) posts#destroy +GET /autocomplete(.:format) autocomplete#index +GET / posts#index +GET /admin/users/:id/edit(.:format) admin/users#edit +PATCH /admin/users/:id(.:format) admin/users#update +PUT /admin/users/:id(.:format) admin/users#update +GET /admin/dashboard(.:format) admin/dashboards#show +GET /moderator/dashboard(.:format) moderator/dashboards#show +GET /moderator/ip_addrs/search(.:format) moderator/ip_addrs#search +GET /moderator/ip_addrs(.:format) moderator/ip_addrs#index +POST /moderator/post/posts/:id/expunge(.:format) moderator/post/posts#expunge +GET /moderator/post/posts/:id/confirm_move_favorites(.:format) moderator/post/posts#confirm_move_favorites +POST /moderator/post/posts/:id/move_favorites(.:format) moderator/post/posts#move_favorites +GET /moderator/post/posts/:id/confirm_ban(.:format) moderator/post/posts#confirm_ban +POST /moderator/post/posts/:id/ban(.:format) moderator/post/posts#ban +POST /moderator/post/posts/:id/unban(.:format) moderator/post/posts#unban +GET /moderator/ip_addrs/search(.:format) moderator/ip_addrs#search +GET /moderator/ip_addrs(.:format) moderator/ip_addrs#index +GET /explore/posts/popular(.:format) explore/posts#popular +GET /explore/posts/curated(.:format) explore/posts#curated +GET /explore/posts/viewed(.:format) explore/posts#viewed +GET /explore/posts/searches(.:format) explore/posts#searches +GET /explore/posts/missed_searches(.:format) explore/posts#missed_searches +GET /maintenance/user/count_fixes/new(.:format) maintenance/user/count_fixes#new +POST /maintenance/user/count_fixes(.:format) maintenance/user/count_fixes#create +GET /maintenance/user/email_notification(.:format) maintenance/user/email_notifications#show +DELETE /maintenance/user/email_notification(.:format) maintenance/user/email_notifications#destroy +GET /maintenance/user/deletion(.:format) maintenance/user/deletions#show +DELETE /maintenance/user/deletion(.:format) maintenance/user/deletions#destroy +POST /maintenance/user/api_key/view(.:format) maintenance/user/api_keys#view +GET /maintenance/user/api_key(.:format) maintenance/user/api_keys#show +PATCH /maintenance/user/api_key(.:format) maintenance/user/api_keys#update +PUT /maintenance/user/api_key(.:format) maintenance/user/api_keys#update +DELETE /maintenance/user/api_key(.:format) maintenance/user/api_keys#destroy +PUT /artists/:id/revert(.:format) artists#revert +PUT /artists/:id/ban(.:format) artists#ban +PUT /artists/:id/unban(.:format) artists#unban +GET /artists/show_or_new(.:format) artists#show_or_new +GET /artists/banned(.:format) artists#banned +GET /artists(.:format) artists#index +POST /artists(.:format) artists#create +GET /artists/new(.:format) artists#new +GET /artists/:id/edit(.:format) artists#edit +GET /artists/:id(.:format) artists#show +PATCH /artists/:id(.:format) artists#update +PUT /artists/:id(.:format) artists#update +DELETE /artists/:id(.:format) artists#destroy +GET /artist_urls(.:format) artist_urls#index +GET /artist_versions/search(.:format) artist_versions#search +GET /artist_versions(.:format) artist_versions#index +GET /artist_versions/:id(.:format) artist_versions#show +GET /bans(.:format) bans#index +POST /bans(.:format) bans#create +GET /bans/new(.:format) bans#new +GET /bans/:id/edit(.:format) bans#edit +GET /bans/:id(.:format) bans#show +PATCH /bans/:id(.:format) bans#update +PUT /bans/:id(.:format) bans#update +DELETE /bans/:id(.:format) bans#destroy +POST /bulk_update_requests/:id/approve(.:format) bulk_update_requests#approve +GET /bulk_update_requests(.:format) bulk_update_requests#index +POST /bulk_update_requests(.:format) bulk_update_requests#create +GET /bulk_update_requests/new(.:format) bulk_update_requests#new +GET /bulk_update_requests/:id/edit(.:format) bulk_update_requests#edit +GET /bulk_update_requests/:id(.:format) bulk_update_requests#show +PATCH /bulk_update_requests/:id(.:format) bulk_update_requests#update +PUT /bulk_update_requests/:id(.:format) bulk_update_requests#update +DELETE /bulk_update_requests/:id(.:format) bulk_update_requests#destroy +GET /comment_votes(.:format) comment_votes#index +DELETE /comments/:comment_id/votes(.:format) comment_votes#destroy +POST /comments/:comment_id/votes(.:format) comment_votes#create +GET /comments/search(.:format) comments#search +POST /comments/:id/undelete(.:format) comments#undelete +GET /comments(.:format) comments#index +POST /comments(.:format) comments#create +GET /comments/new(.:format) comments#new +GET /comments/:id/edit(.:format) comments#edit +GET /comments/:id(.:format) comments#show +PATCH /comments/:id(.:format) comments#update +PUT /comments/:id(.:format) comments#update +DELETE /comments/:id(.:format) comments#destroy +GET /counts/posts(.:format) counts#posts +GET /counts(.:format) counts#index +POST /counts(.:format) counts#create +GET /counts/new(.:format) counts#new +GET /counts/:id/edit(.:format) counts#edit +GET /counts/:id(.:format) counts#show +PATCH /counts/:id(.:format) counts#update +PUT /counts/:id(.:format) counts#update +DELETE /counts/:id(.:format) counts#destroy +PUT /delayed_jobs/:id/run(.:format) delayed_jobs#run +PUT /delayed_jobs/:id/retry(.:format) delayed_jobs#retry +PUT /delayed_jobs/:id/cancel(.:format) delayed_jobs#cancel +GET /delayed_jobs(.:format) delayed_jobs#index +DELETE /delayed_jobs/:id(.:format) delayed_jobs#destroy +POST /dmails/mark_all_as_read(.:format) dmails#mark_all_as_read +GET /dmails(.:format) dmails#index +POST /dmails(.:format) dmails#create +GET /dmails/new(.:format) dmails#new +GET /dmails/:id(.:format) dmails#show +PATCH /dmails/:id(.:format) dmails#update +PUT /dmails/:id(.:format) dmails#update +POST /dtext_preview(.:format) dtext_previews#create +GET /dtext_links(.:format) dtext_links#index +GET /emails(.:format) emails#index +GET /emails/:id(.:format) emails#show +GET /favorites(.:format) favorites#index +POST /favorites(.:format) favorites#create +DELETE /favorites/:id(.:format) favorites#destroy +PUT /favorite_groups/:id/add_post(.:format) favorite_groups#add_post +GET /favorite_groups/:favorite_group_id/order/edit(.:format) favorite_group_orders#edit +GET /favorite_groups(.:format) favorite_groups#index +POST /favorite_groups(.:format) favorite_groups#create +GET /favorite_groups/new(.:format) favorite_groups#new +GET /favorite_groups/:id/edit(.:format) favorite_groups#edit +GET /favorite_groups/:id(.:format) favorite_groups#show +PATCH /favorite_groups/:id(.:format) favorite_groups#update +PUT /favorite_groups/:id(.:format) favorite_groups#update +DELETE /favorite_groups/:id(.:format) favorite_groups#destroy +POST /forum_posts/:id/undelete(.:format) forum_posts#undelete +GET /forum_posts/search(.:format) forum_posts#search +GET /forum_posts(.:format) forum_posts#index +POST /forum_posts(.:format) forum_posts#create +GET /forum_posts/new(.:format) forum_posts#new +GET /forum_posts/:id/edit(.:format) forum_posts#edit +GET /forum_posts/:id(.:format) forum_posts#show +PATCH /forum_posts/:id(.:format) forum_posts#update +PUT /forum_posts/:id(.:format) forum_posts#update +DELETE /forum_posts/:id(.:format) forum_posts#destroy +GET /forum_post_votes(.:format) forum_post_votes#index +POST /forum_post_votes(.:format) forum_post_votes#create +DELETE /forum_post_votes/:id(.:format) forum_post_votes#destroy +POST /forum_topics/:id/undelete(.:format) forum_topics#undelete +POST /forum_topics/mark_all_as_read(.:format) forum_topics#mark_all_as_read +GET /forum_topics(.:format) forum_topics#index +POST /forum_topics(.:format) forum_topics#create +GET /forum_topics/new(.:format) forum_topics#new +GET /forum_topics/:id/edit(.:format) forum_topics#edit +GET /forum_topics/:id(.:format) forum_topics#show +PATCH /forum_topics/:id(.:format) forum_topics#update +PUT /forum_topics/:id(.:format) forum_topics#update +DELETE /forum_topics/:id(.:format) forum_topics#destroy +GET /forum_topic_visits(.:format) forum_topic_visits#index +GET /ip_bans(.:format) ip_bans#index +POST /ip_bans(.:format) ip_bans#create +GET /ip_bans/new(.:format) ip_bans#new +PATCH /ip_bans/:id(.:format) ip_bans#update +PUT /ip_bans/:id(.:format) ip_bans#update +GET /ip_addresses(.:format) ip_addresses#index +GET /ip_addresses/:id(.:format) ip_addresses#show {:id=>/.+?(?=\.json|\.xml|\.html)|.+/} +GET /iqdb_queries/preview(.:format) iqdb_queries#preview +GET /iqdb_queries/check(.:format) redirect(301) +GET /iqdb_queries(.:format) iqdb_queries#show +POST /iqdb_queries(.:format) iqdb_queries#create +GET /mod_actions(.:format) mod_actions#index +POST /mod_actions(.:format) mod_actions#create +GET /mod_actions/new(.:format) mod_actions#new +GET /mod_actions/:id/edit(.:format) mod_actions#edit +GET /mod_actions/:id(.:format) mod_actions#show +PATCH /mod_actions/:id(.:format) mod_actions#update +PUT /mod_actions/:id(.:format) mod_actions#update +DELETE /mod_actions/:id(.:format) mod_actions#destroy +GET /moderation_reports(.:format) moderation_reports#index +POST /moderation_reports(.:format) moderation_reports#create +GET /moderation_reports/new(.:format) moderation_reports#new +GET /moderation_reports/:id(.:format) moderation_reports#show +GET /modqueue(.:format) modqueue#index +GET /news_updates(.:format) news_updates#index +POST /news_updates(.:format) news_updates#create +GET /news_updates/new(.:format) news_updates#new +GET /news_updates/:id/edit(.:format) news_updates#edit +GET /news_updates/:id(.:format) news_updates#show +PATCH /news_updates/:id(.:format) news_updates#update +PUT /news_updates/:id(.:format) news_updates#update +DELETE /news_updates/:id(.:format) news_updates#destroy +PUT /notes/:id/revert(.:format) notes#revert +GET /notes(.:format) notes#index +POST /notes(.:format) notes#create +GET /notes/new(.:format) notes#new +GET /notes/:id/edit(.:format) notes#edit +GET /notes/:id(.:format) notes#show +PATCH /notes/:id(.:format) notes#update +PUT /notes/:id(.:format) notes#update +DELETE /notes/:id(.:format) notes#destroy +GET /note_versions(.:format) note_versions#index +GET /note_versions/:id(.:format) note_versions#show +GET /note_previews(.:format) note_previews#show +GET /password_reset(.:format) password_resets#show +POST /password_reset(.:format) password_resets#create +GET /pixiv_ugoira_frame_data(.:format) pixiv_ugoira_frame_data#index +PUT /pools/:id/revert(.:format) pools#revert +POST /pools/:id/undelete(.:format) pools#undelete +GET /pools/gallery(.:format) pools#gallery +GET /pools/:pool_id/order/edit(.:format) pool_orders#edit +GET /pools(.:format) pools#index +POST /pools(.:format) pools#create +GET /pools/new(.:format) pools#new +GET /pools/:id/edit(.:format) pools#edit +GET /pools/:id(.:format) pools#show +PATCH /pools/:id(.:format) pools#update +PUT /pools/:id(.:format) pools#update +DELETE /pools/:id(.:format) pools#destroy +POST /pool_element(.:format) pool_elements#create +GET /pool_versions/:id/diff(.:format) pool_versions#diff +GET /pool_versions/search(.:format) pool_versions#search +GET /pool_versions(.:format) pool_versions#index +GET /post_replacements(.:format) post_replacements#index +POST /post_replacements(.:format) post_replacements#create +GET /post_replacements/new(.:format) post_replacements#new +PATCH /post_replacements/:id(.:format) post_replacements#update +PUT /post_replacements/:id(.:format) post_replacements#update +GET /post_votes(.:format) post_votes#index +GET /posts/:post_id/events(.:format) post_events#index +GET /posts/:post_id/replacements(.:format) post_replacements#index +POST /posts/:post_id/replacements(.:format) post_replacements#create +GET /posts/:post_id/replacements/new(.:format) post_replacements#new +PUT /posts/:post_id/artist_commentary/create_or_update(.:format) artist_commentaries#create_or_update +PUT /posts/:post_id/artist_commentary/revert(.:format) artist_commentaries#revert +GET /posts/:post_id/artist_commentary(.:format) artist_commentaries#show +DELETE /posts/:post_id/votes(.:format) post_votes#destroy +POST /posts/:post_id/votes(.:format) post_votes#create +PUT /posts/:id/revert(.:format) posts#revert +PUT /posts/:id/copy_notes(.:format) posts#copy_notes +GET /posts/:id/show_seq(.:format) posts#show_seq +PUT /posts/:id/mark_as_translated(.:format) posts#mark_as_translated +GET /posts/:post_id/similar(.:format) iqdb_queries#index +GET /post_appeals(.:format) post_appeals#index +POST /post_appeals(.:format) post_appeals#create +GET /post_appeals/new(.:format) post_appeals#new +GET /post_appeals/:id/edit(.:format) post_appeals#edit +GET /post_appeals/:id(.:format) post_appeals#show +PATCH /post_appeals/:id(.:format) post_appeals#update +PUT /post_appeals/:id(.:format) post_appeals#update +DELETE /post_appeals/:id(.:format) post_appeals#destroy +GET /post_flags(.:format) post_flags#index +POST /post_flags(.:format) post_flags#create +GET /post_flags/new(.:format) post_flags#new +GET /post_flags/:id/edit(.:format) post_flags#edit +GET /post_flags/:id(.:format) post_flags#show +PATCH /post_flags/:id(.:format) post_flags#update +PUT /post_flags/:id(.:format) post_flags#update +DELETE /post_flags/:id(.:format) post_flags#destroy +GET /post_approvals(.:format) post_approvals#index +POST /post_approvals(.:format) post_approvals#create +GET /post_disapprovals(.:format) post_disapprovals#index +POST /post_disapprovals(.:format) post_disapprovals#create +GET /post_disapprovals/:id(.:format) post_disapprovals#show +PUT /post_versions/:id/undo(.:format) post_versions#undo +GET /post_versions/search(.:format) post_versions#search +GET /post_versions(.:format) post_versions#index +PUT /artist_commentaries/create_or_update(.:format) artist_commentaries#create_or_update +GET /artist_commentaries/search(.:format) artist_commentaries#search +PUT /artist_commentaries/:id/revert(.:format) artist_commentaries#revert +GET /artist_commentaries(.:format) artist_commentaries#index +GET /artist_commentaries/:id(.:format) artist_commentaries#show +GET /artist_commentary_versions(.:format) artist_commentary_versions#index +GET /artist_commentary_versions/:id(.:format) artist_commentary_versions#show +GET /related_tag(.:format) related_tags#show +PATCH /related_tag(.:format) related_tags#update +PUT /related_tag(.:format) related_tags#update +GET /recommended_posts(.:format) recommended_posts#index +GET /robots(.:format) robots#index +GET /saved_searches(.:format) saved_searches#index +POST /saved_searches(.:format) saved_searches#create +GET /saved_searches/new(.:format) saved_searches#new +GET /saved_searches/:id/edit(.:format) saved_searches#edit +PATCH /saved_searches/:id(.:format) saved_searches#update +PUT /saved_searches/:id(.:format) saved_searches#update +DELETE /saved_searches/:id(.:format) saved_searches#destroy +GET /session/sign_out(.:format) sessions#sign_out +GET /session/new(.:format) sessions#new +DELETE /session(.:format) sessions#destroy +POST /session(.:format) sessions#create +GET /source(.:format) sources#show +GET /status(.:format) status#show +GET /tags(.:format) tags#index +POST /tags(.:format) tags#create +GET /tags/new(.:format) tags#new +GET /tags/:id/edit(.:format) tags#edit +GET /tags/:id(.:format) tags#show +PATCH /tags/:id(.:format) tags#update +PUT /tags/:id(.:format) tags#update +DELETE /tags/:id(.:format) tags#destroy +GET /tag_aliases(.:format) tag_aliases#index +GET /tag_aliases/:id(.:format) tag_aliases#show +DELETE /tag_aliases/:id(.:format) tag_aliases#destroy +GET /tag_implications(.:format) tag_implications#index +GET /tag_implications/:id(.:format) tag_implications#show +DELETE /tag_implications/:id(.:format) tag_implications#destroy +POST /uploads/preprocess(.:format) uploads#preprocess +GET /uploads/batch(.:format) uploads#batch +GET /uploads/image_proxy(.:format) uploads#image_proxy +GET /uploads(.:format) uploads#index +POST /uploads(.:format) uploads#create +GET /uploads/new(.:format) uploads#new +GET /uploads/:id/edit(.:format) uploads#edit +GET /uploads/:id(.:format) uploads#show +PATCH /uploads/:id(.:format) uploads#update +PUT /uploads/:id(.:format) uploads#update +DELETE /uploads/:id(.:format) uploads#destroy +GET /users/:user_id/favorite_groups(.:format) favorite_groups#index +GET /users/:user_id/email/verify(.:format) emails#verify +POST /users/:user_id/email/send_confirmation(.:format) emails#send_confirmation +GET /users/:user_id/email/edit(.:format) emails#edit +GET /users/:user_id/email(.:format) emails#show +PATCH /users/:user_id/email(.:format) emails#update +PUT /users/:user_id/email(.:format) emails#update +GET /users/:user_id/password/edit(.:format) passwords#edit +PATCH /users/:user_id/password(.:format) passwords#update +PUT /users/:user_id/password(.:format) passwords#update +POST /users/:user_id/api_key/view(.:format) maintenance/user/api_keys#view +GET /users/:user_id/api_key(.:format) maintenance/user/api_keys#show +PATCH /users/:user_id/api_key(.:format) maintenance/user/api_keys#update +PUT /users/:user_id/api_key(.:format) maintenance/user/api_keys#update +DELETE /users/:user_id/api_key(.:format) maintenance/user/api_keys#destroy +GET /users/custom_style(.:format) users#custom_style +GET /users(.:format) users#index +POST /users(.:format) users#create +GET /users/new(.:format) users#new +GET /users/:id/edit(.:format) users#edit +GET /users/:id(.:format) users#show +PATCH /users/:id(.:format) users#update +PUT /users/:id(.:format) users#update +DELETE /users/:id(.:format) users#destroy +GET /user_upgrades(.:format) user_upgrades#index +POST /user_upgrades(.:format) user_upgrades#create +GET /user_upgrades/new(.:format) user_upgrades#new +GET /user_upgrades/:id(.:format) user_upgrades#show +GET /user_feedbacks(.:format) user_feedbacks#index +POST /user_feedbacks(.:format) user_feedbacks#create +GET /user_feedbacks/new(.:format) user_feedbacks#new +GET /user_feedbacks/:id/edit(.:format) user_feedbacks#edit +GET /user_feedbacks/:id(.:format) user_feedbacks#show +PATCH /user_feedbacks/:id(.:format) user_feedbacks#update +PUT /user_feedbacks/:id(.:format) user_feedbacks#update +GET /user_name_change_requests(.:format) user_name_change_requests#index +POST /user_name_change_requests(.:format) user_name_change_requests#create +GET /user_name_change_requests/new(.:format) user_name_change_requests#new +GET /user_name_change_requests/:id(.:format) user_name_change_requests#show +POST /webhooks/receive(.:format) webhooks#receive +GET /webhooks(.:format) webhooks#index +POST /webhooks(.:format) webhooks#create +GET /webhooks/new(.:format) webhooks#new +GET /webhooks/:id/edit(.:format) webhooks#edit +GET /webhooks/:id(.:format) webhooks#show +PATCH /webhooks/:id(.:format) webhooks#update +PUT /webhooks/:id(.:format) webhooks#update +DELETE /webhooks/:id(.:format) webhooks#destroy +PUT /wiki_pages/:id/revert(.:format) wiki_pages#revert {:id=>/.+?(?=\.json|\.xml|\.html)|.+/} +GET /wiki_pages/search(.:format) wiki_pages#search +GET /wiki_pages/show_or_new(.:format) wiki_pages#show_or_new +GET /wiki_pages(.:format) wiki_pages#index +POST /wiki_pages(.:format) wiki_pages#create +GET /wiki_pages/new(.:format) wiki_pages#new +GET /wiki_pages/:id/edit(.:format) wiki_pages#edit {:id=>/.+?(?=\.json|\.xml|\.html)|.+/} +GET /wiki_pages/:id(.:format) wiki_pages#show {:id=>/.+?(?=\.json|\.xml|\.html)|.+/} +PATCH /wiki_pages/:id(.:format) wiki_pages#update {:id=>/.+?(?=\.json|\.xml|\.html)|.+/} +PUT /wiki_pages/:id(.:format) wiki_pages#update {:id=>/.+?(?=\.json|\.xml|\.html)|.+/} +DELETE /wiki_pages/:id(.:format) wiki_pages#destroy {:id=>/.+?(?=\.json|\.xml|\.html)|.+/} +GET /wiki_page_versions/diff(.:format) wiki_page_versions#diff +GET /wiki_page_versions(.:format) wiki_page_versions#index +GET /wiki_page_versions/:id(.:format) wiki_page_versions#show +GET /tag/index.xml(.:format) legacy#tags {:format=>/xml/} +GET /tag/index.json(.:format) legacy#tags {:format=>/json/} +GET /post/index.xml(.:format) legacy#posts {:format=>/xml/} +GET /post/index.json(.:format) legacy#posts {:format=>/json/} +GET /artist(.:format) redirect(301) +GET /artist/show/:id(.:format) redirect(301, /artists/%{id}) +GET /artist/show(.:format) redirect(301) +GET /forum(.:format) redirect(301) +GET /forum/show/:id(.:format) redirect(301) +GET /pool/show/:id(.:format) redirect(301, /pools/%{id}) +GET /post/index(.:format) redirect(301) +GET /post/atom(.:format) redirect(301) +GET /post/show/:id/:tag_title(.:format) redirect(301, /posts/%{id}) +GET /post/show/:id(.:format) redirect(301, /posts/%{id}) +GET /tag(.:format) redirect(301) +GET /tag/index(.:format) redirect(301) +GET /user/show/:id(.:format) redirect(301, /users/%{id}) +GET /wiki/show(.:format) redirect(301) +GET /help/:title(.:format) redirect(301) +GET /login(.:format) sessions#new +GET /logout(.:format) sessions#sign_out +GET /profile(.:format) users#profile +GET /settings(.:format) users#settings +GET /sitemap(.:format) static#sitemap_index +GET /opensearch(.:format) static#opensearch +GET /privacy(.:format) static#privacy_policy +GET /terms_of_service(.:format) static#terms_of_service +GET /static/keyboard_shortcuts(.:format) static#keyboard_shortcuts +GET /static/bookmarklet(.:format) static#bookmarklet +GET /static/site_map(.:format) static#site_map +GET /static/contact(.:format) static#contact +GET /static/dtext_help(.:format) static#dtext_help +GET /static/terms_of_service(.:format) redirect(301) +GET /mock/recommender/recommend/:user_id(.:format) mock_services#recommender_recommend +GET /mock/recommender/similiar/:post_id(.:format) mock_services#recommender_similar +GET /mock/reportbooru/missed_searches(.:format) mock_services#reportbooru_missed_searches +GET /mock/reportbooru/post_searches/rank(.:format) mock_services#reportbooru_post_searches +GET /mock/reportbooru/post_views/rank(.:format) mock_services#reportbooru_post_views +GET /mock/iqdbs/similar(.:format) mock_services#iqdbs_similar +POST /mock/iqdbs/similar(.:format) mock_services#iqdbs_similar + /*other(.:format) static#not_found</pre></div></details><h4>See also</h4><ul><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Anumber_syntax">Help:Number syntax</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Atext_syntax">Help:Text syntax</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Auser_syntax">Help:User syntax</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Aboolean_syntax">Help:Boolean syntax</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Aarray_syntax">Help:Array syntax</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Aapi_read_requests">Help:API read requests</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Aapi_write_requests">Help:API write requests</a></li><li><a class="dtext-link dtext-wiki-link" href="/wiki_pages/help%3Acommon_url_parameters">Help:Common URL Parameters</a></li></ul><h1>Go Back</h1><ul><li><a class="dtext-link" href="/wiki_pages/help:toc#dtext-developer_guide">Return to Developer Guide</a></li><li><a class="dtext-link" href="/help/toc">Return to the Table of Contents</a></li><li><a class="dtext-link" href="/help/home">Return to the Wiki Help Home Page</a></li></ul> + + + + + + + </div> + + + + </section> + </div> + </div> + </div> + + </div> + + <div id="tooltips"></div> + + <footer id="page-footer" class="text-sm text-center flex-initial mt-4 py-3 w-full border-t flex flex-wrap items-center justify-center gap-1 leading-none"> + <a href="/terms_of_service">Terms</a> + / <a href="/privacy">Privacy</a> + / <a href="/upgrade">Upgrade</a> + / <a href="/contact">Contact</a> + / + <a title="Running commit: a75d42dd4" class="social-icon" href="https://github.com/danbooru/danbooru"> + <img class="icon inline-block h-4" src="/packs/static/github-logo-c932001442ab985405de.png" /> +</a> <a class="social-icon" href="https://twitter.com/danboorubot"> + <img class="icon inline-block h-4" src="/packs/static/twitter-logo-44d2b3f3edf069d5a5f2.png" /> +</a> <a class="social-icon" href="https://discord.gg/danbooru"> + <img class="icon inline-block h-4" src="/packs/static/discord-logo-5c40c3a6f162a826276b.png" /> +</a> </footer> +</body></html> + diff --git a/docs/api/gelbooru-howto-api.html b/docs/api/gelbooru-howto-api.html new file mode 100644 index 0000000..b150bad --- /dev/null +++ b/docs/api/gelbooru-howto-api.html @@ -0,0 +1,124 @@ +<!DOCTYPE html><html lang="en"> + <head> + <meta charset="UTF-8"> + <title>howto:api - Wiki | Gelbooru - Anime Art & Hentai Gallery - Free to Explore</title> + <link rel="stylesheet preload" href="https://gelbooru.com//bootstrap.css"> + <link rel="stylesheet preload" type="text/css" media="screen" href="https://gelbooru.com//responsive.css?81" title="default" /> + + + <link rel="stylesheet preload" type="text/css" media="screen" href="https://gelbooru.com//css/jquery-ui.css?81" title="default" /> + <link rel="stylesheet preload" type="text/css" href="https://gelbooru.com//css/jquery-ui.icon-font.min.css?81"/> + <meta name="adsbytrafficjunkycontext" data-invocation-type="publisher" data-spot-new="true" data-site-id="444001" data-site="Gelbooru" data-platform="desktop"> +<link rel="SHORTCUT ICON" href="favicon.png" /> + <meta name="keywords" content="anime, doujinshi, hentai, porn, sex, japanese hentai, anime hentai, rule34, rule 34, imageboard" /> + <meta name="description" content="Browse millions of anime, manga, and video game themed images on Gelbooru. Discover art with detailed tags. Contains explicit hentai content. " /> + <meta name="rating" content="adult" /> + + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="search" type="application/opensearchdescription+xml" title="Gelbooru.com: Coded by Geltas" href="gelbooru.xml" /> + + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> + <script src="https://gelbooru.com//script/miscJs.js?1"></script> + <script src="https://gelbooru.com//script/jquery-hotkeys.js?1"></script> + + <script src="https://gelbooru.com//script/tryt.js"></script> + <script src="https://gelbooru.com//autoDebug.js"></script> + </head> + <style> + .mn-container-adsby_position_bottom-right { + display: none; + } + </style> + <body> + + + <div class="container-fluid"> + <nav class="navbar navbar-default"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="https://gelbooru.com/"></a> + </div> + <div id="navbar" class="navbar-collapse collapse"> + <ul class="nav navbar-nav"> + <li><a href="https://gelbooru.com/index.php?page=account&s=home">Settings</a></li> + <li><a href="https://gelbooru.com/index.php?page=post&s=list&tags=all">Posts</a></li> + <li><a href="https://gelbooru.com/index.php?page=comment&s=list">Comments</a></li> + <li class="active strong"><a href="https://gelbooru.com/index.php?page=wiki&s=list">Wiki</a></li> + <li><a href="https://gelbooru.com/index.php?page=tags&s=list">Tags</a></li> + <li><a href="https://gelbooru.com/index.php?page=pool&s=list">Pools</a></li> + <li><a href="https://gelbooru.com/index.php?page=forum&s=list">Forum</a></li> + <li><a href="https://gelbooru.com/index.php?page=tracker&s=list">Trac</a></li> + <li><a class="ui-icon ui-icon-lightbulb" href="javascript:;" onclick="darkModeToggle(); return false;" style="color: #ffff00; font-size: 20px; margin: 7px 5px 7px 15px;"></a></li> + + </ul> + </div> + </nav> + <nav class="navbar navbar-default" id="submenu"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar2" aria-expanded="false" aria-controls="navbar"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <div id="navbar2" class="navbar-collapse collapse"> + <ul class="nav navbar-nav"><li><a href="index.php?page=wiki&s=create"><b>Create</b></a></li> + <li><a href="index.php?page=wiki&s=list">List</a></li><li><a href="index.php?page=wiki&s=edit&id=18780">Edit</a></li><li><a href="index.php?page=wiki&s=history&id=18780">History</a></li><li><a href="index.php?page=wiki&s=manage&action=delete&id=18780" onclick="javascript: return confirm('Are you sure you wish to delete this wiki entry?');">Delete</a></li><li><a href="index.php?page=wiki&s=manage&action=lock&id=18780">Lock</a></li></ul></div></nav></div><div class="alert alert-warning small" style="padding: 10px 15px 10px 15px; font-size: 11px;" id="motd"> + <i><b>Notice</b></i>: <a href="https://twitter.com/gelbooru/status/1577845556273102848" style="color: #ffff00; font-weight: bold;" target="_blank">My personal stance on AI generated artwork. Retweet and share if you agree. Let us discuss, and not immediately scream bloody murder.</a> + </div> + <div style="display: none; padding: 0px 15px 0px 15px;" id="motdspacer"> </div> + <div class="padding15"> + <div id="long-notice"></div><div id="notice" style="display: none;"></div> + <div class="alert alert-success" role="alert" style="display: none;"><center><a href="index.php?page=gmail">You have mail</a></center></div> + <script type="text/javascript"> + if($.cookie('motd') == 1) + { + $("#motd").hide(); + $("#motdspacer").show(); + } + + function darkModeToggle() + { + if ($.cookie('dark_mode') == 1 ) + { + $.removeCookie("dark_mode"); + } + else + { + $.cookie("dark_mode", 1, { expires : 365 }); + } + location.reload(); + } + </script> + + + <script src="https://gelbooru.com//script/application3.js?62"></script> + <script src="https://gelbooru.com//script/license.30.js"></script> + + <div class="row"> + <div class="col-xs-12"> + <form action="?page=wiki&s=list" method="post"> + <div class="row"> + <div class="col-xs-12"> + <input id="tags-search" name="search" style="padding: 7px; width: calc(100% - 125px);" type="text" value="" placeholder="Ex: blue_sky cloud 1girl"/> + <input name="commit" class="new_secondary_search" type="submit" value="Search" /> + </div> + </div> + </form> + </div> + </div> + <br /> + + + <table cellspacing="0" cellpadding="0" style="width: 100%; padding: 0px; margin: 0px;"><tr><td style="vertical-align: top; padding-right: 20px; text-align: justify; border-right: 3px solid #f7f7f7;"> + <h2 style="display: inline;">Now Viewing: howto:api</h2><br /><span><b>Tag type: None</b></span><br /><br /> + <h1>Api Basics Documentation</h1><br />You should never receive an error unless the server is overloaded or the search dies.<br /><br /><h2>Authentication</h2><br />We will occasionally require authentication to access our API and throttle access to our API. This is to mitigate abusive behavior.<br /><br /><b>&api_key=API_KEY_HERE&user_id=USER_ID_HERE</b><br /><br /><b>API_KEY_HERE</b> Your API Key which is accessible within your account options page.<br /><b>USER_ID_HERE</b> Your user ID, which is accessible on the account options/profile page.<br /><br />Your requests will not be limited if you have contributed to the Patreon in the past.<br /><br /><h2>Posts List</h2><br /><br />Url for API access: <b>/index.php?page=dapi&s=post&q=index</b><br /><br /><b>limit</b> How many posts you want to retrieve. There is a default limit of 100 posts per request.<br /><b>pid</b> The page number.<br /><b>tags</b> The tags to search for. Any tag combination that works on the web site will work here. This includes all the meta-tags. See <a href="index.php?page=wiki&s=list&search=howto:search">howto:search</a> and <a href="index.php?page=wiki&s=list&search=howto:cheatsheet">howto:cheatsheet</a> for more information.<br /><b>cid</b> Change ID of the post. This is in Unix time so there are likely others with the same value if updated at the same time.<br /><b>id</b> The post id.<br /><b>json</b> Set to 1 for JSON formatted response.<br /><br /><h2>Tag List</h2><br /><br />Url for API access: <b>/index.php?page=dapi&s=tag&q=index</b><br /><br /><b>id</b> The tag's id in the database. This is useful to grab a specific tag if you already know this value.<br /><b>limit</b> How many tags you want to retrieve. There is a default limit of 100 per request.<br /><b>after_id</b> Grab tags whose ID is greater than this value.<br /><b>name</b> Find tag information based on this value.<br /><b>names</b> Separated by spaces, get multiple results to tags you specify if it exists. (schoolgirl moon cat)<br /><b>name_pattern</b> A wildcard search for your query using LIKE. Use _ for single character wildcards or % for multi-character wildcards. (%choolgirl% would act as *choolgirl* wildcard search.) <br /><b>json</b> Set to 1 for JSON formatted response.<br /><b>order</b> Order by field specified (ASC or DESC)<br /><b>orderby</b> Order by a field. <br />- date<br />- count<br />- name<br /><br /><h2>User List</h2><br /><br />Url for API access: <b>/index.php?page=dapi&s=user&q=index</b><br /><br /><b>limit</b> How many posts you want to retrieve. There is a default limit of 100 posts per request.<br /><b>pid</b> The page number.<br /><b>name</b> The username to search for<br /><b>name_pattern</b> The username to search for, using a wildcard search.<br /><b>json</b> Set to 1 for JSON formatted response.<br /><br /><br /><h2>Comments List</h2><br /><br />Url for API access: <b>/index.php?page=dapi&s=comment&q=index</b><br /><br /><b>post_id The id number of the comment to retrieve.</b><br /><br /><br /><h2>Deleted Images</h2><br /><br />Url for API access: <b>/index.php?page=dapi&s=post&q=index&deleted=show</b><br /><br /><b>last_id</b> A numerical value. Will return everything above this number.<br /><br /><br /><br /><br /> + <b>Other Wiki Information</b><br /><br /> + <div style="padding: 10px; background: #e9f3ff; border: 1px solid #cee3ff">Last updated: 02/22/22 4:17 PM by <a href="index.php?page=account&s=profile&id=1">lozertuser</a></div><div style="padding: 10px; background: #f7fbff; text-align: center;"><img src="layout/icons/lock.png" alt="lock" style="margin-top: -3px;" /> This entry is locked and can not be edited.</div><br /><br /> + </td> + <td style="width: 50%; vertical-align: top;"><b>There are no images associated with this wiki entry.</b></td></tr></table><br /><br /> + <br /></div></body></html>
\ No newline at end of file diff --git a/docs/api/konachan-help-api.html b/docs/api/konachan-help-api.html new file mode 100644 index 0000000..eef4e0b --- /dev/null +++ b/docs/api/konachan-help-api.html @@ -0,0 +1,1016 @@ +<!DOCTYPE html> +<html class="action-help action-help-api hide-advanced-editing"> +<head> + <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> + <title>konachan.com - Konachan.com Anime Wallpapers</title> + <meta name="description" content="Konachan.com - Image board site for Anime / Manga wallpapers. Unlimited and unrestricted downloads."> + <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> + <link rel="top" title="konachan.com" href="/"> + <link href="https://konachan.com/help/api" rel="canonical" /> + <script type="text/javascript"> + var css = ".javascript-hide { display: none !important; }"; + var style = document.createElement("style"); style.type = "text/css"; + if(style.styleSheet) // IE + style.styleSheet.cssText = css; + else + style.appendChild(document.createTextNode(css)); + document.getElementsByTagName("head")[0].appendChild(style); + </script> + + + <link href="https://konachan.com/post/atom" rel="alternate" title="ATOM" type="application/atom+xml" /> + <link href="/assets/application-10824cb18d32efc10831809ea5f02fad.css" media="screen" rel="stylesheet" /> + + <script src="/assets/application-9ad076d8dede6744cfbcc270a8569b50.js"></script> + <script src="/assets/moe-legacy/application-ce3dc3e48d9ceff5fb362df103a23576.js"></script> + <script type="text/javascript"> + I18n.defaultLocale = "en"; + I18n.locale = "en"; +</script> + + <!--[if lt IE 8]> + <script src="/IE8.js" type="text/javascript"></script> + <![endif]--> + <link href="/opensearch.xml" rel="search" title="konachan.com" type="application/opensearchdescription+xml" /> + + <!--[if lt IE 7]> + <style type="text/css"> + body div#post-view > div#right-col > div > div#note-container > div.note-body { + overflow: visible; + } + </style> + <script src="https://ie7-js.googlecode.com/svn/trunk/lib/IE7.js" type="text/javascript"></script> + <![endif]--> + <meta content="authenticity_token" name="csrf-param" /> +<meta content="j5sqRNAXGCKFQ79J63hovxSbjZYFXr5XXmQvChQEkB4=" name="csrf-token" /> +</head> +<body> + <div class="overlay-notice-container" id="notice-container" style="display: none;"> + <table cellspacing=0 cellpadding=0> <tbody> + <tr> <td> + <div id="notice"> + </div> + </td> </tr> + </tbody> </table> +</div> + + <div id="header"> + <div id="title"><h2 id="site-title"><a href="https://konachan.com"><img alt="konachan.com" height="75" id="logo" src="/images/logo_small.png" width="484" /></a><span></span></h2></div> + <div class="clearfix" id="main-menu" data-controller="help"> + <ul> + <li class="user"><a href="/user/home">My Account</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a class="login-button" href="/user/login" id="login-link">Login</a></li> + <li><a href="/user/signup"><span class="translation_missing" title="translation missing: en.layouts.menu.account.register">Register</span></a></li> + <li><a href="/user/reset_password">Reset Password</a></li> + </ul> + </li> + <li class="post"><a href="/post">Posts</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/post" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="tags" type="text" /><br /> + <input type="submit" value="Search Posts" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/post">View Posts</a></li> + <li><a class="search-link" href="/post">Search Posts</a></li> + <li><a href="/post/upload">Upload</a></li> + <li><a href="/post?tags=order%3Arandom">Random</a></li> + <li><a href="/post/popular_recent">Popular</a></li> + <li><a href="/post/similar">Image Search</a></li> + <li><a href="/history">History</a></li> + </ul> + </li> + <li class="comment"><a href="/comment" id="comments-link">Comments</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/comment/search" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="query" type="text" /><br /> + <input type="submit" value="Search Comments" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/comment">View Comments</a></li> + <li><a class="search-link" href="/comment/search">Search Comments</a></li> + </ul> + </li> + <li class="note"><a href="/note">Notes</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/note/search" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="query" type="text" /><br /> + <input type="submit" value="Search Notes" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/note">View Notes</a></li> + <li><a class="search-link" href="/note/search">Search Notes</a></li> + <li><a href="/post?tags=translation_request">Requests</a></li> + </ul> + </li> + <li class="artist"><a href="/artist?order=date">Artists</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/artist" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="name" type="text" /><br /> + <input type="submit" value="Search Artists" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/artist">View Artists</a></li> + <li><a class="search-link" href="/artist">Search Artists</a></li> + <li><a href="/artist/create">Create</a></li> + </ul> + </li> + <li class="tag"><a href="/tag?order=date">Tags</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/tag" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="name" type="text" /><br /> + <input type="submit" value="Search Tags" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/tag">View Tags</a></li> + <li><a class="search-link" href="/tag">Search Tags</a></li> + <li><a href="/tag/popular_by_day">Popular</a></li> + <li><a href="/tag_alias">Aliases</a></li> + <li><a href="/tag_implication">Implications</a></li> + </ul> + </li> + <li class="switch"> + <a href="/post/switch">Safe Mode</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a href="/post/switch">Turn Explicit OFF</a></li> + </ul> + </li> + <li class="pool"><a href="/pool">Pools</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/pool" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="query" type="text" /><br /> + <input type="submit" value="Search Pools" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/pool">View Pools</a></li> + <li><a class="search-link" href="/pool">Search Pools</a></li> + <li><a href="/pool/create">Create New Pool</a></li> + </ul> + </li> + <li class="wiki"><a href="/wiki/show?title=help%3Ahome">Wiki</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/wiki" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="query" type="text" /><br /> + <input type="submit" value="Search Wiki" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/wiki">View Wiki Index</a></li> + <li><a class="search-link" href="/wiki">Search Wiki</a></li> + <li><a href="/wiki/add">Create New Page</a></li> + </ul> + </li> + <li class="forum"><a href="/forum" id="forum-link">Forum</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form accept-charset="UTF-8" action="/forum/search" method="get"><div style="margin:0;padding:0;display:inline"></div> + <input name="query" type="text" /><br /> + <input type="submit" value="Search Forums" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/forum">View Topics</a></li> + <li><a class="search-link" href="/forum">Search Forums</a></li> + <li><a href="/forum/new">New Topic</a></li> + <li><a href="/forum/mark_all_read" id="forum-mark-all-read" style="display: none;">Mark All Read</a></li> + <li class="forum-items-start"><span class="separator"></span></li> + </ul> + </li> + <li class="help"><a href="/help">Help</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a class="help-item post" href="/help/posts">Post Help</a> + <li><a class="help-item comment" href="/help/comments">Comment Help</a> + <li><a class="help-item note" href="/help/notes">Note Help</a> + <li><a class="help-item artist" href="/help/artists">Artist Help</a> + <li><a class="help-item tag" href="/help/tags">Tag Help</a> + <li><a class="help-item pool" href="/help/pools">Pool Help</a> + <li><a class="help-item wiki" href="/help/wiki">Wiki Help</a> + <li><a class="help-item forum" href="/help/forum">Forum Help</a> + <li><a href="/help">Site Help</a></li> + </ul> + </li> + <li class="static"><a href="/static/more">More »</a> + </li> + <li class="has-mail"> + <a href="/dmail" id="has-mail-notice">New Mail</a> + </li> + </ul> + <span id='cn' style="display: none;"> + </span> +</div> + + </div> + +<div id="login-background" style="display: none;"> </div> + +<div id="login-container" style="display: none;"> + <div id="login-container-inner"> + <div id="login-container-with-tabs"> + <div> + <ul class="flat-list login-tabs" id="login-tabs"> + <li id="tab-login"><a href="#">Login</a></li> + <li id="tab-reset"><a href="#">Reset Password</a></li> + </ul> + </div> + <div id="login" style="position: relative;"> + <p id="tab-login-text" class="tab-header-text"> + Please log in. To create a new account, enter the name and password you want to use. + </p> + <p id="tab-reset-text" class="tab-header-text"> + If you supplied an email address when you signed up or added a email later, you can have your password reset. + </p> + + <form accept-charset="UTF-8" action="/user/authenticate" id="login-popup" method="post"><div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="j5sqRNAXGCKFQ79J63hovxSbjZYFXr5XXmQvChQEkB4=" /></div> + <div style="position: absolute; top: 0; right: 0;"> + <a href="#" id="login-popup-cancel" style="font-size: 1.2em; padding: 2px;">ⓧ</a> + </div> + + <table class="form" style="width: 80%; max-width: 30em; margin-bottom: .5em; margin-left: auto; margin-right: auto;"> + <tr> + <th style="width: 8em"><label class="block" for="login-popup-username">Name</label></th> + <td style="width: 10em" align=left><input id="login-popup-username" name="username" type="text" style="width: 100%;"></td> + </tr> + <tr id="login-popup-email-box"> + <th><label class="block" for="login-popup-email">Email</label></th> + <td align=left><input id="login-popup-email" name="email" type="text" style="width: 100%;"></td> + </tr> + <tr id="login-popup-password-box"> + <th><label class="block" for="login-popup-password">Password</label></th> + <td align=left><input id="login-popup-password" name="password" type="password" style="width: 100%;"></td> + </tr> + <tr id="login-popup-password-confirm-box" style="display: none;"> + <th><label class="block" for="login-popup-password-confirm">Confirm Password</label></th> + <td align=left><input id="login-popup-password-confirm" name="password-confirm" type="password" style="width: 100%;"></td> + </tr> + <tr> + <th style="background: none;"></th> + <td align=left> + </td> + </tr> + </table> + <a href="#" id="login-popup-submit" style="margin-bottom: 1em; margin-left: auto; margin-right: auto;">Login</a> +</form> + <div id="login-popup-notices" class="login-popup-notice"> + <span id="login-popup-login-confirm-password"> + This user name doesn't exist. If you want to create a new account, just verify your password and log in. + </span> + <span id="login-popup-login-user-exists"> + This user name exists. If you want to create a new account, please choose a different name. + </span> + <span id="login-popup-reset-user-exists"> + Enter the current email address you have registered in your profile. You'll get an email containing your new password. + </span> + <span id="login-popup-reset-user-has-no-email"> + You have no email address in your profile, so you can't have your password reset. + </span> + <span id="login-popup-reset-successful"> + Password reset. Check your email in a few minutes + </span> + <span id="login-popup-reset-unknown-user"> + That account does not exist. + </span> + <span id="login-popup-reset-blank"> + </span> + <span id="login-popup-reset-user-email-incorrect"> + The email address specified is not registered with this account. + </span> + <span id="login-popup-reset-user-email-invalid"> + Delivery to this email address has failed. + </span> + <span id="login-popup-message"> + </span> + </div> + </div> + </div> + + </div> +</div> + +<script type="text/javascript">document.observe("dom:loaded", function() { User.init(); });</script> + + + + + <!--[if lt IE 7]> + <div style="display: none;" id="old-browser">Your browser is very old, and this site will not display properly. + Please consider upgrading to a more recent web browser: + <a href="http://www.mozilla.com/firefox/">Firefox</a>, + <a href="http://www.opera.com/">Opera</a>, + <a href="http://www.microsoft.com/windows/internet-explorer/download-ie.aspx">Internet Explorer</a>. + <div style="text-align: right;" id="old-browser-hide"> + <a href="#" onclick='$("old-browser").hide(); Cookie.put("hide-ie-nag", "1");'>(hide this message)</a> + </div> + </div> + <![endif]--> + <div class="overlay-notice-container" id="notice-container" style="display: none;"> + <table cellspacing=0 cellpadding=0> <tbody> + <tr> <td> + <div id="notice"> + </div> + </td> </tr> + </tbody> </table> +</div> + + + <div class="blocked" id="block-reason" style="display: none;"> + </div> + + <div id="content"> + <div class="help"> + <h1>Help: API 1.13.0+update.3</h1> + + <div class="section"> + <p>Moebooru offers API which is mostly compatible with Danbooru API (version 1.13.0) to make scripting easy. All you need is a way to <a href="https://en.wikipedia.org/wiki/HTTP_GET#Request_methods">GET and POST</a> to <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Locator">URLs</a>. The ability to parse <a href="https://en.wikipedia.org/wiki/Xml">XML</a> or <a href="https://en.wikipedia.org/wiki/Json">JSON</a> responses is nice, but not critical. The simplicity of the API means you can write scripts using JavaScript, Perl, Python, Ruby, even shell languages like bash or tcsh.</p> + <p style="text-align: center;"><a href="#changelog">Change Log</a> | <a href="#posts">Posts</a> | <a href="#tags">Tags</a> | <a href="#artists">Artists</a> | <a href="#comments">Comments</a> | <a href="#wiki">Wiki</a> | <a href="#notes">Notes</a> | <a href="#users">Users</a> | <a href="#forum">Forum</a> | <a href="#pools">Pools</a></p> + </div> + + <div class="section"> + <div class="section"> + <h2>Basics</h2> + <p>HTTP defines two request methods: GET and POST. You'll be using these two methods to interact with the Danbooru API. Most API calls that change the state of the database (like creating, updating, or deleting something) require an HTTP POST call. API calls that only retrieve data can typically be done with an HTTP GET call.</p> + <p>In the Danbooru API, a URL is analogous to a function name. You pass in the function parameters as a query string. Here's an extremely simple example: <a class="code" href="/post.xml?limit=1" target="_blank">/post.xml?limit=1</a>.</p> + <p>The <code>post</code> part indicates the controller we're working with. In this case it's posts. <code>index</code> describes the action. Here we're retrieving a list of posts. Finally, the <code>xml</code> part describes what format we want the response in. You can specify <code>.xml</code> for XML responses, <code>.json</code> for JSON responses, and nothing at all for HTML responses.</p> + </div> + + <div class="section"> + <h4>Responses</h4> + <p>All API calls that change state will return a single element response (for XML calls). They are formatted like this:</p> + <div class="code"> + <?xml version="1.0" encoding="UTF-8"?><br> + <response success="false" reason="duplicate"/> + </div> + <p>For JSON responses, they'll look like this:</p> + <div class="code"> + {success: false, reason: "duplicate"} + </div> + <p>While you can usually determine success or failure based on the response object, you can also figure out what happened based on the HTTP status code. In addition to the standard ones, Danbooru uses some custom status codes in the 4xx and 5xx range.</p> + <table> + <thead> + <tr> + <th>Status Code</th> + <th>Meaning</th> + </tr> + </thead> + <tbody> + <tr> + <td>200 OK</td> + <td>Request was successful</td> + </tr> + <tr> + <td>403 Forbidden</td> + <td>Access denied</td> + </tr> + <tr> + <td>404 Not Found</td> + <td>Not found</td> + </tr> + <tr> + <td>420 Invalid Record</td> + <td>Record could not be saved</td> + </tr> + <tr> + <td>421 User Throttled</td> + <td>User is throttled, try again later</td> + </tr> + <tr> + <td>422 Locked</td> + <td>The resource is locked and cannot be modified</td> + </tr> + <tr> + <td>423 Already Exists</td> + <td>Resource already exists</td> + </tr> + <tr> + <td>424 Invalid Parameters</td> + <td>The given parameters were invalid</td> + </tr> + <tr> + <td>500 Internal Server Error</td> + <td>Some unknown error occurred on the server</td> + </tr> + <tr> + <td>503 Service Unavailable</td> + <td>Server cannot currently handle the request, try again later</td> + </tr> + </tbody> + </table> + </div> + + <div class="section"> + <h4>JSON Responses</h4> + <p>While you will probably want to work with XML in the majority of cases, if you're writing something in Javascript then the JSON responses may be preferable. They are much faster to parse and there's less code to write to get your data structure:</p> + <div class="code"> + var data = eval("(" + responseText + ")")<br> + alert(data.response) + </div> + </div> + + <div class="section"> + <h4>Logging In</h4> + <p>Some actions may require you to log in. For any action you can always specify two parameters to identify yourself:</p> + <ul> + <li><strong>login</strong> Your login name.</li> + <li><strong>password_hash</strong> Your SHA1 hashed password. Simply hashing your plain password will NOT work since Danbooru salts its passwords. The actual string that is hashed is "So-I-Heard-You-Like-Mupkids-?--<em>your-password</em>--".</li> + </ul> + <p>Please be aware of the security risks involved in sending your password through an unencrypted channel. Although your password will be hashed, it is still theoretically possible for someone to steal your account by creating a fake cookie based on your hashed password.</p> + </div> + </div> + + + + <div class="section"> + <a name="posts"></a> + <h2>Posts</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /post.xml.</p> + <ul> + <li><strong>limit</strong> How many posts you want to retrieve. There is a hard limit of 100 posts per request.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>tags</strong> The tags to search for. Any tag combination that works on the web site will work here. This includes all the meta-tags.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /post/create.xml. There are only two mandatory fields: you need to supply the tags, and you need to supply the file, either through a multipart form or through a source URL.</p> + <ul> + <li><strong>post[tags]</strong> A space delimited list of tags.</li> + <li><strong>post[file]</strong> The file data encoded as a multipart form.</li> + <li><strong>post[rating]</strong> The rating for the post. Can be: safe, questionable, or explicit.</li> + <li><strong>post[source]</strong> If this is a URL, Danbooru will download the file.</li> + <li><strong>post[is_rating_locked]</strong> Set to true to prevent others from changing the rating.</li> + <li><strong>post[is_note_locked]</strong> Set to true to prevent others from adding notes.</li> + <li><strong>post[parent_id]</strong> The ID of the parent post.</li> + <li><strong>md5</strong> Supply an MD5 if you want Danbooru to verify the file after uploading. If the MD5 doesn't match, the post is destroyed.</li> + </ul> + <p>If the call fails, the following response reasons are possible:</p> + <ul> + <li><strong>MD5 mismatch</strong> This means you supplied an MD5 parameter and what Danbooru got doesn't match. Try uploading the file again.</li> + <li><strong>duplicate</strong> This post already exists in Danbooru (based on the MD5 hash). An additional attribute called <code>location</code> will be set, pointing to the (relative) URL of the original post.</li> + <li><strong><em>other</em></strong> Any other error will have its error message printed.</li> + </ul> + <p>If the post upload succeeded, you'll get an attribute called <code>location</code> in the response pointing to the relative URL of your newly uploaded post.</p> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /post/update.xml. Only the <code>id</code> parameter is required. Leave the other parameters blank if you don't want to change them.</p> + <ul> + <li><strong>id</strong> The id number of the post to update.</li> + <li><strong>post[tags]</strong> A space delimited list of tags.</li> + <li><strong>post[file]</strong> The file data encoded as a multipart form.</li> + <li><strong>post[rating]</strong> The rating for the post. Can be: safe, questionable, or explicit.</li> + <li><strong>post[source]</strong> If this is a URL, Danbooru will download the file.</li> + <li><strong>post[is_rating_locked]</strong> Set to true to prevent others from changing the rating.</li> + <li><strong>post[is_note_locked]</strong> Set to true to prevent others from adding notes.</li> + <li><strong>post[parent_id]</strong> The ID of the parent post.</li> + </ul> + </div> + <div class="section"> + <h4>Destroy</h4> + <p>You must be logged in to use this action. You must also be the user who uploaded the post (or you must be a moderator).</p> + <ul> + <li><strong>id</strong> The id number of the post to delete.</li> + </ul> + </div> + <div class="section"> + <h4>Revert Tags</h4> + <p>This action reverts a post to a previous set of tags. The base URL is /post/revert_tags.xml.</p> + <ul> + <li><strong>id</strong> The post id number to update.</li> + <li><strong>history_id</strong> The id number of the tag history.</li> + </ul> + </div> + <div class="section"> + <h4>Vote</h4> + <p>This action lets you vote for a post. You can only vote once per post per IP address. The base URL is /post/vote.xml.</p> + <ul> + <li><strong>id</strong> The post id number to update.</li> + <li><strong>score</strong> Set to <code>1</code> to vote up and <code>-1</code> to vote down. All other values will be ignored.</li> + </ul> + <p>If the call did not succeed, the following reasons are possible:</p> + <ul> + <li><strong>already voted</strong> You have already voted for this post.</li> + <li><strong>invalid score</strong> You have supplied an invalid score.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="tags"></a> + <h2>Tags</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /tag.xml.</p> + <ul> + <li><strong>limit</strong> How many tags to retrieve. Setting this to 0 will return every tag.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>order</strong> Can be <code>date</code>, <code>count</code>, or <code>name</code>.</li> + <li><strong>id</strong> The id number of the tag.</li> + <li><strong>after_id</strong> Return all tags that have an id number greater than this.</li> + <li><strong>name</strong> The exact name of the tag.</li> + <li><strong>name_pattern</strong> Search for any tag that has this parameter in its name.</li> + </ul> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /tag/update.xml.</p> + <ul> + <li><strong>name</strong> The name of the tag to update.</li> + <li><strong>tag[tag_type]</strong> The tag type. General: 0, artist: 1, copyright: 3, character: 4.</li> + <li><strong>tag[is_ambiguous]</strong> Whether or not this tag is ambiguous. Use 1 for true and 0 for false.</li> + </ul> + </div> + <div class="section"> + <h4>Related</h4> + <p>The base URL is /tag/related.xml.</p> + <ul> + <li><strong>tags</strong> The tag names to query.</li> + <li><strong>type</strong> Restrict results to this tag type (can be <code>general</code>, <code>artist</code>, <code>copyright</code>, or <code>character</code>).</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="artists"></a> + <h2>Artists</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /artist.xml.</p> + <ul> + <li><strong>name</strong> The name (or a fragment of the name) of the artist.</li> + <li><strong>order</strong> Can be <code>date</code> or <code>name</code>.</li> + <li><strong>page</strong> The page number.</li> + </ul> + </div> + <div class="section"> + <h4>Create</h4> + <p>The base URL is /artist/create.xml.</p> + <ul> + <li><strong>artist[name]</strong> The artist's name.</li> + <li><strong>artist[urls]</strong> A list of URLs associated with the artist, whitespace delimited.</li> + <li><strong>artist[alias]</strong> The artist that this artist is an alias for. Simply enter the alias artist's name.</li> + <li><strong>artist[group]</strong> The group or cicle that this artist is a member of. Simply enter the group's name.</li> + </ul> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /artist/update.xml. Only the <strong>id</strong> parameter is required. The other parameters are optional.</p> + <ul> + <li><strong>id</strong> The id of thr artist to update.</li> + <li><strong>artist[name]</strong> The artist's name.</li> + <li><strong>artist[urls]</strong> A list of URLs associated with the artist, whitespace delimited.</li> + <li><strong>artist[alias]</strong> The artist that this artist is an alias for. Simply enter the alias artist's name.</li> + <li><strong>artist[group]</strong> The group or cicle that this artist is a member of. Simply enter the group's name.</li> + </ul> + </div> + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /artist/destroy.xml. You must be logged in to delete artists.</p> + <ul> + <li><strong>id</strong> The id of the artist to destroy.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="comments"></a> + <h2>Comments</h2> + + <div class="section"> + <h4>Show</h4> + <p>The base URL is /comment/show.xml. This retrieves a single comment.</p> + <ul> + <li><strong>id</strong> The id number of the comment to retrieve.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /comment/create.xml.</p> + <ul> + <li><strong>comment[anonymous]</strong> Set to 1 if you want to post this comment anonymously.</li> + <li><strong>comment[post_id]</strong> The post id number to which you are responding.</li> + <li><strong>comment[body]</strong> The body of the comment.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base url is /comment/destroy.xml. You must be logged in to use this action. You must also be the owner of the comment, or you must be a moderator.</p> + <ul> + <li><strong>id</strong> The id number of the comment to delete.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="wiki"></a> + <h2>Wiki</h2> + <p>All titles must be exact (but case and whitespace don't matter).</p> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /wiki.xml. This retrieves a list of every wiki page.</p> + <ul> + <li><strong>order</strong> How you want the pages ordered. Can be: <code>title</code>, <code>date</code>.</li> + <li><strong>limit</strong> The number of pages to retrieve.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>query</strong> A word or phrase to search for.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /wiki/create.xml.</p> + <ul> + <li><strong>wiki_page[title]</strong> The title of the wiki page.</li> + <li><strong>wiki_page[body]</strong> The body of the wiki page.</li> + </ul> + </div> + + <div class="section"> + <h4>Update</h4> + <p>The base URL is /wiki/update.xml. Potential error reasons: "Page is locked"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to update.</li> + <li><strong>wiki_page[title]</strong> The new title of the wiki page.</li> + <li><strong>wiki_page[body]</strong> The new body of the wiki page.</li> + </ul> + </div> + + <div class="section"> + <h4>Show</h4> + <p>The base URL is /wiki/show.xml. Potential error reasons: "artist type"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to retrieve.</li> + <li><strong>version</strong> The version of the page to retrieve.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /wiki/destroy.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to delete.</li> + </ul> + </div> + + <div class="section"> + <h4>Lock</h4> + <p>The base URL is /wiki/lock.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to lock.</li> + </ul> + </div> + + <div class="section"> + <h4>Unlock</h4> + <p>The base URL is /wiki/unlock.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to unlock.</li> + </ul> + </div> + + <div class="section"> + <h4>Revert</h4> + <p>The base URL is /wiki/revert.xml. Potential error reasons: "Page is locked"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to update.</li> + <li><strong>version</strong> The version to revert to.</li> + </ul> + </div> + + <div class="section"> + <h4>History</h4> + <p>The base URL is /wiki/history.xml.</p> + <ul> + <li><strong>title</strong> The title of the wiki page to retrieve versions for.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="notes"></a> + <h2>Notes</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /note.xml.</p> + <ul> + <li><strong>post_id</strong> The post id number to retrieve notes for.</li> + </ul> + </div> + + <div class="section"> + <h4>Search</h4> + <p>The base URL is /note/search.xml.</p> + <ul> + <li><strong>query</strong> A word or phrase to search for.</li> + </ul> + </div> + + <div class="section"> + <h4>History</h4> + <p>The base URL is /note/history.xml. You can either specify <code>id</code>, <code>post_id</code>, or nothing. Specifying nothing will give you a list of every note verison.</p> + <ul> + <li><strong>limit</strong> How many versions to retrieve.</li> + <li><strong>page</strong> The offset.</li> + <li><strong>post_id</strong> The post id number to retrieve note versions for.</li> + <li><strong>id</strong> The note id number to retrieve versions for.</li> + </ul> + </div> + + <div class="section"> + <h4>Revert</h4> + <p>The base URL is /note/revert.xml. Potential error reasons: "Post is locked"</p> + <ul> + <li><strong>id</strong> The note id to update.</li> + <li><strong>version</strong> The version to revert to.</li> + </ul> + </div> + + <div class="section"> + <h4>Create/Update</h4> + <p>The base URL is /note/update.xml. Notes differ from the other controllers in that the interface for creation and updates is the same. If you supply an <code>id</code> parameter, then Danbooru will assume you're updating an existing note. Otherwise, it will create a new note. Potential error reasons: "Post is locked"</p> + <ul> + <li><strong>id</strong> If you are updating a note, this is the note id number to update.</li> + <li><strong>note[post_id]</strong> The post id number this note belongs to.</li> + <li><strong>note[x]</strong> The x coordinate of the note.</li> + <li><strong>note[y]</strong> The y coordinate of the note.</li> + <li><strong>note[width]</strong> The width of the note.</li> + <li><strong>note[height]</strong> The height of the note.</li> + <li><strong>note[is_active]</strong> Whether or not the note is visible. Set to 1 for active, 0 for inactive.</li> + <li><strong>note[body]</strong> The note message.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="users"></a> + <h2>Users</h2> + + <div class="section"> + <h4>Search</h4> + <p>The base URL is /user.xml. If you don't specify any parameters you'll get a listing of all users.</p> + <ul> + <li><strong>id</strong> The id number of the user.</li> + <li><strong>name</strong> The name of the user.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="forum"></a> + <h2>Forum</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /forum.xml. If you don't specify any parameters you'll get a list of all the parent topics.</p> + <ul> + <li><strong>parent_id</strong> The parent ID number. You'll return all the responses to that forum post.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="pools"></a> + <h2>Pools</h2> + + <div class="section"> + <h4>List Pools</h4> + <p>The base URL is /pool.xml. If you don't specify any parameters you'll get a list of all pools.</p> + <ul> + <li><strong>query</strong> The title.</li> + <li><strong>page</strong> The page.</li> + </ul> + </div> + + <div class="section"> + <h4>List Posts</h4> + <p>The base URL is /pool/show.xml. If you don't specify any parameters you'll get a list of all pools.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + <li><strong>page</strong> The page.</li> + </ul> + </div> + + <div class="section"> + <h4>Update</h4> + <p>The base URL is /pool/update.xml.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + <li><strong>pool[name]</strong> The name.</li> + <li><strong>pool[is_public]</strong> 1 or 0, whether or not the pool is public.</li> + <li><strong>pool[description]</strong> A description of the pool.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /pool/create.xml.</p> + <ul> + <li><strong>pool[name]</strong> The name.</li> + <li><strong>pool[is_public]</strong> 1 or 0, whether or not the pool is public.</li> + <li><strong>pool[description]</strong> A description of the pool.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /pool/destroy.xml.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + </ul> + </div> + + <div class="section"> + <h4>Add Post</h4> + <p>The base URL is /pool/add_post.xml. Potential error reasons: "Post already exists", "access denied"</p> + <ul> + <li><strong>pool_id</strong> The pool to add the post to.</li> + <li><strong>post_id</strong> The post to add.</li> + </ul> + </div> + + <div class="section"> + <h4>Remove Post</h4> + <p>The base URL is /pool/remove_post.xml. Potential error reasons: "access denied"</p> + <ul> + <li><strong>pool_id</strong> The pool to remove the post from.</li> + <li><strong>post_id</strong> The post to remove.</li> + </ul> + </div> + + </div> + + + + <div class="section"> + <a name="favorites"></a> + <h2>Favorites</h2> + + <div class="section"> + <h4>List Users</h4> + <p>The base URL is /favorite/list_users.json. There is no XML API for this action.</p> + <ul> + <li><strong>id</strong> The post id.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="changelog"></a> + <h2>Change Log</h2> + <div class="section"> + <h4>1.13.0+update.3</h4> + <ul> + <li>Removed /index from API URLs</li> + </ul> + <h4>1.13.0+update.2</h4> + <ul> + <li>Readd favorite/list_users API</li> + </ul> + <h4>1.13.0+update.1</h4> + <ul> + <li>Added documentation for pools</li> + </ul> + + <h4>1.13.0</h4> + <ul> + <li>Changed interface for artists to use new URL system</li> + <li>JSON requests now end in a .json suffix</li> + <li>Renamed some error reason messages</li> + <li>Removed comment/index from API</li> + <li>Removed url and md5 parameters from artist search (can just pass the URL or MD5 hash to the name parameter)</li> + </ul> + </div> + + <div class="section"> + <h4>1.8.1</h4> + <ul> + <li>Removed post[is_flagged] attribute</li> + </ul> + </div> + </div> +</div> + + + <div class="footer"> + + <ul class="flat-list" id="subnavbar"> + <li><a href="/help">Help</a></li> + + </ul> + </div> + </div> + + <script type="text/javascript"> + InitTextAreas(); + InitAdvancedEditing(); + Post.InitBrowserLinks(); + if(TagCompletion) + TagCompletion.init(1771793380); + </script> + + <!--[if lt IE 7]> + <script type="text/javascript"> + if(Cookie.get("hide-ie-nag") != "1") + $("old-browser").show(); + </script> + <![endif]--> + + <script type="text/javascript"> + var text = Cookie.get("notice"); + if (text) { + notice(text, true); + Cookie.remove("notice"); + } + </script> + <script type="text/javascript"> + var text = Cookie.get("notice"); + if (text) { + notice(text, true); + Cookie.remove("notice"); + } + </script> + + <script type="text/javascript"> + window.google_analytics_uacct = 'UA-16180617-26'; + + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-16180617-26']); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + +</script> +<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9d28685f7deb4afe',t:'MTc3MTg2NzM3MQ=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body> +</html> + diff --git a/docs/api/safebooru-dapi-help.html b/docs/api/safebooru-dapi-help.html new file mode 100644 index 0000000..bf4554e --- /dev/null +++ b/docs/api/safebooru-dapi-help.html @@ -0,0 +1,159 @@ +<!DOCTYPE html> +<html xmlns="//www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <meta charset="utf-8" /> + + + <link rel="stylesheet" type="text/css" media="screen" href="https://safebooru.org/css/desktop.css?11" title="default" /> + <script nomodule src="/script/core-js.js" type="9d9bf39ecaab45d83c1b0138-text/javascript"></script> +<script src="https://safebooru.org/script/application.js?2" type="9d9bf39ecaab45d83c1b0138-text/javascript"></script> +<script src="/script/awesomplete.min.js?v2" type="9d9bf39ecaab45d83c1b0138-text/javascript"></script> + + +<script type="9d9bf39ecaab45d83c1b0138-text/javascript"> + window.captchaSiteKey = "0x4AAAAAAAiCWNfyi_ucjsab"; + window.captchaCSSClass = "cf-turnstile"; + window.captchaProvider = "turnstile"; + window.captchaInstance = "tst1"; + window.captchaInstanceFormKey = "captchaKey"; + window.captchaResponseFormKey = "cf-turnstile-response"; + window.captchaRenderIdFn = (id) => '#' + id; + window.getCaptcha = function() { + if (window["turnstile"]) { + return turnstile; + } else { + return undefined; + } + } + + window.captchaScriptLoaded = false; + window.loadCaptchaScript = function() { + if (window.captchaScriptLoaded) return; + window.captchaScriptLoaded = true; + const script = document.createElement('script'); + script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?onload=loadedCaptchaScript"; + document.body.appendChild(script); + + return new Promise((res, rej) => { + window.loadedCaptchaScript = () => { + console.log("loaded"); + res(); + } + script.onerror = function () { + rej(); + } + }); + } +</script> + + <link rel="shortcut icon" href="favicon.ico" /> + <meta name="theme-color" content="#ffffff"> + <title>Safebooru </title> + + + <meta name="keywords" content="Safebooru, imageboard, anime, search engine, anime search engine, anime imageboard" /> + <meta name="description" content="Safebooru is a anime and manga picture search engine, images are being updated hourly."> + + <meta name="rating" content="general" /> + + <link rel="search" type="application/opensearchdescription+xml" title="safebooru: Coded by Geltas" href="openSearchDesc.xml" /> + + + + +</head> +<body id="body"> +<script src="/script/fluidplayer/fluidplayer.min.js?2" type="9d9bf39ecaab45d83c1b0138-text/javascript"></script> + + <div id="header"> + + <input type="radio" class="tradio" id="rmainmenu" name="navtrigs" /> + <input type="radio" class="tradio" id="rnomenu1" name="navtrigs" checked /> + <input type="radio" class="tradio" id="rsubmenu" name="navtrigs" /> + <input type="radio" class="tradio" id="rnomenu2" name="navtrigs" /> + <label for="rmainmenu" class="tlabel tfirst" id="rlmainmenu"></label> + <label for="rnomenu1" class="tlabel tnomenu tfirst" id="rlnomenu1"></label> + <label for="rsubmenu" class="tlabel tsecond" id="rlsubmenu"></label> + <label for="rnomenu2" class="tlabel tnomenu tsecond" id="rlnomenu2"></label> + + <h2 id="site-title"> + <a href="https://safebooru.org/">Safebooru</a> + + </h2> + <ul class="flat-list" id="navbar"> + <li><a href="https://safebooru.org/index.php?page=account&s=home">My Account</a></li> + <li><a href="https://safebooru.org/index.php?page=post&s=list&tags=all">Posts</a></li> + <li><a href="https://safebooru.org/index.php?page=comment&s=list">Comments</a></li> + <li><a href="https://safebooru.org/index.php?page=wiki&s=list">Wiki</a></li> + <li><a href="https://safebooru.org/index.php?page=alias&s=list">Aliases</a></li> + <li><a href="https://safebooru.org/index.php?page=artist&s=list">Artists</a></li> + <li><a href="https://safebooru.org/index.php?page=tags&s=list">Tags</a></li> + <li><a href="https://safebooru.org/index.php?page=pool&s=list">Pools</a></li> + <li><a href="https://safebooru.org/index.php?page=forum&s=list">Forum</a></li> + <li><a href="https://safebooru.org/index.php?page=stats">Stats</a></li> + <li class="current-page"><a href="https://safebooru.org/index.php?page=help">Help</a></li> + <li><a href="https://twitter.com/safebooru/"> Twitter</a></li> + <li><a href="https://patreon.com/booru" target="_blank"><img src="//safebooru.org/images/p.png"> Patreon</a></li> + + <script type="9d9bf39ecaab45d83c1b0138-text/javascript"> + function desktop_layout() { + document.cookie = "experiment-mobile-layout=false; expires=Fri, 31 Dec 9999 23:59:59 GMT"; + location.reload(); + } + + function mobile_layout() { + document.cookie = "experiment-mobile-layout=; expires=Thu, 01 Jan 1970 00:00:00 GMT"; + location.reload(); + } + </script> + + </ul> +</div><div id="long-notice"></div><div id="notice" class="notice" style="display: none;"></div><div class="has-mail" id="has-mail-notice" style="display: none;"><a href="https://safebooru.org/index.php?page=gmail">You have mail</a></div> +<div id="content"> + <div class="help"> + <h1>API Basics</h1> + You should never receive an error unless the server is overloaded or the search dies. In cases of the searcher breaking, you will receive a response success of "false" and a message stating "search down" or similiar.<br /><br /> + <div class="section"> + <h2>Posts</h2> + <h4>List</h4> +Url for API access: <b>index.php?page=dapi&s=post&q=index</b><br /><br /> +<ul> + <li><strong>limit</strong> How many posts you want to retrieve. There is a hard limit of 1000 posts per request.</li> + <li><strong>pid</strong> The page number.</li> + <li><strong>tags</strong> The tags to search for. Any tag combination that works on the web site will work here. This includes all the meta-tags. See cheatsheet for more information.</li> + <li><strong>cid</strong> Change ID of the post. This is in Unix time so there are likely others with the same value if updated at the same time.</li> + <li><strong>id</strong> The post id.</li> + <li><strong>json</strong> Set to 1 for JSON formatted response.</li> +</ul> + + <h4>Deleted Images</h4> +Url for API access: <b>index.php?page=dapi&s=post&q=index&deleted=show</b><br /><br /> +<ul> + <li><strong>last_id</strong> A numerical value. Will return everything above this number.</li> +</ul> +</div> + <div class="section"> + <h2>Comments</h2> + <h4>List</h4> +Url for API access: <b>ndex.php?page=dapi&s=comment&q=index</b><br /><br /> +<ul> + <li><strong>post_id</strong> The id number of the comment to retrieve.</li> +</ul> + +</div> + + <div class="section"> + <h2>Tags</h2> + <h4>List</h4> +Url for API access: <strong>index.php?page=dapi&s=tag&q=index</strong><br /> +<br /> +<ul> + <li><strong>id</strong> The tag's id in the database. This is useful to grab a specific tag if you already know this value.</li> + <li><strong>limit</strong> How many tags you want to retrieve. There is a default limit of 100 per request.<br> + </li> + </ul> + +</div><script src="/cdn-cgi/scripts/7d0fa10a/cloudflare-static/rocket-loader.min.js" data-cf-settings="9d9bf39ecaab45d83c1b0138-|49" defer></script>
\ No newline at end of file diff --git a/docs/api/sakugabooru-help-api.html b/docs/api/sakugabooru-help-api.html new file mode 100644 index 0000000..bc6c764 --- /dev/null +++ b/docs/api/sakugabooru-help-api.html @@ -0,0 +1,1009 @@ +<!DOCTYPE html> +<html class="action-help action-help-show hide-advanced-editing"> +<head> + <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> + <title>sakugabooru</title> + <meta name="description" content="sakugabooru - a booru dedicated to sakuga videos and images"> + <meta name="keywords" content="japan,anime,animation,sakuga,gif,apng,image,webm,mp4,作画,アニメ"> + <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> + <link rel="top" title="sakugabooru" href="/"> + <script type="text/javascript"> + var css = ".javascript-hide { display: none !important; }"; + var style = document.createElement("style"); style.type = "text/css"; + if(style.styleSheet) // IE + style.styleSheet.cssText = css; + else + style.appendChild(document.createTextNode(css)); + document.getElementsByTagName("head")[0].appendChild(style); + </script> + + + <link rel="alternate" type="application/atom+xml" title="ATOM" href="https://www.sakugabooru.com/post/atom" /> + <link rel="stylesheet" href="/assets/application-52f6752c98971073755b04b53be433da5ba19380bf25eadd39e0b34ae3bd0276.css" /> + + <script id="user-blacklisted-tags" type="application/json"> + [] + </script> + + <script type="text/javascript"> + window.locale = { + current: "en", + default: "en", + } + </script> + + <script src="/assets/application_classic-cbd680469b2d2016b014dfa0f45432624290adb5c5faa7e93dae0b59b1e4a45a.js"></script> + <script src="/assets/application-b8b2f61cd1a8672436cd94ea62ea6ba70ffbec52c9e31224cfcd65854328ac49.jsout"></script> + + <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="sakugabooru" /> + + <meta name="csrf-param" content="authenticity_token" /> +<meta name="csrf-token" content="On6z7OtiH3_g71pTh_ggPL_mE5pV3LIUj6_3YVs_M_lhwsX-BfDh7PiClRnu_N97QNNdptVuHocfB9qZcB9ahQ" /> + <script defer src="https://stats.sakugabooru.com/script.js" data-website-id="5b090cf6-e29f-444d-b491-f61afd8b616b"></script> +</head> +<body> + <div class="overlay-notice-container" id="notice-container" style="display: none;"> + <table cellspacing=0 cellpadding=0> <tbody> + <tr> <td> + <div id="notice"> + </div> + </td> </tr> + </tbody> </table> +</div> + + <div id="news-ticker" style="display: none" data-date="20130822" data-news-hide="1"> + <ul> + <li>We've started a blog! Find it <a href="https://blog.sakugabooru.com">here.</a></li> + <br /> + <li>Please read the <a href="/help/tags">tagging guidelines</a> before posting. | <a href="/wiki/show?title=booru%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9">日本のユーザーはこちらをご覧下さい</a>。</li> + </ul> + + <a href="#" class="close-link">Close</a> +</div> + + <div id="header"> + <div id="title"><h2 id="site-title"><a href="https://www.sakugabooru.com"><img alt="sakugabooru" id="logo" src="/assets/logo_small-42f8ce67ac76c05d9f81fe8b7427de291ac17a614585d8e036c90dcf34fbe519.png" width="506" height="64" /></a><span></span></h2></div> + <div class="clearfix" id="main-menu" data-controller="help"> + <ul> + <li class="user"><a href="/user/home">My Account</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a id="login-link" class="login-button" href="/user/login">Login</a></li> + <li><a href="/user/signup"><span class="translation_missing" title="translation missing: en.layouts.menu.account.register">Register</span></a></li> + <li><a href="/user/reset_password">Reset Password</a></li> + </ul> + </li> + <li class="post"><a href="/post">Posts</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/post" accept-charset="UTF-8" method="get"> + <input type="text" name="tags" /><br /> + <input type="submit" value="Search Posts" data-disable-with="Search Posts" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/post">View Posts</a></li> + <li><a class="search-link" href="/post">Search Posts</a></li> + <li><a href="/post/upload">Upload</a></li> + <li><a href="/post?tags=order%3Arandom">Random</a></li> + <li><a href="/post/popular_recent">Popular</a></li> + <li><a href="/post/similar">Image Search</a></li> + <li><a href="/history">History</a></li> + </ul> + </li> + <li class="comment"><a id="comments-link" href="/comment">Comments</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/comment/search" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Comments" data-disable-with="Search Comments" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/comment">View Comments</a></li> + <li><a class="search-link" href="/comment/search">Search Comments</a></li> + </ul> + </li> + <li class="note"><a href="/note">Notes</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/note/search" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Notes" data-disable-with="Search Notes" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/note">View Notes</a></li> + <li><a class="search-link" href="/note/search">Search Notes</a></li> + <li><a href="/post?tags=translation_request">Requests</a></li> + </ul> + </li> + <li class="artist"><a href="/artist?order=date">Artists</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/artist" accept-charset="UTF-8" method="get"> + <input type="text" name="name" /><br /> + <input type="submit" value="Search Artists" data-disable-with="Search Artists" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/artist">View Artists</a></li> + <li><a class="search-link" href="/artist">Search Artists</a></li> + <li><a href="/artist/create">Create</a></li> + </ul> + </li> + <li class="tag"><a href="/tag?order=date">Tags</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/tag" accept-charset="UTF-8" method="get"> + <input type="text" name="name" /><br /> + <input type="submit" value="Search Tags" data-disable-with="Search Tags" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/tag">View Tags</a></li> + <li><a class="search-link" href="/tag">Search Tags</a></li> + <li><a href="/tag/popular_by_day">Popular</a></li> + <li><a href="/tag_alias">Aliases</a></li> + <li><a href="/tag_implication">Implications</a></li> + </ul> + </li> + <li class="pool"><a href="/pool">Pools</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/pool" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Pools" data-disable-with="Search Pools" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/pool">View Pools</a></li> + <li><a class="search-link" href="/pool">Search Pools</a></li> + <li><a href="/pool/create">Create New Pool</a></li> + </ul> + </li> + <li class="blog"><a href="https://blog.sakugabooru.com">Blog</a> + <a class="submenu-button" href="#">■</a> + </li> + <li class="patreon"><a href="https://patreon.com/Sakugabooru">Patreon</a> + <a class="submenu-button" href="#">■</a> + </li> + <li class="locale"><a href="#">Language</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a href="/post?locale=en">English</a></li> + <li><a href="/post?locale=ja">日本語</a></li> + </ul> + </li> + <li class="wiki"><a href="/wiki/show?title=help%3Ahome">Wiki</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/wiki" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Wiki" data-disable-with="Search Wiki" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/wiki">View Wiki Index</a></li> + <li><a class="search-link" href="/wiki">Search Wiki</a></li> + <li><a href="/wiki/add">Create New Page</a></li> + </ul> + </li> + <li class="forum"><a id="forum-link" href="/forum">Forum</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/forum/search" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Forums" data-disable-with="Search Forums" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/forum">View Topics</a></li> + <li><a class="search-link" href="/forum">Search Forums</a></li> + <li><a href="/forum/new">New Topic</a></li> + <li><a id="forum-mark-all-read" style="display: none;" href="/forum/mark_all_read">Mark All Read</a></li> + <li class="forum-items-start"><span class="separator"></span></li> + </ul> + </li> + <li class="help"><a href="/help">Help</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a class="help-item post" href="/help/posts">Post Help</a> + <li><a class="help-item comment" href="/help/comments">Comment Help</a> + <li><a class="help-item note" href="/help/notes">Note Help</a> + <li><a class="help-item artist" href="/help/artists">Artist Help</a> + <li><a class="help-item tag" href="/help/tags">Tag Help</a> + <li><a class="help-item pool" href="/help/pools">Pool Help</a> + <li><a class="help-item wiki" href="/help/wiki">Wiki Help</a> + <li><a class="help-item forum" href="/help/forum">Forum Help</a> + <li><a href="/help">Site Help</a></li> + </ul> + </li> + <li class="static"><a href="/static/more">More »</a> + </li> + <li class="has-mail"> + <a id="has-mail-notice" href="/dmail/inbox">New Mail</a> + </li> + </ul> +</div> + +<script id="forum-posts-latest" type="application/json"> + [{"id":1652,"pages":1,"title":"Clayface Animator ID/ Tiny Toons TMS Animators","updated_at":"2026-02-03T21:13:58.956Z"},{"id":1709,"pages":1,"title":"Tag Subscriptions","updated_at":"2026-01-31T19:42:21.834Z"},{"id":1706,"pages":1,"title":"Search between scores?","updated_at":"2026-01-15T00:16:26.191Z"},{"id":1703,"pages":1,"title":"Kekkai Sensen Artwork ","updated_at":"2025-11-18T21:01:18.481Z"},{"id":1696,"pages":1,"title":"A frame by frame breakdown app/page/extension?","updated_at":"2025-09-26T15:21:33.552Z"},{"id":1688,"pages":1,"title":"image resolution limit","updated_at":"2025-07-02T17:41:53.016Z"},{"id":34,"pages":1,"title":"Animators on pixiv","updated_at":"2025-06-07T09:34:23.026Z"},{"id":1681,"pages":1,"title":"BEFORE Sakugabooru","updated_at":"2025-06-02T18:59:48.873Z"},{"id":12,"pages":2,"title":"Post errors and admin questions here","updated_at":"2025-05-10T23:06:07.638Z"},{"id":1649,"pages":1,"title":"Can I order the results?","updated_at":"2025-01-21T22:24:57.476Z"}] +</script> +<script id="forum-post-last-read-at" type="application/json"> + "2026-02-23T09:22:53.313-08:00" +</script> + + </div> + +<div id="login-background" style="display: none;"> </div> + +<div id="login-container" style="display: none;"> + <div id="login-container-inner"> + <div id="login-container-with-tabs"> + <div> + <ul class="flat-list login-tabs" id="login-tabs"> + <li id="tab-login"><a href="#">Login</a></li> + <li id="tab-reset"><a href="#">Reset Password</a></li> + </ul> + </div> + <div id="login" style="position: relative;"> + <p id="tab-login-text" class="tab-header-text"> + Please log in. To create a new account, enter the name and password you want to use. + </p> + <p id="tab-reset-text" class="tab-header-text"> + If you supplied an email address when you signed up or added a email later, you can have your password reset. + </p> + + <form id="login-popup" action="/user/authenticate" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="jWzMWkRZDJEMsmJzErr6yPKWVw90-J8lJvhPWDk7kaRucEUeZPoUUgNDl9HLoJZQ9J4v7bCX3iGJtY5M46M3Iw" autocomplete="off" /> + <div style="position: absolute; top: 0; right: 0;"> + <a href="#" id="login-popup-cancel" style="font-size: 1.2em; padding: 2px;">ⓧ</a> + </div> + + <table class="form" style="width: 80%; max-width: 30em; margin-bottom: .5em; margin-left: auto; margin-right: auto;"> + <tr> + <th style="width: 8em"><label class="block" for="login-popup-username">Name</label></th> + <td style="width: 10em" align=left><input id="login-popup-username" name="username" type="text" style="width: 100%;"></td> + </tr> + <tr id="login-popup-email-box"> + <th><label class="block" for="login-popup-email">Email</label></th> + <td align=left><input id="login-popup-email" name="email" type="text" style="width: 100%;"></td> + </tr> + <tr id="login-popup-password-box"> + <th><label class="block" for="login-popup-password">Password</label></th> + <td align=left><input id="login-popup-password" name="password" type="password" style="width: 100%;"></td> + </tr> + <tr id="login-popup-password-confirm-box" style="display: none;"> + <th><label class="block" for="login-popup-password-confirm">Confirm Password</label></th> + <td align=left><input id="login-popup-password-confirm" name="password-confirm" type="password" style="width: 100%;"></td> + </tr> + <tr> + <th style="background: none;"></th> + <td align=left> + </td> + </tr> + </table> + <a href="#" id="login-popup-submit" style="margin-bottom: 1em; margin-left: auto; margin-right: auto;">Login</a> +</form> + <div id="login-popup-notices" class="login-popup-notice"> + <span id="login-popup-login-confirm-password"> + This user name doesn't exist. If you want to create a new account, just verify your password and log in. + </span> + <span id="login-popup-login-user-exists"> + This user name exists. If you want to create a new account, please choose a different name. + </span> + <span id="login-popup-reset-user-exists"> + Enter the current email address you have registered in your profile. You'll get an email containing your new password. + </span> + <span id="login-popup-reset-user-has-no-email"> + You have no email address in your profile, so you can't have your password reset. + </span> + <span id="login-popup-reset-successful"> + Password reset. Check your email in a few minutes + </span> + <span id="login-popup-reset-unknown-user"> + That account does not exist. + </span> + <span id="login-popup-reset-blank"> + </span> + <span id="login-popup-reset-user-email-incorrect"> + The email address specified is not registered with this account. + </span> + <span id="login-popup-reset-user-email-invalid"> + Delivery to this email address has failed. + </span> + <span id="login-popup-message"> + </span> + </div> + </div> + </div> + + </div> +</div> + +<script type="text/javascript">document.observe("dom:loaded", function() { User.init(); });</script> + + + + <!--[if lt IE 7]> + <div style="display: none;" id="old-browser">Your browser is very old, and this site will not display properly. + Please consider upgrading to a more recent web browser: + <a href="http://www.mozilla.com/firefox/">Firefox</a>, + <a href="http://www.opera.com/">Opera</a>, + <a href="http://www.microsoft.com/windows/internet-explorer/download-ie.aspx">Internet Explorer</a>. + <div style="text-align: right;" id="old-browser-hide"> + <a href="#" onclick='$("old-browser").hide(); Cookie.put("hide-ie-nag", "1");'>(hide this message)</a> + </div> + </div> + <![endif]--> + <div class="overlay-notice-container" id="notice-container" style="display: none;"> + <table cellspacing=0 cellpadding=0> <tbody> + <tr> <td> + <div id="notice"> + </div> + </td> </tr> + </tbody> </table> +</div> + + + <div class="blocked" id="block-reason" style="display: none;"> + </div> + + <div id="content"> + <div class="help"> + <h1>Help: API 1.13.0+update.3</h1> + + <div class="section"> + <p>Moebooru offers API which is mostly compatible with Danbooru API (version 1.13.0) to make scripting easy. All you need is a way to <a href="https://en.wikipedia.org/wiki/HTTP_GET#Request_methods">GET and POST</a> to <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Locator">URLs</a>. The ability to parse <a href="https://en.wikipedia.org/wiki/Xml">XML</a> or <a href="https://en.wikipedia.org/wiki/Json">JSON</a> responses is nice, but not critical. The simplicity of the API means you can write scripts using JavaScript, Perl, Python, Ruby, even shell languages like bash or tcsh.</p> + <p style="text-align: center;"><a href="#changelog">Change Log</a> | <a href="#posts">Posts</a> | <a href="#tags">Tags</a> | <a href="#artists">Artists</a> | <a href="#comments">Comments</a> | <a href="#wiki">Wiki</a> | <a href="#notes">Notes</a> | <a href="#users">Users</a> | <a href="#forum">Forum</a> | <a href="#pools">Pools</a></p> + </div> + + <div class="section"> + <div class="section"> + <h2>Basics</h2> + <p>HTTP defines two request methods: GET and POST. You'll be using these two methods to interact with the Danbooru API. Most API calls that change the state of the database (like creating, updating, or deleting something) require an HTTP POST call. API calls that only retrieve data can typically be done with an HTTP GET call.</p> + <p>In the Danbooru API, a URL is analogous to a function name. You pass in the function parameters as a query string. Here's an extremely simple example: <a class="code" href="/post.xml?limit=1" target="_blank">/post.xml?limit=1</a>.</p> + <p>The <code>post</code> part indicates the controller we're working with. In this case it's posts. <code>index</code> describes the action. Here we're retrieving a list of posts. Finally, the <code>xml</code> part describes what format we want the response in. You can specify <code>.xml</code> for XML responses, <code>.json</code> for JSON responses, and nothing at all for HTML responses.</p> + </div> + + <div class="section"> + <h4>Responses</h4> + <p>All API calls that change state will return a single element response (for XML calls). They are formatted like this:</p> + <div class="code"> + <?xml version="1.0" encoding="UTF-8"?><br> + <response success="false" reason="duplicate"/> + </div> + <p>For JSON responses, they'll look like this:</p> + <div class="code"> + {success: false, reason: "duplicate"} + </div> + <p>While you can usually determine success or failure based on the response object, you can also figure out what happened based on the HTTP status code. In addition to the standard ones, Danbooru uses some custom status codes in the 4xx and 5xx range.</p> + <table> + <thead> + <tr> + <th>Status Code</th> + <th>Meaning</th> + </tr> + </thead> + <tbody> + <tr> + <td>200 OK</td> + <td>Request was successful</td> + </tr> + <tr> + <td>403 Forbidden</td> + <td>Access denied</td> + </tr> + <tr> + <td>404 Not Found</td> + <td>Not found</td> + </tr> + <tr> + <td>420 Invalid Record</td> + <td>Record could not be saved</td> + </tr> + <tr> + <td>421 User Throttled</td> + <td>User is throttled, try again later</td> + </tr> + <tr> + <td>422 Locked</td> + <td>The resource is locked and cannot be modified</td> + </tr> + <tr> + <td>423 Already Exists</td> + <td>Resource already exists</td> + </tr> + <tr> + <td>424 Invalid Parameters</td> + <td>The given parameters were invalid</td> + </tr> + <tr> + <td>500 Internal Server Error</td> + <td>Some unknown error occurred on the server</td> + </tr> + <tr> + <td>503 Service Unavailable</td> + <td>Server cannot currently handle the request, try again later</td> + </tr> + </tbody> + </table> + </div> + + <div class="section"> + <h4>JSON Responses</h4> + <p>While you will probably want to work with XML in the majority of cases, if you're writing something in Javascript then the JSON responses may be preferable. They are much faster to parse and there's less code to write to get your data structure:</p> + <div class="code"> + var data = JSON.parse(responseText)<br> + alert(data.response) + </div> + </div> + + <div class="section"> + <h4>Logging In</h4> + <p>Some actions may require you to log in. For any action you can always specify two parameters to identify yourself:</p> + <ul> + <li><strong>login</strong> Your login name.</li> + <li><strong>password_hash</strong> Your SHA1 hashed password. Simply hashing your plain password will NOT work since Danbooru salts its passwords. The actual string that is hashed is "er@!$rjiajd0$!dkaopc350!Y%)--<em>your-password</em>--".</li> + </ul> + <p>Please be aware of the security risks involved in sending your password through an unencrypted channel. Although your password will be hashed, it is still theoretically possible for someone to steal your account by creating a fake cookie based on your hashed password.</p> + </div> + </div> + + + + <div class="section"> + <a name="posts"></a> + <h2>Posts</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /post.xml.</p> + <ul> + <li><strong>limit</strong> How many posts you want to retrieve. There is a hard limit of 100 posts per request.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>tags</strong> The tags to search for. Any tag combination that works on the web site will work here. This includes all the meta-tags.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /post/create.xml. There are only two mandatory fields: you need to supply the tags, and you need to supply the file, either through a multipart form or through a source URL.</p> + <ul> + <li><strong>post[tags]</strong> A space delimited list of tags.</li> + <li><strong>post[file]</strong> The file data encoded as a multipart form.</li> + <li><strong>post[rating]</strong> The rating for the post. Can be: safe, questionable, or explicit.</li> + <li><strong>post[source]</strong> If this is a URL, Danbooru will download the file.</li> + <li><strong>post[is_rating_locked]</strong> Set to true to prevent others from changing the rating.</li> + <li><strong>post[is_note_locked]</strong> Set to true to prevent others from adding notes.</li> + <li><strong>post[parent_id]</strong> The ID of the parent post.</li> + <li><strong>md5</strong> Supply an MD5 if you want Danbooru to verify the file after uploading. If the MD5 doesn't match, the post is destroyed.</li> + </ul> + <p>If the call fails, the following response reasons are possible:</p> + <ul> + <li><strong>MD5 mismatch</strong> This means you supplied an MD5 parameter and what Danbooru got doesn't match. Try uploading the file again.</li> + <li><strong>duplicate</strong> This post already exists in Danbooru (based on the MD5 hash). An additional attribute called <code>location</code> will be set, pointing to the (relative) URL of the original post.</li> + <li><strong><em>other</em></strong> Any other error will have its error message printed.</li> + </ul> + <p>If the post upload succeeded, you'll get an attribute called <code>location</code> in the response pointing to the relative URL of your newly uploaded post.</p> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /post/update.xml. Only the <code>id</code> parameter is required. Leave the other parameters blank if you don't want to change them.</p> + <ul> + <li><strong>id</strong> The id number of the post to update.</li> + <li><strong>post[tags]</strong> A space delimited list of tags.</li> + <li><strong>post[file]</strong> The file data encoded as a multipart form.</li> + <li><strong>post[rating]</strong> The rating for the post. Can be: safe, questionable, or explicit.</li> + <li><strong>post[source]</strong> If this is a URL, Danbooru will download the file.</li> + <li><strong>post[is_rating_locked]</strong> Set to true to prevent others from changing the rating.</li> + <li><strong>post[is_note_locked]</strong> Set to true to prevent others from adding notes.</li> + <li><strong>post[parent_id]</strong> The ID of the parent post.</li> + </ul> + </div> + <div class="section"> + <h4>Destroy</h4> + <p>You must be logged in to use this action. You must also be the user who uploaded the post (or you must be a moderator).</p> + <ul> + <li><strong>id</strong> The id number of the post to delete.</li> + </ul> + </div> + <div class="section"> + <h4>Revert Tags</h4> + <p>This action reverts a post to a previous set of tags. The base URL is /post/revert_tags.xml.</p> + <ul> + <li><strong>id</strong> The post id number to update.</li> + <li><strong>history_id</strong> The id number of the tag history.</li> + </ul> + </div> + <div class="section"> + <h4>Vote</h4> + <p>This action lets you vote for a post. You can only vote once per post per IP address. The base URL is /post/vote.xml.</p> + <ul> + <li><strong>id</strong> The post id number to update.</li> + <li><strong>score</strong> Set to <code>1</code> to vote up and <code>-1</code> to vote down. All other values will be ignored.</li> + </ul> + <p>If the call did not succeed, the following reasons are possible:</p> + <ul> + <li><strong>already voted</strong> You have already voted for this post.</li> + <li><strong>invalid score</strong> You have supplied an invalid score.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="tags"></a> + <h2>Tags</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /tag.xml.</p> + <ul> + <li><strong>limit</strong> How many tags to retrieve. Setting this to 0 will return every tag.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>order</strong> Can be <code>date</code>, <code>count</code>, or <code>name</code>.</li> + <li><strong>id</strong> The id number of the tag.</li> + <li><strong>after_id</strong> Return all tags that have an id number greater than this.</li> + <li><strong>name</strong> The exact name of the tag.</li> + <li><strong>name_pattern</strong> Search for any tag that has this parameter in its name.</li> + </ul> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /tag/update.xml.</p> + <ul> + <li><strong>name</strong> The name of the tag to update.</li> + <li><strong>tag[tag_type]</strong> The tag type. General: 0, artist: 1, copyright: 3, character: 4.</li> + <li><strong>tag[is_ambiguous]</strong> Whether or not this tag is ambiguous. Use 1 for true and 0 for false.</li> + </ul> + </div> + <div class="section"> + <h4>Related</h4> + <p>The base URL is /tag/related.xml.</p> + <ul> + <li><strong>tags</strong> The tag names to query.</li> + <li><strong>type</strong> Restrict results to this tag type (can be <code>general</code>, <code>artist</code>, <code>copyright</code>, or <code>character</code>).</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="artists"></a> + <h2>Artists</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /artist.xml.</p> + <ul> + <li><strong>name</strong> The name (or a fragment of the name) of the artist.</li> + <li><strong>order</strong> Can be <code>date</code> or <code>name</code>.</li> + <li><strong>page</strong> The page number.</li> + </ul> + </div> + <div class="section"> + <h4>Create</h4> + <p>The base URL is /artist/create.xml.</p> + <ul> + <li><strong>artist[name]</strong> The artist's name.</li> + <li><strong>artist[urls]</strong> A list of URLs associated with the artist, whitespace delimited.</li> + <li><strong>artist[alias]</strong> The artist that this artist is an alias for. Simply enter the alias artist's name.</li> + <li><strong>artist[group]</strong> The group or cicle that this artist is a member of. Simply enter the group's name.</li> + </ul> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /artist/update.xml. Only the <strong>id</strong> parameter is required. The other parameters are optional.</p> + <ul> + <li><strong>id</strong> The id of thr artist to update.</li> + <li><strong>artist[name]</strong> The artist's name.</li> + <li><strong>artist[urls]</strong> A list of URLs associated with the artist, whitespace delimited.</li> + <li><strong>artist[alias]</strong> The artist that this artist is an alias for. Simply enter the alias artist's name.</li> + <li><strong>artist[group]</strong> The group or cicle that this artist is a member of. Simply enter the group's name.</li> + </ul> + </div> + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /artist/destroy.xml. You must be logged in to delete artists.</p> + <ul> + <li><strong>id</strong> The id of the artist to destroy.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="comments"></a> + <h2>Comments</h2> + + <div class="section"> + <h4>Show</h4> + <p>The base URL is /comment/show.xml. This retrieves a single comment.</p> + <ul> + <li><strong>id</strong> The id number of the comment to retrieve.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /comment/create.xml.</p> + <ul> + <li><strong>comment[anonymous]</strong> Set to 1 if you want to post this comment anonymously.</li> + <li><strong>comment[post_id]</strong> The post id number to which you are responding.</li> + <li><strong>comment[body]</strong> The body of the comment.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base url is /comment/destroy.xml. You must be logged in to use this action. You must also be the owner of the comment, or you must be a moderator.</p> + <ul> + <li><strong>id</strong> The id number of the comment to delete.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="wiki"></a> + <h2>Wiki</h2> + <p>All titles must be exact (but case and whitespace don't matter).</p> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /wiki.xml. This retrieves a list of every wiki page.</p> + <ul> + <li><strong>order</strong> How you want the pages ordered. Can be: <code>title</code>, <code>date</code>.</li> + <li><strong>limit</strong> The number of pages to retrieve.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>query</strong> A word or phrase to search for.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /wiki/create.xml.</p> + <ul> + <li><strong>wiki_page[title]</strong> The title of the wiki page.</li> + <li><strong>wiki_page[body]</strong> The body of the wiki page.</li> + </ul> + </div> + + <div class="section"> + <h4>Update</h4> + <p>The base URL is /wiki/update.xml. Potential error reasons: "Page is locked"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to update.</li> + <li><strong>wiki_page[title]</strong> The new title of the wiki page.</li> + <li><strong>wiki_page[body]</strong> The new body of the wiki page.</li> + </ul> + </div> + + <div class="section"> + <h4>Show</h4> + <p>The base URL is /wiki/show.xml. Potential error reasons: "artist type"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to retrieve.</li> + <li><strong>version</strong> The version of the page to retrieve.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /wiki/destroy.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to delete.</li> + </ul> + </div> + + <div class="section"> + <h4>Lock</h4> + <p>The base URL is /wiki/lock.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to lock.</li> + </ul> + </div> + + <div class="section"> + <h4>Unlock</h4> + <p>The base URL is /wiki/unlock.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to unlock.</li> + </ul> + </div> + + <div class="section"> + <h4>Revert</h4> + <p>The base URL is /wiki/revert.xml. Potential error reasons: "Page is locked"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to update.</li> + <li><strong>version</strong> The version to revert to.</li> + </ul> + </div> + + <div class="section"> + <h4>History</h4> + <p>The base URL is /wiki/history.xml.</p> + <ul> + <li><strong>title</strong> The title of the wiki page to retrieve versions for.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="notes"></a> + <h2>Notes</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /note.xml.</p> + <ul> + <li><strong>post_id</strong> The post id number to retrieve notes for.</li> + </ul> + </div> + + <div class="section"> + <h4>Search</h4> + <p>The base URL is /note/search.xml.</p> + <ul> + <li><strong>query</strong> A word or phrase to search for.</li> + </ul> + </div> + + <div class="section"> + <h4>History</h4> + <p>The base URL is /note/history.xml. You can either specify <code>id</code>, <code>post_id</code>, or nothing. Specifying nothing will give you a list of every note verison.</p> + <ul> + <li><strong>limit</strong> How many versions to retrieve.</li> + <li><strong>page</strong> The offset.</li> + <li><strong>post_id</strong> The post id number to retrieve note versions for.</li> + <li><strong>id</strong> The note id number to retrieve versions for.</li> + </ul> + </div> + + <div class="section"> + <h4>Revert</h4> + <p>The base URL is /note/revert.xml. Potential error reasons: "Post is locked"</p> + <ul> + <li><strong>id</strong> The note id to update.</li> + <li><strong>version</strong> The version to revert to.</li> + </ul> + </div> + + <div class="section"> + <h4>Create/Update</h4> + <p>The base URL is /note/update.xml. Notes differ from the other controllers in that the interface for creation and updates is the same. If you supply an <code>id</code> parameter, then Danbooru will assume you're updating an existing note. Otherwise, it will create a new note. Potential error reasons: "Post is locked"</p> + <ul> + <li><strong>id</strong> If you are updating a note, this is the note id number to update.</li> + <li><strong>note[post_id]</strong> The post id number this note belongs to.</li> + <li><strong>note[x]</strong> The x coordinate of the note.</li> + <li><strong>note[y]</strong> The y coordinate of the note.</li> + <li><strong>note[width]</strong> The width of the note.</li> + <li><strong>note[height]</strong> The height of the note.</li> + <li><strong>note[is_active]</strong> Whether or not the note is visible. Set to 1 for active, 0 for inactive.</li> + <li><strong>note[body]</strong> The note message.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="users"></a> + <h2>Users</h2> + + <div class="section"> + <h4>Search</h4> + <p>The base URL is /user.xml. If you don't specify any parameters you'll get a listing of all users.</p> + <ul> + <li><strong>id</strong> The id number of the user.</li> + <li><strong>name</strong> The name of the user.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="forum"></a> + <h2>Forum</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /forum.xml. If you don't specify any parameters you'll get a list of all the parent topics.</p> + <ul> + <li><strong>parent_id</strong> The parent ID number. You'll return all the responses to that forum post.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="pools"></a> + <h2>Pools</h2> + + <div class="section"> + <h4>List Pools</h4> + <p>The base URL is /pool.xml. If you don't specify any parameters you'll get a list of all pools.</p> + <ul> + <li><strong>query</strong> The title.</li> + <li><strong>page</strong> The page.</li> + </ul> + </div> + + <div class="section"> + <h4>List Posts</h4> + <p>The base URL is /pool/show.xml. If you don't specify any parameters you'll get a list of all pools.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + <li><strong>page</strong> The page.</li> + </ul> + </div> + + <div class="section"> + <h4>Update</h4> + <p>The base URL is /pool/update.xml.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + <li><strong>pool[name]</strong> The name.</li> + <li><strong>pool[is_public]</strong> 1 or 0, whether or not the pool is public.</li> + <li><strong>pool[description]</strong> A description of the pool.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /pool/create.xml.</p> + <ul> + <li><strong>pool[name]</strong> The name.</li> + <li><strong>pool[is_public]</strong> 1 or 0, whether or not the pool is public.</li> + <li><strong>pool[description]</strong> A description of the pool.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /pool/destroy.xml.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + </ul> + </div> + + <div class="section"> + <h4>Add Post</h4> + <p>The base URL is /pool/add_post.xml. Potential error reasons: "Post already exists", "access denied"</p> + <ul> + <li><strong>pool_id</strong> The pool to add the post to.</li> + <li><strong>post_id</strong> The post to add.</li> + </ul> + </div> + + <div class="section"> + <h4>Remove Post</h4> + <p>The base URL is /pool/remove_post.xml. Potential error reasons: "access denied"</p> + <ul> + <li><strong>pool_id</strong> The pool to remove the post from.</li> + <li><strong>post_id</strong> The post to remove.</li> + </ul> + </div> + + </div> + + + + <div class="section"> + <a name="favorites"></a> + <h2>Favorites</h2> + + <div class="section"> + <h4>List Users</h4> + <p>The base URL is /favorite/list_users.json. There is no XML API for this action.</p> + <ul> + <li><strong>id</strong> The post id.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="changelog"></a> + <h2>Change Log</h2> + <div class="section"> + <h4>2.0.0</h4> + <ul> + <li>Removed <code>blacklist_tags</code> from user object (never documented)</li> + <li>XML tag for user API has been changed from <code>post</code> to <code>user</code></li> + </ul> + <h4>1.13.0+update.3</h4> + <ul> + <li>Removed /index from API URLs</li> + </ul> + <h4>1.13.0+update.2</h4> + <ul> + <li>Readd favorite/list_users API</li> + </ul> + <h4>1.13.0+update.1</h4> + <ul> + <li>Added documentation for pools</li> + </ul> + + <h4>1.13.0</h4> + <ul> + <li>Changed interface for artists to use new URL system</li> + <li>JSON requests now end in a .json suffix</li> + <li>Renamed some error reason messages</li> + <li>Removed comment/index from API</li> + <li>Removed url and md5 parameters from artist search (can just pass the URL or MD5 hash to the name parameter)</li> + </ul> + </div> + + <div class="section"> + <h4>1.8.1</h4> + <ul> + <li>Removed post[is_flagged] attribute</li> + </ul> + </div> + </div> +</div> + + + <div class="footer"> + + <ul class="flat-list" id="subnavbar"> + <li><a href="/help">Help</a></li> + + </ul> + </div> + </div> + + <script type="text/javascript"> + InitTextAreas(); + Post.InitBrowserLinks(); + if(TagCompletion) + TagCompletion.init(2635); + </script> + + <!--[if lt IE 7]> + <script type="text/javascript"> + if(Cookie.get("hide-ie-nag") != "1") + $("old-browser").show(); + </script> + <![endif]--> + + + <script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9d286866bc7e5ebf',t:'MTc3MTg2NzM3Mg=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body> +</html> + diff --git a/docs/api/yandere-help-api.html b/docs/api/yandere-help-api.html new file mode 100644 index 0000000..d8f02e0 --- /dev/null +++ b/docs/api/yandere-help-api.html @@ -0,0 +1,1021 @@ +<!DOCTYPE html> +<html class="action-help action-help-show hide-advanced-editing"> +<head> + <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> + <title>yande.re</title> + <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> + <link rel="top" title="yande.re" href="/"> + <script type="text/javascript"> + var css = ".javascript-hide { display: none !important; }"; + var style = document.createElement("style"); style.type = "text/css"; + if(style.styleSheet) // IE + style.styleSheet.cssText = css; + else + style.appendChild(document.createTextNode(css)); + document.getElementsByTagName("head")[0].appendChild(style); + </script> + + + <link rel="alternate" type="application/atom+xml" title="ATOM" href="https://yande.re/post/atom?tags=" /> + <link rel="stylesheet" href="https://assets.yande.re/assets/application-c99e88fb51193c7d2860b6be344dbb89c941621f4de743808386a02fad731e9f.css" /> + + <script id="user-blacklisted-tags" type="application/json"> + ["extreme_content","loli","rating:e"] + </script> + + <script type="text/javascript"> + window.locale = { + current: "en", + default: "en", + } + </script> + + <script src="https://assets.yande.re/assets/application_classic-af217df13af5cc821755e06a0c0e7e9a0d348191b6a3615c43b38dd35d5ed690.js"></script> + <script src="https://assets.yande.re/assets/application-2b7282301e5a28ca19c05e3429b9340e65851a96d0444f6335540b21be25fc4e.jsout"></script> + + <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="yande.re" /> + + <meta name="csrf-param" content="authenticity_token" /> +<meta name="csrf-token" content="brOyd639quBvmJK8Z-z3F3687F1npB2lE7IM_O4tkqpUKJVDVYVSlBLyJOEDsteXiBHYijDa9OfzYvWZMzu06g" /> + <meta name="juicyads-site-verification" content="a42ccc8181bc457cfad43695b47609d8"> + <meta name="clckd" content="ca7848b3d8df49a04183874ab5d60e23" /> +<style>#blacklisted-sidebar{display:none !important;}</style></head> +<body> + <div class="overlay-notice-container" id="notice-container" style="display: none;"> + <table cellspacing=0 cellpadding=0> <tbody> + <tr> <td> + <div id="notice"> + </div> + </td> </tr> + </tbody> </table> +</div> + + <div id="news-ticker" style="" data-date="20201219"> + <ul> + <li>Try clearing out cookies of you have problem logging in/out.</li> + </ul> + + <a href="#" class="close-link">Close</a> +</div> + + <div id="header"> + <div id="title"><h2 id="site-title"><a href="https://yande.re"><img alt="yande.re" id="logo" src="https://assets.yande.re/assets/logo_small-418e8d5ec0229f274edebe4af43b01aa29ed83b715991ba14bb41ba06b5b57b5.png" width="484" height="75" /></a><span></span></h2></div> + <div class="clearfix" id="main-menu" data-controller="help"> + <ul> + <li class="user"><a href="/user/home">My Account</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a id="login-link" class="login-button" href="/user/login">Login</a></li> + <li><a href="/user/signup"><span class="translation_missing" title="translation missing: en.layouts.menu.account.register">Register</span></a></li> + <li><a href="/user/reset_password">Reset Password</a></li> + </ul> + </li> + <li class="post"><a href="/post">Posts</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/post" accept-charset="UTF-8" method="get"> + <input type="text" name="tags" /><br /> + <input type="submit" value="Search Posts" data-disable-with="Search Posts" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/post">View Posts</a></li> + <li><a class="search-link" href="/post">Search Posts</a></li> + <li><a href="/post/upload">Upload</a></li> + <li><a href="/post?tags=order%3Arandom">Random</a></li> + <li><a href="/post/popular_recent">Popular</a></li> + <li><a href="/post/similar">Image Search</a></li> + <li><a href="/history">History</a></li> + </ul> + </li> + <li class="comment"><a id="comments-link" href="/comment">Comments</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/comment/search" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Comments" data-disable-with="Search Comments" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/comment">View Comments</a></li> + <li><a class="search-link" href="/comment/search">Search Comments</a></li> + </ul> + </li> + <li class="note"><a href="/note">Notes</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/note/search" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Notes" data-disable-with="Search Notes" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/note">View Notes</a></li> + <li><a class="search-link" href="/note/search">Search Notes</a></li> + <li><a href="/post?tags=translation_request">Requests</a></li> + </ul> + </li> + <li class="artist"><a href="/artist?order=date">Artists</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/artist" accept-charset="UTF-8" method="get"> + <input type="text" name="name" /><br /> + <input type="submit" value="Search Artists" data-disable-with="Search Artists" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/artist">View Artists</a></li> + <li><a class="search-link" href="/artist">Search Artists</a></li> + <li><a href="/artist/create">Create</a></li> + </ul> + </li> + <li class="tag"><a href="/tag?order=date">Tags</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/tag" accept-charset="UTF-8" method="get"> + <input type="text" name="name" /><br /> + <input type="submit" value="Search Tags" data-disable-with="Search Tags" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/tag">View Tags</a></li> + <li><a class="search-link" href="/tag">Search Tags</a></li> + <li><a href="/tag/popular_by_day">Popular</a></li> + <li><a href="/tag_alias">Aliases</a></li> + <li><a href="/tag_implication">Implications</a></li> + </ul> + </li> + <li class="pool"><a href="/pool">Pools</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/pool" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Pools" data-disable-with="Search Pools" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/pool">View Pools</a></li> + <li><a class="search-link" href="/pool">Search Pools</a></li> + <li><a href="/pool/create">Create New Pool</a></li> + </ul> + </li> + <li class="wiki"><a href="/wiki/show?title=help%3Ahome">Wiki</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/wiki" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Wiki" data-disable-with="Search Wiki" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/wiki">View Wiki Index</a></li> + <li><a class="search-link" href="/wiki">Search Wiki</a></li> + <li><a href="/wiki/add">Create New Page</a></li> + </ul> + </li> + <li class="forum"><a id="forum-link" href="/forum">Forum</a> + <a class="submenu-button" href="#">■</a> + <ul class="search-box"> + <li> + <div> + <form action="/forum/search" accept-charset="UTF-8" method="get"> + <input type="text" name="query" /><br /> + <input type="submit" value="Search Forums" data-disable-with="Search Forums" /> +</form> </div> + </li> + </ul> + <ul class="submenu"> + <li><a href="/forum">View Topics</a></li> + <li><a class="search-link" href="/forum">Search Forums</a></li> + <li><a href="/forum/new">New Topic</a></li> + <li><a id="forum-mark-all-read" style="display: none;" href="/forum/mark_all_read">Mark All Read</a></li> + <li class="forum-items-start"><span class="separator"></span></li> + </ul> + </li> + <li class="help"><a href="/help">Help</a> + <a class="submenu-button" href="#">■</a> + <ul class="submenu"> + <li><a class="help-item post" href="/help/posts">Post Help</a> + <li><a class="help-item comment" href="/help/comments">Comment Help</a> + <li><a class="help-item note" href="/help/notes">Note Help</a> + <li><a class="help-item artist" href="/help/artists">Artist Help</a> + <li><a class="help-item tag" href="/help/tags">Tag Help</a> + <li><a class="help-item pool" href="/help/pools">Pool Help</a> + <li><a class="help-item wiki" href="/help/wiki">Wiki Help</a> + <li><a class="help-item forum" href="/help/forum">Forum Help</a> + <li><a href="/help">Site Help</a></li> + </ul> + </li> + <li class="static"><a href="/static/more">More »</a> + </li> + <li class="has-mail"> + <a id="has-mail-notice" href="/dmail/inbox">New Mail</a> + </li> + </ul> +</div> + +<script id="forum-posts-latest" type="application/json"> + [{"id":10470,"pages":19,"title":"How would you improve yande.re","updated_at":"2026-02-08T16:55:22.707Z"},{"id":31550,"pages":6,"title":"Why I get 100 KB/s download speed from this site again?","updated_at":"2026-02-07T22:41:55.114Z"},{"id":34774,"pages":1,"title":"Delete my account","updated_at":"2026-02-06T14:25:57.670Z"},{"id":34773,"pages":1,"title":"Password forgotten","updated_at":"2026-02-04T00:29:33.710Z"},{"id":10136,"pages":62,"title":"进站必读 (兼讨论帖)","updated_at":"2026-02-01T08:17:28.064Z"},{"id":34766,"pages":1,"title":"I want to delete my account.","updated_at":"2026-01-31T22:33:14.560Z"},{"id":34762,"pages":1,"title":"Post deleted, how can I get it back?","updated_at":"2026-01-29T05:18:27.245Z"},{"id":34743,"pages":1,"title":"The administrator can answer when he sees it.","updated_at":"2026-01-28T16:30:19.010Z"},{"id":10527,"pages":208,"title":"Scans of tutorial books","updated_at":"2026-01-15T17:31:33.909Z"},{"id":34745,"pages":1,"title":"Uploads of Images with Minor Variations","updated_at":"2025-12-24T03:34:55.661Z"}] +</script> +<script id="forum-post-last-read-at" type="application/json"> + "2026-02-24T02:21:14.336+09:00" +</script> + + </div> + +<div id="login-background" style="display: none;"> </div> + +<div id="login-container" style="display: none;"> + <div id="login-container-inner"> + <div id="login-container-with-tabs"> + <div> + <ul class="flat-list login-tabs" id="login-tabs"> + <li id="tab-login"><a href="#">Login</a></li> + <li id="tab-reset"><a href="#">Reset Password</a></li> + </ul> + </div> + <div id="login" style="position: relative;"> + <p id="tab-login-text" class="tab-header-text"> + Please log in. To create a new account, enter the name and password you want to use. + </p> + <p id="tab-reset-text" class="tab-header-text"> + If you supplied an email address when you signed up or added a email later, you can have your password reset. + </p> + + <form id="login-popup" action="/user/authenticate" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="Fw7qvP1N-YXWBJXshpnCJd9OUS9qPv-gXXcwa27HpjvOOee9DsYayq0PspH9UfYUgaCkgHT3dmcNr8Nf9wFZaA" autocomplete="off" /> + <div style="position: absolute; top: 0; right: 0;"> + <a href="#" id="login-popup-cancel" style="font-size: 1.2em; padding: 2px;">ⓧ</a> + </div> + + <table class="form" style="width: 80%; max-width: 30em; margin-bottom: .5em; margin-left: auto; margin-right: auto;"> + <tr> + <th style="width: 8em"><label class="block" for="login-popup-username">Name</label></th> + <td style="width: 10em" align=left><input id="login-popup-username" name="username" type="text" style="width: 100%;"></td> + </tr> + <tr id="login-popup-email-box"> + <th><label class="block" for="login-popup-email">Email</label></th> + <td align=left><input id="login-popup-email" name="email" type="text" style="width: 100%;"></td> + </tr> + <tr id="login-popup-password-box"> + <th><label class="block" for="login-popup-password">Password</label></th> + <td align=left><input id="login-popup-password" name="password" type="password" style="width: 100%;"></td> + </tr> + <tr id="login-popup-password-confirm-box" style="display: none;"> + <th><label class="block" for="login-popup-password-confirm">Confirm Password</label></th> + <td align=left><input id="login-popup-password-confirm" name="password-confirm" type="password" style="width: 100%;"></td> + </tr> + <tr> + <th style="background: none;"></th> + <td align=left> + </td> + </tr> + </table> + <a href="#" id="login-popup-submit" style="margin-bottom: 1em; margin-left: auto; margin-right: auto;">Login</a> +</form> + <div id="login-popup-notices" class="login-popup-notice"> + <span id="login-popup-login-confirm-password"> + This user name doesn't exist. If you want to create a new account, just verify your password and log in. + </span> + <span id="login-popup-login-user-exists"> + This user name exists. If you want to create a new account, please choose a different name. + </span> + <span id="login-popup-reset-user-exists"> + Enter the current email address you have registered in your profile. You'll get an email containing your new password. + </span> + <span id="login-popup-reset-user-has-no-email"> + You have no email address in your profile, so you can't have your password reset. + </span> + <span id="login-popup-reset-successful"> + Password reset. Check your email in a few minutes + </span> + <span id="login-popup-reset-unknown-user"> + That account does not exist. + </span> + <span id="login-popup-reset-blank"> + </span> + <span id="login-popup-reset-user-email-incorrect"> + The email address specified is not registered with this account. + </span> + <span id="login-popup-reset-user-email-invalid"> + Delivery to this email address has failed. + </span> + <span id="login-popup-message"> + </span> + </div> + </div> + </div> + + </div> +</div> + +<script type="text/javascript">document.observe("dom:loaded", function() { User.init(); });</script> + + + + <!--[if lt IE 7]> + <div style="display: none;" id="old-browser">Your browser is very old, and this site will not display properly. + Please consider upgrading to a more recent web browser: + <a href="http://www.mozilla.com/firefox/">Firefox</a>, + <a href="http://www.opera.com/">Opera</a>, + <a href="http://www.microsoft.com/windows/internet-explorer/download-ie.aspx">Internet Explorer</a>. + <div style="text-align: right;" id="old-browser-hide"> + <a href="#" onclick='$("old-browser").hide(); Cookie.put("hide-ie-nag", "1");'>(hide this message)</a> + </div> + </div> + <![endif]--> + <div class="overlay-notice-container" id="notice-container" style="display: none;"> + <table cellspacing=0 cellpadding=0> <tbody> + <tr> <td> + <div id="notice"> + </div> + </td> </tr> + </tbody> </table> +</div> + + + <div class="blocked" id="block-reason" style="display: none;"> + </div> + + <div id="content"> + <div class="help"> + <h1>Help: API 1.13.0+update.3</h1> + + <div class="section"> + <p>Moebooru offers API which is mostly compatible with Danbooru API (version 1.13.0) to make scripting easy. All you need is a way to <a href="http://en.wikipedia.org/wiki/HTTP_GET#Request_methods">GET and POST</a> to <a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator">URLs</a>. The ability to parse <a href="http://en.wikipedia.org/wiki/Xml">XML</a> or <a href="http://en.wikipedia.org/wiki/Json">JSON</a> responses is nice, but not critical. The simplicity of the API means you can write scripts using JavaScript, Perl, Python, Ruby, even shell languages like bash or tcsh.</p> + <p style="text-align: center;"><a href="#changelog">Change Log</a> | <a href="#posts">Posts</a> | <a href="#tags">Tags</a> | <a href="#artists">Artists</a> | <a href="#comments">Comments</a> | <a href="#wiki">Wiki</a> | <a href="#notes">Notes</a> | <a href="#users">Users</a> | <a href="#forum">Forum</a> | <a href="#pools">Pools</a></p> + </div> + + <div class="section"> + <div class="section"> + <h2>Basics</h2> + <p>HTTP defines two request methods: GET and POST. You'll be using these two methods to interact with the Danbooru API. Most API calls that change the state of the database (like creating, updating, or deleting something) require an HTTP POST call. API calls that only retrieve data can typically be done with an HTTP GET call.</p> + <p>In the Danbooru API, a URL is analogous to a function name. You pass in the function parameters as a query string. Here's an extremely simple example: <a class="code" href="/post.xml?limit=1" target="_blank">/post.xml?limit=1</a>.</p> + <p>The <code>post</code> part indicates the controller we're working with. In this case it's posts. <code>index</code> describes the action. Here we're retrieving a list of posts. Finally, the <code>xml</code> part describes what format we want the response in. You can specify <code>.xml</code> for XML responses, <code>.json</code> for JSON responses, and nothing at all for HTML responses.</p> + </div> + + <div class="section"> + <h4>Responses</h4> + <p>All API calls that change state will return a single element response (for XML calls). They are formatted like this:</p> + <div class="code"> + <?xml version="1.0" encoding="UTF-8"?><br> + <response success="false" reason="duplicate"/> + </div> + <p>For JSON responses, they'll look like this:</p> + <div class="code"> + {success: false, reason: "duplicate"} + </div> + <p>While you can usually determine success or failure based on the response object, you can also figure out what happened based on the HTTP status code. In addition to the standard ones, Danbooru uses some custom status codes in the 4xx and 5xx range.</p> + <table> + <thead> + <tr> + <th>Status Code</th> + <th>Meaning</th> + </tr> + </thead> + <tbody> + <tr> + <td>200 OK</td> + <td>Request was successful</td> + </tr> + <tr> + <td>403 Forbidden</td> + <td>Access denied</td> + </tr> + <tr> + <td>404 Not Found</td> + <td>Not found</td> + </tr> + <tr> + <td>420 Invalid Record</td> + <td>Record could not be saved</td> + </tr> + <tr> + <td>421 User Throttled</td> + <td>User is throttled, try again later</td> + </tr> + <tr> + <td>422 Locked</td> + <td>The resource is locked and cannot be modified</td> + </tr> + <tr> + <td>423 Already Exists</td> + <td>Resource already exists</td> + </tr> + <tr> + <td>424 Invalid Parameters</td> + <td>The given parameters were invalid</td> + </tr> + <tr> + <td>500 Internal Server Error</td> + <td>Some unknown error occurred on the server</td> + </tr> + <tr> + <td>503 Service Unavailable</td> + <td>Server cannot currently handle the request, try again later</td> + </tr> + </tbody> + </table> + </div> + + <div class="section"> + <h4>JSON Responses</h4> + <p>While you will probably want to work with XML in the majority of cases, if you're writing something in Javascript then the JSON responses may be preferable. They are much faster to parse and there's less code to write to get your data structure:</p> + <div class="code"> + var data = JSON.parse(responseText)<br> + alert(data.response) + </div> + </div> + + <div class="section"> + <h4>Logging In</h4> + <p>Some actions may require you to log in. For any action you can always specify two parameters to identify yourself:</p> + <ul> + <li><strong>login</strong> Your login name.</li> + <li><strong>password_hash</strong> Your SHA1 hashed password. Simply hashing your plain password will NOT work since Danbooru salts its passwords. The actual string that is hashed is "choujin-steiner--<em>your-password</em>--".</li> + </ul> + <p>Please be aware of the security risks involved in sending your password through an unencrypted channel. Although your password will be hashed, it is still theoretically possible for someone to steal your account by creating a fake cookie based on your hashed password.</p> + </div> + </div> + + + + <div class="section"> + <a name="posts"></a> + <h2>Posts</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /post.xml.</p> + <ul> + <li><strong>limit</strong> How many posts you want to retrieve. There is a hard limit of 100 posts per request.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>tags</strong> The tags to search for. Any tag combination that works on the web site will work here. This includes all the meta-tags.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /post/create.xml. There are only two mandatory fields: you need to supply the tags, and you need to supply the file, either through a multipart form or through a source URL.</p> + <ul> + <li><strong>post[tags]</strong> A space delimited list of tags.</li> + <li><strong>post[file]</strong> The file data encoded as a multipart form.</li> + <li><strong>post[rating]</strong> The rating for the post. Can be: safe, questionable, or explicit.</li> + <li><strong>post[source]</strong> If this is a URL, Danbooru will download the file.</li> + <li><strong>post[is_rating_locked]</strong> Set to true to prevent others from changing the rating.</li> + <li><strong>post[is_note_locked]</strong> Set to true to prevent others from adding notes.</li> + <li><strong>post[parent_id]</strong> The ID of the parent post.</li> + <li><strong>md5</strong> Supply an MD5 if you want Danbooru to verify the file after uploading. If the MD5 doesn't match, the post is destroyed.</li> + </ul> + <p>If the call fails, the following response reasons are possible:</p> + <ul> + <li><strong>MD5 mismatch</strong> This means you supplied an MD5 parameter and what Danbooru got doesn't match. Try uploading the file again.</li> + <li><strong>duplicate</strong> This post already exists in Danbooru (based on the MD5 hash). An additional attribute called <code>location</code> will be set, pointing to the (relative) URL of the original post.</li> + <li><strong><em>other</em></strong> Any other error will have its error message printed.</li> + </ul> + <p>If the post upload succeeded, you'll get an attribute called <code>location</code> in the response pointing to the relative URL of your newly uploaded post.</p> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /post/update.xml. Only the <code>id</code> parameter is required. Leave the other parameters blank if you don't want to change them.</p> + <ul> + <li><strong>id</strong> The id number of the post to update.</li> + <li><strong>post[tags]</strong> A space delimited list of tags.</li> + <li><strong>post[file]</strong> The file data encoded as a multipart form.</li> + <li><strong>post[rating]</strong> The rating for the post. Can be: safe, questionable, or explicit.</li> + <li><strong>post[source]</strong> If this is a URL, Danbooru will download the file.</li> + <li><strong>post[is_rating_locked]</strong> Set to true to prevent others from changing the rating.</li> + <li><strong>post[is_note_locked]</strong> Set to true to prevent others from adding notes.</li> + <li><strong>post[parent_id]</strong> The ID of the parent post.</li> + </ul> + </div> + <div class="section"> + <h4>Destroy</h4> + <p>You must be logged in to use this action. You must also be the user who uploaded the post (or you must be a moderator).</p> + <ul> + <li><strong>id</strong> The id number of the post to delete.</li> + </ul> + </div> + <div class="section"> + <h4>Revert Tags</h4> + <p>This action reverts a post to a previous set of tags. The base URL is /post/revert_tags.xml.</p> + <ul> + <li><strong>id</strong> The post id number to update.</li> + <li><strong>history_id</strong> The id number of the tag history.</li> + </ul> + </div> + <div class="section"> + <h4>Vote</h4> + <p>This action lets you vote for a post. You can only vote once per post per IP address. The base URL is /post/vote.xml.</p> + <ul> + <li><strong>id</strong> The post id number to update.</li> + <li><strong>score</strong> Set to <code>1</code> to vote up and <code>-1</code> to vote down. All other values will be ignored.</li> + </ul> + <p>If the call did not succeed, the following reasons are possible:</p> + <ul> + <li><strong>already voted</strong> You have already voted for this post.</li> + <li><strong>invalid score</strong> You have supplied an invalid score.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="tags"></a> + <h2>Tags</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /tag.xml.</p> + <ul> + <li><strong>limit</strong> How many tags to retrieve. Setting this to 0 will return every tag.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>order</strong> Can be <code>date</code>, <code>count</code>, or <code>name</code>.</li> + <li><strong>id</strong> The id number of the tag.</li> + <li><strong>after_id</strong> Return all tags that have an id number greater than this.</li> + <li><strong>name</strong> The exact name of the tag.</li> + <li><strong>name_pattern</strong> Search for any tag that has this parameter in its name.</li> + </ul> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /tag/update.xml.</p> + <ul> + <li><strong>name</strong> The name of the tag to update.</li> + <li><strong>tag[tag_type]</strong> The tag type. General: 0, artist: 1, copyright: 3, character: 4.</li> + <li><strong>tag[is_ambiguous]</strong> Whether or not this tag is ambiguous. Use 1 for true and 0 for false.</li> + </ul> + </div> + <div class="section"> + <h4>Related</h4> + <p>The base URL is /tag/related.xml.</p> + <ul> + <li><strong>tags</strong> The tag names to query.</li> + <li><strong>type</strong> Restrict results to this tag type (can be <code>general</code>, <code>artist</code>, <code>copyright</code>, or <code>character</code>).</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="artists"></a> + <h2>Artists</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /artist.xml.</p> + <ul> + <li><strong>name</strong> The name (or a fragment of the name) of the artist.</li> + <li><strong>order</strong> Can be <code>date</code> or <code>name</code>.</li> + <li><strong>page</strong> The page number.</li> + </ul> + </div> + <div class="section"> + <h4>Create</h4> + <p>The base URL is /artist/create.xml.</p> + <ul> + <li><strong>artist[name]</strong> The artist's name.</li> + <li><strong>artist[urls]</strong> A list of URLs associated with the artist, whitespace delimited.</li> + <li><strong>artist[alias]</strong> The artist that this artist is an alias for. Simply enter the alias artist's name.</li> + <li><strong>artist[group]</strong> The group or cicle that this artist is a member of. Simply enter the group's name.</li> + </ul> + </div> + <div class="section"> + <h4>Update</h4> + <p>The base URL is /artist/update.xml. Only the <strong>id</strong> parameter is required. The other parameters are optional.</p> + <ul> + <li><strong>id</strong> The id of thr artist to update.</li> + <li><strong>artist[name]</strong> The artist's name.</li> + <li><strong>artist[urls]</strong> A list of URLs associated with the artist, whitespace delimited.</li> + <li><strong>artist[alias]</strong> The artist that this artist is an alias for. Simply enter the alias artist's name.</li> + <li><strong>artist[group]</strong> The group or cicle that this artist is a member of. Simply enter the group's name.</li> + </ul> + </div> + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /artist/destroy.xml. You must be logged in to delete artists.</p> + <ul> + <li><strong>id</strong> The id of the artist to destroy.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="comments"></a> + <h2>Comments</h2> + + <div class="section"> + <h4>Show</h4> + <p>The base URL is /comment/show.xml. This retrieves a single comment.</p> + <ul> + <li><strong>id</strong> The id number of the comment to retrieve.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /comment/create.xml.</p> + <ul> + <li><strong>comment[anonymous]</strong> Set to 1 if you want to post this comment anonymously.</li> + <li><strong>comment[post_id]</strong> The post id number to which you are responding.</li> + <li><strong>comment[body]</strong> The body of the comment.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base url is /comment/destroy.xml. You must be logged in to use this action. You must also be the owner of the comment, or you must be a moderator.</p> + <ul> + <li><strong>id</strong> The id number of the comment to delete.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="wiki"></a> + <h2>Wiki</h2> + <p>All titles must be exact (but case and whitespace don't matter).</p> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /wiki.xml. This retrieves a list of every wiki page.</p> + <ul> + <li><strong>order</strong> How you want the pages ordered. Can be: <code>title</code>, <code>date</code>.</li> + <li><strong>limit</strong> The number of pages to retrieve.</li> + <li><strong>page</strong> The page number.</li> + <li><strong>query</strong> A word or phrase to search for.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /wiki/create.xml.</p> + <ul> + <li><strong>wiki_page[title]</strong> The title of the wiki page.</li> + <li><strong>wiki_page[body]</strong> The body of the wiki page.</li> + </ul> + </div> + + <div class="section"> + <h4>Update</h4> + <p>The base URL is /wiki/update.xml. Potential error reasons: "Page is locked"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to update.</li> + <li><strong>wiki_page[title]</strong> The new title of the wiki page.</li> + <li><strong>wiki_page[body]</strong> The new body of the wiki page.</li> + </ul> + </div> + + <div class="section"> + <h4>Show</h4> + <p>The base URL is /wiki/show.xml. Potential error reasons: "artist type"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to retrieve.</li> + <li><strong>version</strong> The version of the page to retrieve.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /wiki/destroy.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to delete.</li> + </ul> + </div> + + <div class="section"> + <h4>Lock</h4> + <p>The base URL is /wiki/lock.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to lock.</li> + </ul> + </div> + + <div class="section"> + <h4>Unlock</h4> + <p>The base URL is /wiki/unlock.xml. You must be logged in as a moderator to use this action.</p> + <ul> + <li><strong>title</strong> The title of the page to unlock.</li> + </ul> + </div> + + <div class="section"> + <h4>Revert</h4> + <p>The base URL is /wiki/revert.xml. Potential error reasons: "Page is locked"</p> + <ul> + <li><strong>title</strong> The title of the wiki page to update.</li> + <li><strong>version</strong> The version to revert to.</li> + </ul> + </div> + + <div class="section"> + <h4>History</h4> + <p>The base URL is /wiki/history.xml.</p> + <ul> + <li><strong>title</strong> The title of the wiki page to retrieve versions for.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="notes"></a> + <h2>Notes</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /note.xml.</p> + <ul> + <li><strong>post_id</strong> The post id number to retrieve notes for.</li> + </ul> + </div> + + <div class="section"> + <h4>Search</h4> + <p>The base URL is /note/search.xml.</p> + <ul> + <li><strong>query</strong> A word or phrase to search for.</li> + </ul> + </div> + + <div class="section"> + <h4>History</h4> + <p>The base URL is /note/history.xml. You can either specify <code>id</code>, <code>post_id</code>, or nothing. Specifying nothing will give you a list of every note verison.</p> + <ul> + <li><strong>limit</strong> How many versions to retrieve.</li> + <li><strong>page</strong> The offset.</li> + <li><strong>post_id</strong> The post id number to retrieve note versions for.</li> + <li><strong>id</strong> The note id number to retrieve versions for.</li> + </ul> + </div> + + <div class="section"> + <h4>Revert</h4> + <p>The base URL is /note/revert.xml. Potential error reasons: "Post is locked"</p> + <ul> + <li><strong>id</strong> The note id to update.</li> + <li><strong>version</strong> The version to revert to.</li> + </ul> + </div> + + <div class="section"> + <h4>Create/Update</h4> + <p>The base URL is /note/update.xml. Notes differ from the other controllers in that the interface for creation and updates is the same. If you supply an <code>id</code> parameter, then Danbooru will assume you're updating an existing note. Otherwise, it will create a new note. Potential error reasons: "Post is locked"</p> + <ul> + <li><strong>id</strong> If you are updating a note, this is the note id number to update.</li> + <li><strong>note[post_id]</strong> The post id number this note belongs to.</li> + <li><strong>note[x]</strong> The x coordinate of the note.</li> + <li><strong>note[y]</strong> The y coordinate of the note.</li> + <li><strong>note[width]</strong> The width of the note.</li> + <li><strong>note[height]</strong> The height of the note.</li> + <li><strong>note[is_active]</strong> Whether or not the note is visible. Set to 1 for active, 0 for inactive.</li> + <li><strong>note[body]</strong> The note message.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="users"></a> + <h2>Users</h2> + + <div class="section"> + <h4>Search</h4> + <p>The base URL is /user.xml. If you don't specify any parameters you'll get a listing of all users.</p> + <ul> + <li><strong>id</strong> The id number of the user.</li> + <li><strong>name</strong> The name of the user.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="forum"></a> + <h2>Forum</h2> + + <div class="section"> + <h4>List</h4> + <p>The base URL is /forum.xml. If you don't specify any parameters you'll get a list of all the parent topics.</p> + <ul> + <li><strong>parent_id</strong> The parent ID number. You'll return all the responses to that forum post.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="pools"></a> + <h2>Pools</h2> + + <div class="section"> + <h4>List Pools</h4> + <p>The base URL is /pool.xml. If you don't specify any parameters you'll get a list of all pools.</p> + <ul> + <li><strong>query</strong> The title.</li> + <li><strong>page</strong> The page.</li> + </ul> + </div> + + <div class="section"> + <h4>List Posts</h4> + <p>The base URL is /pool/show.xml. If you don't specify any parameters you'll get a list of all pools.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + <li><strong>page</strong> The page.</li> + </ul> + </div> + + <div class="section"> + <h4>Update</h4> + <p>The base URL is /pool/update.xml.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + <li><strong>pool[name]</strong> The name.</li> + <li><strong>pool[is_public]</strong> 1 or 0, whether or not the pool is public.</li> + <li><strong>pool[description]</strong> A description of the pool.</li> + </ul> + </div> + + <div class="section"> + <h4>Create</h4> + <p>The base URL is /pool/create.xml.</p> + <ul> + <li><strong>pool[name]</strong> The name.</li> + <li><strong>pool[is_public]</strong> 1 or 0, whether or not the pool is public.</li> + <li><strong>pool[description]</strong> A description of the pool.</li> + </ul> + </div> + + <div class="section"> + <h4>Destroy</h4> + <p>The base URL is /pool/destroy.xml.</p> + <ul> + <li><strong>id</strong> The pool id number.</li> + </ul> + </div> + + <div class="section"> + <h4>Add Post</h4> + <p>The base URL is /pool/add_post.xml. Potential error reasons: "Post already exists", "access denied"</p> + <ul> + <li><strong>pool_id</strong> The pool to add the post to.</li> + <li><strong>post_id</strong> The post to add.</li> + </ul> + </div> + + <div class="section"> + <h4>Remove Post</h4> + <p>The base URL is /pool/remove_post.xml. Potential error reasons: "access denied"</p> + <ul> + <li><strong>pool_id</strong> The pool to remove the post from.</li> + <li><strong>post_id</strong> The post to remove.</li> + </ul> + </div> + + </div> + + + + <div class="section"> + <a name="favorites"></a> + <h2>Favorites</h2> + + <div class="section"> + <h4>List Users</h4> + <p>The base URL is /favorite/list_users.json. There is no XML API for this action.</p> + <ul> + <li><strong>id</strong> The post id.</li> + </ul> + </div> + </div> + + + + <div class="section"> + <a name="changelog"></a> + <h2>Change Log</h2> + <div class="section"> + <h4>2.0.0</h4> + <ul> + <li>Removed <code>blacklist_tags</code> from user object (never documented)</li> + <li>XML tag for user API has been changed from <code>post</code> to <code>user</code></li> + </ul> + <h4>1.13.0+update.3</h4> + <ul> + <li>Removed /index from API URLs</li> + </ul> + <h4>1.13.0+update.2</h4> + <ul> + <li>Readd favorite/list_users API</li> + </ul> + <h4>1.13.0+update.1</h4> + <ul> + <li>Added documentation for pools</li> + </ul> + + <h4>1.13.0</h4> + <ul> + <li>Changed interface for artists to use new URL system</li> + <li>JSON requests now end in a .json suffix</li> + <li>Renamed some error reason messages</li> + <li>Removed comment/index from API</li> + <li>Removed url and md5 parameters from artist search (can just pass the URL or MD5 hash to the name parameter)</li> + </ul> + </div> + + <div class="section"> + <h4>1.8.1</h4> + <ul> + <li>Removed post[is_flagged] attribute</li> + </ul> + </div> + </div> +</div> + + + <div class="footer"> + + <ul class="flat-list" id="subnavbar"> + <li><a href="/help">Help</a></li> + + </ul> + </div> + </div> + + <script type="text/javascript"> + InitTextAreas(); + Post.InitBrowserLinks(); + if(TagCompletion) + TagCompletion.init(8384); + </script> + + <!--[if lt IE 7]> + <script type="text/javascript"> + if(Cookie.get("hide-ie-nag") != "1") + $("old-browser").show(); + </script> + <![endif]--> + + <form> + <select name="locale"> + <option value="de" > + Deutsch + </option> + <option value="en" selected> + English + </option> + <option value="es" > + español + </option> + <option value="ja" > + 日本語 + </option> + <option value="ru" > + русский + </option> + <option value="zh_CN" > + 简体中文 + </option> + <option value="zh_TW" > + 繁體中文(台灣) + </option> + </select> + <button type='submit'> + Select + </button> + </form> + + </body> +</html> + diff --git a/docs/plans/2026-02-23-held-posts-toggle-design.md b/docs/plans/2026-02-23-held-posts-toggle-design.md new file mode 100644 index 0000000..b629f0f --- /dev/null +++ b/docs/plans/2026-02-23-held-posts-toggle-design.md @@ -0,0 +1,29 @@ +# Held Posts Toggle Design + +## Goal +Add a user setting that allows Moebooru providers to include held posts in the feed when desired, while preserving current default ordering behavior. + +## Problem +Konachan and yande.re API results can diverge from website ordering because held posts are included unless explicitly filtered. We currently force `holds:false` by default to match the website feed, but users need an option to view held posts. + +## Decision +Implement a global persisted setting: `showHeldMoebooruPosts` (default `false`). + +- When `false`: Moebooru requests continue to append `holds:false` unless user already provides `holds:*`. +- When `true`: Moebooru requests do not add a default `holds:false` filter; explicit `holds:*` tags still win. + +## Scope +- Data model: Add `@AppStorage` boolean to `SettingsManager`. +- Networking: Thread the setting into `BooruManager` and its Moebooru tag helper. +- UI: Add a toggle in Provider settings. +- Wiring: Rebuild `BooruManager` when setting changes so feed refresh reflects the new mode. +- Tests: Add source-based checks for setting persistence, manager wiring, and Moebooru filter behavior. + +## Non-Goals +- Per-provider held-post settings. +- Changing Danbooru/Gelbooru behavior. +- Advanced moderation controls beyond `holds:*` behavior. + +## Rollout Behavior +- Existing users default to `false`, preserving current website-aligned feed order. +- Users can opt in to include held posts through settings. diff --git a/docs/plans/2026-02-23-held-posts-toggle-implementation.md b/docs/plans/2026-02-23-held-posts-toggle-implementation.md new file mode 100644 index 0000000..7f84e55 --- /dev/null +++ b/docs/plans/2026-02-23-held-posts-toggle-implementation.md @@ -0,0 +1,68 @@ +# Held Posts Toggle Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add a settings toggle to allow showing held posts on Moebooru providers, while keeping default feed behavior aligned with website ordering. + +**Architecture:** Persist a global boolean in `SettingsManager`, pass it into `BooruManager`, and conditionally apply default `holds:false` in the Moebooru tag helper. Expose the toggle in Provider settings and rebuild manager instances when the setting changes so requests immediately reflect the new behavior. + +**Tech Stack:** Swift, SwiftUI, `@AppStorage`, XCTest source-assertion tests. + +--- + +### Task 1: Add failing tests for toggle persistence and wiring + +**Files:** +- Modify: `SoraTests/ViewDerivedDataTests.swift` + +**Step 1: Write failing tests** +- Add a test asserting `SettingsManager` contains `@AppStorage("showHeldMoebooruPosts") var showHeldMoebooruPosts = false`. +- Add a test asserting `MainView` passes `showHeldMoebooruPosts: settings.showHeldMoebooruPosts` when creating `BooruManager`. +- Add a test asserting `BooruManager.moebooruTagString` guards on `showHeldMoebooruPosts` and bypasses forced `holds:false` when enabled. + +**Step 2: Run tests to verify failure** +- Run: `xcodebuild -scheme Sora -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' -only-testing:SoraTests/ViewDerivedDataTests test` +- Expected: New tests fail due missing setting/wiring. + +### Task 2: Implement the setting and manager behavior + +**Files:** +- Modify: `Sora/Data/Settings/SettingsManager.swift` +- Modify: `Sora/Data/Booru/BooruManager.swift` +- Modify: `Sora/Views/MainView.swift` +- Modify: `Sora/Views/Settings/Section/SettingsSectionProviderView.swift` + +**Step 1: Add setting storage** +- Add `@AppStorage("showHeldMoebooruPosts") var showHeldMoebooruPosts = false` to `SettingsManager`. + +**Step 2: Thread setting into manager** +- Add `showHeldMoebooruPosts` init param + stored property in `BooruManager`. +- Update Moebooru tag helper: + - Respect explicit `holds:*` as-is. + - If `showHeldMoebooruPosts == true`, return raw tags (no forced filter). + - Else append `holds:false` default. + +**Step 3: Wire manager creation points** +- Update `MainView` manager constructors to pass `showHeldMoebooruPosts: settings.showHeldMoebooruPosts`. +- Add `.onChange(of: settings.showHeldMoebooruPosts)` to rebuild manager and refresh feed. + +**Step 4: Expose toggle in settings UI** +- Add `Toggle("Show Held Posts", isOn: $settings.showHeldMoebooruPosts)` to Provider settings section. +- Add concise help text that this affects Moebooru feeds. + +### Task 3: Verify and finalize + +**Files:** +- Modify (if needed): `SoraTests/ViewDerivedDataTests.swift` + +**Step 1: Run targeted tests** +- Run: `xcodebuild -scheme Sora -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' -only-testing:SoraTests/ViewDerivedDataTests test` +- Expected: PASS. + +**Step 2: Run lint** +- Run: `swiftlint lint --quiet` +- Expected: PASS. + +**Step 3: Summarize behavior** +- Confirm default (`false`) preserves website-aligned ordering. +- Confirm toggle (`true`) includes held posts for Moebooru providers. |