Created
August 13, 2025 22:20
-
-
Save rodhfr/52a6d3e2b80db0b744168add5d95b808 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Debrid Media Manager | |
// @namespace https://debridmediamanager.com | |
// @version 1.6.2 | |
// @description Add accessible DMM buttons to IMDB, MDBList, AniDB, TraktTV, and Bittorrent sites with magnet links | |
// @author Ben Adrian Sarmiento <[email protected]> | |
// @license MIT | |
// @match *://*/* | |
// @grant none | |
// @downloadURL https://update.greasyfork.org/scripts/463268/Debrid%20Media%20Manager.user.js | |
// @updateURL https://update.greasyfork.org/scripts/463268/Debrid%20Media%20Manager.meta.js | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
const DMM_HOST = "https://debridmediamanager.com"; | |
const X_DMM_HOST = "https://x.debridmediamanager.com"; | |
const SEARCH_BTN_LABEL = "DMM🔎"; | |
function createButton(text, url) { | |
const button = document.createElement("button"); | |
// button.tabIndex = 0; | |
// button.disabled = false; | |
button.textContent = text; | |
button.style.fontFamily = "'Roboto', sans-serif"; | |
button.style.marginLeft = "5px"; | |
button.style.padding = "3px 5px"; | |
button.style.border = "none"; | |
button.style.borderRadius = "3px"; | |
button.style.background = "#00A0B0"; // Teal color | |
button.style.color = "#ECF0F1"; // Off-white color | |
button.style.cursor = "pointer"; | |
button.style.transition = "background-color 0.3s, transform 0.1s"; | |
// Hover effect | |
button.onmouseover = function () { | |
this.style.background = "#EDC951"; // Yellow color | |
}; | |
// Revert hover effect | |
button.onmouseout = function () { | |
this.style.background = "#00A0B0"; // Teal color | |
}; | |
// Click effect | |
button.onmousedown = function () { | |
this.style.transform = "scale(0.95)"; | |
this.style.background = "#CC333F"; // Dark red color | |
}; | |
// Revert click effect | |
button.onmouseup = function () { | |
this.style.transform = "scale(1)"; | |
this.style.background = "#EDC951"; // Yellow color (same as hover effect) | |
}; | |
// Open new tab on click | |
button.onclick = (event) => { | |
event.preventDefault(); | |
window.open(url, "_blank"); | |
}; | |
return button; | |
} | |
function createLink(text, url) { | |
const link = document.createElement("a"); | |
link.textContent = text; | |
link.href = url; | |
link.target = "_blank"; // Opens the link in a new tab | |
link.style.display = "inline-block"; // Display as inline-block to style like a button | |
link.style.fontFamily = "'Roboto', sans-serif"; | |
link.style.marginLeft = "5px"; | |
link.style.padding = "3px 5px"; | |
link.style.border = "none"; | |
link.style.borderRadius = "3px"; | |
link.style.background = "#00A0B0"; // Teal color | |
link.style.color = "#ECF0F1"; // Off-white color | |
link.style.textDecoration = "none"; // Remove underline from the link | |
link.style.cursor = "pointer"; | |
return link; | |
} | |
function addButtonToElement(element, text, url) { | |
const button = createButton(text, url); | |
element.appendChild(button); | |
} | |
function addLinkToElement(element, text, url) { | |
const button = createLink(text, url); | |
element.appendChild(button); | |
} | |
function getInfoHashFromMagnetLink(magnetLink) { | |
const urlParams = new URLSearchParams(magnetLink.substring(magnetLink.indexOf('?'))); | |
const xt = urlParams.get('xt'); | |
if (xt && xt.startsWith('urn:btih:')) { | |
return xt.substring(9); // Remove 'urn:btih:' | |
} | |
return null; | |
} | |
// IMDB functions | |
function addButtonsToIMDBSingleTitle() { | |
const targetElement = document.querySelector( | |
"section.ipc-page-background h1 > span" | |
); | |
if (targetElement && targetElement.hasAttribute("data-dmm-btn-added")) | |
return; | |
targetElement.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${X_DMM_HOST}/${window.location.pathname | |
.replaceAll("/", "") | |
.substring(5)}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
function addButtonsToIMDBList() { | |
const items = Array.from( | |
document.querySelectorAll( | |
".lister-item .lister-item-header, .lister-item .media" | |
) | |
).filter((item) => !item.hasAttribute("data-dmm-btn-added")); | |
items.forEach((item) => { | |
item.setAttribute("data-dmm-btn-added", "true"); | |
let link = item.querySelector('a[href^="/title/"]').href; | |
let imdbId = link.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addButtonToElement(item, SEARCH_BTN_LABEL, searchUrl); | |
}); | |
changeObserver("ul.ipc-metadata-list", addButtonsToIMDBList); | |
} | |
function addButtonsToIMDBChart() { | |
const items = Array.from(document.querySelectorAll(".cli-title")).filter( | |
(item) => | |
item.innerText.match(/\d+\./) && | |
!item.hasAttribute("data-dmm-btn-added") | |
); | |
items.forEach((item) => { | |
item.setAttribute("data-dmm-btn-added", "true"); | |
let link = item.querySelector('a[href^="/title/"]').href; | |
let imdbId = link.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addButtonToElement(item, SEARCH_BTN_LABEL, searchUrl); | |
}); | |
changeObserver("ul.ipc-metadata-list", addButtonsToIMDBChart); | |
} | |
// MDBList functions | |
function addButtonsToMDBListSingleTitle() { | |
const targetElement = document.querySelector( | |
"#content-desktop-2 > div > div:nth-child(1) > h3" | |
); | |
if (targetElement && targetElement.hasAttribute("data-dmm-btn-added")) | |
return; | |
targetElement.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${DMM_HOST}${window.location.pathname}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
function addButtonsToMDBListSearchResults() { | |
const items = Array.from( | |
document.querySelectorAll("div.ui.centered.cards > div") | |
).filter((item) => !item.hasAttribute("data-dmm-btn-added")); | |
items.forEach((item) => { | |
item.setAttribute("data-dmm-btn-added", "true"); | |
const targetElement = item.querySelector("div.header"); | |
if (targetElement) { | |
const url = targetElement.parentElement | |
.querySelector("a") | |
.href.replace("https://mdblist.com/", ""); | |
const searchUrl = `${DMM_HOST}/${url}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
}); | |
changeObserver("div.ui.centered.cards", addButtonsToMDBListSearchResults); | |
} | |
// AniDB functions | |
function addButtonsToAniDBSingleTitle() { | |
const targetElement = document.querySelector("#layout-main > h1.anime"); | |
if (targetElement && targetElement.hasAttribute("data-dmm-btn-added")) | |
return; | |
targetElement.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${DMM_HOST}/${window.location.pathname | |
.replaceAll("/", "") | |
.replace("anime", "anime/anidb-")}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
function addButtonsToAniDBAnyPage() { | |
const items = Array.from(document.querySelectorAll("a")).filter( | |
(item) => item.innerText.trim() && /\/anime\/\d+$/.test(item.href) && !item.hasAttribute("data-dmm-btn-added") | |
); | |
items.forEach((item) => { | |
item.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${DMM_HOST}/${item.href | |
.replace("https://anidb.net/", "") | |
.replaceAll("/", "") | |
.replace("anime", "anime/anidb-")}`; | |
addButtonToElement(item, SEARCH_BTN_LABEL, searchUrl); | |
}); | |
} | |
// TraktTV functions | |
function addButtonsToTraktTVSingleTitle() { | |
const targetElement = document.querySelector("#summary-wrapper div > h1"); | |
if (targetElement && targetElement.hasAttribute("data-dmm-btn-added")) | |
return; | |
// find imdb id in page, <a data-type="imdb"> | |
const imdbId = document | |
.querySelector("a#external-link-imdb") | |
?.href?.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
targetElement.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
// iCheckMovies functions | |
function addButtonsToiCheckMoviesSingleTitle() { | |
const imdbId = document | |
.querySelector("a.optionIMDB") | |
?.href?.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
const targetElement = document.querySelector("#movie > h1"); | |
if (targetElement && targetElement.hasAttribute("data-dmm-btn-added")) | |
return; | |
targetElement.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
function addButtonsToiCheckMoviesBetaSingleTitle() { | |
const imdbId = document | |
.querySelector("a.stat-imdb") | |
?.href?.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
const targetElement = document.querySelector("h1.title"); | |
if (targetElement && targetElement.hasAttribute("data-dmm-btn-added")) | |
return; | |
targetElement.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addLinkToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
function addButtonsToiCheckMoviesList() { | |
const items = Array.from( | |
document.querySelectorAll("ol#itemListMovies > li") | |
).filter((item) => !item.hasAttribute("data-dmm-btn-added")); | |
items.forEach((item) => { | |
const imdbId = item | |
.querySelector("a.optionIMDB") | |
?.href?.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
const targetElement = item.querySelector("h2 a"); | |
if (!targetElement) return; | |
item.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
}); | |
} | |
function addButtonsToiCheckMoviesBetaList() { | |
const items = Array.from( | |
document.querySelectorAll("div.media-content") | |
).filter((item) => !item.hasAttribute("data-dmm-btn-added")); | |
items.forEach((item) => { | |
const imdbId = item | |
.querySelector("a.stat-imdb") | |
?.href?.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
const targetElement = item.querySelector("h3.title"); | |
if (!targetElement) return; | |
item.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
}); | |
changeObserver( | |
"#app section.section div.columns", | |
addButtonsToiCheckMoviesBetaList | |
); | |
} | |
// letterboxd functions | |
function addButtonsToLetterboxdSingleTitle() { | |
const imdbId = document | |
.querySelector("a[data-track-action='IMDb']") | |
?.href?.match(/tt\d+/)?.[0]; | |
if (!imdbId) return; | |
// OLD LINE - This selector is incorrect | |
// const targetElement = document.querySelector("h1.filmtitle"); | |
// NEW LINE - This correctly targets the title's container | |
const targetElement = document.querySelector("h1.headline-1.primaryname"); | |
if (!targetElement || targetElement.hasAttribute("data-dmm-btn-added")) { | |
return; | |
} | |
targetElement.setAttribute("data-dmm-btn-added", "true"); | |
const searchUrl = `${X_DMM_HOST}/${imdbId}`; | |
addButtonToElement(targetElement, SEARCH_BTN_LABEL, searchUrl); | |
} | |
// observer utility function | |
function changeObserver(cssSelector, addBtnFn) { | |
const targetNode = document.querySelector(cssSelector); | |
if (!targetNode) return; | |
const config = { childList: true, subtree: true }; | |
let debounceTimer; | |
const callback = function (mutationsList, observer) { | |
if (debounceTimer) { | |
clearTimeout(debounceTimer); | |
} | |
debounceTimer = setTimeout(() => { | |
// if (!targetNode) return; | |
observer.disconnect(); | |
addBtnFn(); | |
observer.observe(targetNode, config); | |
}, 250); | |
}; | |
const observer = new MutationObserver(callback); | |
observer.observe(targetNode, config); | |
} | |
function addMagnetLinkButtonToElements(elements) { | |
elements.forEach(function(link) { | |
const magnetURL = link.href; | |
const infoHash = getInfoHashFromMagnetLink(magnetURL); | |
if (infoHash) { | |
const buttonURL = `https://debridmediamanager.com/library?addMagnet=${infoHash}`; | |
const button = createButton("DMM🧲", buttonURL); | |
link.parentNode.insertBefore(button, link.nextSibling); | |
} | |
}); | |
} | |
// Main function | |
const magnetLinks = document.querySelectorAll('a[href^="magnet:?"]'); | |
addMagnetLinkButtonToElements(magnetLinks); | |
const hostname = window.location.hostname; | |
///// IMDB ///// | |
if (hostname === "www.imdb.com") { | |
const isIMDBSingleTitlePage = /^\/title\//.test(location.pathname); | |
const isIMDBListPage = | |
/^\/search\//.test(location.pathname) || | |
/^\/list\/ls/.test(location.pathname); | |
const isIMDBChartPage = /^\/chart\//.test(location.pathname); | |
if (isIMDBSingleTitlePage) { | |
addButtonsToIMDBSingleTitle(); | |
} else if (isIMDBListPage) { | |
addButtonsToIMDBList(); | |
} else if (isIMDBChartPage) { | |
addButtonsToIMDBChart(); | |
} | |
///// IMDB MOBILE ///// | |
} else if (hostname === "m.imdb.com") { | |
const isIMDBSingleTitlePage = /^\/title\//.test(location.pathname); | |
const isIMDBListPage = | |
/^\/search\//.test(location.pathname) || | |
/^\/list\/ls/.test(location.pathname); | |
const isIMDBChartPage = /^\/chart\//.test(location.pathname); | |
if (isIMDBSingleTitlePage) { | |
addButtonsToIMDBSingleTitle(); | |
} else if (isIMDBListPage) { | |
addButtonsToIMDBList(); | |
} else if (isIMDBChartPage) { | |
addButtonsToIMDBChart(); | |
} | |
///// MDBLIST ///// | |
} else if (hostname === "mdblist.com") { | |
const isMDBListSingleTitlePage = /^\/(movie|show)\//.test( | |
location.pathname | |
); | |
if (isMDBListSingleTitlePage) { | |
addButtonsToMDBListSingleTitle(); | |
} else { | |
addButtonsToMDBListSearchResults(); | |
} | |
///// ANIDB ///// | |
} else if (hostname === "anidb.net") { | |
const isAniDBSingleTitlePage = /^\/anime\/\d+/.test(location.pathname); | |
if (isAniDBSingleTitlePage) { | |
addButtonsToAniDBSingleTitle(); | |
} | |
addButtonsToAniDBAnyPage(); | |
///// TRAKT TV ///// | |
} else if (hostname === "trakt.tv") { | |
const isTraktTVEpisodePage = /\/episodes\/\d/.test(location.pathname); | |
if (isTraktTVEpisodePage) return; | |
const isTraktTVSinglePage = /^\/(shows|movies)\/.+/.test(location.pathname); | |
if (isTraktTVSinglePage) { | |
addButtonsToTraktTVSingleTitle(); | |
} | |
///// ICHECKMOVIES ///// | |
} else if (hostname === "www.icheckmovies.com") { | |
const isiCheckMoviesListPage = /^\/lists\//.test(location.pathname); | |
if (isiCheckMoviesListPage) { | |
addButtonsToiCheckMoviesList(); | |
} | |
const isiCheckMoviesSingleTitlePage = /^\/movies\//.test(location.pathname); | |
if (isiCheckMoviesSingleTitlePage) { | |
addButtonsToiCheckMoviesSingleTitle(); | |
} | |
} else if (hostname === "beta.icheckmovies.com") { | |
const isiCheckMoviesListPage = /^\/lists\//.test(location.pathname); | |
if (isiCheckMoviesListPage) { | |
addButtonsToiCheckMoviesBetaList(); | |
} | |
const isiCheckMoviesSingleTitlePage = /^\/movies\//.test(location.pathname); | |
if (isiCheckMoviesSingleTitlePage) { | |
addButtonsToiCheckMoviesBetaSingleTitle(); | |
} | |
///// MYANIMELIST ///// | |
} else if (hostname === "myanimelist.net") { | |
///// KITSU ///// | |
} else if (hostname === "kitsu.io") { | |
///// LETTERBOXD ///// | |
} else if (hostname === "letterboxd.com") { | |
const isLetterboxdSingleTitlePage = /^\/film\//.test(location.pathname); | |
if (isLetterboxdSingleTitlePage) { | |
addButtonsToLetterboxdSingleTitle(); | |
} | |
///// JUSTWATCH ///// | |
} else if (hostname === "www.justwatch.com") { | |
///// TVDB ///// | |
} else if (hostname === "www.thetvdb.com") { | |
///// TMDB ///// | |
} else if (hostname === "www.themoviedb.org") { | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment