// ==UserScript==
// @name Aniscripts
// @namespace http://tampermonkey.net/
// @version 5.35
// @description Change stuff on Anilist.co
// @author hoh
// @match https://anilist.co/*
// @grant GM_xmlhttpRequest
// @license GPLv3
// @downloadURL none
// ==/UserScript==
(function(){
"use strict";
const scriptInfo = {
"version" : "5.35",
"link" : "https://greasyfork.org/en/scripts/370473-aniscripts",
"author" : "hoh",
"authorLink" : "https://anilist.co/user/hoh/",
"license" : "GPLv3"
};
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
*/
/*
"useScripts" contains the defauls for the various modules. This is stored in the user's localStorage.
*/
//a shared style node for all the modules. All classes are prefixed by "hoh" to avoid collisions with native Anilist classes
var style = document.createElement("style");
style.type = "text/css";
//The default colour is rgb(var(--color-blue)) provided by Anilist, but rgb(var(--color-green)) is preferred for things related to manga
style.textContent = `
#hohSettings{
margin-top: 20px;
display: none;
}
.apps + #hohSettings{
display: inline;
}
.hohTime{
position: absolute;
right: 12px;
top: 6px;
font-size: 1.1rem;
}
.hohUnread{
border-right: 8px;
border-color: rgba(var(--color-blue));
border-right-style: solid;
}
.hohNotification{
margin-bottom: 10px;
background: rgb(var(--color-foreground));
border-radius: 4px;
justify-content: space-between;
line-height: 0;
min-height: 72px;
position: relative;
}
.hohNotification *{
line-height: 1.15;
}
.hohUserImageSmall{
display: inline-block;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
position: absolute;
}
.hohUserImage{
height: 72px;
width: 72px;
display: inline-block;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
position: absolute;
}
.hohMediaImage{
height: 70px;
margin-right: 5px;
}
.hohMessageText{
position: absolute;
margin-top: 30px;
margin-left: 80px;
}
.hohMediaImageContainer{
vertical-align: bottom;
margin-left: 400px;
display: inline;
position: relative;
display: inline-block;
min-height: 70px;
width: calc(100% - 500px);
text-align: right;
padding-bottom: 1px;
}
.hohMediaImageContainer > a{
height: 70px;
line-height: 0!important;
display: inline-block;
}
span.hohMediaImageContainer{
line-height: 0!important;
}
.hohCommentsContainer{
margin-top: 5px;
}
.hohCommentsArea{
margin: 10px;
display: none;
padding-bottom: 2px;
margin-top: 5px;
width: 95%;
}
.hohCommentsContainer > a.link{
font-size: 1.3rem;
}
.hohComments{
float: right;
display: none;
margin-top: -21px;
margin-right: 10px;
cursor: pointer;
margin-left: 600px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.hohCombined .hohComments{
display: none!important;
}
.hohQuickCom{
padding: 5px;
background-color: rgb(var(--color-background));
margin-bottom: 5px;
position: relative;
}
.hohQuickComName{
margin-right: 15px;
color: rgb(var(--color-blue));
}
.hohThisIsMe{
color: rgb(var(--color-green));
}
.hohILikeThis{
color: rgb(var(--color-red));
}
.hohQuickComName::after{
content: ":";
}
.hohQuickComContent{
margin-right: 40px;
display: block;
}
.hohQuickComContent > p{
margin: 1px;
}
.hohQuickComLikes{
position: absolute;
right: 5px;
bottom: 5px;
display: inline-block;
}
.hohQuickComContent img {
max-width: 100%;
}
.hohSpoiler::before{
color: rgb(var(--color-blue));
cursor: pointer;
background: rgb(var(--color-background));
border-radius: 3px;
content: "Spoiler, click to view";
font-size: 1.3rem;
padding: 0 5px;
}
.hohSpoiler.hohClicked::before{
display: none;
}
.hohSpoiler > span{
display: none;
}
.hohMessageText > span > div.time{
display: none;
}
.hohUnhandledSpecial > div{
margin-top: -15px;
}
.hohMonospace{
font-family: monospace;
}
.hohSocialTabActivityCompressedContainer{
min-width: 480px;
}
.hohSocialTabActivityCompressedStatus{
vertical-align: middle;
padding-bottom: 7px;
}
.hohSocialTabActivityCompressedName{
vertical-align: middle;
margin-left: 3px;
}
.hohForumHider{
margin-right: 3px;
cursor: pointer;
font-family: monospace;
}
.hohForumHider:hover{
color: rgb(var(--color-blue));
}
.hohBackgroundCover{
height: 70px;
width: 50px;
display: inline-block;
background-repeat: no-repeat;
background-size: cover;
margin-top: 1px;
line-height: 0;
margin-bottom: 1px;
}
#hohDescription{
width: 280px;
height: 150px;
float: left;
color: rgb(var(--color-blue));
}
.hohStatsTrigger{
cursor: pointer;
border-radius: 3px;
color: rgb(var(--color-text-lighter));
display: block;
font-size: 1.4rem;
margin-bottom: 8px;
padding: 5px 10px;
}
.hohActive{
background: rgba(var(--color-foreground),.8);
color: rgb(var(--color-text));
font-weight: 500;
}
#hohFavCount{
position: absolute;
right: 30px;
color: rgba(var(--color-red));
top: 10px;
font-weight: 400;
}
.hohShamelessLink{
display: block;
margin-bottom: 5px;
}
.hohSlidePlayer{
display: block;
position: relative;
width: 500px;
}
.hohSlide{
position: absolute;
top: 0px;
font-size: 500%;
height: 100%;
display: flex;
align-items: center;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
opacity:0.5;
}
.hohSlide:hover{
background-color: rgb(0,0,0,0.4);
cursor: pointer;
opacity:1;
}
.hohRightSlide{
right: 0px;
padding-left: 10px;
padding-right: 20px;
}
.hohLeftSlide{
left: 0px;
padding-left: 20px;
padding-right: 10px;
}
.hohShare{
position: absolute;
right: 12px;
top: 30px;
cursor: pointer;
color: rgb(var(--color-blue-dim));
}
.activity-entry{
position: relative;
}
.hohEmbed{
border-style: solid;
border-color: rgb(var(--color-text));
border-width: 1px;
padding: 15px;
position: relative;
}
.hohEmbed .avatar{
border-radius: 3px;
height: 40px;
width: 40px;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
display: inline-block;
}
.hohEmbed .name{
display: inline-block;
height: 40px;
line-height: 40px;
vertical-align: top;
color: rgb(var(--color-blue));
font-size: 1.4rem;
margin-left: 12px !important;
}
.hohEmbed .time{
color: rgb(var(--color-text-lighter));
font-size: 1.1rem;
position: absolute;
right: 12px;
top: 12px;
}
.hohRecsLabel{
color: rgb(var(--color-blue)) !important;
}
.hohRecsItem{
margin-top: 5px;
margin-bottom: 10px;
}
.hohTaglessLinkException{
display: block;
}
.hohTaglessLinkException::after{
content: ""!important;
}
.hohStatValue{
color: rgb(var(--color-blue));
}
.markdown-editor > [title="Image"],
.markdown-editor > [title="Youtube Video"],
.markdown-editor > [title="WebM Video"]{
color: rgba(var(--color-red));
}
.hohBackgroundUserCover{
height: 50px;
width: 50px;
display: inline-block;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
margin-top: 11px;
margin-bottom: 1px;
}
.history-day.lv-9{
z-index:1!important
}
.hohRegularTag{
border-style: solid;
border-width: 1px;
border-radius: 3px;
padding: 2px;
margin-right: 3px;
}
.hohTableHider{
cursor: pointer;
margin: 4px;
color: rgb(var(--color-blue));
}
.hohCross{
cursor: pointer;
margin-left: 2px;
color: red;
}
.hohFavCountBrowse{
color: white;
position: absolute;
right: 2px;
font-size: 60%;
opacity: 0.7;
}
.hohColourPicker{
position: absolute;
right: 60px;
margin-top: -110px;
}
.hohColourPicker h2{
color: #3db4f2;
font-size: 1.6rem;
font-weight: 400;
padding-bottom: 12px;
}
.hohSecondaryRow{
background-color: rgb(var(--color-background));
}
.hohSecondaryRow:hover{
background-color: rgb(var(--color-foreground));
}
.media-preview-card meter{
width: 150px;
margin-bottom: 5px;
}
.sidebar .tags .tag{
min-height: 35px;
margin-bottom: 5px !important;
}
.custom-lists .el-checkbox__label{
display: inline !important;
white-space: pre-wrap;
white-space: -webkit-pre-wrap;
white-space: normal;
word-wrap: anywhere;
word-break: break-word;
}
.hohStatusDot{
position: absolute;
width: 10px;
height: 10px;
border-radius: 50px;
}
.hohStatusDotRight{
top: 2px;
right: 2px;
}
.studio .container.header{
position: relative;
}
.studio .favourite{
position: absolute;
top: 10px;
right: 30px;
}
.filter .view-all{
background-color: rgb(var(--color-foreground));
height: 32px;
border-radius: 3px;
text-align: center;
padding-top: 8px;
}
.title > a{
line-height: 1.15!important;
}
.embed .title{
line-height: 18px!important;
}
#dubNotice{
font-size: 12px;
font-weight: 500;
text-align: center;
text-transform: capitalize;
background: rgb(var(--color-foreground));
margin-top: 0em;
margin-bottom: 16px;
border-radius: 3px;
padding: 8px 12px;
}
#hohDraw3x3{
margin-top: 5px;
cursor: pointer;
}
.hohDisplayBox{
position: fixed;
top: 80px;
left: 200px;
z-index: 999;
padding: 20px;
background-color: rgb(var(--color-foreground));
}
.hohDisplayBoxClose{
position: absolute;
right: 20px;
top: 20px;
cursor: pointer;
background-color: red;
}
.hohFeedFilter{
position: absolute;
top: 2px;
font-size: 1.4rem;
font-weight: 500;
}
.hohFeedFilter input{
width: 45px;
background: none;
border: none;
margin-left: 6px;
color: rgb(var(--color-text));
}
.hohFeedFilter input::-webkit-outer-spin-button,
.hohFeedFilter input::-webkit-inner-spin-button{
opacity: 1;
}
[list="staffRoles"]::-webkit-calendar-picker-indicator{
display: none;
}
[list="staffRoles"]{
background: rgb(var(--color-foreground));
background: rgb(var(--color-foreground));
padding: 5px;
border-width: 0px;
border-radius: 2px;
margin-left: 20px;
}
.hohFeedFilter button{
color: rgb(var(--color-text));
cursor: pointer;
background: none;
border: none;
margin-left: 10px;
}
.hohFeedFilter button:hover{
color: rgb(var(--color-blue));
}
.actions .list .add{
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.list-wrap .section-name,
.quick-search input[placeholder="Search AniList"]{
text-transform: none;
}
.list-wrap{
counter-reset: animeCounter;
}
.medialist.table.compact .entry .title::before{
counter-increment: animeCounter;
content: counter(animeCounter);
display: inline-block;
margin-right: 4px;
margin-left: -17px;
opacity: 0.2;
text-align: right;
width: 25px;
min-width: 25px;
font-size: 70%;
}
.hohEnumerateStaff{
position: absolute;
margin-left: -12px;
margin-top: 10px;
}
#hohMALscore .type{
font-size: 1.3rem;
font-weight: 500;
padding-bottom: 5px;
}
#hohMALscore .value{
color: rgb(var(--color-text-lighter));
font-size: 1.2rem;
line-height: 1.3;
}
.hohMediaScore{
color: rgb(var(--color-text-lighter));
font-size: 1.2rem;
position: absolute;
top: -10px;
padding-left: 10px;
padding-right: 10px;
margin-left: -10px;
}
.forum-thread .like .button{
margin-right: 0px!important;
}
#hohFilters{
margin-top: 5px;
margin-bottom: 5px;
}
#hohFilters input{
width: 55px;
margin: 5px;
}
.hohCompare{
margin-top: 10px;
counter-reset: animeCounterComp;
position: relative;
}
.hohCompare .hohUserRow,
.hohCompare .hohHeaderRow{
background: rgb(var(--color-foreground));
}
.hohCompare table,
.hohCompare th,
.hohCompare td{
border-top-width: 0px;
border-bottom-width: 1px;
border-right-width: 1px;
border-left-width: 0px;
border-style: solid;
border-color: black;
padding: 5px;
}
.hohCompare table{
background: rgb(var(--color-foreground-grey));
border-spacing: 0px;
margin-top: 10px;
border-right: none;
border-bottom: none;
}
#app{
overflow: unset;
}
.list-stats{
margin-bottom: 0px!important;
}
.activity-feed-wrap,
.activity-feed-wrap + div{
margin-top: 25px;
}
.page-content > .container,
.notifications-feed,
.page-content > .studio{
margin-top: 67px !important;
}
.hohUserRow td,
.hohUserRow th{
min-width: 120px;
border-top-width: 1px;
position: sticky;
top: 3px;
z-index: 1000;
background: rgb(var(--color-foreground));
}
.hohHeaderRow td,
.hohHeaderRow th{
border-top: none;
}
.hohUserRow input{
width: 100px;
}
.hohUserRow img{
width: 30px;
height: 30px;
border-radius: 2px;
}
tr.hohAnimeTable:nth-child(2n+1){
background-color: rgb(var(--color-foreground));
}
.hohAnimeTable,
.hohAnimeTable td{
position: relative;
}
.hohAnimeTable .hohStatusDot{
top: calc(50% - 5px);
right: 5px;
}
.hohHeaderRow .hohStatusDot{
background: rgb(var(--color-background));
top: calc(50% - 5px);
right: 5px;
cursor: pointer;
}
.hohStatusProgress{
position: absolute;
left: 60px;
top: calc(50% - 5px);
font-size: 60%;
}
.hohAnimeTable > td:nth-child(1)::before{
counter-increment: animeCounterComp;
content: counter(animeCounterComp) ". ";
position: absolute;
left: 1px;
text-align: right;
width: 40px;
color: rgb(var(--color-blue));
}
.hohAnimeTable > td:nth-child(1){
padding-left: 43px;
border-left-width: 1px;
}
.hohUserRow > td:nth-child(1),
.hohHeaderRow > th:nth-child(1){
border-left: solid;
border-left-width: 1px;
border-color: black;
}
.hohArrowSort{
font-size: 3rem;
cursor: pointer;
margin-left: 4px;
margin-right: 4px;
}
.hohFilterSort{
cursor: pointer;
border-width: 1px;
border-style: solid;
padding: 2px;
borderRadius: 4px;
}
.hohArrowSort:hover,
.hohFilterSort:hover{
color: rgb(var(--color-blue));
}
.hohAnimeTableRemove{
cursor: pointer;
position: absolute;
top: 0px;
right: 0px;
}
.hohCheckbox.el-checkbox__input > span.el-checkbox__inner{
background-color: rgb(var(--color-foreground));
margin-right:10px;
border-color: rgba(var(--color-text),.2);
}
.hohCheckbox input:checked + .el-checkbox__inner{
background-color: #409eff;
border-color: #409eff;
}
.hohCheckbox input:checked + .el-checkbox__inner::after{
transform: rotate(45deg) scaleY(1);
}
.hohCheckbox input{
display: none;
}
.hohCheckbox{
margin-left: 2px;
}
.media-card .list-status[status="Repeating"]{
background: violet;
}
.sense-wrap{
display: none;
}
.hohDismiss{
cursor: pointer;
transform: translate(20px,-11px);
width: 10px;
height: 5px;
margin-left: -10px;
}
.substitution .media-roles:not(.substitution){
display: none;
}
.hohButton{
align-items: center;
background: #3db4f2;
border-radius: 4px;
color: rgb(var(--color-text-bright));
cursor: pointer;
display: inline-flex;
font-size: 1.3rem;
margin-right: 10px;
margin-top: 15px;
padding: 10px 15px;
transition: .2s;
border-width: 0px;
}
.user-social .title::before{
font-size: 1.6rem;
}
textarea{
background: rgb(var(--color-foreground));
}
select{
background: rgb(var(--color-foreground));
padding: 5px;
border-radius: 4px;
border-width: 0px;
margin: 4px;
color: rgb(var(--color-text));
}
.hohPostLink{
position: absolute;
top: 30px;
}
.hohBlock{
padding: 4px;
border-width: 1px;
border-style: solid;
border-radius: 5px;
margin: 2px;
}
.hohBlockSpec{
padding-right: 15px;
}
.hohBlockCross{
padding: 5px;
color: red;
cursor: pointer;
}
.medialist .filters .filter-group:first-child > span{
position: relative;
}
.medialist .filters .filter-group:first-child > span .count{
position: absolute;
right: 0px;
}
.like-wrap .users{
overflow-y: scroll!important;
scrollbar-width: none;
-ms-overflow-style: none;
}
.like-wrap .users::-webkit-scrollbar{
width: 0px;
background: transparent;
}
.categories .category{
text-transform: none;
white-space: nowrap;
}
.media-preview-card .hohFallback{
position: absolute;
top: 5px;
left: 5px;
word-break: break-word;
overflow-y: hidden;
max-height: 110px;
max-width: 77px;
}
.media-preview-card .cover{
z-index: 3;
}
.hohChangeScore{
font-family: monospace;
cursor: pointer;
display: none;
}
.row:hover .hohChangeScore,
.hohMediaScore:hover .hohChangeScore{
display: inline;
}
.activity-text .name[href="/user/Dunkan85/"]::after{
background-image: url(https://upload.wikimedia.org/wikipedia/commons/e/e4/Twitter_Verified_Badge.svg);
background-size: 12px;
display: inline-block;
width: 12px;
height: 12px;
content: "";
margin-left: 5px;
}
@media(max-width: 760px){
#hohMALscore{
padding-right: 25px;
}
#hohMALscore .type{
font-weight: 400;
}
#hohMALscore .value{
color: rgb(var(--color-text));
font-size: 1.4rem;
}
.hohMediaImageContainer{
position: absolute;
right: -22px;
max-height: 30px;
width: 25px;
overflow: scroll;
}
.hohBackgroundUserCover{
margin-top: 1px;
}
.hohMediaImageContainer > a{
height: 20px;
}
.hohMediaImage{
height: 20px;
width: 20px;
margin-right: 0px
}
.hohNotification{
margin-right: 23px;
font-size: 1.5rem;
}
.hohCommentsContainer{
position: relative;
top: 70px;
}
.hohComments{
position: absolute;
right: -5px;
top: 5px;
}
.notifications-feed .filters p{
display: inline;
margin-left: 10px;
}
.activity-feed .actions{
font-size: 1.6rem;
}
}
`;
let documentHead = document.querySelector("head");
if(documentHead){
documentHead.appendChild(style);
}
else{
return;//xml documents or something. At least it's not a place where the script can run
}
try{
localStorage.setItem("test","test");
localStorage.removeItem("test");
}
catch(e){
alert("Error: LocalStorage not available.");
console.log("LocalStorage, required for saving settings, is not available. Terminating Aniscripts.");
return;
}
const notificationColourDefaults = {
"ACTIVITY_LIKE":{"colour":"rgb(250,122,122)","supress":false},
"ACTIVITY_REPLY_LIKE":{"colour":"rgb(250,122,122)","supress":false},
"THREAD_COMMENT_LIKE":{"colour":"rgb(250,122,122)","supress":false},
"THREAD_LIKE":{"colour":"rgb(250,122,122)","supress":false},
"THREAD_COMMENT_REPLY":{"colour":"rgb(61,180,242)","supress":false},
"ACTIVITY_REPLY":{"colour":"rgb(61,180,242)","supress":false},
"ACTIVITY_MESSAGE":{"colour":"rgb(123,213,85)","supress":false},
"FOLLOWING":{"colour":"rgb(123,213,85)","supress":false},
"ACTIVITY_MENTION":{"colour":"rgb(123,213,85)","supress":false},
"THREAD_COMMENT_MENTION":{"colour":"rgb(123,213,85)","supress":false},
"THREAD_SUBSCRIBED":{"colour":"rgb(247,191,99)","supress":false},
"AIRING":{"colour":"rgb(247,191,99)","supress":false}
};
let useScripts = {//most modules are turned on by default
notifications: true,
socialTab: true,
forumComments: true,
forumMedia: true,
staffPages: true,
tagDescriptions: true,
completedScore: true,
droppedScore: false,
moreStats: true,
characterFavouriteCount: true,
studioFavouriteCount: true,
CSSfavs: true,
CSScompactBrowse: true,
CSSmangaGreen: false,
CSSfollowCounter: true,
CSSsubmissionCounter: false,
CSSprofileClutter: false,
CSSdecimalPoint: false,
CSSverticalNav: false,
CSSbannerShadow: true,
hideLikes: false,
dubMarker: false,
CSSstudioStats: true,
CSSsmileyScore: true,
CSSexpandFeedFilters: false,
feedCommentFilter: false,
feedCommentComments: 0,
feedCommentLikes: 0,
colourPicker: true,
colourSettings: [],
mangaBrowse: false,
progressBar: false,
noRewatches: false,
hideCustomTags: false,
shortRomaji: false,
replaceNativeTags: true,
draw3x3: true,
limitProgress8: false,
limitProgress10: false,
tagIndex: true,
ALbuttonReload: true,
expandRight: false,
timeToCompleteColumn: false,
mangaGuess: true,
replaceStaffRoles: true,
settingsTip: true,
enumerateSubmissionStaff: true,
MALscore: false,
mobileFriendly: false,
entryScore: true,
activityTimeline: true,
browseFilters: true,
embedHentai: false,
comparissionPage: true,
noImagePolyfill: false,
reviewConfidence: true,
blockWord: false,
dropdownOnHover: false,
showMarkdown: true,
blockWordValue: "nsfw",
databaseStats: {//default numbers
"anime": 12895,
"manga": 45103,
"users": 273172,
"staff": 28296,
"characters": 71083,
"reviews": 2235,
"updated": 0
},
notificationColours: notificationColourDefaults,
staffRoleOrder: "alphabetical",
titleLanguage: "Romaji",
dubMarkerLanguage: "English",
accessToken: "",
};
let forceRebuildFlag = false;
useScripts.save = function(){
localStorage.setItem("hohSettings",JSON.stringify(useScripts));
};
const useScriptsSettings = JSON.parse(localStorage.getItem("hohSettings"));
if(useScriptsSettings){
let keys = Object.keys(useScriptsSettings);
keys.forEach(function(key){//this is to keep the default settings if the version in local storage is outdated
useScripts[key] = useScriptsSettings[key];
});
}
useScripts.save();
let whoAmI = "";
let whoAmIid = 0;
//replace with query selector?
try{//use later for some scripts
whoAmI = document.getElementById("nav").children[1].children[1].children[1].href.match(/[\w\-]*\/$/)[0].slice(0,-1);//looks at the nav
}
catch(err){
try{
whoAmI = document.querySelector(".menu [href^='/user/']").href.match(/\/user\/(.*)\//)[1];
}
catch(err2){
console.log("could not get username");
}
}
function safeURL(URL){
return encodeURIComponent(URL.replace(/\s|\//g,"-").replace(/(\.|\)|\\|#)/g,""));
}
Number.prototype.roundPlaces = function(places){
return +(
Math.round(
this * Math.pow(10,places)
) / Math.pow(10,places)
);
}
String.prototype.capitalize = function(){
return this.charAt(0).toUpperCase() + this.slice(1);
}
let VALUE = ((a,b) => a - b);//Used for storting functions
let VALUE_DESC = ((b,a) => a - b);
let TRUTHY = (a => a);//filtering
function create(type,classes,text,appendLocation,cssText){
let element = document.createElement(type);
if(Array.isArray(classes)){
element.classList.add(...classes);
}
else if(classes){
if(classes[0] === "#"){
element.id = classes.substring(1);
}
else{
element.classList.add(classes);
}
};
if(text || text === 0){
element.innerText = text;
};
if(appendLocation){
appendLocation.appendChild(element);
};
if(cssText){
element.style.cssText = cssText;
};
return element;
};
function createCheckbox(target){
let hohCheckbox = create("label",["hohCheckbox","el-checkbox__input"],false,target);
let checkbox = create("input",false,false,hohCheckbox);
checkbox.type = "checkbox";
create("span","el-checkbox__inner",false,hohCheckbox);
return checkbox;
}
const svgAssets = {
envelope : "✉",
cross : "✕",
frown : `
`,
meh : `
`,
smile : `
`,
star : `
`,
//the column sorting arrow
angleDown : `
`,
view : `
`,
reply : `
`,
repeat : `
`,
external : `
`
};
const distributionColours = {
"COMPLETED" : "rgb(104, 214, 57)",
"CURRENT" : "rgb( 2, 169, 255)",
"PAUSED" : "rgb(247, 121, 164)",
"DROPPED" : "rgb(232, 93, 117)",
"PLANNING" : "rgb(247, 154, 99)",
"REPEATING" : "violet"
};
const distributionFormats = {
"TV" : "TV",
"TV_SHORT" : "TV Short",
"MOVIE" : "Movie",
"SPECIAL" : "Special",
"OVA" : "OVA",
"ONA" : "ONA",
"MUSIC" : "Music",
"MANGA" : "Manga",
"NOVEL" : "Light Novel",
"ONE_SHOT" : "One Shot"
};
const distributionStatus = {
"FINISHED" : "Finished",
"RELEASING" : "Releasing",
"NOT_YET_RELEASED" : "Not Yet Released",
"CANCELLED" : "Cancelled"
};
if(useScripts.mangaBrowse){
const navLinks = document.querySelector(".links");
for(var i=0;i .wrap > .footer > .container");
if(colourPickerLocation){
const supportedColours = [
"--color-background",
"--color-foreground",
"--color-foreground-grey",
"--color-foreground-grey-dark",
"--color-foreground-blue",
"--color-foreground-blue-dark",
"--color-background-blue-dark",
"--color-overlay",
"--color-shadow",
"--color-shadow-dark",
"--color-text",
"--color-text-light",
"--color-text-lighter",
"--color-text-bright",
"--color-blue",
"--color-blue-dim",
"--color-white",
"--color-black",
"--color-red",
"--color-peach",
"--color-orange",
"--color-yellow",
"--color-green"
];
let colourChanger = function(){
for(var i=0;i a${dataSelect}
,a.title${dataSelect}
,.overlay > a.title${dataSelect}
,.media-preview-card a.title${dataSelect}
,.quick-search-results .el-select-dropdown__item a${dataSelect}> span
,.media-embed${dataSelect} .title
,.status > a.title${dataSelect}
,.role-card a.content${dataSelect} > .name{
visibility: hidden;
font-size: 2%;
line-height: 0px;
}
a.title${dataSelect}::before
,.quick-search-results .el-select-dropdown__item a${dataSelect} > span::before
,.role-card a.content${dataSelect} > .name::before
,.title > a${dataSelect}::before
,.home .status > a.title${dataSelect}::before
,.media-embed${dataSelect} .title::before
,.overlay > a.title${dataSelect}::before
,.media-preview-card a.title${dataSelect}::before{
content:"${targetName}"
}`;
}
}
const shortRomaji = [
["/anime/30/","Evangelion"],
["/anime/32/","End of Evangelion"],
["/anime/5114/","FMA:B"],
["/anime/10620/","Mirai Nikki"],
["/anime/1575/","Code Geass"],
["/anime/2904/","Code Geass R2"],
["/anime/21355/","Re:Zero"],
["/anime/2001/","Gurren Lagann"],
["/anime/21202/","Konosuba!"],
["/anime/21699/","Konosuba! 2"],
["/anime/21574/","Konosuba!: Kono Subarashii Choker ni Shufuku wo!"],
["/anime/9756/","Madoka★Magica"],
["/anime/9989/","AnoHana"],
["/anime/20623/","Kiseijuu"],
["/anime/14741/","Chuunibyou!"],
["/anime/18671/","Chuunibyou! 2"],
["/anime/14813/","OreGairu"],
["/anime/20920/","Danmachi"],
["/anime/8074/","HIGHSCHOOL OF THE DEAD"],
["/anime/849/","Haruhi"],
["/anime/4382/","Haruhi (2009)"],
["/anime/19603/","Unlimited Blade Works"],
["/anime/20792/","Unlimited Blade Works 2"],
["/anime/8769/","OreImo"],
["/anime/10020/","OreImo Specials"],
["/anime/13659/","OreImo 2"],
["/anime/18857/","OreImo 2 Specials"],
["/anime/2025/","Darker than BLACK"],
["/anime/20698/","OreGairu 2"],
["/anime/16592/","Danganronpa"],
["/anime/16742/","WataMote"],
["/anime/101291/","Bunny Girl-senpai"],
["/anime/104157/","Bunny Girl-senpai Movie"],
["/anime/19221/","NouKome"],
["/anime/45/","Rurouni Kenshin"],
["/anime/8795/","Panty & Stocking"],
["/anime/21860/","Sukasuka"],
["/anime/33/","Berserk"],
["/anime/97938/","Boruto"],
["/anime/97907/","Death March"],
["/anime/100183/","Gun Gale Online"],
["/anime/20474/","JoJo: Stardust Crusaders"],
["/anime/20799/","JoJo: Stardust Crusaders - Egypt-hen"],
["/anime/21450/","JoJo: Diamond wa Kudakenai"],
["/anime/102883/","JoJo: Ougon no Kaze"],
["/anime/101921/","Kaguya-sama wa Kokuraseta"],
["/anime/101166/","Danmachi: Orion no Ya"],
["/anime/20791/","Heaven’s Feel I. presage flower"],
["/anime/21718/","Heaven’s Feel II. lost butterfly"],
["/anime/21719/","Heaven’s Feel III. spring song"],
["/anime/1089/","Macross: Ai Oboete Imasu ka"],
["/anime/572/","Nausicaä"],
["/anime/513/","Laputa"],
["/anime/44/","Rurouni Kenshin: Tsuioku-hen"],
["/anime/528/","Mewtwo no Gyakushuu"],
["/anime/530/","Sailor Moon"],
["/anime/740/","Sailor Moon R"],
["/anime/532/","Sailor Moon S"],
["/anime/1239/","Sailor Moon SuperS"],
["/anime/996/","Sailor Moon Sailor Stars"],
["/anime/949/","Gunbuster!"],
["/anime/18677/","Yuushibu"],
["/manga/86635/","Kaguya-sama wa Kokurasetai"],
["/anime/17074/","Monogatari Second Season"],
["/anime/20910/","Shimoseka"]
];
let aliasFlag = false;
if(useScripts.shortRomaji){
shortRomaji.forEach(createAlias);
aliasFlag = true;
}
const titleAliases = JSON.parse(localStorage.getItem("titleAliases"));
if(titleAliases){
aliasFlag = true;
titleAliases.forEach(createAlias);
}
if(aliasFlag){
moreStyle.textContent += `
a.title::before
,.quick-search-results .el-select-dropdown__item a > span::before{
visibility: visible;
font-size: 5000%;
line-height: 1.15;
margin-right: 2px;
}
.medialist.table .title > a::before{
visibility: visible;
font-size: 1.5rem;
margin-right: 2px;
}
.medialist.compact .title > a::before
,.medialist.cards .title > a::before
,.home .status > a.title::before
,.media-embed .title::before{
visibility: visible;
font-size: 1.3rem;
margin-right: 2px;
}
.role-card a.content > .name::before{
visibility: visible;
font-size: 1.2rem;
}
.overlay > a.title::before
,.media-preview-card a.title::before{
visibility: visible;
font-size: 1.4rem;
line-height: 1.15;
}
.role-card a.content > .name{
line-height: 1.3!important;
}`;
}
if(useScripts.CSSfavs || useScripts.CSSstudioStats){
/*adds a logo to most favourite studio entries. Add more if needed */
const favStudios = [
[1, "Studio-Pierrot", "https://upload.wikimedia.org/wikipedia/en/thumb/1/10/Studio_Pierrot.jpg/220px-Studio_Pierrot.jpg","studio"],
[2, "Kyoto-Animation","https://upload.wikimedia.org/wikipedia/en/thumb/b/bf/Kyoto_Animation_logo.svg/250px-Kyoto_Animation_logo.svg.png","studio"],
[3, "GONZO", "https://upload.wikimedia.org/wikipedia/commons/thumb/8/85/Gonzo_company.png/220px-Gonzo_company.png","studio"],
[4, "BONES", "https://i.stack.imgur.com/7pRQn.png","studio"],
[5, "Bee-Train", "https://upload.wikimedia.org/wikipedia/commons/4/45/Bee_Train.svg","studio"],
[6, "Gainax", "https://upload.wikimedia.org/wikipedia/en/thumb/a/a8/Gainax_logo.svg/220px-Gainax_logo.svg.png","studio"],
[7, "JC-Staff", "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/J.C.Staff_Logo.svg/220px-J.C.Staff_Logo.svg.png","studio"],
[8, "Artland", "https://upload.wikimedia.org/wikipedia/en/thumb/a/ae/Artland_logo.gif/200px-Artland_logo.gif","studio"],
[10, "Production-IG", "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Production_I.G_Logo.svg/250px-Production_I.G_Logo.svg.png","studio"],
[11, "MADHOUSE", "https://upload.wikimedia.org/wikipedia/commons/thumb/4/44/Madhouse_studio_logo.svg/300px-Madhouse_studio_logo.svg.png","studio"],
[13, "Studio-4C", "https://upload.wikimedia.org/wikipedia/en/e/ec/Studio_4C_logo.png","studio"],
[14, "Sunrise", "https://upload.wikimedia.org/wikipedia/en/thumb/8/8c/Sunrise_company_logo.svg/220px-Sunrise_company_logo.svg.png","studio"],
[17, "Aniplex", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/37/Aniplex_logo.svg/220px-Aniplex_logo.svg.png",""],
[18, "Toei-Animation", "https://i.stack.imgur.com/AjzVI.png","studio",76,30],
[21, "Studio-Ghibli", "https://upload.wikimedia.org/wikipedia/en/thumb/c/ca/Studio_Ghibli_logo.svg/220px-Studio_Ghibli_logo.svg.png","studio",76,30],
[22, "Nippon-Animation","https://upload.wikimedia.org/wikipedia/en/thumb/b/b4/Nippon.png/200px-Nippon.png","studio"],
[25, "Milky-Animation-Label","https://img.fireden.net/a/image/1467/16/1467164781976.png","studio"],
[27, "Xebec", "https://upload.wikimedia.org/wikipedia/fr/b/bd/Logo_Xebec.svg","studio"],
[28, "Oriental-Light-and-Magic","https://i.stack.imgur.com/Sbllv.png","studio"],
[32, "Manglobe", "https://i.imgur.com/W8U74wO.png","studio"],
[34, "Hal-Film-Maker", "https://upload.wikimedia.org/wikipedia/commons/thumb/0/09/Hal_film_maker_logo.gif/220px-Hal_film_maker_logo.gif","studio"],
[35, "Seven-Arcs", "https://upload.wikimedia.org/wikipedia/en/a/ac/Seven_Arcs_logo.png","studio",76,25],
[36, "Studio-Gallop", "https://upload.wikimedia.org/wikipedia/commons/3/37/Studio_Gallop.png","studio"],
[37, "Studio-DEEN", "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/Studio_Deen_logo.svg/220px-Studio_Deen_logo.svg.png","studio"],
[38, "Arms", "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f4/Arms_Corporation.png/200px-Arms_Corporation.png","studio"],
[41, "Satelight", "https://i.stack.imgur.com/qZVQg.png","studio",76,30],
[43, "ufotable", "https://upload.wikimedia.org/wikipedia/en/5/56/Ufotable-Logo.png","studio",76,30],
[44, "Shaft", "https://i.stack.imgur.com/tuqhK.png","studio"],
[45, "Pink-Pineapple", "https://i.stack.imgur.com/2NMQ0.png","studio"],
[47, "Studio-Khara", "https://i.stack.imgur.com/2d1TT.png","studio",76,30],
[48, "AIC", "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6b/AIC_logo.png/220px-AIC_logo.png","studio"],
[51, "diomeda", "https://i.stack.imgur.com/ZHt3T.jpg","studio"],
[53, "Dentsu", "https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Dentsu_logo.svg/200px-Dentsu_logo.svg.png",""],
[58, "Square-Enix", "https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Square_Enix_logo.svg/230px-Square_Enix_logo.svg.png",""],
[65, "Tokyo-Movie-Shinsha","https://upload.wikimedia.org/wikipedia/en/2/22/Tokyo_Movie_Shinsha.png","studio"],
[66, "Key", "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Key_Visual_Arts_Logo.svg/167px-Key_Visual_Arts_Logo.svg.png","",76,25],
[68, "Mushi-Productions","https://i.stack.imgur.com/HmYdT.jpg","studio"],
[73, "TMS-Entertainment","https://upload.wikimedia.org/wikipedia/commons/thumb/b/b9/TMS_Entertainment_logo.svg/220px-TMS_Entertainment_logo.svg.png","studio"],
[79, "Genco", "https://www.thefilmcatalogue.com/assets/company-logos/5644/logo_en.png",""],
[86, "Group-TAC", "https://upload.wikimedia.org/wikipedia/commons/b/b7/Group_TAC.png","studio"],
[91, "feel", "https://upload.wikimedia.org/wikipedia/en/thumb/0/07/Feel_%28company%29_logo.png/220px-Feel_%28company%29_logo.png","studio",76,25],
[95, "Doga-Kobo", "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Doga_Kobo_Logo.svg/220px-Doga_Kobo_Logo.svg.png","studio"],
[97, "ADV-Films", "https://upload.wikimedia.org/wikipedia/en/4/45/A.D._Vision_%28logo%29.png","licensor"],
[102, "FUNimation-Entertainment","https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/Funimation_2016.svg/320px-Funimation_2016.svg.png","licensor"],
[103, "Tatsunoko-Production","https://upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Tatsunoko_2016_logo.png/300px-Tatsunoko_2016_logo.png","studio"],
[104, "Lantis", "https://upload.wikimedia.org/wikipedia/commons/3/39/Lantis_logo.png",""],
[108, "Media-Factory", "https://i.stack.imgur.com/rR7yU.png","",76,25],
[112, "Brains-Base", "https://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Brain%27s_Base_logo.png/200px-Brain%27s_Base_logo.png","studio"],
[113, "Kadokawa-Shoten","https://i.stack.imgur.com/ZsUDR.gif",""],
[119, "Viz-Media", "https://upload.wikimedia.org/wikipedia/en/thumb/e/e9/Viz_Media_logo.png/220px-Viz_Media_logo.png","licensor"],
[132, "PA-Works", "https://i.stack.imgur.com/7kjSn.png","studio"],
[143, "Mainichi-Broadcasting","https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Mainichi_Broadcasting_System_logo.svg/200px-Mainichi_Broadcasting_System_logo.svg.png",""],
[144, "Pony-Canyon", "https://i.stack.imgur.com/9kkew.png",""],
[145, "TBS", "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/TBS_logo.svg/200px-TBS_logo.svg.png",""],
[150, "Sanrio", "https://upload.wikimedia.org/wikipedia/en/thumb/4/41/Sanrio_logo.svg/220px-Sanrio_logo.svg.png",""],
[159, "Kodansha", "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Kodansha.png/200px-Kodansha.png",""],
[166, "Movic", "https://upload.wikimedia.org/wikipedia/commons/f/f3/Movic_logo.png",""],
[167, "Sega", "https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Sega_logo.svg/200px-Sega_logo.svg.png",""],
[169, "Fuji-TV", "https://upload.wikimedia.org/wikipedia/en/thumb/e/e9/Fuji_TV_logo.svg/225px-Fuji_TV_logo.svg.png","",76,30],
[193, "Idea-Factory", "https://upload.wikimedia.org/wikipedia/en/e/eb/Idea_factory.gif",""],
[196, "Production-Reed","https://upload.wikimedia.org/wikipedia/fr/7/7d/Production_Reed_Logo.png","studio"],
[199, "Studio-Nue", "https://i.stack.imgur.com/azzKH.png","studio"],
[200, "Tezuka-Productions","https://upload.wikimedia.org/wikipedia/fr/f/fe/Tezuka_Productions_Logo.png","studio"],
[217, "The-Right-Stuf-International","","licensor"],
[238, "ATX", "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c6/AT-X_logo.svg/150px-AT-X_logo.svg.png","",76,30],
[247, "ShinEi-Animation","https://i.stack.imgur.com/b2lcL.png","studio"],
[250, "Media-Blasters", "","licensor"],
[262, "Kadokawa-Pictures-USA","https://i.stack.imgur.com/ZsUDR.gif",""],
[284, "Central-Park-Media","","licensor"],
[287, "David-Production","https://upload.wikimedia.org/wikipedia/en/thumb/7/75/David_production.jpg/220px-David_production.jpg","studio",76,30],
[290, "Kinema-Citrus", "https://upload.wikimedia.org/wikipedia/commons/c/c0/Kinema_Citrus_logo.png","studio",76,25],
[291, "CoMix-Wave", "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Cwflogo.png/150px-Cwflogo.png","studio"],
[292, "AIC-Plus", "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6b/AIC_logo.png/220px-AIC_logo.png","studio"],
[300, "SILVER-LINK", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Silver_Link_Logo.svg/220px-Silver_Link_Logo.svg.png","studio"],
[309, "GoHands", "https://i.stack.imgur.com/pScIZ.jpg","studio"],
[314, "White-Fox", "https://i.stack.imgur.com/lwG1T.png","studio",76,30],
[333, "TYO-Animations", "https://i.stack.imgur.com/KRqAp.jpg","studio",76,25],
[334, "Ordet", "https://i.stack.imgur.com/evr12.png","studio",76,30],
[346, "Hoods-Entertainment","https://i.stack.imgur.com/p7S0I.png","studio"],
[352, "Kadokawa-Pictures-Japan","https://i.stack.imgur.com/ZsUDR.gif",""],
[365, "PoRO", "https://i.stack.imgur.com/3rlAh.png","studio"],
[372, "NIS-America-Inc","https://upload.wikimedia.org/wikipedia/en/e/e7/Nis.png","licensor"],
[376, "Sentai-Filmworks","https://i.stack.imgur.com/JV8R6.png","licensor",74,30],
[397, "Bridge", "https://i.imgur.com/4Qn4EmK.png","studio"],
[415, "Warner-Bros", "","licensor"],
[417, "Walt-Disney-Studios","","licensor"],
[418, "Studio-Gokumi", "https://i.stack.imgur.com/w1y22.png","studio"],
[436, "AIC-Build", "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6b/AIC_logo.png/220px-AIC_logo.png","studio"],
[437, "Kamikaze-Douga", "https://img7.anidb.net/pics/anime/178777.jpg",""],
[456, "Lerche", "https://i.stack.imgur.com/gRQPc.png","studio"],
[459, "Nitroplus", "https://upload.wikimedia.org/wikipedia/en/thumb/0/09/Nitroplus_logo.png/220px-Nitroplus_logo.png",""],
[467, "Discotek", "","licensor"],
[493, "Aniplex-of-America", "https://upload.wikimedia.org/wikipedia/commons/thumb/3/37/Aniplex_logo.svg/220px-Aniplex_logo.svg.png","licensor"],
[499, "The-Pokemon-Company-International","","licensor"],
[503, "Nintendo-Co-Ltd","https://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Nintendo.svg/220px-Nintendo.svg.png",""],
[537, "SANZIGEN", "https://i.stack.imgur.com/CkuqH.png","",76,30],
[541, "Seven", "","studio"],
[555, "Studio-Chizu", "https://i.stack.imgur.com/h2RuH.gif","studio"],
[561, "A1-Pictures", "https://i.stack.imgur.com/nBUYo.png","studio",76,30],
[569, "MAPPA", "https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/MAPPA_Logo.svg/220px-MAPPA_Logo.svg.png","studio"],
[681, "ASCII-Media-Works","https://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/ASCII_Media_Works_logo.svg/220px-ASCII_Media_Works_logo.svg.png",""],
[803, "Trigger", "https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Trigger_Logo.svg/220px-Trigger_Logo.svg.png","studio"],
[783, "GKids", "https://upload.wikimedia.org/wikipedia/commons/thumb/c/ca/GKIDS_logo.svg/150px-GKIDS_logo.svg.png","licensor"],
[829, "Studio-Jack", "","studio"],
[839, "LIDENFILMS", "https://upload.wikimedia.org/wikipedia/en/6/6e/LidenFilms.png","studio",76,30],
[858, "Wit-Studio", "https://i.stack.imgur.com/o3Rro.png","studio",76,30],
[911, "Passione", "https://i.stack.imgur.com/YyEGg.jpg","studio"],
[2524,"4Kids-Entertainment","","licensor"],
[4418,"8bit", "https://upload.wikimedia.org/wikipedia/en/e/ea/8-Bit_Animation_Studio.png","studio"],
[6069,"Studio-3Hz", "https://i.stack.imgur.com/eD0oe.jpg","studio"],
[6071,"Studio-Shuka", "https://upload.wikimedia.org/wikipedia/commons/f/fa/Shuka_studio.jpg","studio"],
[6077,"Orange", "https://i.stack.imgur.com/ve9mm.gif","studio"],
[6142,"Geno-Studio", "https://upload.wikimedia.org/wikipedia/en/thumb/f/f4/Genostudio.jpg/220px-Genostudio.jpg","",76,25],
[6145,"Science-SARU", "https://i.stack.imgur.com/zo9Fx.png","studio"],
[6222,"CloverWorks", "https://i.stack.imgur.com/9Fvr7.jpg","studio"],
[6225,"TriF-studio", "https://i.stack.imgur.com/lL85s.png","studio",60,50],
[6235,"SEK-Studio", "https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Flag_of_North_Korea.svg/125px-Flag_of_North_Korea.svg.png","studio",74,25]
];
let favStudioString = "";
if(useScripts.CSSfavs){
favStudioString += `
.favourites > div > .wrap > div,
.favourites > div > .wrap > a{
/*make the spaces in the grid even*/
margin-bottom: 0px!important;
margin-right: 0px!important;
column-gap: 10px!important;
}
.user .overview{
grid-template-columns: 460px auto!important;
}
.favourites > div > .wrap{
padding: 0px!important;
display: grid;
grid-gap: 10px;
column-gap: 10px!important;
grid-template-columns: repeat(auto-fill,85px);
grid-template-rows: repeat(auto-fill,115px);
background: rgb(0,0,0,0) !important;
width: 470px;
}
.favourite.studio{
cursor: pointer;
min-height: 115px;
font-size: 15px;
display: grid;
grid-gap: 10px;
padding: 2px!important;
padding-top: 8px!important;
background-color: rgba(var(--color-foreground))!important;
text-align: center;
align-content: center;
}
.site-theme-dark .favourite.studio{
background-color: rgb(49,56,68)!important;
}
.favourite.studio::after{
display: inline-block;
background-repeat: no-repeat;
content:"";
margin-left:5px;
background-size: 76px 19px;
width: 76px;
height: 19px;
}`;
favStudios.forEach(function(studio){
if(studio[2] !== ""){
favStudioString += `.favourite.studio[href="/studio/${studio[0]}/${studio[1]}"]::after{background-image: url("${studio[2]}");`;
if(studio.length === 6){
favStudioString += `background-size: ${studio[4]}px ${studio[5]}px;width: ${studio[4]}px;height: ${studio[5]}px;`;
}
favStudioString += "}";
}
});
}
if(useScripts.CSSstudioStats){
favStudios.forEach(function(studio){
if(studio[3] === "studio"){
favStudioString += `.stats-wrap .row a[href="/studio/${studio[0]}/${studio[1]}"],`;
}
});
favStudioString = favStudioString.replace(/,$/,"");
favStudioString += "{color:rgb(var(--color-blue))}";
favStudios.forEach(function(studio){
if(studio[3] === "licensor"){
favStudioString += `.stats-wrap .row a[href="/studio/${studio[0]}/${studio[1]}"],`;
}
});
favStudioString = favStudioString.replace(/,$/,"");
favStudioString += "{color:rgb(var(--color-green))}";
}
moreStyle.textContent += favStudioString;
}
if(useScripts.CSScompactBrowse){
moreStyle.textContent += `
.search-page-unscoped.container{
padding-left: 10px;
padding-right: 0px;
}
.search-page-unscoped .description{
display: none;
}
.search-page-unscoped .preview-section,
.search-page-unscoped,
.results > .studio{
counter-reset: ranking;
}
.search-page-unscoped .character,
.search-page-unscoped .staff{
position: relative;
}
.search-page-unscoped .data::before,
.search-page-unscoped .results > .character .cover::before,
.search-page-unscoped .results > .staff .cover::before{
left: 2px;
opacity: 0.4;
font-size: 70%;
position: absolute;
counter-increment: ranking;
content: counter(ranking);
}
.search-page-unscoped .media-card{
min-width: 150px!important;
grid-template-columns: 150px auto!important;
height: 297px!important;
width: 150px !important;
}
.search-page-unscoped .cover .overlay{
padding-left: 8px!important;
padding-right: 8px!important;
padding-top: 4px!important;
padding-bottom: 14px!important;
}
.search-page-unscoped .grid-wrap > .media-card{
margin-left: 30px;
}
.search-page-unscoped .media-card .cover{
width: 150px;
height: 215px;
margin-top: 53px;
z-index: 100;
}
.search-page-unscoped .data{
margin-left: -150px;
}
.search-page-unscoped .genres{
min-height:29px;
z-index: 101;
padding: 8px 5px!important;
padding-bottom: 2px !important;
font-size: 1rem!important;
line-height: 1.15;
}
.search-page-unscoped .list-edit{
z-index: 101;
}
.search-page-unscoped .airing-countdown{
padding: 5px!important;
}
.search-page-unscoped .grid-wrap{
grid-template-columns: repeat(auto-fill, 150px) !important;
}
.search-page-unscoped .media{
grid-template-columns: repeat(auto-fill, 150px) !important;
width:100%;
}
.search-page-unscoped .overlay .studio{
margin-top: 2px!important;
margin-bottom: -8px!important;
}
.search-page-unscoped .list-status{
width: 20px!important;
height: 20px!important;
}
.search-page-unscoped .media-card:nth-child(5){
display: inline-grid!important;
}
`;
}
if(useScripts.CSSsubmissionCounter){
moreStyle.textContent += `
.submissions-wrap{
counter-reset: acceptedCount partialCount pendingCount rejectedCount;
}
.submissions-wrap .submission .status.accepted{
counter-increment: acceptedCount;
}
.submissions-wrap .submission .status.accepted::after{
content: counter(acceptedCount);
}
.submissions-wrap .submission .status.pending{
counter-increment: pendingCount;
}
.submissions-wrap .submission .status.pending::after{
content: counter(pendingCount);
}
.submissions-wrap .submission .status.partially_accepted{
counter-increment: partialCount;
}
.submissions-wrap .submission .status.partially_accepted::after{
content: counter(partialCount);
}
.submissions-wrap .submission .status.rejected{
counter-increment: rejectedCount;
}
.submissions-wrap .submission .status.rejected::after{
content: counter(rejectedCount);
}
.submissions-wrap::after{
content: "pending: " counter(pendingCount) ", accepted: " counter(acceptedCount) ", partially accepted: " counter(partialCount) ", rejected: " counter(rejectedCount);
}
`;
}
if(useScripts.CSSprofileClutter){
moreStyle.textContent += `
.overview .list-stats > .footer{
display: none;
}
.overview > .section > .desktop:nth-child(2){
display: none;
}
.overview > .section > .desktop:nth-child(3){
display: none;
}
.overview > .section > .desktop.favourites{
display: inherit;
}
`;
}
if(useScripts.CSSbannerShadow){
moreStyle.textContent += `
.banner .shadow{
display: none;
}
`;
}
if(useScripts.CSSgreenManga){
moreStyle.textContent += `
.activity-manga_list > div > div > div > div > .title{
color: rgba(var(--color-green))!important;
}
.media .relations .cover[href^="/manga/"] + div div{
color: rgba(var(--color-green));
}
.media .relations .cover[href^="/anime/"] + div div{
color: rgba(var(--color-blue));
}
.media .relations .cover[href^="/manga/"]{
border-bottom-style: solid;
border-bottom-color: rgba(var(--color-green));
border-bottom-width: 2px;
}
.media .relations.small .cover[href^="/manga/"]::after{
position:absolute;
left:1px;
bottom:3px;
content:"";
border-style: solid;
border-color: rgba(var(--color-green));
border-width: 2px;
}
.media .relations .cover[href^="/anime/"]{
border-bottom-style: solid;
border-bottom-color: rgba(var(--color-blue));
border-bottom-width: 2px;
}
.media .relations .cover div.image-text{
margin-bottom: 2px!important;
border-radius: 0px!important;
padding-bottom: 8px!important;
padding-top: 8px!important;
font-weight: 500!important;
}
.media-embed[data-media-type="manga"] .title{
color: rgba(var(--color-green));
}
.media-manga .actions .list{
background: rgba(var(--color-green));
}
.media-manga .sidebar .review.button{
background: rgba(var(--color-green));
}
.media-manga .container .content .nav .link{
color:rgba(var(--color-green));
}
`;
}
if(useScripts.CSSexpandFeedFilters && (!useScripts.mobileFriendly)){
moreStyle.textContent += `
.home .activity-feed-wrap .section-header .el-dropdown-menu,
.user .activity-feed-wrap .section-header .el-dropdown-menu{
background: none;
position: static;
display: inline !important;
margin-right: 15px;
box-shadow: none !important;
}
.home .activity-feed-wrap .section-header .el-dropdown-menu__item,
.user .activity-feed-wrap .section-header .el-dropdown-menu__item{
font-weight: normal;
color: rgb(var(--color-text-lighter));
margin-left: -2px !important;
display: inline;
font-size: 1.2rem;
padding: 4px 15px 5px 15px;
border-radius: 3px;
transition: .2s;
background: none;
}
.home .activity-feed-wrap .section-header .el-dropdown-menu__item.active,
.user .activity-feed-wrap .section-header .el-dropdown-menu__item.active{
background: none!important;
color: rgb(var(--color-blue));
}
.home .activity-feed-wrap .section-header .el-dropdown-menu__item:hover,
.user .activity-feed-wrap .section-header .el-dropdown-menu__item:hover{
background: none!important;
color: rgb(var(--color-blue));
}
.home .feed-select .feed-filter,
.user .section-header > .el-dropdown > .el-dropdown-selfdefine{
display: none;
}
`;
}
if(useScripts.CSSverticalNav && (!useScripts.mobileFriendly)){
moreStyle.textContent += `
.activity-entry > .wrap > .actions{
bottom: 0px!important;
}
.page-content > .container,
.notifications-feed,
.page-content > .studio{
margin-top: 25px !important;
}
.logo{
margin-left: -60px!important;
/*the compact layout uses more of the space to the side, so we line up the logo to the left*/
}
.footer{
margin-top: 0px !important;
/*less space wasted over the footer*/
}
.hohUserRow td,
.hohUserRow th{
top: 44px;
}
.container{
padding-left: 10px;
padding-right: 0px;
}
.hide{
top: 0px!important;
/*stop that top bar from jumping all over the place*/
}
.notification{
margin-bottom: 10px!important;
}
.media-embed + br{
display: none;
}
/*Dropdown menus are site theme based*/
.quick-search .el-select .el-input .el-input__inner,
.quick-search .el-select .el-input.is-focus .el-input__inner,
.el-select-dropdown,
.el-dropdown-menu,
.el-dropdown-menu__item--divided::before{
background: rgba(var(--color-foreground));
}
.el-select-dropdown__item.hover,
.el-select-dropdown__item:hover{
background: rgba(159, 173, 189, .2);
}
.el-dropdown-menu__item--divided{
border-color: rgba(var(--color-background));
}
.el-select-group__wrap:not(:last-of-type)::after{
background: rgba(var(--color-foreground));
}
.el-popper[x-placement^="bottom"] .popper__arrow,
.el-popper[x-placement^="bottom"] .popper__arrow::after{
border-bottom-color: rgba(var(--color-foreground));
}
.el-popper[x-placement^="top"] .popper__arrow,
.el-popper[x-placement^="top"] .popper__arrow::after{
border-top-color: rgba(var(--color-foreground));
}
/*Additions to dark theme dropdown*/
.site-theme-dark .quick-search.el-select .el-input.el-input__inner,
.site-theme-dark .quick-search .el-select .el-input.is-focus .el-input__inner,
.site-theme-dark .el-select-dropdown,
.site-theme-dark .el-dropdown-menu,
.site-theme-dark .el-dropdown-menu__item--divided::before{
background: rgba(17, 22, 29);
}
.site-theme-dark .el-select-group__wrap:not(:last-of-type)::after{
background: rgba(17, 22, 29);
}
.site-theme-dark .el-popper[x-placement^="bottom"] .popper__arrow,
.site-theme-dark .el-popper[x-placement^="bottom"] .popper__arrow::after{
border-bottom-color: rgba(17, 22, 29);
opacity: 1;
}
.site-theme-dark .el-popper[x-placement^="top"] .popper__arrow,
.site-theme-dark .el-popper[x-placement^="top"] .popper__arrow::after{
border-top-color: rgba(17, 22, 29);
opacity: 1;
}
.wrap .link.router-link-exact-active.router-link-active,
.nav .link.router-link-exact-active.router-link-active{
background: rgba(var(--color-foreground-grey));
color: rgba(var(--color-blue));
}
/*--------------VERTICAL-NAV----------------*/
/*modified code from Kuwabara: https://userstyles.org/styles/161017/my-little-anilist-theme-can-not-be-this-cute*/
.hohDismiss{
transform: translate(17.5px,-40px);
margin-left: 0px!important;
}
#app > .nav {
border-top: none !important;
}
#app div#nav.nav{
width: 65px;
height: 100%!important;
position: fixed!important;
top: 0!important;
left: 0!important;
transition: none!important;
}
div#nav.transparent{
background: rgba(var(--color-nav))!important;
}
.nav .wrap .links{
font-size: 1rem;
height: 355px!important;
margin-left: 0px;
padding-left: 0px;
width: 65px;
min-width: 65px !important;
flex-direction: column;
}
#app #nav.nav .wrap .links a.link{
width: 65px;
padding: 5px 0px;
margin-bottom: 10px;
text-align: center;
height: unset!important;
transition: 0.3s;
padding-left: 0px!important;
}
div#nav.nav .link.router-link-exact-active.router-link-active,
#nav > div > div.links > a:hover{
border-bottom-width: 0px!important;
}
.nav .wrap .links .link:hover{
background: rgba(var(--color-blue),0.1);
}
.nav .wrap .links .link::before{
display: block;
content: "";
height: 24px!important;
width: 65px!important;
background-size: 24px;
margin-left: 0!important;
margin-bottom: 3px!important;
background-repeat: no-repeat;
background-position: center;
filter: grayscale(100%) brightness(1.4);
}
.nav .link[href*="/user/"]:hover::before,
.nav .link[href^="/forum/"]:hover::before,
.nav .link[href^="/search/"]:hover::before,
.nav .link[href^="/home"]:hover::before{
filter: grayscale(0%);
}
.nav .link[href="/home"]::before{
background: url('data:image/svg+xml;utf8,');
}
.nav .link[href^="/user/"]::before{
background: url('data:image/svg+xml;utf8,');
}
.nav .link[href*="/animelist"]::before,
.nav .link[href*="/mangalist"]::before{
background: url('data:image/svg+xml;utf8,');
}
.nav .link[href^="/search/"]::before{
background: url('data:image/svg+xml;utf8,');
}
.nav .link[href*="/forum"]::before{
background: url('data:image/svg+xml;utf8,');
}
div#nav.transparent{
background: #1f2631!important;
}
#app{
margin-top: 0;
padding-left: 65px;
}
.nav .user{
position: fixed;
top: 0;
display: grid;
grid-gap: 40px;
width: 65px;
grid-template-rows: 50px 20px;
}
.search .dropdown.el-dropdown{
font-size: 10px;
}
.search .el-dropdown-link svg{
width: 65px;
height: 23px;
padding: 5px 0;
background: rgba(0, 0, 0, 0.2);
}
.nav .search{
width: 65px;
margin: 0;
text-align: center;
position: fixed;
top: 56px;
}
.quick-search-results{
z-index: 999!important;
top: 136px!important;
}
.user .avatar:hover+.chevron{
opacity: 0!important;
}
.hide{
top:0px!important;
}
/*-------------------*/
::selection{
background: rgba(var(--color-blue),0.4);
}
::-webkit-selection{
background: rgba(var(--color-blue),0.4);
}
::-moz-selection{
background: rgba(var(--color-blue),0.4);
}
::-webkit-scrollbar{
width: 7px;
height: 7px;
}
::-webkit-scrollbar-thumb{
background: #4e4e4e!important;
}
#app{
overflow:unset;
}
.user .header-wrap{
position: sticky;
top: -332px;
z-index: 100;
}
.list-stats{
margin-bottom:0px!important;
}
.activity-feed-wrap{
margin-top:25px;
}
.logo{
position: absolute;
margin-bottom: -500px;
display:none!important;
margin-left: 0px !important;
}
/*home stuff*/
.reply .header a.name[href="/user/Abyss/"]::after{
content: "Prima Undine";
margin-left:10px;
padding:3px;
border-radius:2px;
animation-duration: 20s;
animation-iteration-count: infinite;
animation-name: rainbow;
animation-timing-function: ease-in-out;
color: rgba(var(--color-white));
}
.reply .header a.name[href="/user/Taluun/"]::after{
content: "Best Friend";
margin-left:10px;
padding:3px;
border-radius:2px;
animation-duration: 20s;
animation-iteration-count: infinite;
animation-name: rainbow;
animation-timing-function: ease-in-out;
color: rgba(var(--color-white));
}
.details > .donator-badge{
left:105px!important;
padding:2px!important;
top: 100%!important;
-ms-transform: translate(0px, -34px);
-webkit-transform: translate(0px, -34px);
transform: translate(0px, -34px);
}
.activity-text > div > div > div > .donator-badge{
position:relative!important;
display:inline-block!important;
left:0px!important;
top:-10px!important;
-ms-transform: translate(0px, 0px);
-webkit-transform: translate(0px, 0px);
transform: translate(0px, 0px);
}
.activity-replies{
margin-top:5px!important;
margin-left:30px!important;
margin-right:0px!important;
}
.activity-entry{
margin-bottom: 10px!important;
}
.list-preview{
grid-gap: 10px!important;
padding:0px!important;
background: rgb(0,0,0,0)!important;
}
.home{
grid-column-gap: 30px!important;
margin-top: 20px!important;
grid-template-columns: auto 470px!important;
}
.activity-feed .reply{
padding:8px!important;
margin-bottom: 5px!important;
}
.list .details{
padding-left:10px!important;
padding-top:5px!important;
padding: 10px 16px!important;
padding-bottom: 7px !important;
}
.search{
margin-top:0px!important;
}
.emoji-spinner{
display:none!important;
}
.wrap{
border-radius: 2px!important;
}
.name{
margin-left: 0px!important;
}
.activity-text > div > div > div > .name{
margin-left: 12px!important;
}
.button{
margin-right: 5px!important;
}
.actions{
margin-bottom: 5px!important;
}
.status{
display: inline-block!important;
}
.avatar{
display: block!important;
}
/*https://anilist.co/activity/29333544*/
.activity-entry .header a:nth-child(1){
display: inline-block!important;
}
.wrap > .list{
min-height: 80px!important;
grid-template-columns: 60px auto!important;
}
.popper__arrow{
display: none!important;
}
.media-preview{
grid-gap: 10px!important;
padding: 0px!important;
background: rgb(0,0,0,0)!important;
}
.media-preview-card{
display: inline-grid!important;
}
.replies > .count{
color: rgba(var(--color-blue));
}
.action.likes{
color: unset;
}
.like-wrap > .button:hover{
color: rgba(var(--color-red));
}
.replies > *:nth-child(2){
color: rgba(var(--color-blue));
}
.actions{
cursor: default;
}
.activity-manga_list > div > div > div > div > .title{
color: rgba(var(--color-green))!important;
}
.markdown-editor > [title="Image"],
.markdown-editor > [title="Youtube Video"],
.markdown-editor > [title="WebM Video"]{
color: rgba(var(--color-red));
}
.markdown-editor > div > svg{
min-width: 1em!important;
}
.feed-select .toggle > div.active[data-v-f37b0a84]{
color: rgba(var(--color-blue))!important;
}
.home .details .status:first-letter,
.social .details .status:first-letter,
.activity-entry .details .status:first-letter{
text-transform: lowercase;
}
.activity-edit .markdown-editor,
.activity-edit .input{
margin-bottom: 10px!important;
}
.activity-edit .actions{
margin-bottom: 25px!important;
}
.page-content .container .home.full-width{
grid-template-columns: unset !important;
}
.activity-text .text {
border-left: solid 5px rgba(var(--color-blue));
}
.section-header{
padding-left:0px!important;
}
.cover[href="/anime/440/Shoujo-Kakumei-Utena/"] + .details{
border-color: #eb609e;
border-width: 4px;
border-style: solid;
border-left-width: 0px;
}
.sticky .avatar, .sticky .body-preview,
.sticky .categories, .sticky .name{
display: none!important;
}
.search > .filter,
.search > .preview{
margin-top: 20px;
}
`;
}
if(useScripts.CSSdecimalPoint){
moreStyle.textContent += `
.medialist.POINT_10_DECIMAL .score[score="10"]::after,
.medialist.POINT_10_DECIMAL .score[score="9"]::after,
.medialist.POINT_10_DECIMAL .score[score="8"]::after,
.medialist.POINT_10_DECIMAL .score[score="7"]::after,
.medialist.POINT_10_DECIMAL .score[score="6"]::after,
.medialist.POINT_10_DECIMAL .score[score="5"]::after,
.medialist.POINT_10_DECIMAL .score[score="4"]::after,
.medialist.POINT_10_DECIMAL .score[score="3"]::after,
.medialist.POINT_10_DECIMAL .score[score="2"]::after,
.medialist.POINT_10_DECIMAL .score[score="1"]::after{
margin-left:-4px;
content: ".0";
}
`;
}
if(useScripts.CSSsmileyScore){
moreStyle.textContent += `
.fa-frown{
color: red;
}
.fa-smile{
color: green;
}
`;
}
if(useScripts.limitProgress8){
moreStyle.textContent += `
.home:not(.full-width) .media-preview-card:nth-child(n+9){
display:none!important;
}
`;
}
else if(useScripts.limitProgress10){
moreStyle.textContent += `
.home:not(.full-width) .media-preview-card:nth-child(n+11){
display:none!important;
}
`;
}
documentHead.appendChild(moreStyle);
const queryMediaList = `
query($name: String!, $listType: MediaType){
MediaListCollection(userName: $name, type: $listType){
lists{
name
isCustomList
entries{
... mediaListEntry
}
}
}
}
fragment mediaListEntry on MediaList{
mediaId
status
progress
progressVolumes
repeat
notes
startedAt{
year
month
day
}
media{
episodes
chapters
volumes
duration
nextAiringEpisode{episode}
format
title{romaji native english}
tags{name}
genres
}
scoreRaw: score(format: POINT_100)
}
`;
const queryMediaListNotes = `
query($name: String!, $listType: MediaType){
MediaListCollection(userName: $name, type: $listType){
lists{
entries{
... mediaListEntry
}
}
}
}
fragment mediaListEntry on MediaList{
mediaId
notes
}
`;
const queryActivity = `
query($id: Int!){
Activity(id: $id){
... on TextActivity{
id
userId
type
text
user{
id
name
avatar{large}
}
likes{id}
replies{
text(asHtml: true)
user{name}
likes{name}
}
}
... on ListActivity {
id
userId
type
status
progress
user{
id
name
avatar{large}
}
media{coverImage{large}}
likes{id}
replies{
text(asHtml: true)
user{name}
likes{name}
}
}
... on MessageActivity{
id
type
likes{id}
replies{
text(asHtml: true)
user{name}
likes{name}
}
}
}
}
`;
const queryAuthNotifications = `
query($page: Int,$name: String){
User(name: $name){unreadNotificationCount}
Page(page: $page){
notifications{
... on AiringNotification{type}
... on FollowingNotification{type}
... on ActivityMessageNotification{type}
... on ActivityMentionNotification{type}
... on ActivityReplyNotification{type}
... on ActivityLikeNotification{type}
... on ActivityReplyLikeNotification{type}
... on ThreadCommentMentionNotification{type}
... on ThreadCommentReplyNotification{type}
... on ThreadCommentSubscribedNotification{type}
... on ThreadCommentLikeNotification{type}
... on ThreadLikeNotification{type}
}
}
}
`;
let APIlimit = 90;
let APIcallsUsed = 0;//this is NOT a reliable way to figure out how many more calls we can use, just a way to set some limit
let pending = {};
let APIcounter = setTimeout(function(){
APIcallsUsed = 0;
},60*1000);//reset counter every minute
let handleResponse = function(response){
APIlimit = response.headers.get("x-ratelimit-limit");
APIcallsUsed = APIlimit - response.headers.get("x-ratelimit-remaining");
return response.json().then(function(json){
return (response.ok ? json : Promise.reject(json));
});
};
const url = "https://graphql.anilist.co";//Current Anilist API location
const authUrl = "https://anilist.co/api/v2/oauth/authorize?client_id=1933&response_type=token";
let aniCast = new BroadcastChannel("aniscripts");
aniCast.onmessage = function(message){
if(message.data.type && message.data.type === "cache"){
sessionStorage.setItem(message.data.key,message.data.value);
}
}
//mandatory: query,variables,callback
//optional: cacheKey, and optionally even then, how long the item is fresh in the cache
function generalAPIcall(query,variables,callback,cacheKey,timeFresh,useLocalStorage){
if(cacheKey){
let cacheItem = JSON.parse(
(useLocalStorage ? localStorage.getItem(cacheKey) : sessionStorage.getItem(cacheKey))
);
if(cacheItem){
if(
!cacheItem.duration
|| ((new Date()).valueOf() < cacheItem.time + cacheItem.duration)
){
callback(cacheItem.data,variables);
return;
}
else{
(useLocalStorage ? localStorage.removeItem(cacheKey) : sessionStorage.removeItem(cacheKey))
}
}
}
let handleData = function(data){
callback(data,variables);
if(cacheKey){
let saltedHam = JSON.stringify({
data: data,
time: (new Date()).valueOf(),
duration: timeFresh
});
if(useLocalStorage){
localStorage.setItem(cacheKey,saltedHam);
}
else{
sessionStorage.setItem(cacheKey,saltedHam);
aniCast.postMessage({type:"cache",key:cacheKey,value:saltedHam});
}
}
};
let options = {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
"query": query,
"variables": variables
})
};
let handleError = function(error){
if(error.errors && error.errors.some(err => err.status === 404)){//not really an error
handleData(null);
return;
};
console.error(error,variables);
};
fetch(url,options).then(handleResponse).then(handleData).catch(handleError);
APIcallsUsed++;
}
/*
rawQueries = [
{
query: single root item graphql query
variables: variables like a normal API call
callback: like in a normal API call
cacheKey: [optional]
duration: [optional]
}
...
]
*/
function queryPacker(rawQueries){//get a list of query calls, and pack them into one query. The result is then split up again and sent back to each call.
let queries = rawQueries.filter(function(query){//filter out those that have data in our local cache
if(query.cacheKey){
let cacheItem = JSON.parse(sessionStorage.getItem(query.cacheKey));
if(cacheItem){
if(
!cacheItem.duration
|| ((new Date()).valueOf() < cacheItem.time + cacheItem.duration)
){
query.callback(cacheItem.data);
return false;
}
else{
sessionStorage.removeItem(query.cacheKey);//expired data
}
}
}
return true;
});
let params = new Set();
queries.forEach(function(query){//inline all variables
query.query = query.query.trim().replace(/^query.*?{/,"").slice(0,-1).trim();
const enums = ["type"];
Object.keys(query.variables).forEach(function(variable){
query.query = query.query.replace(
new RegExp("\\$" + variable,"g"),
(enums.includes(variable) ? query.variables[variable] : (typeof query.variables[variable] === "string" ? "\"" + query.variables[variable] + "\"" : query.variables[variable]))
);
})
});
let enumeratedQueries = queries.map(function(query,index){
return "a" + index + ":" + query.query;
});
let mainQuery = `
query{
${enumeratedQueries.join("\n")}
}
`;
let queryUnpacker = function(data){
if(!data){
queries.forEach(function(query,index){
query.callback(null);
})
}
else{
queries.forEach(function(query,index){
let returnStructure = {data:{}};
returnStructure.data[query.query.match(/^[^({]*/)[0]] = data.data["a" + index];
query.callback(returnStructure);
if(query.cacheKey){
let cacheStrucuture = {
data: returnStructure
}
if(query.duration){
cacheStrucuture.time = (new Date()).valueOf();
cacheStrucuture.duration = query.duration;
}
sessionStorage.setItem(query.cacheKey,JSON.stringify(cacheStrucuture));
}
})
}
}
if(queries.length){//hey, they might all have been in cache
generalAPIcall(mainQuery,{},queryUnpacker);//send our "superquery" to the regular API handler
}
}
function authAPIcall(query,variables,callback){//only use for auth
let handleData = function(data){
callback(data,variables);
};
let options = {
method: "POST",
headers: {
"Authorization": "Bearer " + useScripts.accessToken,
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
"query": query,
"variables": variables
})
};
let handleError = function(error){
console.error(error);
if(error.errors){
error.errors.forEach(function(thing){
if(thing.message === "Invalid token"){
useScripts.accessToken = "";
useScripts.save();
console.log("access token retracted");
};
});
};
};
fetch(url,options).then(handleResponse).then(handleData).catch(handleError);
APIcallsUsed++;
}
function scoreFormatter(score,format,name){
if(name === "shuurei"){
const shuureiSystem = ["",">:(","Ew","Ugh","Hm","Ok","Nice","Ooh","Wow","Fave",":D"];
return `${shuureiSystem[score]}`;
}
else if(format === "POINT_100"){
return score + "/100";
}
else if(
format === "POINT_10_DECIMAL" ||
format === "POINT_10"
){
return score + "/10";
}
else if(format === "POINT_3"){
if(score === 3){
return svgAssets.smile;
}
else if(score === 2){
return svgAssets.meh;
}
else if(score === 1){
return svgAssets.frown;
};
}
else if(format === "POINT_5"){
return score + svgAssets.star;
}
}
function convertScore(score,format){
if(format === "POINT_100"){
return score;
}
else if(
format === "POINT_10_DECIMAL" ||
format === "POINT_10"
){
return score*10;
}
else if(format === "POINT_3"){
if(score === 3){
return 85;
}
else if(score === 2){
return 60;
}
else if(score === 1){
return 45;
}
return 0;
}
else if(format === "POINT_5"){
if(score === 0){
return 0;
};
return score*20 - 10;
}
}
function enhanceSocialTab(){
if(!location.pathname.match(/^\/(anime|manga)\/\d*\/[\w\-]*\/social/)){
return;
}
let listOfActs = Array.from(document.getElementsByClassName("activity-entry"));
listOfActs.forEach(function(act){//compress activities without comments, they are all the same media entry anyway
if(
!act.hasOwnProperty("marked") &&
!(act.children[0].children[2].children[0].children.length > 1)
){
act.marked = true;
act.children[0].children[0].children[0].remove();//remove cover image
let elements = act.children[0].children[0].children[0].children;
elements[2].parentNode.insertBefore(elements[2],elements[0]);//move profile picture to the beginning of the line
elements[0].parentNode.parentNode.style.minHeight = "70px";
elements[0].parentNode.classList.add("hohSocialTabActivityCompressedContainer");
elements[0].style.verticalAlign = "bottom";
elements[0].style.marginTop = "0px";
elements[1].classList.add("hohSocialTabActivityCompressedName");
elements[2].classList.add("hohSocialTabActivityCompressedStatus");
act.style.marginBottom = "10px";
}
});
/*add average score to social tab*/
let listOfFollowers = Array.from(document.getElementsByClassName("follow"));
let averageScore = 0;
let averageCount = 0;
listOfFollowers.forEach(function(follower){
if(
follower.children.length === 4
){
if(follower.children[3].nodeName != "svg"){
const followScore = follower.children[3].innerText.match(/\d+\.?\d*/g);
if(followScore && followScore.length === 2){
averageScore += 100*followScore[0]/followScore[1];
averageCount++;
}
else if(followScore && followScore.length === 1){//star rating
averageScore += (followScore[0]*20 - 10);
averageCount++;
}
}
else{//do count smiley scores, but with lower confidence
const smileyScore = follower.children[3].dataset.icon;
if(smileyScore === "frown"){
averageScore += (45)*0.5;
averageCount += 0.5;
}
else if(smileyScore === "meh"){
averageScore += (60)*0.5;
averageCount += 0.5;
}
else if(smileyScore === "smile"){
averageScore += (85)*0.5;
averageCount += 0.5;
}
}
}
});
if(averageCount){
averageScore = averageScore/averageCount;
let locationForIt = document.getElementById("averageScore");
let dataList = document.getElementById("socialUsers");
if(!locationForIt){
let insertLocation = document.querySelector(".following");
locationForIt = create("span","#averageScore");
insertLocation.insertBefore(
locationForIt,
insertLocation.children[0]
);
dataList = create("datalist");
dataList.id = "socialUsers";
insertLocation.insertBefore(
dataList,
insertLocation.children[0]
);
}
locationForIt.innerText = "Average: " + averageScore.roundPlaces(1) + "/100";
locationForIt.nextSibling.style.marginTop = "5px";
if(dataList.childElementCount < listOfFollowers.length){
listOfFollowers.slice(dataList.childElementCount).forEach(function(follower){
let option = create("option",false,false,dataList);
option.value = follower.children[1].innerText;
});
}
}
setTimeout(enhanceSocialTab,200);
}
function enhanceForum(){//purpose: reddit-style comment three collapse button
if(!document.URL.match(/^https:\/\/anilist\.co\/forum\/thread\/.*/)){
return;
}
let comments = Array.from(document.getElementsByClassName("comment-wrap"));
comments.forEach(function(comment){
if(!comment.hasOwnProperty("hohVisited")){
comment.hohVisited = true;
let hider = create("span","hohForumHider","[-]");
hider.onclick = function(){
let parentComment = this.parentNode.parentNode;
if(this.innerHTML === "[-]"){
this.innerText = "[+]";
parentComment.children[1].style.display = "none";
if(parentComment.parentNode.children.length > 1){
parentComment.parentNode.children[1].style.display = "none";
}
}
else{
this.innerText = "[-]";
parentComment.children[1].style.display = "block";
if(parentComment.parentNode.children.length > 1){
parentComment.parentNode.children[1].style.display = "block";
}
}
};
comment.children[0].children[0].insertBefore(
hider,
comment.children[0].children[0].children[0]
);
}
});
setTimeout(enhanceForum,100);
}
function dubMarker(){
if(!document.URL.match(/^https:\/\/anilist\.co\/anime\/.*/)){
return;
}
if(document.getElementById("dubNotice")){
return;
}
const variables = {
id: document.URL.match(/\/anime\/(\d+)\//)[1],
page: 1,
language: useScripts.dubMarkerLanguage.toUpperCase()
};
const query = `
query($id: Int!, $type: MediaType, $page: Int = 1, $language: StaffLanguage){
Media(id: $id, type: $type){
characters(page: $page, sort: [ROLE], role: MAIN){
edges {
node{id}
voiceActors(language: $language){language}
}
}
}
}`;
let dubCallback = function(data){
if(!document.URL.match(/^https:\/\/anilist\.co\/anime\/.*/)){
return;
};
let dubNoticeLocation = document.getElementsByClassName("sidebar");
if(!dubNoticeLocation.length){
setTimeout(function(){
dubCallback(data);
},200);
return;
}
if(data.data.Media.characters.edges.reduce(
(actors,a) => actors + a.voiceActors.length,0
)){//any voice actors for this language?
if(document.getElementById("dubNotice")){
return;
}
let dubNotice = create("p","#dubNotice",useScripts.dubMarkerLanguage + " dub available");
dubNoticeLocation[0].insertBefore(dubNotice,dubNoticeLocation[0].firstChild);
}
};
generalAPIcall(query,variables,dubCallback,"hohDubInfo" + variables.id + variables.language);
}
function enhanceStaff(){
if(!document.URL.match(/^https:\/\/anilist\.co\/staff\/.*/)){
return;
}
if(document.getElementById("hohFavCount")){
return;
};
let filterGroup = document.getElementsByClassName("content");
if(!filterGroup.length){
setTimeout(function(){
enhanceStaff();
},200);//may take some time to load
return;
}
filterGroup = filterGroup[0];
let favCount = create("span","#hohFavCount",false,filterGroup);
const variables = {id: document.URL.match(/\/staff\/(\d+)\/?/)[1]};
const query = "query($id: Int!){Staff(id: $id){favourites}}";
let favCallback = function(data){
let favButton = document.getElementsByClassName("favourite");
if(data.data.Staff.favourites === 0 && favButton[0].classList.contains("isFavourite")){//safe to assume
favCount.innerText = data.data.Staff.favourites + 1;
}
else{
favCount.innerText = data.data.Staff.favourites;
}
if(favButton.length){
favButton[0].onclick = function(){
if(this.classList.contains("isFavourite")){
favCount.innerText = Math.max(parseInt(favCount.innerText)-1,0);//0 or above, just to avoid looking silly
}
else{
favCount.innerText = parseInt(favCount.innerText)+1;
}
};
}
};
generalAPIcall(query,variables,favCallback,"hohStaffFavs" + variables.id,60*60*1000);
}
function replaceStaffRoles(){
let URLstuff = location.pathname.match(/^\/staff\/(\d+)\/?.*/);
if(!URLstuff){
return;
};
let possibleGarbage = document.getElementById("hoh-media-roles");
if(possibleGarbage){
if(possibleGarbage.dataset.staffId === URLstuff[1]){
return;
}
else{
possibleGarbage.remove();
let possibleFilterBar = document.querySelector(".hohFilterBar");
if(possibleFilterBar){
possibleFilterBar.remove();
};
}
};
let insertParent = document.querySelector(".media-roles");
let insertParentCharacters = document.querySelector(".character-roles");
if(!insertParent && !insertParentCharacters){
setTimeout(replaceStaffRoles,200);
return;
};
let substitution = false;
if(!insertParent){
insertParent = create("div",["media-roles","container","substitution"],false,insertParentCharacters.parentNode);
insertParent.setAttribute("data-v-09607311","");
insertParent.setAttribute("data-v-7ef3dcfc","");
substitution = true;
}
else{
insertParent.classList.add("substitution");
};
insertParent.parentNode.classList.add("substitution");
let hohCharacterRolesBox = create("div","#hoh-character-roles");
let hohCharacterRolesHeader = create("h4",false,"Character Voice Roles",hohCharacterRolesBox);
hohCharacterRolesHeader.style.display = "none";
let hohCharacterRoles = create("div","grid-wrap",false,hohCharacterRolesBox);
hohCharacterRoles.setAttribute("data-v-09607311","");
hohCharacterRoles.style.margin = "10px";
let hohMediaRoles = create("div","#hoh-media-roles");
hohMediaRoles.dataset.staffId = URLstuff[1];
let hohMediaRolesAnimeHeader = create("h4",false,"Anime Staff Roles",hohMediaRoles);
hohMediaRolesAnimeHeader.style.display = "none";
let hohMediaRolesAnime = create("div","grid-wrap",false,hohMediaRoles);
hohMediaRolesAnime.setAttribute("data-v-09607311","");
hohMediaRolesAnime.style.margin = "10px";
let hohMediaRolesMangaHeader = create("h4",false,"Manga Staff Roles",hohMediaRoles);
hohMediaRolesMangaHeader.style.display = "none";
let hohMediaRolesManga = create("div","grid-wrap",false,hohMediaRoles);
hohMediaRolesManga.setAttribute("data-v-09607311","");
hohMediaRolesManga.style.margin = "10px";
//sort
let hohMediaSort = create("div",["container","hohFilterBar"]);
hohMediaSort.setAttribute("data-v-7ef3dcfc","");
let sortText = create("span",false,"Sort",hohMediaSort);
let sortSelect = create("select",false,false,hohMediaSort);
sortSelect.style.marginLeft = "5px";
let filterSelect = create("input",false,false,hohMediaSort);
filterSelect.setAttribute("list","staffRoles");
filterSelect.placeholder = "Filter";
let dataList = create("datalist",false,false,hohMediaSort);
dataList.id = "staffRoles";
let digestStats = create("span",false,false,hohMediaSort,"margin-left:100px;");
let sortOptionAlpha = create("option",false,"Alphabetical",sortSelect);
sortOptionAlpha.value = "alphabetical";
let sortOptionChrono = create("option",false,"Chronological",sortSelect);
sortOptionChrono.value = "chronological";
let sortOptionPopularity = create("option",false,"Popularity",sortSelect);
sortOptionPopularity.value = "popularity";
let sortOptionLength = create("option",false,"Length",sortSelect);
sortOptionLength.value = "length";
let sortOptionScore = create("option",false,"Score",sortSelect);
sortOptionScore.value = "score";
if(useScripts.accessToken){
let sortOptionMyScore = create("option",false,"My Score",sortSelect);
sortOptionMyScore.value = "myScore";
}
let autocomplete = new Set();
sortSelect.value = useScripts.staffRoleOrder;
hohMediaSort.style.marginBottom = "10px";
hohMediaSort.style.marginTop = "3px";
//end sort
let initPerformed = false;
let UIinit = function(){
initPerformed = true;
insertParent.parentNode.insertBefore(hohMediaSort,insertParentCharacters);
insertParent.insertBefore(hohMediaRoles,insertParent.children[0]);
insertParentCharacters.insertBefore(hohCharacterRolesBox,insertParentCharacters.children[0]);
};
let animeRolesList = [];
let mangaRolesList = [];
let voiceRolesList = [];
let animeAliasesToLookFor = [];
let mangaAliasesToLookFor = [];
if(useScripts.shortRomaji){
shortRomaji.forEach(function(alias){
let matches = alias[0].match(/\/(anime|manga)\/(\d+)\//);
if(matches[1] === "anime"){
animeAliasesToLookFor.push([parseInt(matches[2]),alias[1]]);
}
else{
mangaAliasesToLookFor.push([parseInt(matches[2]),alias[1]]);
};
});
};
const titleAliases = JSON.parse(localStorage.getItem("titleAliases"));
if(titleAliases){
titleAliases.forEach(function(alias){
let matches = alias[0].match(/\/(anime|manga)\/(\d+)\//);
if(matches){
if(matches[1] === "anime"){
animeAliasesToLookFor.push([parseInt(matches[2]),alias[1]]);
}
else{
mangaAliasesToLookFor.push([parseInt(matches[2]),alias[1]]);
};
};
});
}
let listRenderer = function(){
if(!initPerformed){
UIinit();
};
useScripts.staffRoleOrder = sortSelect.value;
useScripts.save();
if(sortSelect.value === "alphabetical"){
animeRolesList.sort(function(a,b){return a.title.localeCompare(b.title)});
mangaRolesList.sort(function(a,b){return a.title.localeCompare(b.title)});
voiceRolesList.sort(function(a,b){return a.title.localeCompare(b.title)});
}
else if(sortSelect.value === "chronological"){
let yearSorter = function(a,b){
if(!a.startDate.year){
return 1;
};
if(a.startDate.year === b.startDate.year){
if(a.startDate.month === b.startDate.month){
if(a.startDate.day === b.startDate.day){
return 1;
}
else{
return a.startDate.day - b.startDate.day;
};
}
else{
return a.startDate.month - b.startDate.month;
};
}
else{
return a.startDate.year - b.startDate.year;
};
};
animeRolesList.sort(yearSorter);
mangaRolesList.sort(yearSorter);
voiceRolesList.sort(yearSorter);
}
else if(sortSelect.value === "popularity"){
animeRolesList.sort(function(b,a){return a.popularity - b.popularity});
mangaRolesList.sort(function(b,a){return a.popularity - b.popularity});
voiceRolesList.sort(function(b,a){return a.popularity - b.popularity});
}
else if(sortSelect.value === "score"){
animeRolesList.sort(function(b,a){return a.score - b.score});
mangaRolesList.sort(function(b,a){return a.score - b.score});
voiceRolesList.sort(function(b,a){return a.score - b.score});
}
else if(sortSelect.value === "length"){
animeRolesList.sort(function(b,a){
if(a.episodes === b.episodes){
return a.duration - b.duration
}
else{
return a.episodes - b.episodes
};
});
voiceRolesList.sort(function(b,a){
if(a.episodes === b.episodes){
return a.duration - b.duration
}
else{
return a.episodes - b.episodes
};
});
mangaRolesList.sort(function(b,a){
if(a.chapters === b.chapters){
return a.volumes - b.volumes
}
else{
return a.chapters - b.chapters
};
});
}
else if(sortSelect.value === "myScore"){
let scoreSorter = function(b,a){
let scoreTier = (a.myStatus ? a.myStatus.scoreRaw : 0) - (b.myStatus ? b.myStatus.scoreRaw : 0);
if(scoreTier !== 0){
return scoreTier;
}
let progressTier = (a.myStatus ? a.myStatus.progress : -1) - (b.myStatus ? b.myStatus.progress : -1);
if(progressTier !== 0){
return progressTier;
}
return a.popularity - b.popularity;
}
animeRolesList.sort(scoreSorter);
mangaRolesList.sort(scoreSorter);
voiceRolesList.sort(scoreSorter);
}
const randomData = "data-v-2bb4b515";
if(animeRolesList.length){
hohMediaRolesAnimeHeader.style.display = "inline";
}
else{
hohMediaRolesAnimeHeader.style.display = "none";
}
if(mangaRolesList.length){
hohMediaRolesMangaHeader.style.display = "inline";
}
else{
hohMediaRolesMangaHeader.style.display = "none";
}
if(voiceRolesList.length){
hohCharacterRolesHeader.style.display = "inline";
}
else{
hohCharacterRolesHeader.style.display = "none";
}
let createRoleCard = function(media,type){
let roleCard = create("div",["role-card","view-media"]);
roleCard.setAttribute(randomData,"");
roleCard.style.position = "relative";
let mediaA = create("div","media",false,roleCard);
mediaA.setAttribute(randomData,"");
let cover = create("a","cover",false,mediaA);
cover.href = "/" + type + "/" + media.id + "/" + safeURL(media.title);
cover.style.backgroundImage = "url(" + media.image + ")";
cover.setAttribute(randomData,"");
let content = create("a","content",false,mediaA);
content.href = "/" + type + "/" + media.id + "/" + safeURL(media.title);
content.setAttribute(randomData,"");
let name = create("div","name",media.title,content);
name.setAttribute(randomData,"");
let role = create("div","role",media.role.join(", "),content);
role.setAttribute(randomData,"");
if(media.myStatus){
let statusDot = create("div",["hohStatusDot","hohStatusDotRight"],false,roleCard);
statusDot.style.background = distributionColours[media.myStatus.status];
statusDot.title = media.myStatus.status.toLowerCase();
};
return roleCard;
};
let sumDuration = 0;
let sumChapters = 0;
let sumScores = 0;
let amount = 0;
while(hohCharacterRoles.childElementCount){
hohCharacterRoles.removeChild(hohCharacterRoles.lastChild);
};
for(var i=0;i Chapters Read: " + sumChapters + ""
if(amount){
digestStats.innerHTML += " Mean Score: " + (sumScores/amount).roundPlaces(1) + "";
};
};
};
sortSelect.oninput = listRenderer;
filterSelect.oninput = listRenderer;
let refreshAutocomplete = function(){
while(dataList.lastChild){
dataList.removeChild(dataList.lastChild);
};
autocomplete.forEach(function(value){
let option = create("option",false,false,dataList);
option.value = value;
});
};
let animeHandler = function(data){
if(data.data.Staff.staffMedia.pageInfo.currentPage === 1){
for(var i=2;i<=data.data.Staff.staffMedia.pageInfo.lastPage;i++){
let variables = {
page: i+0,
type: "ANIME",
id: URLstuff[1]
};
if(useScripts.accessToken){
authAPIcall(staffQuery,variables,animeHandler);
}
else{
generalAPIcall(staffQuery,variables,animeHandler);
}
};
};
data.data.Staff.staffMedia.edges.forEach(function(edge){
let anime = {
role: [edge.staffRole],
title: edge.node.title.romaji,
image: edge.node.coverImage.large,
startDate: edge.node.startDate,
id: edge.node.id,
episodes: edge.node.episodes,
popularity: edge.node.popularity,
duration: edge.node.duration || 1,
score: edge.node.averageScore,
myStatus: edge.node.mediaListEntry,
listJSON: edge.node.mediaListEntry ? parseListJSON(edge.node.mediaListEntry.notes) : null
};
if(useScripts.titleLanguage === "Native" && edge.node.title.native){
anime.title = edge.node.title.native;
}
else if(useScripts.titleLanguage === "English" && edge.node.title.english){
anime.title = edge.node.title.english;
};
animeAliasesToLookFor.forEach(function(alias){
if(alias[0] === anime.id){
anime.title = alias[1];
};
});
autocomplete.add(anime.title);
autocomplete.add(edge.staffRole);
animeRolesList.push(anime);
});
animeRolesList.sort(function(a,b){return a.id - b.id});
for(var i=1;i 0){
if(data.media.type === "ANIME"){
rewatchSuffix = " [rewatch";
}
else{
rewatchSuffix = " [reread";
}
if(data.repeat === 1){
rewatchSuffix += "]";
}
else{
rewatchSuffix += " " + data.repeat + "]";
}
};
if(data.score){
if(status.innerText.match(/^completed/i)){
scoreInfo.innerHTML = suffix + rewatchSuffix;
}
else{
scoreInfo.innerHTML = suffix;
};
scoreInfo.style.display = "inline";
};
};
const variables = {
userName: status.parentNode.children[0].innerText,
mediaId: +mediaId[1]
};
const query = `
query($userName: String,$mediaId: Int){
MediaList(
userName: $userName,
mediaId: $mediaId
){
score
mediaId
notes
repeat
media{type}
user{
name
mediaListOptions{scoreFormat}
}
}
}`;
//generalAPIcall(query,variables,callback,"hohCompletedScores" + variables.mediaId + variables.userName,60*1000)
bigQuery.push({
query: query,
variables: variables,
callback: callback,
cacheKey: "hohCompletedScores" + variables.mediaId + variables.userName,
duration: 60*1000
});
};
}
else if(status.children.length === 2 && !status.classList.contains("form")){
status.removeChild(status.children[1]);
};
});
queryPacker(bigQuery);
};
function enhanceTags(){//show tag definition in drop down menu when adding tags
if(!location.pathname.match(/^\/(anime|manga)\/.*/)){
return;
};
setTimeout(enhanceTags,400);
let possibleTagContainers = document.getElementsByClassName("el-select-dropdown__list");
let bestGuess = false;
for(var i=0;i 205){//horrible test, but we have not markup to go from. Assumes the tag dropdown is the only one with more than that number of children
bestGuess = i;
};
};
if(bestGuess === false){
return;
};
if(possibleTagContainers[bestGuess].hasOwnProperty("hohMarked")){
return;
}
else{
possibleTagContainers[bestGuess].hohMarked = true;
};
let superBody = document.getElementsByClassName("el-dialog__body")[0];
let descriptionTarget = create("span","#hohDescription");
superBody.insertBefore(descriptionTarget,superBody.children[2]);
for(var i=0;i apps.
You can also turn off this notice there.`,setting);
};
let regularNotifications = create("span",false,svgAssets.envelope + " Show default notifications");
regularNotifications.style.cursor = "pointer";
regularNotifications.style.fontSize = "small";
regularNotifications.onclick = function(){
if(displayMode === "hoh"){
displayMode = "native";
hohNotsToToggle = document.getElementById("hohNotifications");
if(hohNotsToToggle){
hohNotsToToggle.style.display = "none";
};
var regNotsToToggle = document.getElementsByClassName("notification");
for(var i=0;i 1){
quickComLikes.innerText = reply.likes.length + "♥";
}
else if(reply.likes.length === 1){
quickComLikes.innerText = "♥";
};
reply.likes.forEach(function(like){
if(like.name === whoAmI){
quickComLikes.classList.add("hohILikeThis");
};
});
quickCom.appendChild(quickComName);
quickCom.appendChild(quickComContent);
quickCom.appendChild(quickComLikes);
comment.children[1].appendChild(quickCom);
});
});
};
let notificationDrawer = function(activities){
let newContainer = document.getElementById("hohNotifications")
if(newContainer){
newContainer.remove();
};
newContainer = create("div","#hohNotifications");
let notificationsContainer = document.querySelector(".notifications");
if(!notificationsContainer){
return;
}
notificationsContainer.insertBefore(newContainer,notificationsContainer.firstChild);
for(var i=0;i 1){
textSpan.innerText = " liked your activities.";
};
if(counter === 1){
while(
i + counter < activities.length
&& activities[i + counter].type === "like"
&& activities[i + counter].link === activities[i].link
){//several people likes one of your activities
let miniImageWidth = 40;
let miniImage = create("a","hohUserImageSmall",false,newNotification);
miniImage.href = activities[i + counter].href;
miniImage.title = activities[i + counter].textName;
miniImage.style.backgroundImage = activities[i + counter].image;
miniImage.style.height = miniImageWidth + "px";
miniImage.style.width = miniImageWidth + "px";
miniImage.style.marginLeft = (72 + (counter-1)*miniImageWidth) + "px";
counter++;
};
if(counter > 1){
text.style.marginTop = "45px";
activities[i].textName += " +";
};
}
else{
newNotification.classList.add("hohCombined");
};
textName.innerText = activities[i].textName;
text.appendChild(textName);
text.appendChild(textSpan);
i += counter -1;
}
else if(activities[i].type === "reply" ){
let notNotImage = create("a",false,false,notNotImageContainer);
create("img",["hohMediaImage",activities[i].link],false,notNotImage);
notNotImage.href = activities[i].directLink;
while(
i + counter < activities.length
&& activities[i + counter].type === "reply"
&& activities[i + counter].link === activities[i].link
){
let miniImageWidth = 40;
let miniImage = create("a","hohUserImageSmall",false,newNotification);
miniImage.href = activities[i + counter].href;
miniImage.style.backgroundImage = activities[i + counter].image;
miniImage.style.height = miniImageWidth + "px";
miniImage.style.width = miniImageWidth + "px";
miniImage.style.marginLeft = (72 + (counter-1)*miniImageWidth) + "px";
counter++;
};
if(counter > 1){
text.style.marginTop = "45px";
activities[i].textName += " +";
};
text.href = activities[i].directLink;
textName.innerText = activities[i].textName;
textSpan.innerText = activities[i].textSpan;
text.appendChild(textName);
text.appendChild(textSpan);
i += counter -1;
}
else if(activities[i].type === "replyReply" ){
let notNotImage = create("a",false,false,notNotImageContainer);
create("img",["hohMediaImage",activities[i].link],false,notNotImage);
notNotImage.href = activities[i].directLink;
while(
i + counter < activities.length
&& activities[i + counter].type === "replyReply"
&& activities[i + counter].link === activities[i].link
){
let miniImageWidth = 40;
let miniImage = create("a","hohUserImageSmall",false,newNotification);
miniImage.href = activities[i + counter].href;
miniImage.style.backgroundImage = activities[i + counter].image;
miniImage.style.height = miniImageWidth + "px";
miniImage.style.width = miniImageWidth + "px";
miniImage.style.marginLeft = (72 + (counter-1)*miniImageWidth) + "px";
counter++;
};
if(counter > 1){
text.style.marginTop = "45px";
activities[i].textName += " +";
};
text.href = activities[i].directLink;
textName.innerText = activities[i].textName;
textSpan.innerText = " replied to the same activity as you.";
text.appendChild(textName);
text.appendChild(textSpan);
i += counter -1;
}
else if(
activities[i].type === "message"
|| activities[i].type === "likeReply"
|| activities[i].type === "mention"
){
let notNotImage = create("a",false,false,notNotImageContainer);
create("img",["hohMediaImage",activities[i].link],false,notNotImage);
notNotImage.href = activities[i].directLink;
text.href = activities[i].directLink;
textName.innerText = activities[i].textName;
textSpan.innerText = activities[i].textSpan;
text.appendChild(textName);
text.appendChild(textSpan);
}
else if(activities[i].type === "airing"){
textSpan.innerHTML = activities[i].text;
text.appendChild(textSpan);
}
else if(activities[i].type === "follow"){
text.href = activities[i].directLink;
textName.innerText = activities[i].textName;
textSpan.innerText = activities[i].textSpan;
text.appendChild(textName);
text.appendChild(textSpan);
}
else if(
activities[i].type === "forumCommentLike"
|| activities[i].type === "forumSubscribedComment"
|| activities[i].type === "forumCommentReply"
|| activities[i].type === "forumLike"
|| activities[i].type === "forumMention"
){
text.href = activities[i].directLink;
textName.innerText = activities[i].textName;
textSpan.innerText = activities[i].textSpan;
text.appendChild(textName);
text.appendChild(textSpan);
let textSpan2 = create("span",false,activities[i].text,text,"color:rgb(var(--color-blue));");
text.style.maxWidth = "none";
text.style.marginTop = "17px";
}
else{//display as-is
textSpan.classList.add("hohUnhandledSpecial");
textSpan.innerHTML = activities[i].text;
text.appendChild(textSpan);
};
let time = create("div","hohTime");
time.innerHTML = activities[i - counter + 1].time;
let commentsContainer = create("div",["hohCommentsContainer","b" + activities[i].link]);
let comments = create("a",["hohComments","link"],"comments",commentsContainer);
create("span","hohMonospace","+",comments);
comments.onclick = function(){
if(this.children[0].innerText === "+"){
this.children[0].innerText = "-";
this.parentNode.children[1].style.display = "inline-block";
let variables = {
id: +this.parentNode.classList[1].substring(1)
};
generalAPIcall(queryActivity,variables,commentCallback);
}
else{
this.children[0].innerText = "+";
this.parentNode.children[1].style.display = "none";
};
};
let commentsArea = create("div","hohCommentsArea",false,commentsContainer);
newNotification.appendChild(notImage);
newNotification.appendChild(text);
newNotification.appendChild(notNotImageContainer);
newNotification.appendChild(time);
newNotification.appendChild(commentsContainer);
newContainer.appendChild(newNotification);
};
};
if(useScripts.accessToken && false){
let callback = function(data){
let activities = [];
data.data.Page.notifications.forEach(function(notification){
});
notificationDrawer(activities);
};
}
else{
let activities = [];
let notifications = document.getElementsByClassName("notification");//collect the "real" notifications
if(notifications.length === prevLength && forceRebuildFlag === false){
return;
}
else{
prevLength = notifications.length;
forceRebuildFlag = false;
};
const activityTypes = {
" liked your activity." : "like",
" replied to your activity." : "reply",
" sent you a message." : "message",
" liked your activity reply." : "likeReply",
" mentioned you in their activity." : "mention",
" replied to activity you previously replied to." : "replyReply",
" liked your comment, in the forum thread " : "forumCommentLike",
" commented in your subscribed forum thread " : "forumSubscribedComment",
" replied to your comment, in the forum thread " : "forumCommentReply",
" liked your forum thread, " : "forumLike",
" mentioned you, in the forum thread " : "forumMention"
};
Array.from(notifications).forEach(function(notification){//parse real notifications
notification.already = true;
notification.style.display = "none";
var active = {};
if(
notification.classList.length > 1
&& notification.classList[1] != "hasMedia"
){//"notification unread" classlist
active.unread = true;
}
else{
active.unread = false;
};
active.type = "special";
active.link = "aaa";//fixme. Edit 2019: I have no idea
if(//check if we can query that
notification.children.length >= 2
&& notification.children[1].children.length
&& notification.children[1].children[0].children.length
&& notification.children[1].children[0].children[0].children.length
){
const info = notification.children[1].children[0].children[0];
active.directLink = info.href
active.text = info.innerHTML;
active.textName = info.childNodes[0].textContent.trim();
active.textSpan = info.childNodes[1].textContent;
let linkMatch = info.href.match(/activity\/(\d+)/);
if(linkMatch){
active.link = linkMatch[1];
};
var testType = info.children[0].textContent;
active.type = activityTypes[testType];
if(!active.type){
active.type = "special"; //by default every activity is some weird thing we are displaying as-is
}
else if(
active.type === "forumCommentLike"
|| active.type === "forumSubscribedComment"
|| active.type === "forumCommentReply"
|| active.type === "forumLike"
|| active.type === "forumMention"
){
active.text = info.children[1].textContent;
}
};
if(active.type === "special"){
active.text = notification.children[1].innerHTML;//default
if(notification.children[1].children.length){
const info = notification.children[1].children[0];
if(
info.children.length >= 2
&& info.children[1].textContent === " started following you."
){
active.type = "follow";
active.directLink = info.children[0].href;
active.text = info.children[0].innerHTML;
active.textName = info.children[0].textContent.trim();
active.textSpan = info.children[1].textContent;
}
else if(
info.children.length >= 4
&& info.children[3].textContent === " aired."
){
active.type = "airing";
active.directLink = info.children[0].href;
active.text = info.innerHTML;
};
};
};
if(
notification.children.length > 1
&& notification.children[1].children.length > 1
){
active.time = notification.children[1].children[1].innerHTML;
}
else{
active.time = create("span");
};
active.image = notification.children[0].style.backgroundImage;
active.href = notification.children[0].href;
activities.push(active);
});
notificationDrawer(activities);
for(var i=0;APIcallsUsed < (APIlimit - 5);i++){//heavy
if(!activities.length || i >= activities.length){//loading is difficult to predict. There may be nothing there when this runs
break;
};
let imageCallBack = function(data){
if(!data){
return;
}
pending[data.data.Activity.id + ""] = false;
let type = data.data.Activity.type;
for(var j=0;j div");
if(!mediaCards.length){
setTimeout(function(){
addProgressBar();
},200);//may take some time to load
return;
};
mediaCards.forEach(function(card){
const progressInformation = card.innerText.match(/Progress:\ (\d+)\/(\d+)/);
if(progressInformation){
let pBar = create("meter");
pBar.value = progressInformation[1];
pBar.min = 0;
pBar.max = progressInformation[2];
card.parentNode.insertBefore(pBar,card);
card.parentNode.parentNode.parentNode.querySelector(".plus-progress").onclick = function(){
pBar.value++;
setTimeout(function(){
pBar.value = card.innerText.match(/Progress:\ (\d+)\/(\d+)/)[1];
},1000);
}
};
});
document.querySelector(".size-toggle").onclick = function(){
setTimeout(function(){
addProgressBar();
},200);
};
}
function enhanceCharacter(){//adds a favourite count on every character page
if(!location.pathname.match(/^\/character(\/.*)?/)){
return;
};
if(document.getElementById("hohFavCount")){
return;
};
var filterGroup = document.getElementsByClassName("content");
if(!filterGroup.length){
setTimeout(function(){
enhanceCharacter();
},200);//may take some time to load
return;
};
let favCallback = function(data){
let favButton = document.getElementsByClassName("favourite");
if(!favButton){
setTimeout(function(){
if(location.pathname.match(/^\/character(\/.*)?/)){
favCallback(data);
};
},100);
return;
};
filterGroup = filterGroup[0];
let favCount = create("span","#hohFavCount",false,filterGroup);
if(data.data.Character.favourites === 0 && favButton[0].classList.contains("isFavourite")){//safe to assume
favCount.innerText = data.data.Character.favourites + 1;
}
else{
favCount.innerText = data.data.Character.favourites;
};
if(favButton.length){
favButton[0].onclick = function(){
if(this.classList.contains("isFavourite")){
favCount.innerText = Math.max(parseInt(favCount.innerText)-1,0);//0 or above, just to avoid looking silly
}
else{
favCount.innerText = parseInt(favCount.innerText)+1;
};
};
};
let names = document.querySelector(".content .names");
if(names){
names.innerText = names.innerText.replace(/,$/,"");
};
};
const variables = {id: document.URL.match(/\/character\/(\d+)\/?/)[1]};
generalAPIcall("query($id: Int!){Character(id: $id){favourites}}",variables,favCallback,"hohCharacterFavs" + variables.id,60*60*1000);
let names = document.querySelector(".content .names");
if(names){
names.innerText = names.innerText.replace(/,$/,"");
};
};
function enhanceStudio(){//adds a favourite count to every studio page
if(!location.pathname.match(/^\/studio(\/.*)?/)){
return;
};
var filterGroup = document.querySelector(".container.header");
if(!filterGroup){
setTimeout(function(){
enhanceStudio();
},200);//may take some time to load
return;
};
let favCallback = function(data){
let favButton = document.getElementsByClassName("favourite");
if(!favButton){
setTimeout(function(){
if(location.pathname.match(/^\/studio(\/.*)?/)){
favCallback(data);
};
},100);
return;
};
let favCount = create("span","#hohFavCount",false,filterGroup,"top:-10px;");
if(data.data.Studio.favourites === 0 && favButton[0].classList.contains("isFavourite")){//safe to assume
favCount.innerText = data.data.Studio.favourites + 1;
}
else{
favCount.innerText = data.data.Studio.favourites;
};
if(favButton.length){
favButton[0].onclick = function(){
if(this.classList.contains("isFavourite")){
favCount.innerText = Math.max(parseInt(favCount.innerText)-1,0);//0 or above, just to avoid looking silly
}
else{
favCount.innerText = parseInt(favCount.innerText)+1;
};
};
};
let scoreSum = 0;
let amount = 0;
data.data.Studio.media.nodes.forEach(function(media){
if(media.meanScore){
scoreSum += media.meanScore;
amount++;
}
});
if(amount){
let scoreAverage = create("span","#hohFavCount",
(scoreSum/amount).roundPlaces(1) + "%",
filterGroup,"top:45px;color:rgb(var(--color-blue));z-index:45;font-size:1.2rem;"
);
}
};
const variables = {id: location.pathname.match(/\/studio\/(\d+)\/?/)[1]};
generalAPIcall(
`
query($id: Int!){
Studio(id: $id){
favourites
media(isMain:true,sort:POPULARITY_DESC){
nodes{
meanScore
}
}
}
}`,
variables,favCallback,"hohStudioFavs" + variables.id,60*60*1000
);
};
function returnList(list,skipProcessing){
let retl = [];
for(var i=0;i 100){
retlObj.scoreRaw = 100;
}
if(!retlObj.media.episodes && retlObj.media.nextAiringEpisode){
retlObj.media.episodes = retlObj.media.nextAiringEpisode.episode - 1;
}
if(retlObj.notes){
retlObj.listJSON = parseListJSON(retlObj.notes);
};
};
retl.push(retlObj);
};
};
retl.sort((a,b) => a.mediaId - b.mediaId);
for(var i=1;i a.mediaId - b.mediaId);
let list2 = returnList(data).filter(element => element.scoreRaw);
let list3 = [];
let indeks1 = 0;
let indeks2 = 0;
while(indeks1 < list.length && indeks2 < list2.length){
if(list2[indeks2].mediaId > list[indeks1].mediaId){
indeks1++;
continue;
};
if(list2[indeks2].mediaId < list[indeks1].mediaId){
indeks2++;
continue;
};
if(list2[indeks2].mediaId === list[indeks1].mediaId){
list3.push({
mediaId: list[indeks1].mediaId,
score1: list[indeks1].scoreRaw,
score2: list2[indeks2].scoreRaw
});
indeks1++;
indeks2++;
};
};
let average1 = 0;
let average2 = 0;
list3.forEach(function(item){
average1 += item.score1;
average2 += item.score2;
item.sdiff = item.score1 - item.score2;
});
average1 = average1/list3.length;
average2 = average2/list3.length;
let standev1 = 0;
let standev2 = 0;
list3.forEach(function(item){
standev1 += Math.pow(item.score1 - average1,2);
standev2 += Math.pow(item.score2 - average2,2);
});
standev1 = Math.sqrt(standev1/(list3.length - 1));
standev2 = Math.sqrt(standev2/(list3.length - 1));
let difference = 0;
list3.forEach(function(item){
difference += Math.abs(
(item.score1 - average1)/standev1
- (item.score2 - average2)/standev2
);
});
difference = difference/list3.length;
let differenceSpan = create("span",false,difference.roundPlaces(3));
if(difference < 0.9){
differenceSpan.style.color = "green";
}
else if(difference > 1.1){
differenceSpan.style.color = "red";
};
targetLocation.innerText = "";
targetLocation.appendChild(differenceSpan);
let countSpan = create("span",false," based on " + list3.length + " shared entries. Lower is better. 0.8 - 1.1 is common",targetLocation);
let canvas = create("canvas",false,false,targetLocation,"display:block;");
canvas.width = 200;
canvas.height = 100;
let r1 = Math.sqrt(list.length/(list.length + list2.length));
let r2 = Math.sqrt(list2.length/(list.length + list2.length));
let distance;
if(list3.length === list.length || list3.length === list2.length){
distance = Math.abs(r1 - r2);
}
else if(list3.length === 0){
distance = r1 + r2;
}
else{
let areaOfIntersection = function(d,r0,r1){
let rr0 = r0 * r0;
let rr1 = r1 * r1;
let phi = (Math.acos((rr0 + (d * d) - rr1) / (2 * r0 * d))) * 2;
let theta = (Math.acos((rr1 + (d * d) - rr0) / (2 * r1 * d))) * 2;
let area1 = 0.5 * theta * rr1 - 0.5 * rr1 * Math.sin(theta);
let area2 = 0.5 * phi * rr0 - 0.5 * rr0 * Math.sin(phi);
return area1 + area2;
};
let overlapArea = Math.PI*list3.length/(list.length + list2.length);
let pivot0 = Math.abs(r1 - r2);
let pivot1 = r1 + r2;
while(pivot1 - pivot0 > (r1 + r2)/100){
distance = (pivot0 + pivot1)/2;
if(areaOfIntersection(distance,r1,r2) > overlapArea){
pivot0 = distance;
}
else{
pivot1 = distance;
}
};
}
let ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.fillStyle = "rgb(61,180,242)";
ctx.arc(50,50,50*r1,0,2*Math.PI);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "rgb(250,122,122)";
ctx.arc(50 + 50*distance,50,50*r2,0,2*Math.PI);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "rgb(61,180,242,0.5)";
ctx.arc(50,50,50*r1,0,2*Math.PI);
ctx.fill();
},"hohCompat" + variables.listType + variables.name,5*60*1000);
}
//used by the stats module, and to safeguard the manga chapter guesses
const commonUnfinishedManga = {
"53390":{//aot
chapters:116,
volumes:26
},
"30002":{//berserk
chapters:358,
volumes:40
},
"30013":{//one piece
chapters:942,
volumes:92
},
"85486":{//mha
chapters:202,
volumes:20
},
"74347":{//opm
chapters:154,
volumes:17
},
"30026":{//HxH
chapters:390,
volumes:36
},
"30656":{//vagabond
chapters:327,
volumes:37
},
"30105":{//yotsuba&
chapters:105,
volumes:14
}
};
const listCreatedTime = new Date(2019,4,26);
const currentTime = new Date();
if(currentTime - listCreatedTime > 365*24*60*60*1000){
console.log("remind hoh to update the commonUnfinishedManga list");
};
function settingsPage(){
if(!location.pathname.match(/\/apps\/?$/)){
return;
};
if(document.getElementById("hohSettings")){
return;
};
let targetLocation = document.querySelector(".settings.container .content");
let hohSettings = create("div","#hohSettings",false,targetLocation);
let scriptStatsHead = create("h1",false,"Aniscripts Settings",hohSettings);
let scriptStats = create("div",false,false,hohSettings);
let sVersion = create("p",false,false,scriptStats);
sVersion.innerHTML = "Version: " + scriptInfo.version + "";
let sHome = create("p",false,"Homepage: ",scriptStats);
let sHomeLink = create("a",false,scriptInfo.link,sHome);
sHomeLink.href = scriptInfo.link;
create("p",false,"Some changes requires reloading the page.",scriptStats);
let scriptSettings = create("div",false,false,hohSettings);
useScriptsDefinitions.forEach(function(def){
let setting = create("p");
if(def.visible === false){
setting.style.display = "none";
};
if(def.hasOwnProperty("type")){//other kinds of input
let input;
if(def.type === "select"){
input = create("select",false,false,setting);
def.values.forEach(function(value){
let option = create("option",false,value,input);
option.value = value;
});
}
if(def.type === "text"){
input = create("input",false,false,setting);
}
else if(def.type === "heading"){
input = create("h3",false,def.heading,setting);
}
if(def.type != "heading"){
input.targetSetting = def.id;
input.value = useScripts[def.id];
input.onchange = function(){
useScripts[this.targetSetting] = this.value;
useScripts.save();
};
}
}
else{//default: a checkbox
let input = createCheckbox(setting);
input.targetSetting = def.id;
input.checked = useScripts[def.id];
input.onchange = function(){
useScripts[this.targetSetting] = this.checked;
useScripts.save();
};
};
create("span",false,def.description,setting);
scriptSettings.appendChild(setting);
});
let titleAliasSettings = create("div");
let titleAliasInstructions = create("p");
titleAliasInstructions.innerText = `
Add title aliases. Use the format /type/id/alias , one per line. Examples:
/anime/5114/Fullmetal Alchemist
/manga/30651/Nausicaä
Changes take effect on reload.`;
let titleAliasInput = create("textarea","#titleAliasInput");
let localStorageItem = localStorage.getItem("titleAliases");
if(localStorageItem != null && localStorageItem != ""){
JSON.parse(localStorageItem).forEach(function(alias){;
titleAliasInput.value += alias[0] + alias[1] + "\n";
});
};
titleAliasInput.rows = "6";
titleAliasInput.cols = "50";
let titleAliasChange = create("button",["hohButton","button"],"Submit");
titleAliasChange.onclick = function(){
let newAliases = [];
let aliasContent = titleAliasInput.value.split("\n");
let aliasRegex = /^(\/(anime|manga)\/\d+\/)(.*)/;
let cssAlias = /^(css\/)(.*)/;
for(var i=0;i a.stats.watchedTime)
: Array.from(data.data.Page.users,(a) => a.stats.chaptersRead)
);
if(block[block.length - 1] > amount){
recursiveCall(userName,amount,Math.floor((currentPage + 1 + maxPage)/2),currentPage + 1,maxPage,type);
return;
}
else if(block[0] > amount){
block.forEach(function(item,index){
if(amount === item){
ranks[type].innerText = type.capitalize() + " rank: " + ((currentPage - 1)*50 + index + 1);
return;
};
});
}
else if(block[0] === amount){
if(minPage === currentPage){
ranks[type].innerText = type.capitalize() + " rank: " + ((currentPage-1)*50 + 1);
}
else{
recursiveCall(userName,amount,Math.floor((minPage + currentPage)/2),minPage,currentPage,type);
};
return;
}
else{
recursiveCall(userName,amount,Math.floor((minPage + currentPage - 1)/2),minPage,currentPage - 1,type);
return;
};
},"hohRank" + type + currentPage,60*60*1000
);
};
recursiveCall(user,data.data.User.stats.watchedTime,1000,1,undefined,"anime");
recursiveCall(user,data.data.User.stats.chaptersRead,500,1,undefined,"manga");
},"hohRankStats" + user,2*60*1000
);
}},
{name: "Hidden media entries",code: function(){
miscResults.innerText = "";
let pageCounter = create("p",false,false,miscResults);
let pager = function(page,user){
generalAPIcall(
`
query ($userName: String,$page:Int) {
Page(page:$page){
pageInfo{
currentPage
lastPage
}
mediaList(userName:$userName){
hiddenFromStatusLists
mediaId
media{
type
title{romaji}
}
customLists(asArray:true)
}
}
}
`,
{
page: page,
userName: user
},
function(data){
if(data.data.Page.pageInfo.currentPage < data.data.Page.pageInfo.lastPage){
setTimeout(function(){
pager(data.data.Page.pageInfo.currentPage + 1,user);
},800);
}
pageCounter.innerText = "Searching page " + data.data.Page.pageInfo.currentPage + " of " + data.data.Page.pageInfo.lastPage;
data.data.Page.mediaList.forEach(function(media){
if(media.hiddenFromStatusLists === true){
if(media.customLists.every(cl => cl.enabled === false)){
let newLink = document.createElement("a");
newLink.innerText = media.media.title.romaji;
newLink.href = "https://anilist.co/" + media.media.type.toLowerCase() + "/" + media.mediaId;
miscResults.appendChild(newLink);
miscResults.appendChild(create("br"));
}
}
});
}
);
};pager(1,user);
}}
];
let miscInputSelect = create("select",false,false,miscInput);
let miscInputButton = create("button",["button","hohButton"],"Run",miscInput);
availableQueries.forEach(function(que){
let option = create("option",false,que.name,miscInputSelect);
option.value = que.name;
});
miscInputButton.onclick = function(){
miscResults.innerText = "Loading...";
availableQueries.find(que => que.name === miscInputSelect.value).code();
}
//gather some stats
let currentTime = new Date();
let expired = (currentTime.valueOf() - useScripts.databaseStats.updated) > 10*60*1000;//ten min
let query = "query($page:Int,$type:MediaType){Page(page:$page){pageInfo{total}media(type:$type){id}}}";
let generalStatCall = function(type,path,isMedia){
let updater = function(data){
let target = document.getElementById("hohTotal" + type + "Target");
target.innerText = data.data.Page.pageInfo.total;
target.style.cursor = "pointer";
target.title = "go to a random " + path;
target.onclick = function(){
const selected = Math.floor(Math.random()*data.data.Page.pageInfo.total);
generalAPIcall(
isMedia ? query : "query($page:Int){Page(page:$page){pageInfo{total}" + type + "{id}}}",
{page:Math.ceil(selected/50),type:type.toUpperCase()},
function(data){
window.location.href = "https://anilist.co/" + path + "/" + data.data.Page[isMedia ? "media" : type][selected % 50].id + "/";
}
)
};
}
updater({data:{Page:{pageInfo:{total:useScripts.databaseStats[type]}}}});//cache
if(expired){
generalAPIcall(
isMedia ? query : "query($page:Int){Page(page:$page){pageInfo{total}" + type + "{id}}}",
{page:0,type:type.toUpperCase()},
function(data){
useScripts.databaseStats[type] = data.data.Page.pageInfo.total;
useScripts.save();
updater(data);
}
);
}
};
generalStatCall("anime","anime",true);
generalStatCall("manga","manga",true);
generalStatCall("users","user");
generalStatCall("staff","staff");//nasty plurals in the API
generalStatCall("characters","character");
generalStatCall("reviews","review");
if(expired){
useScripts.databaseStats.updated = currentTime.valueOf();
useScripts.save();
};
var customTagsCollection = function(list,title,fields){
let customTags = [];
let regularTags = [];
let customLists = [];
const localStorageItem = JSON.parse(localStorage.getItem("regularTags" + title));
if(localStorageItem){
localStorageItem.forEach(function(tag){
regularTags.push({
name : tag,
list : []
});
});
};
list.forEach(function(media){
let item = {};
fields.forEach(function(field){
item[field.key] = field.method(media);
});
if(media.notes){
var tagMatches = media.notes.match(/(#\S+)/g);
if(tagMatches){
for(var j=0;j a.list.length - b.list.length);
};
var regularTagsCollection = function(list,fields){
let tags = [];
list.forEach(function(media){
let item = {};
fields.forEach(function(field){
item[field.key] = field.method(media);
});
media.media.tags.forEach(function(tag){
var foundFlag = false;
for(var i=0;i a.average - b.average);
};
let drawTable = function(data,formatter,tableLocation){
while(tableLocation.childElementCount){
tableLocation.removeChild(tableLocation.lastChild);
};
const randomData = "data-v-e2beaf26";//some native css selectors want this
let header = create("p",false,formatter.title);
let tableContent = create("div","table");
tableContent.setAttribute(randomData,"");
let headerRow = create("div",["header","row"],false,tableContent);
headerRow.setAttribute(randomData,"");
let indexAccumulator = 0;
formatter.headings.forEach(function(heading){
let columnTitle = create("div",false,heading,headerRow);
if(formatter.focus === indexAccumulator){
columnTitle.innerHTML += " " + svgAssets.angleDown;
};
columnTitle.setAttribute(randomData,"");
columnTitle.index = +indexAccumulator;
columnTitle.addEventListener("click",function(){
formatter.focus = this.index;
data.sort(formatter.sorting[this.index]);
drawTable(data,formatter,tableLocation);
});
indexAccumulator++;
});
for(var i=0;i a.score - b.score);
}
else{
data[i].list.sort(formatter.sorting[formatter.focus]);
}
for(var j=0;j 1){
cel.innerHTML = svgAssets.repeat + data[index].repeat;
}
}
},
function(cel,data,index,isPrimary){
if(isPrimary){
if(data[index].average === 0){
cel.innerText = "-";
}
else{
cel.innerText = Math.round(data[index].average);
}
}
else{
if(data[index].score === 0){
cel.innerText = "-";
}
else{
cel.innerText = Math.round(data[index].score);
}
}
},
function(cel,data,index,isPrimary){
if(!isPrimary && data[index].type === "MANGA"){
cel.innerText = "-";
}
else if(data[index].duration === 0){
cel.innerText = "-";
}
else if(data[index].duration < 60){
cel.innerText = Math.round(data[index].duration) + "min";
}
else{
cel.innerText = Math.round(data[index].duration/60) + "h";
};
},
function(cel,data,index,isPrimary){
if(isPrimary || data[index].type === "MANGA"){
cel.innerText = data[index].chaptersRead;
}
else{
cel.innerText = "-";
}
}
],
sorting : [
(a,b) => ("" + a.name).localeCompare(b.name),
(b,a) => a.list.length - b.list.length,
(b,a) => a.average - b.average,
(b,a) => a.duration - b.duration,
(b,a) => a.chaptersRead - b.chaptersRead
]
};
let collectedMedia = semaPhoreAnime.concat(semaPhoreManga);
let listOfTags = regularTagsCollection(collectedMedia,mixedFields);
for(var i=0;i div > h2");
if(possibleNativeLocation && possibleNativeLocation.length > 1 && possibleNativeLocation[1].innerText === "Tags"){
if(possibleNativeLocation[1].nextSibling.id != "regularTagsTable"){
let regularTagsTable = create("div","#regularTagsTable");
possibleNativeLocation[1].parentNode.insertBefore(regularTagsTable,possibleNativeLocation[1].nextSibling);
drawTable(listOfTags,mixedFormatter,regularTagsTable);
possibleNativeLocation[1].parentNode.lastChild.style.display = "none";
};
}
setTimeout(checkNativeTable,200);
};
checkNativeTable();
//recycle most of the formatter for genres
mixedFormatter.headings[0] = "Genre";
mixedFormatter.celData[0] = function(cel,data,index,isPrimary){
if(isPrimary){
let nameCellCount = create("div","count",(index+1),cel);
nameCellCount.setAttribute("data-v-e2beaf26","");
let nameCellTag = create("a",false,data[index].name,cel,"cursor:pointer;");
nameCellTag.setAttribute("data-v-2f71893a","");
nameCellTag.href = "https://anilist.co/search/anime?includedGenres=" + data[index].name + "&onList=true";
if(tagDescriptions[data[index].name]){
nameCellTag.title = tagDescriptions[data[index].name];
}
}
else{
let nameCellTag = create("a","title",data[index].name,cel,"margin-left:50px;display:block;");
nameCellTag.setAttribute("data-v-2f71893a","");
if(data[index].type === "ANIME"){
nameCellTag.href = "/anime/" + data[index].mediaId + "/";
nameCellTag.style.color = "rgb(var(--color-blue))";
}
else{
nameCellTag.href = "/manga/" + data[index].mediaId + "/";
nameCellTag.style.color = "rgb(var(--color-green))";
};
}
};
collectedMedia.forEach(function(entry){//swap out the tags for genres so we can reuse the code
entry.media.tags = [];
entry.media.genres.forEach(function(genre){
entry.media.tags.push({name:genre});
});
});
let listOfGenres = regularTagsCollection(collectedMedia,mixedFields);
let checkNativeTable2 = function(){
if(!document.URL.match(/\/stats$/)){
return;
};
let possibleNativeLocation = document.querySelectorAll(".stats-wrap > div > h2");
if(possibleNativeLocation && possibleNativeLocation.length && possibleNativeLocation[0].innerText === "Genres"){
if(possibleNativeLocation[0].nextSibling.id != "regularGenresTable"){
let regularGenresTable = create("div","#regularGenresTable");
possibleNativeLocation[0].parentNode.insertBefore(regularGenresTable,possibleNativeLocation[0].nextSibling);
drawTable(listOfGenres,mixedFormatter,regularGenresTable);
possibleNativeLocation[0].parentNode.lastChild.style.display = "none";
};
}
setTimeout(checkNativeTable2,200);
};
checkNativeTable2();
};
//get anime list
let personalStatsCallback = function(data){
personalStats.innerText = "";
const thisName = document.URL.match(/\/([\w\-]+)\/stats/)[1];
create("hr",false,false,personalStats)
create("h1",false,"Anime stats for " + thisName,personalStats);
let list = returnList(data);
let scoreList = list.filter(element => element.scoreRaw);
if(whoAmI != thisName){
let compatabilityButton = create("button",["button","hohButton"],"Compatibility",personalStats);
compatabilityButton.onclick = function(){
compatCheck(
scoreList,
whoAmI,"hohCheckCompat","ANIME")
};
create("div","#hohCheckCompat",false,personalStats);
};
let addStat = function(text,value,comment){//value,value,html
let newStat = create("p","hohStat",false,personalStats);
create("span",false,text,newStat);
create("span","hohStatValue",value,newStat);
if(comment){
let newStatComment = create("span",false,false,newStat);
newStatComment.innerHTML = comment;
};
};
//first activity
let oldest = list.filter(
item => item.startedAt.year
).map(
item => item.startedAt
).sort((b,a) =>
(a.year < b.year)
|| (a.year === b.year && a.month < b.month)
|| (a.year === b.year && a.month === b.month && a.day < b.day)
)[0];
//scoring stats
let previouScore = 0;
let maxRunLength = 0;
let maxRunLengthScore = 0;
let runLength = 0;
let sumEntries = 0;
let amount = scoreList.length;
let sumWeight = 0;
let sumEntriesWeight = 0;
let average = 0;
let median = 0;
let sumDuration = 0;
let standardDeviation = 0;
let longestDuration = {
time: 0,
name: "",
status: "",
rewatch: 0,
id: 0
};
scoreList.sort((a,b) => a.scoreRaw - b.scoreRaw);
list.forEach(function(item){
let entryDuration = (item.media.duration || 1)*(item.progress|0);//curent round
item.episodes = (item.progress|0);
if(useScripts.noRewatches && (item.repeat|0)){
entryDuration = Math.max(1,(item.media.episodes|0),(item.progress|0))*(item.media.duration || 1);//first round
item.episodes = Math.max(1,(item.media.episodes|0),(item.progress|0));
}
else{
entryDuration += (item.repeat|0)*Math.max(1,(item.media.episodes|0),(item.progress|0))*(item.media.duration || 1);//repeats
item.episodes += (item.repeat|0)*Math.max(1,(item.media.episodes|0),(item.progress|0));
}
if(item.listJSON && item.listJSON.adjustValue){
item.episodes = Math.max(0,item.episodes + item.listJSON.adjustValue);
entryDuration = Math.max(0,entryDuration + item.listJSON.adjustValue*(item.media.duration || 1));
};
item.watchedDuration = entryDuration;
sumDuration += entryDuration;
if(entryDuration > longestDuration.time){
longestDuration.time = entryDuration;
longestDuration.name = item.media.title.romaji;
longestDuration.status = item.status;
longestDuration.rewatch = item.repeat;
longestDuration.id = item.mediaId;
};
});
if(scoreList.length % 2){
median = scoreList[(scoreList.length-1)/2].scoreRaw;
}
else if(scoreList.length){
median = scoreList[(scoreList.length)/2].scoreRaw/2 + scoreList[(scoreList.length)/2-1].scoreRaw/2;
};
scoreList.forEach(function(item){
sumEntries += item.scoreRaw;
if(item.scoreRaw === previouScore){
runLength++;
if(runLength > maxRunLength){
maxRunLength = runLength;
maxRunLengthScore = item.scoreRaw;
};
}
else{
runLength = 1;
previouScore = item.scoreRaw;
};
sumWeight += (item.media.duration || 1)*(item.media.episodes|0);
sumEntriesWeight += item.scoreRaw*(item.media.duration || 1)*(item.media.episodes|0);
});
if(amount){
average = sumEntries/amount;
}
if(scoreList.length){
standardDeviation = Math.sqrt(
scoreList.map(a => a.scoreRaw).reduce(
(accum,element) => accum + Math.pow(average - element,2)
)/amount
);
}
list.sort((a,b) => a.mediaId - b.mediaId);
//display scoring stats
addStat("Anime on list: ",list.length);
addStat("Anime rated: ",amount);
if(amount != 0){//no scores
if(amount === 1){
addStat("Only one score given: ",maxRunLengthScore);
}
else{
addStat(
"Average score: ",
average.roundPlaces(2)
);
addStat(
"Average score: ",
(sumEntriesWeight/sumWeight).roundPlaces(2),
" (weighted by duration)"
);
addStat("Median score: ",median);
addStat(
"Standard deviation: ",
standardDeviation.roundPlaces(2)
);
if(maxRunLength > 1){
addStat("Most common score: ",maxRunLengthScore, " (" + maxRunLength + " instances)");
}
else{
addStat("Most common score: ","","no two scores alike");
};
};
//longest activity
let singleText = (100*longestDuration.time/sumDuration).roundPlaces(2) + "% is ";
singleText += "" + longestDuration.name + "";
if(longestDuration.rewatch === 0){
if(longestDuration.status === "CURRENT"){
singleText += ". Currently watching."
}
else if(longestDuration.status === "PAUSED"){
singleText += ". On hold."
}
else if(longestDuration.status === "DROPPED"){
singleText += ". Dropped."
};
}
else{
if(longestDuration.status === "COMPLETED"){
if(longestDuration.rewatch === 1){
singleText += ". Rewatched once.";
}
else if(longestDuration.rewatch === 2){
singleText += ". Rewatched twice.";
}
else{
singleText += ". Rewatched " + longestDuration.rewatch + " times.";
};
}
else if(longestDuration.status === "CURRENT" || status === "REPEATING"){
if(longestDuration.rewatch === 1){
singleText += ". First rewatch in progress.";
}
else if(longestDuration.rewatch === 2){
singleText += ". Second rewatch in progress.";
}
else{
singleText += ". Rewatch number " + longestDuration.rewatch + " in progress.";
};
}
else if(longestDuration.status === "PAUSED"){
if(longestDuration.rewatch === 1){
singleText += ". First rewatch on hold.";
}
else if(longestDuration.rewatch === 2){
singleText += ". Second rewatch on hold.";
}
else{
singleText += ". Rewatch number " + longestDuration.rewatch + " on hold.";
};
}
else if(longestDuration.status === "DROPPED"){
if(longestDuration.rewatch === 1){
singleText += ". Dropped on first rewatch.";
}
else if(longestDuration.rewatch === 2){
singleText += ". Dropped on second rewatch.";
}
else{
singleText += ". Dropped on rewatch number " + longestDuration.rewatch + ".";
};
};
};
addStat(
"Time watched: ",
(sumDuration/(60*24)).roundPlaces(2),
" days (" + singleText + ")"
);
};
let TVepisodes = 0;
let TVepisodesLeft = 0;
list.filter(show => show.media.format === "TV").forEach(function(show){
TVepisodes += show.progress;
TVepisodes += show.repeat * Math.max(1,(show.media.episodes|0),show.progress);
if(show.status === "CURRENT"){
TVepisodesLeft += Math.max((show.media.episodes|0) - show.progress,0);
};
});
addStat("TV episodes watched: ",TVepisodes);
addStat("TV episodes remaining for current shows: ",TVepisodesLeft);
let tagless = list.filter(
show => show.media.tags.length === 0 && show.status != "PLANNING"
).map(
show => ({
id: show.mediaId,
name: show.media.title.romaji
})
);
if(tagless.length){
create("p",false,"Some shows on your list have no tags. Would you like to help with that?",personalStats);
for(var i=0;i largestValue){
largestValue = distribution[format][statusi];
};
};
};
};
};
let yAxisLimit = Math.ceil(
largestValue/Math.pow(10,(largestValue+"").length-1)
)*Math.pow(10,(largestValue+"").length-1);//cast to string and check the length is floor(log10(x))
let diagramFill = function(statusHeaders,formatHeaders,statusArray,formatArray){
const chartHeight = margins.height - margins.chartTextBottom - margins.bottom - margins.top;
ctx.fillStyle = "rgb(133,150,165)";
ctx.strokeStyle = "rgb(133,150,165)";
ctx.textAlign = "end";
ctx.fillText(yAxisLimit,margins.left + 20,margins.top);
ctx.fillText(0,margins.left + 20,margins.top + chartHeight);
ctx.fillText(yAxisLimit/2,margins.left + 20,margins.top + chartHeight/2);
const chartCellWidth = 100;
ctx.textAlign = "center";
for(var i=0;i 1){
cel.innerHTML += svgAssets.repeat + data[index].repeat;
}
}
},
function(cel,data,index,isPrimary){
if(isPrimary){
if(data[index].average === 0){
cel.innerText = "-";
}
else{
cel.innerText = Math.round(data[index].average);
}
}
else{
if(data[index].score === 0){
cel.innerText = "-";
}
else{
cel.innerText = Math.round(data[index].score);
}
}
},
function(cel,data,index){
if(data[index].duration === 0){
cel.innerText = "-";
}
else if(data[index].duration < 60){
cel.innerText = Math.round(data[index].duration) + "min";
}
else{
cel.innerText = Math.round(data[index].duration/60) + "h";
};
},
function(cel,data,index){
cel.innerText = data[index].episodes;
},
function(cel,data,index){
if(data[index].episodes === 0 && data[index].remaining === 0){
cel.innerText = "-";
}
else if(data[index].remaining === 0){
cel.innerText = "completed";
}
else{
if(useScripts.timeToCompleteColumn){
if(data[index].remainingTime < 60){
cel.innerText = data[index].remaining + " (" + data[index].remainingTime + "min)";
}
else{
cel.innerText = data[index].remaining + " (" + Math.round(data[index].remainingTime/60) + "h)";
};
}
else{
cel.innerText = data[index].remaining;
}
}
}
],
sorting: [
(a,b) => ("" + a.name).localeCompare(b.name),
(b,a) => a.list.length - b.list.length,
(b,a) => a.average - b.average,
(b,a) => a.duration - b.duration,
(b,a) => a.episodes - b.episodes,
(b,a) => a.remaining - b.remaining
]
};
const animeFields = [
{
key : "name",
sumable : false,
method : function(media){
if(useScripts.titleLanguage === "Native" && media.media.title.native){
return media.media.title.native;
}
else if(useScripts.titleLanguage === "English" && media.media.title.english){
return media.media.title.english;
}
return media.media.title.romaji;
}
},{
key : "mediaId",
sumable : false,
method : function(media){
return media.mediaId;
}
},{
key : "score",
sumable : false,
method : function(media){
return media.scoreRaw;
}
},{
key : "repeat",
sumable : false,
method : function(media){
return media.repeat;
}
},{
key : "status",
sumable : false,
method : function(media){
return media.status;
}
},{
key : "duration",
sumable : true,
method : function(media){
return media.watchedDuration;
}
},{
key : "episodes",
sumable : true,
method : function(media){
return media.episodes;
}
},{
key : "remaining",
sumable : true,
method : function(media){
return Math.max((media.media.episodes|0) - media.progress,0);
}
},{
key : "remainingTime",
sumable : true,
method : function(media){
return Math.max(((media.media.episodes|0) - media.progress) * (media.media.duration || 1),0);
}
}
];
let customTags = customTagsCollection(list,animeFormatter.title,animeFields);
if(customTags.length){
let customTagsAnimeTable = create("div","#customTagsAnimeTable",false,personalStats);
drawTable(customTags,animeFormatter,customTagsAnimeTable);
};
semaPhoreAnime = list;
nativeTagsReplacer();
};
generalAPIcall(
queryMediaList,
{
name: document.URL.match(/\/([\w\-]+)\/stats\/?$/)[1],
listType: "ANIME"
},
personalStatsCallback
);
//manga stats
let personalStatsMangaCallback = function(data){
let thisName = document.URL.match(/\/([\w\-]+)\/stats/)[1];
personalStatsManga.innerText = "";
create("hr",false,false,personalStatsManga);
create("h1",false,"Manga stats for " + thisName,personalStatsManga);
let list = returnList(data);
let scoreList = list.filter(element => element.scoreRaw);
let personalStatsMangaContainer = create("div",false,false,personalStatsManga);
if(whoAmI != thisName){
let compatabilityButton = create("button",["button","hohButton"],"Compatibility",personalStatsManga);
compatabilityButton.onclick = function(){
compatCheck(
scoreList,
whoAmI,"hohCheckCompatManga","MANGA")
};
create("div","#hohCheckCompatManga",false,personalStatsManga);
};
let addStat = function(text,value,comment){//value,value,html
let newStat = create("p","hohStat",false,personalStatsManga);
create("span",false,text,newStat);
create("span","hohStatValue",value,newStat);
if(comment){
let newStatComment = create("span",false,false,newStat);
newStatComment.innerHTML = comment;
};
};
let chapters = 0;
let volumes = 0;
/*
For most airing anime, Anilist provides "media.nextAiringEpisode.episode"
Unfortunately, the same is not the case for releasing manga.
THIS DOESN'T MATTER the first time a user is reading something, as we are then just using the current progress.
But on a re-read, we need the total length to count all the chapters read.
I can (and do) get a lower bound for this by using the current progress (this is what Anilist does),
but this is not quite accurate, especially early in a re-read.
The list below is to catch some of those exceptions
*/
let unfinishedLookup = function(mediaId,mode,mediaStatus,mediaProgress){
if(mediaStatus === "FINISHED"){
return 0;//it may have finished since the list was updated
};
if(commonUnfinishedManga.hasOwnProperty(mediaId)){
if(mode === "chapters"){
return commonUnfinishedManga[mediaId].chapters;
}
else if(mode === "volumes"){
return commonUnfinishedManga[mediaId].volumes;
}
else if(mode === "volumesNow"){
if(commonUnfinishedManga[mediaId].chapters <= mediaProgress){
return commonUnfinishedManga[mediaId].volumes;
}
else{
return 0;//conservative
};
};
return 0;//fallback
}
else{
return 0;//not in our list
};
};
list.forEach(function(item){
let chaptersRead = 0;
let volumesRead = 0;
if(item.status === "COMPLETED"){//if it's completed, we can make some safe assumptions
chaptersRead += Math.max(//chapter progress on the current read
item.media.chapters,//in most cases, it has a chapter count
item.media.volumes,//if not, there's at least 1 chapter per volume
item.progress,//if it doesn't have a volume count either, the current progress is probably not out of date
item.progressVolumes,//if it doesn't have a chapter progress, count at least 1 chapter per volume
1//finally, an entry has at least 1 chapter
);
volumesRead += Math.max(
item.progressVolumes,
item.media.volumes,
unfinishedLookup(item.mediaId+"","volumesNow",item.media.status,item.progress)//if people have forgotten to update their volume count and have caught up.
);
}
else{//we may only assume what's on the user's list.
chaptersRead += Math.max(
item.progress,
item.progressVolumes
);
volumesRead += Math.max(
item.progressVolumes,
unfinishedLookup(item.mediaId+"","volumesNow",item.media.status,item.progress)
);
};
if(useScripts.noRewatches && (item.repeat|0)){//if they have a reread, they have at least completed it
chaptersRead = Math.max(//first round
item.media.chapters,
item.media.volumes,
item.progress,
item.progressVolumes,
unfinishedLookup(item.mediaId+"","chapters",item.media.status),//use our lookup table
1
);
volumesRead = Math.max(
item.media.volumes,
item.progressVolumes,
unfinishedLookup(item.mediaId+"","volumes",item.media.status)
);
}
else{
chaptersRead += item.repeat * Math.max(//chapters from rereads
item.media.chapters,
item.media.volumes,
item.progress,
item.progressVolumes,
unfinishedLookup(item.mediaId+"","chapters",item.media.status),//use our lookup table
1
);
volumesRead += item.repeat * Math.max(//many manga have no volumes, so we can't make all of the same assumptions
item.media.volumes,
item.progressVolumes,//better than nothing if a volume count is missing
unfinishedLookup(item.mediaId+"","volumes",item.media.status)
);
};
if(item.listJSON && item.listJSON.adjustValue){
chaptersRead = Math.max(0,chaptersRead + item.listJSON.adjustValue);
};
chapters += chaptersRead;
volumes += volumesRead;
item.volumesRead = volumesRead;
item.chaptersRead = chaptersRead;
});
//
let previouScore = 0;
let maxRunLength = 0;
let maxRunLengthScore = 0;
let runLength = 0;
let sumEntries = 0;
let average = 0;
let standardDeviation = 0;
let amount = scoreList.length;
let median = 0
scoreList.sort((a,b) => a.scoreRaw - b.scoreRaw);
if(scoreList.length % 2){
median = scoreList[(scoreList.length-1)/2].scoreRaw;
}
else if(scoreList.length){
median = scoreList[(scoreList.length)/2].scoreRaw/2 + scoreList[(scoreList.length)/2-1].scoreRaw/2;
};
scoreList.forEach(function(item){
sumEntries += item.scoreRaw;
if(item.scoreRaw === previouScore){
runLength++;
if(runLength > maxRunLength){
maxRunLength = runLength;
maxRunLengthScore = item.scoreRaw;
};
}
else{
runLength = 1;
previouScore = item.scoreRaw;
};
});
addStat("Manga on list: ",list.length);
addStat("Manga rated: ",amount);
addStat("Total chapters: ",chapters);
addStat("Total volumes: ",volumes);
if(amount){
average = sumEntries/amount;
};
if(scoreList.length){
standardDeviation = Math.sqrt(
scoreList.map(a => a.scoreRaw).reduce(
(accum,element) => accum + Math.pow(average - element,2)
)/amount
);
}
list.sort((a,b) => a.mediaId - b.mediaId);
if(amount){//no scores
if(amount === 1){
addStat(
"Only one score given: ",
maxRunLengthScore
);
}
else{
addStat(
"Average score: ",
average.roundPlaces(2)
);
addStat("Median score: ",median);
addStat(
"Standard deviation: ",
standardDeviation.roundPlaces(2)
);
if(maxRunLength > 1){
addStat("Most common score: ",maxRunLengthScore, " (" + maxRunLength + " instances)");
}
else{
addStat("Most common score: ","","no two scores alike");
};
};
};
//
let mangaFormatter = {
title: "Custom Manga Tags",
display: !useScripts.hideCustomTags,
headings: ["Tag","Count","Mean Score","Chapters","Volumes"],
focus: 1,
celData: [
function(cel,data,index,isPrimary){
if(isPrimary){
let nameCellCount = ("div","count",(index+1),cel);
nameCellCount.setAttribute("data-v-e2beaf26","");
let nameCellTag = create("a",false,data[index].name,cel);
nameCellTag.setAttribute("data-v-2f71893a","");
nameCellTag.style.cursor = "pointer";
}
else{
let nameCellTag = create("a","title",data[index].name,cel);
nameCellTag.setAttribute("data-v-2f71893a","");
nameCellTag.href = "/manga/" + data[index].mediaId + "/";
nameCellTag.style.marginLeft = "50px";
nameCellTag.style.display = "block";
}
},
function(cel,data,index,isPrimary){
if(isPrimary){
cel.innerText = data[index].list.length;
}
else{
let statusDot = create("div","hohStatusDot",false,cel);
statusDot.style.backgroundColor = distributionColours[data[index].status];
statusDot.title = data[index].status.toLowerCase();
if(data[index].status === "COMPLETED"){
statusDot.style.backgroundColor = "transparent";//default case
}
if(data[index].repeat === 1){
cel.innerHTML = svgAssets.repeat;
}
else if(data[index].repeat > 1){
cel.innerHTML = svgAssets.repeat + data[index].repeat;
}
}
},
function(cel,data,index,isPrimary){
if(isPrimary){
if(data[index].average === 0){
cel.innerText = "-";
}
else{
cel.innerText = Math.round(data[index].average);
}
}
else{
if(data[index].score === 0){
cel.innerText = "-";
}
else{
cel.innerText = Math.round(data[index].score);
}
}
},
function(cel,data,index){
cel.innerText = data[index].chaptersRead;
},
function(cel,data,index){
cel.innerText = data[index].volumesRead;
}
],
sorting: [
(a,b) => ("" + a.name).localeCompare(b.name),
(b,a) => a.list.length - b.list.length,
(b,a) => a.average - b.average,
(b,a) => a.chaptersRead - b.chaptersRead,
(b,a) => a.volumesRead - b.volumesRead
]
};
const mangaFields = [
{
key : "name",
sumable : false,
method : function(media){
if(useScripts.titleLanguage === "Native" && media.media.title.native){
return media.media.title.native;
}
else if(useScripts.titleLanguage === "English" && media.media.title.english){
return media.media.title.english;
}
return media.media.title.romaji;
}
},{
key : "repeat",
sumable : false,
method : function(media){
return media.repeat;
}
},{
key : "status",
sumable : false,
method : function(media){
return media.status;
}
},{
key : "mediaId",
sumable : false,
method : function(media){
return media.mediaId;
}
},{
key : "score",
sumable : false,
method : function(media){
return media.scoreRaw;
}
},{
key : "chaptersRead",
sumable : true,
method : function(media){
return media.chaptersRead;
}
},{
key : "volumesRead",
sumable : true,
method : function(media){
return media.volumesRead;
}
}
];
let customTags = customTagsCollection(list,mangaFormatter.title,mangaFields);
if(customTags.length){
let customTagsMangaTable = create("div","#customTagsMangaTable",false,personalStatsManga);
drawTable(customTags,mangaFormatter,customTagsMangaTable);
};
semaPhoreManga = list;
nativeTagsReplacer();
};
generalAPIcall(
queryMediaList,
{
name: document.URL.match(/\/([\w\-]+)\/stats/)[1],
listType: "MANGA"
},
personalStatsMangaCallback
);
};
for(var i=1;i a.count - b.count);
while(tagIndex.childElementCount){
tagIndex.removeChild(tagIndex.lastChild);
};
customTags.forEach(function(tag){
let tagElement = create("p",false,tag.name,tagIndex,"cursor:pointer;");
tagElement.onclick = function(){
let filterBox = document.querySelector(".entry-filter input");
filterBox.value = tag.name;
let event = new Event("input");
filterBox.dispatchEvent(event);
};
});
};
let variables = {
name: URLstuff[1],
listType: "ANIME"
};
if(URLstuff[2] === "mangalist"){
variables.listType = "MANGA";
};
generalAPIcall(queryMediaListNotes,variables,collectNotes,"hohCustomTagIndex" + variables.listType + variables.name,60*1000);
}
filters.appendChild(extraFilters);
let filterBox = document.querySelector(".entry-filter input");
let searchParams = new URLSearchParams(location.search);
let paramSearch = searchParams.get("search");
if(paramSearch){
filterBox.value = decodeURIComponent(paramSearch);
let event = new Event("input");
filterBox.dispatchEvent(event);
}
let filterChange = function(){
let newURL = location.protocol + '//' + location.host + location.pathname
if(filterBox.value === ""){
searchParams.delete("search");
}
else{
searchParams.set("search",encodeURIComponent(filterBox.value));
newURL += "?" + searchParams.toString();
}
current = newURL;
history.replaceState({},"",newURL);
if(document.querySelector(".el-icon-circle-close")){
document.querySelector(".el-icon-circle-close").onclick = filterChange;
}
}
filterBox.oninput = filterChange;
filterChange();
let mutationConfig = {
attributes: false,
childList: true,
subtree: true
};
if(
URLstuff[1] === whoAmI
&& useScripts.accessToken
&& (
document.querySelector(".medialist").classList.contains("POINT_100")
|| document.querySelector(".medialist").classList.contains("POINT_10")
|| document.querySelector(".medialist").classList.contains("POINT_10_DECIMAL")
)
){
let minScore = 1;
let maxScore = 100;
let stepSize = 1;
if(document.querySelector(".medialist").classList.contains("POINT_10") || document.querySelector(".medialist").classList.contains("POINT_10_DECIMAL")){
maxScore = 10;
}
if(document.querySelector(".medialist").classList.contains("POINT_10_DECIMAL")){
setpSize = 0.1;
}
let scoreChanger = function(){
observer.disconnect();
lists.querySelectorAll(".list-entries .row .score").forEach(function(entry){
if(!entry.childElementCount){
let updateScore = function(isUp){
let score = parseFloat(entry.attributes.score.value);
if(isUp){
score += stepSize;
}
else{
score -= stepSize;
}
if(score >= minScore && score <= maxScore){
let id = parseInt(entry.previousElementSibling.children[0].href.match(/(anime|manga)\/(\d+)/)[2]);
lists.querySelectorAll("[href=\"" + entry.previousElementSibling.children[0].attributes.href.value + "\"]").forEach(function(rItem){
rItem.parentNode.nextElementSibling.attributes.score.value = score;
rItem.parentNode.nextElementSibling.childNodes[1].textContent = " " + score + " ";
});
authAPIcall(
`mutation($id:Int,$score:Float){
SaveMediaListEntry(mediaId:$id,score:$score){
score
}
}`,
{id:id,score:score},function(data){/*later*/}
);
};
};
let changeMinus = create("span","hohChangeScore","-");
entry.insertBefore(changeMinus,entry.firstChild);
let changePluss = create("span","hohChangeScore","+",entry);
changeMinus.onclick = function(){updateScore(false)};
changePluss.onclick = function(){updateScore(true)};
}
});
observer.observe(lists,mutationConfig);
}
let lists = document.querySelector(".lists");
let observer = new MutationObserver(scoreChanger);
observer.observe(lists,mutationConfig);
scoreChanger();
}
};
function addFeedFilters(){
if(!location.pathname.match(/^\/home\/?$/)){
return;
};
let filterBox = document.querySelector(".hohFeedFilter");
if(filterBox){
return;
};
let activityFeedWrap = document.querySelector(".activity-feed-wrap");
if(!activityFeedWrap){
setTimeout(addFeedFilters,100);
return;
};
let activityFeed = activityFeedWrap.querySelector(".activity-feed");
if(!activityFeed){
setTimeout(addFeedFilters,100);
return;
};
filterBox = create("div","hohFeedFilter","At least ",activityFeedWrap);
activityFeedWrap.style.position = "relative";
activityFeedWrap.children[0].childNodes[0].nodeValue = "";
let commentFilterBoxInput = create("input",false,false,filterBox);
commentFilterBoxInput.type = "number";
commentFilterBoxInput.value = useScripts.feedCommentComments;
let commentFilterBoxLabel = create("span",false," comments, ",filterBox);
let likeFilterBoxInput = create("input",false,false,filterBox);
likeFilterBoxInput.type = "number";
likeFilterBoxInput.value = useScripts.feedCommentLikes;
let likeFilterBoxLabel = create("span",false," likes",filterBox);
let allFilterBox = create("button",false,"⟳",filterBox);
allFilterBox.style.padding = "0px";
let blockList = localStorage.getItem("blockList");
if(blockList){
blockList = JSON.parse(blockList);
}
else{
blockList = [];
};
let postRemover = function(){
if(!location.pathname.match(/^\/home\/?$/)){
return;
};
let duplicates = new Set();
for(var i=0;i a.action").href;
let blockRequire = true;
if(useScripts.blockWord && activityFeed.children[i].classList.contains("activity-text")){
try{
if(activityFeed.children[i].innerText.match(new RegExp(blockWordValue,"i"))){
blockRequire = false;
}
}
catch(err){
if(activityFeed.children[i].innerText.toLowerCase().match(useScripts.blockWordValue.toLowerCase())){
blockRequire = false;
}
}
}
if(
actionLikes >= likeFilterBoxInput.value
&& (likeFilterBoxInput.value >= 0 || actionLikes < -likeFilterBoxInput.value)
&& actionReplies >= commentFilterBoxInput.value
&& (commentFilterBoxInput.value >= 0 || actionReplies < -commentFilterBoxInput.value)
&& !duplicates.has(actionHref)
&& blockRequire
&& blockList.every(function(blocker){
if(blocker.user){
if(activityFeed.children[i].querySelector(".name").innerText.toLowerCase() !== blocker.user.toLowerCase()){
return true;
}
};
if(blocker.media){
if(activityFeed.children[i].classList.contains("activity-text")){
return true;
}
else{
let titleId = activityFeed.children[i].querySelector(".status .title").href.match(/\/(anime|manga)\/(\d)/)[2];
if(titleId !== blocker.media){
return true;
}
}
};
if(blocker.status){
if(blocker.status === "status"){
if(!activityFeed.children[i].classList.contains("activity-text")){
return true;
}
}
else if(blocker.status === "progress"){
if(activityFeed.children[i].classList.contains("activity-text")){
return true;
}
}
else if(blocker.status === "anime"){
if(!activityFeed.children[i].classList.contains("activity-anime_list")){
return true;
}
}
else if(blocker.status === "manga"){
if(!activityFeed.children[i].classList.contains("activity-manga_list")){
return true;
}
}
else if(activityFeed.children[i].classList.contains("activity-text")){
return true;
}
else if(blocker.status === "planning"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^plans/)){
return true;
}
}
else if(blocker.status === "watching"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^watched/)){
return true;
}
}
else if(blocker.status === "reading"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^read/)){
return true;
}
}
else if(blocker.status === "completing"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^completed/)){
return true;
}
}
else if(blocker.status === "pausing"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^paused/)){
return true;
}
}
else if(blocker.status === "dropping"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^dropped/)){
return true;
}
}
else if(blocker.status === "rewatching"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^rewatched/)){
return true;
}
}
else if(blocker.status === "rereading"){
if(!activityFeed.children[i].querySelector(".status").innerText.match(/^reread/)){
return true;
}
}
}
return false;
})
){
activityFeed.children[i].style.display = "";
}
else{
activityFeed.children[i].style.display = "none";
};
duplicates.add(actionHref);
};
};
commentFilterBoxInput.onchange = function(){
useScripts.feedCommentComments = commentFilterBoxInput.value;
useScripts.save();
postRemover();
};
likeFilterBoxInput.onchange = function(){
useScripts.feedCommentLikes = likeFilterBoxInput.value;
useScripts.save();
postRemover();
};
allFilterBox.onclick = function(){
commentFilterBoxInput.value = 0;
likeFilterBoxInput.value = 0;
useScripts.feedCommentComments = 0;
useScripts.feedCommentLikes = 0;
useScripts.save();
postRemover();
};
let mutationConfig = {
attributes: false,
childList: true,
subtree: false
};
let observer = new MutationObserver(function(){
postRemover();
});
observer.observe(activityFeed,mutationConfig);
let observerObserver = new MutationObserver(function(){//Who police police? The police police police police
activityFeed = activityFeedWrap.querySelector(".activity-feed");
if(activityFeed){
observer.disconnect();
observer = new MutationObserver(function(){
postRemover();
});
observer.observe(activityFeed,mutationConfig);
}
});
observerObserver.observe(activityFeedWrap,mutationConfig);
postRemover();
};
function expandRight(){
if(!location.pathname.match(/^\/home\/?$/)){
return;
};
let possibleFullWidth = document.querySelector(".home.full-width");
if(possibleFullWidth){
let homeContainer = possibleFullWidth.parentNode;
let sideBar = document.querySelector(".activity-feed-wrap")
if(!sideBar){
setTimeout(expandRight,100);
return;
};
sideBar = sideBar.nextElementSibling;
sideBar.insertBefore(possibleFullWidth,sideBar.firstChild);
let setSemantics = function(){
let toggle = document.querySelector(".size-toggle.fa-compress");
if(toggle){
toggle.onclick = function(){
homeContainer.insertBefore(possibleFullWidth,homeContainer.firstChild);
};
}
else{
setTimeout(setSemantics,200);
};
};setSemantics();
}
}
function mangaGuess(cleanAnime){
if(cleanAnime){
let possibleMangaGuess = document.querySelector(".data-set .value[data-media-id]");
if(possibleMangaGuess){
while(possibleMangaGuess.children.length){
possibleMangaGuess.removeChild(possibleMangaGuess.lastChild);
};
};
return;
};
let URLstuff = location.pathname.match(/^\/manga\/(\d+)\/?(.*)?/);
if(!URLstuff){
return;
};
let possibleReleaseStatus = Array.from(
document.querySelectorAll(".data-set .value")
).find(
element => element.innerText.match(/^Releasing/)
);
if(!possibleReleaseStatus){
setTimeout(mangaGuess,200);
return;
}
if(possibleReleaseStatus.dataset.mediaId === URLstuff[1]){
if(possibleReleaseStatus.children.length !== 0){
return;
}
}
else{
while(possibleReleaseStatus.children.length){
possibleReleaseStatus.removeChild(possibleReleaseStatus.lastChild);
};
};
possibleReleaseStatus.dataset.mediaId = URLstuff[1];
const variables = {id: URLstuff[1],userName: whoAmI};
let query = `
query($id: Int,$userName: String){
Page(page: 1){
activities(
mediaId: $id,
sort: ID_DESC
){
... on ListActivity{
progress
userId
}
}
}
MediaList(
userName: $userName,
mediaId: $id
){
progress
}
}`;
let possibleMyStatus = document.querySelector(".actions .list .add");
const simpleQuery = !possibleMyStatus || possibleMyStatus.innerText === "Add To List" || possibleMyStatus.innerText === "Planning";
if(simpleQuery){
query = `
query($id: Int){
Page(page: 1){
activities(
mediaId: $id,
sort: ID_DESC
){
... on ListActivity{
progress
userId
}
}
}
}`;
};
let highestChapterFinder = function(data){
if(possibleReleaseStatus.children.length !== 0){
return;
}
let guesses = [];
let userIdCache = new Set();
data.data.Page.activities.forEach(function(activity){
if(activity.progress){
let chapterMatch = parseInt(activity.progress.match(/\d+$/)[0]);
if(!userIdCache.has(activity.userId)){
guesses.push(chapterMatch);
userIdCache.add(activity.userId);
};
};
});
guesses.sort(VALUE_DESC);
if(guesses.length){
let bestGuess = guesses[0];
if(guesses.length > 2){
let diff = guesses[0] - guesses[1];
let inverseDiff = 1 + Math.ceil(50/(diff+1));
if(guesses.length >= inverseDiff){
if(guesses[1] === guesses[inverseDiff]){
bestGuess = guesses[1];
};
};
};
if(commonUnfinishedManga.hasOwnProperty(variables.id)){
if(bestGuess < commonUnfinishedManga[variables.id].chapters){
bestGuess = commonUnfinishedManga[variables.id].chapters;
};
};
if(simpleQuery){
if(bestGuess){
create("span","hohGuess"," (" + bestGuess + "?)",possibleReleaseStatus);
}
}
else{
bestGuess = Math.max(bestGuess,data.data.MediaList.progress);
if(bestGuess){
if(bestGuess === data.data.MediaList.progress){
create("span","hohGuess"," (" + bestGuess + "?)",possibleReleaseStatus,"color:rgb(var(--color-green));");
}
else{
create("span","hohGuess"," (" + bestGuess + "?)",possibleReleaseStatus);
create("span","hohGuess"," [+" + (bestGuess - data.data.MediaList.progress) + "]",possibleReleaseStatus,"color:rgb(var(--color-red));");
}
}
};
};
};
generalAPIcall(query,variables,highestChapterFinder);
}
if(useScripts.ALbuttonReload){
let logo = document.querySelector(".logo");
if(logo){
logo.onclick = function(){
if(location.pathname.match(/\/home\/?$/)){//we only want this behaviour here
window.location.reload(false);//reload page, but use cache if possible
}
}
}
}
function enumerateSubmissionStaff(){
if(!location.pathname.match(/^\/edit/)){
return;
};
setTimeout(function(){
enumerateSubmissionStaff();
},500);
let staffFound = [];
let staffEntries = document.querySelectorAll(".staff-row .col > .image");
Array.from(staffEntries).forEach(function(staff){
let enumerate = staffFound.filter(a => a === staff.href).length;
if(enumerate === 1){
let firstStaff = document.querySelector(".staff-row .col > .image[href=\"" + staff.href.replace("https://anilist.co","") + "\"]");
if(!firstStaff.previousSibling){
let enumerateSpan = create("span","hohEnumerateStaff",1);
firstStaff.parentNode.insertBefore(enumerateSpan,firstStaff);
};
}
if(enumerate > 0){
if(staff.previousSibling){
staff.previousSibling.innerText = enumerate + 1;
}
else{
let enumerateSpan = create("span","hohEnumerateStaff",(enumerate + 1));
staff.parentNode.insertBefore(enumerateSpan,staff);
}
};
staffFound.push(staff.href);
});
}
function addMALscore(type,id){
if(!location.pathname.match(/^\/(anime|manga)/)){
return;
};
if(document.getElementById("hohMALscore")){
return;
};
let possibleReleaseStatus = Array.from(document.querySelectorAll(".data-set .type"));
const MALlocation = possibleReleaseStatus.find(element => element.innerText === "Mean Score");
if(MALlocation){
let MALscore = create("div","data-set");
MALscore.id = "hohMALscore";
MALlocation.parentNode.parentNode.insertBefore(MALscore,MALlocation.parentNode.nextSibling);
generalAPIcall("query($id:Int){Media(id:$id){idMal}}",{id:id},function(data){
if(data.data.Media.idMal){
GM_xmlhttpRequest({
method: "GET",
url: "https://myanimelist.net/" + type + "/" + data.data.Media.idMal + "/placeholder/userrecs",
onload: function(response){
let score = response.responseText.match(/ratingValue.+?(\d+\.\d+)/);
if(score){
MALscore.style.paddingBottom = "14px";
let malEntry = create("a","type","MAL Score",MALscore);
malEntry.href = "https://myanimelist.net/" + type + "/" + data.data.Media.idMal;
malEntry.setAttribute("target","_blank");
create("div","value",score[1],MALscore);
}
let adder = function(){
let possibleOverview = document.querySelector(".overview .grid-section-wrap:last-child");
if(!possibleOverview){
setTimeout(adder,500);
return;
}
let recContainer = create("div","grid-section-wrap",false,possibleOverview);
create("h2",false,"Similar",recContainer);
let pattern = /class="picSurround">(.*?)<\/div>/g;
let matching = [];
let matchingItem;
while((matchingItem = pattern.exec(response.responseText)) && matching.length < 5){//single "=" is intended, we are setting the value of each match, not comparing
matching.push(matchingItem);
}
if(!matching.length){
recContainer.style.display = "none";
}
matching.forEach(function(item){
let idMal = item[2];
let description = item[4];
let rec = create("div",false,false,recContainer,"position:relative;");
let recImage = create("a","hohBackgroundCover",false,rec);
let recTitle = create("a","title",false,rec,"position:absolute;top:25px;left:60px;color:rgb(var(--color-blue));");
recTitle.innerText = "MAL ID " + idMal;
let recDescription = create("p",false,false,rec);
recDescription.innerHTML = description;
generalAPIcall("query($idMal:Int){Media(idMal:$idMal){id title{romaji native english} coverImage{large} siteUrl}}",{idMal:idMal},function(data){
if(!data){
return;
};
recImage.style.backgroundImage = "url(\"" + data.data.Media.coverImage.large + "\")";
recImage.href = data.data.Media.siteUrl;
if(useScripts.titleLanguage === "Native" && data.data.Media.title.native){
recTitle.innerText = data.data.Media.title.native;
}
else if(useScripts.titleLanguage === "English" && data.data.Media.title.english){
recTitle.innerText = data.data.Media.title.english;
}
else{
recTitle.innerText = data.data.Media.title.romaji;
}
recTitle.href = data.data.Media.siteUrl;
},"hohIDmalReverse" + idMal);
})
};adder();
}
});
}
},"hohIDmal" + id);
}
else{
setTimeout(function(){addMALscore(type,id)},200);
};
}
function addEntryScore(id){
if(!location.pathname.match(/^\/(anime|manga)/)){
return;
};
let existing = document.getElementById("hohEntryScore");
if(existing){
if(existing.dataset.mediaId === id){
return;
}
else{
existing.remove();
};
};
let possibleLocation = document.querySelector(".actions .list .add");
if(possibleLocation){
let miniHolder = create("div","#hohEntryScore",false,possibleLocation.parentNode.parentNode,"position:relative;");
miniHolder.dataset.mediaId = id;
let type = possibleLocation.innerText;
if(type === "Reading" || type === "Completed" || type === "Watching" || type === "Paused" || type === "Repeating" || type === "Dropped"){
generalAPIcall(
"query($id:Int,$name:String){MediaList(mediaId:$id,userName:$name){score progress user{mediaListOptions{scoreFormat}}}}",
{id:id,name:whoAmI},
function(data){
let MediaList = data.data.MediaList;
let scoreSpanContainer = create("div","hohMediaScore",false,miniHolder);
let scoreSpan = create("span",false,false,scoreSpanContainer);
let minScore = 1;
let maxScore = 100;
let stepSize = 1;
if(["POINT_10","POINT_10_DECIMAL"].indexOf(MediaList.user.mediaListOptions.scoreFormat) !== -1){
maxScore = 10;
}
if(MediaList.user.mediaListOptions.scoreFormat === "POINT_10_DECIMAL"){
setpSize = 0.1;
}
if(MediaList.score){
scoreSpan.innerHTML = scoreFormatter(MediaList.score,MediaList.user.mediaListOptions.scoreFormat,whoAmI);
if(useScripts.accessToken && ["POINT_100","POINT_10","POINT_10_DECIMAL"].indexOf(MediaList.user.mediaListOptions.scoreFormat) !== -1){
let updateScore = function(isUp){
let score = MediaList.score;
if(isUp){
MediaList.score += stepSize;
}
else{
MediaList.score -= stepSize;
}
if(MediaList.score >= minScore && MediaList.score <= maxScore){
scoreSpan.innerHTML = scoreFormatter(MediaList.score,MediaList.user.mediaListOptions.scoreFormat,whoAmI);
authAPIcall(
`mutation($id:Int,$score:Float){
SaveMediaListEntry(mediaId:$id,score:$score){
score
}
}`,
{id:id,score:MediaList.score},function(data){}
);
let blockingCache = JSON.parse(sessionStorage.getItem("hohEntryScore" + id + whoAmI));
blockingCache.data.data.MediaList.score = MediaList.score;
blockingCache.time = (new Date()).valueOf();
sessionStorage.setItem("hohEntryScore" + id + whoAmI,JSON.stringify(blockingCache));
}
else if(MediaList.score < minScore){
MediaList.score = minScore;
}
else if(MediaList.score > maxScore){
MediaList.score = maxScore;
}
};
let changeMinus = create("span","hohChangeScore","-",false,"padding:2px;position:absolute;left:-1px;top:-2.5px;");
scoreSpanContainer.insertBefore(changeMinus,scoreSpanContainer.firstChild);
let changePluss = create("span","hohChangeScore","+",scoreSpanContainer,"padding:2px;");
changeMinus.onclick = function(){updateScore(false)};
changePluss.onclick = function(){updateScore(true)};
}
};
if(type != "Completed"){
create("span","hohMediaScore",MediaList.progress,miniHolder,"right:0px;");
};
},
"hohEntryScore" + id + whoAmI,30*1000
);
}
}
else{
setTimeout(function(){addEntryScore(id)},200);
};
}
function notificationCake(){
let notificationDot = document.querySelector(".notification-dot");
if(notificationDot && (!notificationDot.childElementCount)){
authAPIcall(
queryAuthNotifications,
{page:1,name:whoAmI},
function(data){
let Page = data.data.Page;
let User = data.data.User;
let types = [];
for(var i=0;i",false,"font-weight:bolder;");
codeLink.setAttribute("data-v-69758bac","");
timeContainer.insertBefore(codeLink,timeContainer.firstChild);
codeLink.onclick = function(){
let activityMarkdown = document.querySelector(".activity-markdown");
if(activityMarkdown.style.display === "none"){
document.querySelector(".hohMarkdownSource").style.display = "none";
activityMarkdown.style.display = "initial";
}
else{
activityMarkdown.style.display = "none";
let markdownSource = document.querySelector(".hohMarkdownSource");
if(markdownSource){
markdownSource.style.display = "initial";
}
else{
generalAPIcall("query($id:Int){Activity(id:$id){...on MessageActivity{text:message}...on TextActivity{text}}}",{id:id},function(data){
if(!location.pathname.match(id) || !data){
return;
};
markdownSource = create("div",["activity-markdown","hohMarkdownSource"],data.data.Activity.text,activityMarkdown.parentNode);
markdownSource.setAttribute("data-v-69758bac","");
},"hohGetMarkdown" + id,20*1000);
}
}
}
}
function addActivityLinks(activityID){
let arrowCallback = function(data){
let queryPrevious;
let queryNext;
let variables = {
userId: data.data.Activity.userId || data.data.Activity.recipientId,
createdAt: data.data.Activity.createdAt
};
if(data.data.Activity.type === "ANIME_LIST" || data.data.Activity.type === "MANGA_LIST"){
variables.mediaId = data.data.Activity.media.id;
queryPrevious = `
query ($userId: Int,$mediaId: Int,$createdAt: Int){
Activity(
userId: $userId,
mediaId: $mediaId,
createdAt_lesser: $createdAt,
sort: ID_DESC
){
... on ListActivity{siteUrl createdAt id}
}
}`;
queryNext = `
query($userId: Int,$mediaId: Int,$createdAt: Int){
Activity(
userId: $userId,
mediaId: $mediaId,
createdAt_greater: $createdAt,
sort: ID
){
... on ListActivity{siteUrl createdAt id}
}
}`;
}
else if(data.data.Activity.type === "TEXT"){
queryPrevious = `
query($userId: Int,$createdAt: Int){
Activity(
userId: $userId,
type: TEXT,
createdAt_lesser: $createdAt,
sort: ID_DESC
){
... on TextActivity{siteUrl createdAt id}
}
}`;
queryNext = `
query($userId: Int,$createdAt: Int){
Activity(
userId: $userId,
type: TEXT,
createdAt_greater: $createdAt,
sort: ID
){
... on TextActivity{siteUrl createdAt id}
}
}`;
}
else if(data.data.Activity.type === "MESSAGE"){
variables.messengerId = data.data.Activity.messengerId;
queryPrevious = `
query($userId: Int,$messengerId: Int,$createdAt: Int){
Activity(
userId: $userId,
type: MESSAGE,
messengerId: $messengerId,
createdAt_lesser: $createdAt,
sort: ID_DESC
){
... on MessageActivity{siteUrl createdAt id}
}
}`;
queryNext = `
query($userId: Int,$messengerId: Int,$createdAt: Int){
Activity(
userId: $userId,
type: MESSAGE,
messengerId: $messengerId,
createdAt_greater: $createdAt,
sort: ID
){
... on MessageActivity{siteUrl createdAt id}
}
}`;
}
else{//unknown new types of activities
return;
};
let adder = function(link){
if(!location.pathname.match("/activity/" + activityID)){
return;
};
let activityLocation = document.querySelector(".activity-entry");
if(activityLocation){
activityLocation.appendChild(link);
return;
}
else{
setTimeout(function(){adder(link)},200);
}
};
if(data.previous){
if(data.previous !== "FIRST"){
let link = create("a","hohPostLink","←",false,"left:-25px;");
link.href = data.previous;
adder(link);
}
}
else{
data.previous = "FIRST";
generalAPIcall(queryPrevious,variables,function(pdata){
if(!pdata){
return;
}
let link = create("a","hohPostLink","←",false,"left:-25px;");
link.href = pdata.data.Activity.siteUrl;
adder(link);
data.previous = pdata.data.Activity.siteUrl;
sessionStorage.setItem("hohActivity" + activityID,JSON.stringify(data));
pdata.data.Activity.type = data.data.Activity.type;
pdata.data.Activity.userId = variables.userId;
pdata.data.Activity.media = data.data.Activity.media;
pdata.data.Activity.messengerId = data.data.Activity.messengerId;
pdata.next = document.URL;
sessionStorage.setItem("hohActivity" + pdata.data.Activity.id,JSON.stringify(pdata));
});
}
if(data.next){
let link = create("a","hohPostLink","→",false,"right:-25px;");
link.href = data.next;
adder(link);
}
else{
generalAPIcall(queryNext,variables,function(pdata){
if(!pdata){
return;
}
let link = create("a","hohPostLink","→",false,"right:-25px;");
link.href = data.data.Activity.siteUrl;
adder(link);
data.next = pdata.data.Activity.siteUrl;
sessionStorage.setItem("hohActivity" + activityID,JSON.stringify(data));
pdata.data.Activity.type = data.data.Activity.type;
pdata.data.Activity.userId = variables.userId;
pdata.data.Activity.media = data.data.Activity.media;
pdata.data.Activity.messengerId = data.data.Activity.messengerId;
pdata.previous = document.URL;
sessionStorage.setItem("hohActivity" + pdata.data.Activity.id,JSON.stringify(pdata));
});
};
sessionStorage.setItem("hohActivity" + activityID,JSON.stringify(data));
}
let possibleCache = sessionStorage.getItem("hohActivity" + activityID);
if(possibleCache){
arrowCallback(JSON.parse(possibleCache));
}
else{
generalAPIcall(`
query($id: Int){
Activity(id: $id){
... on ListActivity{
type
userId
createdAt
media{id}
}
... on TextActivity{
type
userId
createdAt
}
... on MessageActivity{
type
recipientId
messengerId
createdAt
}
}
}`,{id:activityID},arrowCallback);
}
}
function addBrowseFilters(type){
if(!location.pathname.match(/^\/search/)){
return;
};
let sorts = document.querySelector(".hohAlready");
if(!sorts){
sorts = document.querySelector(".filter-group .el-select-dropdown .el-select-dropdown__list");
if(!sorts){
setTimeout(function(){addBrowseFilters(type)},200);
return;
};
sorts.classList.add("hohAlready");
};
let alreadyAdded = document.querySelectorAll(".hohSorts");
alreadyAdded.forEach(function(already){
already.remove();
});
let URLredirect = function(property,value){
let url = new URLSearchParams(location.search);
url.set(property,value);
window.location.href = location.protocol + '//' + location.host + location.pathname + "?" + url.toString();
};
if(type === "anime"){
let episodeSort = create("li",["el-select-dropdown__item","hohSorts"],false,sorts);
create("span",false,"Episodes ↓",episodeSort);
let episodeSortb = create("li",["el-select-dropdown__item","hohSorts"],false,sorts);
create("span",false,"Episodes ↑",episodeSortb);
for(var i=0;i value === "PLANNING").length;
},
"current": function(show){
show.average = show.status.filter(value => (value === "CURRENT" || value === "REPEATING")).length;
},
"favourites": function(show){
show.average = show.favourite.filter(value => value).length;
},
"median": function(show){
let newScores = show.score.filter(TRUTHY).sort(VALUE);
if(newScores.length === 0){
show.average = 0;
}
else if(newScores.length % 2){
show.average = newScores[(newScores.length-1)/2];
}
else{
show.average = (newScores[newScores.length/2] + newScores[newScores.length/2 - 1])/2;
};
}
};
if(ratingMode === "user"){
shows.sort(function(a,b){
return b.score[guser] - a.score[guser];
});
}
else if(ratingMode === "userInverse"){
shows.sort(function(b,a){
return b.score[guser] - a.score[guser];
});
}
else if(ratingMode === "title"){
shows.sort(function(a,b){
return a.title.localeCompare(b.title)
});
}
else if(ratingMode === "titleInverse"){
shows.sort(function(b,a){
return a.title.localeCompare(b.title)
});
}
else{
shows.forEach(sortingModes[ratingMode]);
if(inverse){
shows.sort((b,a) => b.average - a.average);
}
else{
shows.sort((a,b) => b.average - a.average);
}
};
};
let drawTable = function(){
while(table.childElementCount > 2){
table.removeChild(table.lastChild);
};
shows.forEach(function(show){
let display = users.every(function(user,index){
if(user.demand === 1 && show.score[index] === 0){
return false;
}
else if(user.demand === -1 && show.score[index] != 0){
return false;
};
return (!user.status || show.status[index] === user.status);
});
if(formatFilter.value != "all"){
if(formatFilter.value != show.format){
display = false;
};
};
if(show.numberWatched < ratingFilter.value){
display = false;
};
if(!display){
return;
};
let row = create("tr","hohAnimeTable");
row.onclick = function(){
if(this.style.background === "rgb(var(--color-blue),0.5)"){
this.style.background = "unset";
}
else{
this.style.background = "rgb(var(--color-blue),0.5)";
}
}
let showID = create("td");
let showIDlink = create("a",false,show.title,showID);
showIDlink.href = "https://anilist.co/" + type + "/" + show.id + "/" + safeURL(show.title);
showID.style.maxWidth = "250px";
showIDlink.setAttribute("target","_blank");
let showAverage = create("td");
if(show.average){
let fractional = show.average % 1;
if(Math.abs(fractional - 1/3) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ⅓";
}
else if(Math.abs(fractional - 1/2) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ½";
}
else if(Math.abs(fractional - 1/4) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ¼";
}
else if(Math.abs(fractional - 3/4) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ¾";
}
else if(Math.abs(fractional - 2/3) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ⅔";
}
else if(Math.abs(fractional - 1/6) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ⅙";
}
else if(Math.abs(fractional - 5/6) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ⅚";
}
else if(Math.abs(fractional - 1/7) < 0.0001){
showAverage.innerText = Math.floor(show.average) + " ⅐";
}
else{
showAverage.innerText = show.average.roundPlaces(3);
}
};
row.appendChild(showID);
row.appendChild(showAverage);
for(var i=0;i user.name + (user.demand ? (user.demand === -1 ? "-" : "*") : "")).join(",");
}
if(formatFilter.value != "all"){
params += "&filter=" + encodeURIComponent(formatFilter.value);
};
if(ratingFilter.value != 1){
params += "&minRatings=" + encodeURIComponent(ratingFilter.value);
};
if(systemFilter.checked){
params += "&ratingSystems=true";
};
if(colourFilter.checked){;
params += "&fullColour=true";
};
if(ratingMode != "average"){;
params += "&sort=" + ratingMode;
};
if(params.length){
params = "?" + params.substring(1);
}
current = baseState + params;
history.replaceState({},"",baseState + params);
};
let drawUsers = function(){
while(table.childElementCount){
table.removeChild(table.lastChild);
};
let userRow = create("tr");
let resetCel = create("td",false,false,userRow);
let resetButton = create("button",false,"Reset",resetCel);
resetButton.onclick = function(){
users = [];
shows = [];
drawUsers();
changeUserURL();
};
let digestCel = create("td");
digestSelect = create("select");
let addOption = function(value,text){
let newOption = create("option",false,text,digestSelect);
newOption.value = value;
};
addOption("average","Average");
addOption("median","Median");
addOption("average0","Average~0");
addOption("min","Minimum");
addOption("max","Maximum");
addOption("difference","Difference");
addOption("standardDeviation","Std. Deviation");
addOption("absoluteDeviation","Abs. Deviation");
addOption("ratings","#Ratings");
addOption("planned","#Planning");
addOption("current","#Current");
addOption("favourites","#Favourites");
if(["title","titleInverse","user","userInverse"].indexOf(ratingMode) === -1){
digestSelect.value = ratingMode;
};
digestSelect.oninput = function(){
ratingMode = digestSelect.value;
sortShows();
drawTable();
changeUserURL();
};
digestCel.appendChild(digestSelect);
userRow.appendChild(digestCel);
users.forEach(function(user,index){
let userCel = create("td",false,false,userRow);
let avatar = create("img",false,false,userCel);
avatar.src = listCache[user.name].data.MediaListCollection.user.avatar.medium;
let name = create("span",false,user.name,userCel);
name.style.padding = "8px";
let remove = create("span","hohAnimeTableRemove","✕",userCel);
remove.onclick = function(){
deleteUser(index);
};
});
let addCel = create("td");
let addInput = create("input");
let addButton = create("button",false,"Add");
addButton.style.cursor = "pointer";
addButton.onclick = function(){
if(addInput.value != ""){
addUser(addInput.value);
addButton.innerText = "...";
addButton.disabled = true;
addInput.readOnly = true;
};
};
addCel.appendChild(addInput);
addCel.appendChild(addButton);
userRow.appendChild(addCel);
let headerRow = create("tr");
let typeCel = create("th");
let downArrowa = create("span","hohArrowSort","▼",typeCel);
downArrowa.onclick = function(){
ratingMode = "title";
sortShows();
drawTable();
};
let typeCelLabel = create("span",false,type.capitalize(),typeCel);
let upArrowa = create("span","hohArrowSort","▲",typeCel);
upArrowa.onclick = function(){
ratingMode = "titleInverse";
sortShows();
drawTable();
};
headerRow.appendChild(typeCel);
let digestSortCel = create("td");
digestSortCel.style.textAlign = "center";
let downArrow = create("span","hohArrowSort","▼",digestSortCel);
downArrow.onclick = function(){
ratingMode = digestSelect.value;
inverse = false;
sortShows(digestSelect.value);
drawTable();
};
let upArrow = create("span","hohArrowSort","▲",digestSortCel);
upArrow.onclick = function(){
ratingMode = digestSelect.value;
inverse = true;
sortShows();
drawTable();
};
headerRow.appendChild(digestSortCel);
users.forEach(function(user,index){
let userCel = create("td");
userCel.style.textAlign = "center";
userCel.style.position = "relative";
let filter = create("span");
if(user.demand === 0){
filter.innerText = "☵";
}
else if(user.demand === 1){
filter.innerText = "✓";
filter.style.color = "green";
}
else{
filter.innerText = "✕";
filter.style.color = "red";
};
filter.classList.add("hohFilterSort");
filter.onclick = function(){
if(filter.innerText === "☵"){
filter.innerText = "✓";
filter.style.color = "green";
user.demand = 1;
}
else if(filter.innerText === "✓"){
filter.innerText = "✕";
filter.style.color = "red";
user.demand = -1;
}
else{
filter.innerText = "☵";
filter.style.color = "";
user.demand = 0;
};
drawTable();
changeUserURL();
};
let downArrow = create("span","hohArrowSort","▼");
downArrow.onclick = function(){
ratingMode = "user";
guser = index;
sortShows();
drawTable();
};
let upArrow = create("span","hohArrowSort","▲");
upArrow.onclick = function(){
ratingMode = "userInverse";
guser = index;
sortShows();
drawTable();
};
let statusFilterDot = create("div","hohStatusDot");
const stati = ["COMPLETED","CURRENT","PLANNING","PAUSED","DROPPED","REPEATING"];
statusFilterDot.onclick = function(){
if(user.status === "REPEATING"){
user.status = false;
statusFilterDot.style.background = "rgb(var(--color-background))";
statusFilterDot.title = "all";
}
else if(user.status === false){
user.status = "COMPLETED";
statusFilterDot.style.background = distributionColours["COMPLETED"];
statusFilterDot.title = "completed";
}
else{
user.status = stati[stati.indexOf(user.status) + 1];
statusFilterDot.style.background = distributionColours[user.status];
statusFilterDot.title = user.status.toLowerCase();
};
drawTable();
};
userCel.appendChild(downArrow);
userCel.appendChild(filter);
userCel.appendChild(upArrow);
userCel.appendChild(statusFilterDot);
headerRow.appendChild(userCel);
});
userRow.classList.add("hohUserRow");
headerRow.classList.add("hohHeaderRow");
table.appendChild(userRow);
table.appendChild(headerRow);
};
let addUser = function(userName,paramDemand){
let handleData = function(data,cached){
users.push({
name: userName,
demand: (paramDemand ? (paramDemand === "-" ? -1 : 1) : 0),
system: data.data.MediaListCollection.user.mediaListOptions.scoreFormat,
status: false
});
let list = returnList(data,true);
if(!cached){
let aliasesToLookFor = [];
if(useScripts.shortRomaji){
shortRomaji.forEach(function(alias){
let matches = alias[0].match(/\/(anime|manga)\/(\d+)\//);
aliasesToLookFor[matches[2]] = alias[1];
});
};
const titleAliases = JSON.parse(localStorage.getItem("titleAliases"));
if(titleAliases){
titleAliases.forEach(function(alias){
let matches = alias[0].match(/\/(anime|manga)\/(\d+)\//);
if(matches){
aliasesToLookFor[matches[2]] = alias[1];
};
});
}
let language = useScripts.titleLanguage.toLowerCase();
list.forEach(function(alia){
if(aliasesToLookFor[alia.mediaId]){
alia.media.title = aliasesToLookFor[alia.mediaId];
}
else{
alia.media.title = alia.media.title[language] ? alia.media.title[language] : alia.media.title.romaji;
};
alia.scoreRaw = convertScore(alia.score,data.data.MediaListCollection.user.mediaListOptions.scoreFormat);
});
};
shows.sort(function(a,b){return a.id - b.id;});
let listPointer = 0;
let userIndeks = 0;
if(shows.length){
userIndeks = shows[0].score.length;
};
let favs = data.data.MediaListCollection.user.favourites.fav.nodes.concat(
data.data.MediaListCollection.user.favourites.fav2.nodes
).concat(
data.data.MediaListCollection.user.favourites.fav3.nodes
).map(media => media.id);
let createEntry = function(mediaEntry){
let entry = {
id: mediaEntry.mediaId,
average: mediaEntry.scoreRaw,
title: mediaEntry.media.title,
format: mediaEntry.media.format,
score: Array(userIndeks).fill(0),
scorePersonal: Array(userIndeks).fill(0),
status: Array(userIndeks).fill("NOT"),
progress: Array(userIndeks).fill(false),
numberWatched: mediaEntry.scoreRaw ? 1 : 0,
favourite: Array(userIndeks).fill(false)
};
entry.score.push(mediaEntry.scoreRaw);
entry.scorePersonal.push(mediaEntry.score);
entry.status.push(mediaEntry.status);
if(mediaEntry.status != "PLANNING" && mediaEntry.status != "COMPLETED"){
entry.progress.push(mediaEntry.progress + "/" + (mediaEntry.media.chapters || mediaEntry.media.episodes || ""));
}
else{
entry.progress.push(false);
}
entry.favourite.push(favs.includes(entry.id));
return entry;
};
shows.forEach(function(show){
show.score.push(0);
show.scorePersonal.push(0);
show.status.push("NOT");
show.progress.push(false);
show.favourite.push(false);
});
for(var i=0;i status === "NOT")
});
if(guser === index){
guser = false;
}
else if(user > index){
guser--;
};
sortShows();
drawUsers();
drawTable();
changeUserURL();
};
formatFilter.oninput = function(){drawTable();changeUserURL()};
ratingFilter.oninput = function(){drawTable();changeUserURL()};
systemFilter.onclick = function(){drawTable();changeUserURL()};
colourFilter.onclick = function(){drawTable();changeUserURL()};
let searchParams = new URLSearchParams(location.search);
let paramFormat = searchParams.get("filter");
if(paramFormat){
formatFilter.value = paramFormat;
};
let paramRating = searchParams.get("minRatings");
if(paramRating){
ratingFilter.value = paramRating;
};
let paramSystem = searchParams.get("ratingSystems");
if(paramSystem){
systemFilter.checked = (paramSystem === "true");
};
let paramColour = searchParams.get("fullColour");
if(paramColour){
colourFilter.checked = (paramColour === "true");
};
let paramSort = searchParams.get("sort");
if(paramSort){
ratingMode = paramSort;
};
let paramUsers = searchParams.get("users");
if(paramUsers){
paramUsers.split(",").forEach(function(user){
let paramDemand = user.match(/(\*|\-)$/);
if(paramDemand){
paramDemand = paramDemand[0];
}
user = user.replace(/(\*|\-)$/,"");
if(user === "~"){
addUser(whoAmI,paramDemand);
}
else{
addUser(user,paramDemand);
}
});
}
else{
addUser(whoAmI);
addUser(userA);
}
}
function addFollowCount(){
let URLstuff = location.pathname.match(/^\/user\/(.*)\/social/)
if(!URLstuff){
return;
};
generalAPIcall("query($name:String){User(name:$name){id}}",{name:URLstuff[1]},function(data){
generalAPIcall("query($id:Int!){Page(perPage:1){pageInfo{total} followers(userId:$id){id}}}",{id:data.data.User.id},function(data){
let target = document.querySelector(".filter-group");
if(target){
target.style.position = "relative";
create("span",false,data.data.Page.pageInfo.total,target.children[2],"position:absolute;right:3px;");
};
});
generalAPIcall("query($id:Int!){Page(perPage:1){pageInfo{total} following(userId:$id){id}}}",{id:data.data.User.id},function(data){
let target = document.querySelector(".filter-group");
if(target){
target.style.position = "relative";
create("span",false,data.data.Page.pageInfo.total,target.children[1],"position:absolute;right:3px;");
};
});
},"hohIDlookup" + URLstuff[1].toLowerCase());
}
function embedHentai(){
if(!document.URL.match(/^https:\/\/anilist\.co\/(home|user|forum|activity)/)){
return;
};
setTimeout(embedHentai,1000);
let mediaEmbeds = document.querySelectorAll(".media-embed");
let bigQuery = [];
mediaEmbeds.forEach(function(embed){
if(embed.children.length === 0 && !embed.classList.contains("hohMediaEmbed")){
embed.classList.add("hohMediaEmbed");
let createEmbed = function(data){
embed.innerText = "";
let eContainer = create("div",false,false,embed);
eContainer.setAttribute("data-v-4021af81","");
let eEmbed = create("div","embed",false,eContainer);
eEmbed.setAttribute("data-v-4021af81","");
let eCover = create("div","cover",false,eEmbed);
eCover.setAttribute("data-v-4021af81","");
eCover.style.backgroundImage = "url(" + data.data.Media.coverImage.large + ")";
let eWrap = create("div","wrap",false,eEmbed);
eWrap.setAttribute("data-v-4021af81","");
let mediaTitle = data.data.Media.title.romaji;
if(useScripts.titleLanguage === "Native" && data.data.Media.title.native){
mediaTitle = data.data.Media.title.native;
}
else if(useScripts.titleLanguage === "English" && data.data.Media.title.english){
mediaTitle = data.data.Media.title.english;
};
let eTitle = create("div","title",mediaTitle,eWrap);
eTitle.setAttribute("data-v-4021af81","");
let eInfo = create("div","info",false,eWrap);
eInfo.setAttribute("data-v-4021af81","");
let eGenres = create("div","genres",false,eInfo);
eGenres.setAttribute("data-v-4021af81","");
data.data.Media.genres.forEach(function(genre,index){
let eGenre = create("span",false,genre,eGenres);
eGenre.setAttribute("data-v-4021af81","");
let comma = create("span",false,", ",eGenre);
comma.setAttribute("data-v-4021af81","");
if(index === data.data.Media.genres.length - 1){
comma.style.display = "none";
};
});
let eFormat = create("span",false,distributionFormats[data.data.Media.format],eInfo);
eFormat.setAttribute("data-v-4021af81","");
let eStatus = create("span",false," · " + distributionStatus[data.data.Media.status],eInfo);
eStatus.setAttribute("data-v-4021af81","");
if(data.data.Media.season){
let eSeason = create("span",false,
" · " + data.data.Media.season.toLowerCase().capitalize() + " " + data.data.Media.startDate.year,
eInfo
);
eSeason.setAttribute("data-v-4021af81","");
}
else if(data.data.Media.startDate.year){
let eSeason = create("span",false,
" · " + data.data.Media.startDate.year,
eInfo
);
eSeason.setAttribute("data-v-4021af81","");
}
if(data.data.Media.averageScore){
let eScore = create("span",false," · " + data.data.Media.averageScore + "%",eInfo);
eScore.setAttribute("data-v-4021af81","");
}
else if(data.data.Media.meanScore){//fallback if it's not popular enough, better than nothing
let eScore = create("span",false," · " + data.data.Media.meanScore + "%",eInfo);
eScore.setAttribute("data-v-4021af81","");
}
}
bigQuery.push({
query: "query($mediaId:Int,$type:MediaType){Media(id:$mediaId,type:$type){title{romaji native english} coverImage{large} genres format status season meanScore averageScore startDate{year}}}",
variables: {
mediaId: +embed.dataset.mediaId,
type: embed.dataset.mediaType.toUpperCase()
},
callback: createEmbed,
cacheKey: "hohMedia" + embed.dataset.mediaId
});
};
});
queryPacker(bigQuery);
}
function addForumMedia(){
if(location.pathname !== "/home"){
return;
}
let forumThreads = Array.from(document.querySelectorAll(".home .forum-wrap .thread-card .category"));
if(!forumThreads.length){
setTimeout(addForumMedia,200);
return;
};
if(forumThreads.some(function(thread){
return (thread && (thread.innerText.toLowerCase() === "anime" || thread.innerText.toLowerCase() === "manga"))
})){
generalAPIcall("query{Page(perPage:3){threads(sort:REPLIED_AT_DESC){title mediaCategories{title{romaji native english}}}}}",{},function(data){
if(location.pathname !== "/home"){
return;
}
data.data.Page.threads.forEach(function(thread,index){
if(thread.mediaCategories.length && (forumThreads[index].innerText.toLowerCase() === "anime" || forumThreads[index].innerText.toLowerCase() === "manga")){
if(useScripts.titleLanguage === "Native" && thread.mediaCategories[0].title.native){
forumThreads[index].innerText = thread.mediaCategories[0].title.native;
}
else if(useScripts.titleLanguage === "English" && thread.mediaCategories[0].title.english){
forumThreads[index].innerText = thread.mediaCategories[0].title.english;
}
else{
forumThreads[index].innerText = thread.mediaCategories[0].title.romaji;
}
}
});
});
}
}
function addImageFallback(){
if(!document.URL.match(/(\/home|\/user\/)/)){
return;
}
setTimeout(addImageFallback,1000);
let mediaImages = document.querySelectorAll(".media-preview-card:not(.hohFallback) .content .title");
mediaImages.forEach(function(cover){
cover.parentNode.parentNode.classList.add("hohFallback");
let fallback = create("span","hohFallback",cover.textContent,cover.parentNode.parentNode);
if(useScripts.titleLanguage === "Romaji"){
fallback.innerHTML = cover.textContent.replace(/\S{3}(a|e|i|ou|(o|u)(?!u|\s)|n(?!a|e|i|o|u))(?)/gi,m => m + "");
/* create word break opportunities for 'break-word' in nice places in romaji
- after vowels, or 'ou' or 'uu'. Those pairs should not be broken
- If there's a 'n' from 'ん', the break opportunity should be delayed to after it.
- 'ん' is determined by 'not followed by vowel. This doesn't work in cases of '[...]んお[...]' vs '[...]の[...]', but that's a shortcomming of romaji
- don't break early in words, that just looks awkward. just before the last character also looks weird.
- don't break off punctuation or numbers at the end of words*/
}
});
}
function linkFixer(){
if(location.pathname !== "/home"){
return;
}
let recentReviews = document.querySelector(".recent-reviews h2.section-header");
let recentThreads = document.querySelector(".recent-threads h2.section-header");
if(recentReviews && recentThreads){
recentReviews.innerText = "";
let link = create("a",false,"Recent Reviews",recentReviews);
link.href = "https://anilist.co/reviews";
recentThreads.innerText = "";
let link2 = create("a",false,"Forum Activity",recentThreads);
link2.href = "https://anilist.co/forum/overview";
}
else{
setTimeout(linkFixer,2000);//invisible change, does not take priority
}
}
function addReviewConfidence(){
generalAPIcall("query{Page(page:1,perPage:30){reviews(sort:ID_DESC){id rating ratingAmount}}}",{},function(data){
let adder = function(){
if(location.pathname !== "/reviews"){
return;
}
let locationForIt = document.querySelector(".recent-reviews .review-wrap");
if(!locationForIt){
setTimeout(adder,200);
return;
}
let wilson = function(positiveScore,total){
if(total === 0){
return {
left: 0,
right: 0
};
}
// phat is the proportion of successes
// in a Bernoulli trial process
let phat = positiveScore / total;
// z is 1-alpha/2 percentile of a standard
// normal distribution for error alpha=5%
let z = 1.96;
// implement the algorithm https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval#Wilson_score_interval
let a = phat + z * z / (2 * total);
let b = z * Math.sqrt((phat * (1 - phat) + z * z / (4 * total)) / total);
let c = 1 + z * z / total;
return {
left: (a - b) / c,
right: Math.min(1,(a + b) / c)
};
};
data.data.Page.reviews.forEach(function(review,index){
let wilsonLowerBound = wilson(review.rating,review.ratingAmount).left
let extraScore = create("span",false,"~" + Math.round(100*wilsonLowerBound));
extraScore.style.color = "hsl(" + wilsonLowerBound*120 + ",100%,50%)";
extraScore.style.marginRight = "3px";
let parent = locationForIt.children[index].querySelector(".votes");
parent.insertBefore(extraScore,parent.firstChild);
if(wilsonLowerBound < 0.05){
locationForIt.children[index].style.opacity = "0.5";
}
});
};adder();
},"hohRecentReviews",30*1000);
}
function totalMangaBugfix(){
let URLstuff = location.pathname.match(/^\/user\/(.*?)\/?$/);
const query = `
query ($userName: String) {
Page(perPage:1){
pageInfo{
total
}
mediaList(type:MANGA,userName:$userName,status:CURRENT){
id
}
}
User(name:$userName){
stats{
mangaStatusDistribution{
status
amount
}
}
}
}`;
let variables = {
userName: URLstuff[1]
}
generalAPIcall(query,variables,function(data){
if(!data){
return;
}
if(Math.abs(data.data.Page.pageInfo.total - data.data.User.stats.mangaStatusDistribution.find(ele => ele.status === "CURRENT").amount) > 20){
let adder = function(){
if(!location.pathname.match(/^\/user\/(.*?)\/?$/)){
return;
}
let possibleStatsWrap = document.querySelectorAll(".stats-wrap .stats-wrap");
if(possibleStatsWrap && possibleStatsWrap.length === 2){
if(possibleStatsWrap[1].children.length === 3 && possibleStatsWrap[1].children[1].children[1].innerText === "Total Manga"){
let possibleWrongValue = possibleStatsWrap[1].children[1].children[0];
possibleWrongValue.innerText = parseInt(possibleWrongValue.innerText) + data.data.Page.pageInfo.total;
}
}
else{
setTimeout(adder,200);
}
};adder();
}
},"hohTotalMangaBugfix" + variables.userName,60*1000);
}
var urlChangedDependence = false;
if(useScripts.dropdownOnHover){
let addMouseover = function(){
let navThingy = document.querySelector(".nav .user .el-dropdown-link");
if(navThingy){
navThingy.onmouseover = function(){
let controls = document.getElementById(navThingy.attributes["aria-controls"].value);
if(!controls || controls.style.display === "none"){
navThingy.click();
}
}
}
else{
setTimeout(addMouseover,500);
}
};addMouseover();
}
function handleScripts(url){
if(url === "https://anilist.co/settings/apps"){
settingsPage();
}
else if(url === "https://anilist.co/notifications" && useScripts.notifications){
enhanceNotifications();
return;
}
else if(url === "https://anilist.co/reviews" && useScripts.reviewConfidence){
addReviewConfidence();
return;
}
if(url.match(/^https:\/\/anilist\.co\/(anime|manga)\/\d*\/[\w\-]*\/social/)){
if(useScripts.socialTab){
enhanceSocialTab();
};
if(useScripts.activityTimeline){
addActivityTimeline();
};
};
if(
url.match(/\/stats\/?$/)
&& useScripts.moreStats
){
addMoreStats();
};
if(
url.match(/^https:\/\/anilist\.co\/home#access_token/)
){
let tokenList = location.hash.split("&").map(a => a.split("="));
useScripts.accessToken = tokenList[0][1];
useScripts.save();
location.replace(location.protocol + "//" + location.hostname + location.pathname);
};
if(
url.match(/^https:\/\/anilist\.co\/home#aniscripts-login/)
){
if(useScripts.accessToken){
alert("Already authorized. You can rewoke this under 'apps' in your Anilist settings");
}
else{
location.href = authUrl;
};
};
if(url.match(/^https:\/\/anilist\.co\/user/)){
if(useScripts.completedScore || useScripts.droppedScore){//we also want this script to run on user pages
addCompletedScores();
};
if(useScripts.embedHentai){
embedHentai();
};
if(useScripts.noImagePolyfill){
addImageFallback();
};
setTimeout(function(){
let banner = document.querySelector(".banner");
if(banner){
let bannerLink = create("a",false,"⭳",banner,"position:absolute;right:10px;top:305px;font-weight:bolder;font-size:120%;");
bannerLink.href = banner.style.backgroundImage.replace("url(","").replace(")","").replace('"',"").replace('"',"");
bannerLink.title = "Banner Link";
};
},500);
totalMangaBugfix();
}
else if(
url.match(/^https:\/\/anilist\.co\/forum\/thread\/.*/)
){
if(useScripts.forumComments){
enhanceForum();
}
if(useScripts.embedHentai){
embedHentai();
};
}
else if(url.match(/^https:\/\/anilist\.co\/staff\/.*/)){
if(useScripts.staffPages){
enhanceStaff();
}
if(useScripts.replaceStaffRoles){
replaceStaffRoles();
};
}
else if(
url.match(/^https:\/\/anilist\.co\/character\/.*/)
&& useScripts.characterFavouriteCount
){
enhanceCharacter();
}
else if(
url.match(/^https:\/\/anilist\.co\/studio\/.*/)
&& useScripts.studioFavouriteCount
){
enhanceStudio();
}
else if(
url.match(/^https:\/\/anilist\.co\/edit/)
&& useScripts.enumerateSubmissionStaff
){
enumerateSubmissionStaff();
}
if(
url.match(/^https:\/\/anilist\.co\/user\/.*\/social/)
&& useScripts.CSSfollowCounter
){
addFollowCount();
};
if(
url.match(/^https:\/\/anilist\.co\/.+\/(anime|manga)list\/?(\?.*)?$/)
){
drawListStuff();
}
if(
url.match(/^https:\/\/anilist\.co\/user\/(.*)\/(anime|manga)list\/compare/)
&& useScripts.comparissionPage
){
addComparissionPage();
}
else{
let possibleHohCompareRemaining = document.querySelector(".hohCompare");
if(possibleHohCompareRemaining){
possibleHohCompareRemaining.remove();
};
};
if(url.match(/^https:\/\/anilist\.co\/search\/characters/)){
if(useScripts.characterFavouriteCount){
enhanceCharacterBrowse();
};
document.title = "Find Characters · AniList";
}
else if(url.match(/^https:\/\/anilist\.co\/search\/staff/)){
if(useScripts.staffPages){
enhanceStaffBrowse();
};
document.title = "Find Staff · AniList";
}
else if(url.match(/^https:\/\/anilist\.co\/search\/studios/)){
document.title = "Find Studios · AniList";
}
else if(url.match(/^https:\/\/anilist\.co\/search\/anime/)){
document.title = "Find Anime · AniList";
setTimeout(function(){
if(document.URL.match(/^https:\/\/anilist\.co\/search\/anime/)){
document.title = "Find Anime · AniList";
};
},100);
if(useScripts.browseFilters){
addBrowseFilters("anime");
};
}
else if(url.match(/^https:\/\/anilist\.co\/search\/manga/)){
document.title = "Find Manga · AniList";
if(useScripts.browseFilters){
addBrowseFilters("manga");
};
};
let mangaAnimeMatch = url.match(/^https:\/\/anilist\.co\/(anime|manga)\/(\d+)\/?([^/]*)?\/?(.*)?/);
if(mangaAnimeMatch){
setTimeout(function(){
let banner = document.querySelector(".banner");
if(banner){
let bannerLink = create("a",false,"⭳",banner,"position:absolute;right:10px;top:375px;font-weight:bolder;font-size:120%;");
bannerLink.href = banner.style.backgroundImage.replace("url(","").replace(")","").replace('"',"").replace('"',"");
};
},500);
if(useScripts.tagDescriptions){
enhanceTags();
};
if(useScripts.dubMarker && mangaAnimeMatch[1] === "anime"){
dubMarker();
}
else if(useScripts.mangaGuess && mangaAnimeMatch[1] === "manga"){
mangaGuess();
};
if(useScripts.mangaGuess && mangaAnimeMatch[1] === "anime"){
mangaGuess(true);
};
if(useScripts.MALscore){
addMALscore(mangaAnimeMatch[1],mangaAnimeMatch[2]);
};
if(useScripts.entryScore){
addEntryScore(mangaAnimeMatch[2]);
};
let titleAliases = JSON.parse(localStorage.getItem("titleAliases"));
if(useScripts.shortRomaji){
titleAliases = shortRomaji.concat(titleAliases);
};
if(titleAliases){
const urlID = mangaAnimeMatch[2];
for(var i=0;i 60*60*1000;//one hour
};
if(expired){
generalAPIcall("query{MediaTagCollection{name description}}",{},function(data){
data.data.MediaTagCollection.forEach(function(tag){
tagDescriptions[tag.name] = tag.description;
});
localStorage.setItem("hohTagCache",JSON.stringify({tags:tagDescriptions,updated:currentTime.valueOf()}));
});
}
else{
tagDescriptions = tagCache.tags;
};
console.log("Aniscripts " + scriptInfo.version);
Object.keys(localStorage).forEach(function(key){
if(parseInt(key)){//remove old implementation traces
localStorage.removeItem(key);
}
else if(key.match("hohListActivityCall")){
let cacheItem = JSON.parse(localStorage.getItem(key));
if(cacheItem){
if((new Date()).valueOf() > cacheItem.time + cacheItem.duration){
localStorage.removeItem(key)
}
}
}
else if(key === "aniscriptsUsed"){
localStorage.removeItem(key);
}
})
})();