Change YouTube Leftbar Subscription Links To Channel/User Video Page

Change YouTube leftbar's subscription links to channel/user video page. This script can optionally also move the links to top of the list if it has new uploaded videos. Both features can be enabled/disabled. For new YouTube layout only.

当前为 2019-02-14 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Change YouTube Leftbar Subscription Links To Channel/User Video Page
  3. // @namespace ChangeYouTubeLeftbarSubscriptionLinksToChannelUserVideoPage
  4. // @version 1.1.7
  5. // @license AGPL v3
  6. // @description Change YouTube leftbar's subscription links to channel/user video page. This script can optionally also move the links to top of the list if it has new uploaded videos. Both features can be enabled/disabled. For new YouTube layout only.
  7. // @author jcunews
  8. // @match *://www.youtube.com/*
  9. // @grant none
  10. // @run-at document-start
  11. // ==/UserScript==
  12.  
  13. //===== Configuration Start ===
  14.  
  15. var changeLinksURL = true;
  16. var moveLinksToTop = true;
  17.  
  18. //===== Configuration End ===
  19.  
  20. function changeUrl(url, m) {
  21. if (m = url.match(/^\/feed\/subscriptions\/([^\/]+)$/)) {
  22. return "/channel/" + m[1] + "/videos";
  23. } else return url + "/videos";
  24. }
  25.  
  26. function patchGuide(guide) {
  27. if (guide && !guide.cysl_done) {
  28. guide.cysl_done = 1;
  29. guide.items.forEach(function(v, vc, l, w, c, i) {
  30. if (v.guideSubscriptionsSectionRenderer) {
  31. //change links' URL
  32. if (changeLinksURL) {
  33. v.guideSubscriptionsSectionRenderer.items.forEach(function(w) {
  34. if (w.guideCollapsibleEntryRenderer) {
  35. w.guideCollapsibleEntryRenderer.expandableItems.forEach(function(x) {
  36. if (x.guideEntryRenderer.badges && (x = x.guideEntryRenderer.navigationEndpoint)) {
  37. x.commandMetadata.webCommandMetadata.url = changeUrl(x.commandMetadata.webCommandMetadata.url);
  38. if (x.webNavigationEndpointData) x.webNavigationEndpointData.url = changeUrl(x.webNavigationEndpointData.url);
  39. }
  40. });
  41. } else if (w = w.guideEntryRenderer.navigationEndpoint) {
  42. w.commandMetadata.webCommandMetadata.url = changeUrl(w.commandMetadata.webCommandMetadata.url);
  43. if (w.webNavigationEndpointData) w.webNavigationEndpointData.url = changeUrl(w.webNavigationEndpointData.url);
  44. }
  45. });
  46. }
  47. //move links with new uploads to top
  48. if (moveLinksToTop) {
  49. v = v.guideSubscriptionsSectionRenderer.items;
  50. vc = v.length - 1;
  51. w = v[vc].guideCollapsibleEntryRenderer;
  52. l = v.splice(0, vc);
  53. c = -1;
  54. if (w) {
  55. (w = w.expandableItems).some(function(e, i) {
  56. if (!e.guideEntryRenderer.badges) {
  57. c = i;
  58. return true;
  59. }
  60. });
  61. l.push.apply(l, w.splice(0, c));
  62. }
  63. c = [];
  64. for (i = l.length - 1; i >= 0; i--) {
  65. if (l[i].guideEntryRenderer.count || (l[i].guideEntryRenderer.presentationStyle === "GUIDE_ENTRY_PRESENTATION_STYLE_NEW_CONTENT")) {
  66. if (vc--) {
  67. v.unshift(l.splice(i, 1)[0]);
  68. } else c.unshift(l.splice(i, 1)[0]);
  69. }
  70. }
  71. c.push.apply(c, l);
  72. if (vc) {
  73. l = c.splice(0, vc);
  74. l.unshift.apply(l, [v.length - 1, 0]);
  75. v.splice.apply(v, l);
  76. }
  77. if (w) w.unshift.apply(w, c);
  78. }
  79. }
  80. });
  81. return true;
  82. }
  83. return false;
  84. }
  85.  
  86. var ht1 = 0, ht2 = 0;
  87.  
  88. (function chkStatic(ev) {
  89. clearTimeout(ht1);
  90. if (!patchGuide(window.ytInitialGuideData)) {
  91. ht1 = setTimeout(chkStatic, 0);
  92. }
  93. })();
  94.  
  95. (function chkSpf() {
  96. clearTimeout(ht2);
  97. if (window.spf && spf.request && !spf.request_cysl) {
  98. spf.request_cysl = spf.request;
  99. spf.request = function(a, b) {
  100. if (b && b.onDone) {
  101. var onDone_ = b.onDone;
  102. b.onDone = function(response) {
  103. if (response && (/\/guide_ajax\?/).test(response.url) && response.response && response.response.response) {
  104. patchGuide(response.response.response);
  105. }
  106. return onDone_.apply(this, arguments);
  107. };
  108. return this.request_cysl.apply(this, arguments);
  109. }
  110. };
  111. return;
  112. }
  113. ht2 = setTimeout(chkSpf, 0);
  114. })();
  115.  
  116. addEventListener("load", function() {
  117. clearTimeout(ht1);
  118. clearTimeout(ht2);
  119. });