<!DOCTYPE html>
<html>
<head>
  <title>p115dav</title>
  <link rel="shortcut icon" href="/<pic/images/favicon.svg" type="image/x-icon">
  <link href="https://cdnres.115.com/site/static/style_v10.0/file/css/file_type.css?_vh=bf604a2_70" rel="stylesheet" type="text/css">
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    a:hover {
      color: red;
    }

    .file-type {
      flex: 1;
      min-width: 0;
      position: relative;
      height: 32px;
      padding-left: 47px;
      flex-direction: column;
      justify-content: center;
    }

    td {
      vertical-align: middle;
    }

    img {
      height: 32px;
      width: 32px; 
    }

    table {
      border-collapse: collapse;
      margin: 25px 0;
      font-size: 0.9em;
      font-family: sans-serif;
      min-width: 800px;
      box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
    }

    thead tr {
      font-family: Lato-Bold;
      font-size: 18px;
      color: #3636f0;
      line-height: 1.4;
      background-color: #f0f0f0;
      position: sticky;
      top: 0;
      z-index: 100;
    }

    th, td:not(:first-child) {
      padding: 12px 15px;
    }

    tbody tr {
      border-bottom: 1px solid #dddddd;
      background-color: #fff;
      transition: background-color 0.3s, transform 0.3s;
    }

    tbody tr:last-of-type {
      border-bottom: 2px solid #009879;
    }

    tbody tr:hover {
      color: #009879;
      font-weight: bold;
      background-color: rgba(230, 230, 230, 0.5);
      transform: scale(1.02);
    }

    .icon {
      border-radius: 10px;
      display: inline-block;
      padding: 8px;
      transition: background-color 0.5s;
    }
    .icon:hover {
        background-color: #d2d2d2;
    }

    .popup {
      position: relative;
      display: inline-block;
      cursor: pointer;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
      user-select: none;
    }
  
    .popup .popuptext {
      visibility: hidden;
      width: 160px;
      background-color: #555;
      color: #fff;
      text-align: center;
      border-radius: 6px;
      padding: 8px 0;
      position: absolute;
      z-index: 1;
      bottom: 125%;
      left: 50%;
      margin-left: -80px;
    }
  
    .popup .popuptext::after {
      content: "";
      position: absolute;
      top: 100%;
      left: 50%;
      margin-left: -5px;
      border-width: 5px;
      border-style: solid;
      border-color: #555 transparent transparent transparent;
    }
  
    .popup:hover .popuptext {
      visibility: visible;
      -webkit-animation: fadeIn 1s;
      animation: fadeIn 1s;
    }
  
    @-webkit-keyframes fadeIn {
      from {opacity: 0;} 
      to {opacity: 1;}
    }
  
    @keyframes fadeIn {
      from {opacity: 0;}
      to {opacity:1 ;}
    }

    .draggable-resizable-window {
      width: 900px;
      height: 520px;
      position: absolute;
      overflow: hidden;
      resize: both;
      cursor: move;
      display: none;
      z-index: 999;
    }

    .player-container {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: pointer;
      position: absolute;
    }

    .art-icon > svg {
      padding: 0px;
    }
  </style>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/particles.js/2.0.0/particles.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/progressbar.js/1.1.1/progressbar.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/fancybox/fancybox.umd.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/fancybox/fancybox.css" rel="stylesheet"/>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/carousel/carousel.umd.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/carousel/carousel.css" rel="stylesheet"/>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/carousel/carousel.thumbs.umd.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.36/dist/carousel/carousel.thumbs.css" rel="stylesheet"/>
  <script src="https://cdn.jsdelivr.net/npm/artplayer@5.2.2/dist/artplayer.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@1.5.20/dist/hls.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/plyr@3.7.8/dist/plyr.min.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/plyr@3.7.8/dist/plyr.min.css" rel="stylesheet"/>
  {%- if load_libass %}
  <script src="https://artplayer.org/uncompiled/artplayer-plugin-libass/index.js"></script>
  {%- endif %}
</head>
<body>
  <div class="draggable-resizable-window">
    <div class="player-container"></div>
  </div>
  {%- block content %}{% endblock %}
  <script>
document.addEventListener('DOMContentLoaded', function () {
  let player;
  const draggableWindow = document.querySelector(".draggable-resizable-window");
  var playerContainer = draggableWindow.querySelector('.player-container');
  let isDragging = false;
  let initialOffsetX, initialOffsetY, startX, startY;

  playerContainer.addEventListener("mousedown", (e) => {
    isDragging = true;
    initialOffsetX = draggableWindow.offsetLeft;
    initialOffsetY = draggableWindow.offsetTop;
    startX = e.clientX;
    startY = e.clientY;
  });

  playerContainer.addEventListener("mousemove", (e) => {
    if (!isDragging) return;
    const dx = e.clientX - startX;
    const dy = e.clientY - startY;
    const newOffsetX = initialOffsetX + dx;
    const newOffsetY = initialOffsetY + dy;
    const maxWidth = window.pageXOffset + window.innerWidth - draggableWindow.offsetWidth;
    const maxHeight = window.pageYOffset + window.innerHeight - draggableWindow.offsetHeight;
    const newLeft = Math.min(Math.max(newOffsetX, window.pageXOffset), maxWidth);
    const newTop = Math.min(Math.max(newOffsetY, window.pageYOffset), maxHeight);
    draggableWindow.style.left = `${newLeft}px`;
    draggableWindow.style.top = `${newTop}px`;
  });

  playerContainer.addEventListener("mouseup", () => {
    isDragging = false;
  });

  const closeButton = document.createElement("img");
  closeButton.id = "artplayer-close";
  closeButton.src = "/<pic/images/close.svg";
  closeButton.style = "transition: opacity 0.5s ease"

  document.addEventListener('keydown', function(event) {
    if (!player) return;
    if (event.key === 'Escape' && player) {
        if (player instanceof Artplayer && !player.fullscreen)
          player.destroy();
        else if (player instanceof Plyr && !player.fullscreen.active) {
          player.destroy();
          draggableWindow.style.display = 'none';
          player = null;
        }
    }
  });

  document.querySelectorAll('.play-with-artplayer').forEach(function(anchor) {
    const attr = JSON.parse(anchor.parentElement.dataset.attr);
    let multiQualities, subtitles, subtitle;
    anchor.addEventListener('click', async (event) => {
      event.preventDefault();
      if (player) player.destroy();
      draggableWindow.style.display = 'block';
      const scrollX = window.scrollX;
      const scrollY = window.scrollY;
      const windowWidth = window.innerWidth;
      const windowHeight = window.innerHeight;
      const modalWidth = draggableWindow.offsetWidth;
      const modalHeight = draggableWindow.offsetHeight;
      const left = scrollX + (windowWidth - modalWidth) / 2;
      const top = scrollY + (windowHeight - modalHeight) / 2;
      draggableWindow.style.left = left + 'px';
      draggableWindow.style.top = top + 'px';

      if (!multiQualities) {
        multiQualities = [{
          default: true, 
          html: "源文件", 
          url: anchor.href, 
        }];
        const pickcode = attr.pickcode;
        if (pickcode)
          try {
            const resp = await fetch(`/<m3u8?pickcode=${pickcode}`);
            const json = await resp.json();
            if (json instanceof Array && json.length)
              multiQualities.push(...json.map(({title, url})=>({html: title, url, type: "m3u8"})));
          } catch (e) {
            console.error(`can't get multi qualities for ${attr.name}: ${e.message}`);
          }
      }
      if (!subtitles) {
        subtitles = [];
        try {
          const sharecode = attr.share_code;
          const prefix = attr.name.slice(0, attr.name.lastIndexOf("."));
          if (sharecode) {
            const resp = await fetch(`/<share/<list?id=${attr.parent_id}&share_code=${sharecode}`);
            const filelist = await resp.json();
            for (const {name, url} of filelist.children) {
              if (/(?i:.ass|.srt|.ssa|.vtt)$/.test(name) && name.startsWith(prefix)) {
                const type = name.slice(name.lastIndexOf(".") + 1);
                subtitles.push({
                  html: name.slice(prefix.length + 1), 
                  {%- if load_libass %}
                  url: type === "srt" ? `/<sub2ass/a.ass?url=${encodeURIComponent(url)}` : url, 
                  type: type === "srt" ? "ass" : type, 
                  {%- else %}
                  url, 
                  type, 
                  {%- endif %}
                  escape: false, 
                });
              }
              if (!subtitle) subtitle = subtitles.at(-1);
            }
          } else {
            const resp = await fetch(`/<subtitles?pickcode=${attr.pickcode}`);
            const json = await resp.json();
            if (json instanceof Object && json.list.length) {
              for (const {title, url, type, sha1} of json.list) {
                if (!sha1)
                  subtitles.push({
                    html: `${title} ${type}`, 
                    {%- if load_libass %}
                    url: type === "srt" ? `/<sub2ass/a.ass?url=${encodeURIComponent(url)}` : url, 
                    type: type === "srt" ? "ass" : type, 
                    {%- else %}
                    url, 
                    type, 
                    {%- endif %}
                    escape: false, 
                  });
                else if (title.startsWith(prefix)) {
                  subtitles.push({
                    html: title.slice(prefix.length + 1), 
                    {%- if load_libass %}
                    url: type === "srt" ? `/<srt2ass/a.ass?url=${encodeURIComponent(url)}` : `/<redirect/a.${type}?url=${encodeURIComponent(url)}`, 
                    type: type === "srt" ? "ass" : type, 
                    {%- else %}
                    url, 
                    type, 
                    {%- endif %}
                    escape: false, 
                  });
                  if (!subtitle) subtitle = subtitles.at(-1);
                }
              }
            }
          }
          if (!subtitle) subtitle = subtitles[0];
        } catch (e) {
          console.error(`can't get multi subtitles for ${attr.name}: ${e.message}`);
        }
      }
      if (!subtitle) subtitle = {};
      player = new Artplayer({
        container: playerContainer, 
        url: anchor.href, 
        airplay: true, 
        aspectRatio: true, 
        autoMini: true, 
        autoOrientation: true, 
        autoplay: true, 
        fastForward: true, 
        flip: true, 
        fullscreen: true, 
        fullscreenWeb: true, 
        lock: true, 
        miniProgressBar: true, 
        muted: false, 
        pip: true, 
        playbackRate: true, 
        screenshot: true, 
        subtitle, 
        subtitleOffset: true, 
        setting: true, 
        settings: [{
          html: "画质", 
          selector: multiQualities, 
          onSelect: function (item, $dom, event) {
            player.switchQuality(item.url);
            player.type = item.type;
            player.notice.show = `切换画质: ${item.html}`;
            return item.html;
          }, 
        }, {
          html: "字幕", 
          icon: '<img width="22" heigth="22" src="/<pic/images/subtitle.svg">',
          selector: [
            {
              html: 'Display',
              tooltip: 'Show',
              switch: true,
              onSwitch: function (item) {
                item.tooltip = item.switch ? 'Hide' : 'Show';
                player.subtitle.show = !item.switch;
                return !item.switch;
              },
            }, 
            ...subtitles,
          ],
          onSelect: function (item) {
            {%- if load_libass %}
            player.plugins.artplayerPluginLibass.switch(item.url);
            {%- else %}
            player.subtitle.init({
              ...player.subtitle.option, 
              style: {}, 
              ...item, 
            });
            {%- endif %}
            return item.html;
          },
        }],
        customType: {
          m3u8: (video, url, art) => {
            if (Hls.isSupported()) {
              if (art.hls) art.hls.destroy();
              const hls = new Hls();
              hls.loadSource(url);
              hls.attachMedia(video);
              art.hls = hls;
              art.on('destroy', () => hls.destroy());
            } else if (video.canPlayType('application/vnd.apple.mpegurl'))
              video.src = url;
            else
              art.notice.show = 'Unsupported playback format: m3u8';
          }, 
        }, 
        layers: [{
            name: 'potser',
            html: closeButton,
            tooltip: 'close',
            style: {
                position: 'absolute', 
                width: '30px', 
                top: '0px', 
                right: '0px', 
            },
            click: function (...args) {
                player.destroy();
                draggableWindow.style.display = 'none';
            },
          },
        ], 
        moreVideoAttr: {
          [window.location.hostname == "localhost" ? "crossOrigin" : ""]: "anonymous", 
          preload: 'none', 
          playsinline: true, 
        }, 
        plugins: [
          {%- if load_libass %}
          artplayerPluginLibass({
            debug: false, 
            wasmUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.wasm', 
            fallbackFont: 'https://artplayer.org/assets/misc/SourceHanSansCN-Bold.woff2', 
          }),
          {%- endif %}
        ],
      });
      window.player = player;
      playerContainer.addEventListener('mouseenter', () => {
        closeButton.style.opacity = 1;
      });
      playerContainer.addEventListener('mouseleave', () => {
        closeButton.style.opacity = 0;
      });
      let hideTimeout;
      playerContainer.addEventListener('mousemove', () => {
        if (!player) return;
        if (player.fullscreen)
          closeButton.style.display = "block";
        clearTimeout(hideTimeout);
        hideTimeout = setTimeout(() => {
          if (player && player.fullscreen)
            closeButton.style.display = "none";
        }, 1000);
      });
      player.on('fullscreen', (isFullScreen) => {
        if (isFullScreen)
          closeButton.style.display = "none";
        else
          closeButton.style.display = "block";
      });
      player.on('destroy', () => {
        clearTimeout(hideTimeout);
        player.pause();
        player.off();
        if (player.hls) 
            player.hls.destroy();
        if (player.flv)
            player.flv.destroy();
        if (player.dash)
            player.dash.destroy();
        if (player.torrent)
            player.torrent.destroy();
        player = null;
      });
    });
  });
  document.querySelectorAll('.play-with-plyr').forEach(function(anchor) {
    const attr = JSON.parse(anchor.parentElement.dataset.attr);
    anchor.addEventListener('click', function (event) {
      event.preventDefault();
      if (player) player.destroy();
      draggableWindow.style.display = 'block';
      const scrollX = window.scrollX;
      const scrollY = window.scrollY;
      const windowWidth = window.innerWidth;
      const windowHeight = window.innerHeight;
      const modalWidth = draggableWindow.offsetWidth;
      const modalHeight = draggableWindow.offsetHeight;
      const left = scrollX + (windowWidth - modalWidth) / 2;
      const top = scrollY + (windowHeight - modalHeight) / 2;
      draggableWindow.style.left = left + 'px';
      draggableWindow.style.top = top + 'px';
      const type = attr.type == 3 ? "audio" : "video"
      playerContainer.innerHTML = `
      <${type} id="player" controls crossorigin playsinline>
        <source src="${anchor.href}" />
      </${type}>`
      player = new Plyr("#player", {autoplay: true});
    });
  });
});

window.addEventListener("load", function () {
  // startup for particles.js
  // color picker tool: https://www.w3cschool.cn/tools/index?name=cpicker
  const particlesColorDark = ["#1a0000", "#1a1100", "#191a00", "#001a00", "#00001a", "#0f001a", "#160316", "#0d0d0d"];
  const particlesColorLight = ["#ffe5e5", "#fff6e5", "#ffffe5", "#e5ffe5", "#e5e5ff", "#f4e5ff", "#fce9fc", "#f2f2f2"];
  let startThemeColor = document.body.dataset["theme"];
  const particlesConfig = {
    particles: {
      number: {
        value: 80,
        density: {
          enable: true,
          value_area: 800
        }
      },
      color: {
        value: startThemeColor == "dark" ? particlesColorDark : particlesColorLight,
      },
      shape: {
        type: ["circle"],
        stroke: {
          width: 0,
          color: "#fff"
        },
        polygon: {
          nb_sides: 5
        }
      },
      opacity: {
        value: 1,
        random: false,
        anim: {
          enable: false,
          speed: 1,
          opacity_min: 0.1,
          sync: false
        }
      },
      size: {
        value: 8,
        random: true,
        anim: {
          enable: false,
          speed: 10,
          size_min: 10,
          sync: false
        }
      },
      line_linked: {
        enable: true,
        distance: 150,
        color: "#808080",
        opacity: 0.4,
        width: 1
      },
      move: {
        enable: true,
        speed: 5,
        direction: "none",
        random: false,
        straight: false,
        out_mode: "out",
        bounce: false,
        attract: {
          enable: false,
          rotateX: 600,
          rotateY: 1200
        }
      }
    },
    interactivity: {
      detect_on: "canvas",
      events: {
        onhover: {
          enable: true,
          mode: "grab"
        },
        onclick: {
          enable: true,
          mode: "push"
        },
        resize: true
      },
      modes: {
        grab: {
          distance: 140,
          line_linked: {
            opacity: 1
          }
        },
        bubble: {
          distance: 400,
          size: 40,
          duration: 2,
          opacity: 8,
          speed: 3
        },
        repulse: {
          distance: 200,
          duration: 0.4
        },
        push: {
          particles_nb: 4
        },
        remove: {
          particles_nb: 2
        }
      }
    },
    retina_detect: true
  };

  if (startThemeColor != null) {
    // Select the node that will be observed for mutations
    const targetNode = document.body;
    // Options for the observer (which mutations to observe)
    const config = { attributes: true, attributeFilter: ["data-theme"] };
    // Callback function to execute when mutations are observed
    const callback = (mutationList, observer) => {
      for (const mutation of mutationList) {
        if (mutation.type === "attributes") {
          const themeColor = targetNode.dataset["theme"];
          particlesConfig.particles.color.value = themeColor == "dark" ? particlesColorDark : particlesColorLight;
          particlesJS("particles-js", particlesConfig);
        }
      }
    }
    // Create an observer instance linked to the callback function
    const observer = new MutationObserver(callback);
    // Start observing the target node for configured mutations
    observer.observe(targetNode, config);
  }
  var body = document.body;
  var div = document.createElement("div");
  div.id = "particles-js";
  div.setAttribute("style", "position: fixed; height: 100%; width: 100%; z-index: -99;");
  body.insertBefore(div, body.firstElementChild);
  particlesJS("particles-js", particlesConfig);

  function getScrollPercentage() {
    const scrollTop = window.scrollY || document.documentElement.scrollTop;
    const scrollDistance = document.documentElement.scrollHeight - window.innerHeight;
    return (scrollTop / scrollDistance) * 100;
  }

  function rainbowGradient(progress) {
    var colors = [
      [255, 0, 0],    // red
      [255, 165, 0],  // orange
      [255, 255, 0],  // yellow
      [0, 128, 0],    // green
      [0, 0, 255],    // blue
      [75, 0, 130],   // indigo
      [148, 0, 211]   // violet
    ];

    var totalSegments = colors.length - 1;
    var segmentProgress = 1 / totalSegments;
    var segmentIndex = Math.floor(progress / segmentProgress);
    var segmentProgressWithinSegment = (progress - segmentIndex * segmentProgress) / segmentProgress;

    var startColor = colors[segmentIndex];
    var endColor = colors[segmentIndex + 1];

    var r = Math.round(startColor[0] + (endColor[0] - startColor[0]) * segmentProgressWithinSegment);
    var g = Math.round(startColor[1] + (endColor[1] - startColor[1]) * segmentProgressWithinSegment);
    var b = Math.round(startColor[2] + (endColor[2] - startColor[2]) * segmentProgressWithinSegment);

    return 'rgb(' + r + ', ' + g + ', ' + b + ')';
  }

  // progressbar at right-bottom
  var body = document.body;
  var div = document.createElement("div");
  div.id = "progress-container";
  div.setAttribute('style', 'position: fixed; bottom: 10px; right: 10px; width: 4em; height: 4em; z-index: 999; cursor: pointer;');
  body.insertBefore(div, body.firstElementChild);

  var progress = new ProgressBar.Circle("#progress-container", {
    // This has to be the same size as the maximum width to
    // prevent clipping
    strokeWidth: 2,
    trailWidth: 1,
    easing: 'easeInOut',
    duration: 1400,
    text: {
      autoStyleContainer: false,
    },
    from: { color: '#FFFF99', width: 1 },
    to: { color: '#00FF33', width: 4 },
    // Set default step function for all animate calls
    step: function (state, circle) {
      circle.path.setAttribute('stroke', rainbowGradient(circle.value()));
      circle.path.setAttribute('stroke-width', 1 + circle.value() * 3);
      circle.setText(circle.value() * 100);
    }
  });
  progress.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
  progress.text.style.fontSize = '1rem';

  function getScrollPercentage() {
    const scrollTop = window.scrollY || document.documentElement.scrollTop;
    const scrollDistance = document.documentElement.scrollHeight - window.innerHeight;
    return (scrollTop / scrollDistance) * 100;
  }

  function updateScroll() {
    const scrollPercentage = getScrollPercentage();
    if (isNaN(scrollPercentage) || scrollPercentage < 0.1 || scrollPercentage >= 100) {
      progress.svg.parentNode.style.display = "none";
    } else {
      progress.svg.parentNode.style.display = "block";
      progress.set(scrollPercentage / 100);
      progress.setText(scrollPercentage.toFixed(1) + '%');
    }
  }

  window.addEventListener('scroll', updateScroll);

  document.getElementById('progress-container').addEventListener('click', function () {
    window.scrollTo({
      top: document.documentElement.scrollHeight,
      behavior: 'smooth'
    });
  });

  updateScroll();

  Fancybox.bind('[data-fancybox="gallery"]', {
    Toolbar: {
      display: {
        left: ["rotateCCW","rotateCW", "flipX", "flipY", "toggle1to1", "reset"], 
        middle: ["infobar"], 
        right: ["fullscreen", "thumbs", "slideshow", "download", "close"], 
      },
    }
  });
});
  </script>
</body>
</html>