├── .gitattributes
├── .github
└── workflows
│ └── codeql-analysis.yml
├── .gitignore
├── README.md
├── booru-augmentation-project.user.js
├── image_search
├── controller.js
└── index.html
└── js
├── listPage.js
├── optionsPage.js
└── postPage.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | name: "CodeQL"
7 |
8 | on:
9 | push:
10 | branches: [master]
11 | pull_request:
12 | # The branches below must be a subset of the branches above
13 | branches: [master]
14 | schedule:
15 | - cron: '0 4 * * 3'
16 |
17 | jobs:
18 | analyze:
19 | name: Analyze
20 | runs-on: ubuntu-latest
21 |
22 | strategy:
23 | fail-fast: false
24 | matrix:
25 | # Override automatic language detection by changing the below list
26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
27 | language: ['javascript']
28 | # Learn more...
29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
30 |
31 | steps:
32 | - name: Checkout repository
33 | uses: actions/checkout@v2
34 | with:
35 | # We must fetch at least the immediate parents so that if this is
36 | # a pull request then we can checkout the head.
37 | fetch-depth: 2
38 |
39 | # If this run was triggered by a pull request event, then checkout
40 | # the head of the pull request instead of the merge commit.
41 | - run: git checkout HEAD^2
42 | if: ${{ github.event_name == 'pull_request' }}
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear on external disk
35 | .Spotlight-V100
36 | .Trashes
37 |
38 | # Directories potentially created on remote AFP share
39 | .AppleDB
40 | .AppleDesktop
41 | Network Trash Folder
42 | Temporary Items
43 | .apdisk
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Booru Augmentation Project
2 | A userscript that improves usability of basic *.booru.org hosted sites.
3 |
4 | It's no secret that free accounts on booru.org offer very little convenience compared to well-developed sites like Danbooru.
5 | My goal is to do what is possible on client-side to compensate for the lack of functionality of the server side.
6 |
7 | ## List of features:
8 |
9 | * Drop-down select tag list for the search field
10 |
11 | 
12 |
13 | Like on Danbooru, but so far only works for the first tag entered. The data for autocompletion is being collected as you navigate the booru, so its accuracy depends on your booru usage.
14 |
15 | * AJAX tag editor
16 |
17 | 
18 |
19 | Allows you to quickly add, edit and remove tags with just a few clicks and without page reloading. No more scrolling to the bottom of the page to open the edit form, do everything directly in the tag list to the left.
20 |
21 | * Revamp Statistics area below the tag list
22 |
23 | 
24 |
25 | Improve readability, add user links and image title, remove unnecessary info.
26 |
27 | * Shift page number links, so that links to both 5 previous and 5 next pages are available
28 |
29 | 
30 |
31 | By default booru only shows 10 next links, which makes jumping several pages back impossible.
32 |
33 | * The scripts adds its settings section to your account options.
34 |
35 | 
36 |
37 | From here you can see the full list of tags the script collected so far, paired with their amount of posts (this data is used for search autocompletion). Another option is to enable the advanced booru tools:
38 |
39 | * Booru scanner
40 |
41 | 
42 |
43 | This utility allows you to scan the entire booru or just the posts with selected tags. Scanning builds up the tag database for autocompletion and also allows you to download it in JSON format, as well as data for every post (id, rating, score, tags and image cluster) and a list of links to both image thumbnails and full-sizes. The latter can be fed to any mass-downloader to obtain a booru dump. Having both a collection of image thumbnails and a post database allows you to
44 |
45 | * Search posts by images
46 |
47 | 
48 |
49 | You can find what post a saved thumbnail corresponds to by using this tool. It's useful when you're running duplicate checks on your booru and end up with a list of image doubles to delete.
50 |
51 | * Remove tagme tags
52 |
53 | 
54 |
55 | Made to overcome the needless "minimum of 5 tags" requirement that spams your uploads with the tagme tag, making it impossible to find posts that actually need to be tagged. Do note that this tool is only useful for admins, because it will attempt to edit any post it encounters and if you don't have right for it it'll fail and stop the progress. It is also advised to avoid editing other tags manually until the process finishes since booru limits the amount of consecutive edit queries and they're all used up by the script.
56 |
57 | Aside from these, I added some minor tweaks such as fitting the post image into screen width, fixing links to user accounts, linkifying users and links in comments as well as tags in the alias list, highlighting potential mistakes in tags input, fixing incorrect handling of _ in tags and some other.
58 |
59 | You feedback is required, please go to the [Issues](https://github.com/Seedmanc/Booru-Augmentation-Project/issues) section and make suggestions which features I should add, and what would you like to see.
60 |
61 | Be sure to check out my other Booru-related userscript project - the [Mass Uploader](https://github.com/Seedmanc/Booru-mass-uploader)
62 |
--------------------------------------------------------------------------------
/booru-augmentation-project.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Booru Augmentation Project
3 | // @description Enhance your basic booru experience
4 | // @version 1.1.2
5 | // @author Seedmanc
6 | // @include https://*.booru.org/*index.php?page=post*
7 | // @include https://*.booru.org/*index.php?page=alias*
8 | // @include https://*.booru.org/*index.php?page=comment*
9 | // @include https://*.booru.org/*index.php?page=history*
10 | // @include https://*.booru.org/*index.php?page=forum&s=view*
11 | // @include https://*.booru.org/*index.php?page=account-options*
12 | // @include https://*.booru.org/*index.php?page=account&s=profile&uname=*
13 | // @grant none
14 | // @run-at document-body
15 | // @require https://ajax.googleapis.com/ajax/libs/prototype/1.7.3.0/prototype.js
16 | // @noframes
17 | // ==/UserScript==
18 |
19 | var pages = {
20 | 'account-options': optionsPage,
21 | 'account': {
22 | 'profile': profilePage
23 | },
24 | 'alias': aliasPage,
25 | 'comment': commentPage,
26 | 'forum': {
27 | 'view': linkify
28 | },
29 | 'history&type=tag_history': historyPage,
30 | 'post': {
31 | 'list': listPage,
32 | 'view': postPage
33 | }
34 | };
35 | var hosting = 'https://seedmanc.github.io/Booru-Augmentation-Project/';
36 |
37 | window.BAPtags = {};
38 | window.BAPopts = JSON.parse(localStorage.getItem('BAPopts') || '{"ansiOnly":true, "solo":true, "tagme":true}');
39 | window.currentBooru = document.location.host.split('.')[0];
40 | window.taglist = {};
41 | window.linklist = [];
42 | window.thumblist = [];
43 | window.postlist = {};
44 |
45 | if (~document.location.href.indexOf('s=search_image')) {
46 | var frame = document.createElement('iframe');
47 |
48 | document.title = 'BAP - Search by image';
49 |
50 | frame.src = hosting + 'image_search/index.html?booru=' + window.currentBooru;
51 | frame.width = "100%";
52 | frame.height = "96%";
53 | document.body.appendChild(frame);
54 |
55 | } else if (!~document.location.href.indexOf('s=mass_upload')) {
56 | if (document.readyState == 'loading') {
57 | document.addEventListener('DOMContentLoaded', main, false);
58 | } else {
59 | main();
60 | }
61 | }
62 |
63 | function loadAndExecute(url, callback){
64 | var scriptNode = document.createElement ("script");
65 | scriptNode.addEventListener("load", callback);
66 | scriptNode.onerror=function(){
67 | throw new Error("Can't load "+url);
68 | };
69 | scriptNode.src = url;
70 | document.head.appendChild(scriptNode);
71 | };
72 |
73 | function optionsPage() {
74 | loadAndExecute(hosting + '/js/optionsPage.js');
75 | }
76 |
77 | function listPage() {
78 | loadAndExecute(hosting + '/js/listPage.js');
79 | }
80 |
81 | function postPage() {
82 | loadAndExecute(hosting + '/js/postPage.js');
83 | }
84 |
85 | function parseUrl(prefix, handlers) {
86 |
87 | for (var key in handlers) {
88 | if (~document.location.href.indexOf(prefix + key)) {
89 | if (typeof handlers[key] == 'function') {
90 | handlers[key]();
91 |
92 | break;
93 | } else {
94 | parseUrl('s=', handlers[key]); // yay recursion
95 |
96 | break;
97 | }
98 | }
99 | }
100 | }
101 |
102 | function main() {
103 |
104 | parseUrl('page=', pages);
105 |
106 | var ad;
107 | try {
108 | ad = document.querySelectorAll('center div[id*="adbox"]')[0];
109 | if (ad) {
110 | ad.parentNode.parentNode.removeChild(ad.parentNode);
111 | }
112 | ad = document.querySelectorAll('#right-col div[id*="adbox"]')[0];
113 | if (ad) {
114 | ad.parentNode.parentNode.removeChild(ad.parentNode);
115 | }
116 | ad = $$('center a[href*="patreon"]')[0];
117 | if (ad) {
118 | ad.parentNode.parentNode.removeChild(ad.parentNode);
119 | }
120 | new Insertion.Bottom($$('head')[0],
121 | ''
126 | );
127 | } catch (any) {
128 | }
129 | }
130 |
131 | function profilePage() {
132 | document.location.href = document.location.href.replace('account&s=profile', 'account_profile');
133 | }
134 |
135 | window.loadOptions = function(that) {
136 | searchField();
137 | that.onfocus = '';
138 | }
139 |
140 | window.storeTags = function () {
141 | var tags = $$('#tag_list ul li span');
142 | var newtags;
143 |
144 | window.BAPtags = Object.keys(window.BAPtags).length && window.BAPtags || JSON.parse(localStorage.getItem('BAPtags') || '{}');
145 |
146 | tags.each(function (span) {
147 | var tag = span.down('a').href;
148 |
149 | tag = tag && tag.split('tags=')[1];
150 | if (tag) {
151 | tag = decodeURIComponent(tag).replace(/\"|\'/g, '');
152 | window.BAPtags[tag] = Number(span.textContent.split(/\s+/).last());
153 | }
154 | });
155 |
156 | newtags = JSON.stringify(window.BAPtags);
157 | if (Object.keys(newtags).length) {
158 | localStorage.setItem('BAPtags', newtags);
159 | }
160 |
161 | $$('input[name^="tag"]')[0].onfocus = function () {
162 | loadOptions(this);
163 | };
164 | }
165 |
166 | function searchField() {
167 | var datalist = $('datags');
168 | var goFullRetard = ~navigator.userAgent.toLowerCase().indexOf('firefox');
169 |
170 | if (!datalist) {
171 | new Insertion.Top(document.body, '');
172 | }
173 | datalist = $('datags');
174 |
175 | Object.keys(window.BAPtags).each(function (tag) {
176 | if (!datalist.down('option[value="' + tag + '"]')) {
177 | var content = goFullRetard ? tag + ' (' + window.BAPtags[tag] + ')' : window.BAPtags[tag];
178 |
179 | new Insertion.Bottom(datalist, '');
180 | }
181 | });
182 |
183 | $$('input#tags, input#stags, input[name="tag"]')[0].oninput = function () {
184 | enableDatalist(this);
185 | };
186 | }
187 |
188 | window.enableDatalist = function(that) {
189 | if (that.value.length >= 1) {
190 | that.setAttribute('list', 'datags');
191 | } else {
192 | that.removeAttribute('list');
193 | }
194 | }
195 |
196 | window.markTags = function (li) {
197 | var q = li.textContent.trim().split(/\s+/);
198 | var q1 = q[q.length - 1];;
199 |
200 | if (~q.indexOf('tagme') && window.BAPopts.tagme) {
201 | li.style.backgroundColor = 'rgba(255,0,0,0.25)';
202 | }
203 | if (isNaN(q1) || q1 >= 5) {
204 | li.down('span').style.color = "#A0A0A0";
205 |
206 | return;
207 | }
208 | if (q1 <= 1) {
209 | li.style.backgroundColor = "rgba(255,225,0,0.66)";
210 | } else {
211 | li.style.backgroundColor = "rgba(255,255,0,0.33)";
212 | }
213 |
214 | li.down('span').style.color = "#000";
215 | }
216 |
217 | function aliasPage() { // idea by Usernam, how it's actually done by Seedmanc
218 | var example = $$('body > div:nth-child(4)');
219 |
220 | if (example.length && ~example[0].textContent.indexOf('example')) {
221 | example[0].style.color = "black";
222 | example[0].innerHTML = example[0].innerHTML.replace(/(An example)(.+)(Evangelion)(.+)(Neon_Genesis_Evangelion)(.+)\)/gi, "$1: $3$4$5$6");
223 | }
224 |
225 | storeTags();
226 |
227 | $$("th")[2].hide();
228 |
229 | $$('.highlightable td').each(function (td, index) {
230 | var tag = td.textContent;
231 |
232 | if ((index + 1) % 3 == 0) {
233 | td.hide();
234 | } else {
235 | td.innerHTML = "" + tag + "" +
236 | (tag && window.BAPtags[tag.toLowerCase()] ? ' (' + window.BAPtags[tag.toLowerCase()] + ')' : "");
237 | }
238 | });
239 | }
240 |
241 | function commentPage() {
242 |
243 | var commentsData = $$('ul.post-info');
244 |
245 | $A(commentsData).forEach(function (el) {
246 | var user = el.childNodes[2].textContent.split(':')[1].trim();
247 |
248 | var userlink = user == 'Anonymous' ?
249 | 'Anonymous' :
250 | '' + user + '';
251 | el.removeChild(el.childNodes[2]);
252 | new Insertion.Before(el.childNodes[2], '
');
175 |
176 | new Insertion.After($('scanner'),
177 | '
Search by image (hash)
Having the complete post DB allows you to do the advanced post searching.
\
178 |
For example, here is how you can search for duplicating images at your booru:
Get the complete post DB by hash and the list of links to thumbnails.
\
179 |
DL all thumbs by feeding the list to some mass downloader
\
180 |
Run a duplicate finder software on the thumbs, moving all dupes to a folder
\
181 |
Open the hash db and the found images in the Image Search to get links to posts on booru that have duplicating images
\
182 | Note: in Chrome the amount of pictures opened simulaneously might be quite limited by their collective filename length. You can open a folder of images instead.\
183 |
');
184 |
185 | new Insertion.After($('sbi'),
186 | '
Remove tagme
Booru automatically adds the "tagme" tag if your uploads have less than 5 tags. You can\'t turn that off, however, you can batch-delete that tag from the posts that have it.