timedStudyBooru

lazy random image timer tampermonkey edition

As of 2024-07-15. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         timedStudyBooru
// @namespace    http://tampermonkey.net/
// @version      2024-07-15
// @description  lazy random image timer tampermonkey edition
// @author       Izuthree
// @match        https://danbooru.donmai.us/posts/*
// @match        https://safebooru.donmai.us/posts/*
// @match        http://behoimi.org/post/show/*
// @match        https://e621.net/posts/*
// @match        https://gelbooru.com/index.php?page=post*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=donmai.us
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

/* 24-07-15
fixed blur delay default
added force blur and blur slider
*/

/* 24-05-30
added preliminary 3dbooru support
*/

/* 24-03-30
added gm.getset for greasemonkey instead of tampermonkey
*/

/* 24-03-29
added simple vertical mode
*/

/* 24-03-10
fixed toggle states, forced non-toggled save state to be disabled
use domain as localstorage value for site-specific lists
fixed history fetching invalid smaller images (this makes the feature more expensive)
unblur improv mode is now tied to rest period, 0 rest means it won't unblur
cleaned up the mess of defaults because lol ?? exists
*/

/*
todo:
- make a date-driven timer instead of a shitty setinterval
- day awareness/schedule
*/


let domain = window.location.hostname;
let studyTopics = GM_getValue(domain) ?? [['order:rank',true]];
let fullTimer = GM_getValue('studyTimer') ?? 150;
let timeout = GM_getValue('studyTimer') ?? 150;
let enabled = GM_getValue('enabled') ?? false;
let toggled = GM_getValue('exerciseVisible') ?? false;
let multiPart = GM_getValue('multiPart') ?? false;
let improvPractice = GM_getValue('improvPractice') ?? false;
let improvDelay = GM_getValue('improvDelay') ?? 0;
let improvIntensity = GM_getValue('improvIntensity') ?? 50;
let restDelay = GM_getValue('restDelay') ?? 0;
let randomFlip = GM_getValue('randomFlip') ?? false;
let forceBlur = GM_getValue('forceBlur') ?? false;
let setLength = GM_getValue('setLength') ?? -1;
let countupMode = GM_getValue('countupMode') ?? false;
let splitTimer = GM_getValue('splitTimer') ?? false;
let minimalUI = GM_getValue('minimalUI') ?? false;
let history = GM_getValue('history') ?? [];
let historyToggle = GM_getValue('historyToggle') ?? false;
let historyLimit = GM_getValue('historyLimit') ?? 0;
let extraBlacklist = GM_getValue('extraBlacklist'); //currently unused
let countdownTimer;
let countupTimer;
let countupTime = 0;
let imgContainer;
let skipMe = false;

const $ = window.jQuery; //im lazy
embeds();

$(window).ready(function(){
    //some sites have image-container as an id, some have it as a class
    //easiest way to fix this is just have the element as a jquery variable, has to be fetched on .ready
    if($('#image-container').length>0){imgContainer=$('#image-container');}else{imgContainer=$('.image-container');}

    //skip immediately if blacklisted, upgrade needed or removed and the script is active
    let params = [$(imgContainer).find("[href*='/upgrade']").length,$('#blacklist-list>li').length];
    for(let i=0;i<params.length;i++){//check if specified parameters are true
        if(params[i]>0){skipMe[1]=true;}//notify of skip if they are
            //if(enabled){changeImage(true)}
    }//but only actually skip if enabled is true

    //handle listeners regardless of state
    $('.showHideStudy').click(function(){$('body').toggleClass('studyModeActive');$('.studyContainer').removeClass('timerRunning');enabled=false;toggled=!toggled;$('.studymode').prop('disabled',!$('.studymode').prop('disabled')); setValues();});

    $('.studyButton').click(function(){startStudying()});
    $('.skipButton').click(function(){changeImage(true)});
    $(".multiPartMode").click(function(){multiPart = !multiPart; $('.multiPartMode').toggleClass('dialogInactive');setValues()});
    $(".minimalUI").click(function(){minimalUI = !minimalUI; $('.studyContainer').toggleClass('lessUI'); $('.minimalUI').toggleClass('dialogInactive');setValues()});
    $(".improvMode").click(function(){improvPractice = !improvPractice; $('.improvMode').toggleClass('dialogInactive');setValues()});
    $(".randomHorizontal").click(function(){$('.randomHorizontal').toggleClass('dialogInactive');randomFlip=!randomFlip;setValues()});
    $(".horizontalFlip").click(function(){$('.horizontalFlip').toggleClass('dialogInactive');$(imgContainer).toggleClass('horFlipped');});
    $(".forceBlur").click(function(){$('.forceBlur').toggleClass('dialogInactive');forceBlur=!forceBlur;$(imgContainer).toggleClass('forcedBlur');});
    $(".grayscaleToggle").click(function(){$('.grayscaleToggle').toggleClass('dialogInactive');$(imgContainer).toggleClass('multiPartToggle');});
    $(".countupToggle").click(function(){if(!enabled){countupLazy()}});
    $(".timer").click(function() {splitTimer=!splitTimer;if(countupTimer){updateTimer(countupTime)};if(!countupTimer){updateTimer(timeout)}});
    $('.searchTermSave').click(function(){setValues();})
    $('.showSearchTerms').click(function(){$('.searchTermMenus').toggleClass('searchTermsInvisible');$('.showSearchTerms').toggleClass('dialogInactive');});
    $('.searchTermAddOption').click(function(){addStudyOption('Study Option','true');})
    $('.showHistory').click(function(){$('.historyContainer').toggleClass('historyVisible');
                                       if($('.historyVisible').length>0){parseHistory();}
                                       else{$('.historyItems').empty();}})
    $('.addSkips').click(function(){historyToggle=!historyToggle; $('.addSkips').toggleClass('dialogInactive');setValues();})
    $('.historyClear').click(function(){history = []; $('.historyItems').empty();setValues()});
    $('.removeInput').click(function(){$(this).parent().remove()});
    $('.disableInput').click(function(){let setting = $(this).parent().children('.studyTopicOption').attr('enabled') == 'true';;$(this).parent().children('.studyTopicOption').attr('enabled',!setting)});

    $(".improvBlurSlider").on("input", function() {improvIntensity = $('.improvBlurSlider')[0].value;
                                                  $('.lolhack').text('.forcedBlur,.studyModeActive #image-container.improvToggle>img, .image-container.improvToggle>picture{filter:blur('+improvIntensity/100*2+'cqmin);}\
.forcedBlur.multiPartToggle,.studyModeActive #image-container.multiPartToggle.improvToggle>img, .image-container.multiPartToggle.improvToggle>picture{filter: grayscale(100%) blur('+improvIntensity/100*2+'cqmin)!important;}')
                                                  })
    $(".studyTimer").on("input", function() {fullTimer = parseInt($('.studyTimer')[0].value); if(!enabled){updateTimer(fullTimer);} setValues();});
    $(".restTimer").on("input", function() {restDelay = parseInt($('.restTimer')[0].value); let aa = $('.restTimer')[0]; $(aa).attr('value',restDelay); setValues();});
    $(".improvDelay").on("input", function() {improvDelay = parseInt($('.improvDelay')[0].value); let aa = $('.improvDelay')[0]; $(aa).attr('value',improvDelay); setValues();});
    $(".setLength").on("input", function() {setLength = parseInt($('.setLength')[0].value); let aa = $('.setLength')[0];$(aa).attr('value',setLength); setValues();});
    $('.historySize').on('input',function(){historyLimit = parseInt($('.historySize')[0].value); let aa = $('.historySize')[0];$(aa).attr('value',historyLimit); setValues();})



    if(!toggled){$('.studymode').prop('disabled',true); enabled=false;} //script hidden if toggled off
    else{
    $('body').addClass('studyModeActive')
    //if any properties are true, apply them immediately
    if(multiPart){$('.multiPartMode').toggleClass('dialogInactive');}
    if(improvDelay=='0'&&improvPractice&&enabled){$(imgContainer).addClass('improvToggle');}
    if(minimalUI){$('.minimalUI').toggleClass('dialogInactive');$('.studyContainer').toggleClass('lessUI');}
    if(improvPractice){$('.improvMode').toggleClass('dialogInactive');}
    if(forceBlur){$('.forceBlur').toggleClass('dialogInactive');$(imgContainer).toggleClass('forcedBlur');}
    if(countupMode){$('.countupToggle').toggleClass('dialogInactive');updateTimer(countupTime);}
    if(historyToggle){$('.addSkips').toggleClass('dialogInactive');}
    if (randomFlip==true){
        $('.randomHorizontal').toggleClass('dialogInactive');
        if(Math.floor(Math.random()*100)>50){
            $('.horizontalFlip').toggleClass('dialogInactive');
            $(imgContainer).toggleClass('horFlipped');
        }
    }
    }});

//Run when all images/contents are loaded so you don't lose time while it's still loading
$(window).on("load", function() {
    if (enabled&&toggled) {
       $('.studyContainer').addClass('timerRunning');
       enabled=!enabled; //hack to account for startStudying flipping it
       startStudying();
    }
});

function startStudying(){
    enabled = !enabled;
    if(enabled){
        if(countupMode==false){countdownTimer = setInterval(countdown, 1000); }
        if(countupMode==true){countupTime=0; updateTimer(countupTime); countupTimer = setInterval(countup, 1000);}
        if (improvDelay == 0 && $('.improvToggle').length<=0){$('.image-container').addClass('improvToggle')}
        $('.studyContainer').addClass('timerRunning');
    }
    else{
         if(countupMode==false){updateTimer(fullTimer);clearInterval(countdownTimer); timeout = parseInt($('.studyTimer')[0].value);}
         if(countupMode==true){updateTimer(countupTime);clearInterval(countupTimer); countupTime=0;}
        $('.studyContainer').removeClass('timerRunning');
        $(imgContainer).removeClass('improvToggle');$(imgContainer).removeClass('multiPartToggle'); }
}

function parseHistory(){
for(let i=history.length-1;i>=0;i--){
    $('.historyItems').append('<a href="'+history[i][0]+'" style="background-image:url('+history[i][1]+')" /a>');
}
}

//set localstorage variables
//super lazy to set them all at once in a big function but I can't be arsed to make this more elegant
function setValues(){
    //recreate studytopics from the UI to save into an array
    studyTopics = [];
    let searchTerms = $('.searchTermOption');
    let delList = [];
    for(let i=0;i<searchTerms.length;i++){
    if($(searchTerms[i]).children('.studyTopicOption').val()!=''){studyTopics.push(new Array($(searchTerms[i]).children('.studyTopicOption').val(),$(searchTerms[i]).children('.studyTopicOption').attr('enabled')));}}
    GM_setValue(domain,studyTopics); //study topics uses the domain name as a variable name

    timeout = parseInt($('.studyTimer')[0].value); //reset timeout means you can't pause and resume, fixme when changing from shit timer
    fullTimer = parseInt($('.studyTimer')[0].value); //parse this now so the saved value is correct
    GM_setValue('studyTimer',fullTimer);

    //regular vars
    GM_setValue('exerciseVisible',toggled);
    GM_setValue('multiPart',multiPart);
    GM_setValue('improvDelay',$('.improvDelay')[0].value);
    GM_setValue('improvIntensity',$('.improvBlurSlider')[0].value);
    GM_setValue('restDelay',$('.restTimer')[0].value);
    GM_setValue('setLength',$('.setLength')[0].value);
    GM_setValue('randomFlip',randomFlip);
    GM_setValue('forceBlur',forceBlur);
    GM_setValue('countupMode',countupMode);
    GM_setValue('improvPractice',improvPractice);
    GM_setValue('splitTimer',splitTimer);
    GM_setValue('enabled',enabled);
    GM_setValue('minimalUI',minimalUI);
    GM_setValue('history',history);
    GM_setValue('historyLimit',historyLimit);
    GM_setValue('historyToggle',historyToggle);
}

function changeImage(skipped){
    console.log(domain);
    if(skipped==undefined){skipped=false};
    if(skipped && historyToggle && !skipMe[1]){addHistory();}
    else if(!skipped){addHistory();}
    if(!skipMe[0]){setValues();}
    let possibleTopics = [];
    for(let i=0;i<studyTopics.length;i++){if(studyTopics[i][1]=='true'){possibleTopics.push(studyTopics[i][0]);}}

    if(domain=="gelbooru.com"){
        let searchTerm ="index.php?page=post&s=list&tags=sort%3arandom+"+possibleTopics[Math.floor(Math.random()*possibleTopics.length)];
        $('.dummy').load(searchTerm, function(data) {
            window.location.href = $($(data).find('.thumbnail-container a')[0]).attr('href');
        })}
    if(domain=="behoimi.org"){
        let searchParm = possibleTopics[Math.floor(Math.random()*possibleTopics.length)]
        $.ajax({url: "http://behoimi.org/post?tags="+searchParm+"&commit=Search", success: function(data){
          let pageCount = ($($(data).find('#paginator .pagination>a:nth-last-child(2)')[0]).html());
          pageCount = parseInt(pageCount);
          $.ajax({url: "http://behoimi.org/post/index?commit=Search&tags="+searchParm+"&page="+Math.floor(Math.random()*pageCount), success: function(data2){
              let elementNumber = $($(data2).find('.thumb>a'))
              window.location.href = $($(data2).find('.thumb>a')[Math.floor(Math.random()*elementNumber.length)]).attr('href');
          }})
        }})
    }
    else{
        window.location.href = "https://"+domain+"/posts/random?tags="+possibleTopics[Math.floor(Math.random()*possibleTopics.length)];
    }
}

function addHistory(){
    if(historyLimit!=0){
        if(history.length==(historyLimit) && historyLimit!=-1){history.shift()};
        let sampleLink;
        if($('.image-view-large-link').length>0){sampleLink=$('.image-view-large-link').attr('href');}
        else{sampleLink=$('#post-info-size a').attr('href');}
        history.push([window.location.href,sampleLink]);
    }
}

function updateTimer(time){
    if(splitTimer){
    let splitTime = Math.floor(time / 60);
    let seconds = time - Math.floor(time / 60) * 60;
    if(seconds<10){seconds = "0"+seconds;}
    splitTime = splitTime+":"+seconds;
    $('.timer').html(splitTime);}
    else{$('.timer').html(time);}
}

//shitty countdown but it does its job enough:tm:
function countdown(){
    if(enabled){
        if(timeout>-1){
            timeout--;
            //apply multiPart when timer is at 1/2, apply improvDelay when timeout is <= the variable
            if(timeout<=(fullTimer/2) && multiPart==true && $(imgContainer).hasClass('multiPartToggle')==false){$(imgContainer).addClass('multiPartToggle'); updateTimer(timeout);}
            if(timeout<=improvDelay && improvPractice==true && $(imgContainer).hasClass('improvToggle')==false){$(imgContainer).addClass('improvToggle'); updateTimer(timeout);}
            updateTimer(timeout);}
        else if (timeout<=0){
            clearInterval(countdownTimer);
            if(setLength>0){setLength--; ($('.setLength')[0].value) = setLength} //if setlength is >0, reduce it
            if(setLength!=0){ //then if setlength is not 0, load normally
                $('.timer').html("Resting...");
                if(restDelay!=0){$(imgContainer).removeClass('improvToggle');} //remove blur to review the improv image unblurred if delay is greater than 0
                $('.timer').addClass('timerRest');setTimeout(changeImage, (restDelay*1000));}
            }if(setLength==0){startStudying();} //else end study mode
    }
}

//lol lmao
function countupLazy(){
        $('.countupToggle').toggleClass('dialogInactive');
        countupMode = !countupMode;
        if(countupMode==false){updateTimer(fullTimer);}
        if(countupMode==true){updateTimer(countupTime);}
}
function countup(){countupTime++;updateTimer(countupTime);} //super lazy stopwatch that needs making not lazy

//UI button handler
function addStudyOption(studyName,isEnabled){
     $('.searchTermOptionContainer').append("<div class='searchTermOption'><input type='text' class='studyTopicOption' value='"+studyName+"' enabled='"+isEnabled+"'></input><div class='removeInput' title='Click to remove entry.'><p>-</p></div><div class='disableInput' title='Click to enable/disable entry.'><p>=</p></div></div>")
}
//solely so I can collapse this mess lol
//includes hotkey watchers
function embeds(){
    if (domain == "behoimi.org"){
        $('body').append('<style class="3dbooruOverrides">body.studyModeActive .content img{position:fixed;top:0;left:0;right:0;bottom:0;margin:auto!important;background:#000;z-index:2;max-height:100vh!important;max-width:100vw!important;object-fit:contain}body.studyModeActive .content:after{content:"";background:#000;position:fixed;width:100%;height:100%;top:0;left:0;z-index:1}</style>');
    }
    let splitTime;
    if(splitTimer){
    splitTime = Math.floor(fullTimer / 60);
    let seconds = fullTimer - Math.floor(fullTimer / 60) * 60;
    if(seconds<10){seconds = "0"+seconds;}
    splitTime = splitTime+":"+seconds;
    }else{splitTime=fullTimer};
    let screaming;if(enabled){screaming='timerRunning'};
$('body').append("<div class='timedBooruStudy'>\
<div class='dummy'></div>\
<div class='studyContainer "+screaming+"'>\
<div class='timerContainer'>\
<div class='timer'>"+splitTime+"</div>\
<div class='timerButtons'>\
<div class='studyButton' title='Start/stop studying! (Hotkey 1)'></div>\
<div class='skipButton' title='Skip to next image (Hotkey 2)'></div>\
</div>\
<div class='timersContainer'>\
<div class='stTim'><input type='number' class='studyTimer' title='The duration of the timer.' min='0' value='"+fullTimer+"'></input></div>\
<div class='rstTim'><input type='number' class='restTimer' min='0' title='The rest delay before switching to the next picture.' value='"+restDelay+"'></input></div></div>\
<div class='setNo'><input type='number' class='setLength' min='-1' title='Number of images to automatically advance to before disabling. -1 disables the feature, 0 stops the timer advancing to next image.' value='"+setLength+"'></input></div>\
</div>\
<div class='preferencesContainer'>\
<div class='showHideStudy'>Disable Study Mode</div>\
<div class='showSearchTerms dialogInactive'>Show/Hide Search Terms</div>\
<div class='searchTermMenus searchTermsInvisible'>\
<div class='searchTermAddContainer'><div class='searchTermAddOption' title='Add new search option'><p>Add New</p></div><div class='searchTermSave' title='Save changes (this shouldnt be necessary but just in case!)'><p>Save List</p></div></div>\
<div class='searchTermOptionContainer'></div></div>\
<div class='improvContainer' style='flex-wrap:wrap'>\
<div class='modeDialog dialogInactive improvMode' title='After 15 seconds, image is blurred significantly (Hotkey 4)' style='width:calc(100% - 50px); flex-grow:1'><p>Improv mode</p></div>\
<div class='improvInput' style='width:45px;flex-grow:1;'><input type='number' class='improvDelay' min='0' title='The delay before blurring the picture.' value='"+improvDelay+"'></input></div>\
<div class='improvBlur' style='width:100%'><input type='range' min='0' max='100' value='"+improvIntensity+"' class='improvBlurSlider'></div>\
</div>\
<div class='modeToggles'>\
<div class='modeDialog dialogInactive multiPartMode' title='After half duration is elapsed, image turns greyscale (Hotkey 3)'><p>Multi-Part Mode</p></div>\
<div class='modeDialog dialogInactive countupToggle' title='Increase timer instead of decreasing it, to see how long it takes to finish things (Hotkey 8)'><p>Count Up</p></div>\
<div class='modeDialog dialogInactive randomHorizontal' title='Randomly flip image horizontally on load (Hotkey 5)'><p>Random Flip</p></div>\
<div class='modeDialog dialogInactive minimalUI' title='Hide more UI while studying'><p>Hide Running UI</p></div>\
</div>\
<div class='displayToggles'>\
<div class='modeDialog dialogInactive horizontalFlip' title='Flip horizontally (Hotkey 6)'>H</div>\
<div class='modeDialog dialogInactive grayscaleToggle' title='Grayscale filter (Hotkey 7)'>G</div>\
<div class='modeDialog dialogInactive forceBlur' title='Force Blur'>FB</div>\
<div class='modeDialog dialogInactive showHistory' title='Show History'>Show History</div>\
</div></div>\
</div></div>");
for(let i=0;i<studyTopics.length;i++){addStudyOption(studyTopics[i][0],studyTopics[i][1]);}

$('.timedBooruStudy').append("<div class='historyContainer'><div class='historyHeader'>\
<div class='modeDialog dialogInactive addSkips'>Add Skips to History</div><div class='hisSize'><input type='number' class='historySize' min='-1' value='"+historyLimit+"'></input></div><div class='historyClear dialogInactive'>Clear History</div></div>\
<div class='historyItems'></div></div>");

    $('head').append('<link rel="preconnect" href="https://fonts.googleapis.com">\
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>\
<link href="https://fonts.googleapis.com/css2?family=Righteous&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">\
                     ');
$('body').append("<div class='showHideStudy'><p>Enable Study Mode</p></div>");
$('body').append("<style>.panicbutton{opacity:0;!important}</style>");
$('body').append("<style class='studyCSS'>\
@import url('https://fonts.googleapis.com/css2?family=Righteous&display=swap');\
.dummy{position:fixed;right:-100%;opacity:0;}\
.studyModeActive .image-container, .studyModeActive #image-container{position:fixed;top:0!important;left:0;width:100vw;height:100vh!important;background:black;margin:0!important;z-index:100;}\
.studyModeActive .image-container>picture{display:flex!important;width:100vw!important;height:100vh!important;}\
.studyModeActive .image-container>picture>img{height:100%!important;width:100%!important;object-fit:contain!important;max-width:100%!important;max-height:100%!important;}\
.studyModeActive #image-container.multiPartToggle>img, .image-container.multiPartToggle>picture{filter: grayscale(100%);}\
.studyModeActive #image-container.improvToggle>img, .image-container.improvToggle>picture{filter:blur("+improvIntensity/100*2+"cqmin);}\
.studyModeActive #image-container.multiPartToggle.improvToggle>img, .image-container.multiPartToggle.improvToggle>picture{filter: grayscale(100%) blur("+improvIntensity/100*2+"cqmin)!important;}\
.studyModeActive .horFlipped{transform:scaleX(-1);}\
.timedBooruStudy{color:white;}\
.studyModeActive #image-container{max-height:100vh!important;position:fixed;top:0;left:0;display:flex;width:100vw;height:100vh;background:black;justify-content:center;z-index:2;}\
.studyModeActive #image-container>img{max-height:100%;max-width:100%;}\
.image-container>img{max-height:100%;object-fit:contain;position:absolute;padding-left:300px!important;}\
.studyModeActive .timedBooruStudy{font-family:Righteous!important;}\
.timedBooruStudy *{box-sizing:border-box;}.timerRest{font-size:30pt!important;}\
.showSearchTerms,.studyContainer .showHideStudy{width:calc(100% - 20px);height:40px;cursor:pointer;padding:10px;border-radius:10px;margin:10px 10px;font-size:15pt;text-align:center;border:1px solid #ffffff55;user-select: none;transition:opacity 0.2s ease-in-out;}.studyModeActive picture img{padding-right:0px;padding-left:0px;}.studyModeActive:not(:has(.timerRunning)) section:not(.horFlipped)>picture>img{padding-left:clamp(300px,20%,20%);}.studyModeActive:has(.historyVisible) section:not(.horFlipped)>picture>img{padding-right:clamp(300px,20%,20%);}.studyModeActive:not(:has(.timerRunning)) .horFlipped>picture>img{padding-right:clamp(300px,20%,20%);}.studyModeActive:has(.historyVisible) .horFlipped>picture>img{padding-left:clamp(300px,20%,20%);}.studyContainer .showHideStudy{opacity:0.5;font-size:10pt;height:20px;line-height:0px;}.studyContainer .showHideStudy:hover{opacity:0.8}.timedBooruStudy{position:fixed;z-index:100;opacity:0;pointer-events:none;transition:opacity 0.2s ease-in-out}.studyModeActive .timedBooruStudy{opacity:1;pointer-events:auto;transition:opacity 0.2s ease-in-out;}.searchTermMenus{top:0;left:0;width:100%;height:auto;padding:0px 10px 0px 10px;margin:0 0 10px 0 ;text-align:center;position:relative;overflow-y:auto;transition:opacity 0.2s ease-in-out, height 0.2s ease-in-out, padding 0.2s ease-in-out;max-height:calc(44vh);border-bottom:1px solid #ffffff40;}input{background:#1a1a24;}.searchTermOptionContainer{min-height:100px;max-height:calc(100cqh - 40px);overflow-y:auto;}.searchTermOptionContainer>div{display:flex;width:100%;flex-wrap:wrap;}.searchTermOptionContainer>div>input{background:#1a1a24;flex-grow:1;padding-left:10px;border-top-left-radius:10px;border-bottom-left-radius:10px;}.searchTermOptionContainer>div>div{width:40px;height:40px;cursor:pointer;}.searchTermOption{width:100%;height:40px;margin-bottom:5px;}.studyTopicOption[enabled='false']{opacity:0.5;}.historyClear,.searchTermAddContainer{display:flex;}.searchTermAddOption,.searchTermSave{user-select: none;border-radius:10px;width:40%;flex-grow:1;height:40px;left:10px;border:1px solid #ffffff55;box-sizing:border-box;padding:10px;background:#ffffff11;cursor:pointer;text-align:center;}.searchTermSave{left:unset!important;right:10px;}.searchTermsInvisible{transform:scaleY(0);transform-origin:top;pointer-events:none;padding:0px 10px 0px 10px;overflow:hidden;opacity:0;height:0;transition:opacity 0.2s ease-in-out, transform 0.2s ease-in-out, padding 0.2s ease-in-out;}.studyModeActive .image-container.blacklisted-active{display:flex!important;justify-content:center;position:fixed;top:0;left:0;right:0;bottom:0;background:black;height:calc(100vh + 20px);width:100vw;z-index:3;margin:0!important;}.studyModeActive .image-container.blacklisted-active picture{width:100%;height:100%;display:flex;justify-content:center;}.studyModeActive .image-container.blacklisted-active img{filter:blur(40px) brightness(30%);margin:auto;display:block;}.studyModeActive .image-container.blacklisted-active:after{content:'Blacklisted Image';position:fixed;top:0;left:0;right:0;bottom:0;width:400px;height:max-content;color:white;background:#9C1D1Dcf;margin:auto;font-size:40pt;line-height:40pt;text-align:center;padding:20px;border-radius:20px;}.removeInput,.disableInput,.modeDialog{user-select: none;border:1px solid #ffffff55;display:flex;justify-content:center;align-items:center;background:#ffffff11}.disableInput{border-top-right-radius:10px;border-bottom-right-radius:10px;border-left:none;}.historyClear:hover,.removeInput:hover,.disableInput:hover,.searchTermAddOption:hover,.searchTermSave:hover,.modeDialog:hover{background:#ffffff33;transition:background 0.2s ease-in-out;}.studyContainer,.historyContainer{position:fixed;background:#3f4058dc;backdrop-filter: blur(10px);display:flex;flex-direction:column-reverse;z-index:101;left:0;top:0;width:clamp(300px,20%,20%);height:100vh;font-family: 'Righteous', sans-serif;justify-content:space-between;max-height:100vh;flex-wrap:nowrap;transition:background 0.2s ease-in-out, backdrop-filter 0.2s ease-in-out;}.timersContainer,.setNo,.improvContainer{display:flex;width:100%;padding:10px;}.timersContainer>div{position:relative;}.stTim{flex-grow:2;flex-shrink:1;}.stTim>input{border-top-left-radius:10px;border-bottom-left-radius:10px;text-align:right;}.rstTim{flex-grow:1;flex-shrink:2}.rstTim>input{border-top-right-radius:10px;border-bottom-right-radius:10px;}.rstTim:has([value='0']){opacity:0.5}.timersContainer input,.setNo input{width:100%;}.studyTimer,.restTimer,.setLength{height:50px;font-size:24pt;position:relative;}.hisSize:after,.stTim:after,.rstTim:after,.setNo:after,.improvContainer:after{content:'Timer';position:absolute;top:-8px;left:7px;font-size:18pt;pointer-events:none;transform:rotate(-2deg);text-shadow:0 0 4px black;}.rstTim:after{content:'Rest';right:7px;left:unset;transform:rotate(2deg)}.setNo:after{content:'Set Count';top:-2px;left:16px;}.setNo:has([value='-1']){opacity:0.5;}.setNo{position:relative;}.setLength{border-radius:10px;font-size:18pt;height:40px;}.modeToggles,.displayToggles{user-select: none;width:100%;display:flex;flex-wrap:wrap;padding:10px;gap:10px;}.modeToggles>div{width:30%;flex-grow:1;text-align:center;height:50px;display:flex;justify-content:center;}.modeDialog{display:flex;padding:5px;border-radius:10px;box-sizing:border-box;justify-content:center;align-items:center;opacity:1;transition:opacity 0.2s ease-in-out;gap:10px;cursor:pointer;}.showSearchTerms:not(.dialogInactive), .modeDialog:not(.dialogInactive){background:#ffffffcc;color:#3f4058}.modeDialog p,.searchTermOption p{margin:0;}.showSearchTerms.dialogInactive, .modeDialog.dialogInactive{opacity:0.5;}.showSearchTerms.dialogInactive:hover, .modeDialog.dialogInactive:hover{opacity:0.8;}.improvContainer{display:flex;width:100%;gap:0;position:relative;}.improvContainer>*{margin:0;}.improvContainer:has(.dialogInactive):after,.improvContainer:has(.dialogInactive) input{opacity:0.5;}.improvContainer:after{content:'Blur Delay';font-size:10pt;right:15px;left:unset;top:0;}.improvMode{width:70%;border-top-right-radius:0;border-bottom-right-radius:0;}.improvInput{width:30%;}.improvContainer input{width:100%;height:40px;border-top-right-radius:10px;border-bottom-right-radius:10px;}.displayToggles>*{flex-grow:1;}.preferencesContainer{position:relative;flex-grow:1;flex-shrink:1;overflow-y:auto;}.timerContainer{display:flex;flex-wrap:wrap;align-self:flex-end;width:100%;flex-shrink:0;}.timer{font-size:98pt;text-align:center;height:130px;width:100%;padding:10px;cursor:pointer;line-height:110px;text-shadow:0 0 4px #00000066;}.timerButtons{display:flex;width:100%;padding:10px;gap:10px;}.studyButton,.skipButton{cursor:pointer;border:1px solid #ffffff55;height:90px;padding:10px;border-radius:20px;position:relative;}.studyButton{background:#4A964455;flex-grow:1;transition:background 0.2s ease-in-out;}.skipButton{background:#49449655;aspect-ratio:1;min-width:90px;}.studyContainer.timerRunning .studyButton{background:#9C1D1D55;}.studyButton:hover{background:#4A9644cf;}.skipButton:hover{background:#494496cf;}.studyContainer.timerRunning .studyButton{background:#9C1D1Dcf;}.studyButton:after,.skipButton:after{content:'Start';display:block;font-size:24pt;margin:auto;position:absolute;top:0;left:0;right:0;bottom:0;width:max-content;height:max-content;}.studyContainer.timerRunning .studyButton:after{content:'Stop';width:max-content;}.skipButton:after{content:'Skip'}.preferencesContainer,.timerContainer{}.preferencesContainer{padding-bottom:0px;opacity:1;transition:padding-bottom 0.2s ease-in-out,opacity 0.2s ease-in-out;}.studyContainer.timerRunning .preferencesContainer{opacity:0;transition:opacity 0.2s ease-in-out;}.lessUI.timerRunning .preferencesContainer{padding-bottom:130px;transition:padding-bottom 0.2s ease-in-out,opacity 0.2s ease-in-out;}.studyContainer.timerRunning{background:#3f405800;backdrop-filter: blur(0px);transition:background 0.2s ease-in-out, backdrop-filter 0.2s ease-in-out;}.timerRunning .timerContainer{background:#3f40589c;transition:background 0.2s ease-in-out;}.timerContainer{position:relative;bottom:0px;transition:bottom 0.2s ease-in-out;}.lessUI.timerRunning .timerContainer{bottom:-130px;background:#3f40585c;backdrop-filter: blur(10px);transition:bottom 0.2s ease-in-out, opacity 0.2s ease-in-out;}.timersContainer{opacity:1;transition:opacity 0.2s ease-in-out}.lessUI.timerRunning .timersContainer{opacity:0;transition:opacity 0.2s ease-in-out}.historyContainer{left:unset;right:0;top:0;background:#3f4058dc;backdrop-filter: blur(10px);flex-direction:column;justify-content:flex-start;opacity:0;transition:opacity 0.2s ease-in-out;}.historyContainer.historyVisible{opacity:1;transition:opacity 0.2s ease-in-out;}.historyHeader{padding:10px;display:flex;gap:10px;width:100%;text-align:center;box-sizing:border-box;flex-wrap:wrap;}.historyHeader>*{flex-shrink:1;flex-grow:1;}.hisSize{position:relative;width:45%;flex-grow:1;flex-shrink:1;opacity:1;transition:opacity 0.2s ease-in-out;}.addSkips{width:45%;flex-shrink:1;}.hisSize:after{content:'History Length';font-size:12pt;left:unset;right:5px;transform:rotate(2deg)}.historySize{height:100%;width:100%;border-radius:10px;text-align:right;}.hisSize:has([value='-1']){opacity:0.5;transition:opacity 0.2s ease-in-out;}.historyClear{position:static;width:100%;}.historyContainer.historyHidden{}.historyItems{display:flex;background:#1a1a24;overflow-y:auto;flex-wrap:wrap;padding:10px;flex-shrink:1;gap:10px;width:calc(100% - 20px);box-sizing:border-box;margin:0 auto;border-radius:10px;transition:height 0.2s ease-in-out;}.historyItems>a{display:block;width:40%;aspect-ratio:1;flex-grow:1;max-width:calc(50% - 10px);background-size:cover;background-position:50% 50%;border-radius:5px;background-repeat:no-repeat;}.studyModeActive>.showHideStudy{opacity:0;pointer-events:none;}body>.showHideStudy{position:fixed;height:75px;color:white;width:80px;bottom:0px;right:0px;padding:5px;z-index:120;padding:10px;pointer-events:auto;opacity:1;background:#3f40585c;border-left:1px solid #ffffff55;border-top:1px solid #ffffff55;border-top-left-radius:10px;backdrop-filter: blur(10px);text-align:center;cursor:pointer;}body>.showHideStudy:hover{background:#3f4058fc}\
input,textarea,select{color:#fff!important;}.timerContainer:has(.timerRest){bottom:-250px!important;}\
@media (max-aspect-ratio: 1/1.1) {\
#image-container, .image-container{display:flex;align-items:center;width:100%!important;max-width:100%!important;left:0px!important;height:calc(100% - 350px)!important;max-height:calc(100% - 350px)!important;}\
.studyContainer{height:350px;width:100%;flex-direction:row;bottom:0px!important;top:unset!important;}\
.timerContainer{width:300px;margin-right:30px;}\
.timer{font-size:92pt;line-height:130px;}\
.historyContainer:not(.historyVisible){pointer-events:none;}\
body:has(.timerRunning) .image-container,body:has(.timerRunning) #image-container{max-height:100%!important;}\
#image-container img, .image-container picture img{padding:0!important;object-fit:contain}}\
</style>");
$('body').append('<style class="lolhack">\
.forcedBlur,.studyModeActive #image-container.improvToggle>img, .image-container.improvToggle>picture{filter:blur('+improvIntensity/100*2+'cqmin);}\
.forcedBlur.multiPartToggle, .studyModeActive #image-container.multiPartToggle.improvToggle>img, .image-container.multiPartToggle.improvToggle>picture{filter: grayscale(100%) blur('+improvIntensity/100*2+'cqmin)!important;}\
</style>');

//hotkeys
$(document).bind('keydown', function(e) {
    if(e.keyCode==27){$('img').toggleClass('panicbutton');}
    if(!$('input').is(':focus') && toggled){ //prevent hotkeys is an input is focused
       if(e.keyCode=="49"){startStudying();}
       if(e.keyCode=="50"){changeImage(true);}
       if(!enabled){ //doing these while enabled/running breaks stuff, so prevent it
       if(e.keyCode=="51"){multiPart=!multiPart; $('.multiPartMode').toggleClass('dialogInactive');}
       if(e.keyCode=="52"){improvPractice=!improvPractice; $('.improvMode').toggleClass('dialogInactive');}
       if(e.keyCode=="53"){randomFlip=!improvPractice; $('.randomHorizontal').toggleClass('dialogInactive');}
       if(e.keyCode=="54"){$('.horizontalFlip').toggleClass('dialogInactive');$(imgContainer).toggleClass('horFlipped');}
       if(e.keyCode=="55"){$('.grayscaleToggle').toggleClass('dialogInactive');$(imgContainer).toggleClass('multiPartToggle');}
       if(e.keyCode=="56"){countupLazy();}
    }
    }
});
}