🏠 Home 

Redacted YouTube Searcher

Add YouTube search links that open in a new tab.


Install this script?
// ==UserScript==
// @name         Redacted YouTube Searcher
// @license      MIT
// @namespace    https://redacted.sh/
// @version      1.3.1
// @description  Add YouTube search links that open in a new tab.
// @author       x__a
// @match        https://*.redacted.sh/*
// @grant        GM_xmlhttpRequest
// ==/UserScript==
(function () {
'use strict';
if (document.getElementById('redacted-youtube')) {
return;
}
main();
let activeTrack = null;
function slugify(string) {
return string
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_-]+/g, '-')
.replace(/^-+|-+$/g, '');
}
function onLoading(target) {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.id = 'redacted-youtube-spinner';
svg.setAttribute('viewBox', '0 0 100 100');
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.id = 'redacted-youtube-spinner-circle';
circle.setAttribute('cx', '50');
circle.setAttribute('cy', '50');
circle.setAttribute('r', '45');
svg.appendChild(circle);
target.appendChild(svg);
}
function setYoutubePlayerVisibility(state) {
localStorage.setItem('redacted-youtube-player-visibility', state);
const trackList = document.getElementById('redacted-youtube-track-list');
trackList.style.display = state === 'hidden' ? 'none' : '';
}
function onToggleTrackListVisibility(event) {
event.preventDefault();
const currentState = localStorage.getItem('redacted-youtube-player-visibility');
const newState = currentState === 'hidden' ? 'visible' : 'hidden';
setYoutubePlayerVisibility(newState);
}
function playFirstYouTubeR###lt(event) {
event.preventDefault();
let parent = event.target.parentElement;
let query = parent.getAttribute('data-query');
let existingPlayer = document.getElementById('redacted-youtube-player');
if (existingPlayer && activeTrack === parent.id) {
activeTrack = null;
existingPlayer.remove();
return
}
onLoading(parent);
GM_xmlhttpRequest({
method: 'GET',
url: `https://www.youtube.com/r###lts?search_query=${encodeURIComponent(query)}`,
onload: function (response) {
if (response.readyState === 4 && response.status === 200) {
if (existingPlayer) {
existingPlayer.remove();
}
let videoIds = response.responseText.match('"videoId"\s*:\s*"([^"]+)');
if (videoIds.length > 0) {
let player = document.createElement('iframe');
player.id = 'redacted-youtube-player';
player.src = `https://www.youtube-nocookie.com/embed/${videoIds[1]}?autoplay=1`
parent.appendChild(player);
document.getElementById('redacted-youtube-spinner').remove();
activeTrack = parent.id;
}
}
}
});
}
function main() {
const head = document.head || document.getElementsByTagName('head')[0];
const style = document.createElement('style');
style.id = 'redacted-youtube';
style.innerHTML = `
.redacted-youtube-link {
transition: all 0.15s ease !important;
line-height: 0 !important;
color: #c4302b !important;
}
.redacted-youtube-link:hover {
color: #ed5651 !important;
}
.redacted-youtube-link>svg {
width: 12px !important;
height: 12px !important;
}
.redacted-youtube-svg {
width: 12px !important;
height: 12px !important;
}
#redacted-youtube-player {
display: block;
border: none;
border-radius: 0.5rem;
margin-top: 0.5rem;
aspect-ratio: 16/9;
width: 100%;
}
#redacted-youtube-spinner {
animation: 2s linear infinite svg-animation;
max-width: 10px;
margin-left: 5px;
}
@keyframes svg-animation {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
#redacted-youtube-spinner-circle {
animation: 1.4s ease-in-out infinite both circle-animation;
display: block;
fill: transparent;
stroke: #ed5651;
stroke-linecap: round;
stroke-dasharray: 283;
stroke-dashoffset: 280;
stroke-width: 10px;
transform-origin: 50% 50%;
}
@keyframes circle-animation {
0%, 25% {
stroke-dashoffset: 280;
transform: rotate(0);
}
50%, 75% {
stroke-dashoffset: 75;
transform: rotate(45deg);
}
100% {
stroke-dashoffset: 280;
transform: rotate(360deg);
}
}
`;
head.appendChild(style);
const urlParams = new URLSearchParams(window.location.search);
document.querySelectorAll('table.torrent_table > tbody > tr').forEach((torrent) => {
const artistLink = torrent.querySelector('a[href*="artist.php?id"]');
const releaseLink = torrent.querySelector('a[href*="torrents.php?id"]');
if (!artistLink && !releaseLink) {
return;
}
let artist = artistLink ? artistLink.textContent : null;
if (/\/artist.php/.test(window.location.pathname) && urlParams.has('id')) {
artist = document.querySelector('.header > h2').textContent;
}
const release = releaseLink.textContent;
const query = encodeURIComponent(artist ? `${artist} - ${release}` : release);
const actionButtons = torrent.querySelector('span.torrent_action_buttons');
const addBookmarkButton = torrent.querySelector('span.add_bookmark');
if (actionButtons) {
actionButtons.insertAdjacentHTML('beforeend', `
| <a href="https://www.youtube.com/r###lts?search_query=${query}" class="tooltip redacted-youtube-link" rel="noopener" target="_blank" title="Search YouTube">
<svg role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path d="M23.495 6.205a3.007 3.007 0 0 0-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 0 0 .527 6.205a31.247 31.247 0 0 0-.522 5.805 31.247 31.247 0 0 0 .522 5.783 3.007 3.007 0 0 0 2.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 0 0 2.088-2.088 31.247 31.247 0 0 0 .5-5.783 31.247 31.247 0 0 0-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/>
</svg>
</a>
`);
return;
}
if (addBookmarkButton) {
addBookmarkButton.insertAdjacentHTML('beforebegin', `
<span title="Search YouTube" class="tooltip" style="margin-left: 4px">
<a href="https://www.youtube.com/r###lts?search_query=${query}" class="redacted-youtube-link" rel="noopener" target="_blank">
<svg role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
<path d="M23.495 6.205a3.007 3.007 0 0 0-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 0 0 .527 6.205a31.247 31.247 0 0 0-.522 5.805 31.247 31.247 0 0 0 .522 5.783 3.007 3.007 0 0 0 2.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 0 0 2.088-2.088 31.247 31.247 0 0 0 .5-5.783 31.247 31.247 0 0 0-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/>
</svg>
</a>
</span>
`);
}
});
if (/\/torrents.php/.test(window.location.pathname) && urlParams.has('id')) {
const trackLinks = [];
const artist = Array.from(document.querySelectorAll('h2 a[href*="artist.php"'))
.map((link) => link.textContent)
.join(' & ');
let fileRows = document.querySelectorAll('table.filelist_table > tbody > tr:not(.colhead_dark) > td:not(.number_column)');
fileRows.forEach((item, index) => {
let file = item.textContent;
let regex = /^\d+\W* (.*)\.(flac|mp3)$/g;
let matches = [...file.matchAll(regex)];
let track = matches[0] ? matches[0][1] : null;
if (!track) {
return;
}
let artistAndTrack = track.includes(artist) ? track : `${artist} - ${track}`;
let trackId = slugify(track);
let trackLinkElement = document.createElement('tr');
let trackLinkTableData = document.createElement('td');
trackLinkTableData.id = trackId;
trackLinkTableData.setAttribute('data-query', artistAndTrack);
let trackLinkAnchor = document.createElement('a');
trackLinkAnchor.href = '#'
trackLinkAnchor.innerHTML = track;
trackLinkAnchor.addEventListener('click', () => playFirstYouTubeR###lt(window.event));
let trackSearchAnchor = document.createElement('a');
trackSearchAnchor.innerHTML = `
<a href="https://www.youtube.com/r###lts?search_query=${encodeURIComponent(artistAndTrack)}" title="Search on YouTube" rel="noopener" target="_blank">
<svg width="12" height="12" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5">
<path fill-rule="evenodd" d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z" clip-rule="evenodd" />
<path fill-rule="evenodd" d="M6.194 12.753a.75.75 0 001.06.053L16.5 4.44v2.81a.75.75 0 001.5 0v-4.5a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.553l-9.056 8.194a.75.75 0 00-.053 1.06z" clip-rule="evenodd" />
</svg>
</a>`;
trackLinkElement.appendChild(trackLinkTableData);
trackLinkTableData.appendChild(trackLinkAnchor);
trackLinkTableData.appendChild(trackSearchAnchor);
if (trackLinks.findIndex(trackLink => trackLink.id === trackId) === -1) {
trackLinks.push({
id: trackId,
element: trackLinkElement
});
}
});
if (trackLinks.length > 0) {
const table = document.createElement('table');
table.id = 'redacted-youtube-tracks-table';
table.className = 'collage_table';
const thead = document.createElement('thead');
const headerRow = document.createElement('tr');
headerRow.className = 'colhead';
const headerCell = document.createElement('td');
const upLink = document.createElement('a');
upLink.href = '#';
upLink.textContent = '↑';
const trackSearchText = document.createTextNode(' YouTube Track Search ');
const showLink = document.createElement('a');
showLink.href = '#';
showLink.textContent = '(Show)';
showLink.onclick = onToggleTrackListVisibility;
headerCell.appendChild(upLink);
headerCell.appendChild(trackSearchText);
headerCell.appendChild(showLink);
headerRow.appendChild(headerCell);
thead.appendChild(headerRow);
const tbody = document.createElement('tbody');
tbody.id = 'redacted-youtube-track-list';
tbody.style = localStorage.getItem('redacted-youtube-player-visibility') === 'hidden' ? 'display: none' : '';
table.appendChild(thead);
table.appendChild(tbody);
document.querySelector('div.box.torrent_description').insertAdjacentElement('beforebegin', table);
trackLinks.forEach(track => {
document.querySelector('table#redacted-youtube-tracks-table > tbody').appendChild(track.element);
});
}
}
};
})();