• Login
  • Register
  • Login Register
    Login
    Username/Email:
    Password:
    Or login with a social network below
  • Forum
  • Website
  • GitHub
  • Status
  • Translation
  • Features
  • Team
  • Rules
  • Help
  • Feeds
User Links
  • Login
  • Register
  • Login Register
    Login
    Username/Email:
    Password:
    Or login with a social network below

    Useful Links Forum Website GitHub Status Translation Features Team Rules Help Feeds
    Jellyfin Forum Development Client Development Add additional keyboard shortsuts for image selection

     
    • 0 Vote(s) - 0 Average

    Add additional keyboard shortsuts for image selection

    Avoid long click paths with shortcuts
    dilyo
    Offline

    Junior Member

    Posts: 3
    Threads: 2
    Joined: 2023 Nov
    Reputation: 0
    #1
    2025-03-15, 02:54 PM
    I added some more keyboard shortcuts to edit images, because click path takes so long for modals to animate. Just throw the code into client.

    Code:
    // History of this ugly code - used with https://github.com/crittermike/shortkeys (split in per shortcut code, no shared functions). Moved it to a script, so i can use it in JMP.

    function clickElement(selector) {
      // Do not use it while using an input like search
      const activeElement = document.activeElement;
      if (activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA") {
        return;
      }
      return new Promise((resolve) => {
        const element = document.querySelector(selector);
        if (element) {
          element.click();
          resolve();
        } else {
          reject();
        }
      });
    }

    // Loading and animation takes a moment for a element to match selector
    function clickElementRetry(selector) {
      return new Promise((resolve) => {
        const interval = setInterval(() => {
          const element = document.querySelector(selector);
          if (element) {
            element.click();
            clearInterval(interval);
            resolve();
          }
        }, 100);
      });
    }

    // Loading and animation takes a moment for a element to match selector - edit hovered image type
    function clickElementRetryImageType(selector, imageType) {
      return new Promise((resolve) => {
        const interval = setInterval(() => {
          const element = document.querySelector(selector);
          if (element) {
            element.setAttribute("data-imagetype", imageType);
            element.click();
            clearInterval(interval);
            resolve();
          }
        }, 100);
      });
    }

    function triggerRightClick(selector) {
      return new Promise((resolve) => {
        const element = document.querySelector(selector);
        if (element) {
          const event = new MouseEvent("contextmenu", {
            bubbles: true,
            cancelable: true,
            view: window,
          });
          element.dispatchEvent(event);
          resolve();
        } else {
          reject();
        }
      });
    }

    function extractTagValue(url) {
      const urlParams = new URLSearchParams(url.split("?")[1]);
      return urlParams.get("tag");
    }

    function getType() {
      const possibleTags = ["Logo", "Thumb", "Primary", "Art"];
      let imageWithTag;

      for (let tag of possibleTags) {
        imageWithTag = document.querySelector(
          `.card-withuserdata .cardImageContainer.coveredImage img[src*="/Images/${tag}?"]`
        );
        if (imageWithTag) {
          return tag;
        }
      }
      return "Primary";
    }

    document.addEventListener("keydown", function (event) {
      if (event.ctrlKey && event.key === "e") {
        event.preventDefault();
        if (
          document.querySelector(
            ".card-hoverable:hover, .detailPageContent div.listItem:hover"
          )
        ) {
          triggerRightClick(
            ".card-hoverable:hover, .detailPageContent div.listItem:hover"
          ).then(() => {
            let imageType = getType();
            clickElementRetry('[data-id="editimages"]').then(() => {
              clickElementRetryImageType(".btnBrowseAllImages", imageType);
            });
          });
        } else {
          clickElement(
            '#itemDetailPage:not(.hide) .detailRibbon [title="More"]'
          ).then(() => {
            clickElementRetry('[data-id="editimages"]').then(() => {
              clickElementRetry(".btnBrowseAllImages");
            });
          });
        }
      }

      if (event.ctrlKey && event.key === "3") {
        if (document.querySelector(".card-hoverable:hover")) {
          triggerRightClick(".card-hoverable:hover").then(() => {
            clickElementRetry('[data-id="editimages"]');
          });
        } else {
          clickElement(
            '#itemDetailPage:not(.hide) .detailRibbon [title="More"]'
          ).then(() => {
            clickElementRetry('[data-id="editimages"]');
          });
        }
      }

      if (event.key === "s") {
        clickElement('[href="#/search.html"]');
      }

      if (event.key === "h") {
        clickElement('[href="#/"]');
      }
    });

    Usage
    Quote:
    CTRL+e (e for edit and unused)
    1. Dashboard (hovered element) - Next up/recently added episode will open selection for the primary episode image. Movie will open the image selection for primary image
    2. List (hovered element) - will open the image selection for currently used image type (primary/thumb/logo or (clear)Art) - I know I patched art and also removed banner in my client
    3. Search (hovered element) - will open the image selection for primary image
    4. Detail view - opens primary image OR the hovered resource. e.g. current movie or episode, but if next up is hovered, it will open that instead

    CTRL+3 (near e-key and unused)
    Opens only overview for the images and not the selection

    s
    Go to search

    h
    Go to hone/dashboard



    FAQ

    Code looks complicated! Why?!
    Over time, I wanted more and more features with same combo and I used a browser add-on, that had a code box per shortcut.
    ⇉ You Should use a switch-case! ⇒ "Fork" it and maintain it. Please post the plugin or PR below - thx  Ok-hand

    Why not integrate it into jellyfin-web?
    I know there is a shortcut functionality (used it before), but the jellyfin code base separates between devices types and shortcuts. I used a keyboard on Tablet, TV or Desktop. Easiest way was to just trigger/emulate the click path for my desired functionality. GitHub issues around shortcuts are stale, and I guess everybody wants something else (mapping and functions...). This can easily be adjusted for own needs e.g. add a metadata edit shortcut.

    Known issues
    - Clicks to fast and loading animation will be removed form finishing modal before - I DO NOT CARE (not a big fan of layering modals in a UI)
    - s for search will also search for s (new - suppression of input was handled by browser add-on, before I moved to a script)

    --- 

    I shared this, because I found some useful stuff in forum and metadata manager has no image maintenance.
    « Next Oldest | Next Newest »

    Users browsing this thread: 1 Guest(s)


    • View a Printable Version
    • Subscribe to this thread
    Forum Jump:

    Home · Team · Help · Contact
    © Designed by D&D - Powered by MyBB
    L


    Jellyfin

    The Free Software Media System

    Linear Mode
    Threaded Mode