Instagram Keyboard Shortcuts for Power User (Fixed)

Scroll through posts with J/K keys, like with L, save with O, control videos with U/I/M/Space. Fully compatible with typing in text fields.

// ==UserScript==
// @name         Instagram Keyboard Shortcuts for Power User (Fixed)
// @namespace    http://tampermonkey.net/
// @version      2.7.0
// @description  Scroll through posts with J/K keys, like with L, save with O, control videos with U/I/M/Space. Fully compatible with typing in text fields.
// @author       French Bond (Fixes by Tampermonkey Scripter)
// @license      MIT
// @match        https://www.instagram.com/*
// @grant        none
// @icon         https://www.google.com/s2/favicons?sz=64&domain=instagram.com
// @require      https://code.jquery.com/jquery-3.4.1.min.js
// ==/UserScript==

/* globals jQuery, $ */
/* jshint esversion: 6 */

$(function () {
  'use strict';

  let seeAll = true;
  let currentArticle = null;
  let searchFocused = false;
  let scrolling = false;
  let slideshowInterval;
  let isSlideshow = false;

  const fastForward = 2;
  const rewind = 1;
  const headerHeight = 10;
  const scrollSpeed = 200;

  // ----------------------------
  // Improved Focus Detection
  // ----------------------------
  $(document).on('focus', 'input, textarea, [contenteditable="true"], [role="textbox"]', () => {
    searchFocused = true;
  });
  $(document).on('blur', 'input, textarea, [contenteditable="true"], [role="textbox"]', () => {
    searchFocused = false;
  });

  // ----------------------------
  // Helper Functions
  // ----------------------------

  function startSlideshow() {
    isSlideshow = true;
    slideshowInterval = setInterval(() => {
      findAndClickButton('Next');
    }, 5000);
  }

  function stopSlideshow() {
    isSlideshow = false;
    clearInterval(slideshowInterval);
  }

  function getCurrentPage() {
    const url = window.location.href;
    if (url === 'https://www.instagram.com/') return 'home';
    if (url.includes('?variant=favorites')) return 'favorites';
    if (url.includes('?variant=following')) return 'following';
    if (url.includes('/reels/')) return 'reels';
    if (url.includes('/p/')) return 'post';
    if (url.includes('/saved/')) return 'saved';
    if (url.includes('/explore/')) return 'explore';
    if (url.includes('/accounts/')) return 'profile';
    if (url.includes('/explore/tags/')) return 'tag';
    if (url.includes('/explore/locations/')) return 'location';
    if (url.includes('/tv/')) return 'igtv';
    return 'unknown';
  }

  function isVisible(element) {
    if (!element) return false;
    const style = window.getComputedStyle(element);
    const hasSize = !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
    const isNotHidden = style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
    return hasSize && isNotHidden;
  }

  function findAndControlVideo(action) {
    const video = $(currentArticle).find('video')[0];
    if (video) {
      switch (action) {
        case 'playPause':
          video.paused ? video.play() : video.pause();
          break;
        case 'rewind':
          video.currentTime -= rewind;
          break;
        case 'fastForward':
          video.currentTime += fastForward;
          break;
        case 'muteUnmute':
          const muteButton = $(currentArticle).find('[aria-label="Toggle audio"]');
          if (muteButton.length) muteButton.click();
          break;
      }
    }
  }

  function findTopVideo() {
    let closestVideo = null;
    let closestDistance = Infinity;
    $('video').each(function () {
      const rect = this.getBoundingClientRect();
      const distance = Math.abs(rect.top);
      if (distance < closestDistance) {
        closestDistance = distance;
        closestVideo = this;
      }
    });
    return closestVideo;
  }

  function scrollTo(pageY) {
    scrolling = true;
    $('html, body').animate(
      { scrollTop: pageY },
      {
        duration: scrollSpeed,
        done: () => {
          scrolling = false;
        },
      }
    );
  }

  // Case-insensitive and more robust button finder
  function findAndClickButton(ariaLabel) {
    ariaLabel = ariaLabel.toLowerCase();
    let buttons = document.querySelectorAll('article button, button');
    for (let btn of buttons) {
      const label = btn.getAttribute('aria-label');
      if (label && label.toLowerCase() === ariaLabel) {
        btn.click();
        return;
      }
    }
  }

  // ----------------------------
  // Keyboard Shortcuts
  // ----------------------------

  function homeKeyboardShortcuts(e) {
    switch (e.keyCode) {
      case 65: // A - Toggle see all
        seeAll = !seeAll;
        break;
      case 74: // J - Scroll down or next post
        if (seeAll && $(currentArticle).find('[aria-label="Next"]').length) {
          $(currentArticle).find('[aria-label="Next"]').click();
        } else {
          $('article').each(function (index, article) {
            const top = $(article).offset().top - headerHeight;
            if (isVisible(article) && top > $(window).scrollTop() + 1) {
              scrollTo(top);
              currentArticle = article;
              return false;
            }
          });
        }
        break;
      case 75: // K - Scroll up
        if (seeAll && $(currentArticle).find('[aria-label="Go Back"]').length) {
          $(currentArticle).find('[aria-label="Go Back"]').click();
        } else {
          let previousArticle = null;
          $('article').each(function (index, article) {
            const top = $(article).offset().top - headerHeight;
            if (isVisible(article) && top > $(window).scrollTop() - headerHeight - 20) {
              if (previousArticle) {
                scrollTo($(previousArticle).offset().top - headerHeight);
                currentArticle = previousArticle;
              }
              return false;
            }
            previousArticle = article;
          });
        }
        break;
      case 76: // L - Like
        $('[aria-label="Like"],[aria-label="Unlike"]', currentArticle).parent().click();
        break;
      case 79: // O - Save
        const firstElement = $('[aria-label="Save"],[aria-label="Remove"]', currentArticle)[0];
        $(firstElement).parent().click();
        break;
      case 32: // Space - Play/pause video
        findAndControlVideo('playPause');
        break;
      case 85: // U - Rewind
        findAndControlVideo('rewind');
        break;
      case 73: // I - Fast forward
        findAndControlVideo('fastForward');
        break;
      case 77: // M - Mute/unmute video
        findAndControlVideo('muteUnmute');
        break;
    }
  }

  function postKeyboardShortcuts(e) {
    switch (e.keyCode) {
      case 74: // J - Next
        findAndClickButton('Next');
        break;
      case 75: // K - Previous
        findAndClickButton('Go back');
        break;
      case 32: // Space - Toggle slideshow
        isSlideshow ? stopSlideshow() : startSlideshow();
        break;
    }
  }

  function reelsKeyboardShortcuts(e) {
    switch (e.keyCode) {
      case 39: // Right arrow - Fast forward
        const videoFF = findTopVideo();
        if (videoFF) videoFF.currentTime += fastForward;
        break;
      case 37: // Left arrow - Rewind
        const videoRW = findTopVideo();
        if (videoRW) videoRW.currentTime -= rewind;
        break;
    }
  }

  // ----------------------------
  // Main Keydown Handler
  // ----------------------------
  $('body').keydown(function (e) {
  if (
    searchFocused ||
    scrolling ||
    $(e.target).closest('[contenteditable="true"], input, textarea, [role="textbox"]').length > 0
  ) return;

  // Ignore browser/system shortcuts
  if (e.ctrlKey || e.altKey || e.metaKey) return;

  const handledKeys = [65, 74, 75, 76, 79, 32, 85, 73, 77, 37, 39]; // A, J, K, L, O, Space, U, I, M, Left, Right
  if (handledKeys.includes(e.keyCode)) {
    e.preventDefault();
    document.activeElement.blur();
  }

  const currentPage = getCurrentPage();
  console.log('Current page:', currentPage);

  switch (currentPage) {
    case 'home':
    case 'favorites':
    case 'following':
      homeKeyboardShortcuts(e);
      break;
    case 'reels':
      reelsKeyboardShortcuts(e);
      break;
    case 'post':
      postKeyboardShortcuts(e);
      break;
  }
  });
});