YouTube Flag Tracker

Track changes in YouTube's experiment flags

  1. // ==UserScript==
  2. // @name YouTube Flag Tracker
  3. // @namespace Violentmonkey Scripts
  4. // @version 1.2.2
  5. // @description Track changes in YouTube's experiment flags
  6. // @include http*://www.youtube.com/*
  7. // @grant unsafeWindow
  8. // @grant GM_setValue
  9. // @grant GM_getValue
  10. // @run-at document-end
  11. // ==/UserScript==
  12.  
  13. function save(key, data) {
  14.  
  15. if (!Object.keys(data).length) {
  16. return;
  17. }
  18.  
  19. if (key === "changes") {
  20. const changes = GM_getValue("changes", []);
  21. changes.unshift(data);
  22. data = changes;
  23. }
  24.  
  25. GM_setValue(key, data);
  26. }
  27.  
  28. function isEqual(a, b) {
  29.  
  30. if (Array.isArray(a) && Array.isArray(b)) {
  31. return (
  32. a.length === b.length &&
  33. JSON.stringify(a) === JSON.stringify(b)
  34. );
  35. }
  36.  
  37. return a === b;
  38. }
  39.  
  40. function diffChecker(prev = {}, curr = {}) {
  41.  
  42. let changes = {};
  43.  
  44. const allKeys = new Set([...Object.keys(prev), ...Object.keys(curr)]);
  45.  
  46. allKeys.forEach(key => {
  47.  
  48. const prevVal = prev[key];
  49. const currVal = curr[key];
  50.  
  51. if (prevVal === undefined) {
  52. changes[key] = { type: "added", value: currVal };
  53. }
  54.  
  55. else if (currVal === undefined) {
  56. changes[key] = { type: "removed" };
  57. }
  58.  
  59. else if (!isEqual(prevVal, currVal)) {
  60. changes[key] = { type: "modified", value: currVal };
  61. }
  62. });
  63.  
  64. return changes;
  65. }
  66.  
  67. function updateStorage(currentFlags) {
  68.  
  69. const previousFlags = GM_getValue("flags", {});
  70. const changes = diffChecker(previousFlags, currentFlags);
  71.  
  72. const numChanges = Object.keys(changes).length;
  73. const maxChanges = Object.keys(previousFlags).length / 2;
  74.  
  75. if (!maxChanges || numChanges <= maxChanges) {
  76. save("changes", changes);
  77. save("flags", currentFlags);
  78. }
  79. }
  80.  
  81. function observeFlags() {
  82.  
  83. const observer = new MutationObserver(() => {
  84.  
  85. const flags = unsafeWindow.yt?.config_?.EXPERIMENT_FLAGS;
  86.  
  87. if (flags) {
  88. observer.disconnect();
  89. updateStorage(flags);
  90. }
  91. });
  92.  
  93. observer.observe(document.body, { childList: true, subtree: true });
  94. }
  95.  
  96.  
  97. observeFlags();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址