Netflix subtitle cleanup

Remove all "[inhales]", "[loud noise]" from the subtitles

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name        Netflix subtitle cleanup
// @namespace   Violentmonkey Scripts
// @match       https://www.netflix.com/*
// @grant       none
// @version     1.4
// @author      Einar Lielmanis, [email protected]
// @license     MIT
// @description Remove all "[inhales]", "[loud noise]" from the subtitles
// ==/UserScript==

let observed_node = undefined

let kill_song_lyrics = false

const cleanup = (t) => {
  if (kill_song_lyrics && t.includes('♪')) {
    return '' // ignore song lyrics
  } else if (t.includes('[') && t.includes(']')) {
    return t.replace(/(- *)?\[[^\]]+\]/g, '') // (maybe "- ") "[" .. (not "]")+ .. "]"
  } else if (t.includes('(') && t.includes(')')) {
    return t.replace(/(- *)?\([^\)]+\)/g, '') // (maybe "- ") "(" .. (not ")")+ .. ")"
  }

  return t
}

const on_mutated = (changes) => {
  const ts = observed_node.querySelectorAll('.player-timedtext-text-container span')
  for (let i = 0; i < ts.length; i++) {
    
    const t = ts[i].innerHTML
    const nt = cleanup(t)
    
    if (nt !== t) {
      ts[i].innerHTML = nt
      // console.log({ original: t, filtered: nt })
    }
  }
}

const observer = new MutationObserver(on_mutated)

const reobserve = () => {
  const elems = document.getElementsByClassName('player-timedtext')
  if (elems[0] !== undefined) {
    if (observed_node !== elems[0]) {
      observed_node = elems[0]
      console.log({ observed_node })
      observer.observe(observed_node, { childList: true, subtree: true})
    }
  }
  window.setTimeout(reobserve, 1000)
}


const run_tests = () => {
  // the tests are lightning fast, so just do run them quickly on every script startup
  const test_cleanup = (source, expected) => {
    console.assert(cleanup(source) === expected, { test_result: false, source, expected, actual: cleanup(source) })
  }
  test_cleanup('normal text', 'normal text')
  test_cleanup('[coughs]', '')
  test_cleanup('[coughs] yeah', ' yeah')
  test_cleanup('-[coughs]', '')
  test_cleanup('- [coughs]', '')
  test_cleanup('- (inhales)', '')
  test_cleanup('some ♪ singing', '')
  console.log('tests ok')
}


console.log('Netflix subtitle filter userscript starting up')
run_tests()
reobserve()