FTP Index to M3U8 Playlist Converter

Convert HTTP index directory to M3U8 playlist

// ==UserScript==
// @name         FTP Index to M3U8 Playlist Converter
// @namespace    http://tampermonkey.net/
// @version      2.6.4
// @description  Convert HTTP index directory to M3U8 playlist 
// @author       Beluga
// @license MIT
// @match        http*://*.circleftp.net/*
// @match        http*://172.16.50.4/*
// @match        http*://172.16.50.7/*
// @match        http*://172.16.50.9/*
// @match        http*://172.16.50.12/*
// @match        http*://172.16.50.14/*
// @match        http*://*.ftpbd.net/*
// @match        http*://10.16.100.244/*
// @match        http*://freedrivemovie.com/*
// @match        http*://movies.discoveryftp.net/*
// @match        http*://172.19.178.62:48781/*
// @match        http*://cdn.dflix.live:5050/*
// @match        http*://fs.ebox.live/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const videoFormats = ['mp4', '3gp', 'mkv', 'wav', 'wmv', 'avi', 'flv', 'mov', 'ts'];

    function cleanFileName(fileName) {
        return fileName.replace(/S(\d{1,2})E\d{1,3}/i, 'S$1').trim();
    }

    function getPlaylistName(links) {
        if (links.length === 0) return "Playlist";
        let firstFileName = decodeURIComponent(links[0].split('/').pop());
        firstFileName = cleanFileName(firstFileName);
        return firstFileName.replace(/\.\w+$/, '') + ".m3u8";
    }

    function createM3U8Content(links) {
        let content = "#EXTM3U\n";
        links.forEach(link => {
            let fileName = decodeURIComponent(link.split('/').pop()).replace(/\s+/g, '.');
            content += `#EXTINF:-1,${fileName}\n${link}\n`;
        });
        return content;
    }

    function downloadM3U8(content, filename) {
        const userFilename = prompt("Saving the playlist as:", filename);
        if (!userFilename) return;

        const blob = new Blob([content], { type: 'application/x-mpegURL' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = userFilename.endsWith('.m3u8') ? userFilename : userFilename + ".m3u8";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }

    function gatherVideoLinks() {
        const links = [];
        document.querySelectorAll('a').forEach(anchor => {
            try {
                const url = new URL(anchor.href, document.baseURI);
                const ext = url.pathname.split('.').pop().toLowerCase();
                if (videoFormats.includes(ext)) {
                    links.push(url.href);
                }
            } catch (error) {
                console.warn(`Skipping invalid URL: ${anchor.href}`);
            }
        });
        return links.sort();
    }

    function createDownloadButton() {
        let existingButton = document.getElementById("playlistDownloadBtn");
        if (existingButton) return existingButton; // Prevent duplicate buttons

        const button = document.createElement('button');
        button.id = "playlistDownloadBtn";
        button.textContent = "Download Playlist";
        button.style.cssText = `
            position: fixed;
            top: 10px;
            right: 10px;
            padding: 8px 15px;
            font-size: 14px;
            font-weight: bold;
            color: white;
            background: linear-gradient(135deg, #ff6a00, #ee0979);
            border: none;
            cursor: pointer;
            text-align: center;
            border-radius: 6px;
            box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2);
            transition: all 0.2s ease-in-out;
            z-index: 1000;
        `;
        button.addEventListener('mouseover', () => button.style.background = 'linear-gradient(135deg, #ff4500, #d70270)');
        button.addEventListener('mouseout', () => button.style.background = 'linear-gradient(135deg, #ff6a00, #ee0979)');
        document.body.appendChild(button);
        return button;
    }

    function generatePlaylist() {
        const links = gatherVideoLinks();
        if (links.length === 0) {
            alert('No video files found in this directory.');
            return;
        }

        console.log(`Found ${links.length} video links.`);
        const button = document.getElementById("playlistDownloadBtn");
        if (button) {
            button.textContent = "Generating...";
            button.disabled = true;
            button.style.opacity = "0.6";
        }

        setTimeout(() => {
            const filename = getPlaylistName(links);
            const content = createM3U8Content(links);
            downloadM3U8(content, filename);
            if (button) {
                button.textContent = "Download Playlist";
                button.disabled = false;
                button.style.opacity = "1";
            }
        }, 1000);
    }

    function addDownloadFunctionality() {
        let downloadButton = createDownloadButton();
        if (!downloadButton) return;

        downloadButton.addEventListener('click', (event) => {
            event.preventDefault();
            event.stopPropagation();
            generatePlaylist();
        });

        document.addEventListener('keydown', (event) => {
            if (event.shiftKey && event.altKey && event.code === 'KeyD') {
                console.log("Shortcut Shift+Alt+D triggered");
                generatePlaylist();
            }
        });
    }

    window.addEventListener('load', addDownloadFunctionality);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址