如何在浏览器中将 m3u8 URL 转换为 mp4 可下载文件?

How to convert m3u8 URL to mp4 downloadable file in browser?

我正在编写一个扩展程序以从网站下载视频。该网站有 mp4 个文件和 m3u8 个文件。我已经实现了下载直接 mp4 文件的部分。我坚持将 m3u8 文件转换为 mp4。我尝试了很多 js 包,但是有很多依赖项,甚至在使用 browserfy.

后仍然失败

当前popup.js文件

function loadvideoList(callback){
    chrome.storage.sync.get(['courseID'], function(result) {
        if(result.courseID != 'undefined'){
            $.ajax({
                type: 'GET',
                url: "http://localhost:80/get_videos_list/"+result.courseID,
                crossDomain: true,
                success: function(response) {
                    document.getElementById("loading_icon").style.display='none';
                    document.getElementById("videos_list").style.display='block';
                    document.getElementById("videos_list").style.padding='10px';
                    for(var i = 0; i < response.video_list.length; i++){
                        if(response.video_list[i].type == 'mp4'){
                            handleDownloadButton(response.video_list[i]);
                        }else{
                            // ************ HERE ***************
                            handleDownloadButton-m3u8Tomp4(response.video_list[i].video_url)
                        }
                    }
                },
                error: function (err) {
                    alert("unexpected error occured: "+err.code);
                    console.log(err);
                }
             });
        }else{
            document.getElementById("videos_list").style.display='none';
            document.getElementById("videos_list").style.padding='0';
        }
    });
}

function handleDownloadButton(json_vid){
    var node = document.createElement("DIV"); 
    // node.style.marginBottom = "5px"
    var t = document.createElement('p');
    t.textContent = json_vid.file_name;
    t.style.width ="240px";
    node.appendChild(t);
    node.style.padding = "5px";
    var downloadBtn = document.createElement("BUTTON");
    downloadBtn.style.cssFloat = "right";
    downloadBtn.className = "btn btn-primary btn-sm download_btn";
    downloadBtn.innerHTML = "Download"; 
    // downloadBtn.value = json_vid.video_url;
    node.appendChild(downloadBtn);
    downloadBtn.id = json_vid.video_id;
    document.getElementById("videos_list").appendChild(node);

    var progress_bar = document.createElement("DIV");
    progress_bar.className = "progress_container";
    node.appendChild(progress_bar);
    var moving_bar = document.createElement("DIV");
    moving_bar.className = "progress_bar";
    progress_bar.appendChild(moving_bar);
    moving_bar.id = json_vid.video_id+"bar";

    $(function(){
        $(`#${json_vid.video_id}`).click(function(){
            $(`#${json_vid.video_id}`).attr("disabled", true);
            // alert(json_vid.video_url);
            var that = this;
            var page_url = json_vid.video_url;
        
            var req = new XMLHttpRequest();
            req.open("GET", page_url, true);
            // req.withCredentials = true;
            req.addEventListener("progress", function (evt) {
                if(evt.lengthComputable) {
                    var percentComplete = evt.loaded / evt.total;
                    // document.getElementById("download_stat").innerHTML = percentComplete;
                    // console.log(percentComplete);
                    document.getElementById(json_vid.video_id+"bar").style.width = `${percentComplete*100}%`;
                    document.getElementById(json_vid.video_id).textContent = `${(percentComplete*100).toFixed(2)}%`;
                }
            }, false);
            
            req.responseType = "blob";
            req.onreadystatechange = function () {
                if (req.readyState === 4 && req.status === 200) {
                    var filename = $(that).data('filename');
                    if (typeof window.chrome !== 'undefined') {
                        // Chrome version
                        $(`#${json_vid.video_id}`).attr("disabled", false);
                        $(`#${json_vid.video_id}`).attr("onclick", "").unbind("click");
                        document.getElementById(json_vid.video_id).textContent = 'Save';
                        $(function(){
                            $(`#${json_vid.video_id}`).click(function(){
                                // alert("download is ready");
                                var link = document.createElement('a');
                                // link.text = "download is ready";
                                // document.getElementById("videos_list").appendChild(link);
                                link.href = window.URL.createObjectURL(req.response);
                                link.download = json_vid.file_name;
                                link.click();
                            });
                        });
                        
                    } else if (typeof window.navigator.msSaveBlob !== 'undefined') {
                        // IE version
                        var blob = new Blob([req.response], { type: 'application/force-download' });
                        window.navigator.msSaveBlob(blob, filename);
                    } else {
                        // Firefox version
                        var file = new File([req.response], filename, { type: 'application/force-download' });
                        window.open(URL.createObjectURL(file));
                    }
                }
            };
            req.send();
        });

    });
}

handleDownloadButton 函数创建按钮以直接下载 mp4 文件。我需要实现一个名为 handleDownloadButton-m3u8Tomp4 的类似函数(参见代码示例),它应该首先将 http://...file.m3u8 转换为 mp4 并使其也可下载。我在类似 https://github.com/puemos/hls-downloader-chrome-extension 的回购协议中寻找脚本,但我无法这样做。太好了,如果有人能帮助我,在此先感谢!

您可以尝试使用ffmpeg.wasm to convert the .m3u8 file to a .mp4 file. ffmpeg.wasm is a pure WebAssembly / JavaScript port of FFmpeg. They even have an example repository for a Chrome extension。不过我还没有亲自测试过。

例如,Whosebug 上还有其他问题涉及如何使用 FFmpeg, like 转换 m3u8 文件。