Instagram Keyboard Shortcuts for Power User

Scroll through posts with standard J/K keyboard shortcuts. L to like, O to save, U/I to rewind/fast forward video, M to Mute/Unmute, Space to play/pause video. Why J/K navigation? Because it's also used in Facebook, Twitter, Tumblr, Gmail, etc.

// ==UserScript==
// @name         Instagram Keyboard Shortcuts for Power User
// @namespace    http://tampermonkey.net/
// @version      2.2.0
// @description  Scroll through posts with standard J/K keyboard shortcuts. L to like, O to save, U/I to rewind/fast forward video, M to Mute/Unmute, Space to play/pause video. Why J/K navigation? Because it's also used in Facebook, Twitter, Tumblr, Gmail, etc.
// @author       French Bond
// @match        https://www.instagram.com/*
// @grant        none
// @require      https://code.jquery.com/jquery-3.4.1.min.js
// ==/UserScript==

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

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

$(function () {
  'use strict';

  const headerHeight = 62;
  const scrollSpeed = 200;

  // Disable when user is typing
  $('input,textbox,select')
    .focus(() => {
      searchFocused = true;
    })
    .blur(() => {
      searchFocused = false;
    });

  // Function to check if an element is visible
  function isVisible(element) {
    if (!element) return false;

    const style = window.getComputedStyle(element);

    // Check if the element has zero size
    const hasSize = !!(
      element.offsetWidth ||
      element.offsetHeight ||
      element.getClientRects().length
    );

    // Check visibility-related CSS properties
    const isNotHidden =
      style.display !== 'none' &&
      style.visibility !== 'hidden' &&
      style.opacity !== '0';

    return hasSize && isNotHidden;
  }

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

  // Handle key press
  $('body').keydown(function (e) {
    if (searchFocused || scrolling) return;

    // A - Toggle see all
    if (e.keyCode === 65) {
      seeAll = !seeAll;
    }

    // J - Scroll down
    if (e.keyCode === 74) {
      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) {
            scrolling = true;
            $('html, body').animate(
              { scrollTop: top },
              {
                duration: scrollSpeed,
                done: () => {
                  scrolling = false;
                },
              }
            );
            currentArticle = article;
            return false;
          }
        });
      }
    }

    // K - Scroll up
    if (e.keyCode === 75) {
      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) {
              scrolling = true;
              $('html, body').animate(
                { scrollTop: $(previousArticle).offset().top - headerHeight },
                {
                  duration: scrollSpeed,
                  done: () => {
                    scrolling = false;
                  },
                }
              );
              currentArticle = previousArticle;
            }
            return false;
          }
          previousArticle = article;
        });
      }
    }

    // L - Like
    if (e.keyCode == 76) {
      $('[aria-label="Like"],[aria-label="Unlike"]', currentArticle)
        .parent()
        .click();
    }

    // O - Save
    if (e.keyCode == 79) {
      const firstElement = $(
        '[aria-label="Save"],[aria-label="Remove"]',
        currentArticle
      )[0];
      $(firstElement).parent().click();
    }

    // Space - Play/pause video
    if (e.keyCode == 32) {
      findAndControlVideo('playPause');
      e.preventDefault(); // Prevent page scroll
    }

    // U - Rewind 5 seconds
    if (e.keyCode == 85) {
      findAndControlVideo('rewind');
    }

    // I - Fast forward 10 seconds
    if (e.keyCode == 73) {
      findAndControlVideo('fastForward');
    }

    // M - Mute/unmute video
    if (e.keyCode == 77) {
      findAndControlVideo('muteUnmute');
    }
  });
});