Stream URL grabber

Adds a button that gives you a .m3u8 file for a stream on Twitch or Hitbox.

目前為 2018-05-15 提交的版本,檢視 最新版本

// ==UserScript==
// @name Stream URL grabber
// @description Adds a button that gives you a .m3u8 file for a stream on Twitch or Hitbox.
// @include *://twitch.tv/*
// @include *.twitch.tv/*
// @include *://player.twitch.tv/*
// @include *://www.player.twitch.tv/*
// @include *://www.hitbox.tv/*
// @include	*://api.twitch.tv/*?grabber
// @include	*://api.twitch.tv/*&grabber
// @namespace https://greasyforks.org/users/3167
// @run-at      document-load
// @grant none
// @require https://cdn.jsdelivr.net/npm/hls.js@latest
// @version 10.2
// ==/UserScript==

console.log("Loading streamgrabber...");

if (window.top != window.self) {
  //don't run on frames or iframes
    console.log("Skipping frame/iframe...");
    return;
}


var host = window.location.host;

function html5m3u8(link, filename) {
 
  var html = '<div id="wrap_video"><div id="video_box" style="float:left; width: 100%; height: 100%;"><div id="video_overlay" style="text-align: center; position:absolute; float:left; z-index:10; width: 100%;"></div><div><video id="video" style="width:100%; max-height:100vh;" controls></video></div></div></div></div>';
  document.body.innerHTML = html;
  document.body.style.margin = "0px";
  
  var video = document.getElementById('video');
  if(Hls.isSupported()) {
    var hls = new Hls();
    hls.loadSource(link);
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
    });
  }
  else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = link;
    video.addEventListener('loadedmetadata',function() {
      video.play();
    });
  }
  
  var overlay = document.getElementById('video_overlay');

  var fileNameToSaveAs = filename + '.m3u8';

  var downloadLink = document.createElement("a");
  downloadLink.download = fileNameToSaveAs;
  downloadLink.innerHTML = fileNameToSaveAs;

  downloadLink.href = link;
  downloadLink.style = "color: white;  padding: 3px; border: solid 1px white; border-radius: 4px; background-color: rgba(0, 0, 0, 0.5); "

  overlay.appendChild(downloadLink);
  
  var hidelink = document.createElement("a");
  hidelink.innerHTML = "hide";
  hidelink.href = "#hideoverlay";
  hidelink.style = "color: white; padding: 3px; border: solid 1px white; border-radius: 4px; background-color: rgba(0, 0, 0, 0.5);"
  overlay.appendChild(hidelink);
  
  //overlay.style = "border: solid 1px black; border-radius: 4px;";
  
  hidelink.onclick = function (event) {
    overlay.hidden = true;
  };
  
  console.log(html);
}

function downloadm3u8(link, filename) {

    document.body.innerHTML = 'Link: ';

    var fileNameToSaveAs = filename + '.m3u8';

    var downloadLink = document.createElement("a");
    downloadLink.download = fileNameToSaveAs;
    downloadLink.innerHTML = fileNameToSaveAs;

    downloadLink.href = link;

    document.body.innerHTML = document.body.innerHTML + '<br>';
    document.body.appendChild(downloadLink);

    setTimeout(function() {
        downloadLink.click();
        setTimeout(function() {
            //window.close(); 
        }, 1000);
    }, 1000);
}

if (document.URL.split("grabber").length > 1) {
  console.log("Grab command detected...");
    if (host == "api.twitch.tv" || host == "www.api.twitch.tv") {
        //var text = document.body.textContent;
        var text = document.body.innerText;
      	if (document.body.children.length>0) {
          	text = document.body.children[0].innerText;
        }
      	
        
        var json = JSON.parse(text);
        var user = document.URL.split("api.twitch.tv/api/channels/")[1].split("/")[0];

        var token = json['token'] || '';
        var signature = json['sig'] || '';

        if (token && token!='') {
          var tokenjson = JSON.parse(decodeURI(token));
          if (tokenjson) {
            user = tokenjson['channel'] || user;
          }
          
        }

        var randomp = Math.round(Math.random() * 9999999);

        var url = location.protocol + '//usher.ttvnw.net/api/channel/hls/' + user + '.m3u8?player=twitchweb&token=' + token + '&sig=' + signature + '&allow_audio_only=true&allow_source=true&type=any&p=' + randomp;

        console.log("Encoding url...");
        var urle = encodeURI(url);

        console.log(urle);
        

        html5m3u8(urle, user);

        

        console.log("Stream grabbed on: " + host);

    }
    //return;
    //

} else {
    
    var hook = function(retries) {
        console.log("Hooking... Retries left: " + retries);
        var loaded = document.getElementById("grabber");

        if (retries > 0 && !loaded) {
            retries--;

            if (host.split("twitch.tv").length > 1) {
                var div = document.querySelectorAll('.channel-actions')[0];
              
              
                if (div == null) {
                    div = document.querySelectorAll('.channel-info-bar__action-container')[0];
                }
              
                if (div == null) {
                    div = document.querySelectorAll('.cn-metabar__more')[0];
                }
              
              if (div == null) {
                    div = document.querySelectorAll('.channel-header__right')[0];
                }


                if (div == null) {
                    setTimeout(function() {
                        hook(retries);
                    }, 1000);
                    return;
                }
                else
                 {
                   //do
                  var user = document.URL.split("twitch.tv/")[1].split("/")[0];

                  var clientid = "rp5xf0lwwskmtt1nyuee68mgd0hthrw";
                  var url = location.protocol + '//api.twitch.tv/api/channels/' + user + '/access_token?client_id=' + clientid + '&grabber';
                  //var url = 'http://api.twitch.tv/api/channels/' + user + '/access_token?client_id=' + clientid + '&grabber';

                  var isvideo = document.URL.split("/v/")[1];
                  if (isvideo != undefined) {
                      url = location.protocol + '//player.twitch.tv/?!branding&!channelInfo&video=v' + isvideo + '&client_id=' + clientid + '&grabber';
                      //url = 'http://player.twitch.tv/?!branding&!channelInfo&video=v' + isvideo + '&client_id=' + clientid + '&grabber';
                  }

                  var newspan = document.createElement("span");
                   
                  
                  newspan.innerHTML = '<button class="tw-button tw-button--hollow"><span class="tw-button-icon__icon" style="cursor:pointer;">Grabber</span></button>';

                  newspan.classList.add('tw-mg-x-1');
                  newspan.id = "grabber";
                  
                  div.appendChild(newspan);
                   
                  newspan.onclick = function (event) {
                    window.open(url);
                  };

                  console.log("Stream link: " + url);

                 }
                
            }

            if (host == "www.hitbox.tv") {
                var div = document.querySelectorAll('.status')[0];
                if (div == null) {
                    setTimeout(function() {
                        hook(retries);
                    }, 1000);
                    return
                }
                else
                {
                  //do
                  var user = document.URL.split("hitbox.tv/")[1].split("/")[0];

                  var url = location.protocol + '//api.hitbox.tv/player/hls/' + user + '.m3u8';

                  var newspan = document.createElement("span");
                  newspan.innerHTML = '<span style="cursor:pointer;">Grabber</span>';
                  newspan.id = "grabber";
                  div.appendChild(newspan);
                  
                  newspan.onclick = function (event) {
                      window.open(url);
                  };

                  console.log("Stream link: " + url);
                }
                
            }
        }

        if (loaded) {
            console.log("Stream grabber loaded on host: " + host);
        } else {
            //console.log("Something went wrong when loading on host: " + host);
        }
    };
    
    console.log("Attempting hooks...");

    if (host.split("twitch.tv").length > 1) {
      var retries = 1;
      
      var targetNode = document.getElementsByTagName("main")[0];
      
      if (targetNode) {
        var config = { childList: true };

        var callback = function(mutationsList) {
            hook(retries);
        };

        var observer = new MutationObserver(callback);
        observer.observe(targetNode, config);
        
      }
    }

    var retries = 3;
    hook(retries);


}

长期地址
遇到问题?请前往 GitHub 提 Issues。