Skip to content

Instantly share code, notes, and snippets.

@dpschen
Last active May 28, 2024 13:08
Show Gist options
  • Save dpschen/ffcff6d1c6a2f02b85690a5943769b78 to your computer and use it in GitHub Desktop.
Save dpschen/ffcff6d1c6a2f02b85690a5943769b78 to your computer and use it in GitHub Desktop.
Find duplicates links in OneTab
(function findDuplicatesInOnetab() {
const isOneTab = document
.querySelector("title")
?.innerHTML.includes("OneTab"); // cheap OneTab check
if (!isOneTab) {
alert("Run this script in a OneTab tab");
return;
}
const getOneTabLinks = () => [
...document.querySelectorAll("#contentAreaDiv [href]"),
];
const getDuplicateLinks = (links) => {
let linkList = links || getOneTabLinks();
linkList = linkList.map((linkEl) => ({
link: linkEl.getAttribute("href"),
linkEl,
}));
const duplicateLinks = [];
const groupedDuplicates = [];
linkList.forEach(({ link, linkEl }, index) => {
const alreadyFound = duplicateLinks.includes(link);
if (alreadyFound) {
return;
}
const foundDuplicateEls = linkList
.filter(({ link: linkCompare }, indexCompare) => {
const alreadyFound = duplicateLinks.includes(linkCompare);
if (index === indexCompare || alreadyFound || link !== linkCompare) {
return false;
}
return true;
})
.map(({ linkEl }) => linkEl);
if (foundDuplicateEls.length) {
duplicateLinks.push(link);
groupedDuplicates.push({
link,
linkEls: [linkEl, ...foundDuplicateEls],
});
}
});
return groupedDuplicates;
};
const scrollToEl = (el) => {
el.scrollIntoView({ behavior: "smooth", block: "center" });
};
const markLink = (el, text) => {
el.style.backgroundColor = "#DE5918";
el.style.color = "#fff";
if (text) {
const duplicateMarker = document.createElement("span");
duplicateMarker.innerHTML = text;
duplicateMarker.classList.add("duplicate-marker");
duplicateMarker.style.marginRight = "20px";
el.insertAdjacentElement("afterbegin", duplicateMarker);
}
};
const unMarkLinks = (linkEls = getOneTabLinks()) => {
linkEls.forEach((el) => {
el.style.backgroundColor = undefined;
el.style.color = undefined;
const duplicateMarker = el.querySelector(".duplicate-marker");
if (duplicateMarker) duplicateMarker.remove();
});
};
const findDuplicates = (links) => {
unMarkLinks(links);
const groupedDuplicates = getDuplicateLinks(links);
if (!groupedDuplicates.length) {
alert("No Duplicates Found");
} else {
groupedDuplicates.forEach((duplicate, groupIndex) =>
duplicate.linkEls.forEach((el, duplicateIndex) =>
markLink(
el,
`${groupIndex + 1}/${groupedDuplicates.length} | ${
duplicateIndex + 1
}/${duplicate.linkEls.length}`
)
)
);
alert(`${groupedDuplicates.length} Duplicates Found`);
scrollToEl(groupedDuplicates[0].linkEls[0]);
}
};
findDuplicates(getOneTabLinks());
})();
@sychochicken
Copy link

Hello, I've just used this and it worked very well, thank you for your work.

@insectman
Copy link

insectman commented May 28, 2024

I've made this change to improve performance drastically (relevant for large number of tabs):

  const getDuplicateLinks = (links) => {
    const linkMap = new Map();
    let linkList = links || getOneTabLinks();
    linkList.forEach((linkEl) => {
      const link = linkEl.getAttribute("href");
      if (!linkMap.has(link)) {
        linkMap.set(link, [linkEl]);
      } else {
        linkMap.get(link).push(linkEl);
      }
    });
    return Array.from(linkMap.values()).filter((linkEls) => linkEls.length > 1).map((le) => ({ link: le[0].getAttribute("href"), linkEls: le }));
  };

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