Get m3u8 URL

获取网页中m3u8视频地址

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==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()