-
-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This extension is derived from Danbooru's blacklist code
- Loading branch information
1 parent
ddf5001
commit 4a5d30e
Showing
5 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Shimmie2; | ||
|
||
class FilterInfo extends ExtensionInfo | ||
{ | ||
public const KEY = "filter"; | ||
|
||
public string $key = self::KEY; | ||
public string $name = "Filter Tags"; | ||
public array $authors = ["Danbooru Project" => "", "Discomrade" => ""]; | ||
public string $license = "WTFPL"; | ||
public string $description = "Allow users to filter out tags."; | ||
public ?string $documentation = "Admins can set default filters and users can override them in user settings. This is derived from Danbooru's blacklist code, it works in the user's browser with JavaScript, and will hide posts until the filter runs."; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Shimmie2; | ||
|
||
class Filter extends Extension | ||
{ | ||
/** @var FilterTheme */ | ||
protected Themelet $theme; | ||
|
||
public function onInitExt(InitExtEvent $event): void | ||
{ | ||
global $config; | ||
$config->set_default_string("filter_tags", "spoilers\nguro\nscat\nfurry -rating:s\n"); | ||
} | ||
|
||
public function onPageRequest(PageRequestEvent $event): void | ||
{ | ||
global $page; | ||
$this->theme->addFilterBox(); | ||
$page->add_html_header("<script> | ||
Array.from(document.getElementsByClassName('thumb')).forEach(function(post) { | ||
post.style.display='none'; | ||
});</script>"); | ||
} | ||
|
||
public function onSetupBuilding(SetupBuildingEvent $event): void | ||
{ | ||
$sb = $event->panel->create_new_block("Filters"); | ||
$sb->add_longtext_option("filter_tags", 'Default filtered tags'); | ||
$sb->add_label("This controls the tags which are hidden by default. This feature currently requires JavaScript. Separate filters by line, or by commas. You can enter multiple tags per filter, as well as negative tags."); | ||
} | ||
|
||
public function onInitUserConfig(InitUserConfigEvent $event): void | ||
{ | ||
global $config; | ||
$event->user_config->set_default_string("filter_tags", $config->get_string("filter_tags")); | ||
} | ||
|
||
public function onUserOptionsBuilding(UserOptionsBuildingEvent $event): void | ||
{ | ||
global $user; | ||
|
||
$sb = $event->panel->create_new_block("Filters"); | ||
$sb->add_longtext_option("filter_tags", 'Default filtered tags'); | ||
$sb->add_label("This controls the tags which are hidden by default. This feature currently requires JavaScript. Separate filters by line, or by commas. You can enter multiple tags per filter, as well as negative tags."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
// This code is a modified, jquery-less adaptation of danbooru/app/javascript/src/javascripts/blacklists.js, with snippets from utility.js | ||
// The following copyright notice is a legal requirement of Danbooru's BSD 2-Clause license | ||
|
||
// Copyright (c) 2013~2021, Danbooru Project | ||
// All rights reserved. | ||
|
||
let Utility = {}; | ||
|
||
Utility.is_subset = function(array, subarray) { | ||
var all = true; | ||
|
||
$.each(subarray, function(i, val) { | ||
if ($.inArray(val, array) === -1) { | ||
all = false; | ||
} | ||
}); | ||
|
||
return all; | ||
} | ||
|
||
Utility.intersect = function(a, b) { | ||
a = a.slice(0).sort(); | ||
b = b.slice(0).sort(); | ||
var result = []; | ||
while (a.length > 0 && b.length > 0) { | ||
if (a[0] < b[0]) { | ||
a.shift(); | ||
} else if (a[0] > b[0]) { | ||
b.shift(); | ||
} else { | ||
result.push(a.shift()); | ||
b.shift(); | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
let Filter = {}; | ||
|
||
Filter.entries = []; | ||
|
||
Filter.parse_entry = function(string) { | ||
var entry = { | ||
"tags": string, | ||
"require": [], | ||
"exclude": [], | ||
"optional": [], | ||
"disabled": false, | ||
"hits": 0, | ||
"min_score": null | ||
}; | ||
|
||
let tags = string.split(/ +/); | ||
tags.forEach(function(tag) { | ||
if (tag.charAt(0) === '-') { | ||
entry.exclude.push(tag.slice(1)); | ||
} else if (tag.charAt(0) === '~') { | ||
entry.optional.push(tag.slice(1)); | ||
} else if (tag.match(/^score:<.+/)) { | ||
var score = tag.match(/^score:<(.+)/)[1]; | ||
entry.min_score = parseInt(score); | ||
} else { | ||
entry.require.push(tag); | ||
} | ||
}); | ||
return entry; | ||
} | ||
|
||
Filter.parse_entries = function() { | ||
var entries = document.getElementById("filter-tags").getAttribute("tags").replace(/(rating:\w)\w+/ig, "$1").toLowerCase().split(/[,\n]/); | ||
entries = entries.filter(e => e.trim() !== ""); | ||
|
||
entries.forEach(function(tags) { | ||
var entry = Filter.parse_entry(tags); | ||
Filter.entries.push(entry); | ||
}); | ||
} | ||
|
||
Filter.toggle_entry = function(e) { | ||
var link = e.target; | ||
var tags = link.innerText; | ||
var match = Filter.entries.find(function(entry, i) { | ||
return entry.tags === tags; | ||
}); | ||
if (match) { | ||
match.disabled = !match.disabled; | ||
if (match.disabled) { | ||
link.classList.add("filter-inactive"); | ||
} else { | ||
link.classList.remove("filter-inactive"); | ||
} | ||
} | ||
Filter.apply(); | ||
e.preventDefault(); | ||
} | ||
|
||
Filter.update_sidebar = function() { | ||
Filter.entries.forEach(function(entry) { | ||
if (entry.hits.length === 0) { | ||
return; | ||
} | ||
|
||
var item = document.createElement("li"); | ||
var link = document.createElement("a"); | ||
var count = document.createElement("span"); | ||
|
||
link.innerText = entry.tags; | ||
link.classList.add("filter"); | ||
link.setAttribute("href", `/posts?tags=${encodeURIComponent(entry.tags)}`); | ||
link.setAttribute("title", entry.tags); | ||
link.addEventListener("click", Filter.toggle_entry); | ||
let unique_hits = new Set(entry.hits).size; | ||
count.innerText = unique_hits; | ||
count.classList.add("tag_count"); | ||
item.append(link); | ||
item.append(" "); | ||
item.append(count); | ||
|
||
document.getElementById("filter-list").append(item); | ||
}); | ||
|
||
document.getElementById("Filtersleft").style.display = ""; | ||
} | ||
|
||
Filter.disable_all = function() { | ||
Filter.entries.forEach(function(entry) { | ||
entry.disabled = true; | ||
}); | ||
// There is no need to process the filter when disabling | ||
Array.from(Filter.posts()).forEach(function(post) { | ||
post.classList.remove("filtered-active"); | ||
}); | ||
document.getElementById("disable-all-filters").style.display = "none"; | ||
document.getElementById("re-enable-all-filters").style.display = ""; | ||
Array.from(document.getElementsByClassName("filter")).forEach(function(post) { | ||
post.classList.add("filter-inactive"); | ||
}); | ||
} | ||
|
||
Filter.enable_all = function() { | ||
Filter.entries.forEach(function(entry) { | ||
entry.disabled = false; | ||
}); | ||
Filter.apply(); | ||
document.getElementById("disable-all-filters").style.display = ""; | ||
document.getElementById("re-enable-all-filters").style.display = "none"; | ||
Array.from(document.getElementsByClassName("filter")).forEach(function(post) { | ||
post.classList.remove("filter-inactive"); | ||
}); | ||
} | ||
|
||
Filter.initialize_disable_all_filters = function() { | ||
if (shm_cookie_get("ui-disable-filters") === "1") { | ||
Filter.disable_all(); | ||
} else { | ||
// The filter has already been processed by this point | ||
document.getElementById("disable-all-filters").style.display = ""; | ||
} | ||
|
||
document.getElementById("disable-all-filters").addEventListener("click", function(e) { | ||
shm_cookie_set("ui-disable-filters", "1"); | ||
Filter.disable_all(); | ||
e.preventDefault(); | ||
}); | ||
|
||
document.getElementById("re-enable-all-filters").addEventListener("click", function(e) { | ||
shm_cookie_set("ui-disable-filters", "0"); | ||
Filter.enable_all(); | ||
e.preventDefault(); | ||
}); | ||
} | ||
|
||
|
||
Filter.apply = function() { | ||
Filter.entries.forEach(function(entry) { | ||
entry.hits = []; | ||
}); | ||
|
||
var count = 0 | ||
Array.from(Filter.posts()).forEach(function(post) { | ||
count += Filter.apply_post(post); | ||
}); | ||
|
||
return count; | ||
} | ||
|
||
Filter.apply_post = function(post) { | ||
var post_count = 0; | ||
Filter.entries.forEach(function(entry) { | ||
if (Filter.post_match(post, entry)) { | ||
let post_id = post.getAttribute("data-post-id"); | ||
entry.hits.push(post_id); | ||
post_count += 1; | ||
} | ||
}); | ||
if (post_count > 0) { | ||
Filter.post_hide(post); | ||
} else { | ||
Filter.post_unhide(post); | ||
} | ||
return post_count; | ||
}; | ||
|
||
Filter.posts = function() { | ||
return document.getElementsByClassName("thumb"); | ||
} | ||
|
||
Filter.post_match = function(post, entry) { | ||
if (entry.disabled) { | ||
return false; | ||
} | ||
|
||
var score = parseInt(post.getAttribute("data-score")); | ||
var score_test = entry.min_score === null || score < entry.min_score; | ||
|
||
var tags = post.getAttribute("data-tags").split(/ +/); | ||
// tags.push(...(post.getAttribute("data-pools")).split(/ +/)); | ||
tags.push("rating:" + post.getAttribute("data-rating")); | ||
// tags.push("uploaderid:" + post.getAttribute("data-uploader-id")); | ||
// post.getAttribute("flags").split(/ +/).forEach(function(v) { | ||
// tags.push("status:" + v); | ||
// }); | ||
|
||
return (Utility.is_subset(tags, entry.require) && score_test) | ||
&& (!entry.optional.length || Utility.intersect(tags, entry.optional).length) | ||
&& !Utility.intersect(tags, entry.exclude).length; | ||
} | ||
|
||
Filter.post_hide = function(post) { | ||
post.classList.add("filtered"); | ||
post.classList.add("filtered-active"); | ||
|
||
var video = post.querySelector("video"); | ||
if (video) { | ||
video.pause(); | ||
video.currentTime = 0; | ||
} | ||
} | ||
|
||
Filter.post_unhide = function(post) { | ||
post.classList.add("filtered") | ||
post.classList.remove("filtered-active"); | ||
|
||
var video = post.querySelector("video"); | ||
if (video) { | ||
video.play(); | ||
} | ||
} | ||
|
||
Filter.initialize_all = function() { | ||
Filter.parse_entries(); | ||
|
||
if (Filter.apply() > 0) { | ||
Filter.update_sidebar(); | ||
Filter.initialize_disable_all_filters(); | ||
} else { | ||
document.getElementById("Filtersleft").style.display = "none"; | ||
} | ||
} | ||
|
||
if (document.getElementById("Filtersleft")) { | ||
Filter.initialize_all(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#filter-list{padding:revert; text-align:left;} | ||
.thumb.filtered{display:unset} | ||
.thumb.filtered.filtered-active{display:none;} | ||
.filter-inactive,.filter-inactive:hover{text-decoration: line-through;} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Shimmie2; | ||
|
||
class FilterTheme extends Themelet | ||
{ | ||
public function addFilterBox(): void | ||
{ | ||
global $config, $page, $user, $user_config; | ||
|
||
// If user is not able to set their own filters, use the default filters. | ||
if ($user->can(Permissions::CHANGE_USER_SETTING)) { | ||
$tags = $user_config->get_string("filter_tags"); | ||
} else { | ||
$tags = $config->get_string("filter_tags"); | ||
} | ||
$html = "<noscript>Post filtering requires JavaScript</noscript> | ||
<ul id='filter-list' class='list-bulleted'></ul> | ||
<a id='disable-all-filters' style='display: none;' href='#'>Disable all</a> | ||
<a id='re-enable-all-filters' style='display: none;' href='#'>Re-enable all</a> | ||
"; | ||
$page->add_html_header("<meta id='filter-tags' tags='$tags'>"); | ||
$page->add_block(new Block("Filters", $html, "left", 10)); | ||
} | ||
} |