Get m3u8 URL

获取网页中m3u8视频地址

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

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