Get m3u8 URL

获取网页中m3u8视频地址

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name      Get m3u8 URL
// @name:en      Get m3u8 URL
// @namespace   Violentmonkey Scripts
// @match        https://missav.com/*
// @grant       none
// @icon  https://i.imgur.com/ufHwbFY.jpeg
// @description  获取网页中m3u8视频地址
// @description:en  获取网页中m3u8视频地址
// @version     1.2
// @license      MIT
// @run-at      document-end
// ==/UserScript==

const purgeSpecialCharacters = (str) => str.replace(/[<>:"/|?*\x00-\x1F]/g, '')
const isM3u8Url = (url) => /\.m3u8$/.test(url.split('?')[0])

localStorage.setItem('m3u8Url', '')
localStorage.setItem('title', '')

const findTitleAndM3u8 = (m3u8Box, titleBox) => {
  let title = purgeSpecialCharacters(document.title)
  titleBox.innerText = title
  if (title === localStorage.getItem('title')) {
    m3u8Box.innerText = localStorage.getItem('m3u8Url')
    return
  }
  console.log('找到标题:', title)
  localStorage.setItem('title', title)

  const resources = window.performance.getEntries()
  for (const resource of resources) {
    const m3u8Url = resource.name
    if (isM3u8Url(m3u8Url)) {
      m3u8Box.innerText = m3u8Url
      console.log('找到m3u8:', m3u8Url)
      localStorage.setItem('m3u8Url', m3u8Url)
      return
    }
  }
  m3u8Box.innerText = '未找到m3u8地址'
  console.log('未找到m3u8地址')
}

const copyToClipboard = (text) => {
  navigator.clipboard
    .writeText(text)
    .then(() => console.log('复制成功:', text))
    .catch((err) => console.error('复制失败:', err))
}

const createDynamicElement = (type, text, styles, onClick, onDblClick) => {
  const element = document.createElement(type)
  Object.assign(element.style, styles)
  element.innerText = text
  if (onClick) element.addEventListener('click', onClick)
  if (onDblClick) element.addEventListener('dblclick', onDblClick)
  return element
}

const getContainer = () => {
  let isVisible = true
  let isDragging = false
  let offsetX, offsetY

  const mainContainer = createDynamicElement('div', '', {
    position: 'fixed',
    top: '50%',
    left: '50%',
    transform: 'translate(-50%, -50%)',
    borderRadius: '10px',
    backgroundColor: '#C4B6D7',
    border: '2px solid black',
    zIndex: '9999',
    padding: '10px',
    display: 'flex',
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    boxShadow: '0 4px 8px rgba(0,0,0,0.1)',
    resize: 'both',
    overflow: 'auto',
    minWidth: '300px',
    minHeight: '200px',
  })

  const m3u8UrlBox = createDynamicElement(
    'div',
    '',
    {
      width: 'calc(100% - 20px)',
      margin: '5px 0',
      padding: '8px',
      border: '1px solid #ccc',
      borderRadius: '5px',
      backgroundColor: 'white',
      wordBreak: 'break-all',
      cursor: 'pointer',
    },
    () => copyToClipboard(m3u8UrlBox.innerText),
  )

  const titleBox = createDynamicElement(
    'div',
    '',
    {
      width: 'calc(100% - 20px)',
      margin: '5px 0',
      padding: '8px',
      border: '1px solid #ccc',
      borderRadius: '5px',
      backgroundColor: 'white',
      wordBreak: 'break-all',
      cursor: 'pointer',
    },
    () => copyToClipboard(titleBox.innerText),
  )

  const toggleButton = createDynamicElement(
    'button',
    '',
    {
      position: 'absolute',
      top: '5px',
      left: '5px',
      width: '20px',
      height: '20px',
      border: 'none',
      background: 'transparent',
      cursor: 'pointer',
    },
    () => {
      isVisible = !isVisible
      mainContainer.style.display = isVisible ? 'flex' : 'none'
    },
  )

  const refreshButton = createDynamicElement(
    'button',
    '',
    {
      position: 'absolute',
      top: '5px',
      left: '30px',
      width: '20px',
      height: '20px',
      border: 'none',
      background: 'transparent',
      cursor: 'pointer',
    },
    () => findTitleAndM3u8(m3u8UrlBox, titleBox),
  )

  toggleButton.innerHTML =
    '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 7v4"/><path d="M7.998 9.003a5 5 0 1 0 8-.005"/><circle cx="12" cy="12" r="10"/></svg>'
  refreshButton.innerHTML =
    '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg>'

  mainContainer.addEventListener('mousedown', (e) => {
    isDragging = true
    offsetX = e.clientX - mainContainer.offsetLeft
    offsetY = e.clientY - mainContainer.offsetTop
  })

  document.addEventListener('mousemove', (e) => {
    if (isDragging) {
      mainContainer.style.left = e.clientX - offsetX + 'px'
      mainContainer.style.top = e.clientY - offsetY + 'px'
    }
  })

  document.addEventListener('mouseup', () => {
    isDragging = false
  })

  mainContainer.style.paddingTop = '30px'
  mainContainer.appendChild(toggleButton)
  mainContainer.appendChild(refreshButton)
  mainContainer.appendChild(m3u8UrlBox)
  mainContainer.appendChild(titleBox)
  return mainContainer
}

const main = () => {
  const mainButton = createDynamicElement(
    'button',
    '',
    {
      position: 'fixed',
      width: '50px',
      height: '50px',
      borderRadius: '25px',
      backgroundColor: '#C4B6D7',
      top: '50%',
      right: '0',
      transform: 'translate(-50%, -50%)',
      zIndex: '9999',
      border: 'none',
      boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
      cursor: 'pointer',
    },
    () => {},
    showBox,
  )

  mainButton.innerHTML =
    '<div style="margin-inline: 12px"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z"/><path d="m9 12 2 2 4-4"/></svg></div>'

  document.body.appendChild(mainButton)
}

const showBox = () => {
  const container = getContainer()
  const m3u8UrlBox = container.querySelectorAll('div')[0]
  const titleBox = container.querySelectorAll('div')[1]
  findTitleAndM3u8(m3u8UrlBox, titleBox)
  document.body.appendChild(container)
}

main()