YouTube 超快聊天

YouTube直播聊天的终极性能提升

当前为 2024-12-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube Super Fast Chat
  3. // @version 0.66.11
  4. // @license MIT
  5. // @name:ja YouTube スーパーファーストチャット
  6. // @name:zh-TW YouTube 超快聊天
  7. // @name:zh-CN YouTube 超快聊天
  8. // @icon https://raw.githubusercontent.com/cyfung1031/userscript-supports/main/icons/super-fast-chat.png
  9. // @namespace UserScript
  10. // @match https://www.youtube.com/live_chat*
  11. // @match https://www.youtube.com/live_chat_replay*
  12. // @author CY Fung
  13. // @run-at document-start
  14. // @grant none
  15. // @unwrap
  16. // @allFrames true
  17. // @inject-into page
  18. // @require https://update.greasyfork.org/scripts/475632/1361351/ytConfigHacks.js
  19. //
  20. // @compatible firefox Violentmonkey
  21. // @compatible firefox Tampermonkey
  22. // @compatible firefox FireMonkey
  23. // @compatible chrome Violentmonkey
  24. // @compatible chrome Tampermonkey
  25. // @compatible opera Violentmonkey
  26. // @compatible opera Tampermonkey
  27. // @compatible safari Stay
  28. // @compatible edge Violentmonkey
  29. // @compatible edge Tampermonkey
  30. // @compatible brave Violentmonkey
  31. // @compatible brave Tampermonkey
  32. //
  33. // @description Ultimate Performance Boost for YouTube Live Chats
  34. // @description:ja YouTubeのライブチャットの究極のパフォーマンスブースト
  35. // @description:zh-TW YouTube直播聊天的終極性能提升
  36. // @description:zh-CN YouTube直播聊天的终极性能提升
  37. //
  38. // ==/UserScript==
  39.  
  40. ((__CONTEXT__) => {
  41. 'use strict';
  42.  
  43. /** @type {WeakMapConstructor} */
  44. const WeakMap = window.WeakMapOriginal || window.WeakMap;
  45.  
  46. const DEBUG_LOG_GROUP_EXPAND = !!localStorage.__debugSuperFastChat__;
  47. const DEBUG_customCreateComponent = false;
  48.  
  49. // *********** DON'T REPORT NOT WORKING DUE TO THE CHANGED SETTINGS ********************
  50. // The settings are FIXED! You might change them to try but if the script does not work due to your change, please, don't report them as issues
  51.  
  52. const ENABLE_REDUCED_MAXITEMS_FOR_FLUSH = true; // TRUE to enable trimming down to MAX_ITEMS_FOR_FULL_FLUSH (25) messages when there are too many unrendered messages
  53. const MAX_ITEMS_FOR_TOTAL_DISPLAY = 90; // By default, 250 latest messages will be displayed, but displaying MAX_ITEMS_FOR_TOTAL_DISPLAY (90) messages is already sufficient. (not exceeding 900)
  54. const MAX_ITEMS_FOR_FULL_FLUSH = 25; // If there are too many new (stacked) messages not yet rendered, clean all and flush MAX_ITEMS_FOR_FULL_FLUSH (25) latest messages then incrementally added back to MAX_ITEMS_FOR_TOTAL_DISPLAY (90) messages. (not exceeding 900)
  55.  
  56. const ENABLE_NO_SMOOTH_TRANSFORM = true; // Depends on whether you want the animation effect for new chat messages <<< DON'T CHANGE >>>
  57. const USE_OPTIMIZED_ON_SCROLL_ITEMS = true; // TRUE for the majority
  58. const ENABLE_OVERFLOW_ANCHOR_PREFERRED = true; // Enable `overflow-anchor: auto` to lock the scroll list at the bottom for no smooth transform.
  59.  
  60. const FIX_SHOW_MORE_BUTTON_LOCATION = true; // When there are voting options (bottom panel), move the "show more" button to the top.
  61. const FIX_INPUT_PANEL_OVERFLOW_ISSUE = true; // When the super chat button is flicking with color, the scrollbar might come out.
  62. const FIX_INPUT_PANEL_BORDER_ISSUE = true; // No border should be allowed if there is an empty input panel.
  63. const SET_CONTAIN_FOR_CHATROOM = true; // Rendering hacks (`contain`) for chatroom elements. [ General ]
  64.  
  65. const FORCE_CONTENT_VISIBILITY_UNSET = true; // Content-visibility should be always VISIBLE for high performance and great rendering.
  66. const FORCE_WILL_CHANGE_UNSET = true; // Will-change should be always UNSET (auto) for high performance and low energy impact.
  67.  
  68. // Replace requestAnimationFrame timers with custom implementation
  69. const ENABLE_RAF_HACK_TICKERS = true; // When there is a ticker
  70. const ENABLE_RAF_HACK_DOCKED_MESSAGE = true; // To be confirmed
  71. const ENABLE_RAF_HACK_INPUT_RENDERER = true; // To be confirmed
  72. const ENABLE_RAF_HACK_EMOJI_PICKER = true; // When changing the page of the emoji picker
  73.  
  74. // Force rendering all the character subsets of the designated font(s) before messages come (Pre-Rendering of Text)
  75. const ENABLE_FONT_PRE_RENDERING_PREFERRED = 1 | 2 | 4 | 8 | 16;
  76.  
  77. // Backdrop `filter: blur(4px)` inside the iframe can extend to the whole page, causing a negative visual impact on the video you are watching.
  78. const NO_BACKDROP_FILTER_WHEN_MENU_SHOWN = true;
  79.  
  80. // Data Manipulation for Participants (Participant List)
  81. // << if DO_PARTICIPANT_LIST_HACKS >>
  82. const DO_PARTICIPANT_LIST_HACKS = true; // TRUE for the majority
  83. const SHOW_PARTICIPANT_CHANGES_IN_CONSOLE = false; // Just too annoying to show them all in popular chat
  84. const CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT = true; // Only consider changes in renderable content (not concerned with the last chat message of the participants)
  85. const PARTICIPANT_UPDATE_ONLY_ONLY_IF_MODIFICATION_DETECTED = true;
  86. // << end >>
  87.  
  88. // show more button
  89. const ENABLE_SHOW_MORE_BLINKER = true; // BLINK WHEN NEW MESSAGES COME
  90.  
  91. // faster stampDomArray_ for participants list creation
  92. const ENABLE_FLAGS_MAINTAIN_STABLE_LIST_VAL = 1; // 0 - OFF; 1 - ON; 2 - ON(PARTICIPANTS_LIST ONLY)
  93. const USE_MAINTAIN_STABLE_LIST_ONLY_WHEN_KS_FLAG_IS_SET = false;
  94.  
  95. // reuse yt components
  96. const ENABLE_FLAGS_REUSE_COMPONENTS = true;
  97.  
  98. // ShadyDom Free is buggy
  99. const DISABLE_FLAGS_SHADYDOM_FREE = true;
  100.  
  101. // images <Group#I01>
  102. const AUTHOR_PHOTO_SINGLE_THUMBNAIL = 1; // 0 - disable; 1- smallest; 2- largest
  103. const EMOJI_IMAGE_SINGLE_THUMBNAIL = 1; // 0 - disable; 1- smallest; 2- largest
  104. const LEAST_IMAGE_SIZE = 48; // minium size = 48px
  105.  
  106. const DO_LINK_PREFETCH = true; // DO NOT CHANGE
  107. // << if DO_LINK_PREFETCH >>
  108. const ENABLE_BASE_PREFETCHING = true; // (SUB-)DOMAIN | dns-prefetch & preconnect
  109. const ENABLE_PRELOAD_THUMBNAIL = true; // subresource (prefetch) [LINK for Images]
  110. const SKIP_PRELOAD_EMOJI = true;
  111. const PREFETCH_LIMITED_SIZE_EMOJI = 512; // DO NOT CHANGE THIS
  112. const PREFETCH_LIMITED_SIZE_AUTHOR_PHOTO = 68; // DO NOT CHANGE THIS
  113. // << end >>
  114.  
  115. const FIX_SETSRC_AND_THUMBNAILCHANGE_ = true; // Function Replacement for yt-img-shadow....
  116. const FIX_THUMBNAIL_DATACHANGED = true; // Function Replacement for yt-live-chat-author-badge-renderer..dataChanged
  117. // const REMOVE_PRELOADAVATARFORADDACTION = false; // Function Replacement for yt-live-chat-renderer..preloadAvatarForAddAction
  118.  
  119. const FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION = true; // important [depends on <Group#I01>]
  120. const FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT = true; // [depends on <Group#I01>]
  121.  
  122. const ATTEMPT_ANIMATED_TICKER_BACKGROUND = ''; // false OR '' for disabled, 'linear', 'steps' for easing-function
  123. // <<<< ATTEMPT_ANIMATED_TICKER_BACKGROUND to be reviewed with memory leakage issues >>>>
  124. // << if ATTEMPT_ANIMATED_TICKER_BACKGROUND >>
  125. // BROWSER SUPPORT: Chrome 75+, Edge 79+, Safari 13.1+, Firefox 63+, Opera 62+
  126. const TICKER_MAX_STEPS_LIMIT = 500; // NOT LESS THAN 5 STEPS!!
  127. // [limiting 500 max steps] is recommended for "confortable visual change"
  128. // min. step increment 0.2% => max steps: 500 => 800ms per each update
  129. // min. step increment 0.5% => max steps: 200 => 1000ms per each update
  130. // min. step increment 1.0% => max steps: 100 => 1000ms per each update
  131. // min. step increment 2.5% => max steps: 40 => 1000ms per each update
  132. // min. step increment 5.0% => max steps: 20 => 1250ms per each update
  133. const ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX = true; // for video playback's ticker issue. [ Playback Replay - Pause at Middle - Backwards Seeking ]
  134. const SKIP_VIDEO_PLAYBACK_PROGRESS_STATE_FIX_FOR_NO_TIMEFX = false; // debug use; yt-live-chat-ticker-renderer might not require ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX
  135. // << end >>
  136.  
  137. const FIX_TOOLTIP_DISPLAY = true; // changed in 2024.05.02
  138. const USE_VANILLA_DEREF = true;
  139. const FIX_DROPDOWN_DERAF = true; // DONT CHANGE
  140.  
  141.  
  142. const CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN = true; // cache the menu data and used for the next reopen
  143. const ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU = false; // pause auto scroll faster when the context menu is about to show
  144. const ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU = true; // avoid multiple requests on the same time
  145.  
  146. const BOOST_MENU_OPENCHANGED_RENDERING = true;
  147. const FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK = true; // click again = close
  148. const NO_ITEM_TAP_FOR_NON_STATIONARY_TAP = true; // dont open the menu (e.g. text message) if cursor is moved or long press
  149. const TAP_ACTION_DURATION = 280; // exceeding 280ms would not consider as a tap action
  150. const PREREQUEST_CONTEXT_MENU_ON_MOUSE_DOWN = true; // require CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN = true
  151. // const FIX_MENU_CAPTURE_SCROLL = true;
  152. const CHAT_MENU_REFIT_ALONG_SCROLLING = 0; // 0 for locking / default; 1 for unlocking only; 2 for unlocking and refit
  153.  
  154. const RAF_FIX_keepScrollClamped = true;
  155. const RAF_FIX_scrollIncrementally = 2; // 0: no action; 1: basic fix; 2: also fix scroll position
  156.  
  157. // << if BOOST_MENU_OPENCHANGED_RENDERING >>
  158. const FIX_MENU_POSITION_N_SIZING_ON_SHOWN = 1; // correct size and position when the menu dropdown opens
  159.  
  160. const CHECK_JSONPRUNE = true; // This is a bug in Brave
  161. // << end >>
  162.  
  163. // const LIVE_CHAT_FLUSH_ON_FOREGROUND_ONLY = false;
  164.  
  165. const CHANGE_DATA_FLUSH_ASYNC = false;
  166. // CHANGE_DATA_FLUSH_ASYNC is disabled due to bug report: https://greasyfork.org/scripts/469878/discussions/199479
  167. // to be further investigated
  168.  
  169. const CHANGE_MANAGER_UNSUBSCRIBE = true;
  170.  
  171. const INTERACTIVITY_BACKGROUND_ANIMATION = 1; // mostly for pinned message
  172. // 0 = default Yt animation background [= no fix];
  173. // 1 = disable default animation background [= keep special animation];
  174. // 2 = disable all animation backgrounds [= no animation backbround]
  175.  
  176. const CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED = true;
  177.  
  178. const MAX_TOOLTIP_NO_WRAP_WIDTH = '72vw'; // '' for disable; accept values like '60px', '25vw'
  179.  
  180.  
  181.  
  182. // (Dec 2024: AMEND_TICKER_handleLiveChatAction to be removed)
  183. const AMEND_TICKER_handleLiveChatAction = false; // to fix ticker duplication and unresponsively fast ticker generation
  184. // AMEND_TICKER_handleLiveChatAction to be fixed (2024.05.21)
  185.  
  186. // (Dec 2024: AMEND_TICKER_handleLiveChatAction_v3 to be removed)
  187. const AMEND_TICKER_handleLiveChatAction_v3 = false; // responsiveness fix (Major Feature)
  188.  
  189. const USE_ADVANCED_TICKING = true; // added in Dec 2024 v0.66.0; need to ensure it would not affect the function if ticker design changed. to be reviewed
  190. // const END_ANIMATING_TICKERS = true; // added in Dec 2024 v0.66.5; see pressure test like https://www.youtube.com/watch?v=CQaUs-vNgXo
  191. const FIX_TIMESTAMP_FOR_REPLAY = true;
  192.  
  193. // const ADVANCED_TICKING_MEMORY_CLEAN_FOR_REMOVAL = true;
  194.  
  195.  
  196. const ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION = true; // MUST BE true
  197. const ADJUST_TICKER_DURATION_ALIGN_RENDER_TIME = true;
  198. const FIX_BATCH_TICKER_ORDER = true;
  199.  
  200. const DISABLE_Translation_By_Google = true;
  201.  
  202. const FASTER_ICON_RENDERING = true;
  203.  
  204. const DELAY_FOCUSEDCHANGED = true;
  205.  
  206. const skipErrorForhandleAddChatItemAction_ = true; // currently depends on ENABLE_NO_SMOOTH_TRANSFORM
  207. const fixChildrenIssue801 = true; // if __children801__ is set [fix polymer controller method extration for `.set()`]
  208.  
  209. const SUPPRESS_refreshOffsetContainerHeight_ = true; // added in FEB 2024; true for default layout options; no effect if ENABLE_NO_SMOOTH_TRANSFORM is false
  210.  
  211. const NO_FILTER_DROPDOWN_BORDER = true; // added in 2024.03.02
  212.  
  213. const FIX_ANIMATION_TICKER_TEXT_POSITION = true; // CSS fix; experimental; added in 2024.04.07
  214. const FIX_AUTHOR_CHIP_BADGE_POSITION = true;
  215.  
  216. const FIX_ToggleRenderPolymerControllerExtractionBug = false; // to be reviewed
  217.  
  218. const REACTION_ANIMATION_PANEL_CSS_FIX = true;
  219.  
  220. const FIX_UNKNOWN_BUG_FOR_OVERLAY = true; // no .prepare() in backdrop element. reason is unknown.
  221. const REUSE_TICKER = true; // for better memory control; currently it is only available in ADVANCED_TICKING; to be further reviewed
  222.  
  223. // -------------------------------
  224.  
  225. const USE_OBTAIN_LCR_BY_BOTH_METHODS = false; // true for play safe
  226.  
  227. const FIX_MEMORY_LEAKAGE_TICKER_ACTIONMAP = true; // To fix Memory Leakage in yt-live-chat-ticker-...-item-renderer
  228. const FIX_MEMORY_LEAKAGE_TICKER_STATSBAR = true; // To fix Memory Leakage in updateStatsBarAndMaybeShowAnimation
  229. const FIX_MEMORY_LEAKAGE_TICKER_TIMER = true; // To fix Memory Leakage in setContainerWidth, slideDown, collapse // Dec 2024 fix in advance tickering
  230. const FIX_MEMORY_LEAKAGE_TICKER_DATACHANGED_setContainerWidth = true; // To fix Memory Leakage due to _.ytLiveChatTickerItemBehavior.setContainerWidth()
  231.  
  232. // leakage in ytd-sponsorships-live-chat-gift-purchase-announcement-renderer - to be confirmed
  233.  
  234. // <<<<< FOR MEMORY LEAKAGE >>>>
  235. const DEBUG_wmList = false;
  236. let DEBUG_wmList_started = false;
  237. // const FLAG_001 = true;
  238. const FLAG_001a = false;
  239. const FLAG_001b = false;
  240. const FLAG_001c = false;
  241. const FLAG_001d = false;
  242. const FLAG_001e = false;
  243. const FLAG_001f = false;
  244. // const FLAG_001g = true;
  245.  
  246.  
  247.  
  248. /**
  249. *
  250. *
  251. *
  252. *
  253. *
  254. rendererStamperObserver_: function(a, b, c) {
  255. if (c.path == a) {
  256. if (c.value === void 0 && !this.hasDataPath_[a])
  257. return;
  258. this.hasDataPath_[a] = c.value !== void 0
  259. }
  260. this.rendererStamperApplyChangeRecord_(a, b, c)
  261. },
  262.  
  263.  
  264. addStampDomObserverFns_: function() {
  265. for (var a in this.stampDom) {
  266. var b = this.stampDom[a];
  267. b.id ? (this[SQa(b.id)] = this.rendererStamperObserver_.bind(this, a, b.id),
  268. this.hasDataPath_[a] = !1) : Er(new Dn("Bad rendererstamper config",this.is + ":" + a))
  269. }
  270. },
  271. *
  272. *
  273. *
  274. *
  275. *
  276. */
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283. // <<<<< FOR MEMORY LEAKAGE >>>>
  284.  
  285. // ========= EXPLANTION FOR 0.2% @ step timing [min. 0.2%] ===========
  286. /*
  287.  
  288. ### Time Approach
  289.  
  290. // all below values can make the time interval > 250ms
  291. // 250ms (practical value) refers to the minimum frequency for timeupdate in most browsers (typically, shorter timeupdate interval in modern browsers)
  292. if (totalDuration > 400000) stepInterval = 0.2; // 400000ms with 0.2% increment => 800ms
  293. else if (totalDuration > 200000) stepInterval = 0.5; // 200000ms with 0.5% increment => 1000ms
  294. else if (totalDuration > 100000) stepInterval = 1; // 100000ms with 1% increment => 1000ms
  295. else if (totalDuration > 50000) stepInterval = 2; // 50000ms with 2% increment => 1000ms
  296. else if (totalDuration > 25000) stepInterval = 5; // 25000ms with 5% increment => 1250ms
  297.  
  298. ### Pixel Check
  299. // Target Max Pixel Increment < 5px for Short Period Ticker (Rapid Background Change)
  300. // Assume total width <= 99px for short period ticker, like small donation & member welcome
  301. 99px * 5% = 4.95px < 5px [Condition Fulfilled]
  302.  
  303. ### Example - totalDuration = 280000
  304. totalDuration 280000
  305. stepInterval 0.5
  306. numOfSteps = Math.round(100 / stepInterval) = 200
  307. time interval = 280000 / 200 = 1400ms <acceptable>
  308.  
  309. ### Example - totalDuration = 18000
  310. totalDuration 18000
  311. stepInterval 5
  312. numOfSteps = Math.round(100 / stepInterval) = 20
  313. time interval = 18000 / 20 = 900ms <acceptable>
  314.  
  315. ### Example - totalDuration = 5000
  316. totalDuration 5000
  317. stepInterval 5
  318. numOfSteps = Math.round(100 / stepInterval) = 20
  319. time interval = 5000 / 20 = 250ms <threshold value>
  320.  
  321. ### Example - totalDuration = 3600
  322. totalDuration 3600
  323. stepInterval 5
  324. numOfSteps = Math.round(100 / stepInterval) = 20
  325. time interval = 3600 / 20 = 180ms <reasonable for 3600ms ticker>
  326.  
  327. */
  328.  
  329. // =======================================================================================================
  330.  
  331. // AUTOMAICALLY DETERMINED
  332. const ENABLE_FLAGS_MAINTAIN_STABLE_LIST = ENABLE_FLAGS_MAINTAIN_STABLE_LIST_VAL === 1;
  333. const ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST = ENABLE_FLAGS_MAINTAIN_STABLE_LIST_VAL >= 1;
  334. const CHAT_MENU_SCROLL_UNLOCKING = CHAT_MENU_REFIT_ALONG_SCROLLING >= 1;
  335. let runTickerClassName = 'run-ticker';
  336.  
  337. const dummyImgURL = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
  338. /*
  339. WebP: data:image/webp;base64,UklGRjAB
  340. PNG: data:image/png;base64,iVBORw0KGg==
  341. JPEG: data:image/jpeg;base64,/9j/4AA=
  342. GIF: data:image/gif;base64,R0lGODlhAQABAIA=
  343. BMP: data:image/bmp;base64,Qk1oAAAA
  344. SVG: data:image/svg+xml;base64,PHN2Zy8+Cg==
  345.  
  346. WebP: data:image/webp;base64,AAAAAAA=
  347. PNG: data:image/png;base64,AAAAAAA=
  348. JPEG: data:image/jpeg;base64,AAAAAAA=
  349. GIF: data:image/gif;base64,AAAAAAA=
  350. BMP: data:image/bmp;base64,AAAAAAA=
  351.  
  352. data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  353.  
  354.  
  355. */
  356.  
  357. // image sizing code
  358. // (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null)
  359.  
  360.  
  361. // function KC(a, b, c, d) {
  362. // d = void 0 === d ? "width" : d;
  363. // if (!a || !a.length)
  364. // return null;
  365. // if (z("kevlar_tuner_should_always_use_device_pixel_ratio")) {
  366. // var e = window.devicePixelRatio;
  367. // z("kevlar_tuner_should_clamp_device_pixel_ratio") ? e = Math.min(e, zl("kevlar_tuner_clamp_device_pixel_ratio")) : z("kevlar_tuner_should_use_thumbnail_factor") && (e = zl("kevlar_tuner_thumbnail_factor"));
  368. // HC = e
  369. // } else
  370. // HC || (HC = window.devicePixelRatio);
  371. // e = HC;
  372. // z("kevlar_tuner_should_always_use_device_pixel_ratio") ? b *= e : 1 < e && (b *= e);
  373. // if (z("kevlar_tuner_min_thumbnail_quality"))
  374. // return a[0].url || null;
  375. // e = a.length;
  376. // if (z("kevlar_tuner_max_thumbnail_quality"))
  377. // return a[e - 1].url || null;
  378. // if (c)
  379. // for (var h = 0; h < e; h++)
  380. // if (0 <= a[h].url.indexOf(c))
  381. // return a[h].url || null;
  382. // for (c = 0; c < e; c++)
  383. // if (a[c][d] >= b)
  384. // return a[c].url || null;
  385. // for (b = e - 1; 0 < b; b--)
  386. // if (a[b][d])
  387. // return a[b].url || null;
  388. // return a[0].url || null
  389. // }
  390.  
  391.  
  392. /// ------
  393.  
  394. // https://www.youtube.com/watch?v=byyvH5t0hKc
  395. // yt-live-chat-ticker-creator-goal-view-model
  396. // no ticker effect on timing
  397.  
  398. /*
  399.  
  400.  
  401. {
  402. "id": "ChwKGkNQS0pyNV9NdG9vREZVYlB6Z2FkRHWFUv2E",
  403. "initialTickerText": {
  404. "content": "Goal",
  405. "styleRuns": [
  406. {
  407. "startIndex": 0,
  408. "length": 4
  409. }
  410. ]
  411. },
  412. "tickerIcon": {
  413. "sources": [
  414. {
  415. "clientResource": {
  416. "imageName": "TARGET_ADD"
  417. }
  418. }
  419. ]
  420. },
  421. "showGoalStatusCommand": {
  422. "innertubeCommand": {
  423. "clickTrackingParams": "CCQQ7NANIhMI58DT_ef5rhMVxMW1Cx4qBzTz",
  424. "showEngagementPanelEndpoint": {
  425. "engagementPanel": {
  426. "engagementPanelSectionListRenderer": {
  427. "header": {
  428. "engagementPanelTitleHeaderRenderer": {
  429. "actionButton": {
  430. "buttonRenderer": {
  431. "icon": {
  432. "iconType": "QUESTION_CIRCLE"
  433. },
  434. "trackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  435. "command": {
  436. "clickTrackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  437. "commandExecutorCommand": {
  438. "commands": [
  439. {
  440. "clickTrackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  441. "liveChatDialogEndpoint": {
  442. "content": {
  443. "liveChatDialogRenderer": {
  444. "trackingParams": "CCkQzS8iEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  445. "title": {
  446. "runs": [
  447. {
  448. "text": "Super Chat Goal"
  449. }
  450. ]
  451. },
  452. "dialogMessages": [
  453. {
  454. "runs": [
  455. {
  456. "text": "Join the fun by participating in the goal! "
  457. },
  458. {
  459. "text": "Learn more.\n",
  460. "navigationEndpoint": {
  461. "clickTrackingParams": "CCkQzS8iEwjm0Iz72rbKBxXT1EQBJekHNQM="
  462. }
  463. }
  464. ]
  465. },
  466. {
  467. "runs": [
  468. {
  469. "text": "How to participate",
  470. "bold": true,
  471. "textColor": 4294967295
  472. },
  473. {
  474. "text": "\n"
  475. },
  476. {
  477. "text": "1. Press \"Continue\"\n2. Purchase a Super Chat \n3. Watch the progress towards the goal\n4. Celebrate achieving it with the community!",
  478. "textColor": 4294967295
  479. }
  480. ]
  481. }
  482. ],
  483. "confirmButton": {
  484. "buttonRenderer": {
  485. "style": "STYLE_MONO_FILLED",
  486. "size": "SIZE_DEFAULT",
  487. "isDisabled": false,
  488. "text": {
  489. "simpleText": "Got it"
  490. },
  491. "trackingParams": "CCoQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  492. "accessibilityData": {
  493. "accessibilityData": {
  494. "label": "Got it"
  495. }
  496. }
  497. }
  498. }
  499. }
  500. }
  501. }
  502. },
  503. {
  504. "clickTrackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  505. "hideEngagementPanelEndpoint": {
  506. "identifier": {
  507. "surface": "ENGAGEMENT_PANEL_SURFACE_LIVE_CHAT",
  508. "tag": "creator_goal_progress_engagement_panel"
  509. }
  510. }
  511. }
  512. ]
  513. }
  514. }
  515. }
  516. },
  517. "trackingParams": "CCUQ040EIhMI58DT_ef5rhMVxMW1Cx4qBzTz"
  518. }
  519. },
  520. "content": {
  521. "sectionListRenderer": {
  522. "contents": [
  523. {
  524. "creatorGoalProgressFlowViewModel": {
  525. "creatorGoalEntityKey": "EgtieXl2SDV0MGhLYyG7BzhF",
  526. "progressFlowButton": {
  527. "buttonViewModel": {
  528. "onTap": {
  529. "innertubeCommand": {
  530. "clickTrackingParams": "CCcQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  531. "commandMetadata": {
  532. "webCommandMetadata": {
  533. "ignoreNavigation": true
  534. }
  535. },
  536. "liveChatPurchaseMessageEndpoint": {
  537. "params": "Q2lrcUp3b1lWVU14ZFdObmIwTmZjMGQzZDE5RmRYVTFhVTF4Y0ZGM0VndGllWGwyU0RWME1HaExZeEFCSUFFNEFFSUNDQUUlM0Q="
  538. }
  539. }
  540. },
  541. "style": "BUTTON_VIEW_MODEL_STYLE_MONO",
  542. "trackingParams": "CCcQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  543. "type": "BUTTON_VIEW_MODEL_TYPE_FILLED",
  544. "titleFormatted": {
  545. "content": "Continue",
  546. "styleRuns": [
  547. {
  548. "startIndex": 0,
  549. "length": 8
  550. }
  551. ]
  552. }
  553. }
  554. },
  555. "progressCountA11yLabel": "Super Chat goal progress: $0 out of $1"
  556. }
  557. }
  558. ],
  559. "trackingParams": "CCYQui8iEwjm0Iz72rbKBxXT1EQBJekHNQM="
  560. }
  561. },
  562. "identifier": {
  563. "surface": "ENGAGEMENT_PANEL_SURFACE_LIVE_CHAT",
  564. "tag": "creator_goal_progress_engagement_panel"
  565. }
  566. }
  567. },
  568. "identifier": {
  569. "surface": "ENGAGEMENT_PANEL_SURFACE_LIVE_CHAT",
  570. "tag": "creator_goal_progress_engagement_panel"
  571. },
  572. "engagementPanelPresentationConfigs": {
  573. "engagementPanelPopupPresentationConfig": {
  574. "popupType": "PANEL_POPUP_TYPE_DIALOG"
  575. }
  576. }
  577. }
  578. }
  579. },
  580. "creatorGoalEntityKey": "EgtieXl2SDV0MGhLYyG7BzhF",
  581. "shouldShowSetUpFlowOnMobile": true,
  582. "a11yLabel": "See Super Chat goal",
  583. "loggingDirectives": {
  584. "trackingParams": "CCQQ7NANIhMI58DT_ef5rhMVxMW1Cx4qBzTz",
  585. "visibility": {
  586. "types": "12"
  587. }
  588. }
  589. }
  590.  
  591.  
  592. */
  593.  
  594.  
  595. // ------
  596.  
  597.  
  598. // document.createElement4521 = document.createElement;
  599. // document.createElement = function(){
  600. // if(arguments[0]==='yt-live-chat-ticker-paid-message-item-renderer' || arguments[0]==='yt-live-chat-ticker-paid-sticker-item-renderer' || arguments[0]==='yt-live-chat-ticker-sponsor-item-renderer'){
  601. // console.log(8123, [...arguments]);
  602. // debugger;
  603. // }
  604. // // if(`${arguments[0]}`.indexOf('-')>=0) console.log(8123, [...arguments]);
  605. // return document.createElement4521(...arguments);
  606. // };
  607.  
  608. const { IntersectionObserver } = __CONTEXT__;
  609. let _x69;
  610. try {
  611. _x69 = document.createAttributeNS("http://www.w3.org/2000/svg", "nil").addEventListener;
  612. } catch (e) { }
  613. const pureAddEventListener = _x69;
  614. if (!pureAddEventListener) return console.warn("pureAddEventListener cannot be obtained.");
  615.  
  616. /** @type {globalThis.PromiseConstructor} */
  617. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  618.  
  619. // let jsonParseFix = null;
  620.  
  621. if (!IntersectionObserver) return console.warn("Your browser does not support IntersectionObserver.\nPlease upgrade to the latest version.");
  622. if (typeof WebAssembly !== 'object') return console.warn("Your browser is too old.\nPlease upgrade to the latest version."); // for passive and once
  623.  
  624. // necessity of cssText3_smooth_transform_position to be checked.
  625. const cssText3_smooth_transform_position = ENABLE_NO_SMOOTH_TRANSFORM ? `
  626.  
  627. #item-offset.style-scope.yt-live-chat-item-list-renderer > #items.style-scope.yt-live-chat-item-list-renderer {
  628. position: static !important;
  629. }
  630.  
  631. `: '';
  632.  
  633. // fallback if dummy style fn fails
  634. const cssText4_smooth_transform_forced_props = ENABLE_NO_SMOOTH_TRANSFORM ? `
  635.  
  636. /* optional */
  637. #item-offset.style-scope.yt-live-chat-item-list-renderer {
  638. height: auto !important;
  639. min-height: unset !important;
  640. }
  641.  
  642. #items.style-scope.yt-live-chat-item-list-renderer {
  643. transform: translateY(0px) !important;
  644. }
  645.  
  646. /* optional */
  647.  
  648. `: '';
  649.  
  650. const cssText5 = SET_CONTAIN_FOR_CHATROOM ? `
  651.  
  652. /* ------------------------------------------------------------------------------------------------------------- */
  653.  
  654. yt-live-chat-author-chip #chat-badges.yt-live-chat-author-chip, yt-live-chat-author-chip #chat-badges.yt-live-chat-author-chip yt-live-chat-author-badge-renderer, yt-live-chat-author-chip #chat-badges.yt-live-chat-author-chip yt-live-chat-author-badge-renderer #image, yt-live-chat-author-chip #chat-badges.yt-live-chat-author-chip yt-live-chat-author-badge-renderer #image img {
  655. contain: layout style;
  656. }
  657.  
  658. #items.style-scope.yt-live-chat-item-list-renderer {
  659. contain: layout paint style;
  660. }
  661.  
  662. #item-offset.style-scope.yt-live-chat-item-list-renderer {
  663. contain: style;
  664. }
  665.  
  666. #item-scroller.style-scope.yt-live-chat-item-list-renderer {
  667. contain: size style;
  668. }
  669.  
  670. #contents.style-scope.yt-live-chat-item-list-renderer, #chat.style-scope.yt-live-chat-renderer, img.style-scope.yt-img-shadow[width][height] {
  671. contain: size layout paint style;
  672. }
  673.  
  674. .style-scope.yt-live-chat-ticker-renderer[role="button"][aria-label], .style-scope.yt-live-chat-ticker-renderer[role="button"][aria-label] > #container {
  675. contain: layout paint style;
  676. }
  677.  
  678. yt-live-chat-text-message-renderer.style-scope.yt-live-chat-item-list-renderer, yt-live-chat-membership-item-renderer.style-scope.yt-live-chat-item-list-renderer, yt-live-chat-paid-message-renderer.style-scope.yt-live-chat-item-list-renderer, yt-live-chat-banner-manager.style-scope.yt-live-chat-item-list-renderer {
  679. contain: layout style;
  680. }
  681.  
  682. tp-yt-paper-tooltip[style*="inset"][role="tooltip"] {
  683. contain: layout paint style;
  684. }
  685.  
  686. /* ------------------------------------------------------------------------------------------------------------- */
  687.  
  688. ` : '';
  689.  
  690. const cssText6b_show_more_button = FIX_SHOW_MORE_BUTTON_LOCATION ? `
  691.  
  692. yt-live-chat-renderer[has-action-panel-renderer] #show-more.yt-live-chat-item-list-renderer{
  693. top: 4px;
  694. transition-property: top;
  695. bottom: unset;
  696. }
  697.  
  698. yt-live-chat-renderer[has-action-panel-renderer] #show-more.yt-live-chat-item-list-renderer[disabled]{
  699. top: -42px;
  700. }
  701.  
  702. `: '';
  703.  
  704. const cssText6c_input_panel_overflow = FIX_INPUT_PANEL_OVERFLOW_ISSUE ? `
  705.  
  706. #input-panel #picker-buttons yt-live-chat-icon-toggle-button-renderer#product-picker {
  707. contain: layout style;
  708. }
  709.  
  710. #chat.yt-live-chat-renderer ~ #panel-pages.yt-live-chat-renderer {
  711. overflow: visible;
  712. }
  713.  
  714. `: '';
  715.  
  716. const cssText6d_input_panel_border = FIX_INPUT_PANEL_BORDER_ISSUE ? `
  717.  
  718. html #panel-pages.yt-live-chat-renderer > #input-panel.yt-live-chat-renderer:not(:empty) {
  719. --yt-live-chat-action-panel-top-border: none;
  720. }
  721.  
  722. html #panel-pages.yt-live-chat-renderer > #input-panel.yt-live-chat-renderer.iron-selected > *:first-child {
  723. border-top: 1px solid var(--yt-live-chat-panel-pages-border-color);
  724. }
  725.  
  726. html #panel-pages.yt-live-chat-renderer {
  727. border-top: 0;
  728. border-bottom: 0;
  729. }
  730.  
  731. `: '';
  732.  
  733. const cssText7b_content_visibility_unset = FORCE_CONTENT_VISIBILITY_UNSET ? `
  734.  
  735. img,
  736. yt-img-shadow[height][width],
  737. yt-img-shadow {
  738. content-visibility: visible !important;
  739. }
  740.  
  741. ` : '';
  742.  
  743. const cssText7c_will_change_unset = FORCE_WILL_CHANGE_UNSET ? `
  744.  
  745. /* remove YouTube constant will-change */
  746. /* constant value will slow down the performance; default auto */
  747.  
  748. /* www-player.css */
  749. html .ytp-contextmenu,
  750. html .ytp-settings-menu {
  751. will-change: unset;
  752. }
  753.  
  754. /* frequently matched elements */
  755. html .fill.yt-interaction,
  756. html .stroke.yt-interaction,
  757. html .yt-spec-touch-feedback-shape__fill,
  758. html .yt-spec-touch-feedback-shape__stroke {
  759. will-change: unset;
  760. }
  761.  
  762. /* live_chat_polymer.js */
  763. /*
  764. html .toggle-button.tp-yt-paper-toggle-button,
  765. html #primaryProgress.tp-yt-paper-progress,
  766. html #secondaryProgress.tp-yt-paper-progress,
  767. html #onRadio.tp-yt-paper-radio-button,
  768. html .fill.yt-interaction,
  769. html .stroke.yt-interaction,
  770. html .yt-spec-touch-feedback-shape__fill,
  771. html .yt-spec-touch-feedback-shape__stroke {
  772. will-change: unset;
  773. }
  774. */
  775.  
  776. /* desktop_polymer_enable_wil_icons.js */
  777. /* html .fill.yt-interaction,
  778. html .stroke.yt-interaction, */
  779. html tp-yt-app-header::before,
  780. html tp-yt-iron-list,
  781. html #items.tp-yt-iron-list > *,
  782. html #onRadio.tp-yt-paper-radio-button,
  783. html .toggle-button.tp-yt-paper-toggle-button,
  784. html ytd-thumbnail-overlay-toggle-button-renderer[use-expandable-tooltip] #label.ytd-thumbnail-overlay-toggle-button-renderer,
  785. html #items.ytd-post-multi-image-renderer,
  786. html #items.ytd-horizontal-card-list-renderer,
  787. html #items.yt-horizontal-list-renderer,
  788. html #left-arrow.yt-horizontal-list-renderer,
  789. html #right-arrow.yt-horizontal-list-renderer,
  790. html #items.ytd-video-description-infocards-section-renderer,
  791. html #items.ytd-video-description-music-section-renderer,
  792. html #chips.ytd-feed-filter-chip-bar-renderer,
  793. html #chips.yt-chip-cloud-renderer,
  794. html #items.ytd-merch-shelf-renderer,
  795. html #items.ytd-product-details-image-carousel-renderer,
  796. html ytd-video-preview,
  797. html #player-container.ytd-video-preview,
  798. html #primaryProgress.tp-yt-paper-progress,
  799. html #secondaryProgress.tp-yt-paper-progress,
  800. html ytd-miniplayer[enabled] /* ,
  801. html .yt-spec-touch-feedback-shape__fill,
  802. html .yt-spec-touch-feedback-shape__stroke */ {
  803. will-change: unset;
  804. }
  805.  
  806. /* other */
  807. .ytp-videowall-still-info-content[class],
  808. .ytp-suggestion-image[class] {
  809. will-change: unset !important;
  810. }
  811.  
  812. ` : '';
  813.  
  814. const ENABLE_FONT_PRE_RENDERING = typeof HTMLElement.prototype.append === 'function' ? (ENABLE_FONT_PRE_RENDERING_PREFERRED || 0) : 0;
  815. const cssText8_fonts_pre_render = ENABLE_FONT_PRE_RENDERING ? `
  816.  
  817. elzm-fonts {
  818. visibility: collapse;
  819. position: fixed;
  820. top: -10px;
  821. left: -10px;
  822. font-size: 10pt;
  823. line-height: 100%;
  824. width: 100px;
  825. height: 100px;
  826. transform: scale(0.1);
  827. transform: scale(0.01);
  828. transform: scale(0.001);
  829. transform-origin: 0 0;
  830. contain: strict;
  831. display: block;
  832.  
  833. pointer-events: none !important;
  834. user-select: none !important;
  835. }
  836.  
  837. elzm-fonts[id]#elzm-fonts-yk75g {
  838. user-select: none !important;
  839. pointer-events: none !important;
  840. }
  841.  
  842. elzm-font {
  843. visibility: collapse;
  844. position: absolute;
  845. line-height: 100%;
  846. width: 100px;
  847. height: 100px;
  848. contain: strict;
  849. display: block;
  850.  
  851. user-select: none !important;
  852. pointer-events: none !important;
  853. }
  854.  
  855. elzm-font::before {
  856. visibility: collapse;
  857. position: absolute;
  858. line-height: 100%;
  859. width: 100px;
  860. height: 100px;
  861. contain: strict;
  862. display: block;
  863.  
  864. content: '0aZ!@#$~^&*()_-+[]{}|;:><?\\0460\\0301\\0900\\1F00\\0370\\0102\\0100\\28EB2\\28189\\26DA0\\25A9C\\249BB\\23F61\\22E8B\\21927\\21076\\2048E\\1F6F5\\FF37\\F94F\\F0B2\\9F27\\9D9A\\9BEA\\9A6B\\98EC\\9798\\9602\\949D\\9370\\926B\\913A\\8FA9\\8E39\\8CC1\\8B26\\8983\\8804\\8696\\8511\\83BC\\828D\\8115\\7F9A\\7E5B\\7D07\\7B91\\7A2C\\78D2\\776C\\7601\\74AA\\73B9\\7265\\70FE\\6FBC\\6E88\\6D64\\6C3F\\6A9C\\6957\\67FE\\66B3\\6535\\63F2\\628E\\612F\\5FE7\\5E6C\\5CEE\\5B6D\\5A33\\58BC\\575B\\5611\\54BF\\536E\\51D0\\505D\\4F22\\4AD1\\41DB\\3B95\\3572\\2F3F\\26FD\\25A1\\2477\\208D\\1D0A\\1FB\\A1\\A3\\B4\\2CB\\60\\10C\\E22\\A5\\4E08\\B0\\627\\2500\\5E\\201C\\3C\\B7\\23\\26\\3E\\D\\20\\25EE8\\1F235\\FFD7\\FA10\\F92D\\9E8B\\9C3E\\9AE5\\98EB\\971D\\944A\\92BC\\9143\\8F52\\8DC0\\8B2D\\8973\\87E2\\8655\\84B4\\82E8\\814A\\7F77\\7D57\\7BC8\\7A17\\7851\\768C\\7511\\736C\\7166\\6F58\\6D7C\\6B85\\69DD\\6855\\667E\\64D2\\62CF\\6117\\5F6C\\5D9B\\5BBC\\598B\\57B3\\5616\\543F\\528D\\50DD\\4F57\\4093\\3395\\32B5\\31C8\\3028\\2F14\\25E4\\24D1\\2105\\2227\\A8\\2D9\\2CA\\2467\\B1\\2020\\2466\\251C\\266B\\AF\\4E91\\221E\\2464\\2266\\2207\\4E32\\25B3\\2463\\2010\\2103\\3014\\25C7\\24\\25BD\\4E18\\2460\\21D2\\2015\\2193\\4E03\\7E\\25CB\\2191\\25BC\\3D\\500D\\4E01\\25\\30F6\\2605\\266A\\40\\2B\\4E16\\7C\\A9\\4E\\21\\1F1E9\\FEE3\\F0A7\\9F3D\\9DFA\\9C3B\\9A5F\\98C8\\972A\\95B9\\94E7\\9410\\92B7\\914C\\8FE2\\8E2D\\8CAF\\8B5E\\8A02\\8869\\86E4\\8532\\83B4\\82A9\\814D\\7FFA\\7ED7\\7DC4\\7CCC\\7BC3\\7ACA\\797C\\783E\\770F\\760A\\74EF\\73E7\\72DD\\719C\\7005\\6ED8\\6DC3\\6CB2\\6A01\\68E1\\6792\\663A\\64F8\\63BC\\623B\\60FA\\5FD1\\5EA3\\5D32\\5BF5\\5AB2\\5981\\5831\\570A\\5605\\5519\\53FB\\52A2\\5110\\4FE3\\4EB8\\3127\\279C\\2650\\254B\\23E9\\207B\\1D34\\2AE\\176\\221A\\161\\200B\\300C\\4E4C\\1F921\\FF78\\FA0A\\F78A\\9EB9\\9D34\\9BD3\\9A6F\\9912\\97C6\\964E\\950C\\93E4\\92E5\\91F0\\90BB\\8F68\\8E18\\8B6C\\89F6\\889B\\874C\\8602\\84B1\\8378\\826E\\8113\\7FB1\\7EAF\\7D89\\7C20\\7AFB\\7988\\7840\\7705\\75CC\\749A\\73B3\\727F\\7113\\6FE8\\6ED6\\6DD3\\6CDA\\6BBB\\6A31\\6900\\67D9\\66A7\\655D\\6427\\630D\\61C6\\60AC\\5F78\\5E34\\5CE0\\5B80\\5A51\\590B\\57A1\\566F\\5551\\543D\\52DB\\518F\\5032\\3A17\\305C\\2749\\264A\\2567\\2476\\2139\\1EC0\\11AF\\2C8\\1AF\\E17\\2190\\2022\\2502\\2312\\2025\\50';
  865.  
  866. user-select: none !important;
  867. pointer-events: none !important;
  868. }
  869.  
  870. `: '';
  871.  
  872. const cssText9_no_backdrop_filter_when_menu_shown = NO_BACKDROP_FILTER_WHEN_MENU_SHOWN ? `
  873. tp-yt-iron-dropdown.yt-live-chat-app ytd-menu-popup-renderer {
  874. -webkit-backdrop-filter: none;
  875. backdrop-filter: none;
  876. }
  877. `: '';
  878.  
  879. const cssText10_show_more_blinker = ENABLE_SHOW_MORE_BLINKER ? `
  880.  
  881. @keyframes blinker-miuzp {
  882. 0%, 60%, 100% {
  883. opacity: 1;
  884. }
  885. 30% {
  886. opacity: 0.6;
  887. }
  888. }
  889.  
  890. yt-icon-button#show-more.has-new-messages-miuzp {
  891. animation: blinker-miuzp 1.74s linear infinite;
  892. }
  893.  
  894. `: '';
  895.  
  896. const cssText11_entire_message_clickable = FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK ? `
  897.  
  898. yt-live-chat-paid-message-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  899. pointer-events: none !important;
  900. }
  901.  
  902. yt-live-chat-membership-item-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  903. pointer-events: none !important;
  904. }
  905.  
  906. yt-live-chat-paid-sticker-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  907. pointer-events: none !important;
  908. }
  909.  
  910. yt-live-chat-text-message-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  911. pointer-events: none !important; /* TO_BE_REVIEWED */
  912. }
  913.  
  914. yt-live-chat-auto-mod-message-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  915. pointer-events: none !important;
  916. }
  917.  
  918. `: '';
  919.  
  920. const cssText12_nowrap_tooltip = MAX_TOOLTIP_NO_WRAP_WIDTH && typeof MAX_TOOLTIP_NO_WRAP_WIDTH === 'string' ? `
  921.  
  922.  
  923. tp-yt-paper-tooltip[role="tooltip"] {
  924. box-sizing: content-box !important;
  925. margin: 0px !important;
  926. padding: 0px !important;
  927. contain: none !important;
  928. }
  929.  
  930. tp-yt-paper-tooltip[role="tooltip"] #tooltip[style-target="tooltip"] {
  931. box-sizing: content-box !important;
  932. display: inline-block;
  933. contain: none !important;
  934. }
  935.  
  936.  
  937. tp-yt-paper-tooltip[role="tooltip"] #tooltip[style-target="tooltip"]{
  938. max-width: ${MAX_TOOLTIP_NO_WRAP_WIDTH};
  939. width: max-content;
  940. text-overflow: ellipsis;
  941. overflow: hidden;
  942. white-space: nowrap;
  943. }
  944.  
  945.  
  946. `: '';
  947.  
  948.  
  949. const cssText13_no_text_select_when_menu_visible = `
  950. [menu-visible] {
  951. --sfc47-text-select: none;
  952. }
  953. [menu-visible] #header[id][class],
  954. [menu-visible] #content[id][class],
  955. [menu-visible] #header[id][class] *,
  956. [menu-visible] #content[id][class] * {
  957. user-select: var(--sfc47-text-select) !important;
  958. }
  959. [menu-visible] #menu {
  960. --sfc47-text-select: inherit;
  961. }
  962. `;
  963.  
  964. const cssText14_NO_FILTER_DROPDOWN_BORDER = NO_FILTER_DROPDOWN_BORDER ? `
  965. yt-live-chat-header-renderer.yt-live-chat-renderer #label.yt-dropdown-menu::before {
  966. border:0;
  967. }
  968. ` : '';
  969.  
  970. const cssText15_FIX_ANIMATION_TICKER_TEXT_POSITION = FIX_ANIMATION_TICKER_TEXT_POSITION ? `
  971. .style-scope.yt-live-chat-ticker-renderer #animation-container[id][class] {
  972. position: relative;
  973. display: grid;
  974. grid-auto-columns: 1fr;
  975. grid-auto-rows: 1fr;
  976. grid-template-columns: repeat(1, 1fr);
  977. gap: 7px;
  978. padding-bottom: 0;
  979. margin-bottom: 0;
  980. padding-top: 0;
  981. align-self: flex-start;
  982. flex-wrap: nowrap;
  983. margin-top: 1px;
  984. }
  985.  
  986. .style-scope.yt-live-chat-ticker-renderer #animation-container > [id][class] {
  987. margin-top: 0px;
  988. margin-bottom: 0px;
  989. flex-direction: row;
  990. flex-wrap: nowrap;
  991. align-items: center;
  992. justify-content: flex-start;
  993. }
  994.  
  995. .style-scope.yt-live-chat-ticker-renderer #animation-container > [id][class]:first-child::after {
  996. content: '補';
  997. visibility: collapse;
  998. display: inline-block;
  999. position: relative;
  1000. width: 0;
  1001. line-height: 22px;
  1002. }
  1003.  
  1004. ` : '';
  1005.  
  1006. const cssText16_FIX_AUTHOR_CHIP_BADGE_POSITION = FIX_AUTHOR_CHIP_BADGE_POSITION ? `
  1007. #card #author-name-chip > yt-live-chat-author-chip[single-line] {
  1008. flex-wrap: nowrap;
  1009. white-space: nowrap;
  1010. display: inline-flex;
  1011. flex-direction: row;
  1012. text-wrap: nowrap;
  1013. flex-shrink: 0;
  1014. align-items: center;
  1015. }
  1016.  
  1017. #card #author-name-chip {
  1018. display: inline-flex;
  1019. flex-direction: row;
  1020. align-items: flex-start;
  1021. }
  1022. `: '';
  1023.  
  1024.  
  1025. // Example: https://www.youtube.com/watch?v=Xfytz-igsuc
  1026. const cssText17_FIX_overwidth_banner_message = `
  1027. yt-live-chat-banner-manager#live-chat-banner.style-scope.yt-live-chat-item-list-renderer {
  1028. max-width: 100%;
  1029. box-sizing: border-box;
  1030. }
  1031. `;
  1032.  
  1033.  
  1034. const cssText18_REACTION_ANIMATION_PANEL_CSS_FIX = REACTION_ANIMATION_PANEL_CSS_FIX ? `
  1035. #reaction-control-panel-overlay[class] {
  1036. contain: strict;
  1037. margin: 0;
  1038. padding: 0;
  1039. border: 0;
  1040. box-sizing: border-box;
  1041. will-change: initial;
  1042. }
  1043. #reaction-control-panel-overlay[class] *[class] {
  1044. will-change: initial;
  1045. }
  1046. `: '';
  1047.  
  1048. const cssText19_FOR_ADVANCED_TICKING = USE_ADVANCED_TICKING ? `
  1049. ticker-bg-overlay {
  1050. display: block;
  1051. position: absolute;
  1052. z-index: -1;
  1053. box-sizing: border-box;
  1054. border: 0;
  1055. padding: 0;
  1056. margin: 0;
  1057. width: 200%;
  1058. top: 0;
  1059. bottom: 0;
  1060. left: clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%);
  1061. contain: strict;
  1062. }
  1063. ticker-bg-overlay-end2 {
  1064.  
  1065. all:unset;
  1066. position: fixed;
  1067. display: block;
  1068. margin-left: -0.5px;
  1069. top: 8px;
  1070. left: clamp(-250px, calc( 250px * ( ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) - 1 ) ), 2px);
  1071.  
  1072. width: 1px;
  1073. height: 1px;
  1074. opacity: 0;
  1075. pointer-events: none;
  1076. box-sizing: border-box;
  1077. border: 0;
  1078. padding: 0;
  1079. margin: 0;
  1080. contain: strict;
  1081. z-index: -1;
  1082. visibility: collapse;
  1083.  
  1084. }
  1085.  
  1086.  
  1087. /* .r6-closing-ticker is provided in ADVANCED_TICKING */
  1088. /* so .r6-width-adjustable is only available for ADVANCED_TICKING too */
  1089.  
  1090. .r6-width-adjustable ~ .r6-width-adjustable {
  1091. --r6-min-width: max-content;
  1092. }
  1093. .r6-closing-ticker[class] {
  1094. --r6-min-width: 0px;
  1095. }
  1096. .r6-width-adjustable {
  1097. min-width: var(--r6-min-width, 0px);
  1098. }
  1099.  
  1100. ` : '';
  1101. // const cssText19_FOR_ADVANCED_TICKING = `
  1102. // ticker-bg-overlay {
  1103. // display: block;
  1104. // position: absolute;
  1105. // z-index: -1;
  1106. // box-sizing: border-box;
  1107. // border: 0;
  1108. // padding: 0;
  1109. // margin: 0;
  1110. // width: 200%;
  1111. // top: 0;
  1112. // bottom: 0;
  1113. // left: clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%);
  1114. // contain: strict;
  1115. // }
  1116. // /*
  1117. // ticker-bg-overlay-end {
  1118. // position: absolute;
  1119. // right: 0px;
  1120. // top: 50%;
  1121. // display: block;
  1122. // width: 1px;
  1123. // height: 1px;
  1124. // opacity: 0;
  1125. // pointer-events: none;
  1126. // box-sizing: border-box;
  1127. // border: 0;
  1128. // padding: 0;
  1129. // margin: 0;
  1130. // contain: strict;
  1131. // }
  1132. // */
  1133.  
  1134. // ticker-bg-overlay-end2 {
  1135.  
  1136. // all:unset;
  1137. // position: fixed;
  1138. // display: block;
  1139. // margin-left: -0.5px;
  1140. // top: 8px;
  1141. // left: clamp(-250px, calc( 250px * ( ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) - 1 ) ), 2px);
  1142.  
  1143. // width: 1px;
  1144. // height: 1px;
  1145. // opacity: 0;
  1146. // pointer-events: none;
  1147. // box-sizing: border-box;
  1148. // border: 0;
  1149. // padding: 0;
  1150. // margin: 0;
  1151. // contain: strict;
  1152. // z-index: -1;
  1153. // visibility: collapse;
  1154.  
  1155. // }
  1156.  
  1157. // /* USE_ADVANCED_TICKING */
  1158.  
  1159. // /*
  1160.  
  1161. // .ticker-no-transition-time, .ticker-no-transition-time [id] {
  1162. // transition-duration: 0s !important;
  1163. // }
  1164.  
  1165. // [r6-advanced-ticking] .style-scope.yt-live-chat-ticker-renderer ~ .style-scope.yt-live-chat-ticker-renderer:not(.r6-closing-ticker) {
  1166. // transition-duration: 0s !important;
  1167. // }
  1168.  
  1169. // */
  1170.  
  1171. // .r6-width-adjustable ~ .r6-width-adjustable {
  1172. // --r6-min-width: max-content;
  1173. // }
  1174.  
  1175. // .r6-closing-ticker[class] {
  1176. // --r6-min-width: 0px;
  1177. // }
  1178.  
  1179. // .r6-width-adjustable {
  1180. // min-width: var(--r6-min-width, 0px);
  1181. // }
  1182.  
  1183.  
  1184. // /*
  1185.  
  1186.  
  1187. // .r6-width-adjustable {
  1188. // transition-duration: var(--r6-transition-duration, 0s) !important;
  1189. // }
  1190.  
  1191. // .r6-width-adjustable-first {
  1192. // --r6-transition-duration: 0.2s;
  1193. // }
  1194.  
  1195. // .r6-width-adjustable ~ .r6-width-adjustable-first {
  1196. // --r6-transition-duration: 0s;
  1197. // }
  1198.  
  1199. // .r6-closing-ticker {
  1200. // --r6-transition-duration: 0.2s;
  1201. // }
  1202. // */
  1203.  
  1204. // /*
  1205.  
  1206.  
  1207. // ey.style.position = 'absolute';
  1208. // ey.style.right = '0px';
  1209. // ey.style.top = '50%';
  1210. // ey.style.display='block';
  1211. // ey.style.width='1px';
  1212. // ey.style.height='1px';
  1213. // ey.style.opacity = '0';
  1214.  
  1215. // em.style.display = 'block';
  1216. // em.style.position = 'absolute';
  1217. // em.style.boxSizing = 'border-box';
  1218. // em.style.width = '200%';
  1219. // em.style.top = '0';
  1220. // em.style.bottom = '0';
  1221. // // em.style.height = '100%';
  1222.  
  1223.  
  1224. // // em.style.left = '-50%';
  1225. // // em.style.left = "clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%)";
  1226.  
  1227. // */
  1228.  
  1229. // `;
  1230.  
  1231. const addCss = () => `
  1232.  
  1233. @property --ticker-rtime {
  1234. syntax: "<percentage>";
  1235. inherits: false;
  1236. initial-value: 0%;
  1237. }
  1238.  
  1239. /*
  1240. .run-ticker {
  1241. background:linear-gradient(90deg, var(--ticker-c1),var(--ticker-c1) var(--ticker-rtime),var(--ticker-c2) var(--ticker-rtime),var(--ticker-c2));
  1242. }
  1243.  
  1244. .run-ticker-test {
  1245. background: #00000001;
  1246. }
  1247.  
  1248. .run-ticker-forced,
  1249. yt-live-chat-ticker-renderer #items > * > #container.run-ticker-forced,
  1250. yt-live-chat-ticker-renderer[class] #items[class] > *[class] > #container.run-ticker-forced[class]
  1251. {
  1252. background:linear-gradient(90deg, var(--ticker-c1),var(--ticker-c1) var(--ticker-rtime),var(--ticker-c2) var(--ticker-rtime),var(--ticker-c2)) !important;
  1253. }
  1254. */
  1255.  
  1256. .run-ticker {
  1257. --ticker-bg:linear-gradient(90deg, var(--ticker-c1),var(--ticker-c1) var(--ticker-rtime),var(--ticker-c2) var(--ticker-rtime),var(--ticker-c2));
  1258. }
  1259.  
  1260. .run-ticker,
  1261. yt-live-chat-ticker-renderer #items > * > #container.run-ticker,
  1262. yt-live-chat-ticker-renderer[class] #items[class] > *[class] > #container.run-ticker[class]
  1263. {
  1264. background: var(--ticker-bg) !important;
  1265. }
  1266.  
  1267. yt-live-chat-ticker-dummy777-item-renderer {
  1268. background: #00000001;
  1269. }
  1270.  
  1271. yt-live-chat-ticker-dummy777-item-renderer[dummy777] {
  1272. position: fixed !important;
  1273. top: -1000px !important;
  1274. left: -1000px !important;
  1275. font-size: 1px !important;
  1276. color: transparent !important;
  1277. pointer-events: none !important;
  1278. z-index: -1 !important;
  1279. contain: strict !important;
  1280. box-sizing: border-box !important;
  1281. pointer-events: none !important;
  1282. user-select: none !important;
  1283. max-width: 1px !important;
  1284. max-height: 1px !important;
  1285. overflow: hidden !important;
  1286. visibility: collapse !important;
  1287. display: none !important;
  1288. }
  1289.  
  1290. yt-live-chat-ticker-dummy777-item-renderer #container {
  1291. background: inherit;
  1292. }
  1293.  
  1294.  
  1295. ${cssText8_fonts_pre_render}
  1296.  
  1297. ${cssText9_no_backdrop_filter_when_menu_shown}
  1298.  
  1299. @supports (contain: layout paint style) {
  1300.  
  1301. ${cssText5}
  1302.  
  1303. }
  1304.  
  1305. @supports (color: var(--general)) {
  1306.  
  1307. html {
  1308. --yt-live-chat-item-list-renderer-padding: 0px 0px;
  1309. }
  1310.  
  1311. ${cssText3_smooth_transform_position}
  1312.  
  1313. ${cssText7c_will_change_unset}
  1314.  
  1315. ${cssText7b_content_visibility_unset}
  1316.  
  1317. yt-live-chat-item-list-renderer:not([allow-scroll]) #item-scroller.yt-live-chat-item-list-renderer {
  1318. overflow-y: scroll;
  1319. padding-right: 0;
  1320. }
  1321.  
  1322. ${cssText4_smooth_transform_forced_props}
  1323.  
  1324. yt-icon[icon="down_arrow"] > *, yt-icon-button#show-more > * {
  1325. pointer-events: none !important;
  1326. }
  1327.  
  1328. #continuations, #continuations * {
  1329. contain: strict;
  1330. position: fixed;
  1331. top: 2px;
  1332. height: 1px;
  1333. width: 2px;
  1334. height: 1px;
  1335. visibility: collapse;
  1336. }
  1337.  
  1338. ${cssText6b_show_more_button}
  1339.  
  1340. ${cssText6d_input_panel_border}
  1341.  
  1342. ${cssText6c_input_panel_overflow}
  1343.  
  1344. }
  1345.  
  1346.  
  1347. @supports (overflow-anchor: auto) {
  1348.  
  1349. .no-anchor * {
  1350. overflow-anchor: none;
  1351. }
  1352. .no-anchor > item-anchor {
  1353. overflow-anchor: auto;
  1354. }
  1355.  
  1356. item-anchor {
  1357.  
  1358. height:1px;
  1359. width: 100%;
  1360. transform: scaleY(0.00001);
  1361. transform-origin:0 0;
  1362. contain: strict;
  1363. opacity:0;
  1364. display:flex;
  1365. position:relative;
  1366. flex-shrink:0;
  1367. flex-grow:0;
  1368. margin-bottom:0;
  1369. overflow:hidden;
  1370. box-sizing:border-box;
  1371. visibility: visible;
  1372. content-visibility: visible;
  1373. contain-intrinsic-size: auto 1px;
  1374. pointer-events:none !important;
  1375.  
  1376. }
  1377.  
  1378. #item-scroller.style-scope.yt-live-chat-item-list-renderer[class] {
  1379. overflow-anchor: initial !important; /* whenever ENABLE_OVERFLOW_ANCHOR or not */
  1380. }
  1381.  
  1382. html item-anchor {
  1383.  
  1384. height: 1px;
  1385. width: 1px;
  1386. top: auto;
  1387. left: auto;
  1388. right: auto;
  1389. bottom: auto;
  1390. transform: translateY(-1px);
  1391. position: absolute;
  1392. z-index: -1;
  1393.  
  1394. }
  1395.  
  1396. }
  1397.  
  1398. @supports (color: var(--pre-rendering)) {
  1399.  
  1400. @keyframes dontRenderAnimation {
  1401. 0% {
  1402. background-position-x: 3px;
  1403. }
  1404. 100% {
  1405. background-position-x: 4px;
  1406. }
  1407. }
  1408.  
  1409. .dont-render[class] {
  1410. /* visibility: collapse !important; */
  1411. /* visibility: collapse will make innerText become "" which conflicts with BetterStreamChat; see https://greasyfork.org/scripts/469878/discussions/197267 */
  1412.  
  1413. transform: scale(0.01) !important;
  1414. transform: scale(0.00001) !important;
  1415. transform: scale(0.0000001) !important;
  1416. transform-origin: 0 0 !important;
  1417. z-index: -1 !important;
  1418. contain: strict !important;
  1419. box-sizing: border-box !important;
  1420.  
  1421. height: 1px !important;
  1422. height: 0.1px !important;
  1423. height: 0.01px !important;
  1424. height: 0.0001px !important;
  1425. height: 0.000001px !important;
  1426.  
  1427. animation: dontRenderAnimation 1ms linear 80ms 1 normal forwards !important;
  1428.  
  1429. pointer-events: none !important;
  1430. user-select: none !important;
  1431.  
  1432. }
  1433.  
  1434. #sk35z {
  1435. display: block !important;
  1436.  
  1437. visibility: collapse !important;
  1438.  
  1439. transform: scale(0.01) !important;
  1440. transform: scale(0.00001) !important;
  1441. transform: scale(0.0000001) !important;
  1442. transform-origin: 0 0 !important;
  1443. z-index: -1 !important;
  1444. contain: strict !important;
  1445. box-sizing: border-box !important;
  1446.  
  1447. height: 1px !important;
  1448. height: 0.1px !important;
  1449. height: 0.01px !important;
  1450. height: 0.0001px !important;
  1451. height: 0.000001px !important;
  1452.  
  1453. position: absolute !important;
  1454. top: -1000px !important;
  1455. left: -1000px !important;
  1456.  
  1457. }
  1458.  
  1459. }
  1460.  
  1461. [rNgzQ] {
  1462. opacity: 0 !important;
  1463. pointer-events: none !important;
  1464. }
  1465.  
  1466.  
  1467. ${cssText10_show_more_blinker}
  1468.  
  1469. ${cssText11_entire_message_clickable}
  1470.  
  1471. ${cssText12_nowrap_tooltip}
  1472.  
  1473. ${cssText13_no_text_select_when_menu_visible}
  1474.  
  1475. ${cssText14_NO_FILTER_DROPDOWN_BORDER}
  1476.  
  1477. ${cssText15_FIX_ANIMATION_TICKER_TEXT_POSITION}
  1478.  
  1479. ${cssText16_FIX_AUTHOR_CHIP_BADGE_POSITION}
  1480.  
  1481. ${cssText17_FIX_overwidth_banner_message}
  1482.  
  1483. ${cssText18_REACTION_ANIMATION_PANEL_CSS_FIX}
  1484.  
  1485. ${cssText19_FOR_ADVANCED_TICKING}
  1486.  
  1487. `;
  1488.  
  1489.  
  1490. const konsole = {
  1491. nil: Symbol(),
  1492. logs: [],
  1493. style: '',
  1494. log(...args) {
  1495. konsole.logs.push({
  1496. type: 'log',
  1497. msg: [konsole.tag || konsole.nil, ...args, konsole.style || konsole.nil].filter(e => e !== konsole.nil)
  1498. });
  1499. },
  1500. setTag(tag) {
  1501. konsole.tag = tag;
  1502. },
  1503. setStyle(style) {
  1504. konsole.style = style;
  1505. },
  1506. groupCollapsed(...args) {
  1507.  
  1508. konsole.logs.push({
  1509. type: 'groupCollapsed',
  1510. msg: [...args].filter(e => e !== konsole.nil)
  1511. });
  1512. },
  1513. groupEnd() {
  1514.  
  1515. konsole.logs.push({
  1516. type: 'groupEnd'
  1517. })
  1518. },
  1519. print() {
  1520. const copy = konsole.logs.slice(0);
  1521. konsole.logs.length = 0;
  1522. for (const { type, msg } of copy) {
  1523. if (type === 'log') {
  1524. console.log(...msg)
  1525. } else if (type === 'groupCollapsed') {
  1526.  
  1527. console.groupCollapsed(...msg)
  1528. } else if (type === 'groupEnd') {
  1529. console.groupEnd();
  1530. }
  1531.  
  1532. }
  1533.  
  1534. }
  1535. };
  1536.  
  1537. /*
  1538. konsole.groupCollapsedX = (text1, text2) => {
  1539.  
  1540. if(!text2){
  1541.  
  1542. konsole.groupCollapsed(`%c${text1}`,
  1543. "background-color: #010502; color: #6acafe; font-weight: 700; padding: 2px;"
  1544. );
  1545. }else{
  1546.  
  1547. konsole.groupCollapsed(`%c${text1}%c${text2}`,
  1548. "background-color: #010502; color: #6acafe; font-weight: 700; padding: 2px;",
  1549. "background-color: #010502; color: #6ad9fe; font-weight: 300; padding: 2px;"
  1550. );
  1551. }
  1552. }
  1553.  
  1554. konsole.groupCollapsedX('YouTube Super Fast Chat');
  1555.  
  1556. setTimeout(()=>{
  1557.  
  1558. konsole.setTag('[[Fonts Pre-Rendering]]');
  1559. konsole.log(123);
  1560. konsole.log('wsd',332, 'ssa');
  1561. konsole.setTag('');
  1562. }, 100);
  1563.  
  1564. setTimeout(()=>{
  1565.  
  1566. konsole.setTag('[[Fonts Pre-Rendering 2]]');
  1567. konsole.log(123);
  1568. konsole.log('wsd',332, 'ssa');
  1569. konsole.setTag('');
  1570. }, 300);
  1571.  
  1572. setTimeout(()=>{
  1573.  
  1574. konsole.groupEnd();
  1575. konsole.print();
  1576. }, 1000);
  1577.  
  1578. */
  1579.  
  1580. const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : (this instanceof Window ? this : window);
  1581.  
  1582. // Create a unique key for the script and check if it is already running
  1583. const hkey_script = 'mchbwnoasqph';
  1584. if (win[hkey_script]) throw new Error('Duplicated Userscript Calling'); // avoid duplicated scripting
  1585. win[hkey_script] = true;
  1586.  
  1587. let unexpectedErr = "";
  1588.  
  1589. if (!!ATTEMPT_ANIMATED_TICKER_BACKGROUND) {
  1590.  
  1591. let te4 = setTimeout(() => { }); // dummy; skip timerId only;
  1592. if (te4 < 3) {
  1593. setTimeout(() => { });
  1594. setTimeout(() => { });
  1595. }
  1596.  
  1597. }
  1598.  
  1599. const firstKey = (obj) => {
  1600. for (const key in obj) {
  1601. if (obj.hasOwnProperty(key)) return key;
  1602. }
  1603. return null;
  1604. }
  1605.  
  1606. const firstObjectKey = (obj) => {
  1607. for (const key in obj) {
  1608. if (obj.hasOwnProperty(key) && typeof obj[key] === 'object') return key;
  1609. }
  1610. return null;
  1611. }
  1612.  
  1613. /**
  1614. * Takes in a __SORTED__ array and inserts the provided value into
  1615. * the correct, sorted, position.
  1616. * > https://github.com/bhowell2/binary-insert-js/
  1617. * @param array the sorted array where the provided value needs to be inserted (in order)
  1618. * @param insertValue value to be added to the array
  1619. * @param comparator function that helps determine where to insert the value (
  1620. */
  1621. function binaryInsert(array, insertValue, comparator) {
  1622. let left = 0;
  1623. let right = array.length;
  1624.  
  1625. let z;
  1626. // Directly return if array is empty or the insertValue should be at the end
  1627. if (right === 0 || (z = comparator(array[right - 1], insertValue)) <= 0) {
  1628. array.push(insertValue);
  1629. return array;
  1630. }
  1631.  
  1632. // Check if the insertValue should be at the beginning
  1633. if ((right === 1 ? z : comparator(array[0], insertValue)) >= 0) {
  1634. array.unshift(insertValue);
  1635. return array;
  1636. }
  1637. ++left; --right;
  1638.  
  1639. // Main binary search loop to find the insertion position
  1640. while (left < right) {
  1641. const mid = Math.floor((right + left) / 2);
  1642. const compared = comparator(array[mid], insertValue);
  1643. if (compared < 0) {
  1644. left = mid + 1;
  1645. } else if (compared > 0) {
  1646. right = mid;
  1647. } else {
  1648. // If equal, insert at the mid position
  1649. left = right = mid;
  1650. break;
  1651. }
  1652. }
  1653.  
  1654. // Insertion is always at the right position due to the nature of the binary search
  1655. array.splice(right, 0, insertValue);
  1656. return array;
  1657. }
  1658.  
  1659.  
  1660.  
  1661.  
  1662. class LimitedSizeSet extends Set {
  1663. constructor(n) {
  1664. super();
  1665. this.limit = n;
  1666. }
  1667.  
  1668. add(key) {
  1669. if (!super.has(key)) {
  1670. super.add(key);
  1671. let n = super.size - this.limit;
  1672. if (n > 0) {
  1673. const iterator = super.values();
  1674. do {
  1675. const firstKey = iterator.next().value; // Get the first (oldest) key
  1676. super.delete(firstKey); // Delete the oldest key
  1677. } while (--n > 0)
  1678. }
  1679. }
  1680. }
  1681.  
  1682. removeAdd(key) {
  1683. super.delete(key);
  1684. this.add(key);
  1685. }
  1686.  
  1687. }
  1688.  
  1689.  
  1690. class LimitedSizeMap extends Map {
  1691. constructor(n) {
  1692. super();
  1693. this.limit = n;
  1694. }
  1695.  
  1696. set(key, val) {
  1697. if (!super.has(key)) {
  1698. super.set(key, val);
  1699. let n = super.size - this.limit;
  1700. if (n > 0) {
  1701. const iterator = super.keys();
  1702. do {
  1703. const firstKey = iterator.next().value; // Get the first (oldest) key
  1704. super.delete(firstKey); // Delete the oldest key
  1705. } while (--n > 0)
  1706. }
  1707. }
  1708. }
  1709.  
  1710. removeSet(key, val) {
  1711. super.delete(key);
  1712. this.set(key, val);
  1713. }
  1714.  
  1715. }
  1716.  
  1717. // function removeElementFromArray(arr, index) {
  1718. // if (index >= 0 && index < arr.length) {
  1719. // arr.splice(index, 1);
  1720. // }
  1721. // }
  1722.  
  1723. // function getRandomInt(a, b) {
  1724. // // Ensure that 'a' and 'b' are integers
  1725. // a = Math.ceil(a);
  1726. // b = Math.floor(b);
  1727.  
  1728. // // Generate a random integer in the range [a, b]
  1729. // return Math.floor(Math.random() * (b - a + 1)) + a;
  1730. // }
  1731.  
  1732. function deepCopy(obj, skipKeys) {
  1733. skipKeys = skipKeys || [];
  1734. if (!obj || typeof obj !== 'object') return obj;
  1735. if (Array.isArray(obj)) {
  1736. return obj.map(item => deepCopy(item, skipKeys));
  1737. }
  1738. const copy = {};
  1739. for (let key in obj) {
  1740. if (!skipKeys.includes(key)) {
  1741. copy[key] = deepCopy(obj[key], skipKeys);
  1742. }
  1743. }
  1744. return copy;
  1745. }
  1746.  
  1747. class Mutex {
  1748.  
  1749. constructor() {
  1750. this.p = Promise.resolve()
  1751. }
  1752.  
  1753. /**
  1754. * @param {(lockResolve: () => void)} f
  1755. */
  1756. lockWith(f) {
  1757. this.p = this.p.then(() => new Promise(f).catch(console.warn))
  1758. }
  1759.  
  1760. }
  1761.  
  1762. const PromiseExternal = ((resolve_, reject_) => {
  1763. const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
  1764. return class PromiseExternal extends Promise {
  1765. constructor(cb = h) {
  1766. super(cb);
  1767. if (cb === h) {
  1768. /** @type {(value: any) => void} */
  1769. this.resolve = resolve_;
  1770. /** @type {(reason?: any) => void} */
  1771. this.reject = reject_;
  1772. }
  1773. }
  1774. };
  1775. })();
  1776.  
  1777.  
  1778. const createPipeline = () => {
  1779. let pipelineMutex = Promise.resolve();
  1780. const pipelineExecution = fn => {
  1781. return new Promise((resolve, reject) => {
  1782. pipelineMutex = pipelineMutex.then(async () => {
  1783. let res;
  1784. try {
  1785. res = await fn();
  1786. } catch (e) {
  1787. console.log('error_F1', e);
  1788. reject(e);
  1789. }
  1790. resolve(res);
  1791. }).catch(console.warn);
  1792. });
  1793. };
  1794. return pipelineExecution;
  1795. };
  1796.  
  1797. const tickerPE = createPipeline();
  1798.  
  1799. /** @type {typeof PromiseExternal.prototype | null} */
  1800. let relayPromise = null;
  1801.  
  1802.  
  1803. /** @type {typeof PromiseExternal.prototype | null} */
  1804. let onPlayStateChangePromise = null;
  1805.  
  1806.  
  1807. const reuseId = `${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
  1808.  
  1809. const reuseStore = new Map();
  1810.  
  1811. const customCreateComponent = (component, data, bool)=>{
  1812.  
  1813. const componentTag = typeof component === 'string' ? component : typeof (component||0).component === 'string' ? (component||0).component : '';
  1814. if(componentTag){
  1815.  
  1816. if(REUSE_TICKER && data.id && data.fullDurationSec){
  1817. // bool (param c) is true by default; just force it to reuse no matter true or false
  1818.  
  1819. if (!bool) {
  1820. // show a warning if it is false.
  1821. console.warn('[yt-chat] REUSE_TICKER: reuse bool is false');
  1822. }
  1823.  
  1824. const record = reuseStore.get(`<${componentTag}>${data.id}:${data.fullDurationSec}`);
  1825. const cnt = kRef(record);
  1826.  
  1827. if(cnt && cnt.isAttached === false){
  1828.  
  1829. const hostElement = cnt.hostElement;
  1830.  
  1831. if(hostElement instanceof HTMLElement && hostElement.isConnected === false && hostElement.parentNode === null && hostElement.getAttribute('__reuseid__')===reuseId ){
  1832. // console.log(952, cnt.hostElement.parentNode)
  1833. // debugger;
  1834. if (hostElement.hasAttribute('__nogc__')) {
  1835.  
  1836. Promise.resolve(hostElement).then((hostElement) => {
  1837. // microtask to provide some time for DOM attachment.
  1838. hostElement.isConnected && hostElement.removeAttribute('__nogc__');
  1839. });
  1840.  
  1841. }
  1842. return hostElement;
  1843.  
  1844.  
  1845. }
  1846.  
  1847. }
  1848.  
  1849. }
  1850.  
  1851. }
  1852. DEBUG_customCreateComponent && console.log(component, data, bool);
  1853. /*
  1854.  
  1855. const cntData = this.data;
  1856. reuseStore.set(`${cntData.id}:${cntData.fullDurationSec}`, mWeakRef(this));
  1857. */
  1858.  
  1859. }
  1860.  
  1861. const valAssign = (elm, attr, val) => {
  1862. if (typeof val === 'number') val = val.toFixed(3);
  1863. if (!(Math.abs(elm.style.getPropertyValue(attr) - val) < 1e-5)) {
  1864. elm.style.setProperty(attr, val);
  1865. return true;
  1866. }
  1867. return false;
  1868. };
  1869.  
  1870. let playEventsStack = Promise.resolve();
  1871.  
  1872.  
  1873. let playerProgressChangedArg1 = null;
  1874. let playerProgressChangedArg2 = null;
  1875. let playerProgressChangedArg3 = null;
  1876.  
  1877. let dntElementWeak = null;
  1878.  
  1879.  
  1880. let timestampUnderLiveMode = false;
  1881.  
  1882. const updateTickerCurrentTime = () => {
  1883.  
  1884. if(resistanceUpdateDebugMode){
  1885. console.log('updateTickerCurrentTime')
  1886.  
  1887. if(!dntElementWeak || !kRef(dntElementWeak)) dntElementWeak = mWeakRef(document.querySelector('yt-live-chat-ticker-renderer'));
  1888. timestampUnderLiveMode = true;
  1889. }
  1890.  
  1891. const dntElement = kRef(dntElementWeak);
  1892. const v = timestampUnderLiveMode ? (Date.now() / 1000 - timeOriginDT / 1000) : playerProgressChangedArg1;
  1893. if (dntElement instanceof HTMLElement && v >= 0) {
  1894. valAssign(dntElement, '--ticker-current-time', v);
  1895. }
  1896. }
  1897.  
  1898. // ================== FOR USE_ADVANCED_TICKING ================
  1899.  
  1900. const timeOriginDT = +new Date(performance.timeOrigin);
  1901. let startResistanceUpdaterStarted = false;
  1902.  
  1903. const RESISTANCE_UPDATE_OPT = 3;
  1904. let resistanceUpdateLast = 0;
  1905. let resistanceUpdateBusy = false;
  1906. let resistanceUpdateRetry = false;
  1907. const resistanceUpdateDebugMode = false;
  1908. const allBackgroundOverLays = document.getElementsByTagName('ticker-bg-overlay');
  1909. const rgFlag = {};
  1910. const resistanceUpdateFn = (b) => {
  1911. if(b !== rgFlag && resistanceUpdateRetry === false) return;
  1912. if (!resistanceUpdateDebugMode && allBackgroundOverLays.length === 0) return;
  1913. resistanceUpdateBusy = false;
  1914. const t = Date.now();
  1915. const d = t - resistanceUpdateLast;
  1916. if (d > 375) {
  1917. resistanceUpdateLast = t;
  1918. resistanceUpdateRetry = false;
  1919. updateTickerCurrentTime();
  1920. } else if (typeof requestIdleCallback === 'function') {
  1921. resistanceUpdateRetry = true;
  1922. requestIdleCallback(resistanceUpdateFn);
  1923. } else {
  1924. resistanceUpdateRetry = true;
  1925. setTimeout(resistanceUpdateFn, d + 17);
  1926. }
  1927. }
  1928. const resistanceUpdateFn_ = ()=>{
  1929. if (!resistanceUpdateBusy) {
  1930. resistanceUpdateBusy = true;
  1931. resistanceUpdateRetry = false;
  1932. Promise.resolve(rgFlag).then(resistanceUpdateFn);
  1933. }
  1934. }
  1935. const startResistanceUpdater = () => {
  1936.  
  1937. if (startResistanceUpdaterStarted) return;
  1938. startResistanceUpdaterStarted = true;
  1939.  
  1940.  
  1941. if (RESISTANCE_UPDATE_OPT & 1)
  1942. document.addEventListener('yt-action', () => {
  1943. resistanceUpdateFn_();
  1944. }, true)
  1945.  
  1946. if (RESISTANCE_UPDATE_OPT & 2)
  1947. new MutationObserver(() => {
  1948. resistanceUpdateFn_();
  1949. }).observe(document, {
  1950. subtree: true, childList: true, attributes: true
  1951. });
  1952. resistanceUpdateFn_();
  1953. }
  1954.  
  1955. if(resistanceUpdateDebugMode) startResistanceUpdater();
  1956.  
  1957.  
  1958. function dr(s) {
  1959. // reserved for future use
  1960. return s;
  1961. // return window.deWeakJS ? window.deWeakJS(s) : s;
  1962. }
  1963.  
  1964. const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);
  1965. const indr = o => insp(o).$ || o.$ || 0;
  1966.  
  1967. const getProto = (element) => {
  1968. if (element) {
  1969. const cnt = insp(element);
  1970. return cnt.constructor.prototype || null;
  1971. }
  1972. return null;
  1973. }
  1974.  
  1975.  
  1976.  
  1977. const logFn = (key, f) => {
  1978. return Function.prototype.bind.call(console.log, console, `%c ${key}`, 'background: #222; color: #bada55', f);
  1979. }
  1980.  
  1981.  
  1982. const assertor = (f) => f() || (console.assert(false, f + ""), false);
  1983.  
  1984. const fnIntegrity = (f, d) => {
  1985.  
  1986.  
  1987. if (!f || typeof f !== 'function') {
  1988. console.warn('f is not a function', f);
  1989. return;
  1990. }
  1991. // return; // M44
  1992. let p = `${f}`, s = 0, j = -1, w = 0;
  1993. // return; // M44
  1994. for (let i = 0, l = p.length; i < l; i++) {
  1995. const t = p[i];
  1996. if (((t >= 'a' && t <= 'z') || (t >= 'A' && t <= 'Z'))) {
  1997. if (j < i - 1) w++;
  1998. j = i;
  1999. } else {
  2000. s++;
  2001. }
  2002. }
  2003. // if(p.length > 44 && p.length < 50){
  2004.  
  2005. // (window.skam|| (window.skam=[])).push(p);
  2006. // return false;
  2007. // }
  2008.  
  2009. // if(p.length > 405 && p.length < 415 ){ //350 450
  2010.  
  2011.  
  2012. // //  [353, 411, 411, 411]
  2013.  
  2014. // // if(p.length >= 350 && p.length<=450){
  2015.  
  2016. // // (window.skam|| (window.skam=[])).push(p.length);
  2017. // // }
  2018. // (window.skam|| (window.skam=[])).push(p);
  2019. // return false;
  2020. // }
  2021.  
  2022. // if(p.length < 50) return true; else return false;
  2023. // return; // M44
  2024. let itz = `${f.length}.${s}.${w}`;
  2025. if (!d) {
  2026. return itz;
  2027. } else if (itz !== d) {
  2028. console.warn('fnIntegrity=false', itz);
  2029. return false;
  2030. } else {
  2031. return true;
  2032. }
  2033. }
  2034.  
  2035. const px2cm = (px) => px * window.devicePixelRatio * 0.026458333;
  2036. const px2mm = (px) => px * window.devicePixelRatio * 0.26458333;
  2037.  
  2038.  
  2039. ; (ENABLE_FLAGS_MAINTAIN_STABLE_LIST || ENABLE_FLAGS_REUSE_COMPONENTS || DISABLE_FLAGS_SHADYDOM_FREE) && (() => {
  2040.  
  2041. const _config_ = () => {
  2042. try {
  2043. return ytcfg.data_;
  2044. } catch (e) { }
  2045. return null;
  2046. };
  2047.  
  2048. const flagsFn = (EXPERIMENT_FLAGS) => {
  2049.  
  2050. // console.log(700)
  2051.  
  2052. if (!EXPERIMENT_FLAGS) return;
  2053.  
  2054. if (ENABLE_FLAGS_MAINTAIN_STABLE_LIST) {
  2055. if (USE_MAINTAIN_STABLE_LIST_ONLY_WHEN_KS_FLAG_IS_SET ? EXPERIMENT_FLAGS.kevlar_should_maintain_stable_list === true : true) {
  2056. // EXPERIMENT_FLAGS.kevlar_tuner_should_test_maintain_stable_list = true; // timestamp toggle issue
  2057. EXPERIMENT_FLAGS.kevlar_should_maintain_stable_list = true;
  2058. // console.log(701)
  2059. }
  2060. }
  2061.  
  2062. if (ENABLE_FLAGS_REUSE_COMPONENTS) {
  2063. EXPERIMENT_FLAGS.kevlar_tuner_should_test_reuse_components = true;
  2064. EXPERIMENT_FLAGS.kevlar_tuner_should_reuse_components = true;
  2065. // console.log(702);
  2066. }
  2067.  
  2068. if (DISABLE_FLAGS_SHADYDOM_FREE) {
  2069. EXPERIMENT_FLAGS.enable_shadydom_free_scoped_node_methods = false;
  2070. EXPERIMENT_FLAGS.enable_shadydom_free_scoped_query_methods = false;
  2071. EXPERIMENT_FLAGS.enable_shadydom_free_scoped_readonly_properties_batch_one = false;
  2072. EXPERIMENT_FLAGS.enable_shadydom_free_parent_node = false;
  2073. EXPERIMENT_FLAGS.enable_shadydom_free_children = false;
  2074. EXPERIMENT_FLAGS.enable_shadydom_free_last_child = false;
  2075. }
  2076.  
  2077. // EXPERIMENT_FLAGS.enable_button_behavior_reuse = false;
  2078.  
  2079. };
  2080.  
  2081. const uf = (config_) => {
  2082. config_ = config_ || _config_();
  2083. if (config_) {
  2084. const { EXPERIMENT_FLAGS, EXPERIMENTS_FORCED_FLAGS } = config_;
  2085. if (EXPERIMENT_FLAGS) {
  2086. flagsFn(EXPERIMENT_FLAGS);
  2087. if (EXPERIMENTS_FORCED_FLAGS) flagsFn(EXPERIMENTS_FORCED_FLAGS);
  2088. }
  2089. }
  2090. }
  2091.  
  2092. window._ytConfigHacks.add((config_) => {
  2093. uf(config_);
  2094. });
  2095.  
  2096. uf();
  2097.  
  2098. })();
  2099.  
  2100. if (DISABLE_Translation_By_Google) {
  2101.  
  2102. let mo = new MutationObserver(() => {
  2103.  
  2104. if (!mo) return;
  2105. let h = document.head;
  2106. if (!h) return;
  2107. mo.disconnect();
  2108. mo.takeRecords();
  2109. mo = null;
  2110.  
  2111. let meta = document.createElement('meta');
  2112. meta.setAttribute('name', 'google');
  2113. meta.setAttribute('content', 'notranslate');
  2114. h.appendChild(meta);
  2115.  
  2116.  
  2117. });
  2118. mo.observe(document, { subtree: true, childList: true });
  2119. }
  2120.  
  2121.  
  2122. console.assert(MAX_ITEMS_FOR_TOTAL_DISPLAY > 0 && MAX_ITEMS_FOR_FULL_FLUSH > 0 && MAX_ITEMS_FOR_TOTAL_DISPLAY > MAX_ITEMS_FOR_FULL_FLUSH)
  2123.  
  2124. const isContainSupport = CSS.supports('contain', 'layout paint style');
  2125. if (!isContainSupport) {
  2126. console.warn("Your browser does not support css property 'contain'.\nPlease upgrade to the latest version.".trim());
  2127. }
  2128.  
  2129. const isOverflowAnchorSupport = CSS.supports('overflow-anchor', 'auto');
  2130. if (!isOverflowAnchorSupport) {
  2131. console.warn("Your browser does not support css property 'overflow-anchor'.\nPlease upgrade to the latest version.".trim());
  2132. }
  2133.  
  2134. const ENABLE_OVERFLOW_ANCHOR = ENABLE_OVERFLOW_ANCHOR_PREFERRED && isOverflowAnchorSupport && ENABLE_NO_SMOOTH_TRANSFORM;
  2135.  
  2136. let hasTimerModified = null;
  2137. const DO_CHECK_TICKER_BACKGROUND_OVERRIDED = !!ATTEMPT_ANIMATED_TICKER_BACKGROUND || ENABLE_RAF_HACK_TICKERS;
  2138.  
  2139. const fxOperator = (proto, propertyName) => {
  2140. let propertyDescriptorGetter = null;
  2141. try {
  2142. propertyDescriptorGetter = Object.getOwnPropertyDescriptor(proto, propertyName).get;
  2143. } catch (e) { }
  2144. return typeof propertyDescriptorGetter === 'function' ? (e) => {
  2145. try {
  2146.  
  2147. return propertyDescriptorGetter.call(dr(e));
  2148. } catch (e) { }
  2149. return e[propertyName];
  2150. } : (e) => e[propertyName];
  2151. };
  2152.  
  2153. const nodeParent = fxOperator(Node.prototype, 'parentNode');
  2154. // const nFirstElem = fxOperator(HTMLElement.prototype, 'firstElementChild');
  2155. const nPrevElem = fxOperator(HTMLElement.prototype, 'previousElementSibling');
  2156. const nNextElem = fxOperator(HTMLElement.prototype, 'nextElementSibling');
  2157. const nLastElem = fxOperator(HTMLElement.prototype, 'lastElementChild');
  2158.  
  2159. const groupCollapsed = (text1, text2) => {
  2160.  
  2161. let w = 'groupCollapsed';
  2162. if (DEBUG_LOG_GROUP_EXPAND) w = 'group';
  2163. console[w](`%c${text1}%c${text2}`,
  2164. "background-color: #010502; color: #6acafe; font-weight: 700; padding: 2px;",
  2165. "background-color: #010502; color: #6ad9fe; font-weight: 300; padding: 2px;"
  2166. );
  2167. }
  2168.  
  2169. // const microNow = () => performance.now() + (performance.timeOrigin || performance.timing.navigationStart);
  2170.  
  2171.  
  2172. const EVENT_KEY_ON_REGISTRY_READY = "ytI-ce-registry-created";
  2173. const onRegistryReady = (callback) => {
  2174. if (typeof customElements === 'undefined') {
  2175. if (!('__CE_registry' in document)) {
  2176. // https://github.com/webcomponents/polyfills/
  2177. Object.defineProperty(document, '__CE_registry', {
  2178. get() {
  2179. // return undefined
  2180. },
  2181. set(nv) {
  2182. if (typeof nv == 'object') {
  2183. delete this.__CE_registry;
  2184. this.__CE_registry = nv;
  2185. this.dispatchEvent(new CustomEvent(EVENT_KEY_ON_REGISTRY_READY));
  2186. }
  2187. return true;
  2188. },
  2189. enumerable: false,
  2190. configurable: true
  2191. })
  2192. }
  2193. let eventHandler = (evt) => {
  2194. document.removeEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  2195. const f = callback;
  2196. callback = null;
  2197. eventHandler = null;
  2198. f();
  2199. };
  2200. document.addEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  2201. } else {
  2202. callback();
  2203. }
  2204. };
  2205.  
  2206. const promiseForCustomYtElementsReady = new Promise(onRegistryReady);
  2207.  
  2208. const renderReadyPn = typeof ResizeObserver !== 'undefined' ? (sizingTarget) => {
  2209.  
  2210. return new Promise(resolve => {
  2211.  
  2212. let ro = new ResizeObserver(entries => {
  2213. if (entries && entries.length >= 1) {
  2214. resolve();
  2215. ro.disconnect();
  2216. ro = null;
  2217. }
  2218. });
  2219. ro.observe(sizingTarget);
  2220.  
  2221.  
  2222.  
  2223. });
  2224.  
  2225. } : (sizingTarget) => {
  2226.  
  2227.  
  2228. return new Promise(resolve => {
  2229.  
  2230. let io = new IntersectionObserver(entries => {
  2231. if (entries && entries.length >= 1) {
  2232. resolve();
  2233. io.disconnect();
  2234. io = null;
  2235. }
  2236. });
  2237. io.observe(sizingTarget);
  2238.  
  2239.  
  2240.  
  2241. });
  2242.  
  2243. };
  2244.  
  2245. /* globals WeakRef:false */
  2246.  
  2247. /** @type {(o: Object | null) => WeakRef | null} */
  2248. const mWeakRef = typeof WeakRef === 'function' ? (o => o ? new WeakRef(o) : null) : (o => o || null);
  2249.  
  2250. /** @type {(wr: Object | null) => Object | null} */
  2251. const kRef = (wr => (wr && wr.deref) ? wr.deref() : wr);
  2252.  
  2253. let __LCRInjection__ = 0; // 0 for no injection
  2254. const LCRImmedidates = []; // array of sync. func
  2255.  
  2256. let getLCRDummyP_ = null;
  2257. // lcrPromiseFn
  2258. const getLCRDummy = () => {
  2259. // direct createElement or createComponent_ will make the emoji rendering crashed. reason TBC
  2260.  
  2261. return getLCRDummyP_ || (getLCRDummyP_ = Promise.all([customElements.whenDefined('yt-live-chat-app'), customElements.whenDefined('yt-live-chat-renderer')]).then(async () => {
  2262.  
  2263. const tag = "yt-live-chat-renderer"
  2264. let dummy = document.querySelector(tag);
  2265. if (!dummy) {
  2266.  
  2267. let mo = null;
  2268.  
  2269. const ytLiveChatApp = document.querySelector('yt-live-chat-app') || document.createElement('yt-live-chat-app');
  2270.  
  2271. const lcaProto = getProto(ytLiveChatApp);
  2272. let fz38;
  2273.  
  2274. let qt38=0;
  2275. let bypass = false;
  2276.  
  2277. dummy = await new Promise(resolve => {
  2278.  
  2279.  
  2280. if (typeof lcaProto.createComponent_ === 'function' && !lcaProto.createComponent99_ && lcaProto.createComponent_.length === 3) {
  2281. console.log('[yt-chat-lcr] lcaProto.createComponent_ is found');
  2282.  
  2283. lcaProto.createComponent99_ = lcaProto.createComponent_;
  2284. lcaProto.createComponent98_ = function (a, b, c) {
  2285. const z = customCreateComponent(a,b,c);
  2286. if(z !== undefined) return z;
  2287. // (3) ['yt-live-chat-renderer', {…}, true]
  2288. const r = this.createComponent99_(a, b,c);
  2289. const componentTag = (typeof a === 'string' ? a : (a||0).component) || `${(r||0).nodeName}`.toLowerCase();
  2290. if ( componentTag === 'yt-live-chat-renderer' && !bypass) {
  2291. qt38 = 1;
  2292.  
  2293. __LCRInjection__ = __LCRInjection__ | 1;
  2294.  
  2295. // r.polymerController.__proto__.handleLiveChatActions471_ = r.polymerController.__proto__.handleLiveChatActions_;
  2296. // r.polymerController.__proto__.handleLiveChatActions_ = function (arr) {
  2297.  
  2298.  
  2299. // preprocessChatLiveActions(arr);
  2300.  
  2301. // return this.handleLiveChatActions471_(arr);
  2302.  
  2303. // }
  2304.  
  2305. for (const f of LCRImmedidates) {
  2306. f(r);
  2307. }
  2308. LCRImmedidates.length = 0;
  2309.  
  2310. resolve(r); // note: this dom is not yet adopted, but promise resolve is later than ops.
  2311. console.log('[yt-chat-lcr] element found by method 1');
  2312. }
  2313. return r;
  2314. };
  2315. lcaProto.createComponent_ = lcaProto.createComponent98_;
  2316.  
  2317. if (!USE_OBTAIN_LCR_BY_BOTH_METHODS) return;
  2318.  
  2319. }
  2320.  
  2321. // console.log('[yt-chat] lcaProto traditional');
  2322.  
  2323. const pz38 = document.getElementsByTagName(tag);
  2324. fz38 = () => {
  2325. const t = pz38[0]
  2326. if (t) {
  2327. qt38 = 2;
  2328.  
  2329. __LCRInjection__ = __LCRInjection__ | 2;
  2330. resolve(t);
  2331. console.log('[yt-chat-lcr] element found by method 2');
  2332. }
  2333. };
  2334. mo = new MutationObserver(fz38);
  2335. mo.observe(document, { subtree: true, childList: true, attributes: true });
  2336. document.addEventListener('yt-action', fz38, true);
  2337. fz38();
  2338.  
  2339. });
  2340.  
  2341. bypass = true;
  2342.  
  2343. if (mo) {
  2344. mo.disconnect();
  2345. mo.takeRecords();
  2346. mo = null;
  2347. }
  2348. if (fz38) {
  2349. document.removeEventListener('yt-action', fz38, true);
  2350. fz38 = null;
  2351. }
  2352. console.log(`[yt-chat-lcr] lcr appears, dom = ${document.getElementsByTagName(tag).length}, method = ${qt38}`);
  2353.  
  2354.  
  2355. // if (lcaProto.createComponent99_ && lcaProto.createComponent_ && lcaProto.createComponent98_ === lcaProto.createComponent_) {
  2356. // lcaProto.createComponent_ = lcaProto.createComponent99_;
  2357. // lcaProto.createComponent99_ = null;
  2358. // lcaProto.createComponent98_ = null;
  2359. // }
  2360.  
  2361. } else {
  2362. console.log('[yt-chat-lcr] lcr exists');
  2363. }
  2364. return dummy;
  2365.  
  2366. }));
  2367. }
  2368.  
  2369.  
  2370. // keeps as alternative option
  2371. let lcrPromise_ = null;
  2372. const lcrPromiseFn = () => {
  2373. if (lcrPromise_) return lcrPromise_;
  2374. const pz38 = document.getElementsByTagName("yt-live-chat-renderer");
  2375. const qz38 = new PromiseExternal();
  2376. const fz38 = () => {
  2377. if (pz38.length > 0) {
  2378. qz38.resolve(() => (pz38[0] || document.createElement("yt-live-chat-renderer")));
  2379. mo.disconnect();
  2380. document.removeEventListener('yt-action', fz38, true);
  2381. }
  2382. };
  2383. const mo = new MutationObserver(fz38);
  2384. mo.observe(document, {
  2385. subtree: true, childList: true, attributes: true
  2386. });
  2387. document.addEventListener('yt-action', fz38, true);
  2388. fz38();
  2389. return (lcrPromise_ = qz38);
  2390. }
  2391.  
  2392. const { addCssManaged } = (() => {
  2393.  
  2394. const addFontPreRendering = () => {
  2395.  
  2396. groupCollapsed("YouTube Super Fast Chat", " | Fonts Pre-Rendering");
  2397.  
  2398. let efsContainer = document.createElement('elzm-fonts');
  2399. efsContainer.id = 'elzm-fonts-yk75g'
  2400.  
  2401. const arr = [];
  2402. let p = document.createElement('elzm-font');
  2403. arr.push(p);
  2404.  
  2405. if (ENABLE_FONT_PRE_RENDERING & 1) {
  2406. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2407.  
  2408. p = document.createElement('elzm-font');
  2409. p.style.fontWeight = size;
  2410. arr.push(p);
  2411. }
  2412. }
  2413.  
  2414. if (ENABLE_FONT_PRE_RENDERING & 2) {
  2415. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2416.  
  2417. p = document.createElement('elzm-font');
  2418. p.style.fontFamily = 'Roboto';
  2419. p.style.fontWeight = size;
  2420. arr.push(p);
  2421. }
  2422. }
  2423.  
  2424. if (ENABLE_FONT_PRE_RENDERING & 4) {
  2425. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2426.  
  2427. p = document.createElement('elzm-font');
  2428. p.style.fontFamily = '"YouTube Noto",Roboto,Arial,Helvetica,sans-serif';
  2429. p.style.fontWeight = size;
  2430. arr.push(p);
  2431. }
  2432. }
  2433.  
  2434.  
  2435. if (ENABLE_FONT_PRE_RENDERING & 8) {
  2436. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2437.  
  2438. p = document.createElement('elzm-font');
  2439. p.style.fontFamily = '"Noto",Roboto,Arial,Helvetica,sans-serif';
  2440. p.style.fontWeight = size;
  2441. arr.push(p);
  2442. }
  2443. }
  2444.  
  2445.  
  2446. if (ENABLE_FONT_PRE_RENDERING & 16) {
  2447. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2448.  
  2449. p = document.createElement('elzm-font');
  2450. p.style.fontFamily = 'sans-serif';
  2451. p.style.fontWeight = size;
  2452. arr.push(p);
  2453. }
  2454. }
  2455.  
  2456. console.log('number of elzm-font elements', arr.length);
  2457.  
  2458. HTMLElement.prototype.append.apply(efsContainer, arr);
  2459.  
  2460. (document.body || document.documentElement).appendChild(efsContainer);
  2461.  
  2462.  
  2463. console.log('elzm-font elements have been added to the page for rendering.');
  2464.  
  2465. console.groupEnd();
  2466.  
  2467. }
  2468.  
  2469. let isCssAdded = false;
  2470.  
  2471. function addCssElement() {
  2472. let s = document.createElement('style');
  2473. s.id = 'ewRvC';
  2474. return s;
  2475. }
  2476.  
  2477. const addCssManaged = () => {
  2478. if (!isCssAdded && document.documentElement && document.head) {
  2479. isCssAdded = true;
  2480. document.head.appendChild(dr(addCssElement())).textContent = addCss();
  2481. if (ENABLE_FONT_PRE_RENDERING) {
  2482. Promise.resolve().then(addFontPreRendering)
  2483. }
  2484. }
  2485. }
  2486.  
  2487. return { addCssManaged };
  2488. })();
  2489.  
  2490.  
  2491. const { setupStyle } = (() => {
  2492.  
  2493. const sp7 = Symbol();
  2494.  
  2495. const proxyHelperFn = (dummy) => ({
  2496.  
  2497. get(target, prop) {
  2498. return (prop in dummy) ? dummy[prop] : prop === sp7 ? target : target[prop];
  2499. },
  2500. set(target, prop, value) {
  2501. if (!(prop in dummy)) {
  2502. target[prop] = value;
  2503. }
  2504. return true;
  2505. },
  2506. has(target, prop) {
  2507. return (prop in target);
  2508. },
  2509. deleteProperty(target, prop) {
  2510. return true;
  2511. },
  2512. ownKeys(target) {
  2513. return Object.keys(target);
  2514. },
  2515. defineProperty(target, key, descriptor) {
  2516. return Object.defineProperty(target, key, descriptor);
  2517. },
  2518. getOwnPropertyDescriptor(target, key) {
  2519. return Object.getOwnPropertyDescriptor(target, key);
  2520. },
  2521.  
  2522. });
  2523.  
  2524. const setupStyle = (m1, m2) => {
  2525. if (!ENABLE_NO_SMOOTH_TRANSFORM) return;
  2526.  
  2527. const dummy1v = {
  2528. transform: '',
  2529. height: '',
  2530. minHeight: '',
  2531. paddingBottom: '',
  2532. paddingTop: ''
  2533. };
  2534.  
  2535. const dummyStyleFn = (k) => (function () { const style = this[sp7]; return style[k](...arguments); });
  2536. for (const k of ['toString', 'getPropertyPriority', 'getPropertyValue', 'item', 'removeProperty', 'setProperty']) {
  2537. dummy1v[k] = dummyStyleFn(k);
  2538. }
  2539.  
  2540. const dummy1p = proxyHelperFn(dummy1v);
  2541. const sp1v = new Proxy(m1.style, dummy1p);
  2542. const sp2v = new Proxy(m2.style, dummy1p);
  2543. Object.defineProperty(m1, 'style', { get() { return sp1v }, set() { }, enumerable: true, configurable: true });
  2544. Object.defineProperty(m2, 'style', { get() { return sp2v }, set() { }, enumerable: true, configurable: true });
  2545. m1.removeAttribute("style");
  2546. m2.removeAttribute("style");
  2547.  
  2548. }
  2549.  
  2550. return { setupStyle };
  2551.  
  2552. })();
  2553.  
  2554.  
  2555.  
  2556. function setThumbnails(config) {
  2557.  
  2558. const { baseObject, thumbnails, flag0, imageLinks } = config;
  2559.  
  2560. if (flag0 || (ENABLE_PRELOAD_THUMBNAIL && imageLinks)) {
  2561.  
  2562.  
  2563. if (thumbnails && thumbnails.length > 0) {
  2564. if (flag0 > 0 && thumbnails.length > 1) {
  2565. let pSize = 0;
  2566. let newThumbnails = [];
  2567. for (const thumbnail of thumbnails) {
  2568. if (!thumbnail || !thumbnail.url) continue;
  2569. const squarePhoto = thumbnail.width === thumbnail.height && typeof thumbnail.width === 'number';
  2570. const condSize = pSize <= 0 || (flag0 === 1 ? pSize > thumbnail.width : pSize < thumbnail.width);
  2571. const leastSizeFulfilled = squarePhoto ? thumbnail.width >= LEAST_IMAGE_SIZE : true;
  2572. if ((!squarePhoto || condSize) && leastSizeFulfilled) {
  2573. newThumbnails.push(thumbnail);
  2574. if (imageLinks) imageLinks.add(thumbnail.url);
  2575. }
  2576. if (squarePhoto && condSize && leastSizeFulfilled) {
  2577. pSize = thumbnail.width;
  2578. }
  2579. }
  2580. if (thumbnails.length !== newThumbnails.length && thumbnails === baseObject.thumbnails && newThumbnails.length > 0) {
  2581. baseObject.thumbnails = newThumbnails;
  2582. } else {
  2583. newThumbnails.length = 0;
  2584. }
  2585. newThumbnails = null;
  2586. } else {
  2587. for (const thumbnail of thumbnails) {
  2588. if (thumbnail && thumbnail.url) {
  2589. if (imageLinks) imageLinks.add(thumbnail.url);
  2590. }
  2591. }
  2592. }
  2593. }
  2594.  
  2595. }
  2596. }
  2597.  
  2598. function fixLiveChatItem(item, imageLinks) {
  2599. const liveChatTextMessageRenderer = (item || 0).liveChatTextMessageRenderer || 0;
  2600. if (liveChatTextMessageRenderer) {
  2601. const messageRuns = (liveChatTextMessageRenderer.message || 0).runs || 0;
  2602. if (messageRuns && messageRuns.length > 0) {
  2603. for (const run of messageRuns) {
  2604. const emojiImage = (((run || 0).emoji || 0).image || 0);
  2605. setThumbnails({
  2606. baseObject: emojiImage,
  2607. thumbnails: emojiImage.thumbnails,
  2608. flag0: EMOJI_IMAGE_SINGLE_THUMBNAIL,
  2609. imageLinks
  2610. });
  2611. }
  2612. }
  2613. const authorPhoto = liveChatTextMessageRenderer.authorPhoto || 0;
  2614. setThumbnails({
  2615. baseObject: authorPhoto,
  2616. thumbnails: authorPhoto.thumbnails,
  2617. flag0: AUTHOR_PHOTO_SINGLE_THUMBNAIL,
  2618. imageLinks
  2619. });
  2620. }
  2621. }
  2622.  
  2623.  
  2624.  
  2625. let kptPF = null;
  2626. const emojiPrefetched = new LimitedSizeSet(PREFETCH_LIMITED_SIZE_EMOJI);
  2627. const authorPhotoPrefetched = new LimitedSizeSet(PREFETCH_LIMITED_SIZE_AUTHOR_PHOTO);
  2628.  
  2629. function linker(link, rel, href, _as) {
  2630. return new Promise(resolve => {
  2631. if (!link) link = document.createElement('link');
  2632. link.rel = rel;
  2633. if (_as) link.setAttribute('as', _as);
  2634. link.onload = function () {
  2635. resolve({
  2636. link: this,
  2637. success: true
  2638. })
  2639. this.remove();
  2640. };
  2641. link.onerror = function () {
  2642. resolve({
  2643. link: this,
  2644. success: false
  2645. });
  2646. this.remove();
  2647. };
  2648. link.href = href;
  2649. document.head.appendChild(link);
  2650. link = null;
  2651. });
  2652. }
  2653.  
  2654.  
  2655.  
  2656. const cleanContext = async (win) => {
  2657. const waitFn = requestAnimationFrame; // shall have been binded to window
  2658. try {
  2659. let mx = 16; // MAX TRIAL
  2660. const frameId = 'vanillajs-iframe-v1';
  2661. /** @type {HTMLIFrameElement | null} */
  2662. let frame = document.getElementById(frameId);
  2663. let removeIframeFn = null;
  2664. if (!frame) {
  2665. frame = document.createElement('iframe');
  2666. frame.id = frameId;
  2667. const blobURL = typeof webkitCancelAnimationFrame === 'function' && typeof kagi === 'undefined' ? (frame.src = URL.createObjectURL(new Blob([], { type: 'text/html' }))) : null; // avoid Brave Crash
  2668. frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe
  2669. let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting)
  2670. n.appendChild(frame);
  2671. while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine
  2672. const root = document.documentElement;
  2673. root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL
  2674. if (blobURL) Promise.resolve().then(() => URL.revokeObjectURL(blobURL));
  2675.  
  2676. removeIframeFn = (setTimeout) => {
  2677. const removeIframeOnDocumentReady = (e) => {
  2678. e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
  2679. e = n;
  2680. n = win = removeIframeFn = 0;
  2681. setTimeout ? setTimeout(() => e.remove(), 200) : e.remove();
  2682. }
  2683. if (!setTimeout || document.readyState !== 'loading') {
  2684. removeIframeOnDocumentReady();
  2685. } else {
  2686. win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
  2687. }
  2688. }
  2689. }
  2690. while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn);
  2691. const fc = frame.contentWindow;
  2692. if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL
  2693. try {
  2694. const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, getComputedStyle } = fc;
  2695. const res = { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, getComputedStyle };
  2696. for (let k in res) res[k] = res[k].bind(win); // necessary
  2697. if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn);
  2698.  
  2699. /** @type {HTMLElement} */
  2700. const HTMLElementProto = fc.HTMLElement.prototype;
  2701. /** @type {EventTarget} */
  2702. const EventTargetProto = fc.EventTarget.prototype;
  2703. // jsonParseFix = {
  2704. // _JSON: fc.JSON, _parse: fc.JSON.parse
  2705. // }
  2706. return {
  2707. ...res,
  2708. animate: HTMLElementProto.animate,
  2709. addEventListener: EventTargetProto.addEventListener,
  2710. removeEventListener: EventTargetProto.removeEventListener
  2711. };
  2712. } catch (e) {
  2713. if (removeIframeFn) removeIframeFn();
  2714. return null;
  2715. }
  2716. } catch (e) {
  2717. console.warn(e);
  2718. return null;
  2719. }
  2720. };
  2721.  
  2722.  
  2723. let xoIcjPr = null;
  2724. window.addEventListener('message', (evt) => {
  2725. if ((evt || 0).data === 'xoIcj' && xoIcjPr !== null) xoIcjPr.resolve();
  2726. });
  2727. const timelineResolve = async () => {
  2728. if (xoIcjPr !== null) {
  2729. await xoIcjPr.then();
  2730. return;
  2731. }
  2732. xoIcjPr = new PromiseExternal();
  2733. window.postMessage('xoIcj');
  2734. await xoIcjPr.then();
  2735. xoIcjPr = null;
  2736. }
  2737.  
  2738. cleanContext(win).then(__CONTEXT__ => {
  2739. if (!__CONTEXT__) return null;
  2740.  
  2741. const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, animate, getComputedStyle, addEventListener, removeEventListener } = __CONTEXT__;
  2742.  
  2743. const wmComputedStyle = new WeakMap();
  2744. const getComputedStyleCached = (elem) => {
  2745. let cs = wmComputedStyle.get(elem);
  2746. if (!cs) {
  2747. cs = getComputedStyle(elem);
  2748. wmComputedStyle.set(elem, cs);
  2749. }
  2750. return cs;
  2751. }
  2752.  
  2753.  
  2754. const isGPUAccelerationAvailable = (() => {
  2755. // https://gist.github.com/cvan/042b2448fcecefafbb6a91469484cdf8
  2756. try {
  2757. const canvas = document.createElement('canvas');
  2758. return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
  2759. } catch (e) {
  2760. return false;
  2761. }
  2762. })();
  2763.  
  2764. const foregroundPromiseFn_noGPU = (() => {
  2765.  
  2766. if (isGPUAccelerationAvailable) return null;
  2767.  
  2768. const pd = Object.getOwnPropertyDescriptor(Document.prototype, 'visibilityState');
  2769. if (!pd || typeof pd.get !== 'function') return null;
  2770. const pdGet = pd.get;
  2771.  
  2772. let pr = null;
  2773.  
  2774. let hState = pdGet.call(document) === 'hidden';
  2775. // let cid = 0;
  2776. pureAddEventListener.call(document, 'visibilitychange', (evt) => {
  2777. const newHState = pdGet.call(document) === 'hidden';
  2778. if (hState !== newHState) {
  2779. // if (cid > 0) cid = clearInterval(cid);
  2780. hState = newHState;
  2781. if (!hState && pr) pr = pr.resolve();
  2782. }
  2783. });
  2784.  
  2785. // cid = setInterval(() => {
  2786. // const newHState = document.visibilityState === 'hidden';
  2787. // if (hState !== newHState) {
  2788. // hState = newHState;
  2789. // if (!hState && pr) pr = pr.resolve();
  2790. // }
  2791. // }, 100);
  2792.  
  2793.  
  2794. return (() => {
  2795. if (pr) return pr;
  2796. const w = ((!hState && setTimeout(() => {
  2797. if (!hState && pr === w) pr = pr.resolve();
  2798. })), (pr = new PromiseExternal()));
  2799. return w;
  2800. });
  2801.  
  2802. })();
  2803.  
  2804. // window.foregroundPromiseFn_noGPU = foregroundPromiseFn_noGPU;
  2805.  
  2806. let rafPromise = null;
  2807. const getRafPromise = () => rafPromise || (rafPromise = new Promise(resolve => {
  2808. requestAnimationFrame(hRes => {
  2809. rafPromise = null;
  2810. resolve(hRes);
  2811. });
  2812. }));
  2813. const foregroundPromiseFn = foregroundPromiseFn_noGPU || getRafPromise;
  2814.  
  2815. const iAFP = foregroundPromiseFn_noGPU ? foregroundPromiseFn_noGPU : typeof IntersectionObserver === 'undefined' ? getRafPromise : (() => {
  2816.  
  2817. const ioWM = new WeakMap();
  2818. const ek = Symbol();
  2819. /** @type {IntersectionObserverCallback} */
  2820. const ioCb = (entries, observer) => {
  2821. /** @type {PromiseExternal} */
  2822. const pr = observer[ek];
  2823. const resolve = pr.resolve;
  2824. let target;
  2825. if (resolve && (target = ((entries ? entries[0] : 0) || 0).target) instanceof Element) {
  2826. pr.resolve = null;
  2827. observer.unobserve(target);
  2828. resolve();
  2829. }
  2830. };
  2831. /**
  2832. *
  2833. * @param {Element} elm
  2834. * @returns {Promise<void>}
  2835. */
  2836. const iAFP = (elm) => {
  2837. let io = ioWM.get(elm);
  2838. if (!io) {
  2839. io = new IntersectionObserver(ioCb);
  2840. ioWM.set(elm, io); // strong reference
  2841. }
  2842. let pr = io[ek];
  2843. if (!pr) {
  2844. pr = io[ek] = new PromiseExternal();
  2845. io.observe(elm);
  2846. }
  2847. return pr;
  2848. }
  2849.  
  2850. return iAFP;
  2851.  
  2852. })();
  2853.  
  2854. let playerState = null;
  2855. let _playerState = null;
  2856. let lastPlayerProgress = null;
  2857. let relayCount = 0;
  2858. let playerEventsByIframeRelay = false;
  2859. let isPlayProgressTriggered = false;
  2860. let waitForInitialDataCompletion = 0;
  2861.  
  2862.  
  2863.  
  2864. let aeConstructor = null;
  2865.  
  2866. // << __openedChanged82 >>
  2867. let currentMenuPivotWR = null;
  2868.  
  2869. // << if DO_PARTICIPANT_LIST_HACKS >>
  2870. const beforeParticipantsMap = new WeakMap();
  2871. // << end >>
  2872.  
  2873.  
  2874.  
  2875. // << if onRegistryReadyForDOMOperations >>
  2876.  
  2877. let dt0 = Date.now() - 2000;
  2878. const dateNow = () => Date.now() - dt0;
  2879. // let lastScroll = 0;
  2880. // let lastLShow = 0;
  2881. let lastWheel = 0;
  2882. let lastMouseDown = 0;
  2883. let lastMouseUp = 0;
  2884. let currentMouseDown = false;
  2885. let lastTouchDown = 0;
  2886. let lastTouchUp = 0;
  2887. let currentTouchDown = false;
  2888. let lastUserInteraction = 0;
  2889.  
  2890. let scrollChatFn = null;
  2891.  
  2892. let skipDontRender = true; // true first; false by flushActiveItems_
  2893. let allowDontRender = null;
  2894.  
  2895. // ---- #items mutation ----
  2896. let sk35zResolveFn = null;
  2897. let firstList = true;
  2898.  
  2899. // << end >>
  2900.  
  2901. class RAFHub {
  2902. constructor() {
  2903. /** @type {number} */
  2904. this.startAt = 8170;
  2905. /** @type {number} */
  2906. this.counter = 0;
  2907. /** @type {number} */
  2908. this.rid = 0;
  2909. /** @type {Map<number, FrameRequestCallback>} */
  2910. this.funcs = new Map();
  2911. const funcs = this.funcs;
  2912. /** @type {FrameRequestCallback} */
  2913. this.bCallback = this.mCallback.bind(this);
  2914. this.pClear = () => funcs.clear();
  2915. this.keepRAF = false;
  2916. }
  2917. /** @param {DOMHighResTimeStamp} highResTime */
  2918. mCallback(highResTime) {
  2919. this.rid = 0;
  2920. Promise.resolve().then(this.pClear);
  2921. this.funcs.forEach(func => Promise.resolve(highResTime).then(func).catch(console.warn));
  2922. }
  2923. /** @param {FrameRequestCallback} f */
  2924. request(f) {
  2925. if (this.counter > 1e9) this.counter = 9;
  2926. let cid = this.startAt + (++this.counter);
  2927. this.funcs.set(cid, f);
  2928. if (this.rid === 0) this.rid = requestAnimationFrame(this.bCallback);
  2929. return cid;
  2930. }
  2931. /** @param {number} cid */
  2932. cancel(cid) {
  2933. cid = +cid;
  2934. if (cid > 0) {
  2935. if (cid <= this.startAt) {
  2936. return cancelAnimationFrame(cid);
  2937. }
  2938. if (this.rid > 0) {
  2939. this.funcs.delete(cid);
  2940. if (this.funcs.size === 0 && !this.keepRAF) {
  2941. cancelAnimationFrame(this.rid);
  2942. this.rid = 0;
  2943. }
  2944. }
  2945. }
  2946. }
  2947. }
  2948.  
  2949. function basePrefetching() {
  2950.  
  2951. new Promise(resolve => {
  2952.  
  2953. if (document.readyState !== 'loading') {
  2954. resolve();
  2955. } else {
  2956. win.addEventListener("DOMContentLoaded", resolve, false);
  2957. }
  2958.  
  2959. }).then(() => {
  2960. const hostL1 = [
  2961. 'https://www.youtube.com', 'https://googlevideo.com',
  2962. 'https://googleapis.com', 'https://accounts.youtube.com',
  2963. 'https://www.gstatic.com', 'https://ggpht.com',
  2964. 'https://yt3.ggpht.com', 'https://yt4.ggpht.com'
  2965. ];
  2966.  
  2967. const hostL2 = [
  2968. 'https://youtube.com',
  2969. 'https://fonts.googleapis.com', 'https://fonts.gstatic.com'
  2970. ];
  2971.  
  2972. let link = null;
  2973.  
  2974. function kn() {
  2975.  
  2976. link = document.createElement('link');
  2977. if (link.relList && link.relList.supports) {
  2978. kptPF = (link.relList.supports('dns-prefetch') ? 1 : 0) + (link.relList.supports('preconnect') ? 2 : 0) + (link.relList.supports('prefetch') ? 4 : 0) + (link.relList.supports('subresource') ? 8 : 0) + (link.relList.supports('preload') ? 16 : 0)
  2979. } else {
  2980. kptPF = 0;
  2981. }
  2982.  
  2983. groupCollapsed("YouTube Super Fast Chat", " | PREFETCH SUPPORTS");
  2984. if (ENABLE_BASE_PREFETCHING) console.log('dns-prefetch', (kptPF & 1) ? 'OK' : 'NG');
  2985. if (ENABLE_BASE_PREFETCHING) console.log('preconnect', (kptPF & 2) ? 'OK' : 'NG');
  2986. if (ENABLE_PRELOAD_THUMBNAIL) console.log('prefetch', (kptPF & 4) ? 'OK' : 'NG');
  2987. // console.log('subresource', (kptPF & 8) ? 'OK' : 'NG');
  2988. if (ENABLE_PRELOAD_THUMBNAIL) console.log('preload', (kptPF & 16) ? 'OK' : 'NG');
  2989. console.groupEnd();
  2990.  
  2991. }
  2992.  
  2993. for (const h of hostL1) {
  2994.  
  2995. if (kptPF === null) kn();
  2996. if (ENABLE_BASE_PREFETCHING) {
  2997. // if (kptPF & 1) {
  2998. // linker(link, 'dns-prefetch', h);
  2999. // link = null;
  3000. // }
  3001. if (kptPF & 2) {
  3002. linker(link, 'preconnect', h);
  3003. link = null;
  3004. }
  3005. }
  3006. }
  3007.  
  3008. for (const h of hostL2) {
  3009. if (kptPF === null) kn();
  3010. if (ENABLE_BASE_PREFETCHING) {
  3011. if (kptPF & 1) {
  3012. linker(link, 'dns-prefetch', h);
  3013. link = null;
  3014. }
  3015. }
  3016. }
  3017.  
  3018. })
  3019.  
  3020.  
  3021. }
  3022.  
  3023. if (DO_LINK_PREFETCH) basePrefetching();
  3024.  
  3025. const { notifyPath7081 } = (() => {
  3026. // DO_PARTICIPANT_LIST_HACKS
  3027.  
  3028. const mutexParticipants = new Mutex();
  3029.  
  3030. let uvid = 0;
  3031. let r95dm = 0;
  3032. let c95dm = -1;
  3033.  
  3034. const foundMap = (base, content) => {
  3035. /*
  3036. let lastSearch = 0;
  3037. let founds = base.map(baseEntry => {
  3038. let search = content.indexOf(baseEntry, lastSearch);
  3039. if (search < 0) return false;
  3040. lastSearch = search + 1;
  3041. return true;
  3042. });
  3043. return founds;
  3044. */
  3045. const contentSet = new Set(content);
  3046. return base.map(baseEntry => contentSet.has(baseEntry));
  3047.  
  3048. }
  3049.  
  3050.  
  3051.  
  3052. let participantsForSpliceWR = null;
  3053.  
  3054. class IndexSpliceEntry {
  3055. /**
  3056. *
  3057. * @param {number} _index
  3058. * @param {number} _addedCount
  3059. * @param {any[]} _removed
  3060. */
  3061. constructor(_index, _addedCount, _removed) {
  3062. this.index = _index;
  3063. this.addedCount = _addedCount;
  3064. this.removed = _removed;
  3065. }
  3066. get __proxy312__() {
  3067. return 1
  3068. }
  3069. get type() {
  3070. return 'splice'
  3071. }
  3072. get object() {
  3073. return kRef(participantsForSpliceWR); // avoid memory leakage
  3074. }
  3075. }
  3076.  
  3077. const spliceIndicesFunc = (beforeParticipants, participants, idsBefore, idsAfter) => {
  3078.  
  3079. let foundsForAfter = foundMap(idsAfter, idsBefore);
  3080. let foundsForBefore = foundMap(idsBefore, idsAfter);
  3081.  
  3082. const nAfter = foundsForAfter.length;
  3083. const nBefore = foundsForBefore.length;
  3084.  
  3085. const indexSplices = [];
  3086. const contentUpdates = [];
  3087. participantsForSpliceWR = null;
  3088. for (let i = 0, j = 0; i < nBefore || j < nAfter;) {
  3089. if (beforeParticipants[i] === participants[j]) {
  3090. i++; j++;
  3091. } else if (idsBefore[i] === idsAfter[j]) {
  3092. // content changed
  3093. contentUpdates.push({ indexI: i, indexJ: j })
  3094. i++; j++;
  3095. } else {
  3096. let addedCount = 0;
  3097. for (let q = j; q < nAfter; q++) {
  3098. if (foundsForAfter[q] === false) addedCount++;
  3099. else break;
  3100. }
  3101. let removedCount = 0;
  3102. for (let q = i; q < nBefore; q++) {
  3103. if (foundsForBefore[q] === false) removedCount++;
  3104. else break;
  3105. }
  3106. if (!addedCount && !removedCount) {
  3107. throw 'ERROR(0xFF32): spliceIndicesFunc';
  3108. }
  3109. const entry = new IndexSpliceEntry(
  3110. j,
  3111. addedCount,
  3112. removedCount >= 1 ? beforeParticipants.slice(i, i + removedCount) : []
  3113. );
  3114. indexSplices.push(entry);
  3115. i += removedCount;
  3116. j += addedCount;
  3117. }
  3118. }
  3119. foundsForBefore = null;
  3120. foundsForAfter = null;
  3121. idsBefore = null;
  3122. idsAfter = null;
  3123. beforeParticipants = null;
  3124. participantsForSpliceWR = indexSplices.length > 0 ? mWeakRef(participants) : null;
  3125. participants = null;
  3126. return { indexSplices, contentUpdates };
  3127.  
  3128. }
  3129.  
  3130. /*
  3131.  
  3132. customElements.get("yt-live-chat-participant-renderer").prototype.notifyPath=function(){ console.log(123); console.log(new Error().stack)}
  3133.  
  3134. VM63631:1 Error
  3135. at customElements.get.notifyPath (<anonymous>:1:122)
  3136. at e.forwardRendererStamperChanges_ (live_chat_polymer.js:4453:35)
  3137. at e.rendererStamperApplyChangeRecord_ (live_chat_polymer.js:4451:12)
  3138. at e.rendererStamperObserver_ (live_chat_polymer.js:4448:149)
  3139. at Object.pu [as fn] (live_chat_polymer.js:1692:118)
  3140. at ju (live_chat_polymer.js:1674:217)
  3141. at a._propertiesChanged (live_chat_polymer.js:1726:122)
  3142. at b._flushProperties (live_chat_polymer.js:1597:200)
  3143. at a._invalidateProperties (live_chat_polymer.js:1718:69)
  3144. at a.notifyPath (live_chat_polymer.js:1741:182)
  3145.  
  3146. */
  3147.  
  3148. function convertToIds(participants) {
  3149. return participants.map(participant => {
  3150. if (!participant || typeof participant !== 'object') {
  3151. console.warn('Error(0xFA41): convertToIds', participant);
  3152. return participant; // just in case
  3153. }
  3154. let keys = Object.keys(participant);
  3155. // liveChatTextMessageRenderer
  3156. // liveChatParticipantRenderer - livestream channel owner [no authorExternalChannelId]
  3157. // liveChatPaidMessageRenderer
  3158. /*
  3159.  
  3160. 'yt-live-chat-participant-renderer' utilizes the following:
  3161. authorName.simpleText: string
  3162. authorPhoto.thumbnails: Object{url:string, width:int, height:int} []
  3163. authorBadges[].liveChatAuthorBadgeRenderer.icon.iconType: string
  3164. authorBadges[].liveChatAuthorBadgeRenderer.tooltip: string
  3165. authorBadges[].liveChatAuthorBadgeRenderer.accessibility.accessibilityData: Object{label:string}
  3166.  
  3167. */
  3168. if (keys.length !== 1) {
  3169. console.warn('Error(0xFA42): convertToIds', participant);
  3170. return participant; // just in case
  3171. }
  3172. let key = keys[0];
  3173. let renderer = (participant[key] || 0);
  3174. let authorName = (renderer.authorName || 0);
  3175. let text = `${authorName.simpleText || authorName.text}`
  3176. let res = participant; // fallback if it is not a vaild entry
  3177. if (typeof text !== 'string') {
  3178. console.warn('Error(0xFA53): convertToIds', participant);
  3179. } else {
  3180. text = `${renderer.authorExternalChannelId || 'null'}|${text || ''}`;
  3181. if (text.length > 1) res = text;
  3182. }
  3183. return res;
  3184. // return renderer?`${renderer.id}|${renderer.authorExternalChannelId}`: '';
  3185. // note: renderer.id will be changed if the user typed something to trigger the update of the participants' record.
  3186. });
  3187. }
  3188.  
  3189. const checkChangeToParticipantRendererContent = CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT ? (p1, p2) => {
  3190. // just update when content is changed.
  3191. if (p1.authorName !== p2.authorName) return true;
  3192. if (p1.authorPhoto !== p2.authorPhoto) return true;
  3193. if (p1.authorBadges !== p2.authorBadges) return true;
  3194. return false;
  3195. } : (p1, p2) => {
  3196. // keep integrity all the time.
  3197. return p1 !== p2; // always true
  3198. }
  3199.  
  3200. function notifyPath7081(path) { // cnt "yt-live-chat-participant-list-renderer"
  3201.  
  3202. if (PARTICIPANT_UPDATE_ONLY_ONLY_IF_MODIFICATION_DETECTED) {
  3203. if (path !== "participantsManager.participants") {
  3204. return this.__notifyPath5036__.apply(this, arguments);
  3205. }
  3206. if (c95dm === r95dm) return;
  3207. } else {
  3208. const stack = new Error().stack;
  3209. if (path !== "participantsManager.participants" || stack.indexOf('.onParticipantsChanged') < 0) {
  3210. return this.__notifyPath5036__.apply(this, arguments);
  3211. }
  3212. }
  3213.  
  3214. if (uvid > 1e8) uvid = uvid % 100;
  3215. let tid = ++uvid;
  3216.  
  3217.  
  3218. // const cnt = this; // "yt-live-chat-participant-list-renderer"
  3219.  
  3220. const wNode = mWeakRef(this);
  3221.  
  3222. mutexParticipants.lockWith(lockResolve => {
  3223.  
  3224. const cnt = kRef(wNode);
  3225.  
  3226. const participants00 = (((cnt || 0).participantsManager || 0).participants || 0);
  3227.  
  3228. if (tid !== uvid || !cnt || typeof (participants00 || 0).splice !== 'function') {
  3229. lockResolve();
  3230. return;
  3231. }
  3232.  
  3233. let doUpdate = false;
  3234.  
  3235. if (PARTICIPANT_UPDATE_ONLY_ONLY_IF_MODIFICATION_DETECTED) {
  3236.  
  3237. if (!participants00.r94dm) {
  3238. participants00.r94dm = 1;
  3239. if (++r95dm > 1e9) r95dm = 9;
  3240. participants00.push = function () {
  3241. if (++r95dm > 1e9) r95dm = 9;
  3242. return Array.prototype.push.apply(this, arguments);
  3243. }
  3244. participants00.pop = function () {
  3245. if (++r95dm > 1e9) r95dm = 9;
  3246. return Array.prototype.pop.apply(this, arguments);
  3247. }
  3248. participants00.shift = function () {
  3249. if (++r95dm > 1e9) r95dm = 9;
  3250. return Array.prototype.shift.apply(this, arguments);
  3251. }
  3252. participants00.unshift = function () {
  3253. if (++r95dm > 1e9) r95dm = 9;
  3254. return Array.prototype.unshift.apply(this, arguments);
  3255. }
  3256. participants00.splice = function () {
  3257. if (++r95dm > 1e9) r95dm = 9;
  3258. return Array.prototype.splice.apply(this, arguments);
  3259. }
  3260. participants00.sort = function () {
  3261. if (++r95dm > 1e9) r95dm = 9;
  3262. return Array.prototype.sort.apply(this, arguments);
  3263. }
  3264. participants00.reverse = function () {
  3265. if (++r95dm > 1e9) r95dm = 9;
  3266. return Array.prototype.reverse.apply(this, arguments);
  3267. }
  3268. }
  3269.  
  3270. if (c95dm !== r95dm) {
  3271. c95dm = r95dm;
  3272. doUpdate = true;
  3273. }
  3274.  
  3275. } else {
  3276. doUpdate = true;
  3277. }
  3278.  
  3279. if (!doUpdate) {
  3280. lockResolve();
  3281. return;
  3282. }
  3283.  
  3284. const participants = participants00.slice(0);
  3285. const beforeParticipants = beforeParticipantsMap.get(cnt) || [];
  3286. beforeParticipantsMap.set(cnt, participants);
  3287.  
  3288. const resPromise = (async () => {
  3289.  
  3290. if (beforeParticipants.length === 0) {
  3291. // not error
  3292. return 0;
  3293. }
  3294.  
  3295. let countOfElements = cnt.__getAllParticipantsDOMRenderedLength__()
  3296.  
  3297. // console.log(participants.length, doms.length) // different if no requestAnimationFrame
  3298. if (beforeParticipants.length !== countOfElements) {
  3299. // there is somewrong for the cache. - sometimes happen
  3300. return 0;
  3301. }
  3302.  
  3303. const idsBefore = convertToIds(beforeParticipants);
  3304. const idsAfter = convertToIds(participants);
  3305.  
  3306. let { indexSplices, contentUpdates } = spliceIndicesFunc(beforeParticipants, participants, idsBefore, idsAfter);
  3307.  
  3308. let res = 1; // default 1 for no update
  3309.  
  3310. if (indexSplices.length >= 1) {
  3311.  
  3312.  
  3313. // let p2 = participants.slice(indexSplices[0].index, indexSplices[0].index+indexSplices[0].addedCount);
  3314. // let p1 = indexSplices[0].removed;
  3315. // console.log(indexSplices.length, indexSplices ,p1,p2, convertToIds(p1),convertToIds(p2))
  3316.  
  3317. /* folllow
  3318. a.notifyPath(c + ".splices", d);
  3319. a.notifyPath(c + ".length", b.length);
  3320. */
  3321. // stampDomArraySplices_
  3322.  
  3323.  
  3324. await new Promise(resolve => {
  3325. cnt.resolveForDOMRendering781 = resolve;
  3326.  
  3327. cnt.__notifyPath5036__("participantsManager.participants.splices", {
  3328. indexSplices
  3329. });
  3330. indexSplices = null;
  3331. participantsForSpliceWR = null;
  3332. cnt.__notifyPath5036__("participantsManager.participants.length",
  3333. participants.length
  3334. );
  3335.  
  3336. });
  3337.  
  3338. // play safe for the change of 'length'
  3339. if (typeof nextBrowserTick !== 'function') {
  3340. await Promise.resolve(0);
  3341. } else {
  3342. await new Promise(resolve => nextBrowserTick(resolve)).then();
  3343. }
  3344.  
  3345. countOfElements = cnt.__getAllParticipantsDOMRenderedLength__();
  3346.  
  3347. const wrongSize = participants.length !== countOfElements
  3348. if (wrongSize) {
  3349. console.warn("ERROR(0xE2C3): notifyPath7081", beforeParticipants.length, participants.length, doms.length)
  3350. return 0;
  3351. }
  3352.  
  3353. res = 2 | 4;
  3354.  
  3355. } else {
  3356.  
  3357. indexSplices = null;
  3358. participantsForSpliceWR = null;
  3359.  
  3360. if (participants.length !== countOfElements) {
  3361. // other unhandled cases
  3362. return 0;
  3363. }
  3364.  
  3365. }
  3366.  
  3367. // participants.length === countOfElements before contentUpdates
  3368. if (contentUpdates.length >= 1) {
  3369. for (const contentUpdate of contentUpdates) {
  3370. let isChanged = checkChangeToParticipantRendererContent(beforeParticipants[contentUpdate.indexI], participants[contentUpdate.indexJ]);
  3371. if (isChanged) {
  3372. cnt.__notifyPath5036__(`participantsManager.participants[${contentUpdate.indexJ}]`);
  3373. res |= 4 | 8;
  3374. }
  3375. }
  3376. }
  3377. contentUpdates = null;
  3378.  
  3379. return res;
  3380.  
  3381.  
  3382. })();
  3383.  
  3384.  
  3385. resPromise.then(resValue => {
  3386.  
  3387. const isLogRequired = SHOW_PARTICIPANT_CHANGES_IN_CONSOLE && ((resValue === 0) || ((resValue & 4) === 4));
  3388. isLogRequired && groupCollapsed("Participant List Change", `tid = ${tid}; res = ${resValue}`);
  3389. if (resValue === 0) {
  3390. new Promise(resolve => {
  3391. cnt.resolveForDOMRendering781 = resolve;
  3392. isLogRequired && console.log("Full Refresh begins");
  3393. cnt.__notifyPath5036__("participantsManager.participants"); // full refresh
  3394. }).then(() => {
  3395. isLogRequired && console.log("Full Refresh ends");
  3396. console.groupEnd();
  3397. }).then(lockResolve);
  3398. return;
  3399. }
  3400.  
  3401. const delayLockResolve = (resValue & 4) === 4;
  3402.  
  3403. if (delayLockResolve) {
  3404. isLogRequired && console.log(`Number of participants (before): ${beforeParticipants.length}`);
  3405. isLogRequired && console.log(`Number of participants (after): ${participants.length}`);
  3406. isLogRequired && console.log(`Total number of rendered participants: ${cnt.__getAllParticipantsDOMRenderedLength__()}`);
  3407. isLogRequired && console.log(`Participant Renderer Content Updated: ${(resValue & 8) === 8}`);
  3408. isLogRequired && console.groupEnd();
  3409. // requestAnimationFrame is required to avoid particiant update during DOM changing (stampDomArraySplices_)
  3410. // mutex lock with requestAnimationFrame can also disable participants update in background
  3411. requestAnimationFrame(lockResolve);
  3412. } else {
  3413. lockResolve();
  3414. }
  3415.  
  3416. });
  3417.  
  3418. });
  3419.  
  3420. }
  3421.  
  3422. return { notifyPath7081 };
  3423.  
  3424. })();
  3425.  
  3426. const whenDefinedMultiple = async (tags) => {
  3427.  
  3428. const sTags = [...new Set(tags)];
  3429. const len = sTags.length;
  3430.  
  3431. const pTags = new Array(len);
  3432. for (let i = 0; i < len; i++) {
  3433. pTags[i] = customElements.whenDefined(sTags[i]);
  3434. }
  3435.  
  3436. await Promise.all(pTags);
  3437. pTags.length = 0;
  3438.  
  3439. return sTags;
  3440.  
  3441. }
  3442.  
  3443. const onRegistryReadyForDataManipulation = () => {
  3444.  
  3445. function dummy5035(a, b, c) { }
  3446. function dummy411(a, b, c) { }
  3447.  
  3448.  
  3449.  
  3450. customElements.whenDefined("yt-live-chat-participant-list-renderer").then(() => {
  3451.  
  3452. if (!DO_PARTICIPANT_LIST_HACKS) return;
  3453.  
  3454. const tag = "yt-live-chat-participant-list-renderer";
  3455. const cProto = getProto(document.createElement(tag));
  3456. if (!cProto || typeof cProto.attached !== 'function') {
  3457. // for _registered, proto.attached shall exist when the element is defined.
  3458. // for controller extraction, attached shall exist when instance creates.
  3459. console.warn(`proto.attached for ${tag} is unavailable.`);
  3460. return;
  3461. }
  3462.  
  3463.  
  3464. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-participant-list-renderer hacks");
  3465.  
  3466. const fgsArr = ['kevlar_tuner_should_test_maintain_stable_list', 'kevlar_should_maintain_stable_list', 'kevlar_tuner_should_test_reuse_components', 'kevlar_tuner_should_reuse_components'];
  3467. const fgs = {};
  3468. for (const key of fgsArr) fgs[key] = undefined;
  3469.  
  3470. try {
  3471. const EXPERIMENT_FLAGS = ytcfg.data_.EXPERIMENT_FLAGS;
  3472. for (const key of fgsArr) fgs[key] = EXPERIMENT_FLAGS[key];
  3473. } catch (e) { }
  3474. console.log(`EXPERIMENT_FLAGS: ${JSON.stringify(fgs, null, 2)}`);
  3475.  
  3476. const canDoReplacement = (() => {
  3477. if (typeof cProto.__notifyPath5035__ === 'function' && cProto.__notifyPath5035__.name !== 'dummy5035') {
  3478. console.warn('YouTube Live Chat Tamer is running.');
  3479. return;
  3480. }
  3481.  
  3482. if (typeof cProto.__attached411__ === 'function' && cProto.__attached411__.name !== 'dummy411') {
  3483. console.warn('YouTube Live Chat Tamer is running.');
  3484. return;
  3485. }
  3486.  
  3487. cProto.__notifyPath5035__ = dummy5035 // just to against Live Chat Tamer
  3488. cProto.__attached411__ = dummy411 // just to against Live Chat Tamer
  3489.  
  3490. if (typeof cProto.flushRenderStamperComponentBindings_ !== 'function' || cProto.flushRenderStamperComponentBindings_.length !== 0) {
  3491. console.warn("ERROR(0xE355): cProto.flushRenderStamperComponentBindings_ not found");
  3492. return;
  3493. }
  3494.  
  3495. if (typeof cProto.flushRenderStamperComponentBindings66_ === 'function') {
  3496. console.warn("ERROR(0xE356): cProto.flushRenderStamperComponentBindings66_");
  3497. return;
  3498. }
  3499.  
  3500. if (typeof cProto.__getAllParticipantsDOMRenderedLength__ === 'function') {
  3501. console.warn("ERROR(0xE357): cProto.__getAllParticipantsDOMRenderedLength__");
  3502. return;
  3503. }
  3504. return true;
  3505. })();
  3506.  
  3507. console.log(`Data Manipulation Boost = ${canDoReplacement}`);
  3508.  
  3509. assertor(() => fnIntegrity(cProto.attached, '0.32.22')) // just warning
  3510. if (typeof cProto.flushRenderStamperComponentBindings_ === 'function') {
  3511. const fiRSCB = fnIntegrity(cProto.flushRenderStamperComponentBindings_);
  3512. // const s = fiRSCB.split('.');
  3513. // Feb 2024: 0.403.247 => NG
  3514. // if (s[0] === '0' && +s[1] > 381 && +s[1] < 391 && +s[2] > 228 && +s[2] < 238) {
  3515. // console.log(`flushRenderStamperComponentBindings_ ### ${fiRSCB} ### - OK`);
  3516. // } else {
  3517. // console.log(`flushRenderStamperComponentBindings_ ### ${fiRSCB} ### - NG`);
  3518. // }
  3519. console.log(`flushRenderStamperComponentBindings_ ### ${fiRSCB} ###`);
  3520. } else {
  3521. console.log("flushRenderStamperComponentBindings_ - not found");
  3522. }
  3523. // assertor(() => fnIntegrity(cProto.flushRenderStamperComponentBindings_, '0.386.233')) // just warning
  3524.  
  3525. if (typeof cProto.flushRenderStamperComponentBindings_ === 'function') {
  3526. cProto.flushRenderStamperComponentBindings66_ = cProto.flushRenderStamperComponentBindings_;
  3527. cProto.flushRenderStamperComponentBindings_ = function () {
  3528. // console.log('flushRenderStamperComponentBindings_')
  3529. this.flushRenderStamperComponentBindings66_();
  3530. if (this.resolveForDOMRendering781) {
  3531. this.resolveForDOMRendering781();
  3532. this.resolveForDOMRendering781 = null;
  3533. }
  3534. };
  3535. }
  3536.  
  3537. cProto.__getAllParticipantsDOMRenderedLength__ = function () {
  3538. const container = ((this || 0).$ || 0).participants;
  3539. if (!container) return 0;
  3540. return HTMLElement.prototype.querySelectorAll.call(container, 'yt-live-chat-participant-renderer').length;
  3541. }
  3542.  
  3543. const onPageElements = [...document.querySelectorAll('yt-live-chat-participant-list-renderer:not(.n9fJ3)')];
  3544.  
  3545. cProto.__attached412__ = cProto.attached;
  3546. const fpPList = function (hostElement) {
  3547. const cnt = insp(hostElement);
  3548. if (beforeParticipantsMap.has(cnt)) return;
  3549. hostElement.classList.add('n9fJ3');
  3550.  
  3551. assertor(() => (cnt.__dataEnabled === true && cnt.__dataReady === true));
  3552. if (typeof cnt.notifyPath !== 'function' || typeof cnt.__notifyPath5036__ !== 'undefined') {
  3553. console.warn("ERROR(0xE318): yt-live-chat-participant-list-renderer")
  3554. return;
  3555. }
  3556.  
  3557. groupCollapsed("Participant List attached", "");
  3558. // cnt.$.participants.appendChild = cnt.$.participants.__shady_native_appendChild = function(){
  3559. // console.log(123, 'appendChild');
  3560. // return HTMLElement.prototype.appendChild.apply(this, arguments)
  3561. // }
  3562.  
  3563. // cnt.$.participants.insertBefore =cnt.$.participants.__shady_native_insertBefore = function(){
  3564. // console.log(123, 'insertBefore');
  3565. // return HTMLElement.prototype.insertBefore.apply(this, arguments)
  3566. // }
  3567.  
  3568. cnt.__notifyPath5036__ = cnt.notifyPath
  3569. const participants = ((cnt.participantsManager || 0).participants || 0);
  3570. assertor(() => (participants.length > -1 && typeof participants.slice === 'function'));
  3571. console.log(`initial number of participants: ${participants.length}`);
  3572. const newParticipants = (participants.length >= 1 && typeof participants.slice === 'function') ? participants.slice(0) : [];
  3573. beforeParticipantsMap.set(cnt, newParticipants);
  3574. cnt.notifyPath = notifyPath7081;
  3575. console.log(`CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT = ${CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT}`);
  3576. console.groupEnd();
  3577. }
  3578. cProto.attached = function () {
  3579. fpPList(this.hostElement || this);
  3580. this.__attached412__.apply(this, arguments);
  3581. };
  3582.  
  3583.  
  3584. if (ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST) {
  3585.  
  3586. /** @type {boolean | (()=>boolean)} */
  3587. let toUseMaintainStableList = USE_MAINTAIN_STABLE_LIST_ONLY_WHEN_KS_FLAG_IS_SET ? (() => ytcfg.data_.EXPERIMENT_FLAGS.kevlar_should_maintain_stable_list === true) : true;
  3588. if (typeof cProto.stampDomArray_ === 'function' && cProto.stampDomArray_.length === 6 && !cProto.stampDomArray_.nIegT && !cProto.stampDomArray66_) {
  3589.  
  3590. let lastMessageDate = 0;
  3591. cProto.stampDomArray66_ = cProto.stampDomArray_;
  3592.  
  3593. cProto.stampDomArray_ = function (...args) {
  3594. if (args[0] && args[0].length > 0 && args[1] === "participants" && args[2] && args[3] === true && !args[5]) {
  3595. if (typeof toUseMaintainStableList === 'function') {
  3596. toUseMaintainStableList = toUseMaintainStableList();
  3597. }
  3598. args[5] = toUseMaintainStableList;
  3599. let currentDate = Date.now();
  3600. if (currentDate - lastMessageDate > 440) {
  3601. lastMessageDate = currentDate;
  3602. console.log('maintain_stable_list for participants list', toUseMaintainStableList);
  3603. }
  3604. }
  3605. return this.stampDomArray66_.apply(this, args);
  3606. }
  3607.  
  3608. cProto.stampDomArray_.nIegT = 1;
  3609.  
  3610. }
  3611. console.log(`ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST - YES`);
  3612. } else {
  3613. console.log(`ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST - NO`);
  3614. }
  3615.  
  3616. console.groupEnd();
  3617.  
  3618. if (onPageElements.length >= 1) {
  3619. for (const s of onPageElements) {
  3620. if (insp(s).isAttached === true) {
  3621. fpPList(s);
  3622. }
  3623. }
  3624. }
  3625.  
  3626. }).catch(console.warn);
  3627.  
  3628. };
  3629.  
  3630. if (DO_PARTICIPANT_LIST_HACKS) {
  3631. promiseForCustomYtElementsReady.then(onRegistryReadyForDataManipulation);
  3632. }
  3633.  
  3634.  
  3635.  
  3636. const rafHub = (ENABLE_RAF_HACK_TICKERS || ENABLE_RAF_HACK_DOCKED_MESSAGE || ENABLE_RAF_HACK_INPUT_RENDERER || ENABLE_RAF_HACK_EMOJI_PICKER) ? new RAFHub() : null;
  3637.  
  3638. const transitionEndAfterFnSimple = new WeakMap();
  3639. // let prevTransitionClosing = null;
  3640.  
  3641. const fixChildrenIssue = !!fixChildrenIssue801;
  3642. if (fixChildrenIssue && typeof Object.getOwnPropertyDescriptor === 'function' && typeof Proxy !== 'undefined') {
  3643. const divProto = HTMLDivElement.prototype;
  3644. const polymerControllerSetData3 = function (c, d, e) {
  3645. return insp(this).set(c, d, e);
  3646. }
  3647. const polymerControllerSetData2 = function (c, d) {
  3648. return insp(this).set(c, d);
  3649. }
  3650. const dummyFn = function () {
  3651. console.log('dummyFn', ...arguments);
  3652. };
  3653.  
  3654. const wm44 = new Map();
  3655. function unPolymerSet(elem) {
  3656. const is = elem.is;
  3657. if (is && !elem.set) {
  3658. let rt = wm44.get(is);
  3659. if (!rt) {
  3660. rt = 1;
  3661. const cnt = insp(elem);
  3662. if (cnt !== elem && cnt && typeof cnt.set === 'function') {
  3663. const pcSet = cnt.constructor.prototype.set;
  3664. if (pcSet && typeof pcSet === 'function' && pcSet.length === 3) {
  3665. rt = polymerControllerSetData3;
  3666. } else if (pcSet && typeof pcSet === 'function' && pcSet.length === 2) {
  3667. rt = polymerControllerSetData2;
  3668. }
  3669. }
  3670. wm44.set(is, rt);
  3671. }
  3672. if (typeof rt === 'function') {
  3673. elem.set = rt;
  3674. } else {
  3675. elem.set = dummyFn;
  3676. }
  3677. }
  3678. }
  3679. if (!divProto.__children577__ && !divProto.__children578__) {
  3680.  
  3681. const dp = Object.getOwnPropertyDescriptor(Element.prototype, 'children');
  3682. const dp2 = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children');
  3683. const dp3 = Object.getOwnPropertyDescriptor(divProto, 'children');
  3684.  
  3685. if (dp && dp.configurable === true && dp.enumerable === true && typeof dp.get === 'function' && !dp2 && !dp3) {
  3686.  
  3687. if (divProto instanceof HTMLElement && divProto instanceof Element) {
  3688.  
  3689. let m = Object.assign({}, dp);
  3690. divProto.__children577__ = dp.get;
  3691. divProto.__children578__ = function () {
  3692. if (this.__children803__) return this.__children803__;
  3693. if (this.__children801__) {
  3694. let arr = [];
  3695. for (let elem = this.firstElementChild; elem !== null; elem = elem.nextElementSibling) {
  3696. if (elem.is) {
  3697. unPolymerSet(elem);
  3698. arr.push(elem);
  3699. }
  3700. }
  3701. if (this.__children801__ === 2) this.__children803__ = arr;
  3702. return arr;
  3703. }
  3704. return 577;
  3705. };
  3706. m.get = function () {
  3707. const r = this.__children578__();
  3708. if (r !== 577) return r;
  3709. return this.__children577__();
  3710. };
  3711. Object.defineProperty(divProto, 'children', m);
  3712.  
  3713. console.log('fixChildrenIssue - set OK')
  3714.  
  3715. }
  3716. }
  3717.  
  3718. }
  3719.  
  3720.  
  3721. }
  3722.  
  3723.  
  3724. // const bnForDelayChatOccurrence = () => {
  3725.  
  3726. // document.addEventListener('animationstart', (evt) => {
  3727.  
  3728. // if (evt.animationName === 'dontRenderAnimation') {
  3729. // evt.target.classList.remove('dont-render');
  3730. // if (scrollChatFn) scrollChatFn();
  3731. // }
  3732.  
  3733. // }, true);
  3734.  
  3735. // const f = (elm) => {
  3736. // if (elm && elm.nodeType === 1) {
  3737. // if (!skipDontRender && allowDontRender === true) {
  3738. // // innerTextFixFn();
  3739. // elm.classList.add('dont-render');
  3740. // }
  3741. // }
  3742. // }
  3743.  
  3744. // Node.prototype.__appendChild931__ = function (a) {
  3745. // a = dr(a);
  3746. // if (this.id === 'items' && this.classList.contains('yt-live-chat-item-list-renderer')) {
  3747. // if (a && a.nodeType === 1) f(a);
  3748. // else if (a instanceof DocumentFragment) {
  3749. // for (let n = a.firstChild; n; n = n.nextSibling) {
  3750. // f(n);
  3751. // }
  3752. // }
  3753. // }
  3754. // }
  3755.  
  3756. // Node.prototype.__appendChild932__ = function () {
  3757. // this.__appendChild931__.apply(this, arguments);
  3758. // return Node.prototype.appendChild.apply(this, arguments);
  3759. // }
  3760.  
  3761.  
  3762. // };
  3763.  
  3764. const watchUserCSS = () => {
  3765.  
  3766. // if (!CSS.supports('contain-intrinsic-size', 'auto var(--wsr94)')) return;
  3767.  
  3768. const getElemFromWR = (nr) => {
  3769. const n = kRef(nr);
  3770. if (n && n.isConnected) return n;
  3771. return null;
  3772. }
  3773.  
  3774. const clearContentVisibilitySizing = () => {
  3775. Promise.resolve().then(() => {
  3776.  
  3777. const e = document.querySelector('#show-more[disabled]');
  3778. let btnShowMoreWR = e ? mWeakRef(e) : null;
  3779.  
  3780. let lastVisibleItemWR = null;
  3781. for (const elm of document.querySelectorAll('[wSr93]')) {
  3782. if (elm.getAttribute('wSr93') === 'visible') lastVisibleItemWR = mWeakRef(elm);
  3783. elm.setAttribute('wSr93', '');
  3784. // custom CSS property --wsr94 not working when attribute wSr93 removed
  3785. }
  3786. foregroundPromiseFn().then(() => {
  3787. const btnShowMore = getElemFromWR(btnShowMoreWR); btnShowMoreWR = null;
  3788. if (btnShowMore) btnShowMore.click();
  3789. else {
  3790. // would not work if switch it frequently
  3791. const lastVisibleItem = getElemFromWR(lastVisibleItemWR); lastVisibleItemWR = null;
  3792. if (lastVisibleItem) {
  3793.  
  3794. Promise.resolve()
  3795. .then(() => lastVisibleItem.scrollIntoView())
  3796. .then(() => lastVisibleItem.scrollIntoView(false))
  3797. .then(() => lastVisibleItem.scrollIntoView({ behavior: "instant", block: "end", inline: "nearest" }))
  3798. .catch(e => { }) // break the chain when method not callable
  3799.  
  3800. }
  3801. }
  3802. });
  3803.  
  3804. });
  3805.  
  3806. }
  3807.  
  3808. const mutObserver = new MutationObserver((mutations) => {
  3809. for (const mutation of mutations) {
  3810. if ((mutation.addedNodes || 0).length >= 1) {
  3811. for (const addedNode of mutation.addedNodes) {
  3812. if (addedNode.nodeName === 'STYLE') {
  3813. clearContentVisibilitySizing();
  3814. return;
  3815. }
  3816. }
  3817. }
  3818. if ((mutation.removedNodes || 0).length >= 1) {
  3819. for (const removedNode of mutation.removedNodes) {
  3820. if (removedNode.nodeName === 'STYLE') {
  3821. clearContentVisibilitySizing();
  3822. return;
  3823. }
  3824. }
  3825. }
  3826. }
  3827. });
  3828.  
  3829. mutObserver.observe(document.documentElement, {
  3830. childList: true,
  3831. subtree: false
  3832. });
  3833. mutObserver.observe(document.head, {
  3834. childList: true,
  3835. subtree: false
  3836. });
  3837. mutObserver.observe(document.body, {
  3838. childList: true,
  3839. subtree: false
  3840. });
  3841.  
  3842. }
  3843.  
  3844.  
  3845. // class WillChangeController {
  3846. // constructor(itemScroller, willChangeValue) {
  3847. // this.element = itemScroller;
  3848. // this.counter = 0;
  3849. // this.active = false;
  3850. // this.willChangeValue = willChangeValue;
  3851. // }
  3852.  
  3853. // beforeOper() {
  3854. // if (!this.active) {
  3855. // this.active = true;
  3856. // this.element.style.willChange = this.willChangeValue;
  3857. // }
  3858. // this.counter++;
  3859. // }
  3860.  
  3861. // afterOper() {
  3862. // const c = this.counter;
  3863. // foregroundPromiseFn().then(() => {
  3864. // if (c === this.counter) {
  3865. // this.active = false;
  3866. // this.element.style.willChange = '';
  3867. // }
  3868. // });
  3869. // }
  3870.  
  3871. // release() {
  3872. // const element = this.element;
  3873. // this.element = null;
  3874. // this.counter = 1e16;
  3875. // this.active = false;
  3876. // try {
  3877. // element.style.willChange = '';
  3878. // } catch (e) { }
  3879. // }
  3880.  
  3881. // }
  3882.  
  3883.  
  3884. // const skzData = (skz) => skz.data = {
  3885. // "message": {
  3886. // "runs": [
  3887. // {
  3888. // "text": "em2o"
  3889. // },
  3890. // {
  3891. // "emoji": {
  3892. // "emojiId": "cm35z",
  3893. // "shortcuts": [
  3894. // ":_s:",
  3895. // ":s:"
  3896. // ],
  3897. // "searchTerms": [
  3898. // "_s",
  3899. // "s"
  3900. // ],
  3901. // "image": {
  3902. // "thumbnails": [
  3903. // {
  3904. // "url": dummyImgURL,
  3905. // "width": 48,
  3906. // "height": 48
  3907. // }
  3908. // ],
  3909. // "accessibility": {
  3910. // "accessibilityData": {
  3911. // "label": "s"
  3912. // }
  3913. // }
  3914. // },
  3915. // "isCustomEmoji": true
  3916. // }
  3917. // },
  3918. // {
  3919. // "text": "ji"
  3920. // }
  3921. // ]
  3922. // },
  3923. // "authorName": {
  3924. // "simpleText": "N"
  3925. // },
  3926. // "authorPhoto": {
  3927. // "thumbnails": [
  3928. // {
  3929. // "url": dummyImgURL,
  3930. // "width": 64,
  3931. // "height": 64
  3932. // }
  3933. // ]
  3934. // },
  3935. // "contextMenuEndpoint": {
  3936. // "commandMetadata": {
  3937. // "webCommandMetadata": {
  3938. // "ignoreNavigation": true
  3939. // }
  3940. // },
  3941. // "liveChatItemContextMenuEndpoint": {
  3942. // "params": "123=="
  3943. // }
  3944. // },
  3945. // "id": "sk35z",
  3946. // "timestampUsec": "1232302352350000",
  3947. // "authorBadges": [
  3948. // {
  3949. // "liveChatAuthorBadgeRenderer": {
  3950. // "customThumbnail": {
  3951. // "thumbnails": [
  3952. // {
  3953. // "url": dummyImgURL,
  3954. // "width": 16,
  3955. // "height": 16
  3956. // },
  3957. // {
  3958. // "url": dummyImgURL,
  3959. // "width": 32,
  3960. // "height": 32
  3961. // }
  3962. // ]
  3963. // },
  3964. // "tooltip": "T",
  3965. // "accessibility": {
  3966. // "accessibilityData": {
  3967. // "label": "E"
  3968. // }
  3969. // }
  3970. // }
  3971. // }
  3972. // ],
  3973. // "authorExternalChannelId": "A",
  3974. // "contextMenuAccessibility": {
  3975. // "accessibilityData": {
  3976. // "label": "E"
  3977. // }
  3978. // },
  3979. // "timestampText": {
  3980. // "simpleText": "0:43"
  3981. // }
  3982. // };
  3983.  
  3984.  
  3985.  
  3986. const { lcRendererElm, visObserver } = (() => {
  3987.  
  3988.  
  3989.  
  3990. let lcRendererWR = null;
  3991.  
  3992. const lcRendererElm = () => {
  3993. let lcRenderer = kRef(lcRendererWR);
  3994. if (!lcRenderer || !lcRenderer.isConnected) {
  3995. lcRenderer = document.querySelector('yt-live-chat-item-list-renderer.yt-live-chat-renderer');
  3996. lcRendererWR = lcRenderer ? mWeakRef(lcRenderer) : null;
  3997. }
  3998. return lcRenderer;
  3999. };
  4000.  
  4001.  
  4002. let hasFirstShowMore = false;
  4003.  
  4004. const visObserverFn = (entry) => {
  4005.  
  4006. const target = entry.target;
  4007. if (!target) return;
  4008. // if(target.classList.contains('dont-render')) return;
  4009. let isVisible = entry.isIntersecting === true && entry.intersectionRatio > 0.5;
  4010. // const h = entry.boundingClientRect.height;
  4011. /*
  4012. if (h < 16) { // wrong: 8 (padding/margin); standard: 32; test: 16 or 20
  4013. // e.g. under fullscreen. the element created but not rendered.
  4014. target.setAttribute('wSr93', '');
  4015. return;
  4016. }
  4017. */
  4018. if (isVisible) {
  4019. // target.style.setProperty('--wsr94', h + 'px');
  4020. target.setAttribute('wSr93', 'visible');
  4021. if (nNextElem(target) === null) {
  4022.  
  4023. // firstVisibleItemDetected = true;
  4024. /*
  4025. if (dateNow() - lastScroll < 80) {
  4026. lastLShow = 0;
  4027. lastScroll = 0;
  4028. Promise.resolve().then(clickShowMore);
  4029. } else {
  4030. lastLShow = dateNow();
  4031. }
  4032. */
  4033. // lastLShow = dateNow();
  4034. } else if (!hasFirstShowMore) { // should more than one item being visible
  4035. // implement inside visObserver to ensure there is sufficient delay
  4036. hasFirstShowMore = true;
  4037. foregroundPromiseFn().then(() => {
  4038. // foreground page
  4039. // page visibly ready -> load the latest comments at initial loading
  4040. const lcRenderer = lcRendererElm();
  4041. if (lcRenderer) {
  4042. if (typeof nextBrowserTick !== 'function') {
  4043. insp(lcRenderer).scrollToBottom_();
  4044. } else {
  4045. nextBrowserTick(() => {
  4046. const cnt = insp(lcRenderer);
  4047. if (cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  4048. cnt.scrollToBottom_();
  4049. });
  4050. }
  4051. }
  4052. });
  4053. }
  4054. }
  4055. else if (target.getAttribute('wSr93') === 'visible') { // ignore target.getAttribute('wSr93') === '' to avoid wrong sizing
  4056.  
  4057. // target.style.setProperty('--wsr94', h + 'px');
  4058. target.setAttribute('wSr93', 'hidden');
  4059. } // note: might consider 0 < entry.intersectionRatio < 0.5 and target.getAttribute('wSr93') === '' <new last item>
  4060.  
  4061. }
  4062.  
  4063.  
  4064.  
  4065. const visObserver = new IntersectionObserver((entries) => {
  4066.  
  4067. for (const entry of entries) {
  4068.  
  4069. Promise.resolve(entry).then(visObserverFn);
  4070.  
  4071. }
  4072.  
  4073. }, {
  4074. // root: HTMLElement.prototype.closest.call(m2, '#item-scroller.yt-live-chat-item-list-renderer'), // nullable
  4075. rootMargin: "0px",
  4076. threshold: [0.05, 0.95],
  4077. });
  4078.  
  4079.  
  4080. return { lcRendererElm, visObserver }
  4081.  
  4082.  
  4083. })();
  4084.  
  4085. const { setupMutObserver } = (() => {
  4086.  
  4087. async function asyncTickerBackgroundOverridedChecker() {
  4088.  
  4089. try {
  4090. await promiseForCustomYtElementsReady.then();
  4091. await customElements.whenDefined('yt-live-chat-text-message-renderer');
  4092. await new Promise(r => setTimeout(r, 800));
  4093.  
  4094. if (!hasTimerModified) return;
  4095. const tickerRenderer = document.querySelector('#ticker yt-live-chat-ticker-renderer.style-scope.yt-live-chat-renderer');
  4096. if (!tickerRenderer) return;
  4097.  
  4098. const tickerRendererDollar = indr(tickerRenderer);
  4099. const items = (tickerRendererDollar || 0).items || 0;
  4100. if (!items) return;
  4101. const template = document.createElement('template');
  4102. template.innerHTML = `<yt-live-chat-ticker-dummy777-item-renderer class="style-scope yt-live-chat-ticker-renderer" whole-message-clickable=""
  4103. modern="" aria-label="¥1,000" role="button" tabindex="0" id="Chw777" style="width: 94px; overflow: hidden;"
  4104. dimmed="" [dummy777]>
  4105. <div id="container" dir="ltr" class="style-scope yt-live-chat-ticker-dummy777-item-renderer"
  4106. style="--background:linear-gradient(90deg, rgba(1,2,3,1),rgba(1,2,3,1) 7%,rgba(4,0,0,1) 7%,rgba(4,0,0,1));">
  4107. <div id="content" class="style-scope yt-live-chat-ticker-dummy777-item-renderer" style="color: rgb(255, 255, 255);">
  4108. <yt-img-shadow777 id="author-photo" height="24" width="24"
  4109. class="style-scope yt-live-chat-ticker-dummy777-item-renderer no-transition"
  4110. style="background-color: transparent;" loaded=""><img id="img"
  4111. draggable="false" class="style-scope yt-img-shadow" alt="I" height="24" width="24"
  4112. src="${dummyImgURL}"></yt-img-shadow777>
  4113.  
  4114. <span id="text" dir="ltr" class="style-scope yt-live-chat-ticker-dummy777-item-renderer"1,000</span>
  4115. </div>
  4116. </div>
  4117. </yt-live-chat-ticker-dummy777-item-renderer>`;
  4118. const dummy777 = template.content.firstElementChild;
  4119. await Promise.resolve().then();
  4120. let res = 0;
  4121. if (items instanceof HTMLElement && items.isConnected === true) {
  4122. try {
  4123. items.appendChild(dummy777);
  4124. let container = HTMLElement.prototype.querySelector.call(dummy777, '#container') || 0;
  4125. if (container.isConnected === true) {
  4126. const evaluated = `${getComputedStyleCached(container).background}`;
  4127. container = null;
  4128. res = evaluated.indexOf('0.') < 4 ? 1 : 2;
  4129. }
  4130. } catch (e) { console.warn(e) }
  4131. HTMLElement.prototype.remove.call(dummy777);
  4132. }
  4133. await Promise.resolve().then();
  4134. dummy777.textContent = '';
  4135. if (res === 1) {
  4136. // not fulfilling
  4137. // rgba(0, 0, 0, 0.004) none repeat scroll 0% 0% / auto padding-box border-box
  4138. console.groupCollapsed(`%c${"YouTube Super Fast Chat"}%c${" | Incompatibility Found"}`,
  4139. "background-color: #010502; color: #fe806a; font-weight: 700; padding: 2px;",
  4140. "background-color: #010502; color: #fe806a; font-weight: 300; padding: 2px;"
  4141. );
  4142. console.warn(`%cWarning:\n\tYou might have added a userscript or extension that also modifies the ticker background.\n\tYouTube Super Fast Chat is taking over.`, 'color: #bada55');
  4143. console.groupEnd();
  4144. console.log('%cALLOW_ADVANCED_ANIMATED_TICKER_BACKGROUND (Overriding other scripting)', 'background-color: #7eb32b; color: #102624; padding: 2px 4px');
  4145. } else if (res === 2) {
  4146. console.log('%cALLOW_ADVANCED_ANIMATED_TICKER_BACKGROUND', 'background-color: #16c450; color: #102624; padding: 2px 4px');
  4147. }
  4148. } catch (e) {
  4149. console.warn(e);
  4150. }
  4151. }
  4152.  
  4153. // async function asyncDelayChatOccurrence(m2) {
  4154. // try {
  4155. // await promiseForCustomYtElementsReady.then();
  4156. // await customElements.whenDefined('yt-live-chat-text-message-renderer');
  4157. // await new Promise(r => setTimeout(r, 1));
  4158. // const dummy888 = document.createElement('yt-live-chat-text-message-renderer');
  4159. // // const template = document.createElement('template');
  4160. // // template.innerHTML = "<yt-live-chat-text-message-renderer></yt-live-chat-text-message-renderer>"
  4161. // // const dummy888 = template.content.firstElementChild;
  4162. // const skzCnt = insp(dummy888);
  4163. // if (!(skzCnt && 'data' in skzCnt && 'attached' in skzCnt)) {
  4164. // return;
  4165. // }
  4166. // if (!skzCnt.hostElement) skzCnt.hostElement = dummy888;
  4167. // /** @type {HTMLTemplateElement} */
  4168. // const skzElem = dummy888;
  4169. // let cz1 = null;
  4170. // const deferredZy1 = new Promise(resolve => {
  4171. // skzCnt.attached = function () {
  4172. // cz1 = HTMLElement.prototype.querySelector.call(skzElem, '#message img') !== null;
  4173. // resolve(skzElem.textContent);
  4174. // }
  4175. // skzCnt.detached = function () {
  4176. // }
  4177. // });
  4178. // skzElem.id = 'sk35z';
  4179. // skzData(skzCnt);
  4180. // sk35zResolveFn = null;
  4181. // const deferredMutation = new Promise(resolve => {
  4182. // sk35zResolveFn = resolve;
  4183. // HTMLElement.prototype.appendChild.call(m2, skzElem);
  4184. // });
  4185. // const [zy1, _] = await Promise.all([deferredZy1, deferredMutation]);
  4186. // skzCnt.attached = function () { };
  4187. // function fn() {
  4188. // const zy2 = skzElem.textContent;
  4189. // const cz2 = HTMLElement.prototype.querySelector.call(skzElem, '#message img') !== null;
  4190. // if (typeof zy1 === 'string' && typeof zy2 === 'string') {
  4191. // allowDontRender = zy1 === zy2 && cz1 === cz2; // '0:43N​em2oji'
  4192. // }
  4193. // if (allowDontRender === true) return true;
  4194. // if (allowDontRender === false) {
  4195. // console.groupCollapsed(`%c${"YouTube Super Fast Chat"}%c${" | Incompatibility Found"}`,
  4196. // "background-color: #010502; color: #fe806a; font-weight: 700; padding: 2px;",
  4197. // "background-color: #010502; color: #fe806a; font-weight: 300; padding: 2px;"
  4198. // );
  4199. // console.warn(`%cWarning:\n\tYou might have added a userscript or extension that stops YouTube Super Fast Chat's quick loading.\n\tTo figure out which one affects the script, turn them off one by one and let the author know.`, 'color: #bada55');
  4200. // console.groupEnd();
  4201. // }
  4202. // }
  4203. // await new Promise(r => setTimeout(r, 1));
  4204. // if (!fn()) return;
  4205. // await foregroundPromiseFn().then();
  4206. // if (!fn()) return;
  4207. // skzElem.remove();
  4208. // await Promise.resolve().then();
  4209. // skzElem.textContent = '';
  4210. // console.log('%cALLOW_DELAYED_CHAT_OCCURRENCE', 'background-color: #16c450; color: #102624; padding: 2px 4px');
  4211. // } catch (e) {
  4212. // console.warn(e);
  4213. // }
  4214. // }
  4215.  
  4216. const mutFn = (items) => {
  4217. let seqIndex = -1;
  4218. const elementSet = new Set();
  4219. for (let node = nLastElem(items); node !== null; node = nPrevElem(node)) {
  4220. if (node.hasAttribute('wSr93')) {
  4221. seqIndex = parseInt(node.getAttribute('yt-chat-item-seq'), 10);
  4222. break;
  4223. }
  4224. node.setAttribute('wSr93', '');
  4225. visObserver.observe(node);
  4226. elementSet.add(node);
  4227. }
  4228. let iter = elementSet.values();
  4229. let i = seqIndex + elementSet.size;
  4230. for (let curr; curr = iter.next().value;) {
  4231. curr.setAttribute('yt-chat-item-seq', i % 60);
  4232. curr.classList.add('yt-chat-item-' + ((i % 2) ? 'odd' : 'even'));
  4233. i--;
  4234. }
  4235. iter = null;
  4236. elementSet.clear();
  4237. }
  4238.  
  4239. const mutObserver = new MutationObserver((mutations) => {
  4240. const items = (mutations[0] || 0).target;
  4241. if (!items) return;
  4242. if (sk35zResolveFn) {
  4243. sk35zResolveFn();
  4244. sk35zResolveFn = null;
  4245. }
  4246. mutFn(items);
  4247. });
  4248.  
  4249. const setupMutObserver = (m2) => {
  4250. scrollChatFn = null;
  4251. mutObserver.disconnect();
  4252. mutObserver.takeRecords();
  4253. if (m2) {
  4254. if (typeof m2.__appendChild932__ === 'function') {
  4255. if (typeof m2.appendChild === 'function') m2.appendChild = m2.__appendChild932__;
  4256. if (typeof m2.__shady_native_appendChild === 'function') m2.__shady_native_appendChild = m2.__appendChild932__;
  4257. }
  4258. mutObserver.observe(m2, {
  4259. childList: true,
  4260. subtree: false
  4261. });
  4262. mutFn(m2);
  4263.  
  4264. const isFirstList = firstList;
  4265. firstList = false;
  4266.  
  4267. if (ENABLE_OVERFLOW_ANCHOR) {
  4268.  
  4269. let items = m2;
  4270. let addedAnchor = false;
  4271. if (items) {
  4272. if (items.nextElementSibling === null) {
  4273. items.classList.add('no-anchor');
  4274. addedAnchor = true;
  4275. items.parentNode.appendChild(dr(document.createElement('item-anchor')));
  4276. }
  4277. }
  4278.  
  4279.  
  4280.  
  4281. if (addedAnchor) {
  4282. nodeParent(m2).classList.add('no-anchor'); // required
  4283. }
  4284.  
  4285. }
  4286.  
  4287.  
  4288.  
  4289. if (ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX) {
  4290.  
  4291. (() => {
  4292.  
  4293. const tag = 'yt-iframed-player-events-relay'
  4294. const dummy = document.createElement(tag);
  4295.  
  4296. const cProto = getProto(dummy);
  4297. if (!cProto || !cProto.handlePostMessage_) {
  4298. console.warn(`proto.handlePostMessage_ for ${tag} is unavailable.`);
  4299. return;
  4300. }
  4301.  
  4302. if (typeof cProto.handlePostMessage_ === 'function' && !cProto.handlePostMessage66_ && !cProto.handlePostMessage67_ ) {
  4303.  
  4304. cProto.handlePostMessage66_ = cProto.handlePostMessage_;
  4305.  
  4306. const handlePostMessageAfterPromiseA = (da) => {
  4307.  
  4308. if (!da || typeof da !== 'object') return;
  4309.  
  4310. if ('yt-player-state-change' in da) {
  4311.  
  4312. const qc = da['yt-player-state-change'];
  4313.  
  4314.  
  4315. let isQcChanged = false;
  4316.  
  4317. if (qc === 2) { isQcChanged = qc !== _playerState; _playerState = 2; relayCount = 0; } // paused
  4318. else if (qc === 3) { isQcChanged = qc !== _playerState; _playerState = 3; } // playing
  4319. else if (qc === 1) { isQcChanged = qc !== _playerState; _playerState = 1; } // playing
  4320.  
  4321.  
  4322. if ((isQcChanged) && playerState !== _playerState) {
  4323. playerEventsByIframeRelay = true;
  4324. onPlayStateChangePromise = new Promise((resolve) => {
  4325. const k = _playerState;
  4326. foregroundPromiseFn().then(() => {
  4327. if (k === _playerState && playerState !== _playerState) playerState = _playerState;
  4328. onPlayStateChangePromise = null;
  4329. resolve();
  4330. })
  4331. }).catch(console.warn);
  4332.  
  4333. }
  4334.  
  4335. } else if ('yt-player-video-progress' in da) {
  4336. const vp = da['yt-player-video-progress'];
  4337.  
  4338.  
  4339. relayCount++;
  4340. lastPlayerProgress = vp > 0 ? vp : 0;
  4341.  
  4342.  
  4343. if (relayPromise && vp > 0 && relayCount >= 2) {
  4344. if (onPlayStateChangePromise) {
  4345. onPlayStateChangePromise.then(() => {
  4346. relayPromise && relayPromise.resolve();
  4347. relayPromise = null;
  4348. })
  4349. } else {
  4350. relayPromise.resolve();
  4351. relayPromise = null;
  4352. }
  4353. }
  4354.  
  4355. }
  4356.  
  4357. };
  4358.  
  4359. cProto.handlePostMessage67_ = function (a) {
  4360.  
  4361. let da = a.data;
  4362. const wNode = mWeakRef(this);
  4363. // const wData = mWeakRef(da);
  4364.  
  4365. playEventsStack = playEventsStack.then(() => {
  4366.  
  4367. const cnt = kRef(wNode);
  4368. // const da = kRef(wData);
  4369.  
  4370. if (!cnt || !a || !da) return;
  4371. handlePostMessageAfterPromiseA(da);
  4372. da = null;
  4373.  
  4374. const r = cnt.handlePostMessage66_(a);
  4375. a = null;
  4376.  
  4377. }).catch(console.warn);
  4378.  
  4379. }
  4380.  
  4381. const handlePostMessageAfterPromiseB = (da) => {
  4382.  
  4383. const lcr = document.querySelector('yt-live-chat-renderer');
  4384. const psc = document.querySelector("yt-player-seek-continuation");
  4385. if (lcr && psc && lcr.replayBuffer_) {
  4386.  
  4387. const rbProgress = lcr.replayBuffer_.lastVideoOffsetTimeMsec;
  4388. const daProgress = da['yt-player-video-progress'] * 1000
  4389. // document.querySelector('yt-live-chat-renderer').playerProgressChanged_(1e-5);
  4390.  
  4391. const front_ = (lcr.replayBuffer_.replayQueue || 0).front_;
  4392. const back_ = (lcr.replayBuffer_.replayQueue || 0).back_;
  4393.  
  4394. // console.log(deepCopy( front_))
  4395. // console.log(deepCopy( back_))
  4396. // console.log(rbProgress, daProgress, )
  4397. if (front_ && back_ && rbProgress > daProgress && back_.length > 2 && back_.some(e => e && +e.videoOffsetTimeMsec > daProgress) && back_.some(e => e && +e.videoOffsetTimeMsec < daProgress)) {
  4398. // no action
  4399. // console.log('ss1')
  4400. } else if (rbProgress < daProgress + 3400 && rbProgress > daProgress - 1200) {
  4401. // daProgress - 1200 < rbProgress < daProgress + 3400
  4402. // console.log('ss2')
  4403. } else {
  4404.  
  4405. lcr.previousProgressSec = 1E-5;
  4406. // lcr._setIsSeeking(!0),
  4407. lcr.replayBuffer_.clear()
  4408. psc.fireSeekContinuation_(da['yt-player-video-progress']);
  4409. }
  4410.  
  4411. }
  4412.  
  4413.  
  4414. };
  4415.  
  4416. cProto.handlePostMessage_ = function (a) {
  4417.  
  4418. let da = (a || 0).data || 0;
  4419. const wNode = mWeakRef(this);
  4420.  
  4421. if (typeof da !== 'object') return;
  4422.  
  4423. if (waitForInitialDataCompletion === 1) return;
  4424.  
  4425. if (!isPlayProgressTriggered) {
  4426. isPlayProgressTriggered = true; // set once
  4427.  
  4428. if ('yt-player-video-progress' in da) {
  4429. waitForInitialDataCompletion = 1;
  4430.  
  4431. const wrapWith = (data) => {
  4432. const { origin } = a;
  4433. return {
  4434. origin,
  4435. data
  4436. };
  4437. }
  4438.  
  4439. this.handlePostMessage67_(wrapWith({
  4440. "yt-iframed-parent-ready": true
  4441. }));
  4442.  
  4443.  
  4444. playEventsStack = playEventsStack.then(() => {
  4445.  
  4446. const cnt = kRef(wNode);
  4447.  
  4448. if (!cnt || !a || !da) return;
  4449.  
  4450. handlePostMessageAfterPromiseB(da);
  4451. da = null;
  4452.  
  4453. waitForInitialDataCompletion = 2;
  4454.  
  4455. const r = cnt.handlePostMessage_(a); // isPlayProgressTriggered is set
  4456. a = null;
  4457.  
  4458. }).catch(console.warn);
  4459.  
  4460. return;
  4461.  
  4462. }
  4463.  
  4464. }
  4465.  
  4466. this.handlePostMessage67_(a);
  4467.  
  4468. }
  4469.  
  4470. }
  4471.  
  4472.  
  4473. })();
  4474.  
  4475. }
  4476.  
  4477. if (isFirstList && DO_CHECK_TICKER_BACKGROUND_OVERRIDED) {
  4478. asyncTickerBackgroundOverridedChecker();
  4479. }
  4480.  
  4481. }
  4482. }
  4483.  
  4484. return { setupMutObserver };
  4485.  
  4486.  
  4487.  
  4488. })();
  4489.  
  4490. const setupEvents = () => {
  4491.  
  4492.  
  4493. let scrollCount = 0;
  4494.  
  4495. const passiveCapture = typeof IntersectionObserver === 'function' ? { capture: true, passive: true } : true;
  4496.  
  4497.  
  4498. const delayFlushActiveItemsAfterUserActionK_ = () => {
  4499.  
  4500. const lcRenderer = lcRendererElm();
  4501. if (lcRenderer) {
  4502. const cnt = insp(lcRenderer);
  4503. if (!cnt.hasUserJustInteracted11_) return;
  4504. if (cnt.atBottom && cnt.allowScroll && cnt.activeItems_.length >= 1 && cnt.hasUserJustInteracted11_()) {
  4505. cnt.delayFlushActiveItemsAfterUserAction11_ && cnt.delayFlushActiveItemsAfterUserAction11_();
  4506. }
  4507. }
  4508.  
  4509. }
  4510.  
  4511. document.addEventListener('scroll', (evt) => {
  4512. if (!evt || !evt.isTrusted) return;
  4513. // lastScroll = dateNow();
  4514. if (++scrollCount > 1e9) scrollCount = 9;
  4515. }, passiveCapture); // support contain => support passive
  4516.  
  4517. let lastScrollCount = -1;
  4518. document.addEventListener('wheel', (evt) => {
  4519. if (!evt || !evt.isTrusted) return;
  4520. if (lastScrollCount === scrollCount) return;
  4521. lastScrollCount = scrollCount;
  4522. lastWheel = dateNow();
  4523. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  4524. }, passiveCapture); // support contain => support passive
  4525.  
  4526. document.addEventListener('mousedown', (evt) => {
  4527. if (!evt || !evt.isTrusted) return;
  4528. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  4529. lastMouseDown = dateNow();
  4530. currentMouseDown = true;
  4531. lastUserInteraction = lastMouseDown;
  4532. }, passiveCapture);
  4533.  
  4534. document.addEventListener('pointerdown', (evt) => {
  4535. if (!evt || !evt.isTrusted) return;
  4536. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  4537. lastMouseDown = dateNow();
  4538. currentMouseDown = true;
  4539. lastUserInteraction = lastMouseDown;
  4540. }, passiveCapture);
  4541.  
  4542. document.addEventListener('click', (evt) => {
  4543. if (!evt || !evt.isTrusted) return;
  4544. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  4545. lastMouseDown = lastMouseUp = dateNow();
  4546. currentMouseDown = false;
  4547. lastUserInteraction = lastMouseDown;
  4548. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  4549. }, passiveCapture);
  4550.  
  4551. document.addEventListener('tap', (evt) => {
  4552. if (!evt || !evt.isTrusted) return;
  4553. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  4554. lastMouseDown = lastMouseUp = dateNow();
  4555. currentMouseDown = false;
  4556. lastUserInteraction = lastMouseDown;
  4557. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  4558. }, passiveCapture);
  4559.  
  4560.  
  4561. document.addEventListener('mouseup', (evt) => {
  4562. if (!evt || !evt.isTrusted) return;
  4563. if (currentMouseDown) {
  4564. lastMouseUp = dateNow();
  4565. currentMouseDown = false;
  4566. lastUserInteraction = lastMouseUp;
  4567. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  4568. }
  4569. }, passiveCapture);
  4570.  
  4571.  
  4572. document.addEventListener('pointerup', (evt) => {
  4573. if (!evt || !evt.isTrusted) return;
  4574. if (currentMouseDown) {
  4575. lastMouseUp = dateNow();
  4576. currentMouseDown = false;
  4577. lastUserInteraction = lastMouseUp;
  4578. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  4579. }
  4580. }, passiveCapture);
  4581.  
  4582. document.addEventListener('touchstart', (evt) => {
  4583. if (!evt || !evt.isTrusted) return;
  4584. lastTouchDown = dateNow();
  4585. currentTouchDown = true;
  4586. lastUserInteraction = lastTouchDown;
  4587. }, passiveCapture);
  4588.  
  4589. document.addEventListener('touchmove', (evt) => {
  4590. if (!evt || !evt.isTrusted) return;
  4591. lastTouchDown = dateNow();
  4592. currentTouchDown = true;
  4593. lastUserInteraction = lastTouchDown;
  4594. }, passiveCapture);
  4595.  
  4596. document.addEventListener('touchend', (evt) => {
  4597. if (!evt || !evt.isTrusted) return;
  4598. if (currentTouchDown) {
  4599. lastTouchUp = dateNow();
  4600. currentTouchDown = false;
  4601. lastUserInteraction = lastTouchUp;
  4602. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  4603. }
  4604. }, passiveCapture);
  4605.  
  4606. document.addEventListener('touchcancel', (evt) => {
  4607. if (!evt || !evt.isTrusted) return;
  4608. if (currentTouchDown) {
  4609. lastTouchUp = dateNow();
  4610. currentTouchDown = false;
  4611. lastUserInteraction = lastTouchUp;
  4612. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  4613. }
  4614. }, passiveCapture);
  4615.  
  4616.  
  4617. }
  4618.  
  4619. const getTimestampUsec = (itemRenderer) => {
  4620. if (itemRenderer && 'timestampUsec' in itemRenderer) {
  4621. return itemRenderer.timestampUsec
  4622. } else if (itemRenderer && itemRenderer.showItemEndpoint) {
  4623. const messageRenderer = ((itemRenderer.showItemEndpoint.showLiveChatItemEndpoint || 0).renderer || 0);
  4624. if (messageRenderer) {
  4625.  
  4626. const messageRendererKey = firstObjectKey(messageRenderer);
  4627. if (messageRendererKey && messageRenderer[messageRendererKey]) {
  4628. const messageRendererData = messageRenderer[messageRendererKey];
  4629. if (messageRendererData && 'timestampUsec' in messageRendererData) {
  4630. return messageRendererData.timestampUsec
  4631. }
  4632. }
  4633. }
  4634. }
  4635. return null;
  4636. }
  4637.  
  4638. const onRegistryReadyForDOMOperations = () => {
  4639.  
  4640. let firstCheckedOnYtInit = false;
  4641.  
  4642. const assertorURL = () => assertor(() => location.pathname.startsWith('/live_chat') && (location.search.indexOf('continuation=') > 0 || location.search.indexOf('v=') > 0));
  4643.  
  4644. const mightFirstCheckOnYtInit = () => {
  4645. if (firstCheckedOnYtInit) return;
  4646. firstCheckedOnYtInit = true;
  4647.  
  4648. if (!document.body || !document.head) return;
  4649. if (!assertorURL()) return;
  4650.  
  4651. addCssManaged();
  4652.  
  4653. let efsContainer = document.getElementById('elzm-fonts-yk75g');
  4654. if (efsContainer && efsContainer.parentNode !== document.body) {
  4655. document.body.appendChild(efsContainer);
  4656. }
  4657.  
  4658. };
  4659.  
  4660. if (!assertorURL()) return;
  4661. // if (!assertor(() => document.getElementById('yt-masthead') === null)) return;
  4662.  
  4663.  
  4664. const { weakWrap } = (() => {
  4665.  
  4666.  
  4667. // const tickerFuncProps = new Set([
  4668. // 'animateShowStats', 'animateHideStats', // updateStatsBarAndMaybeShowAnimationRevised
  4669. // 'collapse', // slideDownNoSelfLeakage
  4670. // 'requestRemoval', // collapseNoSelfLeakage
  4671. // 'setContainerWidth', 'get', 'set', // deletedChangedNoSelfLeakage
  4672. // 'computeAriaLabel', //dataChanged
  4673. // 'startCountdown', // dataChanged [in case]
  4674. // ]);
  4675.  
  4676. // const tickerTags = new Set([
  4677. // "yt-live-chat-ticker-renderer",
  4678. // "yt-live-chat-ticker-paid-message-item-renderer",
  4679. // "yt-live-chat-ticker-paid-sticker-item-renderer",
  4680. // "yt-live-chat-ticker-sponsor-item-renderer"
  4681. // ]);
  4682.  
  4683. // const emptySet = new Set();
  4684.  
  4685.  
  4686.  
  4687. // const tickerFuncPropsFn = (cnt) => {
  4688.  
  4689. // const is = `${cnt.is}`;
  4690.  
  4691. // if (tickerTags.has(is)) {
  4692. // let flg = 0;
  4693. // if (cnt.get && cnt.set) flg |= 1;
  4694. // if (cnt.setContainerWidth && cnt.collapse && cnt.requestRemoval) flg |= 2;
  4695. // if (cnt.animateShowStats && cnt.animateHideStats) flg |= 4;
  4696. // if (cnt.startCountdown) flg |= 8;
  4697. // console.log(`DEBUG flag_6877 = ${flg}`, is);
  4698. // // DEBUG flag_6877 = 15 yt-live-chat-ticker-paid-message-item-renderer
  4699. // // DEBUG flag_6877 = 11 yt-live-chat-ticker-sponsor-item-renderer
  4700. // return tickerFuncProps;
  4701. // }
  4702.  
  4703. // return emptySet;
  4704.  
  4705.  
  4706. // }
  4707.  
  4708.  
  4709. // const smb = Symbol();
  4710. const vmb = 'dtz02' // Symbol(); // return kThis for thisArg
  4711. const vmc = 'dtz04' // Symbol(); // whether it is proxied fn
  4712. const vmd = 'dtz08' // Symbol(); // self fn proxy (fn--fn)
  4713.  
  4714.  
  4715.  
  4716.  
  4717. const thisConversionFn = (thisArg) => {
  4718. if (!thisArg) return null;
  4719. const kThis = thisArg[vmb];
  4720. if (kThis) {
  4721. const ref = kThis.ref;
  4722. return (ref ? kRef(ref) : null) || null;
  4723. }
  4724. return thisArg;
  4725. }
  4726. const pFnHandler2 = {
  4727. get(target, prop) {
  4728. if (prop === vmc) return target;
  4729. return Reflect.get(target, prop);
  4730. },
  4731. apply(target, thisArg, argumentsList) {
  4732. thisArg = thisConversionFn(thisArg);
  4733. if (thisArg) return Reflect.apply(target, thisArg, argumentsList);
  4734. }
  4735. }
  4736. const proxySelfHandler = {
  4737. get(target, prop) {
  4738. if(prop === vmb) return target;
  4739. const ref = target.ref;
  4740. const cnt = kRef(ref);
  4741. if (!cnt) return;
  4742. if (typeof cnt[prop] === 'function' && !cnt[prop][vmc] && !cnt[prop][vmb]) {
  4743. if (!cnt[prop][vmd]) cnt[prop][vmd] = new Proxy(cnt[prop], pFnHandler2);
  4744. return cnt[prop][vmd];
  4745. }
  4746. return cnt[prop];
  4747. },
  4748. set(target, prop, value) {
  4749. const cnt = kRef(target.ref);
  4750. if (!cnt) return true;
  4751. if(value && (value[vmc] || value[vmb])){
  4752. cnt[prop] = value[vmc] || thisConversionFn(value);
  4753. return true;
  4754. }
  4755. cnt[prop] = value;
  4756. return true;
  4757. }
  4758. };
  4759. const weakWrap = (thisArg) => {
  4760. thisArg = thisConversionFn(thisArg);
  4761. if (!thisArg) {
  4762. console.error('thisArg is not found');
  4763. return null;
  4764. }
  4765. return new Proxy({ ref: mWeakRef(thisArg) }, proxySelfHandler);
  4766. }
  4767.  
  4768.  
  4769.  
  4770.  
  4771.  
  4772.  
  4773. if (!window.getComputedStyle533 && typeof window.getComputedStyle === 'function') {
  4774. window.getComputedStyle533 = window.getComputedStyle;
  4775. window.getComputedStyle = function (a, ...args) {
  4776. a = thisConversionFn(a);
  4777. if (a) {
  4778. return getComputedStyle533(a, ...args);
  4779. }
  4780. return null;
  4781. }
  4782. }
  4783.  
  4784.  
  4785.  
  4786.  
  4787.  
  4788.  
  4789.  
  4790. // const fnProxySelf = function (...args) {
  4791. // const cnt = kRef(this.ref);
  4792. // if (cnt) {
  4793. // return cnt[this.prop](...args); // might throw error
  4794. // }
  4795. // }
  4796. // const proxySelfHandler = {
  4797. // get(target, prop) {
  4798. // const ref = target.ref;
  4799. // const cnt = kRef(ref);
  4800. // if (!cnt) return;
  4801. // if (prop === 'dtz06') return 1;
  4802. // if (typeof cnt[prop] === 'function') {
  4803. // if (!target.funcs.has(prop)) {
  4804. // console.warn(`proxy get to function | prop: ${prop} | is: ${cnt.is}`);
  4805. // }
  4806. // if (!target[`$$${prop}$$`]) target[`$$${prop}$$`] = fnProxySelf.bind({ prop, ref });
  4807. // return target[`$$${prop}$$`];
  4808. // }
  4809. // return cnt[prop];
  4810. // },
  4811. // set(target, prop, value) {
  4812. // const cnt = kRef(target.ref);
  4813. // if (!cnt) return true;
  4814. // if (typeof value === 'function') {
  4815. // console.warn(`proxy set to function | prop: ${prop} | is: ${cnt.is}`);
  4816. // cnt[prop] = value;
  4817. // return true;
  4818. // }
  4819. // cnt[prop] = value;
  4820. // return true;
  4821. // }
  4822. // };
  4823.  
  4824. // return { tickerFuncPropsFn, proxySelfHandler }
  4825.  
  4826. return {weakWrap}
  4827. })();
  4828.  
  4829.  
  4830.  
  4831. if (document.documentElement && document.head) {
  4832. addCssManaged();
  4833. }
  4834. // console.log(document.body===null)
  4835.  
  4836. const preprocessChatLiveActionsMap = new WeakSet();
  4837.  
  4838. const toLAObj=(aItem)=>{
  4839.  
  4840. if (!aItem || typeof aItem !== 'object') return false;
  4841. const key = firstObjectKey(aItem); // addLiveChatTickerItemAction
  4842. if (!key) return false;
  4843. let obj = aItem[key];
  4844. if (!obj || typeof obj !== 'object') return false;
  4845.  
  4846. if (typeof (obj.item || 0) == 'object' && firstObjectKey(obj) === 'item') {
  4847. obj = obj.item;
  4848. const key = firstObjectKey(obj);
  4849. if (key) {
  4850. obj = obj[key];
  4851. }
  4852. }
  4853.  
  4854. return obj;
  4855.  
  4856. };
  4857.  
  4858. const groupsK38=[];
  4859.  
  4860. const weightingFn = (values, weights)=>{
  4861. // assume all weights are positive
  4862. // inf -> NaN
  4863.  
  4864.  
  4865. // Calculate weighted average:
  4866. // Weighted average = (sum of (value_i * weight_i)) / (sum of weights)
  4867. let weightedSum = 0;
  4868. let totalWeight = 0;
  4869.  
  4870. let qv = 0, qw = 0;
  4871. for (let i = 0, l = values.length; i < l; i++) {
  4872. const w = weights[i], v = values[i];
  4873. if (Number.isFinite(w)) {
  4874. weightedSum += v * w;
  4875. totalWeight += w;
  4876. } else {
  4877. qv += v; qw++;
  4878. }
  4879. }
  4880. return qw > 0 ? qv / qw : weightedSum / totalWeight;
  4881. }
  4882.  
  4883. // const doConsolidation = (groups)=>{
  4884.  
  4885. // const b = 5e5;
  4886. // try{
  4887.  
  4888. // const nl = groups.length;
  4889. // for(const group of groups){
  4890. // const [groupStart, groupEnd, groupMid] = group;
  4891. // const gCen = (groupStart + groupEnd) / 2;
  4892.  
  4893. // group[3] = gCen;
  4894. // group[4] = null;
  4895.  
  4896. // }
  4897.  
  4898. // const resArr = [];
  4899.  
  4900. // for (let j = 0; j < nl; j++) {
  4901. // const gCenJ = groups[j][3];
  4902.  
  4903. // let sb = groups[j][4];
  4904. // if(!sb){
  4905. // groups[j][4] = sb = new Set();
  4906. // resArr.push(sb);
  4907. // }
  4908. // sb.add(j);
  4909. // for (let k = j+1; k < nl; k++) {
  4910. // const gCenK = groups[k][3];
  4911.  
  4912. // let r = ((gCenK-b >= gCenJ-b && gCenK-b <= gCenJ+b) || (gCenK+b >= gCenJ-b && gCenK+b <= gCenJ+b));
  4913. // if(r) {
  4914. // sb.add(k);
  4915. // if(!groups[k][4]) groups[k][4] = sb;
  4916. // }
  4917.  
  4918.  
  4919. // }
  4920.  
  4921. // }
  4922.  
  4923.  
  4924. // const resArr2 = resArr.map(e=>[...e]).map(entry=>{
  4925.  
  4926.  
  4927.  
  4928. // const edge1s = entry.map(k => (groups[k][0]));
  4929. // const edge2s = entry.map(k => (groups[k][1]));
  4930. // const ws = entry.map(k => (groups[k][2]));
  4931.  
  4932. // const maxW = Math.max(...ws);
  4933.  
  4934. // const weights = ws.map(w=> maxW/w );
  4935.  
  4936. // const edge1 = weightingFn(edge1s, weights);
  4937. // const edge2 = weightingFn(edge2s, weights);
  4938.  
  4939. // const cen = (edge1 + edge2)/2;
  4940.  
  4941.  
  4942. // return {
  4943. // edge1,
  4944. // edge2,
  4945. // cen,
  4946. // size: ws.reduce((a, b) => a + b, 0),
  4947. // entry
  4948. // };
  4949.  
  4950. // });
  4951. // for(const e of resArr){
  4952. // e.clear();
  4953. // }
  4954. // resArr.length = 0;
  4955.  
  4956.  
  4957. // return resArr2;
  4958.  
  4959. // }catch(e){
  4960.  
  4961. // console.warn(e)
  4962. // return [];
  4963.  
  4964. // }
  4965.  
  4966. // // console.log(4546, 'resArr', resArr2)
  4967.  
  4968.  
  4969.  
  4970. // }
  4971.  
  4972. /*
  4973. const doConsolidation = (groups)=>{
  4974.  
  4975. const consolidatedGroups = [];
  4976. for(const group of groups){
  4977. const [groupStart, groupEnd] = group;
  4978. const gCen = (groupStart + groupEnd) / 2;
  4979. let [gMin, gMax] = [gCen - 0.5, gCen + 0.5];
  4980. consolidatedGroups.push({gMin, gCen, gMax, groups:[], reductionFactor: 1.0});
  4981.  
  4982. }
  4983.  
  4984. for (let j = 0; j < consolidatedGroups.length; j++) {
  4985. const { gMin: gMinJ, gCen: gCenJ, gMax: gMaxJ, groups: groupsJ } = consolidatedGroups[j];
  4986. for (let k = 0; k < consolidatedGroups.length; k++) {
  4987.  
  4988. const { gMin: gMinK, gCen: gCenK, gMax: gMaxK } = consolidatedGroups[k];
  4989.  
  4990. let r = ((gMinK >= gMinJ && gMinK <= gMaxJ) || (gMaxK >= gMinJ && gMaxK <= gMaxJ));
  4991. if (r) groupsJ.push(k);
  4992.  
  4993. }
  4994. if(groupsJ.length > 1){
  4995.  
  4996. let vMin = 0.0, vMax = 1.0; // vMin = no overlapping; vMax = with overlapping
  4997.  
  4998. while ((vMax - vMin) > 1e-3 && vMin > 0) {
  4999. let vMid = (vMin+vMax)/2;
  5000.  
  5001. let wJ = (gMaxJ - gMinJ);
  5002. let gMinJr = gCenJ - wJ * vMid;
  5003. let gMaxJr = gCenJ + wJ * vMid;
  5004. let overlapped = false;
  5005.  
  5006. for (const k of groupsJ) {
  5007. if (k === j) continue;
  5008.  
  5009. const { gMin: gMinK, gCen: gCenK, gMax: gMaxK } = consolidatedGroups[k];
  5010.  
  5011. let wK = (gMaxK - gMinK);
  5012. let gMinKr = gCenK - wK * vMid;
  5013. let gMaxKr = gCenK + wK * vMid;
  5014.  
  5015. let r = ((gMinKr >= gMinJr && gMinKr <= gMaxJr) || (gMaxKr >= gMinJr && gMaxKr <= gMaxJr));
  5016. if (r) {
  5017. overlapped = true;
  5018. break;
  5019. }
  5020.  
  5021. }
  5022. if(overlapped) vMax = vMid;
  5023. else vMin = vMid;
  5024. }
  5025.  
  5026. // 0.14453125 0.1455078125
  5027. // 0.0322265625 0.033203125
  5028. consolidatedGroups[j].reductionFactor = vMin;
  5029. // console.log(3475, groupsJ, vMin, vMax )
  5030.  
  5031.  
  5032. }
  5033. }
  5034.  
  5035. const aFactors = new Array(consolidatedGroups.length).fill(1);
  5036. for (let j = 0; j < consolidatedGroups.length; j++) {
  5037. const groups = consolidatedGroups[j].groups;
  5038. const reductionFactor = consolidatedGroups[j].reductionFactor;
  5039. if (reductionFactor < 1) {
  5040. for (const k of groups) {
  5041. if (reductionFactor < aFactors[k]) aFactors[k] = reductionFactor;
  5042. }
  5043. }
  5044. }
  5045.  
  5046.  
  5047. const consolidatedGroups2 = new Array(consolidatedGroups.length);
  5048. for (let j = 0; j < consolidatedGroups.length; j++) {
  5049.  
  5050. const factor = aFactors[j];
  5051. const gCen = consolidatedGroups[j].gCen;
  5052. const gW = consolidatedGroups[j].gMax - consolidatedGroups[j].gMin;
  5053. consolidatedGroups2[j] = {
  5054. gMin:consolidatedGroups[j].gMin,
  5055. gMax:consolidatedGroups[j].gMax,
  5056. sMin: gCen - gW * factor,
  5057. gCen: gCen,
  5058. sMax: gCen + gW * factor,
  5059. reductionFactor: factor
  5060. }
  5061.  
  5062. }
  5063.  
  5064. console.log('consolidatedGroups2', consolidatedGroups2)
  5065.  
  5066. return consolidatedGroups2;
  5067. }
  5068. */
  5069.  
  5070. function insertIntoSortedArray(arr, val) {
  5071. // Define the binary search boundaries
  5072. let left = 0;
  5073. let right = arr.length;
  5074. // Perform binary search to find correct insertion index
  5075. while (left < right) {
  5076. const mid = (left + right) >>> 1; // Using bitwise for floor division
  5077. if (arr[mid] < val) {
  5078. left = mid + 1;
  5079. } else {
  5080. right = mid;
  5081. }
  5082. }
  5083. // Insert the value at the found index
  5084. arr.splice(left, 0, val);
  5085. }
  5086.  
  5087. function intervalsOverlap(a1, a2, b1, b2) {
  5088. // Order the intervals without using Math functions
  5089. var startA = a1 <= a2 ? a1 : a2;
  5090. var endA = a1 <= a2 ? a2 : a1;
  5091. var startB = b1 <= b2 ? b1 : b2;
  5092. var endB = b1 <= b2 ? b2 : b1;
  5093. // Check for overlap
  5094. return endA >= startB && endB >= startA;
  5095. }
  5096.  
  5097.  
  5098. const insertIntoSortedArrayA27 = (arr, val) => {
  5099. let left = 0;
  5100. let right = arr.length;
  5101. // Binary search to find the correct insertion index:
  5102. // We want the first index where arr[index][2] >= val[2].
  5103. while (left < right) {
  5104. const mid = (left + right) >>> 1;
  5105. if (arr[mid][2] < val[2]) {
  5106. left = mid + 1;
  5107. } else {
  5108. right = mid;
  5109. }
  5110. }
  5111. // 'left' is now the insertion index
  5112. left === right ? arr.push(val): arr.splice(left, 0, val);
  5113. };
  5114.  
  5115.  
  5116. const insertIntoSortedArrayA28 = (arr, val) => {
  5117. let left = 0;
  5118. const n = arr.length;
  5119. let right = n;
  5120. // Binary search to find the correct insertion index:
  5121. // We want the first index where arr[index][2] >= val[2].
  5122. while (left < right) {
  5123. const mid = (left + right) >>> 1;
  5124. if (arr[mid][0] < val[0]) {
  5125. left = mid + 1;
  5126. } else {
  5127. right = mid;
  5128. }
  5129. }
  5130. // 'left' is now the insertion index
  5131. left === n ? arr.push(val): arr.splice(left, 0, val);
  5132. };
  5133.  
  5134. /*
  5135. const insertIntoSortedArrayA27 = (arr, val)=>{
  5136. // Define the binary search boundaries
  5137. let left = 0;
  5138. let right = arr.length-1;
  5139. // Perform binary search to find correct insertion index
  5140. while (right - left > 1) {
  5141. const mid = (left + right) >>> 1; // Using bitwise for floor division
  5142. if (arr[mid][2] <= val[2]) {
  5143. left = mid;
  5144. } else {
  5145. right = mid;
  5146. }
  5147. }
  5148. let i = -1;
  5149. if (right >= 0 && right >= left && arr[right][2] <= val[2]) i = right + 1;
  5150. else if (left >= 0 && right >= left && arr[left][2] <= val[2]) i = left + 1;
  5151. else if (left === 0 && right >= left) i = 0;
  5152. if (i >= 0) {
  5153.  
  5154. // Insert the value at the found index
  5155. arr.splice(i, 0, val);
  5156.  
  5157. } else {
  5158. arr.push(val);
  5159. }
  5160.  
  5161. }
  5162. */
  5163. function removeNullsInPlace(arr, startI = 0) {
  5164. let insertPos = startI;
  5165. for (let i = startI; i < arr.length; i++) {
  5166. if (arr[i] !== null) {
  5167. insertPos !== i && (arr[insertPos] = arr[i]);
  5168. insertPos++;
  5169. }
  5170. }
  5171. arr.length = insertPos; // Remove the trailing nulls.
  5172. }
  5173.  
  5174. let fir = 0;
  5175.  
  5176. const limitAddition = (a, b) => {
  5177. // Number.MAX_SAFE_INTEGER = 9007199254740991
  5178. // k^2 = 9007199254740991 => k = 94906265.62425154
  5179. // Choose k = 2^26 = 67108864 < 94906265.62425154
  5180. // Consider x - x/sqrt(1+x^2/k^2) = 0.4 |x=w => w = 153302.9412
  5181. // Choose w = 2^17 = 131072 < 153302.9412
  5182.  
  5183. const k = 67108864;
  5184. const w = 131072;
  5185. if (a < w && b < w) return a + b;
  5186. return Math.round((a + b) / (1 + a * b / k / k));
  5187. }
  5188.  
  5189. const preprocessChatLiveActions = (arr) =>{
  5190.  
  5191. if (!__LCRInjection__) {
  5192. console.error('[yt-chat] preprocessChatLiveActions might fail because of no __LCRInjection__');
  5193. }
  5194.  
  5195. if (!fir) {
  5196.  
  5197.  
  5198. console.log('[yt-chat-debug] 5990', 'preprocessChatLiveActions', arr)
  5199.  
  5200. console.log('[yt-chat-debug] 5991', document.querySelectorAll('yt-live-chat-ticker-renderer #ticker-items [class]').length)
  5201.  
  5202. fir = 1;
  5203. // debugger;
  5204. }
  5205.  
  5206. if(!arr || !arr.length) return arr;
  5207.  
  5208. if(preprocessChatLiveActionsMap.has(arr)) return arr;
  5209. preprocessChatLiveActionsMap.add(arr);
  5210.  
  5211.  
  5212.  
  5213. const ct = Date.now();
  5214.  
  5215. let groups_ = null;
  5216.  
  5217. // console.log(1237005);
  5218. // const conversionMap = new WeakMap();
  5219.  
  5220. const additionalInfo = new WeakMap();
  5221.  
  5222. // const adjustmentMap = new Map();
  5223.  
  5224. if (FIX_TIMESTAMP_FOR_REPLAY) {
  5225.  
  5226. // console.log('group02331')
  5227. // console.time('FIX_TIMESTAMP_FOR_REPLAY')
  5228.  
  5229. // const stack = new Array(arr.length);
  5230. // let stackL = 0;
  5231.  
  5232. // const arrHash = new Array(arr.length);
  5233.  
  5234.  
  5235. const groups = groupsK38;
  5236. // const delta = 2.0; // head-to-tail + 0.5 + 0.5 = 1.0 -> symmetric -> 1.0 * 2 = 2.0
  5237. // (2)
  5238. // (1.5, 2.5)
  5239. // (1.51, 2.49)
  5240. // -> (1.01, 2.01) , (1.99, 2.99)
  5241. // 2.99 - 1.01 = 1.98 -> 2
  5242.  
  5243.  
  5244.  
  5245. const pushToGroup = (t0mu)=>{
  5246.  
  5247. const t0auDv = t0mu - 1e6; // t0buDv - t0auDv = 2e6
  5248. const t0buDv = t0mu + 1e6;
  5249. // const t0auEv = t0mu - 2e6;
  5250. // const t0buEv = t0mu + 2e6;
  5251.  
  5252. let groupK = false;
  5253. // let m = -1;
  5254. // let q= 0;
  5255. //const qq =true;
  5256. //qq && console.log('-------')
  5257.  
  5258. let lastRight = null;
  5259. let lastK = null;
  5260. let deletedStartIndex = -1;
  5261.  
  5262. for (let k = 0, kl = groups.length; k < kl; k++) {
  5263.  
  5264. const group = groups[k];
  5265. const [groupStart, groupEnd, gCount] = group;
  5266. //qq && console.log(`-- ${k} ----- ${groupMid} : [${groupStart},${groupEnd}] || C1 = ${t0buEv < groupMid} || C2 = ${t0auEv > groupMid}`);
  5267.  
  5268. // if (t0bsEv < groupMid) continue; // if(t0m + 1.0 < groupMid - 1.0) continue;
  5269. // if (m < 0) m = k;
  5270. // if (t0asEv > groupMid){
  5271. // continue; // if(t0m - 1.0 > groupMid + 1.0) break;
  5272. // }
  5273.  
  5274.  
  5275. // if (m < 0) m = k;
  5276.  
  5277. if (lastRight > groupStart) {
  5278. if (!groupK) {
  5279. // just in case sth wrong
  5280. console.warn('logic ERROR');
  5281. groups[k] = null;
  5282. if(deletedStartIndex < 0) deletedStartIndex = k;
  5283. break;
  5284. } else {
  5285.  
  5286.  
  5287. // GroupA: N_a' = N_a + n_e{1} ; Note n_e is the only way to shift right to cause " (lastRight > groupStart) "
  5288. // GroupB: N_b
  5289. // Merge Group (A) = N_a' + N_b
  5290.  
  5291. // without entry moditification, no overlap
  5292. // this must be due to entry moditifcation
  5293. // entry is already count. so can be skipped after merging
  5294.  
  5295. // for merging, groupA will move to right side but left than groupB, so no overlap to groupC
  5296.  
  5297. const group = groups[lastK];
  5298. const newN = limitAddition(group[2], gCount);
  5299.  
  5300. group[0] = (group[0] * group[2] + groupStart * gCount) / (group[2] + gCount)
  5301.  
  5302. group[1] = lastRight = (group[1] * group[2] + groupEnd * gCount) / (group[2] + gCount)
  5303.  
  5304. group[2] = newN;
  5305. // no change of lastK
  5306. groups[k] = null;
  5307. if(deletedStartIndex < 0) deletedStartIndex = k;
  5308. continue;
  5309. }
  5310. }
  5311.  
  5312. const minGroupStart = lastRight; // all groupStart, groupEnd >= minGroupStart for k, k+1, ...
  5313. if (t0buDv < minGroupStart) {
  5314. // no overlapping could be possible
  5315. break;
  5316. }
  5317.  
  5318. if (intervalsOverlap(t0auDv, t0buDv, groupStart, groupEnd)) {
  5319.  
  5320. groupK = true;
  5321.  
  5322. // if (t0auDv > groupStart) group[0] = t0auDv;
  5323. // else if (t0buDv < groupEnd) group[1] = t0buDv;
  5324.  
  5325. const newStart = (groupStart * gCount + t0auDv) / (gCount + 1);
  5326.  
  5327. if (newStart < lastRight) {
  5328. // n_e{1} will make N_b shift left
  5329.  
  5330. // GroupA: N_a
  5331. // GroupB: N_b
  5332. // Merge Group (A) = N_a + N_b + n_e{1}
  5333.  
  5334. const group = groups[lastK];
  5335. const newN = limitAddition(limitAddition(group[2], gCount), 1);
  5336.  
  5337. group[0] = (group[0] * group[2] + groupStart * gCount + t0auDv) / (group[2] + gCount + 1)
  5338.  
  5339. group[1] = lastRight = (group[1] * group[2] + groupEnd * gCount + t0buDv) / (group[2] + gCount + 1)
  5340.  
  5341. group[2] = newN;
  5342. // no change of lastK
  5343. groups[k] = null;
  5344. if(deletedStartIndex < 0) deletedStartIndex = k;
  5345. continue;
  5346.  
  5347. } else {
  5348. // n_e{1} will make N_b shift either left or right
  5349.  
  5350. // GroupT: N_t
  5351. // Group (T) = N_t + n_e{1}
  5352.  
  5353. const newN = limitAddition(gCount, 1);
  5354.  
  5355. group[0] = newStart;
  5356. group[1] = lastRight = (groupEnd * gCount + t0buDv) / (gCount + 1);
  5357. group[2] = newN;
  5358.  
  5359. lastK = k;
  5360.  
  5361. // (t0asDv > groupStart) && (t0bsDv < groupEnd) means full containement
  5362. // however, group size is smaller than or equal to t0width
  5363. }
  5364.  
  5365. } else {
  5366. // just update record for next iteration
  5367.  
  5368. lastRight = groupEnd;
  5369. lastK = k;
  5370. }
  5371.  
  5372.  
  5373.  
  5374. }
  5375.  
  5376. if (deletedStartIndex >= 0) {
  5377. // rarely used
  5378.  
  5379. removeNullsInPlace(groups, deletedStartIndex);
  5380.  
  5381. }
  5382. if (!groupK) {
  5383. // groups.push([t0auDv, t0buDv, 1]);
  5384. insertIntoSortedArrayA28(groups, [t0auDv, t0buDv, 1]);
  5385. // insertIntoSortedArrayA27(groups, [t0auDv, t0buDv, t0mu]);
  5386. }
  5387.  
  5388.  
  5389. }
  5390.  
  5391. let autoTimeStampFrameChoose = 0;
  5392.  
  5393. const noTransform = (x) => {
  5394. return x;
  5395. }
  5396.  
  5397. const prettyNum = (x) => {
  5398.  
  5399. if (x > 1110553200000000) return +(x / 1e6 - autoTimeStampFrameChoose).toFixed(2);
  5400. return x;
  5401. }
  5402.  
  5403.  
  5404. // console.log('group02332')
  5405. for (let j = 0, l = arr.length; j < l; j++) {
  5406. const aItem = arr[j];
  5407.  
  5408. const obj = toLAObj(aItem);
  5409. if (obj === false) continue;
  5410.  
  5411. let p = obj.timestampText;
  5412. let p2, p3=null, p4a=null, p4b=null;
  5413. if(p&&p.simpleText ) p2 = p.simpleText;
  5414.  
  5415. let q = obj.timestampUsec ;
  5416. let q2;
  5417. if(q && +q > 1110553200000000) q2 = +q;
  5418. if (q2 > 0 && !autoTimeStampFrameChoose) {
  5419. const q2cc = Math.round(q2 / 1e6);
  5420. autoTimeStampFrameChoose = q2cc - (q2cc % 10000000);
  5421. if (q2cc - autoTimeStampFrameChoose < 2000000) autoTimeStampFrameChoose -= 10000000;
  5422. // around 10day range
  5423. // exceeded ~10day -> above 10000000
  5424. }
  5425.  
  5426. // console.log('group02333', p2, q2)
  5427. // console.log(3775, q2/1e6, autoTimeStampFrameChoose)
  5428.  
  5429. if(p2 && q2){
  5430.  
  5431. let m;
  5432.  
  5433. if (m = /^\s*(-?)(\d+):(\d+)\s*$/.exec(p2)) {
  5434. let c0z = m[1] ? -1 : 1;
  5435. let c1 = (+m[2]);
  5436. let c2 = (+m[3]);
  5437. if (c0z > 0 && c1 >= 0 && c2 >= 0) {
  5438.  
  5439. p3 = c1 * 60 + c2;
  5440. } else if (c0z < 0 && c1 >= 0 && c2 >= 0) {
  5441. // -4:43 -> -4:42 -> -4:41 ... -> -4:01 -> -4:00 -> -3:59 -> -3:58
  5442. // -> ... -1:01 -> -1:00 -> -0:59 -> ... -> -0:02 -> -0:01 -> -0:00 -> 0:00 -> ...
  5443.  
  5444. p3 = (-c1 * 60) + (-c2);
  5445.  
  5446. }
  5447. if (p3 !== null) {
  5448. // 0:14 -> 13.5s ~ 14.4999s -> [13.5, 14.5)
  5449. p4a = p3 - 0.5;
  5450. p4b = p3 + 0.5;
  5451. }
  5452. } else if (m = /^\s*(-?)(\d+):(\d+):(\d+)\s*$/.exec(p2)) {
  5453.  
  5454. let c0z = m[1] ? -1 : 1;
  5455. let c1 = (+m[2]);
  5456. let c2 = (+m[3]);
  5457. let c3 = (+m[4]);
  5458.  
  5459.  
  5460.  
  5461. if (c0z > 0 && c1 >= 0 && c2 >= 0 && c3 >= 0) {
  5462.  
  5463. p3 = c1 * 60 * 60 + c2 * 60 + c3;
  5464. } else if (c0z < 0 && c1 >= 0 && c2 >= 0 && c3>=0) {
  5465. // -4:43 -> -4:42 -> -4:41 ... -> -4:01 -> -4:00 -> -3:59 -> -3:58
  5466. // -> ... -1:01 -> -1:00 -> -0:59 -> ... -> -0:02 -> -0:01 -> -0:00 -> 0:00 -> ...
  5467.  
  5468. p3 = (-c1 * 60 * 60) + (-c2 * 60) + (-c3);
  5469.  
  5470. }
  5471. if (p3 !== null) {
  5472. // 0:14 -> 13.5s ~ 14.4999s -> [13.5, 14.5)
  5473. p4a = p3 - 0.5;
  5474. p4b = p3 + 0.5;
  5475. }
  5476.  
  5477.  
  5478. }
  5479.  
  5480. }
  5481.  
  5482. if(p4a !== null && p4b !== null && q2 > 0){
  5483.  
  5484. // q2_us = t0_us + dt_us
  5485. // p4a_us <= dt_us < p4b_us
  5486. let p4au = p4a * 1e6;
  5487. let p4bu = p4b * 1e6;
  5488.  
  5489. // p4a_us <= q2_us - t0_us < p4b_us
  5490.  
  5491.  
  5492. // p4a_us - q2_us <= - t0_us < p4b_us - q2_us
  5493.  
  5494. // -p4a_us + q2_us >= t0_us > -p4b_us + q2_us
  5495.  
  5496.  
  5497. let t0au = q2 - p4bu; // q2_us - p4b_us
  5498. let t0bu = q2 - p4au; // q2_us - p4a_us
  5499.  
  5500. // t0 (t0au, t0bu]
  5501.  
  5502. const t0mu = (t0au+t0bu)/2;
  5503.  
  5504. // stack[stackL++]=({
  5505. // id: obj.id,
  5506. // idx: j,
  5507. // p2,
  5508. // // q2s : (q2/ 1e6 - autoTimeStampFrameChoose).toFixed(2),
  5509. // p3,
  5510. // /*
  5511. // timestampText: obj.timestampText,
  5512. // timestampUsec: obj.timestampUsec, // us = 1/1000 ms
  5513. // q2,
  5514. // p4a,
  5515. // p4b,
  5516. // */
  5517. // q2s: +(q2 / 1e6 - autoTimeStampFrameChoose).toFixed(2),
  5518. // t0as: +(t0au / 1e6 - autoTimeStampFrameChoose).toFixed(2),
  5519. // t0bs: +(t0bu /1e6 - autoTimeStampFrameChoose).toFixed(2),
  5520.  
  5521. // t0au,
  5522. // t0bu,
  5523. // t0mu
  5524. // });
  5525.  
  5526. // console.log('group02334')
  5527. let wobj = additionalInfo.get(obj);
  5528. if(!wobj) additionalInfo.set(obj, wobj = {});
  5529.  
  5530. wobj.timestampUsecOriginal = q2;
  5531. // wobj.timestampUsecAdjusted = q2;
  5532. wobj.t0au = t0au;
  5533. wobj.t0bu = t0bu;
  5534. wobj.t0mu = t0mu;
  5535.  
  5536. // arrHash[j] = {
  5537. // index: j,
  5538. // id: obj.id,
  5539. // timestampUsec: q2,
  5540. // t0au,
  5541. // t0bu,
  5542. // t0mu
  5543. // };
  5544.  
  5545. pushToGroup(t0mu);
  5546.  
  5547. // console.log('group02335')
  5548. // console.log('grouping', `${obj.id}.${obj.timestampUsec}`);
  5549.  
  5550. // timestamp (q2) can be incorrect.
  5551.  
  5552. // https://www.youtube.com/watch?v=IKKar5SS29E
  5553. // ChwKGkNQZUxfXzZxLS04Q0ZXNGxyUVlkODZrQzNR
  5554.  
  5555. /*
  5556.  
  5557.  
  5558. [
  5559. {
  5560. "id": "ChwKGkNNWHZqXy1xLS04Q0ZXNGxyUVlkODZrQzNR",
  5561. "p2": "2:04",
  5562. "p3": 124,
  5563. "t0as": 8320733.78,
  5564. "t0bs": 8320734.78
  5565. },
  5566. {
  5567. "id": "ChwKGkNQZUxfXzZxLS04Q0ZXNGxyUVlkODZrQzNR",
  5568. "p2": "2:04",
  5569. "p3": 124,
  5570. "t0as": 8320898.89, // incorrect
  5571. "t0bs": 8320899.89
  5572. }
  5573. ]
  5574.  
  5575.  
  5576. */
  5577.  
  5578. }
  5579.  
  5580.  
  5581. }
  5582.  
  5583. // stack.length = stackL;
  5584.  
  5585.  
  5586. groups_ = groups;
  5587. // console.log('groups', groups)
  5588.  
  5589. }
  5590.  
  5591. // console.log(1237006);
  5592.  
  5593. // console.log(5592,1)
  5594. const groupMids = FIX_TIMESTAMP_FOR_REPLAY ? groups_.map(group=>{
  5595.  
  5596. const [groupStart, groupEnd ] = group;
  5597. const groupMid = (groupStart+groupEnd)/2;
  5598. return groupMid;
  5599. }): null;
  5600. // console.log('groupMids', groupMids)
  5601.  
  5602.  
  5603. // console.log(1237007);
  5604.  
  5605. const adjustTimestampFn = (obj) => {
  5606.  
  5607. const groupCount = groupMids.length;
  5608.  
  5609. if (groupCount < 1) return null;
  5610.  
  5611. // const obj = toLAObj(aItem);
  5612. if (obj === false) return null;
  5613.  
  5614. const wobj = additionalInfo.get(obj);
  5615. if (!wobj) return null;
  5616.  
  5617. const { t0mu } = wobj;
  5618.  
  5619.  
  5620. let i0 = 0;
  5621.  
  5622. if (groupCount >= 3) {
  5623. // For larger arrays, use binary search.
  5624. let low = 0;
  5625. let high = groupCount - 1;
  5626.  
  5627. while (high - low > 1) {
  5628. const mid = (low + high) >>> 1;
  5629. if (groupMids[mid] >= t0mu) {
  5630. high = mid;
  5631. } else {
  5632. low = mid;
  5633. }
  5634. }
  5635. i0 = low;
  5636.  
  5637. }
  5638.  
  5639. let upperDiff = -1;
  5640. let lowerDiff = -1;
  5641. for (let i = i0; i < groupCount; i++) {
  5642. const y = groupMids[i] - t0mu;
  5643. if (y >= 0) {
  5644. upperDiff = y; // >=0, entry > value is found
  5645. break;
  5646. }
  5647. lowerDiff = -y; // >0, cache
  5648. }
  5649.  
  5650. const d1 = upperDiff;
  5651. const d2 = lowerDiff;
  5652.  
  5653.  
  5654. // console.log(5381, index1 ,d1, index2 , d2);
  5655.  
  5656. if (d1 >= 0 && ((d2 < 0) || (d1 <= d2))) {
  5657. wobj.chosenT0 = t0mu + d1; // groupMids[index1];
  5658. } else if (d2 >= 0 && ((d1 < 0) || (d2 <= d1))) {
  5659. wobj.chosenT0 = t0mu - d2; // groupMids[index2];
  5660. } else {
  5661. console.warn('logic error');
  5662. return null;
  5663. }
  5664.  
  5665. const adjusted = wobj.timestampUsecOriginal - wobj.chosenT0;
  5666.  
  5667. wobj.timestampUsecAdjusted = adjusted + 1110553200000000;
  5668.  
  5669. // console.log('adjusted', `${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  5670.  
  5671. // adjustmentMap.set(`${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  5672.  
  5673. return adjusted;
  5674.  
  5675.  
  5676.  
  5677. };
  5678.  
  5679.  
  5680. // console.log(5592,2)
  5681. // console.log(1237008);
  5682. // if (FIX_TIMESTAMP_FOR_REPLAY) {
  5683.  
  5684.  
  5685. // try{
  5686.  
  5687. // // console.log('groupmid',groupMids, groups);
  5688.  
  5689. // for(let j = 0; j< arr.length;j++){
  5690. // if(groupMids.length<1) break;
  5691.  
  5692. // const aItem = arr[j];
  5693. // const obj = toLAObj(aItem);
  5694. // if (obj === false) continue;
  5695.  
  5696. // const wobj = additionalInfo.get(obj);
  5697. // if(!wobj) continue;
  5698.  
  5699. // // wobj.timestampUsecOriginal = q2;
  5700. // // wobj.timestampUsecAdjusted = q2;
  5701. // // wobj.t0au = t0au;
  5702. // // wobj.t0bu = t0bu;
  5703. // // wobj.t0mu = t0mu;
  5704.  
  5705. // const {t0au, t0bu, t0mu} = wobj;
  5706.  
  5707. // let upper = -1;
  5708.  
  5709. // for(let i = 0; i <groupMids.length;i++){
  5710. // const groupMid = groupMids[i];
  5711. // if(groupMid>= t0mu){
  5712. // upper = i;
  5713. // break;
  5714. // }
  5715. // }
  5716. // let index1, index2;
  5717. // if(upper>-1){
  5718. // index1 = upper-1;
  5719. // index2 = upper;
  5720. // }else{
  5721. // index1 = groups.length-1;
  5722. // index2 = -1;
  5723. // }
  5724. // let d1 = null;
  5725. // if(index1 >=0){
  5726. // d1 = Math.abs(groupMids[index1] - t0mu);
  5727. // }
  5728. // let d2 = null;
  5729. // if(index2 >=0){
  5730. // d2 = Math.abs(groupMids[index2] - t0mu);
  5731. // }
  5732. // // console.log(5381, index1 ,d1, index2 , d2);
  5733. // if(d1 >= 0 && ((d1 <= d2) || (d2 === null)) ){
  5734. // wobj.chosenT0 = groupMids[index1];
  5735. // } else if(d2 >= 0 && ((d2 <= d1) || (d1 === null))){
  5736. // wobj.chosenT0 = groupMids[index2];
  5737. // } else {
  5738. // console.warn('logic error');
  5739. // continue;
  5740. // }
  5741.  
  5742. // wobj.timestampUsecAdjusted = wobj.timestampUsecOriginal - wobj.chosenT0 + 1110553200000000;
  5743.  
  5744. // console.log('adjusted', `${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  5745.  
  5746. // adjustmentMap.set(`${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  5747. // // conversionMap.set(obj, arrHash[j].adjustedTime);
  5748.  
  5749. // // console.log(5382, index, id, t0mu, arrHash[j].adjustedT0, arrHash[j].timestampUsec, arrHash[j].adjustedTime);
  5750. // }
  5751.  
  5752. // }catch(e){
  5753. // console.warn(e);
  5754. // }
  5755.  
  5756.  
  5757.  
  5758.  
  5759.  
  5760. // // if(stack.length > 1){
  5761. // // stack.sort((a,b)=>{
  5762. // // return a.t0mu - b.t0mu
  5763. // // });
  5764. // // // small to large
  5765. // // // console.log(34588, stack.map(e=>e.t0as))
  5766. // // }
  5767.  
  5768. // // grouping
  5769.  
  5770.  
  5771.  
  5772.  
  5773. // // if (stack.length > 0) {
  5774.  
  5775. // // try {
  5776.  
  5777. // // for (let j = 0, l = stack.length; j < l; j++) {
  5778. // // pushToGroup(stack[j].t0mu);
  5779.  
  5780. // // }
  5781.  
  5782. // // }catch(e){
  5783.  
  5784. // // console.warn(e)
  5785. // // }
  5786.  
  5787. // // // console.log(4882, groups.map(e=>e.slice()), stack.slice())
  5788.  
  5789. // // }
  5790.  
  5791.  
  5792.  
  5793. // // console.log(376, 'group', groups);
  5794.  
  5795.  
  5796. // // consolidated group
  5797. // // const consolidatedGroups = doConsolidation(groups);
  5798.  
  5799.  
  5800.  
  5801.  
  5802.  
  5803.  
  5804. // // if(stack.length > 1){
  5805.  
  5806.  
  5807. // // // // console.log(341, 'consolidatedGroups', consolidatedGroups ,groups.map(e=>{
  5808. // // // // return e.map(noTransform);
  5809. // // // // // return e.map(prettyNum);
  5810. // // // // }))
  5811.  
  5812.  
  5813. // // // console.log(344, 'groups', groups.map(e=>{
  5814. // // // return e.map(noTransform);
  5815. // // // // return e.map(prettyNum);
  5816. // // // }))
  5817.  
  5818. // // // // for(const s of stack){
  5819. // // // // for(const g of consolidatedGroups){
  5820. // // // // if(s.t0as<=g.cen && s.t0bs >=g.cen ){
  5821. // // // // s.cen = g.cen;
  5822. // // // // break;
  5823. // // // // }
  5824. // // // // }
  5825.  
  5826. // // // // }
  5827.  
  5828. // // // console.log(377, stack) // Ms
  5829.  
  5830. // // }
  5831.  
  5832.  
  5833. // // console.timeEnd('FIX_TIMESTAMP_FOR_REPLAY')
  5834.  
  5835. // }
  5836.  
  5837.  
  5838.  
  5839.  
  5840.  
  5841.  
  5842.  
  5843.  
  5844.  
  5845. // console.log(5592,5)
  5846.  
  5847. // console.log('preprocessChatLiveActions', arr)
  5848.  
  5849.  
  5850. const mapper = new Map();
  5851.  
  5852. // without delaying. get the time of request
  5853. // (both streaming and replay, but replay relys on progress update so background operation is suppressed)
  5854. for (let j = 0, l = arr.length; j < l; j++) {
  5855. const aItem = arr[j];
  5856.  
  5857. const obj = toLAObj(aItem);
  5858. if(obj === false) continue;
  5859. if (obj.id && !obj.__timestampActionRequest__) {
  5860. // for all item entries
  5861. obj.__timestampActionRequest__ = ct;
  5862. }
  5863.  
  5864. if (obj.id && obj.__timestampActionRequest__ > 0 && obj.durationSec > 0 && obj.fullDurationSec) {
  5865.  
  5866. // console.log(948700, obj , obj.id, (obj.fullDurationSec - obj.durationSec) * 1000)
  5867. const m = obj.__timestampActionRequest__ - (obj.fullDurationSec - obj.durationSec) * 1000;
  5868.  
  5869. // obj.__t374__ = (obj.fullDurationSec - obj.durationSec) * 1000;
  5870. // obj.__t375__ = obj.__timestampActionRequest__ - (obj.fullDurationSec - obj.durationSec) * 1000;
  5871. // console.log(5993, obj)
  5872. // obj.__orderTime__ = m;
  5873. mapper.set(aItem, m);
  5874.  
  5875.  
  5876. }
  5877.  
  5878. }
  5879.  
  5880. if (mapper.size > 1) {
  5881.  
  5882. const idxices = [];
  5883.  
  5884. // sort ticker
  5885. let mArr1 = arr.filter((aItem,idx) => {
  5886.  
  5887. if (mapper.has(aItem)) {
  5888. idxices.push(idx);
  5889. return true;
  5890. }
  5891. return false;
  5892.  
  5893. });
  5894.  
  5895.  
  5896. let mArr2 = mArr1/*.slice(0)*/.sort((a, b) => {
  5897. return mapper.get(a) - mapper.get(b);
  5898. // low index = oldest = smallest timestamp
  5899. });
  5900.  
  5901.  
  5902.  
  5903. // console.log(948701, arr.slice(0));
  5904. for(let j = 0, l=mArr1.length;j <l;j++){
  5905.  
  5906. const idx = idxices[j];
  5907. // arr[idx] = mArr1[j]
  5908. arr[idx] = mArr2[j];
  5909.  
  5910. // const obj1 = toObj(mArr1[j]);
  5911. // const obj2 = toObj(mArr2[j]);
  5912.  
  5913. // console.log(948705, idx, obj1 , obj1.id, (obj1.fullDurationSec - obj1.durationSec) * 1000, obj1.__orderTime__)
  5914.  
  5915. // console.log(948706, idx, obj2 , obj2.id, (obj2.fullDurationSec - obj2.durationSec) * 1000, obj2.__orderTime__)
  5916.  
  5917. }
  5918.  
  5919. // console.log(5994,arr)
  5920.  
  5921. // console.log(948702, arr.slice(0));
  5922. // console.log(948701, arr);
  5923. // arr = arr.map(aItem => {
  5924. // const idx = mArr1.indexOf(aItem);
  5925. // if (idx < 0) return aItem;
  5926. // return mArr2[idx];
  5927. // });
  5928. // console.log(948702, arr);
  5929.  
  5930. // mostly in order, but some not in order
  5931.  
  5932.  
  5933. // eg
  5934.  
  5935. /*
  5936.  
  5937.  
  5938. 948711 68 '1734488590715474'
  5939. 948711 69 '1734488590909853'
  5940. 948711 70 '1734488594763719'
  5941. 948711 71 '1734488602334615' <
  5942. 948711 72 '1734488602267214' <
  5943. 948711 73 '1734488602751771'
  5944. */
  5945.  
  5946. // arr.filter(aItem=>{
  5947.  
  5948. // const p = toObj(aItem);
  5949. // if(p.timestampUsec) return true;
  5950.  
  5951. // }).forEach((aItem,idx)=>{
  5952.  
  5953. // const p = toObj(aItem);
  5954. // console.log(948711, idx, p.timestampUsec);
  5955. // })
  5956.  
  5957. // return arr;
  5958.  
  5959. }
  5960.  
  5961. // console.log(1237001);
  5962.  
  5963. {
  5964.  
  5965.  
  5966. const mapper = new Map();
  5967.  
  5968.  
  5969. const idxices = [];
  5970.  
  5971.  
  5972. let mArr1 = arr.filter((aItem,idx) => {
  5973.  
  5974. const obj = toLAObj(aItem);
  5975. if (!obj) return false;
  5976.  
  5977. const baseText = obj.timestampText;
  5978. const baseTime = +obj.timestampUsec;
  5979. if (!baseTime || !baseText) return false;
  5980. // const timestampUsec = +toLAObj(aItem).timestampUsec; // +false.x = NaN
  5981. // const timestampUsec = +toLAObj(aItem).adjustedTime;
  5982.  
  5983. let timestampUsec;
  5984.  
  5985. // console.log(1237002)
  5986. if (FIX_TIMESTAMP_FOR_REPLAY) {
  5987.  
  5988. // const adjustmentTime = adjustmentMap.get(`${obj.id}.${obj.timestampUsec}`);
  5989.  
  5990. // // const wobj = additionalInfo.get(obj);
  5991.  
  5992. // // if(!wobj){
  5993. // // console.warn('FIX_TIMESTAMP_FOR_REPLAY - no wobj', obj)
  5994. // // return false;
  5995. // // }
  5996.  
  5997. // // timestampUsec = +wobj.timestampUsecAdjusted;
  5998. // if (!Number.isFinite(adjustmentTime)) {
  5999. // console.warn(`FIX_TIMESTAMP_FOR_REPLAY - no adjustmentTime for ${obj.id}.${obj.timestampUsec}`, obj, [...adjustmentMap])
  6000. // return false;
  6001. // }
  6002. // timestampUsec = adjustmentTime;
  6003.  
  6004.  
  6005. const adjustmentTime = adjustTimestampFn(obj);
  6006.  
  6007. if (!Number.isFinite(adjustmentTime)) {
  6008.  
  6009. console.warn(`FIX_TIMESTAMP_FOR_REPLAY - no adjustmentTime for ${obj.id}.${obj.timestampUsec}`, obj);
  6010. return false;
  6011. }
  6012. timestampUsec = adjustmentTime;
  6013.  
  6014.  
  6015. } else {
  6016.  
  6017. if (!Number.isFinite(baseTime)) {
  6018. console.warn(`no baseTime for ${obj.id}.${obj.timestampUsec}`, obj);
  6019. return false;
  6020. }
  6021. timestampUsec = baseTime;
  6022.  
  6023. }
  6024.  
  6025. // if(timestampUsec > 0){
  6026. idxices.push(idx);
  6027. mapper.set(aItem, timestampUsec)
  6028. return true;
  6029. // }
  6030. // return false;
  6031. });
  6032.  
  6033. if(mapper.size > 1){
  6034.  
  6035. // console.log(1237004)
  6036. let mArr2 = mArr1/*.slice(0)*/.sort((a, b) => {
  6037. return mapper.get(a) - mapper.get(b);
  6038. // low index = oldest = smallest timestamp
  6039. });
  6040. // console.log(948701, arr.slice(0));
  6041. for(let j = 0, l=mArr1.length;j <l;j++){
  6042. const idx = idxices[j];
  6043. arr[idx] = mArr2[j];
  6044. // const obj1 = toObj(mArr1[j]);
  6045. // const obj2 = toObj(mArr2[j]);
  6046. // console.log(948711, idx, obj1 === obj2, obj1, obj1.timestampUsec);
  6047. // console.log(948712, idx, obj1 === obj2, obj2, obj2.timestampUsec);
  6048. }
  6049.  
  6050. }
  6051.  
  6052. }
  6053.  
  6054. // console.log(1237005)
  6055.  
  6056. // console.log(378, arr);
  6057.  
  6058. return arr;
  6059.  
  6060.  
  6061. }
  6062.  
  6063. if (ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION) {
  6064.  
  6065. console.log('ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION is used.')
  6066.  
  6067. // console.log('ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION 0001')
  6068.  
  6069. const pop078 = function () {
  6070. const r = this.pop78();
  6071.  
  6072. if (r && (r.actions || 0).length >= 1 && r.videoOffsetTimeMsec) {
  6073. for (const action of r.actions) {
  6074.  
  6075. const itemActionKey = !action ? null : 'addChatItemAction' in action ? 'addChatItemAction' : 'addLiveChatTickerItemAction' in action ? 'addLiveChatTickerItemAction' : null;
  6076. if (itemActionKey) {
  6077.  
  6078. const itemAction = action[itemActionKey];
  6079. const item = (itemAction || 0).item;
  6080. if (typeof item === 'object') {
  6081.  
  6082. const rendererKey = firstObjectKey(item);
  6083. if (rendererKey) {
  6084. const renderer = item[rendererKey];
  6085. if (renderer && typeof renderer === 'object') {
  6086. renderer.__videoOffsetTimeMsec__ = r.videoOffsetTimeMsec;
  6087. renderer.__progressAt__ = playerProgressChangedArg1;
  6088.  
  6089. // console.log(48117006)
  6090. }
  6091.  
  6092. }
  6093.  
  6094. }
  6095. }
  6096. }
  6097. }
  6098. return r;
  6099. }
  6100.  
  6101.  
  6102.  
  6103. const replayQueueProxyHandler = {
  6104. get(target, prop, receiver) {
  6105. if (prop === 'qe3') return 1;
  6106. const v = target[prop];
  6107. if (prop === 'front_') {
  6108. if (v && typeof v.length === 'number') {
  6109. if (!v.pop78) {
  6110. v.pop78 = v.pop;
  6111. v.pop = pop078;
  6112. }
  6113. }
  6114. }
  6115. return v;
  6116. }
  6117. };
  6118.  
  6119. // lcrFn2 will run twice to ensure the method is successfully injected.
  6120. const lcrFn2 = (lcrDummy)=>{
  6121. // make minimal function overhead by pre-defining all possible outside.
  6122.  
  6123. const tag = "yt-live-chat-renderer"
  6124. const dummy = lcrDummy;
  6125.  
  6126. const cProto = getProto(dummy);
  6127. if (!cProto || !cProto.attached) {
  6128. console.warn(`proto.attached for ${tag} is unavailable.`);
  6129. return;
  6130. }
  6131.  
  6132. // mightFirstCheckOnYtInit();
  6133. // groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-renderer hacks");
  6134. // console.log("[Begin]");
  6135.  
  6136.  
  6137. if (typeof cProto.playerProgressChanged_ === 'function' && !cProto.playerProgressChanged32_) {
  6138.  
  6139. cProto.playerProgressChanged32_ = cProto.playerProgressChanged_;
  6140.  
  6141.  
  6142. cProto.playerProgressChanged_ = function (a, b, c) {
  6143. // console.log(48117005)
  6144. playerProgressChangedArg1 = a;
  6145. playerProgressChangedArg2 = b;
  6146. playerProgressChangedArg3 = c;
  6147. const replayBuffer_ = this.replayBuffer_;
  6148. if (replayBuffer_) {
  6149. const replayQueue = replayBuffer_.replayQueue
  6150. if (replayQueue && typeof replayQueue === 'object' && !replayQueue.qe3) {
  6151. replayBuffer_.replayQueue = new Proxy(replayBuffer_.replayQueue, replayQueueProxyHandler);
  6152. }
  6153. }
  6154. Promise.resolve().then(updateTickerCurrentTime);
  6155. return this.playerProgressChanged32_.apply(this, arguments);
  6156. };
  6157.  
  6158. }
  6159.  
  6160. // console.log("[End]");
  6161. // console.groupEnd();
  6162.  
  6163. };
  6164. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  6165.  
  6166.  
  6167. // console.log('ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION 0002')
  6168.  
  6169. // getLCRDummy() must be called for injection
  6170. getLCRDummy().then(lcrFn2);
  6171.  
  6172. }
  6173.  
  6174.  
  6175.  
  6176. customElements.whenDefined('yt-live-chat-item-list-renderer').then(() => {
  6177.  
  6178.  
  6179. const tag = "yt-live-chat-item-list-renderer"
  6180. const dummy = document.createElement(tag);
  6181.  
  6182. const cProto = getProto(dummy);
  6183. if (!cProto || !cProto.attached) {
  6184. console.warn(`proto.attached for ${tag} is unavailable.`);
  6185. return;
  6186. }
  6187.  
  6188. mightFirstCheckOnYtInit();
  6189. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-item-list-renderer hacks");
  6190. console.log("[Begin]");
  6191.  
  6192. const mclp = cProto;
  6193. const _flag0281_ = window._flag0281_ || mclp._flag0281_;
  6194.  
  6195. try {
  6196. assertor(() => typeof mclp.scrollToBottom_ === 'function');
  6197. assertor(() => typeof mclp.flushActiveItems_ === 'function');
  6198. assertor(() => typeof mclp.canScrollToBottom_ === 'function');
  6199. assertor(() => typeof mclp.setAtBottom === 'function');
  6200. assertor(() => typeof mclp.scrollToBottom66_ === 'undefined');
  6201. assertor(() => typeof mclp.flushActiveItems66_ === 'undefined');
  6202. } catch (e) { }
  6203.  
  6204.  
  6205. try {
  6206. assertor(() => typeof mclp.attached === 'function');
  6207. assertor(() => typeof mclp.detached === 'function');
  6208. assertor(() => typeof mclp.canScrollToBottom_ === 'function');
  6209. assertor(() => typeof mclp.isSmoothScrollEnabled_ === 'function');
  6210. assertor(() => typeof mclp.maybeResizeScrollContainer_ === 'function');
  6211. assertor(() => typeof mclp.refreshOffsetContainerHeight_ === 'function');
  6212. assertor(() => typeof mclp.smoothScroll_ === 'function');
  6213. assertor(() => typeof mclp.resetSmoothScroll_ === 'function');
  6214. } catch (e) { }
  6215.  
  6216. mclp.__intermediate_delay__ = null;
  6217.  
  6218. let myk = 0;
  6219. let mlf = 0;
  6220. let myw = 0;
  6221. let mzt = 0;
  6222. let zarr = null;
  6223. let mlg = 0;
  6224.  
  6225. if ((_flag0281_ & 0x2000) == 0) {
  6226.  
  6227. if ((mclp.clearList || 0).length === 0) {
  6228. (_flag0281_ & 0x2) == 0 && assertor(() => fnIntegrity(mclp.clearList, '0.106.50'));
  6229. mclp.clearList66 = mclp.clearList;
  6230. mclp.clearList = function () {
  6231. myk++;
  6232. mlf++;
  6233. myw++;
  6234. mzt++;
  6235. mlg++;
  6236. zarr = null;
  6237. this.__intermediate_delay__ = null;
  6238. this.clearList66();
  6239. };
  6240. console.log("clearList", "OK");
  6241. } else {
  6242. console.log("clearList", "NG");
  6243. }
  6244.  
  6245. }
  6246.  
  6247.  
  6248.  
  6249. let onListRendererAttachedDone = false;
  6250.  
  6251. function setList(itemOffset, items) {
  6252.  
  6253. const isFirstTime = onListRendererAttachedDone === false;
  6254.  
  6255. if (isFirstTime) {
  6256. onListRendererAttachedDone = true;
  6257. Promise.resolve().then(watchUserCSS);
  6258. addCssManaged();
  6259. setupEvents();
  6260. }
  6261.  
  6262. setupStyle(itemOffset, items);
  6263.  
  6264. setupMutObserver(items);
  6265. }
  6266.  
  6267. mclp.attached419 = async function () {
  6268.  
  6269. if (!this.isAttached) return;
  6270.  
  6271. let maxTrial = 16;
  6272. while (!this.$ || !this.$['item-scroller'] || !this.$['item-offset'] || !this.$['items']) {
  6273. if (--maxTrial < 0 || !this.isAttached) return;
  6274. await iAFP(this.hostElement).then();
  6275. // await new Promise(requestAnimationFrame);
  6276. }
  6277.  
  6278. if (this.isAttached !== true) return;
  6279.  
  6280. if (!this.$) {
  6281. console.warn("!this.$");
  6282. return;
  6283. }
  6284. if (!this.$) return;
  6285. /** @type {HTMLElement | null} */
  6286. const itemScroller = this.$['item-scroller'];
  6287. /** @type {HTMLElement | null} */
  6288. const itemOffset = this.$['item-offset'];
  6289. /** @type {HTMLElement | null} */
  6290. const items = this.$['items'];
  6291.  
  6292. if (!itemScroller || !itemOffset || !items) {
  6293. console.warn("items.parentNode !== itemOffset");
  6294. return;
  6295. }
  6296.  
  6297. if (nodeParent(items) !== itemOffset) {
  6298.  
  6299. console.warn("items.parentNode !== itemOffset");
  6300. return;
  6301. }
  6302.  
  6303.  
  6304. if (items.id !== 'items' || itemOffset.id !== "item-offset") {
  6305.  
  6306. console.warn("id incorrect");
  6307. return;
  6308. }
  6309.  
  6310. const isTargetItems = HTMLElement.prototype.matches.call(items, '#item-offset.style-scope.yt-live-chat-item-list-renderer > #items.style-scope.yt-live-chat-item-list-renderer')
  6311.  
  6312. if (!isTargetItems) {
  6313. console.warn("!isTargetItems");
  6314. return;
  6315. }
  6316.  
  6317. setList(itemOffset, items);
  6318.  
  6319. }
  6320.  
  6321. mclp.attached331 = mclp.attached;
  6322. mclp.attached = function () {
  6323. this.attached419 && this.attached419();
  6324. return this.attached331();
  6325. }
  6326.  
  6327. mclp.detached331 = mclp.detached;
  6328.  
  6329. mclp.detached = function () {
  6330. setupMutObserver();
  6331. return this.detached331();
  6332. }
  6333.  
  6334. const t29s = document.querySelectorAll("yt-live-chat-item-list-renderer");
  6335. for (const t29 of t29s) {
  6336. if (insp(t29).isAttached === true) {
  6337. t29.attached419();
  6338. }
  6339. }
  6340.  
  6341. if ((mclp.async || 0).length === 2 && (mclp.cancelAsync || 0).length === 1) {
  6342.  
  6343. assertor(() => fnIntegrity(mclp.async, '2.24.15'));
  6344. assertor(() => fnIntegrity(mclp.cancelAsync, '1.15.8'));
  6345.  
  6346. /** @type {Map<number, any>} */
  6347. const aMap = new Map();
  6348. let count = 6150;
  6349. mclp.async66 = mclp.async;
  6350. mclp.async = function (e, f) {
  6351. // ensure the previous operation is done
  6352. // .async is usually after the time consuming functions like flushActiveItems_ and scrollToBottom_
  6353. const hasF = arguments.length === 2;
  6354. const stack = new Error().stack;
  6355. const isFlushAsync = stack.indexOf('flushActiveItems_') >= 0;
  6356. if (count > 1e9) count = 6159;
  6357. const resId = ++count;
  6358. aMap.set(resId, e);
  6359. (this.__intermediate_delay__ || Promise.resolve()).then(rk => {
  6360. const rp = aMap.get(resId);
  6361. if (typeof rp !== 'function') {
  6362. return;
  6363. }
  6364. let cancelCall = false;
  6365. if (isFlushAsync) {
  6366. if (rk < 0) {
  6367. cancelCall = true;
  6368. } else if (rk === 2 && arguments[0] === this.maybeScrollToBottom_) {
  6369. cancelCall = true;
  6370. }
  6371. }
  6372. if (cancelCall) {
  6373. aMap.delete(resId);
  6374. } else {
  6375. const asyncEn = function () {
  6376. aMap.delete(resId);
  6377. return rp.apply(this, arguments);
  6378. };
  6379. aMap.set(resId, hasF ? this.async66(asyncEn, f) : this.async66(asyncEn));
  6380. }
  6381. });
  6382.  
  6383. return resId;
  6384. }
  6385.  
  6386. mclp.cancelAsync66 = mclp.cancelAsync;
  6387. mclp.cancelAsync = function (resId) {
  6388. if (resId <= 6150) {
  6389. this.cancelAsync66(resId);
  6390. } else if (aMap.has(resId)) {
  6391. const rp = aMap.get(resId);
  6392. aMap.delete(resId);
  6393. if (typeof rp !== 'function') {
  6394. this.cancelAsync66(rp);
  6395. }
  6396. }
  6397. }
  6398.  
  6399. console.log("async", "OK");
  6400. } else {
  6401. console.log("async", "NG");
  6402. }
  6403.  
  6404.  
  6405. if ((_flag0281_ & 0x2) == 0) {
  6406. if ((mclp.showNewItems_ || 0).length === 0 && ENABLE_NO_SMOOTH_TRANSFORM) {
  6407.  
  6408. assertor(() => fnIntegrity(mclp.showNewItems_, '0.170.79'));
  6409. mclp.showNewItems66_ = mclp.showNewItems_;
  6410.  
  6411. mclp.showNewItems77_ = async function () {
  6412. if (myk > 1e9) myk = 9;
  6413. let tid = ++myk;
  6414.  
  6415. await iAFP(this.hostElement).then();
  6416. // await new Promise(requestAnimationFrame);
  6417.  
  6418. if (tid !== myk) {
  6419. return;
  6420. }
  6421.  
  6422. const cnt = this;
  6423.  
  6424. await Promise.resolve();
  6425. cnt.showNewItems66_();
  6426.  
  6427. await Promise.resolve();
  6428.  
  6429. }
  6430.  
  6431. mclp.showNewItems_ = function () {
  6432.  
  6433. const cnt = this;
  6434. cnt.__intermediate_delay__ = new Promise(resolve => {
  6435. cnt.showNewItems77_().then(() => {
  6436. resolve();
  6437. });
  6438. });
  6439. }
  6440.  
  6441. console.log("showNewItems_", "OK");
  6442. } else {
  6443. console.log("showNewItems_", "NG");
  6444. }
  6445.  
  6446. }
  6447.  
  6448. if ((_flag0281_ & 0x2000) == 0) {
  6449. if ((mclp.flushActiveItems_ || 0).length === 0) {
  6450.  
  6451. if ((_flag0281_ & 0x2) == 0) {
  6452.  
  6453. const sfi = fnIntegrity(mclp.flushActiveItems_);
  6454. if(sfi === '0.158.86'){
  6455.  
  6456. // https://www.youtube.com/s/desktop/c01ea7e3/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  6457.  
  6458.  
  6459. // f.flushActiveItems_ = function() {
  6460. // var a = this;
  6461. // if (this.activeItems_.length > 0)
  6462. // if (this.canScrollToBottom_()) {
  6463. // var b = Math.max(this.visibleItems.length + this.activeItems_.length - this.data.maxItemsToDisplay, 0);
  6464. // b && this.splice("visibleItems", 0, b);
  6465. // if (this.isSmoothScrollEnabled_() || this.dockableMessages.length)
  6466. // this.preinsertHeight_ = this.items.clientHeight;
  6467. // this.activeItems_.unshift("visibleItems");
  6468. // try {
  6469. // this.push.apply(this, this.activeItems_)
  6470. // } catch (c) {
  6471. // Tm(c)
  6472. // }
  6473. // this.activeItems_ = [];
  6474. // this.isSmoothScrollEnabled_() ? this.canScrollToBottom_() && $u(function() {
  6475. // a.showNewItems_()
  6476. // }) : $u(function() {
  6477. // a.refreshOffsetContainerHeight_();
  6478. // a.maybeScrollToBottom_()
  6479. // })
  6480. // } else
  6481. // this.activeItems_.length > this.data.maxItemsToDisplay && this.activeItems_.splice(0, this.activeItems_.length - this.data.maxItemsToDisplay)
  6482. // }
  6483.  
  6484. } else if (sfi === '0.156.86') {
  6485. // https://www.youtube.com/s/desktop/f61c8d85/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  6486.  
  6487. // added "refreshOffsetContainerHeight_"
  6488.  
  6489. // f.flushActiveItems_ = function() {
  6490. // var a = this;
  6491. // if (0 < this.activeItems_.length)
  6492. // if (this.canScrollToBottom_()) {
  6493. // var b = Math.max(this.visibleItems.length + this.activeItems_.length - this.data.maxItemsToDisplay, 0);
  6494. // b && this.splice("visibleItems", 0, b);
  6495. // if (this.isSmoothScrollEnabled_() || this.dockableMessages.length)
  6496. // this.preinsertHeight_ = this.items.clientHeight;
  6497. // this.activeItems_.unshift("visibleItems");
  6498. // try {
  6499. // this.push.apply(this, this.activeItems_)
  6500. // } catch (c) {
  6501. // fm(c)
  6502. // }
  6503. // this.activeItems_ = [];
  6504. // this.isSmoothScrollEnabled_() ? this.canScrollToBottom_() && Mw(function() {
  6505. // a.showNewItems_()
  6506. // }) : Mw(function() {
  6507. // a.refreshOffsetContainerHeight_();
  6508. // a.maybeScrollToBottom_()
  6509. // })
  6510. // } else
  6511. // this.activeItems_.length > this.data.maxItemsToDisplay && this.activeItems_.splice(0, this.activeItems_.length - this.data.maxItemsToDisplay)
  6512. // }
  6513. // ;
  6514.  
  6515. } else if (sfi === '0.150.84') {
  6516. // https://www.youtube.com/s/desktop/e4d15d2c/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  6517. // var b = Math.max(this.visibleItems.length + this.activeItems_.length - this.data.maxItemsToDisplay, 0);
  6518. // b && this.splice("visibleItems", 0, b);
  6519. // if (this.isSmoothScrollEnabled_() || this.dockableMessages.length)
  6520. // this.preinsertHeight_ = this.items.clientHeight;
  6521. // this.activeItems_.unshift("visibleItems");
  6522. // try {
  6523. // this.push.apply(this, this.activeItems_)
  6524. // } catch (c) {
  6525. // nm(c)
  6526. // }
  6527. // this.activeItems_ = [];
  6528. // this.isSmoothScrollEnabled_() ? this.canScrollToBottom_() && zQ(function() {
  6529. // a.showNewItems_()
  6530. // }) : zQ(function() {
  6531. // a.maybeScrollToBottom_()
  6532. // })
  6533. } else if (sfi === '0.137.81' || sfi === '0.138.81') {
  6534. // e.g. https://www.youtube.com/yts/jsbin/live_chat_polymer-vflCyWEBP/live_chat_polymer.js
  6535. } else {
  6536. assertor(() => fnIntegrity(mclp.flushActiveItems_, '0.158.86'))
  6537. || logFn('mclp.flushActiveItems_', mclp.flushActiveItems_)();
  6538. }
  6539. }
  6540.  
  6541. let hasMoreMessageState = !ENABLE_SHOW_MORE_BLINKER ? -1 : 0;
  6542.  
  6543. mclp.flushActiveItems66_ = mclp.flushActiveItems_;
  6544.  
  6545.  
  6546. const preloadFn = (acItems) => {
  6547. let waitFor = [];
  6548. /** @type {Set<string>} */
  6549. const imageLinks = new Set();
  6550.  
  6551. if (ENABLE_PRELOAD_THUMBNAIL || EMOJI_IMAGE_SINGLE_THUMBNAIL || AUTHOR_PHOTO_SINGLE_THUMBNAIL) {
  6552. for (const item of acItems) {
  6553. fixLiveChatItem(item, imageLinks);
  6554. }
  6555. }
  6556. if (ENABLE_PRELOAD_THUMBNAIL && kptPF !== null && (kptPF & (8 | 4)) && imageLinks.size > 0) {
  6557.  
  6558. // reference: https://github.com/Yuanfang-fe/Blog-X/issues/34
  6559. const rel = kptPF & 8 ? 'subresource' : kptPF & 16 ? 'preload' : kptPF & 4 ? 'prefetch' : '';
  6560. // preload performs the high priority fetching.
  6561. // prefetch delays the chat display if the video resoruce is demanding.
  6562.  
  6563. if (rel) {
  6564.  
  6565. imageLinks.forEach(imageLink => {
  6566. let d = false;
  6567. if (SKIP_PRELOAD_EMOJI && imageLink.includes('.ggpht.com/')) return;
  6568. const isEmoji = imageLink.includes('/emoji/');
  6569. const pretechedSet = isEmoji ? emojiPrefetched : authorPhotoPrefetched;
  6570. if (!pretechedSet.has(imageLink)) {
  6571. pretechedSet.add(imageLink);
  6572. d = true;
  6573. }
  6574. if (d) {
  6575. waitFor.push(linker(null, rel, imageLink, 'image'));
  6576.  
  6577. }
  6578. })
  6579.  
  6580. }
  6581.  
  6582. }
  6583.  
  6584. return async () => {
  6585. if (waitFor.length > 0) {
  6586. await Promise.race([new Promise(r => setTimeout(r, 250)), Promise.all(waitFor)]);
  6587. }
  6588. waitFor.length = 0;
  6589. waitFor = null;
  6590. };
  6591.  
  6592. };
  6593.  
  6594. mclp.flushActiveItems78_ = async function (tid) {
  6595. try {
  6596.  
  6597. if (tid !== mlf) return;
  6598. if ((this._flag0281_ & 0x4) == 0x4) {
  6599. const cnt = this;
  6600.  
  6601. if (tid !== mlf || cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  6602. if (!cnt.activeItems_ || cnt.activeItems_.length === 0) return;
  6603.  
  6604. mlf++;
  6605. if (mlg > 1e9) mlg = 9;
  6606. ++mlg;
  6607. const acItems = cnt.activeItems_;
  6608. if (acItems.length < MAX_ITEMS_FOR_FULL_FLUSH) {
  6609. const pn = preloadFn(acItems);
  6610. await pn();
  6611. }
  6612. cnt.flushActiveItems66_();
  6613.  
  6614. return 1;
  6615.  
  6616. }
  6617. const lockedMaxItemsToDisplay = this.data.maxItemsToDisplay944;
  6618. let logger = false;
  6619. const cnt = this;
  6620. let immd = cnt.__intermediate_delay__;
  6621. await iAFP(this.hostElement).then();
  6622. // await new Promise(requestAnimationFrame);
  6623.  
  6624. if (tid !== mlf || cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  6625. if (!cnt.activeItems_ || cnt.activeItems_.length === 0) return;
  6626.  
  6627. mlf++;
  6628. if (mlg > 1e9) mlg = 9;
  6629. ++mlg;
  6630.  
  6631. const tmpMaxItemsCount = this.data.maxItemsToDisplay;
  6632. const reducedMaxItemsToDisplay = MAX_ITEMS_FOR_FULL_FLUSH;
  6633. let changeMaxItemsToDisplay = false;
  6634. const activeItemsLen = this.activeItems_.length;
  6635. if (activeItemsLen > tmpMaxItemsCount && tmpMaxItemsCount > 0) {
  6636. logger = true;
  6637.  
  6638. groupCollapsed("YouTube Super Fast Chat", " | flushActiveItems78_");
  6639.  
  6640. logger && console.log('[Begin]')
  6641.  
  6642. console.log('this.activeItems_.length > N', activeItemsLen, tmpMaxItemsCount);
  6643. if (ENABLE_REDUCED_MAXITEMS_FOR_FLUSH && lockedMaxItemsToDisplay === tmpMaxItemsCount && lockedMaxItemsToDisplay !== reducedMaxItemsToDisplay) {
  6644. console.log('reduce maxitems');
  6645. if (tmpMaxItemsCount > reducedMaxItemsToDisplay) {
  6646. // as all the rendered chats are already "outdated"
  6647. // all old chats shall remove and reduced number of few chats will be rendered
  6648. // then restore to the original number
  6649. changeMaxItemsToDisplay = true;
  6650. this.data.maxItemsToDisplay = reducedMaxItemsToDisplay;
  6651. console.log(`'maxItemsToDisplay' is reduced from ${tmpMaxItemsCount} to ${reducedMaxItemsToDisplay}.`)
  6652. }
  6653. this.activeItems_.splice(0, activeItemsLen - this.data.maxItemsToDisplay);
  6654. // console.log('changeMaxItemsToDisplay 01', this.data.maxItemsToDisplay, oMaxItemsToDisplay, reducedMaxItemsToDisplay)
  6655.  
  6656. console.log('new this.activeItems_.length > N', this.activeItems_.length);
  6657. } else {
  6658. this.activeItems_.splice(0, activeItemsLen - (tmpMaxItemsCount < 900 ? tmpMaxItemsCount : 900));
  6659.  
  6660. console.log('new this.activeItems_.length > N', this.activeItems_.length);
  6661. }
  6662. }
  6663. // it is found that it will render all stacked chats after switching back from background
  6664. // to avoid lagging in popular livestream with massive chats, trim first before rendering.
  6665. // this.activeItems_.length > this.data.maxItemsToDisplay && this.activeItems_.splice(0, this.activeItems_.length - this.data.maxItemsToDisplay);
  6666.  
  6667. cnt.__intermediate_delay__ = Promise.all([cnt.__intermediate_delay__ || null, immd || null]);
  6668. await Promise.resolve();
  6669. const acItems = cnt.activeItems_;
  6670. const len1 = acItems.length;
  6671. if (!len1) console.warn('cnt.activeItems_.length = 0');
  6672.  
  6673. const pn = preloadFn(acItems);
  6674. const noVisibleItem1 = ((cnt.visibleItems || 0).length || 0) === 0;
  6675. skipDontRender = noVisibleItem1;
  6676. await pn();
  6677. // console.log('ss2', Date.now())
  6678. cnt.flushActiveItems66_();
  6679. const noVisibleItem2 = ((cnt.visibleItems || 0).length || 0) === 0;
  6680. skipDontRender = noVisibleItem2;
  6681. await Promise.resolve();
  6682. if (changeMaxItemsToDisplay && this.data.maxItemsToDisplay === reducedMaxItemsToDisplay && tmpMaxItemsCount > reducedMaxItemsToDisplay) {
  6683. this.data.maxItemsToDisplay = tmpMaxItemsCount;
  6684.  
  6685. logger && console.log(`'maxItemsToDisplay' is restored from ${reducedMaxItemsToDisplay} to ${tmpMaxItemsCount}.`);
  6686. // console.log('changeMaxItemsToDisplay 02', this.data.maxItemsToDisplay, oMaxItemsToDisplay, reducedMaxItemsToDisplay)
  6687. } else if (changeMaxItemsToDisplay) {
  6688.  
  6689. logger && console.log(`'maxItemsToDisplay' cannot be restored`, {
  6690. maxItemsToDisplay: this.data.maxItemsToDisplay,
  6691. reducedMaxItemsToDisplay,
  6692. originalMaxItemsToDisplay: tmpMaxItemsCount
  6693. });
  6694. }
  6695. logger && console.log('[End]');
  6696.  
  6697. logger && console.groupEnd();
  6698.  
  6699. if (noVisibleItem1 && !noVisibleItem2) {
  6700. // fix possible no auto scroll issue.
  6701. !((cnt.__notRequired__ || 0) & 256) && setTimeout(() => cnt.setAtBottom(), 1);
  6702. }
  6703.  
  6704. if (!ENABLE_NO_SMOOTH_TRANSFORM) {
  6705.  
  6706.  
  6707. const ff = () => {
  6708.  
  6709. if (cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  6710. // if (tid !== mlf || cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  6711. if (!cnt.atBottom && cnt.allowScroll && cnt.hasUserJustInteracted11_ && !cnt.hasUserJustInteracted11_()) {
  6712.  
  6713. if (typeof nextBrowserTick !== 'function') {
  6714. cnt.scrollToBottom_();
  6715. Promise.resolve().then(() => {
  6716. if (cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  6717. if (!cnt.canScrollToBottom_()) cnt.scrollToBottom_();
  6718. });
  6719. } else {
  6720. nextBrowserTick(() => {
  6721. if (cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  6722. cnt.scrollToBottom_();
  6723. });
  6724. }
  6725.  
  6726. }
  6727. }
  6728.  
  6729. ff();
  6730.  
  6731.  
  6732. Promise.resolve().then(ff);
  6733.  
  6734. // requestAnimationFrame(ff);
  6735. } else if (true) { // it might not be sticky to bottom when there is a full refresh.
  6736.  
  6737. const knt = cnt;
  6738. if (!scrollChatFn) {
  6739. const cnt = knt;
  6740. const f = () => {
  6741. const itemScroller = cnt.itemScroller;
  6742. if (!itemScroller || itemScroller.isConnected === false || cnt.isAttached === false) return;
  6743. if (!cnt.atBottom) {
  6744. cnt.scrollToBottom_();
  6745. } else if (itemScroller.scrollTop === 0) { // not yet interacted by user; cannot stick to bottom
  6746. itemScroller.scrollTop = itemScroller.scrollHeight;
  6747. }
  6748. };
  6749. if (typeof nextBrowserTick !== 'function') {
  6750. scrollChatFn = () => Promise.resolve().then(f).then(f);
  6751. } else {
  6752. scrollChatFn = () => nextBrowserTick(f);
  6753. }
  6754. }
  6755.  
  6756. scrollChatFn();
  6757. }
  6758.  
  6759. return 1;
  6760.  
  6761.  
  6762. } catch (e) {
  6763. console.warn(e);
  6764. }
  6765. }
  6766.  
  6767. mclp.flushActiveItems77_ = function () {
  6768.  
  6769. return new Promise(resResolve => {
  6770. try {
  6771. const cnt = this;
  6772. if (mlf > 1e9) mlf = 9;
  6773. let tid = ++mlf;
  6774. const hostElement = cnt.hostElement || cnt;
  6775. if (tid !== mlf || cnt.isAttached === false || hostElement.isConnected === false) return resResolve();
  6776. if (!cnt.activeItems_ || cnt.activeItems_.length === 0) return resResolve();
  6777.  
  6778. // 4 times to maxItems to avoid frequent trimming.
  6779. // 1 ... 10 ... 20 ... 30 ... 40 ... 50 ... 60 => 16 ... 20 ... 30 ..... 60 ... => 16
  6780.  
  6781. const lockedMaxItemsToDisplay = this.data.maxItemsToDisplay944;
  6782. this.activeItems_.length > lockedMaxItemsToDisplay * 4 && lockedMaxItemsToDisplay > 4 && this.activeItems_.splice(0, this.activeItems_.length - lockedMaxItemsToDisplay - 1);
  6783. if (cnt.canScrollToBottom_()) {
  6784. cnt.mutexPromiseFA78 = (cnt.mutexPromiseFA78 || Promise.resolve())
  6785. .then(() => cnt.flushActiveItems78_(tid)) // async function
  6786. .then((asyncResult) => {
  6787. resResolve(asyncResult); // either undefined or 1
  6788. resResolve = null;
  6789. }).catch((e) => {
  6790. console.warn(e);
  6791. if (resResolve) resResolve();
  6792. });
  6793. } else {
  6794. resResolve(2);
  6795. resResolve = null;
  6796. }
  6797. } catch (e) {
  6798. console.warn(e);
  6799. if (resResolve) resResolve();
  6800. }
  6801.  
  6802.  
  6803. });
  6804.  
  6805. }
  6806.  
  6807. mclp.flushActiveItems_ = function () {
  6808. const cnt = this;
  6809.  
  6810. if (arguments.length !== 0 || !cnt.activeItems_ || !cnt.canScrollToBottom_) return cnt.flushActiveItems66_.apply(this, arguments);
  6811.  
  6812. if (cnt.activeItems_.length === 0) {
  6813. cnt.__intermediate_delay__ = null;
  6814. return;
  6815. }
  6816.  
  6817. const cntData = ((cnt || 0).data || 0);
  6818. if (cntData.maxItemsToDisplay944 === undefined) {
  6819. cntData.maxItemsToDisplay944 = null;
  6820. if (cntData.maxItemsToDisplay > MAX_ITEMS_FOR_TOTAL_DISPLAY) cntData.maxItemsToDisplay = MAX_ITEMS_FOR_TOTAL_DISPLAY;
  6821. cntData.maxItemsToDisplay944 = cntData.maxItemsToDisplay || null;
  6822. }
  6823.  
  6824. // ignore previous __intermediate_delay__ and create a new one
  6825. cnt.__intermediate_delay__ = new Promise(resolve => {
  6826. cnt.flushActiveItems77_().then(rt => { // either undefined or 1 or 2
  6827. if (rt === 1) {
  6828. resolve(1); // success, scroll to bottom
  6829. if (hasMoreMessageState === 1) {
  6830. hasMoreMessageState = 0;
  6831. const showMore = (cnt.$ || 0)['show-more'];
  6832. if (showMore) {
  6833. showMore.classList.remove('has-new-messages-miuzp');
  6834. }
  6835. }
  6836. }
  6837. else if (rt === 2) {
  6838. resolve(2); // success, trim
  6839. if (hasMoreMessageState === 0) {
  6840. hasMoreMessageState = 1;
  6841. const showMore = cnt.$['show-more'];
  6842. if (showMore) {
  6843. showMore.classList.add('has-new-messages-miuzp');
  6844. }
  6845. }
  6846. }
  6847. else resolve(-1); // skip
  6848. }).catch(e => {
  6849. console.warn(e);
  6850. });
  6851. });
  6852.  
  6853. }
  6854. console.log("flushActiveItems_", "OK");
  6855. } else {
  6856. console.log("flushActiveItems_", "NG");
  6857. }
  6858. }
  6859.  
  6860. if ((_flag0281_ & 0x40) == 0) {
  6861.  
  6862. if (ENABLE_NO_SMOOTH_TRANSFORM && SUPPRESS_refreshOffsetContainerHeight_ && typeof mclp.refreshOffsetContainerHeight_ === 'function' && !mclp.refreshOffsetContainerHeight26_ && mclp.refreshOffsetContainerHeight_.length === 0) {
  6863. assertor(() => fnIntegrity(mclp.refreshOffsetContainerHeight_, '0.31.21'));
  6864. mclp.refreshOffsetContainerHeight26_ = mclp.refreshOffsetContainerHeight_;
  6865. mclp.refreshOffsetContainerHeight_ = function () {
  6866. // var a = this.itemScroller.clientHeight;
  6867. // this.itemOffset.style.height = this.items.clientHeight + "px";
  6868. // this.bottomAlignMessages && (this.itemOffset.style.minHeight = a + "px")
  6869. }
  6870. console.log("refreshOffsetContainerHeight_", "OK");
  6871. } else {
  6872. console.log("refreshOffsetContainerHeight_", "NG");
  6873. }
  6874.  
  6875. }
  6876.  
  6877. if ((_flag0281_ & 0x80) == 0) {
  6878. mclp.delayFlushActiveItemsAfterUserAction11_ = async function () {
  6879. try {
  6880. if (mlg > 1e9) mlg = 9;
  6881. const tid = ++mlg;
  6882. const keepTrialCond = () => this.atBottom && this.allowScroll && (tid === mlg) && this.isAttached === true && this.activeItems_.length >= 1 && (this.hostElement || 0).isConnected === true;
  6883. const runCond = () => this.canScrollToBottom_();
  6884. if (!keepTrialCond()) return;
  6885. if (runCond()) return this.flushActiveItems_() | 1; // avoid return promise
  6886. await new Promise(r => setTimeout(r, 80));
  6887. if (!keepTrialCond()) return;
  6888. if (runCond()) return this.flushActiveItems_() | 1;
  6889. await iAFP(this.hostElement).then();
  6890. // await new Promise(requestAnimationFrame);
  6891. if (runCond()) return this.flushActiveItems_() | 1;
  6892. } catch (e) {
  6893. console.warn(e);
  6894. }
  6895. }
  6896. }
  6897.  
  6898. if ((_flag0281_ & 0x40) == 0 ) {
  6899.  
  6900. if( (mclp.atBottomChanged_ || 0).length === 0) {
  6901. // note: if the scrolling is too frequent, the show more visibility might get wrong.
  6902.  
  6903.  
  6904.  
  6905.  
  6906.  
  6907. const sfi = fnIntegrity(mclp.atBottomChanged_);
  6908.  
  6909. if(sfi === '0.75.37'){
  6910. // https://www.youtube.com/s/desktop/f7495da0/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  6911.  
  6912.  
  6913. // Dec 2024.
  6914.  
  6915. /**
  6916. *
  6917. *
  6918. f.atBottomChanged_ = function() {
  6919. var a = this;
  6920. this.atBottom ? this.hideShowMoreAsync_ || (this.hideShowMoreAsync_ = Zu(function() {
  6921. R(a.hostElement).querySelector("#show-more").style.visibility = "hidden"
  6922. }, 200)) : (this.hideShowMoreAsync_ && $u(this.hideShowMoreAsync_),
  6923. this.hideShowMoreAsync_ = null,
  6924. R(this.hostElement).querySelector("#show-more").style.visibility = "visible")
  6925. }
  6926. *
  6927. */
  6928.  
  6929. } else {
  6930. assertor(() => fnIntegrity(mclp.atBottomChanged_, '0.75.37'));
  6931. }
  6932.  
  6933.  
  6934. const querySelector = HTMLElement.prototype.querySelector;
  6935. const U = (element) => ({
  6936. querySelector: (selector) => querySelector.call(element, selector)
  6937. });
  6938.  
  6939. let qid = 0;
  6940. mclp.__updateButtonVisibility371__ = function (button) {
  6941. Promise.resolve(this).then((cnt) => {
  6942. button.style.visibility = cnt.__buttonVisibility371__;
  6943. });
  6944. }
  6945. const fixButtonOnClick = function (cnt, button) {
  6946. button.addEventListener('click', (evt) => {
  6947. evt.stopImmediatePropagation();
  6948. evt.stopPropagation();
  6949. evt.preventDefault();
  6950. Promise.resolve(cnt).then((cnt) => {
  6951. cnt.scrollToBottom_();
  6952. });
  6953. }, true);
  6954. // button.addEventListener('pointerup', (evt)=>{
  6955. // evt.stopImmediatePropagation();
  6956. // evt.stopPropagation();
  6957. // }, true);
  6958. // button.addEventListener('mouseup', (evt)=>{
  6959. // evt.stopImmediatePropagation();
  6960. // evt.stopPropagation();
  6961. // }, true);
  6962. }
  6963. mclp.atBottomChanged_ = function () {
  6964. let a = this.atBottom;
  6965. const button = (this.$ || 0)['show-more'];
  6966. if (button) {
  6967. // primary execution
  6968. if (a) {
  6969. if (this.__buttonVisibility371__ !== "hidden") {
  6970. this.__buttonVisibility371__ = "hidden";
  6971. if (!this.hideShowMoreAsync_) {
  6972. const tid = ++qid;
  6973. this.hideShowMoreAsync_ = foregroundPromiseFn().then(() => {
  6974. if (tid !== qid) {
  6975. return;
  6976. }
  6977. this.__updateButtonVisibility371__(button);
  6978. });
  6979. }
  6980. }
  6981. } else {
  6982. if (this.__buttonVisibility371__ !== "visible") {
  6983. this.__buttonVisibility371__ = "visible";
  6984. if (this.hideShowMoreAsync_) {
  6985. qid++;
  6986. }
  6987. this.hideShowMoreAsync_ = null;
  6988. if (!button.__fix_onclick__) {
  6989. button.__fix_onclick__ = true;
  6990. fixButtonOnClick(this, button);
  6991. }
  6992. this.__updateButtonVisibility371__(button);
  6993. }
  6994. }
  6995. } else {
  6996. // fallback
  6997. let tid = ++qid;
  6998. let b = this;
  6999. a ? this.hideShowMoreAsync_ || (this.hideShowMoreAsync_ = this.async(function () {
  7000. if (tid !== qid) return;
  7001. U(b.hostElement).querySelector("#show-more").style.visibility = "hidden"
  7002. }, 200)) : (this.hideShowMoreAsync_ && this.cancelAsync(this.hideShowMoreAsync_),
  7003. this.hideShowMoreAsync_ = null,
  7004. U(this.hostElement).querySelector("#show-more").style.visibility = "visible")
  7005. }
  7006. }
  7007.  
  7008. console.log("atBottomChanged_", "OK");
  7009.  
  7010. } else if ((mclp.atBottomChanged_ || 0).length === 1) {
  7011. // note: if the scrolling is too frequent, the show more visibility might get wrong.
  7012.  
  7013. const sfi = fnIntegrity(mclp.atBottomChanged_);
  7014. if (sfi === '1.73.37') {
  7015. // https://www.youtube.com/s/desktop/e4d15d2c/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  7016.  
  7017. /**
  7018. *
  7019. *
  7020. *
  7021. f.atBottomChanged_ = function(a) {
  7022. var b = this;
  7023. a ? this.hideShowMoreAsync_ || (this.hideShowMoreAsync_ = zQ(function() {
  7024. T(b.hostElement).querySelector("#show-more").style.visibility = "hidden"
  7025. }, 200)) : (this.hideShowMoreAsync_ && AQ(this.hideShowMoreAsync_),
  7026. this.hideShowMoreAsync_ = null,
  7027. T(this.hostElement).querySelector("#show-more").style.visibility = "visible")
  7028. };
  7029.  
  7030. *
  7031. *
  7032. */
  7033.  
  7034.  
  7035. } else if (sfi === '1.75.39') {
  7036. // e.g. https://www.youtube.com/yts/jsbin/live_chat_polymer-vflCyWEBP/live_chat_polymer.js
  7037. } else {
  7038. assertor(() => fnIntegrity(mclp.atBottomChanged_, '1.73.37'));
  7039. }
  7040.  
  7041. const querySelector = HTMLElement.prototype.querySelector;
  7042. const U = (element) => ({
  7043. querySelector: (selector) => querySelector.call(element, selector)
  7044. });
  7045.  
  7046. let qid = 0;
  7047. mclp.__updateButtonVisibility371__ = function (button) {
  7048. Promise.resolve(this).then((cnt) => {
  7049. button.style.visibility = cnt.__buttonVisibility371__;
  7050. });
  7051. }
  7052. const fixButtonOnClick = function (cnt, button) {
  7053. button.addEventListener('click', (evt) => {
  7054. evt.stopImmediatePropagation();
  7055. evt.stopPropagation();
  7056. evt.preventDefault();
  7057. Promise.resolve(cnt).then((cnt) => {
  7058. cnt.scrollToBottom_();
  7059. });
  7060. }, true);
  7061. // button.addEventListener('pointerup', (evt)=>{
  7062. // evt.stopImmediatePropagation();
  7063. // evt.stopPropagation();
  7064. // }, true);
  7065. // button.addEventListener('mouseup', (evt)=>{
  7066. // evt.stopImmediatePropagation();
  7067. // evt.stopPropagation();
  7068. // }, true);
  7069. }
  7070. mclp.atBottomChanged_ = function (a) {
  7071. const button = (this.$ || 0)['show-more'];
  7072. if (button) {
  7073. // primary execution
  7074. if (a) {
  7075. if (this.__buttonVisibility371__ !== "hidden") {
  7076. this.__buttonVisibility371__ = "hidden";
  7077. if (!this.hideShowMoreAsync_) {
  7078. const tid = ++qid;
  7079. this.hideShowMoreAsync_ = foregroundPromiseFn().then(() => {
  7080. if (tid !== qid) {
  7081. return;
  7082. }
  7083. this.__updateButtonVisibility371__(button);
  7084. });
  7085. }
  7086. }
  7087. } else {
  7088. if (this.__buttonVisibility371__ !== "visible") {
  7089. this.__buttonVisibility371__ = "visible";
  7090. if (this.hideShowMoreAsync_) {
  7091. qid++;
  7092. }
  7093. this.hideShowMoreAsync_ = null;
  7094. if (!button.__fix_onclick__) {
  7095. button.__fix_onclick__ = true;
  7096. fixButtonOnClick(this, button);
  7097. }
  7098. this.__updateButtonVisibility371__(button);
  7099. }
  7100. }
  7101. } else {
  7102. // fallback
  7103. let tid = ++qid;
  7104. let b = this;
  7105. a ? this.hideShowMoreAsync_ || (this.hideShowMoreAsync_ = this.async(function () {
  7106. if (tid !== qid) return;
  7107. U(b.hostElement).querySelector("#show-more").style.visibility = "hidden"
  7108. }, 200)) : (this.hideShowMoreAsync_ && this.cancelAsync(this.hideShowMoreAsync_),
  7109. this.hideShowMoreAsync_ = null,
  7110. U(this.hostElement).querySelector("#show-more").style.visibility = "visible")
  7111. }
  7112. }
  7113.  
  7114. console.log("atBottomChanged_", "OK");
  7115. } else {
  7116. console.log("atBottomChanged_", "NG");
  7117. }
  7118. }
  7119.  
  7120.  
  7121. if ((_flag0281_ & 0x2) == 0) {
  7122. if ((mclp.onScrollItems_ || 0).length === 1) {
  7123.  
  7124. assertor(() => fnIntegrity(mclp.onScrollItems_, '1.17.9'));
  7125. mclp.onScrollItems66_ = mclp.onScrollItems_;
  7126. mclp.onScrollItems77_ = async function (evt) {
  7127. if (myw > 1e9) myw = 9;
  7128. let tid = ++myw;
  7129.  
  7130. await iAFP(this.hostElement).then();
  7131. // await new Promise(requestAnimationFrame);
  7132.  
  7133. if (tid !== myw) {
  7134. return;
  7135. }
  7136.  
  7137. const cnt = this;
  7138.  
  7139. await Promise.resolve();
  7140. if (USE_OPTIMIZED_ON_SCROLL_ITEMS) {
  7141. const onScrollItemsBasicOnly_ = !!((cnt.__notRequired__ || 0) & 512);
  7142. await Promise.resolve().then(() => {
  7143. this.ytRendererBehavior.onScroll(evt);
  7144. }).then(() => {
  7145. if (onScrollItemsBasicOnly_) return;
  7146. if (this.canScrollToBottom_()) {
  7147. const hasUserJustInteracted = this.hasUserJustInteracted11_ ? this.hasUserJustInteracted11_() : true;
  7148. if (hasUserJustInteracted) {
  7149. // only when there is an user action
  7150. !((cnt.__notRequired__ || 0) & 256) && this.setAtBottom();
  7151. return 1;
  7152. }
  7153. } else {
  7154. // no message inserting
  7155. !((cnt.__notRequired__ || 0) & 256) && this.setAtBottom();
  7156. return 1;
  7157. }
  7158. }).then((r) => {
  7159.  
  7160. if (onScrollItemsBasicOnly_) return;
  7161. if (this.activeItems_.length) {
  7162.  
  7163. if (this.canScrollToBottom_()) {
  7164. this.flushActiveItems_();
  7165. return 1 && r;
  7166. } else if (this.atBottom && this.allowScroll && (this.hasUserJustInteracted11_ && this.hasUserJustInteracted11_())) {
  7167. // delayed due to user action
  7168. this.delayFlushActiveItemsAfterUserAction11_ && this.delayFlushActiveItemsAfterUserAction11_();
  7169. return 0;
  7170. }
  7171. }
  7172. }).then((r) => {
  7173. if (onScrollItemsBasicOnly_) return;
  7174. if (r) {
  7175. // ensure setAtBottom is correctly set
  7176. !((cnt.__notRequired__ || 0) & 256) && this.setAtBottom();
  7177. }
  7178. });
  7179. } else {
  7180. cnt.onScrollItems66_(evt);
  7181. }
  7182.  
  7183. await Promise.resolve();
  7184.  
  7185. }
  7186.  
  7187. mclp.onScrollItems_ = function (evt) {
  7188.  
  7189. const cnt = this;
  7190. cnt.__intermediate_delay__ = new Promise(resolve => {
  7191. cnt.onScrollItems77_(evt).then(() => {
  7192. resolve();
  7193. });
  7194. });
  7195. }
  7196. console.log("onScrollItems_", "OK");
  7197. } else {
  7198. console.log("onScrollItems_", "NG");
  7199. }
  7200. }
  7201.  
  7202. if ((_flag0281_ & 0x2) == 0) {
  7203. if ((mclp.handleLiveChatActions_ || 0).length === 1) {
  7204.  
  7205. const sfi = fnIntegrity(mclp.handleLiveChatActions_);
  7206. // handleLiveChatActions66_
  7207. if(sfi === '1.40.20') {
  7208. // https://www.youtube.com/s/desktop/c01ea7e3/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  7209.  
  7210.  
  7211. // f.handleLiveChatActions_ = function(a) {
  7212. // var b = this;
  7213. // a.length && (a.forEach(this.handleLiveChatAction_, this),
  7214. // this.maybeResizeScrollContainer_(a),
  7215. // this.flushActiveItems_(),
  7216. // $u(function() {
  7217. // b.maybeScrollToBottom_()
  7218. // }))
  7219. // }
  7220.  
  7221. } else if (sfi === '1.39.20') {
  7222. // TBC
  7223. } else if (sfi === '1.31.17') {
  7224. // original
  7225. } else {
  7226. assertor(() => fnIntegrity(mclp.handleLiveChatActions_, '1.40.20'))
  7227. || logFn('mclp.handleLiveChatActions_', mclp.handleLiveChatActions_)();
  7228. }
  7229.  
  7230. mclp.handleLiveChatActions66_ = mclp.handleLiveChatActions_;
  7231.  
  7232. mclp.handleLiveChatActions77_ = async function (arr) {
  7233. if (typeof (arr || 0).length !== 'number') {
  7234. this.handleLiveChatActions66_(arr);
  7235. return;
  7236. }
  7237. if (mzt > 1e9) mzt = 9;
  7238. let tid = ++mzt;
  7239.  
  7240. if (zarr === null) zarr = arr;
  7241. else Array.prototype.push.apply(zarr, arr);
  7242. arr = null;
  7243.  
  7244. await iAFP(this.hostElement).then();
  7245. // await new Promise(requestAnimationFrame);
  7246.  
  7247. if (tid !== mzt || zarr === null) {
  7248. return;
  7249. }
  7250.  
  7251. const carr = zarr;
  7252. zarr = null;
  7253.  
  7254. await Promise.resolve();
  7255. this.handleLiveChatActions66_(carr);
  7256. await Promise.resolve();
  7257.  
  7258. }
  7259.  
  7260. mclp.handleLiveChatActions_ = function (arr) {
  7261.  
  7262.  
  7263. try{
  7264. preprocessChatLiveActions(arr);
  7265. }catch(e){
  7266. console.warn(e);
  7267. }
  7268.  
  7269.  
  7270.  
  7271. // console.log(1929, cnt.activeItems_)
  7272. // console.log(9487, arr);
  7273.  
  7274. const cnt = this;
  7275. cnt.__intermediate_delay__ = new Promise(resolve => {
  7276. cnt.handleLiveChatActions77_(arr).then(() => {
  7277. resolve();
  7278. });
  7279. });
  7280.  
  7281. resistanceUpdateFn_();
  7282. }
  7283. console.log("handleLiveChatActions_", "OK");
  7284. } else {
  7285. console.log("handleLiveChatActions_", "NG");
  7286. }
  7287. }
  7288.  
  7289. mclp.hasUserJustInteracted11_ = () => {
  7290. const t = dateNow();
  7291. return (t - lastWheel < 80) || currentMouseDown || currentTouchDown || (t - lastUserInteraction < 80);
  7292. }
  7293.  
  7294. if ((mclp.canScrollToBottom_ || 0).length === 0) {
  7295.  
  7296. assertor(() => fnIntegrity(mclp.canScrollToBottom_, '0.9.5'));
  7297.  
  7298. mclp.canScrollToBottom_ = function () {
  7299. return this.atBottom && this.allowScroll && !this.hasUserJustInteracted11_();
  7300. }
  7301.  
  7302. console.log("canScrollToBottom_", "OK");
  7303. } else {
  7304. console.log("canScrollToBottom_", "NG");
  7305. }
  7306.  
  7307. if (ENABLE_NO_SMOOTH_TRANSFORM) {
  7308.  
  7309. mclp.isSmoothScrollEnabled_ = function () {
  7310. return false;
  7311. }
  7312.  
  7313. mclp.maybeResizeScrollContainer_ = function () {
  7314. //
  7315. }
  7316.  
  7317. mclp.refreshOffsetContainerHeight_ = function () {
  7318. //
  7319. }
  7320.  
  7321. mclp.smoothScroll_ = function () {
  7322. //
  7323. }
  7324.  
  7325. mclp.resetSmoothScroll_ = function () {
  7326. //
  7327. }
  7328. console.log("ENABLE_NO_SMOOTH_TRANSFORM", "OK");
  7329. } else {
  7330. console.log("ENABLE_NO_SMOOTH_TRANSFORM", "NG");
  7331. }
  7332.  
  7333. if ((_flag0281_ & 0x8) == 0) {
  7334.  
  7335.  
  7336. if (typeof mclp.forEachItem_ === 'function' && !mclp.forEachItem66_ && skipErrorForhandleAddChatItemAction_ && mclp.forEachItem_.length === 1) {
  7337.  
  7338. mclp.forEachItem66_ = mclp.forEachItem_;
  7339. mclp.forEachItem_ = function (a) {
  7340.  
  7341. if ((this._flag0281_ & 0x8) == 0x8) return this.forEachItem66_(a);
  7342.  
  7343. // ƒ (a){this.visibleItems.forEach(a.bind(this,"visibleItems"));this.activeItems_.forEach(a.bind(this,"activeItems_"))}
  7344.  
  7345. try {
  7346.  
  7347. let items801 = false;
  7348. if (typeof a === 'function') {
  7349. const items = this.items;
  7350. if (items instanceof HTMLDivElement) {
  7351. const ev = this.visibleItems;
  7352. const ea = this.activeItems_;
  7353. if (ev && ea && ev.length >= 0 && ea.length >= 0) {
  7354. items801 = items;
  7355. }
  7356. }
  7357. }
  7358.  
  7359. if (items801) {
  7360. items801.__children801__ = 1;
  7361. const res = this.forEachItem66_(a);
  7362. items801.__children801__ = 0;
  7363. return res;
  7364. }
  7365.  
  7366. } catch (e) { }
  7367. return this.forEachItem66_(a);
  7368.  
  7369.  
  7370. // this.visibleItems.forEach((val, idx, arr)=>{
  7371. // a.call(this, 'visibleItems', val, idx, arr);
  7372. // });
  7373.  
  7374. // this.activeItems_.forEach((val, idx, arr)=>{
  7375. // a.call(this, 'activeItems_', val, idx, arr);
  7376. // });
  7377.  
  7378.  
  7379.  
  7380. }
  7381.  
  7382.  
  7383. }
  7384.  
  7385. }
  7386.  
  7387. if (typeof mclp.handleAddChatItemAction_ === 'function' && !mclp.handleAddChatItemAction66_ && FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION && (EMOJI_IMAGE_SINGLE_THUMBNAIL || AUTHOR_PHOTO_SINGLE_THUMBNAIL)) {
  7388.  
  7389. mclp.handleAddChatItemAction66_ = mclp.handleAddChatItemAction_;
  7390. mclp.handleAddChatItemAction_ = function (a) {
  7391. try {
  7392. if (a && typeof a === 'object' && !('length' in a)) {
  7393. fixLiveChatItem(a.item, null);
  7394. console.assert(arguments[0] === a);
  7395. }
  7396. } catch (e) { console.warn(e) }
  7397. let res;
  7398. if (skipErrorForhandleAddChatItemAction_) { // YouTube Native Engine Issue
  7399. try {
  7400. res = this.handleAddChatItemAction66_.apply(this, arguments);
  7401. } catch (e) {
  7402. if (e && (e.message || '').includes('.querySelector(')) {
  7403. console.log("skipErrorForhandleAddChatItemAction_", e.message);
  7404. } else {
  7405. throw e;
  7406. }
  7407. }
  7408. } else {
  7409. res = this.handleAddChatItemAction66_.apply(this, arguments);
  7410. }
  7411. return res;
  7412. }
  7413.  
  7414. if (FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION) console.log("handleAddChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION ]", "OK");
  7415. } else {
  7416.  
  7417. if (FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION) console.log("handleAddChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION ]", "OK");
  7418. }
  7419.  
  7420.  
  7421. if (typeof mclp.handleReplaceChatItemAction_ === 'function' && !mclp.handleReplaceChatItemAction66_ && FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT && (EMOJI_IMAGE_SINGLE_THUMBNAIL || AUTHOR_PHOTO_SINGLE_THUMBNAIL)) {
  7422.  
  7423. mclp.handleReplaceChatItemAction66_ = mclp.handleReplaceChatItemAction_;
  7424. mclp.handleReplaceChatItemAction_ = function (a) {
  7425. try {
  7426. if (a && typeof a === 'object' && !('length' in a)) {
  7427. fixLiveChatItem(a.replacementItem, null);
  7428. console.assert(arguments[0] === a);
  7429. }
  7430. } catch (e) { console.warn(e) }
  7431. return this.handleReplaceChatItemAction66_.apply(this, arguments);
  7432. }
  7433.  
  7434. if (FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT) console.log("handleReplaceChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT ]", "OK");
  7435. } else {
  7436.  
  7437. if (FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT) console.log("handleReplaceChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT ]", "OK");
  7438. }
  7439.  
  7440. console.log("[End]");
  7441. console.groupEnd();
  7442.  
  7443. }).catch(console.warn);
  7444.  
  7445.  
  7446. const tickerContainerSetAttribute = function (attrName, attrValue) { // ensure '14.30000001%'.toFixed(1)
  7447.  
  7448. let yd = (this.__dataHost || insp(this).__dataHost || 0).__data;
  7449.  
  7450. if (arguments.length === 2 && attrName === 'style' && yd && attrValue) {
  7451.  
  7452. // let v = yd.containerStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_;
  7453. let v = `${attrValue}`;
  7454. // conside a ticker is 101px width
  7455. // 1% = 1.01px
  7456. // 0.2% = 0.202px
  7457.  
  7458.  
  7459. const ratio1 = (yd.ratio * 100);
  7460. if (ratio1 > -1) { // avoid NaN
  7461.  
  7462. // countdownDurationMs
  7463. // 600000 - 0.2% <1% = 6s> <0.2% = 1.2s>
  7464. // 300000 - 0.5% <1% = 3s> <0.5% = 1.5s>
  7465. // 150000 - 1% <1% = 1.5s>
  7466. // 75000 - 2% <1% =0.75s > <2% = 1.5s>
  7467. // 30000 - 5% <1% =0.3s > <5% = 1.5s>
  7468.  
  7469. // 99px * 5% = 4.95px
  7470.  
  7471. // 15000 - 10% <1% =0.15s > <10% = 1.5s>
  7472.  
  7473.  
  7474. // 1% Duration
  7475.  
  7476. let ratio2 = ratio1;
  7477.  
  7478. const ydd = yd.data;
  7479. if (ydd) {
  7480.  
  7481. const d1 = ydd.durationSec;
  7482. const d2 = ydd.fullDurationSec;
  7483.  
  7484. // @ step timing [min. 0.2%]
  7485. let numOfSteps = 500;
  7486. if ((d1 === d2 || (d1 + 1 === d2)) && d1 > 1) {
  7487. if (d2 > 400) numOfSteps = 500; // 0.2%
  7488. else if (d2 > 200) numOfSteps = 200; // 0.5%
  7489. else if (d2 > 100) numOfSteps = 100; // 1%
  7490. else if (d2 > 50) numOfSteps = 50; // 2%
  7491. else if (d2 > 25) numOfSteps = 20; // 5% (max => 99px * 5% = 4.95px)
  7492. else numOfSteps = 20;
  7493. }
  7494. if (numOfSteps > TICKER_MAX_STEPS_LIMIT) numOfSteps = TICKER_MAX_STEPS_LIMIT;
  7495. if (numOfSteps < 5) numOfSteps = 5;
  7496.  
  7497. const rd = numOfSteps / 100.0;
  7498.  
  7499. ratio2 = Math.round(ratio2 * rd) / rd;
  7500.  
  7501. // ratio2 = Math.round(ratio2 * 5) / 5;
  7502. ratio2 = ratio2.toFixed(1);
  7503. v = v.replace(`${ratio1}%`, `${ratio2}%`).replace(`${ratio1}%`, `${ratio2}%`);
  7504.  
  7505. if (yd.__style_last__ === v) return;
  7506. yd.__style_last__ = v;
  7507. // do not consider any delay here.
  7508. // it shall be inside the looping for all properties changes. all the css background ops are in the same microtask.
  7509.  
  7510. }
  7511. }
  7512.  
  7513. HTMLElement.prototype.setAttribute.call(dr(this), attrName, v);
  7514.  
  7515.  
  7516. } else {
  7517. HTMLElement.prototype.setAttribute.apply(dr(this), arguments);
  7518. }
  7519.  
  7520. };
  7521.  
  7522.  
  7523. const fpTicker = (renderer) => {
  7524. if (FLAG_001a) return;
  7525. const cnt = insp(renderer);
  7526. assertor(() => typeof (cnt || 0).is === 'string');
  7527. assertor(() => ((cnt || 0).hostElement || 0).nodeType === 1);
  7528. const container = (cnt.$ || 0).container;
  7529. if (container) {
  7530. assertor(() => (container || 0).nodeType === 1);
  7531. assertor(() => typeof container.setAttribute === 'function');
  7532. container.setAttribute = tickerContainerSetAttribute;
  7533. } else {
  7534. console.warn(`"container" does not exist in ${cnt.is}`);
  7535. }
  7536. };
  7537.  
  7538.  
  7539. const tags = [
  7540. "yt-live-chat-ticker-renderer",
  7541. "yt-live-chat-ticker-paid-message-item-renderer",
  7542. "yt-live-chat-ticker-paid-sticker-item-renderer",
  7543. "yt-live-chat-ticker-sponsor-item-renderer"
  7544. ];
  7545.  
  7546. const tagsItemRenderer = [
  7547. "yt-live-chat-ticker-renderer",
  7548. "yt-live-chat-ticker-paid-message-item-renderer",
  7549. "yt-live-chat-ticker-paid-sticker-item-renderer",
  7550. "yt-live-chat-ticker-sponsor-item-renderer"
  7551. ];
  7552.  
  7553. const wmList = new Set;
  7554. if (DEBUG_wmList) {
  7555.  
  7556. setInterval(() => {
  7557. let q = document.querySelector('#label-text');
  7558. if(!q) return;
  7559. const size = new Set([...wmList].filter(e => e?.deref()?.isConnected === false).map(e => e?.deref())).size;
  7560. q.textContent = `${48833}, ${DEBUG_wmList_started}, ${size}`;
  7561.  
  7562. // console.log(48833, )
  7563. }, 100);
  7564. }
  7565.  
  7566.  
  7567. /*
  7568. Promise.all(tags.map(tag => customElements.whenDefined(tag))).then(() => {
  7569. const dProto = {
  7570. detachedForTickerInit: function () {
  7571. try {
  7572. this.actionHandlerBehavior.unregisterActionMap(this.behaviorActionMap)
  7573. // this.behaviorActionMap = 0;
  7574. // this.isVisibilityRoot = 0;
  7575. } catch (e) { }
  7576. return this.detached582MemoryLeak();
  7577. },
  7578. attachedForTickerInit: function () {
  7579. wmList.add(new WeakRef(this))
  7580. // fpTicker(this.hostElement || this);
  7581. return this.attached77();
  7582. },
  7583. }
  7584. for (const tag of tagsItemRenderer) { // ##tag##
  7585. const dummy = document.createElement(tag);
  7586. const cProto = getProto(dummy);
  7587. if (!cProto || !cProto.attached) {
  7588. console.warn(`proto.attached for ${tag} is unavailable.`);
  7589. continue;
  7590. }
  7591. if (FIX_MEMORY_LEAKAGE_TICKER_ACTIONMAP && typeof cProto.detached582MemoryLeak !== 'function' && typeof cProto.detached === 'function') {
  7592. cProto.detached582MemoryLeak = cProto.detached;
  7593. cProto.detached = cProto.detachedForTickerInit;
  7594. }
  7595. cProto.attached77 = cProto.attached;
  7596. cProto.attached = dProto.attachedForTickerInit;
  7597. }
  7598. });
  7599. */
  7600.  
  7601.  
  7602. Promise.all(tags.map(tag => customElements.whenDefined(tag))).then(() => {
  7603.  
  7604. if (FLAG_001b) return;
  7605. mightFirstCheckOnYtInit();
  7606. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-ticker-... hacks");
  7607. console.log("[Begin]");
  7608.  
  7609. let dummyValueForStyleReturn = null;
  7610.  
  7611. const genDummyValueForStyleReturn = () => {
  7612. let s = `--nx:82;`
  7613. let ro = {
  7614. "privateDoNotAccessOrElseSafeStyleWrappedValue_": s,
  7615. "implementsGoogStringTypedString": true
  7616. };
  7617. ro.getTypedStringValue = ro.toString = function () { return this.privateDoNotAccessOrElseSafeStyleWrappedValue_ };
  7618. return ro;
  7619. }
  7620.  
  7621. let isCSSPropertySupported_ = null;
  7622. const isCSSPropertySupported = () => {
  7623.  
  7624. // @property --ticker-rtime
  7625.  
  7626. if (typeof isCSSPropertySupported_ === 'boolean') return isCSSPropertySupported_;
  7627. isCSSPropertySupported_ = false;
  7628.  
  7629. if (typeof CSS !== 'object' || typeof (CSS || 0).registerProperty !== 'function') return false;
  7630. const documentElement = document.documentElement;
  7631. if (!documentElement) {
  7632. console.warn('document.documentElement is not found');
  7633. return false;
  7634. }
  7635. if (`${getComputedStyleCached(documentElement).getPropertyValue('--ticker-rtime')}`.length === 0) {
  7636. return false;
  7637. }
  7638.  
  7639. const ae = animate.call(documentElement,
  7640. [
  7641. { '--ticker-rtime': '70%' },
  7642. { '--ticker-rtime': '30%' }
  7643. ],
  7644. {
  7645. fill: "forwards",
  7646. duration: 1000 * 40,
  7647. easing: 'linear'
  7648. }
  7649. );
  7650.  
  7651. let animatedValue = getComputedStyleCached(document.documentElement).getPropertyValue('--ticker-rtime');
  7652. ae.finish();
  7653. if (`${animatedValue}`.length !== 3) return false;
  7654.  
  7655. isCSSPropertySupported_ = true;
  7656. return true;
  7657.  
  7658. };
  7659.  
  7660. let tickerAttachmentId = 0;
  7661.  
  7662. let windowShownAt = -1;
  7663. const setupEventForWindowShownAt = () => {
  7664. window.addEventListener('visibilitychange', () => {
  7665. if (document.visibilityState === 'visible') windowShownAt = Date.now();
  7666. else windowShownAt = 0;
  7667. }, false);
  7668. }
  7669.  
  7670. const __requestRemoval__ = function (cnt) {
  7671. if (cnt.hostElement && typeof cnt.requestRemoval === 'function') {
  7672. try {
  7673. const id = (cnt.data || 0).id;
  7674. if (!id) cnt.data = { id: 1 };
  7675. } catch (e) { }
  7676. try {
  7677. cnt.requestRemoval();
  7678. return true;
  7679. } catch (e) { }
  7680. }
  7681. return false;
  7682. }
  7683.  
  7684. const widthIORes = new WeakMap();
  7685. const widthIO = new IntersectionObserver((mutations) => {
  7686. for (const mutation of mutations) {
  7687. const elm = mutation.target;
  7688. widthIO.unobserve(elm);
  7689. const {promise, values} =widthIORes.get(elm) || {};
  7690. if(promise && values){
  7691.  
  7692.  
  7693. widthIORes.delete(elm);
  7694. values.width= mutation.boundingClientRect.width;
  7695. promise.resolve(values);
  7696. }
  7697. }
  7698. });
  7699. const widthReq = (elm)=>{
  7700.  
  7701. {
  7702.  
  7703. const {promise, values} =widthIORes.get(elm) || {};
  7704. if(promise) return promise;
  7705. }
  7706. const promise = new PromiseExternal();
  7707. widthIORes.set(elm, {promise, values: {}});
  7708. widthIO.unobserve(elm);
  7709. widthIO.observe(elm);
  7710.  
  7711. return promise;
  7712.  
  7713. }
  7714.  
  7715. let mo43p = null;
  7716. const mo43 = new MutationObserver(()=>{
  7717.  
  7718. const p = mo43p;
  7719. mo43p = null;
  7720. if(p){
  7721. p.resolve();
  7722. }
  7723. });
  7724.  
  7725.  
  7726. const dProto = {
  7727.  
  7728.  
  7729. /**
  7730. *
  7731.  
  7732. f.updateStatsBarAndMaybeShowAnimation = function(a, b, c) {
  7733. var d = this;
  7734. a || c();
  7735. a && this.statsBar && this.username && this.textContent && (this.isMouseOver ? (b(),
  7736. c()) : (a = this.animateShowStats(),
  7737. this.data.animationOrigin && this.data.trackingParams && aB().stateChanged(this.data.trackingParams, {
  7738. animationEventData: {
  7739. origin: this.data.animationOrigin
  7740. }
  7741. }),
  7742. a.finished.then(function() {
  7743. var e;
  7744. setTimeout(function() {
  7745. b();
  7746. c();
  7747. if (!d.isMouseOver) {
  7748. var g, k;
  7749. d.animateHideStats(((g = d.data) == null ? void 0 : g.dynamicStateData.stateSlideDurationMs) || 0, ((k = d.data) == null ? void 0 : k.dynamicStateData.stateUpdateDelayAfterMs) || 0)
  7750. }
  7751. }, ((e = d.data) == null ? void 0 : e.dynamicStateData.stateUpdateDelayBeforeMs) || 0)
  7752. })))
  7753. }
  7754.  
  7755. *
  7756. */
  7757.  
  7758.  
  7759.  
  7760. /**
  7761. *
  7762. *
  7763.  
  7764. f.animateShowStats = function() {
  7765. var a = this.textContent.animate({
  7766. transform: "translateY(-30px)"
  7767. }, {
  7768. duration: this.data.dynamicStateData.stateSlideDurationMs,
  7769. fill: "forwards"
  7770. });
  7771. this.username.animate({
  7772. opacity: 0
  7773. }, {
  7774. duration: 500,
  7775. fill: "forwards"
  7776. });
  7777. this.statsBar.animate({
  7778. opacity: 1
  7779. }, {
  7780. duration: 500,
  7781. fill: "forwards"
  7782. });
  7783. return a
  7784. }
  7785. ;
  7786. f.animateHideStats = function(a, b) {
  7787. this.textContent.animate({
  7788. transform: "translateY(0)"
  7789. }, {
  7790. duration: a,
  7791. fill: "forwards",
  7792. delay: b
  7793. });
  7794. this.username.animate({
  7795. opacity: 1
  7796. }, {
  7797. duration: 300,
  7798. fill: "forwards",
  7799. delay: b
  7800. });
  7801. this.statsBar.animate({
  7802. opacity: 0
  7803. }, {
  7804. duration: 300,
  7805. fill: "forwards",
  7806. delay: b
  7807. })
  7808. }
  7809. *
  7810. */
  7811. updateStatsBarAndMaybeShowAnimationRevised: function (a, b, c) {
  7812. // prevent memory leakage due to d.data was asked in a.finished.then
  7813. try{
  7814. // console.log('updateStatsBarAndMaybeShowAnimation called', this.is)
  7815. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  7816. return this.updateStatsBarAndMaybeShowAnimation38.call(this.__proxySelf0__, a, b, c);
  7817. }catch(e){
  7818. console.log('updateStatsBarAndMaybeShowAnimationRevised ERROR');
  7819. console.error(e);
  7820. }
  7821. },
  7822.  
  7823. detachedForMemoryLeakage: function () {
  7824.  
  7825. try{
  7826. this.actionHandlerBehavior.unregisterActionMap(this.behaviorActionMap)
  7827. // this.behaviorActionMap = 0;
  7828. // this.isVisibilityRoot = 0;
  7829. }catch(e){}
  7830. return this.detached582MemoryLeak();
  7831. },
  7832.  
  7833. detachedForTickerInit: function () {
  7834.  
  7835. Promise.resolve(this).then((cnt) => {
  7836. if (cnt.isAttached) return;
  7837. cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false && __requestRemoval__(cnt);
  7838. cnt.rafId > 1 && rafHub.cancel(cnt.rafId);
  7839. }).catch(console.warn);
  7840.  
  7841. let r;
  7842. try {
  7843. r = this.detached77();
  7844. } catch (e) {
  7845. console.warn(e);
  7846. }
  7847. this.__ticker_attachmentId__ = 0;
  7848. return r;
  7849. },
  7850.  
  7851. attachedForTickerInit: function () {
  7852. if (tickerAttachmentId > 1e9) tickerAttachmentId = 9;
  7853. this.__ticker_attachmentId__ = ++tickerAttachmentId;
  7854.  
  7855. const hostElement = this.hostElement;
  7856. if ( USE_ADVANCED_TICKING && hostElement instanceof HTMLElement) {
  7857. hostElement.classList.add('r6-width-adjustable');
  7858. }
  7859.  
  7860. DEBUG_wmList && wmList.add(new WeakRef(this))
  7861. if (DEBUG_wmList && !DEBUG_wmList_started) {
  7862. console.log('!!!!!!!!!!!!! DEBUG_wmList_started !!!!!!!!!')
  7863. DEBUG_wmList_started = 1;
  7864. }
  7865.  
  7866. fpTicker(hostElement || this);
  7867. return this.attached77();
  7868.  
  7869. },
  7870.  
  7871.  
  7872. // doAnimator
  7873.  
  7874. _makeAnimator: function () {
  7875. if (this._r782) return;
  7876. // if (!this.isAttached) return;
  7877. if (!this._runnerAE) {
  7878. /** @type {HTMLElement | null} */
  7879. const aElement = (this.$ || 0).container;
  7880. if (!aElement) return console.warn("this.$.container is undefined");
  7881. const da = this.data;
  7882. if (!da || !da.startBackgroundColor || !da.endBackgroundColor) return console.warn("this.data is undefined or incorrect");
  7883. const c1 = this.colorFromDecimal(da.startBackgroundColor);
  7884. const c2 = this.colorFromDecimal(da.endBackgroundColor);
  7885. if (typeof c1 !== 'string' || typeof c2 !== 'string') return console.warn('c1, c2 is not a string');
  7886.  
  7887. // if (!this.__tickerBackgroundInitialChecked__) {
  7888. // this.constructor.prototype.__tickerBackgroundInitialChecked__ = true;
  7889. // console.log('__tickerBackgroundInitialChecked__')
  7890. // this._checkTickerBackgroundChanged();
  7891. // }
  7892.  
  7893. aElement.style.setProperty('--ticker-c1', c1);
  7894. aElement.style.setProperty('--ticker-c2', c2);
  7895. aElement.classList.add(runTickerClassName);
  7896. const p = (this.countdownMs / this.countdownDurationMs) * 100;
  7897. // this._aeStartV = this.countdownMs;
  7898. // this._aeStartT = this.countdownDurationMs;
  7899. if (!(p >= 0 && p <= 100)) {
  7900. console.warn('incorrect time ratio', p);
  7901. } else {
  7902. /*
  7903. const u0 = p.toFixed(4) + '%';
  7904. this._runnerAE = animate.call(aElement,
  7905. [
  7906. { '--ticker-rtime': u0 },
  7907. { '--ticker-rtime': '0%' }
  7908. ]
  7909. ,
  7910. {
  7911. fill: "forwards",
  7912. duration: this.countdownMs,
  7913. easing: "linear"
  7914. }
  7915. );
  7916. */
  7917.  
  7918. let timingFn = 'linear';
  7919.  
  7920. const totalDuration = this.countdownDurationMs;
  7921.  
  7922. if (ATTEMPT_ANIMATED_TICKER_BACKGROUND === 'steps') {
  7923.  
  7924. // @ step timing [min. 0.2%]
  7925. let stepInterval = 0.2; // unit: %
  7926. if (totalDuration > 400000) stepInterval = 0.2;
  7927. else if (totalDuration > 200000) stepInterval = 0.5;
  7928. else if (totalDuration > 100000) stepInterval = 1;
  7929. else if (totalDuration > 50000) stepInterval = 2;
  7930. else if (totalDuration > 25000) stepInterval = 5;
  7931. else stepInterval = 5;
  7932.  
  7933. let numOfSteps = Math.round(100 / stepInterval);
  7934.  
  7935. if (numOfSteps > TICKER_MAX_STEPS_LIMIT) numOfSteps = TICKER_MAX_STEPS_LIMIT;
  7936. if (numOfSteps < 5) numOfSteps = 5;
  7937.  
  7938. timingFn = `steps(${numOfSteps}, end)`;
  7939.  
  7940. }
  7941.  
  7942.  
  7943. /** @type {Animation} */
  7944. const ae = animate.call(aElement,
  7945. [
  7946. { '--ticker-rtime': '100%' },
  7947. { '--ticker-rtime': '0%' }
  7948. ]
  7949. ,
  7950. {
  7951. fill: "forwards",
  7952. duration: totalDuration,
  7953. easing: timingFn
  7954. }
  7955. );
  7956.  
  7957. this._runnerAE = ae;
  7958.  
  7959. ae.onfinish = (event) => {
  7960. this.onfinish = null;
  7961. if (this._runnerAE !== ae) return;
  7962. if (this.isAttached === true && !this._r782 && ((this.$ || 0).container || 0).isConnected === true) {
  7963. this._aeFinished(event);
  7964. }
  7965. }
  7966.  
  7967. let bq = (1.0 - (this.countdownMs / totalDuration)) * totalDuration;
  7968.  
  7969. if (bq >= 0 && bq <= totalDuration) {
  7970.  
  7971. if (bq > totalDuration - 1) {
  7972. ae.currentTime = bq;
  7973. // setTimeout(() => {
  7974. // if (this._runnerAE === ae && ae.onfinish) ae.onfinish();
  7975. // }, 1);
  7976. } else {
  7977. ae.currentTime = bq;
  7978. }
  7979. } else {
  7980. console.warn('Error on setting _runnerAE.currentTime!');
  7981. }
  7982.  
  7983.  
  7984. aeConstructor = ae.constructor; // constructor is from iframe
  7985. return ae;
  7986. }
  7987. } else {
  7988. if (!aeConstructor) return console.warn('aeConstructor is undefined');
  7989. // assume just time update
  7990. const ae = this._runnerAE;
  7991. if (!(ae instanceof aeConstructor)) return console.warn('this._runnerAE is not Animation');
  7992. if (ae.playState !== 'paused') console.warn('ae.playState !== paused');
  7993. let p = (this.countdownMs / this.countdownDurationMs) * 100;
  7994. if (!(p >= 0 && p <= 100)) {
  7995. console.warn('incorrect time ratio', p);
  7996. } else {
  7997. // let u0 = p.toFixed(4) + '%'
  7998. /*
  7999. ae.effect.setKeyframes([
  8000. { '--ticker-rtime': u0 },
  8001. { '--ticker-rtime': '0%' }
  8002. ]);
  8003. ae.effect.updateTiming({ duration: this.countdownMs });
  8004. */
  8005. // ae.currentTime = 0;
  8006.  
  8007.  
  8008.  
  8009. let bq = (1.0 - (this.countdownMs / this.countdownDurationMs)) * this.countdownDurationMs;
  8010. if (bq >= 0 && bq <= this.countdownDurationMs) {
  8011.  
  8012. this._runnerAE.currentTime = bq
  8013. } else {
  8014. console.warn('Error on setting _runnerAE.currentTime!');
  8015. }
  8016.  
  8017.  
  8018. ae.play();
  8019. return ae;
  8020. }
  8021. }
  8022. },
  8023.  
  8024. _aeFinished: function (event) {
  8025.  
  8026. if (this._r782) return;
  8027.  
  8028. if (this.isAttached === false && ((this.$ || 0).container || 0).isConnected === false) {
  8029. this._throwOut();
  8030. return;
  8031. }
  8032.  
  8033. if (!this._runnerAE) console.warn('Error in .updateTimeout; this._runnerAE is undefined');
  8034.  
  8035. let lc = window.performance.now();
  8036. this.countdownMs = Math.max(0, this.countdownMs - (lc - this.lastCountdownTimeMs));
  8037. if (this.countdownMs > this.countdownDurationMs) this.countdownMs = this.countdownDurationMs;
  8038. this.lastCountdownTimeMs = this._lastCountdownTimeMsX0 = lc;
  8039. if (this.countdownMs > 76) console.warn('Warning: this.countdownMs is not zero when finished!', this.countdownMs, this, event); // just warning.
  8040.  
  8041. this.countdownMs = 0;
  8042. this.lastCountdownTimeMs = this._lastCountdownTimeMsX0 = null;
  8043.  
  8044. if (this.isAttached) {
  8045. let fastRemoved = false;
  8046. if (Date.now() - windowShownAt < 80 && typeof this.requestRemoval === 'function') {
  8047. // no animation if the video page is switched from background to foreground
  8048. // this.hostElement.style.display = 'none';
  8049.  
  8050. fastRemoved = __requestRemoval__(this);
  8051. }
  8052.  
  8053. if (!fastRemoved) {
  8054. "auto" === this.hostElement.style.width && this.setContainerWidth();
  8055. this.slideDown();
  8056. }
  8057. }
  8058.  
  8059.  
  8060.  
  8061. },
  8062.  
  8063.  
  8064. /** @type {()} */
  8065. _throwOut: function () {
  8066. this._r782 = 1;
  8067. Promise.resolve(this).then((cnt) => {
  8068. __requestRemoval__(cnt);
  8069. cnt.detached();
  8070. if (cnt.__dataClientsReady === true) cnt.__dataClientsReady = false;
  8071. if (cnt.__dataEnabled === true) cnt.__dataEnabled = false;
  8072. if (cnt.__dataReady === true) cnt.__dataReady = false;
  8073. cnt.data = null;
  8074. cnt.countdownMs = 0;
  8075. cnt.lastCountdownTimeMs = null;
  8076. const hm = cnt.hostElement || cnt;
  8077. if (hm.parentNode) hm.remove();
  8078. for (let t; t = hm.firstChild;) t.remove();
  8079. }).catch(e => {
  8080. console.warn(e);
  8081. });
  8082. },
  8083.  
  8084.  
  8085. // doTimerFnModification
  8086.  
  8087.  
  8088. /** @type {(a, b)} */
  8089. startCountdownForTimerFnModA: function (a, b) { // .startCountdown(a.durationSec, a.fullDurationSec)
  8090. try {
  8091.  
  8092. const cnt = kRef(this);
  8093. if (!cnt) return;
  8094. if (!cnt.hostElement) return;
  8095.  
  8096. const attachementId = cnt.__ticker_attachmentId__;
  8097. if(!attachementId) return;
  8098.  
  8099. // a.durationSec [s] => countdownMs [ms]
  8100. // a.fullDurationSec [s] => countdownDurationMs [ms] OR countdownMs [ms]
  8101. // lastCountdownTimeMs => raf ongoing
  8102. // lastCountdownTimeMs = 0 when rafId = 0 OR countdownDurationMs = 0
  8103.  
  8104. if (cnt._r782) return;
  8105.  
  8106. if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  8107. cnt._throwOut();
  8108. return;
  8109. }
  8110.  
  8111. // TimerFnModA
  8112.  
  8113. b = void 0 === b ? 0 : b;
  8114. if (void 0 !== a) {
  8115.  
  8116. cnt.countdownMs = 1E3 * a; // decreasing from durationSec[s] to zero
  8117. cnt.countdownDurationMs = b ? 1E3 * b : cnt.countdownMs; // constant throughout the animation
  8118. if (!(cnt.lastCountdownTimeMs || cnt.isAnimationPaused)) {
  8119. cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = performance.now()
  8120. cnt.rafId = 1
  8121. if (cnt._runnerAE) console.warn('Error in .startCountdown; cnt._runnerAE already created.')
  8122. cnt.detlaSincePausedSecs = 0;
  8123. const ae = cnt._makeAnimator();
  8124. if (!ae) console.warn('Error in startCountdown._makeAnimator()');
  8125.  
  8126. // if (playerProgressChangedArg1 === null) {
  8127. // console.log('startCountdownForTimerFnModA', cnt.data)
  8128. // }
  8129.  
  8130. if (isPlayProgressTriggered && cnt.isAnimationPaused !== true && cnt.__ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED__) {
  8131.  
  8132.  
  8133.  
  8134.  
  8135. cnt.playerProgressSec = lastPlayerProgress > 0 ? lastPlayerProgress : 0; // save the progress first
  8136. cnt.isAnimationPaused = true; // trigger isAnimationPausedChanged
  8137. cnt.detlaSincePausedSecs = 0;
  8138. cnt._forceNoDetlaSincePausedSecs783 = 1; // reset cnt.detlaSincePausedSecs = 0 when resumed
  8139.  
  8140. relayPromise = relayPromise || new PromiseExternal();
  8141.  
  8142. relayPromise.then(() => {
  8143.  
  8144. const cnt = kRef(this);
  8145. if (!cnt) return;
  8146. if (!cnt.hostElement) return;
  8147.  
  8148. if (cnt && attachementId !== cnt.__ticker_attachmentId__) return;
  8149. if (cnt.isAttached === true && cnt.countdownDurationMs > 0 && cnt.isAnimationPaused === true && cnt.isReplayPaused !== true) {
  8150. cnt.isAnimationPaused = false;
  8151. }
  8152. });
  8153.  
  8154.  
  8155. }
  8156.  
  8157.  
  8158.  
  8159. }
  8160. }
  8161.  
  8162. } catch (e) {
  8163. console.warn(e);
  8164. }
  8165.  
  8166. },
  8167.  
  8168.  
  8169.  
  8170. /** @type {(a, b)} */
  8171. startCountdownForTimerFnModT: function (a, b) { // .startCountdown(a.durationSec, a.fullDurationSec)
  8172.  
  8173. try {
  8174. const cnt = kRef(this);
  8175. if (!cnt) return;
  8176. if (!cnt.hostElement) return;
  8177.  
  8178. const attachementId = cnt.__ticker_attachmentId__;
  8179. if(!attachementId) return;
  8180.  
  8181. // a.durationSec [s] => countdownMs [ms]
  8182. // a.fullDurationSec [s] => countdownDurationMs [ms] OR countdownMs [ms]
  8183. // lastCountdownTimeMs => raf ongoing
  8184. // lastCountdownTimeMs = 0 when rafId = 0 OR countdownDurationMs = 0
  8185.  
  8186. if (cnt._r782) return;
  8187.  
  8188. if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  8189. cnt._throwOut();
  8190. return;
  8191. }
  8192.  
  8193. // TimerFnModT
  8194.  
  8195. // console.log('cProto.startCountdown', tag) // yt-live-chat-ticker-sponsor-item-renderer
  8196. if (!cnt.boundUpdateTimeout37_) cnt.boundUpdateTimeout37_ = cnt.updateTimeout.bind(mWeakRef(cnt));
  8197. b = void 0 === b ? 0 : b;
  8198. void 0 !== a && (cnt.countdownMs = 1E3 * a,
  8199. cnt.countdownDurationMs = b ? 1E3 * b : cnt.countdownMs,
  8200. cnt.ratio = 1,
  8201. cnt.lastCountdownTimeMs || cnt.isAnimationPaused || (cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = performance.now(),
  8202. cnt.rafId = rafHub.request(cnt.boundUpdateTimeout37_)))
  8203.  
  8204. } catch (e) {
  8205. console.warn(e);
  8206. }
  8207.  
  8208. },
  8209.  
  8210.  
  8211. /** @type {(a,)} */
  8212. updateTimeoutForTimerFnModA: function (a) {
  8213.  
  8214. try {
  8215. const cnt = kRef(this);
  8216. if (!cnt) return;
  8217. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  8218.  
  8219. const attachementId = cnt.__ticker_attachmentId__;
  8220. if(!attachementId) return;
  8221.  
  8222. // _lastCountdownTimeMsX0 is required since performance.now() is not fully the same with rAF timestamp
  8223.  
  8224. if (cnt._r782) return;
  8225.  
  8226. if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  8227. cnt._throwOut();
  8228. return;
  8229. }
  8230.  
  8231. // TimerFnModA
  8232.  
  8233. if (!cnt._runnerAE) console.warn('Error in .updateTimeout; cnt._runnerAE is undefined');
  8234. if (cnt.lastCountdownTimeMs !== cnt._lastCountdownTimeMsX0) {
  8235. cnt.countdownMs = Math.max(0, cnt.countdownMs - (a - (cnt.lastCountdownTimeMs || 0)));
  8236. }
  8237. if (cnt.countdownMs > cnt.countdownDurationMs) cnt.countdownMs = cnt.countdownDurationMs;
  8238. if (cnt.isAttached && cnt.countdownMs) {
  8239. cnt.lastCountdownTimeMs = a
  8240. const ae = cnt._makeAnimator(); // request raf
  8241. if (!ae) console.warn('Error in startCountdown._makeAnimator()');
  8242. } else {
  8243. (cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = null,
  8244. cnt.isAttached && ("auto" === cnt.hostElement.style.width && cnt.setContainerWidth(),
  8245. cnt.slideDown()));
  8246. }
  8247.  
  8248. } catch (e) {
  8249. console.warn(e);
  8250. }
  8251.  
  8252.  
  8253. },
  8254.  
  8255. /** @type {(a,)} */
  8256. updateTimeoutForTimerFnModT: function (a) {
  8257.  
  8258. try {
  8259. const cnt = kRef(this);
  8260. if (!cnt) return;
  8261. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  8262.  
  8263. const attachementId = cnt.__ticker_attachmentId__;
  8264. if(!attachementId) return;
  8265.  
  8266. // _lastCountdownTimeMsX0 is required since performance.now() is not fully the same with rAF timestamp
  8267.  
  8268. if (cnt._r782) return;
  8269.  
  8270. if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  8271. cnt._throwOut();
  8272. return;
  8273. }
  8274.  
  8275. // TimerFnModT
  8276.  
  8277. // console.log('cProto.updateTimeout', tag) // yt-live-chat-ticker-sponsor-item-renderer
  8278. if (!cnt.boundUpdateTimeout37_) cnt.boundUpdateTimeout37_ = cnt.updateTimeout.bind(mWeakRef(cnt));
  8279. if (cnt.lastCountdownTimeMs !== cnt._lastCountdownTimeMsX0) {
  8280. cnt.countdownMs = Math.max(0, cnt.countdownMs - (a - (cnt.lastCountdownTimeMs || 0)));
  8281. }
  8282. // console.log(703, cnt.countdownMs)
  8283. cnt.ratio = cnt.countdownMs / cnt.countdownDurationMs;
  8284. cnt.isAttached && cnt.countdownMs ? (cnt.lastCountdownTimeMs = a,
  8285. cnt.rafId = rafHub.request(cnt.boundUpdateTimeout37_)) : (cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = null,
  8286. cnt.isAttached && ("auto" === cnt.hostElement.style.width && cnt.setContainerWidth(),
  8287. cnt.slideDown()))
  8288.  
  8289.  
  8290. } catch (e) {
  8291. console.warn(e);
  8292. }
  8293. },
  8294.  
  8295. /** @type {(a,b)} */
  8296. isAnimationPausedChangedForTimerFnModA: function (a, b) {
  8297.  
  8298. const cnt = kRef(this);
  8299. if (!cnt) return;
  8300. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  8301.  
  8302. const attachementId = cnt.__ticker_attachmentId__;
  8303. if(!attachementId) return;
  8304.  
  8305. if (cnt._r782) return;
  8306.  
  8307. if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  8308. cnt._throwOut();
  8309. return;
  8310. }
  8311. let forceNoDetlaSincePausedSecs783 = cnt._forceNoDetlaSincePausedSecs783;
  8312. cnt._forceNoDetlaSincePausedSecs783 = 0;
  8313.  
  8314. Promise.resolve(cnt).then((cnt) => {
  8315.  
  8316. if(attachementId !== cnt.__ticker_attachmentId__) return;
  8317.  
  8318. if (a) {
  8319.  
  8320. if (cnt._runnerAE && cnt._runnerAE.playState === 'running') {
  8321.  
  8322. cnt._runnerAE.pause()
  8323. let lc = window.performance.now();
  8324. cnt.countdownMs = Math.max(0, cnt.countdownMs - (lc - cnt.lastCountdownTimeMs));
  8325. if (cnt.countdownMs > cnt.countdownDurationMs) cnt.countdownMs = cnt.countdownDurationMs;
  8326. cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = lc;
  8327. }
  8328.  
  8329. } else if (!a && b) {
  8330.  
  8331.  
  8332. if (forceNoDetlaSincePausedSecs783) cnt.detlaSincePausedSecs = 0;
  8333. a = cnt.detlaSincePausedSecs ? (cnt.lastCountdownTimeMs || 0) + 1000 * cnt.detlaSincePausedSecs : (cnt.lastCountdownTimeMs || 0);
  8334. cnt.detlaSincePausedSecs = 0;
  8335. cnt.updateTimeout(a);
  8336. cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = window.performance.now();
  8337.  
  8338. }
  8339.  
  8340. cnt = null;
  8341.  
  8342.  
  8343. }).catch(e => {
  8344. console.log(e);
  8345. });
  8346.  
  8347.  
  8348.  
  8349. },
  8350.  
  8351.  
  8352. /** @type {(a,b)} */
  8353. isAnimationPausedChangedForTimerFnModT: function (a, b) {
  8354.  
  8355. const cnt = kRef(this);
  8356. if (!cnt) return;
  8357. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  8358.  
  8359. const attachementId = cnt.__ticker_attachmentId__;
  8360. if(!attachementId) return;
  8361.  
  8362. if (cnt._r782) return;
  8363.  
  8364. if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  8365. cnt._throwOut();
  8366. return;
  8367. }
  8368. // let forceNoDetlaSincePausedSecs783 = cnt._forceNoDetlaSincePausedSecs783;
  8369. // cnt._forceNoDetlaSincePausedSecs783 = 0;
  8370.  
  8371. Promise.resolve(cnt).then((cnt) => {
  8372.  
  8373. if(attachementId !== cnt.__ticker_attachmentId__) return;
  8374.  
  8375. // TimerFnModT
  8376.  
  8377. // ez++;
  8378. // if(ez> 1e9) ez=9;
  8379. if (!cnt.boundUpdateTimeout37_) cnt.boundUpdateTimeout37_ = cnt.updateTimeout.bind(mWeakRef(cnt));
  8380. a ? rafHub.cancel(cnt.rafId) : !a && b && (a = cnt.lastCountdownTimeMs || 0,
  8381. cnt.detlaSincePausedSecs && (a = (cnt.lastCountdownTimeMs || 0) + 1E3 * cnt.detlaSincePausedSecs,
  8382. cnt.detlaSincePausedSecs = 0),
  8383. cnt.boundUpdateTimeout37_(a),
  8384. cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = window.performance.now())
  8385.  
  8386. cnt = null;
  8387.  
  8388. }).catch(e => {
  8389. console.log(e);
  8390. });
  8391.  
  8392.  
  8393.  
  8394. },
  8395.  
  8396. setContainerWidthNoSelfLeakage: function(){
  8397. // prevent memory leakage due ot delay function
  8398. try{
  8399. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8400. return this.setContainerWidth55.call(this.__proxySelf0__);
  8401. }catch(e){
  8402. console.log('setContainerWidthNoSelfLeakage ERROR');
  8403. console.error(e);
  8404. }
  8405.  
  8406. },
  8407.  
  8408. slideDownNoSelfLeakage: function(){
  8409. // prevent memory leakage due ot delay function
  8410. try{
  8411. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8412. return this.slideDown55.call(this.__proxySelf0__);
  8413. }catch(e){
  8414. console.log('slideDownNoSelfLeakage ERROR');
  8415. console.error(e);
  8416. }
  8417. },
  8418.  
  8419. collapseNoSelfLeakage: function(){
  8420. // prevent memory leakage due ot delay function
  8421. try{
  8422. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8423. return this.collapse55.call(this.__proxySelf0__);
  8424. }catch(e){
  8425. console.log('collapseNoSelfLeakage ERROR');
  8426. console.error(e);
  8427. }
  8428. },
  8429.  
  8430. deletedChangedNoSelfLeakage: function(){
  8431. // prevent memory leakage due ot delay function
  8432. try{
  8433. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8434. return this.deletedChanged55.call(this.__proxySelf0__);
  8435. }catch(e){
  8436. console.log('deletedChangedNoSelfLeakage ERROR');
  8437. console.error(e);
  8438. }
  8439.  
  8440. },
  8441.  
  8442.  
  8443. /** @type {(a,b)} */
  8444. computeContainerStyleForAnimatorEnabled: function (a, b) {
  8445.  
  8446. if (this._r782) return;
  8447. const attachementId = this.__ticker_attachmentId__;
  8448. if(!attachementId) return;
  8449.  
  8450. if (this.isAttached === false && ((this.$ || 0).container || 0).isConnected === false) {
  8451. this._throwOut();
  8452. return;
  8453. }
  8454.  
  8455. return (dummyValueForStyleReturn || (dummyValueForStyleReturn = genDummyValueForStyleReturn()));
  8456.  
  8457. },
  8458.  
  8459.  
  8460.  
  8461. /** @type {()} */
  8462. handlePauseReplayForPlaybackProgressState: function () {
  8463. if (!playerEventsByIframeRelay) return this.handlePauseReplay66.apply(this, arguments);
  8464.  
  8465. const attachementId = this.__ticker_attachmentId__;
  8466. if(!attachementId) return;
  8467.  
  8468. const jr = mWeakRef(this);
  8469.  
  8470. if (onPlayStateChangePromise) {
  8471.  
  8472. if (this.rtu > 1e9) this.rtu = this.rtu % 1e4;
  8473. const tid = ++this.rtu;
  8474.  
  8475. onPlayStateChangePromise.then(() => {
  8476. const cnt = kRef(jr);
  8477. if(attachementId !== cnt.__ticker_attachmentId__) return;
  8478. if (cnt.isAttached) {
  8479. if (tid === cnt.rtu && !onPlayStateChangePromise && typeof cnt.handlePauseReplay === 'function' && cnt.hostElement) cnt.handlePauseReplay.apply(cnt, arguments);
  8480. // this.handlePauseReplay can be undefined if it is memory cleaned
  8481. }
  8482. });
  8483.  
  8484. return;
  8485. }
  8486.  
  8487. if (playerState !== 2) return;
  8488. if (this.isAttached) {
  8489. if (this.rtk > 1e9) this.rtk = this.rtk % 1e4;
  8490. const tid = ++this.rtk;
  8491. const tc = relayCount;
  8492. foregroundPromiseFn().then(() => {
  8493. const cnt = kRef(jr);
  8494. if (attachementId !== cnt.__ticker_attachmentId__) return;
  8495. if (cnt.isAttached) {
  8496. if (tid === cnt.rtk && tc === relayCount && playerState === 2 && _playerState === playerState && cnt.hostElement) {
  8497. cnt.handlePauseReplay66();
  8498. }
  8499. }
  8500.  
  8501. })
  8502. }
  8503. },
  8504.  
  8505. /** @type {()} */
  8506. handleResumeReplayForPlaybackProgressState: function () {
  8507. if (!playerEventsByIframeRelay) return this.handleResumeReplay66.apply(this, arguments);
  8508.  
  8509. const attachementId = this.__ticker_attachmentId__;
  8510. if(!attachementId) return;
  8511.  
  8512. const jr = mWeakRef(this);
  8513. if (onPlayStateChangePromise) {
  8514.  
  8515. if (this.rtv > 1e9) this.rtv = this.rtv % 1e4;
  8516. const tid = ++this.rtv;
  8517.  
  8518. onPlayStateChangePromise.then(() => {
  8519. const cnt = kRef(jr);
  8520. if(attachementId !== cnt.__ticker_attachmentId__) return;
  8521. if (tid === cnt.rtv && !onPlayStateChangePromise && typeof cnt.handleResumeReplay === 'function' && cnt.hostElement) cnt.handleResumeReplay.apply(cnt, arguments);
  8522. // this.handleResumeReplay can be undefined if it is memory cleaned
  8523. });
  8524.  
  8525. return;
  8526. }
  8527.  
  8528.  
  8529. if (playerState !== 1) return;
  8530. if (this.isAttached) {
  8531. const tc = relayCount;
  8532.  
  8533. relayPromise = relayPromise || new PromiseExternal();
  8534. relayPromise.then(() => {
  8535. const cnt = kRef(jr);
  8536. if(attachementId !== cnt.__ticker_attachmentId__) return;
  8537. if (relayCount > tc && playerState === 1 && _playerState === playerState && cnt.hostElement) {
  8538. cnt.handleResumeReplay66();
  8539. }
  8540. });
  8541. }
  8542. },
  8543.  
  8544. /** @type {(a,)} */
  8545. handleReplayProgressForPlaybackProgressState: function (a) {
  8546. if (this.isAttached) {
  8547. const attachementId = this.__ticker_attachmentId__;
  8548. if(!attachementId) return;
  8549. const tid = ++this.rtk;
  8550. const jr = mWeakRef(kRef(this));
  8551. foregroundPromiseFn().then(() => {
  8552. const cnt = kRef(jr);
  8553. if(attachementId !== cnt.__ticker_attachmentId__) return;
  8554. if (cnt.isAttached) {
  8555. if (tid === cnt.rtk && cnt.hostElement) {
  8556. cnt.handleReplayProgress66(a);
  8557. }
  8558. }
  8559. })
  8560. }
  8561. }
  8562.  
  8563.  
  8564. }
  8565.  
  8566.  
  8567. let tagI = 0;
  8568. for (const tag of tagsItemRenderer) { // ##tag##
  8569.  
  8570. tagI++;
  8571.  
  8572. const dummy = document.createElement(tag);
  8573.  
  8574. const cProto = getProto(dummy);
  8575. if (!cProto || !cProto.attached) {
  8576. console.warn(`proto.attached for ${tag} is unavailable.`);
  8577. continue;
  8578. }
  8579.  
  8580. if (FIX_MEMORY_LEAKAGE_TICKER_ACTIONMAP && typeof cProto.detached582MemoryLeak !== 'function' && typeof cProto.detached === 'function') {
  8581. cProto.detached582MemoryLeak = cProto.detached;
  8582. cProto.detached = dProto.detachedForMemoryLeakage;
  8583. }
  8584.  
  8585. cProto.detached77 = cProto.detached;
  8586. cProto.detached = dProto.detachedForTickerInit;
  8587.  
  8588. cProto.attached77 = cProto.attached;
  8589.  
  8590. cProto.attached = dProto.attachedForTickerInit;
  8591.  
  8592. if (FLAG_001c) continue;
  8593.  
  8594. let flgLeakageFixApplied = 0;
  8595.  
  8596. if (FIX_MEMORY_LEAKAGE_TICKER_STATSBAR && typeof cProto.updateStatsBarAndMaybeShowAnimation === 'function' && !cProto.updateStatsBarAndMaybeShowAnimation38 && cProto.updateStatsBarAndMaybeShowAnimation.length === 3) {
  8597.  
  8598. cProto.updateStatsBarAndMaybeShowAnimation38 = cProto.updateStatsBarAndMaybeShowAnimation;
  8599. cProto.updateStatsBarAndMaybeShowAnimation = dProto.updateStatsBarAndMaybeShowAnimationRevised;
  8600.  
  8601. flgLeakageFixApplied |= 2;
  8602. } else {
  8603. // the function is only in yt-live-chat-ticker-paid-message-item-renderer
  8604. }
  8605.  
  8606.  
  8607. // ------------- withTimerFn_ -------------
  8608.  
  8609. let withTimerFn_ = 0;
  8610. if (typeof cProto.startCountdown === 'function' && typeof cProto.updateTimeout === 'function' && typeof cProto.isAnimationPausedChanged === 'function') {
  8611.  
  8612. // console.log('startCountdown', typeof cProto.startCountdown)
  8613. // console.log('updateTimeout', typeof cProto.updateTimeout)
  8614. // console.log('isAnimationPausedChanged', typeof cProto.isAnimationPausedChanged)
  8615.  
  8616. // <<< to be reviewed cProto.updateTimeout --- isTimingFunctionHackable -- doHack >>>
  8617. const isTimingFunctionHackable = fnIntegrity(cProto.startCountdown, '2.66.37') && fnIntegrity(cProto.updateTimeout, '1.76.45') && fnIntegrity(cProto.isAnimationPausedChanged, '2.56.30')
  8618. if (!isTimingFunctionHackable) console.log('isTimingFunctionHackable = false');
  8619. withTimerFn_ = isTimingFunctionHackable ? 2 : 1;
  8620. } else {
  8621. let flag = 0;
  8622. if (typeof cProto.startCountdown === 'function') flag |= 1;
  8623. if (typeof cProto.updateTimeout === 'function') flag |= 2;
  8624. if (typeof cProto.isAnimationPausedChanged === 'function') flag |= 4;
  8625.  
  8626. console.log(`Skip Timing Function Modification: ${flag} / ${1 + 2 + 4}`, ` ${tag}`);
  8627. // console.log(Object.getOwnPropertyNames(cProto))
  8628. // continue;
  8629. }
  8630. // ------------- withTimerFn_ -------------
  8631.  
  8632. // ------------- ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX -------------
  8633.  
  8634. let urt = 0;
  8635.  
  8636. if (ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX) {
  8637.  
  8638.  
  8639. /**
  8640. *
  8641. f.handlePauseReplay = function() {
  8642. this.isAnimationPaused = !0;
  8643. this.detlaSincePausedSecs = 0
  8644. }
  8645. */
  8646.  
  8647. /**
  8648. *
  8649. f.handlePauseReplay = function() {
  8650. this.isReplayPaused = !0
  8651. }
  8652. *
  8653. */
  8654.  
  8655. if (typeof cProto.handlePauseReplay === 'function' && !cProto.handlePauseReplay66 && cProto.handlePauseReplay.length === 0) {
  8656. const fi = fnIntegrity(cProto.handlePauseReplay);
  8657. urt++;
  8658. if (fi === '0.8.2' || fi === '0.12.4') {
  8659. } else {
  8660. assertor(() => fnIntegrity(cProto.handlePauseReplay, '0.12.4'));
  8661. }
  8662. } else {
  8663. if (withTimerFn_ > 0) console.log('Error for setting cProto.handlePauseReplay', tag)
  8664. }
  8665.  
  8666. if (typeof cProto.handleResumeReplay === 'function' && !cProto.handleResumeReplay66 && cProto.handleResumeReplay.length === 0) {
  8667. urt++;
  8668. assertor(() => fnIntegrity(cProto.handleResumeReplay, '0.8.2'));
  8669. } else {
  8670. if (withTimerFn_ > 0) console.log('Error for setting cProto.handleResumeReplay', tag)
  8671. }
  8672.  
  8673. if (typeof cProto.handleReplayProgress === 'function' && !cProto.handleReplayProgress66 && cProto.handleReplayProgress.length === 1) {
  8674. urt++;
  8675. assertor(() => fnIntegrity(cProto.handleReplayProgress, '1.16.13'));
  8676. } else {
  8677. if (withTimerFn_ > 0) console.log('Error for setting cProto.handleReplayProgress', tag)
  8678. }
  8679.  
  8680.  
  8681.  
  8682. }
  8683.  
  8684. const ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED = ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX && urt === 3 && (SKIP_VIDEO_PLAYBACK_PROGRESS_STATE_FIX_FOR_NO_TIMEFX ? (withTimerFn_ > 0) : true);
  8685. cProto.__ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED__ = ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED;
  8686.  
  8687. if (ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED) {
  8688.  
  8689. cProto.rtk = 0;
  8690. cProto.rtu = 0;
  8691. cProto.rtv = 0;
  8692.  
  8693. cProto.handlePauseReplay66 = cProto.handlePauseReplay;
  8694. cProto.handlePauseReplay = dProto.handlePauseReplayForPlaybackProgressState;
  8695.  
  8696. cProto.handleResumeReplay66 = cProto.handleResumeReplay;
  8697. cProto.handleResumeReplay = dProto.handleResumeReplayForPlaybackProgressState;
  8698.  
  8699. cProto.handleReplayProgress66 = cProto.handleReplayProgress;
  8700. cProto.handleReplayProgress = dProto.handleReplayProgressForPlaybackProgressState;
  8701.  
  8702. }
  8703.  
  8704. // ------------- ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX -------------
  8705.  
  8706. // ------------- FIX_MEMORY_LEAKAGE_TICKER_TIMER -------------
  8707.  
  8708. if (FIX_MEMORY_LEAKAGE_TICKER_TIMER) {
  8709. if (!USE_ADVANCED_TICKING && typeof cProto.setContainerWidth === 'function' && !cProto.setContainerWidth55 && cProto.setContainerWidth.length === 0) {
  8710. cProto.setContainerWidth55 = cProto.setContainerWidth;
  8711. cProto.setContainerWidth = dProto.setContainerWidthNoSelfLeakage;
  8712. flgLeakageFixApplied |= 4;
  8713. }
  8714. if (!USE_ADVANCED_TICKING && typeof cProto.slideDown === 'function' && !cProto.slideDown55 && cProto.slideDown.length === 0) {
  8715. cProto.slideDown55 = cProto.slideDown;
  8716. cProto.slideDown = dProto.slideDownNoSelfLeakage;
  8717. flgLeakageFixApplied |= 8;
  8718. }
  8719. if (!USE_ADVANCED_TICKING && typeof cProto.collapse === 'function' && !cProto.collapse55 && cProto.collapse.length === 0) {
  8720. cProto.collapse55 = cProto.collapse;
  8721. cProto.collapse = dProto.collapseNoSelfLeakage;
  8722. flgLeakageFixApplied |= 16;
  8723. }
  8724. if (typeof cProto.deletedChanged === 'function' && !cProto.deletedChanged55 && cProto.deletedChanged.length === 0) {
  8725.  
  8726. cProto.deletedChanged55 = cProto.deletedChanged;
  8727. cProto.deletedChanged = dProto.deletedChangedNoSelfLeakage;
  8728. flgLeakageFixApplied |= 32;
  8729. }
  8730.  
  8731. }
  8732.  
  8733. console.log(`FIX_MEMORY_LEAKAGE_TICKER_: ${flgLeakageFixApplied} / ${1 + 2 + 4 + 8 + 16 + 32}`, cProto.is);
  8734.  
  8735. // ------------- FIX_MEMORY_LEAKAGE_TICKER_TIMER -------------
  8736.  
  8737.  
  8738.  
  8739.  
  8740. if (withTimerFn_ > 0) {
  8741.  
  8742. const isTimingFunctionHackable = withTimerFn_ & 2;
  8743.  
  8744. let doAnimator_ = false;
  8745.  
  8746. let rafHackState = 0;
  8747. // continue;
  8748. if (ENABLE_RAF_HACK_TICKERS && rafHub !== null) {
  8749.  
  8750. // cancelable - this.rafId < isAnimationPausedChanged >
  8751. rafHackState = 1;
  8752.  
  8753. if (isTimingFunctionHackable) {
  8754. rafHackState = 2;
  8755.  
  8756. } else {
  8757. rafHackState = 4;
  8758. }
  8759.  
  8760. }
  8761. // continue;
  8762.  
  8763. doAnimator_ = !USE_ADVANCED_TICKING && !!ATTEMPT_ANIMATED_TICKER_BACKGROUND && isTimingFunctionHackable && typeof KeyframeEffect === 'function' && typeof animate === 'function' && typeof cProto.computeContainerStyle === 'function' && typeof cProto.colorFromDecimal === 'function' && isCSSPropertySupported();
  8764.  
  8765.  
  8766. const doAnimator = doAnimator_;
  8767.  
  8768. cProto._throwOut = dProto._throwOut;
  8769.  
  8770. cProto._makeAnimator = doAnimator ? dProto._makeAnimator : null;
  8771.  
  8772. cProto._aeFinished = doAnimator ? dProto._aeFinished : null;
  8773.  
  8774.  
  8775. const doRAFHack = rafHackState === 2;
  8776.  
  8777.  
  8778. const doTimerFnModification = !USE_ADVANCED_TICKING && (doRAFHack || doAnimator);
  8779. // doTimerFnModification = false; // M55
  8780.  
  8781. if (doTimerFnModification) { // including memory fix leakage
  8782.  
  8783. if (doAnimator && windowShownAt < 0) {
  8784. windowShownAt = 0;
  8785. setupEventForWindowShownAt();
  8786. }
  8787.  
  8788. cProto.startCountdown = (
  8789. doAnimator ? dProto.startCountdownForTimerFnModA : dProto.startCountdownForTimerFnModT
  8790. );
  8791.  
  8792. // _lastCountdownTimeMsX0 is required since performance.now() is not fully the same with rAF timestamp
  8793. cProto.updateTimeout = (
  8794. doAnimator ? dProto.updateTimeoutForTimerFnModA : dProto.updateTimeoutForTimerFnModT
  8795. );
  8796.  
  8797.  
  8798. // let ez = 0;
  8799. cProto.isAnimationPausedChanged = (
  8800. doAnimator ? dProto.isAnimationPausedChangedForTimerFnModA : dProto.isAnimationPausedChangedForTimerFnModT
  8801. );
  8802.  
  8803. flgLeakageFixApplied |= 1;
  8804. }
  8805.  
  8806.  
  8807. if (doAnimator) {
  8808.  
  8809.  
  8810. const s = fnIntegrity(cProto.computeContainerStyle);
  8811.  
  8812. if (s === '2.46.29') {
  8813. // f.computeContainerStyle = function(a, b) {
  8814. // if (!a)
  8815. // return $h(kmb);
  8816. // var c = this.colorFromDecimal(a.startBackgroundColor);
  8817. // a = this.colorFromDecimal(a.endBackgroundColor);
  8818. // b = 100 * b + "%";
  8819. // return $h(lmb, c, c, b, a, b, a)
  8820. // }
  8821. } else if (s === '2.44.29' || s === '2.81.31') {
  8822.  
  8823. // var ofb = da([""])
  8824. // pfb = da("background:linear-gradient(90deg, {,{ {,{ {,{);".split("{"))
  8825.  
  8826. // f.computeContainerStyle = function(a, b) {
  8827. // if (!a)
  8828. // return pi(ofb);
  8829. // var c = this.colorFromDecimal(a.startBackgroundColor);
  8830. // a = this.colorFromDecimal(a.endBackgroundColor);
  8831. // b = 100 * b + "%";
  8832. // return pi(pfb, c, c, b, a, b, a)
  8833. // }
  8834.  
  8835. } else {
  8836. assertor(() => fnIntegrity(cProto.computeContainerStyle, '2.46.29'));
  8837. }
  8838.  
  8839. cProto.computeContainerStyle66 = cProto.computeContainerStyle;
  8840.  
  8841. cProto.computeContainerStyle = dProto.computeContainerStyleForAnimatorEnabled;
  8842.  
  8843. }
  8844.  
  8845. if (doTimerFnModification === true) hasTimerModified = true;
  8846.  
  8847.  
  8848. if (!!ATTEMPT_ANIMATED_TICKER_BACKGROUND) {
  8849. console.log('ATTEMPT_ANIMATED_TICKER_BACKGROUND', tag, doAnimator ? 'OK' : 'NG');
  8850. }
  8851.  
  8852.  
  8853. if (!doAnimator && (rafHackState === 2 || rafHackState === 4)) {
  8854. console.log('RAF_HACK_TICKERS', tag, doRAFHack ? "OK" : "NG");
  8855. }
  8856. }
  8857.  
  8858. const canDoAdvancedTicking = 1 &&
  8859. ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION &&
  8860. typeof cProto.startCountdown === 'function' && !cProto.startCountdown49 && cProto.startCountdown.length === 2 &&
  8861. typeof cProto.updateTimeout === 'function' && !cProto.updateTimeout49 && cProto.updateTimeout.length === 1 &&
  8862. typeof cProto.isAnimationPausedChanged === 'function' && !cProto.isAnimationPausedChanged49 && cProto.isAnimationPausedChanged.length === 2 &&
  8863. typeof cProto.setContainerWidth === 'function' && cProto.setContainerWidth.length === 0 &&
  8864. typeof cProto.requestRemoval === 'function' && !cProto.requestRemoval49 && cProto.requestRemoval.length === 0
  8865. CSS.supports("left","clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%)");
  8866.  
  8867.  
  8868. if (USE_ADVANCED_TICKING && canDoAdvancedTicking) {
  8869. // startResistanceUpdater();
  8870. // live replay video -> 48117005 -> 48117006 keep fire. ->48117007 0 -> 48117007 {...}
  8871. // live stream video -> 48117007 0 -> 48117007 YES
  8872.  
  8873. document.documentElement.setAttribute('r6-advanced-ticking', '');
  8874. console.log(`USE_ADVANCED_TICKING[#${tagI}]::START`)
  8875.  
  8876. const wio2 = dProto.wio2 || (dProto.wio2 = new IntersectionObserver((mutations) => {
  8877.  
  8878. for (const mutation of mutations) {
  8879. if (mutation.isIntersecting) {
  8880.  
  8881. const marker = mutation.target;
  8882. let endId = marker.id
  8883. if (!endId) continue;
  8884. let tid = endId.substring(0, endId.length - 2);
  8885. if (!tid) continue;
  8886. // let bId = `${tid}-b`;
  8887. const bgElm = document.querySelector(`#${tid}-b`);
  8888. if (!bgElm) continue;
  8889. const overlay = bgElm;
  8890.  
  8891. wio2.unobserve(marker);
  8892. marker.remove();
  8893. let p = overlay || 0;
  8894. let cn = 4;
  8895. while ((p = p.parentElement) instanceof HTMLElement) {
  8896. if (p instanceof HTMLElement) {
  8897. const cnt = insp(p);
  8898. if (cnt && typeof cnt.slideDown === 'function' && typeof cnt.setContainerWidth === 'function' && cnt.__advancedTicking038__ === 1) {
  8899.  
  8900. cnt.__advancedTicking038__ = 2;
  8901.  
  8902. let deletionMode = false;
  8903. const cntData = ((cnt || 0).__data || 0).data || (cnt || 0).data || 0;
  8904. if (timestampUnderLiveMode && cntData && cntData.durationSec > 0 && cntData.__timestampActionRequest__ > 0) {
  8905.  
  8906. // time choose - 0.2s for transition (slideDown sliding-down)
  8907. // 60hz = 17ms
  8908. // choose 0.28s
  8909. const targetFutureTime = cntData.__timestampActionRequest__ + cntData.durationSec * 1000;
  8910. // check whether the targetFutureTime is already the past
  8911. if (targetFutureTime + 280 < Date.now()) {
  8912. // just dispose
  8913. deletionMode = true;
  8914. }
  8915. } else if (__LCRInjection__ && !timestampUnderLiveMode && cntData && cntData.durationSec > 0 && cntData.__progressAt__ > 0) {
  8916.  
  8917. const targetFutureTime = (cntData.__progressAt__ + cntData.durationSec);
  8918. // check whether the targetFutureTime is already the past
  8919. if (targetFutureTime + 0.28 < playerProgressChangedArg1) {
  8920. // just dispose
  8921. deletionMode = true;
  8922. }
  8923.  
  8924.  
  8925. }
  8926.  
  8927.  
  8928. if (deletionMode) {
  8929. __requestRemoval__(cnt);
  8930. } else {
  8931.  
  8932. const w = cnt.hostElement.style.width;
  8933. if (w === "auto" || w === "") cnt.setContainerWidth();
  8934. cnt.slideDown();
  8935. }
  8936.  
  8937. break;
  8938. }
  8939. }
  8940. cn--;
  8941. if (!cn) {
  8942. console.log('cnt not found for ticker-bg-overlay');
  8943. break;
  8944. }
  8945. }
  8946.  
  8947.  
  8948. }
  8949. }
  8950.  
  8951. // console.log(mutations);
  8952. }, {
  8953.  
  8954. rootMargin: '0px',
  8955. threshold: [1]
  8956.  
  8957. }));
  8958.  
  8959. // const wio = dProto.wio || (dProto.wio = new IntersectionObserver((mutations) => {
  8960.  
  8961. // // for (const mutation of mutations) {
  8962. // // if (mutation.isIntersecting) {
  8963. // // const marker = mutation.target;
  8964. // // const overlay = marker instanceof HTMLElement ? marker.closest('ticker-bg-overlay') : 0;
  8965. // // wio.unobserve(marker);
  8966. // // marker.remove();
  8967. // // let p = overlay || 0;
  8968. // // let cn = 4;
  8969. // // while ((p = p.parentElement) instanceof HTMLElement) {
  8970. // // if (p instanceof HTMLElement) {
  8971. // // const cnt = insp(p);
  8972. // // if (cnt && typeof cnt.slideDown === 'function' && typeof cnt.setContainerWidth === 'function' && cnt.__advancedTicking038__ === 1 ) {
  8973.  
  8974. // // cnt.__advancedTicking038__ = 2;
  8975.  
  8976. // // let deletionMode = false;
  8977. // // const cntData = ((cnt || 0).__data || 0).data || (cnt || 0).data || 0;
  8978. // // if (timestampUnderLiveMode && cntData && cntData.duration > 0 && cntData.__timestampActionRequest__ > 0) {
  8979.  
  8980. // // const targetFutureTime = cntData.__timestampActionRequest__ + cntData.durationSec * 1000;
  8981. // // // check whether the targetFutureTime is already the past
  8982. // // if (targetFutureTime + 800 < Date.now()) {
  8983. // // // just dispose
  8984. // // deletionMode = true;
  8985. // // }
  8986. // // }
  8987.  
  8988.  
  8989. // // if (deletionMode) {
  8990. // // __requestRemoval__(cnt);
  8991. // // } else {
  8992.  
  8993. // // ("auto" === cnt.hostElement.style.width && cnt.setContainerWidth(),
  8994. // // cnt.slideDown());
  8995. // // }
  8996.  
  8997. // // break;
  8998. // // }
  8999. // // }
  9000. // // cn--;
  9001. // // if (!cn) {
  9002. // // console.log('cnt not found for ticker-bg-overlay');
  9003. // // break;
  9004. // // }
  9005. // // }
  9006. // // }
  9007. // // }
  9008. // }, {
  9009. // rootMargin: '1px',
  9010. // threshold: [0]
  9011. // }));
  9012.  
  9013. // cProto._throwOut = dProto._throwOut;
  9014.  
  9015.  
  9016. const u37fn = dProto.u37fn || (dProto.u37fn = function (cnt) {
  9017.  
  9018. if (!__LCRInjection__) {
  9019. console.error('[yt-chat] USE_ADVANCED_TICKING fails because of no __LCRInjection__');
  9020. }
  9021.  
  9022. const cntData = ((cnt || 0).__data || 0).data || (cnt || 0).data || 0;
  9023. if (!cntData) return;
  9024. const cntElement = cnt.hostElement;
  9025. if (!(cntElement instanceof HTMLElement)) return;
  9026.  
  9027. const duration = (cntData.fullDurationSec || cntData.durationSec || 0);
  9028.  
  9029. let ct;
  9030.  
  9031. if (__LCRInjection__ && cntData && duration > 0 && !('__progressAt__' in cntData)) {
  9032. ct = Date.now();
  9033. cntData.__liveTimestamp__ = (cntData.__timestampActionRequest__ || ct) / 1000 - timeOriginDT / 1000;
  9034. timestampUnderLiveMode = true;
  9035. } else if (__LCRInjection__ && cntData && duration > 0 && cntData.__progressAt__ > 0) {
  9036. timestampUnderLiveMode = false;
  9037. }
  9038. // console.log(48117007, cntData)
  9039.  
  9040. let tk = cntData.__progressAt__ || cntData.__liveTimestamp__;
  9041.  
  9042. if (!tk) {
  9043. console.log('time property is not found');
  9044. return;
  9045. }
  9046.  
  9047.  
  9048.  
  9049. const liveOffsetMs = ct > 0 && cntData.__timestampActionRequest__ > 0 ? ct - cntData.__timestampActionRequest__ : 0;
  9050.  
  9051. // console.log(1237, liveOffsetMs, cntData.durationSec)
  9052.  
  9053. if (liveOffsetMs > 0) {
  9054. cntData.durationSec -= Math.floor(liveOffsetMs / 1000);
  9055. if (cntData.durationSec < 0) cntData.durationSec = 0;
  9056. // console.log(1238, liveOffsetMs, cntData.durationSec)
  9057. if (!cntData.durationSec) {
  9058. try {
  9059. cnt.requestRemoval();
  9060. } catch (e) { }
  9061. return;
  9062. }
  9063. }
  9064.  
  9065.  
  9066. let offset = cntData.fullDurationSec - cntData.durationSec; // consider this is live replay video, offset can be > 0
  9067. if (offset > 0) tk -= offset;
  9068. // in livestreaming. tk can be negative as we use performance.timeOrigin for t=0s time frame
  9069.  
  9070.  
  9071.  
  9072. const existingOverlaySelector = `ticker-bg-overlay[ticker-id="${cnt.__ticker_attachmentId__}"]`;
  9073.  
  9074. if (valAssign(cntElement, '--ticker-start-time', tk) && duration > 0) {
  9075.  
  9076. // t0 ...... 1 ... fullDurationSec
  9077. // tk ...... k ... fullDurationSec-durationSec
  9078. // t0-fullDurationSec ...... 0 ... 0
  9079.  
  9080. // now - (fullDurationSec-durationSec)
  9081.  
  9082.  
  9083. // update dntElementWeak
  9084. const dnt = cnt.parentComponent;
  9085. const dntElement = dnt ? dnt.hostElement || dnt : 0;
  9086. if (dntElement) {
  9087. dntElementWeak = mWeakRef(dntElement);
  9088. resistanceUpdateBusy = false;
  9089. if (!startResistanceUpdaterStarted) startResistanceUpdater();
  9090. else updateTickerCurrentTime();
  9091. }
  9092.  
  9093. // create overlay if needed
  9094. if (!cntElement.querySelector(existingOverlaySelector)) {
  9095.  
  9096. // remove if any
  9097. const oldElement = cntElement.querySelector('ticker-bg-overlay');
  9098. if (oldElement) oldElement.remove();
  9099.  
  9100. // use advancedTicking, ticker enabled
  9101. cnt.__advancedTicking038__ = 1;
  9102.  
  9103. const em = document.createElement('ticker-bg-overlay');
  9104. // const ey = document.createElement('ticker-bg-overlay-end');
  9105. const wy = document.createElement('ticker-bg-overlay-end2');
  9106.  
  9107. const cr1 = cnt.colorFromDecimal(cntData.startBackgroundColor);
  9108. const cr2 = cnt.colorFromDecimal(cntData.endBackgroundColor);
  9109.  
  9110. const container = cnt.$.container;
  9111.  
  9112. em.setAttribute('ticker-id', `${cnt.__ticker_attachmentId__}`);
  9113.  
  9114. const tid = `ticker-${cnt.__ticker_attachmentId__}-${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
  9115.  
  9116. em.id = `${tid}-b`;
  9117. em.style.background = `linear-gradient(90deg, ${cr1},${cr1} 50%,${cr2} 50%,${cr2})`;
  9118.  
  9119. if (!(container instanceof HTMLElement)) {
  9120. // em.insertBefore(ey, em.firstChild);
  9121. cntElement.insertBefore(em, cntElement.firstChild);
  9122. cntElement.style.borderRadius = '16px';
  9123. container.style.borderRadius = 'initial';
  9124. } else {
  9125. // em.insertBefore(ey, em.firstChild);
  9126. container.insertBefore(em, container.firstChild);
  9127. }
  9128.  
  9129. // em.style.left = '-50%';
  9130. // em.style.left = "clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%)";
  9131.  
  9132. if (container instanceof HTMLElement) {
  9133.  
  9134. container.style.background = 'transparent';
  9135. container.style.backgroundColor = 'transparent';
  9136. // container.style.zIndex = '1';
  9137. }
  9138. // em.style.zIndex = '-1';
  9139. valAssign(cntElement, '--ticker-duration-time', duration)
  9140.  
  9141. valAssign(wy, '--ticker-start-time', tk);
  9142. valAssign(wy, '--ticker-duration-time', duration);
  9143. wy.id = `${tid}-e`;
  9144.  
  9145. dntElement.appendChild(wy);
  9146.  
  9147. // if (wio instanceof IntersectionObserver) {
  9148. // wio.observe(ey);
  9149. // }
  9150.  
  9151. if (wio2 instanceof IntersectionObserver) {
  9152. wio2.observe(wy);
  9153. }
  9154.  
  9155. }
  9156. }
  9157. });
  9158.  
  9159. const timeFn = (cnt) => {
  9160.  
  9161. if (!cnt) return;
  9162. if (!cnt.hostElement) return;
  9163.  
  9164. const attachementId = cnt.__ticker_attachmentId__;
  9165. if (!attachementId) return;
  9166.  
  9167. Promise.resolve(cnt).then(u37fn);
  9168.  
  9169. }
  9170.  
  9171. cProto.startCountdown = dProto.startCountdownAdv || (dProto.startCountdownAdv = function (a, b) {
  9172.  
  9173. timeFn(kRef(this));
  9174.  
  9175. // try {
  9176. // const cnt = kRef(this);
  9177. // if (!cnt) return;
  9178. // if (!cnt.hostElement) return;
  9179.  
  9180. // const attachementId = cnt.__ticker_attachmentId__;
  9181. // if (!attachementId) return;
  9182.  
  9183. // // a.durationSec [s] => countdownMs [ms]
  9184. // // a.fullDurationSec [s] => countdownDurationMs [ms] OR countdownMs [ms]
  9185. // // lastCountdownTimeMs => raf ongoing
  9186. // // lastCountdownTimeMs = 0 when rafId = 0 OR countdownDurationMs = 0
  9187.  
  9188. // // if (cnt._r782) return;
  9189.  
  9190. // // if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  9191. // // cnt._throwOut();
  9192. // // return;
  9193. // // }
  9194.  
  9195. // // TimerFnModT
  9196.  
  9197. // // b = void 0 === b ? 0 : b;
  9198. // // void 0 !== a && (cnt.countdownMs = 1E3 * a,
  9199. // // cnt.countdownDurationMs = b ? 1E3 * b : cnt.countdownMs,
  9200. // // // cnt.ratio = 1,
  9201. // // cnt.lastCountdownTimeMs || cnt.isAnimationPaused || (cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = performance.now(),
  9202. // // cnt.rafId = -1))
  9203.  
  9204. // Promise.resolve(cnt).then((cnt) => {
  9205. // u37fn(cnt);
  9206. // })
  9207.  
  9208. // } catch (e) {
  9209. // console.warn(e);
  9210. // }
  9211.  
  9212.  
  9213. });
  9214.  
  9215. cProto.updateTimeout = dProto.updateTimeoutAdv || (dProto.updateTimeoutAdv = function (a) {
  9216.  
  9217.  
  9218. // timeFn(kRef(this));
  9219.  
  9220. // try {
  9221. // const cnt = kRef(this);
  9222. // if (!cnt) return;
  9223. // if (!cnt.hostElement) return; // memory leakage. to be reviewed
  9224.  
  9225. // const attachementId = cnt.__ticker_attachmentId__;
  9226. // if (!attachementId) return;
  9227.  
  9228. // // _lastCountdownTimeMsX0 is required since performance.now() is not fully the same with rAF timestamp
  9229.  
  9230. // // if (cnt._r782) return;
  9231.  
  9232. // // if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  9233. // // cnt._throwOut();
  9234. // // return;
  9235. // // }
  9236.  
  9237. // // if (cnt.lastCountdownTimeMs !== cnt._lastCountdownTimeMsX0) {
  9238. // // cnt.countdownMs = Math.max(0, cnt.countdownMs - (a - (cnt.lastCountdownTimeMs || 0)));
  9239. // // }
  9240. // // console.log(703, cnt.countdownMs)
  9241. // // cnt.ratio = cnt.countdownMs / cnt.countdownDurationMs;
  9242.  
  9243. // // u37fn(cnt);
  9244. // // cnt.isAttached && cnt.countdownMs ? (cnt.lastCountdownTimeMs = a,
  9245. // // cnt.rafId = -1) : (cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = null,
  9246. // // cnt.isAttached && ("auto" === cnt.hostElement.style.width && cnt.setContainerWidth(),
  9247. // // cnt.slideDown()))
  9248.  
  9249.  
  9250. // } catch (e) {
  9251. // console.warn(e);
  9252. // }
  9253.  
  9254. });
  9255.  
  9256. cProto.isAnimationPausedChanged = dProto.isAnimationPausedChangedAdv || (dProto.isAnimationPausedChangedAdv = function (a, b) {
  9257.  
  9258.  
  9259. // timeFn(kRef(this));
  9260.  
  9261. // const cnt = kRef(this);
  9262. // if (!cnt) return;
  9263. // if (!cnt.hostElement) return; // memory leakage. to be reviewed
  9264.  
  9265. // const attachementId = cnt.__ticker_attachmentId__;
  9266. // if (!attachementId) return;
  9267.  
  9268. // if (cnt._r782) return;
  9269.  
  9270. // if (cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false) {
  9271. // cnt._throwOut();
  9272. // return;
  9273. // }
  9274. // let forceNoDetlaSincePausedSecs783 = cnt._forceNoDetlaSincePausedSecs783;
  9275. // cnt._forceNoDetlaSincePausedSecs783 = 0;
  9276.  
  9277. // u37fn(cnt);
  9278. // Promise.resolve(cnt).then((cnt) => {
  9279.  
  9280. // if (attachementId !== cnt.__ticker_attachmentId__) return;
  9281.  
  9282. // // a ? 0 : !a && b && (a = cnt.lastCountdownTimeMs || 0,
  9283. // // cnt.detlaSincePausedSecs && (a = (cnt.lastCountdownTimeMs || 0) + 1E3 * cnt.detlaSincePausedSecs,
  9284. // // cnt.detlaSincePausedSecs = 0),
  9285. // // cnt.lastCountdownTimeMs = cnt._lastCountdownTimeMsX0 = window.performance.now())
  9286.  
  9287. // cnt = null;
  9288.  
  9289. // }).catch(e => {
  9290. // console.log(e);
  9291. // });
  9292.  
  9293.  
  9294. });
  9295.  
  9296.  
  9297. if (typeof cProto.slideDown === 'function' && !cProto.slideDown43 && cProto.slideDown.length === 0) {
  9298.  
  9299. cProto.slideDown43 = cProto.slideDown;
  9300. cProto.slideDown = dProto.slideDownAdv || (dProto.slideDownAdv = async function () {
  9301.  
  9302. // console.log('calling slideDown', Date.now())
  9303. if (this.__advancedTicking038__) {
  9304.  
  9305. if (this.__advancedTicking038__ === 1) this.__advancedTicking038__ = 2; // ignore intersectionobserver detection
  9306.  
  9307.  
  9308. const hostElement = this.hostElement;
  9309. const container = this.$.container;
  9310. if (hostElement instanceof HTMLElement && container instanceof HTMLElement) {
  9311. // const prevTransitionClosingElm = kRef(prevTransitionClosing);
  9312. // if (prevTransitionClosingElm !== hostElement) {
  9313. // prevTransitionClosingElm && prevTransitionClosingElm.classList.add('ticker-no-transition-time');
  9314. // prevTransitionClosing = mWeakRef(hostElement);
  9315. // }
  9316. // if (hostElement.classList.contains('ticker-no-transition-time')) hostElement.classList.remove('ticker-no-transition-time');
  9317. hostElement.classList.add('r6-closing-ticker');
  9318.  
  9319. const pr = new PromiseExternal();
  9320. transitionEndAfterFnSimple.set(hostElement, pr);
  9321. transitionEndAfterFnSimple.set(container, pr);
  9322. hostElement.classList.add("sliding-down");
  9323. await pr.then();
  9324. transitionEndAfterFnSimple.delete(hostElement);
  9325. transitionEndAfterFnSimple.delete(container);
  9326. if (this && this.hostElement instanceof HTMLElement) {
  9327.  
  9328. this.collapse();
  9329. }
  9330. return;
  9331. }
  9332. }
  9333. this.slideDown43();
  9334.  
  9335. });
  9336.  
  9337.  
  9338. console.log(`USE_ADVANCED_TICKING[#${tagI}]::slideDown - OK`)
  9339. } else {
  9340.  
  9341. console.log(`USE_ADVANCED_TICKING[#${tagI}]::slideDown - NG`)
  9342. }
  9343.  
  9344.  
  9345. if (typeof cProto.collapse === 'function' && !cProto.collapse43 && cProto.collapse.length === 0) {
  9346. cProto.collapse43 = cProto.collapse;
  9347. cProto.collapse = dProto.collapseAdv || (dProto.collapseAdv = async function () {
  9348.  
  9349.  
  9350. if (this.__advancedTicking038__) {
  9351.  
  9352.  
  9353. if (this.__advancedTicking038__ === 1) this.__advancedTicking038__ = 2; // ignore intersectionobserver detection
  9354.  
  9355.  
  9356. const hostElement = this.hostElement;
  9357. const container = this.$.container;
  9358. if (hostElement instanceof HTMLElement && container instanceof HTMLElement) {
  9359. // const prevTransitionClosingElm = kRef(prevTransitionClosing);
  9360. // if (prevTransitionClosingElm !== hostElement) {
  9361. // prevTransitionClosingElm && prevTransitionClosingElm.classList.add('ticker-no-transition-time');
  9362. // prevTransitionClosing = mWeakRef(hostElement);
  9363. // }
  9364. // if (hostElement.classList.contains('ticker-no-transition-time')) hostElement.classList.remove('ticker-no-transition-time');
  9365. hostElement.classList.add('r6-closing-ticker');
  9366.  
  9367. const pr = new PromiseExternal();
  9368. transitionEndAfterFnSimple.set(hostElement, pr);
  9369. transitionEndAfterFnSimple.set(container, pr);
  9370. hostElement.classList.add("collapsing");
  9371. hostElement.style.width = "0";
  9372. await pr.then();
  9373. transitionEndAfterFnSimple.delete(hostElement);
  9374. transitionEndAfterFnSimple.delete(container);
  9375. if (this && this.hostElement instanceof HTMLElement) {
  9376.  
  9377. this.requestRemoval();
  9378. }
  9379.  
  9380. return;
  9381. }
  9382.  
  9383.  
  9384. }
  9385. this.collapse43();
  9386.  
  9387.  
  9388. });
  9389.  
  9390. console.log(`USE_ADVANCED_TICKING[#${tagI}]::collapse - OK`)
  9391. } else {
  9392.  
  9393. console.log(`USE_ADVANCED_TICKING[#${tagI}]::collapse - NG`)
  9394. }
  9395.  
  9396.  
  9397.  
  9398. if (typeof cProto.requestRemoval === 'function' && !cProto.requestRemoval49 && cProto.requestRemoval.length === 0) {
  9399. cProto.requestRemoval49 = cProto.requestRemoval;
  9400. cProto.requestRemoval = dProto.requestRemovalAdv || (dProto.requestRemovalAdv = function () {
  9401. if (this.__advancedTicking038__) {
  9402. try {
  9403. const overlayBg = this.hostElement.querySelector('ticker-bg-overlay[id]');
  9404. if (overlayBg) {
  9405. const overlayBgId = overlayBg.id;
  9406. const tid = overlayBgId ? overlayBgId.substring(0, overlayBgId.length - 2) : '';
  9407. const endElm = tid ? document.querySelector(`#${tid}-e`) : null;
  9408. if (endElm) {
  9409. wio2.unobserve(endElm);
  9410. endElm.remove();
  9411. }
  9412. }
  9413. } catch (e) { }
  9414. this.__advancedTicking038__ = 2;
  9415. // console.log('requestRemoval!!')
  9416. if (REUSE_TICKER) {
  9417. const hostElement = this.hostElement;
  9418. const cntData = this.data;
  9419. if (hostElement instanceof HTMLElement && cntData.id && cntData.fullDurationSec && !hostElement.hasAttribute('__reuseid__')) {
  9420. hostElement.setAttribute('__reuseid__', reuseId);
  9421. hostElement.setAttribute('__nogc__', ''); // provided to leakage detection script
  9422. // this.__markReuse13__ = true;
  9423. reuseStore.set(`<${this.is}>${cntData.id}:${cntData.fullDurationSec}`, mWeakRef(this));
  9424. }
  9425. }
  9426. }
  9427. const hostElement = this.hostElement;
  9428. if (hostElement instanceof HTMLElement) {
  9429. // try {
  9430. // // hostElement.remove();
  9431.  
  9432. // if (!hostElement.classList.contains('ticker-no-transition-time')) hostElement.classList.add('ticker-no-transition-time');
  9433. // } catch (e) { }
  9434.  
  9435. try {
  9436.  
  9437. hostElement.classList.remove('r6-closing-ticker');
  9438. } catch (e) { }
  9439.  
  9440. // if(ADVANCED_TICKING_MEMORY_CLEAN_FOR_REMOVAL){
  9441. // const wr = mWeakRef(hostElement);
  9442. // const wf = ()=>{
  9443. // const element = kRef(wr);
  9444. // if(!element) {
  9445. // console.log('[yt-chat-removalrequest] element was memory cleaned.');
  9446. // return;
  9447. // }
  9448.  
  9449. // setTimeout(wf, 8000);
  9450. // if(element.isConnected){
  9451. // console.log('[yt-chat-removalrequest] element is still connected to DOM Tree.');
  9452. // return;
  9453. // }
  9454.  
  9455. // const cnt = insp(element)
  9456. // if(typeof cnt.requestRemoval !== 'function'){
  9457. // console.log('[yt-chat-removalrequest] element is not connected to cnt.');
  9458. // return;
  9459. // }
  9460. // console.log('[yt-chat-removalrequest] element is not GC.');
  9461. // try{
  9462. // cnt.data = null;
  9463. // }catch(e){}
  9464. // Object.setPrototypeOf(cnt, Object.prototype);
  9465. // for(const k of Object.getOwnPropertyNames(cnt)){
  9466. // try{
  9467. // cnt[k] = null;
  9468. // }catch(e){}
  9469.  
  9470. // try{
  9471. // delete cnt[k];
  9472. // }catch(e){}
  9473. // }
  9474.  
  9475.  
  9476. // for(const k of Object.getOwnPropertySymbols(cnt)){
  9477. // try{
  9478. // cnt[k] = null;
  9479. // }catch(e){}
  9480.  
  9481. // try{
  9482. // delete cnt[k];
  9483. // }catch(e){}
  9484. // }
  9485.  
  9486. // }
  9487. // setTimeout(wf, 8000);
  9488. // }
  9489.  
  9490. return this.requestRemoval49();
  9491. }
  9492. });
  9493.  
  9494.  
  9495. console.log(`USE_ADVANCED_TICKING[#${tagI}]::requestRemoval - OK`)
  9496. } else {
  9497.  
  9498. console.log(`USE_ADVANCED_TICKING[#${tagI}]::requestRemoval - NG`)
  9499. }
  9500.  
  9501.  
  9502. if (typeof cProto.computeContainerStyle === 'function' && !cProto.computeContainerStyle49 && cProto.computeContainerStyle.length === 2) {
  9503. cProto.computeContainerStyle49 = cProto.computeContainerStyle;
  9504. cProto.computeContainerStyle = dProto.computeContainerStyleAdv || (dProto.computeContainerStyleAdv = function (a, b) {
  9505. if (this.__advancedTicking038__) {
  9506. return "";
  9507. }
  9508. return this.computeContainerStyle49(a, b);
  9509. });
  9510.  
  9511.  
  9512. console.log(`USE_ADVANCED_TICKING[#${tagI}]::computeContainerStyle - OK`)
  9513. } else {
  9514.  
  9515. console.log(`USE_ADVANCED_TICKING[#${tagI}]::computeContainerStyle - NG`)
  9516. }
  9517.  
  9518.  
  9519.  
  9520. if (typeof cProto.setRevampContainerWidth === 'function' && !cProto.setRevampContainerWidth41 && cProto.setRevampContainerWidth.length === 0) {
  9521. cProto.setRevampContainerWidth41 = cProto.setRevampContainerWidth;
  9522. cProto.setRevampContainerWidth = dProto.setRevampContainerWidthAdv || (dProto.setRevampContainerWidthAdv = async function () {
  9523.  
  9524. // not sure the reason for auto instead of pixel.
  9525. // this is a new function in Dec 2024, but not mainly adopted in the coding yet
  9526.  
  9527. /*
  9528. var a = this;
  9529. (R(this.hostElement).querySelector("#container").clientWidth || 0) === 0 ? (this.hostElement.style.overflow = "visible",
  9530. this.hostElement.style.width = "auto") : (this.hostElement.style.overflow = "hidden",
  9531. this.ytLiveChatTickerItemBehavior.shouldAnimateIn ? (this.hostElement.style.width = "0",
  9532. Zu(function() {
  9533. a.hostElement.style.width = "auto"
  9534. }, 1)) : this.hostElement.style.width = "auto")
  9535. */
  9536.  
  9537.  
  9538.  
  9539.  
  9540. const hostElement = (this || 0).hostElement;
  9541. const container = this.$.container;
  9542.  
  9543.  
  9544. let qw = null;
  9545.  
  9546. {
  9547.  
  9548.  
  9549. let maxC = 4;
  9550.  
  9551. for (let p = hostElement.getAttribute('r6-ticker-width') || ''; maxC--;) {
  9552.  
  9553. const ed = `${hostElement.id}`
  9554. if (!p || !p.startsWith(`${ed}::`)) {
  9555.  
  9556. const w = hostElement.style.width;
  9557. if (w !== '' && w !== 'auto') hostElement.style.width = 'auto';
  9558.  
  9559. const res = await widthReq(container);
  9560.  
  9561. hostElement.setAttribute('r6-ticker-width', p = `${ed}::${(res.width).toFixed(2)}`);
  9562.  
  9563. } else {
  9564. qw = p.split('::');
  9565. break;
  9566. }
  9567.  
  9568. }
  9569.  
  9570. }
  9571.  
  9572. if (!qw) {
  9573.  
  9574. console.log('container width failure');
  9575. this.setRevampContainerWidth41();
  9576. return; // failure
  9577. }
  9578.  
  9579.  
  9580. const shouldAnimateIn = ((this || 0).ytLiveChatTickerItemBehavior || 0).shouldAnimateIn || (this || 0).shouldAnimateIn || false;
  9581. if (shouldAnimateIn) {
  9582.  
  9583.  
  9584.  
  9585. const w = hostElement.style.width;
  9586. if (w !== '0px' && w !== '0') hostElement.style.width = '0';
  9587. // hostElement.classList.remove('ticker-no-transition-time');
  9588. await widthReq(container);
  9589.  
  9590. hostElement.style.width = `${qw[1]}px`;
  9591. return;
  9592.  
  9593.  
  9594. } else {
  9595. hostElement.style.width = `${qw[1]}px`;
  9596. }
  9597.  
  9598.  
  9599. // const container = this.$.container;
  9600. // if(hostElement instanceof HTMLElement && hostElement.style.width) hostElement.style.width = '';
  9601. });
  9602.  
  9603.  
  9604. console.log(`USE_ADVANCED_TICKING[#${tagI}]::setRevampContainerWidth - OK`)
  9605. } else {
  9606.  
  9607. console.log(`USE_ADVANCED_TICKING[#${tagI}]::setRevampContainerWidth - NG (acceptable)`)
  9608. }
  9609.  
  9610.  
  9611. if (typeof cProto.setContainerWidth === 'function' && !cProto.setContainerWidth41 && cProto.setContainerWidth.length === 0) {
  9612. cProto.setContainerWidth41 = cProto.setContainerWidth;
  9613. cProto.setContainerWidth = dProto.setContainerWidthAdv || (dProto.setContainerWidthAdv = async function () {
  9614.  
  9615.  
  9616.  
  9617. /*
  9618.  
  9619.  
  9620. var a = this
  9621. , b = R(this.hostElement).querySelector("#container").clientWidth || 0;
  9622. b === 0 ? (this.hostElement.style.overflow = "visible",
  9623. this.hostElement.style.width = "auto") : (this.hostElement.style.overflow = "hidden",
  9624. this.shouldAnimateIn ? (this.hostElement.style.width = "0",
  9625. Zu(function() {
  9626. a.hostElement.style.width = b + "px"
  9627. }, 1)) : this.hostElement.style.width = b + "px")
  9628.  
  9629. */
  9630.  
  9631. const hostElement = (this || 0).hostElement;
  9632. const container = this.$.container;
  9633.  
  9634.  
  9635. let qw = null;
  9636.  
  9637. {
  9638.  
  9639.  
  9640. let maxC = 4;
  9641.  
  9642. for (let p = hostElement.getAttribute('r6-ticker-width') || ''; maxC--;) {
  9643.  
  9644. const ed = `${hostElement.id}`
  9645. if (!p || !p.startsWith(`${ed}::`)) {
  9646.  
  9647. const w = hostElement.style.width;
  9648. if (w !== '' && w !== 'auto') hostElement.style.width = 'auto';
  9649.  
  9650. const res = await widthReq(container);
  9651.  
  9652. hostElement.setAttribute('r6-ticker-width', p = `${ed}::${(res.width).toFixed(2)}`);
  9653.  
  9654. } else {
  9655. qw = p.split('::');
  9656. break;
  9657. }
  9658.  
  9659. }
  9660.  
  9661. }
  9662.  
  9663. if (!qw) {
  9664.  
  9665. console.log('container width failure');
  9666. this.setContainerWidth41();
  9667. return; // failure
  9668. }
  9669.  
  9670.  
  9671. const shouldAnimateIn = ((this || 0).ytLiveChatTickerItemBehavior || 0).shouldAnimateIn || (this || 0).shouldAnimateIn || false;
  9672. if (shouldAnimateIn) {
  9673.  
  9674.  
  9675.  
  9676. const w = hostElement.style.width;
  9677. if (w !== '0px' && w !== '0') hostElement.style.width = '0';
  9678. // hostElement.classList.remove('ticker-no-transition-time');
  9679. await widthReq(container);
  9680.  
  9681. hostElement.style.width = `${qw[1]}px`;
  9682. return;
  9683.  
  9684.  
  9685. } else {
  9686. hostElement.style.width = `${qw[1]}px`;
  9687. }
  9688.  
  9689.  
  9690. });
  9691.  
  9692.  
  9693.  
  9694. console.log(`USE_ADVANCED_TICKING[#${tagI}]::setContainerWidth - OK`)
  9695. } else {
  9696.  
  9697.  
  9698. console.log(`USE_ADVANCED_TICKING[#${tagI}]::setContainerWidth - NG`)
  9699. }
  9700.  
  9701.  
  9702.  
  9703.  
  9704. } else if (USE_ADVANCED_TICKING) {
  9705. console.log(`USE_ADVANCED_TICKING[#${tagI}] is not injected.`);
  9706. }
  9707.  
  9708.  
  9709.  
  9710. }
  9711.  
  9712. const selector = tags.join(', ');
  9713. const elements = document.querySelectorAll(selector);
  9714. if (elements.length >= 1) {
  9715. for (const elm of elements) {
  9716. if (insp(elm).isAttached === true) {
  9717. fpTicker(elm);
  9718. }
  9719. }
  9720. }
  9721.  
  9722. console.log("[End]");
  9723. console.groupEnd();
  9724.  
  9725.  
  9726. }).catch(console.warn);
  9727.  
  9728. if(FIX_MEMORY_LEAKAGE_TICKER_DATACHANGED_setContainerWidth){
  9729.  
  9730. /**
  9731. *
  9732. *
  9733. *
  9734. *
  9735. cT.prototype.dataChanged = function() {
  9736. var a = this;
  9737. this.data && (Q(this.hostElement).querySelector("#content").style.color = this.ytLiveChatTickerItemBehavior.colorFromDecimal(this.data.detailTextColor),
  9738. this.hostElement.ariaLabel = this.computeAriaLabel(this.data),
  9739. this.ytLiveChatTickerItemBehavior.startCountdown(this.data.durationSec, this.data.fullDurationSec),
  9740. qw(function() {
  9741. a.ytLiveChatTickerItemBehavior.setContainerWidth()
  9742. }))
  9743. }
  9744.  
  9745.  
  9746. znb.prototype.dataChanged = function(a) {
  9747. var b = this;
  9748. a && (a.tickerThumbnails.length > 1 && Q(this.hostElement).querySelector("#content").classList.add("multiple-thumbnails"),
  9749. this.ytLiveChatTickerItemBehavior.startCountdown(a.durationSec, a.fullDurationSec),
  9750. qw(function() {
  9751. b.ytLiveChatTickerItemBehavior.setContainerWidth()
  9752. }))
  9753. }
  9754.  
  9755. *
  9756. */
  9757.  
  9758. const dProto = {
  9759. dataChanged54500: function () {
  9760. // prevent memory leakage due to _.ytLiveChatTickerItemBehavior.setContainerWidth() in _.dataChanged
  9761. if (typeof (this.ytLiveChatTickerItemBehavior || 0).setContainerWidth === 'function') {
  9762. try {
  9763. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  9764. return this.dataChanged544.call(this.__proxySelf0__);
  9765. } catch (e) {
  9766. console.log('dataChanged54500 ERROR');
  9767. console.error(e);
  9768. }
  9769. } else {
  9770. return this.dataChanged544();
  9771. }
  9772. },
  9773. dataChanged54501: function (a) {
  9774. // prevent memory leakage due to _.ytLiveChatTickerItemBehavior.setContainerWidth() in _.dataChanged
  9775. if (typeof (this.ytLiveChatTickerItemBehavior || 0).setContainerWidth === 'function') {
  9776. try {
  9777. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  9778. return this.dataChanged544.call(this.__proxySelf0__, a);
  9779. } catch (e) {
  9780. console.log('dataChanged54501 ERROR');
  9781. console.error(e);
  9782. }
  9783. } else {
  9784. return this.dataChanged544(a);
  9785. }
  9786. },
  9787. }
  9788.  
  9789. for (const sto of [
  9790. 'yt-live-chat-ticker-sponsor-item-renderer',
  9791. 'yt-live-chat-ticker-paid-sticker-item-renderer'
  9792. ].map(tag => [tag, customElements.whenDefined(tag)])) {
  9793. const [tag, promise] = sto;
  9794. promise.then(()=>{
  9795. const dummy = document.createElement(tag);
  9796. const cProto = getProto(dummy);
  9797. if (!cProto || !cProto.attached) {
  9798. console.warn(`proto.attached for ${tag} is unavailable.`);
  9799. return;
  9800. }
  9801. if (!cProto.dataChanged || cProto.dataChanged544 || typeof cProto.dataChanged !== 'function' || !(cProto.dataChanged.length >= 0 && cProto.dataChanged.length <= 1)) return;
  9802.  
  9803. cProto.dataChanged544 = cProto.dataChanged;
  9804.  
  9805. if (cProto.dataChanged.length === 0) cProto.dataChanged = dProto.dataChanged54500;
  9806. else if (cProto.dataChanged.length === 1) cProto.dataChanged = dProto.dataChanged54501;
  9807. })
  9808. }
  9809.  
  9810. }
  9811.  
  9812. customElements.whenDefined('yt-live-chat-ticker-renderer').then(() => {
  9813.  
  9814. if (FLAG_001d) return;
  9815.  
  9816. mightFirstCheckOnYtInit();
  9817. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-ticker-renderer hacks");
  9818. console.log("[Begin]");
  9819. (() => {
  9820.  
  9821. /* pending!!
  9822.  
  9823. handleLiveChatAction
  9824.  
  9825. removeTickerItemById
  9826.  
  9827. _itemsChanged
  9828. itemsChanged
  9829.  
  9830. handleMarkChatItemAsDeletedAction
  9831. handleMarkChatItemsByAuthorAsDeletedAction
  9832. handleRemoveChatItemByAuthorAction
  9833.  
  9834.  
  9835. */
  9836.  
  9837. const tag = "yt-live-chat-ticker-renderer"
  9838. const dummy = document.createElement(tag);
  9839.  
  9840. const cProto = getProto(dummy);
  9841. if (!cProto || !cProto.attached) {
  9842. console.warn(`proto.attached for ${tag} is unavailable.`);
  9843. return;
  9844. }
  9845.  
  9846. if(typeof cProto.createComponent_ === 'function' && cProto.createComponent_.length === 3 && !cProto.createComponent58_ ){
  9847.  
  9848. cProto.createComponent58_ = cProto.createComponent_;
  9849. cProto.createComponent_ = function (a, b, c) {
  9850.  
  9851. const z = customCreateComponent(a, b, c);
  9852. if (z !== undefined) return z;
  9853. const r = this.createComponent58_(a, b, c);
  9854. return r;
  9855.  
  9856. }
  9857.  
  9858. }
  9859.  
  9860. const do_amend_ticker_handleLiveChatAction = AMEND_TICKER_handleLiveChatAction && !AMEND_TICKER_handleLiveChatAction_v3
  9861. && typeof cProto.handleLiveChatAction === 'function' && !cProto.handleLiveChatAction45 && cProto.handleLiveChatAction.length === 1
  9862. && typeof cProto.handleLiveChatActions === 'function' && !cProto.handleLiveChatActions45 && cProto.handleLiveChatActions.length === 1
  9863. && typeof cProto.unshift === 'function' && cProto.unshift.length === 1
  9864. && typeof cProto.handleMarkChatItemAsDeletedAction === 'function' && cProto.handleMarkChatItemAsDeletedAction.length === 1
  9865. && typeof cProto.removeTickerItemById === 'function' && cProto.removeTickerItemById.length === 1
  9866. && typeof cProto.handleMarkChatItemsByAuthorAsDeletedAction === 'function' && cProto.handleMarkChatItemsByAuthorAsDeletedAction.length === 1
  9867. && typeof cProto.handleRemoveChatItemByAuthorAction === 'function' && cProto.handleRemoveChatItemByAuthorAction.length === 1
  9868. ;
  9869.  
  9870. console.log('do_amend_ticker_handleLiveChatAction', fnIntegrity(cProto.handleLiveChatAction), fnIntegrity(cProto.handleLiveChatActions))
  9871.  
  9872.  
  9873. if (do_amend_ticker_handleLiveChatAction) {
  9874.  
  9875.  
  9876. if (fnIntegrity(cProto.handleLiveChatActions) === '1.23.12') {
  9877.  
  9878. console.log(`handleLiveChatActions`, 'modified');
  9879.  
  9880. cProto.handleLiveChatActions45 = cProto.handleLiveChatActions;
  9881.  
  9882. cProto.handleLiveChatActions = function (a) {
  9883. /**
  9884. *
  9885. f.handleLiveChatActions = function(a) {
  9886. a.length && (a.forEach(this.handleLiveChatAction, this),
  9887. this.updateHighlightedItem(),
  9888. this.shouldAnimateIn = !0)
  9889. }
  9890. *
  9891. */
  9892. const len = a.length;
  9893. if (len) {
  9894. const batchToken = String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 19861 + 19861).toString(36);
  9895.  
  9896. if (FIX_BATCH_TICKER_ORDER && len >= 2) {
  9897.  
  9898. // Primarily for the initial batch, this is due to replayBuffer._back.
  9899. const entries = [];
  9900. const entriesI = [];
  9901. for (let i = 0; i < len; i++) {
  9902. const item = ((a[i] || 0).addLiveChatTickerItemAction || 0).item || 0;
  9903. const timestampUsec = item ? parseInt(getTimestampUsec(item[firstObjectKey(item)]), 10) : 0;
  9904. if (timestampUsec > 0) {
  9905. entriesI.push(i);
  9906. binaryInsert(entries, { e: a[i], timestampUsec }, (a, b) => {
  9907. const diff = a.timestampUsec - b.timestampUsec;
  9908. return diff > 0.1 ? 1 : diff < -0.1 ? -1 : 0;
  9909. });
  9910. }
  9911. }
  9912. const mLen = entries.length;
  9913. if (mLen >= 2) {
  9914. for (let j = 0; j < mLen; j++) {
  9915. a[entriesI[j]] = entries[j].e;
  9916. }
  9917. }
  9918. entries.length = 0;
  9919. entriesI.length = 0;
  9920. }
  9921. for (const action of a) {
  9922. action.__batchId45__ = batchToken;
  9923. this.handleLiveChatAction(action);
  9924. }
  9925. }
  9926. }
  9927.  
  9928.  
  9929. }
  9930.  
  9931.  
  9932. console.log(`handleLiveChatAction`, 'modified');
  9933.  
  9934. const cacheChatActions = new LimitedSizeSet(16);
  9935.  
  9936. cProto.handleLiveChatAction45 = cProto.handleLiveChatAction;
  9937.  
  9938. cProto.handleLiveChatAction = function (a) {
  9939.  
  9940. const key = firstObjectKey(a);
  9941. if (!key) return;
  9942.  
  9943. const val = a[key];
  9944. let itemKey = '';
  9945. let itemId = '';
  9946. const valItem = val ? val.item : null;
  9947. if (valItem) {
  9948. itemKey = firstObjectKey(valItem);
  9949. if (itemKey) {
  9950. const itemVal = valItem[itemKey];
  9951. itemId = itemVal ? itemVal.id : '';
  9952. if (itemId) {
  9953. const cacheKey = `${key}.${itemKey}::${itemId}`;
  9954. if (key === 'addChatItemAction' && itemId) return; // no need
  9955. if (cacheChatActions.has(cacheKey)) {
  9956. console.log('handleLiveChatAction Repeated Item', cacheKey);
  9957. return;
  9958. } else {
  9959. cacheChatActions.add(cacheKey);
  9960. }
  9961. }
  9962. }
  9963. }
  9964. return this.handleLiveChatAction45(a);
  9965. };
  9966.  
  9967. console.log("AMEND_TICKER_handleLiveChatAction - OK (v2)");
  9968.  
  9969. } else if (0 && do_amend_ticker_handleLiveChatAction
  9970. && '|1.63.48|1.64.48|'.includes(`|${fnIntegrity(cProto.handleLiveChatAction)}|`)
  9971. && fnIntegrity(cProto.handleLiveChatActions) === '1.23.12'
  9972. ) {
  9973.  
  9974. cProto.handleLiveChatActions45 = cProto.handleLiveChatActions;
  9975.  
  9976. cProto.handleLiveChatActions = function (a) {
  9977. /**
  9978. *
  9979. f.handleLiveChatActions = function(a) {
  9980. a.length && (a.forEach(this.handleLiveChatAction, this),
  9981. this.updateHighlightedItem(),
  9982. this.shouldAnimateIn = !0)
  9983. }
  9984. *
  9985. */
  9986.  
  9987. if (a.length) {
  9988. const batchToken = String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 19861 + 19861).toString(36);
  9989. const len = a.length;
  9990. if (FIX_BATCH_TICKER_ORDER && len >= 2) {
  9991. // Primarily for the initial batch, this is due to replayBuffer._back.
  9992. const entries = [];
  9993. const entriesI = [];
  9994. for (let i = 0; i < len; i++) {
  9995. const item = ((a[i] || 0).addLiveChatTickerItemAction || 0).item || 0;
  9996. if (item) {
  9997. const itemRendererKey = firstObjectKey(item);
  9998. const itemRenderer = item[itemRendererKey];
  9999. if (itemRenderer) {
  10000. let timestampUsec = getTimestampUsec(itemRenderer);
  10001. if (timestampUsec !== null) {
  10002. timestampUsec = parseInt(timestampUsec, 10);
  10003. if (timestampUsec > 0) {
  10004. entriesI.push(i);
  10005. entries.push({ e: a[i], timestampUsec })
  10006. }
  10007. }
  10008. }
  10009. }
  10010. }
  10011. const mLen = entries.length;
  10012. if (mLen >= 2) {
  10013. entries.sort((a, b) => {
  10014. const diff = a.timestampUsec - b.timestampUsec;
  10015. return diff > 0.1 ? 1 : diff < -0.1 ? -1 : 0;
  10016. });
  10017. for (let j = 0; j < mLen; j++) {
  10018. const i = entriesI[j];
  10019. a[i] = entries[j].e;
  10020. }
  10021. }
  10022. entries.length = 0;
  10023. entriesI.length = 0;
  10024. }
  10025. for (const action of a) {
  10026. action.__batchId45__ = batchToken;
  10027. this.handleLiveChatAction(action);
  10028. }
  10029. }
  10030. }
  10031.  
  10032. cProto.handleLiveChatAction45 = cProto.handleLiveChatAction;
  10033.  
  10034. cProto._nszlv_ = 0;
  10035. cProto._stackedLCAs_ = null;
  10036. cProto._lastAddItem_ = null;
  10037. cProto._lastAddItemInStack_ = false;
  10038. cProto.handleLiveChatAction = function (a) {
  10039.  
  10040. /**
  10041. *
  10042. *
  10043. f.handleLiveChatAction = function(a) {
  10044. var b = C(a, xO)
  10045. , c = C(a, yO)
  10046. , d = C(a, o1a)
  10047. , e = C(a, p1a);
  10048. a = C(a, A1a);
  10049. b ? this.unshift("items", b.item) : c ? this.handleMarkChatItemAsDeletedAction(c) : d ? this.removeTickerItemById(d.targetItemId) : e ? this.handleMarkChatItemsByAuthorAsDeletedAction(e) : a && this.handleRemoveChatItemByAuthorAction(a)
  10050. }
  10051. *
  10052. */
  10053.  
  10054. // return this.handleLiveChatAction45(a)
  10055. const { addChatItemAction, addLiveChatTickerItemAction, markChatItemAsDeletedAction,
  10056. removeChatItemAction, markChatItemsByAuthorAsDeletedAction, removeChatItemByAuthorAction, __batchId45__ } = a
  10057.  
  10058. if (addChatItemAction) return;
  10059. const d = Date.now();
  10060.  
  10061. if (this._stackedLCAs_ === null) this._stackedLCAs_ = [];
  10062. const stackArr = this._stackedLCAs_;
  10063. let newStackEntry = null;
  10064. if (addLiveChatTickerItemAction) {
  10065. let isDuplicated = false;
  10066.  
  10067. const newItem = addLiveChatTickerItemAction.item;
  10068. const tickerType = firstObjectKey(newItem);
  10069. if (!tickerType) return;
  10070. const tickerItem = newItem[tickerType];
  10071. const tickerId = tickerItem.id;
  10072. if (!tickerId) return;
  10073.  
  10074. if (this._lastAddItem_ && this._lastAddItem_.id === tickerId) {
  10075. let prevTickerItem = null;
  10076. if (this._lastAddItemInStack_) {
  10077. const entry = stackArr[stackArr.length - 1]; // only consider the last entry
  10078. if (entry && entry.action === 'addItem') {
  10079. prevTickerItem = entry.data; // only consider the first item;
  10080. }
  10081. } else {
  10082. prevTickerItem = this.items[0]; // only consider the first item;
  10083. }
  10084. if (prevTickerItem && prevTickerItem[tickerType]) {
  10085. if (prevTickerItem[tickerType].id === tickerId) {
  10086. isDuplicated = true;
  10087. }
  10088. }
  10089. }
  10090. if (!isDuplicated) {
  10091. this._lastAddItem_ = tickerItem;
  10092. this._lastAddItemInStack_ = true;
  10093. // console.log('newItem', newItem)
  10094.  
  10095. const item = newItem;
  10096. const key = firstObjectKey(item);
  10097. if (key) {
  10098. const itemRenderer = item[key] || 0;
  10099. if (itemRenderer.fullDurationSec > 0) {
  10100. itemRenderer.__actionAt__ = d;
  10101. }
  10102. }
  10103.  
  10104. newStackEntry = { action: 'addItem', data: newItem };
  10105.  
  10106. } else {
  10107. console.log('handleLiveChatAction Repeated Item', tickerItem.id, tickerItem); // happen in both live and playback. Reason Unknown.
  10108. return;
  10109. }
  10110.  
  10111. } else {
  10112. markChatItemAsDeletedAction && (newStackEntry = { action: 'mcItemD', data: markChatItemAsDeletedAction });
  10113. removeChatItemAction && (newStackEntry = { action: 'removeItemById', data: removeChatItemAction.targetId });
  10114. markChatItemsByAuthorAsDeletedAction && (newStackEntry = { action: 'mcItemAD', data: markChatItemsByAuthorAsDeletedAction });
  10115. removeChatItemByAuthorAction && (newStackEntry = { action: 'removeItemA', data: removeChatItemByAuthorAction })
  10116. }
  10117.  
  10118.  
  10119. if (!newStackEntry) return;
  10120. stackArr.push(newStackEntry);
  10121.  
  10122.  
  10123. this._nszlv_++;
  10124. if (this._nszlv_ > 1e9) this._nszlv_ = 9;
  10125. const tid = this._nszlv_;
  10126.  
  10127. newStackEntry.__batchId45__ = __batchId45__ || '';
  10128. newStackEntry.dateTime = Date.now();
  10129.  
  10130.  
  10131. foregroundPromiseFn().then(() => {
  10132.  
  10133. if (tid !== this._nszlv_) return;
  10134. const dateNow = Date.now(); // time difference to shift animation start time shall be considered. (pending)
  10135. const stackArr = this._stackedLCAs_.slice(0);
  10136. this._stackedLCAs_.length = 0;
  10137. this._lastAddItemInStack_ = false;
  10138. let lastDateTime = 0;
  10139. let prevBatchId = '';
  10140. const addItems = [];
  10141. // const previousShouldAnimateIn = this.shouldAnimateIn;
  10142.  
  10143. const addItemsFx = () => {
  10144.  
  10145. if (addItems.length >= 1) {
  10146. const eArr = addItems.slice(0);
  10147. addItems.length = 0;
  10148. if (ADJUST_TICKER_DURATION_ALIGN_RENDER_TIME) {
  10149.  
  10150. const arr = []; // size of arr <= size of eArr
  10151. const d = Date.now();
  10152. for (const item of eArr) {
  10153. const key = firstObjectKey(item);
  10154. if (key) {
  10155.  
  10156.  
  10157. const itemRenderer = item[key] || 0;
  10158. const { durationSec, fullDurationSec, __actionAt__ } = itemRenderer;
  10159. if (__actionAt__ > 0 && durationSec > 0 && fullDurationSec > 0) {
  10160.  
  10161.  
  10162. const offset = d - __actionAt__;
  10163. if (offset > 0 && typeof durationSec === 'number' && typeof fullDurationSec === 'number' && fullDurationSec >= durationSec) {
  10164. const adjustedDurationSec = durationSec - Math.floor(offset / 1000);
  10165. if (adjustedDurationSec < durationSec) { // prevent NaN
  10166. // console.log('adjustedDurationSec', adjustedDurationSec);
  10167. if (adjustedDurationSec > 0) {
  10168. // console.log('offset Sec', Math.floor(offset / 1000));
  10169. itemRenderer.durationSec = adjustedDurationSec;
  10170. } else {
  10171. // if adjustedDurationSec equal 0 or invalid
  10172. continue; // skip adding
  10173. }
  10174. }
  10175.  
  10176. }
  10177.  
  10178. }
  10179.  
  10180. if (fullDurationSec > 0 && durationSec < 1) continue; // fallback check
  10181.  
  10182.  
  10183.  
  10184. }
  10185. arr.push(item)
  10186. // arr.unshift(item);
  10187. }
  10188.  
  10189.  
  10190. // console.log(arr.slice(0))
  10191. this.unshift("items", ...arr);
  10192. } else {
  10193. this.unshift("items", ...eArr);
  10194. }
  10195. }
  10196. }
  10197.  
  10198. for (const entry of stackArr) {
  10199.  
  10200. const { action, data, dateTime, __batchId45__ } = entry;
  10201.  
  10202. const finishLastAction = (
  10203. (prevBatchId !== __batchId45__ && prevBatchId)
  10204. || (dateNow - lastDateTime >= 1000 && dateNow - dateTime < 1000)
  10205. );
  10206.  
  10207. const addPrevItems = addItems.length >= 1 && (finishLastAction || action !== 'addItem');
  10208. lastDateTime = dateTime;
  10209. prevBatchId = __batchId45__;
  10210.  
  10211. if (addPrevItems) {
  10212. addItemsFx();
  10213. }
  10214.  
  10215. if (action === 'addItem') addItems.unshift(data);
  10216. else if (action === 'mcItemD') this.handleMarkChatItemAsDeletedAction(data);
  10217. else if (action === 'removeItemById') this.removeTickerItemById(data);
  10218. else if (action === 'mcItemAD') this.handleMarkChatItemsByAuthorAsDeletedAction(data);
  10219. else if (action === 'removeItemA') this.handleRemoveChatItemByAuthorAction(data);
  10220.  
  10221. }
  10222.  
  10223. addItemsFx();
  10224. })
  10225.  
  10226. }
  10227.  
  10228. console.log("AMEND_TICKER_handleLiveChatAction - OK (v1)");
  10229. } else {
  10230. console.log("AMEND_TICKER_handleLiveChatAction - NG (acceptable)");
  10231. }
  10232.  
  10233.  
  10234.  
  10235.  
  10236.  
  10237.  
  10238. /* Dec 2024 */
  10239.  
  10240. /*
  10241.  
  10242.  
  10243. f.handleLiveChatActions = function(a) {
  10244. a.length && (a.forEach(this.handleLiveChatAction, this),
  10245. this.updateHighlightedItem(),
  10246. this.shouldAnimateIn = !0)
  10247. }
  10248. ;
  10249. f.handleLiveChatAction = function(a) {
  10250. var b = z(a, fL)
  10251. , c = z(a, gL)
  10252. , d = z(a, eL)
  10253. , e = z(a, gdb)
  10254. , g = z(a, rdb)
  10255. , k = z(a, Deb);
  10256. a = z(a, Ceb);
  10257. b ? this.unshift("tickerItems", b.item) : c ? this.handleMarkChatItemAsDeletedAction(c) : d ? this.removeTickerItemById(d.targetItemId) : e ? this.handleMarkChatItemsByAuthorAsDeletedAction(e) : g ? this.handleRemoveChatItemByAuthorAction(g) : k ? this.showCreatorGoalTickerChip(k) : a && this.removeCreatorGoalTickerChip(a)
  10258. }
  10259. */
  10260.  
  10261.  
  10262. if(USE_ADVANCED_TICKING && !cProto.handleLiveChatActions47 && typeof cProto.handleLiveChatActions === 'function' && cProto.handleLiveChatActions.length ===1){
  10263.  
  10264. cProto.handleLiveChatActions47 = cProto.handleLiveChatActions;
  10265.  
  10266. cProto.handleLiveChatActions = function (a) {
  10267.  
  10268. // first loading in livestream. so this is required for sorting.
  10269.  
  10270. try{
  10271. preprocessChatLiveActions(a);
  10272. }catch(e){
  10273. console.warn(e);
  10274. }
  10275. return this.handleLiveChatActions47(a);
  10276.  
  10277. }
  10278.  
  10279. console.log("USE_ADVANCED_TICKING::handleLiveChatActions - OK");
  10280. }else if(USE_ADVANCED_TICKING){
  10281.  
  10282.  
  10283. console.log("USE_ADVANCED_TICKING::handleLiveChatActions - NG");
  10284.  
  10285. }
  10286.  
  10287.  
  10288. const do_amend_ticker_handleLiveChatAction_v3 = AMEND_TICKER_handleLiveChatAction_v3 && !AMEND_TICKER_handleLiveChatAction
  10289. && typeof cProto.handleLiveChatAction === 'function' && !cProto.handleLiveChatAction45 && cProto.handleLiveChatAction.length === 1
  10290. && typeof cProto.handleLiveChatActions === 'function' && !cProto.handleLiveChatActions45 && cProto.handleLiveChatActions.length === 1
  10291. && typeof cProto.unshift === 'function' && cProto.unshift.length === 1
  10292. && typeof cProto.handleMarkChatItemAsDeletedAction === 'function' && cProto.handleMarkChatItemAsDeletedAction.length === 1
  10293. && typeof cProto.removeTickerItemById === 'function' && cProto.removeTickerItemById.length === 1
  10294. && typeof cProto.handleMarkChatItemsByAuthorAsDeletedAction === 'function' && cProto.handleMarkChatItemsByAuthorAsDeletedAction.length === 1
  10295. && typeof cProto.handleRemoveChatItemByAuthorAction === 'function' && cProto.handleRemoveChatItemByAuthorAction.length === 1
  10296. ;
  10297.  
  10298. // yt-live-chat-ticker-renderer hacks
  10299. // console.log('handleLiveChatActions', cProto.handleLiveChatActions, cProto.is);
  10300. // console.log('handleLiveChatAction', cProto.handleLiveChatAction, cProto.is);
  10301.  
  10302. if (do_amend_ticker_handleLiveChatAction_v3 ) {
  10303.  
  10304. // causing no transition ??
  10305. // affect performance if many tickers need to be added. (become multiple reflows)
  10306. // performance issue shall be fixed by no transition instead (or min-width: max-content)
  10307.  
  10308. /*
  10309. f.handleLiveChatActions = function(a) {
  10310. a.length && (a.forEach(this.handleLiveChatAction, this),
  10311. this.updateHighlightedItem(),
  10312. this.shouldAnimateIn = !0)
  10313. }
  10314. */
  10315.  
  10316. /*
  10317.  
  10318. f.handleLiveChatAction = function(a) {
  10319. var b = y(a, PM)
  10320. , c = y(a, QM)
  10321. , d = y(a, OM)
  10322. , e = y(a, Yab);
  10323. a = y(a, ibb);
  10324. b && this.enableCreatorGoalRevamp ? this.unshift("tickerItems", b.item) : b ? this.unshift("items", b.item) : c ? this.handleMarkChatItemAsDeletedAction(c) : d ? this.removeTickerItemById(d.targetItemId) : e ? this.handleMarkChatItemsByAuthorAsDeletedAction(e) : a && this.handleRemoveChatItemByAuthorAction(a)
  10325. }
  10326. */
  10327.  
  10328. /* Dec 2024 */
  10329.  
  10330. /*
  10331.  
  10332.  
  10333. f.handleLiveChatActions = function(a) {
  10334. a.length && (a.forEach(this.handleLiveChatAction, this),
  10335. this.updateHighlightedItem(),
  10336. this.shouldAnimateIn = !0)
  10337. }
  10338. ;
  10339. f.handleLiveChatAction = function(a) {
  10340. var b = z(a, fL)
  10341. , c = z(a, gL)
  10342. , d = z(a, eL)
  10343. , e = z(a, gdb)
  10344. , g = z(a, rdb)
  10345. , k = z(a, Deb);
  10346. a = z(a, Ceb);
  10347. b ? this.unshift("tickerItems", b.item) : c ? this.handleMarkChatItemAsDeletedAction(c) : d ? this.removeTickerItemById(d.targetItemId) : e ? this.handleMarkChatItemsByAuthorAsDeletedAction(e) : g ? this.handleRemoveChatItemByAuthorAction(g) : k ? this.showCreatorGoalTickerChip(k) : a && this.removeCreatorGoalTickerChip(a)
  10348. }
  10349. */
  10350.  
  10351.  
  10352.  
  10353. const arr00 = new Array(1);
  10354. arr00.forEach = () => { };
  10355. arr00.push = (...args) => { return 1 + args.length };
  10356. arr00.pop = () => { };
  10357. arr00.shift = () => { };
  10358. arr00.unshift = () => { };
  10359. arr00.splice = () => [];
  10360. cProto.handleLiveChatActionsArr0 = arr00;
  10361.  
  10362. cProto.handleLiveChatActions58 = cProto.handleLiveChatActions;
  10363. cProto.xGqq4mo = null;
  10364. cProto.xGqq4Flg = 0;
  10365. cProto.xGqq4moPreparePromise = null;
  10366. cProto.xGqq4f = function () {
  10367. if (this.xGqq4Flg === 2) {
  10368. this.xGqq4Flg = 0;
  10369. tickerPE(async () => { // avoid confliction with ticker generation
  10370. await this.xGqq4moPreparePromise; // just in case
  10371. const s = this.handleLiveChatActionsArr0;
  10372. try {
  10373. this.handleLiveChatActions58(s);
  10374. } catch (e) {
  10375. console.warn(e);
  10376. }
  10377. // console.log('xGqq4f done')
  10378. });
  10379.  
  10380. }
  10381. }
  10382. const liveActionQM = new WeakSet();
  10383. let liveActionsLastTickerAction = null;
  10384. const lastTickerActionM = new WeakSet();
  10385. cProto.handleLiveChatActions = function (a) {
  10386. // let promise = null;
  10387. if (a && a.length) {
  10388. /** @type {MutationObserver | null} */
  10389. let mo = this.xGqq4mo;
  10390. // console.log('xGqq4f aaaa')
  10391. const hostElement = this.hostElement;
  10392. if (hostElement instanceof HTMLElement) {
  10393. if (mo === null || (mo instanceof MutationObserver && this.xGqq4p !== hostElement.xGqq4q)) {
  10394. if (mo instanceof MutationObserver) {
  10395. mo.disconnect();
  10396. mo.takeRecords();
  10397. }
  10398. this.xGqq4mo = mo = new MutationObserver(() => {
  10399. this.xGqq4f();
  10400. })
  10401. const moid = `dm-${Date.now()}-${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;;
  10402. this.xGqq4p = moid;
  10403. hostElement.xGqq4q = moid;
  10404. mo.observe(hostElement, { subtree: true, childList: true });
  10405. }
  10406. }
  10407. for (const u of a) {
  10408. u && liveActionQM.add(u)
  10409. }
  10410.  
  10411. /** @type {Promise} */
  10412. const pastPromise = this.xGqq4moPreparePromise || null;
  10413. this.xGqq4moPreparePromise = (async () => {
  10414. try {
  10415. await pastPromise; // just in case
  10416. liveActionsLastTickerAction = null;
  10417. a.forEach(this.handleLiveChatAction, this);
  10418. if (liveActionsLastTickerAction) lastTickerActionM.add(liveActionsLastTickerAction)
  10419. } catch (e) { console.warn(e); } // Promise catch can make the promise always resolved
  10420. // now tickerPE can execute
  10421. })();
  10422.  
  10423.  
  10424. // console.log('xGqq4f bbbb')
  10425. // promise = this.handleLiveChatAction_LastPromise;
  10426. // const f = () => {
  10427. // const s = this.handleLiveChatActionsArr0;
  10428. // try {
  10429. // return this.handleLiveChatActions58(s);
  10430. // } catch (e) {
  10431. // console.warn(e);
  10432. // }
  10433. // }
  10434. // if (!promise) {
  10435. // f();
  10436. // } else {
  10437. // promise.then(f);
  10438. // }
  10439. } else {
  10440. return this.handleLiveChatActions58(a);
  10441. }
  10442. }
  10443.  
  10444. // 12:17:05.748 PM
  10445. // 12:17:05.785 v {name: 'addLiveChatTickerItemAction'}
  10446. // 12:17:08.059 QM
  10447. // 12:17:08.068 v {name: 'markChatItemAsDeletedAction'}
  10448. // 12:17:09.123 OM
  10449. // 12:17:09.133 v {name: 'removeChatItemAction'}
  10450. // 12:17:11.566 Yab
  10451. // 12:17:11.574 v {name: 'markChatItemsByAuthorAsDeletedAction'}
  10452. // 12:17:14.272 ibb
  10453. // 12:17:14.282 v {name: 'removeChatItemByAuthorAction'}
  10454.  
  10455. const keyFilter = (a, keySet) => {
  10456. if (typeof (a || 0) === 'object') {
  10457. for (const k of Object.keys(a)) {
  10458. if (keySet.has(k)) {
  10459. return k;
  10460. }
  10461. }
  10462. }
  10463. return null;
  10464. }
  10465.  
  10466. cProto.lcuJB = function () {
  10467. this.ddnB8 = 1;
  10468. let res = new Set();
  10469. const pxy = new Proxy({}, {
  10470. get(target, prop) {
  10471. res.add(prop);
  10472. },
  10473. set(target, prop, value) {
  10474. return true;
  10475. }
  10476. });
  10477. this.handleLiveChatAction(pxy);
  10478. this.ddnB8 = 0;
  10479. return res.size > 0 ? res : null;
  10480. }
  10481.  
  10482. cProto.ddnB8 = 0;
  10483. cProto.handleLiveChatAction58 = cProto.handleLiveChatAction;
  10484. cProto.liveChatActionFilterKeys = null;
  10485. cProto.handleLiveChatActionTM = new LimitedSizeMap(24);
  10486. const tt0 = Date.now() - 100000;
  10487. cProto.handleLiveChatAction = function (a) {
  10488. if (this.ddnB8) return this.handleLiveChatAction58(a);
  10489. const inQM = a && liveActionQM.delete(a); // true if added from handleLiveChatActions
  10490. let keySet = this.liveChatActionFilterKeys;
  10491. if (keySet === null) {
  10492. const keys = this.lcuJB();
  10493. this.liveChatActionFilterKeys = keySet = (keys || false);
  10494. }
  10495. if (!keySet) {
  10496. if (!unexpectedErr) {
  10497. console.error(unexpectedErr = "************************ [YouTube Super Fast Chat] TickerRenderer:handleLiveChatAction keySet not found; ERR 0xF3D0 ************************");
  10498. }
  10499. return this.handleLiveChatAction58(a);
  10500. }
  10501. const key = keyFilter(a, keySet);
  10502. if (!key) {
  10503. return this.handleLiveChatAction58(a); // just by default
  10504. }
  10505.  
  10506. // ------ avoid duplicate items -------
  10507. const item = ((a[key] || 0).item || 0);
  10508. const ifk = item ? firstObjectKey(item) : null;
  10509. const rendererItem = ifk ? item[ifk] : null;
  10510. if (rendererItem && rendererItem.id) {
  10511. const id = rendererItem.id || 0;
  10512. if (typeof id === 'string') {
  10513. const map = this.handleLiveChatActionTM;
  10514. if (map) {
  10515. const mid = `${rendererItem.authorExternalChannelId}::${rendererItem.id}`;
  10516. const prevTime = map.get(mid);
  10517. const now = Date.now() - tt0;
  10518. map.removeSet(mid, now);
  10519. if (prevTime > 0 && now - prevTime < 2400) {
  10520. console.log('handleLiveChatAction Repeated Item OK', rendererItem.id, rendererItem);
  10521. return; // skip
  10522. } else if (prevTime) {
  10523. console.log('handleLiveChatAction Repeated Item NG', mid, now, prevTime, rendererItem.id, rendererItem);
  10524. }
  10525. // map.removeSet(mid, now);
  10526. }
  10527. }
  10528. }
  10529. // ------ avoid duplicate items -------
  10530.  
  10531. if (inQM) {
  10532. liveActionsLastTickerAction = a;
  10533. }
  10534. this.handleLiveChatAction_LastPromise = tickerPE(async () => {
  10535. await this.xGqq4moPreparePromise; // avoid tickerPE is called before actions under looping in handleLiveChatActions
  10536. const inLQM = lastTickerActionM.delete(a); // multiple candidates
  10537. if (inLQM) this.xGqq4Flg = 2; // 2 to 2 in case two batches are added "in the same time"
  10538. this.handleLiveChatAction58(a);
  10539. // if (inLQM) await timelineResolve(); // timing split by marco event to make tickers generation in different 16ms frame
  10540. // else await Promise.resolve();
  10541. // await Promise.resolve();
  10542. await timelineResolve(); // timing split by marco event to make tickers generation in different 16ms frame
  10543. });
  10544. }
  10545.  
  10546. }
  10547.  
  10548. if (RAF_FIX_keepScrollClamped) {
  10549.  
  10550. // to be improved
  10551.  
  10552. if (typeof cProto.keepScrollClamped === 'function' && !cProto.keepScrollClamped72 && fnIntegrity(cProto.keepScrollClamped) === '0.17.10') {
  10553.  
  10554. cProto.keepScrollClamped72 = cProto.keepScrollClamped;
  10555. cProto.keepScrollClamped = function () {
  10556.  
  10557. const cnt = kRef(this);
  10558. if (!cnt) return;
  10559. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10560.  
  10561. cnt._bound_keepScrollClamped = cnt._bound_keepScrollClamped || cnt.keepScrollClamped.bind(mWeakRef(cnt));
  10562. cnt.scrollClampRaf = requestAnimationFrame(cnt._bound_keepScrollClamped);
  10563. cnt.maybeClampScroll()
  10564. }
  10565.  
  10566. console.log('RAF_FIX: keepScrollClamped', tag, "OK")
  10567. } else {
  10568.  
  10569. assertor(() => fnIntegrity(cProto.keepScrollClamped, '0.17.10'));
  10570. console.log('RAF_FIX: keepScrollClamped', tag, "NG")
  10571. }
  10572.  
  10573. }
  10574.  
  10575.  
  10576. if (RAF_FIX_scrollIncrementally && typeof cProto.startScrolling === 'function' && typeof cProto.scrollIncrementally === 'function'
  10577. && '|1.43.31|1.44.31|'.indexOf('|' + fnIntegrity(cProto.startScrolling) + '|') >= 0
  10578. && '|1.78.45|1.82.43|1.43.31|'.indexOf('|' + fnIntegrity(cProto.scrollIncrementally) + '|') >= 0) {
  10579. // to be replaced by animator
  10580.  
  10581. cProto.startScrolling = function (a) {
  10582.  
  10583. const cnt = kRef(this);
  10584. if (!cnt) return;
  10585. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10586.  
  10587. cnt.scrollStopHandle && cnt.cancelAsync(cnt.scrollStopHandle);
  10588. cnt.asyncHandle && cancelAnimationFrame(cnt.asyncHandle);
  10589. cnt.lastFrameTimestamp = cnt.scrollStartTime = performance.now();
  10590. cnt.scrollRatePixelsPerSecond = a;
  10591. cnt._bound_scrollIncrementally = cnt._bound_scrollIncrementally || cnt.scrollIncrementally.bind(mWeakRef(cnt));
  10592. cnt.asyncHandle = requestAnimationFrame(cnt._bound_scrollIncrementally)
  10593. };
  10594.  
  10595. // related functions: startScrollBack, startScrollingLeft, startScrollingRight, etc.
  10596.  
  10597. /**
  10598. *
  10599. * // 2024.12.17
  10600. * // https://www.youtube.com/s/desktop/f7495da0/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  10601.  
  10602. f.startScrolling = function(a) {
  10603. this.scrollStopHandle && $u(this.scrollStopHandle);
  10604. this.asyncHandle && window.cancelAnimationFrame(this.asyncHandle);
  10605. this.scrollStartTime = performance.now();
  10606. this.lastFrameTimestamp = performance.now();
  10607. this.scrollRatePixelsPerSecond = a;
  10608. this.asyncHandle = window.requestAnimationFrame(this.scrollIncrementally.bind(this))
  10609. }
  10610. ;
  10611. f.scrollIncrementally = function(a) {
  10612. var b = a - (this.lastFrameTimestamp || 0);
  10613. R(this.hostElement).querySelector(this.tickerBarQuery).scrollLeft += b / 1E3 * (this.scrollRatePixelsPerSecond || 0);
  10614. this.maybeClampScroll();
  10615. this.updateArrows();
  10616. this.lastFrameTimestamp = a;
  10617. R(this.hostElement).querySelector(this.tickerBarQuery).scrollLeft > 0 || this.scrollRatePixelsPerSecond && this.scrollRatePixelsPerSecond > 0 ? this.asyncHandle = window.requestAnimationFrame(this.scrollIncrementally.bind(this)) : this.stopScrolling()
  10618. }
  10619. ;
  10620. *
  10621. */
  10622.  
  10623. /**
  10624. *
  10625. // 2024.12.20
  10626.  
  10627.  
  10628.  
  10629. f.startScrolling = function(a) {
  10630. this.scrollStopHandle && av(this.scrollStopHandle);
  10631. this.asyncHandle && window.cancelAnimationFrame(this.asyncHandle);
  10632. this.scrollStartTime = performance.now();
  10633. this.lastFrameTimestamp = performance.now();
  10634. this.scrollRatePixelsPerSecond = a;
  10635. this.asyncHandle = window.requestAnimationFrame(this.scrollIncrementally.bind(this))
  10636. }
  10637.  
  10638. *
  10639. *
  10640. */
  10641.  
  10642. cProto.__getTickerBarQuery__ = function () {
  10643. const tickerBarQuery = this.tickerBarQuery === '#items' ? this.$.items : this.hostElement.querySelector(this.tickerBarQuery);
  10644. return tickerBarQuery;
  10645. }
  10646.  
  10647. cProto.scrollIncrementally = (RAF_FIX_scrollIncrementally === 2) ? function (a) {
  10648.  
  10649. const cnt = kRef(this);
  10650. if (!cnt) return;
  10651. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10652.  
  10653. const b = a - (cnt.lastFrameTimestamp || 0);
  10654. const rate = cnt.scrollRatePixelsPerSecond
  10655. const q = b / 1E3 * (rate || 0);
  10656.  
  10657. const tickerBarQuery = cnt.__getTickerBarQuery__();
  10658. const sl = tickerBarQuery.scrollLeft;
  10659. // console.log(rate, sl, q)
  10660. if (cnt.lastFrameTimestamp == cnt.scrollStartTime) {
  10661.  
  10662. } else if (q > -1e-5 && q < 1e-5) {
  10663.  
  10664. } else {
  10665. let cond1 = sl > 0 && rate > 0 && q > 0;
  10666. let cond2 = sl > 0 && rate < 0 && q < 0;
  10667. let cond3 = sl < 1e-5 && sl > -1e-5 && rate > 0 && q > 0;
  10668. if (cond1 || cond2 || cond3) {
  10669. tickerBarQuery.scrollLeft += q;
  10670. cnt.maybeClampScroll();
  10671. cnt.updateArrows();
  10672. }
  10673. }
  10674.  
  10675. cnt.lastFrameTimestamp = a;
  10676. cnt._bound_scrollIncrementally = cnt._bound_scrollIncrementally || cnt.scrollIncrementally.bind(mWeakRef(cnt));
  10677. 0 < tickerBarQuery.scrollLeft || rate && 0 < rate ? cnt.asyncHandle = requestAnimationFrame(cnt._bound_scrollIncrementally) : cnt.stopScrolling()
  10678. } : function (a) {
  10679.  
  10680. const cnt = kRef(this);
  10681. if (!cnt) return;
  10682. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10683.  
  10684. const b = a - (cnt.lastFrameTimestamp || 0);
  10685. const tickerBarQuery = cnt.__getTickerBarQuery__();
  10686. tickerBarQuery.scrollLeft += b / 1E3 * (cnt.scrollRatePixelsPerSecond || 0);
  10687. cnt.maybeClampScroll();
  10688. cnt.updateArrows();
  10689. cnt.lastFrameTimestamp = a;
  10690. cnt._bound_scrollIncrementally = cnt._bound_scrollIncrementally || cnt.scrollIncrementally.bind(mWeakRef(cnt));
  10691. 0 < tickerBarQuery.scrollLeft || cnt.scrollRatePixelsPerSecond && 0 < cnt.scrollRatePixelsPerSecond ? cnt.asyncHandle = requestAnimationFrame(cnt._bound_scrollIncrementally) : cnt.stopScrolling()
  10692. };
  10693.  
  10694. console.log(`RAF_FIX: scrollIncrementally${RAF_FIX_scrollIncrementally}`, tag, "OK")
  10695. } else {
  10696. assertor(() => fnIntegrity(cProto.startScrolling, '1.43.31'))
  10697. || logFn('cProto.startScrolling', cProto.startScrolling)();
  10698. assertor(() => fnIntegrity(cProto.scrollIncrementally, '1.78.45'))
  10699. || logFn('cProto.scrollIncrementally', cProto.scrollIncrementally)();
  10700. console.log('RAF_FIX: scrollIncrementally', tag, "NG")
  10701. }
  10702.  
  10703.  
  10704. if (CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED && typeof cProto.attached === 'function' && !cProto.attached37 && typeof cProto.detached === 'function' && !cProto.detached37) {
  10705.  
  10706. cProto.attached37 = cProto.attached;
  10707. cProto.detached37 = cProto.detached;
  10708.  
  10709. let naohzId = 0;
  10710. cProto.__naohzId__ = 0;
  10711. cProto.attached = function () {
  10712. Promise.resolve(this).then((cnt) => {
  10713.  
  10714. const hostElement = cnt.hostElement || cnt;
  10715. if (!(hostElement instanceof HTMLElement)) return;
  10716. if (!HTMLElement.prototype.matches.call(hostElement, '.yt-live-chat-renderer')) return;
  10717. const ironPage = HTMLElement.prototype.closest.call(hostElement, 'iron-pages.yt-live-chat-renderer');
  10718. // or #chat-messages
  10719. if (!ironPage) return;
  10720.  
  10721. if (cnt.__naohzId__) removeEventListener.call(ironPage, 'click', cnt.messageBoxClickHandlerForFade, { capture: false, passive: true });
  10722. if (naohzId > 1e9) naohzId = naohzId % 1e4;
  10723. cnt.__naohzId__ = ++naohzId;
  10724. ironPage.setAttribute('naohz', `${+cnt.__naohzId__}`);
  10725.  
  10726. addEventListener.call(ironPage, 'click', cnt.messageBoxClickHandlerForFade, { capture: false, passive: true });
  10727. cnt = null;
  10728.  
  10729. });
  10730. return this.attached37.apply(this, arguments);
  10731. };
  10732. cProto.detached = function () {
  10733. Promise.resolve(this).then((cnt) => {
  10734.  
  10735. const ironPage = document.querySelector(`iron-pages[naohz="${+cnt.__naohzId__}"]`);
  10736. if (!ironPage) return;
  10737.  
  10738. removeEventListener.call(ironPage, 'click', cnt.messageBoxClickHandlerForFade, { capture: false, passive: true });
  10739.  
  10740. cnt = null;
  10741.  
  10742. });
  10743. return this.detached37.apply(this, arguments);
  10744. };
  10745.  
  10746. const clickFade = (u) => {
  10747. u.click();
  10748. };
  10749. cProto.messageBoxClickHandlerForFade = async (evt) => {
  10750.  
  10751. const target = (evt || 0).target || 0;
  10752. if (!target) return;
  10753.  
  10754. for (let p = target; p instanceof HTMLElement; p = nodeParent(p)) {
  10755. const is = p.is;
  10756. if (typeof is === 'string' && is) {
  10757.  
  10758. if (is === 'yt-live-chat-pinned-message-renderer') {
  10759. return;
  10760. }
  10761. if (is === 'iron-pages' || is === 'yt-live-chat-renderer' || is === 'yt-live-chat-app') {
  10762. const fade = HTMLElement.prototype.querySelector.call(p, 'yt-live-chat-pinned-message-renderer:not([hidden]) #fade');
  10763. if (fade) {
  10764. Promise.resolve(fade).then(clickFade);
  10765. evt && evt.stopPropagation();
  10766. }
  10767. return;
  10768. }
  10769. if (is !== 'yt-live-chat-ticker-renderer') {
  10770. if (is.startsWith('yt-live-chat-ticker-')) return;
  10771. if (!is.endsWith('-renderer')) return;
  10772. }
  10773.  
  10774. } else {
  10775. if ((p.nodeName || '').includes('BUTTON')) return;
  10776. }
  10777.  
  10778. }
  10779. };
  10780.  
  10781. console.log("CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED - OK")
  10782.  
  10783. } else {
  10784. console.log("CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED - NG")
  10785. }
  10786.  
  10787.  
  10788. })();
  10789.  
  10790. console.log("[End]");
  10791.  
  10792. console.groupEnd();
  10793.  
  10794. }).catch(console.warn);
  10795.  
  10796.  
  10797.  
  10798. if (ENABLE_RAF_HACK_INPUT_RENDERER || DELAY_FOCUSEDCHANGED) {
  10799.  
  10800. customElements.whenDefined("yt-live-chat-message-input-renderer").then(() => {
  10801.  
  10802. mightFirstCheckOnYtInit();
  10803. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-message-input-renderer hacks");
  10804. console.log("[Begin]");
  10805. (() => {
  10806.  
  10807.  
  10808.  
  10809. const tag = "yt-live-chat-message-input-renderer"
  10810. const dummy = document.createElement(tag);
  10811.  
  10812. const cProto = getProto(dummy);
  10813. if (!cProto || !cProto.attached) {
  10814. console.warn(`proto.attached for ${tag} is unavailable.`);
  10815. return;
  10816. }
  10817.  
  10818.  
  10819. if (ENABLE_RAF_HACK_INPUT_RENDERER && rafHub !== null) {
  10820.  
  10821. let doHack = false;
  10822. if (typeof cProto.handleTimeout === 'function' && typeof cProto.updateTimeout === 'function') {
  10823.  
  10824. // not cancellable
  10825.  
  10826. // <<< to be reviewed cProto.updateTimeout --- isTimingFunctionHackable -- doHack >>>
  10827.  
  10828. doHack = fnIntegrity(cProto.handleTimeout, '1.27.16') && fnIntegrity(cProto.updateTimeout, '1.50.33');
  10829.  
  10830. if (!doHack) console.log('doHack = false')
  10831.  
  10832. }
  10833. // doHack = false; // M55
  10834.  
  10835. if (doHack) {
  10836.  
  10837. cProto.handleTimeout = function (a) {
  10838.  
  10839. const cnt = kRef(this);
  10840. if (!cnt) return;
  10841. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10842.  
  10843. console.log('cProto.handleTimeout', tag)
  10844. if (!cnt.boundUpdateTimeout38_) cnt.boundUpdateTimeout38_ = cnt.updateTimeout.bind(mWeakRef(cnt));
  10845. cnt.timeoutDurationMs = cnt.timeoutMs = a;
  10846. cnt.countdownRatio = 1;
  10847. 0 === cnt.lastTimeoutTimeMs && rafHub.request(cnt.boundUpdateTimeout38_)
  10848. };
  10849. cProto.updateTimeout = function (a) {
  10850.  
  10851. const cnt = kRef(this);
  10852. if (!cnt) return;
  10853. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10854.  
  10855. console.log('cProto.updateTimeout', tag)
  10856. if (!cnt.boundUpdateTimeout38_) cnt.boundUpdateTimeout38_ = cnt.updateTimeout.bind(mWeakRef(cnt));
  10857. cnt.lastTimeoutTimeMs && (cnt.timeoutMs = Math.max(0, cnt.timeoutMs - (a - cnt.lastTimeoutTimeMs)),
  10858. cnt.countdownRatio = cnt.timeoutMs / cnt.timeoutDurationMs);
  10859. cnt.isAttached && cnt.timeoutMs ? (cnt.lastTimeoutTimeMs = a,
  10860. rafHub.request(cnt.boundUpdateTimeout38_)) : cnt.lastTimeoutTimeMs = 0
  10861. };
  10862.  
  10863. console.log('RAF_HACK_INPUT_RENDERER', tag, "OK")
  10864. } else {
  10865.  
  10866. console.log('typeof handleTimeout', typeof cProto.handleTimeout)
  10867. console.log('typeof updateTimeout', typeof cProto.updateTimeout)
  10868.  
  10869. console.log('RAF_HACK_INPUT_RENDERER', tag, "NG")
  10870. }
  10871.  
  10872.  
  10873. }
  10874.  
  10875. if (DELAY_FOCUSEDCHANGED && typeof cProto.onFocusedChanged === 'function' && cProto.onFocusedChanged.length === 1 && !cProto.onFocusedChanged372) {
  10876. cProto.onFocusedChanged372 = cProto.onFocusedChanged;
  10877. cProto.onFocusedChanged = function (a) {
  10878. Promise.resolve(this).then((cnt) => {
  10879. if (cnt.isAttached === true) cnt.onFocusedChanged372(a);
  10880. cnt = null;
  10881. }).catch(console.warn);
  10882. }
  10883. }
  10884.  
  10885. })();
  10886.  
  10887. console.log("[End]");
  10888.  
  10889. console.groupEnd();
  10890.  
  10891.  
  10892. })
  10893.  
  10894. }
  10895.  
  10896.  
  10897. if (ENABLE_RAF_HACK_EMOJI_PICKER && rafHub !== null) {
  10898.  
  10899. customElements.whenDefined("yt-emoji-picker-renderer").then(() => {
  10900.  
  10901. mightFirstCheckOnYtInit();
  10902. groupCollapsed("YouTube Super Fast Chat", " | yt-emoji-picker-renderer hacks");
  10903. console.log("[Begin]");
  10904. (() => {
  10905.  
  10906. const tag = "yt-emoji-picker-renderer"
  10907. const dummy = document.createElement(tag);
  10908.  
  10909. const cProto = getProto(dummy);
  10910. if (!cProto || !cProto.attached) {
  10911. console.warn(`proto.attached for ${tag} is unavailable.`);
  10912. return;
  10913. }
  10914.  
  10915. let doHack = false;
  10916. if (typeof cProto.animateScroll_ === 'function') {
  10917.  
  10918. // not cancellable
  10919. console.log('animateScroll_', typeof cProto.animateScroll_)
  10920.  
  10921. doHack = fnIntegrity(cProto.animateScroll_, '1.102.49')
  10922.  
  10923. }
  10924.  
  10925. if (doHack) {
  10926.  
  10927. const querySelector = HTMLElement.prototype.querySelector;
  10928. const U = (element) => ({
  10929. querySelector: (selector) => querySelector.call(element, selector)
  10930. });
  10931.  
  10932. cProto.animateScroll_ = function (a) {
  10933.  
  10934. const cnt = kRef(this);
  10935. if (!cnt) return;
  10936. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10937.  
  10938. // console.log('cProto.animateScroll_', tag) // yt-emoji-picker-renderer
  10939. if (!cnt.boundAnimateScroll39_) cnt.boundAnimateScroll39_ = cnt.animateScroll_.bind(mWeakRef(cnt));
  10940. cnt.lastAnimationTime_ || (cnt.lastAnimationTime_ = a);
  10941. a -= cnt.lastAnimationTime_;
  10942. 200 > a ? (U(cnt.hostElement).querySelector("#categories").scrollTop = cnt.animationStart_ + (cnt.animationEnd_ - cnt.animationStart_) * a / 200,
  10943. rafHub.request(cnt.boundAnimateScroll39_)) : (null != cnt.animationEnd_ && (U(cnt.hostElement).querySelector("#categories").scrollTop = cnt.animationEnd_),
  10944. cnt.animationEnd_ = cnt.animationStart_ = null,
  10945. cnt.lastAnimationTime_ = 0);
  10946. cnt.updateButtons_()
  10947. }
  10948.  
  10949. console.log('ENABLE_RAF_HACK_EMOJI_PICKER', tag, "OK")
  10950. } else {
  10951.  
  10952. console.log('ENABLE_RAF_HACK_EMOJI_PICKER', tag, "NG")
  10953. }
  10954.  
  10955. })();
  10956.  
  10957. console.log("[End]");
  10958.  
  10959. console.groupEnd();
  10960. });
  10961. }
  10962.  
  10963. if (ENABLE_RAF_HACK_DOCKED_MESSAGE && rafHub !== null) {
  10964.  
  10965. customElements.whenDefined("yt-live-chat-docked-message").then(() => {
  10966.  
  10967. mightFirstCheckOnYtInit();
  10968. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-docked-message hacks");
  10969. console.log("[Begin]");
  10970. (() => {
  10971.  
  10972. const tag = "yt-live-chat-docked-message"
  10973. const dummy = document.createElement(tag);
  10974.  
  10975. const cProto = getProto(dummy);
  10976. if (!cProto || !cProto.attached) {
  10977. console.warn(`proto.attached for ${tag} is unavailable.`);
  10978. return;
  10979. }
  10980.  
  10981. let doHack = false;
  10982. if (typeof cProto.detached === 'function' && typeof cProto.checkIntersections === 'function' && typeof cProto.onDockableMessagesChanged === 'function' && typeof cProto.boundCheckIntersections === 'undefined') {
  10983.  
  10984. // cancelable - this.intersectRAF <detached>
  10985. // yt-live-chat-docked-message
  10986. // boundCheckIntersections <-> checkIntersections
  10987. // onDockableMessagesChanged
  10988. // this.intersectRAF = window.requestAnimationFrame(this.boundCheckIntersections);
  10989.  
  10990. console.log('detached', typeof cProto.detached)
  10991. console.log('checkIntersections', typeof cProto.checkIntersections)
  10992. console.log('onDockableMessagesChanged', typeof cProto.onDockableMessagesChanged)
  10993.  
  10994. doHack = fnIntegrity(cProto.detached, '0.32.22') && fnIntegrity(cProto.checkIntersections, '0.128.85') && fnIntegrity(cProto.onDockableMessagesChanged, '0.20.11')
  10995.  
  10996. }
  10997.  
  10998. if (doHack) {
  10999.  
  11000. cProto.__boundCheckIntersectionsSubstitutionFn__ = function () {
  11001. const cnt = this;
  11002. if (!cnt.i5zmk && typeof cnt.boundCheckIntersections === 'function' && typeof cnt.checkIntersections === 'function') {
  11003. cnt.i5zmk = 1
  11004. cnt.boundCheckIntersections = cnt.checkIntersections.bind(mWeakRef(cnt));
  11005. }
  11006. }
  11007.  
  11008. cProto.checkIntersections = function () {
  11009.  
  11010. const cnt = kRef(this);
  11011. if (!cnt) return;
  11012. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  11013.  
  11014. if(typeof cnt.__boundCheckIntersectionsSubstitutionFn__ === 'function') cnt.__boundCheckIntersectionsSubstitutionFn__();
  11015.  
  11016. // console.log('cProto.checkIntersections', tag)
  11017. if (cnt.dockableMessages.length) {
  11018. cnt.intersectRAF = rafHub.request(cnt.boundCheckIntersections);
  11019. let a = cnt.dockableMessages[0]
  11020. , b = cnt.hostElement.getBoundingClientRect();
  11021. a = a.getBoundingClientRect();
  11022. let c = a.top - b.top
  11023. , d = 8 >= c;
  11024. c = 8 >= c - cnt.hostElement.clientHeight;
  11025. if (d) {
  11026. let e;
  11027. for (; d;) {
  11028. e = cnt.dockableMessages.shift();
  11029. d = cnt.dockableMessages[0];
  11030. if (!d)
  11031. break;
  11032. d = d.getBoundingClientRect();
  11033. c = d.top - b.top;
  11034. let f = 8 >= c;
  11035. if (8 >= c - a.height)
  11036. if (f)
  11037. a = d;
  11038. else
  11039. return;
  11040. d = f
  11041. }
  11042. cnt.dock(e)
  11043. } else
  11044. c && cnt.dockedItem && cnt.clear()
  11045. } else
  11046. cnt.intersectRAF = 0
  11047. }
  11048.  
  11049. cProto.onDockableMessagesChanged = function () {
  11050. const cnt = this;
  11051. if(typeof cnt.__boundCheckIntersectionsSubstitutionFn__ === 'function') cnt.__boundCheckIntersectionsSubstitutionFn__();
  11052. // console.log('cProto.onDockableMessagesChanged', tag) // yt-live-chat-docked-message
  11053. cnt.dockableMessages.length && !cnt.intersectRAF && (cnt.intersectRAF = rafHub.request(cnt.boundCheckIntersections))
  11054. }
  11055.  
  11056. cProto.detached = function () {
  11057. this.intersectRAF && rafHub.cancel(this.intersectRAF)
  11058. }
  11059.  
  11060. console.log('ENABLE_RAF_HACK_DOCKED_MESSAGE', tag, "OK")
  11061. } else {
  11062.  
  11063. console.log('ENABLE_RAF_HACK_DOCKED_MESSAGE', tag, "NG")
  11064. }
  11065.  
  11066. })();
  11067.  
  11068. console.log("[End]");
  11069.  
  11070. console.groupEnd();
  11071.  
  11072. }).catch(console.warn);
  11073.  
  11074. }
  11075.  
  11076. if (FIX_SETSRC_AND_THUMBNAILCHANGE_) {
  11077.  
  11078. customElements.whenDefined("yt-img-shadow").then(() => {
  11079.  
  11080. mightFirstCheckOnYtInit();
  11081. groupCollapsed("YouTube Super Fast Chat", " | yt-img-shadow hacks");
  11082. console.log("[Begin]");
  11083. (() => {
  11084.  
  11085. const tag = "yt-img-shadow"
  11086. const dummy = document.createElement(tag);
  11087.  
  11088. const cProto = getProto(dummy);
  11089. if (!cProto || !cProto.attached) {
  11090. console.warn(`proto.attached for ${tag} is unavailable.`);
  11091. return;
  11092. }
  11093.  
  11094. if (typeof cProto.thumbnailChanged_ === 'function' && !cProto.thumbnailChanged66_) {
  11095.  
  11096. cProto.thumbnailChanged66_ = cProto.thumbnailChanged_;
  11097. cProto.thumbnailChanged_ = function (a) {
  11098.  
  11099. if (this.oldThumbnail_ && this.thumbnail && this.oldThumbnail_.thumbnails === this.thumbnail.thumbnails) return;
  11100. if (!this.oldThumbnail_ && !this.thumbnail) return;
  11101.  
  11102. return this.thumbnailChanged66_.apply(this, arguments)
  11103.  
  11104. }
  11105. console.log("cProto.thumbnailChanged_ - OK");
  11106.  
  11107. } else {
  11108. console.log("cProto.thumbnailChanged_ - NG");
  11109.  
  11110. }
  11111. if (typeof cProto.setSrc_ === 'function' && !cProto.setSrc66_) {
  11112.  
  11113. cProto.setSrc66_ = cProto.setSrc_;
  11114. cProto.setSrc_ = function (a) {
  11115. if ((((this || 0).$ || 0).img || 0).src === a) return;
  11116. return this.setSrc66_.apply(this, arguments)
  11117. }
  11118.  
  11119. console.log("cProto.setSrc_ - OK");
  11120. } else {
  11121.  
  11122. console.log("cProto.setSrc_ - NG");
  11123. }
  11124.  
  11125. })();
  11126.  
  11127. console.log("[End]");
  11128.  
  11129. console.groupEnd();
  11130.  
  11131. }).catch(console.warn);
  11132.  
  11133. }
  11134.  
  11135. if (FIX_THUMBNAIL_DATACHANGED) {
  11136.  
  11137. customElements.whenDefined("yt-live-chat-author-badge-renderer").then(() => {
  11138.  
  11139. mightFirstCheckOnYtInit();
  11140. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-author-badge-renderer hacks");
  11141. console.log("[Begin]");
  11142. (() => {
  11143.  
  11144. const tag = "yt-live-chat-author-badge-renderer"
  11145. const dummy = document.createElement(tag);
  11146.  
  11147. const cProto = getProto(dummy);
  11148. if (!cProto || !cProto.attached) {
  11149. console.warn(`proto.attached for ${tag} is unavailable.`);
  11150. return;
  11151. }
  11152.  
  11153. if (typeof cProto.dataChanged === 'function' && !cProto.dataChanged86 && '|0.169.106|'.includes(`|${fnIntegrity(cProto.dataChanged)}|`)) {
  11154.  
  11155. cProto.dataChanged86 = cProto.dataChanged;
  11156. cProto.dataChanged = function () {
  11157.  
  11158. /* 2024.12.15 */
  11159. /*
  11160. zO.prototype.dataChanged = function() {
  11161. for (var a = Ov(R(this.hostElement).querySelector("#image")); a.firstChild; )
  11162. a.removeChild(a.firstChild);
  11163. if (this.data)
  11164. if (this.data.icon) {
  11165. var b = document.createElement("yt-icon");
  11166. this.data.icon.iconType === "MODERATOR" && this.enableNewModeratorBadge ? (b.polymerController.icon = "yt-sys-icons:shield-filled",
  11167. b.polymerController.defaultToFilled = !0) : b.polymerController.icon = "live-chat-badges:" + this.data.icon.iconType.toLowerCase();
  11168. a.appendChild(b)
  11169. } else if (this.data.customThumbnail) {
  11170. b = document.createElement("img");
  11171. var c;
  11172. (c = (c = UA(this.data.customThumbnail.thumbnails, 16)) ? Yb(kc(c)) : null) ? (b.src = c,
  11173. a.appendChild(b),
  11174. b.setAttribute("alt", this.hostElement.ariaLabel || "")) : Fq(new Zn("Could not compute URL for thumbnail",this.data.customThumbnail))
  11175. }
  11176. }
  11177. */
  11178.  
  11179. const a = (this || 0).data;
  11180. const image = ((this || 0).$ || 0).image;
  11181. if (image && a && image.firstElementChild) {
  11182. const exisiting = image.firstElementChild;
  11183. if (exisiting === image.lastElementChild) {
  11184.  
  11185. if (a.icon && exisiting.nodeName.toUpperCase() === 'YT-ICON') {
  11186.  
  11187. const c = exisiting;
  11188. const t = insp(c);
  11189. const w = ('icon' in t || 'defaultToFilled' in t) ? t : c;
  11190. if ("MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge) {
  11191. if (w.icon !== "yt-sys-icons:shield-filled") w.icon = "yt-sys-icons:shield-filled";
  11192. if (w.defaultToFilled !== true) w.defaultToFilled = true;
  11193. } else {
  11194. const p = "live-chat-badges:" + a.icon.iconType.toLowerCase();;
  11195. if (w.icon !== p) w.icon = p;
  11196. if (w.defaultToFilled !== false) w.defaultToFilled = false;
  11197. }
  11198. return;
  11199.  
  11200.  
  11201. } else if (a.customThumbnail && exisiting.nodeName.toUpperCase() == 'IMG') {
  11202.  
  11203. const c = exisiting;
  11204. if (a.customThumbnail.thumbnails.map(e => e.url).includes(c.src)) {
  11205.  
  11206. c.setAttribute("alt", this.hostElement.ariaLabel || "");
  11207. return;
  11208. }
  11209. /*
  11210.  
  11211. var d;
  11212. (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null) ? (c.src = d,
  11213.  
  11214. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : lq(new tm("Could not compute URL for thumbnail", a.customThumbnail))
  11215. */
  11216. }
  11217.  
  11218. }
  11219. }
  11220. return this.dataChanged86.apply(this, arguments)
  11221.  
  11222. }
  11223. console.log("cProto.dataChanged - OK");
  11224.  
  11225. } else if (typeof cProto.dataChanged === 'function' && !cProto.dataChanged86 && '|1.163.100|1.162.100|1.160.97|1.159.97|'.includes(`|${fnIntegrity(cProto.dataChanged)}|`)) {
  11226.  
  11227. cProto.dataChanged86 = cProto.dataChanged;
  11228. cProto.dataChanged = function (a) {
  11229.  
  11230. /*
  11231.  
  11232. for (var b = xC(Z(this.hostElement).querySelector("#image")); b.firstChild; )
  11233. b.removeChild(b.firstChild);
  11234. if (a)
  11235. if (a.icon) {
  11236. var c = document.createElement("yt-icon");
  11237. "MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge ? (c.icon = "yt-sys-icons:shield-filled",
  11238. c.defaultToFilled = !0) : c.icon = "live-chat-badges:" + a.icon.iconType.toLowerCase();
  11239. b.appendChild(c)
  11240. } else if (a.customThumbnail) {
  11241. c = document.createElement("img");
  11242. var d;
  11243. (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null) ? (c.src = d,
  11244. b.appendChild(c),
  11245. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : lq(new tm("Could not compute URL for thumbnail",a.customThumbnail))
  11246. }
  11247.  
  11248. */
  11249.  
  11250.  
  11251. /* 2024.04.20 */
  11252. /*
  11253. for (var b = Tx(N(this.hostElement).querySelector("#image")); b.firstChild; )
  11254. b.removeChild(b.firstChild);
  11255. if (a)
  11256. if (a.icon) {
  11257. var c = document.createElement("yt-icon");
  11258. "MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge ? (c.polymerController.icon = "yt-sys-icons:shield-filled",
  11259. c.polymerController.defaultToFilled = !0) : c.polymerController.icon = "live-chat-badges:" + a.icon.iconType.toLowerCase();
  11260. b.appendChild(c)
  11261. } else if (a.customThumbnail) {
  11262. c = document.createElement("img");
  11263. var d;
  11264. (d = (d = WD(a.customThumbnail.thumbnails, 16)) ? Sb(ec(d)) : null) ? (c.src = d,
  11265. b.appendChild(c),
  11266. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : nr(new mn("Could not compute URL for thumbnail",a.customThumbnail))
  11267. }
  11268. */
  11269.  
  11270. const image = ((this || 0).$ || 0).image
  11271. if (image && a && image.firstElementChild) {
  11272. const exisiting = image.firstElementChild;
  11273. if (exisiting === image.lastElementChild) {
  11274.  
  11275. if (a.icon && exisiting.nodeName.toUpperCase() === 'YT-ICON') {
  11276.  
  11277. const c = exisiting;
  11278. const t = insp(c);
  11279. const w = ('icon' in t || 'defaultToFilled' in t) ? t : c;
  11280. if ("MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge) {
  11281. if (w.icon !== "yt-sys-icons:shield-filled") w.icon = "yt-sys-icons:shield-filled";
  11282. if (w.defaultToFilled !== true) w.defaultToFilled = true;
  11283. } else {
  11284. const p = "live-chat-badges:" + a.icon.iconType.toLowerCase();;
  11285. if (w.icon !== p) w.icon = p;
  11286. if (w.defaultToFilled !== false) w.defaultToFilled = false;
  11287. }
  11288. return;
  11289.  
  11290.  
  11291. } else if (a.customThumbnail && exisiting.nodeName.toUpperCase() == 'IMG') {
  11292.  
  11293. const c = exisiting;
  11294. if (a.customThumbnail.thumbnails.map(e => e.url).includes(c.src)) {
  11295.  
  11296. c.setAttribute("alt", this.hostElement.ariaLabel || "");
  11297. return;
  11298. }
  11299. /*
  11300.  
  11301. var d;
  11302. (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null) ? (c.src = d,
  11303.  
  11304. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : lq(new tm("Could not compute URL for thumbnail", a.customThumbnail))
  11305. */
  11306. }
  11307.  
  11308. }
  11309. }
  11310. return this.dataChanged86.apply(this, arguments)
  11311.  
  11312. }
  11313. console.log("cProto.dataChanged - OK");
  11314.  
  11315. } else {
  11316. assertor(() => fnIntegrity(cProto.dataChanged, '0.169.106'));
  11317. console.log("cProto.dataChanged - NG");
  11318.  
  11319. }
  11320.  
  11321. })();
  11322.  
  11323. console.log("[End]");
  11324.  
  11325. console.groupEnd();
  11326.  
  11327. }).catch(console.warn);
  11328.  
  11329.  
  11330. }
  11331.  
  11332. if (USE_ADVANCED_TICKING) {
  11333. // leading the emoji cannot be rendered.
  11334.  
  11335. // const qz38 = lcrPromiseFn();
  11336.  
  11337. // qz38.then((lcrGet) => {
  11338.  
  11339. // const tag = "yt-live-chat-renderer"
  11340. // const dummy = lcrGet();
  11341.  
  11342. const lcrFn2 = (lcrDummy) => {
  11343.  
  11344. const tag = "yt-live-chat-renderer"
  11345. const dummy = lcrDummy;
  11346.  
  11347.  
  11348. const cProto = getProto(dummy);
  11349.  
  11350. // dummy.usePatchedLifecycles = false;
  11351. // dummy.data = null;
  11352. // dummy.__data = null;
  11353. // Object.setPrototypeOf(dummy, Object.prototype);
  11354. if (!cProto || !cProto.attached) {
  11355. console.warn(`proto.attached for ${tag} is unavailable.`);
  11356. return;
  11357. }
  11358.  
  11359. /*
  11360. <tp-yt-paper-tooltip class="style-scope yt-live-chat-author-badge-renderer" role="tooltip" tabindex="-1" style="--paper-tooltip-delay-in: 0ms; inset: -63.3984px auto auto 0px;
  11361. */
  11362.  
  11363. if (cProto && typeof cProto.immediatelyApplyLiveChatActions === 'function' && cProto.immediatelyApplyLiveChatActions.length === 1 && !cProto.immediatelyApplyLiveChatActions82) {
  11364. cProto.immediatelyApplyLiveChatActions82 = cProto.immediatelyApplyLiveChatActions;
  11365. cProto.immediatelyApplyLiveChatActions = function (arr) {
  11366.  
  11367.  
  11368. // console.log(1237)
  11369. try {
  11370. preprocessChatLiveActions(arr);
  11371. } catch (e) {
  11372. console.warn(e);
  11373. }
  11374. return this.immediatelyApplyLiveChatActions82(arr);
  11375. };
  11376. }
  11377.  
  11378.  
  11379. if (cProto && typeof cProto.preprocessActions_ === 'function' && cProto.preprocessActions_.length === 1 && !cProto.preprocessActions82_) {
  11380. cProto.preprocessActions82_ = cProto.preprocessActions_;
  11381. cProto.preprocessActions_ = function (arr) {
  11382.  
  11383. arr = this.preprocessActions82_(arr);
  11384.  
  11385. try {
  11386. preprocessChatLiveActions(arr);
  11387. } catch (e) {
  11388. console.warn(e);
  11389. }
  11390. return arr;
  11391. };
  11392. }
  11393.  
  11394.  
  11395.  
  11396. };
  11397. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  11398. getLCRDummy().then(lcrFn2);
  11399. }
  11400.  
  11401.  
  11402. if (FIX_TOOLTIP_DISPLAY) {
  11403.  
  11404. // ----------------------------------------------------------------------------------------------------
  11405.  
  11406. const checkPDGet = (pd) => {
  11407. return pd && pd.get && !pd.set && pd.enumerable && pd.configurable;
  11408. }
  11409.  
  11410. const tooltipUIWM = new WeakMap();
  11411. const tooltipInitProps = {};
  11412. const createTooltipIfRequired_ = function () {
  11413. let r;
  11414. if (tooltipUIWM.get(this) === void 0) {
  11415. const w = document.createElement;
  11416. let EU = null;
  11417. tooltipUIWM.set(this, null);
  11418. document.createElement = function () {
  11419. let r = w.apply(this, arguments);
  11420. EU = r;
  11421. return r;
  11422. };
  11423. r = this.createTooltipIfRequired14_();
  11424. document.createElement = w;
  11425. if (EU instanceof HTMLElement && EU.is) {
  11426. tooltipUIWM.set(this, EU);
  11427. EU.setAttribute('__nogc__', ''); // avoid gc process script
  11428.  
  11429. if (typeof EU.offset === 'number') tooltipInitProps['offset'] = EU.offset;
  11430. if (typeof EU.fitToVisibleBounds === 'boolean') tooltipInitProps['fitToVisibleBounds'] = EU.fitToVisibleBounds;
  11431. if (typeof EU.position === 'string') tooltipInitProps['position'] = EU.position;
  11432. if (typeof EU.for === 'string') tooltipInitProps['for'] = EU.for;
  11433.  
  11434. // this.__mcT__ = EU.outerHTML;
  11435. // EU.__dataX = JSON.stringify(EU.__data);
  11436. // EU.__dataY = Object.entries(EU);
  11437.  
  11438. // <<< FOR DEBUG >>>
  11439. // let kx;
  11440. // Object.defineProperty(EU, '_target', {
  11441. // get(){
  11442. // return kx;
  11443. // },
  11444. // set(nv){
  11445. // kx= nv;
  11446. // debugger;
  11447. // return true;
  11448. // }
  11449. // });
  11450. // <<< FOR DEBUG >>>
  11451.  
  11452. if (typeof Polymer !== 'undefined' && Polymer.__fixedGetOwnerRoot__ && Polymer.__fixedQuerySelector__) {
  11453.  
  11454. } else {
  11455. let eProto = null;
  11456. const euCnt = insp(EU);
  11457. if (checkPDGet(Object.getOwnPropertyDescriptor(euCnt.constructor.prototype || {}, 'target'))) {
  11458.  
  11459. eProto = euCnt.constructor.prototype;
  11460. } else if (checkPDGet(Object.getOwnPropertyDescriptor(EU.constructor.prototype || {}, 'target'))) {
  11461.  
  11462. eProto = EU.constructor.prototype;
  11463. }
  11464. if (eProto) {
  11465. delete eProto.target;
  11466. /*
  11467.  
  11468. get target() {
  11469. var a = Pv(this).parentNode, b = Pv(this).getOwnerRoot(), c;
  11470. this.for ? c = Pv(b).querySelector("#" + this.for) : c = a.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? b.host : a;
  11471. return c
  11472. },
  11473. */
  11474. Object.defineProperty(eProto, 'target', {
  11475. get() {
  11476. let a = this.parentNode, b = this.getRootNode();
  11477. return (this.for ? b.querySelector("#" + this.for) : a)
  11478. }
  11479. })
  11480. }
  11481. }
  11482. // setInterval(()=>EU.updatePosition(), 100)
  11483.  
  11484. } else {
  11485. tooltipUIWM.set(this, null);
  11486. }
  11487. } else {
  11488. r = this.createTooltipIfRequired14_();
  11489. }
  11490.  
  11491. const EU = tooltipUIWM.get(this);
  11492. if (EU) {
  11493. EU.remove();
  11494. if (typeof tooltipInitProps.offset === 'number') EU['offset'] = tooltipInitProps.offset;
  11495. if (typeof tooltipInitProps.fitToVisibleBounds === 'boolean') EU['fitToVisibleBounds'] = tooltipInitProps.fitToVisibleBounds;
  11496. try {
  11497. if (typeof tooltipInitProps.position === 'string') EU['position'] = tooltipInitProps.position;
  11498. if (typeof tooltipInitProps.for === 'string') EU['for'] = tooltipInitProps.for; else delete EU.for;
  11499. } catch (e) { }
  11500. }
  11501. return r;
  11502. };
  11503.  
  11504.  
  11505. // added in 2024.05.02
  11506. const lcrFn2 = (lcrDummy) => {
  11507.  
  11508. // console.log(8171, 99);
  11509. const tag = "yt-live-chat-renderer"
  11510. const dummy = lcrDummy;
  11511.  
  11512. const cProto = getProto(dummy);
  11513. if (!cProto || !cProto.attached) {
  11514. console.warn(`proto.attached for ${tag} is unavailable.`);
  11515. return;
  11516. }
  11517.  
  11518. /*
  11519. <tp-yt-paper-tooltip class="style-scope yt-live-chat-author-badge-renderer" role="tooltip" tabindex="-1" style="--paper-tooltip-delay-in: 0ms; inset: -63.3984px auto auto 0px;
  11520. */
  11521.  
  11522. if (cProto && typeof cProto.createTooltipIfRequired_ === 'function' && cProto.createTooltipIfRequired_.length === 0 && !cProto.createTooltipIfRequired14_) {
  11523. cProto.createTooltipIfRequired14_ = cProto.createTooltipIfRequired_;
  11524. cProto.createTooltipIfRequired_ = createTooltipIfRequired_;
  11525. }
  11526.  
  11527. };
  11528. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  11529. getLCRDummy().then(lcrFn2);
  11530.  
  11531. // ----------------------------------------------------------------------------------------------------
  11532.  
  11533. customElements.whenDefined("tp-yt-paper-tooltip").then(() => {
  11534.  
  11535. mightFirstCheckOnYtInit();
  11536. groupCollapsed("YouTube Super Fast Chat", " | tp-yt-paper-tooltip hacks");
  11537. console.log("[Begin]");
  11538. (() => {
  11539.  
  11540. const tag = "tp-yt-paper-tooltip"
  11541. const dummy = document.createElement(tag);
  11542.  
  11543. const cProto = getProto(dummy);
  11544. if (!cProto || !cProto.attached) {
  11545. console.warn(`proto.attached for ${tag} is unavailable.`);
  11546. return;
  11547. }
  11548.  
  11549. if (typeof cProto.attached === 'function' && typeof cProto.detached === 'function' && cProto._readyClients && cProto._attachDom && cProto.ready && !cProto._readyClients43) {
  11550.  
  11551. cProto._readyClients43 = cProto._readyClients;
  11552. cProto._readyClients = function () {
  11553. // console.log(1238)
  11554.  
  11555. let r = cProto._readyClients43.apply(this, arguments);
  11556. if (this.$ && this.$$ && this.$.tooltip) this.root = null; // fix this.root = null != (b = a.root) ? b : this.host
  11557. return r;
  11558. }
  11559.  
  11560. console.log("_readyClients - OK");
  11561.  
  11562. } else {
  11563. console.log("_readyClients - NG");
  11564.  
  11565. }
  11566.  
  11567. if (typeof cProto.show === 'function' && !cProto.show17) {
  11568. cProto.show17 = cProto.show;
  11569. cProto.show = function () {
  11570.  
  11571. let r = this.show17.apply(this, arguments);
  11572. this._showing === true && Promise.resolve(this).then((cnt) => {
  11573. const tooltip = (cnt.$ || 0).tooltip;
  11574.  
  11575. if (tooltip && tooltip.firstElementChild === null) {
  11576. let text = tooltip.textContent;
  11577. if (typeof text === 'string' && text.length >= 2) {
  11578. tooltip.textContent = text.trim();
  11579. }
  11580. }
  11581. cnt = null;
  11582. }).catch(console.warn)
  11583. return r;
  11584. }
  11585.  
  11586. console.log("trim tooltip content - OK");
  11587.  
  11588. } else {
  11589. console.log("trim tooltip content - NG");
  11590.  
  11591. }
  11592.  
  11593.  
  11594. })();
  11595.  
  11596. console.log("[End]");
  11597.  
  11598. console.groupEnd();
  11599.  
  11600. }).catch(console.warn);
  11601.  
  11602. }
  11603.  
  11604.  
  11605. if (FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK) {
  11606.  
  11607. const hookDocumentMouseDownSetupFn = () => {
  11608.  
  11609. let muzTimestamp = 0;
  11610. let nszDropdown = null;
  11611.  
  11612. const handlerObject = {
  11613.  
  11614. muHandler282: function (evt) {
  11615. // console.log(evt, 7, document.querySelector('tp-yt-iron-dropdown[focused].style-scope.yt-live-chat-app'))
  11616. if (!evt || !evt.isTrusted || !muzTimestamp) return;
  11617. const dropdown = nszDropdown;
  11618. muzTimestamp = 0;
  11619. nszDropdown = null;
  11620.  
  11621. const kurMPCe = kRef(currentMenuPivotWR) || 0;
  11622. const hostElement = kurMPCe.hostElement || kurMPCe; // should be always hostElement === kurMPCe ?
  11623. if (!hostElement.hasAttribute('menu-visible')) return;
  11624.  
  11625. const chatBanner = HTMLElement.prototype.closest.call(hostElement, 'yt-live-chat-banner-renderer') || 0;
  11626. if (chatBanner) return;
  11627.  
  11628. if (dropdown && dropdown.positionTarget && hostElement.contains(dropdown.positionTarget)) {
  11629. muzTimestamp = Date.now();
  11630. evt.stopImmediatePropagation();
  11631. evt.stopPropagation();
  11632. Promise.resolve(dropdown).then((dropdown) => {
  11633. dropdown.cancel();
  11634. dropdown = null;
  11635. });
  11636. }
  11637.  
  11638. },
  11639.  
  11640. mlHandler282: function (evt) {
  11641. muzTimestamp = 0;
  11642. nszDropdown = null;
  11643. },
  11644.  
  11645. ckHandler282: function (evt) {
  11646. if (!evt || !evt.isTrusted || !muzTimestamp) return;
  11647. if (Date.now() - muzTimestamp < 40) {
  11648. muzTimestamp = Date.now();
  11649. evt.stopImmediatePropagation();
  11650. evt.stopPropagation();
  11651. }
  11652. },
  11653.  
  11654. tapHandler282: function (evt) {
  11655. if (!evt || !evt.isTrusted || !muzTimestamp) return;
  11656. if (Date.now() - muzTimestamp < 40) {
  11657. muzTimestamp = Date.now();
  11658. evt.stopImmediatePropagation();
  11659. evt.stopPropagation();
  11660. }
  11661. },
  11662.  
  11663. handleEvent(evt) {
  11664. if (evt) {
  11665. const kurMPCe = kRef(currentMenuPivotWR) || 0;
  11666. const kurMPCc = insp(kurMPCe);
  11667. const hostElement = kurMPCc.hostElement || kurMPCc;
  11668. if (!kurMPCc || kurMPCc.isAttached !== true || hostElement.isConnected !== true) return;
  11669. switch (evt.type) {
  11670. case 'mouseup':
  11671. return this.muHandler282(evt);
  11672. case 'mouseleave':
  11673. return this.mlHandler282(evt);
  11674. case 'tap':
  11675. return this.tapHandler282(evt);
  11676. case 'click':
  11677. return this.ckHandler282(evt);
  11678. }
  11679. }
  11680. }
  11681.  
  11682. }
  11683.  
  11684. document.addEventListener('mousedown', function (evt) {
  11685.  
  11686. if (!evt || !evt.isTrusted || !evt.target) return;
  11687.  
  11688. muzTimestamp = 0;
  11689. nszDropdown = null;
  11690.  
  11691. /** @type {HTMLElement | null} */
  11692. const kurMP = kRef(currentMenuPivotWR);
  11693. if (!kurMP) return;
  11694. const kurMPCe = HTMLElement.prototype.closest.call(kurMP, '[menu-visible]') || 0; // element
  11695.  
  11696. if (!kurMPCe || !kurMPCe.hasAttribute('whole-message-clickable')) return;
  11697.  
  11698. const kurMPCc = insp(kurMPCe); // controller
  11699.  
  11700. if (!kurMPCc.isClickableChatRow111 || !kurMPCc.isClickableChatRow111() || !HTMLElement.prototype.contains.call(kurMPCe, evt.target)) return;
  11701.  
  11702. const chatBanner = HTMLElement.prototype.closest.call(kurMPCe, 'yt-live-chat-banner-renderer') || 0;
  11703. if (chatBanner) return;
  11704.  
  11705. let targetDropDown = null;
  11706. for (const dropdown of document.querySelectorAll('tp-yt-iron-dropdown.style-scope.yt-live-chat-app')) {
  11707. if (dropdown && dropdown.positionTarget === kurMP) {
  11708. targetDropDown = dropdown;
  11709. }
  11710. }
  11711.  
  11712. if (!targetDropDown) return;
  11713.  
  11714. if ((nszDropdown = targetDropDown)) {
  11715. muzTimestamp = Date.now();
  11716. evt.stopImmediatePropagation();
  11717. evt.stopPropagation();
  11718. currentMenuPivotWR = mWeakRef(kurMPCe);
  11719.  
  11720. const listenOpts = { capture: true, passive: false, once: true };
  11721.  
  11722. // remove unexcecuted eventHandler
  11723. document.removeEventListener('mouseup', handlerObject, listenOpts);
  11724. document.removeEventListener('mouseleave', handlerObject, listenOpts);
  11725. document.removeEventListener('tap', handlerObject, listenOpts);
  11726. document.removeEventListener('click', handlerObject, listenOpts);
  11727.  
  11728. // inject one time eventHandler to by pass events
  11729. document.addEventListener('mouseup', handlerObject, listenOpts);
  11730. document.addEventListener('mouseleave', handlerObject, listenOpts);
  11731. document.addEventListener('tap', handlerObject, listenOpts);
  11732. document.addEventListener('click', handlerObject, listenOpts);
  11733.  
  11734. }
  11735.  
  11736. }, true);
  11737.  
  11738. }
  11739.  
  11740.  
  11741. // yt-live-chat-paid-message-renderer ??
  11742.  
  11743. /*
  11744.  
  11745. [...(new Set([...document.querySelectorAll('*')].filter(e=>e.is&&('shouldSupportWholeItemClick' in e)).map(e=>e.is))).keys()]
  11746.  
  11747.  
  11748. "yt-live-chat-ticker-paid-message-item-renderer"
  11749. "yt-live-chat-ticker-paid-sticker-item-renderer"
  11750. "yt-live-chat-paid-message-renderer"
  11751. "yt-live-chat-text-message-renderer"
  11752. "yt-live-chat-paid-sticker-renderer"
  11753.  
  11754. */
  11755.  
  11756.  
  11757. whenDefinedMultiple([
  11758.  
  11759. "yt-live-chat-paid-message-renderer",
  11760. "yt-live-chat-membership-item-renderer",
  11761. "yt-live-chat-paid-sticker-renderer",
  11762. "yt-live-chat-text-message-renderer",
  11763. "yt-live-chat-auto-mod-message-renderer",
  11764.  
  11765. /*
  11766. "yt-live-chat-ticker-paid-message-item-renderer",
  11767. "yt-live-chat-ticker-paid-sticker-item-renderer",
  11768. "yt-live-chat-paid-message-renderer",
  11769. "yt-live-chat-text-message-renderer",
  11770. "yt-live-chat-paid-sticker-renderer",
  11771.  
  11772. "yt-live-chat-ticker-sponsor-item-renderer",
  11773. "yt-live-chat-banner-header-renderer",
  11774. "ytd-sponsorships-live-chat-gift-purchase-announcement-renderer",
  11775. "ytd-sponsorships-live-chat-header-renderer",
  11776. "ytd-sponsorships-live-chat-gift-redemption-announcement-renderer",
  11777.  
  11778.  
  11779.  
  11780.  
  11781. "yt-live-chat-auto-mod-message-renderer",
  11782. "yt-live-chat-text-message-renderer",
  11783. "yt-live-chat-paid-message-renderer",
  11784.  
  11785. "yt-live-chat-legacy-paid-message-renderer",
  11786. "yt-live-chat-membership-item-renderer",
  11787. "yt-live-chat-paid-sticker-renderer",
  11788. "yt-live-chat-donation-announcement-renderer",
  11789. "yt-live-chat-moderation-message-renderer",
  11790. "ytd-sponsorships-live-chat-gift-purchase-announcement-renderer",
  11791. "ytd-sponsorships-live-chat-gift-redemption-announcement-renderer",
  11792. "yt-live-chat-viewer-engagement-message-renderer",
  11793.  
  11794. */
  11795.  
  11796.  
  11797. ]).then(sTags => {
  11798. // return; // M33
  11799.  
  11800. if (FLAG_001e) return;
  11801.  
  11802. mightFirstCheckOnYtInit();
  11803. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-message-renderer(s)... hacks");
  11804. console.log("[Begin]");
  11805. let doMouseHook = false;
  11806.  
  11807. const dProto = {
  11808. isClickableChatRow111: function () {
  11809. return (
  11810. this.data && typeof this.shouldSupportWholeItemClick === 'function' && typeof this.hasModerationOverlayVisible === 'function' &&
  11811. this.data.contextMenuEndpoint && this.wholeMessageClickable && this.shouldSupportWholeItemClick() && !this.hasModerationOverlayVisible()
  11812. ); // follow .onItemTap(a)
  11813. }
  11814. };
  11815.  
  11816. for (const sTag of sTags) { // ##tag##
  11817.  
  11818.  
  11819. (() => {
  11820.  
  11821. const tag = sTag;
  11822. const dummy = document.createElement(tag);
  11823.  
  11824. const cProto = getProto(dummy);
  11825. if (!cProto || !cProto.attached) {
  11826. console.warn(`proto.attached for ${tag} is unavailable.`);
  11827. return;
  11828. }
  11829.  
  11830. const dCnt = insp(dummy);
  11831. if ('wholeMessageClickable' in dCnt && typeof dCnt.hasModerationOverlayVisible === 'function' && typeof dCnt.shouldSupportWholeItemClick === 'function') {
  11832.  
  11833. cProto.isClickableChatRow111 = dProto.isClickableChatRow111;
  11834.  
  11835. const toHookDocumentMouseDown = typeof cProto.shouldSupportWholeItemClick === 'function' && typeof cProto.hasModerationOverlayVisible === 'function';
  11836.  
  11837. if (toHookDocumentMouseDown) {
  11838. doMouseHook = true;
  11839. }
  11840.  
  11841. console.log("shouldSupportWholeItemClick Y", tag);
  11842.  
  11843. } else {
  11844.  
  11845. console.log("shouldSupportWholeItemClick N", tag);
  11846. }
  11847.  
  11848.  
  11849. })();
  11850.  
  11851. }
  11852.  
  11853.  
  11854. if (doMouseHook) {
  11855.  
  11856. hookDocumentMouseDownSetupFn();
  11857.  
  11858. console.log("FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK - Doc MouseEvent OK");
  11859. }
  11860.  
  11861. console.log("[End]");
  11862.  
  11863. console.groupEnd();
  11864.  
  11865.  
  11866. }).catch(console.warn);
  11867.  
  11868.  
  11869. // https://www.youtube.com/watch?v=oQzFi1NO7io
  11870.  
  11871.  
  11872. }
  11873.  
  11874. if (NO_ITEM_TAP_FOR_NON_STATIONARY_TAP) {
  11875. let targetElementCntWR = null;
  11876. let _e0 = null;
  11877. document.addEventListener('mousedown', (e) => {
  11878. if (!e || !e.isTrusted) return;
  11879. let element = e.target;
  11880. for (; element instanceof HTMLElement; element = element.parentNode) {
  11881. if (element.is) break;
  11882. }
  11883. if (!element || !element.is) return;
  11884. const cnt = insp(element);
  11885. if (typeof cnt.onItemTap === 'function') {
  11886. cnt._onItemTap_isNonStationary = 0;
  11887. const cProto = getProto(element);
  11888. if (!cProto.onItemTap366 && typeof cProto.onItemTap === 'function' && cProto.onItemTap.length === 1) {
  11889. cProto.onItemTap366 = cProto.onItemTap; // note: [onItemTap] .some(function(){...})
  11890. cProto.onItemTap = function (a) {
  11891. const t = this._onItemTap_isNonStationary;
  11892. this._onItemTap_isNonStationary = 0;
  11893. if (t > Date.now()) return;
  11894. return this.onItemTap366.apply(this, arguments)
  11895. }
  11896. }
  11897. _e0 = e;
  11898. targetElementCntWR = mWeakRef(cnt);
  11899. } else {
  11900. _e0 = null;
  11901. targetElementCntWR = null;
  11902. }
  11903. }, { capture: true, passive: true });
  11904.  
  11905. document.addEventListener('mouseup', (e) => {
  11906. if (!e || !e.isTrusted) return;
  11907. const e0 = _e0;
  11908. _e0 = null;
  11909. if (!e0) return;
  11910. const cnt = kRef(targetElementCntWR);
  11911. targetElementCntWR = null;
  11912. if (!cnt) return;
  11913. if (e.timeStamp - e0.timeStamp > TAP_ACTION_DURATION) {
  11914. cnt._onItemTap_isNonStationary = Date.now() + 40;
  11915. } else if ((window.getSelection() + "").trim().replace(/[\u2000-\u200a\u202f\u2800\u200B\u200C\u200D\uFEFF]+/g, '').length >= 1) {
  11916. cnt._onItemTap_isNonStationary = Date.now() + 40;
  11917. } else {
  11918. const dx = e.clientX - e0.clientX;
  11919. const dy = e.clientY - e0.clientY;
  11920. const dd = Math.sqrt(dx * dx + dy * dy);
  11921. const ddmm = px2mm(dd);
  11922. if (ddmm > 1.0) {
  11923. cnt._onItemTap_isNonStationary = Date.now() + 40;
  11924. } else {
  11925. cnt._onItemTap_isNonStationary = 0;
  11926. }
  11927. }
  11928. }, { capture: true, passive: true });
  11929.  
  11930. }
  11931.  
  11932.  
  11933. const __showContextMenu_assign_lock_with_external_unlock_ = function (targetCnt) {
  11934.  
  11935. let rr = null;
  11936. const p1 = new Promise(resolve => {
  11937. rr = resolve;
  11938. });
  11939.  
  11940. const p1unlock = () => {
  11941. const f = rr;
  11942. if (f) {
  11943. rr = null;
  11944. f();
  11945. }
  11946. }
  11947.  
  11948. return {
  11949. p1,
  11950. p1unlock,
  11951. assignLock: (targetCnt, timeout) => {
  11952. targetCnt.__showContextMenu_assign_lock__(p1);
  11953. if (timeout) setTimeout(p1unlock, timeout);
  11954. }
  11955. }
  11956.  
  11957. }
  11958.  
  11959. if (PREREQUEST_CONTEXT_MENU_ON_MOUSE_DOWN) {
  11960.  
  11961. document.addEventListener('mousedown', function (evt) {
  11962.  
  11963. const maxloopDOMTreeElements = 4;
  11964. const maxloopYtCompontents = 4;
  11965. let j1 = 0;
  11966. let j2 = 0;
  11967. let target = (evt || 0).target || 0;
  11968. if (!target) return;
  11969.  
  11970.  
  11971. while (target instanceof HTMLElement) {
  11972. if (++j1 > maxloopDOMTreeElements) break;
  11973. if (typeof (target.is || insp(target).is || null) === 'string') break;
  11974. target = nodeParent(target);
  11975. }
  11976. const components = [];
  11977. while (target instanceof HTMLElement) {
  11978. if (++j2 > maxloopYtCompontents) break;
  11979. const cnt = insp(target);
  11980. if (typeof (target.is || cnt.is || null) === 'string') {
  11981. components.push(target);
  11982. }
  11983. if (typeof cnt.showContextMenu === 'function') break;
  11984. target = target.parentComponent || cnt.parentComponent || null;
  11985. }
  11986. if (!(target instanceof HTMLElement)) return;
  11987. const targetCnt = insp(target);
  11988. if (typeof targetCnt.handleGetContextMenuResponse_ !== 'function' || typeof targetCnt.handleGetContextMenuError !== 'function') {
  11989. console.log('Error Found: handleGetContextMenuResponse_ OR handleGetContextMenuError is not defined on a component with showContextMenu')
  11990. return;
  11991. }
  11992.  
  11993. const endpoint = (targetCnt.data || 0).contextMenuEndpoint
  11994. if (!endpoint) return;
  11995. if (targetCnt.opened || !targetCnt.isAttached) return;
  11996.  
  11997. if (typeof targetCnt.__cacheResolvedEndpointData__ !== 'function') {
  11998. console.log(`preRequest for showContextMenu in ${targetCnt.is} is not yet supported.`)
  11999. }
  12000.  
  12001. const targetDollar = indr(target);
  12002.  
  12003. let doPreRequest = false;
  12004. if (components.length >= 2 && components[0].id === 'menu-button' && (targetDollar || 0)['menu-button'] === components[0]) {
  12005. doPreRequest = true;
  12006. } else if (components.length === 1 && components[0] === target) {
  12007. doPreRequest = true;
  12008. } else if (components.length >= 2 && components[0].id === 'author-photo' && (targetDollar || 0)['author-photo'] === components[0]) {
  12009. doPreRequest = true;
  12010. }
  12011. if (doPreRequest === false) {
  12012. console.log('doPreRequest = fasle on showContextMenu', components);
  12013. return;
  12014. }
  12015.  
  12016. if (typeof targetCnt.__getCachedEndpointData__ !== 'function' || targetCnt.__getCachedEndpointData__(endpoint)) return;
  12017.  
  12018. if ((typeof targetCnt.__showContextMenu_mutex_unlock_isEmpty__ === 'function') && !targetCnt.__showContextMenu_mutex_unlock_isEmpty__()) {
  12019. console.log('preRequest on showContextMenu aborted due to stacked network request');
  12020. return;
  12021. }
  12022.  
  12023.  
  12024. const onSuccess = (a) => {
  12025. /*
  12026.  
  12027. dQ() && (a = a.response);
  12028. a.liveChatItemContextMenuSupportedRenderers && a.liveChatItemContextMenuSupportedRenderers.menuRenderer && this.showContextMenu_(a.liveChatItemContextMenuSupportedRenderers.menuRenderer);
  12029. a.actions && Eu(this.hostElement, "yt-live-chat-actions", [a.actions])
  12030.  
  12031. */
  12032.  
  12033. a = a.response || a;
  12034.  
  12035. if (!a) {
  12036. console.log('unexpected error in prerequest for showContextMenu.onSuccess');
  12037. return;
  12038. }
  12039.  
  12040. let z = null;
  12041. a.liveChatItemContextMenuSupportedRenderers && a.liveChatItemContextMenuSupportedRenderers.menuRenderer && (z = a.liveChatItemContextMenuSupportedRenderers.menuRenderer);
  12042.  
  12043. if (z) {
  12044. a = z;
  12045. targetCnt.__cacheResolvedEndpointData__(endpoint, a, true);
  12046. }
  12047.  
  12048. };
  12049. const onFailure = (a) => {
  12050.  
  12051. /*
  12052.  
  12053. if (a instanceof Error || a instanceof Object || a instanceof String)
  12054. var b = a;
  12055. hq(new xm("Error encountered calling GetLiveChatItemContextMenu",b))
  12056.  
  12057. */
  12058.  
  12059. targetCnt.__cacheResolvedEndpointData__(endpoint, null);
  12060. // console.log('onFailure', a)
  12061.  
  12062. };
  12063.  
  12064. if (doPreRequest) {
  12065.  
  12066. let propertyCounter = 0;
  12067. const pm1 = __showContextMenu_assign_lock_with_external_unlock_(targetCnt);
  12068. const p1Timeout = 800;
  12069. const proxyKey = '__$$__proxy_to_this__$$__' + Date.now();
  12070.  
  12071. try {
  12072.  
  12073. const onSuccessHelperFn = function () {
  12074. pm1.p1unlock();
  12075. if (propertyCounter !== 5) {
  12076. console.log('Error in prerequest for showContextMenu.onSuccessHelperFn')
  12077. return;
  12078. }
  12079. if (this[proxyKey] !== targetCnt) {
  12080. console.log('Error in prerequest for showContextMenu.this');
  12081. return;
  12082. }
  12083. onSuccess(...arguments);
  12084. };
  12085. const onFailureHelperFn = function () {
  12086. pm1.p1unlock();
  12087. if (propertyCounter !== 5) {
  12088. console.log('Error in prerequest for showContextMenu.onFailureHelperFn')
  12089. return;
  12090. }
  12091. if (this[proxyKey] !== targetCnt) {
  12092. console.log('Error in prerequest for showContextMenu.this');
  12093. return;
  12094. }
  12095. onFailure(...arguments);
  12096.  
  12097. }
  12098. const fakeTargetCnt = new Proxy({
  12099. __showContextMenu_forceNativeRequest__: 1,
  12100. get handleGetContextMenuResponse_() {
  12101. propertyCounter += 2;
  12102. return onSuccessHelperFn;
  12103. },
  12104. get handleGetContextMenuError() {
  12105. propertyCounter += 3;
  12106. return onFailureHelperFn;
  12107. }
  12108. }, {
  12109. get(_, key, receiver) {
  12110. if (key in _) return _[key];
  12111. if (key === proxyKey) return targetCnt;
  12112.  
  12113. let giveNative = false;
  12114. if (key in targetCnt) {
  12115. if (key === 'data') giveNative = true;
  12116. else if (typeof targetCnt[key] === 'function') giveNative = true;
  12117. }
  12118. if (giveNative) return targetCnt[key];
  12119. }
  12120. });
  12121.  
  12122. const fakeEvent = (() => {
  12123. const { target, bubbles, cancelable, cancelBubble, srcElement, timeStamp, defaultPrevented, currentTarget, composed } = evt;
  12124. const nf = function () { }
  12125. const [stopPropagation, stopImmediatePropagation, preventDefault] = [nf, nf, nf];
  12126.  
  12127. return {
  12128. type: 'tap',
  12129. eventPhase: 0,
  12130. isTrusted: false,
  12131. __composed: true,
  12132. bubbles, cancelable, cancelBubble, timeStamp,
  12133. target, srcElement, defaultPrevented, currentTarget, composed,
  12134. stopPropagation, stopImmediatePropagation, preventDefault
  12135. };
  12136. })(evt);
  12137. targetCnt.showContextMenu.call(fakeTargetCnt, fakeEvent);
  12138.  
  12139.  
  12140. } catch (e) {
  12141. console.warn(e);
  12142. propertyCounter = 7;
  12143.  
  12144. }
  12145. if (propertyCounter !== 5) {
  12146. console.log('Error in prerequest for showContextMenu', propertyCounter);
  12147. return;
  12148. }
  12149.  
  12150. pm1.assignLock(targetCnt, p1Timeout);
  12151.  
  12152. }
  12153.  
  12154.  
  12155.  
  12156.  
  12157.  
  12158.  
  12159. }, true);
  12160.  
  12161.  
  12162. }
  12163.  
  12164.  
  12165.  
  12166. /*
  12167.  
  12168. const w=new Set(); for(const a of document.getElementsByTagName('*')) if(a.showContextMenu && a.showContextMenu_) w.add(a.is||''); console.log([...w.keys()])
  12169.  
  12170. */
  12171.  
  12172. whenDefinedMultiple([
  12173. "yt-live-chat-ticker-sponsor-item-renderer",
  12174. "yt-live-chat-ticker-paid-message-item-renderer",
  12175.  
  12176. "yt-live-chat-banner-header-renderer",
  12177. "yt-live-chat-text-message-renderer",
  12178. "ytd-sponsorships-live-chat-gift-purchase-announcement-renderer",
  12179. "ytd-sponsorships-live-chat-header-renderer",
  12180. "ytd-sponsorships-live-chat-gift-redemption-announcement-renderer",
  12181.  
  12182. "yt-live-chat-paid-sticker-renderer",
  12183. "yt-live-chat-viewer-engagement-message-renderer",
  12184. "yt-live-chat-paid-message-renderer"
  12185.  
  12186.  
  12187.  
  12188.  
  12189. ]).then(sTags => {
  12190.  
  12191. if (FLAG_001f) return;
  12192.  
  12193. mightFirstCheckOnYtInit();
  12194. groupCollapsed("YouTube Super Fast Chat", " | fixShowContextMenu");
  12195. console.log("[Begin]");
  12196.  
  12197.  
  12198. const __showContextMenu_mutex__ = new Mutex();
  12199. let __showContextMenu_mutex_unlock__ = null;
  12200. let lastShowMenuTarget = null;
  12201.  
  12202.  
  12203.  
  12204.  
  12205. const wm37 = new WeakMap();
  12206.  
  12207. const dProto = {
  12208.  
  12209.  
  12210. // CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN
  12211.  
  12212. __cacheResolvedEndpointData__: (endpoint, a, doDeepCopy) => {
  12213. if (a) {
  12214. if (doDeepCopy) a = deepCopy(a);
  12215. wm37.set(endpoint, a);
  12216. } else {
  12217. wm37.remove(endpoint);
  12218. }
  12219. },
  12220. __getCachedEndpointData__: function (endpoint) {
  12221. endpoint = endpoint || (this.data || 0).contextMenuEndpoint || 0;
  12222. if (endpoint) return wm37.get(endpoint);
  12223. return null;
  12224. },
  12225. /** @type {(resolvedEndpoint: any) => void 0} */
  12226. __showCachedContextMenu__: function (resolvedEndpoint) { // non-null
  12227.  
  12228. resolvedEndpoint = deepCopy(resolvedEndpoint);
  12229. // let b = deepCopy(resolvedEndpoint, ['trackingParams', 'clickTrackingParams'])
  12230. Promise.resolve(resolvedEndpoint).then((resolvedEndpoint) => {
  12231. this.__showContextMenu_skip_cacheResolvedEndpointData__ = 1;
  12232. this.showContextMenu_(resolvedEndpoint);
  12233. this.__showContextMenu_skip_cacheResolvedEndpointData__ = 0;
  12234. resolvedEndpoint = null;
  12235. });
  12236.  
  12237.  
  12238. },
  12239.  
  12240.  
  12241.  
  12242. showContextMenuForCacheReopen: function (a) {
  12243. if (this && this.__showContextMenu_forceNativeRequest__) return this.showContextMenu37(a);
  12244. if (!this || !this.isAttached) return; // in case; avoid Error: No provider for: InjectionToken(NETWORK_TOKEN) in _.showContextMenu
  12245. if (!this.__showContextMenu_forceNativeRequest__) {
  12246. const endpoint = (this.data || 0).contextMenuEndpoint || 0;
  12247. if (endpoint) {
  12248. const resolvedEndpoint = this.__getCachedEndpointData__(endpoint);
  12249. if (resolvedEndpoint) {
  12250. this.__showCachedContextMenu__(resolvedEndpoint);
  12251. a && a.stopPropagation()
  12252. return;
  12253. }
  12254. }
  12255. }
  12256. return this.showContextMenu37(a);
  12257. },
  12258.  
  12259. showContextMenuForCacheReopen_: function (a) {
  12260. if (this && this.__showContextMenu_forceNativeRequest__) return this.showContextMenu37_(a);
  12261. if (!this || !this.isAttached) return; // in case; avoid Error: No provider for: InjectionToken(NETWORK_TOKEN) in _.showContextMenu
  12262. if (!this.__showContextMenu_skip_cacheResolvedEndpointData__) {
  12263. const endpoint = (this.data || 0).contextMenuEndpoint || 0;
  12264. if (endpoint) {
  12265. const f = this.__cacheResolvedEndpointData__;
  12266. if (typeof f === 'function') f(endpoint, a, true);
  12267. }
  12268. }
  12269. return this.showContextMenu37_(a);
  12270. },
  12271.  
  12272. // ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU
  12273.  
  12274. showContextMenuWithDisableScroll: function (a) {
  12275.  
  12276. const endpoint = (this.data || 0).contextMenuEndpoint || 0;
  12277. if (endpoint && typeof this.is === 'string' && this.menuVisible === false && this.menuOpen === false) {
  12278.  
  12279. const parentComponent = this.parentComponent;
  12280. if (parentComponent && parentComponent.is === 'yt-live-chat-item-list-renderer' && parentComponent.contextMenuOpen === false && parentComponent.allowScroll === true) {
  12281. parentComponent.contextMenuOpen = true; // computeAllowScroll_(contextMenuOpen, moderationModeEnabled): allowScroll = !(contextMenuOpen || moderationModeEnabled)
  12282. }
  12283. }
  12284.  
  12285. return this.showContextMenu48.apply(this, arguments);
  12286.  
  12287. },
  12288.  
  12289. // ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU
  12290.  
  12291. __showContextMenu_mutex_unlock_isEmpty__: () => {
  12292. return __showContextMenu_mutex_unlock__ === null;
  12293. },
  12294.  
  12295. __showContextMenu_assign_lock__: function (p) {
  12296.  
  12297. const mutex = __showContextMenu_mutex__;
  12298.  
  12299. mutex.lockWith(unlock => {
  12300. p.then(unlock);
  12301. p = null;
  12302. unlock = null;
  12303. });
  12304.  
  12305. },
  12306.  
  12307. showContextMenuWithMutex: function (a) {
  12308. if (this.__showContextMenu_forceNativeRequest__) return this.showContextMenu47(a);
  12309. if (!this || !this.isAttached) return; // in case; avoid Error: No provider for: InjectionToken(NETWORK_TOKEN) in _.showContextMenu
  12310. lastShowMenuTarget = this;
  12311. const wNode = mWeakRef(this);
  12312.  
  12313.  
  12314. const mutex = __showContextMenu_mutex__;
  12315.  
  12316. mutex.lockWith(unlock => {
  12317. const cnt = kRef(wNode);
  12318. if (lastShowMenuTarget !== cnt || !cnt) {
  12319. unlock();
  12320. return;
  12321. }
  12322.  
  12323. setTimeout(unlock, 800); // in case network failure
  12324. __showContextMenu_mutex_unlock__ = unlock;
  12325. try {
  12326. cnt.showContextMenu47(a);
  12327. } catch (e) {
  12328. console.warn(e);
  12329. unlock(); // in case function script error
  12330. }
  12331.  
  12332. });
  12333.  
  12334.  
  12335. },
  12336.  
  12337. showContextMenuWithMutex_: function (a) {
  12338.  
  12339. if (__showContextMenu_mutex_unlock__ && this === lastShowMenuTarget) {
  12340. __showContextMenu_mutex_unlock__();
  12341. __showContextMenu_mutex_unlock__ = null;
  12342. }
  12343. return this.showContextMenu47_(a);
  12344.  
  12345. }
  12346.  
  12347. }
  12348.  
  12349. for (const tag of sTags) { // ##tag##
  12350.  
  12351. (() => {
  12352.  
  12353. const dummy = document.createElement(tag);
  12354.  
  12355. const cProto = getProto(dummy);
  12356. if (!cProto || !cProto.attached) {
  12357. console.warn(`proto.attached for ${tag} is unavailable.`);
  12358. return;
  12359. }
  12360.  
  12361.  
  12362. if (CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN && typeof cProto.showContextMenu === 'function' && typeof cProto.showContextMenu_ === 'function' && !cProto.showContextMenu37 && !cProto.showContextMenu37_ && cProto.showContextMenu.length === 1 && cProto.showContextMenu_.length === 1) {
  12363. cProto.showContextMenu37_ = cProto.showContextMenu_;
  12364. cProto.showContextMenu37 = cProto.showContextMenu;
  12365. cProto.__showContextMenu_forceNativeRequest__ = 0;
  12366. cProto.__cacheResolvedEndpointData__ = dProto.__cacheResolvedEndpointData__
  12367. cProto.__getCachedEndpointData__ = dProto.__getCachedEndpointData__
  12368. cProto.__showCachedContextMenu__ = dProto.__showCachedContextMenu__
  12369. cProto.showContextMenu = dProto.showContextMenuForCacheReopen;
  12370. cProto.showContextMenu_ = dProto.showContextMenuForCacheReopen_;
  12371. console.log("CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN - OK", tag);
  12372. } else {
  12373. console.log("CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN - NG", tag);
  12374. }
  12375.  
  12376. if (ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU && typeof cProto.showContextMenu === 'function' && typeof cProto.showContextMenu_ === 'function' && !cProto.showContextMenu48 && !cProto.showContextMenu48_ && cProto.showContextMenu.length === 1 && cProto.showContextMenu_.length === 1) {
  12377. cProto.showContextMenu48 = cProto.showContextMenu;
  12378. cProto.showContextMenu = dProto.showContextMenuWithDisableScroll;
  12379. console.log("ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU - OK", tag);
  12380. } else if (!ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU) {
  12381. console.log("ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU - N/A", tag);
  12382. } else {
  12383. console.log("ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU - NG", tag);
  12384. }
  12385.  
  12386.  
  12387. if (ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU && typeof cProto.showContextMenu === 'function' && typeof cProto.showContextMenu_ === 'function' && !cProto.showContextMenu47 && !cProto.showContextMenu47_ && cProto.showContextMenu.length === 1 && cProto.showContextMenu_.length === 1) {
  12388. cProto.showContextMenu47_ = cProto.showContextMenu_;
  12389. cProto.showContextMenu47 = cProto.showContextMenu;
  12390. cProto.__showContextMenu_mutex_unlock_isEmpty__ = dProto.__showContextMenu_mutex_unlock_isEmpty__;
  12391. cProto.__showContextMenu_assign_lock__ = dProto.__showContextMenu_assign_lock__;
  12392. cProto.showContextMenu = dProto.showContextMenuWithMutex;
  12393. cProto.showContextMenu_ = dProto.showContextMenuWithMutex_;
  12394. console.log("ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU - OK", tag);
  12395. } else {
  12396. console.log("ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU - NG", tag);
  12397. }
  12398.  
  12399. })();
  12400.  
  12401. }
  12402.  
  12403. console.log("[End]");
  12404.  
  12405. console.groupEnd();
  12406.  
  12407. }).catch(console.warn);
  12408.  
  12409.  
  12410.  
  12411. if (FIX_UNKNOWN_BUG_FOR_OVERLAY) {
  12412. // this is to fix " TypeError: this.backdropElement.prepare is not a function "
  12413.  
  12414. customElements.whenDefined('tp-yt-paper-dialog').then(() => {
  12415.  
  12416.  
  12417. mightFirstCheckOnYtInit();
  12418. groupCollapsed("YouTube Super Fast Chat", " | tp-yt-paper-dialog hacks");
  12419. console.log("[Begin]");
  12420. (() => {
  12421.  
  12422. const tag = "tp-yt-paper-dialog";
  12423. const dummy = document.createElement(tag);
  12424.  
  12425. const cProto = getProto(dummy);
  12426. if (!cProto || !cProto.attached) {
  12427. console.warn(`proto.attached for ${tag} is unavailable.`);
  12428. return;
  12429. }
  12430.  
  12431. if (typeof cProto.__openedChanged === 'function' && !cProto.__openedChanged49 && cProto.__openedChanged.length === 0) {
  12432.  
  12433.  
  12434. cProto.__openedChanged49 = cProto.__openedChanged;
  12435.  
  12436. cProto.__openedChanged = function () {
  12437. const manager = (this || 0)._manager || 0;
  12438. if (manager && !manager.trackBackdrop49 && manager.trackBackdrop) {
  12439. manager.trackBackdrop49 = manager.trackBackdrop;
  12440. if (manager.trackBackdrop.length === 0) {
  12441. manager.trackBackdrop = function () {
  12442. try {
  12443. return this.trackBackdrop49();
  12444. } catch (e) {
  12445. let showMessage = true;
  12446. if (e instanceof TypeError && e.message === 'this.backdropElement.prepare is not a function') {
  12447. // this is well known issue.
  12448. showMessage = false;
  12449. }
  12450. showMessage && console.log('manager.trackBackdrop', e);
  12451. }
  12452. }
  12453. }
  12454. }
  12455. return this.__openedChanged49();
  12456. };
  12457.  
  12458.  
  12459. }
  12460.  
  12461.  
  12462. })();
  12463.  
  12464.  
  12465.  
  12466. });
  12467.  
  12468. }
  12469.  
  12470.  
  12471. customElements.whenDefined('tp-yt-iron-dropdown').then(() => {
  12472.  
  12473. mightFirstCheckOnYtInit();
  12474. groupCollapsed("YouTube Super Fast Chat", " | tp-yt-iron-dropdown hacks");
  12475. console.log("[Begin]");
  12476. (() => {
  12477.  
  12478. const tag = "tp-yt-iron-dropdown";
  12479. const dummy = document.createElement(tag);
  12480.  
  12481. const cProto = getProto(dummy);
  12482. if (!cProto || !cProto.attached) {
  12483. console.warn(`proto.attached for ${tag} is unavailable.`);
  12484. return;
  12485. }
  12486.  
  12487. if (USE_VANILLA_DEREF && typeof cProto.__deraf === 'function' && cProto.__deraf.length === 2 && !cProto.__deraf34 && fnIntegrity(cProto.__deraf) === '2.42.24') {
  12488. cProto.__deraf_hn__ = function (sId, fn) {
  12489. const rhKey = `_rafHandler_${sId}`;
  12490. const m = this[rhKey] || (this[rhKey] = new WeakMap());
  12491. if (m.has(fn)) return m.get(fn);
  12492. const resFn = () => {
  12493. this.__rafs[sId] = null;
  12494. fn.call(this)
  12495. };
  12496. m.set(fn, resFn);
  12497. m.set(resFn, resFn);
  12498. return resFn;
  12499. };
  12500. cProto.__deraf34 = cProto.__deraf;
  12501. cProto.__deraf = function (a, b) { // sId, fn
  12502. let c = this.__rafs;
  12503. null !== c[a] && cancelAnimationFrame(c[a]);
  12504. c[a] = requestAnimationFrame(this.__deraf_hn__(a, b));
  12505. };
  12506. console.log("USE_VANILLA_DEREF - OK");
  12507. } else {
  12508. console.log("USE_VANILLA_DEREF - NG");
  12509. }
  12510.  
  12511. if (FIX_DROPDOWN_DERAF && typeof cProto.__deraf === 'function' && cProto.__deraf.length === 2 && !cProto.__deraf66) {
  12512. cProto.__deraf66 = cProto.__deraf;
  12513. cProto.__deraf = function (sId, fn) {
  12514. if (this.__byPassRAF__) {
  12515. Promise.resolve(this).then((cnt) => {
  12516. fn.call(cnt);
  12517. cnt = null;
  12518. });
  12519. }
  12520. let r = this.__deraf66.apply(this, arguments);
  12521. return r;
  12522. }
  12523. console.log("FIX_DROPDOWN_DERAF - OK");
  12524. } else {
  12525. console.log("FIX_DROPDOWN_DERAF - NG");
  12526. }
  12527.  
  12528.  
  12529. if (BOOST_MENU_OPENCHANGED_RENDERING && typeof cProto.__openedChanged === 'function' && !cProto.__mtChanged__ && fnIntegrity(cProto.__openedChanged) === '0.46.20') {
  12530.  
  12531. let lastClose = null;
  12532. let lastOpen = null;
  12533. let cid = 0;
  12534.  
  12535. cProto.__mtChanged__ = function (b) {
  12536.  
  12537. Promise.resolve(this).then((cnt) => {
  12538. cnt._applyFocus();
  12539. return cnt;
  12540. }).then((cnt) => {
  12541. b ? cnt._renderOpened() : cnt._renderClosed();
  12542. cnt = null;
  12543. }).catch(console.warn);
  12544.  
  12545. };
  12546.  
  12547. const __moChanged__ = () => {
  12548. if (!cid) return;
  12549. // console.log(553, !!lastOpen, !!lastClose);
  12550. cid = 0;
  12551. if (lastOpen && !lastClose && lastOpen.isAttached) {
  12552. lastOpen.__mtChanged__(1)
  12553. } else if (lastClose && !lastOpen && lastClose.isAttached) {
  12554. lastClose.__mtChanged__(0);
  12555. }
  12556. lastOpen = null;
  12557. lastClose = null;
  12558. };
  12559.  
  12560.  
  12561. if (typeof cProto._openedChanged === 'function' && !cProto._openedChanged66) {
  12562. cProto._openedChanged66 = cProto._openedChanged;
  12563. cProto._openedChanged = function () {
  12564. // this.__byPassRAF__ = !lastOpen ? true : false; // or just true?
  12565. this.__byPassRAF__ = true;
  12566. let r = this._openedChanged66.apply(this, arguments);
  12567. this.__byPassRAF__ = false;
  12568. return r;
  12569. }
  12570. }
  12571.  
  12572. const pSetGet = (key, pdThis, pdBase) => {
  12573. // note: this is not really a standard way for the getOwnPropertyDescriptors; but it is sufficient to make the job done
  12574. return {
  12575. get: (pdThis[key] || 0).get || (pdBase[key] || 0).get,
  12576. set: (pdThis[key] || 0).set || (pdBase[key] || 0).set
  12577. };
  12578. };
  12579.  
  12580. cProto.__modifiedMenuPropsFn__ = function () {
  12581. const pdThis = Object.getOwnPropertyDescriptors(this.constructor.prototype)
  12582. const pdBase = Object.getOwnPropertyDescriptors(this)
  12583.  
  12584. const pdAutoFitOnAttach = pSetGet('autoFitOnAttach', pdThis, pdBase);
  12585. const pdExpandSizingTargetForScrollbars = pSetGet('expandSizingTargetForScrollbars', pdThis, pdBase);
  12586. const pdAllowOutsideScroll = pSetGet('allowOutsideScroll', pdThis, pdBase);
  12587.  
  12588. if (pdAutoFitOnAttach.get || pdAutoFitOnAttach.set) {
  12589. console.warn('there is setter/getter for autoFitOnAttach');
  12590. return;
  12591. }
  12592. if (pdExpandSizingTargetForScrollbars.get || pdExpandSizingTargetForScrollbars.set) {
  12593. console.warn('there is setter/getter for expandSizingTargetForScrollbars');
  12594. return;
  12595. }
  12596. if (!pdAllowOutsideScroll.get || !pdAllowOutsideScroll.set) {
  12597. console.warn('there is NO setter-getter for allowOutsideScroll');
  12598. return;
  12599. }
  12600.  
  12601. let { autoFitOnAttach, expandSizingTargetForScrollbars, allowOutsideScroll } = this;
  12602.  
  12603. this.__AllowOutsideScrollPD__ = pdAllowOutsideScroll;
  12604.  
  12605. const fitEnable = CHAT_MENU_REFIT_ALONG_SCROLLING === 2;
  12606.  
  12607. Object.defineProperties(this, {
  12608. autoFitOnAttach: {
  12609. get() {
  12610. if (fitEnable && this._modifiedMenuPropOn062__) return true;
  12611. return autoFitOnAttach;
  12612. },
  12613. set(nv) {
  12614. autoFitOnAttach = nv;
  12615. return true;
  12616. },
  12617. enumerable: true,
  12618. configurable: true
  12619. }, expandSizingTargetForScrollbars: {
  12620. get() {
  12621. if (fitEnable && this._modifiedMenuPropOn062__) return true;
  12622. return expandSizingTargetForScrollbars;
  12623. },
  12624. set(nv) {
  12625. expandSizingTargetForScrollbars = nv;
  12626. return true;
  12627. },
  12628. enumerable: true,
  12629. configurable: true
  12630. }, allowOutsideScroll: {
  12631. get() {
  12632. if (this._modifiedMenuPropOn062__) return true;
  12633. return allowOutsideScroll;
  12634. },
  12635. set(nv) {
  12636. allowOutsideScroll = nv;
  12637. this.__AllowOutsideScrollPD__.set.call(this, nv);
  12638. return true;
  12639. },
  12640. enumerable: true,
  12641. configurable: true
  12642. }
  12643. })
  12644. };
  12645.  
  12646. /*
  12647. // ***** position() to be changed. *****
  12648. tp-yt-iron-dropdown[class], tp-yt-iron-dropdown[class] #contentWrapper, tp-yt-iron-dropdown[class] ytd-menu-popup-renderer[class] {
  12649.  
  12650. overflow: visible !important;
  12651. min-width: max-content !important;
  12652. max-width: max-content !important;
  12653. max-height: max-content !important;
  12654. min-height: max-content !important;
  12655. white-space: nowrap;
  12656. }
  12657.  
  12658. */
  12659. if (FIX_MENU_POSITION_N_SIZING_ON_SHOWN && typeof cProto.position === 'function' && !cProto.position34 && typeof cProto.refit === 'function') {
  12660.  
  12661. let m34 = 0;
  12662. cProto.__refitByPosition__ = function () {
  12663. m34++;
  12664. if (m34 <= 0) m34 = 0;
  12665. if (m34 !== 1) return;
  12666. const hostElement = this.hostElement || this;
  12667. if (document.visibilityState === 'visible') {
  12668. const sizingTarget = this.sizingTarget;
  12669. if (!sizingTarget) {
  12670. m34 = 0;
  12671. return;
  12672. }
  12673. hostElement.setAttribute('rNgzQ', '');
  12674. sizingTarget.setAttribute('rNgzQ', '');
  12675.  
  12676. const gn = () => {
  12677. hostElement.removeAttribute('rNgzQ');
  12678. sizingTarget.removeAttribute('rNgzQ');
  12679. }
  12680.  
  12681. const an = async () => {
  12682. while (m34 >= 1) {
  12683. await renderReadyPn(sizingTarget);
  12684. if (this.opened && this.isAttached && sizingTarget.isConnected === true && sizingTarget === this.sizingTarget) {
  12685. if (sizingTarget.matches('ytd-menu-popup-renderer[slot="dropdown-content"].yt-live-chat-app')) this.refit();
  12686. }
  12687. m34--;
  12688. }
  12689. m34 = 0;
  12690. Promise.resolve().then(gn);
  12691. }
  12692. setTimeout(an, 4); // wait those resizing function calls
  12693.  
  12694.  
  12695. } else {
  12696. m34 = 0;
  12697. }
  12698. }
  12699. cProto.position34 = cProto.position
  12700. cProto.position = function () {
  12701. if (this._positionInitialize_) {
  12702. this._positionInitialize_ = 0;
  12703. this.__refitByPosition__();
  12704. }
  12705. let r = cProto.position34.apply(this, arguments);
  12706. return r;
  12707. }
  12708. console.log("FIX_MENU_POSITION_ON_SHOWN - OK");
  12709.  
  12710. } else {
  12711.  
  12712. console.log("FIX_MENU_POSITION_ON_SHOWN - NG");
  12713.  
  12714. }
  12715.  
  12716.  
  12717.  
  12718. cProto.__openedChanged = function () {
  12719. // console.log(123445)
  12720. this._positionInitialize_ = 1;
  12721. // this.removeAttribute('horizontal-align')
  12722. // this.removeAttribute('vertical-align')
  12723. if (typeof this.__menuTypeCheck__ !== 'boolean') {
  12724. this.__menuTypeCheck__ = true;
  12725. if (CHAT_MENU_SCROLL_UNLOCKING) {
  12726. this._modifiedMenuPropOn062__ = false;
  12727. // console.log(513, this.positionTarget && this.positionTarget.classList.contains('yt-live-chat-text-message-renderer'))
  12728. // this.autoFitOnAttach = true;
  12729. // this.expandSizingTargetForScrollbars = true;
  12730. // this.allowOutsideScroll = true;
  12731. // console.log(519,Object.getOwnPropertyDescriptors(this.constructor.prototype))
  12732. this.__modifiedMenuPropsFn__();
  12733. // this.constrain= function(){}
  12734. // this.position= function(){}
  12735.  
  12736. // this.autoFitOnAttach = true;
  12737. // this.expandSizingTargetForScrollbars = true;
  12738. // this.allowOutsideScroll = true;
  12739. }
  12740. }
  12741. if (CHAT_MENU_SCROLL_UNLOCKING && this.opened) {
  12742. let newValue = null;
  12743. const positionTarget = this.positionTarget;
  12744. if (positionTarget && positionTarget.classList.contains('yt-live-chat-text-message-renderer')) {
  12745. if (this._modifiedMenuPropOn062__ === false) {
  12746. newValue = true;
  12747. }
  12748. } else if (this._modifiedMenuPropOn062__ === true) {
  12749. newValue = false;
  12750. }
  12751. if (newValue !== null) {
  12752. const beforeAllowOutsideScroll = this.allowOutsideScroll;
  12753. this._modifiedMenuPropOn062__ = newValue;
  12754. const afterAllowOutsideScroll = this.allowOutsideScroll;
  12755. if (beforeAllowOutsideScroll !== afterAllowOutsideScroll) this.__AllowOutsideScrollPD__.set.call(this, afterAllowOutsideScroll);
  12756. }
  12757. }
  12758.  
  12759. if (this.opened) {
  12760.  
  12761. Promise.resolve().then(() => {
  12762.  
  12763. this._prepareRenderOpened();
  12764. }).then(() => {
  12765. console.log('[yt-chat-dialog]', this._manager)
  12766. try{
  12767. this._manager.addOverlay(this);
  12768. }catch(e){
  12769. console.log('this._manager.addOverlay(this) fails.')
  12770. }
  12771. if (this._manager._overlays.length === 1) {
  12772. lastOpen = this;
  12773. lastClose = null;
  12774. } else {
  12775. return 1;
  12776. }
  12777. // if (cid) {
  12778. // clearTimeout(cid);
  12779. // cid = -1;
  12780. // this.__moChanged__();
  12781. // cid = 0;
  12782. // } else {
  12783. // cid = -1;
  12784. // this.__moChanged__();
  12785. // cid = 0;
  12786. // }
  12787. // cid = cid > 0 ? clearTimeout(cid) : 0;
  12788. // console.log(580, this.positionTarget && this.positionTarget.classList.contains('yt-live-chat-text-message-renderer'))
  12789. // cid = cid || setTimeout(__moChanged__, delay1);
  12790. cid = cid || requestAnimationFrame(__moChanged__);
  12791. }).then((r) => {
  12792.  
  12793. if (r) this.__mtChanged__(1);
  12794. }).catch(console.warn);
  12795.  
  12796. } else {
  12797. Promise.resolve().then(() => {
  12798. console.log('[yt-chat-dialog]', this._manager)
  12799. try{
  12800. this._manager.removeOverlay(this);
  12801. }catch(e){
  12802. console.log('this._manager.removeOverlay(this) fails.')
  12803. }
  12804. if (this._manager._overlays.length === 0) {
  12805. lastClose = this;
  12806. lastOpen = null;
  12807. } else {
  12808. return 1;
  12809. }
  12810. // cid = cid > 0 ? clearTimeout(cid) : 0;
  12811. // console.log(581, this.positionTarget && this.positionTarget.classList.contains('yt-live-chat-text-message-renderer'))
  12812. // cid = cid || setTimeout(__moChanged__, delay1);
  12813. cid = cid || requestAnimationFrame(__moChanged__);
  12814. }).then((r) => {
  12815. if (r) this.__mtChanged__(0);
  12816. }).catch(console.warn);
  12817.  
  12818. }
  12819.  
  12820. }
  12821. console.log("BOOST_MENU_OPENCHANGED_RENDERING - OK");
  12822.  
  12823. } else {
  12824.  
  12825. assertor(() => fnIntegrity(cProto.__openedChanged, '0.46.20'));
  12826. console.log("FIX_MENU_REOPEN_RENDER_PERFORMANC_1 - NG");
  12827.  
  12828. }
  12829.  
  12830.  
  12831. if (FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK && typeof cProto.__openedChanged === 'function' && !cProto.__openedChanged82) {
  12832.  
  12833. cProto.__openedChanged82 = cProto.__openedChanged;
  12834.  
  12835.  
  12836. cProto.__openedChanged = function () {
  12837. const positionTarget = this.positionTarget;
  12838. currentMenuPivotWR = positionTarget ? mWeakRef(positionTarget) : null;
  12839. return this.__openedChanged82.apply(this, arguments);
  12840. }
  12841. }
  12842.  
  12843.  
  12844. })();
  12845.  
  12846. console.log("[End]");
  12847.  
  12848. console.groupEnd();
  12849.  
  12850. }).catch(console.warn);
  12851.  
  12852.  
  12853.  
  12854. FIX_ToggleRenderPolymerControllerExtractionBug && customElements.whenDefined('yt-live-chat-toggle-renderer').then(() => {
  12855.  
  12856. mightFirstCheckOnYtInit();
  12857. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-toggle-renderer hacks");
  12858. console.log("[Begin]");
  12859. (() => {
  12860.  
  12861. const tag = "yt-live-chat-toggle-renderer";
  12862. const dummy = document.createElement(tag);
  12863.  
  12864. const cProto = getProto(dummy);
  12865. if (!cProto || !cProto.attached) {
  12866. console.warn(`proto.attached for ${tag} is unavailable.`);
  12867. return;
  12868. }
  12869.  
  12870. })();
  12871.  
  12872. console.log("[End]");
  12873. console.groupEnd();
  12874.  
  12875. });
  12876.  
  12877.  
  12878.  
  12879.  
  12880. /*
  12881.  
  12882.  
  12883.  
  12884.  
  12885.  
  12886. var FU = function() {
  12887. var a = this;
  12888. this.nextHandle_ = 1;
  12889. this.clients_ = {};
  12890. this.JSC$10323_callbacks_ = {};
  12891. this.unsubscribeAsyncHandles_ = {};
  12892. this.subscribe = vl(function(b, c, d) {
  12893. var e = Geb(b);
  12894. if (e in a.clients_)
  12895. e in a.unsubscribeAsyncHandles_ && Jq.cancel(a.unsubscribeAsyncHandles_[e]);
  12896. else {
  12897. a: {
  12898. var h = Geb(b), l;
  12899. for (l in a.unsubscribeAsyncHandles_) {
  12900. var m = a.clients_[l];
  12901. if (m instanceof KO) {
  12902. delete a.clients_[l];
  12903. delete a.JSC$10323_callbacks_[l];
  12904. Jq.cancel(a.unsubscribeAsyncHandles_[l]);
  12905. delete a.unsubscribeAsyncHandles_[l];
  12906. i6a(m);
  12907. m.objectId_ = new FQa(h);
  12908. m.register();
  12909. d = m;
  12910. break a
  12911. }
  12912. }
  12913. d.objectSource = b.invalidationId.objectSource;
  12914. d.objectId = h;
  12915. if (b = b.webAuthConfigurationData)
  12916. b.multiUserSessionIndex && (d.sessionIndex = parseInt(b.multiUserSessionIndex, 10)),
  12917. b.pageId && (d.pageId = b.pageId);
  12918. d = new KO(d,a.handleInvalidationData_.bind(a));
  12919. d.register()
  12920. }
  12921. a.clients_[e] = d;
  12922. a.JSC$10323_callbacks_[e] = {}
  12923. }
  12924. d = a.nextHandle_++;
  12925. a.JSC$10323_callbacks_[e][d] = c;
  12926. return d
  12927. })
  12928. };
  12929. FU.prototype.unsubscribe = function(a, b) {
  12930. var c = Geb(a);
  12931. if (c in this.JSC$10323_callbacks_ && (delete this.JSC$10323_callbacks_[c][b],
  12932. !this.JSC$10323_callbacks_[c].length)) {
  12933. var d = this.clients_[c];
  12934. b = Jq.run(function() {
  12935. ei(d);
  12936. delete this.clients_[c];
  12937. delete this.unsubscribeAsyncHandles_[c]
  12938. }
  12939. .bind(this));
  12940. this.unsubscribeAsyncHandles_[c] = b
  12941. }
  12942. }
  12943. ;
  12944.  
  12945.  
  12946. */
  12947.  
  12948.  
  12949. const onManagerFound = (dummyManager) => {
  12950. if (!dummyManager || typeof dummyManager !== 'object') return;
  12951.  
  12952. const mgrProto = dummyManager.constructor.prototype;
  12953.  
  12954. let keyCallbackStore = '';
  12955. for (const [key, v] of Object.entries(dummyManager)) {
  12956. if (key.includes('_callbacks_')) keyCallbackStore = key;
  12957. }
  12958.  
  12959. if (!keyCallbackStore || typeof mgrProto.unsubscribe !== 'function' || mgrProto.unsubscribe.length !== 2) return;
  12960.  
  12961. if (mgrProto.unsubscribe16) return;
  12962.  
  12963. mgrProto.unsubscribe16 = mgrProto.unsubscribe;
  12964.  
  12965. groupCollapsed("YouTube Super Fast Chat", " | *live-chat-manager* hacks");
  12966. console.log("[Begin]");
  12967.  
  12968. const isEmptyObject = ((obj) => (firstKey(obj) === null));
  12969.  
  12970. const idMapper = new Map();
  12971.  
  12972. const convertId = function (objectId) {
  12973. if (!objectId || typeof objectId !== 'string') return null;
  12974.  
  12975. let result = idMapper.get(objectId)
  12976. if (result) return result;
  12977. result = atob(objectId.replace(/-/g, "+").replace(/_/g, "/"));
  12978. idMapper.set(objectId, result)
  12979. return result;
  12980. }
  12981.  
  12982.  
  12983. const rafHandleHolder = [];
  12984.  
  12985. let pzw = 0;
  12986. let lza = 0;
  12987. const rafHandlerFn = () => {
  12988. pzw = 0;
  12989. if (rafHandleHolder.length === 1) {
  12990. const f = rafHandleHolder[0];
  12991. rafHandleHolder.length = 0;
  12992. f();
  12993. } else if (rafHandleHolder.length > 1) {
  12994. const arr = rafHandleHolder.slice(0);
  12995. rafHandleHolder.length = 0;
  12996. for (const fn of arr) fn();
  12997. }
  12998. };
  12999.  
  13000.  
  13001. if (CHANGE_MANAGER_UNSUBSCRIBE) {
  13002.  
  13003. const checkIntegrityForSubscribe = (mgr) => {
  13004. if (mgr
  13005. && typeof mgr.unsubscribe16 === 'function' && mgr.unsubscribe16.length === 2
  13006. && typeof mgr.subscribe18 === 'function' && (mgr.subscribe18.length === 0 || mgr.subscribe18.length === 3)) {
  13007.  
  13008. const ns = new Set(Object.keys(mgr));
  13009. const ms = new Set(Object.keys(mgr.constructor.prototype));
  13010.  
  13011. if (ns.size >= 6 && ms.size >= 4) {
  13012. // including 'subscribe18'
  13013. // 'unsubscribe16', 'subscribe19'
  13014.  
  13015. let r = 0;
  13016. for (const k of ['nextHandle_', 'clients_', keyCallbackStore, 'unsubscribeAsyncHandles_', 'subscribe', 'subscribe18']) {
  13017. r += ns.has(k) ? 1 : 0;
  13018. }
  13019. for (const k of ['unsubscribe', 'handleInvalidationData_', 'unsubscribe16', 'subscribe19']) {
  13020. r += ms.has(k) ? 1 : 0;
  13021. }
  13022. if (r === 10) {
  13023. const isObject = (c) => (c || 0).constructor === Object;
  13024.  
  13025. if (isObject(mgr['clients_']) && isObject(mgr[keyCallbackStore]) && isObject(mgr['unsubscribeAsyncHandles_'])) {
  13026.  
  13027. return true;
  13028. }
  13029.  
  13030.  
  13031. }
  13032.  
  13033. }
  13034.  
  13035.  
  13036. }
  13037. return false;
  13038. }
  13039.  
  13040. mgrProto.subscribe19 = function (o, f, opts) {
  13041.  
  13042. const ct_clients_ = this.clients_ || 0;
  13043. const ct_handles_ = this.unsubscribeAsyncHandles_ || 0;
  13044.  
  13045. if (this.__doCustomSubscribe__ !== true || !ct_clients_ || !ct_handles_) return this.subscribe18.apply(this, arguments);
  13046.  
  13047. let objectId = ((o || 0).invalidationId || 0).objectId;
  13048. if (!objectId) return this.subscribe18.apply(this, arguments);
  13049. objectId = convertId(objectId);
  13050.  
  13051. // console.log('subscribe', objectId, ct_clients_[objectId], arguments);
  13052.  
  13053. if (ct_clients_[objectId]) {
  13054. if (ct_handles_[objectId] < 0) delete ct_handles_[objectId];
  13055. }
  13056.  
  13057. return this.subscribe18.apply(this, arguments);
  13058. }
  13059.  
  13060. mgrProto.unsubscribe = function (o, d) {
  13061. if (!this.subscribe18 && typeof this.subscribe === 'function') {
  13062. this.subscribe18 = this.subscribe;
  13063. this.subscribe = this.subscribe19;
  13064. this.__doCustomSubscribe__ = checkIntegrityForSubscribe(this);
  13065. }
  13066. const ct_clients_ = this.clients_;
  13067. const ct_handles_ = this.unsubscribeAsyncHandles_;
  13068. if (this.__doCustomSubscribe__ !== true || !ct_clients_ || !ct_handles_) return this.unsubscribe16.apply(this, arguments);
  13069.  
  13070. let objectId = ((o || 0).invalidationId || 0).objectId;
  13071. if (!objectId) return this.unsubscribe16.apply(this, arguments);
  13072.  
  13073. objectId = convertId(objectId);
  13074.  
  13075.  
  13076. // console.log('unsubscribe', objectId, ct_clients_[objectId], arguments);
  13077.  
  13078. const callbacks = this[keyCallbackStore] || 0;
  13079. const callbackObj = callbacks[objectId] || 0;
  13080.  
  13081.  
  13082. if (callbackObj && (delete callbackObj[d], isEmptyObject(callbackObj))) {
  13083. const w = ct_clients_[objectId];
  13084. --lza;
  13085. if (lza < -1e9) lza = -1;
  13086. const qta = lza;
  13087. rafHandleHolder.push(() => {
  13088. if (qta === ct_handles_[objectId]) {
  13089. const o = {
  13090. callbacks, callbackObj,
  13091. client: ct_clients_[objectId],
  13092. handle: ct_handles_[objectId]
  13093. };
  13094. let p = 0;
  13095. try {
  13096. if (ct_clients_[objectId] === w) {
  13097. w && "function" === typeof w.dispose && w.dispose();
  13098. delete ct_clients_[objectId];
  13099. delete ct_handles_[objectId];
  13100. p = 1;
  13101. } else {
  13102. // w && "function" === typeof w.dispose && w.dispose();
  13103. // delete ct_clients_[objectId];
  13104. // delete ct_handles_[objectId];
  13105. p = 2;
  13106. }
  13107. } catch (e) {
  13108. console.warn(e);
  13109. }
  13110. console.log(`unsubscribed: ${p}`, this, o);
  13111. }
  13112. });
  13113. ct_handles_[objectId] = qta;
  13114. if (pzw === 0) {
  13115. pzw = requestAnimationFrame(rafHandlerFn);
  13116. }
  13117. }
  13118. }
  13119.  
  13120.  
  13121. console.log("CHANGE_MANAGER_UNSUBSCRIBE - OK")
  13122.  
  13123. } else {
  13124.  
  13125. console.log("CHANGE_MANAGER_UNSUBSCRIBE - NG")
  13126. }
  13127.  
  13128. console.log("[End]");
  13129.  
  13130. console.groupEnd();
  13131.  
  13132. }
  13133.  
  13134.  
  13135.  
  13136. /*
  13137.  
  13138.  
  13139. a.prototype.async = function(e, h) {
  13140. return 0 < h ? Iq.run(e.bind(this), h) : ~Kq.run(e.bind(this))
  13141. }
  13142. ;
  13143. a.prototype.cancelAsync = function(e) {
  13144. 0 > e ? Kq.cancel(~e) : Iq.cancel(e)
  13145. }
  13146.  
  13147. */
  13148.  
  13149.  
  13150. (FASTER_ICON_RENDERING && Promise.all(
  13151. [
  13152. customElements.whenDefined("yt-icon-shape"),
  13153. customElements.whenDefined("yt-icon")
  13154. // document.createElement('icon-shape'),
  13155. ]
  13156. )).then(() => {
  13157. let cq = 0;
  13158. let dummys = [document.createElement('yt-icon-shape'), document.createElement('yt-icon')]
  13159. for (const dummy of dummys) {
  13160. let cProto = getProto(dummy);
  13161. if (cProto && typeof cProto.shouldRenderIconShape === 'function' && !cProto.shouldRenderIconShape571 && cProto.shouldRenderIconShape.length === 1) {
  13162. assertor(() => fnIntegrity(cProto.shouldRenderIconShape, '1.70.38'));
  13163. cq++;
  13164. cProto.shouldRenderIconShape571 = cProto.shouldRenderIconShape;
  13165. cProto.shouldRenderIconShape = function (a) {
  13166. if (this.isAnimatedIcon) return this.shouldRenderIconShape571(a);
  13167. if (!this.iconType || !this.iconShapeData) return this.shouldRenderIconShape571(a);
  13168. if (!this.iconName) return this.shouldRenderIconShape571(a);
  13169. return false;
  13170. // console.log(1051, this.iconType)
  13171. // console.log(1052, this.iconShapeData)
  13172. // console.log(1053, this.isAnimatedIcon)
  13173. }
  13174. }
  13175. // if(cProto && cProto.switchTemplateAtRegistration){
  13176. // cProto.switchTemplateAtRegistration = false;
  13177. // }
  13178. }
  13179. if (cq === 1) {
  13180. console.log("modified shouldRenderIconShape - Y")
  13181. } else {
  13182. console.log("modified shouldRenderIconShape - N", cq)
  13183. }
  13184. });
  13185.  
  13186. customElements.whenDefined("yt-invalidation-continuation").then(() => {
  13187.  
  13188. let __dummyManager__ = null;
  13189.  
  13190. mightFirstCheckOnYtInit();
  13191. groupCollapsed("YouTube Super Fast Chat", " | yt-invalidation-continuation hacks");
  13192. console.log("[Begin]");
  13193. (() => {
  13194.  
  13195. const tag = "yt-invalidation-continuation"
  13196. const dummy = document.createElement(tag);
  13197.  
  13198. const cProto = getProto(dummy);
  13199. if (!cProto || !cProto.attached) {
  13200. console.warn(`proto.attached for ${tag} is unavailable.`);
  13201. return;
  13202. }
  13203.  
  13204. const dummyManager = insp(dummy).manager_ || 0;
  13205. __dummyManager__ = dummyManager;
  13206.  
  13207. if (CHANGE_DATA_FLUSH_ASYNC && typeof cProto.async === 'function' && !cProto.async71 && cProto.async.length === 2 && typeof cProto.cancelAsync === 'function' && !cProto.cancelAsync71 && cProto.cancelAsync.length === 1) {
  13208.  
  13209.  
  13210. const rafHub = new RAFHub();
  13211.  
  13212. rafHub.keepRAF = true;
  13213. cProto.async71 = cProto.async;
  13214. cProto.cancelAsync71 = cProto.cancelAsync;
  13215.  
  13216. // mostly for subscription timeoutMs 10000ms
  13217. let mcw = 1; // 1, 3, 5, ...
  13218. let arr = new Map();
  13219.  
  13220. let __asyncInited__ = 0;
  13221. let __timeoutStartId__ = null;
  13222. const __asyncInit__ = () => {
  13223.  
  13224. if (__asyncInited__) return;
  13225. __asyncInited__ = 1;
  13226.  
  13227. __timeoutStartId__ = setTimeout(() => { });
  13228. mcw = __timeoutStartId__ * 2 + 1;
  13229.  
  13230. setInterval(() => {
  13231.  
  13232. if (!arr.length) return;
  13233.  
  13234. const p = Date.now();
  13235. let deleteKeys = [];
  13236. arr.forEach((entry, key) => {
  13237.  
  13238.  
  13239. if (entry.cid === -1) {
  13240. entry.cid = -2;
  13241. } else if (entry.cid === -2) {
  13242.  
  13243. let offset = p - entry.add
  13244. if (offset < 0) offset = 0;
  13245. let delay2 = entry.delay - offset;
  13246. if (delay2 < 0) delay2 = 0;
  13247. entry.cid = setTimeout(entry.q(), delay2);
  13248. entry.q = null;
  13249.  
  13250. } else if (entry.add + entry.delay < p) {
  13251. deleteKeys.push(key);
  13252.  
  13253. }
  13254.  
  13255. })
  13256.  
  13257. for (const key of deleteKeys) arr.delete(key);
  13258.  
  13259. }, 2000)
  13260.  
  13261. }
  13262.  
  13263.  
  13264. cProto.async = function (e, h) {
  13265.  
  13266. if (!(0 < h)) return this.async71(e, h); // unknown timing Fn
  13267.  
  13268. if (h < 8000) return this.async71(e, h) * 2; // native setTimeout
  13269.  
  13270. if (typeof h !== 'number') return this.async71(e, h); // exceptional case
  13271.  
  13272.  
  13273. if (!this.__asyncInited__) {
  13274. this.__asyncInited__ = 1;
  13275. __asyncInit__();
  13276. }
  13277. mcw += 2; // 2K+3, 2K+4, ...
  13278. if (mcw > 1e9) mcw = mcw % 1e4;
  13279. const cid = mcw;
  13280. const q = () => {
  13281. return () => {
  13282. console.log('async h > 8000');
  13283. e.call(this);
  13284. }
  13285. }
  13286. // setTimeout(q, delay)
  13287. arr.set(cid, {
  13288. cid: -1, // -1 -> -2 -> cid
  13289. add: Date.now(),
  13290. q,
  13291. delay: h
  13292. });
  13293. // console.log('cid-async', cid)
  13294. return cid;
  13295.  
  13296. }
  13297.  
  13298.  
  13299. cProto.cancelAsync = function (e) {
  13300.  
  13301. if (typeof e !== 'number') return this.cancelAsync71(e); // exceptional case
  13302.  
  13303. // console.log('cid-unasync', e)
  13304.  
  13305. if (0 > e) return this.cancelAsync71(e); // unknown timing fn
  13306.  
  13307. if (e > __timeoutStartId__ * 2) { // __timeoutStartId__ is recorded and min is 2K+1
  13308.  
  13309. if ((e % 2) === 0) return this.cancelAsync71(e / 2); // 2(K+1), 2(K+2), ...
  13310.  
  13311. if (!arr.has(e)) return; // duplciated cancel
  13312.  
  13313. const entry = arr.get(e);
  13314. if (entry.cid < 0) {
  13315. entry.cid = 0;
  13316. arr.delete(e);
  13317. } else {
  13318. clearTimeout(entry.cid); // cid >= 1
  13319. entry.cid = 0;
  13320. arr.delete(e);
  13321. }
  13322.  
  13323. } else {
  13324.  
  13325. return this.cancelAsync71(e);
  13326.  
  13327. }
  13328.  
  13329. }
  13330.  
  13331. console.log("CHANGE_DATA_FLUSH_ASYNC - OK");
  13332.  
  13333. } else if(!CHANGE_DATA_FLUSH_ASYNC){
  13334. console.log("CHANGE_DATA_FLUSH_ASYNC - N/A");
  13335. } else {
  13336. console.log("CHANGE_DATA_FLUSH_ASYNC - NG");
  13337.  
  13338. }
  13339.  
  13340. })();
  13341.  
  13342. console.log("[End]");
  13343.  
  13344. console.groupEnd();
  13345.  
  13346.  
  13347.  
  13348. onManagerFound(__dummyManager__);
  13349.  
  13350. }).catch(console.warn);
  13351.  
  13352.  
  13353. if (INTERACTIVITY_BACKGROUND_ANIMATION >= 1) {
  13354.  
  13355. customElements.whenDefined("yt-live-interactivity-component-background").then(() => {
  13356.  
  13357. mightFirstCheckOnYtInit();
  13358. groupCollapsed("YouTube Super Fast Chat", " | yt-live-interactivity-component-background hacks");
  13359. console.log("[Begin]");
  13360. (() => {
  13361.  
  13362. const tag = "yt-live-interactivity-component-background"
  13363. const dummy = document.createElement(tag);
  13364.  
  13365. const cProto = getProto(dummy);
  13366. if (!cProto || !cProto.attached) {
  13367. console.warn(`proto.attached for ${tag} is unavailable.`);
  13368. return;
  13369. }
  13370.  
  13371. cProto.__toStopAfterRun__ = function (hostElement) {
  13372. let mo = new MutationObserver(() => {
  13373. mo.disconnect();
  13374. mo.takeRecords();
  13375. mo = null;
  13376. this.lottieAnimation && this.lottieAnimation.stop(); // primary
  13377. foregroundPromiseFn().then(() => { // if the lottieAnimation is started with rAf triggering
  13378. this.lottieAnimation && this.lottieAnimation.stop(); // fallback
  13379. });
  13380. });
  13381. mo.observe(hostElement, { subtree: true, childList: true });
  13382. }
  13383.  
  13384. if (INTERACTIVITY_BACKGROUND_ANIMATION >= 1 && typeof cProto.maybeLoadAnimationBackground === 'function' && !cProto.maybeLoadAnimationBackground77 && cProto.maybeLoadAnimationBackground.length === 0) {
  13385.  
  13386. cProto.maybeLoadAnimationBackground77 = cProto.maybeLoadAnimationBackground;
  13387. cProto.maybeLoadAnimationBackground = function () {
  13388. let toRun = true;
  13389. let stopAfterRun = false;
  13390. if (!this.__bypassDisableAnimationBackground__) {
  13391. let doFix = false;
  13392. if (INTERACTIVITY_BACKGROUND_ANIMATION === 1) {
  13393. if (!this.lottieAnimation) {
  13394. doFix = true;
  13395. }
  13396. } else if (INTERACTIVITY_BACKGROUND_ANIMATION === 2) {
  13397. doFix = true;
  13398. }
  13399. if (doFix) {
  13400. if (this.useAnimationBackground === true) {
  13401. console.log('DISABLE_INTERACTIVITY_BACKGROUND_ANIMATION', this.lottieAnimation);
  13402. }
  13403. toRun = true;
  13404. stopAfterRun = true;
  13405. }
  13406. }
  13407. if (toRun) {
  13408. if (stopAfterRun && (this.hostElement instanceof HTMLElement)) {
  13409. this.__toStopAfterRun__(this.hostElement); // primary
  13410. }
  13411. const r = this.maybeLoadAnimationBackground77.apply(this, arguments);
  13412. if (stopAfterRun && this.lottieAnimation) {
  13413. this.lottieAnimation.stop(); // fallback if no mutation
  13414. }
  13415. return r;
  13416. }
  13417. }
  13418.  
  13419. console.log(`INTERACTIVITY_BACKGROUND_ANIMATION(${INTERACTIVITY_BACKGROUND_ANIMATION}) - OK`);
  13420.  
  13421. } else {
  13422. console.log(`INTERACTIVITY_BACKGROUND_ANIMATION(${INTERACTIVITY_BACKGROUND_ANIMATION}) - NG`);
  13423.  
  13424. }
  13425.  
  13426. })();
  13427.  
  13428. console.log("[End]");
  13429.  
  13430. console.groupEnd();
  13431.  
  13432.  
  13433. }).catch(console.warn);
  13434.  
  13435. }
  13436.  
  13437.  
  13438. if (DELAY_FOCUSEDCHANGED) {
  13439.  
  13440. customElements.whenDefined("yt-live-chat-text-input-field-renderer").then(() => {
  13441.  
  13442.  
  13443. mightFirstCheckOnYtInit();
  13444. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-text-input-field-renderer hacks");
  13445. console.log("[Begin]");
  13446. (() => {
  13447.  
  13448. const tag = "yt-live-chat-text-input-field-renderer"
  13449. const dummy = document.createElement(tag);
  13450.  
  13451. const cProto = getProto(dummy);
  13452. if (!cProto || !cProto.attached) {
  13453. console.warn(`proto.attached for ${tag} is unavailable.`);
  13454. return;
  13455. }
  13456.  
  13457. if (DELAY_FOCUSEDCHANGED && typeof cProto.focusedChanged === 'function' && cProto.focusedChanged.length === 0 && !cProto.focusedChanged372) {
  13458. cProto.focusedChanged372 = cProto.focusedChanged;
  13459. cProto.focusedChanged = function () {
  13460. Promise.resolve(this).then((cnt) => {
  13461. if (cnt.isAttached === true) cnt.focusedChanged372();
  13462. });
  13463. }
  13464. }
  13465.  
  13466. })();
  13467.  
  13468. console.log("[End]");
  13469.  
  13470. console.groupEnd();
  13471.  
  13472. });
  13473.  
  13474. }
  13475.  
  13476.  
  13477. }
  13478.  
  13479.  
  13480.  
  13481.  
  13482. promiseForCustomYtElementsReady.then(onRegistryReadyForDOMOperations);
  13483.  
  13484. const fixJsonParse = () => {
  13485.  
  13486. let p1 = window.onerror;
  13487.  
  13488. try {
  13489. JSON.parse("{}");
  13490. } catch (e) {
  13491. console.warn(e);
  13492. }
  13493.  
  13494. let p2 = window.onerror;
  13495.  
  13496. if (p1 !== p2) {
  13497.  
  13498.  
  13499. console.groupCollapsed(`%c${"YouTube Super Fast Chat"}%c${" | JS Engine Issue Found"}`,
  13500. "background-color: #010502; color: #fe806a; font-weight: 700; padding: 2px;",
  13501. "background-color: #010502; color: #fe806a; font-weight: 300; padding: 2px;"
  13502. );
  13503.  
  13504. console.warn("\nJSON.parse is hacked (e.g. Brave's script injection) which causes window.onerror changes on every JSON.parse call.\nPlease install https://greasyfork.org/scripts/473972-youtube-js-engine-tamer to fix the issue.\n");
  13505.  
  13506. console.groupEnd();
  13507.  
  13508. }
  13509.  
  13510. }
  13511.  
  13512. if (CHECK_JSONPRUNE) {
  13513. promiseForCustomYtElementsReady.then(fixJsonParse);
  13514. }
  13515.  
  13516. if(USE_ADVANCED_TICKING){ // if(END_ANIMATING_TICKERS){
  13517.  
  13518.  
  13519. // let lastElmW = null;
  13520.  
  13521. // document.addEventListener('transitionstart', (evt) => {
  13522.  
  13523. // if (evt.propertyName === 'width' && !evt.pseudoElement) {
  13524.  
  13525. // const elm = evt.target;
  13526. // let act = false;
  13527. // /*
  13528. // switch(elm.nodeName.toLowerCase()){
  13529.  
  13530. // case 'yt-live-chat-ticker-creator-goal-view-model':
  13531. // case 'yt-live-chat-ticker-paid-message-item-renderer':
  13532. // case 'yt-live-chat-ticker-paid-sticker-item-renderer':
  13533.  
  13534. // case 'yt-live-chat-ticker-sponsor-item-renderer':
  13535. // act =true;
  13536. // break;
  13537.  
  13538.  
  13539. // }
  13540. // */
  13541. // if (elm instanceof HTMLElement && ((elm || 0).parentElement || 0).id === 'ticker-items' && elm.classList.contains('yt-live-chat-ticker-renderer')) {
  13542. // act = true;
  13543. // }
  13544. // if (act) {
  13545. // const lastElm = kRef(lastElmW);
  13546. // if (elm !== lastElm) {
  13547.  
  13548. // if (lastElm instanceof HTMLElement) {
  13549. // lastElm.classList.add('ticker-no-transition-time');
  13550. // }
  13551. // lastElmW = mWeakRef(elm);
  13552.  
  13553. // }
  13554.  
  13555.  
  13556. // }
  13557. // }
  13558.  
  13559. // }, true);
  13560.  
  13561.  
  13562.  
  13563. document.addEventListener('transitionend', (evt) => {
  13564.  
  13565. if (evt.propertyName && !evt.pseudoElement) {
  13566.  
  13567. const elm = evt.target;
  13568. const f = transitionEndAfterFnSimple.get(elm);
  13569. if (f) {
  13570. transitionEndAfterFnSimple.delete(elm);
  13571. f.resolve(evt.propertyName);
  13572. }
  13573. }
  13574.  
  13575. }, true);
  13576.  
  13577. /*
  13578.  
  13579. document.addEventListener('transitionend', (evt) => {
  13580.  
  13581. if (evt.propertyName === 'width' && !evt.pseudoElement) {
  13582.  
  13583. const elm = evt.target;
  13584. let act = false;
  13585. /-*
  13586. switch(elm.nodeName.toLowerCase()){
  13587.  
  13588. case 'yt-live-chat-ticker-creator-goal-view-model':
  13589. case 'yt-live-chat-ticker-paid-message-item-renderer':
  13590. case 'yt-live-chat-ticker-paid-sticker-item-renderer':
  13591.  
  13592. case 'yt-live-chat-ticker-sponsor-item-renderer':
  13593. act =true;
  13594. break;
  13595.  
  13596.  
  13597. }
  13598. *-/
  13599. if (elm instanceof HTMLElement && ((elm || 0).parentElement || 0).id === 'ticker-items' && elm.classList.contains('yt-live-chat-ticker-renderer')) {
  13600. act = true;
  13601. }
  13602. if (act) {
  13603. elm.style.transitionDuration = '0s';
  13604.  
  13605. }
  13606. }
  13607.  
  13608. }, true);
  13609.  
  13610.  
  13611. document.addEventListener('transitioncancel', (evt) => {
  13612.  
  13613. if (evt.propertyName === 'width' && !evt.pseudoElement) {
  13614.  
  13615. const elm = evt.target;
  13616. let act = false;
  13617. /-*
  13618. switch(elm.nodeName.toLowerCase()){
  13619.  
  13620. case 'yt-live-chat-ticker-creator-goal-view-model':
  13621. case 'yt-live-chat-ticker-paid-message-item-renderer':
  13622. case 'yt-live-chat-ticker-paid-sticker-item-renderer':
  13623.  
  13624. case 'yt-live-chat-ticker-sponsor-item-renderer':
  13625. act =true;
  13626. break;
  13627.  
  13628.  
  13629. }
  13630. *-/
  13631. if (elm instanceof HTMLElement && ((elm || 0).parentElement || 0).id === 'ticker-items' && elm.classList.contains('yt-live-chat-ticker-renderer')) {
  13632. act = true;
  13633. }
  13634. if (act) {
  13635. elm.style.transitionDuration = '0s';
  13636.  
  13637. }
  13638. }
  13639.  
  13640. }, true);
  13641.  
  13642. */
  13643.  
  13644.  
  13645. }
  13646.  
  13647. });
  13648.  
  13649.  
  13650.  
  13651. })({ IntersectionObserver });