Skip to content

Instantly share code, notes, and snippets.

@alana314
Last active December 17, 2025 12:45
Show Gist options
  • Select an option

  • Save alana314/6bdc9af962fd8620a4fb to your computer and use it in GitHub Desktop.

Select an option

Save alana314/6bdc9af962fd8620a4fb to your computer and use it in GitHub Desktop.
//Now with less jquery
//1) go to your my-list page, and scroll to the bottom to make sure it's all loaded:
//http://www.netflix.com/browse/my-list
//2) Next, paste this in your developer tools console and hit enter:
[...document.querySelectorAll('.slider [aria-label]')].map(ele => ele.getAttribute('aria-label'))
//or use this to copy the list to your clipboard:
copy([...document.querySelectorAll('.slider [aria-label]')].map(ele => ele.getAttribute('aria-label')))
@m1337v
Copy link

m1337v commented Jan 2, 2021

Does anyone have an idea how to hide movies if they are either upvoted or downvoted? I only have a solution for downvotes if they are "greyed out". Maybe one could combine the scripts from here with this one?

    // ==/UserScript==
var $ = window.jQuery;
setInterval(function(){
        $('.slider-item:has(.is-disliked)').remove();
}, 1000);

@dwhitz
Copy link

dwhitz commented Sep 3, 2022

I suggest to take a look to https://github.com/origamiofficial/docker-netflix-migrate for exporting and importing netflix ratings

@shubkb07
Copy link

shubkb07 commented Dec 17, 2025

New, Support extracting title, URL to watch and Image + description,
Best things is Auto Scroll,
Future proof for class change, time in config,
Option to skip description to make it fast.

Step 1: Go to Netflix - My List - https://www.netflix.com/browse/my-list
Step 2: Press Control + Shift + J on Windows/Linux or Command + Option + J on Mac
Step 3: Copy Paste Below script

(async () => {
  'use strict';

  /* ================= CONFIG ================= */
  const CONFIG = {
    collectDescription: true, // true = slow, false = FAST 
    scrollIntervalMs: 3000,
    noIncreaseTimeoutMs: 30000, 
    modalOpenTimeoutMs: 8000,
    modalCloseTimeoutMs: 8000,
  };

  /* ================= SELECTORS ================= */
  const ROW_SELECTOR =
    '.galleryLockups .rowContainer.rowContainer_title_card';

  const ITEM_SELECTOR =
    '.galleryLockups .rowContainer.rowContainer_title_card .slider-item .ptrack-content';

  const MODAL_SELECTOR =
    '.focus-trap-wrapper.previewModal--wrapper.detail-modal';

  const MODAL_DESCRIPTION_SELECTOR =
    '.previewModal--detailsMetadata-left p div';

  /* ================= UTILS ================= */
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
  const nowMs = () => Date.now();

  const waitFor = async (fn, timeoutMs, stepMs = 200) => {
    let waited = 0;
    while (waited < timeoutMs) {
      const res = fn();
      if (res) return res;
      await sleep(stepMs);
      waited += stepMs;
    }
    return null;
  };

  const scrollToBottom = () => {
    window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth'
    });
  };

  const getRowCount = () =>
    document.querySelectorAll(ROW_SELECTOR).length;

  const closeModalViaHistory = async () => {
    // Netflix modal is route-based
    window.history.back();

    // wait until modal is really gone
    await waitFor(
      () => !document.querySelector(MODAL_SELECTOR),
      CONFIG.modalCloseTimeoutMs
    );

    // animation buffer
    await sleep(300);
  };

  const downloadJson = (data) => {
    const fileName = `netflix_my_list_${nowMs()
    }.json`;
    const blob = new Blob([JSON.stringify(data,
      null,
      2)
    ],
    {
      type: 'application/json',
    });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(a.href);
  };

  /* ================= STEP 1: AUTO SCROLL ================= */
  console.log('[Netflix Export
  ] Loading all items…');

  let lastCount = 0;
  let lastIncreaseAt = nowMs();

  while (true) {
    scrollToBottom();
    await sleep(CONFIG.scrollIntervalMs);

    const count = getRowCount();
    if (count > lastCount) {
      lastCount = count;
      lastIncreaseAt = nowMs();
      console.log(`[Scroll
      ] Rows: ${count
      }`);
    } else if (nowMs() - lastIncreaseAt >= CONFIG.noIncreaseTimeoutMs) {
      break;
    }
  }
  /* ================= STEP 2: COLLECT DATA ================= */
  console.log('[Netflix Export
  ] Collecting titles…');

  const nodes = Array.from(document.querySelectorAll(ITEM_SELECTOR));
  const results = [];

  for (let i = 0; i < nodes.length; i++) {
    const node = nodes[i
    ];
    const link = node.querySelector('a');
    const img = node.querySelector('.boxart-container img');
    if (!link) continue;

    const entry = {
      index: i + 1,
      href: 'https: //www.netflix.com/' + link.getAttribute('href'),
      title: link.getAttribute('aria-label'),
      image: img?.getAttribute('src') || null,
      description: null,
    };

    if (CONFIG.collectDescription) {
      try {
        link.scrollIntoView({ block: 'center'
        });
        await sleep(400);
        link.click();

        const modal = await waitFor(
          () => document.querySelector(MODAL_SELECTOR),
          CONFIG.modalOpenTimeoutMs
        );

        if (modal) {
          const descEl = await waitFor(
            () => modal.querySelector(MODAL_DESCRIPTION_SELECTOR),
            CONFIG.modalOpenTimeoutMs
          );

          if (descEl) {
            entry.description = descEl.innerText.trim();
          }

          await closeModalViaHistory();
        }
      } catch (e) {
        console.warn(`[${entry.title
          }
        ] description failed`, e);
        await closeModalViaHistory();
      }
    }

    results.push(entry);
    console.log(`[Collected
    ] ${entry.title
    }`);
  }
  /* ================= EXPORT ================= */
  downloadJson(results);
  console.log('[Netflix Export
  ] DONE 🎉');
})();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment