timedStudyBooru

lazy random image timer tampermonkey edition

Od 12.02.2024.. Pogledajte najnovija verzija.

// ==UserScript==
// @name         timedStudyBooru
// @namespace    http://tampermonkey.net/
// @version      2024-02-12.3
// @description  lazy random image timer tampermonkey edition
// @author       Izuthree
// @match        https://danbooru.donmai.us/posts/*
// @match        https://safebooru.donmai.us/posts/*
// @match        https://e621.net/posts/*
// @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
// ==/UserScript==

/*
todo:
- image set count limit but cleaner
- search term switching and randomize between saved searches
- day awareness/schedule
- gui overhaul
- fix behaviour when blacklisted image and not enabled
*/


let domain = window.location.hostname;
let studyTopic = GM_getValue('studyTopic');
let fullTimer = parseInt(GM_getValue('studyTimer'));
let timeout = parseInt(GM_getValue('studyTimer'));
let enabled = GM_getValue('enabled');
let toggled = GM_getValue('exerciseVisible');
let multiPart = GM_getValue('multiPart');
let improvPractice = GM_getValue('improvPractice');
let improvDelay = GM_getValue('improvDelay');
let restDelay = parseInt(GM_getValue('restDelay'));
let randomFlip = GM_getValue('randomFlip');
let setLength = parseInt(GM_getValue('setLength'));
let countupMode = GM_getValue('countupMode');
let countdownTimer;
let countupTimer;
let countupTime = 0;
let imgContainer;

const $ = window.jQuery; //im lazy

$(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
    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
    if($(imgContainer).attr("href")=="[/upgrade]" || $('#blacklist-list>li').length>0){
        if(enabled && toggled){window.location.href = "https://"+domain+"/posts/random?tags="+studyTopic;}}
    else if($('#page>p').length>0){
        if(enabled && toggled && $('#page>p').html().indexOf('takedown request.')>-1){
            window.location.href = "https://"+domain+"/posts/random?tags="+studyTopic;
    }}

    else{
    //if any undefined assume first run and get/set defaults
    if(enabled==undefined){enabled = false;}
    if(studyTopic==undefined){studyTopic = 'order:rank';}
    if(fullTimer==undefined){fullTimer = 150; timeout = 150;}
    if(toggled==undefined){toggled = false;}
    if(multiPart==undefined){multiPart = false;}
    if(improvPractice==undefined){improvPractice = false;}
    if(improvDelay==undefined){improvDelay=15};
    if(restDelay==undefined){restDelay=0};
    if(randomFlip==undefined){randomFlip=false;};
    if(setLength==undefined){setLength=-1;};
    if(countupMode==undefined){countupMode=false};

    //embed stuff after you fixed for defaults not before dumbass
    embeds();

    //weird but prevents it flickering enabled then disabling
    $('body').addClass('studyModeActive');
    if(improvDelay=='0'&&improvPractice&&enabled){$(imgContainer).addClass('improvToggle');}
    if(!toggled){$('.studymode').prop('disabled',true);}

    //if any properties are true, apply them immediately
    if(multiPart){$('.multiPartMode').toggleClass('dialogInactive');}
    if(improvPractice){$('.improvMode').toggleClass('dialogInactive');}
    if(countupMode){$('.countupToggle').toggleClass('dialogInactive');$('.timer').html(countupTime);}
    if (randomFlip==true){
        $('.randomHorizontal').toggleClass('dialogInactive');
        if(Math.floor(Math.random()*100)>50){
            $('.horizontalFlip').toggleClass('dialogInactive');
            $(imgContainer).toggleClass('horFlipped');
        }
    }
    //study button click handler
    $('.studyButton').click(function(){startStudying()});

    //skip button
    $('.skipButton').click(function(){changeImage()});

    //mode toggles
    $(".multiPartMode").click(function(){multiPart = !multiPart; $('.multiPartMode').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');
    });

    $(".grayscaleToggle").click(function(){
        $('.grayscaleToggle').toggleClass('dialogInactive');
        $(imgContainer).toggleClass('multiPartToggle');
    });

    $(".countupToggle").click(function(){countupLazy()});

    //toggle study mode
    $('.showHideStudy').click(function(){$('body').toggleClass('studyModeActive'); enabled=false; setValues();
                                         $('.studymode').prop('disabled',!$('.studymode').prop('disabled'));
                                         toggled = !$('.studymode').prop('disabled'); GM_setValue('exerciseVisible',toggled);});

    $(".studyTimer").on("input", function() {fullTimer = parseInt($('.studyTimer')[0].value); if(!enabled){$('.timer').html(fullTimer);} setValues();});
    $(".restTimer").on("input", function() {restDelay = parseInt($('.restTimer')[0].value); setValues();});
    $(".improvDelay").on("input", function() {improvDelay = parseInt($('.improvDelay')[0].value); setValues();});
    $(".setLength").on("input", function() {setLength = parseInt($('.setLength')[0].value); setValues();});
    }
});

//Run when all images/contents are loaded
$(window).on("load", function() {
    if (enabled==true) {$('.studymode').prop('disabled',false); countdownTimer = setInterval(countdown, 1000);}
});

//lol lmao
function countupLazy(){
        $('.countupToggle').toggleClass('dialogInactive');
        countupMode = !countupMode;
        if(countupMode==false){$('.timer').html(fullTimer);}
        if(countupMode==true){$('.timer').html(countupTime);}
}

function startStudying(){
    enabled = !enabled; setValues();
    if(enabled==true){
        if(countupMode==false){countdownTimer = setInterval(countdown, 1000); }
        if(countupMode==true){countupTime=0; $('.timer').html(countupTime); countupTimer = setInterval(countup, 1000);}
    }
    else{
         if(countupMode==false){$('.timer').html(fullTimer);clearInterval(countdownTimer); timeout = parseInt($('.studyTimer')[0].value);}
         if(countupMode==true){$('.timer').html(countupTime);clearInterval(countupTimer); countupTime=0;}
        $(imgContainer).removeClass('improvToggle');$(imgContainer).removeClass('multiPartToggle'); }
}

//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(){
    //reset timeout means you can't pause and resume but I don't care to fix this rn
    timeout = parseInt($('.studyTimer')[0].value);
    GM_setValue('exerciseVisible',toggled);
    studyTopic = $('.studyTopic')[0].value;
    fullTimer = parseInt($('.studyTimer')[0].value);
    GM_setValue('studyTopic',$('.studyTopic')[0].value);
    GM_setValue('studyTimer',$('.studyTimer')[0].value);
    GM_setValue('multiPart',multiPart);
    GM_setValue('improvDelay',$('.improvDelay')[0].value);
    GM_setValue('restDelay',$('.restTimer')[0].value);
    GM_setValue('setLength',$('.setLength')[0].value);
    GM_setValue('randomFlip',randomFlip);
    GM_setValue('countupMode',countupMode);
    GM_setValue('improvPractice',improvPractice);
    GM_setValue('enabled',enabled);
}

function changeImage(){
setValues();
window.location.href = "https://"+domain+"/posts/random?tags="+studyTopic;
}

function countup(){
    countupTime++;
    $('.timer').html(countupTime);
}

//shitty countdown but it does its job enough:tm:
function countdown(){
    if(enabled){
        timeout--;
        if(timeout>-1){$('.timer').html(timeout);}
        else{$('.timer').html("Resting...");}

        if(timeout < 1){
            clearInterval(countdownTimer);
            if(setLength>0){setLength--; ($('.setLength')[0].value) = setLength}
            if(setLength!=0){setTimeout(changeImage, (restDelay*1000));}
                       }
        if(timeout<=(fullTimer/2) && multiPart==true && $(imgContainer).hasClass('multiPartToggle')==false){
               $(imgContainer).addClass('multiPartToggle'); $('.timer').html(timeout);
        }
        //if session length is less than 15s, disable it
        //after improvDelay elapsed, blur the image
        //only if timer is more than 15 seconds
        if(fullTimer>15 && timeout<=(fullTimer-improvDelay) && timeout>15 && improvPractice==true && $(imgContainer).hasClass('improvToggle')==false){
               $(imgContainer).addClass('improvToggle'); $('.timer').html(timeout);
        }
        //if timer is less than 15 seconds, unblur the image to review versus the reference
        if(timeout<=15 && improvPractice==true && improvDelay!=0){$(imgContainer).removeClass('improvToggle');}
    }
}

//solely so I can collapse this mess lol
function embeds(){
$('body').append("<div class='studyContainer' style='display:none'>\
<div class='studyButton' title='Start/stop studying! (Hotkey 1)'>⏯</div>\
<input type='text' class='studyTopic' title='The search term to use for study topic.' value='"+studyTopic+"'></input>\
<input type='number' class='studyTimer' title='The duration of the timer.' min='0' value='"+fullTimer+"'></input>\
<input type='number' class='restTimer' min='0' title='The rest delay before switching to the next picture.' value='"+restDelay+"'></input>\
<div class='skipButton' title='Skip to next image (Hotkey 2)'>⏩</div>\
<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 class='modeDialog dialogInactive multiPartMode' title='After half duration is elapsed, image turns greyscale (Hotkey 3)'>Multi-part mode enabled</div>\
<div class='modeDialog dialogInactive improvMode' title='After 15 seconds, image is blurred significantly (Hotkey 4)'>Improv mode enabled</div>\
<input type='number' class='improvDelay' min='0' title='The delay before blurring the picture.' value='"+improvDelay+"'></input>\
<div class='modeDialog dialogInactive randomHorizontal' title='Randomly flip image horizontally on load (Hotkey 5)'>Random Horizontal Flip</div>\
<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 countupToggle' title='Increase timer instead of decreasing it, to see how long it takes to finish things (Hotkey 8)'>Count Up</div>\
</div>");


$('body').append("<div class='timer'>"+fullTimer+"</div>");
$('body').append("<div class='showHideStudy' style='position:fixed;height:25px;background:#333;color:white;bottom:0px;right:0px;padding:5px;z-index:99;'>Toggle Study Mode</div>");
$('body').append("<style>.panicbutton{opacity:0;!important}</style>");
$('body').append("<style class='studymode'>\
.timer{position:fixed;bottom:50px;left:0;font-size:8vw;padding:10px;height:8vw;line-height:calc(10vw - 20px);color:rgba(255,255,255,1);text-shadow:0px 0px 7px black;z-index:99;}\
.image-container{position:fixed;top:0!important;left:0;width:100vw;height:100vh!important;background:black;margin:0!important;z-index:98;}\
.image-container>picture{display:flex!important;width:100vw!important;height:100vh!important;}\
.image-container>picture>img{height:100%!important;width:100%!important;object-fit:contain!important;max-width:100%!important;max-height:100%!important;}\
.studyContainer{width:calc(100vw - 200px);height:24px;position:fixed;bottom:0px;left:0px;z-index:999999999990;display:flex!important;}\
.studyTopic{width:220px;}\
.setLength{margin:0 4px 0 0}\
.studyTimer, .restTimer, .improvDelay, .setLength{width:70px;}\
.studyButton,.skipButton{height:22px;width:30px;font-size:22px;line-height:22px;cursor:pointer;}\
#image-container.multiPartToggle>img, .image-container.multiPartToggle>picture{filter: grayscale(100%);}\
#image-container.improvToggle>img, .image-container.improvToggle>picture{filter:blur(20px);}\
#image-container.multiPartToggle.improvToggle>img, .image-container.multiPartToggle.improvToggle>picture{filter: grayscale(100%) blur(20px)!important;}\
.modeDialog{cursor:pointer; padding:2px 8px;margin:0px 4px 2px 0px;color:white;background:#0078d7;}\
.dialogInactive{background:rgba(22,22,22,0.5)!important;}\
.horFlipped{transform:scaleX(-1);}\
.improvDelay{margin:0 5px 2px -5px;display:none;}\
.studyContainer:has(.modeDialog.improvMode:not(.dialogInactive)) .improvDelay{display:block;}\
#image-container{position:fixed;top:0;left:0;display:flex;width:100vw;height:100vh;background:black;justify-content:center;z-index:2;}\
#image-container>img{max-height:100%;object-fit:contain;}\
</style>");

//hotkeys
$(document).bind('keydown', function(e) {
    if(e.keyCode==27){$('picture').toggleClass('panicbutton');}
    if(!$('input').is(':focus') && toggled){
       if(e.keyCode=="49"){startStudying();}
       if(e.keyCode=="50"){changeImage();}
       if(!enabled){
       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();}
    }
    }
});
}