Plex External Player

Play plex videos in an external player

当前为 2015-10-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Plex External Player
  3. // @namespace https://github.com/Kayomani/PlexExternalPlayer
  4. // @version 1.0
  5. // @description Play plex videos in an external player
  6. // @author Kayomani
  7. // @include /^https?://.*:32400/web.*
  8. // @grant GM_xmlhttpRequest
  9. // ==/UserScript==
  10.  
  11. var makeRequest = function(url){
  12. return new Promise( function (resolve, reject) {
  13. GM_xmlhttpRequest({
  14. method: "GET",
  15. url: url,
  16. onload: resolve,
  17. onerror: reject
  18. });
  19. });
  20. };
  21.  
  22. var logMessage = function(msg){
  23. console.log('Plex External: ' + msg);
  24. };
  25.  
  26. var markAsPlayedInPlex = function(id) {
  27. logMessage('Marking ' + id + ' as played');
  28. return makeRequest(window.location.origin + '/:/scrobble?key='+ id +'&identifier=com.plexapp.plugins.library');
  29. };
  30.  
  31. var playFileUsingAgent = function(path, id) {
  32. logMessage('Playing ' + path);
  33. var url = 'http://localhost:7251/' + btoa(path);
  34. return new Promise(function (resolve, reject) {
  35. makeRequest(url).then(function(){
  36. markAsPlayedInPlex(id).then(resolve, reject);
  37. },reject);
  38. });
  39. };
  40.  
  41. var clickListener = function(e) {
  42. e.preventDefault();
  43. e.stopPropagation();
  44. var a = jQuery(e.target).closest('a');
  45. var link = a.attr('href');
  46. var url = link;
  47. if (link === '#' || link === undefined) {
  48. url = window.location.hash;
  49. }
  50.  
  51. if (url.indexOf('%2Fmetadata%2F') > -1) {
  52. var idx = url.indexOf('%2Fmetadata%2F');
  53. var id = url.substr(idx + 14);
  54.  
  55. // Get metadata
  56. makeRequest(window.location.origin + '/library/metadata/' + id + '?checkFiles=1&includeExtras=1')
  57. .then(function(response){
  58. // Play the first availible part
  59. var parts = response.responseXML.getElementsByTagName('Part');
  60. for (var i = 0; i < parts.length; i++) {
  61. if (parts[i].attributes['file'] !== undefined) {
  62. playFileUsingAgent(parts[i].attributes['file'].value, id);
  63. return;
  64. }
  65. }
  66.  
  67. if (parts.length === 0) {
  68. // If we got a directory/Season back then get the files in it
  69. var dirs = response.responseXML.getElementsByTagName('Directory');
  70. if (dirs.length > 0) {
  71. makeRequest(window.location.origin + dirs[0].attributes['key'].value)
  72. .then(function(response){
  73. var videos = response.responseXML.getElementsByTagName('Video');
  74. var file = null;
  75. var id = null;
  76. for (var i = 0; i < videos.length; i++) {
  77. var vparts = videos[i].getElementsByTagName('Part');
  78. if (vparts.length > 0) {
  79. file = vparts[0].attributes['file'].value;
  80. id = vparts[0].attributes['id'].value;
  81. if (videos[i].attributes['lastViewedAt'] === null || videos[i].attributes['lastViewedAt'] === undefined) {
  82. break;
  83. }
  84. }
  85. }
  86.  
  87. if (file !== null) {
  88. playFileUsingAgent(file, id);
  89. }
  90. });
  91. }
  92. }
  93. });
  94. }
  95. };
  96.  
  97. var bindClicks = function() {
  98. jQuery(".glyphicon.play").each(function(i, e) {
  99. e = jQuery(e);
  100. if (!e.hasClass('plexextplayer')) {
  101. if (!e.parent().hasClass('hidden')) {
  102. e.addClass('plexextplayer');
  103. var parent = e.parent().parent();
  104. if (parent.is('li')) {
  105. var template = jQuery('<li><a class="btn-gray" href="#" title="Play Externally" data-toggle="Play Externally" data-original-title="Play Externally"><i style="color: #41D677" class="glyphicon play plexextplayer plexextplayerico"></i></a></li>');
  106. parent.after(template);
  107. template.click(clickListener);
  108. } else if (parent.is('div') && parent.hasClass('media-poster-actions')) {
  109. var template = jQuery('<button class="play-btn media-poster-btn btn-link" tabindex="-1"><i style="color: #41D677" class="glyphicon play plexextplayer plexextplayerico"></i></button>');
  110. parent.prepend(template);
  111. template.click(clickListener);
  112. }
  113. }
  114. }
  115. });
  116. };
  117.  
  118. // Make buttons smaller
  119. jQuery('body').append('<style>.media-poster-btn { padding: 8px !important; }</style>');
  120.  
  121. // Bind buttons and check for new ones every 100ms
  122. setInterval(bindClicks, 100);
  123. bindClicks();