Bs ToastPopup

Popup for toast

이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.sleazyfork.org/scripts/578336/1841909/Bs%20ToastPopup.js을(를) 사용하여 포함하는 라이브러리입니다.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        Bsodergren Library
// @version     1.7.0
// @grant       GM_xmlhttpRequest
// @grant       nsafeWindow
// @license     MIT
// @namespace   https://greasyfork.org/users/984905
// ==/UserScript==

function showToast(message, duration = 3000, cmdElement = null) {
  // Create toast container if it doesn't exist
  let container = document.getElementById('tm-toast-container');
  if (!container) {
    container = document.createElement('div');
    container.id = 'tm-toast-container';
    container.style.position = 'fixed';
    container.style.top = '20px';
    container.style.left = '20px';
    container.style.zIndex = '999999';
    container.style.display = 'flex';
    container.style.flexDirection = 'column';
    container.style.gap = '10px';
    document.body.appendChild(container);
  }

  // Create toast element
  const toast = document.createElement('div');
  toast.textContent = message;
  toast.style.background = 'rgb(0, 0, 0)';
  toast.style.color = '#fff';
  toast.style.padding = '10px 16px';
  toast.style.borderRadius = '6px';
  toast.style.borderColor = 'white';
  toast.style.borderWidth = '3px';
  toast.style.borderStyle = 'double';
  toast.style.fontSize = '18px';
  toast.style.boxShadow = '0 2px 8px rgba(0,0,0,0.3)';
  toast.style.opacity = '0.5';
  toast.style.transition = 'opacity 0.3s ease';

  container.appendChild(toast);

  // Fade in
  requestAnimationFrame(() => {
    toast.style.opacity = '1';
  });

  // Remove after duration
  setTimeout(() => {
    toast.style.opacity = '0';
    toast.addEventListener('transitionend', () => {
      toast.remove();
      if (cmdElement !== null) {
        cmdElement();
      }
    });
  }, duration);
}

function waitForElement(selector, callback) {
  const observer = new MutationObserver(() => {
    const element = document.querySelector(selector);
    if (element) {
      observer.disconnect(); // Stop observing
      callback(element);
    }
  });

  // Observe changes in the entire document
  observer.observe(document.body, {
    childList: true,
    subtree: true,
  });
}

function jsonToUrlEncoded(jsonObj) {
  if (typeof jsonObj !== 'object' || jsonObj === null) {
    throw new Error('Input must be a non-null object');
  }
  return Object.keys(jsonObj)
    .map(
      key => encodeURIComponent(key) + '=' + encodeURIComponent(jsonObj[key])
    )
    .join('&');
}

function saveToLocalServer(postUrl, data, toast, command = null) {
  postUrl = 'http://media.lan/plex/' + postUrl;
  const encoded = jsonToUrlEncoded(data);

  GM_xmlhttpRequest({
    method: 'POST',
    url: postUrl,
    data: encoded,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    responseType: 'document',
    onload: function (response) {
      var responseXML = response.responseXML;
      if (!responseXML) {
        try {
          responseXML = new DOMParser().parseFromString(
            response.responseText,
            'text/html'
          );
        } catch (err) { }
      }
      showToast(response.responseText, 3000, command);
    },
  });
}