youtube-playlist-randomizer improvements

Improve your youtube-playlist-randomizer experience with these cosmetic changes.

// ==UserScript==
// @name         youtube-playlist-randomizer improvements
// @namespace    https://r5ne.carrd.co/
// @version      1.1
// @include      https://youtube-playlist-randomizer.bitbucket.io*
// @include      https://ytplr.bitbucket.io*
// @description  Improve your youtube-playlist-randomizer experience with these cosmetic changes.
// @author       r5ne
// @grant        none
// @license      GPL-3.0-only
// ==/UserScript==


;(function() {
  const html = document.documentElement;
  const body = document.body;
  const CENTER_CSS = `
    html, body {
      margin: 0; padding: 0; height: 100%; width: 100%;
      display: flex; flex-direction: column;
      align-items: center; text-align: center;
    }
    body { margin: 0; }
    body > div { max-width: 100%; width: auto; }
    iframe {
      display: block; margin: 1em 0;
      flex: 0 0 auto; /* respect its own width/height */
    }
  `;
  const centerStyle = document.createElement('style');
  centerStyle.textContent = CENTER_CSS;
  document.head.appendChild(centerStyle);
  const contentOverlayCSS = document.createElement('style');
  contentOverlayCSS.textContent = `
    /* Box all top‑level DIVs except the placeholder */
    body > div:not(#video-placeholder) {
      background: rgba(0,0,0,0.35);
      padding: 1rem;
      border-radius: 0.5rem;
      max-width: 90vw;
      box-sizing: border-box;
    }
  `;
  document.head.appendChild(contentOverlayCSS);

  const dynamicStyle = document.createElement('style');
  dynamicStyle.id = 'dynamic-theme';
  document.head.appendChild(dynamicStyle);

  const LUMINANCE_THRESHOLD  = `120`;  // Increase to have the dark theme (e.g. white font) used for lighter images.
  const DARK_TEXT_COLOR      = '#000';
  const LIGHT_TEXT_COLOR     = '#fff';
  const DARK_LINK_COLOR      = '#0066cc';
  const DARK_LINK_VISITED    = '#551A8B';
  const LIGHT_LINK_COLOR     = '#66CCFF';
  const LIGHT_LINK_VISITED   = '#AA99FF';
  const HEAVY_TEXT_SHADOW    = `
    1px 1px 2px rgba(0,0,0,0.8),
    -1px -1px 2px rgba(0,0,0,0.8),
    1px -1px 2px rgba(0,0,0,0.8),
    -1px 1px 2px rgba(0,0,0,0.8)
  `;
  const UNSPLASH_ACCESS_KEY = 'bla bla bla ble ble ble blu blu blu';  // Replace with your own unsplash access key. See userscript description for more info.
  const queries = ["landscape", "abandoned", "cosmos", "waterfall", "mountain", "desert landscape", "stars", "sky", "day", "night", "night sky", "nature"];  // Replace with whatever themes you want your images to be.

  const sampleCanvas = document.createElement('canvas');
  sampleCanvas.width = sampleCanvas.height = 10;
  const sampleCtx = sampleCanvas.getContext('2d');

  function pickTextColorFromImage(url) {
    return new Promise(resolve => {
      const img = new Image();
      img.crossOrigin = 'anonymous';
      img.onload = () => {
        sampleCtx.drawImage(img, 0, 0, 10, 10);
        const data = sampleCtx.getImageData(0, 0, 10, 10).data;
        let total = 0, count = 0;
        for (let i = 0; i < data.length; i += 4) {
          const [r,g,b] = [data[i], data[i+1], data[i+2]];
          total += 0.2126*r + 0.7152*g + 0.0722*b;
          count++;
        }
        console.log('average Luminance = ', (total/count));
        resolve((total/count) < LUMINANCE_THRESHOLD);
      };
      img.onerror = () => resolve(false);
      img.src = url;
    });
  }

  function showAttribution({ photoHref, authorHref, authorName, homeHref, location, tag, fallback }) {
    let el = document.getElementById('bg-attribution');
    if (!el) {
      el = document.createElement('div');
      el.id = 'bg-attribution';
      Object.assign(el.style, {
        position:       'fixed',
        bottom:         '8px',
        right:          '8px',
        padding:        '4px 8px',
        background:     'rgba(0,0,0,0.25)',
        color:          'white',
        fontSize:       '14px',
        borderRadius:   '4px',
        zIndex:         9999,
        pointerEvents:  'auto',
        lineHeight:     '1.2',
        whiteSpace:     'nowrap',
      });
      document.body.appendChild(el);
    }

    const linkStyles = `
      <style>
        #bg-attribution a {
          color: #fff !important;
          text-decoration: none !important;
        }
        #bg-attribution a:hover {
          text-decoration: underline !important;
        }
      </style>
    `;

    let html = `
      ${linkStyles}
      <div>
        <a href="https://greasyfork.org/en/scripts/537152-youtube-playlist-randomizer-improvements" target="_blank">
          Userscript
        </a>
        by
        <a href="https://r5ne.carrd.co" target="_blank">
          r5ne
        </a>
      </div>
    `;

    if (!fallback) {
      html += `
        <div>
          <a href="${photoHref}"  target="_blank">Photo</a> by
          <a href="${authorHref}" target="_blank">${authorName}</a> on
          <a href="${homeHref}"   target="_blank">Unsplash</a>
        </div>
        <div>
          ${location? `${location}`:''}
        </div>
        <div>
          ${tag? `Query: ${tag}`:''}
        </div>
      `;
    } else {
      html += `
        <div>
          <a href="https://picsum.photos/" target="_blank">
            Image from Lorem Picsum
          </a>
        </div>
      `;
    }

    el.innerHTML = html;
  }

  async function BG_change() {
    const selectedQuery = queries[Math.floor(Math.random() * queries.length)];
    const apiUrl = `https://api.unsplash.com/photos/random?client_id=${UNSPLASH_ACCESS_KEY}&query=${selectedQuery}&orientation=landscape`;
    try {
      const res   = await fetch(apiUrl);
      if (!res.ok) throw new Error(res.status);
      const photo = await res.json();

      const finalUrl = `${photo.urls.raw}&w=2560&h=1440&fit=crop&crop=entropy`;
      const isDark   = await pickTextColorFromImage(finalUrl);

      const linkColor   = isDark ? LIGHT_LINK_COLOR  : DARK_LINK_COLOR;
      const linkVisited = isDark ? LIGHT_LINK_VISITED: DARK_LINK_VISITED;
      const textColor   = isDark ? LIGHT_TEXT_COLOR : DARK_TEXT_COLOR;
      const textShadow  = isDark ? HEAVY_TEXT_SHADOW : 'none';

      dynamicStyle.textContent = `
        html { color: ${textColor}; }
        body { text-shadow: ${textShadow}; }
        a, a:visited { color: ${linkColor} !important; }
        a:visited { color: ${linkVisited} !important; }
      `;

      body.style.backgroundImage    = `url("${finalUrl}")`;
      body.style.backgroundSize     = 'cover';
      body.style.backgroundRepeat   = 'no-repeat';
      body.style.backgroundPosition = 'center';
      html.style.minHeight          = '100vh';
      body.style.minHeight          = '100vh';
      body.style.margin             = '0';

      showAttribution({
        photoHref:  photo.links.html,
        authorHref: photo.user.links.html,
        authorName: photo.user.name,
        homeHref:   'https://unsplash.com',
        location:   photo.location?.name,
        tag:        selectedQuery,
        fallback:   false
      });
    }
    catch (err) {
      console.error('BG_change error:', err);
      body.style.backgroundImage = 'url("https://picsum.photos/1920/1080")';
      showAttribution({
        fallback: true
      });
    }
  }

  window.addEventListener('load', BG_change);
})();