ExHentai/E-Hentai Infinite Pages / No Date Limit In Watched

Removes post limit when browsing watched tag posts

// ==UserScript==
// @name        ExHentai/E-Hentai Infinite Pages / No Date Limit In Watched
// @description Removes post limit when browsing watched tag posts
// @namespace   Violentmonkey Scripts
// @match       https://exhentai.org/watched
// @match       https://e-hentai.org/watched
// @version     1.0
// @author      shlsdv
// @icon        https://e-hentai.org/favicon.ico
// @license     MIT
// ==/UserScript==

var firstWatchedPage = null;
var firstWatchedDate = null;

const fullTag = {
  a: 'artist',
  c: 'character',
  char: 'character',
  cos: 'cosplayer',
  f: 'female',
  g: 'group',
  circle: 'group',
  l: 'language',
  lang: 'language',
  m: 'male',
  x: 'mixed',
  o: 'other',
  p: 'parody',
  series: 'parody',
  r: 'reclass'
}

function addFilterButton() {
  const fsearch = document.getElementById('f_search');
  const inputButton = document.createElement('input');
  inputButton.type = 'button';
  inputButton.value = 'Filter';

  inputButton.addEventListener('click', function() {
      sessionStorage.setItem('searchFilter',fsearch.value);
      applyFilter();
  });

  const searchBtn = fsearch.parentNode.querySelector('input[value="Search"]');

  searchBtn.addEventListener('mousedown', function() {
      sessionStorage.setItem('searchFilter','');
  });

  const clearBtn = fsearch.parentNode.querySelector('input[value="Clear"]');

  clearBtn.addEventListener('mousedown', function() {
      sessionStorage.setItem('searchFilter','');
  });

  if (fsearch) {
      const parentNode = fsearch.parentNode;
      parentNode.appendChild(inputButton);
  }
}

function parseFilterString(input) {
    if (!input) return {};

    let split = input.match(/([-]\b\w*:\s*"[^"]+"|[-]\b\w*:\s*\w+|-[^"]\w*\b(?=\s|$)|\b\w*:\s*"[^"]+"|\b\w*:\s*\w+|[^"]\w*\b(?=\s|$))/g);
    let result = {content: []};
    split.forEach(item => {
        let kv = item.trim().split(/:(.+)/);

        if (kv.length >= 2) {
            let x = kv[0].startsWith('-') ? kv[0].substring(1) : kv[0];
            if (x in fullTag) {
              kv[0] = (kv[0].startsWith('-') ? '-' : '') +  fullTag[x];
            }
            result[kv[0]] = kv[1].trim().replace(/["$]/g, '');
        } else {
            result['content'].push(kv[0]);
        }
    });

    result.content = result.content.join(' ');
    return result;
}

function setSearchBarToFilter() {
  var search = sessionStorage.getItem('searchFilter');
  if (search) {
   document.getElementById('f_search').value = search;
  }
}

function applyFilter() {
  var search = sessionStorage.getItem('searchFilter');
  var dict = parseFilterString(search);

  let elems = document.querySelectorAll('.glname');
  elems.forEach(elem => {
      let ancestor = elem.closest('tr') || elem.closest('.gl1t');
      if (!ancestor) return;
      ancestor.style.display = '';
      for (let key in dict) {
          let negation = key.startsWith('-');
          let adjustedKey = negation ? key.substring(1) : key;
          let containsKeyValue = ancestor.innerHTML.includes(adjustedKey + ':' + dict[key]);

          if ((negation && containsKeyValue) || (!negation && key === 'content' && ancestor.innerHTML.indexOf(dict[key]) === -1) ||
              (!negation && key !== 'content' && !containsKeyValue))
          {
              ancestor.style.display = 'none';
              break;
          }
      }
  });
}

function getDomain() {
  return window.location.href.includes('exhentai') ? 'exhentai.org' : 'e-hentai.org';
}

function getEarliestPostId() {
  const regex = new RegExp(`https://${getDomain()}/g/(\\d+)/.*`);
  const elements = document.querySelectorAll('a');
  for (let i = elements.length - 1; i >= 0; i--) {
      const match = elements[i].href.match(regex);
      if (match && match[1]) {
          return match[1];
      }
  }
  return null;
}

function initInfinitePages2() {
  const unext = document.querySelector('#unext');
  if (unext === null) {
    console.log('Infinite pages: unext does not exist in document (first page is probably empty).');
    return;
  }

  if (unext.tagName.toLowerCase() === 'span') {
    var id = getEarliestPostId();

    var nextUrl = '';
    var jump = 1;

    if (window.location.href.includes('&jump=')) {
      const urlParams = new URLSearchParams(window.location.search);
      jump = parseInt(urlParams.get('jump').replace(/\D/g, '')) + 1;
    }

    if (!window.location.href.includes('?next=') && id === null) {
      console.log("Infinite pages: url does not contain '?next=' and no post exists in document");
      return;
    }
    else if (id === null) {
      nextUrl = window.location.href.split('&jump=')[0];
      nextUrl += '&jump=' + jump;
    }
    else {
      var id = parseInt(id);
      nextUrl = `https://${getDomain()}/watched?next=${id}&jump=${jump}`;
    }

    console.log(nextUrl);

    const nextJumpLink = `<a id="unext" href="${nextUrl}">Jump &gt;</a>`;
    document.querySelector('#unext').parentNode.innerHTML = nextJumpLink;
    document.querySelector('#dnext').parentNode.innerHTML = nextJumpLink;
  }
}

(function() {
  initInfinitePages2();
  addFilterButton();
  applyFilter();
  setSearchBarToFilter();
})();