dieson 发表于 2019-9-6 20:51

[软件求助] 有请大佬帮忙修改一个plex相关的油猴脚本

本帖最后由 dieson 于 2019-9-6 20:53 编辑

现有一个运行在plex media server网页端上的油猴脚本,目的是当在plex网页端点击播放时,把实际文件地址传送给一个安装在pc端的小程序,实现调用pc系统默认播放器来播放(而不是直接在网页上播放)。
脚本代码放在最后

由于此脚本原本要求plex media server安装在pc本地,而我自己则是安装在群晖上,导致脚本传递的地址实际上是对群晖而言的“本地地址“(如下),无法在pc本地被识别
/volume2/Movie/Furious.Seven.2015.EXTENDED.1080p.BluRay.x264-SPARKS/Furious.Seven.2015.EXTENDED.1080p.BluRay.x264-SPARKS.mkv
有大佬提供了解决思路:
I got it working for a client PC where my library is located on an external server by installing the script "as is" and then selecting a movie and clicking the external player icon. This will fail on a client as it will attempt to use a local address on the server (it should be successful if performed on the server). When it fails you should get a "toast" pop-up telling you what it tried to play, including the address. It's that address you need to modify in the script to get it to work by changing this address to the correct address for the selected media on the server.

I setup some symbolic links to the server each named as a single letter that matches the drive letters of the server drives and with the symbolic link pointing to those drives. I put them all in a folder called symlinks in the C: drive on the client PC. So c:/symlinks/m points to the m drive on the server.

It was then a case of stripping off the m: prefix in the script (or whatever it is from the toast) and then adding the prefix c:/symlinks/m (you'll need to keep the letter, i.e. just strip out the colon really, and add the symlinks folder location as a prefix)
大概是讲在pc本地建立指向群晖磁盘的符号链接,同时链接名称要与群晖磁盘的卷名相同,然后修改脚本中代表文件地址的变量,在其前面增加前缀使之能指向pc本地建立的符号链接,最终实现指向群晖上的文件

然而我看不懂这脚本,只大概理解是要在与“path”相关的地方修改,求大佬出手

脚本如下:
// ==UserScript==
// @name         Plex External Player
// @namespace    https://github.com/Kayomani/PlexExternalPlayer
// @version      1.18
// @descriptionPlay plex videos in an external player
// @author       Kayomani
// @include   /^https?://.*:32400/web.*
// @include   http://*:32400/web/index.html*
// @include   https://*:32400/web/index.html*
// @require   http://code.jquery.com/jquery-3.2.1.min.js
// @connect   *
// @require   https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js
// @grant       GM_xmlhttpRequest
// ==/UserScript==

$("head").append (
    '<link href="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css" rel="stylesheet" type="text/css">'
);


toastr.options = {
    "closeButton": true,
    "debug": false,
    "newestOnTop": true,
    "progressBar": true,
    "positionClass": "toast-bottom-right",
    "preventDuplicates": false,
    "onclick": null,
    "showDuration": "300",
    "hideDuration": "1000",
    "timeOut": "5000",
    "extendedTimeOut": "1000",
    "showEasing": "swing",
    "hideEasing": "linear",
    "showMethod": "fadeIn",
    "hideMethod": "fadeOut"
};

var showToast = function(msg, error){
    var title = 'Plex External Player';
    if(error){
      toastr.error(msg, title, {timeOut: 10000});
      logMessage(msg);
    }
    else
    {
      toastr.success(msg, title);
    }
};

var logMessage = function(msg){
    console.log(' ' + msg);
};

var makeRequest = function(url, user, server){
    return new Promise( function (resolve, reject) {
      var origAccessToken = localStorage.myPlexAccessToken;
      var serverNode = {};
      if(localStorage.users) {
         serverNode = JSON.parse(localStorage.users);
      } else {
         logMessage('User details not found');
      }
      var tokenToTry = origAccessToken;
      if(serverNode===undefined)
      {
            serverNode = {
                users : []
            };
      }

      if(user!==undefined && server !==undefined)
      {
            if(user < serverNode.users.length)
            {
                if(server < serverNode.users.servers.length)
                {
                  tokenToTry = serverNode.users.servers.accessToken;
                }
                else
                {
                  showToast('Could not find authentication info', 1);
                  reject();
                  return;
                }
            }
            else
            {
                showToast('Could not find authentication info', 1);
                reject();
                return;
            }
      }
      var onError =function()
      {
            if(user===undefined)
            {
                user = 0;
                server = 0;
            } else
            {
                server++;
                if(serverNode.users.servers.length===server)
                {
                  user++;
                  server = 0;
                }
            }
            makeRequest(url,user,server).then(resolve, reject);
      };

      var authedUrl =url + '&X-Plex-Token=' +tokenToTry;
      logMessage('Calling ' + authedUrl);
      GM_xmlhttpRequest({
            method: "GET",

            url: authedUrl,
            onload: function(state){
                if (state.status === 200) {
                      logMessage('Called sucessfully to ' + url);
                  resolve(state);
                }
            },
            onreadystatechange: function(state) {
                if (state.readyState === 4) {

                  if(state.status === 401)
                  {
                        logMessage('Not Authorised ' + url);
                        onError();
                  } else if (state.status !== 200) {
                     logMessage('Request returned ' + state.status);
                        showToast('Error calling: ' + url + '. Response: ' + state.responseText + ' Code:' + state.status + ' Message: ' + state.statusText, 1);
                  }
                }
            },
            onerror: onError
      });
    });
};



var markAsPlayedInPlex = function(id) {
    logMessage('Marking ' + id + ' as played');
    return makeRequest(window.location.origin + '/:/scrobble?key='+ id +'&identifier=com.plexapp.plugins.library').catch(function(){
      showToast('Failed to mark item ' + id + ' as played');
    });
};

var openItemOnAgent = function(path, id, openFolder) {
    if(openFolder){
      var fwd = path.lastIndexOf('/');
      var bck = path.lastIndexOf('\\');
      var best = fwd>bck?fwd:bck;
      if(best>-1){
            path = path.substr(0, best);
      }
    }
    showToast('Playing ' + path, 0);
    logMessage('Playing ' + path);
    // umicrosharp doesn't handle plus properly
    path = path.replace(/\+/g, '');
    var url = 'http://localhost:7251/?protocol=2&item=' + encodeURIComponent(path);
    return new Promise(function (resolve, reject) {
      makeRequest(url).then(function(){
            markAsPlayedInPlex(id).then(resolve, reject);
      },reject);
    });
};

var clickListener = function(e) {
    e.preventDefault();
    e.stopPropagation();
    var a = jQuery(e.target).closest('a');
    var link = a.attr('href');
    var openFolder = jQuery(e.target).attr('title') === 'Open folder';
    var url = link;
    if (link === '#' || link === undefined || link === 'javascript:void(0)') {
      url = window.location.hash;
    }

    if (url.indexOf('%2Fmetadata%2F') > -1) {
      var idx = url.indexOf('%2Fmetadata%2F');
      var id = url.substr(idx + 14);
      var idToken = id.indexOf('&');
      if(idToken>-1){
         id= id.substr(0, idToken);
      }

      // Get metadata
      var metaDataPath = window.location.origin + '/library/metadata/' + id + '?includeConcerts=1&includeExtras=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeChapters=1&asyncCheckFiles=0&asyncRefreshAnalysis=0&asyncRefreshLocalMediaAgent=0';
      makeRequest(metaDataPath)
            .then(function(response){
            // Play the first availible part
            var parts = response.respon**ML.getElementsByTagName('Part');
            for (var i = 0; i < parts.length; i++) {
                if (parts.attributes['file'] !== undefined) {
                  openItemOnAgent(parts.attributes['file'].value, id, openFolder).catch(function(){
                        showToast('Failed to connect to agent, is it running or firewalled?',1);
                  });
                  return;
                }
            }

            if (parts.length === 0) {
                // If we got a directory/Season back then get the files in it
                var dirs = response.respon**ML.getElementsByTagName('Directory');
                if (dirs.length > 0) {
                  makeRequest(window.location.origin + dirs.attributes['key'].value)
                        .then(function(response){
                        var videos = response.respon**ML.getElementsByTagName('Video');
                        var file = null;
                        var id = null;
                        if(videos.length === 0)
                        {
                            showToast('Could not determine which video to play as there are multiple seasons.',true);
                            return;
                        }
                        for (var i = 0; i < videos.length; i++) {
                            var vparts = videos.getElementsByTagName('Part');
                            if (vparts.length > 0) {
                              file = vparts.attributes['file'].value;
                              id = vparts.attributes['id'].value;
                              if (videos.attributes['lastViewedAt'] === null || videos.attributes['lastViewedAt'] === undefined) {
                                    break;
                              }
                            }
                        }

                        if (file !== null)
                        {
                            openItemOnAgent(file, id, openFolder).catch(function(){
                              showToast('Failed to connect to agent, is it running or firewalled?',1);
                            });
                        }
                  }).catch(function(){
                        showToast('Failed to get information for directory',1);
                  });
                }
            }
      }, function(error){
            showToast('Error getting metadata from ' + metaDataPath + "Error: " + error, 1);
            logMessage('Error ' + JSON.stringify(error));
      });
    }
};

var bindClicks = function() {
    var hasBtn = false;
    var toolBar= jQuery("#plex-icon-toolbar-play-560").parent().parent();
    toolBar.children('button').each(function(i, e) {
      if(jQuery(e).hasClass('plexextplayer'))
            hasBtn = true;
    });


    if(!hasBtn)
    {
      var template = jQuery('<button class="play-btn media-poster-btn btn-link plexextplayer" tabindex="-1" title="Play Externally"><i class="glyphicon play plexextplayer plexextplayerico"></i></button><button class="play-btn media-poster-btn btn-link plexextplayer" title="Open folder" tabindex="-1"><idata-type="folder"title="Open folder" class="glyphicon play plexextplayer plexfolderextplayerico"></i></button>');
      toolBar.prepend(template);
      template.click(clickListener);

    }

    // Cover page
    jQuery('').each(function(i, e) {
      e = jQuery(e);
      var poster = e.parent().parent();
      if(poster.length === 1 && poster.className.trim().startsWith('MetadataPosterCardOverlay'))
      {
            var existingButton = poster.find('.plexextplayerico');
            if(existingButton.length === 0)
            {
                var url = poster.find('a').attr('href');
                var template = jQuery('<a href="'+ url +'" aria-haspopup="false"aria-role="button" class="" type="button"><i class="glyphicon play plexextplayer plexextplayerico plexextplayericocover"></i></button>');
                var newButton = template.appendTo(poster);
                newButton.click(clickListener);
                poster.mouseenter(function(){
                  newButton.find('i').css('display','block');
                });
                poster.mouseleave(function(){
                  newButton.find('i').css('display','none');
                });
            }
      }
    });
};

// Make buttons smaller
jQuery('body').append('<style>.plexextplayericocover {right: 10px; top: 10px; position:absolute; display:none;font-size:15px;} .glyphicon.plexfolderextplayerico:before {content: "\\e145";   } .glyphicon.plexextplayerico:before {content: "\\e161";   }</style>');

// Bind buttons and check for new ones every 100ms
setInterval(bindClicks, 100);
bindClicks();

dieson 发表于 2019-9-7 12:00

好吧求人不如求己,在PlexExternalPlayer-1.12的readme里找到了要修改的脚本位置,问题已经解决

现在可以用plex的网页浏览封面,然后点一下就可以调用pc本地播放器播放,插帧madvr都有了

下一步是解决批量字幕的问题
页: [1]
查看完整版本: [软件求助] 有请大佬帮忙修改一个plex相关的油猴脚本