Sonarr & Radarr Link Adder

Adds links to specified series on the table view

当前为 2025-02-20 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Sonarr & Radarr Link Adder
  3. // @namespace https://greasyfork.org/en/users/814-bunta
  4. // @version 3.1
  5. // @description Adds links to specified series on the table view
  6. // @author Bunta
  7. // @include http://localhost:8989/*
  8. // @include http://localhost:7878/*
  9. // @license http://creativecommons.org/licenses/by-nc-sa/3.0/us/
  10. // @require http://code.jquery.com/jquery-3.4.1.min.js
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. // define what links to add to series/movie on the table list
  18. // these links will appear as icons to the right of the specified series' or movies' names
  19. // syntax: [Title, URL, icon] Note: Title must match the series/movie title in the list
  20. let tableLinks = [
  21. ['Tokyo Revengers', 'https://nyaa.si/?f=0&c=0_0&q=tokyo+revengers+dual', 'https://nyaa.si/static/favicon.png'],
  22. ];
  23.  
  24. // define what links to add to the "Links" menu for all series/movies
  25. // syntax: [Link Title, URL]
  26. // URL can use following substitutions:
  27. // {title} - Link Title
  28. let menuLinks = [
  29. ['MyAnimeList', 'https://myanimelist.net/anime.php?q={title}'],
  30. ];
  31.  
  32. var tableArray = [];
  33. tableLinks.forEach(item => {tableArray.push(item[0])});
  34.  
  35. var menuArray = [];
  36. menuLinks.forEach(item => {menuArray.push(item[0])});
  37.  
  38. // Options for the observer (which mutations to observe: attributes, childList, subtree, characterData)
  39. const config = { attributes: false, characterData: false, childList: true, subtree: true };
  40.  
  41. // Callback function to execute when mutations are observed
  42. const callback = function(mutationsList, observer) {
  43.  
  44. // Use traditional 'for loops' for IE 11
  45. for(const mutation of mutationsList) {
  46. if (mutation.type === 'childList') {
  47. console.log(mutation);
  48. //console.log(mutation.target.classList);
  49.  
  50. // Adding initial links on series table view page load
  51. if (mutation.target.classList.length > 0 && (mutation.target.classList[0].contains('root') || mutation.target.classList[0].contains('Page-main-Swphf'))) {
  52. $(mutation.target).find('a').filter(function() { return tableArray.includes($(this).text()) && $(this).parent().find('a').length < 2 }).each( function(index) {
  53. //console.log( $( this ).text() );
  54. tableLinks.forEach(item => {
  55. if (item[0] == $(this).text())
  56. $( '<a href="' + item[1] + '" target="_blank"><img src="' + item[2] + '" width=25 height=20 style="padding:0 5px 0 0;">' ).insertBefore(this);
  57. });
  58. });
  59. }
  60.  
  61. // Adding links to series table view when scrolling table
  62. if (mutation.addedNodes.length > 0) {
  63. mutation.addedNodes.forEach(function (node) {
  64. if (node.classList.length > 0 && (node.classList[0].contains('SeriesIndexTable-row-mcybv') || node.classList[0].contains('MovieIndexTable-row-MZIas'))) {
  65. $(node).find('a').filter(function() { return tableArray.includes($(this).text()) && $(this).parent().find('a').length < 2 }).each( function(index) {
  66. //console.log( $( this ).text() );
  67. tableLinks.forEach(item => {
  68. if (item[0] == $(this).text())
  69. $( '<a href="' + item[1] + '" target="_blank"><img src="' + item[2] + '" width=25 height=20 style="padding:0 5px 0 0;">' ).insertBefore(this);
  70. });
  71. });
  72. }
  73. });
  74. }
  75.  
  76. // Adding links to "Links" shortcuts on series view
  77. if (mutation.target.classList.length > 0) {
  78. if (menuLinks.length > 0 && mutation.target.classList[0].contains('Tooltip-tooltipContainer-gDO7_')) {
  79. var linkClass = 'SeriesDetailsLinks-link-RfjeR Link-link-RInnp Link-to-kylTi'
  80. var spanClass = 'SeriesDetailsLinks-linkLabel-SAKtg Label-label-DYldh Label-info-QWFsu Label-large-qZ9AP'
  81. var links = $(mutation.target).find('div.SeriesDetailsLinks-links-cHw2_');
  82. if (links.length === 0) {
  83. linkClass = 'MovieDetailsLinks-link-RA9Kf Link-link-RInnp Link-to-kylTi'
  84. spanClass = 'MovieDetailsLinks-linkLabel-GGMIV Label-label-DYldh Label-info-QWFsu Label-large-qZ9AP'
  85. links = $(mutation.target).find('div.MovieDetailsLinks-links-eFF77');
  86. }
  87. //console.log("Links: " + links.length);
  88. if (links.length === 0) continue;
  89. if (links.find('a').filter(function() { return menuArray.includes($(this).text()) }).length > 0) continue;
  90. var itemTitle = $('div.SeriesDetails-title-pJv1g,div.MovieDetails-title-yaEzx span').text();
  91. if (!itemTitle) continue;
  92. menuLinks.forEach(item => {
  93. links.append( '<a target="_blank" href="'+item[1].replace('{title}', itemTitle)+'" class="'+linkClass+'"><span class="'+spanClass+'">'+item[0]+'</span></a>');
  94. });
  95. }
  96. }
  97. }
  98. }
  99. };
  100.  
  101. // Create an observer instance linked to the callback function
  102. const observer = new MutationObserver(callback);
  103.  
  104. // Start observing the target node for configured mutations
  105. observer.observe(document.body, config);
  106.  
  107. // Later, you can stop observing
  108. //observer.disconnect();
  109.  
  110. })();