YouTube 超快聊天

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

当前为 2025-06-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube Super Fast Chat
  3. // @version 0.102.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. // @require https://cdn.jsdelivr.net/gh/cyfung1031/userscript-supports@c2b707e4977f77792042d4a5015fb188aae4772e/library/nextBrowserTick.min.js
  20. //
  21. // @compatible firefox Violentmonkey
  22. // @compatible firefox Tampermonkey
  23. // @compatible firefox FireMonkey
  24. // @compatible chrome Violentmonkey
  25. // @compatible chrome Tampermonkey
  26. // @compatible opera Violentmonkey
  27. // @compatible opera Tampermonkey
  28. // @compatible safari Stay
  29. // @compatible edge Violentmonkey
  30. // @compatible edge Tampermonkey
  31. // @compatible brave Violentmonkey
  32. // @compatible brave Tampermonkey
  33. //
  34. // @description Ultimate Performance Boost for YouTube Live Chats
  35. // @description:ja YouTubeのライブチャットの究極のパフォーマンスブースト
  36. // @description:zh-TW YouTube直播聊天的終極性能提升
  37. // @description:zh-CN YouTube直播聊天的终极性能提升
  38. //
  39. // ==/UserScript==
  40.  
  41. ((__CONTEXT__) => {
  42. 'use strict';
  43.  
  44. /** @type {WeakMapConstructor} */
  45. const WeakMap = window.WeakMapOriginal || window.WeakMap;
  46.  
  47. const DEBUG_LOG_GROUP_EXPAND = +localStorage.__debugSuperFastChat__ > 0;
  48. const DEBUG_LOG_HIDE_OK = true;
  49. const DEBUG_skipLog001 = true;
  50. const DEBUG_preprocessChatLiveActions = false;
  51. const DEBUG_customCreateComponent = false;
  52. // const SHOW_DEVTOOL_DEBUG = true; // for debug use
  53. const SHOW_DEVTOOL_DEBUG = typeof ResizeObserver === 'function' && CSS.supports('position-area:center');
  54.  
  55. // *********** DON'T REPORT NOT WORKING DUE TO THE CHANGED SETTINGS ********************
  56. // 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
  57.  
  58. /// -------------------------------------------------------------------------
  59.  
  60. const USE_ADVANCED_TICKING = true; // DONT CHANGE
  61. // << if USE_ADVANCED_TICKING >>
  62. const FIX_TIMESTAMP_FOR_REPLAY = true;
  63. const ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION = true; // MUST BE true
  64. const REUSE_TICKER = true; // for better memory control; currently it is only available in ADVANCED_TICKING; to be further reviewed << NO EFFECT SINCE ENABLE_TICKERS_BOOSTED_STAMPING IS USED >>
  65. // << end >>
  66.  
  67. const ENABLE_CHAT_MESSAGES_BOOSTED_STAMPING = true; // TRUE to boost chat messages rendering (DONT CHANGE)
  68. const ENABLE_TICKERS_BOOSTED_STAMPING = true; // TRUE to boost chat messages rendering (DONT CHANGE)
  69. const DISABLE_DYNAMIC_TICKER_WIDTH = true; // We use the opacity change instead
  70. const FIX_REMOVE_TICKER_ITEM_BY_ID = true; // TRUE by default
  71.  
  72. /// -------------------------------------------------------------------------
  73.  
  74. // ENABLE_REDUCED_MAXITEMS_FOR_FLUSH and MAX_ITEMS_FOR_FULL_FLUSH are removed due to ENABLE_CHAT_MESSAGES_BOOSTED_STAMPING is introduced
  75.  
  76. // 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
  77. 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)
  78. // 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)
  79.  
  80. const ENABLE_NO_SMOOTH_TRANSFORM = true; // Depends on whether you want the animation effect for new chat messages <<< DON'T CHANGE >>>
  81. // const USE_OPTIMIZED_ON_SCROLL_ITEMS = true; // TRUE for the majority
  82. const ENABLE_OVERFLOW_ANCHOR_PREFERRED = true; // Enable `overflow-anchor: auto` to lock the scroll list at the bottom for no smooth transform. (Safari is not supported)
  83.  
  84. const FIX_SHOW_MORE_BUTTON_LOCATION = true; // When there are voting options (bottom panel), move the "show more" button to the top.
  85. const FIX_INPUT_PANEL_OVERFLOW_ISSUE = true; // When the super chat button is flicking with color, the scrollbar might come out.
  86. const FIX_INPUT_PANEL_BORDER_ISSUE = true; // No border should be allowed if there is an empty input panel.
  87. const SET_CONTAIN_FOR_CHATROOM = true; // Rendering hacks (`contain`) for chatroom elements. [ General ]
  88.  
  89. const FORCE_CONTENT_VISIBILITY_UNSET = true; // Content-visibility should be always VISIBLE for high performance and great rendering.
  90. const FORCE_WILL_CHANGE_UNSET = true; // Will-change should be always UNSET (auto) for high performance and low energy impact.
  91.  
  92. // Replace requestAnimationFrame timers with custom implementation
  93. const ENABLE_RAF_HACK_TICKERS = true; // When there is a ticker
  94. const ENABLE_RAF_HACK_DOCKED_MESSAGE = true; // To be confirmed
  95. const ENABLE_RAF_HACK_INPUT_RENDERER = true; // To be confirmed
  96. const ENABLE_RAF_HACK_EMOJI_PICKER = true; // When changing the page of the emoji picker
  97.  
  98. // Force rendering all the character subsets of the designated font(s) before messages come (Pre-Rendering of Text)
  99. const ENABLE_FONT_PRE_RENDERING_PREFERRED = 1 | 2 | 4 | 8 | 16;
  100.  
  101. // Backdrop `filter: blur(4px)` inside the iframe can extend to the whole page, causing a negative visual impact on the video you are watching.
  102. const NO_BACKDROP_FILTER_WHEN_MENU_SHOWN = true;
  103.  
  104. // Data Manipulation for Participants (Participant List)
  105. // << if DO_PARTICIPANT_LIST_HACKS >>
  106. const DO_PARTICIPANT_LIST_HACKS = true; // TRUE for the majority
  107. const SHOW_PARTICIPANT_CHANGES_IN_CONSOLE = false; // Just too annoying to show them all in popular chat
  108. const CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT = true; // Only consider changes in renderable content (not concerned with the last chat message of the participants)
  109. const PARTICIPANT_UPDATE_ONLY_ONLY_IF_MODIFICATION_DETECTED = true;
  110. // << end >>
  111.  
  112. // show more button
  113. const ENABLE_SHOW_MORE_BLINKER = true; // BLINK WHEN NEW MESSAGES COME
  114.  
  115. // faster stampDomArray_ for participants list creation
  116. const ENABLE_FLAGS_MAINTAIN_STABLE_LIST_VAL = 1; // 0 - OFF; 1 - ON; 2 - ON(PARTICIPANTS_LIST ONLY)
  117. const USE_MAINTAIN_STABLE_LIST_ONLY_WHEN_KS_FLAG_IS_SET = false;
  118.  
  119. // reuse yt components
  120. const ENABLE_FLAGS_REUSE_COMPONENTS = true;
  121.  
  122. // ShadyDom Free is buggy
  123. const DISABLE_FLAGS_SHADYDOM_FREE = true;
  124.  
  125. // images <Group#I01>
  126. const AUTHOR_PHOTO_SINGLE_THUMBNAIL = 1; // 0 - disable; 1- smallest; 2- largest
  127. const EMOJI_IMAGE_SINGLE_THUMBNAIL = 1; // 0 - disable; 1- smallest; 2- largest
  128. const LEAST_IMAGE_SIZE = 48; // minium size = 48px
  129.  
  130. const DO_LINK_PREFETCH = true; // DO NOT CHANGE
  131. // << if DO_LINK_PREFETCH >>
  132. const ENABLE_BASE_PREFETCHING = true; // (SUB-)DOMAIN | dns-prefetch & preconnect
  133. const ENABLE_PRELOAD_THUMBNAIL = true; // subresource (prefetch) [LINK for Images]
  134. const SKIP_PRELOAD_EMOJI = true;
  135. const PREFETCH_LIMITED_SIZE_EMOJI = 512; // DO NOT CHANGE THIS
  136. const PREFETCH_LIMITED_SIZE_AUTHOR_PHOTO = 68; // DO NOT CHANGE THIS
  137. // << end >>
  138.  
  139. const FIX_SETSRC_AND_THUMBNAILCHANGE_ = true; // Function Replacement for yt-img-shadow....
  140. const FIX_THUMBNAIL_DATACHANGED = true; // Function Replacement for yt-live-chat-author-badge-renderer..dataChanged
  141. // const REMOVE_PRELOADAVATARFORADDACTION = false; // Function Replacement for yt-live-chat-renderer..preloadAvatarForAddAction
  142.  
  143. const FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION = true; // important [depends on <Group#I01>]
  144. const FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT = true; // [depends on <Group#I01>]
  145.  
  146. // BROWSER SUPPORT: Chrome 75+, Edge 79+, Safari 13.1+, Firefox 63+, Opera 62+
  147. const TICKER_MAX_STEPS_LIMIT = 500; // NOT LESS THAN 5 STEPS!!
  148. // (( KEEP AS ALTERNATIVE IF USE_ADVANCED_TICKING NOT WORKING ))
  149. // [limiting 500 max steps] is recommended for "confortable visual change"
  150. // min. step increment 0.2% => max steps: 500 => 800ms per each update
  151. // min. step increment 0.5% => max steps: 200 => 1000ms per each update
  152. // min. step increment 1.0% => max steps: 100 => 1000ms per each update
  153. // min. step increment 2.5% => max steps: 40 => 1000ms per each update
  154. // min. step increment 5.0% => max steps: 20 => 1250ms per each update
  155. const ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX = true; // for video playback's ticker issue. [ Playback Replay - Pause at Middle - Backwards Seeking ]
  156. 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
  157. // << end >>
  158.  
  159. const FIX_TOOLTIP_DISPLAY = true; // changed in 2024.05.02; updated in 2025.01.10
  160. const USE_VANILLA_DEREF = true;
  161. const FIX_DROPDOWN_DERAF = true; // DONT CHANGE
  162.  
  163.  
  164. const CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN = true; // cache the menu data and used for the next reopen
  165. const ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU = false; // pause auto scroll faster when the context menu is about to show
  166. const ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU = true; // avoid multiple requests on the same time
  167.  
  168. const BOOST_MENU_OPENCHANGED_RENDERING = true;
  169. const FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK = true; // click again = close
  170. const NO_ITEM_TAP_FOR_NON_STATIONARY_TAP = true; // dont open the menu (e.g. text message) if cursor is moved or long press
  171. const TAP_ACTION_DURATION = 280; // exceeding 280ms would not consider as a tap action
  172. const PREREQUEST_CONTEXT_MENU_ON_MOUSE_DOWN = true; // require CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN = true
  173. // const FIX_MENU_CAPTURE_SCROLL = true;
  174. const CHAT_MENU_REFIT_ALONG_SCROLLING = 0; // 0 for locking / default; 1 for unlocking only; 2 for unlocking and refit
  175.  
  176. const RAF_FIX_keepScrollClamped = true;
  177. const RAF_FIX_scrollIncrementally = 2; // 0: no action; 1: basic fix; 2: also fix scroll position
  178.  
  179. // << if BOOST_MENU_OPENCHANGED_RENDERING >>
  180. const FIX_MENU_POSITION_N_SIZING_ON_SHOWN = 1; // correct size and position when the menu dropdown opens
  181.  
  182. const CHECK_JSONPRUNE = true; // This is a bug in Brave
  183. // << end >>
  184.  
  185. // const LIVE_CHAT_FLUSH_ON_FOREGROUND_ONLY = false;
  186.  
  187. const CHANGE_MANAGER_UNSUBSCRIBE = true;
  188.  
  189. const INTERACTIVITY_BACKGROUND_ANIMATION = 1; // mostly for pinned message
  190. // 0 = default Yt animation background [= no fix];
  191. // 1 = disable default animation background [= keep special animation];
  192. // 2 = disable all animation backgrounds [= no animation backbround]
  193.  
  194. const CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED = true;
  195.  
  196. const MAX_TOOLTIP_NO_WRAP_WIDTH = '72vw'; // '' for disable; accept values like '60px', '25vw'
  197.  
  198. const DISABLE_Translation_By_Google = true;
  199.  
  200. const FASTER_ICON_RENDERING = true;
  201.  
  202. const DELAY_FOCUSEDCHANGED = true;
  203.  
  204. const skipErrorForhandleAddChatItemAction_ = true; // currently depends on ENABLE_NO_SMOOTH_TRANSFORM
  205. const fixChildrenIssue801 = true; // if __children801__ is set [fix polymer controller method extration for `.set()`]
  206.  
  207. const SUPPRESS_refreshOffsetContainerHeight_ = true; // added in FEB 2024; true for default layout options; no effect if ENABLE_NO_SMOOTH_TRANSFORM is false
  208.  
  209. const NO_FILTER_DROPDOWN_BORDER = true; // added in 2024.03.02
  210.  
  211. const FIX_ANIMATION_TICKER_TEXT_POSITION = true; // CSS fix; experimental; added in 2024.04.07
  212. const FIX_AUTHOR_CHIP_BADGE_POSITION = true;
  213.  
  214. const FIX_ToggleRenderPolymerControllerExtractionBug = false; // to be reviewed
  215.  
  216. const REACTION_ANIMATION_PANEL_CSS_FIX = true;
  217.  
  218. const FIX_UNKNOWN_BUG_FOR_OVERLAY = true; // no .prepare() in backdrop element. reason is unknown.
  219.  
  220. const FIX_MOUSEOVER_FN = true; // avoid onMouseOver_ being triggerd quite a lot
  221.  
  222. // -------------------------------
  223.  
  224. const USE_OBTAIN_LCR_BY_BOTH_METHODS = false; // true for play safe
  225.  
  226. const FIX_MEMORY_LEAKAGE_TICKER_ACTIONMAP = true; // To fix Memory Leakage in yt-live-chat-ticker-...-item-renderer
  227. const FIX_MEMORY_LEAKAGE_TICKER_STATSBAR = true; // To fix Memory Leakage in updateStatsBarAndMaybeShowAnimation
  228. const FIX_MEMORY_LEAKAGE_TICKER_TIMER = true; // To fix Memory Leakage in setContainerWidth, slideDown, collapse // Dec 2024 fix in advance tickering
  229. const FIX_MEMORY_LEAKAGE_TICKER_DATACHANGED_setContainerWidth = true; // To fix Memory Leakage due to _.ytLiveChatTickerItemBehavior.setContainerWidth()
  230.  
  231.  
  232. // const USE_RM_ON_FOUNTAIN_MODEL = false; // No longer working since 2025.04.15
  233. // const DEBUG_RM_ON_FOUNTAIN_MODEL = false;
  234. // const FOUNTAIN_MODEL_TIME_CONFIRM = 1600; // 800 not sufficient; re-adding?
  235. const MODIFY_EMIT_MESSAGES_FOR_BOOST_CHAT = true; // enabled for boost chat only; instant emit & no background flush
  236.  
  237. /**
  238. *
  239. *
  240. *
  241. *
  242. *
  243. rendererStamperObserver_: function(a, b, c) {
  244. if (c.path == a) {
  245. if (c.value === void 0 && !this.hasDataPath_[a])
  246. return;
  247. this.hasDataPath_[a] = c.value !== void 0
  248. }
  249. this.rendererStamperApplyChangeRecord_(a, b, c)
  250. },
  251.  
  252.  
  253. addStampDomObserverFns_: function() {
  254. for (var a in this.stampDom) {
  255. var b = this.stampDom[a];
  256. b.id ? (this[SQa(b.id)] = this.rendererStamperObserver_.bind(this, a, b.id),
  257. this.hasDataPath_[a] = !1) : Er(new Dn("Bad rendererstamper config",this.is + ":" + a))
  258. }
  259. },
  260. *
  261. *
  262. *
  263. *
  264. *
  265. */
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272. // <<<<< FOR MEMORY LEAKAGE >>>>
  273.  
  274. // ========= EXPLANTION FOR 0.2% @ step timing [min. 0.2%] ===========
  275. /*
  276.  
  277. ### Time Approach
  278.  
  279. // all below values can make the time interval > 250ms
  280. // 250ms (practical value) refers to the minimum frequency for timeupdate in most browsers (typically, shorter timeupdate interval in modern browsers)
  281. if (totalDuration > 400000) stepInterval = 0.2; // 400000ms with 0.2% increment => 800ms
  282. else if (totalDuration > 200000) stepInterval = 0.5; // 200000ms with 0.5% increment => 1000ms
  283. else if (totalDuration > 100000) stepInterval = 1; // 100000ms with 1% increment => 1000ms
  284. else if (totalDuration > 50000) stepInterval = 2; // 50000ms with 2% increment => 1000ms
  285. else if (totalDuration > 25000) stepInterval = 5; // 25000ms with 5% increment => 1250ms
  286.  
  287. ### Pixel Check
  288. // Target Max Pixel Increment < 5px for Short Period Ticker (Rapid Background Change)
  289. // Assume total width <= 99px for short period ticker, like small donation & member welcome
  290. 99px * 5% = 4.95px < 5px [Condition Fulfilled]
  291.  
  292. ### Example - totalDuration = 280000
  293. totalDuration 280000
  294. stepInterval 0.5
  295. numOfSteps = Math.round(100 / stepInterval) = 200
  296. time interval = 280000 / 200 = 1400ms <acceptable>
  297.  
  298. ### Example - totalDuration = 18000
  299. totalDuration 18000
  300. stepInterval 5
  301. numOfSteps = Math.round(100 / stepInterval) = 20
  302. time interval = 18000 / 20 = 900ms <acceptable>
  303.  
  304. ### Example - totalDuration = 5000
  305. totalDuration 5000
  306. stepInterval 5
  307. numOfSteps = Math.round(100 / stepInterval) = 20
  308. time interval = 5000 / 20 = 250ms <threshold value>
  309.  
  310. ### Example - totalDuration = 3600
  311. totalDuration 3600
  312. stepInterval 5
  313. numOfSteps = Math.round(100 / stepInterval) = 20
  314. time interval = 3600 / 20 = 180ms <reasonable for 3600ms ticker>
  315.  
  316. */
  317.  
  318. // =======================================================================================================
  319.  
  320. // AUTOMAICALLY DETERMINED
  321. const ENABLE_FLAGS_MAINTAIN_STABLE_LIST = ENABLE_FLAGS_MAINTAIN_STABLE_LIST_VAL === 1;
  322. const ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST = ENABLE_FLAGS_MAINTAIN_STABLE_LIST_VAL >= 1;
  323. const CHAT_MENU_SCROLL_UNLOCKING = CHAT_MENU_REFIT_ALONG_SCROLLING >= 1;
  324.  
  325.  
  326. // image sizing code
  327. // (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null)
  328.  
  329.  
  330. // function KC(a, b, c, d) {
  331. // d = void 0 === d ? "width" : d;
  332. // if (!a || !a.length)
  333. // return null;
  334. // if (z("kevlar_tuner_should_always_use_device_pixel_ratio")) {
  335. // var e = window.devicePixelRatio;
  336. // 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"));
  337. // HC = e
  338. // } else
  339. // HC || (HC = window.devicePixelRatio);
  340. // e = HC;
  341. // z("kevlar_tuner_should_always_use_device_pixel_ratio") ? b *= e : 1 < e && (b *= e);
  342. // if (z("kevlar_tuner_min_thumbnail_quality"))
  343. // return a[0].url || null;
  344. // e = a.length;
  345. // if (z("kevlar_tuner_max_thumbnail_quality"))
  346. // return a[e - 1].url || null;
  347. // if (c)
  348. // for (var h = 0; h < e; h++)
  349. // if (0 <= a[h].url.indexOf(c))
  350. // return a[h].url || null;
  351. // for (c = 0; c < e; c++)
  352. // if (a[c][d] >= b)
  353. // return a[c].url || null;
  354. // for (b = e - 1; 0 < b; b--)
  355. // if (a[b][d])
  356. // return a[b].url || null;
  357. // return a[0].url || null
  358. // }
  359.  
  360.  
  361. /// ------
  362.  
  363. // https://www.youtube.com/watch?v=byyvH5t0hKc
  364. // yt-live-chat-ticker-creator-goal-view-model
  365. // no ticker effect on timing
  366.  
  367. /*
  368.  
  369.  
  370. {
  371. "id": "ChwKGkNQS0pyNV9NdG9vREZVYlB6Z2FkRHWFUv2E",
  372. "initialTickerText": {
  373. "content": "Goal",
  374. "styleRuns": [
  375. {
  376. "startIndex": 0,
  377. "length": 4
  378. }
  379. ]
  380. },
  381. "tickerIcon": {
  382. "sources": [
  383. {
  384. "clientResource": {
  385. "imageName": "TARGET_ADD"
  386. }
  387. }
  388. ]
  389. },
  390. "showGoalStatusCommand": {
  391. "innertubeCommand": {
  392. "clickTrackingParams": "CCQQ7NANIhMI58DT_ef5rhMVxMW1Cx4qBzTz",
  393. "showEngagementPanelEndpoint": {
  394. "engagementPanel": {
  395. "engagementPanelSectionListRenderer": {
  396. "header": {
  397. "engagementPanelTitleHeaderRenderer": {
  398. "actionButton": {
  399. "buttonRenderer": {
  400. "icon": {
  401. "iconType": "QUESTION_CIRCLE"
  402. },
  403. "trackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  404. "command": {
  405. "clickTrackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  406. "commandExecutorCommand": {
  407. "commands": [
  408. {
  409. "clickTrackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  410. "liveChatDialogEndpoint": {
  411. "content": {
  412. "liveChatDialogRenderer": {
  413. "trackingParams": "CCkQzS8iEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  414. "title": {
  415. "runs": [
  416. {
  417. "text": "Super Chat Goal"
  418. }
  419. ]
  420. },
  421. "dialogMessages": [
  422. {
  423. "runs": [
  424. {
  425. "text": "Join the fun by participating in the goal! "
  426. },
  427. {
  428. "text": "Learn more.\n",
  429. "navigationEndpoint": {
  430. "clickTrackingParams": "CCkQzS8iEwjm0Iz72rbKBxXT1EQBJekHNQM="
  431. }
  432. }
  433. ]
  434. },
  435. {
  436. "runs": [
  437. {
  438. "text": "How to participate",
  439. "bold": true,
  440. "textColor": 4294967295
  441. },
  442. {
  443. "text": "\n"
  444. },
  445. {
  446. "text": "1. Press \"Continue\"\n2. Purchase a Super Chat \n3. Watch the progress towards the goal\n4. Celebrate achieving it with the community!",
  447. "textColor": 4294967295
  448. }
  449. ]
  450. }
  451. ],
  452. "confirmButton": {
  453. "buttonRenderer": {
  454. "style": "STYLE_MONO_FILLED",
  455. "size": "SIZE_DEFAULT",
  456. "isDisabled": false,
  457. "text": {
  458. "simpleText": "Got it"
  459. },
  460. "trackingParams": "CCoQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  461. "accessibilityData": {
  462. "accessibilityData": {
  463. "label": "Got it"
  464. }
  465. }
  466. }
  467. }
  468. }
  469. }
  470. }
  471. },
  472. {
  473. "clickTrackingParams": "CCgQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  474. "hideEngagementPanelEndpoint": {
  475. "identifier": {
  476. "surface": "ENGAGEMENT_PANEL_SURFACE_LIVE_CHAT",
  477. "tag": "creator_goal_progress_engagement_panel"
  478. }
  479. }
  480. }
  481. ]
  482. }
  483. }
  484. }
  485. },
  486. "trackingParams": "CCUQ040EIhMI58DT_ef5rhMVxMW1Cx4qBzTz"
  487. }
  488. },
  489. "content": {
  490. "sectionListRenderer": {
  491. "contents": [
  492. {
  493. "creatorGoalProgressFlowViewModel": {
  494. "creatorGoalEntityKey": "EgtieXl2SDV0MGhLYyG7BzhF",
  495. "progressFlowButton": {
  496. "buttonViewModel": {
  497. "onTap": {
  498. "innertubeCommand": {
  499. "clickTrackingParams": "CCcQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  500. "commandMetadata": {
  501. "webCommandMetadata": {
  502. "ignoreNavigation": true
  503. }
  504. },
  505. "liveChatPurchaseMessageEndpoint": {
  506. "params": "Q2lrcUp3b1lWVU14ZFdObmIwTmZjMGQzZDE5RmRYVTFhVTF4Y0ZGM0VndGllWGwyU0RWME1HaExZeEFCSUFFNEFFSUNDQUUlM0Q="
  507. }
  508. }
  509. },
  510. "style": "BUTTON_VIEW_MODEL_STYLE_MONO",
  511. "trackingParams": "CCcQ8FsiEwjm0Iz72rbKBxXT1EQBJekHNQM=",
  512. "type": "BUTTON_VIEW_MODEL_TYPE_FILLED",
  513. "titleFormatted": {
  514. "content": "Continue",
  515. "styleRuns": [
  516. {
  517. "startIndex": 0,
  518. "length": 8
  519. }
  520. ]
  521. }
  522. }
  523. },
  524. "progressCountA11yLabel": "Super Chat goal progress: $0 out of $1"
  525. }
  526. }
  527. ],
  528. "trackingParams": "CCYQui8iEwjm0Iz72rbKBxXT1EQBJekHNQM="
  529. }
  530. },
  531. "identifier": {
  532. "surface": "ENGAGEMENT_PANEL_SURFACE_LIVE_CHAT",
  533. "tag": "creator_goal_progress_engagement_panel"
  534. }
  535. }
  536. },
  537. "identifier": {
  538. "surface": "ENGAGEMENT_PANEL_SURFACE_LIVE_CHAT",
  539. "tag": "creator_goal_progress_engagement_panel"
  540. },
  541. "engagementPanelPresentationConfigs": {
  542. "engagementPanelPopupPresentationConfig": {
  543. "popupType": "PANEL_POPUP_TYPE_DIALOG"
  544. }
  545. }
  546. }
  547. }
  548. },
  549. "creatorGoalEntityKey": "EgtieXl2SDV0MGhLYyG7BzhF",
  550. "shouldShowSetUpFlowOnMobile": true,
  551. "a11yLabel": "See Super Chat goal",
  552. "loggingDirectives": {
  553. "trackingParams": "CCQQ7NANIhMI58DT_ef5rhMVxMW1Cx4qBzTz",
  554. "visibility": {
  555. "types": "12"
  556. }
  557. }
  558. }
  559.  
  560.  
  561. */
  562.  
  563.  
  564. // ------
  565.  
  566. const { IntersectionObserver } = __CONTEXT__;
  567. let _x69;
  568. try {
  569. _x69 = document.createAttributeNS("http://www.w3.org/2000/svg", "nil").addEventListener;
  570. } catch (e) { }
  571. const pureAddEventListener = _x69;
  572. if (!pureAddEventListener) return console.warn("pureAddEventListener cannot be obtained.");
  573.  
  574. /** @type {globalThis.PromiseConstructor} */
  575. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  576. const [setTimeout_] = [setTimeout];
  577. // let jsonParseFix = null;
  578. const Image_ = Image;
  579. /** @type {typeof HTMLElement} */
  580. const HTMLElement_ = Reflect.getPrototypeOf(HTMLTitleElement);
  581.  
  582. const nextBrowserTick_ = nextBrowserTick;
  583. if (typeof nextBrowserTick_ !== "function" || (nextBrowserTick_.version || 0) < 2) {
  584. console.log('nextBrowserTick is not found.');
  585. return;
  586. }
  587.  
  588. if (!IntersectionObserver) return console.warn("Your browser does not support IntersectionObserver.\nPlease upgrade to the latest version.");
  589. if (typeof WebAssembly !== 'object') return console.warn("Your browser is too old.\nPlease upgrade to the latest version."); // for passive and once
  590.  
  591. if (typeof CSS === 'undefined' || typeof (CSS || 0).supports !== 'function' || !CSS.supports('left', 'clamp(-100%, calc( -100% * 0.5 ), 0%)')) {
  592. return console.warn("Your browser is too old.\nPlease upgrade to the latest version."); // for advanced tickering
  593. }
  594.  
  595.  
  596. // necessity of cssText3_smooth_transform_position to be checked.
  597. const cssText3_smooth_transform_position = ENABLE_NO_SMOOTH_TRANSFORM ? `
  598.  
  599. #item-offset.style-scope.yt-live-chat-item-list-renderer > #items.style-scope.yt-live-chat-item-list-renderer {
  600. position: static !important;
  601. }
  602.  
  603. `: '';
  604.  
  605. // fallback if dummy style fn fails
  606. const cssText4_smooth_transform_forced_props = ENABLE_NO_SMOOTH_TRANSFORM ? `
  607.  
  608. /* optional */
  609. #item-offset.style-scope.yt-live-chat-item-list-renderer {
  610. height: auto !important;
  611. min-height: unset !important;
  612. }
  613.  
  614. #items.style-scope.yt-live-chat-item-list-renderer {
  615. transform: translateY(0px) !important;
  616. }
  617.  
  618. /* optional */
  619.  
  620. `: '';
  621.  
  622. const cssText5 = SET_CONTAIN_FOR_CHATROOM ? `
  623.  
  624. /* ------------------------------------------------------------------------------------------------------------- */
  625.  
  626. 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 {
  627. contain: layout style;
  628. }
  629.  
  630. #items.style-scope.yt-live-chat-item-list-renderer {
  631. contain: layout paint style;
  632. }
  633.  
  634. #item-offset.style-scope.yt-live-chat-item-list-renderer {
  635. contain: style;
  636. }
  637.  
  638. #item-scroller.style-scope.yt-live-chat-item-list-renderer {
  639. contain: size style;
  640. }
  641.  
  642. #contents.style-scope.yt-live-chat-item-list-renderer, #chat.style-scope.yt-live-chat-renderer, img.style-scope.yt-img-shadow[width][height] {
  643. contain: size layout paint style;
  644. }
  645.  
  646. .style-scope.yt-live-chat-ticker-renderer[role="button"][aria-label], .style-scope.yt-live-chat-ticker-renderer[role="button"][aria-label] > #container {
  647. contain: layout paint style;
  648. }
  649.  
  650. 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 {
  651. contain: layout style;
  652. }
  653.  
  654. tp-yt-paper-tooltip[style*="inset"][role="tooltip"] {
  655. contain: layout paint style;
  656. }
  657.  
  658. /* ------------------------------------------------------------------------------------------------------------- */
  659.  
  660. ` : '';
  661.  
  662. const cssText6b_show_more_button = FIX_SHOW_MORE_BUTTON_LOCATION ? `
  663.  
  664. yt-live-chat-renderer[has-action-panel-renderer] #show-more.yt-live-chat-item-list-renderer{
  665. top: 4px;
  666. transition-property: top;
  667. bottom: unset;
  668. }
  669.  
  670. yt-live-chat-renderer[has-action-panel-renderer] #show-more.yt-live-chat-item-list-renderer[disabled]{
  671. top: -42px;
  672. }
  673.  
  674. `: '';
  675.  
  676. const cssText6c_input_panel_overflow = FIX_INPUT_PANEL_OVERFLOW_ISSUE ? `
  677.  
  678. #input-panel #picker-buttons yt-live-chat-icon-toggle-button-renderer#product-picker {
  679. contain: layout style;
  680. }
  681.  
  682. #chat.yt-live-chat-renderer ~ #panel-pages.yt-live-chat-renderer {
  683. overflow: visible;
  684. }
  685.  
  686. `: '';
  687.  
  688. const cssText6d_input_panel_border = FIX_INPUT_PANEL_BORDER_ISSUE ? `
  689.  
  690. html #panel-pages.yt-live-chat-renderer > #input-panel.yt-live-chat-renderer:not(:empty) {
  691. --yt-live-chat-action-panel-top-border: none;
  692. }
  693.  
  694. html #panel-pages.yt-live-chat-renderer > #input-panel.yt-live-chat-renderer.iron-selected > *:first-child {
  695. border-top: 1px solid var(--yt-live-chat-panel-pages-border-color);
  696. }
  697.  
  698. html #panel-pages.yt-live-chat-renderer {
  699. border-top: 0;
  700. border-bottom: 0;
  701. }
  702.  
  703. `: '';
  704.  
  705. const cssText7b_content_visibility_unset = FORCE_CONTENT_VISIBILITY_UNSET ? `
  706.  
  707. img,
  708. yt-img-shadow[height][width],
  709. yt-img-shadow {
  710. content-visibility: visible !important;
  711. }
  712.  
  713. ` : '';
  714.  
  715. const cssText7c_will_change_unset = FORCE_WILL_CHANGE_UNSET ? `
  716.  
  717. /* remove YouTube constant will-change */
  718. /* constant value will slow down the performance; default auto */
  719.  
  720. /* www-player.css */
  721. html .ytp-contextmenu,
  722. html .ytp-settings-menu {
  723. will-change: unset;
  724. }
  725.  
  726. /* frequently matched elements */
  727. html .fill.yt-interaction,
  728. html .stroke.yt-interaction,
  729. html .yt-spec-touch-feedback-shape__fill,
  730. html .yt-spec-touch-feedback-shape__stroke {
  731. will-change: unset;
  732. }
  733.  
  734. /* live_chat_polymer.js */
  735. /*
  736. html .toggle-button.tp-yt-paper-toggle-button,
  737. html #primaryProgress.tp-yt-paper-progress,
  738. html #secondaryProgress.tp-yt-paper-progress,
  739. html #onRadio.tp-yt-paper-radio-button,
  740. html .fill.yt-interaction,
  741. html .stroke.yt-interaction,
  742. html .yt-spec-touch-feedback-shape__fill,
  743. html .yt-spec-touch-feedback-shape__stroke {
  744. will-change: unset;
  745. }
  746. */
  747.  
  748. /* desktop_polymer_enable_wil_icons.js */
  749. /* html .fill.yt-interaction,
  750. html .stroke.yt-interaction, */
  751. html tp-yt-app-header::before,
  752. html tp-yt-iron-list,
  753. html #items.tp-yt-iron-list > *,
  754. html #onRadio.tp-yt-paper-radio-button,
  755. html .toggle-button.tp-yt-paper-toggle-button,
  756. html ytd-thumbnail-overlay-toggle-button-renderer[use-expandable-tooltip] #label.ytd-thumbnail-overlay-toggle-button-renderer,
  757. html #items.ytd-post-multi-image-renderer,
  758. html #items.ytd-horizontal-card-list-renderer,
  759. html #items.yt-horizontal-list-renderer,
  760. html #left-arrow.yt-horizontal-list-renderer,
  761. html #right-arrow.yt-horizontal-list-renderer,
  762. html #items.ytd-video-description-infocards-section-renderer,
  763. html #items.ytd-video-description-music-section-renderer,
  764. html #chips.ytd-feed-filter-chip-bar-renderer,
  765. html #chips.yt-chip-cloud-renderer,
  766. html #items.ytd-merch-shelf-renderer,
  767. html #items.ytd-product-details-image-carousel-renderer,
  768. html ytd-video-preview,
  769. html #player-container.ytd-video-preview,
  770. html #primaryProgress.tp-yt-paper-progress,
  771. html #secondaryProgress.tp-yt-paper-progress,
  772. html ytd-miniplayer[enabled] /* ,
  773. html .yt-spec-touch-feedback-shape__fill,
  774. html .yt-spec-touch-feedback-shape__stroke */ {
  775. will-change: unset;
  776. }
  777.  
  778. /* other */
  779. .ytp-videowall-still-info-content[class],
  780. .ytp-suggestion-image[class] {
  781. will-change: unset !important;
  782. }
  783.  
  784. ` : '';
  785.  
  786. const ENABLE_FONT_PRE_RENDERING = typeof HTMLElement_.prototype.append === 'function' ? (ENABLE_FONT_PRE_RENDERING_PREFERRED || 0) : 0;
  787. const cssText8_fonts_pre_render = ENABLE_FONT_PRE_RENDERING ? `
  788.  
  789. elzm-fonts {
  790. visibility: collapse;
  791. position: fixed;
  792. top: -10px;
  793. left: -10px;
  794. font-size: 10pt;
  795. line-height: 100%;
  796. width: 100px;
  797. height: 100px;
  798. transform: scale(0.1);
  799. transform: scale(0.01);
  800. transform: scale(0.001);
  801. transform-origin: 0 0;
  802. contain: strict;
  803. display: block;
  804.  
  805. pointer-events: none !important;
  806. user-select: none !important;
  807. }
  808.  
  809. elzm-fonts[id]#elzm-fonts-yk75g {
  810. user-select: none !important;
  811. pointer-events: none !important;
  812. }
  813.  
  814. elzm-font {
  815. visibility: collapse;
  816. position: absolute;
  817. line-height: 100%;
  818. width: 100px;
  819. height: 100px;
  820. contain: strict;
  821. display: block;
  822.  
  823. user-select: none !important;
  824. pointer-events: none !important;
  825. }
  826.  
  827. elzm-font::before {
  828. visibility: collapse;
  829. position: absolute;
  830. line-height: 100%;
  831. width: 100px;
  832. height: 100px;
  833. contain: strict;
  834. display: block;
  835.  
  836. 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';
  837.  
  838. user-select: none !important;
  839. pointer-events: none !important;
  840. }
  841.  
  842. `: '';
  843.  
  844. const cssText9_no_backdrop_filter_when_menu_shown = NO_BACKDROP_FILTER_WHEN_MENU_SHOWN ? `
  845. tp-yt-iron-dropdown.yt-live-chat-app ytd-menu-popup-renderer {
  846. -webkit-backdrop-filter: none;
  847. backdrop-filter: none;
  848. }
  849. `: '';
  850.  
  851. const cssText10_show_more_blinker = ENABLE_SHOW_MORE_BLINKER ? `
  852.  
  853. @keyframes blinker-miuzp {
  854. 0%, 60%, 100% {
  855. opacity: 1;
  856. }
  857. 30% {
  858. opacity: 0.6;
  859. }
  860. }
  861.  
  862. yt-icon-button#show-more.has-new-messages-miuzp {
  863. animation: blinker-miuzp 1.74s linear infinite;
  864. }
  865.  
  866. `: '';
  867.  
  868. const cssText11_entire_message_clickable = FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK ? `
  869.  
  870. yt-live-chat-paid-message-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  871. pointer-events: none !important;
  872. }
  873.  
  874. yt-live-chat-membership-item-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  875. pointer-events: none !important;
  876. }
  877.  
  878. yt-live-chat-paid-sticker-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  879. pointer-events: none !important;
  880. }
  881.  
  882. yt-live-chat-text-message-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  883. pointer-events: none !important; /* TO_BE_REVIEWED */
  884. }
  885.  
  886. yt-live-chat-auto-mod-message-renderer.yt-live-chat-item-list-renderer[whole-message-clickable] #menu.style-scope[class] {
  887. pointer-events: none !important;
  888. }
  889.  
  890. `: '';
  891.  
  892. const cssText12_nowrap_tooltip = MAX_TOOLTIP_NO_WRAP_WIDTH && typeof MAX_TOOLTIP_NO_WRAP_WIDTH === 'string' ? `
  893.  
  894.  
  895. tp-yt-paper-tooltip[role="tooltip"] {
  896. box-sizing: content-box !important;
  897. margin: 0px !important;
  898. padding: 0px !important;
  899. contain: none !important;
  900. }
  901.  
  902. tp-yt-paper-tooltip[role="tooltip"] #tooltip[style-target="tooltip"] {
  903. box-sizing: content-box !important;
  904. display: inline-block;
  905. contain: none !important;
  906. }
  907.  
  908.  
  909. tp-yt-paper-tooltip[role="tooltip"] #tooltip[style-target="tooltip"]{
  910. max-width: ${MAX_TOOLTIP_NO_WRAP_WIDTH};
  911. width: max-content;
  912. text-overflow: ellipsis;
  913. overflow: hidden;
  914. white-space: nowrap;
  915. }
  916.  
  917.  
  918. `: '';
  919.  
  920.  
  921. const cssText13_no_text_select_when_menu_visible = `
  922. [menu-visible] {
  923. --sfc47-text-select: none;
  924. }
  925. [menu-visible] #header[id][class],
  926. [menu-visible] #content[id][class],
  927. [menu-visible] #header[id][class] *,
  928. [menu-visible] #content[id][class] * {
  929. user-select: var(--sfc47-text-select) !important;
  930. }
  931. [menu-visible] #menu {
  932. --sfc47-text-select: inherit;
  933. }
  934. `;
  935.  
  936. const cssText14_NO_FILTER_DROPDOWN_BORDER = NO_FILTER_DROPDOWN_BORDER ? `
  937. yt-live-chat-header-renderer.yt-live-chat-renderer #label.yt-dropdown-menu::before {
  938. border:0;
  939. }
  940. ` : '';
  941.  
  942. const cssText15_FIX_ANIMATION_TICKER_TEXT_POSITION = FIX_ANIMATION_TICKER_TEXT_POSITION ? `
  943. .style-scope.yt-live-chat-ticker-renderer #animation-container[id][class] {
  944. position: relative;
  945. display: grid;
  946. grid-auto-columns: 1fr;
  947. grid-auto-rows: 1fr;
  948. grid-template-columns: repeat(1, 1fr);
  949. gap: 7px;
  950. padding-bottom: 0;
  951. margin-bottom: 0;
  952. padding-top: 0;
  953. align-self: flex-start;
  954. flex-wrap: nowrap;
  955. margin-top: 1px;
  956. }
  957.  
  958. .style-scope.yt-live-chat-ticker-renderer #animation-container > [id][class] {
  959. margin-top: 0px;
  960. margin-bottom: 0px;
  961. flex-direction: row;
  962. flex-wrap: nowrap;
  963. align-items: center;
  964. justify-content: flex-start;
  965. }
  966.  
  967. .style-scope.yt-live-chat-ticker-renderer #animation-container > [id][class]:first-child::after {
  968. content: '補';
  969. visibility: collapse;
  970. display: inline-block;
  971. position: relative;
  972. width: 0;
  973. line-height: 22px;
  974. }
  975.  
  976. ` : '';
  977.  
  978. const cssText16_FIX_AUTHOR_CHIP_BADGE_POSITION = FIX_AUTHOR_CHIP_BADGE_POSITION ? `
  979. #card #author-name-chip > yt-live-chat-author-chip[single-line] {
  980. flex-wrap: nowrap;
  981. white-space: nowrap;
  982. display: inline-flex;
  983. flex-direction: row;
  984. text-wrap: nowrap;
  985. flex-shrink: 0;
  986. align-items: center;
  987. }
  988.  
  989. #card #author-name-chip {
  990. display: inline-flex;
  991. flex-direction: row;
  992. align-items: flex-start;
  993. }
  994. `: '';
  995.  
  996.  
  997. // Example: https://www.youtube.com/watch?v=Xfytz-igsuc
  998. const cssText17_FIX_overwidth_banner_message = `
  999. yt-live-chat-banner-manager#live-chat-banner.style-scope.yt-live-chat-item-list-renderer {
  1000. max-width: 100%;
  1001. box-sizing: border-box;
  1002. }
  1003. `;
  1004.  
  1005.  
  1006. const cssText18_REACTION_ANIMATION_PANEL_CSS_FIX = REACTION_ANIMATION_PANEL_CSS_FIX ? `
  1007. #reaction-control-panel-overlay[class] {
  1008. contain: strict;
  1009. margin: 0;
  1010. padding: 0;
  1011. border: 0;
  1012. box-sizing: border-box;
  1013. will-change: initial;
  1014. }
  1015. #reaction-control-panel-overlay[class] *[class] {
  1016. will-change: initial;
  1017. }
  1018. `: '';
  1019.  
  1020. const cssText19_FOR_ADVANCED_TICKING = USE_ADVANCED_TICKING ? `
  1021.  
  1022. ticker-bg-overlay {
  1023. display: block;
  1024. position: absolute;
  1025. z-index: -1;
  1026. box-sizing: border-box;
  1027. border: 0;
  1028. padding: 0;
  1029. margin: 0;
  1030. width: 200%;
  1031. top: 0;
  1032. bottom: 0;
  1033. left: clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%);
  1034. contain: strict;
  1035. pointer-events: none;
  1036. }
  1037. ticker-bg-overlay-end2 {
  1038.  
  1039. all:unset;
  1040. position: fixed;
  1041. display: block;
  1042. margin-left: -0.5px;
  1043. top: 8px;
  1044. left: clamp(-250px, calc( 250px * ( ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) - 1 ) ), 2px);
  1045.  
  1046. width: 1px;
  1047. height: 1px;
  1048. opacity: 0;
  1049. pointer-events: none;
  1050. box-sizing: border-box;
  1051. border: 0;
  1052. padding: 0;
  1053. margin: 0;
  1054. contain: strict;
  1055. z-index: -1;
  1056. visibility: collapse;
  1057.  
  1058.  
  1059. }
  1060.  
  1061.  
  1062. /* .r6-closing-ticker is provided in ADVANCED_TICKING */
  1063. /* so .r6-width-adjustable is only available for ADVANCED_TICKING too */
  1064.  
  1065. /* DO NOT use .r6-width-adjustable ~ .r6-width-adjustable => very laggy */
  1066.  
  1067. /*
  1068. yt-live-chat-ticker-renderer {
  1069. --r6-transition-duration: 0.2s;
  1070. }
  1071.  
  1072. .r6-width-adjustable, .yt-live-chat-ticker-stampdom {
  1073. --r6-transition-duration-v: var(--r6-transition-duration);
  1074. transition: var(--r6-transition-duration-v);
  1075. }
  1076.  
  1077. .r6-width-adjustable-f {
  1078. --r6-transition-duration-v: 0s;
  1079. }
  1080.  
  1081. .r6-closing-ticker[class] {
  1082. --r6-transition-duration-v: var(--r6-transition-duration);
  1083. }
  1084. */
  1085.  
  1086.  
  1087.  
  1088. .r6-width-adjustable {
  1089. --r6-min-width: 0;
  1090. min-width: var(--r6-min-width);
  1091. }
  1092.  
  1093. .r6-width-adjustable-f {
  1094. --r6-min-width: max-content;
  1095. }
  1096.  
  1097. .r6-closing-ticker[class] {
  1098. --r6-min-width: 0;
  1099. }
  1100.  
  1101. ` : '';
  1102.  
  1103. const cssText20_TICKER_SIZING = ENABLE_TICKERS_BOOSTED_STAMPING && DISABLE_DYNAMIC_TICKER_WIDTH ? `
  1104.  
  1105. :root {
  1106. --ticker-items-gap: 8px;
  1107. }
  1108. #ticker-items.yt-live-chat-ticker-renderer {
  1109. position: relative;
  1110. transform: translateZ(1px);
  1111. box-sizing: border-box;
  1112. contain: style;
  1113. display: flex;
  1114. flex-direction: row;
  1115. gap: var(--ticker-items-gap);
  1116. }
  1117. #container.yt-live-chat-ticker-renderer {
  1118. contain: layout paint style;
  1119. }
  1120.  
  1121. .yt-live-chat-ticker-stampdom {
  1122. position: static;
  1123. width: max-content;
  1124. content-visibility:auto;
  1125. }
  1126. .yt-live-chat-ticker-stampdom[class] {
  1127. transition: none;
  1128. }
  1129. .yt-live-chat-ticker-stampdom-container {
  1130. position: static;
  1131. width: max-content;
  1132. content-visibility:auto;
  1133. }
  1134.  
  1135. .yt-live-chat-ticker-stampdom {
  1136. margin-right:0 !important; /* flex gap 8px */
  1137. }
  1138.  
  1139. /* default animation */
  1140. .yt-live-chat-ticker-stampdom {
  1141. animation: ticker-shown-animation 220ms ease-in 0s 1 normal forwards;
  1142. }
  1143. /* default animation */
  1144. @keyframes ticker-shown-animation {
  1145. 0%, 70%, 100% { opacity: 1; }
  1146. 30% { opacity: 0.2; }
  1147. }
  1148.  
  1149.  
  1150. ` : "";
  1151. // const cssText19_FOR_ADVANCED_TICKING = `
  1152.  
  1153. // ticker-bg-overlay {
  1154. // display: block;
  1155. // position: absolute;
  1156. // z-index: -1;
  1157. // box-sizing: border-box;
  1158. // border: 0;
  1159. // padding: 0;
  1160. // margin: 0;
  1161. // width: 200%;
  1162. // top: 0;
  1163. // bottom: 0;
  1164. // left: clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%);
  1165. // contain: strict;
  1166. // }
  1167. // /*
  1168. // ticker-bg-overlay-end {
  1169. // position: absolute;
  1170. // right: 0px;
  1171. // top: 50%;
  1172. // display: block;
  1173. // width: 1px;
  1174. // height: 1px;
  1175. // opacity: 0;
  1176. // pointer-events: none;
  1177. // box-sizing: border-box;
  1178. // border: 0;
  1179. // padding: 0;
  1180. // margin: 0;
  1181. // contain: strict;
  1182. // }
  1183. // */
  1184.  
  1185. // ticker-bg-overlay-end2 {
  1186.  
  1187. // all:unset;
  1188. // position: fixed;
  1189. // display: block;
  1190. // margin-left: -0.5px;
  1191. // top: 8px;
  1192. // left: clamp(-250px, calc( 250px * ( ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) - 1 ) ), 2px);
  1193.  
  1194. // width: 1px;
  1195. // height: 1px;
  1196. // opacity: 0;
  1197. // pointer-events: none;
  1198. // box-sizing: border-box;
  1199. // border: 0;
  1200. // padding: 0;
  1201. // margin: 0;
  1202. // contain: strict;
  1203. // z-index: -1;
  1204. // visibility: collapse;
  1205.  
  1206.  
  1207. // }
  1208.  
  1209. // /* USE_ADVANCED_TICKING */
  1210.  
  1211. // /*
  1212.  
  1213. // .ticker-no-transition-time, .ticker-no-transition-time [id] {
  1214. // transition-duration: 0s !important;
  1215. // }
  1216.  
  1217. // [r6-advanced-ticking] .style-scope.yt-live-chat-ticker-renderer ~ .style-scope.yt-live-chat-ticker-renderer:not(.r6-closing-ticker) {
  1218. // transition-duration: 0s !important;
  1219. // }
  1220.  
  1221. // */
  1222.  
  1223. // .r6-width-adjustable ~ .r6-width-adjustable {
  1224. // --r6-min-width: max-content;
  1225. // }
  1226.  
  1227. // .r6-closing-ticker[class] {
  1228. // --r6-min-width: 0px;
  1229. // }
  1230.  
  1231. // .r6-width-adjustable {
  1232. // min-width: var(--r6-min-width, 0px);
  1233. // }
  1234.  
  1235.  
  1236. // /*
  1237.  
  1238.  
  1239. // .r6-width-adjustable {
  1240. // transition-duration: var(--r6-transition-duration, 0s) !important;
  1241. // }
  1242.  
  1243. // .r6-width-adjustable-first {
  1244. // --r6-transition-duration: 0.2s;
  1245. // }
  1246.  
  1247. // .r6-width-adjustable ~ .r6-width-adjustable-first {
  1248. // --r6-transition-duration: 0s;
  1249. // }
  1250.  
  1251. // .r6-closing-ticker {
  1252. // --r6-transition-duration: 0.2s;
  1253. // }
  1254. // */
  1255.  
  1256. // /*
  1257.  
  1258.  
  1259. // ey.style.position = 'absolute';
  1260. // ey.style.right = '0px';
  1261. // ey.style.top = '50%';
  1262. // ey.style.display='block';
  1263. // ey.style.width='1px';
  1264. // ey.style.height='1px';
  1265. // ey.style.opacity = '0';
  1266.  
  1267. // em.style.display = 'block';
  1268. // em.style.position = 'absolute';
  1269. // em.style.boxSizing = 'border-box';
  1270. // em.style.width = '200%';
  1271. // em.style.top = '0';
  1272. // em.style.bottom = '0';
  1273. // // em.style.height = '100%';
  1274.  
  1275.  
  1276. // // em.style.left = '-50%';
  1277. // // em.style.left = "clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%)";
  1278.  
  1279. // */
  1280.  
  1281. // `;
  1282.  
  1283. const addCss = () => `
  1284.  
  1285. yt-live-chat-renderer {
  1286. max-height: 100vh;
  1287. }
  1288.  
  1289. @property --ticker-rtime {
  1290. syntax: "<percentage>";
  1291. inherits: false;
  1292. initial-value: 0%;
  1293. }
  1294.  
  1295. .run-ticker {
  1296. --ticker-bg:linear-gradient(90deg, var(--ticker-c1),var(--ticker-c1) var(--ticker-rtime),var(--ticker-c2) var(--ticker-rtime),var(--ticker-c2));
  1297. }
  1298.  
  1299. .run-ticker,
  1300. yt-live-chat-ticker-renderer #items > * > #container.run-ticker,
  1301. yt-live-chat-ticker-renderer[class] #items[class] > *[class] > #container.run-ticker[class]
  1302. {
  1303. background: var(--ticker-bg) !important;
  1304. }
  1305.  
  1306. yt-live-chat-ticker-dummy777-item-renderer {
  1307. background: #00000001;
  1308. }
  1309.  
  1310. yt-live-chat-ticker-dummy777-item-renderer[dummy777] {
  1311. position: fixed !important;
  1312. top: -1000px !important;
  1313. left: -1000px !important;
  1314. font-size: 1px !important;
  1315. color: transparent !important;
  1316. pointer-events: none !important;
  1317. z-index: -1 !important;
  1318. contain: strict !important;
  1319. box-sizing: border-box !important;
  1320. pointer-events: none !important;
  1321. user-select: none !important;
  1322. max-width: 1px !important;
  1323. max-height: 1px !important;
  1324. overflow: hidden !important;
  1325. visibility: collapse !important;
  1326. display: none !important;
  1327. }
  1328.  
  1329. yt-live-chat-ticker-dummy777-item-renderer #container {
  1330. background: inherit;
  1331. }
  1332.  
  1333.  
  1334. ${cssText8_fonts_pre_render}
  1335.  
  1336. ${cssText9_no_backdrop_filter_when_menu_shown}
  1337.  
  1338. @supports (contain: layout paint style) {
  1339.  
  1340. ${cssText5}
  1341.  
  1342. }
  1343.  
  1344. @supports (color: var(--general)) {
  1345.  
  1346. html {
  1347. --yt-live-chat-item-list-renderer-padding: 0px 0px;
  1348. }
  1349.  
  1350. ${cssText3_smooth_transform_position}
  1351.  
  1352. ${cssText7c_will_change_unset}
  1353.  
  1354. ${cssText7b_content_visibility_unset}
  1355.  
  1356. yt-live-chat-item-list-renderer:not([allow-scroll]) #item-scroller.yt-live-chat-item-list-renderer {
  1357. overflow-y: scroll;
  1358. padding-right: 0;
  1359. }
  1360.  
  1361. ${cssText4_smooth_transform_forced_props}
  1362.  
  1363. yt-icon[icon="down_arrow"] > *, yt-icon-button#show-more > * {
  1364. pointer-events: none !important;
  1365. }
  1366.  
  1367. #continuations, #continuations * {
  1368. contain: strict;
  1369. position: fixed;
  1370. top: 2px;
  1371. height: 1px;
  1372. width: 2px;
  1373. height: 1px;
  1374. visibility: collapse;
  1375. }
  1376.  
  1377. ${cssText6b_show_more_button}
  1378.  
  1379. ${cssText6d_input_panel_border}
  1380.  
  1381. ${cssText6c_input_panel_overflow}
  1382.  
  1383. }
  1384.  
  1385.  
  1386. @supports (overflow-anchor: auto) {
  1387.  
  1388. .no-anchor * {
  1389. overflow-anchor: none;
  1390. }
  1391. .no-anchor > item-anchor {
  1392. overflow-anchor: auto;
  1393. }
  1394. #item-scroller.style-scope.yt-live-chat-item-list-renderer[class] {
  1395. overflow-anchor: initial !important; /* whenever ENABLE_OVERFLOW_ANCHOR or not */
  1396. }
  1397. }
  1398.  
  1399. item-anchor {
  1400.  
  1401. height: 1px;
  1402. width: 100%;
  1403. transform: scaleY(0.00001);
  1404. transform-origin:0 0;
  1405. contain: strict;
  1406. opacity:0;
  1407. display:flex;
  1408. position:relative;
  1409. flex-shrink:0;
  1410. flex-grow:0;
  1411. margin-bottom:0;
  1412. overflow:hidden;
  1413. box-sizing:border-box;
  1414. visibility: visible;
  1415. content-visibility: visible;
  1416. contain-intrinsic-size: auto 1px;
  1417. pointer-events:none !important;
  1418.  
  1419. }
  1420.  
  1421. html item-anchor {
  1422.  
  1423. height: 1px;
  1424. width: 1px;
  1425. top: auto;
  1426. left: auto;
  1427. right: auto;
  1428. bottom: auto;
  1429. transform: translateY(-1px);
  1430. position: absolute;
  1431. z-index: -1;
  1432.  
  1433. }
  1434.  
  1435. @supports (color: var(--pre-rendering)) {
  1436.  
  1437. @keyframes dontRenderAnimation {
  1438. 0% {
  1439. background-position-x: 3px;
  1440. }
  1441. 100% {
  1442. background-position-x: 4px;
  1443. }
  1444. }
  1445.  
  1446. .dont-render[class] {
  1447. /* visibility: collapse !important; */
  1448. /* visibility: collapse will make innerText become "" which conflicts with BetterStreamChat; see https://greasyfork.org/scripts/469878/discussions/197267 */
  1449.  
  1450. transform: scale(0.01) !important;
  1451. transform: scale(0.00001) !important;
  1452. transform: scale(0.0000001) !important;
  1453. transform-origin: 0 0 !important;
  1454. z-index: -1 !important;
  1455. contain: strict !important;
  1456. box-sizing: border-box !important;
  1457.  
  1458. height: 1px !important;
  1459. height: 0.1px !important;
  1460. height: 0.01px !important;
  1461. height: 0.0001px !important;
  1462. height: 0.000001px !important;
  1463.  
  1464. animation: dontRenderAnimation 1ms linear 80ms 1 normal forwards !important;
  1465.  
  1466. pointer-events: none !important;
  1467. user-select: none !important;
  1468.  
  1469. }
  1470.  
  1471. #sk35z {
  1472. display: block !important;
  1473.  
  1474. visibility: collapse !important;
  1475.  
  1476. transform: scale(0.01) !important;
  1477. transform: scale(0.00001) !important;
  1478. transform: scale(0.0000001) !important;
  1479. transform-origin: 0 0 !important;
  1480. z-index: -1 !important;
  1481. contain: strict !important;
  1482. box-sizing: border-box !important;
  1483.  
  1484. height: 1px !important;
  1485. height: 0.1px !important;
  1486. height: 0.01px !important;
  1487. height: 0.0001px !important;
  1488. height: 0.000001px !important;
  1489.  
  1490. position: absolute !important;
  1491. top: -1000px !important;
  1492. left: -1000px !important;
  1493.  
  1494. }
  1495.  
  1496. }
  1497.  
  1498. [rNgzQ] {
  1499. opacity: 0 !important;
  1500. pointer-events: none !important;
  1501. }
  1502.  
  1503.  
  1504. ${cssText10_show_more_blinker}
  1505.  
  1506. ${cssText11_entire_message_clickable}
  1507.  
  1508. ${cssText12_nowrap_tooltip}
  1509.  
  1510. ${cssText13_no_text_select_when_menu_visible}
  1511.  
  1512. ${cssText14_NO_FILTER_DROPDOWN_BORDER}
  1513.  
  1514. ${cssText15_FIX_ANIMATION_TICKER_TEXT_POSITION}
  1515.  
  1516. ${cssText16_FIX_AUTHOR_CHIP_BADGE_POSITION}
  1517.  
  1518. ${cssText17_FIX_overwidth_banner_message}
  1519.  
  1520. ${cssText18_REACTION_ANIMATION_PANEL_CSS_FIX}
  1521.  
  1522. ${cssText19_FOR_ADVANCED_TICKING}
  1523.  
  1524. ${cssText20_TICKER_SIZING}
  1525.  
  1526. `;
  1527.  
  1528. const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : (this instanceof Window ? this : window);
  1529.  
  1530. // Create a unique key for the script and check if it is already running
  1531. const hkey_script = 'mchbwnoasqph';
  1532. if (win[hkey_script]) throw new Error('Duplicated Userscript Calling'); // avoid duplicated scripting
  1533. win[hkey_script] = true;
  1534.  
  1535. const setTimeoutX0 = setTimeout;
  1536. const clearTimeoutX0 = clearTimeout;
  1537. const setIntervalX0 = setInterval;
  1538. const clearIntervalX0 = clearInterval;
  1539.  
  1540. const __shady_native_appendChild = HTMLElement_.prototype.__shady_native_appendChild || HTMLElement_.prototype.appendChild;
  1541. const __shady_native_removeChild = HTMLElement_.prototype.__shady_native_removeChild || HTMLElement_.prototype.removeChild;
  1542.  
  1543. const isEmptyObject = (obj) => {
  1544. for (const key in obj) {
  1545. if (obj.hasOwnProperty(key)) return false;
  1546. }
  1547. return true;
  1548. }
  1549.  
  1550. const firstObjectKey = (obj) => {
  1551. for (const key in obj) {
  1552. if (obj.hasOwnProperty(key) && typeof obj[key] === 'object') return key;
  1553. }
  1554. return null;
  1555. }
  1556.  
  1557.  
  1558. class LimitedSizeSet extends Set {
  1559. constructor(n) {
  1560. super();
  1561. this.limit = n;
  1562. }
  1563.  
  1564. add(key) {
  1565. if (!super.has(key)) {
  1566. super.add(key);
  1567. let n = super.size - this.limit;
  1568. if (n > 0) {
  1569. const iterator = super.values();
  1570. do {
  1571. const firstKey = iterator.next().value; // Get the first (oldest) key
  1572. super.delete(firstKey); // Delete the oldest key
  1573. } while (--n > 0)
  1574. }
  1575. }
  1576. }
  1577.  
  1578. removeAdd(key) {
  1579. super.delete(key);
  1580. this.add(key);
  1581. }
  1582.  
  1583. }
  1584.  
  1585.  
  1586. function deepCopy(obj, skipKeys) {
  1587. skipKeys = skipKeys || [];
  1588. if (!obj || typeof obj !== 'object') return obj;
  1589. if (Array.isArray(obj)) {
  1590. return obj.map(item => deepCopy(item, skipKeys));
  1591. }
  1592. const copy = {};
  1593. for (let key in obj) {
  1594. if (!skipKeys.includes(key)) {
  1595. copy[key] = deepCopy(obj[key], skipKeys);
  1596. }
  1597. }
  1598. return copy;
  1599. }
  1600.  
  1601. class Mutex {
  1602.  
  1603. constructor() {
  1604. this.p = Promise.resolve()
  1605. }
  1606.  
  1607. /**
  1608. * @param {(lockResolve: () => void)} f
  1609. */
  1610. lockWith(f) {
  1611. this.p = this.p.then(() => new Promise(f).catch(console.warn))
  1612. }
  1613.  
  1614. }
  1615.  
  1616. const PromiseExternal = ((resolve_, reject_) => {
  1617. const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
  1618. return class PromiseExternal extends Promise {
  1619. constructor(cb = h) {
  1620. super(cb);
  1621. if (cb === h) {
  1622. /** @type {(value: any) => void} */
  1623. this.resolve = resolve_;
  1624. /** @type {(reason?: any) => void} */
  1625. this.reject = reject_;
  1626. }
  1627. }
  1628. };
  1629. })();
  1630.  
  1631. let ttpHTML = (s) => {
  1632. ttpHTML = s => s;
  1633. if (typeof trustedTypes !== 'undefined' && trustedTypes.defaultPolicy === null) {
  1634. let s = s => s;
  1635. trustedTypes.createPolicy('default', { createHTML: s, createScriptURL: s, createScript: s });
  1636. }
  1637. return s;
  1638. }
  1639.  
  1640. // const nextBrowserTick_ = nextBrowserTick;
  1641. // const nextBrowserTick_ = (f) => {
  1642. // typeof nextBrowserTick === 'function' ? nextBrowserTick(f) : setTimeout(f, Number.MIN_VALUE);
  1643. // };
  1644.  
  1645.  
  1646. // const { accurateTiming, isAccurateTimingUsable } = (() => {
  1647. // let audioCtx_ = null;
  1648. // let sampleRate = 0;
  1649. // const isAccurateTimingUsable = () => sampleRate > 0;
  1650. // const kill = () => {
  1651. // sampleRate = audioCtx_.currentTime;
  1652. // document.removeEventListener('pointerdown', listener, { capture: true, passive: true });
  1653. // document.removeEventListener('keydown', listener, { capture: true, passive: true });
  1654. // };
  1655. // const listener = (e) => {
  1656. // if (e.isTrusted === true) {
  1657. // if (!audioCtx_) {
  1658. // audioCtx_ = new (window.AudioContext || window.webkitAudioContext)();
  1659. // }
  1660. // if (audioCtx_.state === 'suspended') {
  1661. // const p = audioCtx_.resume();
  1662. // if (p && typeof p.then === 'function') p.then(kill);
  1663. // } else if (audioCtx_.state === 'running') {
  1664. // kill();
  1665. // }
  1666. // }
  1667. // };
  1668. // document.addEventListener('pointerdown', listener, { capture: true, passive: true });
  1669. // document.addEventListener('keydown', listener, { capture: true, passive: true });
  1670. // const fnSym = Symbol()
  1671. // const commonOscClean = (osc) => {
  1672. // osc[fnSym] = osc.onended = null;
  1673. // }
  1674. // const commonOscOnEnded = function () {
  1675. // this[fnSym]()
  1676. // Promise.resolve(this).then(commonOscClean)
  1677. // }
  1678. // let buffer_;
  1679. // const accurateTiming = (fn, delay) => {
  1680. // if (!sampleRate) return false;
  1681. // const audioCtx = audioCtx_;
  1682. // const ct = audioCtx.currentTime;
  1683.  
  1684. // if (!(delay >= 0)) delay = 0;
  1685. // const stopTime = ct + delay;
  1686. // let startTime = ct + delay - (1 / sampleRate);
  1687. // if (startTime === stopTime) startTime -= 1;
  1688. // if (startTime < 0) startTime = 0;
  1689.  
  1690. // if (!buffer_) {
  1691. // buffer_ = audioCtx.createBuffer(1, 1, sampleRate);
  1692. // // const data = buffer.getChannelData(0)
  1693. // // data[0] = 1e-20 // tiny pulse – not silent!
  1694. // }
  1695.  
  1696. // const buffer = buffer_;
  1697. // const source = audioCtx.createBufferSource()
  1698. // source.buffer = buffer
  1699. // source.connect(audioCtx.destination) // or silent gain node
  1700.  
  1701. // source[fnSym] = fn
  1702. // source.onended = commonOscOnEnded
  1703. // source.start(startTime) // schedule start
  1704.  
  1705. // return true;
  1706. // }
  1707. // return { accurateTiming, isAccurateTimingUsable }
  1708. // })();
  1709.  
  1710. const toUniqueArr = (arr) => {
  1711. const s = new Set(arr);
  1712. const r = [...s];
  1713. s.clear();
  1714. return r;
  1715. }
  1716.  
  1717. let qWidthAdjustable = null;
  1718.  
  1719. /** @type {typeof PromiseExternal.prototype | null} */
  1720. let relayPromise = null;
  1721.  
  1722.  
  1723. /** @type {typeof PromiseExternal.prototype | null} */
  1724. let onPlayStateChangePromise = null;
  1725.  
  1726.  
  1727. const reuseId = `${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
  1728.  
  1729. const reuseStore = new Map();
  1730. reuseStore.set = reuseStore.setOriginal || reuseStore.set;
  1731.  
  1732. let onPageContainer = null;
  1733.  
  1734. const customCreateComponent = (component, data, bool)=>{
  1735.  
  1736. const componentTag = typeof component === 'string' ? component : typeof (component||0).component === 'string' ? (component||0).component : '';
  1737. if(componentTag){
  1738.  
  1739. if(REUSE_TICKER && data.id && data.fullDurationSec){
  1740. // bool (param c) is true by default; just force it to reuse no matter true or false
  1741.  
  1742. if (!bool) {
  1743. // show a warning if it is false.
  1744. console.warn('[yt-chat] REUSE_TICKER: reuse bool is false');
  1745. }
  1746.  
  1747. const record = reuseStore.get(`<${componentTag}>${data.id}:${data.fullDurationSec}`);
  1748.  
  1749. const cnt = kRef(record);
  1750.  
  1751.  
  1752. if(cnt && cnt.isAttached === false){
  1753.  
  1754. const hostElement = cnt.hostElement;
  1755.  
  1756. if(hostElement instanceof HTMLElement_ && hostElement.isConnected === false && hostElement.parentNode === null && hostElement.getAttribute('__reuseid__')===reuseId ){
  1757.  
  1758. // console.log(952, cnt.hostElement.parentNode)
  1759. // debugger;
  1760. if (hostElement.hasAttribute('__nogc__')) {
  1761.  
  1762. Promise.resolve(hostElement).then((hostElement) => {
  1763. // microtask to provide some time for DOM attachment.
  1764. hostElement.isConnected && hostElement.removeAttribute('__nogc__');
  1765. });
  1766.  
  1767. }
  1768.  
  1769. // ------- follow rm3 -------
  1770.  
  1771. // a.prototype._initializeProtoProperties = function(c) {
  1772. // this.__data = Object.create(c);
  1773. // this.__dataPending = Object.create(c);
  1774. // this.__dataOld = {}
  1775. // }
  1776. // a.prototype._initializeProperties = function() {
  1777. // this.__dataProto && (this._initializeProtoProperties(this.__dataProto),
  1778. // this.__dataProto = null);
  1779. // b.prototype._initializeProperties.call(this)
  1780. // }
  1781. // ;
  1782.  
  1783. if(!cnt.__dataInvalid && cnt.__dataEnabled && cnt.__dataReady ){
  1784.  
  1785. // console.log(12883);
  1786.  
  1787.  
  1788. if (!onPageContainer) {
  1789. let p = document.createElement('noscript');
  1790. p.style.all = 'unset';
  1791. document.body.prepend(p);
  1792. onPageContainer = p;
  1793. }
  1794.  
  1795. onPageContainer.appendChild(hostElement); // to fix some issues for the rendered elements
  1796.  
  1797. cnt.__dataInvalid = false;
  1798. cnt.__dataEnabled = true;
  1799. cnt.__dataReady = true;
  1800. // cnt._initializeProtoProperties(cnt.data)
  1801.  
  1802. // window.meaa = cnt.$.container;
  1803. if (cnt.__data) cnt.__data = Object.assign({}, cnt.__data);
  1804. cnt.__dataPending = {};
  1805. cnt.__dataOld = {}
  1806.  
  1807. try{
  1808. cnt.markDirty();
  1809. }catch(e){}
  1810. try{
  1811. cnt.markDirtyVisibilityObserver();
  1812. }catch(e){}
  1813. try{
  1814. cnt.wasPrescan = cnt.wasVisible = !1
  1815. }catch(e){}
  1816. // try{
  1817. // cnt._setPendingProperty('data', Object.assign({}, cntData), !0);
  1818. // }catch(e){}
  1819. // // cnt.__dataInvalid = false;
  1820. // // cnt._enableProperties();
  1821.  
  1822. // try {
  1823. // cnt._flushProperties();
  1824. // } catch (e) { }
  1825. // cnt.ready();
  1826.  
  1827. return hostElement;
  1828.  
  1829. }
  1830.  
  1831.  
  1832. // console.log(12323)
  1833.  
  1834. // setTimeoutX0(()=>{
  1835. // console.log(window.meaa.parentNode)
  1836. // }, 1000)
  1837.  
  1838.  
  1839. // ------------ commented ------------
  1840. // cnt.__dataInvalid = false;
  1841. // cnt.__dataEnabled = false;
  1842. // if (cnt.__dataPending && typeof cnt.__dataPending === 'object') cnt.__dataPending = null;
  1843. // if (cnt.__dataOld && typeof cnt.__dataOld === 'object') cnt.__dataOld = null;
  1844. // if (cnt.__dataCounter && typeof cnt.__dataCounter === 'number') cnt.__dataCounter = 0;
  1845. // if ('__dataClientsInitialized' in cnt || '__dataClientsReady' in cnt) {
  1846. // cnt.__dataClientsReady = !1;
  1847. // cnt.__dataLinkedPaths = cnt.__dataToNotify = cnt.__dataPendingClients = null;
  1848. // cnt.__dataHasPaths = !1;
  1849. // cnt.__dataCompoundStorage = null; // cnt.__dataCompoundStorage = cnt.__dataCompoundStorage || null;
  1850. // cnt.__dataHost = null; // cnt.__dataHost = cnt.__dataHost || null;
  1851. // if (!cnt.__dataTemp) cnt.__dataTemp = {}; // cnt.__dataTemp = {};
  1852. // cnt.__dataClientsInitialized = !1;
  1853. // }
  1854. // try{
  1855. // cnt._flushProperties();
  1856. // }catch(e){
  1857. // console.warn(e)
  1858. // }
  1859. // for (const elm of cnt.hostElement.getElementsByTagName('*')) {
  1860. // if (elm.is) {
  1861. // const cnt = insp(elm);
  1862. // cnt.__dataInvalid = false;
  1863. // cnt.__dataEnabled = false;
  1864. // if (cnt.__dataPending && typeof cnt.__dataPending === 'object') cnt.__dataPending = null;
  1865. // if (cnt.__dataOld && typeof cnt.__dataOld === 'object') cnt.__dataOld = null;
  1866. // if (cnt.__dataCounter && typeof cnt.__dataCounter === 'number') cnt.__dataCounter = 0;
  1867. // if ('__dataClientsInitialized' in cnt || '__dataClientsReady' in cnt) {
  1868. // cnt.__dataClientsReady = !1;
  1869. // cnt.__dataLinkedPaths = cnt.__dataToNotify = cnt.__dataPendingClients = null;
  1870. // cnt.__dataHasPaths = !1;
  1871. // cnt.__dataCompoundStorage = null; // cnt.__dataCompoundStorage = cnt.__dataCompoundStorage || null;
  1872. // cnt.__dataHost = null; // cnt.__dataHost = cnt.__dataHost || null;
  1873. // if (!cnt.__dataTemp) cnt.__dataTemp = {}; // cnt.__dataTemp = {};
  1874. // cnt.__dataClientsInitialized = !1;
  1875. // }
  1876. // try {
  1877. // cnt._flushProperties();
  1878. // } catch (e) {
  1879. // console.warn(e)
  1880. // }
  1881. // if (elm.nodeName === 'YT-ICON') {
  1882. // // console.log(2133, JSON.stringify( cnt.__data))
  1883. // const qq = Object.assign({}, cnt.__data)
  1884. // console.log(1232466)
  1885. // const _qww = cnt;
  1886. // cnt.__data = new Proxy(Object.assign({}, qq), {
  1887. // get(target, p) {
  1888. // console.log(12838, p)
  1889. // if (p === 'icon') {
  1890. // window.wmk = _qww.hostElement;
  1891. // // debugger;
  1892. // }
  1893. // return target[p]
  1894. // },
  1895. // set(target, p, v) {
  1896. // console.log(12839, p)
  1897. // target[p] = v;
  1898. // if (p === 'icon') debugger;
  1899. // return true;
  1900. // }
  1901. // });
  1902. // Promise.resolve(cnt).then((cnt) => {
  1903. // cnt.__data = Object.assign({}, qq);
  1904. // });
  1905. // }
  1906. // // let q = elm.nextSibling;
  1907. // // let h = elm.parentNode;
  1908. // // elm.remove();
  1909. // // h.insertBefore(elm, q);
  1910. // // console.log(2233, elm)
  1911. // }
  1912. // }
  1913. // ------------ commented ------------
  1914.  
  1915. // ------- follow rm3 -------
  1916.  
  1917. // console.log('[yt-chat] reuse')
  1918.  
  1919.  
  1920.  
  1921. }
  1922.  
  1923. }
  1924.  
  1925. }
  1926.  
  1927. }
  1928. DEBUG_customCreateComponent && console.log(component, data, bool);
  1929. /*
  1930.  
  1931. const cntData = this.data;
  1932. reuseStore.set(`${cntData.id}:${cntData.fullDurationSec}`, mWeakRef(this));
  1933. */
  1934.  
  1935. }
  1936.  
  1937. const valAssign = (elm, attr, val) => {
  1938. if (typeof val === 'number') val = val.toFixed(3);
  1939. const currentVal = elm.style.getPropertyValue(attr);
  1940. if (currentVal === '' || !(Math.abs(currentVal - val) < 1e-5)) {
  1941. elm.style.setProperty(attr, val);
  1942. return true;
  1943. }
  1944. return false;
  1945. };
  1946.  
  1947. const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);
  1948. const indr = o => insp(o).$ || o.$ || 0;
  1949.  
  1950.  
  1951. const getAttributes = (node) => {
  1952. const attrs = node.attributes;
  1953. const res = {};
  1954. for (const { name, value } of attrs) {
  1955. res[name] = value;
  1956. }
  1957. res['"'] = attrs.length;
  1958. // const res = new Array(attrs.length);
  1959. // for (let i = 0; i < res.length; i++) {
  1960. // const { name, value } = attrs[i];
  1961. // res[i] = { name, value };
  1962. // }
  1963. return res;
  1964. };
  1965.  
  1966. // const __refreshData938o__ = {};
  1967. // const __refreshData938__ = function (prop, opt) {
  1968. // const d = this[prop];
  1969. // if (d) {
  1970. // this._setPendingProperty(prop, __refreshData938o__, opt);
  1971. // this._setPendingProperty(prop, d, opt);
  1972. // this._invalidateProperties();
  1973. // }
  1974. // };
  1975.  
  1976. // const __refreshData933__ = function (prop, opt) {
  1977. // const d = this[prop];
  1978. // if (d) {
  1979. // this.signalProxy.setWithPath([prop], d);
  1980. // }
  1981. // }
  1982.  
  1983. // const setupRefreshData930 = (cnt) => {
  1984. // if (cnt.__refreshData930__ !== undefined) return;
  1985. // const cProto = Reflect.getPrototypeOf(cnt);
  1986. // let r = null;
  1987. // let flag = 0;
  1988. // if (typeof cnt._setPendingProperty === 'function' && typeof cnt._invalidateProperties === 'function' && cnt._setPendingProperty.length === 3 && cnt._invalidateProperties.length === 0) {
  1989. // flag |= 1;
  1990. // }
  1991. // if (typeof cnt.signalProxy !== "undefined") {
  1992. // flag |= 2;
  1993. // }
  1994. // if (typeof (cnt.signalProxy || 0).setWithPath === 'function' && cnt.signalProxy.setWithPath.length === 2) {
  1995. // flag |= 4;
  1996. // }
  1997. // if (r === 1) r = __refreshData938__;
  1998. // // else if (r === 6) r = __refreshData933__;
  1999. // cProto.__refreshData930__ = r;
  2000. // // ytd-comments-header-renderer : no _invalidateProperties (cnt.signalProxy.setWithPath)
  2001. // }
  2002.  
  2003. // const __refreshProps938__ = function () {
  2004. // const __data = this.__data;
  2005. // if (__data) {
  2006. // for (const key in __data) {
  2007. // const v = __data[key];
  2008. // if (typeof v === 'boolean') {
  2009. // this._setPendingProperty(key, !v) && this._setPendingProperty(key, v);
  2010. // } else if (typeof v === 'string') {
  2011. // this._setPendingProperty(key, `!${v}`) && this._setPendingProperty(key, `${v}`);
  2012. // } else if (typeof v === 'number') {
  2013. // this._setPendingProperty(key, v + 1) && this._setPendingProperty(key, v);
  2014. // }
  2015. // }
  2016. // }
  2017. // }
  2018.  
  2019. // const setupRefreshProps930 = (cnt) => {
  2020. // if (cnt.__refreshProps930__ !== undefined) return;
  2021. // const cProto = Reflect.getPrototypeOf(cnt);
  2022. // let r = null;
  2023. // let flag = 0;
  2024. // if (typeof cnt._setPendingProperty === 'function' && typeof cnt._invalidateProperties === 'function' && cnt._setPendingProperty.length === 3 && cnt._invalidateProperties.length === 0) {
  2025. // flag |= 1;
  2026. // }
  2027. // if (typeof cnt.signalProxy !== "undefined") {
  2028. // flag |= 2;
  2029. // }
  2030. // if (typeof (cnt.signalProxy || 0).setWithPath === 'function' && cnt.signalProxy.setWithPath.length === 2) {
  2031. // flag |= 4;
  2032. // }
  2033. // if (r === 1) r = __refreshProps938__;
  2034. // cProto.__refreshProps930__ = r;
  2035. // // ytd-comments-header-renderer : no _invalidateProperties (cnt.signalProxy.setWithPath)
  2036. // }
  2037.  
  2038. // const refreshChildrenYtIcons = (node) => {
  2039. // let goNext = false;
  2040. // for (const iconElm of node.getElementsByTagName('yt-icon')) {
  2041. // try {
  2042. // const cnt = insp(iconElm);
  2043. // setupRefreshProps930(cnt);
  2044. // if (cnt.__refreshProps930__) {
  2045. // cnt.__refreshProps930__();
  2046. // goNext = true;
  2047. // }
  2048. // // cnt.removeIconShape(); // detach iconShapeDataSignal?
  2049. // // cnt._setPendingProperty('isAttached', false);
  2050. // } catch (e) { }
  2051. // if (!goNext) break;
  2052. // }
  2053. // }
  2054.  
  2055.  
  2056. // const imageFetchCache = new Set();
  2057. // const imageFetch = function (imageLink) {
  2058. // return new Promise(resolve => {
  2059. // let img = null;
  2060. // for (const cacheWR of imageFetchCache) {
  2061. // let p = kRef(cacheWR);
  2062. // if (!p) {
  2063. // imageFetchCache.delete(cacheWR);
  2064. // } else if (img.busy588 === false) {
  2065. // img = p;
  2066. // break;
  2067. // }
  2068. // }
  2069. // if (!img) {
  2070. // img = new Image_();
  2071. // imageFetchCache.add(mWeakRef(img));
  2072. // }
  2073. // img.busy588 = true;
  2074.  
  2075. // window.mkek = imageFetchCache.size;
  2076. // let f = () => {
  2077. // resolve && resolve();
  2078. // resolve = null;
  2079. // img.onload = null;
  2080. // img.onerror = null;
  2081. // img.busy588 = false;
  2082. // img = null;
  2083. // }
  2084. // img.onload = f;
  2085. // img.onerror = f;
  2086. // img.src = imageLink;
  2087. // f = null;
  2088. // imageLink = null;
  2089. // });
  2090. // };
  2091.  
  2092.  
  2093. const autoTimerFn = (() => {
  2094.  
  2095. let p1 = null;
  2096. let p2 = null;
  2097. let p3 = null;
  2098. setInterval(() => {
  2099. if (p1) p1.resolve();
  2100. p1 = p2;
  2101. p2 = p3;
  2102. p3 = null;
  2103. }, 345.00123);
  2104.  
  2105. return () => {
  2106. const p = (p3 || (p3 = new PromiseExternal()));
  2107. return p;
  2108. };
  2109.  
  2110. })();
  2111.  
  2112. const __mockChildren__ = { get length() { return 0 } };
  2113. const mockCommentElement = (x) => {
  2114. // for flow chat
  2115. if (x instanceof Node && x.nodeType !== 1 && !x.children) {
  2116. x.children = __mockChildren__;
  2117. }
  2118. return x;
  2119. }
  2120.  
  2121. const wme = mockCommentElement(document.createComment('1'));
  2122. let wmp = new PromiseExternal();
  2123. const wmo = new MutationObserver(() => {
  2124. wmp.resolve();
  2125. wmp = new PromiseExternal();
  2126. });
  2127. wmo.observe(wme, { characterData: true });
  2128.  
  2129.  
  2130. let playEventsStack = Promise.resolve();
  2131.  
  2132.  
  2133. let playerProgressChangedArg1 = null;
  2134. let playerProgressChangedArg2 = null;
  2135. let playerProgressChangedArg3 = null;
  2136.  
  2137. let dntElementWeak = null;
  2138.  
  2139.  
  2140. let timestampUnderLiveMode = false;
  2141.  
  2142. const updateTickerCurrentTime = () => {
  2143.  
  2144. if (resistanceUpdateDebugMode) {
  2145. console.log('updateTickerCurrentTime')
  2146.  
  2147. if (!dntElementWeak || !kRef(dntElementWeak)) dntElementWeak = mWeakRef(document.querySelector('yt-live-chat-ticker-renderer'));
  2148. timestampUnderLiveMode = true;
  2149. }
  2150.  
  2151. const dntElement = kRef(dntElementWeak);
  2152. const v = timestampUnderLiveMode ? (Date.now() / 1000 - timeOriginDT / 1000) : playerProgressChangedArg1;
  2153. if (dntElement instanceof HTMLElement_ && v >= 0) {
  2154. valAssign(dntElement, '--ticker-current-time', v);
  2155. }
  2156. }
  2157.  
  2158. // ================== FOR USE_ADVANCED_TICKING ================
  2159.  
  2160. const timeOriginDT = +new Date(Math.floor(performance.timeOrigin)) - 1000;
  2161. let startResistanceUpdaterStarted = false;
  2162.  
  2163. const RESISTANCE_UPDATE_OPT = 3;
  2164. let resistanceUpdateLast = 0;
  2165. let resistanceUpdateBusy = false;
  2166. const resistanceUpdateDebugMode = false;
  2167. const allBackgroundOverLays = document.getElementsByTagName('ticker-bg-overlay');
  2168. // const rgFlag = {};
  2169. const resistanceUpdateFn = (b) => {
  2170. if (!resistanceUpdateDebugMode && allBackgroundOverLays.length === 0) return;
  2171. resistanceUpdateBusy = false;
  2172. const t = Date.now();
  2173. const d = t - resistanceUpdateLast;
  2174. if (d > 375) {
  2175. resistanceUpdateLast = t;
  2176. updateTickerCurrentTime();
  2177. }
  2178. }
  2179. const resistanceUpdateFn_ = (forced = false) => {
  2180. if (forced === true || timestampUnderLiveMode) {
  2181. if (!resistanceUpdateBusy) {
  2182. resistanceUpdateBusy = true;
  2183. Promise.resolve().then(resistanceUpdateFn);
  2184. }
  2185. }
  2186. }
  2187. const startResistanceUpdater = () => {
  2188.  
  2189. if (startResistanceUpdaterStarted) return;
  2190. startResistanceUpdaterStarted = true;
  2191.  
  2192. if (RESISTANCE_UPDATE_OPT & 1)
  2193. document.addEventListener('yt-action', () => {
  2194. resistanceUpdateFn_(true);
  2195. }, true)
  2196.  
  2197. resistanceUpdateFn_(true);
  2198. setIntervalX0(resistanceUpdateFn_, 400);
  2199. }
  2200.  
  2201. if(resistanceUpdateDebugMode) startResistanceUpdater();
  2202.  
  2203.  
  2204. function dr(s) {
  2205. // reserved for future use
  2206. return s;
  2207. // return window.deWeakJS ? window.deWeakJS(s) : s;
  2208. }
  2209.  
  2210.  
  2211. const getProto = (element) => {
  2212. if (element) {
  2213. const cnt = insp(element);
  2214. return cnt.constructor.prototype || null;
  2215. }
  2216. return null;
  2217. }
  2218.  
  2219.  
  2220.  
  2221. const logFn = (key, f) => {
  2222. return Function.prototype.bind.call(console.log, console, `%c ${key}`, 'background: #222; color: #bada55', f);
  2223. }
  2224.  
  2225.  
  2226.  
  2227. const assertor = (f) => f() || (console.assert(false, `${f}`), false);
  2228.  
  2229. const fnIntegrity = (f, d) => {
  2230.  
  2231.  
  2232. if (!f || typeof f !== 'function') {
  2233. console.warn('f is not a function', f);
  2234. return;
  2235. }
  2236. // return; // M44
  2237. let p = `${f}`, s = 0, j = -1, w = 0;
  2238. // return; // M44
  2239. for (let i = 0, l = p.length; i < l; i++) {
  2240. const t = p[i];
  2241. if (((t >= 'a' && t <= 'z') || (t >= 'A' && t <= 'Z'))) {
  2242. if (j < i - 1) w++;
  2243. j = i;
  2244. } else {
  2245. s++;
  2246. }
  2247. }
  2248. // if(p.length > 44 && p.length < 50){
  2249.  
  2250. // (window.skam|| (window.skam=[])).push(p);
  2251. // return false;
  2252. // }
  2253.  
  2254. // if(p.length > 405 && p.length < 415 ){ //350 450
  2255.  
  2256.  
  2257. // //  [353, 411, 411, 411]
  2258.  
  2259. // // if(p.length >= 350 && p.length<=450){
  2260.  
  2261. // // (window.skam|| (window.skam=[])).push(p.length);
  2262. // // }
  2263. // (window.skam|| (window.skam=[])).push(p);
  2264. // return false;
  2265. // }
  2266.  
  2267. // if(p.length < 50) return true; else return false;
  2268. // return; // M44
  2269. let itz = `${f.length}.${s}.${w}`;
  2270. if (!d) {
  2271. return itz;
  2272. } else if (itz !== d) {
  2273. console.warn('fnIntegrity=false', itz);
  2274. return false;
  2275. } else {
  2276. return true;
  2277. }
  2278. }
  2279.  
  2280. const px2cm = (px) => px * window.devicePixelRatio * 0.026458333;
  2281. const px2mm = (px) => px * window.devicePixelRatio * 0.26458333;
  2282.  
  2283. // let createElement_fountain_model_fn = null;
  2284. // let createElement_fountain_model_enabled = null;
  2285.  
  2286. // ; (USE_RM_ON_FOUNTAIN_MODEL) && (()=>{
  2287. // document.createElement4719 = document.createElement;
  2288. // document.createElement = function (a) {
  2289. // if (createElement_fountain_model_enabled) {
  2290. // const r = createElement_fountain_model_fn(a);
  2291. // if (r) return r;
  2292. // }
  2293. // return document.createElement4719(a);
  2294. // }
  2295. // })();
  2296.  
  2297. ; (ENABLE_FLAGS_MAINTAIN_STABLE_LIST || ENABLE_FLAGS_REUSE_COMPONENTS || DISABLE_FLAGS_SHADYDOM_FREE) && (() => {
  2298.  
  2299. const _config_ = () => {
  2300. try {
  2301. return ytcfg.data_;
  2302. } catch (e) { }
  2303. return null;
  2304. };
  2305.  
  2306. const flagsFn = (EXPERIMENT_FLAGS) => {
  2307.  
  2308. // console.log(700)
  2309.  
  2310. if (!EXPERIMENT_FLAGS) return;
  2311.  
  2312. if (ENABLE_FLAGS_MAINTAIN_STABLE_LIST) {
  2313. if (USE_MAINTAIN_STABLE_LIST_ONLY_WHEN_KS_FLAG_IS_SET ? EXPERIMENT_FLAGS.kevlar_should_maintain_stable_list === true : true) {
  2314. // EXPERIMENT_FLAGS.kevlar_tuner_should_test_maintain_stable_list = true; // timestamp toggle issue
  2315. EXPERIMENT_FLAGS.kevlar_should_maintain_stable_list = true;
  2316. // console.log(701)
  2317. }
  2318. }
  2319.  
  2320. if (ENABLE_FLAGS_REUSE_COMPONENTS) {
  2321. EXPERIMENT_FLAGS.kevlar_tuner_should_test_reuse_components = true;
  2322. EXPERIMENT_FLAGS.kevlar_tuner_should_reuse_components = true;
  2323. // console.log(702);
  2324. }
  2325.  
  2326. if (DISABLE_FLAGS_SHADYDOM_FREE) {
  2327. EXPERIMENT_FLAGS.enable_shadydom_free_scoped_node_methods = false;
  2328. EXPERIMENT_FLAGS.enable_shadydom_free_scoped_query_methods = false;
  2329. EXPERIMENT_FLAGS.enable_shadydom_free_scoped_readonly_properties_batch_one = false;
  2330. EXPERIMENT_FLAGS.enable_shadydom_free_parent_node = false;
  2331. EXPERIMENT_FLAGS.enable_shadydom_free_children = false;
  2332. EXPERIMENT_FLAGS.enable_shadydom_free_last_child = false;
  2333. }
  2334.  
  2335. // EXPERIMENT_FLAGS.enable_button_behavior_reuse = false;
  2336.  
  2337. };
  2338.  
  2339. const uf = (config_) => {
  2340. config_ = config_ || _config_();
  2341. if (config_) {
  2342. const { EXPERIMENT_FLAGS, EXPERIMENTS_FORCED_FLAGS } = config_;
  2343. if (EXPERIMENT_FLAGS) {
  2344. flagsFn(EXPERIMENT_FLAGS);
  2345. if (EXPERIMENTS_FORCED_FLAGS) flagsFn(EXPERIMENTS_FORCED_FLAGS);
  2346. }
  2347. }
  2348. }
  2349.  
  2350. window._ytConfigHacks.add((config_) => {
  2351. uf(config_);
  2352. });
  2353.  
  2354. uf();
  2355.  
  2356. })();
  2357.  
  2358. if (DISABLE_Translation_By_Google) {
  2359.  
  2360. let mo = new MutationObserver(() => {
  2361.  
  2362. if (!mo) return;
  2363. let h = document.head;
  2364. if (!h) return;
  2365. mo.disconnect();
  2366. mo.takeRecords();
  2367. mo = null;
  2368.  
  2369. let meta = document.createElement('meta');
  2370. meta.setAttribute('name', 'google');
  2371. meta.setAttribute('content', 'notranslate');
  2372. h.appendChild(meta);
  2373.  
  2374.  
  2375. });
  2376. mo.observe(document, { subtree: true, childList: true });
  2377. }
  2378.  
  2379. console.assert(MAX_ITEMS_FOR_TOTAL_DISPLAY > 0)
  2380. // console.assert(MAX_ITEMS_FOR_TOTAL_DISPLAY > 0 && MAX_ITEMS_FOR_FULL_FLUSH > 0 && MAX_ITEMS_FOR_TOTAL_DISPLAY > MAX_ITEMS_FOR_FULL_FLUSH)
  2381.  
  2382. const isContainSupport = CSS.supports('contain', 'layout paint style');
  2383. if (!isContainSupport) {
  2384. console.warn("Your browser does not support css property 'contain'.\nPlease upgrade to the latest version.".trim());
  2385. }
  2386.  
  2387. const isOverflowAnchorSupport = CSS.supports('overflow-anchor', 'auto');
  2388. if (!isOverflowAnchorSupport) {
  2389. console.warn("Your browser does not support css property 'overflow-anchor'.\nPlease upgrade to the latest version.".trim());
  2390. }
  2391.  
  2392. const ENABLE_OVERFLOW_ANCHOR = ENABLE_OVERFLOW_ANCHOR_PREFERRED && isOverflowAnchorSupport && ENABLE_NO_SMOOTH_TRANSFORM && typeof ResizeObserver === 'function';
  2393. let WITH_SCROLL_ANCHOR = false;
  2394.  
  2395. const fxOperator = (proto, propertyName) => {
  2396. let propertyDescriptorGetter = null;
  2397. try {
  2398. propertyDescriptorGetter = Object.getOwnPropertyDescriptor(proto, propertyName).get;
  2399. } catch (e) { }
  2400. return typeof propertyDescriptorGetter === 'function' ? (e) => {
  2401. try {
  2402.  
  2403. return propertyDescriptorGetter.call(dr(e));
  2404. } catch (e) { }
  2405. return e[propertyName];
  2406. } : (e) => e[propertyName];
  2407. };
  2408.  
  2409. const nodeParent = fxOperator(Node.prototype, 'parentNode');
  2410. const nPrevElem = fxOperator(HTMLElement_.prototype, 'previousElementSibling');
  2411. const nNextElem = fxOperator(HTMLElement_.prototype, 'nextElementSibling');
  2412. const nLastElem = fxOperator(HTMLElement_.prototype, 'lastElementChild');
  2413.  
  2414. let groupCI = [];
  2415. let groupDI = 0;
  2416.  
  2417. const [console_] = [console];
  2418. const console1 = {
  2419. log(...args) {
  2420. if (!SHOW_DEVTOOL_DEBUG) return;
  2421. if (groupDI === 1) return grouppedConsoleLog(...args);
  2422. return console_.log(...args);
  2423. },
  2424. warn(...args) {
  2425. if (!SHOW_DEVTOOL_DEBUG) return;
  2426. if (groupDI === 1) return grouppedConsoleWarn(...args);
  2427. return console_.warn(...args);
  2428. },
  2429. debug(...args) {
  2430. if (!SHOW_DEVTOOL_DEBUG) return;
  2431. if (groupDI === 1) return grouppedConsoleDebug(...args);
  2432. return console_.debug(...args);
  2433. }
  2434. }
  2435. const grouppedConsoleLog = (...args) => {
  2436. if (DEBUG_LOG_HIDE_OK) {
  2437. for (const arg of args) {
  2438. if (typeof arg !== 'string') break;
  2439. if (arg.endsWith('OK')) return;
  2440. }
  2441. }
  2442. groupCI.push(['log', ...args]);
  2443. }
  2444. const grouppedConsoleWarn = (...args) => {
  2445. groupCI.push(['warn', ...args]);
  2446. }
  2447. const grouppedConsoleDebug = (...args) => {
  2448. groupCI.push(['debug', ...args]);
  2449. }
  2450. const groupCollapsed = (text1, text2) => {
  2451. if (!SHOW_DEVTOOL_DEBUG) return;
  2452. if (groupDI !== 0) console_.warn('groupDI in groupCollapsed fails', groupDI);
  2453. groupDI++;
  2454. groupCI.length = 0;
  2455.  
  2456. let w = 'groupCollapsed';
  2457. if (DEBUG_LOG_GROUP_EXPAND) w = 'group';
  2458. groupCI.push([w, `%c${text1}%c${text2}`,
  2459. "background-color: #010502; color: #6acafe; font-weight: 700; padding: 2px;",
  2460. "background-color: #010502; color: #6ad9fe; font-weight: 300; padding: 2px;"
  2461. ]);
  2462. }
  2463. const groupEnd = () => {
  2464. if (!SHOW_DEVTOOL_DEBUG) return;
  2465. groupDI--;
  2466. if (groupDI !== 0) console_.warn('groupDI in groupEnd fails', groupDI);
  2467. if (groupCI.length >= 0) {
  2468. let withContent = false;
  2469. for (const entry of groupCI) {
  2470. if (entry[0] === 'group' || entry[0] === 'groupCollapsed') continue;
  2471. if (entry[1] === '[Begin]' || entry[1] === '[End]') continue;
  2472. withContent = true;
  2473. break;
  2474. }
  2475. if (withContent) {
  2476. for (const entry of groupCI) {
  2477. const args = entry.slice(1);
  2478. let colorHighLight = '';
  2479. for (const arg of args) {
  2480. if (typeof arg !== 'string') {
  2481. colorHighLight = '';
  2482. break;
  2483. }
  2484. if (arg === 'OK' || arg === 'NG') {
  2485. colorHighLight = arg;
  2486. } else {
  2487. if (arg.endsWith(' OK')) colorHighLight = 'OK';
  2488. else if (arg.endsWith(' NG')) colorHighLight = 'NG';
  2489. }
  2490. }
  2491. let print = args;
  2492. if (colorHighLight) {
  2493. print = [args.map(e => `%c${e}`).join(' '), ...args.map(e => {
  2494. if (colorHighLight === 'OK' && e.includes(colorHighLight)) return "background-color:rgb(29, 29, 29); color:rgb(57, 215, 83); font-weight: 600;";
  2495. if (colorHighLight === 'NG' && e.includes(colorHighLight)) return "background-color:rgb(29, 29, 29); color:rgb(215, 133, 57); font-weight: 600;";
  2496. return "background-color:rgb(29, 29, 29); color:rgb(231, 231, 231); font-weight: 400;";
  2497. })];
  2498. }
  2499. console[entry[0]](...print);
  2500. }
  2501. console.groupEnd();
  2502. groupCI.length = 0;
  2503. }
  2504. }
  2505. }
  2506.  
  2507. // const microNow = () => performance.now() + (performance.timeOrigin || performance.timing.navigationStart);
  2508.  
  2509.  
  2510. const EVENT_KEY_ON_REGISTRY_READY = "ytI-ce-registry-created";
  2511. const onRegistryReady = (callback) => {
  2512. if (typeof customElements === 'undefined') {
  2513. if (!('__CE_registry' in document)) {
  2514. // https://github.com/webcomponents/polyfills/
  2515. Object.defineProperty(document, '__CE_registry', {
  2516. get() {
  2517. // return undefined
  2518. },
  2519. set(nv) {
  2520. if (typeof nv == 'object') {
  2521. delete this.__CE_registry;
  2522. this.__CE_registry = nv;
  2523. this.dispatchEvent(new CustomEvent(EVENT_KEY_ON_REGISTRY_READY));
  2524. }
  2525. return true;
  2526. },
  2527. enumerable: false,
  2528. configurable: true
  2529. })
  2530. }
  2531. let eventHandler = (evt) => {
  2532. document.removeEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  2533. const f = callback;
  2534. callback = null;
  2535. eventHandler = null;
  2536. f();
  2537. };
  2538. document.addEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  2539. } else {
  2540. callback();
  2541. }
  2542. };
  2543.  
  2544. const promiseForCustomYtElementsReady = new Promise(onRegistryReady);
  2545.  
  2546. const renderReadyPn = typeof ResizeObserver !== 'undefined' ? (sizingTarget) => {
  2547.  
  2548. return new Promise(resolve => {
  2549.  
  2550. let ro = new ResizeObserver(entries => {
  2551. if (entries && entries.length >= 1) {
  2552. resolve();
  2553. ro.disconnect();
  2554. ro = null;
  2555. }
  2556. });
  2557. ro.observe(sizingTarget);
  2558.  
  2559.  
  2560.  
  2561. });
  2562.  
  2563. } : (sizingTarget) => {
  2564.  
  2565.  
  2566. return new Promise(resolve => {
  2567.  
  2568. let io = new IntersectionObserver(entries => {
  2569. if (entries && entries.length >= 1) {
  2570. resolve();
  2571. io.disconnect();
  2572. io = null;
  2573. }
  2574. });
  2575. io.observe(sizingTarget);
  2576.  
  2577.  
  2578.  
  2579. });
  2580.  
  2581. };
  2582.  
  2583. /* globals WeakRef:false */
  2584.  
  2585. /** @type {(o: Object | null) => WeakRef | null} */
  2586. const mWeakRef = typeof WeakRef === 'function' ? (o => o ? new WeakRef(o) : null) : (o => o || null);
  2587.  
  2588. /** @type {(wr: Object | null) => Object | null} */
  2589. const kRef = (wr => (wr && wr.deref) ? wr.deref() : wr);
  2590.  
  2591. const { insertBeforeNaFn, appendChildNaFn } = (() => {
  2592. // native methods
  2593.  
  2594. const insertBefore = HTMLElement_.prototype.insertBefore;
  2595. const appendChild = HTMLElement_.prototype.appendChild;
  2596.  
  2597. return {
  2598. insertBeforeNaFn: (parent, node, child) => {
  2599. insertBefore.call(parent, node, child);
  2600. },
  2601. appendChildNaFn: (parent, node) => {
  2602. appendChild.call(parent, node);
  2603. }
  2604. };
  2605.  
  2606. /*
  2607. const insertBeforeFn = (parent, node, child) => {
  2608. if ('__shady_native_insertBefore' in parent) parent.__shady_native_insertBefore(node, child);
  2609. else parent.insertBefore(node, child);
  2610. }
  2611.  
  2612. const appendChildFn = (parent, node) =>{
  2613. if('__shady_native_appendChild' in parent) parent.__shady_native_appendChild(node);
  2614. else parent.appendChild(node);
  2615. }
  2616. */
  2617.  
  2618. })();
  2619.  
  2620.  
  2621.  
  2622. let __LCRInjection__ = 0; // 0 for no injection
  2623. const LCRImmedidates = []; // array of sync. func
  2624.  
  2625. let getLCRDummyP_ = null;
  2626. // lcrPromiseFn
  2627. const getLCRDummy = () => {
  2628.  
  2629. /* remarks */
  2630.  
  2631. /*
  2632.  
  2633. // YouTube uses `<ps-dom-if class="style-scope ytd-live-chat-frame"><template></template></ps-dom-if>` to create yt-live-chat-renderer
  2634. // <ps-dom-if> is located inside ytd-live-chat-frame#chat in main frame
  2635. // <ps-dom-if>.hostElement is located as iframe's yt-live-chat-app > div#contents > yt-live-chat-renderer
  2636.  
  2637. */
  2638.  
  2639.  
  2640. // direct createElement or createComponent_ will make the emoji rendering crashed. reason TBC
  2641.  
  2642. return getLCRDummyP_ || (getLCRDummyP_ = Promise.all([customElements.whenDefined('yt-live-chat-app'), customElements.whenDefined('yt-live-chat-renderer')]).then(async () => {
  2643.  
  2644. const tag = "yt-live-chat-renderer"
  2645. let dummy = document.querySelector(tag);
  2646. if (!dummy) {
  2647.  
  2648. let mo = null;
  2649.  
  2650. const ytLiveChatApp = document.querySelector('yt-live-chat-app') || document.createElement('yt-live-chat-app');
  2651.  
  2652. const lcaProto = getProto(ytLiveChatApp);
  2653. let fz38;
  2654.  
  2655. let qt38=0;
  2656. let bypass = false;
  2657.  
  2658.  
  2659. dummy = await new Promise(resolve => {
  2660.  
  2661.  
  2662. if (typeof lcaProto.createComponent_ === 'function' && !lcaProto.createComponent99_ && lcaProto.createComponent_.length === 3) {
  2663. console.log('[yt-chat-lcr] lcaProto.createComponent_ is found');
  2664.  
  2665. lcaProto.createComponent99_ = lcaProto.createComponent_;
  2666. lcaProto.createComponent98_ = function (a, b, c) {
  2667. const z = customCreateComponent(a,b,c);
  2668. if(z !== undefined) return z;
  2669. // (3) ['yt-live-chat-renderer', {…}, true]
  2670. const r = this.createComponent99_(a, b,c);
  2671. const componentTag = (typeof a === 'string' ? a : (a||0).component) || `${(r||0).nodeName}`.toLowerCase();
  2672. if ( componentTag === 'yt-live-chat-renderer' && !bypass) {
  2673. qt38 = 1;
  2674.  
  2675. __LCRInjection__ = __LCRInjection__ | 1;
  2676.  
  2677. // r.polymerController.__proto__.handleLiveChatActions471_ = r.polymerController.__proto__.handleLiveChatActions_;
  2678. // r.polymerController.__proto__.handleLiveChatActions_ = function (arr) {
  2679.  
  2680.  
  2681. // preprocessChatLiveActions(arr);
  2682.  
  2683. // return this.handleLiveChatActions471_(arr);
  2684.  
  2685.  
  2686. // }
  2687.  
  2688. for (const f of LCRImmedidates) {
  2689. f(r);
  2690. }
  2691. LCRImmedidates.length = 0;
  2692.  
  2693. resolve(r); // note: this dom is not yet adopted, but promise resolve is later than ops.
  2694. console.log('[yt-chat-lcr] element found by method 1');
  2695. }
  2696. return r;
  2697. };
  2698. lcaProto.createComponent_ = lcaProto.createComponent98_;
  2699.  
  2700. if (!USE_OBTAIN_LCR_BY_BOTH_METHODS) return;
  2701.  
  2702. }
  2703.  
  2704. // console.log('[yt-chat] lcaProto traditional');
  2705.  
  2706. const pz38 = document.getElementsByTagName(tag);
  2707. fz38 = () => {
  2708. const t = pz38[0]
  2709. if (t) {
  2710. qt38 = 2;
  2711.  
  2712. __LCRInjection__ = __LCRInjection__ | 2;
  2713. resolve(t);
  2714. console.log('[yt-chat-lcr] element found by method 2');
  2715. }
  2716. };
  2717. mo = new MutationObserver(fz38);
  2718. mo.observe(document, { subtree: true, childList: true, attributes: true });
  2719. document.addEventListener('yt-action', fz38, true);
  2720. fz38();
  2721.  
  2722. });
  2723.  
  2724. bypass = true;
  2725.  
  2726. if (mo) {
  2727. mo.disconnect();
  2728. mo.takeRecords();
  2729. mo = null;
  2730. }
  2731. if (fz38) {
  2732. document.removeEventListener('yt-action', fz38, true);
  2733. fz38 = null;
  2734. }
  2735. console.log(`[yt-chat-lcr] lcr appears, dom = ${document.getElementsByTagName(tag).length}, method = ${qt38}`);
  2736.  
  2737.  
  2738. // if (lcaProto.createComponent99_ && lcaProto.createComponent_ && lcaProto.createComponent98_ === lcaProto.createComponent_) {
  2739. // lcaProto.createComponent_ = lcaProto.createComponent99_;
  2740. // lcaProto.createComponent99_ = null;
  2741. // lcaProto.createComponent98_ = null;
  2742. // }
  2743.  
  2744. } else {
  2745. console.log('[yt-chat-lcr] lcr exists');
  2746. }
  2747. return dummy;
  2748.  
  2749. }));
  2750. }
  2751.  
  2752. const { addCssManaged } = (() => {
  2753.  
  2754. const addFontPreRendering = () => {
  2755.  
  2756. groupCollapsed("YouTube Super Fast Chat", " | Fonts Pre-Rendering");
  2757.  
  2758. let efsContainer = document.createElement('elzm-fonts');
  2759. efsContainer.id = 'elzm-fonts-yk75g'
  2760.  
  2761. const arr = [];
  2762. let p = document.createElement('elzm-font');
  2763. arr.push(p);
  2764.  
  2765. if (ENABLE_FONT_PRE_RENDERING & 1) {
  2766. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2767.  
  2768. p = document.createElement('elzm-font');
  2769. p.style.fontWeight = size;
  2770. arr.push(p);
  2771. }
  2772. }
  2773.  
  2774. if (ENABLE_FONT_PRE_RENDERING & 2) {
  2775. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2776.  
  2777. p = document.createElement('elzm-font');
  2778. p.style.fontFamily = 'Roboto';
  2779. p.style.fontWeight = size;
  2780. arr.push(p);
  2781. }
  2782. }
  2783.  
  2784. if (ENABLE_FONT_PRE_RENDERING & 4) {
  2785. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2786.  
  2787. p = document.createElement('elzm-font');
  2788. p.style.fontFamily = '"YouTube Noto",Roboto,Arial,Helvetica,sans-serif';
  2789. p.style.fontWeight = size;
  2790. arr.push(p);
  2791. }
  2792. }
  2793.  
  2794.  
  2795. if (ENABLE_FONT_PRE_RENDERING & 8) {
  2796. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2797.  
  2798. p = document.createElement('elzm-font');
  2799. p.style.fontFamily = '"Noto",Roboto,Arial,Helvetica,sans-serif';
  2800. p.style.fontWeight = size;
  2801. arr.push(p);
  2802. }
  2803. }
  2804.  
  2805.  
  2806. if (ENABLE_FONT_PRE_RENDERING & 16) {
  2807. for (const size of [100, 200, 300, 400, 500, 600, 700, 800, 900]) {
  2808.  
  2809. p = document.createElement('elzm-font');
  2810. p.style.fontFamily = 'sans-serif';
  2811. p.style.fontWeight = size;
  2812. arr.push(p);
  2813. }
  2814. }
  2815.  
  2816. console1.log('number of elzm-font elements', arr.length);
  2817.  
  2818. HTMLElement_.prototype.append.apply(efsContainer, arr);
  2819.  
  2820. (document.body || document.documentElement).appendChild(efsContainer);
  2821.  
  2822.  
  2823. console1.log('elzm-font elements have been added to the page for rendering.');
  2824.  
  2825. groupEnd();
  2826.  
  2827. }
  2828.  
  2829. let isCssAdded = false;
  2830.  
  2831. function addCssElement() {
  2832. let s = document.createElement('style');
  2833. s.id = 'ewRvC';
  2834. return s;
  2835. }
  2836.  
  2837. const addCssManaged = () => {
  2838. if (!isCssAdded && document.documentElement && document.head) {
  2839. isCssAdded = true;
  2840. document.head.appendChild(dr(addCssElement())).textContent = addCss();
  2841. if (ENABLE_FONT_PRE_RENDERING) {
  2842. Promise.resolve().then(addFontPreRendering)
  2843. }
  2844. }
  2845. }
  2846.  
  2847. return { addCssManaged };
  2848. })();
  2849.  
  2850.  
  2851. const { setupStyle } = (() => {
  2852.  
  2853. const sp7 = Symbol();
  2854.  
  2855. const proxyHelperFn = (dummy) => ({
  2856.  
  2857. get(target, prop) {
  2858. return (prop in dummy) ? dummy[prop] : prop === sp7 ? target : target[prop];
  2859. },
  2860. set(target, prop, value) {
  2861. if (!(prop in dummy)) {
  2862. target[prop] = value;
  2863. }
  2864. return true;
  2865. },
  2866. has(target, prop) {
  2867. return (prop in target);
  2868. },
  2869. deleteProperty(target, prop) {
  2870. return true;
  2871. },
  2872. ownKeys(target) {
  2873. return Object.keys(target);
  2874. },
  2875. defineProperty(target, key, descriptor) {
  2876. return Object.defineProperty(target, key, descriptor);
  2877. },
  2878. getOwnPropertyDescriptor(target, key) {
  2879. return Object.getOwnPropertyDescriptor(target, key);
  2880. },
  2881.  
  2882. });
  2883.  
  2884. const setupStyle = (m1, m2) => {
  2885. if (!ENABLE_NO_SMOOTH_TRANSFORM) return;
  2886.  
  2887. const dummy1v = {
  2888. transform: '',
  2889. height: '',
  2890. minHeight: '',
  2891. paddingBottom: '',
  2892. paddingTop: ''
  2893. };
  2894.  
  2895. const dummyStyleFn = (k) => (function () { const style = this[sp7]; return style[k](...arguments); });
  2896. for (const k of ['toString', 'getPropertyPriority', 'getPropertyValue', 'item', 'removeProperty', 'setProperty']) {
  2897. dummy1v[k] = dummyStyleFn(k);
  2898. }
  2899.  
  2900. const dummy1p = proxyHelperFn(dummy1v);
  2901. const sp1v = new Proxy(m1.style, dummy1p);
  2902. const sp2v = new Proxy(m2.style, dummy1p);
  2903. Object.defineProperty(m1, 'style', { get() { return sp1v }, set() { }, enumerable: true, configurable: true });
  2904. Object.defineProperty(m2, 'style', { get() { return sp2v }, set() { }, enumerable: true, configurable: true });
  2905. m1.removeAttribute("style");
  2906. m2.removeAttribute("style");
  2907.  
  2908. }
  2909.  
  2910. return { setupStyle };
  2911.  
  2912. })();
  2913.  
  2914.  
  2915.  
  2916. function setThumbnails(config) {
  2917.  
  2918. const { baseObject, thumbnails, flag0, imageLinks } = config;
  2919.  
  2920. if (flag0 || (ENABLE_PRELOAD_THUMBNAIL && imageLinks)) {
  2921.  
  2922.  
  2923. if (thumbnails && thumbnails.length > 0) {
  2924. if (flag0 > 0 && thumbnails.length > 1) {
  2925. let pSize = 0;
  2926. let newThumbnails = [];
  2927. for (const thumbnail of thumbnails) {
  2928. if (!thumbnail || !thumbnail.url) continue;
  2929. const squarePhoto = thumbnail.width === thumbnail.height && typeof thumbnail.width === 'number';
  2930. const condSize = pSize <= 0 || (flag0 === 1 ? pSize > thumbnail.width : pSize < thumbnail.width);
  2931. const leastSizeFulfilled = squarePhoto ? thumbnail.width >= LEAST_IMAGE_SIZE : true;
  2932. if ((!squarePhoto || condSize) && leastSizeFulfilled) {
  2933. newThumbnails.push(thumbnail);
  2934. if (imageLinks) imageLinks.add(thumbnail.url);
  2935. }
  2936. if (squarePhoto && condSize && leastSizeFulfilled) {
  2937. pSize = thumbnail.width;
  2938. }
  2939. }
  2940. if (thumbnails.length !== newThumbnails.length && thumbnails === baseObject.thumbnails && newThumbnails.length > 0) {
  2941. baseObject.thumbnails = newThumbnails;
  2942. } else {
  2943. newThumbnails.length = 0;
  2944. }
  2945. newThumbnails = null;
  2946. } else {
  2947. for (const thumbnail of thumbnails) {
  2948. if (thumbnail && thumbnail.url) {
  2949. if (imageLinks) imageLinks.add(thumbnail.url);
  2950. }
  2951. }
  2952. }
  2953. }
  2954.  
  2955. }
  2956. }
  2957.  
  2958. function fixLiveChatItem(item, imageLinks) {
  2959. const liveChatTextMessageRenderer = (item || 0).liveChatTextMessageRenderer || 0;
  2960. if (liveChatTextMessageRenderer) {
  2961. const messageRuns = (liveChatTextMessageRenderer.message || 0).runs || 0;
  2962. if (messageRuns && messageRuns.length > 0) {
  2963. for (const run of messageRuns) {
  2964. const emojiImage = (((run || 0).emoji || 0).image || 0);
  2965. setThumbnails({
  2966. baseObject: emojiImage,
  2967. thumbnails: emojiImage.thumbnails,
  2968. flag0: EMOJI_IMAGE_SINGLE_THUMBNAIL,
  2969. imageLinks
  2970. });
  2971. }
  2972. }
  2973. const authorPhoto = liveChatTextMessageRenderer.authorPhoto || 0;
  2974. setThumbnails({
  2975. baseObject: authorPhoto,
  2976. thumbnails: authorPhoto.thumbnails,
  2977. flag0: AUTHOR_PHOTO_SINGLE_THUMBNAIL,
  2978. imageLinks
  2979. });
  2980. }
  2981. }
  2982.  
  2983.  
  2984.  
  2985. let kptPF = null;
  2986. const emojiPrefetched = new LimitedSizeSet(PREFETCH_LIMITED_SIZE_EMOJI);
  2987. const authorPhotoPrefetched = new LimitedSizeSet(PREFETCH_LIMITED_SIZE_AUTHOR_PHOTO);
  2988.  
  2989. const linkerOnload = function () {
  2990. this.resolveFn({
  2991. link: this,
  2992. success: true
  2993. });
  2994. this.remove();
  2995. };
  2996. const linkerOnError = function () {
  2997. this.resolveFn({
  2998. link: this,
  2999. success: false
  3000. });
  3001. this.remove();
  3002. };
  3003. function linker(link, rel, href, _as) {
  3004. return new Promise(resolve => {
  3005. if (!link) link = document.createElement('link');
  3006. link.rel = rel;
  3007. if (_as) link.setAttribute('as', _as);
  3008. link.resolveFn = resolve;
  3009. link.onload = linkerOnload;
  3010. link.onerror = linkerOnError;
  3011. link.href = href;
  3012. document.head.appendChild(link);
  3013. link = null;
  3014. });
  3015. }
  3016.  
  3017. // ------- side process [sideProcesses] -------
  3018. const reuseFixDataViewModel = (elm) => {
  3019. // detach data-view model signal
  3020. return Promise.resolve(elm).then((elm) => {
  3021. for (const node of elm.getElementsByTagName('*')) {
  3022. const cnt = insp(node);
  3023. if (typeof cnt.dispose === 'function' && cnt.dispose.length === 0) {
  3024. try {
  3025. cnt.dispose();
  3026. } catch (e) { }
  3027. } else if (typeof node.dispose === 'function' && node.dispose.length === 0) {
  3028. try {
  3029. node.dispose();
  3030. } catch (e) { }
  3031. }
  3032. }
  3033. }).catch(console.warn);;
  3034. };
  3035. const reuseFixYtIconRendering = (elm) => {
  3036. // make properties fresh for flushing
  3037. // return Promise.resolve(elm).then((elm) => {
  3038. // refreshChildrenYtIcons(elm);
  3039. // }).catch(console.warn);;
  3040. };
  3041. const tickerMessageRemovalMo = new MutationObserver(() => {
  3042. const elements = document.querySelectorAll('[ticker-message-removed]:nth-child(n + 40)');
  3043. for (const s of elements) {
  3044. insp(s).requestRemoval();
  3045. }
  3046. });
  3047. tickerMessageRemovalMo.observe(document, { subtree: true, attributes: true, attributeFilter: ['ticker-message-removed'] });
  3048. const onVisibleItemStampNodeRemoval = (elmId) => {
  3049. // set the corresponding ticker [ticker-message-removed]
  3050. return Promise.resolve(elmId).then((elmId) => {
  3051. const tickerElm = document.querySelector(`.style-scope.yt-live-chat-ticker-renderer[id="${elmId}"]`);
  3052. if (tickerElm) {
  3053. tickerElm.setAttribute('ticker-message-removed', '');
  3054. }
  3055. }).catch(console.warn);;
  3056. };
  3057. let onTickerItemStampNodeAddedwaiting = false;
  3058. const onTickerItemStampNodeAdded = () =>{
  3059. // remove the stale ticker(s)
  3060. if (onTickerItemStampNodeAddedwaiting) return;
  3061. onTickerItemStampNodeAddedwaiting = true;
  3062. return Promise.resolve().then(() => {
  3063. onTickerItemStampNodeAddedwaiting = false;
  3064. const selector = "[ticker-message-removed]:nth-child(n + 40)";
  3065. const tickerElm = document.querySelector(selector);
  3066. if (tickerElm) { // likely false
  3067. const tickerElms = document.querySelectorAll(selector);
  3068. for (const tickerElm of tickerElms) insp(tickerElm).requestRemoval();
  3069. }
  3070. }).catch(console.warn);;
  3071. };
  3072. // const mutationDelayedRefreshData = async (cnt) => {
  3073. // // ensure data is invalidated correctly after mutation
  3074. // return Promise.resolve(cnt).then(async cnt => {
  3075. // wme.data = `${(wme.data & 7) + 1}`;
  3076. // await wmp;
  3077. // cnt.__refreshData930__ && cnt.data && cnt.isAttached && cnt.parentComponent && cnt.__refreshData930__('data', !0);
  3078. // });
  3079. // }
  3080. // ------- side process [sideProcesses] -------
  3081.  
  3082. const cleanContext = async (win) => {
  3083. const waitFn = requestAnimationFrame; // shall have been binded to window
  3084. try {
  3085. let mx = 16; // MAX TRIAL
  3086. const frameId = 'vanillajs-iframe-v1';
  3087. /** @type {HTMLIFrameElement | null} */
  3088. let frame = document.getElementById(frameId);
  3089. let removeIframeFn = null;
  3090. if (!frame) {
  3091. frame = document.createElement('iframe');
  3092. frame.id = frameId;
  3093. const blobURL = typeof webkitCancelAnimationFrame === 'function' && typeof kagi === 'undefined' ? (frame.src = URL.createObjectURL(new Blob([], { type: 'text/html' }))) : null; // avoid Brave Crash
  3094. frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe
  3095. let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting)
  3096. n.appendChild(frame);
  3097. while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine
  3098. const root = document.documentElement;
  3099. root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL
  3100. if (blobURL) Promise.resolve().then(() => URL.revokeObjectURL(blobURL));
  3101.  
  3102. removeIframeFn = (setTimeout) => {
  3103. const removeIframeOnDocumentReady = (e) => {
  3104. e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
  3105. e = n;
  3106. n = win = removeIframeFn = 0;
  3107. setTimeout ? setTimeout(() => e.remove(), 200) : e.remove();
  3108. }
  3109. if (!setTimeout || document.readyState !== 'loading') {
  3110. removeIframeOnDocumentReady();
  3111. } else {
  3112. win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
  3113. }
  3114. }
  3115. }
  3116. while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn);
  3117. const fc = frame.contentWindow;
  3118. if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL
  3119. try {
  3120. const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, getComputedStyle } = fc;
  3121. const res = { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, getComputedStyle };
  3122. for (let k in res) res[k] = res[k].bind(win); // necessary
  3123. if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn);
  3124.  
  3125. /** @type {HTMLElement} */
  3126. const HTMLElementProto = fc.HTMLElement.prototype;
  3127. /** @type {EventTarget} */
  3128. const EventTargetProto = fc.EventTarget.prototype;
  3129. // jsonParseFix = {
  3130. // _JSON: fc.JSON, _parse: fc.JSON.parse
  3131. // }
  3132. return {
  3133. ...res,
  3134. animate: HTMLElementProto.animate,
  3135. addEventListener: EventTargetProto.addEventListener,
  3136. removeEventListener: EventTargetProto.removeEventListener
  3137. };
  3138. } catch (e) {
  3139. if (removeIframeFn) removeIframeFn();
  3140. return null;
  3141. }
  3142. } catch (e) {
  3143. console.warn(e);
  3144. return null;
  3145. }
  3146. };
  3147.  
  3148. cleanContext(win).then(__CONTEXT__ => {
  3149. if (!__CONTEXT__) return null;
  3150.  
  3151. const { requestAnimationFrame, setTimeout, cancelAnimationFrame, setInterval, clearInterval, animate, getComputedStyle, addEventListener, removeEventListener } = __CONTEXT__;
  3152.  
  3153. const wmComputedStyle = new WeakMap();
  3154. const getComputedStyleCached = (elem) => {
  3155. let cs = wmComputedStyle.get(elem);
  3156. if (!cs) {
  3157. cs = getComputedStyle(elem);
  3158. wmComputedStyle.set(elem, cs);
  3159. }
  3160. return cs;
  3161. }
  3162.  
  3163.  
  3164. const isGPUAccelerationAvailable = (() => {
  3165. // https://gist.github.com/cvan/042b2448fcecefafbb6a91469484cdf8
  3166. try {
  3167. const canvas = document.createElement('canvas');
  3168. return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
  3169. } catch (e) {
  3170. return false;
  3171. }
  3172. })();
  3173.  
  3174. const foregroundPromiseFn_noGPU = (() => {
  3175.  
  3176. if (isGPUAccelerationAvailable) return null;
  3177.  
  3178. const pd = Object.getOwnPropertyDescriptor(Document.prototype, 'visibilityState');
  3179. if (!pd || typeof pd.get !== 'function') return null;
  3180. const pdGet = pd.get;
  3181.  
  3182. let pr = null;
  3183.  
  3184. let hState = pdGet.call(document) === 'hidden';
  3185. // let cid = 0;
  3186. pureAddEventListener.call(document, 'visibilitychange', (evt) => {
  3187. const newHState = pdGet.call(document) === 'hidden';
  3188. if (hState !== newHState) {
  3189. // if (cid > 0) cid = clearInterval(cid);
  3190. hState = newHState;
  3191. if (!hState && pr) pr = pr.resolve();
  3192. }
  3193. });
  3194.  
  3195. // cid = setInterval(() => {
  3196. // const newHState = document.visibilityState === 'hidden';
  3197. // if (hState !== newHState) {
  3198. // hState = newHState;
  3199. // if (!hState && pr) pr = pr.resolve();
  3200. // }
  3201. // }, 100);
  3202.  
  3203.  
  3204. return (() => {
  3205. if (pr) return pr;
  3206. const w = ((!hState && setTimeout(() => {
  3207. if (!hState && pr === w) pr = pr.resolve();
  3208. })), (pr = new PromiseExternal()));
  3209. return w;
  3210. });
  3211.  
  3212. })();
  3213.  
  3214. // window.foregroundPromiseFn_noGPU = foregroundPromiseFn_noGPU;
  3215.  
  3216. let rafPromise = null;
  3217. const getRafPromise = () => rafPromise || (rafPromise = new Promise(resolve => {
  3218. requestAnimationFrame(hRes => {
  3219. rafPromise = null;
  3220. resolve(hRes);
  3221. });
  3222. }));
  3223. const foregroundPromiseFn = foregroundPromiseFn_noGPU || getRafPromise;
  3224.  
  3225. // const iAFP = foregroundPromiseFn_noGPU ? foregroundPromiseFn_noGPU : typeof IntersectionObserver === 'undefined' ? getRafPromise : (() => {
  3226.  
  3227. // const ioWM = new WeakMap();
  3228. // const ek = Symbol();
  3229. // /** @type {IntersectionObserverCallback} */
  3230. // const ioCb = (entries, observer) => {
  3231. // /** @type {PromiseExternal} */
  3232. // const pr = observer[ek];
  3233. // const resolve = pr.resolve;
  3234. // let target;
  3235. // if (resolve && (target = ((entries ? entries[0] : 0) || 0).target) instanceof Element) {
  3236. // pr.resolve = null;
  3237. // observer.unobserve(target);
  3238. // resolve();
  3239. // }
  3240. // };
  3241. // /**
  3242. // *
  3243. // * @param {Element} elm
  3244. // * @returns {Promise<void>}
  3245. // */
  3246. // const iAFP = (elm) => {
  3247. // let io = ioWM.get(elm);
  3248. // if (!io) {
  3249. // io = new IntersectionObserver(ioCb);
  3250. // ioWM.set(elm, io); // strong reference
  3251. // }
  3252. // let pr = io[ek];
  3253. // if (!pr) {
  3254. // pr = io[ek] = new PromiseExternal();
  3255. // io.observe(elm);
  3256. // }
  3257. // return pr;
  3258. // }
  3259.  
  3260. // return iAFP;
  3261.  
  3262. // })();
  3263.  
  3264. let playerState = null;
  3265. let _playerState = null;
  3266. let lastPlayerProgress = null;
  3267. let relayCount = 0;
  3268. let playerEventsByIframeRelay = false;
  3269. let isPlayProgressTriggered = false;
  3270. let waitForInitialDataCompletion = 0;
  3271.  
  3272.  
  3273.  
  3274. // let aeConstructor = null;
  3275.  
  3276. // << __openedChanged82 >>
  3277. let currentMenuPivotWR = null;
  3278.  
  3279. // << if DO_PARTICIPANT_LIST_HACKS >>
  3280. const beforeParticipantsMap = new WeakMap();
  3281. // << end >>
  3282.  
  3283.  
  3284.  
  3285. // << if onRegistryReadyForDOMOperations >>
  3286.  
  3287. let dt0 = Date.now() - 2000;
  3288. const dateNow = () => Date.now() - dt0;
  3289. // let lastScroll = 0;
  3290. // let lastLShow = 0;
  3291. let lastWheel = 0;
  3292. let lastMouseUp = 0;
  3293. let currentMouseDown = false;
  3294. let lastTouchDown = 0;
  3295. let lastTouchUp = 0;
  3296. let currentTouchDown = false;
  3297. let lastUserInteraction = 0;
  3298.  
  3299. let scrollChatFn = null;
  3300.  
  3301. // let skipDontRender = true; // true first; false by flushActiveItems_
  3302. // let allowDontRender = null;
  3303.  
  3304. // ---- #items mutation ----
  3305. // let firstList = true;
  3306.  
  3307. // << end >>
  3308.  
  3309.  
  3310. const stackMarcoTask = (f) => {
  3311. return new Promise(resolve => {
  3312. nextBrowserTick_(async () => {
  3313. try {
  3314. await f();
  3315. } catch (e) {
  3316. console.warn(e);
  3317. } finally {
  3318. resolve();
  3319. }
  3320. });
  3321. })
  3322. };
  3323.  
  3324.  
  3325. const elementFirstElementChild = Object.getOwnPropertyDescriptor(Element.prototype, 'firstElementChild');
  3326. const sFirstElementChild = Symbol();
  3327. Object.defineProperty(Element.prototype, sFirstElementChild, elementFirstElementChild);
  3328.  
  3329. const elementLastElementChild = Object.getOwnPropertyDescriptor(Element.prototype, 'lastElementChild');
  3330. const sLastElementChild = Symbol();
  3331. Object.defineProperty(Element.prototype, sLastElementChild, elementLastElementChild);
  3332.  
  3333. const elementPrevElementSibling = Object.getOwnPropertyDescriptor(Element.prototype, 'previousElementSibling');
  3334. const sPrevElementSibling = Symbol();
  3335. Object.defineProperty(Element.prototype, sPrevElementSibling, elementPrevElementSibling);
  3336.  
  3337. const elementNextElementSibling = Object.getOwnPropertyDescriptor(Element.prototype, 'nextElementSibling');
  3338. const sNextElementSibling = Symbol();
  3339. Object.defineProperty(Element.prototype, sNextElementSibling, elementNextElementSibling);
  3340.  
  3341. const firstComponentChildFn = (elNode) => {
  3342. elNode = elNode[sFirstElementChild];
  3343. while ((elNode instanceof Element) && !elNode.is) elNode = elNode[sNextElementSibling];
  3344. return elNode;
  3345. }
  3346. const lastComponentChildFn = (elNode) => {
  3347. elNode = elNode[sLastElementChild];
  3348. while ((elNode instanceof Element) && !elNode.is) elNode = elNode[sPrevElementSibling];
  3349. return elNode;
  3350. }
  3351. const nextComponentSiblingFn = (elNode) => {
  3352. do {
  3353. elNode = elNode[sNextElementSibling];
  3354. } while ((elNode instanceof Element) && !elNode.is);
  3355. return elNode;
  3356. }
  3357.  
  3358. const nativeNow = performance.constructor.prototype.now.bind(performance);
  3359.  
  3360. const queueMicrotask_ = typeof queueMicrotask === 'function' ? queueMicrotask : (f) => (Promise.resolve().then(f), void 0);
  3361.  
  3362. const executeTaskBatch = function (taskArr, firstMarco = true) {
  3363. if (!(taskArr || 0).length) throw new TypeError(`Illegal invocation`);
  3364. return new Promise(resolveFinal => {
  3365. let resolveFn = null;
  3366. const len = taskArr.length;
  3367. const results = new Array(len);
  3368. const makePromise = () => new Promise(resolve => { resolveFn = resolve });
  3369. let firedCount = 0;
  3370. const executor = () => {
  3371. if (taskArr.length !== len) throw new TypeError(`Illegal invocation`);
  3372. const resolveFn_ = resolveFn;
  3373. let t0 = 0;
  3374. let next = 0;
  3375. taskArr.forEach((task, idx) => {
  3376. if (typeof (task || 0) !== 'object') throw new TypeError(`Illegal invocation`);
  3377. if (!task.fired) {
  3378. queueMicrotask_(() => {
  3379. if (next || task.fired) return;
  3380. task.fired = true;
  3381. if (++firedCount === len) next |= 2;
  3382. if (!t0) t0 = nativeNow() + 10;
  3383. const { fn } = task;
  3384. results[idx] = fn(task); // sync task only
  3385. if (nativeNow() > t0) next |= 1;
  3386. });
  3387. }
  3388. });
  3389. queueMicrotask_(() => resolveFn_(next))
  3390. }
  3391. const looper = (next) => {
  3392. if (!next) throw new TypeError(`Illegal invocation`);
  3393. if (next & 2) {
  3394. if (next & 1) {
  3395. nextBrowserTick_(() => resolveFinal(results))
  3396. } else {
  3397. resolveFinal(results);
  3398. }
  3399. } else {
  3400. const p = makePromise();
  3401. nextBrowserTick_(executor);
  3402. p.then(looper);
  3403. }
  3404. }
  3405. const p = makePromise();
  3406. firstMarco ? nextBrowserTick_(executor) : executor();
  3407. p.then(looper);
  3408.  
  3409. })
  3410.  
  3411. }
  3412. // window.executeTaskBatch = executeTaskBatch;
  3413.  
  3414.  
  3415. const renderMap = new WeakMap();
  3416.  
  3417.  
  3418. // reserved for future use
  3419. const countKeys = (H) => {
  3420.  
  3421. const countKeys_ = (H, u, q, l) => {
  3422. if (u.has(H)) return;
  3423. u.add(H);
  3424. const pds = Object.getOwnPropertyDescriptors(H);
  3425. for (const name in pds) {
  3426. const pd_ = pds[name];
  3427. const o = pd_.value;
  3428. if (o && pd_.configurable && pd_.writable && !(o instanceof EventTarget)) {
  3429. if (typeof o === 'object') {
  3430. q.push([l, name.length]);
  3431. countKeys_(o, u, q, l+1);
  3432. }
  3433. }
  3434. }
  3435. };
  3436. const m = [];
  3437. countKeys_(H, new WeakSet(), m, 0);
  3438. return `-${tupleHash(m, false).toString(36)}${tupleHash(m, true).toString(36)}`; // 12 chars
  3439. }
  3440.  
  3441. // reserved for future use
  3442. function tupleHash(pairs, reversed) {
  3443. let hash = 17; // Prime seed
  3444. const prime1 = 31;
  3445. for (let i = 0; i < pairs.length; i++) {
  3446. const [a_, b_] = pairs[i];
  3447. const a = reversed ? b_ : a_;
  3448. const b = reversed ? a_ : b_;
  3449. // Combine a and b into pairHash
  3450. let pairHash = ((a * prime1) ^ b) >>> 0;
  3451. // Mix pairHash into hash with bitwise operations
  3452. hash ^= pairHash;
  3453. hash = ((hash << 5) | (hash >>> 27)) >>> 0; // Rotate left 5 bits
  3454. hash = (hash * 37 + 11) >>> 0; // Small prime multiplier and offset
  3455. }
  3456. // Finalize to ensure fixed range (optional: constrain to 30 bits)
  3457. return 0x2FFFFFFF + (hash & 0x3FFFFFFF); // Mask to 30 bits (max: 1073741823)
  3458. }
  3459.  
  3460.  
  3461. const rendererStamperFactory = (cProto, options) => {
  3462.  
  3463. let pDivResourceEventCount = 0;
  3464.  
  3465. const pDivOnResource = function (evt) {
  3466. const target = evt.target;
  3467. if (target && target.nodeType === 1 && target.nodeName === "IMG") {
  3468. pDivResourceEventCount = (pDivResourceEventCount & 1073741823) + 1;
  3469. }
  3470. };
  3471.  
  3472. const { key, stamperDomClass, preloadFn } = options;
  3473.  
  3474. // const newDoc = document.implementation.createHTMLDocument("NewDoc");
  3475. const pSpace = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  3476. document.documentElement.insertAdjacentHTML('beforeend', ttpHTML('<!---->'));
  3477. mockCommentElement(document.documentElement.lastChild);
  3478. document.documentElement.lastChild.replaceWith(pSpace);
  3479. const pNode = document.createElement('ns-538');
  3480. pSpace.insertAdjacentHTML('beforeend', ttpHTML('<!---->'));
  3481. mockCommentElement(pSpace.lastChild);
  3482. pSpace.lastChild.replaceWith(pNode);
  3483.  
  3484. const pDiv = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  3485. if (typeof pNode.attachShadow === 'function') {
  3486. const pShadow = pNode.attachShadow({ mode: "open" });
  3487. pShadow.replaceChildren(pDiv);
  3488. } else {
  3489. pNode.insertAdjacentHTML('beforeend', ttpHTML('<!---->'));
  3490. mockCommentElement(pNode.lastChild);
  3491. pNode.lastChild.replaceWith(pDiv);
  3492. }
  3493.  
  3494. const pDivNew = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  3495.  
  3496. pDiv.insertAdjacentHTML('beforeend', ttpHTML('<!---->'));
  3497. mockCommentElement(pDiv.lastChild);
  3498. pDiv.lastChild.replaceWith(pDivNew);
  3499.  
  3500. pDivNew.addEventListener('load', pDivOnResource, true);
  3501. pDivNew.addEventListener('error', pDivOnResource, true);
  3502.  
  3503. const wmRemoved = new Map();
  3504. wmRemoved.set = wmRemoved.setOriginal || wmRemoved.set;
  3505.  
  3506. // const wmMapToItem = new WeakMap();
  3507. // let wmPendingList = null;
  3508.  
  3509. const nullComponents = new Map();
  3510. nullComponents.set = nullComponents.setOriginal || nullComponents.set;
  3511.  
  3512. const componentDefaultAttributes = new WeakMap();
  3513.  
  3514. const fnKeyH = `${key}$$c472`;
  3515.  
  3516. cProto.__ensureContainerDomApi7577 = function (cId) {
  3517. const container = this.getStampContainer_(cId);
  3518. if (container && !container.__checkedDomApi33__) {
  3519. container.__checkedDomApi33__ = true;
  3520. if (!container.__domApi) {
  3521. if (typeof this.stampDomArray366_ === 'function' && this.stampDomArray366_.length === 6) {
  3522. let c = container;
  3523. try {
  3524. this.stampDomArray366_.call({
  3525. getStampContainer_(d) {
  3526. return c
  3527. },
  3528. get is() {
  3529. throw new Error('');
  3530. },
  3531. get hostElement() {
  3532. throw new Error('');
  3533. }
  3534. }, 0, cId, false, false, false, false);
  3535. } catch (e) { }
  3536. c = null;
  3537. }
  3538. }
  3539. }
  3540. }
  3541.  
  3542. cProto[fnKeyH] = async function (cTag, cId, pr00) {
  3543.  
  3544. // console.log(38806)
  3545. if (!this) return;
  3546. const fxCounter_ = this.fxCounter5355 = (this.fxCounter5355 & 1073741823) + 1;
  3547.  
  3548. // await the current executing task (if any)
  3549. // and avoid stacking in the same marco task
  3550. await Promise.all([pr00, nextBrowserTick_()]);
  3551. if (fxCounter_ !== this.fxCounter5355) return;
  3552.  
  3553. const addedCount0 = this.ec389a;
  3554. const removedCount0 = this.ec389r;
  3555.  
  3556. this.ec389 = false;
  3557. this.ec389a = 0;
  3558. this.ec389r = 0;
  3559.  
  3560. if (!addedCount0 && !removedCount0) return;
  3561. const stampDom_ = (this.stampDom || 0)[cTag] || 0;
  3562. const stampDomMap_ = stampDom_.mapping;
  3563. const stampDomEvent_ = stampDom_.events;
  3564. if (!stampDomMap_) return;
  3565. if (!this.__ensureContainerDomApi7577) return;
  3566. const hostElement = this.hostElement;
  3567. if (!hostElement) return;
  3568.  
  3569. spliceTempDisabled = true;
  3570.  
  3571. this.__ensureContainerDomApi7577(cId);
  3572.  
  3573. const isTickerRendering = cTag === 'tickerItems';
  3574. const isMessageListRendering = cTag === 'visibleItems';
  3575.  
  3576. // coming process can be stacked as ec389a and ec389r are reset.
  3577.  
  3578. const deObjectComponent = (itemEntry) => {
  3579. const I = firstObjectKey(itemEntry);
  3580. const L = stampDomMap_[I];
  3581. const H = itemEntry[I];
  3582. return [L, H];
  3583. };
  3584.  
  3585. let renderNodeCount = 0;
  3586.  
  3587. let renderOrdering = {};
  3588. let doFix = false;
  3589. const renderEntries = this[cTag].map((item) => {
  3590. const [L, H] = deObjectComponent(item);
  3591. const componentName = this.getComponentName_(L, H);
  3592. if (H && H.id && componentName) {
  3593. if (!H.__renderOrderId422__) {
  3594. H.__renderOrderId422__ = this.renderOrderId411 = (this.renderOrderId411 & 1073741823) + 1;
  3595. }
  3596. let p = renderOrdering[`${componentName}#${H.id}`];
  3597. if (p) doFix = true;
  3598. if (!p || p > H.__renderOrderId422__) {
  3599. renderOrdering[`${componentName}#${H.id}`] = H.__renderOrderId422__;
  3600. }
  3601. return [item, L, H, componentName, `${componentName}#${H.id}`]
  3602. } else {
  3603. return [item, L, H, componentName, true]
  3604. }
  3605. });
  3606. if (doFix) {
  3607. const arr = this[cTag];
  3608. for (let i = renderEntries.length - 1; i >= 0; i--) {
  3609. const e = renderEntries[i];
  3610. let m = e[4];
  3611. if (m === true) {
  3612. } else if (renderOrdering[m] === e[2].__renderOrderId422__) {
  3613. } else {
  3614. arr.splice(i, 1);
  3615. renderEntries.splice(i, 1);
  3616. }
  3617. }
  3618. }
  3619. renderOrdering = null;
  3620.  
  3621. const renderList = renderEntries.map((e) => {
  3622. const [item, L, H, componentName] = e;
  3623. const node = kRef(renderMap.get(H));
  3624. if (node && hostElement.contains(node)) {
  3625. renderNodeCount++;
  3626. return node;
  3627. } else if (node && !hostElement.contains(node)) {
  3628. renderMap.delete(H);
  3629. return item;
  3630. } else {
  3631. return item;
  3632. }
  3633. });
  3634.  
  3635. const isRenderListEmpty = renderList.length === 0;
  3636.  
  3637. // console.log(1773, this.ec389a, this.ec389r)
  3638.  
  3639. this.ec389a = 0;
  3640. this.ec389r = 0;
  3641.  
  3642.  
  3643. // this.ec389 = null;
  3644. // this.ec389a = 0;
  3645. // this.ec389r = 0;
  3646.  
  3647. let addedCounter = 0;
  3648. let removedCounter = 0;
  3649.  
  3650. const createConnectedComponentElm = (insertionObj, L, H, componentName) => {
  3651. // const reusable = false;
  3652. // const componentName = this.getComponentName_(L, H);
  3653. let component;
  3654. if (!nullComponents.has(componentName)) {
  3655. nullComponents.set(componentName, (component = document.createElement(componentName)));
  3656. component.className = stamperDomClass;
  3657. // shadowElm.insertAdjacentElement('beforeend', component);
  3658. } else {
  3659. component = nullComponents.get(componentName);
  3660. }
  3661. component = component.cloneNode(false);
  3662.  
  3663. // const cnt = insp(component);
  3664.  
  3665. // cnt.__dataOld = cnt.__dataPending = null;
  3666. pDivNew.insertAdjacentHTML('beforeend', ttpHTML('<!---->'));
  3667. mockCommentElement(pDivNew.lastChild);
  3668. pDivNew.lastChild.replaceWith(component);
  3669. // cnt.__dataOld = cnt.__dataPending = null;
  3670.  
  3671. return component;
  3672. }
  3673.  
  3674. const listDom = this.getStampContainer_(cId);
  3675.  
  3676. const pnForNewItem = (item) => {
  3677.  
  3678. const [L, H] = deObjectComponent(item);
  3679.  
  3680. const componentName = this.getComponentName_(L, H);
  3681.  
  3682. const wmList = wmRemoved.get(componentName.toLowerCase());
  3683.  
  3684. let connectedComponent = null;
  3685. if (wmList && (connectedComponent = wmList.firstElementChild)) {
  3686. if (this.telemetry_) this.telemetry_.reuse++;
  3687. // if (!wmPendingList) {
  3688. // wmPendingList = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  3689. // wmPendingList.setAttributeNS('http://www.w3.org/2000/svg', 'wm-pending', 'true');
  3690. // pDiv.insertAdjacentElement('afterend', wmPendingList);
  3691. // }
  3692. // wmPendingList.insertAdjacentElement('beforeend', connectedComponent);
  3693. pDivNew.insertAdjacentHTML('beforeend', ttpHTML('<!---->'));
  3694. mockCommentElement(pDivNew.lastChild);
  3695. pDivNew.lastChild.replaceWith(connectedComponent);
  3696. const attrMap = connectedComponent.attributes;
  3697. const defaultAttrs = componentDefaultAttributes.get(connectedComponent);
  3698. if (defaultAttrs) {
  3699. for (const attr of [...attrMap]) {
  3700. const name = attr.name;
  3701. if (name in defaultAttrs) attr.value = defaultAttrs[name];
  3702. else attrMap.removeNamedItem(name);
  3703. }
  3704. if (attrMap.length !== defaultAttrs['"']) {
  3705. for (const name in defaultAttrs) {
  3706. if (!attrMap[name] && name !== '"') connectedComponent.setAttribute(name, defaultAttrs[name]);
  3707. }
  3708. }
  3709. }
  3710.  
  3711. } else {
  3712. connectedComponent = createConnectedComponentElm(item, L, H, componentName);
  3713. if (this.telemetry_) this.telemetry_.create++;
  3714. }
  3715. if (isTickerRendering) {
  3716. const container = connectedComponent.firstElementChild;
  3717. if (container) container.classList.add('yt-live-chat-ticker-stampdom-container');
  3718. }
  3719.  
  3720. return [item, L, H, connectedComponent];
  3721.  
  3722. };
  3723.  
  3724. let imgPreloadPr = null;
  3725. if (isMessageListRendering) {
  3726. const addedItems = renderList.filter(item => item === 'object' && (item instanceof Node));
  3727. imgPreloadPr = preloadFn(addedItems)();
  3728. }
  3729.  
  3730. spliceTempDisabled = false;
  3731.  
  3732. // const pt1 = performance.now();
  3733. // const newComponentsEntries = await Promise.all(renderList.map((item) => {
  3734. // return typeof item === 'object' && !(item instanceof Node) ? Promise.resolve(item).then(pnForNewItem) : item;
  3735. // }));
  3736. const newComponentsEntries = isRenderListEmpty ? [] : await executeTaskBatch(renderList.map(item => ({
  3737. item,
  3738. fn(task) {
  3739. const { item } = task;
  3740. return typeof item === 'object' && !(item instanceof Node) ? pnForNewItem(item) : item;
  3741. }
  3742. })));
  3743. // const pt2 = performance.now();
  3744.  
  3745. const imgPromises = [];
  3746.  
  3747. const imgPaths = new Set();
  3748.  
  3749. const pnForRenderNewItem = (entry) => {
  3750. const [item, L, H, connectedComponent] = entry;
  3751.  
  3752. const cnt = insp(connectedComponent);
  3753. // setupRefreshData930(cnt);
  3754. // if (typeof cnt.data === 'object' && cnt.__dataEnabled === true && cnt.__dataReady === true && cnt.__dataInvalid === false) {
  3755. // cnt.data = H;
  3756. // } else {
  3757. const q = this.deferRenderStamperBinding_
  3758. let q2;
  3759. if (typeof q === 'object') q2 = this.deferRenderStamperBinding_ = [];
  3760. this.deferRenderStamperBinding_(connectedComponent, L, Object.assign({}, H)); // pre-flush
  3761. this.flushRenderStamperComponentBindings_();
  3762. if (typeof q === 'object') {
  3763. this.deferRenderStamperBinding_ = q;
  3764. q2.length = 0;
  3765. }
  3766. // }
  3767. // if (cnt.__refreshData930__ && cnt.data) cnt.__refreshData930__('data', !0); // ensure data is invalidated
  3768.  
  3769. // fix yt-icon issue
  3770. // refreshChildrenYtIcons(connectedComponent);
  3771.  
  3772. // const imgs = connectedComponent.getElementsByTagName('IMG');
  3773. // if (imgs.length > 0) {
  3774. // for (let i = 0, l = imgs.length; i < l; i++) {
  3775. // const src = imgs[i].src;
  3776. // if (src.includes('://') && !imgPaths.has(src)) {
  3777. // imgPaths.add(src);
  3778. // imgPromises.push(imageFetch(src));
  3779. // }
  3780. // }
  3781. // }
  3782. componentDefaultAttributes.set(connectedComponent, getAttributes(connectedComponent));
  3783. return entry;
  3784. }
  3785.  
  3786. // const pt3 = performance.now();
  3787. // const newRenderedComponents = await Promise.all(newComponentsEntries.map((entry) => {
  3788. // return typeof entry === 'object' && !(entry instanceof Node) ? Promise.resolve(entry).then(pnForRenderNewItem) : entry;
  3789. // }));
  3790. const newRenderedComponents = isRenderListEmpty ? [] : await executeTaskBatch(newComponentsEntries.map(entry => ({
  3791. entry,
  3792. fn(task) {
  3793. const { entry } = task;
  3794. return typeof entry === 'object' && !(entry instanceof Node) ? pnForRenderNewItem(entry) : entry;
  3795. }
  3796. })));
  3797. // const pt4 = performance.now();
  3798.  
  3799. // console.log('xxss' , pt2-pt1, pt4-pt3)
  3800.  
  3801. this.flushRenderStamperComponentBindings_(); // ensure all deferred flush render tasks clear.
  3802.  
  3803. // imgPromises.push(imageFetch('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'));
  3804. if (imgPromises.length > 0) {
  3805. const pr1 = Promise.all(imgPromises).catch(e => { });
  3806. const pr2 = autoTimerFn();
  3807. await Promise.race([pr1, pr2]).catch(e => { });
  3808. imgPaths.clear();
  3809. imgPromises.length = 0;
  3810. }
  3811. if (imgPreloadPr) await imgPreloadPr;
  3812.  
  3813. // const batching = [];
  3814. // let j = 0;
  3815. // let elNode;
  3816.  
  3817. const sideProcesses = [];
  3818.  
  3819. const removeStampNode_ = (elNode) => {
  3820.  
  3821. const elm = elNode;
  3822. const cnt = insp(elm);
  3823. let elemCount1 = elm.querySelectorAll('yt-img-shadow').length;
  3824.  
  3825. const elParent = elm.parentNode;
  3826. if (elm.__requestRemovalAt003__) {
  3827. elm.__requestRemovalAt003__ = 0;
  3828. } else {
  3829. if (cnt.requestRemoval) cnt.requestRemoval();
  3830. }
  3831. try {
  3832. (elParent.__domApi || elParent).removeChild(elm);
  3833. } catch (e) { }
  3834. const frag = document.createDocumentFragment();
  3835. frag.appendChild(elm);
  3836.  
  3837. const componentName = elm.nodeName.toLowerCase();
  3838. let wmList = wmRemoved.get(componentName);
  3839. if (!wmList) {
  3840. wmList = document.createDocumentFragment();
  3841. wmRemoved.set(componentName, wmList);
  3842. }
  3843. const data = cnt.data;
  3844. if (data) renderMap.delete(cnt.data);
  3845.  
  3846. let elemCount2 = elm.querySelectorAll('yt-img-shadow').length;
  3847.  
  3848. const [p1, p2] = [reuseFixDataViewModel(elm), reuseFixYtIconRendering(elm)];
  3849.  
  3850. sideProcesses.push(p1);
  3851. sideProcesses.push(p2);
  3852.  
  3853. if (!window.__fixTemplateReuse1058__ && elemCount1 !== elemCount2) return; // cannot reuse
  3854.  
  3855. Promise.all([elm, wmList, p1, p2]).then((r) => {
  3856. const [elm, wmList] = r;
  3857. wmList.appendChild(elm);
  3858. });
  3859. }
  3860.  
  3861. // const removeStampNode = async () => {
  3862.  
  3863. // removedCounter++;
  3864.  
  3865. // const nextElm = nextComponentSiblingFn(elNode);
  3866. // const elmId = elNode.id;
  3867. // removeStampNode_(elNode);
  3868. // // const dzid = this.getAttribute('dz-component-id');
  3869. // // ---- no-cache ----
  3870. // // try{
  3871. // // elm.remove();
  3872. // // }catch(e){}
  3873. // // ---- no-cache ----
  3874.  
  3875. // if (cTag === 'visibleItems') {
  3876. // sideProcesses.push(onVisibleItemStampNodeRemoval(elmId));
  3877. // }
  3878.  
  3879. // j++;
  3880. // elNode = nextElm;
  3881.  
  3882. // }
  3883.  
  3884. // if (typeof Polymer !== "undefined" && typeof Polymer.flush === "function") {
  3885. // // clear all pending rendering first
  3886. // await stackMarcoTask(async () => {
  3887. // Polymer.flush();
  3888. // });
  3889. // }
  3890.  
  3891. // main UI thread - DOM modification
  3892. await new Promise((resolveDM) => {
  3893. nextBrowserTick_(() => {
  3894.  
  3895. const isAtBottom = this.atBottom === true;
  3896. // if (ENABLE_OVERFLOW_ANCHOR && isAtBottom) {
  3897. // shouldScrollAfterFlush = true;
  3898. // }
  3899.  
  3900.  
  3901. const tasks = [];
  3902. let fragAppend = document.createDocumentFragment();
  3903. let shouldManualScroll = null;
  3904. let scrollTop1 = null, scrollTop2 = null;
  3905.  
  3906. const taskFn = {
  3907. remove: (task) => {
  3908.  
  3909. const { elNode } = task;
  3910.  
  3911. removedCounter++;
  3912.  
  3913. const elmId = elNode.id;
  3914. removeStampNode_(elNode);
  3915. // const dzid = this.getAttribute('dz-component-id');
  3916. // ---- no-cache ----
  3917. // try{
  3918. // elm.remove();
  3919. // }catch(e){}
  3920. // ---- no-cache ----
  3921.  
  3922. if (isMessageListRendering) {
  3923. sideProcesses.push(onVisibleItemStampNodeRemoval(elmId));
  3924. }
  3925.  
  3926. return 2
  3927.  
  3928. },
  3929. append: (task) => {
  3930.  
  3931. if (!fragAppend) return;
  3932.  
  3933. const { newNode, nodeAfter, parentNode, L, H } = task;
  3934.  
  3935. fragAppend.appendChild(newNode);
  3936.  
  3937.  
  3938. const itemScrollerX = (isMessageListRendering && isAtBottom) ? this.itemScroller : null;
  3939.  
  3940.  
  3941. if (itemScrollerX) {
  3942. if (scrollTop1 === null) scrollTop1 = itemScrollerX.scrollTop;
  3943. }
  3944.  
  3945. if (nodeAfter) {
  3946. (parentNode.__domApi || parentNode).insertBefore(fragAppend, nodeAfter);
  3947. } else {
  3948. (parentNode.__domApi || parentNode).appendChild(fragAppend);
  3949. }
  3950.  
  3951. this.deferRenderStamperBinding_(newNode, L, H);
  3952. this.flushRenderStamperComponentBindings_();
  3953.  
  3954.  
  3955. // nodeAfter ? nodeAfter.insertAdjacentElement('beforebegin', newNode) : parentNode.insertAdjacentElement('beforeend', newNode);
  3956. const connectedComponent = newNode;
  3957. const cnt = insp(connectedComponent);
  3958. renderMap.set(cnt.data, mWeakRef(connectedComponent));
  3959. // mutationDelayedRefreshData(cnt); // not included to sideProcesses
  3960. addedCounter++;
  3961.  
  3962. if (isTickerRendering) {
  3963. sideProcesses.push(onTickerItemStampNodeAdded());
  3964. }
  3965.  
  3966. if (itemScrollerX) {
  3967. if (scrollTop2 === null) scrollTop2 = itemScrollerX.scrollTop;
  3968. if (shouldManualScroll === null) shouldManualScroll = (scrollTop1 >= 0 && scrollTop2 >= 0 && Math.abs(scrollTop2 - scrollTop1) < 6);
  3969. if (shouldManualScroll) {
  3970. itemScrollerX.scrollTop = scrollTop2 + 16777216;
  3971. }
  3972. }
  3973.  
  3974. return 1
  3975. }
  3976. }
  3977.  
  3978. {
  3979. const indexMap = new WeakMap();
  3980. // let index = 0;
  3981.  
  3982. if (!isRenderListEmpty) {
  3983. for (let elNode_ = firstComponentChildFn(listDom), index = 0; elNode_ instanceof Node; elNode_ = nextComponentSiblingFn(elNode_)) {
  3984. indexMap.set(elNode_, index++);
  3985. }
  3986. }
  3987.  
  3988.  
  3989.  
  3990. const keepIndices = new Array(renderNodeCount);
  3991. let keepIndicesLen = 0, lastKeepIndex = -1, requireSort = false;
  3992. for (let i = 0, l = newRenderedComponents.length; i < l; i++) {
  3993. const entry = newRenderedComponents[i];
  3994. if (entry instanceof Node) {
  3995. const index = indexMap.get(entry);
  3996. keepIndices[keepIndicesLen++] = [index, entry];
  3997. if (index > lastKeepIndex) lastKeepIndex = index;
  3998. else requireSort = true;
  3999. }
  4000. }
  4001. keepIndices.length = keepIndicesLen;
  4002. if (requireSort) keepIndices.sort((a, b) => a[0] - b[0]);
  4003. let dk = 0;
  4004.  
  4005. let j = 0;
  4006. let elNode;
  4007.  
  4008. elNode = firstComponentChildFn(listDom);
  4009.  
  4010. if (!isRenderListEmpty) {
  4011. for (const rcEntry of newRenderedComponents) {
  4012. const index = indexMap.get(rcEntry);
  4013. if (typeof index === 'number') {
  4014. const indexEntry = keepIndices[dk++];
  4015. const [dIdx, dNode] = indexEntry;
  4016. indexMap.delete(rcEntry);
  4017. const idx = dIdx;
  4018. while (j < idx && elNode) {
  4019. tasks.push({
  4020. type: 'remove',
  4021. elNode,
  4022. fn: taskFn.remove
  4023. });
  4024. elNode = nextComponentSiblingFn(elNode);
  4025. j++;
  4026. }
  4027. if (j === idx) {
  4028. if (elNode) {
  4029. // if (dNode !== elNode) tasks.push({
  4030. // type: 'swap',
  4031. // earlyNode: indexEntry[1],
  4032. // laterNode: elNode
  4033. // });
  4034. elNode = nextComponentSiblingFn(elNode);
  4035. j++;
  4036. } else {
  4037. console.warn('elNode is not available?', renderList, addedCount0, removedCount0, j, idx);
  4038. }
  4039. }
  4040. } else if (rcEntry instanceof Node) {
  4041. // interruped by the external like clearList
  4042.  
  4043. tasks.push({
  4044. type: 'remove',
  4045. elNode: rcEntry,
  4046. fn: taskFn.remove
  4047. });
  4048.  
  4049. } else {
  4050. const [item, L, H, connectedComponent] = rcEntry;
  4051.  
  4052. tasks.push({
  4053. type: 'append',
  4054. newNode: connectedComponent,
  4055. nodeAfter: elNode,
  4056. parentNode: listDom,
  4057. item, L, H,
  4058. fn: taskFn.append
  4059. });
  4060.  
  4061. }
  4062.  
  4063. }
  4064. }
  4065.  
  4066. while (elNode) {
  4067.  
  4068. tasks.push({
  4069. type: 'remove',
  4070. elNode,
  4071. fn: taskFn.remove
  4072. });
  4073. elNode = nextComponentSiblingFn(elNode);
  4074.  
  4075. }
  4076.  
  4077. }
  4078.  
  4079. if (tasks.length >= 1) {
  4080. executeTaskBatch(tasks).then(() => {
  4081. fragAppend = null;
  4082. resolveDM();
  4083. }).catch(console.warn);
  4084. }
  4085.  
  4086. });
  4087. }).catch(console.warn);
  4088.  
  4089. {
  4090. const arr = this[cTag];
  4091. let b = 0;
  4092. b = b | this._setPendingPropertyOrPath(`${cTag}.splices`, {}, true, true);
  4093. b = b | this._setPendingPropertyOrPath(`${cTag}.length`, arr.length, true, true);
  4094. b && this._invalidateProperties();
  4095. }
  4096.  
  4097. // this.flushRenderStamperComponentBindings_(); // just in case...
  4098.  
  4099. await Promise.all(sideProcesses);
  4100.  
  4101. const detail = {
  4102. container: listDom
  4103. };
  4104. stampDomEvent_ && this.hostElement.dispatchEvent(new CustomEvent("yt-rendererstamper-finished", {
  4105. bubbles: !0,
  4106. cancelable: !1,
  4107. composed: !0,
  4108. detail
  4109. }));
  4110. detail.container = null;
  4111.  
  4112. // if (typeof Polymer !== "undefined" && typeof Polymer.flush === "function") {
  4113. // // clear all remaining rendering before promise resolve
  4114. // await stackMarcoTask(async () => {
  4115. // Polymer.flush();
  4116. // });
  4117. // }
  4118.  
  4119. }
  4120.  
  4121. let spliceTempDisabled = false;
  4122.  
  4123. // proceedStampDomArraySplices371_ // proceedStampDomArraySplices381_
  4124. cProto[key] = function (cTag, cId, indexSplice) {
  4125.  
  4126. if (spliceTempDisabled) return true;
  4127. // console.log('proceedStampDomArraySplices_')
  4128. // assume no error -> no try catch (performance consideration)
  4129. const { index, addedCount, removed } = indexSplice;
  4130. const removedCount = removed ? removed.length : indexSplice.removedCount;
  4131. indexSplice = null;
  4132. if (!addedCount && !removedCount) {
  4133. console.warn('proceedStampDomArraySplices_', 'Error 001');
  4134. return false;
  4135. }
  4136. if (!this.ec389) {
  4137. if (this.ec389a || this.ec389r) {
  4138. console.warn('proceedStampDomArraySplices_', 'Error 002');
  4139. return false;
  4140. }
  4141. this.ec389 = true;
  4142. this.ec389a = addedCount;
  4143. this.ec389r = removedCount;
  4144. } else {
  4145. this.ec389a += addedCount;
  4146. this.ec389r += removedCount;
  4147. return true;
  4148. }
  4149.  
  4150. const pr00 = this.ec389pr;
  4151. const pr11 = this.ec389pr = this[fnKeyH](cTag, cId, pr00).catch(console.warn);
  4152.  
  4153. if (cTag === 'visibleItems') {
  4154. this.prDelay288 = pr11;
  4155. }
  4156. return true;
  4157. }
  4158.  
  4159.  
  4160.  
  4161.  
  4162.  
  4163. }
  4164.  
  4165.  
  4166. class RAFHub {
  4167. constructor() {
  4168. /** @type {number} */
  4169. this.startAt = 8170;
  4170. /** @type {number} */
  4171. this.counter = 0;
  4172. /** @type {number} */
  4173. this.rid = 0;
  4174. /** @type {Map<number, FrameRequestCallback>} */
  4175. this.funcs = new Map();
  4176. const funcs = this.funcs;
  4177. /** @type {FrameRequestCallback} */
  4178. this.bCallback = this.mCallback.bind(this);
  4179. this.pClear = () => funcs.clear();
  4180. this.keepRAF = false;
  4181. }
  4182. /** @param {DOMHighResTimeStamp} highResTime */
  4183. mCallback(highResTime) {
  4184. this.rid = 0;
  4185. Promise.resolve().then(this.pClear);
  4186. this.funcs.forEach(func => Promise.resolve(highResTime).then(func).catch(console.warn));
  4187. }
  4188. /** @param {FrameRequestCallback} f */
  4189. request(f) {
  4190. const cid = this.startAt + (this.counter = (this.counter & 1073741823) + 1);
  4191. this.funcs.set(cid, f);
  4192. if (this.rid === 0) this.rid = requestAnimationFrame(this.bCallback);
  4193. return cid;
  4194. }
  4195. /** @param {number} cid */
  4196. cancel(cid) {
  4197. cid = +cid;
  4198. if (cid > 0) {
  4199. if (cid <= this.startAt) {
  4200. return cancelAnimationFrame(cid);
  4201. }
  4202. if (this.rid > 0) {
  4203. this.funcs.delete(cid);
  4204. if (this.funcs.size === 0 && !this.keepRAF) {
  4205. cancelAnimationFrame(this.rid);
  4206. this.rid = 0;
  4207. }
  4208. }
  4209. }
  4210. }
  4211. }
  4212.  
  4213. function basePrefetching() {
  4214.  
  4215. new Promise(resolve => {
  4216.  
  4217. if (document.readyState !== 'loading') {
  4218. resolve();
  4219. } else {
  4220. win.addEventListener("DOMContentLoaded", resolve, false);
  4221. }
  4222.  
  4223. }).then(() => {
  4224. const hostL1 = [
  4225. 'https://www.youtube.com', 'https://googlevideo.com',
  4226. 'https://googleapis.com', 'https://accounts.youtube.com',
  4227. 'https://www.gstatic.com', 'https://ggpht.com',
  4228. 'https://yt3.ggpht.com', 'https://yt4.ggpht.com'
  4229. ];
  4230.  
  4231. const hostL2 = [
  4232. 'https://youtube.com',
  4233. 'https://fonts.googleapis.com', 'https://fonts.gstatic.com'
  4234. ];
  4235.  
  4236. let link = null;
  4237.  
  4238. function kn() {
  4239.  
  4240. link = document.createElement('link');
  4241. if (link.relList && link.relList.supports) {
  4242. 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)
  4243. } else {
  4244. kptPF = 0;
  4245. }
  4246.  
  4247. groupCollapsed("YouTube Super Fast Chat", " | PREFETCH SUPPORTS");
  4248. if (ENABLE_BASE_PREFETCHING) console1.log('dns-prefetch', (kptPF & 1) ? 'OK' : 'NG');
  4249. if (ENABLE_BASE_PREFETCHING) console1.log('preconnect', (kptPF & 2) ? 'OK' : 'NG');
  4250. if (ENABLE_PRELOAD_THUMBNAIL) console1.log('prefetch', (kptPF & 4) ? 'OK' : 'NG');
  4251. if (ENABLE_PRELOAD_THUMBNAIL) console1.log('preload', (kptPF & 16) ? 'OK' : 'NG');
  4252. groupEnd();
  4253.  
  4254. }
  4255.  
  4256. for (const h of hostL1) {
  4257.  
  4258. if (kptPF === null) kn();
  4259. if (ENABLE_BASE_PREFETCHING) {
  4260. // if (kptPF & 1) {
  4261. // linker(link, 'dns-prefetch', h);
  4262. // link = null;
  4263. // }
  4264. if (kptPF & 2) {
  4265. linker(link, 'preconnect', h);
  4266. link = null;
  4267. }
  4268. }
  4269. }
  4270.  
  4271. for (const h of hostL2) {
  4272. if (kptPF === null) kn();
  4273. if (ENABLE_BASE_PREFETCHING) {
  4274. if (kptPF & 1) {
  4275. linker(link, 'dns-prefetch', h);
  4276. link = null;
  4277. }
  4278. }
  4279. }
  4280.  
  4281. })
  4282.  
  4283.  
  4284. }
  4285.  
  4286. if (DO_LINK_PREFETCH) basePrefetching();
  4287.  
  4288. const { notifyPath7081 } = (() => {
  4289. // DO_PARTICIPANT_LIST_HACKS
  4290.  
  4291. const mutexParticipants = new Mutex();
  4292.  
  4293. let uvid = 0;
  4294. let r95dm = 0;
  4295. let c95dm = -1;
  4296.  
  4297. const foundMap = (base, content) => {
  4298. /*
  4299. let lastSearch = 0;
  4300. let founds = base.map(baseEntry => {
  4301. let search = content.indexOf(baseEntry, lastSearch);
  4302. if (search < 0) return false;
  4303. lastSearch = search + 1;
  4304. return true;
  4305. });
  4306. return founds;
  4307. */
  4308. const contentSet = new Set(content);
  4309. const r = base.map(baseEntry => contentSet.has(baseEntry));
  4310. contentSet.clear();
  4311. return r
  4312.  
  4313. }
  4314.  
  4315.  
  4316.  
  4317. let participantsForSpliceWR = null;
  4318.  
  4319. class IndexSpliceEntry {
  4320. /**
  4321. *
  4322. * @param {number} _index
  4323. * @param {number} _addedCount
  4324. * @param {any[]} _removed
  4325. */
  4326. constructor(_index, _addedCount, _removed) {
  4327. this.index = _index;
  4328. this.addedCount = _addedCount;
  4329. this.removed = _removed;
  4330. }
  4331. get __proxy312__() {
  4332. return 1
  4333. }
  4334. get type() {
  4335. return 'splice'
  4336. }
  4337. get object() {
  4338. return kRef(participantsForSpliceWR); // avoid memory leakage
  4339. }
  4340. }
  4341.  
  4342. const spliceIndicesFunc = (beforeParticipants, participants, idsBefore, idsAfter) => {
  4343.  
  4344. let foundsForAfter = foundMap(idsAfter, idsBefore);
  4345. let foundsForBefore = foundMap(idsBefore, idsAfter);
  4346.  
  4347. const nAfter = foundsForAfter.length;
  4348. const nBefore = foundsForBefore.length;
  4349.  
  4350. const indexSplices = [];
  4351. const contentUpdates = [];
  4352. participantsForSpliceWR = null;
  4353. for (let i = 0, j = 0; i < nBefore || j < nAfter;) {
  4354. if (beforeParticipants[i] === participants[j]) {
  4355. i++; j++;
  4356. } else if (idsBefore[i] === idsAfter[j]) {
  4357. // content changed
  4358. contentUpdates.push({ indexI: i, indexJ: j })
  4359. i++; j++;
  4360. } else {
  4361. let addedCount = 0;
  4362. for (let q = j; q < nAfter; q++) {
  4363. if (foundsForAfter[q] === false) addedCount++;
  4364. else break;
  4365. }
  4366. let removedCount = 0;
  4367. for (let q = i; q < nBefore; q++) {
  4368. if (foundsForBefore[q] === false) removedCount++;
  4369. else break;
  4370. }
  4371. if (!addedCount && !removedCount) {
  4372. throw 'ERROR(0xFF32): spliceIndicesFunc';
  4373. }
  4374. const entry = new IndexSpliceEntry(
  4375. j,
  4376. addedCount,
  4377. removedCount >= 1 ? beforeParticipants.slice(i, i + removedCount) : []
  4378. );
  4379. indexSplices.push(entry);
  4380. i += removedCount;
  4381. j += addedCount;
  4382. }
  4383. }
  4384. foundsForBefore = null;
  4385. foundsForAfter = null;
  4386. idsBefore = null;
  4387. idsAfter = null;
  4388. beforeParticipants = null;
  4389. participantsForSpliceWR = indexSplices.length > 0 ? mWeakRef(participants) : null;
  4390. participants = null;
  4391. return { indexSplices, contentUpdates };
  4392.  
  4393. }
  4394.  
  4395. /*
  4396.  
  4397. customElements.get("yt-live-chat-participant-renderer").prototype.notifyPath=function(){ console.log(123); console.log(new Error().stack)}
  4398.  
  4399. VM63631:1 Error
  4400. at customElements.get.notifyPath (<anonymous>:1:122)
  4401. at e.forwardRendererStamperChanges_ (live_chat_polymer.js:4453:35)
  4402. at e.rendererStamperApplyChangeRecord_ (live_chat_polymer.js:4451:12)
  4403. at e.rendererStamperObserver_ (live_chat_polymer.js:4448:149)
  4404. at Object.pu [as fn] (live_chat_polymer.js:1692:118)
  4405. at ju (live_chat_polymer.js:1674:217)
  4406. at a._propertiesChanged (live_chat_polymer.js:1726:122)
  4407. at b._flushProperties (live_chat_polymer.js:1597:200)
  4408. at a._invalidateProperties (live_chat_polymer.js:1718:69)
  4409. at a.notifyPath (live_chat_polymer.js:1741:182)
  4410.  
  4411. */
  4412.  
  4413. function convertToIds(participants) {
  4414. return participants.map(participant => {
  4415. if (!participant || typeof participant !== 'object') {
  4416. console.warn('Error(0xFA41): convertToIds', participant);
  4417. return participant; // just in case
  4418. }
  4419. let keys = Object.keys(participant);
  4420. // liveChatTextMessageRenderer
  4421. // liveChatParticipantRenderer - livestream channel owner [no authorExternalChannelId]
  4422. // liveChatPaidMessageRenderer
  4423. /*
  4424.  
  4425. 'yt-live-chat-participant-renderer' utilizes the following:
  4426. authorName.simpleText: string
  4427. authorPhoto.thumbnails: Object{url:string, width:int, height:int} []
  4428. authorBadges[].liveChatAuthorBadgeRenderer.icon.iconType: string
  4429. authorBadges[].liveChatAuthorBadgeRenderer.tooltip: string
  4430. authorBadges[].liveChatAuthorBadgeRenderer.accessibility.accessibilityData: Object{label:string}
  4431.  
  4432. */
  4433. if (keys.length !== 1) {
  4434. console.warn('Error(0xFA42): convertToIds', participant);
  4435. return participant; // just in case
  4436. }
  4437. let key = keys[0];
  4438. let renderer = (participant[key] || 0);
  4439. let authorName = (renderer.authorName || 0);
  4440. let text = `${authorName.simpleText || authorName.text}`
  4441. let res = participant; // fallback if it is not a vaild entry
  4442. if (typeof text !== 'string') {
  4443. console.warn('Error(0xFA53): convertToIds', participant);
  4444. } else {
  4445. text = `${renderer.authorExternalChannelId || 'null'}|${text || ''}`;
  4446. if (text.length > 1) res = text;
  4447. }
  4448. return res;
  4449. // return renderer?`${renderer.id}|${renderer.authorExternalChannelId}`: '';
  4450. // note: renderer.id will be changed if the user typed something to trigger the update of the participants' record.
  4451. });
  4452. }
  4453.  
  4454. const checkChangeToParticipantRendererContent = CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT ? (p1, p2) => {
  4455. // just update when content is changed.
  4456. if (p1.authorName !== p2.authorName) return true;
  4457. if (p1.authorPhoto !== p2.authorPhoto) return true;
  4458. if (p1.authorBadges !== p2.authorBadges) return true;
  4459. return false;
  4460. } : (p1, p2) => {
  4461. // keep integrity all the time.
  4462. return p1 !== p2; // always true
  4463. }
  4464.  
  4465. function notifyPath7081(path) { // cnt "yt-live-chat-participant-list-renderer"
  4466.  
  4467. if (PARTICIPANT_UPDATE_ONLY_ONLY_IF_MODIFICATION_DETECTED) {
  4468. if (path !== "participantsManager.participants") {
  4469. return this.__notifyPath5036__.apply(this, arguments);
  4470. }
  4471. if (c95dm === r95dm) return;
  4472. } else {
  4473. const stack = new Error().stack;
  4474. if (path !== "participantsManager.participants" || stack.indexOf('.onParticipantsChanged') < 0) {
  4475. return this.__notifyPath5036__.apply(this, arguments);
  4476. }
  4477. }
  4478.  
  4479. if (uvid > 1e8) uvid = uvid % 100;
  4480. let tid = ++uvid;
  4481.  
  4482.  
  4483. // const cnt = this; // "yt-live-chat-participant-list-renderer"
  4484.  
  4485. const wNode = mWeakRef(this);
  4486.  
  4487. mutexParticipants.lockWith(lockResolve => {
  4488.  
  4489. const cnt = kRef(wNode);
  4490.  
  4491. const participants00 = (((cnt || 0).participantsManager || 0).participants || 0);
  4492.  
  4493. if (tid !== uvid || !cnt || typeof (participants00 || 0).splice !== 'function') {
  4494. lockResolve();
  4495. return;
  4496. }
  4497.  
  4498. let doUpdate = false;
  4499.  
  4500. if (PARTICIPANT_UPDATE_ONLY_ONLY_IF_MODIFICATION_DETECTED) {
  4501.  
  4502. if (!participants00.r94dm) {
  4503. participants00.r94dm = 1;
  4504. r95dm = (r95dm & 1073741823) + 1;
  4505. participants00.push = function () {
  4506. r95dm = (r95dm & 1073741823) + 1;
  4507. return Array.prototype.push.apply(this, arguments);
  4508. }
  4509. participants00.pop = function () {
  4510. r95dm = (r95dm & 1073741823) + 1;
  4511. return Array.prototype.pop.apply(this, arguments);
  4512. }
  4513. participants00.shift = function () {
  4514. r95dm = (r95dm & 1073741823) + 1;
  4515. return Array.prototype.shift.apply(this, arguments);
  4516. }
  4517. participants00.unshift = function () {
  4518. r95dm = (r95dm & 1073741823) + 1;
  4519. return Array.prototype.unshift.apply(this, arguments);
  4520. }
  4521. participants00.splice = function () {
  4522. r95dm = (r95dm & 1073741823) + 1;
  4523. return Array.prototype.splice.apply(this, arguments);
  4524. }
  4525. participants00.sort = function () {
  4526. r95dm = (r95dm & 1073741823) + 1;
  4527. return Array.prototype.sort.apply(this, arguments);
  4528. }
  4529. participants00.reverse = function () {
  4530. r95dm = (r95dm & 1073741823) + 1;
  4531. return Array.prototype.reverse.apply(this, arguments);
  4532. }
  4533. }
  4534.  
  4535. if (c95dm !== r95dm) {
  4536. c95dm = r95dm;
  4537. doUpdate = true;
  4538. }
  4539.  
  4540. } else {
  4541. doUpdate = true;
  4542. }
  4543.  
  4544. if (!doUpdate) {
  4545. lockResolve();
  4546. return;
  4547. }
  4548.  
  4549. const participants = participants00.slice(0);
  4550. const beforeParticipants = beforeParticipantsMap.get(cnt) || [];
  4551. beforeParticipantsMap.set(cnt, participants);
  4552.  
  4553. const resPromise = (async () => {
  4554.  
  4555. if (beforeParticipants.length === 0) {
  4556. // not error
  4557. return 0;
  4558. }
  4559.  
  4560. let countOfElements = cnt.__getAllParticipantsDOMRenderedLength__()
  4561.  
  4562. // console.log(participants.length, doms.length) // different if no requestAnimationFrame
  4563. if (beforeParticipants.length !== countOfElements) {
  4564. // there is somewrong for the cache. - sometimes happen
  4565. return 0;
  4566. }
  4567.  
  4568. const idsBefore = convertToIds(beforeParticipants);
  4569. const idsAfter = convertToIds(participants);
  4570.  
  4571. let { indexSplices, contentUpdates } = spliceIndicesFunc(beforeParticipants, participants, idsBefore, idsAfter);
  4572.  
  4573. let res = 1; // default 1 for no update
  4574.  
  4575. if (indexSplices.length >= 1) {
  4576.  
  4577.  
  4578. // let p2 = participants.slice(indexSplices[0].index, indexSplices[0].index+indexSplices[0].addedCount);
  4579. // let p1 = indexSplices[0].removed;
  4580. // console.log(indexSplices.length, indexSplices ,p1,p2, convertToIds(p1),convertToIds(p2))
  4581.  
  4582. /* folllow
  4583. a.notifyPath(c + ".splices", d);
  4584. a.notifyPath(c + ".length", b.length);
  4585. */
  4586. // stampDomArraySplices_
  4587.  
  4588.  
  4589. await new Promise(resolve => {
  4590. cnt.resolveForDOMRendering781 = resolve;
  4591.  
  4592. cnt.__notifyPath5036__("participantsManager.participants.splices", {
  4593. indexSplices
  4594. });
  4595. indexSplices = null;
  4596. participantsForSpliceWR = null;
  4597. cnt.__notifyPath5036__("participantsManager.participants.length",
  4598. participants.length
  4599. );
  4600.  
  4601. });
  4602.  
  4603. // play safe for the change of 'length'
  4604. await nextBrowserTick_();
  4605.  
  4606. countOfElements = cnt.__getAllParticipantsDOMRenderedLength__();
  4607.  
  4608. const wrongSize = participants.length !== countOfElements
  4609. if (wrongSize) {
  4610. console.warn("ERROR(0xE2C3): notifyPath7081", beforeParticipants.length, participants.length, doms.length)
  4611. return 0;
  4612. }
  4613.  
  4614. res = 2 | 4;
  4615.  
  4616. } else {
  4617.  
  4618. indexSplices = null;
  4619. participantsForSpliceWR = null;
  4620.  
  4621. if (participants.length !== countOfElements) {
  4622. // other unhandled cases
  4623. return 0;
  4624. }
  4625.  
  4626. }
  4627.  
  4628. // participants.length === countOfElements before contentUpdates
  4629. if (contentUpdates.length >= 1) {
  4630. for (const contentUpdate of contentUpdates) {
  4631. let isChanged = checkChangeToParticipantRendererContent(beforeParticipants[contentUpdate.indexI], participants[contentUpdate.indexJ]);
  4632. if (isChanged) {
  4633. cnt.__notifyPath5036__(`participantsManager.participants[${contentUpdate.indexJ}]`);
  4634. res |= 4 | 8;
  4635. }
  4636. }
  4637. }
  4638. contentUpdates = null;
  4639.  
  4640. return res;
  4641.  
  4642.  
  4643. })();
  4644.  
  4645.  
  4646. resPromise.then(async (resValue) => {
  4647. const condition = resValue === 0 ? 1 : (resValue & 4) === 4 ? 2 : 0;
  4648. const isLogRequired = SHOW_PARTICIPANT_CHANGES_IN_CONSOLE && condition > 0;
  4649. isLogRequired && groupCollapsed("Participant List Change", `tid = ${tid}; res = ${resValue}`);
  4650. if (condition === 1) {
  4651. isLogRequired && console1.log("Full Refresh begins");
  4652. await new Promise(resolve => {
  4653. cnt.resolveForDOMRendering781 = resolve;
  4654. cnt.__notifyPath5036__("participantsManager.participants"); // full refresh
  4655. });
  4656. isLogRequired && console1.log("Full Refresh ends");
  4657. } else if (condition === 2) {
  4658. isLogRequired && console1.log(`Number of participants (before): ${beforeParticipants.length}`);
  4659. isLogRequired && console1.log(`Number of participants (after): ${participants.length}`);
  4660. isLogRequired && console1.log(`Total number of rendered participants: ${cnt.__getAllParticipantsDOMRenderedLength__()}`);
  4661. isLogRequired && console1.log(`Participant Renderer Content Updated: ${(resValue & 8) === 8}`);
  4662. // requestAnimationFrame is required to avoid particiant update during DOM changing (stampDomArraySplices_)
  4663. // mutex lock with requestAnimationFrame can also disable participants update in background
  4664. }
  4665. isLogRequired && groupEnd();
  4666. (condition === 2) && (await new Promise(requestAnimationFrame));
  4667. lockResolve();
  4668. });
  4669.  
  4670. });
  4671.  
  4672. }
  4673.  
  4674. return { notifyPath7081 };
  4675.  
  4676. })();
  4677.  
  4678. const whenDefinedMultiple = async (tags) => {
  4679.  
  4680. const sTags = [...new Set(tags)];
  4681. const len = sTags.length;
  4682.  
  4683. const pTags = new Array(len);
  4684. for (let i = 0; i < len; i++) {
  4685. pTags[i] = customElements.whenDefined(sTags[i]);
  4686. }
  4687.  
  4688. await Promise.all(pTags);
  4689. pTags.length = 0;
  4690.  
  4691. return sTags;
  4692.  
  4693. }
  4694.  
  4695. const onRegistryReadyForDataManipulation = () => {
  4696.  
  4697. function dummy5035(a, b, c) { }
  4698. function dummy411(a, b, c) { }
  4699.  
  4700.  
  4701.  
  4702. customElements.whenDefined("yt-live-chat-participant-list-renderer").then(() => {
  4703.  
  4704. if (!DO_PARTICIPANT_LIST_HACKS) return;
  4705.  
  4706. const tag = "yt-live-chat-participant-list-renderer";
  4707. const cProto = getProto(document.createElement(tag));
  4708. if (!cProto || typeof cProto.attached !== 'function') {
  4709. // for _registered, proto.attached shall exist when the element is defined.
  4710. // for controller extraction, attached shall exist when instance creates.
  4711. console.warn(`proto.attached for ${tag} is unavailable.`);
  4712. return;
  4713. }
  4714.  
  4715.  
  4716. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-participant-list-renderer hacks");
  4717.  
  4718. 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'];
  4719. const fgs = {};
  4720. for (const key of fgsArr) fgs[key] = undefined;
  4721.  
  4722. try {
  4723. const EXPERIMENT_FLAGS = ytcfg.data_.EXPERIMENT_FLAGS;
  4724. for (const key of fgsArr) fgs[key] = EXPERIMENT_FLAGS[key];
  4725. } catch (e) { }
  4726. console1.log(`EXPERIMENT_FLAGS: ${JSON.stringify(fgs, null, 2)}`);
  4727.  
  4728. const canDoReplacement = (() => {
  4729. if (typeof cProto.__notifyPath5035__ === 'function' && cProto.__notifyPath5035__.name !== 'dummy5035') {
  4730. console.warn('YouTube Live Chat Tamer is running.');
  4731. return;
  4732. }
  4733.  
  4734. if (typeof cProto.__attached411__ === 'function' && cProto.__attached411__.name !== 'dummy411') {
  4735. console.warn('YouTube Live Chat Tamer is running.');
  4736. return;
  4737. }
  4738.  
  4739. cProto.__notifyPath5035__ = dummy5035 // just to against Live Chat Tamer
  4740. cProto.__attached411__ = dummy411 // just to against Live Chat Tamer
  4741.  
  4742. if (typeof cProto.flushRenderStamperComponentBindings_ !== 'function' || cProto.flushRenderStamperComponentBindings_.length !== 0) {
  4743. console.warn("ERROR(0xE355): cProto.flushRenderStamperComponentBindings_ not found");
  4744. return;
  4745. }
  4746.  
  4747. if (typeof cProto.flushRenderStamperComponentBindings66_ === 'function') {
  4748. console.warn("ERROR(0xE356): cProto.flushRenderStamperComponentBindings66_");
  4749. return;
  4750. }
  4751.  
  4752. if (typeof cProto.__getAllParticipantsDOMRenderedLength__ === 'function') {
  4753. console.warn("ERROR(0xE357): cProto.__getAllParticipantsDOMRenderedLength__");
  4754. return;
  4755. }
  4756. return true;
  4757. })();
  4758.  
  4759. console1.log(`Data Manipulation Boost = ${canDoReplacement}`);
  4760.  
  4761. assertor(() => fnIntegrity(cProto.attached, '0.32.22')) // just warning
  4762. if (typeof cProto.flushRenderStamperComponentBindings_ === 'function') {
  4763. const fiRSCB = fnIntegrity(cProto.flushRenderStamperComponentBindings_);
  4764. console1.log(`flushRenderStamperComponentBindings_ ### ${fiRSCB} ###`);
  4765. } else {
  4766. console1.log("flushRenderStamperComponentBindings_ - not found");
  4767. }
  4768. // assertor(() => fnIntegrity(cProto.flushRenderStamperComponentBindings_, '0.386.233')) // just warning
  4769.  
  4770. if (typeof cProto.flushRenderStamperComponentBindings_ === 'function') {
  4771. cProto.flushRenderStamperComponentBindings66_ = cProto.flushRenderStamperComponentBindings_;
  4772. cProto.flushRenderStamperComponentBindings_ = function () {
  4773. // console.log('flushRenderStamperComponentBindings_')
  4774. this.flushRenderStamperComponentBindings66_();
  4775. if (this.resolveForDOMRendering781) {
  4776. this.resolveForDOMRendering781();
  4777. this.resolveForDOMRendering781 = null;
  4778. }
  4779. };
  4780. }
  4781.  
  4782. cProto.__getAllParticipantsDOMRenderedLength__ = function () {
  4783. const container = ((this || 0).$ || 0).participants;
  4784. if (!container) return 0;
  4785. return HTMLElement_.prototype.querySelectorAll.call(container, 'yt-live-chat-participant-renderer').length;
  4786. }
  4787.  
  4788. const onPageElements = [...document.querySelectorAll('yt-live-chat-participant-list-renderer:not(.n9fJ3)')];
  4789.  
  4790. cProto.__attached412__ = cProto.attached;
  4791. const fpPList = function (hostElement) {
  4792. const cnt = insp(hostElement);
  4793. if (beforeParticipantsMap.has(cnt)) return;
  4794. hostElement.classList.add('n9fJ3');
  4795.  
  4796. assertor(() => (cnt.__dataEnabled === true && cnt.__dataReady === true));
  4797. if (typeof cnt.notifyPath !== 'function' || typeof cnt.__notifyPath5036__ !== 'undefined') {
  4798. console.warn("ERROR(0xE318): yt-live-chat-participant-list-renderer")
  4799. return;
  4800. }
  4801.  
  4802. groupCollapsed("Participant List attached", "");
  4803. cnt.__notifyPath5036__ = cnt.notifyPath
  4804. const participants = ((cnt.participantsManager || 0).participants || 0);
  4805. assertor(() => (participants.length > -1 && typeof participants.slice === 'function'));
  4806. console1.log(`initial number of participants: ${participants.length}`);
  4807. const newParticipants = (participants.length >= 1 && typeof participants.slice === 'function') ? participants.slice(0) : [];
  4808. beforeParticipantsMap.set(cnt, newParticipants);
  4809. cnt.notifyPath = notifyPath7081;
  4810. console1.log(`CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT = ${CHECK_CHANGE_TO_PARTICIPANT_RENDERER_CONTENT}`);
  4811. groupEnd();
  4812. }
  4813. cProto.attached = function () {
  4814. fpPList(this.hostElement || this);
  4815. this.__attached412__.apply(this, arguments);
  4816. };
  4817.  
  4818.  
  4819. if (ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST) {
  4820.  
  4821. /** @type {boolean | (()=>boolean)} */
  4822. let toUseMaintainStableList = USE_MAINTAIN_STABLE_LIST_ONLY_WHEN_KS_FLAG_IS_SET ? (() => ytcfg.data_.EXPERIMENT_FLAGS.kevlar_should_maintain_stable_list === true) : true;
  4823. if (typeof cProto.stampDomArray_ === 'function' && cProto.stampDomArray_.length === 6 && !cProto.stampDomArray_.nIegT && !cProto.stampDomArray66_) {
  4824.  
  4825. let lastMessageDate = 0;
  4826. cProto.stampDomArray66_ = cProto.stampDomArray_;
  4827.  
  4828. cProto.stampDomArray_ = function (...args) {
  4829. if (args[0] && args[0].length > 0 && args[1] === "participants" && args[2] && args[3] === true && !args[5]) {
  4830. if (typeof toUseMaintainStableList === 'function') {
  4831. toUseMaintainStableList = toUseMaintainStableList();
  4832. }
  4833. args[5] = toUseMaintainStableList;
  4834. let currentDate = Date.now();
  4835. if (currentDate - lastMessageDate > 440) {
  4836. lastMessageDate = currentDate;
  4837. console.log('maintain_stable_list for participants list', toUseMaintainStableList);
  4838. }
  4839. }
  4840. return this.stampDomArray66_.apply(this, args);
  4841. }
  4842.  
  4843. cProto.stampDomArray_.nIegT = 1;
  4844.  
  4845. }
  4846. console1.log(`ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST - OK`);
  4847. } else {
  4848. console1.log(`ENABLE_FLAGS_MAINTAIN_STABLE_LIST_FOR_PARTICIPANTS_LIST - NG`);
  4849. }
  4850.  
  4851. groupEnd();
  4852.  
  4853. if (onPageElements.length >= 1) {
  4854. for (const s of onPageElements) {
  4855. if (insp(s).isAttached === true) {
  4856. fpPList(s);
  4857. }
  4858. }
  4859. }
  4860.  
  4861. }).catch(console.warn);
  4862.  
  4863. };
  4864.  
  4865. if (DO_PARTICIPANT_LIST_HACKS) {
  4866. promiseForCustomYtElementsReady.then(onRegistryReadyForDataManipulation);
  4867. }
  4868.  
  4869.  
  4870.  
  4871. const rafHub = (ENABLE_RAF_HACK_TICKERS || ENABLE_RAF_HACK_DOCKED_MESSAGE || ENABLE_RAF_HACK_INPUT_RENDERER || ENABLE_RAF_HACK_EMOJI_PICKER) ? new RAFHub() : null;
  4872.  
  4873. const transitionEndHooks = new WeakSet();
  4874. const transitionEndAfterFnSimple = new WeakMap();
  4875. let transitionEndAfterFnSimpleEnable = 0;
  4876. // let prevTransitionClosing = null;
  4877.  
  4878. const passiveCapture = typeof IntersectionObserver === 'function' ? { capture: true, passive: true } : true;
  4879.  
  4880.  
  4881. const transitionEndAfterFn = (evt) => {
  4882. if (transitionEndAfterFnSimpleEnable > 0 && evt.propertyName && !evt.pseudoElement) {
  4883. const elm = evt.target;
  4884. const f = transitionEndAfterFnSimple.get(elm);
  4885. if (f) {
  4886. transitionEndAfterFnSimple.delete(elm);
  4887. f.resolve(evt.propertyName);
  4888. }
  4889. }
  4890. };
  4891.  
  4892. const fixChildrenIssue = !!fixChildrenIssue801;
  4893. if (fixChildrenIssue && typeof Object.getOwnPropertyDescriptor === 'function' && typeof Proxy !== 'undefined') {
  4894. let fixChildrenIssue_status = false;
  4895. const divProto = HTMLDivElement.prototype;
  4896. const polymerControllerSetData3 = function (c, d, e) {
  4897. return insp(this).set(c, d, e);
  4898. }
  4899. const polymerControllerSetData2 = function (c, d) {
  4900. return insp(this).set(c, d);
  4901. }
  4902. const dummyFn = function () {
  4903. console.log('dummyFn', ...arguments);
  4904. };
  4905.  
  4906. const wm44 = new Map();
  4907. function unPolymerSet(elem) {
  4908. const is = elem.is;
  4909. if (is && !elem.set) {
  4910. let rt = wm44.get(is);
  4911. if (!rt) {
  4912. rt = 1;
  4913. const cnt = insp(elem);
  4914. if (cnt !== elem && cnt && typeof cnt.set === 'function') {
  4915. const pcSet = cnt.constructor.prototype.set;
  4916. if (pcSet && typeof pcSet === 'function' && pcSet.length === 3) {
  4917. rt = polymerControllerSetData3;
  4918. } else if (pcSet && typeof pcSet === 'function' && pcSet.length === 2) {
  4919. rt = polymerControllerSetData2;
  4920. }
  4921. }
  4922. wm44.set(is, rt);
  4923. }
  4924. if (typeof rt === 'function') {
  4925. elem.set = rt;
  4926. } else {
  4927. elem.set = dummyFn;
  4928. }
  4929. }
  4930. }
  4931. if (!divProto.__children577__ && !divProto.__children578__) {
  4932.  
  4933. const dp = Object.getOwnPropertyDescriptor(Element.prototype, 'children');
  4934. const dp2 = Object.getOwnPropertyDescriptor(HTMLElement_.prototype, 'children');
  4935. const dp3 = Object.getOwnPropertyDescriptor(divProto, 'children');
  4936.  
  4937. if (dp && dp.configurable === true && dp.enumerable === true && typeof dp.get === 'function' && !dp2 && !dp3) {
  4938.  
  4939. if (divProto instanceof HTMLElement_ && divProto instanceof Element) {
  4940.  
  4941. let m = Object.assign({}, dp);
  4942. divProto.__children577__ = dp.get;
  4943. divProto.__children578__ = function () {
  4944. if (this.__children803__) return this.__children803__;
  4945. if (this.__children801__) {
  4946. let arr = [];
  4947. for (let elem = this.firstElementChild; elem !== null; elem = elem.nextElementSibling) {
  4948. if (elem.is) {
  4949. unPolymerSet(elem);
  4950. arr.push(elem);
  4951. }
  4952. }
  4953. if (this.__children801__ === 2) this.__children803__ = arr;
  4954. return arr;
  4955. }
  4956. return 577;
  4957. };
  4958. m.get = function () {
  4959. const r = this.__children578__();
  4960. if (r !== 577) return r;
  4961. return this.__children577__();
  4962. };
  4963. Object.defineProperty(divProto, 'children', m);
  4964.  
  4965. fixChildrenIssue_status = true;
  4966.  
  4967. }
  4968. }
  4969.  
  4970. }
  4971.  
  4972. if (!fixChildrenIssue_status) {
  4973. console.log('fixChildrenIssue - set NG')
  4974. }
  4975.  
  4976.  
  4977. }
  4978.  
  4979.  
  4980. const watchUserCSS = () => {
  4981.  
  4982. // if (!CSS.supports('contain-intrinsic-size', 'auto var(--wsr94)')) return;
  4983.  
  4984. const getElemFromWR = (nr) => {
  4985. const n = kRef(nr);
  4986. if (n && n.isConnected) return n;
  4987. return null;
  4988. }
  4989.  
  4990. const clearContentVisibilitySizing = () => {
  4991. Promise.resolve().then(() => {
  4992.  
  4993. const e = document.querySelector('#show-more[disabled]');
  4994. let btnShowMoreWR = e ? mWeakRef(e) : null;
  4995.  
  4996. let lastVisibleItemWR = null;
  4997. for (const elm of document.querySelectorAll('[wsr93]')) {
  4998. if (elm.getAttribute('wsr93') === 'visible') lastVisibleItemWR = mWeakRef(elm);
  4999. elm.setAttribute('wsr93', '');
  5000. // custom CSS property --wsr94 not working when attribute wsr93 removed
  5001. }
  5002. foregroundPromiseFn().then(() => {
  5003. const btnShowMore = getElemFromWR(btnShowMoreWR); btnShowMoreWR = null;
  5004. if (btnShowMore) btnShowMore.click();
  5005. else {
  5006. // would not work if switch it frequently
  5007. const lastVisibleItem = getElemFromWR(lastVisibleItemWR); lastVisibleItemWR = null;
  5008. if (lastVisibleItem) {
  5009.  
  5010. Promise.resolve()
  5011. .then(() => lastVisibleItem.scrollIntoView())
  5012. .then(() => lastVisibleItem.scrollIntoView(false))
  5013. .then(() => lastVisibleItem.scrollIntoView({ behavior: "instant", block: "end", inline: "nearest" }))
  5014. .catch(e => { }) // break the chain when method not callable
  5015.  
  5016. }
  5017. }
  5018. });
  5019.  
  5020. }).catch(console.warn);
  5021.  
  5022. }
  5023.  
  5024. const mutObserver = new MutationObserver((mutations) => {
  5025. for (const mutation of mutations) {
  5026. if ((mutation.addedNodes || 0).length >= 1) {
  5027. for (const addedNode of mutation.addedNodes) {
  5028. if (addedNode.nodeName === 'STYLE') {
  5029. clearContentVisibilitySizing();
  5030. return;
  5031. }
  5032. }
  5033. }
  5034. if ((mutation.removedNodes || 0).length >= 1) {
  5035. for (const removedNode of mutation.removedNodes) {
  5036. if (removedNode.nodeName === 'STYLE') {
  5037. clearContentVisibilitySizing();
  5038. return;
  5039. }
  5040. }
  5041. }
  5042. }
  5043. });
  5044.  
  5045. mutObserver.observe(document.documentElement, {
  5046. childList: true,
  5047. subtree: false
  5048. });
  5049. mutObserver.observe(document.head, {
  5050. childList: true,
  5051. subtree: false
  5052. });
  5053. mutObserver.observe(document.body, {
  5054. childList: true,
  5055. subtree: false
  5056. });
  5057.  
  5058. }
  5059.  
  5060.  
  5061. const { lcRendererElm, visObserver } = (() => {
  5062.  
  5063. let lcRendererWR = null;
  5064.  
  5065. const lcRendererElm = () => {
  5066. let lcRenderer = kRef(lcRendererWR);
  5067. if (!lcRenderer || !lcRenderer.isConnected) {
  5068. lcRenderer = document.querySelector('yt-live-chat-item-list-renderer.yt-live-chat-renderer');
  5069. lcRendererWR = lcRenderer ? mWeakRef(lcRenderer) : null;
  5070. }
  5071. return lcRenderer;
  5072. };
  5073.  
  5074.  
  5075. let hasFirstShowMore = false;
  5076. // let lastVisible = null;
  5077.  
  5078. const visObserverFn = (entry) => {
  5079.  
  5080. const target = entry.target;
  5081. if (!target || !target.hasAttribute('wsr93')) return;
  5082. // if(target.classList.contains('dont-render')) return;
  5083. let isVisible = entry.isIntersecting === true && entry.intersectionRatio > 0.5;
  5084. // const h = entry.boundingClientRect.height;
  5085. /*
  5086. if (h < 16) { // wrong: 8 (padding/margin); standard: 32; test: 16 or 20
  5087. // e.g. under fullscreen. the element created but not rendered.
  5088. target.setAttribute('wsr93', '');
  5089. return;
  5090. }
  5091. */
  5092. if (isVisible) {
  5093. // target.style.setProperty('--wsr94', h + 'px');
  5094. target.setAttribute('wsr93', 'visible');
  5095. // lastVisible = mWeakRef(target);
  5096. if (nNextElem(target) === null) {
  5097.  
  5098. // firstVisibleItemDetected = true;
  5099. /*
  5100. if (dateNow() - lastScroll < 80) {
  5101. lastLShow = 0;
  5102. lastScroll = 0;
  5103. Promise.resolve().then(clickShowMore);
  5104. } else {
  5105. lastLShow = dateNow();
  5106. }
  5107. */
  5108. // lastLShow = dateNow();
  5109. } else if (!hasFirstShowMore) { // should more than one item being visible
  5110. // implement inside visObserver to ensure there is sufficient delay
  5111. hasFirstShowMore = true;
  5112. // foregroundPromiseFn().then(() => {
  5113. // // foreground page
  5114. // // page visibly ready -> load the latest comments at initial loading
  5115. // const lcRenderer = lcRendererElm();
  5116. // if (lcRenderer) {
  5117. // nextBrowserTick_(() => {
  5118. // const cnt = insp(lcRenderer);
  5119. // if (cnt.isAttached === false || (cnt.hostElement || cnt).isConnected === false) return;
  5120. // cnt.scrollToBottom_();
  5121. // });
  5122. // }
  5123. // });
  5124. }
  5125. }
  5126. else if (target.getAttribute('wsr93') === 'visible') { // ignore target.getAttribute('wsr93') === '' to avoid wrong sizing
  5127.  
  5128. // target.style.setProperty('--wsr94', h + 'px');
  5129. target.setAttribute('wsr93', 'hidden');
  5130. } // note: might consider 0 < entry.intersectionRatio < 0.5 and target.getAttribute('wsr93') === '' <new last item>
  5131.  
  5132. }
  5133.  
  5134.  
  5135.  
  5136. const visObserver = new IntersectionObserver((entries) => {
  5137.  
  5138. for (const entry of entries) {
  5139.  
  5140. Promise.resolve(entry).then(visObserverFn);
  5141.  
  5142. }
  5143.  
  5144. }, {
  5145. rootMargin: "0px",
  5146. threshold: [0.05, 0.95],
  5147. });
  5148.  
  5149.  
  5150. return { lcRendererElm, visObserver }
  5151.  
  5152.  
  5153. })();
  5154.  
  5155. // let itemsResizeObserverAttached = false;
  5156. // const resizeObserverFallback = new IntersectionObserver((mutation, observer) => {
  5157. // const itemScroller = mutation[0].target;
  5158. // observer.unobserve(itemScroller);
  5159. // if (itemScroller.scrollTop === 0) itemScroller.scrollTop = window.screen.height; // scrollTop changing
  5160. // });
  5161.  
  5162. const itemScrollerResizeObserver = typeof ResizeObserver === 'function' && ENABLE_OVERFLOW_ANCHOR ? new ResizeObserver((mutations) => {
  5163. const mutation = mutations[mutations.length - 1];
  5164. // console.log('resizeObserver', mutation)
  5165. const itemScroller = (mutation || 0).target;
  5166. if (!itemScroller) return;
  5167. const listDom = itemScroller.closest('yt-live-chat-item-list-renderer');
  5168. if (!listDom) return;
  5169. const listCnt = insp(listDom);
  5170. if(listCnt.visibleItems.length === 0) return;
  5171. if (listCnt.atBottom !== true) return;
  5172. // if (itemScroller.scrollTop === 0) {
  5173. itemScroller.scrollTop = 16777216; // scrollTop changing
  5174. // }
  5175. }) : null;
  5176.  
  5177. const { setupMutObserver } = (() => {
  5178.  
  5179.  
  5180. const mutFn = (items) => {
  5181. let seqIndex = -1;
  5182. const elementSet = new Set();
  5183. elementSet.add = elementSet.addOriginal || elementSet.add;
  5184. for (let node = nLastElem(items); node !== null; node = nPrevElem(node)) { // from bottom
  5185. let found = node.hasAttribute('wsr93') ? (node.hasAttribute('yt-chat-item-seq') ? 2 : 1) : 0;
  5186. if (found === 1) node.removeAttribute('wsr93'); // reuse -> wsr93: hidden after re-attach
  5187. if (found === 2) {
  5188. seqIndex = parseInt(node.getAttribute('yt-chat-item-seq'), 10);
  5189. break;
  5190. }
  5191. visObserver.unobserve(node); // reuse case
  5192. node.setAttribute('wsr93', '');
  5193. visObserver.observe(node);
  5194. elementSet.add(node);
  5195. }
  5196. let iter = elementSet.values();
  5197. let i = seqIndex + elementSet.size;
  5198. for (let curr; curr = iter.next().value;) { // from bottom
  5199. curr.setAttribute('yt-chat-item-seq', i % 60);
  5200. curr.classList.add('yt-chat-item-' + ((i % 2) ? 'odd' : 'even'));
  5201. i--;
  5202. }
  5203. iter = null;
  5204. elementSet.clear();
  5205. }
  5206.  
  5207. // const itemsResizeObserver = typeof ResizeObserver === 'function' && 0 ? new ResizeObserver((mutations) => {
  5208. // const mutation = mutations[mutations.length - 1];
  5209. // // console.log('resizeObserver', mutation)
  5210. // const items = (mutation || 0).target;
  5211. // if (!items) return;
  5212. // const listDom = items.closest('yt-live-chat-item-list-renderer');
  5213. // if (!listDom) return;
  5214. // const listCnt = insp(listDom);
  5215. // if (listCnt.atBottom !== true) return;
  5216. // const itemScroller = listCnt.itemScroller || listCnt.$['item-scroller'] || listCnt.querySelector('#item-scroller') || 0;
  5217. // // if (itemScroller.scrollTop === 0) {
  5218. // itemScroller.scrollTop = mutation.contentRect.height; // scrollTop changing
  5219. // // }
  5220. // }) : null;
  5221. // itemsResizeObserverAttached = itemsResizeObserver !== null;
  5222.  
  5223. const mutObserver = new MutationObserver((mutations) => {
  5224. const items = (mutations[0] || 0).target;
  5225. if (!items) return;
  5226. mutFn(items);
  5227. });
  5228.  
  5229. const setupMutObserver = (items) => {
  5230. scrollChatFn = null;
  5231. mutObserver.disconnect();
  5232. mutObserver.takeRecords();
  5233. if (items) {
  5234. if (typeof items.__appendChild932__ === 'function') {
  5235. if (typeof items.appendChild === 'function') items.appendChild = items.__appendChild932__;
  5236. if (typeof items.__shady_native_appendChild === 'function') items.__shady_native_appendChild = items.__appendChild932__;
  5237. }
  5238. mutObserver.observe(items, {
  5239. childList: true,
  5240. subtree: false
  5241. });
  5242. mutFn(items);
  5243.  
  5244.  
  5245. // if (itemsResizeObserver) itemsResizeObserver.observe(items);
  5246.  
  5247. // const isFirstList = firstList;
  5248. // firstList = false;
  5249.  
  5250.  
  5251. if (items && items.nextElementSibling === null) {
  5252. items.parentNode.appendChild(dr(document.createElement('item-anchor')));
  5253. WITH_SCROLL_ANCHOR = true;
  5254. if (ENABLE_OVERFLOW_ANCHOR) {
  5255. items.classList.add('no-anchor');
  5256. nodeParent(items).classList.add('no-anchor'); // required
  5257. }
  5258. }
  5259.  
  5260.  
  5261.  
  5262.  
  5263. if (ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX) {
  5264.  
  5265. (() => {
  5266.  
  5267. const tag = 'yt-iframed-player-events-relay'
  5268. const dummy = document.createElement(tag);
  5269.  
  5270. const cProto = getProto(dummy);
  5271. if (!cProto || !cProto.handlePostMessage_) {
  5272. console.warn(`proto.handlePostMessage_ for ${tag} is unavailable.`);
  5273. return;
  5274. }
  5275.  
  5276. if (typeof cProto.handlePostMessage_ === 'function' && !cProto.handlePostMessage66_ && !cProto.handlePostMessage67_ ) {
  5277.  
  5278. cProto.handlePostMessage66_ = cProto.handlePostMessage_;
  5279.  
  5280. const handlePostMessageAfterPromiseA = (da) => {
  5281.  
  5282. if (!da || typeof da !== 'object') return;
  5283.  
  5284. if ('yt-player-state-change' in da) {
  5285.  
  5286. const qc = da['yt-player-state-change'];
  5287.  
  5288.  
  5289. let isQcChanged = false;
  5290.  
  5291. if (qc === 2) { isQcChanged = qc !== _playerState; _playerState = 2; relayCount = 0; } // paused
  5292. else if (qc === 3) { isQcChanged = qc !== _playerState; _playerState = 3; } // playing
  5293. else if (qc === 1) { isQcChanged = qc !== _playerState; _playerState = 1; } // playing
  5294.  
  5295.  
  5296. if ((isQcChanged) && playerState !== _playerState) {
  5297. playerEventsByIframeRelay = true;
  5298. onPlayStateChangePromise = new Promise((resolve) => {
  5299. const k = _playerState;
  5300. foregroundPromiseFn().then(() => {
  5301. if (k === _playerState && playerState !== _playerState) playerState = _playerState;
  5302. onPlayStateChangePromise = null;
  5303. resolve();
  5304. })
  5305. }).catch(console.warn);
  5306.  
  5307. }
  5308.  
  5309. } else if ('yt-player-video-progress' in da) {
  5310. const vp = da['yt-player-video-progress'];
  5311.  
  5312.  
  5313. relayCount++;
  5314. lastPlayerProgress = vp > 0 ? vp : 0; // no use ?
  5315.  
  5316.  
  5317. if (relayPromise && vp > 0 && relayCount >= 2) {
  5318. if (onPlayStateChangePromise) {
  5319. onPlayStateChangePromise.then(() => {
  5320. relayPromise && relayPromise.resolve();
  5321. relayPromise = null;
  5322. })
  5323. } else {
  5324. relayPromise.resolve();
  5325. relayPromise = null;
  5326. }
  5327. }
  5328.  
  5329. }
  5330.  
  5331. };
  5332.  
  5333. cProto.handlePostMessage67_ = function (a) {
  5334.  
  5335. let da = a.data;
  5336. const wNode = mWeakRef(this);
  5337. // const wData = mWeakRef(da);
  5338.  
  5339. playEventsStack = playEventsStack.then(() => {
  5340.  
  5341. const cnt = kRef(wNode);
  5342. // const da = kRef(wData);
  5343.  
  5344. if (!cnt || !a || !da) return;
  5345. handlePostMessageAfterPromiseA(da);
  5346. da = null;
  5347.  
  5348. const r = cnt.handlePostMessage66_(a);
  5349. a = null;
  5350.  
  5351. }).catch(console.warn);
  5352.  
  5353. }
  5354.  
  5355. const handlePostMessageAfterPromiseB = (da) => {
  5356.  
  5357. const lcr = document.querySelector('yt-live-chat-renderer');
  5358. const psc = document.querySelector("yt-player-seek-continuation");
  5359. if (lcr && psc && lcr.replayBuffer_) {
  5360.  
  5361. const rbProgress = lcr.replayBuffer_.lastVideoOffsetTimeMsec;
  5362. const daProgress = da['yt-player-video-progress'] * 1000
  5363. // document.querySelector('yt-live-chat-renderer').playerProgressChanged_(1e-5);
  5364.  
  5365. const front_ = (lcr.replayBuffer_.replayQueue || 0).front_;
  5366. const back_ = (lcr.replayBuffer_.replayQueue || 0).back_;
  5367.  
  5368. // console.log(deepCopy( front_))
  5369. // console.log(deepCopy( back_))
  5370. // console.log(rbProgress, daProgress, )
  5371. if (front_ && back_ && rbProgress > daProgress && back_.length > 2 && back_.some(e => e && +e.videoOffsetTimeMsec > daProgress) && back_.some(e => e && +e.videoOffsetTimeMsec < daProgress)) {
  5372. // no action
  5373. // console.log('ss1')
  5374. } else if (rbProgress < daProgress + 3400 && rbProgress > daProgress - 1200) {
  5375. // daProgress - 1200 < rbProgress < daProgress + 3400
  5376. // console.log('ss2')
  5377. } else {
  5378.  
  5379. lcr.previousProgressSec = 1E-5;
  5380. // lcr._setIsSeeking(!0),
  5381. lcr.replayBuffer_.clear()
  5382. psc.fireSeekContinuation_(da['yt-player-video-progress']);
  5383. }
  5384.  
  5385. }
  5386.  
  5387.  
  5388. };
  5389.  
  5390. cProto.handlePostMessage_ = function (a) {
  5391.  
  5392. let da = (a || 0).data || 0;
  5393. const wNode = mWeakRef(this);
  5394.  
  5395. if (typeof da !== 'object') return;
  5396.  
  5397. if (waitForInitialDataCompletion === 1) return;
  5398.  
  5399. if (!isPlayProgressTriggered) {
  5400. isPlayProgressTriggered = true; // set once
  5401.  
  5402. if ('yt-player-video-progress' in da) {
  5403. waitForInitialDataCompletion = 1;
  5404.  
  5405. const wrapWith = (data) => {
  5406. const { origin } = a;
  5407. return {
  5408. origin,
  5409. data
  5410. };
  5411. }
  5412.  
  5413. this.handlePostMessage67_(wrapWith({
  5414. "yt-iframed-parent-ready": true
  5415. }));
  5416.  
  5417.  
  5418. playEventsStack = playEventsStack.then(() => {
  5419.  
  5420. const cnt = kRef(wNode);
  5421.  
  5422. if (!cnt || !a || !da) return;
  5423.  
  5424. handlePostMessageAfterPromiseB(da);
  5425. da = null;
  5426.  
  5427. waitForInitialDataCompletion = 2;
  5428.  
  5429. const r = cnt.handlePostMessage_(a); // isPlayProgressTriggered is set
  5430. a = null;
  5431.  
  5432. }).catch(console.warn);
  5433.  
  5434. return;
  5435.  
  5436. }
  5437.  
  5438. }
  5439.  
  5440. this.handlePostMessage67_(a);
  5441.  
  5442. }
  5443.  
  5444. }
  5445.  
  5446.  
  5447. })();
  5448.  
  5449. }
  5450.  
  5451.  
  5452. }
  5453. }
  5454.  
  5455. return { setupMutObserver };
  5456.  
  5457.  
  5458.  
  5459. })();
  5460.  
  5461. const setupEvents = () => {
  5462. // not called when boost chat is enabled
  5463.  
  5464. // global - currentMouseDown, lastUserInteraction
  5465.  
  5466. let scrollCount = 0;
  5467. let lastScrollCount = -1;
  5468. let lastMouseDown = 0;
  5469.  
  5470. const passiveCapture = typeof IntersectionObserver === 'function' ? { capture: true, passive: true } : true;
  5471.  
  5472. // const delayFlushActiveItemsAfterUserActionK_ = () => {
  5473.  
  5474. // const lcRenderer = lcRendererElm();
  5475. // if (lcRenderer) {
  5476. // const cnt = insp(lcRenderer);
  5477. // if (!cnt.hasUserJustInteracted11_) return;
  5478. // if (cnt.atBottom && cnt.allowScroll && cnt.activeItems_.length >= 1 && cnt.hasUserJustInteracted11_()) {
  5479. // cnt.delayFlushActiveItemsAfterUserAction11_ && cnt.delayFlushActiveItemsAfterUserAction11_();
  5480. // }
  5481. // }
  5482.  
  5483. // }
  5484.  
  5485. const delayFlushActiveItemsAfterUserActionK_ = null;
  5486.  
  5487. document.addEventListener('scroll', (evt) => {
  5488. if (!evt || !evt.isTrusted) return;
  5489. // lastScroll = dateNow();
  5490. scrollCount = (scrollCount & 1073741823) + 1;
  5491. }, passiveCapture); // support contain => support passive
  5492.  
  5493. document.addEventListener('wheel', (evt) => {
  5494. if (!evt || !evt.isTrusted) return;
  5495. if (lastScrollCount === scrollCount) return;
  5496. lastScrollCount = scrollCount;
  5497. lastWheel = dateNow();
  5498. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  5499. }, passiveCapture); // support contain => support passive
  5500.  
  5501. document.addEventListener('mousedown', (evt) => {
  5502. if (!evt || !evt.isTrusted) return;
  5503. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  5504. lastMouseDown = dateNow();
  5505. currentMouseDown = true;
  5506. lastUserInteraction = lastMouseDown;
  5507. }, passiveCapture);
  5508.  
  5509. document.addEventListener('pointerdown', (evt) => {
  5510. if (!evt || !evt.isTrusted) return;
  5511. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  5512. lastMouseDown = dateNow();
  5513. currentMouseDown = true;
  5514. lastUserInteraction = lastMouseDown;
  5515. }, passiveCapture);
  5516.  
  5517. document.addEventListener('click', (evt) => {
  5518. if (!evt || !evt.isTrusted) return;
  5519. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  5520. lastMouseDown = lastMouseUp = dateNow();
  5521. currentMouseDown = false;
  5522. lastUserInteraction = lastMouseDown;
  5523. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  5524. }, passiveCapture);
  5525.  
  5526. document.addEventListener('tap', (evt) => {
  5527. if (!evt || !evt.isTrusted) return;
  5528. if (((evt || 0).target || 0).id !== 'item-scroller') return;
  5529. lastMouseDown = lastMouseUp = dateNow();
  5530. currentMouseDown = false;
  5531. lastUserInteraction = lastMouseDown;
  5532. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  5533. }, passiveCapture);
  5534.  
  5535.  
  5536. document.addEventListener('mouseup', (evt) => {
  5537. if (!evt || !evt.isTrusted) return;
  5538. if (currentMouseDown) {
  5539. lastMouseUp = dateNow();
  5540. currentMouseDown = false;
  5541. lastUserInteraction = lastMouseUp;
  5542. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  5543. }
  5544. }, passiveCapture);
  5545.  
  5546.  
  5547. document.addEventListener('pointerup', (evt) => {
  5548. if (!evt || !evt.isTrusted) return;
  5549. if (currentMouseDown) {
  5550. lastMouseUp = dateNow();
  5551. currentMouseDown = false;
  5552. lastUserInteraction = lastMouseUp;
  5553. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  5554. }
  5555. }, passiveCapture);
  5556.  
  5557. document.addEventListener('touchstart', (evt) => {
  5558. if (!evt || !evt.isTrusted) return;
  5559. lastTouchDown = dateNow();
  5560. currentTouchDown = true;
  5561. lastUserInteraction = lastTouchDown;
  5562. }, passiveCapture);
  5563.  
  5564. document.addEventListener('touchmove', (evt) => {
  5565. if (!evt || !evt.isTrusted) return;
  5566. lastTouchDown = dateNow();
  5567. currentTouchDown = true;
  5568. lastUserInteraction = lastTouchDown;
  5569. }, passiveCapture);
  5570.  
  5571. document.addEventListener('touchend', (evt) => {
  5572. if (!evt || !evt.isTrusted) return;
  5573. if (currentTouchDown) {
  5574. lastTouchUp = dateNow();
  5575. currentTouchDown = false;
  5576. lastUserInteraction = lastTouchUp;
  5577. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  5578. }
  5579. }, passiveCapture);
  5580.  
  5581. document.addEventListener('touchcancel', (evt) => {
  5582. if (!evt || !evt.isTrusted) return;
  5583. if (currentTouchDown) {
  5584. lastTouchUp = dateNow();
  5585. currentTouchDown = false;
  5586. lastUserInteraction = lastTouchUp;
  5587. delayFlushActiveItemsAfterUserActionK_ && delayFlushActiveItemsAfterUserActionK_();
  5588. }
  5589. }, passiveCapture);
  5590.  
  5591.  
  5592. }
  5593.  
  5594. // const getTimestampUsec = (itemRenderer) => {
  5595. // if (itemRenderer && 'timestampUsec' in itemRenderer) {
  5596. // return itemRenderer.timestampUsec
  5597. // } else if (itemRenderer && itemRenderer.showItemEndpoint) {
  5598. // const messageRenderer = ((itemRenderer.showItemEndpoint.showLiveChatItemEndpoint || 0).renderer || 0);
  5599. // if (messageRenderer) {
  5600.  
  5601. // const messageRendererKey = firstObjectKey(messageRenderer);
  5602. // if (messageRendererKey && messageRenderer[messageRendererKey]) {
  5603. // const messageRendererData = messageRenderer[messageRendererKey];
  5604. // if (messageRendererData && 'timestampUsec' in messageRendererData) {
  5605. // return messageRendererData.timestampUsec
  5606. // }
  5607. // }
  5608. // }
  5609. // }
  5610. // return null;
  5611. // }
  5612.  
  5613. const onRegistryReadyForDOMOperations = () => {
  5614.  
  5615. let firstCheckedOnYtInit = false;
  5616.  
  5617. const assertorURL = () => assertor(() => location.pathname.startsWith('/live_chat') && (location.search.indexOf('continuation=') > 0 || location.search.indexOf('v=') > 0));
  5618.  
  5619. const mightFirstCheckOnYtInit = () => {
  5620. if (firstCheckedOnYtInit) return;
  5621. firstCheckedOnYtInit = true;
  5622.  
  5623. if (!document.body || !document.head) return;
  5624. if (!assertorURL()) return;
  5625.  
  5626. addCssManaged();
  5627.  
  5628. let efsContainer = document.getElementById('elzm-fonts-yk75g');
  5629. if (efsContainer && efsContainer.parentNode !== document.body) {
  5630. document.body.appendChild(efsContainer);
  5631. }
  5632.  
  5633. };
  5634.  
  5635. if (!assertorURL()) return;
  5636. // if (!assertor(() => document.getElementById('yt-masthead') === null)) return;
  5637.  
  5638.  
  5639. const { weakWrap } = (() => {
  5640.  
  5641.  
  5642. // const tickerFuncProps = new Set([
  5643. // 'animateShowStats', 'animateHideStats', // updateStatsBarAndMaybeShowAnimationRevised
  5644. // 'collapse', // slideDownNoSelfLeakage
  5645. // 'requestRemoval', // collapseNoSelfLeakage
  5646. // 'setContainerWidth', 'get', 'set', // deletedChangedNoSelfLeakage
  5647. // 'computeAriaLabel', //dataChanged
  5648. // 'startCountdown', // dataChanged [in case]
  5649. // ]);
  5650.  
  5651. // const tickerTags = new Set([
  5652. // "yt-live-chat-ticker-renderer",
  5653. // "yt-live-chat-ticker-paid-message-item-renderer",
  5654. // "yt-live-chat-ticker-paid-sticker-item-renderer",
  5655. // "yt-live-chat-ticker-sponsor-item-renderer"
  5656. // ]);
  5657.  
  5658. // const emptySet = new Set();
  5659.  
  5660.  
  5661.  
  5662. // const tickerFuncPropsFn = (cnt) => {
  5663.  
  5664. // const is = `${cnt.is}`;
  5665.  
  5666. // if (tickerTags.has(is)) {
  5667. // let flg = 0;
  5668. // if (cnt.get && cnt.set) flg |= 1;
  5669. // if (cnt.setContainerWidth && cnt.collapse && cnt.requestRemoval) flg |= 2;
  5670. // if (cnt.animateShowStats && cnt.animateHideStats) flg |= 4;
  5671. // if (cnt.startCountdown) flg |= 8;
  5672. // console.log(`DEBUG flag_6877 = ${flg}`, is);
  5673. // // DEBUG flag_6877 = 15 yt-live-chat-ticker-paid-message-item-renderer
  5674. // // DEBUG flag_6877 = 11 yt-live-chat-ticker-sponsor-item-renderer
  5675. // return tickerFuncProps;
  5676. // }
  5677.  
  5678. // return emptySet;
  5679.  
  5680.  
  5681. // }
  5682.  
  5683.  
  5684. // const smb = Symbol();
  5685. const vmb = 'dtz02' // Symbol(); // return kThis for thisArg
  5686. const vmc = 'dtz04' // Symbol(); // whether it is proxied fn
  5687. const vmd = 'dtz08' // Symbol(); // self fn proxy (fn--fn)
  5688.  
  5689.  
  5690.  
  5691.  
  5692. const thisConversionFn = (thisArg) => {
  5693. if (!thisArg) return null;
  5694. const kThis = thisArg[vmb];
  5695. if (kThis) {
  5696. const ref = kThis.ref;
  5697. return (ref ? kRef(ref) : null) || null;
  5698. }
  5699. return thisArg;
  5700. }
  5701.  
  5702. const pFnHandler2 = {
  5703. get(target, prop) {
  5704. if (prop === vmc) return target;
  5705. return Reflect.get(target, prop);
  5706. },
  5707. apply(target, thisArg, argumentsList) {
  5708. thisArg = thisConversionFn(thisArg);
  5709. if (thisArg) return Reflect.apply(target, thisArg, argumentsList);
  5710. }
  5711. }
  5712.  
  5713.  
  5714. const proxySelfHandler = {
  5715. get(target, prop) {
  5716. if(prop === vmb) return target;
  5717. const ref = target.ref;
  5718. const cnt = kRef(ref);
  5719. if (!cnt) return;
  5720. if (typeof cnt[prop] === 'function' && !cnt[prop][vmc] && !cnt[prop][vmb]) {
  5721. if (!cnt[prop][vmd]) cnt[prop][vmd] = new Proxy(cnt[prop], pFnHandler2);
  5722. return cnt[prop][vmd];
  5723. }
  5724. return cnt[prop];
  5725. },
  5726. set(target, prop, value) {
  5727. const cnt = kRef(target.ref);
  5728. if (!cnt) return true;
  5729. if(value && (value[vmc] || value[vmb])){
  5730. cnt[prop] = value[vmc] || thisConversionFn(value);
  5731. return true;
  5732. }
  5733. cnt[prop] = value;
  5734. return true;
  5735. }
  5736. };
  5737.  
  5738. const weakWrap = (thisArg) => {
  5739. thisArg = thisConversionFn(thisArg);
  5740. if (!thisArg) {
  5741. console.error('thisArg is not found');
  5742. return null;
  5743. }
  5744. return new Proxy({ ref: mWeakRef(thisArg) }, proxySelfHandler);
  5745. }
  5746.  
  5747.  
  5748.  
  5749.  
  5750.  
  5751.  
  5752. if (!window.getComputedStyle533 && typeof window.getComputedStyle === 'function') {
  5753. window.getComputedStyle533 = window.getComputedStyle;
  5754. window.getComputedStyle = function (a, ...args) {
  5755. a = thisConversionFn(a);
  5756. if (a) {
  5757. return getComputedStyle533(a, ...args);
  5758. }
  5759. return null;
  5760. }
  5761. }
  5762.  
  5763.  
  5764.  
  5765.  
  5766.  
  5767.  
  5768.  
  5769. // const fnProxySelf = function (...args) {
  5770. // const cnt = kRef(this.ref);
  5771. // if (cnt) {
  5772. // return cnt[this.prop](...args); // might throw error
  5773. // }
  5774. // }
  5775. // const proxySelfHandler = {
  5776. // get(target, prop) {
  5777. // const ref = target.ref;
  5778. // const cnt = kRef(ref);
  5779. // if (!cnt) return;
  5780. // if (prop === 'dtz06') return 1;
  5781. // if (typeof cnt[prop] === 'function') {
  5782. // if (!target.funcs.has(prop)) {
  5783. // console.warn(`proxy get to function | prop: ${prop} | is: ${cnt.is}`);
  5784. // }
  5785. // if (!target[`$$${prop}$$`]) target[`$$${prop}$$`] = fnProxySelf.bind({ prop, ref });
  5786. // return target[`$$${prop}$$`];
  5787. // }
  5788. // return cnt[prop];
  5789. // },
  5790. // set(target, prop, value) {
  5791. // const cnt = kRef(target.ref);
  5792. // if (!cnt) return true;
  5793. // if (typeof value === 'function') {
  5794. // console.warn(`proxy set to function | prop: ${prop} | is: ${cnt.is}`);
  5795. // cnt[prop] = value;
  5796. // return true;
  5797. // }
  5798. // cnt[prop] = value;
  5799. // return true;
  5800. // }
  5801. // };
  5802.  
  5803. // return { tickerFuncPropsFn, proxySelfHandler }
  5804.  
  5805. return {weakWrap}
  5806. })();
  5807.  
  5808.  
  5809.  
  5810. if (document.documentElement && document.head) {
  5811. addCssManaged();
  5812. }
  5813. // console.log(document.body===null)
  5814.  
  5815. const preprocessChatLiveActionsMap = new WeakSet();
  5816.  
  5817. const toLAObj=(aItem)=>{
  5818.  
  5819. if (!aItem || typeof aItem !== 'object') return false;
  5820. const key = firstObjectKey(aItem); // addLiveChatTickerItemAction
  5821. if (!key) return false;
  5822. let obj = aItem[key];
  5823. if (!obj || typeof obj !== 'object') return false;
  5824.  
  5825. if (typeof (obj.item || 0) == 'object' && firstObjectKey(obj) === 'item') {
  5826. obj = obj.item;
  5827. const key = firstObjectKey(obj);
  5828. if (key) {
  5829. obj = obj[key];
  5830. }
  5831. }
  5832.  
  5833. return obj;
  5834.  
  5835. };
  5836.  
  5837. const groupsK38=[];
  5838.  
  5839.  
  5840. function intervalsOverlap(a1, a2, b1, b2) {
  5841. // Order the intervals without using Math functions
  5842. var startA = a1 <= a2 ? a1 : a2;
  5843. var endA = a1 <= a2 ? a2 : a1;
  5844.  
  5845. var startB = b1 <= b2 ? b1 : b2;
  5846. var endB = b1 <= b2 ? b2 : b1;
  5847.  
  5848. // Check for overlap
  5849. return endA >= startB && endB >= startA;
  5850. }
  5851.  
  5852.  
  5853.  
  5854. const insertIntoSortedArrayA28 = (arr, val) => {
  5855. let left = 0;
  5856. const n = arr.length;
  5857. let right = n;
  5858.  
  5859. // Binary search to find the correct insertion index:
  5860. // We want the first index where arr[index][2] >= val[2].
  5861. while (left < right) {
  5862. const mid = (left + right) >>> 1;
  5863. if (arr[mid][0] < val[0]) {
  5864. left = mid + 1;
  5865. } else {
  5866. right = mid;
  5867. }
  5868. }
  5869.  
  5870. // 'left' is now the insertion index
  5871. left === n ? arr.push(val): arr.splice(left, 0, val);
  5872. };
  5873.  
  5874. function removeNullsInPlace(arr, startI = 0) {
  5875. let insertPos = startI;
  5876. for (let i = startI; i < arr.length; i++) {
  5877. if (arr[i] !== null) {
  5878. insertPos !== i && (arr[insertPos] = arr[i]);
  5879. insertPos++;
  5880. }
  5881. }
  5882. arr.length = insertPos; // Remove the trailing nulls.
  5883. }
  5884.  
  5885. let fir = 0;
  5886.  
  5887. const limitAddition = (a, b) => {
  5888. // Number.MAX_SAFE_INTEGER = 9007199254740991
  5889. // formula = Math.round((a + b) / (1 + a * b / k / k))
  5890. // avoid a*b > 9007199254740991
  5891. // say a, b <= 94800000
  5892. // Consider (x+x) - (x+x) / (1 + x^2 / k^2) < 0.49
  5893. // x < 130095
  5894.  
  5895. const w = 130095;
  5896. if (a < w && b < w) return a + b;
  5897. const k2 = 94800000 * 94800000;
  5898. return Math.round((a + b) / (1 + (a * b) / k2));
  5899. }
  5900.  
  5901. const preprocessChatLiveActions = (arr, ct_) =>{
  5902.  
  5903. if (!ct_) ct_ = Date.now();
  5904.  
  5905. if (!fir) {
  5906.  
  5907. if (!__LCRInjection__) {
  5908. console.error('[yt-chat] preprocessChatLiveActions might fail because of no __LCRInjection__');
  5909. }
  5910.  
  5911. DEBUG_preprocessChatLiveActions && console.log('[yt-chat-debug] 5990', 'preprocessChatLiveActions', arr)
  5912.  
  5913. DEBUG_preprocessChatLiveActions && console.log('[yt-chat-debug] 5991', document.querySelectorAll('yt-live-chat-ticker-renderer #ticker-items [class]').length)
  5914.  
  5915. fir = 1;
  5916. // debugger;
  5917. }
  5918.  
  5919. if (!arr || !arr.length) return arr;
  5920.  
  5921. if (preprocessChatLiveActionsMap.has(arr)) return arr;
  5922. preprocessChatLiveActionsMap.add(arr);
  5923.  
  5924.  
  5925.  
  5926. const ct = ct_;
  5927.  
  5928. let groups_ = null;
  5929.  
  5930. // console.log(1237005);
  5931. // const conversionMap = new WeakMap();
  5932.  
  5933. const additionalInfo = new WeakMap();
  5934.  
  5935. // const adjustmentMap = new Map();
  5936.  
  5937. if (FIX_TIMESTAMP_FOR_REPLAY) {
  5938.  
  5939. // console.log('group02331')
  5940. // console.time('FIX_TIMESTAMP_FOR_REPLAY')
  5941.  
  5942. // const stack = new Array(arr.length);
  5943. // let stackL = 0;
  5944.  
  5945. // const arrHash = new Array(arr.length);
  5946.  
  5947.  
  5948. const groups = groupsK38;
  5949. // const delta = 2.0; // head-to-tail + 0.5 + 0.5 = 1.0 -> symmetric -> 1.0 * 2 = 2.0
  5950. // (2)
  5951. // (1.5, 2.5)
  5952. // (1.51, 2.49)
  5953. // -> (1.01, 2.01) , (1.99, 2.99)
  5954. // 2.99 - 1.01 = 1.98 -> 2
  5955.  
  5956.  
  5957.  
  5958. const pushToGroup = (t0mu)=>{
  5959.  
  5960. const t0auDv = t0mu - 1e6; // t0buDv - t0auDv = 2e6
  5961. const t0buDv = t0mu + 1e6;
  5962. // const t0auEv = t0mu - 2e6;
  5963. // const t0buEv = t0mu + 2e6;
  5964.  
  5965. let groupK = false;
  5966. // let m = -1;
  5967. // let q= 0;
  5968. //const qq =true;
  5969. //qq && console.log('-------')
  5970.  
  5971. let lastRight = null;
  5972. let lastK = null;
  5973. let deletedStartIndex = -1;
  5974.  
  5975. for (let k = 0, kl = groups.length; k < kl; k++) {
  5976.  
  5977. const group = groups[k];
  5978. const [groupStart, groupEnd, gCount] = group;
  5979. //qq && console.log(`-- ${k} ----- ${groupMid} : [${groupStart},${groupEnd}] || C1 = ${t0buEv < groupMid} || C2 = ${t0auEv > groupMid}`);
  5980.  
  5981. // if (t0bsEv < groupMid) continue; // if(t0m + 1.0 < groupMid - 1.0) continue;
  5982. // if (m < 0) m = k;
  5983. // if (t0asEv > groupMid){
  5984. // continue; // if(t0m - 1.0 > groupMid + 1.0) break;
  5985. // }
  5986.  
  5987.  
  5988. // if (m < 0) m = k;
  5989.  
  5990. if (lastRight > groupStart) {
  5991. if (!groupK) {
  5992. // just in case sth wrong
  5993. console.warn('logic ERROR');
  5994. groups[k] = null;
  5995. if(deletedStartIndex < 0) deletedStartIndex = k;
  5996. break;
  5997. } else {
  5998.  
  5999.  
  6000. // GroupA: N_a' = N_a + n_e{1} ; Note n_e is the only way to shift right to cause " (lastRight > groupStart) "
  6001. // GroupB: N_b
  6002. // Merge Group (A) = N_a' + N_b
  6003.  
  6004. // without entry moditification, no overlap
  6005. // this must be due to entry moditifcation
  6006. // entry is already count. so can be skipped after merging
  6007.  
  6008. // for merging, groupA will move to right side but left than groupB, so no overlap to groupC
  6009.  
  6010. const group = groups[lastK];
  6011. const newN = limitAddition(group[2], gCount);
  6012.  
  6013. const factor = gCount / (group[2] + gCount);
  6014.  
  6015. // group[0] = (group[0] * group[2] + groupStart * gCount) / (group[2] + gCount)
  6016. group[0] += (groupStart - group[0]) * factor;
  6017.  
  6018. // group[1] = lastRight = (group[1] * group[2] + groupEnd * gCount) / (group[2] + gCount)
  6019. group[1] += (groupEnd - group[1]) * factor;
  6020.  
  6021. group[2] = newN;
  6022. // no change of lastK
  6023. groups[k] = null;
  6024. if(deletedStartIndex < 0) deletedStartIndex = k;
  6025. continue;
  6026. }
  6027. }
  6028.  
  6029. const minGroupStart = lastRight; // all groupStart, groupEnd >= minGroupStart for k, k+1, ...
  6030. if (t0buDv < minGroupStart) {
  6031. // no overlapping could be possible
  6032. break;
  6033. }
  6034.  
  6035. if (intervalsOverlap(t0auDv, t0buDv, groupStart, groupEnd)) {
  6036.  
  6037. groupK = true;
  6038.  
  6039. // if (t0auDv > groupStart) group[0] = t0auDv;
  6040. // else if (t0buDv < groupEnd) group[1] = t0buDv;
  6041.  
  6042. // const newStart = (groupStart * gCount + t0auDv) / (gCount + 1);
  6043. const newStart = groupStart + (t0auDv - groupStart) * 1 / (gCount + 1);
  6044.  
  6045. if (newStart < lastRight) {
  6046. // n_e{1} will make N_b shift left
  6047.  
  6048. // GroupA: N_a
  6049. // GroupB: N_b
  6050. // Merge Group (A) = N_a + N_b + n_e{1}
  6051.  
  6052. const group = groups[lastK];
  6053. const newN = limitAddition(limitAddition(group[2], gCount), 1);
  6054. const f1 = gCount / (group[2] + gCount + 1);
  6055. const f2 = 1 / (group[2] + gCount + 1);
  6056.  
  6057. // group[0] = (group[0] * group[2] + groupStart * gCount + t0auDv) / (group[2] + gCount + 1);
  6058. group[0] += (groupStart - group[0]) * f1 + (t0auDv - group[0]) * f2;
  6059.  
  6060. // group[1] = lastRight = (group[1] * group[2] + groupEnd * gCount + t0buDv) / (group[2] + gCount + 1)
  6061. lastRight = (group[1] += (groupEnd - group[1]) * f1 + (t0buDv - group[1]) * f2);
  6062.  
  6063. group[2] = newN;
  6064. // no change of lastK
  6065. groups[k] = null;
  6066. if(deletedStartIndex < 0) deletedStartIndex = k;
  6067. continue;
  6068.  
  6069. } else {
  6070. // n_e{1} will make N_b shift either left or right
  6071.  
  6072. // GroupT: N_t
  6073. // Group (T) = N_t + n_e{1}
  6074.  
  6075. const newN = limitAddition(gCount, 1);
  6076.  
  6077. group[0] = newStart;
  6078. // group[1] = lastRight = (groupEnd * gCount + t0buDv) / (gCount + 1);
  6079. group[1] = lastRight = groupEnd + (t0buDv - groupEnd) * 1 / (gCount + 1);
  6080. group[2] = newN;
  6081.  
  6082. lastK = k;
  6083.  
  6084. // (t0asDv > groupStart) && (t0bsDv < groupEnd) means full containement
  6085. // however, group size is smaller than or equal to t0width
  6086. }
  6087.  
  6088.  
  6089. } else {
  6090. // just update record for next iteration
  6091.  
  6092. lastRight = groupEnd;
  6093. lastK = k;
  6094. }
  6095.  
  6096.  
  6097.  
  6098. }
  6099.  
  6100. if (deletedStartIndex >= 0) {
  6101. // rarely used
  6102.  
  6103. removeNullsInPlace(groups, deletedStartIndex);
  6104.  
  6105. }
  6106. if (!groupK) {
  6107. // groups.push([t0auDv, t0buDv, 1]);
  6108. insertIntoSortedArrayA28(groups, [t0auDv, t0buDv, 1]);
  6109. // insertIntoSortedArrayA27(groups, [t0auDv, t0buDv, t0mu]);
  6110. }
  6111.  
  6112.  
  6113. }
  6114.  
  6115. let autoTimeStampFrameChoose = 0;
  6116.  
  6117. // console.log('group02332')
  6118. for (let j = 0, l = arr.length; j < l; j++) {
  6119. const aItem = arr[j];
  6120.  
  6121. const obj = toLAObj(aItem);
  6122. if (obj === false) continue;
  6123.  
  6124. let p = obj.timestampText;
  6125. let p2, p3=null, p4a=null, p4b=null;
  6126. if(p&&p.simpleText ) p2 = p.simpleText;
  6127.  
  6128. let q = obj.timestampUsec ;
  6129. let q2;
  6130.  
  6131. if(q && +q > 1110553200000000) q2 = +q;
  6132. if (q2 > 0 && !autoTimeStampFrameChoose) {
  6133. const q2cc = Math.round(q2 / 1e6);
  6134. autoTimeStampFrameChoose = q2cc - (q2cc % 10000000);
  6135. if (q2cc - autoTimeStampFrameChoose < 2000000) autoTimeStampFrameChoose -= 10000000;
  6136. // around 10day range
  6137. // exceeded ~10day -> above 10000000
  6138. }
  6139.  
  6140. // console.log('group02333', p2, q2)
  6141. // console.log(3775, q2/1e6, autoTimeStampFrameChoose)
  6142.  
  6143. if(p2 && q2){
  6144.  
  6145. let m;
  6146.  
  6147. if (m = /^\s*(-?)(\d+):(\d+)\s*$/.exec(p2)) {
  6148. let c0z = m[1] ? -1 : 1;
  6149. let c1 = (+m[2]);
  6150. let c2 = (+m[3]);
  6151. if (c0z > 0 && c1 >= 0 && c2 >= 0) {
  6152.  
  6153. p3 = c1 * 60 + c2;
  6154. } else if (c0z < 0 && c1 >= 0 && c2 >= 0) {
  6155. // -4:43 -> -4:42 -> -4:41 ... -> -4:01 -> -4:00 -> -3:59 -> -3:58
  6156. // -> ... -1:01 -> -1:00 -> -0:59 -> ... -> -0:02 -> -0:01 -> -0:00 -> 0:00 -> ...
  6157.  
  6158. p3 = (-c1 * 60) + (-c2);
  6159.  
  6160. }
  6161. if (p3 !== null) {
  6162. // 0:14 -> 13.5s ~ 14.4999s -> [13.5, 14.5)
  6163. p4a = p3 - 0.5;
  6164. p4b = p3 + 0.5;
  6165. }
  6166. } else if (m = /^\s*(-?)(\d+):(\d+):(\d+)\s*$/.exec(p2)) {
  6167.  
  6168. let c0z = m[1] ? -1 : 1;
  6169. let c1 = (+m[2]);
  6170. let c2 = (+m[3]);
  6171. let c3 = (+m[4]);
  6172.  
  6173.  
  6174.  
  6175. if (c0z > 0 && c1 >= 0 && c2 >= 0 && c3 >= 0) {
  6176.  
  6177. p3 = c1 * 60 * 60 + c2 * 60 + c3;
  6178. } else if (c0z < 0 && c1 >= 0 && c2 >= 0 && c3>=0) {
  6179. // -4:43 -> -4:42 -> -4:41 ... -> -4:01 -> -4:00 -> -3:59 -> -3:58
  6180. // -> ... -1:01 -> -1:00 -> -0:59 -> ... -> -0:02 -> -0:01 -> -0:00 -> 0:00 -> ...
  6181.  
  6182. p3 = (-c1 * 60 * 60) + (-c2 * 60) + (-c3);
  6183.  
  6184. }
  6185. if (p3 !== null) {
  6186. // 0:14 -> 13.5s ~ 14.4999s -> [13.5, 14.5)
  6187. p4a = p3 - 0.5;
  6188. p4b = p3 + 0.5;
  6189. }
  6190.  
  6191.  
  6192. }
  6193.  
  6194. }
  6195.  
  6196. if(p4a !== null && p4b !== null && q2 > 0){
  6197.  
  6198. // q2_us = t0_us + dt_us
  6199. // p4a_us <= dt_us < p4b_us
  6200. let p4au = p4a * 1e6;
  6201. let p4bu = p4b * 1e6;
  6202.  
  6203. // p4a_us <= q2_us - t0_us < p4b_us
  6204.  
  6205.  
  6206. // p4a_us - q2_us <= - t0_us < p4b_us - q2_us
  6207.  
  6208. // -p4a_us + q2_us >= t0_us > -p4b_us + q2_us
  6209.  
  6210.  
  6211. let t0au = q2 - p4bu; // q2_us - p4b_us
  6212. let t0bu = q2 - p4au; // q2_us - p4a_us
  6213.  
  6214. // t0 (t0au, t0bu]
  6215.  
  6216. const t0mu = (t0au+t0bu)/2;
  6217.  
  6218. // stack[stackL++]=({
  6219. // id: obj.id,
  6220. // idx: j,
  6221. // p2,
  6222. // // q2s : (q2/ 1e6 - autoTimeStampFrameChoose).toFixed(2),
  6223. // p3,
  6224. // /*
  6225. // timestampText: obj.timestampText,
  6226. // timestampUsec: obj.timestampUsec, // us = 1/1000 ms
  6227. // q2,
  6228. // p4a,
  6229. // p4b,
  6230. // */
  6231. // q2s: +(q2 / 1e6 - autoTimeStampFrameChoose).toFixed(2),
  6232. // t0as: +(t0au / 1e6 - autoTimeStampFrameChoose).toFixed(2),
  6233. // t0bs: +(t0bu /1e6 - autoTimeStampFrameChoose).toFixed(2),
  6234.  
  6235. // t0au,
  6236. // t0bu,
  6237. // t0mu
  6238. // });
  6239.  
  6240. // console.log('group02334')
  6241. let wobj = additionalInfo.get(obj);
  6242. if(!wobj) additionalInfo.set(obj, wobj = {});
  6243.  
  6244. wobj.timestampUsecOriginal = q2;
  6245. // wobj.timestampUsecAdjusted = q2;
  6246. wobj.t0au = t0au;
  6247. wobj.t0bu = t0bu;
  6248. wobj.t0mu = t0mu;
  6249.  
  6250. // arrHash[j] = {
  6251. // index: j,
  6252. // id: obj.id,
  6253. // timestampUsec: q2,
  6254. // t0au,
  6255. // t0bu,
  6256. // t0mu
  6257. // };
  6258.  
  6259. pushToGroup(t0mu);
  6260.  
  6261. // console.log('group02335')
  6262. // console.log('grouping', `${obj.id}.${obj.timestampUsec}`);
  6263.  
  6264. // timestamp (q2) can be incorrect.
  6265.  
  6266. // https://www.youtube.com/watch?v=IKKar5SS29E
  6267. // ChwKGkNQZUxfXzZxLS04Q0ZXNGxyUVlkODZrQzNR
  6268.  
  6269. /*
  6270.  
  6271.  
  6272. [
  6273. {
  6274. "id": "ChwKGkNNWHZqXy1xLS04Q0ZXNGxyUVlkODZrQzNR",
  6275. "p2": "2:04",
  6276. "p3": 124,
  6277. "t0as": 8320733.78,
  6278. "t0bs": 8320734.78
  6279. },
  6280. {
  6281. "id": "ChwKGkNQZUxfXzZxLS04Q0ZXNGxyUVlkODZrQzNR",
  6282. "p2": "2:04",
  6283. "p3": 124,
  6284. "t0as": 8320898.89, // incorrect
  6285. "t0bs": 8320899.89
  6286. }
  6287. ]
  6288.  
  6289.  
  6290. */
  6291.  
  6292. }
  6293.  
  6294.  
  6295.  
  6296.  
  6297. }
  6298.  
  6299. // stack.length = stackL;
  6300.  
  6301.  
  6302. groups_ = groups;
  6303. // console.log('groups', groups)
  6304.  
  6305. }
  6306.  
  6307. // console.log(1237006);
  6308.  
  6309. // console.log(5592,1)
  6310. const groupMids = FIX_TIMESTAMP_FOR_REPLAY ? groups_.map(group=>{
  6311.  
  6312. const [groupStart, groupEnd ] = group;
  6313. const groupMid = (groupStart+groupEnd)/2;
  6314. return groupMid;
  6315. }): null;
  6316. // console.log('groupMids', groupMids)
  6317.  
  6318.  
  6319. // console.log(1237007);
  6320.  
  6321. const adjustTimestampFn = (obj) => {
  6322.  
  6323. const groupCount = groupMids.length;
  6324.  
  6325. if (groupCount < 1) return null;
  6326.  
  6327. // const obj = toLAObj(aItem);
  6328. if (obj === false) return null;
  6329.  
  6330. const wobj = additionalInfo.get(obj);
  6331. if (!wobj) return null;
  6332.  
  6333. const { t0mu } = wobj;
  6334.  
  6335.  
  6336. let i0 = 0;
  6337.  
  6338. if (groupCount >= 3) {
  6339. // For larger arrays, use binary search.
  6340. let low = 0;
  6341. let high = groupCount - 1;
  6342.  
  6343. while (high - low > 1) {
  6344. const mid = (low + high) >>> 1;
  6345. if (groupMids[mid] >= t0mu) {
  6346. high = mid;
  6347. } else {
  6348. low = mid;
  6349. }
  6350. }
  6351. i0 = low;
  6352.  
  6353. }
  6354.  
  6355. let upperDiff = -1;
  6356. let lowerDiff = -1;
  6357. for (let i = i0; i < groupCount; i++) {
  6358. const y = groupMids[i] - t0mu;
  6359. if (y >= 0) {
  6360. upperDiff = y; // >=0, entry > value is found
  6361. break;
  6362. }
  6363. lowerDiff = -y; // >0, cache
  6364. }
  6365.  
  6366.  
  6367. const d1 = upperDiff;
  6368. const d2 = lowerDiff;
  6369.  
  6370.  
  6371. // console.log(5381, index1 ,d1, index2 , d2);
  6372.  
  6373. if (d1 >= 0 && ((d2 < 0) || (d1 <= d2))) {
  6374. wobj.chosenT0 = t0mu + d1; // groupMids[index1];
  6375. } else if (d2 >= 0 && ((d1 < 0) || (d2 <= d1))) {
  6376. wobj.chosenT0 = t0mu - d2; // groupMids[index2];
  6377. } else {
  6378. console.warn('logic error');
  6379. return null;
  6380. }
  6381.  
  6382. const adjusted = wobj.timestampUsecOriginal - wobj.chosenT0;
  6383.  
  6384. wobj.timestampUsecAdjusted = adjusted + 1110553200000000;
  6385.  
  6386. // console.log('adjusted', `${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  6387.  
  6388. // adjustmentMap.set(`${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  6389.  
  6390. return adjusted;
  6391.  
  6392.  
  6393.  
  6394. };
  6395.  
  6396.  
  6397. // console.log(5592,2)
  6398. // console.log(1237008);
  6399. // if (FIX_TIMESTAMP_FOR_REPLAY) {
  6400.  
  6401.  
  6402. // try{
  6403.  
  6404. // // console.log('groupmid',groupMids, groups);
  6405.  
  6406. // for(let j = 0; j< arr.length;j++){
  6407. // if(groupMids.length<1) break;
  6408.  
  6409. // const aItem = arr[j];
  6410. // const obj = toLAObj(aItem);
  6411. // if (obj === false) continue;
  6412.  
  6413. // const wobj = additionalInfo.get(obj);
  6414. // if(!wobj) continue;
  6415.  
  6416. // // wobj.timestampUsecOriginal = q2;
  6417. // // wobj.timestampUsecAdjusted = q2;
  6418. // // wobj.t0au = t0au;
  6419. // // wobj.t0bu = t0bu;
  6420. // // wobj.t0mu = t0mu;
  6421.  
  6422. // const {t0au, t0bu, t0mu} = wobj;
  6423.  
  6424. // let upper = -1;
  6425.  
  6426. // for(let i = 0; i <groupMids.length;i++){
  6427. // const groupMid = groupMids[i];
  6428. // if(groupMid>= t0mu){
  6429. // upper = i;
  6430. // break;
  6431. // }
  6432. // }
  6433. // let index1, index2;
  6434. // if(upper>-1){
  6435. // index1 = upper-1;
  6436. // index2 = upper;
  6437. // }else{
  6438. // index1 = groups.length-1;
  6439. // index2 = -1;
  6440. // }
  6441. // let d1 = null;
  6442. // if(index1 >=0){
  6443. // d1 = Math.abs(groupMids[index1] - t0mu);
  6444. // }
  6445.  
  6446. // let d2 = null;
  6447. // if(index2 >=0){
  6448. // d2 = Math.abs(groupMids[index2] - t0mu);
  6449. // }
  6450. // // console.log(5381, index1 ,d1, index2 , d2);
  6451. // if(d1 >= 0 && ((d1 <= d2) || (d2 === null)) ){
  6452.  
  6453. // wobj.chosenT0 = groupMids[index1];
  6454. // } else if(d2 >= 0 && ((d2 <= d1) || (d1 === null))){
  6455. // wobj.chosenT0 = groupMids[index2];
  6456. // } else {
  6457. // console.warn('logic error');
  6458. // continue;
  6459. // }
  6460.  
  6461. // wobj.timestampUsecAdjusted = wobj.timestampUsecOriginal - wobj.chosenT0 + 1110553200000000;
  6462.  
  6463. // console.log('adjusted', `${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  6464.  
  6465. // adjustmentMap.set(`${obj.id}.${obj.timestampUsec}`, wobj.timestampUsecOriginal - wobj.chosenT0);
  6466. // // conversionMap.set(obj, arrHash[j].adjustedTime);
  6467.  
  6468. // // console.log(5382, index, id, t0mu, arrHash[j].adjustedT0, arrHash[j].timestampUsec, arrHash[j].adjustedTime);
  6469.  
  6470. // }
  6471.  
  6472.  
  6473. // }catch(e){
  6474. // console.warn(e);
  6475. // }
  6476.  
  6477.  
  6478.  
  6479.  
  6480.  
  6481. // // if(stack.length > 1){
  6482. // // stack.sort((a,b)=>{
  6483. // // return a.t0mu - b.t0mu
  6484. // // });
  6485. // // // small to large
  6486. // // // console.log(34588, stack.map(e=>e.t0as))
  6487. // // }
  6488.  
  6489. // // grouping
  6490.  
  6491.  
  6492.  
  6493.  
  6494. // // if (stack.length > 0) {
  6495.  
  6496. // // try {
  6497.  
  6498. // // for (let j = 0, l = stack.length; j < l; j++) {
  6499. // // pushToGroup(stack[j].t0mu);
  6500.  
  6501. // // }
  6502.  
  6503. // // }catch(e){
  6504.  
  6505. // // console.warn(e)
  6506. // // }
  6507.  
  6508. // // // console.log(4882, groups.map(e=>e.slice()), stack.slice())
  6509.  
  6510. // // }
  6511.  
  6512.  
  6513.  
  6514.  
  6515. // // console.log(376, 'group', groups);
  6516.  
  6517.  
  6518. // // consolidated group
  6519. // // const consolidatedGroups = doConsolidation(groups);
  6520.  
  6521.  
  6522.  
  6523.  
  6524.  
  6525.  
  6526. // // if(stack.length > 1){
  6527.  
  6528.  
  6529. // // // // console.log(341, 'consolidatedGroups', consolidatedGroups ,groups.map(e=>{
  6530. // // // // return e.map(noTransform);
  6531. // // // // // return e.map(prettyNum);
  6532. // // // // }))
  6533.  
  6534.  
  6535. // // // console.log(344, 'groups', groups.map(e=>{
  6536. // // // return e.map(noTransform);
  6537. // // // // return e.map(prettyNum);
  6538. // // // }))
  6539.  
  6540. // // // // for(const s of stack){
  6541. // // // // for(const g of consolidatedGroups){
  6542. // // // // if(s.t0as<=g.cen && s.t0bs >=g.cen ){
  6543. // // // // s.cen = g.cen;
  6544. // // // // break;
  6545. // // // // }
  6546. // // // // }
  6547.  
  6548. // // // // }
  6549.  
  6550. // // // console.log(377, stack) // Ms
  6551.  
  6552. // // }
  6553.  
  6554.  
  6555. // // console.timeEnd('FIX_TIMESTAMP_FOR_REPLAY')
  6556.  
  6557. // }
  6558.  
  6559.  
  6560.  
  6561.  
  6562.  
  6563.  
  6564.  
  6565.  
  6566.  
  6567. // console.log(5592,5)
  6568.  
  6569.  
  6570. // console.log('preprocessChatLiveActions', arr)
  6571.  
  6572.  
  6573. const mapper = new Map();
  6574. mapper.set = mapper.setOriginal || mapper.set;
  6575.  
  6576. // without delaying. get the time of request
  6577. // (both streaming and replay, but replay relys on progress update so background operation is suppressed)
  6578.  
  6579. for (let j = 0, l = arr.length; j < l; j++) {
  6580. const aItem = arr[j];
  6581.  
  6582. const obj = toLAObj(aItem);
  6583. if(obj === false) continue;
  6584.  
  6585. if (obj.id && !obj.__timestampActionRequest__) {
  6586. // for all item entries
  6587. obj.__timestampActionRequest__ = ct;
  6588. }
  6589.  
  6590. if (obj.id && obj.__timestampActionRequest__ > 0 && obj.durationSec > 0 && obj.fullDurationSec) {
  6591.  
  6592. // console.log(948700, obj , obj.id, (obj.fullDurationSec - obj.durationSec) * 1000)
  6593. const m = obj.__timestampActionRequest__ - (obj.fullDurationSec - obj.durationSec) * 1000;
  6594.  
  6595. // obj.__t374__ = (obj.fullDurationSec - obj.durationSec) * 1000;
  6596. // obj.__t375__ = obj.__timestampActionRequest__ - (obj.fullDurationSec - obj.durationSec) * 1000;
  6597. // console.log(5993, obj)
  6598. // obj.__orderTime__ = m;
  6599. mapper.set(aItem, m);
  6600.  
  6601.  
  6602. }
  6603.  
  6604. }
  6605.  
  6606. if (mapper.size > 1) {
  6607.  
  6608. const idxices = [];
  6609.  
  6610. // sort ticker
  6611. let mArr1 = arr.filter((aItem,idx) => {
  6612.  
  6613. if (mapper.has(aItem)) {
  6614. idxices.push(idx);
  6615. return true;
  6616. }
  6617. return false;
  6618.  
  6619. });
  6620.  
  6621.  
  6622. let mArr2 = mArr1/*.slice(0)*/.sort((a, b) => {
  6623. return mapper.get(a) - mapper.get(b);
  6624. // low index = oldest = smallest timestamp
  6625. });
  6626.  
  6627.  
  6628.  
  6629. // console.log(948701, arr.slice(0));
  6630. for(let j = 0, l=mArr1.length;j <l;j++){
  6631.  
  6632. const idx = idxices[j];
  6633. // arr[idx] = mArr1[j]
  6634. arr[idx] = mArr2[j];
  6635.  
  6636. // const obj1 = toObj(mArr1[j]);
  6637. // const obj2 = toObj(mArr2[j]);
  6638.  
  6639. // console.log(948705, idx, obj1 , obj1.id, (obj1.fullDurationSec - obj1.durationSec) * 1000, obj1.__orderTime__)
  6640.  
  6641. // console.log(948706, idx, obj2 , obj2.id, (obj2.fullDurationSec - obj2.durationSec) * 1000, obj2.__orderTime__)
  6642.  
  6643. }
  6644.  
  6645. // console.log(5994,arr)
  6646.  
  6647. // console.log(948702, arr.slice(0));
  6648. // console.log(948701, arr);
  6649. // arr = arr.map(aItem => {
  6650. // const idx = mArr1.indexOf(aItem);
  6651. // if (idx < 0) return aItem;
  6652. // return mArr2[idx];
  6653. // });
  6654. // console.log(948702, arr);
  6655.  
  6656. // mostly in order, but some not in order
  6657.  
  6658.  
  6659. // eg
  6660.  
  6661. /*
  6662.  
  6663.  
  6664. 948711 68 '1734488590715474'
  6665. 948711 69 '1734488590909853'
  6666. 948711 70 '1734488594763719'
  6667. 948711 71 '1734488602334615' <
  6668. 948711 72 '1734488602267214' <
  6669. 948711 73 '1734488602751771'
  6670. */
  6671.  
  6672. // arr.filter(aItem=>{
  6673.  
  6674. // const p = toObj(aItem);
  6675. // if(p.timestampUsec) return true;
  6676.  
  6677. // }).forEach((aItem,idx)=>{
  6678.  
  6679. // const p = toObj(aItem);
  6680. // console.log(948711, idx, p.timestampUsec);
  6681. // })
  6682.  
  6683. // return arr;
  6684.  
  6685. }
  6686.  
  6687. // console.log(1237001);
  6688.  
  6689. {
  6690.  
  6691. const mapper = new Map();
  6692. mapper.set = mapper.setOriginal || mapper.set;
  6693.  
  6694. const idxices = [];
  6695.  
  6696. let mArr1 = arr.filter((aItem,idx) => {
  6697.  
  6698. const obj = toLAObj(aItem);
  6699. if (!obj) return false;
  6700.  
  6701. const baseText = obj.timestampText;
  6702. const baseTime = +obj.timestampUsec;
  6703. if (!baseTime || !baseText) return false;
  6704. // const timestampUsec = +toLAObj(aItem).timestampUsec; // +false.x = NaN
  6705. // const timestampUsec = +toLAObj(aItem).adjustedTime;
  6706.  
  6707. let timestampUsec;
  6708.  
  6709. // console.log(1237002)
  6710. if (FIX_TIMESTAMP_FOR_REPLAY) {
  6711.  
  6712. // const adjustmentTime = adjustmentMap.get(`${obj.id}.${obj.timestampUsec}`);
  6713.  
  6714. // // const wobj = additionalInfo.get(obj);
  6715.  
  6716. // // if(!wobj){
  6717. // // console.warn('FIX_TIMESTAMP_FOR_REPLAY - no wobj', obj)
  6718. // // return false;
  6719. // // }
  6720.  
  6721. // // timestampUsec = +wobj.timestampUsecAdjusted;
  6722. // if (!Number.isFinite(adjustmentTime)) {
  6723. // console.warn(`FIX_TIMESTAMP_FOR_REPLAY - no adjustmentTime for ${obj.id}.${obj.timestampUsec}`, obj, [...adjustmentMap])
  6724. // return false;
  6725. // }
  6726. // timestampUsec = adjustmentTime;
  6727.  
  6728.  
  6729. const adjustmentTime = adjustTimestampFn(obj);
  6730.  
  6731. if (!Number.isFinite(adjustmentTime)) {
  6732.  
  6733. console.warn(`FIX_TIMESTAMP_FOR_REPLAY - no adjustmentTime for ${obj.id}.${obj.timestampUsec}`, obj);
  6734. return false;
  6735. }
  6736. timestampUsec = adjustmentTime;
  6737.  
  6738.  
  6739. } else {
  6740.  
  6741. if (!Number.isFinite(baseTime)) {
  6742. console.warn(`no baseTime for ${obj.id}.${obj.timestampUsec}`, obj);
  6743.  
  6744. return false;
  6745. }
  6746. timestampUsec = baseTime;
  6747.  
  6748. }
  6749.  
  6750. // if(timestampUsec > 0){
  6751. idxices.push(idx);
  6752. mapper.set(aItem, timestampUsec)
  6753. return true;
  6754. // }
  6755. // return false;
  6756.  
  6757. });
  6758.  
  6759. if(mapper.size > 1){
  6760.  
  6761.  
  6762. // console.log(1237004)
  6763. let mArr2 = mArr1/*.slice(0)*/.sort((a, b) => {
  6764. return mapper.get(a) - mapper.get(b);
  6765. // low index = oldest = smallest timestamp
  6766. });
  6767.  
  6768.  
  6769.  
  6770. // console.log(948701, arr.slice(0));
  6771. for(let j = 0, l=mArr1.length;j <l;j++){
  6772.  
  6773. const idx = idxices[j];
  6774. arr[idx] = mArr2[j];
  6775.  
  6776. // const obj1 = toObj(mArr1[j]);
  6777. // const obj2 = toObj(mArr2[j]);
  6778.  
  6779.  
  6780. // console.log(948711, idx, obj1 === obj2, obj1, obj1.timestampUsec);
  6781. // console.log(948712, idx, obj1 === obj2, obj2, obj2.timestampUsec);
  6782. }
  6783.  
  6784. }
  6785.  
  6786.  
  6787. }
  6788.  
  6789. // console.log(1237005)
  6790.  
  6791. // console.log(378, arr);
  6792.  
  6793. return arr;
  6794.  
  6795.  
  6796. }
  6797.  
  6798. if (ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION) {
  6799.  
  6800. console.log('[yt-chat-control] ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION is used.')
  6801.  
  6802. // console.log('ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION 0001')
  6803.  
  6804. const pop078 = function () {
  6805. const r = this.pop78();
  6806.  
  6807. if (r && (r.actions || 0).length >= 1 && r.videoOffsetTimeMsec) {
  6808. for (const action of r.actions) {
  6809.  
  6810. const itemActionKey = !action ? null : 'addChatItemAction' in action ? 'addChatItemAction' : 'addLiveChatTickerItemAction' in action ? 'addLiveChatTickerItemAction' : null;
  6811. if (itemActionKey) {
  6812.  
  6813. const itemAction = action[itemActionKey];
  6814. const item = (itemAction || 0).item;
  6815. if (typeof item === 'object') {
  6816.  
  6817. const rendererKey = firstObjectKey(item);
  6818. if (rendererKey) {
  6819. const renderer = item[rendererKey];
  6820. if (renderer && typeof renderer === 'object') {
  6821. renderer.__videoOffsetTimeMsec__ = r.videoOffsetTimeMsec;
  6822. renderer.__progressAt__ = playerProgressChangedArg1;
  6823.  
  6824. // console.log(48117006)
  6825. }
  6826.  
  6827. }
  6828.  
  6829. }
  6830. }
  6831. }
  6832. }
  6833. return r;
  6834. }
  6835.  
  6836.  
  6837.  
  6838. const replayQueueProxyHandler = {
  6839. get(target, prop, receiver) {
  6840. if (prop === 'qe3') return 1;
  6841. const v = target[prop];
  6842. if (prop === 'front_') {
  6843. if (v && typeof v.length === 'number') {
  6844. if (!v.pop78) {
  6845. v.pop78 = v.pop;
  6846. v.pop = pop078;
  6847. }
  6848. }
  6849. }
  6850. return v;
  6851. }
  6852. };
  6853.  
  6854. // lcrFn2 will run twice to ensure the method is successfully injected.
  6855. const lcrFn2 = (lcrDummy)=>{
  6856. // make minimal function overhead by pre-defining all possible outside.
  6857.  
  6858. const tag = "yt-live-chat-renderer"
  6859. const dummy = lcrDummy;
  6860.  
  6861. const cProto = getProto(dummy);
  6862. if (!cProto || !cProto.attached) {
  6863. console.warn(`proto.attached for ${tag} is unavailable.`);
  6864. return;
  6865. }
  6866.  
  6867. // mightFirstCheckOnYtInit();
  6868. // groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-renderer hacks");
  6869. // console.log("[Begin]");
  6870.  
  6871.  
  6872. if (typeof cProto.playerProgressChanged_ === 'function' && !cProto.playerProgressChanged32_) {
  6873.  
  6874. cProto.playerProgressChanged32_ = cProto.playerProgressChanged_;
  6875.  
  6876.  
  6877. cProto.playerProgressChanged_ = function (a, b, c) {
  6878. // console.log(48117005)
  6879. if (a === 0) a = arguments[0] = Number.MIN_VALUE; // avoid issue dealing with zero value
  6880. playerProgressChangedArg1 = a;
  6881. playerProgressChangedArg2 = b;
  6882. playerProgressChangedArg3 = c;
  6883. const replayBuffer_ = this.replayBuffer_;
  6884. if (replayBuffer_) {
  6885. const replayQueue = replayBuffer_.replayQueue
  6886. if (replayQueue && typeof replayQueue === 'object' && !replayQueue.qe3) {
  6887. replayBuffer_.replayQueue = new Proxy(replayBuffer_.replayQueue, replayQueueProxyHandler);
  6888. }
  6889. }
  6890. Promise.resolve().then(updateTickerCurrentTime);
  6891. return this.playerProgressChanged32_.apply(this, arguments);
  6892. };
  6893.  
  6894. }
  6895.  
  6896. // console.log("[End]");
  6897. // groupEnd();
  6898.  
  6899.  
  6900. };
  6901. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  6902.  
  6903.  
  6904. // console.log('ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION 0002')
  6905.  
  6906. // getLCRDummy() must be called for injection
  6907. getLCRDummy().then(lcrFn2);
  6908.  
  6909. }
  6910.  
  6911. const stackDM = (()=>{
  6912.  
  6913. let cm, stack, mo;
  6914.  
  6915. let firstRun = ()=>{
  6916. cm = mockCommentElement(document.createComment('1'));
  6917. stack = new Set();
  6918. mo = new MutationObserver(()=>{
  6919. const stack_ = stack;
  6920. stack = new Set();
  6921. // for(const value of stack_){
  6922. // Promise.resolve(value).then(f=>f());
  6923. // }
  6924. for(const value of stack_){
  6925. value();
  6926. }
  6927. stack_.clear();
  6928. });
  6929. mo.observe(cm, {characterData: true});
  6930.  
  6931. }
  6932.  
  6933.  
  6934. const stackDM = (f) => {
  6935.  
  6936. if (firstRun) firstRun = firstRun();
  6937. stack.add(f);
  6938. cm.data = `${(cm.data & 1) + 1}`;
  6939. }
  6940. return stackDM;
  6941. })();
  6942. window.stackDM = stackDM;
  6943.  
  6944.  
  6945. const widthReq = (()=>{
  6946.  
  6947. let widthIORes;
  6948. let widthIO;
  6949.  
  6950. let firstRun = () => {
  6951. widthIORes = new WeakMap();
  6952. widthIO = new IntersectionObserver((mutations) => {
  6953. const r = new Map();
  6954. for (const mutation of mutations) {
  6955. r.set(mutation.target, mutation.boundingClientRect);
  6956. }
  6957.  
  6958. for (const [elm, rect] of r) {
  6959. widthIO.unobserve(elm);
  6960. const o = widthIORes.get(elm);
  6961. o && widthIORes.delete(elm);
  6962. const { promise, values } = o || {};
  6963. if (promise && values) {
  6964. values.width = rect.width;
  6965. promise.resolve(values);
  6966. }
  6967. }
  6968. });
  6969. };
  6970.  
  6971. const widthReq = (elm) => {
  6972.  
  6973. if (firstRun) firstRun = firstRun();
  6974.  
  6975. {
  6976. const { promise, values } = widthIORes.get(elm) || {};
  6977. if (promise) return promise;
  6978. }
  6979.  
  6980. const promise = new PromiseExternal();
  6981. widthIORes.set(elm, { promise, values: {} });
  6982. widthIO.unobserve(elm);
  6983. widthIO.observe(elm);
  6984.  
  6985. return promise;
  6986.  
  6987. }
  6988. return widthReq;
  6989. })();
  6990.  
  6991.  
  6992.  
  6993.  
  6994. customElements.whenDefined('yt-live-chat-item-list-renderer').then(() => {
  6995.  
  6996.  
  6997. const tag = "yt-live-chat-item-list-renderer"
  6998. const dummy = document.createElement(tag);
  6999.  
  7000. const cProto = getProto(dummy);
  7001. if (!cProto || !cProto.attached) {
  7002. console.warn(`proto.attached for ${tag} is unavailable.`);
  7003. return;
  7004. }
  7005.  
  7006. mightFirstCheckOnYtInit();
  7007. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-item-list-renderer hacks");
  7008. console1.log("[Begin]");
  7009.  
  7010. const mclp = cProto;
  7011. const _flag0281_ = window._flag0281_;
  7012.  
  7013. try {
  7014. assertor(() => typeof mclp.scrollToBottom_ === 'function');
  7015. assertor(() => typeof mclp.flushActiveItems_ === 'function');
  7016. assertor(() => typeof mclp.canScrollToBottom_ === 'function');
  7017. assertor(() => typeof mclp.setAtBottom === 'function');
  7018. assertor(() => typeof mclp.scrollToBottom66_ === 'undefined');
  7019. assertor(() => typeof mclp.flushActiveItems66_ === 'undefined');
  7020. } catch (e) { }
  7021.  
  7022.  
  7023. try {
  7024. assertor(() => typeof mclp.attached === 'function');
  7025. assertor(() => typeof mclp.detached === 'function');
  7026. assertor(() => typeof mclp.canScrollToBottom_ === 'function');
  7027. assertor(() => typeof mclp.isSmoothScrollEnabled_ === 'function');
  7028. assertor(() => typeof mclp.maybeResizeScrollContainer_ === 'function');
  7029. assertor(() => typeof mclp.refreshOffsetContainerHeight_ === 'function');
  7030. assertor(() => typeof mclp.smoothScroll_ === 'function');
  7031. assertor(() => typeof mclp.resetSmoothScroll_ === 'function');
  7032. } catch (e) { }
  7033.  
  7034. mclp.prDelay171 = null;
  7035.  
  7036. let myk = 0; // showNewItems77_
  7037. let mlf = 0; // flushActiveItems77_
  7038. let myw = 0; // onScrollItems77_
  7039. let mzt = 0; // handleLiveChatActions77_
  7040. let mlg = 0; // delayFlushActiveItemsAfterUserAction11_
  7041. let zarr = null;
  7042.  
  7043. if ((_flag0281_ & 0x2000) == 0) {
  7044.  
  7045. if ((mclp.clearList || 0).length === 0) {
  7046. (_flag0281_ & 0x2) == 0 && assertor(() => fnIntegrity(mclp.clearList, '0.106.50'));
  7047. mclp.clearList66 = mclp.clearList;
  7048. mclp.clearList = function () {
  7049. myk = (myk & 1073741823) + 1;
  7050. mlf = (mlf & 1073741823) + 1;
  7051. myw = (myw & 1073741823) + 1;
  7052. mzt = (mzt & 1073741823) + 1;
  7053. mlg = (mlg & 1073741823) + 1;
  7054. zarr = null;
  7055. this.prDelay171 = null;
  7056. this.clearList66();
  7057. };
  7058. console1.log("clearList", "OK");
  7059. } else {
  7060. console1.log("clearList", "NG");
  7061. }
  7062.  
  7063. }
  7064.  
  7065.  
  7066.  
  7067. let onListRendererAttachedDone = false;
  7068.  
  7069. function setList(itemOffset, items) {
  7070.  
  7071. const isFirstTime = onListRendererAttachedDone === false;
  7072.  
  7073. if (isFirstTime) {
  7074. onListRendererAttachedDone = true;
  7075. Promise.resolve().then(watchUserCSS);
  7076. addCssManaged();
  7077.  
  7078. const isBoostChatEnabled = (window._flag0281_ & 0x40000) === 0x40000;
  7079. if (!isBoostChatEnabled) setupEvents();
  7080. }
  7081.  
  7082. setupStyle(itemOffset, items);
  7083.  
  7084. setupMutObserver(items);
  7085.  
  7086. console.log('[yt-chat] setupMutObserver DONE')
  7087. }
  7088.  
  7089.  
  7090. const deferSeqFns = []; // ensure correct sequence
  7091. let deferSeqFnI = 0;
  7092. const deferCallbackLooper = entry => {
  7093. nextBrowserTick_(() => {
  7094. const { a, b } = entry;
  7095. const cnt = kRef(a);
  7096. if (cnt && b) b.call(cnt);
  7097. entry.a = entry.b = null;
  7098. });
  7099. }
  7100. const deferCallback = async (cnt, callback) => {
  7101. const a = cnt.__weakRef9441__ || (cnt.__weakRef9441__ = mWeakRef(cnt));
  7102. deferSeqFns[deferSeqFnI++] = { a, b: callback };
  7103. if (deferSeqFnI > 1) return;
  7104. const pr288 = cnt.prDelay288;
  7105. await pr288;
  7106. wme.data = `${(wme.data & 7) + 1}`;
  7107. await wmp;
  7108. const l = deferSeqFnI;
  7109. deferSeqFnI = 0;
  7110. for (let i = 0; i < l; i++) {
  7111. const o = deferSeqFns[i];
  7112. deferSeqFns[i] = null;
  7113. Promise.resolve(o).then(deferCallbackLooper);
  7114. }
  7115. };
  7116.  
  7117. let showMoreBtnTransitionTrigg = null;
  7118.  
  7119. mclp.__showMoreBtn_transitionstart011__ = function (evt) {
  7120. showMoreBtnTransitionTrigg = true;
  7121. const newVisibility = (this.atBottom === true) ? "hidden" : "visible";
  7122. if (newVisibility === "visible") {
  7123. const btn = evt.target;
  7124. if (btn.style.visibility !== newVisibility) btn.style.visibility = newVisibility;
  7125. }
  7126. };
  7127.  
  7128.  
  7129. mclp.__showMoreBtn_transitionend011__ = function (evt) {
  7130. showMoreBtnTransitionTrigg = true;
  7131. const newVisibility = (this.atBottom === true) ? "hidden" : "visible";
  7132. if (newVisibility === "hidden") {
  7133. const btn = evt.target;
  7134. if (btn.style.visibility !== newVisibility) btn.style.visibility = newVisibility;
  7135. }
  7136. };
  7137. mclp.attached419 = async function () {
  7138.  
  7139. if (!this.isAttached) return;
  7140.  
  7141. let maxTrial = 16;
  7142. while (!this.$ || !this.$['item-scroller'] || !this.$['item-offset'] || !this.$['items']) {
  7143. if (--maxTrial < 0 || !this.isAttached) return;
  7144. await nextBrowserTick_();
  7145. // await new Promise(requestAnimationFrame);
  7146. }
  7147.  
  7148. if (this.isAttached !== true) return;
  7149.  
  7150. if (!this.$) {
  7151. console.warn("!this.$");
  7152. return;
  7153. }
  7154. if (!this.$) return;
  7155. /** @type {HTMLElement | null} */
  7156. const itemScroller = this.$['item-scroller'];
  7157. /** @type {HTMLElement | null} */
  7158. const itemOffset = this.$['item-offset'];
  7159. /** @type {HTMLElement | null} */
  7160. const items = this.$['items'];
  7161.  
  7162. if (!itemScroller || !itemOffset || !items) {
  7163. console.warn("items.parentNode !== itemOffset");
  7164. return;
  7165. }
  7166.  
  7167. if (nodeParent(items) !== itemOffset) {
  7168.  
  7169. console.warn("items.parentNode !== itemOffset");
  7170. return;
  7171. }
  7172.  
  7173.  
  7174. if (items.id !== 'items' || itemOffset.id !== "item-offset") {
  7175.  
  7176. console.warn("id incorrect");
  7177. return;
  7178. }
  7179.  
  7180. 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')
  7181.  
  7182. if (!isTargetItems) {
  7183. console.warn("!isTargetItems");
  7184. return;
  7185. }
  7186.  
  7187. setList(itemOffset, items);
  7188.  
  7189. if (WITH_SCROLL_ANCHOR) this.__itemAnchorColl011__ = itemOffset.getElementsByTagName('item-anchor');
  7190. else this.__itemAnchorColl011__ = null;
  7191.  
  7192.  
  7193.  
  7194. // btn-show-more-transition
  7195. const btn = this.$['show-more'];
  7196. if (btn) {
  7197. if (!this.__showMoreBtn_transitionstart012__) this.__showMoreBtn_transitionstart012__ = this.__showMoreBtn_transitionstart011__.bind(this);
  7198. if (!this.__showMoreBtn_transitionend012__) this.__showMoreBtn_transitionend012__ = this.__showMoreBtn_transitionend011__.bind(this);
  7199. btn.addEventListener('transitionrun', this.__showMoreBtn_transitionstart012__, false);
  7200. btn.addEventListener('transitionstart', this.__showMoreBtn_transitionstart012__, false);
  7201. btn.addEventListener('transitionend', this.__showMoreBtn_transitionend012__, false);
  7202. btn.addEventListener('transitioncancel', this.__showMoreBtn_transitionend012__, false);
  7203. }
  7204.  
  7205. // fix panel height changing issue (ENABLE_OVERFLOW_ANCHOR only)
  7206. if (itemScrollerResizeObserver) itemScrollerResizeObserver.observe(this.itemScroller || this.$['item-scroller']);
  7207.  
  7208. }
  7209.  
  7210. mclp.attached331 = mclp.attached;
  7211. mclp.attached = function () {
  7212. this.attached419 && this.attached419();
  7213. return this.attached331();
  7214. }
  7215.  
  7216. mclp.detached331 = mclp.detached;
  7217.  
  7218. mclp.detached = function () {
  7219. setupMutObserver();
  7220. return this.detached331();
  7221. }
  7222.  
  7223. const t29s = document.querySelectorAll("yt-live-chat-item-list-renderer");
  7224. for (const t29 of t29s) {
  7225. const cnt = insp(t29);
  7226. if (cnt.isAttached === true) {
  7227. cnt.attached419();
  7228. }
  7229. }
  7230.  
  7231. if ((mclp.async || 0).length === 2 && (mclp.cancelAsync || 0).length === 1) {
  7232.  
  7233. assertor(() => fnIntegrity(mclp.async, '2.24.15'));
  7234. assertor(() => fnIntegrity(mclp.cancelAsync, '1.15.8'));
  7235.  
  7236. /** @type {Map<number, any>} */
  7237. const aMap = new Map();
  7238. const mcid = setTimeout(() => 0, 0.625);
  7239. const maid = requestAnimationFrame(() => 0);
  7240. clearTimeout(mcid);
  7241. cancelAnimationFrame(maid);
  7242. const count0 = mcid + maid + 1740;
  7243. let count = count0;
  7244. mclp.async66 = mclp.async;
  7245. mclp.async = function (e, f) {
  7246. // ensure the previous operation is done
  7247. // .async is usually after the time consuming functions like flushActiveItems_ and scrollToBottom_
  7248. const hasF = arguments.length === 2;
  7249. if (count > 1e9) count = count0 + 9;
  7250. const resId = ++count;
  7251. aMap.set(resId, e);
  7252. const pr1 = Promise.all([this.prDelay288, wmp, this.prDelay171, Promise.resolve()]);
  7253. const pr2 = autoTimerFn();
  7254. Promise.race([pr1, pr2]).then(() => {
  7255. const rp = aMap.get(resId);
  7256. if (typeof rp !== 'function') {
  7257. return;
  7258. }
  7259. const asyncEn = function () {
  7260. return aMap.delete(resId) && rp.apply(this, arguments);
  7261. };
  7262. aMap.set(resId, hasF ? this.async66(asyncEn, f) : this.async66(asyncEn));
  7263. });
  7264.  
  7265. return resId;
  7266. }
  7267.  
  7268. mclp.cancelAsync66 = mclp.cancelAsync;
  7269. mclp.cancelAsync = function (resId) {
  7270. if (resId <= count0) {
  7271. this.cancelAsync66(resId);
  7272. } else if (aMap.has(resId)) {
  7273. const rp = aMap.get(resId);
  7274. aMap.delete(resId);
  7275. if (typeof rp !== 'function') {
  7276. this.cancelAsync66(rp);
  7277. }
  7278. }
  7279. }
  7280.  
  7281. console1.log("async", "OK");
  7282. } else {
  7283. console1.log("async", "NG");
  7284. }
  7285.  
  7286.  
  7287. if ((_flag0281_ & 0x2) == 0) {
  7288. if ((mclp.showNewItems_ || 0).length === 0 && ENABLE_NO_SMOOTH_TRANSFORM) {
  7289.  
  7290. assertor(() => fnIntegrity(mclp.showNewItems_, '0.170.79'));
  7291. mclp.showNewItems66_ = mclp.showNewItems_;
  7292. mclp.showNewItems_ = function () {
  7293. //
  7294. }
  7295.  
  7296. console1.log("showNewItems_", "OK");
  7297. } else {
  7298. console1.log("showNewItems_", "NG");
  7299. }
  7300.  
  7301. }
  7302.  
  7303.  
  7304.  
  7305. if ((_flag0281_ & 0x2) == 0) {
  7306. if ((mclp.onScrollItems_ || 0).length === 1) {
  7307.  
  7308. if (mclp.onScrollItems3641_) {
  7309.  
  7310. } else {
  7311. assertor(() => fnIntegrity(mclp.onScrollItems_, '1.17.9'));
  7312.  
  7313. }
  7314.  
  7315. if (typeof mclp.setAtBottom === 'function' && mclp.setAtBottom.length === 0) {
  7316.  
  7317. mclp.setAtBottom217 = mclp.setAtBottom;
  7318. mclp.setAtBottom = function () {
  7319. const v = this.ec217;
  7320. if (typeof v !== 'boolean') return this.setAtBottom217();
  7321. const u = this.atBottom;
  7322. if (u !== v && typeof u === 'boolean') this.atBottom = v;
  7323. // this.atBottom = a.scrollTop >= a.scrollHeight - a.clientHeight - 15
  7324. }
  7325.  
  7326. let lastScrollTarget = null;
  7327. mclp.onScrollItems66_ = mclp.onScrollItems_;
  7328. let callback = () => { };
  7329.  
  7330. // let itemScrollerWR = null;
  7331. let lastEvent = null;
  7332.  
  7333. let io2 = null, io1 = null;
  7334. const io2f = (entries, observer) => {
  7335. const entry = entries[entries.length - 1];
  7336. if (entry.target !== lastScrollTarget) return;
  7337. callback(entry);
  7338. };
  7339. const io1f = (entries, observer) => {
  7340. const entry = entries[entries.length - 1];
  7341. observer.unobserve(entry.target);
  7342. if (entry.target !== lastScrollTarget) return;
  7343. lastScrollTarget = null;
  7344. callback(entry);
  7345. };
  7346. mclp.onScrollItems3885cb2_ = function (entry) {
  7347. const v = (entry.isIntersecting === true);
  7348. this.ec217 = v;
  7349. this.onScrollItems66_(lastEvent);
  7350. this.ec217 = null;
  7351. }
  7352. mclp.onScrollItems3885cb1_ = function (entry) {
  7353. const v = (entry.intersectionRatio > 0.98);
  7354. this.ec217 = v;
  7355. this.onScrollItems66_(lastEvent);
  7356. this.ec217 = null;
  7357. };
  7358.  
  7359. mclp.onScrollItems_ = function (evt) {
  7360.  
  7361. if (evt === lastEvent) return;
  7362. if (evt && lastEvent && evt.timeStamp === lastEvent.timeStamp) return;
  7363. lastEvent = evt;
  7364. const ytRendererBehavior = this.ytRendererBehavior || 0;
  7365. if (typeof ytRendererBehavior.onScroll === 'function') ytRendererBehavior.onScroll(evt);
  7366. const coll = this.__itemAnchorColl011__;
  7367. if (coll) {
  7368. const anchorElement = coll.length === 1 ? coll[0] : null;
  7369. if (lastScrollTarget !== anchorElement) {
  7370. if (io2) io2.disconnect();
  7371. lastScrollTarget = anchorElement;
  7372. if (anchorElement) {
  7373. if (!this.onScrollItems3886cb2_) this.onScrollItems3886cb2_ = this.onScrollItems3885cb2_.bind(this);
  7374. callback = this.onScrollItems3886cb2_;
  7375. if (!io2) io2 = new IntersectionObserver(io2f);
  7376. io2.observe(anchorElement);
  7377. }
  7378. }
  7379. } else {
  7380. const items = this.$.items;
  7381. if (!items) return this.onScrollItems66_();
  7382. const lastComponent = lastComponentChildFn(items);
  7383. if (!lastComponent) return this.onScrollItems66_();
  7384. if (lastScrollTarget === lastComponent) return;
  7385. lastScrollTarget = lastComponent;
  7386.  
  7387. if (io1) io1.disconnect();
  7388. if (!this.onScrollItems3886cb1_) this.onScrollItems3886cb1_ = this.onScrollItems3885cb1_.bind(this);
  7389. callback = this.onScrollItems3886cb1_;
  7390. if (!io1) io1 = new IntersectionObserver(io1f);
  7391. io1.observe(lastComponent);
  7392. }
  7393. };
  7394.  
  7395. }
  7396.  
  7397. console1.log("onScrollItems_", "OK");
  7398. } else {
  7399. console1.log("onScrollItems_", "NG");
  7400. }
  7401. }
  7402.  
  7403.  
  7404. if ((_flag0281_ & 0x40) == 0) {
  7405.  
  7406. if (ENABLE_NO_SMOOTH_TRANSFORM && SUPPRESS_refreshOffsetContainerHeight_ && typeof mclp.refreshOffsetContainerHeight_ === 'function' && !mclp.refreshOffsetContainerHeight26_ && mclp.refreshOffsetContainerHeight_.length === 0) {
  7407. assertor(() => fnIntegrity(mclp.refreshOffsetContainerHeight_, '0.31.21'));
  7408. mclp.refreshOffsetContainerHeight26_ = mclp.refreshOffsetContainerHeight_;
  7409. mclp.refreshOffsetContainerHeight_ = function () {
  7410. // var a = this.itemScroller.clientHeight;
  7411. // this.itemOffset.style.height = this.items.clientHeight + "px";
  7412. // this.bottomAlignMessages && (this.itemOffset.style.minHeight = a + "px")
  7413. }
  7414. console1.log("refreshOffsetContainerHeight_", "OK");
  7415. } else {
  7416. console1.log("refreshOffsetContainerHeight_", "NG");
  7417. }
  7418.  
  7419. }
  7420.  
  7421. if ((_flag0281_ & 0x2000) == 0) {
  7422. if ((mclp.flushActiveItems_ || 0).length === 0) {
  7423.  
  7424. if ((_flag0281_ & 0x2) == 0) {
  7425.  
  7426. const sfi = fnIntegrity(mclp.flushActiveItems_);
  7427. if(sfi === '0.158.86'){
  7428.  
  7429. // https://www.youtube.com/s/desktop/c01ea7e3/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  7430.  
  7431.  
  7432. // f.flushActiveItems_ = function() {
  7433. // var a = this;
  7434. // if (this.activeItems_.length > 0)
  7435. // if (this.canScrollToBottom_()) {
  7436. // var b = Math.max(this.visibleItems.length + this.activeItems_.length - this.data.maxItemsToDisplay, 0);
  7437. // b && this.splice("visibleItems", 0, b);
  7438. // if (this.isSmoothScrollEnabled_() || this.dockableMessages.length)
  7439. // this.preinsertHeight_ = this.items.clientHeight;
  7440. // this.activeItems_.unshift("visibleItems");
  7441. // try {
  7442. // this.push.apply(this, this.activeItems_)
  7443. // } catch (c) {
  7444. // Tm(c)
  7445. // }
  7446. // this.activeItems_ = [];
  7447. // this.isSmoothScrollEnabled_() ? this.canScrollToBottom_() && $u(function() {
  7448. // a.showNewItems_()
  7449. // }) : $u(function() {
  7450. // a.refreshOffsetContainerHeight_();
  7451. // a.maybeScrollToBottom_()
  7452. // })
  7453. // } else
  7454. // this.activeItems_.length > this.data.maxItemsToDisplay && this.activeItems_.splice(0, this.activeItems_.length - this.data.maxItemsToDisplay)
  7455. // }
  7456.  
  7457. } else if (sfi === '0.156.86') {
  7458. // https://www.youtube.com/s/desktop/f61c8d85/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  7459.  
  7460. // added "refreshOffsetContainerHeight_"
  7461.  
  7462. // f.flushActiveItems_ = function() {
  7463. // var a = this;
  7464. // if (0 < this.activeItems_.length)
  7465. // if (this.canScrollToBottom_()) {
  7466. // var b = Math.max(this.visibleItems.length + this.activeItems_.length - this.data.maxItemsToDisplay, 0);
  7467. // b && this.splice("visibleItems", 0, b);
  7468. // if (this.isSmoothScrollEnabled_() || this.dockableMessages.length)
  7469. // this.preinsertHeight_ = this.items.clientHeight;
  7470. // this.activeItems_.unshift("visibleItems");
  7471. // try {
  7472. // this.push.apply(this, this.activeItems_)
  7473. // } catch (c) {
  7474. // fm(c)
  7475. // }
  7476. // this.activeItems_ = [];
  7477. // this.isSmoothScrollEnabled_() ? this.canScrollToBottom_() && Mw(function() {
  7478. // a.showNewItems_()
  7479. // }) : Mw(function() {
  7480. // a.refreshOffsetContainerHeight_();
  7481. // a.maybeScrollToBottom_()
  7482. // })
  7483. // } else
  7484. // this.activeItems_.length > this.data.maxItemsToDisplay && this.activeItems_.splice(0, this.activeItems_.length - this.data.maxItemsToDisplay)
  7485. // }
  7486. // ;
  7487.  
  7488. } else if (sfi === '0.150.84') {
  7489. // https://www.youtube.com/s/desktop/e4d15d2c/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  7490. // var b = Math.max(this.visibleItems.length + this.activeItems_.length - this.data.maxItemsToDisplay, 0);
  7491. // b && this.splice("visibleItems", 0, b);
  7492. // if (this.isSmoothScrollEnabled_() || this.dockableMessages.length)
  7493. // this.preinsertHeight_ = this.items.clientHeight;
  7494. // this.activeItems_.unshift("visibleItems");
  7495. // try {
  7496. // this.push.apply(this, this.activeItems_)
  7497. // } catch (c) {
  7498. // nm(c)
  7499. // }
  7500. // this.activeItems_ = [];
  7501. // this.isSmoothScrollEnabled_() ? this.canScrollToBottom_() && zQ(function() {
  7502. // a.showNewItems_()
  7503. // }) : zQ(function() {
  7504. // a.maybeScrollToBottom_()
  7505. // })
  7506. } else if (sfi === '0.137.81' || sfi === '0.138.81') {
  7507. // e.g. https://www.youtube.com/yts/jsbin/live_chat_polymer-vflCyWEBP/live_chat_polymer.js
  7508. } else {
  7509. assertor(() => fnIntegrity(mclp.flushActiveItems_, '0.158.86'))
  7510. || logFn('mclp.flushActiveItems_', mclp.flushActiveItems_)();
  7511. }
  7512. }
  7513.  
  7514. let hasMoreMessageState = !ENABLE_SHOW_MORE_BLINKER ? -1 : 0;
  7515.  
  7516. mclp.flushActiveItems66a_ = mclp.flushActiveItems_;
  7517. // let lastLastRow = null;
  7518.  
  7519.  
  7520. const preloadFn = (acItems) => {
  7521. let waitFor = [];
  7522. /** @type {Set<string>} */
  7523. const imageLinks = new Set();
  7524. imageLinks.add = imageLinks.addOriginal || imageLinks.add;
  7525.  
  7526. if (ENABLE_PRELOAD_THUMBNAIL || EMOJI_IMAGE_SINGLE_THUMBNAIL || AUTHOR_PHOTO_SINGLE_THUMBNAIL) {
  7527. for (const item of acItems) {
  7528. fixLiveChatItem(item, imageLinks);
  7529. }
  7530. }
  7531. if (ENABLE_PRELOAD_THUMBNAIL && kptPF !== null && (kptPF & (8 | 4)) && imageLinks.size > 0) {
  7532.  
  7533. // reference: https://github.com/Yuanfang-fe/Blog-X/issues/34
  7534. const rel = kptPF & 8 ? 'subresource' : kptPF & 16 ? 'preload' : kptPF & 4 ? 'prefetch' : '';
  7535. // preload performs the high priority fetching.
  7536. // prefetch delays the chat display if the video resoruce is demanding.
  7537.  
  7538. if (rel) {
  7539.  
  7540. imageLinks.forEach(imageLink => {
  7541. let d = false;
  7542. if (SKIP_PRELOAD_EMOJI && imageLink.includes('.ggpht.com/')) return;
  7543. const isEmoji = imageLink.includes('/emoji/');
  7544. const pretechedSet = isEmoji ? emojiPrefetched : authorPhotoPrefetched;
  7545. if (!pretechedSet.has(imageLink)) {
  7546. pretechedSet.add(imageLink);
  7547. d = true;
  7548. }
  7549. if (d) {
  7550. waitFor.push(linker(null, rel, imageLink, 'image'));
  7551.  
  7552. }
  7553. })
  7554.  
  7555. }
  7556.  
  7557. }
  7558. imageLinks.clear();
  7559.  
  7560. return async () => {
  7561. if (waitFor.length > 0) {
  7562. await Promise.race([new Promise(r => setTimeout(r, 250)), Promise.all(waitFor)]);
  7563. }
  7564. waitFor.length = 0;
  7565. waitFor = null;
  7566. };
  7567.  
  7568. };
  7569.  
  7570.  
  7571.  
  7572. if(ENABLE_CHAT_MESSAGES_BOOSTED_STAMPING && `${mclp.flushActiveItems_}`.includes("this.push.apply(this,this.activeItems_)") && `${mclp.flushActiveItems_}`.includes(`this.splice("visibleItems",0,`) && !cProto.notifyPath371){
  7573.  
  7574.  
  7575.  
  7576. {
  7577.  
  7578.  
  7579. rendererStamperFactory(cProto, {
  7580. key: 'proceedStampDomArraySplices381_',
  7581. stamperDomClass: 'style-scope yt-live-chat-item-list-renderer yt-live-chat-item-list-stampdom',
  7582. preloadFn
  7583. });
  7584. cProto.notifyPath371 = cProto.notifyPath;
  7585.  
  7586.  
  7587. cProto.stampDomArraySplices381_ = cProto.stampDomArraySplices_;
  7588.  
  7589. cProto.stampDomArraySplices_ = function (a, b, c) {
  7590. if (a === 'visibleItems' && b === 'items' && (c || 0).indexSplices) {
  7591. // if (this.ec388) {
  7592. const indexSplices = c.indexSplices;
  7593. if (indexSplices.length === 1 || typeof indexSplices.length === "undefined") {
  7594. const indexSplice = indexSplices[0] || indexSplices;
  7595. if (indexSplice.type === 'splice' && (indexSplice.addedCount >= 1 || (indexSplice.removed || []).length >= 1)) {
  7596. // console.log(1059, a, b, indexSplice);
  7597. if (this.proceedStampDomArraySplices381_(a, b, indexSplice)) return;
  7598. }
  7599. }
  7600. // } else {
  7601. // console.warn('stampDomArraySplices_ warning', ...arguments);
  7602. // }
  7603. }
  7604. return this.stampDomArraySplices381_(...arguments);
  7605. }
  7606.  
  7607. cProto.stampDomArray366_ = cProto.stampDomArray_;
  7608. cProto.stampDomArray_ = function (items, containerId, componentConfig, rxConfig, shouldCallback, isStableList) {
  7609. const isTickerRendering = items === this.tickerItems && containerId === 'ticker-items';
  7610. const isMessageListRendering = items === this.visibleItems && containerId === 'items';
  7611. if(!isTickerRendering && !isMessageListRendering){
  7612. console.log('stampDomArray_ warning 0xF501', ...arguments)
  7613. return this.stampDomArray366_(...arguments);
  7614. }
  7615.  
  7616. const container = (this.$ || 0)[containerId];
  7617. if (!container) {
  7618. console.log('stampDomArray_ warning 0xF502', ...arguments)
  7619. return this.stampDomArray366_(...arguments);
  7620. }
  7621.  
  7622. if (container[sFirstElementChild] === null && items.length === 0) {
  7623.  
  7624. } else {
  7625. const cTag = isTickerRendering ? 'tickerItems' : 'visibleItems';
  7626. this.proceedStampDomArraySplices381_(cTag, containerId, {
  7627. addedCount: items.length,
  7628. removedCount: container.childElementCount
  7629. });
  7630. }
  7631.  
  7632. const f = () => {
  7633. this.markDirty && this.markDirty();
  7634. const detail = {
  7635. container
  7636. };
  7637. shouldCallback && this.hostElement.dispatchEvent(new CustomEvent("yt-rendererstamper-finished", {
  7638. bubbles: !0,
  7639. cancelable: !1,
  7640. composed: !0,
  7641. detail
  7642. }));
  7643. detail.container = null;
  7644. };
  7645.  
  7646. if (this.ec389pr) {
  7647. this.ec389pr.then(f)
  7648. } else {
  7649. f();
  7650. }
  7651.  
  7652. };
  7653.  
  7654. mclp.push377 = mclp.push;
  7655. mclp.splice377 = mclp.splice;
  7656.  
  7657.  
  7658.  
  7659. const emptyArr = [];
  7660. emptyArr.push = () => 0;
  7661. emptyArr.unshift = () => 0;
  7662. emptyArr.pop = () => void 0;
  7663. emptyArr.shift = () => void 0;
  7664. emptyArr.splice = () => void 0;
  7665. emptyArr.slice = function () { return this };
  7666.  
  7667.  
  7668. mclp.push = function (cTag, ...fnArgs) {
  7669. if (cTag !== 'visibleItems' || !fnArgs.length || !fnArgs[0]) return this.push377(...arguments);
  7670. const arr = this.visibleItems;
  7671. const len = arr.length;
  7672. const newTotalLen = arr.push(...fnArgs);
  7673. const addedCount = fnArgs.length;
  7674. // console.log('push')
  7675. this.proceedStampDomArraySplices381_('visibleItems', 'items', {
  7676. index: len, addedCount: addedCount, removedCount: 0
  7677. })
  7678. return newTotalLen;
  7679. }
  7680.  
  7681. mclp.splice = function (cTag, ...fnArgs) {
  7682. if (cTag !== 'visibleItems' || !fnArgs.length || (fnArgs.length === 2 && !fnArgs[1]) || (fnArgs.length > 2 && !fnArgs[2])) return this.splice377(...arguments);
  7683. const arr = this.visibleItems;
  7684. const removed = arr.splice(...fnArgs);
  7685. const removedCount = removed.length;
  7686. const addedCount = (fnArgs.length > 2 ? fnArgs.length - 2 : 0);
  7687. if (fnArgs.length >= 2 && removedCount !== fnArgs[1]) {
  7688. console.warn(`incorrect splice count. expected = ${fnArgs[1]}; actual = ${removedCount}`);
  7689. }
  7690. // console.log('splice')
  7691. this.proceedStampDomArraySplices381_('visibleItems', 'items', {
  7692. index: fnArgs[0], addedCount: addedCount, removedCount
  7693. })
  7694. return removed;
  7695. }
  7696.  
  7697.  
  7698.  
  7699. }
  7700.  
  7701. /*
  7702. mclp.flushActiveItems66b_ = function () {
  7703.  
  7704. let prWait = null;
  7705. let shouldProceedNextFlushActiveItems = false;
  7706.  
  7707. try {
  7708.  
  7709.  
  7710. const activeItems_ = this.activeItems_;
  7711. const activeItemsCount = activeItems_.length;
  7712. const maxItemsToDisplay = this.data.maxItemsToDisplay;
  7713. if (activeItemsCount > maxItemsToDisplay) {
  7714. activeItems_.splice(0, activeItemsCount - maxItemsToDisplay);
  7715. }
  7716. const qLen = this.visibleItems.length;
  7717. const pr0 = this.prDelay288;
  7718. const pr = this.prDelay288 = new PromiseExternal();
  7719. this.ec377 = true;
  7720. const ec378 = this.ec378 = new Array(qLen).fill(0).map((e, idx) => idx);
  7721. this.flushActiveItems66a_();
  7722. this.ec377 = false;
  7723. this.ec378 = null;
  7724. this.prDelay288 = pr0;
  7725. this.activeItems_ = typeof activeItems_[0] === 'string' ? activeItems_.slice(1) : activeItems_;
  7726. wme.data = `${(wme.data & 7) + 1}`;
  7727. const isSuccess = this.renderSplicedList323(ec378, qLen, pr);
  7728. if (isSuccess) {
  7729. // console.log('19949 - ok')
  7730. this.prDelay288 = pr;
  7731. shouldProceedNextFlushActiveItems = true;
  7732.  
  7733. wme.data = `${(wme.data & 7) + 1}`;
  7734. prWait = wmp;
  7735.  
  7736. } else if (activeItemsCount === 0 || !this.canScrollToBottom_()) {
  7737. // skip
  7738. } else {
  7739. const ppr = ((slist, qLen, pr) => {
  7740. const deleteCount = (typeof slist[0] === 'number') ? slist[0] : qLen;
  7741. let newAt = qLen - deleteCount;
  7742. if (newAt > 0 && slist[newAt - 1] !== qLen - 1) return 3;
  7743. if (newAt > slist.length) return 4;
  7744. if (newAt < slist.length && typeof slist[newAt] === 'number') return 5;
  7745. const addedCount = slist.length - newAt;
  7746. // if (deleteCount > addedCount) return 6;
  7747.  
  7748. if (deleteCount === 0 && addedCount === 0) return 7;
  7749.  
  7750. })(ec378, qLen, pr);
  7751.  
  7752. console.log('19949 - ng', ppr)
  7753.  
  7754. const pr2 = this.prDelay288 = new PromiseExternal();
  7755. this.flushActiveItems66a_();
  7756. pr2.resolve();
  7757. shouldProceedNextFlushActiveItems = true;
  7758.  
  7759. wme.data = `${(wme.data & 7) + 1}`;
  7760. prWait = wmp;
  7761.  
  7762. }
  7763.  
  7764. } catch (e) {
  7765.  
  7766. console.warn(e);
  7767. }
  7768.  
  7769.  
  7770. const pr5 = this.prDelay288;
  7771.  
  7772. (async ()=>{
  7773. await pr5;
  7774. await prWait;
  7775. flushActiveItemExecuted = false;
  7776. if (shouldProceedNextFlushActiveItems && this.activeItems_.length > 0) setTimeout(() => this.flushActiveItems_(), 0);
  7777. })();
  7778.  
  7779. }
  7780. */
  7781.  
  7782.  
  7783. mclp.flushActiveItemsFix001_ = function () {
  7784.  
  7785. // fix YouTube wrong code
  7786. // var b = Math.max(this.visibleItems.length + this.activeItems_.length - this.data.maxItemsToDisplay, 0);
  7787. // b && this.splice("visibleItems", 0, b);
  7788. // e.g. 0 + 99 - 90 = 9
  7789.  
  7790. const data = this.data;
  7791. if (!data) return;
  7792. const visibleItems = this.visibleItems;
  7793. const activeItems_ = this.activeItems_;
  7794. if (!visibleItems || !activeItems_) return;
  7795. const viLen = visibleItems.length;
  7796. const aiLen = activeItems_.length;
  7797. const maxDisplayLen = data.maxItemsToDisplay;
  7798. if (!maxDisplayLen) return;
  7799. if (viLen + aiLen > maxDisplayLen) {
  7800. if (aiLen > maxDisplayLen) activeItems_.splice(0, aiLen - maxDisplayLen);
  7801. // visibleItems splice done by original flushActiveItems_
  7802. }
  7803. }
  7804.  
  7805. mclp.flushActiveItems3641_ = mclp.flushActiveItems_;
  7806.  
  7807. mclp.__moreItemButtonBlinkingCheck183__ = function () {
  7808. const hasPendingItems = (this.activeItems_ && this.activeItems_.length > 0) ? 1 : 0;
  7809. const shouldChange = (hasMoreMessageState === (1 - hasPendingItems));
  7810. if (shouldChange) {
  7811. hasMoreMessageState = hasPendingItems;
  7812. const showMore = (this.$ || 0)['show-more'];
  7813. if (showMore) {
  7814. showMore.classList.toggle('has-new-messages-miuzp', hasPendingItems ? true : false);
  7815. }
  7816. }
  7817. }
  7818.  
  7819. let ps00 = false;
  7820. mclp.flushActiveItems_ = function () {
  7821. if (ps00) return;
  7822. // console.log('flushActiveItems_')
  7823. ps00 = true;
  7824. deferCallback(this, () => {
  7825. ps00 = false;
  7826. // console.log('flushActiveItems3641_')
  7827. if (this.activeItems_.length > 0) {
  7828. const data = this.data;
  7829. if (data) {
  7830. if (data.maxItemsToDisplay > MAX_ITEMS_FOR_TOTAL_DISPLAY) data.maxItemsToDisplay = MAX_ITEMS_FOR_TOTAL_DISPLAY;
  7831. this.flushActiveItemsFix001_(); // bug fix
  7832. this.flushActiveItems3641_();
  7833. if (ENABLE_SHOW_MORE_BLINKER) {
  7834. this.__moreItemButtonBlinkingCheck183__(); // blink the button if there are activeItems remaining.
  7835. }
  7836. }
  7837. }
  7838. }).catch(console.warn);
  7839. };
  7840.  
  7841. mclp.showNewItems3641_ = mclp.showNewItems_;
  7842. mclp.refreshOffsetContainerHeight3641_ = mclp.refreshOffsetContainerHeight_;
  7843. mclp.maybeScrollToBottom3641_ = mclp.maybeScrollToBottom_;
  7844.  
  7845. let ps01 = false;
  7846. mclp.showNewItems_ = function () {
  7847. if (ps01) return;
  7848. // console.log('showNewItems_')
  7849. ps01 = true;
  7850. deferCallback(this, () => {
  7851. ps01 = false;
  7852. this.showNewItems3641_();
  7853. }).catch(console.warn);
  7854. };
  7855.  
  7856. if (!ENABLE_NO_SMOOTH_TRANSFORM && !mclp.refreshOffsetContainerHeight26_) {
  7857. let ps02 = false;
  7858. mclp.refreshOffsetContainerHeight_ = function () {
  7859. if (ps02) return;
  7860. // console.log('refreshOffsetContainerHeight_')
  7861. ps02 = true;
  7862. deferCallback(this, () => {
  7863. ps02 = false;
  7864. this.refreshOffsetContainerHeight3641_();
  7865. }).catch(console.warn);
  7866. };
  7867. }
  7868.  
  7869.  
  7870. let ps03 = false;
  7871. mclp.maybeScrollToBottom_ = function () {
  7872. if (ps03) return;
  7873. // console.log('maybeScrollToBottom_')
  7874. ps03 = true;
  7875. deferCallback(this, () => {
  7876. ps03 = false;
  7877. if (this.atBottom === true) {
  7878.  
  7879. // if (itemsResizeObserverAttached !== true && this.atBottom === true) {
  7880. // // fallback for old browser
  7881. // const itemScroller = this.itemScroller || this.$['item-scroller'] || this.querySelector('#item-scroller') || 0;
  7882. // if (itemScroller.scrollTop === 0) {
  7883. // resizeObserverFallback.observe(itemScroller);
  7884. // }
  7885. // }
  7886. } else {
  7887.  
  7888. this.maybeScrollToBottom3641_();
  7889. }
  7890. }).catch(console.warn);
  7891. };
  7892.  
  7893. mclp.onScrollItems3641_ = mclp.onScrollItems_;
  7894. mclp.maybeResizeScrollContainer3641_ = mclp.maybeResizeScrollContainer_;
  7895. mclp.handleLiveChatActions3641_ = mclp.handleLiveChatActions_;
  7896.  
  7897. let ps11 = false;
  7898. mclp.onScrollItems_ = function (a) {
  7899. if (ps11) return;
  7900. // console.log('onScrollItems_')
  7901. ps11 = true;
  7902. deferCallback(this, () => {
  7903. ps11 = false;
  7904. this.onScrollItems3641_(a);
  7905. }).catch(console.warn);
  7906. };
  7907.  
  7908. if (!ENABLE_NO_SMOOTH_TRANSFORM) { // no function for ENABLE_NO_SMOOTH_TRANSFORM
  7909. let ps12 = false;
  7910. mclp.maybeResizeScrollContainer_ = function (a) {
  7911. if (ps12) return;
  7912. // console.log('maybeResizeScrollContainer_')
  7913. ps12 = true;
  7914. deferCallback(this, () => {
  7915. ps12 = false;
  7916. this.maybeResizeScrollContainer3641_(a);
  7917. }).catch(console.warn);
  7918. };
  7919. }
  7920.  
  7921. }
  7922.  
  7923. console1.log("flushActiveItems_", "OK");
  7924. } else {
  7925. console1.log("flushActiveItems_", "NG");
  7926. }
  7927. }
  7928.  
  7929.  
  7930. if ((_flag0281_ & 0x40) == 0 ) {
  7931.  
  7932.  
  7933. let showBtnLastState = null;
  7934. let lastAtBottomState = null;
  7935. // let showMoreBtnTransitionTrigg = false;
  7936. mclp.atBottomChanged314_ = mclp.atBottomChanged_;
  7937. mclp.atBottomChanged_ = function () {
  7938.  
  7939. const currentAtBottomState = this.atBottom;
  7940. if(lastAtBottomState === currentAtBottomState) return;
  7941. lastAtBottomState = currentAtBottomState;
  7942.  
  7943. // console.log(1289, showMoreBtnTransitionTrigg)
  7944.  
  7945. /*
  7946. if (!this.___btn3848___) {
  7947. this.___btn3848___ = true;
  7948. const btn = ((this || 0).$ || 0)["show-more"] || 0;
  7949. if (btn) {
  7950. btn.addEventListener('transitionstart', (evt) => {
  7951. showMoreBtnTransitionTrigg = true;
  7952. const newVisibility = (this.atBottom === true) ? "hidden" : "visible";
  7953. if (newVisibility === "visible") {
  7954. const btn = evt.target;
  7955. if (btn.style.visibility !== newVisibility) btn.style.visibility = newVisibility;
  7956. }
  7957. });
  7958. btn.addEventListener('transitionend', (evt) => {
  7959. showMoreBtnTransitionTrigg = true;
  7960. const newVisibility = (this.atBottom === true) ? "hidden" : "visible";
  7961. if (newVisibility === "hidden") {
  7962. const btn = evt.target;
  7963. if (btn.style.visibility !== newVisibility) btn.style.visibility = newVisibility;
  7964. }
  7965. });
  7966. btn.addEventListener('transitioncancel', (evt) => {
  7967. showMoreBtnTransitionTrigg = true;
  7968. const newVisibility = (this.atBottom === true) ? "hidden" : "visible";
  7969. if (newVisibility === "hidden") {
  7970. const btn = evt.target;
  7971. if (btn.style.visibility !== newVisibility) btn.style.visibility = newVisibility;
  7972. }
  7973. });
  7974. }
  7975. }
  7976. */
  7977.  
  7978. // btn-show-more-transition
  7979. if (showMoreBtnTransitionTrigg) return;
  7980.  
  7981. const btn = ((this || 0).$ || 0)["show-more"] || 0;
  7982. if (!btn) return this.atBottomChanged314_();
  7983.  
  7984. const showBtnCurrentState = btn.hasAttribute('disabled');
  7985. if (showBtnLastState === showBtnCurrentState) return;
  7986. showBtnLastState = showBtnCurrentState;
  7987.  
  7988. if (this.visibleItems.length === 0) {
  7989. if (this.atBottom === true) {
  7990. btn.setAttribute('disabled', '');
  7991. showBtnLastState = true;
  7992. }
  7993. const newVisibility = (this.atBottom === true) ? "hidden" : "visible";
  7994. if (btn.style.visibility !== newVisibility) btn.style.visibility = newVisibility;
  7995. return;
  7996. }
  7997.  
  7998. nextBrowserTick_(() => {
  7999.  
  8000. if (showMoreBtnTransitionTrigg) return;
  8001.  
  8002. // fallback
  8003.  
  8004. // const isAtBottom = this.atBottom === true;
  8005. // if (isAtBottom) {
  8006. // if (!this.hideShowMoreAsync_) {
  8007. // this.hideShowMoreAsync_ = setTimeoutX0(function () {
  8008. // const btn = ((this || 0).$ || 0)["#show-more"] || 0;
  8009. // if (btn) btn.style.visibility = "hidden";
  8010. // }, 200 - 0.125);
  8011. // }
  8012. // } else {
  8013. // if (this.hideShowMoreAsync_) {
  8014. // clearTimeoutX0(this.hideShowMoreAsync_);
  8015. // this.hideShowMoreAsync_ = null;
  8016. // }
  8017. // const btn = ((this || 0).$ || 0)["#show-more"] || 0;
  8018. // if (btn) btn.style.visibility = "visible";
  8019. // }
  8020.  
  8021. const btn = ((this || 0).$ || 0)["show-more"] || 0;
  8022. const newVisibility = (this.atBottom === true) ? "hidden" : "visible";
  8023.  
  8024. if (newVisibility === "hidden") {
  8025. console.warn('show-more-btn no transition')
  8026. }
  8027.  
  8028. if (btn && btn.style.visibility !== newVisibility) btn.style.visibility = newVisibility;
  8029.  
  8030. });
  8031.  
  8032. };
  8033.  
  8034. }
  8035.  
  8036.  
  8037.  
  8038. if ((_flag0281_ & 0x2) == 0) {
  8039. if ((mclp.handleLiveChatActions_ || 0).length === 1) {
  8040.  
  8041. const sfi = fnIntegrity(mclp.handleLiveChatActions_);
  8042. // handleLiveChatActions66_
  8043. if (sfi === '1.40.20') {
  8044. // https://www.youtube.com/s/desktop/c01ea7e3/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  8045.  
  8046.  
  8047. // f.handleLiveChatActions_ = function(a) {
  8048. // var b = this;
  8049. // a.length && (a.forEach(this.handleLiveChatAction_, this),
  8050. // this.maybeResizeScrollContainer_(a),
  8051. // this.flushActiveItems_(),
  8052. // $u(function() {
  8053. // b.maybeScrollToBottom_()
  8054. // }))
  8055. // }
  8056.  
  8057. } else if (sfi === '1.39.20') {
  8058. // TBC
  8059. } else if (sfi === '1.31.17') {
  8060. // original
  8061. } else if (mclp.handleLiveChatActions3641_){
  8062. } else {
  8063. assertor(() => fnIntegrity(mclp.handleLiveChatActions_, '1.40.20'))
  8064. || logFn('mclp.handleLiveChatActions_', mclp.handleLiveChatActions_)();
  8065. }
  8066.  
  8067. mclp.handleLiveChatActions66_ = mclp.handleLiveChatActions_;
  8068.  
  8069. mclp.handleLiveChatActions_ = function (arr) {
  8070.  
  8071. try {
  8072. preprocessChatLiveActions(arr);
  8073. } catch (e) {
  8074. console.warn(e);
  8075. }
  8076.  
  8077. this.handleLiveChatActions66_(arr);
  8078.  
  8079. resistanceUpdateFn_(true);
  8080. }
  8081. console1.log("handleLiveChatActions_", "OK");
  8082. } else {
  8083. console1.log("handleLiveChatActions_", "NG");
  8084. }
  8085. }
  8086.  
  8087. // we do not need to do user interaction check for Boost Chat (0x40000)
  8088. const noScrollToBottomCheckForBoostChat = (_flag0281_ & 0x40000) === 0x40000;
  8089.  
  8090. if (noScrollToBottomCheckForBoostChat === false) {
  8091.  
  8092. mclp.hasUserJustInteracted11_ = () => {
  8093. const t = dateNow();
  8094. return (t - lastWheel < 80) || currentMouseDown || currentTouchDown || (t - lastUserInteraction < 80);
  8095. }
  8096.  
  8097. if ((mclp.canScrollToBottom_ || 0).length === 0 && !mclp.canScrollToBottom157_) {
  8098.  
  8099. assertor(() => fnIntegrity(mclp.canScrollToBottom_, '0.9.5'));
  8100.  
  8101. mclp.canScrollToBottom157_ = mclp.canScrollToBottom_;
  8102. mclp.canScrollToBottom_ = function () {
  8103. return this.canScrollToBottom157_() && !this.hasUserJustInteracted11_();
  8104. }
  8105.  
  8106. console1.log("canScrollToBottom_", "OK");
  8107.  
  8108.  
  8109. } else {
  8110. console1.log("canScrollToBottom_", "NG");
  8111. }
  8112.  
  8113. }
  8114.  
  8115. if (ENABLE_NO_SMOOTH_TRANSFORM) {
  8116.  
  8117. mclp.isSmoothScrollEnabled_ = function () {
  8118. return false;
  8119. }
  8120.  
  8121. mclp.maybeResizeScrollContainer_ = function () {
  8122. //
  8123. }
  8124.  
  8125. mclp.refreshOffsetContainerHeight_ = function () {
  8126. //
  8127. }
  8128.  
  8129. mclp.smoothScroll_ = function () {
  8130. //
  8131. }
  8132.  
  8133. mclp.resetSmoothScroll_ = function () {
  8134. //
  8135. }
  8136. console1.log("ENABLE_NO_SMOOTH_TRANSFORM", "OK");
  8137. } else {
  8138. console1.log("ENABLE_NO_SMOOTH_TRANSFORM", "NG");
  8139. }
  8140.  
  8141. if ((_flag0281_ & 0x8) == 0) {
  8142.  
  8143.  
  8144. if (typeof mclp.forEachItem_ === 'function' && !mclp.forEachItem66_ && skipErrorForhandleAddChatItemAction_ && mclp.forEachItem_.length === 1) {
  8145.  
  8146. mclp.forEachItem66_ = mclp.forEachItem_;
  8147. mclp.forEachItem_ = function (a) {
  8148.  
  8149. if ((this._flag0281_ & 0x8) == 0x8) return this.forEachItem66_(a);
  8150.  
  8151. // ƒ (a){this.visibleItems.forEach(a.bind(this,"visibleItems"));this.activeItems_.forEach(a.bind(this,"activeItems_"))}
  8152.  
  8153. try {
  8154.  
  8155. let items801 = false;
  8156. if (typeof a === 'function') {
  8157. const items = this.items;
  8158. if (items instanceof HTMLDivElement) {
  8159. const ev = this.visibleItems;
  8160. const ea = this.activeItems_;
  8161. if (ev && ea && ev.length >= 0 && ea.length >= 0) {
  8162. items801 = items;
  8163. }
  8164. }
  8165. }
  8166.  
  8167. if (items801) {
  8168. items801.__children801__ = 1;
  8169. const res = this.forEachItem66_(a);
  8170. items801.__children801__ = 0;
  8171. return res;
  8172. }
  8173.  
  8174. } catch (e) { }
  8175. return this.forEachItem66_(a);
  8176.  
  8177.  
  8178. // this.visibleItems.forEach((val, idx, arr)=>{
  8179. // a.call(this, 'visibleItems', val, idx, arr);
  8180. // });
  8181.  
  8182. // this.activeItems_.forEach((val, idx, arr)=>{
  8183. // a.call(this, 'activeItems_', val, idx, arr);
  8184. // });
  8185.  
  8186.  
  8187.  
  8188. }
  8189.  
  8190.  
  8191. }
  8192.  
  8193. }
  8194.  
  8195. if (typeof mclp.handleAddChatItemAction_ === 'function' && !mclp.handleAddChatItemAction66_ && FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION && (EMOJI_IMAGE_SINGLE_THUMBNAIL || AUTHOR_PHOTO_SINGLE_THUMBNAIL)) {
  8196.  
  8197. mclp.handleAddChatItemAction66_ = mclp.handleAddChatItemAction_;
  8198. mclp.handleAddChatItemAction_ = function (a) {
  8199. try {
  8200. if (a && typeof a === 'object' && !('length' in a)) {
  8201. fixLiveChatItem(a.item, null);
  8202. console.assert(arguments[0] === a);
  8203. }
  8204. } catch (e) { console.warn(e) }
  8205. let res;
  8206. if (skipErrorForhandleAddChatItemAction_) { // YouTube Native Engine Issue
  8207. try {
  8208. res = this.handleAddChatItemAction66_.apply(this, arguments);
  8209. } catch (e) {
  8210. if (e && (e.message || '').includes('.querySelector(')) {
  8211. console.log("skipErrorForhandleAddChatItemAction_", e.message);
  8212. } else {
  8213. throw e;
  8214. }
  8215. }
  8216. } else {
  8217. res = this.handleAddChatItemAction66_.apply(this, arguments);
  8218. }
  8219. return res;
  8220. }
  8221.  
  8222. if (FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION) console1.log("handleAddChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION ]", "OK");
  8223. } else {
  8224.  
  8225. if (FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION) console1.log("handleAddChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_ADDITION ]", "OK");
  8226. }
  8227.  
  8228.  
  8229. if (typeof mclp.handleReplaceChatItemAction_ === 'function' && !mclp.handleReplaceChatItemAction66_ && FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT && (EMOJI_IMAGE_SINGLE_THUMBNAIL || AUTHOR_PHOTO_SINGLE_THUMBNAIL)) {
  8230.  
  8231. mclp.handleReplaceChatItemAction66_ = mclp.handleReplaceChatItemAction_;
  8232. mclp.handleReplaceChatItemAction_ = function (a) {
  8233. try {
  8234. if (a && typeof a === 'object' && !('length' in a)) {
  8235. fixLiveChatItem(a.replacementItem, null);
  8236. console.assert(arguments[0] === a);
  8237. }
  8238. } catch (e) { console.warn(e) }
  8239. return this.handleReplaceChatItemAction66_.apply(this, arguments);
  8240. }
  8241.  
  8242. if (FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT) console1.log("handleReplaceChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT ]", "OK");
  8243. } else {
  8244.  
  8245. if (FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT) console1.log("handleReplaceChatItemAction_ [ FIX_THUMBNAIL_SIZE_ON_ITEM_REPLACEMENT ]", "OK");
  8246. }
  8247.  
  8248. console1.log("[End]");
  8249. groupEnd();
  8250.  
  8251. }).catch(console.warn);
  8252.  
  8253.  
  8254. const tickerContainerSetAttribute = function (attrName, attrValue) { // ensure '14.30000001%'.toFixed(1)
  8255.  
  8256. let yd = (this.__dataHost || insp(this).__dataHost || 0).__data;
  8257.  
  8258. if (arguments.length === 2 && attrName === 'style' && yd && attrValue) {
  8259.  
  8260. // let v = yd.containerStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_;
  8261. let v = `${attrValue}`;
  8262. // conside a ticker is 101px width
  8263. // 1% = 1.01px
  8264. // 0.2% = 0.202px
  8265.  
  8266.  
  8267. const ratio1 = (yd.ratio * 100);
  8268. if (ratio1 > -1) { // avoid NaN
  8269.  
  8270. // countdownDurationMs
  8271. // 600000 - 0.2% <1% = 6s> <0.2% = 1.2s>
  8272. // 300000 - 0.5% <1% = 3s> <0.5% = 1.5s>
  8273. // 150000 - 1% <1% = 1.5s>
  8274. // 75000 - 2% <1% =0.75s > <2% = 1.5s>
  8275. // 30000 - 5% <1% =0.3s > <5% = 1.5s>
  8276.  
  8277. // 99px * 5% = 4.95px
  8278.  
  8279. // 15000 - 10% <1% =0.15s > <10% = 1.5s>
  8280.  
  8281.  
  8282. // 1% Duration
  8283.  
  8284. let ratio2 = ratio1;
  8285.  
  8286. const ydd = yd.data;
  8287. if (ydd) {
  8288.  
  8289. const d1 = ydd.durationSec;
  8290. const d2 = ydd.fullDurationSec;
  8291.  
  8292. // @ step timing [min. 0.2%]
  8293. let numOfSteps = 500;
  8294. if ((d1 === d2 || (d1 + 1 === d2)) && d1 > 1) {
  8295. if (d2 > 400) numOfSteps = 500; // 0.2%
  8296. else if (d2 > 200) numOfSteps = 200; // 0.5%
  8297. else if (d2 > 100) numOfSteps = 100; // 1%
  8298. else if (d2 > 50) numOfSteps = 50; // 2%
  8299. else if (d2 > 25) numOfSteps = 20; // 5% (max => 99px * 5% = 4.95px)
  8300. else numOfSteps = 20;
  8301. }
  8302. if (numOfSteps > TICKER_MAX_STEPS_LIMIT) numOfSteps = TICKER_MAX_STEPS_LIMIT;
  8303. if (numOfSteps < 5) numOfSteps = 5;
  8304.  
  8305. const rd = numOfSteps / 100.0;
  8306.  
  8307. ratio2 = Math.round(ratio2 * rd) / rd;
  8308.  
  8309. // ratio2 = Math.round(ratio2 * 5) / 5;
  8310. ratio2 = ratio2.toFixed(1);
  8311. v = v.replace(`${ratio1}%`, `${ratio2}%`).replace(`${ratio1}%`, `${ratio2}%`);
  8312.  
  8313. if (yd.__style_last__ === v) return;
  8314. yd.__style_last__ = v;
  8315. // do not consider any delay here.
  8316. // it shall be inside the looping for all properties changes. all the css background ops are in the same microtask.
  8317.  
  8318. }
  8319. }
  8320.  
  8321. HTMLElement_.prototype.setAttribute.call(dr(this), attrName, v);
  8322.  
  8323.  
  8324. } else {
  8325. HTMLElement_.prototype.setAttribute.apply(dr(this), arguments);
  8326. }
  8327.  
  8328. };
  8329.  
  8330.  
  8331. const fpTicker = (renderer) => {
  8332. const cnt = insp(renderer);
  8333. assertor(() => typeof (cnt || 0).is === 'string');
  8334. assertor(() => ((cnt || 0).hostElement || 0).nodeType === 1);
  8335. const container = (cnt.$ || 0).container;
  8336. if (container) {
  8337. assertor(() => (container || 0).nodeType === 1);
  8338. assertor(() => typeof container.setAttribute === 'function');
  8339. container.setAttribute = tickerContainerSetAttribute;
  8340. } else {
  8341. console.warn(`"container" does not exist in ${cnt.is}`);
  8342. }
  8343. };
  8344.  
  8345.  
  8346. const tags = [
  8347. "yt-live-chat-ticker-renderer",
  8348. "yt-live-chat-ticker-paid-message-item-renderer",
  8349. "yt-live-chat-ticker-paid-sticker-item-renderer",
  8350. "yt-live-chat-ticker-sponsor-item-renderer"
  8351. ];
  8352.  
  8353. const tagsItemRenderer = [
  8354. "yt-live-chat-ticker-renderer",
  8355. "yt-live-chat-ticker-paid-message-item-renderer",
  8356. "yt-live-chat-ticker-paid-sticker-item-renderer",
  8357. "yt-live-chat-ticker-sponsor-item-renderer"
  8358. ];
  8359.  
  8360. // const wmList = new Set;
  8361.  
  8362. true && (new MutationObserver((mutations) => {
  8363.  
  8364. const s = new Set();
  8365. for (const mutation of mutations) {
  8366. if (mutation.type === 'attributes') {
  8367. s.add(mutation.target);
  8368. }
  8369. }
  8370. for (const target of s) {
  8371. const p = target && target.isConnected === true ? target.getAttribute('q92wb') : '';
  8372. if (p === '1') {
  8373. target.setAttribute('q92wb', '2');
  8374. const cnt = insp(target);
  8375. const dataId = ((cnt || 0).data || 0).id;
  8376. if (cnt && typeof cnt.requestRemoval49 === 'function' && dataId) {
  8377. target.id = dataId;
  8378. cnt.requestRemoval49();
  8379. target.setAttribute('q92wb', '3');
  8380. }
  8381. } else if (p === '3') {
  8382. target.setAttribute('q92wb', '4');
  8383. const cnt = insp(target);
  8384. const dataId = ((cnt || 0).data || 0).id;
  8385. if (cnt && typeof cnt.requestRemoval49 === 'function' && dataId) {
  8386. target.id = dataId;
  8387. const parentComponent = target.closest('yt-live-chat-ticker-renderer') || cnt.parentComponent;
  8388. const parentCnt = insp(parentComponent);
  8389. if(parentComponent && parentCnt && parentCnt.removeTickerItemById){
  8390. parentCnt.removeTickerItemById(dataId);
  8391. target.setAttribute('q92wb', '5');
  8392. }
  8393. }
  8394. }
  8395. }
  8396. s.clear();
  8397.  
  8398. })).observe(document, { attributes: true, attributeFilter: ['q92wb'], subtree: true });
  8399.  
  8400. Promise.all(tags.map(tag => customElements.whenDefined(tag))).then(() => {
  8401.  
  8402. mightFirstCheckOnYtInit();
  8403. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-ticker-... hacks");
  8404. console1.log("[Begin]");
  8405.  
  8406.  
  8407. let tickerAttachmentId = 0;
  8408.  
  8409.  
  8410. const __requestRemoval__ = function (cnt) {
  8411. if (cnt.hostElement && typeof cnt.requestRemoval === 'function') {
  8412. try {
  8413. const id = (cnt.data || 0).id;
  8414. if (!id) cnt.data = { id: 1 };
  8415. } catch (e) { }
  8416. try {
  8417. cnt.requestRemoval();
  8418. return true;
  8419. } catch (e) { }
  8420. }
  8421. return false;
  8422. }
  8423.  
  8424.  
  8425. const overlayBgMap = new WeakMap();
  8426.  
  8427. const dProto = {
  8428.  
  8429.  
  8430. /**
  8431. *
  8432.  
  8433. f.updateStatsBarAndMaybeShowAnimation = function(a, b, c) {
  8434. var d = this;
  8435. a || c();
  8436. a && this.statsBar && this.username && this.textContent && (this.isMouseOver ? (b(),
  8437. c()) : (a = this.animateShowStats(),
  8438. this.data.animationOrigin && this.data.trackingParams && aB().stateChanged(this.data.trackingParams, {
  8439. animationEventData: {
  8440. origin: this.data.animationOrigin
  8441. }
  8442. }),
  8443. a.finished.then(function() {
  8444. var e;
  8445. setTimeout(function() {
  8446. b();
  8447. c();
  8448. if (!d.isMouseOver) {
  8449. var g, k;
  8450. d.animateHideStats(((g = d.data) == null ? void 0 : g.dynamicStateData.stateSlideDurationMs) || 0, ((k = d.data) == null ? void 0 : k.dynamicStateData.stateUpdateDelayAfterMs) || 0)
  8451. }
  8452. }, ((e = d.data) == null ? void 0 : e.dynamicStateData.stateUpdateDelayBeforeMs) || 0)
  8453. })))
  8454. }
  8455.  
  8456. *
  8457. */
  8458.  
  8459.  
  8460.  
  8461. /**
  8462. *
  8463. *
  8464.  
  8465. f.animateShowStats = function() {
  8466. var a = this.textContent.animate({
  8467. transform: "translateY(-30px)"
  8468. }, {
  8469. duration: this.data.dynamicStateData.stateSlideDurationMs,
  8470. fill: "forwards"
  8471. });
  8472. this.username.animate({
  8473. opacity: 0
  8474. }, {
  8475. duration: 500,
  8476. fill: "forwards"
  8477. });
  8478. this.statsBar.animate({
  8479. opacity: 1
  8480. }, {
  8481. duration: 500,
  8482. fill: "forwards"
  8483. });
  8484. return a
  8485. }
  8486. ;
  8487. f.animateHideStats = function(a, b) {
  8488. this.textContent.animate({
  8489. transform: "translateY(0)"
  8490. }, {
  8491. duration: a,
  8492. fill: "forwards",
  8493. delay: b
  8494. });
  8495. this.username.animate({
  8496. opacity: 1
  8497. }, {
  8498. duration: 300,
  8499. fill: "forwards",
  8500. delay: b
  8501. });
  8502. this.statsBar.animate({
  8503. opacity: 0
  8504. }, {
  8505. duration: 300,
  8506. fill: "forwards",
  8507. delay: b
  8508. })
  8509. }
  8510. *
  8511. */
  8512.  
  8513. updateStatsBarAndMaybeShowAnimationRevised: function (a, b, c) {
  8514. // prevent memory leakage due to d.data was asked in a.finished.then
  8515. try{
  8516. // console.log('updateStatsBarAndMaybeShowAnimation called', this.is)
  8517. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8518. return this.updateStatsBarAndMaybeShowAnimation38.call(this.__proxySelf0__, a, b, c);
  8519. }catch(e){
  8520. console.log('updateStatsBarAndMaybeShowAnimationRevised ERROR');
  8521. console.error(e);
  8522. }
  8523. },
  8524.  
  8525. detachedForMemoryLeakage: function () {
  8526.  
  8527. try{
  8528.  
  8529. this.actionHandlerBehavior.unregisterActionMap(this.behaviorActionMap)
  8530.  
  8531. // this.behaviorActionMap = 0;
  8532. // this.isVisibilityRoot = 0;
  8533.  
  8534.  
  8535. }catch(e){}
  8536.  
  8537. return this.detached582MemoryLeak();
  8538. },
  8539.  
  8540. detachedForTickerInit: function () {
  8541.  
  8542. Promise.resolve(this).then((cnt) => {
  8543. if (cnt.isAttached) return;
  8544. cnt.isAttached === false && ((cnt.$ || 0).container || 0).isConnected === false && __requestRemoval__(cnt);
  8545. cnt.rafId > 1 && rafHub.cancel(cnt.rafId);
  8546. }).catch(console.warn);
  8547.  
  8548.  
  8549. const hostElement = (this || 0).hostElement;
  8550. if (USE_ADVANCED_TICKING && (this || 0).__isTickerItem58__ && hostElement instanceof HTMLElement_) {
  8551. // otherwise the startCountDown not working
  8552. hostElement.style.removeProperty('--ticker-start-time');
  8553. hostElement.style.removeProperty('--ticker-duration-time');
  8554.  
  8555. if (kRef(qWidthAdjustable) === hostElement) {
  8556.  
  8557. // need to update the first ticker
  8558. const q = document.querySelector('.r6-width-adjustable');
  8559. if (q instanceof HTMLElement_ && q.classList.contains('r6-width-adjustable-f')) {
  8560. q.classList.remove('r6-width-adjustable-f');
  8561. }
  8562. qWidthAdjustable = mWeakRef(q);
  8563.  
  8564. }
  8565. }
  8566.  
  8567. let r;
  8568. try {
  8569. r = this.detached77();
  8570. } catch (e) {
  8571. console.warn(e);
  8572. }
  8573. this.__ticker_attachmentId__ = 0;
  8574. return r;
  8575. },
  8576.  
  8577. attachedForTickerInit: function () {
  8578. this.__ticker_attachmentId__ = tickerAttachmentId = (tickerAttachmentId & 1073741823) + 1;
  8579.  
  8580. const hostElement = (this || 0).hostElement;
  8581. if (USE_ADVANCED_TICKING && (this || 0).__isTickerItem58__ && hostElement instanceof HTMLElement_) {
  8582. const prevElement = kRef(qWidthAdjustable);
  8583. if (prevElement instanceof HTMLElement_) {
  8584. prevElement.classList.add('r6-width-adjustable-f');
  8585. }
  8586. if (hostElement.__fgvm573__) {
  8587. hostElement.classList.remove('r6-closing-ticker');
  8588. hostElement.classList.remove('r6-width-adjustable-f');
  8589. } else {
  8590. hostElement.__fgvm573__ = 1;
  8591. hostElement.classList.add('r6-width-adjustable');
  8592. }
  8593. qWidthAdjustable = mWeakRef(hostElement);
  8594. }
  8595.  
  8596.  
  8597. fpTicker(hostElement || this);
  8598. return this.attached77();
  8599.  
  8600. },
  8601.  
  8602.  
  8603.  
  8604. setContainerWidthNoSelfLeakage: function(){
  8605. // prevent memory leakage due ot delay function
  8606. try{
  8607. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8608. return this.setContainerWidth55.call(this.__proxySelf0__);
  8609. }catch(e){
  8610. console.log('setContainerWidthNoSelfLeakage ERROR');
  8611. console.error(e);
  8612. }
  8613.  
  8614. },
  8615.  
  8616. slideDownNoSelfLeakage: function(){
  8617. // prevent memory leakage due ot delay function
  8618. try{
  8619. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8620. return this.slideDown55.call(this.__proxySelf0__);
  8621. }catch(e){
  8622. console.log('slideDownNoSelfLeakage ERROR');
  8623. console.error(e);
  8624. }
  8625.  
  8626. },
  8627.  
  8628. collapseNoSelfLeakage: function(){
  8629. // prevent memory leakage due ot delay function
  8630. try{
  8631. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8632. return this.collapse55.call(this.__proxySelf0__);
  8633. }catch(e){
  8634. console.log('collapseNoSelfLeakage ERROR');
  8635. console.error(e);
  8636. }
  8637. },
  8638.  
  8639. deletedChangedNoSelfLeakage: function(){
  8640. // prevent memory leakage due ot delay function
  8641. try{
  8642. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  8643. return this.deletedChanged55.call(this.__proxySelf0__);
  8644. }catch(e){
  8645. console.log('deletedChangedNoSelfLeakage ERROR');
  8646. console.error(e);
  8647. }
  8648.  
  8649. },
  8650.  
  8651.  
  8652.  
  8653.  
  8654. /** @type {()} */
  8655. handlePauseReplayForPlaybackProgressState: function () {
  8656. if (!playerEventsByIframeRelay) return this.handlePauseReplay66.apply(this, arguments);
  8657.  
  8658. const attachementId = this.__ticker_attachmentId__;
  8659. if(!attachementId) return;
  8660.  
  8661. const jr = mWeakRef(this);
  8662.  
  8663. if (onPlayStateChangePromise) {
  8664.  
  8665. const tid = this._Y7rtu = (this._Y7rtu & 1073741823) + 1;
  8666.  
  8667. onPlayStateChangePromise.then(() => {
  8668. const cnt = kRef(jr) || 0;
  8669. if (attachementId !== cnt.__ticker_attachmentId__) return;
  8670. if (cnt.isAttached) {
  8671. if (tid === cnt._Y7rtu && !onPlayStateChangePromise && typeof cnt.handlePauseReplay === 'function' && cnt.hostElement) cnt.handlePauseReplay.apply(cnt, arguments);
  8672. // this.handlePauseReplay can be undefined if it is memory cleaned
  8673. }
  8674. });
  8675.  
  8676. return;
  8677. }
  8678.  
  8679. if (playerState !== 2) return;
  8680. if (this.isAttached) {
  8681. const tid = this._Y7rtk = (this._Y7rtk & 1073741823) + 1;
  8682. const tc = relayCount;
  8683. foregroundPromiseFn().then(() => {
  8684. const cnt = kRef(jr);
  8685. if (attachementId !== (cnt || 0).__ticker_attachmentId__) return;
  8686. if (cnt.isAttached) {
  8687. if (tid === cnt._Y7rtk && tc === relayCount && playerState === 2 && _playerState === playerState && cnt.hostElement) {
  8688. cnt.handlePauseReplay66();
  8689. }
  8690. }
  8691. })
  8692. }
  8693. },
  8694.  
  8695. /** @type {()} */
  8696. handleResumeReplayForPlaybackProgressState: function () {
  8697. if (!playerEventsByIframeRelay) return this.handleResumeReplay66.apply(this, arguments);
  8698.  
  8699. const attachementId = this.__ticker_attachmentId__;
  8700. if(!attachementId) return;
  8701.  
  8702. const jr = mWeakRef(this);
  8703. if (onPlayStateChangePromise) {
  8704.  
  8705. const tid = this._Y7rtv = (this._Y7rtv & 1073741823) + 1;
  8706.  
  8707. onPlayStateChangePromise.then(() => {
  8708. const cnt = kRef(jr);
  8709. if(attachementId !== (cnt || 0).__ticker_attachmentId__) return;
  8710. if (tid === cnt._Y7rtv && !onPlayStateChangePromise && typeof cnt.handleResumeReplay === 'function' && cnt.hostElement) cnt.handleResumeReplay.apply(cnt, arguments);
  8711. // this.handleResumeReplay can be undefined if it is memory cleaned
  8712. });
  8713.  
  8714. return;
  8715. }
  8716.  
  8717.  
  8718. if (playerState !== 1) return;
  8719. if (this.isAttached) {
  8720. const tc = relayCount;
  8721.  
  8722. relayPromise = relayPromise || new PromiseExternal();
  8723. relayPromise.then(() => {
  8724. const cnt = kRef(jr);
  8725. if(attachementId !== (cnt || 0).__ticker_attachmentId__) return;
  8726. if (relayCount > tc && playerState === 1 && _playerState === playerState && cnt.hostElement) {
  8727. cnt.handleResumeReplay66();
  8728. }
  8729. });
  8730. }
  8731. },
  8732.  
  8733. /** @type {(a,)} */
  8734. handleReplayProgressForPlaybackProgressState: function (a) {
  8735. if (this.isAttached) {
  8736. const attachementId = this.__ticker_attachmentId__;
  8737. if(!attachementId) return;
  8738. const tid = this._Y7rtk = (this._Y7rtk & 1073741823) + 1;
  8739. const jr = mWeakRef(kRef(this));
  8740. foregroundPromiseFn().then(() => {
  8741. const cnt = kRef(jr);
  8742. if(attachementId !== (cnt || 0).__ticker_attachmentId__) return;
  8743. if (cnt.isAttached) {
  8744. if (tid === cnt._Y7rtk && cnt.hostElement) {
  8745. cnt.handleReplayProgress66(a);
  8746. }
  8747. }
  8748. })
  8749. }
  8750. }
  8751.  
  8752.  
  8753. }
  8754.  
  8755.  
  8756.  
  8757. const isTickerItemsScrolling = function () {
  8758. const elm = document.querySelector('#ticker-bar.yt-live-chat-ticker-renderer');
  8759. if (!elm) return false;
  8760. return (elm.scrollLeft > 0);
  8761. }
  8762.  
  8763.  
  8764.  
  8765.  
  8766. const u37fn = function (cnt) {
  8767.  
  8768. if (cnt.__dataEnabled === false || cnt.__dataInvalid === true) return;
  8769.  
  8770. if (!__LCRInjection__) {
  8771. console.error('[yt-chat] USE_ADVANCED_TICKING fails because of no __LCRInjection__');
  8772. }
  8773.  
  8774. const cntData = ((cnt || 0).__data || 0).data || (cnt || 0).data || 0;
  8775. if (!cntData) return;
  8776. const cntElement = cnt.hostElement;
  8777. if (!(cntElement instanceof HTMLElement_)) return;
  8778.  
  8779. const duration = (cntData.fullDurationSec || cntData.durationSec || 0);
  8780.  
  8781. let ct;
  8782.  
  8783. if (__LCRInjection__ && cntData && duration > 0 && !('__progressAt__' in cntData)) {
  8784. ct = Date.now();
  8785.  
  8786. if (!cntData.__timestampActionRequest__) {
  8787. console.log(' 5688001 ');
  8788. // console.log(`(5688001) ${new Error().stack}`);
  8789. }
  8790. cntData.__liveTimestamp__ = (((cntData.__timestampActionRequest__ || ct) - timeOriginDT) / 1000) || Number.MIN_VALUE;
  8791. timestampUnderLiveMode = true;
  8792. } else if (__LCRInjection__ && cntData && duration > 0 && cntData.__progressAt__ > 0) {
  8793. timestampUnderLiveMode = false;
  8794. }
  8795. // console.log(48117007, cntData)
  8796.  
  8797. let tk = cntData.__progressAt__ || cntData.__liveTimestamp__;
  8798.  
  8799. if (!tk) {
  8800. console.log('time property is not found', !!__LCRInjection__, !!cntData, !!(duration > 0), !('__progressAt__' in cntData), cntData.__progressAt__, cntData.__liveTimestamp__);
  8801. return;
  8802. }
  8803.  
  8804.  
  8805.  
  8806. const liveOffsetMs = ct > 0 && cntData.__timestampActionRequest__ > 0 ? ct - cntData.__timestampActionRequest__ : 0;
  8807.  
  8808. // console.log(1237, liveOffsetMs, cntData.durationSec)
  8809.  
  8810. if (liveOffsetMs > 0) {
  8811. cntData.durationSec -= Math.floor(liveOffsetMs / 1000);
  8812. if (cntData.durationSec < 0) cntData.durationSec = 0;
  8813. // console.log(1238, liveOffsetMs, cntData.durationSec)
  8814. if (!cntData.durationSec) {
  8815. try {
  8816. cnt.requestRemoval();
  8817. } catch (e) { }
  8818. return;
  8819. }
  8820. }
  8821.  
  8822.  
  8823. let offset = cntData.fullDurationSec - cntData.durationSec; // consider this is live replay video, offset can be > 0
  8824. if (offset > 0) tk -= offset;
  8825. // in livestreaming. tk can be negative as we use performance.timeOrigin for t=0s time frame
  8826.  
  8827.  
  8828.  
  8829. const existingOverlaySelector = `ticker-bg-overlay[ticker-id="${cnt.__ticker_attachmentId__}"]`;
  8830.  
  8831. const q = kRef(overlayBgMap.get(cnt));
  8832.  
  8833. let r = valAssign(cntElement, '--ticker-start-time', tk);
  8834.  
  8835. if ((r || !q || q.isConnected === false) && duration > 0) {
  8836.  
  8837. // t0 ...... 1 ... fullDurationSec
  8838. // tk ...... k ... fullDurationSec-durationSec
  8839. // t0-fullDurationSec ...... 0 ... 0
  8840.  
  8841. // now - (fullDurationSec-durationSec)
  8842.  
  8843.  
  8844. // update dntElementWeak
  8845. const dnt = cnt.parentComponent;
  8846. const dntElement = dnt ? dnt.hostElement || dnt : 0;
  8847. if (dntElement) {
  8848. dntElementWeak = mWeakRef(dntElement);
  8849. resistanceUpdateBusy = false;
  8850. if (!startResistanceUpdaterStarted) startResistanceUpdater();
  8851. else updateTickerCurrentTime();
  8852. }
  8853.  
  8854.  
  8855. // create overlay if needed
  8856. if (!cntElement.querySelector(existingOverlaySelector)) {
  8857.  
  8858. // remove if any
  8859. const oldElement = cntElement.querySelector('ticker-bg-overlay');
  8860. if (oldElement) oldElement.remove();
  8861.  
  8862. // use advancedTicking, ticker enabled
  8863. cnt.__advancedTicking038__ = 1;
  8864.  
  8865. const em = q || document.createElement('ticker-bg-overlay');
  8866.  
  8867. overlayBgMap.set(cnt, mWeakRef(em));
  8868. // const ey = document.createElement('ticker-bg-overlay-end');
  8869. const wy = document.createElement('ticker-bg-overlay-end2');
  8870.  
  8871. const cr1 = cnt.colorFromDecimal(cntData.startBackgroundColor);
  8872. const cr2 = cnt.colorFromDecimal(cntData.endBackgroundColor);
  8873.  
  8874. const container = cnt.$.container;
  8875.  
  8876. em.setAttribute('ticker-id', `${cnt.__ticker_attachmentId__}`);
  8877.  
  8878. const tid = `ticker-${cnt.__ticker_attachmentId__}-${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
  8879.  
  8880. em.id = `${tid}-b`;
  8881. em.style.background = `linear-gradient(90deg, ${cr1},${cr1} 50%,${cr2} 50%,${cr2})`;
  8882.  
  8883. if (!(container instanceof HTMLElement_)) {
  8884. // em.insertBefore(ey, em.firstChild);
  8885. insertBeforeNaFn(cntElement, em, cntElement.firstChild); // cntElement.insertBefore(em, cntElement.firstChild);
  8886. cntElement.style.borderRadius = '16px';
  8887. container.style.borderRadius = 'initial';
  8888. } else {
  8889. // em.insertBefore(ey, em.firstChild);
  8890. insertBeforeNaFn(container, em, container.firstChild); // container.insertBefore(em, container.firstChild);
  8891. }
  8892.  
  8893. // em.style.left = '-50%';
  8894. // em.style.left = "clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%)";
  8895.  
  8896. if (container instanceof HTMLElement_) {
  8897.  
  8898. container.style.background = 'transparent';
  8899. container.style.backgroundColor = 'transparent';
  8900. // container.style.zIndex = '1';
  8901. }
  8902. // em.style.zIndex = '-1';
  8903. valAssign(cntElement, '--ticker-duration-time', duration)
  8904.  
  8905. valAssign(wy, '--ticker-start-time', tk);
  8906. valAssign(wy, '--ticker-duration-time', duration);
  8907. wy.id = `${tid}-e`;
  8908.  
  8909. appendChildNaFn(dntElement, wy);
  8910.  
  8911. // if (wio instanceof IntersectionObserver) {
  8912. // wio.observe(ey);
  8913. // }
  8914.  
  8915. const wio2 = dProto.wio2;
  8916. if (wio2 instanceof IntersectionObserver) {
  8917. wio2.observe(wy);
  8918. }
  8919.  
  8920. }
  8921. }
  8922. };
  8923.  
  8924.  
  8925.  
  8926. const timeFn749 = (cnt) => {
  8927. cnt = kRef(cnt);
  8928. if (!cnt) return;
  8929. cnt.__startCountdownAdv477__ = Date.now();
  8930.  
  8931. if (
  8932. cnt
  8933. && (cnt.hostElement && cnt.isAttached && cnt.hostElement.isConnected)
  8934. && cnt.parentComponent // startCountdown is triggered by dataChanged; // not yet attached to the actual dom tree
  8935. && cnt.__ticker_attachmentId__
  8936. ) {
  8937.  
  8938. const data = cnt.data;
  8939. const dataId = data ? ((cnt || 0).data || 0).id : null;
  8940. const elemId = ((cnt || 0).hostElement || 0).id;
  8941.  
  8942. if (dataId && dataId === elemId) {
  8943.  
  8944. const attachId = cnt.__ticker_attachmentId__;
  8945. const uid = `${attachId}!${dataId}`;
  8946.  
  8947. if (data.__wsi6c__ !== uid) {
  8948. data.__wsi6c__ = uid;
  8949. Promise.resolve(cnt).then(u37fn);
  8950. return true;
  8951. }
  8952.  
  8953. }
  8954.  
  8955. }
  8956.  
  8957. return false;
  8958. }
  8959.  
  8960. let tagI = 0;
  8961. for (const tag of tagsItemRenderer) { // ##tag##
  8962.  
  8963. tagI++;
  8964.  
  8965. const dummy = document.createElement(tag);
  8966.  
  8967. const cProto = getProto(dummy);
  8968. if (!cProto || !cProto.attached) {
  8969. console1.warn(`proto.attached for ${tag} is unavailable.`);
  8970. continue;
  8971. }
  8972.  
  8973. if (FIX_MEMORY_LEAKAGE_TICKER_ACTIONMAP && typeof cProto.detached582MemoryLeak !== 'function' && typeof cProto.detached === 'function') {
  8974. cProto.detached582MemoryLeak = cProto.detached;
  8975. cProto.detached = dProto.detachedForMemoryLeakage;
  8976. }
  8977.  
  8978. cProto.detached77 = cProto.detached;
  8979. cProto.detached = dProto.detachedForTickerInit;
  8980.  
  8981. cProto.attached77 = cProto.attached;
  8982.  
  8983. cProto.attached = dProto.attachedForTickerInit;
  8984.  
  8985. let flgLeakageFixApplied = 0;
  8986.  
  8987. if (FIX_MEMORY_LEAKAGE_TICKER_STATSBAR && typeof cProto.updateStatsBarAndMaybeShowAnimation === 'function' && !cProto.updateStatsBarAndMaybeShowAnimation38 && cProto.updateStatsBarAndMaybeShowAnimation.length === 3) {
  8988.  
  8989. cProto.updateStatsBarAndMaybeShowAnimation38 = cProto.updateStatsBarAndMaybeShowAnimation;
  8990. cProto.updateStatsBarAndMaybeShowAnimation = dProto.updateStatsBarAndMaybeShowAnimationRevised;
  8991.  
  8992. flgLeakageFixApplied |= 2;
  8993. } else {
  8994. // the function is only in yt-live-chat-ticker-paid-message-item-renderer
  8995. }
  8996.  
  8997.  
  8998. // ------------- withTimerFn_ -------------
  8999.  
  9000. let withTimerFn_ = 0;
  9001. if (typeof cProto.startCountdown === 'function' && typeof cProto.updateTimeout === 'function' && typeof cProto.isAnimationPausedChanged === 'function') {
  9002.  
  9003. // console.log('startCountdown', typeof cProto.startCountdown)
  9004. // console.log('updateTimeout', typeof cProto.updateTimeout)
  9005. // console.log('isAnimationPausedChanged', typeof cProto.isAnimationPausedChanged)
  9006.  
  9007. // <<< to be reviewed cProto.updateTimeout --- isTimingFunctionHackable -- doHack >>>
  9008. const isTimingFunctionHackable = fnIntegrity(cProto.startCountdown, '2.66.37') && fnIntegrity(cProto.updateTimeout, '1.76.45') && fnIntegrity(cProto.isAnimationPausedChanged, '2.56.30')
  9009. if (!isTimingFunctionHackable) console1.log('isTimingFunctionHackable = false');
  9010. withTimerFn_ = isTimingFunctionHackable ? 2 : 1;
  9011. } else {
  9012. let flag = 0;
  9013. if (typeof cProto.startCountdown === 'function') flag |= 1;
  9014. if (typeof cProto.updateTimeout === 'function') flag |= 2;
  9015. if (typeof cProto.isAnimationPausedChanged === 'function') flag |= 4;
  9016.  
  9017. console1.log(`Skip Timing Function Modification[#${tagI}]: ${flag} / ${1 + 2 + 4}`, ` ${tag}`);
  9018. // console.log(Object.getOwnPropertyNames(cProto))
  9019. // continue;
  9020. }
  9021.  
  9022. // ------------- withTimerFn_ -------------
  9023.  
  9024. // ------------- ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX -------------
  9025.  
  9026. let urt = 0;
  9027.  
  9028. if (ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX) {
  9029.  
  9030.  
  9031. /**
  9032. *
  9033. f.handlePauseReplay = function() {
  9034. this.isAnimationPaused = !0;
  9035. this.detlaSincePausedSecs = 0
  9036. }
  9037. */
  9038.  
  9039. /**
  9040. *
  9041.  
  9042. f.handlePauseReplay = function() {
  9043. this.isReplayPaused = !0
  9044. }
  9045. *
  9046. */
  9047.  
  9048. if (typeof cProto.handlePauseReplay === 'function' && !cProto.handlePauseReplay66 && cProto.handlePauseReplay.length === 0) {
  9049. const fi = fnIntegrity(cProto.handlePauseReplay);
  9050. urt++;
  9051. if (fi === '0.8.2' || fi === '0.12.4') {
  9052. } else {
  9053. assertor(() => fnIntegrity(cProto.handlePauseReplay, '0.12.4'));
  9054. }
  9055. } else {
  9056. if (withTimerFn_ > 0) console1.log('Error for setting cProto.handlePauseReplay', tag)
  9057. }
  9058.  
  9059. if (typeof cProto.handleResumeReplay === 'function' && !cProto.handleResumeReplay66 && cProto.handleResumeReplay.length === 0) {
  9060. urt++;
  9061. assertor(() => fnIntegrity(cProto.handleResumeReplay, '0.8.2'));
  9062. } else {
  9063. if (withTimerFn_ > 0) console1.log('Error for setting cProto.handleResumeReplay', tag)
  9064. }
  9065.  
  9066. if (typeof cProto.handleReplayProgress === 'function' && !cProto.handleReplayProgress66 && cProto.handleReplayProgress.length === 1) {
  9067. urt++;
  9068. assertor(() => fnIntegrity(cProto.handleReplayProgress, '1.16.13'));
  9069. } else {
  9070. if (withTimerFn_ > 0) console1.log('Error for setting cProto.handleReplayProgress', tag)
  9071. }
  9072.  
  9073.  
  9074.  
  9075. }
  9076.  
  9077. 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);
  9078. cProto.__ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED__ = ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED;
  9079.  
  9080. if (ENABLE_VIDEO_PROGRESS_STATE_FIX_AND_URT_PASSED) {
  9081.  
  9082. cProto._Y7rtk = 0;
  9083. cProto._Y7rtu = 0;
  9084. cProto._Y7rtv = 0;
  9085.  
  9086. cProto.handlePauseReplay66 = cProto.handlePauseReplay;
  9087. cProto.handlePauseReplay = dProto.handlePauseReplayForPlaybackProgressState;
  9088.  
  9089. cProto.handleResumeReplay66 = cProto.handleResumeReplay;
  9090. cProto.handleResumeReplay = dProto.handleResumeReplayForPlaybackProgressState;
  9091.  
  9092. cProto.handleReplayProgress66 = cProto.handleReplayProgress;
  9093. cProto.handleReplayProgress = dProto.handleReplayProgressForPlaybackProgressState;
  9094.  
  9095. }
  9096.  
  9097. // ------------- ENABLE_VIDEO_PLAYBACK_PROGRESS_STATE_FIX -------------
  9098.  
  9099. // ------------- FIX_MEMORY_LEAKAGE_TICKER_TIMER -------------
  9100.  
  9101. if (FIX_MEMORY_LEAKAGE_TICKER_TIMER) {
  9102. if (!USE_ADVANCED_TICKING && typeof cProto.setContainerWidth === 'function' && !cProto.setContainerWidth55 && cProto.setContainerWidth.length === 0) {
  9103. cProto.setContainerWidth55 = cProto.setContainerWidth;
  9104. cProto.setContainerWidth = dProto.setContainerWidthNoSelfLeakage;
  9105. flgLeakageFixApplied |= 4;
  9106. }
  9107. if (!USE_ADVANCED_TICKING && typeof cProto.slideDown === 'function' && !cProto.slideDown55 && cProto.slideDown.length === 0) {
  9108. cProto.slideDown55 = cProto.slideDown;
  9109. cProto.slideDown = dProto.slideDownNoSelfLeakage;
  9110. flgLeakageFixApplied |= 8;
  9111. }
  9112. if (!USE_ADVANCED_TICKING && typeof cProto.collapse === 'function' && !cProto.collapse55 && cProto.collapse.length === 0) {
  9113. cProto.collapse55 = cProto.collapse;
  9114. cProto.collapse = dProto.collapseNoSelfLeakage;
  9115. flgLeakageFixApplied |= 16;
  9116. }
  9117. if (typeof cProto.deletedChanged === 'function' && !cProto.deletedChanged55 && cProto.deletedChanged.length === 0) {
  9118.  
  9119. cProto.deletedChanged55 = cProto.deletedChanged;
  9120. cProto.deletedChanged = dProto.deletedChangedNoSelfLeakage;
  9121. flgLeakageFixApplied |= 32;
  9122. }
  9123.  
  9124. }
  9125.  
  9126. const flgTotal = USE_ADVANCED_TICKING ? 1 + 2 + 32 : 1 + 2 + 4 + 8 + 16 + 32;
  9127.  
  9128. console1.log(`FIX_MEMORY_LEAKAGE_TICKER_[#${tagI}]: ${flgLeakageFixApplied} / ${flgTotal}`, cProto.is);
  9129.  
  9130. // ------------- FIX_MEMORY_LEAKAGE_TICKER_TIMER -------------
  9131.  
  9132.  
  9133.  
  9134. const canDoAdvancedTicking = 1 &&
  9135. ATTEMPT_TICKER_ANIMATION_START_TIME_DETECTION &&
  9136. typeof cProto.startCountdown === 'function' && !cProto.startCountdown49 && cProto.startCountdown.length === 2 &&
  9137. typeof cProto.updateTimeout === 'function' && !cProto.updateTimeout49 && cProto.updateTimeout.length === 1 &&
  9138. typeof cProto.isAnimationPausedChanged === 'function' && !cProto.isAnimationPausedChanged49 && cProto.isAnimationPausedChanged.length === 2 &&
  9139. typeof cProto.setContainerWidth === 'function' && cProto.setContainerWidth.length === 0 &&
  9140. typeof cProto.requestRemoval === 'function' && !cProto.requestRemoval49 && cProto.requestRemoval.length === 0
  9141. CSS.supports("left","clamp(-100%, calc( -100% * ( var(--ticker-current-time) - var(--ticker-start-time) ) / var(--ticker-duration-time) ), 0%)");
  9142.  
  9143.  
  9144.  
  9145. if (USE_ADVANCED_TICKING && canDoAdvancedTicking && ENABLE_TICKERS_BOOSTED_STAMPING) {
  9146. // startResistanceUpdater();
  9147. // live replay video -> 48117005 -> 48117006 keep fire. ->48117007 0 -> 48117007 {...}
  9148. // live stream video -> 48117007 0 -> 48117007 YES
  9149.  
  9150. document.documentElement.setAttribute('r6-advanced-ticking', '');
  9151. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::START`)
  9152.  
  9153. const wio2 = dProto.wio2 || (dProto.wio2 = new IntersectionObserver((mutations) => {
  9154.  
  9155. for (const mutation of mutations) {
  9156. if (mutation.isIntersecting) {
  9157.  
  9158. const marker = mutation.target;
  9159. let endId = marker.id
  9160. if (!endId) continue;
  9161. let tid = endId.substring(0, endId.length - 2);
  9162. if (!tid) continue;
  9163. // let bId = `${tid}-b`;
  9164. const bgElm = document.querySelector(`#${tid}-b`);
  9165. if (!bgElm) continue;
  9166. const overlay = bgElm;
  9167.  
  9168. wio2.unobserve(marker);
  9169. marker.remove();
  9170. let p = overlay || 0;
  9171. let cn = 4;
  9172. while ((p = p.parentElement) instanceof HTMLElement_) {
  9173. if (p instanceof HTMLElement_) {
  9174. const cnt = insp(p);
  9175. if (cnt && typeof cnt.slideDown === 'function' && typeof cnt.setContainerWidth === 'function' && cnt.__advancedTicking038__ === 1) {
  9176.  
  9177. cnt.__advancedTicking038__ = 2;
  9178.  
  9179. let deletionMode = false;
  9180. const cntData = ((cnt || 0).__data || 0).data || (cnt || 0).data || 0;
  9181. if (timestampUnderLiveMode && cntData && cntData.durationSec > 0 && cntData.__timestampActionRequest__ > 0) {
  9182.  
  9183. // time choose - 0.2s for transition (slideDown sliding-down)
  9184. // 60hz = 17ms
  9185. // choose 0.28s
  9186. const targetFutureTime = cntData.__timestampActionRequest__ + cntData.durationSec * 1000;
  9187. // check whether the targetFutureTime is already the past
  9188. if (targetFutureTime + 280 < Date.now()) {
  9189. // just dispose
  9190. deletionMode = true;
  9191. }
  9192. } else if (__LCRInjection__ && !timestampUnderLiveMode && cntData && cntData.durationSec > 0 && cntData.__progressAt__ > 0) {
  9193.  
  9194. const targetFutureTime = (cntData.__progressAt__ + cntData.durationSec);
  9195. // check whether the targetFutureTime is already the past
  9196. if (targetFutureTime + 0.28 < playerProgressChangedArg1) {
  9197. // just dispose
  9198. deletionMode = true;
  9199. }
  9200.  
  9201.  
  9202. }
  9203.  
  9204.  
  9205. if (deletionMode) {
  9206. __requestRemoval__(cnt);
  9207. } else {
  9208.  
  9209. const w = cnt.hostElement.style.width;
  9210. if (w === "auto" || w === "") cnt.setContainerWidth();
  9211. cnt.slideDown();
  9212. }
  9213.  
  9214. break;
  9215. }
  9216. }
  9217. cn--;
  9218. if (!cn) {
  9219. console.log('cnt not found for ticker-bg-overlay');
  9220. break;
  9221. }
  9222. }
  9223.  
  9224.  
  9225. }
  9226. }
  9227.  
  9228. // console.log(mutations);
  9229. }, {
  9230.  
  9231. rootMargin: '0px',
  9232. threshold: [1]
  9233.  
  9234. }));
  9235.  
  9236.  
  9237.  
  9238. cProto.__isTickerItem58__ = 1;
  9239. cProto.attached747 = cProto.attached;
  9240. cProto.attached = function () {
  9241. const hostElement = (this || 0).hostElement;
  9242. if (hostElement && hostElement.hasAttribute('q92wb')) hostElement.removeAttribute('q92wb');
  9243. if (hostElement && hostElement.__requestRemovalAt003__) hostElement.__requestRemovalAt003__ = 0;
  9244. Promise.resolve().then(() => {
  9245. if (this.hostElement && this.isAttached && this.hostElement.isConnected && this.parentComponent) {
  9246. if (this.__startCountdownAdv477__) Promise.resolve(this).then(timeFn749);
  9247. }
  9248. }).catch(console.warn);
  9249. return this.attached747();
  9250. };
  9251. cProto.startCountdown = dProto.startCountdownAdv || (dProto.startCountdownAdv = function (a, b) {
  9252.  
  9253.  
  9254. timeFn749(this);
  9255.  
  9256.  
  9257. });
  9258.  
  9259. cProto.updateTimeout = dProto.updateTimeoutAdv || (dProto.updateTimeoutAdv = function (a) {
  9260.  
  9261.  
  9262.  
  9263. });
  9264.  
  9265. cProto.isAnimationPausedChanged = dProto.isAnimationPausedChangedAdv || (dProto.isAnimationPausedChangedAdv = function (a, b) {
  9266.  
  9267.  
  9268.  
  9269. });
  9270.  
  9271.  
  9272. if (typeof cProto.slideDown === 'function' && !cProto.slideDown43 && cProto.slideDown.length === 0) {
  9273.  
  9274. cProto.slideDown43 = cProto.slideDown;
  9275. cProto.slideDown = dProto.slideDownAdv || (dProto.slideDownAdv = async function () {
  9276.  
  9277. // console.log('calling slideDown', Date.now())
  9278. if (this.__advancedTicking038__) {
  9279.  
  9280. if (this.__advancedTicking038__ === 1) this.__advancedTicking038__ = 2; // ignore intersectionobserver detection
  9281.  
  9282.  
  9283. const hostElement = this.hostElement;
  9284. const container = this.$.container;
  9285.  
  9286. const parentComponentCnt = insp(this.parentComponent);
  9287. const parentComponentElm = parentComponentCnt? parentComponentCnt.hostElement : null;
  9288.  
  9289. if (hostElement instanceof HTMLElement_ && container instanceof HTMLElement_ && parentComponentElm instanceof HTMLElement_) {
  9290. // const prevTransitionClosingElm = kRef(prevTransitionClosing);
  9291. // if (prevTransitionClosingElm !== hostElement) {
  9292. // prevTransitionClosingElm && prevTransitionClosingElm.classList.add('ticker-no-transition-time');
  9293. // prevTransitionClosing = mWeakRef(hostElement);
  9294. // }
  9295. // if (hostElement.classList.contains('ticker-no-transition-time')) hostElement.classList.remove('ticker-no-transition-time');
  9296. hostElement.classList.add('r6-closing-ticker');
  9297.  
  9298. if (!transitionEndHooks.has(parentComponentElm)) {
  9299. transitionEndHooks.add(parentComponentElm);
  9300. document.addEventListener('transitionend', transitionEndAfterFn, passiveCapture);
  9301. }
  9302.  
  9303. const pr = new PromiseExternal();
  9304. transitionEndAfterFnSimple.set(hostElement, pr);
  9305. transitionEndAfterFnSimple.set(container, pr);
  9306. transitionEndAfterFnSimpleEnable++;
  9307. hostElement.classList.add("sliding-down");
  9308. await pr.then();
  9309. transitionEndAfterFnSimpleEnable--;
  9310. transitionEndAfterFnSimple.delete(hostElement);
  9311. transitionEndAfterFnSimple.delete(container);
  9312. if (this && this.hostElement instanceof HTMLElement_) {
  9313.  
  9314. this.collapse();
  9315. }
  9316. return;
  9317. }
  9318. }
  9319. this.slideDown43();
  9320.  
  9321. });
  9322.  
  9323.  
  9324. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::slideDown - OK`)
  9325. } else {
  9326.  
  9327. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::slideDown - NG`)
  9328. }
  9329.  
  9330.  
  9331. if (typeof cProto.collapse === 'function' && !cProto.collapse43 && cProto.collapse.length === 0) {
  9332. cProto.collapse43 = cProto.collapse;
  9333. cProto.collapse = dProto.collapseAdv || (dProto.collapseAdv = async function () {
  9334.  
  9335.  
  9336. if (this.__advancedTicking038__) {
  9337.  
  9338.  
  9339. if (this.__advancedTicking038__ === 1) this.__advancedTicking038__ = 2; // ignore intersectionobserver detection
  9340.  
  9341.  
  9342. const hostElement = this.hostElement;
  9343. const container = this.$.container;
  9344.  
  9345. const parentComponentCnt = insp(this.parentComponent);
  9346. const parentComponentElm = parentComponentCnt ? parentComponentCnt.hostElement : null;
  9347.  
  9348. if (hostElement instanceof HTMLElement_ && container instanceof HTMLElement_ && parentComponentElm instanceof HTMLElement_) {
  9349. // const prevTransitionClosingElm = kRef(prevTransitionClosing);
  9350. // if (prevTransitionClosingElm !== hostElement) {
  9351. // prevTransitionClosingElm && prevTransitionClosingElm.classList.add('ticker-no-transition-time');
  9352. // prevTransitionClosing = mWeakRef(hostElement);
  9353. // }
  9354. // if (hostElement.classList.contains('ticker-no-transition-time')) hostElement.classList.remove('ticker-no-transition-time');
  9355. hostElement.classList.add('r6-closing-ticker');
  9356.  
  9357. if (!transitionEndHooks.has(parentComponentElm)) {
  9358. transitionEndHooks.add(parentComponentElm);
  9359. document.addEventListener('transitionend', transitionEndAfterFn, passiveCapture);
  9360. }
  9361.  
  9362. const pr = new PromiseExternal();
  9363. transitionEndAfterFnSimple.set(hostElement, pr);
  9364. transitionEndAfterFnSimple.set(container, pr);
  9365. transitionEndAfterFnSimpleEnable++;
  9366. hostElement.classList.add("collapsing");
  9367. hostElement.style.width = "0";
  9368. await pr.then();
  9369. transitionEndAfterFnSimpleEnable--;
  9370. transitionEndAfterFnSimple.delete(hostElement);
  9371. transitionEndAfterFnSimple.delete(container);
  9372. if (this && this.hostElement instanceof HTMLElement_) {
  9373.  
  9374. this.requestRemoval();
  9375. }
  9376.  
  9377. return;
  9378. }
  9379.  
  9380.  
  9381. }
  9382. this.collapse43();
  9383.  
  9384.  
  9385. });
  9386.  
  9387. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::collapse - OK`)
  9388. } else {
  9389.  
  9390. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::collapse - NG`)
  9391. }
  9392.  
  9393.  
  9394.  
  9395. if (typeof cProto.requestRemoval === 'function' && !cProto.requestRemoval49 && cProto.requestRemoval.length === 0) {
  9396.  
  9397. cProto.requestRemoval49 = cProto.requestRemoval;
  9398. cProto.requestRemoval = dProto.requestRemovalAdv || (dProto.requestRemovalAdv = function () {
  9399.  
  9400. const hostElement = this.hostElement;
  9401. hostElement.__requestRemovalAt003__ = Date.now();
  9402. if (this.__advancedTicking038__) {
  9403. try {
  9404. const overlayBg = hostElement.querySelector('ticker-bg-overlay[id]');
  9405. if (overlayBg) {
  9406. const overlayBgId = overlayBg.id;
  9407. const tid = overlayBgId ? overlayBgId.substring(0, overlayBgId.length - 2) : '';
  9408. const endElm = tid ? document.querySelector(`#${tid}-e`) : null;
  9409. if (endElm) {
  9410. wio2.unobserve(endElm);
  9411. endElm.remove();
  9412. }
  9413. }
  9414. } catch (e) { }
  9415. this.__advancedTicking038__ = 2;
  9416. // console.log('requestRemoval!!')
  9417. if (hostElement instanceof HTMLElement_) {
  9418. // otherwise the startCountDown not working
  9419. hostElement.style.removeProperty('--ticker-start-time');
  9420. hostElement.style.removeProperty('--ticker-duration-time');
  9421. }
  9422. if (REUSE_TICKER) {
  9423. const cntData = this.data;
  9424. if (hostElement instanceof HTMLElement_ && cntData.id && cntData.fullDurationSec && !hostElement.hasAttribute('__reuseid__')) {
  9425. hostElement.setAttribute('__reuseid__', reuseId);
  9426. hostElement.setAttribute('__nogc__', ''); // provided to leakage detection script
  9427. // this.__markReuse13__ = true;
  9428. reuseStore.set(`<${this.is}>${cntData.id}:${cntData.fullDurationSec}`, mWeakRef(this));
  9429. }
  9430. }
  9431. }
  9432. if (hostElement instanceof HTMLElement_) {
  9433. // try {
  9434. // // hostElement.remove();
  9435.  
  9436. // if (!hostElement.classList.contains('ticker-no-transition-time')) hostElement.classList.add('ticker-no-transition-time');
  9437. // } catch (e) { }
  9438.  
  9439. try {
  9440.  
  9441. hostElement.classList.remove('r6-closing-ticker');
  9442. hostElement.classList.remove('r6-width-adjustable-f');
  9443. } catch (e) { }
  9444.  
  9445. // if(ADVANCED_TICKING_MEMORY_CLEAN_FOR_REMOVAL){
  9446. // const wr = mWeakRef(hostElement);
  9447. // const wf = ()=>{
  9448. // const element = kRef(wr);
  9449. // if(!element) {
  9450. // console.log('[yt-chat-removalrequest] element was memory cleaned.');
  9451. // return;
  9452. // }
  9453.  
  9454. // setTimeout(wf, 8000);
  9455. // if(element.isConnected){
  9456. // console.log('[yt-chat-removalrequest] element is still connected to DOM Tree.');
  9457. // return;
  9458. // }
  9459.  
  9460. // const cnt = insp(element)
  9461. // if(typeof cnt.requestRemoval !== 'function'){
  9462.  
  9463. // console.log('[yt-chat-removalrequest] element is not connected to cnt.');
  9464. // return;
  9465. // }
  9466. // console.log('[yt-chat-removalrequest] element is not GC.');
  9467. // try{
  9468. // cnt.data = null;
  9469. // }catch(e){}
  9470.  
  9471. // Object.setPrototypeOf(cnt, Object.prototype);
  9472. // for(const k of Object.getOwnPropertyNames(cnt)){
  9473. // try{
  9474. // cnt[k] = null;
  9475. // }catch(e){}
  9476.  
  9477. // try{
  9478. // delete cnt[k];
  9479. // }catch(e){}
  9480. // }
  9481.  
  9482.  
  9483. // for(const k of Object.getOwnPropertySymbols(cnt)){
  9484. // try{
  9485. // cnt[k] = null;
  9486. // }catch(e){}
  9487.  
  9488. // try{
  9489. // delete cnt[k];
  9490. // }catch(e){}
  9491. // }
  9492.  
  9493. // }
  9494. // setTimeout(wf, 8000);
  9495. // }
  9496.  
  9497. hostElement.setAttribute('q92wb', '1');
  9498. }
  9499. });
  9500.  
  9501.  
  9502. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::requestRemoval - OK`)
  9503. } else {
  9504.  
  9505. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::requestRemoval - NG`)
  9506. }
  9507.  
  9508.  
  9509. if (typeof cProto.computeContainerStyle === 'function' && !cProto.computeContainerStyle49 && cProto.computeContainerStyle.length === 2) {
  9510. cProto.computeContainerStyle49 = cProto.computeContainerStyle;
  9511. cProto.computeContainerStyle = dProto.computeContainerStyleAdv || (dProto.computeContainerStyleAdv = function (a, b) {
  9512. if (this.__advancedTicking038__) {
  9513. return "";
  9514. }
  9515. return this.computeContainerStyle49(a, b);
  9516. });
  9517.  
  9518.  
  9519. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::computeContainerStyle - OK`)
  9520. } else {
  9521.  
  9522. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::computeContainerStyle - NG`)
  9523. }
  9524.  
  9525.  
  9526.  
  9527. if(ENABLE_TICKERS_BOOSTED_STAMPING && DISABLE_DYNAMIC_TICKER_WIDTH && typeof cProto.updateWidthOnDataChanged === 'function' && cProto.updateWidthOnDataChanged.length === 0 && !cProto.updateWidthOnDataChanged41){
  9528.  
  9529. cProto.updateWidthOnDataChanged41 = cProto.updateWidthOnDataChanged;
  9530. cProto.updateWidthOnDataChanged = dProto.updateWidthOnDataChangedAdv || (dProto.updateWidthOnDataChangedAdv = function(){
  9531. const style = this.hostElement.style;
  9532. style.width = "";
  9533. style.overflow = "";
  9534. });
  9535.  
  9536. }
  9537.  
  9538.  
  9539. if (!cProto.setStandardContainerWidth8447) {
  9540. cProto.setStandardContainerWidth8447 = dProto.setStandardContainerWidthAdv || (dProto.setStandardContainerWidthAdv = async function (kName) {
  9541.  
  9542. if (this.__startCountdownAdv477__) Promise.resolve(this).then(timeFn749);
  9543.  
  9544. const hostElement = (this || 0).hostElement;
  9545. const container = this.$.container;
  9546.  
  9547. let qw = null;
  9548. let qt = '';
  9549.  
  9550. {
  9551.  
  9552. let maxC = 4;
  9553.  
  9554. for (let p = qt = hostElement.getAttribute('r6-ticker-width') || ''; maxC--;) {
  9555.  
  9556. const ed = `${hostElement.id}`
  9557. if (!p || !p.startsWith(`${ed}::`)) {
  9558.  
  9559. const w = hostElement.style.width;
  9560. if (w !== '' && w !== 'auto') hostElement.style.width = 'auto';
  9561.  
  9562. const res = await widthReq(container);
  9563.  
  9564. if (res.width < 1 || !Number.isFinite(res.width)) {
  9565. // just skip due to iron-page hidden
  9566. return;
  9567. }
  9568.  
  9569. hostElement.setAttribute('r6-ticker-width', p = qt = `${ed}::${(res.width).toFixed(2)}`);
  9570.  
  9571. } else {
  9572. qw = p.split('::');
  9573. break;
  9574. }
  9575.  
  9576. }
  9577.  
  9578. }
  9579.  
  9580. if (!qw) {
  9581.  
  9582. console.log('container width failure');
  9583. if(kName === 'setContainerWidth') this.setContainerWidth41(); else this.setRevampContainerWidth41();
  9584. return; // failure
  9585. }
  9586.  
  9587.  
  9588. const shouldAnimateIn = ((this || 0).ytLiveChatTickerItemBehavior || 0).shouldAnimateIn || (this || 0).shouldAnimateIn || false;
  9589. if (shouldAnimateIn) {
  9590.  
  9591. stackDM(async () => {
  9592.  
  9593. if (hostElement.getAttribute('r6-ticker-width') !== qt || hostElement.isConnected !== true) return;
  9594. if (hostElement.previousElementSibling || isTickerItemsScrolling()) {
  9595.  
  9596. hostElement.style.width = `${qw[1]}px`;
  9597.  
  9598. } else {
  9599.  
  9600. const w = hostElement.style.width;
  9601. if (w !== '0px' && w !== '0') hostElement.style.width = '0';
  9602.  
  9603. await widthReq(container);
  9604.  
  9605. hostElement.style.width = `${qw[1]}px`;
  9606. }
  9607.  
  9608.  
  9609. });
  9610.  
  9611.  
  9612. } else {
  9613.  
  9614.  
  9615. stackDM(async () => {
  9616.  
  9617.  
  9618.  
  9619. if (hostElement.getAttribute('r6-ticker-width') !== qt || hostElement.isConnected !== true) return;
  9620.  
  9621. hostElement.style.width = `${qw[1]}px`;
  9622.  
  9623. });
  9624. }
  9625.  
  9626.  
  9627.  
  9628. });
  9629. }
  9630.  
  9631. if (typeof cProto.setRevampContainerWidth === 'function' && !cProto.setRevampContainerWidth41 && cProto.setRevampContainerWidth.length === 0 && typeof cProto.setStandardContainerWidth8447 === 'function' && cProto.setStandardContainerWidth8447.length === 1) {
  9632. cProto.setRevampContainerWidth41 = cProto.setRevampContainerWidth;
  9633. if (ENABLE_TICKERS_BOOSTED_STAMPING && DISABLE_DYNAMIC_TICKER_WIDTH) {
  9634.  
  9635. cProto.setRevampContainerWidth = dProto.setRevampContainerWidthAdv || (dProto.setRevampContainerWidthAdv = async function () {
  9636. const hostElement = this.hostElement;
  9637. if (((hostElement || 0).style || 0).width) hostElement.style.width = '';
  9638. return;
  9639. });
  9640.  
  9641. } else {
  9642.  
  9643.  
  9644.  
  9645. cProto.setRevampContainerWidth = dProto.setRevampContainerWidthAdv || (dProto.setRevampContainerWidthAdv = async function () {
  9646.  
  9647. // not sure the reason for auto instead of pixel.
  9648. // this is a new function in Dec 2024, but not mainly adopted in the coding yet
  9649.  
  9650. /*
  9651. var a = this;
  9652. (R(this.hostElement).querySelector("#container").clientWidth || 0) === 0 ? (this.hostElement.style.overflow = "visible",
  9653. this.hostElement.style.width = "auto") : (this.hostElement.style.overflow = "hidden",
  9654. this.ytLiveChatTickerItemBehavior.shouldAnimateIn ? (this.hostElement.style.width = "0",
  9655. Zu(function() {
  9656. a.hostElement.style.width = "auto"
  9657. }, 1)) : this.hostElement.style.width = "auto")
  9658. */
  9659.  
  9660.  
  9661. return this.setStandardContainerWidth8447('setRevampContainerWidth');
  9662.  
  9663. });
  9664. }
  9665.  
  9666.  
  9667. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::setRevampContainerWidth - OK`)
  9668. } else {
  9669.  
  9670. DEBUG_skipLog001 || console1.log(`USE_ADVANCED_TICKING[#${tagI}]::setRevampContainerWidth - NG (acceptable)`)
  9671. }
  9672.  
  9673.  
  9674. if (typeof cProto.setContainerWidth === 'function' && !cProto.setContainerWidth41 && cProto.setContainerWidth.length === 0 && typeof cProto.setStandardContainerWidth8447 === 'function' && cProto.setStandardContainerWidth8447.length === 1) {
  9675. cProto.setContainerWidth41 = cProto.setContainerWidth;
  9676.  
  9677. if (ENABLE_TICKERS_BOOSTED_STAMPING && DISABLE_DYNAMIC_TICKER_WIDTH) {
  9678.  
  9679. cProto.setContainerWidth = dProto.setContainerWidthAdv || (dProto.setContainerWidthAdv = async function () {
  9680. const hostElement = this.hostElement;
  9681. if (((hostElement || 0).style || 0).width) hostElement.style.width = '';
  9682. return;
  9683. });
  9684.  
  9685. } else {
  9686.  
  9687. cProto.setContainerWidth = dProto.setContainerWidthAdv || (dProto.setContainerWidthAdv = async function () {
  9688.  
  9689.  
  9690.  
  9691. /*
  9692. var a = this
  9693. , b = R(this.hostElement).querySelector("#container").clientWidth || 0;
  9694. b === 0 ? (this.hostElement.style.overflow = "visible",
  9695. this.hostElement.style.width = "auto") : (this.hostElement.style.overflow = "hidden",
  9696. this.shouldAnimateIn ? (this.hostElement.style.width = "0",
  9697. Zu(function() {
  9698. a.hostElement.style.width = b + "px"
  9699. }, 1)) : this.hostElement.style.width = b + "px")
  9700. */
  9701. return this.setStandardContainerWidth8447('setContainerWidth');
  9702.  
  9703. });
  9704.  
  9705. }
  9706.  
  9707.  
  9708.  
  9709. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::setContainerWidth - OK`)
  9710. } else {
  9711.  
  9712.  
  9713. console1.log(`USE_ADVANCED_TICKING[#${tagI}]::setContainerWidth - NG`)
  9714. }
  9715.  
  9716.  
  9717.  
  9718.  
  9719. } else if (USE_ADVANCED_TICKING) {
  9720. console1.log(`USE_ADVANCED_TICKING[#${tagI}] is not injected.`);
  9721. }
  9722.  
  9723.  
  9724.  
  9725. }
  9726.  
  9727. const selector = tags.join(', ');
  9728. const elements = document.querySelectorAll(selector);
  9729. if (elements.length >= 1) {
  9730. for (const elm of elements) {
  9731. if (insp(elm).isAttached === true) {
  9732. fpTicker(elm);
  9733. }
  9734. }
  9735. }
  9736.  
  9737. console1.log("[End]");
  9738. groupEnd();
  9739.  
  9740.  
  9741. }).catch(console.warn);
  9742.  
  9743. if(FIX_MEMORY_LEAKAGE_TICKER_DATACHANGED_setContainerWidth){
  9744.  
  9745. /**
  9746. *
  9747. *
  9748. *
  9749. *
  9750. cT.prototype.dataChanged = function() {
  9751. var a = this;
  9752. this.data && (Q(this.hostElement).querySelector("#content").style.color = this.ytLiveChatTickerItemBehavior.colorFromDecimal(this.data.detailTextColor),
  9753. this.hostElement.ariaLabel = this.computeAriaLabel(this.data),
  9754. this.ytLiveChatTickerItemBehavior.startCountdown(this.data.durationSec, this.data.fullDurationSec),
  9755. qw(function() {
  9756. a.ytLiveChatTickerItemBehavior.setContainerWidth()
  9757. }))
  9758. }
  9759.  
  9760.  
  9761. znb.prototype.dataChanged = function(a) {
  9762. var b = this;
  9763. a && (a.tickerThumbnails.length > 1 && Q(this.hostElement).querySelector("#content").classList.add("multiple-thumbnails"),
  9764. this.ytLiveChatTickerItemBehavior.startCountdown(a.durationSec, a.fullDurationSec),
  9765. qw(function() {
  9766. b.ytLiveChatTickerItemBehavior.setContainerWidth()
  9767. }))
  9768. }
  9769.  
  9770. *
  9771. */
  9772.  
  9773. const dProto = {
  9774. dataChanged54500: function () {
  9775. // prevent memory leakage due to _.ytLiveChatTickerItemBehavior.setContainerWidth() in _.dataChanged
  9776. if (typeof (this.ytLiveChatTickerItemBehavior || 0).setContainerWidth === 'function') {
  9777. try {
  9778. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  9779. return this.dataChanged544.call(this.__proxySelf0__);
  9780. } catch (e) {
  9781. console.log('dataChanged54500 ERROR');
  9782. console.error(e);
  9783. }
  9784. } else {
  9785. return this.dataChanged544();
  9786. }
  9787. },
  9788. dataChanged54501: function (a) {
  9789. // prevent memory leakage due to _.ytLiveChatTickerItemBehavior.setContainerWidth() in _.dataChanged
  9790. if (typeof (this.ytLiveChatTickerItemBehavior || 0).setContainerWidth === 'function') {
  9791. try {
  9792. if (!this.__proxySelf0__) this.__proxySelf0__ = weakWrap(this);
  9793. return this.dataChanged544.call(this.__proxySelf0__, a);
  9794. } catch (e) {
  9795. console.log('dataChanged54501 ERROR');
  9796. console.error(e);
  9797. }
  9798. } else {
  9799. return this.dataChanged544(a);
  9800. }
  9801. },
  9802. }
  9803.  
  9804. for (const sto of [
  9805. 'yt-live-chat-ticker-sponsor-item-renderer',
  9806. 'yt-live-chat-ticker-paid-sticker-item-renderer'
  9807. ].map(tag => [tag, customElements.whenDefined(tag)])) {
  9808.  
  9809. const [tag, promise] = sto;
  9810.  
  9811. promise.then(()=>{
  9812.  
  9813. const dummy = document.createElement(tag);
  9814.  
  9815. const cProto = getProto(dummy);
  9816. if (!cProto || !cProto.attached) {
  9817. console.warn(`proto.attached for ${tag} is unavailable.`);
  9818. return;
  9819. }
  9820.  
  9821. if (!cProto.dataChanged || cProto.dataChanged544 || typeof cProto.dataChanged !== 'function' || !(cProto.dataChanged.length >= 0 && cProto.dataChanged.length <= 1)) return;
  9822.  
  9823. cProto.dataChanged544 = cProto.dataChanged;
  9824.  
  9825. if (cProto.dataChanged.length === 0) cProto.dataChanged = dProto.dataChanged54500;
  9826. else if (cProto.dataChanged.length === 1) cProto.dataChanged = dProto.dataChanged54501;
  9827.  
  9828.  
  9829.  
  9830. })
  9831.  
  9832.  
  9833. }
  9834.  
  9835. }
  9836.  
  9837. customElements.whenDefined('yt-live-chat-ticker-renderer').then(() => {
  9838.  
  9839. mightFirstCheckOnYtInit();
  9840. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-ticker-renderer hacks");
  9841. console1.log("[Begin]");
  9842. (() => {
  9843.  
  9844. /* pending!!
  9845.  
  9846. handleLiveChatAction
  9847.  
  9848. removeTickerItemById
  9849.  
  9850. _itemsChanged
  9851. itemsChanged
  9852.  
  9853. handleMarkChatItemAsDeletedAction
  9854. handleMarkChatItemsByAuthorAsDeletedAction
  9855. handleRemoveChatItemByAuthorAction
  9856.  
  9857.  
  9858. */
  9859.  
  9860. const tag = "yt-live-chat-ticker-renderer"
  9861. const dummy = document.createElement(tag);
  9862.  
  9863. const cProto = getProto(dummy);
  9864. if (!cProto || !cProto.attached) {
  9865. console1.warn(`proto.attached for ${tag} is unavailable.`);
  9866. return;
  9867. }
  9868.  
  9869. if (FIX_REMOVE_TICKER_ITEM_BY_ID && typeof cProto.splice === 'function' && typeof cProto.markDirty === 'function' && typeof cProto.removeTickerItemById === 'function' && !cProto.removeTickerItemById737) {
  9870. cProto.removeTickerItemById737 = cProto.removeTickerItemById;
  9871. cProto.removeTickerItemById = function (a) {
  9872. // console.log('removeTickerItemById#01', a);
  9873. if (this.tickerItemsQuery !== '#ticker-items' || typeof (a || 0) !== 'string') return this.removeTickerItemById737(a);
  9874. // console.log('removeTickerItemById#02', a);
  9875. const hostElement = this.hostElement;
  9876. if (!hostElement || !a) return this.removeTickerItemById737(a);
  9877. // console.log('removeTickerItemById#03', a);
  9878. const arr = hostElement.querySelectorAll(`[id="${a}"]`);
  9879. const s = new Set();
  9880. if (typeof (a || 0) === 'string') s.add(a);
  9881. for (const elem of arr) {
  9882. if (!elem) continue;
  9883. const elemId = elem.id;
  9884. if (!elemId) continue;
  9885. s.add(elemId);
  9886. const data = (insp(elem).data || 0);
  9887. if (data) {
  9888. const u = data.id;
  9889. if (u) s.add(u);
  9890. else data.id = elemId;
  9891. }
  9892. }
  9893. const tickerItems = this.tickerItems;
  9894. let deleteCount = 0;
  9895. for (let i = tickerItems.length - 1; i >= 0; i--) {
  9896. const obj = tickerItems[i];
  9897. if (!obj || typeof obj !== 'object') continue;
  9898. const key = firstObjectKey(obj);
  9899. if (!key) continue;
  9900. const dataObj = obj[key];
  9901. const dataId = (dataObj || 0).id;
  9902. if (s.has(dataId)) {
  9903. this.splice("tickerItems", i, 1);
  9904. this.markDirty();
  9905. deleteCount++;
  9906. }
  9907. }
  9908. // console.log('removeTickerItemById#06', a, deleteCount);
  9909. s.has(this.highlightId) && (this.highlightId = void 0);
  9910. // console.log('removeTickerItemById#07', a, deleteCount);
  9911. }
  9912. }
  9913.  
  9914. // const imgCollection = document.getElementsByTagName('IMG');
  9915.  
  9916. if (ENABLE_TICKERS_BOOSTED_STAMPING && typeof cProto.notifyPath === 'function' && cProto.notifyPath.length === 2 && typeof cProto.stampDomArraySplices_ === 'function' && cProto.stampDomArraySplices_.length === 3 && !cProto.notifyPath371) {
  9917.  
  9918. rendererStamperFactory(cProto, {
  9919. key: 'proceedStampDomArraySplices371_',
  9920. stamperDomClass: 'style-scope yt-live-chat-ticker-renderer yt-live-chat-ticker-stampdom'
  9921. });
  9922.  
  9923. cProto.notifyPath371 = cProto.notifyPath;
  9924.  
  9925. // cProto.notifyPath = function (a, b) {
  9926. // // console.log(a, b);
  9927. // if (a === 'tickerItems.splices' && (b||0).indexSplices && !this.ec388) {
  9928. // const indexSplices = b.indexSplices;
  9929. // if (indexSplices.length === 1 || typeof indexSplices.length === "undefined") {
  9930. // const indexSplice = indexSplices[0] || indexSplices;
  9931. // if (indexSplice.type === 'splice' && (indexSplice.addedCount >= 1 || (indexSplice.removed || []).length >= 1)) {
  9932. // // console.log(1039, a, indexSplice);
  9933. // this.ec388 = true;
  9934. // const r = this.notifyPath371(a, b);
  9935. // this.ec388 = false;
  9936. // return r;
  9937. // }
  9938. // }
  9939. // }
  9940.  
  9941. // return this.notifyPath371(a, b);
  9942. // }
  9943.  
  9944. cProto.stampDomArraySplices371_ = cProto.stampDomArraySplices_;
  9945.  
  9946. cProto.stampDomArraySplices_ = function (a, b, c) {
  9947. if (a === 'tickerItems' && b === 'ticker-items' && (c || 0).indexSplices) {
  9948. // if (this.ec388) {
  9949. const indexSplices = c.indexSplices;
  9950. if (indexSplices.length === 1 || typeof indexSplices.length === "undefined") {
  9951. const indexSplice = indexSplices[0] || indexSplices;
  9952. if (indexSplice.type === 'splice' && (indexSplice.addedCount >= 1 || (indexSplice.removed || 0).length >= 1)) {
  9953. // console.log(1059, a, b, indexSplice);
  9954. if (this.proceedStampDomArraySplices371_(a, b, indexSplice)) return;
  9955. }
  9956. }
  9957. // } else {
  9958. // console.warn('stampDomArraySplices_ warning', ...arguments);
  9959. // }
  9960. }
  9961. return this.stampDomArraySplices371_(...arguments);
  9962. };
  9963.  
  9964. cProto.stampDomArray366_ = cProto.stampDomArray_;
  9965. cProto.stampDomArray_ = function (items, containerId, componentConfig, rxConfig, shouldCallback, isStableList) {
  9966. const isTickerRendering = items === this.tickerItems && containerId === 'ticker-items';
  9967. const isMessageListRendering = items === this.visibleItems && containerId === 'items';
  9968.  
  9969. if(!isTickerRendering && !isMessageListRendering){
  9970. console.log('stampDomArray_ warning 0xF501', ...arguments)
  9971. return this.stampDomArray366_(...arguments);
  9972. }
  9973.  
  9974. const container = (this.$ || 0)[containerId];
  9975. if (!container) {
  9976. console.log('stampDomArray_ warning 0xF502', ...arguments)
  9977. return this.stampDomArray366_(...arguments);
  9978. }
  9979.  
  9980. if (container[sFirstElementChild] === null && items.length === 0){
  9981.  
  9982. }else{
  9983. const cTag = isTickerRendering ? 'tickerItems' : 'visibleItems';
  9984. this.proceedStampDomArraySplices371_(cTag, containerId, {
  9985. addedCount: items.length,
  9986. removedCount: container.childElementCount
  9987. });
  9988. }
  9989.  
  9990. const f = () => {
  9991. this.markDirty && this.markDirty();
  9992. const detail = {
  9993. container
  9994. };
  9995. shouldCallback && this.hostElement.dispatchEvent(new CustomEvent("yt-rendererstamper-finished", {
  9996. bubbles: !0,
  9997. cancelable: !1,
  9998. composed: !0,
  9999. detail
  10000. }));
  10001. detail.container = null;
  10002. };
  10003. if (this.ec389pr) {
  10004. this.ec389pr.then(f)
  10005. } else {
  10006. f();
  10007. }
  10008.  
  10009. };
  10010.  
  10011. }
  10012.  
  10013.  
  10014.  
  10015. if(typeof cProto.createComponent_ === 'function' && cProto.createComponent_.length === 3 && !cProto.createComponent58_ ){
  10016.  
  10017. cProto.createComponent58_ = cProto.createComponent_;
  10018. cProto.createComponent_ = function (a, b, c) {
  10019.  
  10020. const z = customCreateComponent(a, b, c);
  10021. if (z !== undefined) return z;
  10022. const r = this.createComponent58_(a, b, c);
  10023. return r;
  10024.  
  10025. }
  10026.  
  10027. }
  10028.  
  10029.  
  10030.  
  10031.  
  10032.  
  10033.  
  10034.  
  10035.  
  10036. /* Dec 2024 */
  10037.  
  10038. /*
  10039.  
  10040.  
  10041. f.handleLiveChatActions = function(a) {
  10042. a.length && (a.forEach(this.handleLiveChatAction, this),
  10043. this.updateHighlightedItem(),
  10044. this.shouldAnimateIn = !0)
  10045. }
  10046. ;
  10047. f.handleLiveChatAction = function(a) {
  10048. var b = z(a, fL)
  10049. , c = z(a, gL)
  10050. , d = z(a, eL)
  10051. , e = z(a, gdb)
  10052. , g = z(a, rdb)
  10053. , k = z(a, Deb);
  10054. a = z(a, Ceb);
  10055. 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)
  10056. }
  10057. */
  10058.  
  10059.  
  10060. if(USE_ADVANCED_TICKING && !cProto.handleLiveChatActions47 && typeof cProto.handleLiveChatActions === 'function' && cProto.handleLiveChatActions.length ===1){
  10061.  
  10062. cProto.handleLiveChatActions47 = cProto.handleLiveChatActions;
  10063.  
  10064. cProto.handleLiveChatActions = function (a) {
  10065.  
  10066. // first loading in livestream. so this is required for sorting.
  10067.  
  10068. try{
  10069. preprocessChatLiveActions(a);
  10070. }catch(e){
  10071. console.warn(e);
  10072. }
  10073. return this.handleLiveChatActions47(a);
  10074.  
  10075. }
  10076.  
  10077. console1.log("USE_ADVANCED_TICKING::handleLiveChatActions - OK");
  10078.  
  10079. }else if(USE_ADVANCED_TICKING){
  10080.  
  10081.  
  10082. console1.log("USE_ADVANCED_TICKING::handleLiveChatActions - NG");
  10083.  
  10084. }
  10085.  
  10086. // yt-live-chat-ticker-renderer hacks
  10087.  
  10088.  
  10089. if (RAF_FIX_keepScrollClamped) {
  10090.  
  10091. // to be improved
  10092.  
  10093. if (typeof cProto.keepScrollClamped === 'function' && !cProto.keepScrollClamped72 && fnIntegrity(cProto.keepScrollClamped) === '0.17.10') {
  10094.  
  10095. cProto.keepScrollClamped72 = cProto.keepScrollClamped;
  10096. cProto.keepScrollClamped = function () {
  10097.  
  10098. const cnt = kRef(this);
  10099. if (!cnt) return;
  10100. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10101.  
  10102. cnt._bound_keepScrollClamped = cnt._bound_keepScrollClamped || cnt.keepScrollClamped.bind(mWeakRef(cnt));
  10103. cnt.scrollClampRaf = requestAnimationFrame(cnt._bound_keepScrollClamped);
  10104. cnt.maybeClampScroll()
  10105. }
  10106.  
  10107. console1.log('RAF_FIX: keepScrollClamped', tag, "OK")
  10108. } else {
  10109.  
  10110. assertor(() => fnIntegrity(cProto.keepScrollClamped, '0.17.10'));
  10111. console1.log('RAF_FIX: keepScrollClamped', tag, "NG")
  10112. }
  10113.  
  10114. }
  10115.  
  10116.  
  10117. if (RAF_FIX_scrollIncrementally && typeof cProto.startScrolling === 'function' && typeof cProto.scrollIncrementally === 'function'
  10118. && '|1.43.31|1.44.31|'.indexOf('|' + fnIntegrity(cProto.startScrolling) + '|') >= 0
  10119. && '|1.78.45|1.82.43|1.43.31|'.indexOf('|' + fnIntegrity(cProto.scrollIncrementally) + '|') >= 0) {
  10120. // to be replaced by animator
  10121.  
  10122. cProto.startScrolling = function (a) {
  10123.  
  10124. const cnt = kRef(this);
  10125. if (!cnt) return;
  10126. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10127.  
  10128. cnt.scrollStopHandle && cnt.cancelAsync(cnt.scrollStopHandle);
  10129. cnt.asyncHandle && cancelAnimationFrame(cnt.asyncHandle);
  10130. cnt.lastFrameTimestamp = cnt.scrollStartTime = performance.now();
  10131. cnt.scrollRatePixelsPerSecond = a;
  10132. cnt._bound_scrollIncrementally = cnt._bound_scrollIncrementally || cnt.scrollIncrementally.bind(mWeakRef(cnt));
  10133. cnt.asyncHandle = requestAnimationFrame(cnt._bound_scrollIncrementally)
  10134. };
  10135.  
  10136. // related functions: startScrollBack, startScrollingLeft, startScrollingRight, etc.
  10137.  
  10138. /**
  10139. *
  10140. * // 2024.12.17
  10141. * // https://www.youtube.com/s/desktop/f7495da0/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  10142.  
  10143. f.startScrolling = function(a) {
  10144. this.scrollStopHandle && $u(this.scrollStopHandle);
  10145. this.asyncHandle && window.cancelAnimationFrame(this.asyncHandle);
  10146. this.scrollStartTime = performance.now();
  10147. this.lastFrameTimestamp = performance.now();
  10148. this.scrollRatePixelsPerSecond = a;
  10149. this.asyncHandle = window.requestAnimationFrame(this.scrollIncrementally.bind(this))
  10150. }
  10151. ;
  10152. f.scrollIncrementally = function(a) {
  10153. var b = a - (this.lastFrameTimestamp || 0);
  10154. R(this.hostElement).querySelector(this.tickerBarQuery).scrollLeft += b / 1E3 * (this.scrollRatePixelsPerSecond || 0);
  10155. this.maybeClampScroll();
  10156. this.updateArrows();
  10157. this.lastFrameTimestamp = a;
  10158. R(this.hostElement).querySelector(this.tickerBarQuery).scrollLeft > 0 || this.scrollRatePixelsPerSecond && this.scrollRatePixelsPerSecond > 0 ? this.asyncHandle = window.requestAnimationFrame(this.scrollIncrementally.bind(this)) : this.stopScrolling()
  10159. }
  10160. ;
  10161. *
  10162. */
  10163.  
  10164. /**
  10165. *
  10166. // 2024.12.20
  10167.  
  10168.  
  10169.  
  10170. f.startScrolling = function(a) {
  10171. this.scrollStopHandle && av(this.scrollStopHandle);
  10172. this.asyncHandle && window.cancelAnimationFrame(this.asyncHandle);
  10173. this.scrollStartTime = performance.now();
  10174. this.lastFrameTimestamp = performance.now();
  10175. this.scrollRatePixelsPerSecond = a;
  10176. this.asyncHandle = window.requestAnimationFrame(this.scrollIncrementally.bind(this))
  10177. }
  10178.  
  10179. *
  10180. *
  10181. */
  10182.  
  10183. cProto.__getTickerBarQuery__ = function () {
  10184. const tickerBarQuery = this.tickerBarQuery === '#items' ? this.$.items : this.hostElement.querySelector(this.tickerBarQuery);
  10185. return tickerBarQuery;
  10186. }
  10187.  
  10188. cProto.scrollIncrementally = (RAF_FIX_scrollIncrementally === 2) ? function (a) {
  10189.  
  10190. const cnt = kRef(this);
  10191. if (!cnt) return;
  10192. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10193.  
  10194. const b = a - (cnt.lastFrameTimestamp || 0);
  10195. const rate = cnt.scrollRatePixelsPerSecond
  10196. const q = b / 1E3 * (rate || 0);
  10197.  
  10198. const tickerBarQuery = cnt.__getTickerBarQuery__();
  10199. if (!tickerBarQuery) return; // memory leakage. to be reviewed
  10200. const sl = tickerBarQuery.scrollLeft;
  10201. // console.log(rate, sl, q)
  10202. if (cnt.lastFrameTimestamp == cnt.scrollStartTime) {
  10203.  
  10204. } else if (q > -1e-5 && q < 1e-5) {
  10205.  
  10206. } else {
  10207. let cond1 = sl > 0 && rate > 0 && q > 0;
  10208. let cond2 = sl > 0 && rate < 0 && q < 0;
  10209. let cond3 = sl < 1e-5 && sl > -1e-5 && rate > 0 && q > 0;
  10210. if (cond1 || cond2 || cond3) {
  10211. tickerBarQuery.scrollLeft += q;
  10212. cnt.maybeClampScroll();
  10213. cnt.updateArrows();
  10214. }
  10215. }
  10216.  
  10217. cnt.lastFrameTimestamp = a;
  10218. cnt._bound_scrollIncrementally = cnt._bound_scrollIncrementally || cnt.scrollIncrementally.bind(mWeakRef(cnt));
  10219. 0 < tickerBarQuery.scrollLeft || rate && 0 < rate ? cnt.asyncHandle = requestAnimationFrame(cnt._bound_scrollIncrementally) : cnt.stopScrolling()
  10220. } : function (a) {
  10221.  
  10222. const cnt = kRef(this);
  10223. if (!cnt) return;
  10224. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10225.  
  10226. const b = a - (cnt.lastFrameTimestamp || 0);
  10227. const tickerBarQuery = cnt.__getTickerBarQuery__();
  10228. if (!tickerBarQuery) return; // memory leakage. to be reviewed
  10229. tickerBarQuery.scrollLeft += b / 1E3 * (cnt.scrollRatePixelsPerSecond || 0);
  10230. cnt.maybeClampScroll();
  10231. cnt.updateArrows();
  10232. cnt.lastFrameTimestamp = a;
  10233. cnt._bound_scrollIncrementally = cnt._bound_scrollIncrementally || cnt.scrollIncrementally.bind(mWeakRef(cnt));
  10234. 0 < tickerBarQuery.scrollLeft || cnt.scrollRatePixelsPerSecond && 0 < cnt.scrollRatePixelsPerSecond ? cnt.asyncHandle = requestAnimationFrame(cnt._bound_scrollIncrementally) : cnt.stopScrolling()
  10235. };
  10236.  
  10237. console1.log(`RAF_FIX: scrollIncrementally${RAF_FIX_scrollIncrementally}`, tag, "OK")
  10238. } else {
  10239. assertor(() => fnIntegrity(cProto.startScrolling, '1.43.31'))
  10240. || logFn('cProto.startScrolling', cProto.startScrolling)();
  10241. assertor(() => fnIntegrity(cProto.scrollIncrementally, '1.78.45'))
  10242. || logFn('cProto.scrollIncrementally', cProto.scrollIncrementally)();
  10243. console1.log('RAF_FIX: scrollIncrementally', tag, "NG")
  10244. }
  10245.  
  10246.  
  10247. if (CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED && typeof cProto.attached === 'function' && !cProto.attached37 && typeof cProto.detached === 'function' && !cProto.detached37) {
  10248.  
  10249. cProto.attached37 = cProto.attached;
  10250. cProto.detached37 = cProto.detached;
  10251.  
  10252. let naohzId = 0;
  10253. cProto.__naohzId__ = 0;
  10254. cProto.attached = function () {
  10255. Promise.resolve(this).then((cnt) => {
  10256.  
  10257. const hostElement = cnt.hostElement || cnt;
  10258. if (!(hostElement instanceof HTMLElement_)) return;
  10259. if (!HTMLElement_.prototype.matches.call(hostElement, '.yt-live-chat-renderer')) return;
  10260. const ironPage = HTMLElement_.prototype.closest.call(hostElement, 'iron-pages.yt-live-chat-renderer');
  10261. // or #chat-messages
  10262. if (!ironPage) return;
  10263.  
  10264. if (cnt.__naohzId__) removeEventListener.call(ironPage, 'click', cnt.messageBoxClickHandlerForFade, { capture: false, passive: true });
  10265. cnt.__naohzId__ = naohzId = (naohzId & 1073741823) + 1;
  10266. ironPage.setAttribute('naohz', `${+cnt.__naohzId__}`);
  10267.  
  10268. addEventListener.call(ironPage, 'click', cnt.messageBoxClickHandlerForFade, { capture: false, passive: true });
  10269.  
  10270. cnt = null;
  10271.  
  10272. });
  10273. return this.attached37.apply(this, arguments);
  10274. };
  10275. cProto.detached = function () {
  10276. Promise.resolve(this).then((cnt) => {
  10277.  
  10278. const ironPage = document.querySelector(`iron-pages[naohz="${+cnt.__naohzId__}"]`);
  10279. if (!ironPage) return;
  10280.  
  10281. removeEventListener.call(ironPage, 'click', cnt.messageBoxClickHandlerForFade, { capture: false, passive: true });
  10282.  
  10283. cnt = null;
  10284.  
  10285. });
  10286. return this.detached37.apply(this, arguments);
  10287. };
  10288.  
  10289. const clickFade = (u) => {
  10290. u.click();
  10291. };
  10292. cProto.messageBoxClickHandlerForFade = async (evt) => {
  10293.  
  10294. const target = (evt || 0).target || 0;
  10295. if (!target) return;
  10296.  
  10297. for (let p = target; p instanceof HTMLElement_; p = nodeParent(p)) {
  10298. const is = p.is;
  10299. if (typeof is === 'string' && is) {
  10300.  
  10301. if (is === 'yt-live-chat-pinned-message-renderer') {
  10302. return;
  10303. }
  10304. if (is === 'iron-pages' || is === 'yt-live-chat-renderer' || is === 'yt-live-chat-app') {
  10305. const fade = HTMLElement_.prototype.querySelector.call(p, 'yt-live-chat-pinned-message-renderer:not([hidden]) #fade');
  10306. if (fade) {
  10307. Promise.resolve(fade).then(clickFade);
  10308. evt && evt.stopPropagation();
  10309. }
  10310. return;
  10311. }
  10312. if (is !== 'yt-live-chat-ticker-renderer') {
  10313. if (is.startsWith('yt-live-chat-ticker-')) return;
  10314. if (!is.endsWith('-renderer')) return;
  10315. }
  10316.  
  10317. } else {
  10318. if ((p.nodeName || '').includes('BUTTON')) return;
  10319. }
  10320.  
  10321. }
  10322. };
  10323.  
  10324. console1.log("CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED - OK")
  10325.  
  10326. } else {
  10327. console1.log("CLOSE_TICKER_PINNED_MESSAGE_WHEN_HEADER_CLICKED - NG")
  10328. }
  10329.  
  10330.  
  10331. })();
  10332.  
  10333. console1.log("[End]");
  10334.  
  10335. groupEnd();
  10336.  
  10337. }).catch(console.warn);
  10338.  
  10339.  
  10340.  
  10341. if (ENABLE_RAF_HACK_INPUT_RENDERER || DELAY_FOCUSEDCHANGED) {
  10342.  
  10343. customElements.whenDefined("yt-live-chat-message-input-renderer").then(() => {
  10344.  
  10345. mightFirstCheckOnYtInit();
  10346. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-message-input-renderer hacks");
  10347. console1.log("[Begin]");
  10348. (() => {
  10349.  
  10350.  
  10351.  
  10352. const tag = "yt-live-chat-message-input-renderer"
  10353. const dummy = document.createElement(tag);
  10354.  
  10355. const cProto = getProto(dummy);
  10356. if (!cProto || !cProto.attached) {
  10357. console1.warn(`proto.attached for ${tag} is unavailable.`);
  10358. return;
  10359. }
  10360.  
  10361.  
  10362. if (ENABLE_RAF_HACK_INPUT_RENDERER && rafHub !== null) {
  10363.  
  10364. let doHack = false;
  10365. if (typeof cProto.handleTimeout === 'function' && typeof cProto.updateTimeout === 'function') {
  10366.  
  10367. // not cancellable
  10368.  
  10369. // <<< to be reviewed cProto.updateTimeout --- isTimingFunctionHackable -- doHack >>>
  10370.  
  10371. doHack = fnIntegrity(cProto.handleTimeout, '1.27.16') && fnIntegrity(cProto.updateTimeout, '1.50.33');
  10372.  
  10373. if (!doHack) console1.log('doHack = false')
  10374.  
  10375. }
  10376. // doHack = false; // M55
  10377.  
  10378. if (doHack) {
  10379.  
  10380. cProto.handleTimeout = function (a) {
  10381.  
  10382. const cnt = kRef(this);
  10383. if (!cnt) return;
  10384. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10385.  
  10386. console.log('cProto.handleTimeout', tag)
  10387. if (!cnt.boundUpdateTimeout38_) cnt.boundUpdateTimeout38_ = cnt.updateTimeout.bind(mWeakRef(cnt));
  10388. cnt.timeoutDurationMs = cnt.timeoutMs = a;
  10389. cnt.countdownRatio = 1;
  10390. 0 === cnt.lastTimeoutTimeMs && rafHub.request(cnt.boundUpdateTimeout38_)
  10391. };
  10392. cProto.updateTimeout = function (a) {
  10393.  
  10394. const cnt = kRef(this);
  10395. if (!cnt) return;
  10396. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10397.  
  10398. console.log('cProto.updateTimeout', tag)
  10399. if (!cnt.boundUpdateTimeout38_) cnt.boundUpdateTimeout38_ = cnt.updateTimeout.bind(mWeakRef(cnt));
  10400. cnt.lastTimeoutTimeMs && (cnt.timeoutMs = Math.max(0, cnt.timeoutMs - (a - cnt.lastTimeoutTimeMs)),
  10401. cnt.countdownRatio = cnt.timeoutMs / cnt.timeoutDurationMs);
  10402. cnt.isAttached && cnt.timeoutMs ? (cnt.lastTimeoutTimeMs = a,
  10403. rafHub.request(cnt.boundUpdateTimeout38_)) : cnt.lastTimeoutTimeMs = 0
  10404. };
  10405.  
  10406. console1.log('RAF_HACK_INPUT_RENDERER', tag, "OK")
  10407. } else {
  10408.  
  10409. console1.log('typeof handleTimeout', typeof cProto.handleTimeout)
  10410. console1.log('typeof updateTimeout', typeof cProto.updateTimeout)
  10411.  
  10412. console1.log('RAF_HACK_INPUT_RENDERER', tag, "NG")
  10413. }
  10414.  
  10415.  
  10416. }
  10417.  
  10418. if (DELAY_FOCUSEDCHANGED && typeof cProto.onFocusedChanged === 'function' && cProto.onFocusedChanged.length === 1 && !cProto.onFocusedChanged372) {
  10419. cProto.onFocusedChanged372 = cProto.onFocusedChanged;
  10420. cProto.onFocusedChanged = function (a) {
  10421. Promise.resolve(this).then((cnt) => {
  10422. if (cnt.isAttached === true) cnt.onFocusedChanged372(a);
  10423. cnt = null;
  10424. }).catch(console.warn);
  10425. }
  10426. }
  10427.  
  10428. })();
  10429.  
  10430. console1.log("[End]");
  10431.  
  10432. groupEnd();
  10433.  
  10434.  
  10435. })
  10436.  
  10437. }
  10438.  
  10439.  
  10440. if (ENABLE_RAF_HACK_EMOJI_PICKER && rafHub !== null) {
  10441.  
  10442. customElements.whenDefined("yt-emoji-picker-renderer").then(() => {
  10443.  
  10444. mightFirstCheckOnYtInit();
  10445. groupCollapsed("YouTube Super Fast Chat", " | yt-emoji-picker-renderer hacks");
  10446. console1.log("[Begin]");
  10447. (() => {
  10448.  
  10449. const tag = "yt-emoji-picker-renderer"
  10450. const dummy = document.createElement(tag);
  10451.  
  10452. const cProto = getProto(dummy);
  10453. if (!cProto || !cProto.attached) {
  10454. console1.warn(`proto.attached for ${tag} is unavailable.`);
  10455. return;
  10456. }
  10457.  
  10458. let doHack = false;
  10459. if (typeof cProto.animateScroll_ === 'function') {
  10460.  
  10461. // not cancellable
  10462. console1.log('animateScroll_: function - OK')
  10463.  
  10464. doHack = fnIntegrity(cProto.animateScroll_, '1.102.49')
  10465.  
  10466. } else {
  10467.  
  10468. console1.log('animateScroll_', typeof cProto.animateScroll_)
  10469. }
  10470.  
  10471. if (doHack) {
  10472.  
  10473. const querySelector = HTMLElement_.prototype.querySelector;
  10474. const U = (element) => ({
  10475. querySelector: (selector) => querySelector.call(element, selector)
  10476. });
  10477.  
  10478. cProto.animateScroll_ = function (a) {
  10479.  
  10480. const cnt = kRef(this);
  10481. if (!cnt) return;
  10482. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10483.  
  10484. // console.log('cProto.animateScroll_', tag) // yt-emoji-picker-renderer
  10485. if (!cnt.boundAnimateScroll39_) cnt.boundAnimateScroll39_ = cnt.animateScroll_.bind(mWeakRef(cnt));
  10486. cnt.lastAnimationTime_ || (cnt.lastAnimationTime_ = a);
  10487. a -= cnt.lastAnimationTime_;
  10488. 200 > a ? (U(cnt.hostElement).querySelector("#categories").scrollTop = cnt.animationStart_ + (cnt.animationEnd_ - cnt.animationStart_) * a / 200,
  10489. rafHub.request(cnt.boundAnimateScroll39_)) : (null != cnt.animationEnd_ && (U(cnt.hostElement).querySelector("#categories").scrollTop = cnt.animationEnd_),
  10490. cnt.animationEnd_ = cnt.animationStart_ = null,
  10491. cnt.lastAnimationTime_ = 0);
  10492. cnt.updateButtons_()
  10493. }
  10494.  
  10495. console1.log('ENABLE_RAF_HACK_EMOJI_PICKER', tag, "OK")
  10496. } else {
  10497.  
  10498. console1.log('ENABLE_RAF_HACK_EMOJI_PICKER', tag, "NG")
  10499. }
  10500.  
  10501. })();
  10502.  
  10503. console1.log("[End]");
  10504.  
  10505. groupEnd();
  10506. });
  10507. }
  10508.  
  10509. if (ENABLE_RAF_HACK_DOCKED_MESSAGE && rafHub !== null) {
  10510.  
  10511. customElements.whenDefined("yt-live-chat-docked-message").then(() => {
  10512.  
  10513. mightFirstCheckOnYtInit();
  10514. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-docked-message hacks");
  10515. console1.log("[Begin]");
  10516. (() => {
  10517.  
  10518. const tag = "yt-live-chat-docked-message"
  10519. const dummy = document.createElement(tag);
  10520.  
  10521. const cProto = getProto(dummy);
  10522. if (!cProto || !cProto.attached) {
  10523. console1.warn(`proto.attached for ${tag} is unavailable.`);
  10524. return;
  10525. }
  10526.  
  10527. let doHack = false;
  10528. if (typeof cProto.detached === 'function' && typeof cProto.checkIntersections === 'function' && typeof cProto.onDockableMessagesChanged === 'function' && typeof cProto.boundCheckIntersections === 'undefined') {
  10529.  
  10530. // cancelable - this.intersectRAF <detached>
  10531. // yt-live-chat-docked-message
  10532. // boundCheckIntersections <-> checkIntersections
  10533. // onDockableMessagesChanged
  10534. // this.intersectRAF = window.requestAnimationFrame(this.boundCheckIntersections);
  10535.  
  10536. console1.log(`detached: function - OK`)
  10537. console1.log('checkIntersections: function - OK')
  10538. console1.log('onDockableMessagesChanged: function - OK')
  10539.  
  10540. doHack = fnIntegrity(cProto.detached, '0.32.22') && fnIntegrity(cProto.checkIntersections, '0.128.85') && fnIntegrity(cProto.onDockableMessagesChanged, '0.20.11')
  10541.  
  10542. } else {
  10543.  
  10544. console1.log('detached', typeof cProto.detached, 'NG')
  10545. console1.log('checkIntersections', typeof cProto.checkIntersections, 'NG')
  10546. console1.log('onDockableMessagesChanged', typeof cProto.onDockableMessagesChanged, 'NG')
  10547. }
  10548.  
  10549. if (doHack) {
  10550.  
  10551. cProto.__boundCheckIntersectionsSubstitutionFn__ = function () {
  10552. const cnt = this;
  10553. if (!cnt.i5zmk && typeof cnt.boundCheckIntersections === 'function' && typeof cnt.checkIntersections === 'function') {
  10554. cnt.i5zmk = 1
  10555. cnt.boundCheckIntersections = cnt.checkIntersections.bind(mWeakRef(cnt));
  10556. }
  10557. }
  10558.  
  10559. cProto.checkIntersections = function () {
  10560.  
  10561. const cnt = kRef(this);
  10562. if (!cnt) return;
  10563. if (!cnt.hostElement) return; // memory leakage. to be reviewed
  10564.  
  10565. if(typeof cnt.__boundCheckIntersectionsSubstitutionFn__ === 'function') cnt.__boundCheckIntersectionsSubstitutionFn__();
  10566.  
  10567. // console.log('cProto.checkIntersections', tag)
  10568. if (cnt.dockableMessages.length) {
  10569. cnt.intersectRAF = rafHub.request(cnt.boundCheckIntersections);
  10570. let a = cnt.dockableMessages[0]
  10571. , b = cnt.hostElement.getBoundingClientRect();
  10572. a = a.getBoundingClientRect();
  10573. let c = a.top - b.top
  10574. , d = 8 >= c;
  10575. c = 8 >= c - cnt.hostElement.clientHeight;
  10576. if (d) {
  10577. let e;
  10578. for (; d;) {
  10579. e = cnt.dockableMessages.shift();
  10580. d = cnt.dockableMessages[0];
  10581. if (!d)
  10582. break;
  10583. d = d.getBoundingClientRect();
  10584. c = d.top - b.top;
  10585. let f = 8 >= c;
  10586. if (8 >= c - a.height)
  10587. if (f)
  10588. a = d;
  10589. else
  10590. return;
  10591. d = f
  10592. }
  10593. cnt.dock(e)
  10594. } else
  10595. c && cnt.dockedItem && cnt.clear()
  10596. } else
  10597. cnt.intersectRAF = 0
  10598. }
  10599.  
  10600. cProto.onDockableMessagesChanged = function () {
  10601. const cnt = this;
  10602. if(typeof cnt.__boundCheckIntersectionsSubstitutionFn__ === 'function') cnt.__boundCheckIntersectionsSubstitutionFn__();
  10603. // console.log('cProto.onDockableMessagesChanged', tag) // yt-live-chat-docked-message
  10604. cnt.dockableMessages.length && !cnt.intersectRAF && (cnt.intersectRAF = rafHub.request(cnt.boundCheckIntersections))
  10605. }
  10606.  
  10607. cProto.detached = function () {
  10608. this.intersectRAF && rafHub.cancel(this.intersectRAF)
  10609. }
  10610.  
  10611. console1.log('ENABLE_RAF_HACK_DOCKED_MESSAGE', tag, "OK")
  10612. } else {
  10613.  
  10614. console1.log('ENABLE_RAF_HACK_DOCKED_MESSAGE', tag, "NG")
  10615. }
  10616.  
  10617. })();
  10618.  
  10619. console1.log("[End]");
  10620.  
  10621. groupEnd();
  10622.  
  10623. }).catch(console.warn);
  10624.  
  10625. }
  10626.  
  10627. if (FIX_SETSRC_AND_THUMBNAILCHANGE_) {
  10628.  
  10629. customElements.whenDefined("yt-img-shadow").then(() => {
  10630.  
  10631. mightFirstCheckOnYtInit();
  10632. groupCollapsed("YouTube Super Fast Chat", " | yt-img-shadow hacks");
  10633. console1.log("[Begin]");
  10634. (() => {
  10635.  
  10636. const tag = "yt-img-shadow"
  10637. const dummy = document.createElement(tag);
  10638.  
  10639. const cProto = getProto(dummy);
  10640. if (!cProto || !cProto.attached) {
  10641. console1.warn(`proto.attached for ${tag} is unavailable.`);
  10642. return;
  10643. }
  10644.  
  10645. if (typeof cProto.thumbnailChanged_ === 'function' && !cProto.thumbnailChanged66_) {
  10646.  
  10647. cProto.thumbnailChanged66_ = cProto.thumbnailChanged_;
  10648. cProto.thumbnailChanged_ = function (a) {
  10649.  
  10650. if (this.oldThumbnail_ && this.thumbnail && this.oldThumbnail_.thumbnails === this.thumbnail.thumbnails) return;
  10651. if (!this.oldThumbnail_ && !this.thumbnail) return;
  10652.  
  10653. return this.thumbnailChanged66_.apply(this, arguments)
  10654.  
  10655. }
  10656. console1.log("cProto.thumbnailChanged_ - OK");
  10657.  
  10658. } else {
  10659. console1.log("cProto.thumbnailChanged_ - NG");
  10660.  
  10661. }
  10662. if (typeof cProto.setSrc_ === 'function' && !cProto.setSrc66_) {
  10663.  
  10664. cProto.setSrc66_ = cProto.setSrc_;
  10665. cProto.setSrc_ = function (a) {
  10666. if ((((this || 0).$ || 0).img || 0).src === a) return;
  10667. return this.setSrc66_.apply(this, arguments)
  10668. }
  10669.  
  10670. console1.log("cProto.setSrc_ - OK");
  10671. } else {
  10672.  
  10673. console1.log("cProto.setSrc_ - NG");
  10674. }
  10675.  
  10676. })();
  10677.  
  10678. console1.log("[End]");
  10679.  
  10680. groupEnd();
  10681.  
  10682. }).catch(console.warn);
  10683.  
  10684. }
  10685.  
  10686. if (FIX_THUMBNAIL_DATACHANGED) {
  10687.  
  10688. customElements.whenDefined("yt-live-chat-author-badge-renderer").then(() => {
  10689.  
  10690. mightFirstCheckOnYtInit();
  10691. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-author-badge-renderer hacks");
  10692. console1.log("[Begin]");
  10693. (() => {
  10694.  
  10695. const tag = "yt-live-chat-author-badge-renderer"
  10696. const dummy = document.createElement(tag);
  10697.  
  10698. const cProto = getProto(dummy);
  10699. if (!cProto || !cProto.attached) {
  10700. console1.warn(`proto.attached for ${tag} is unavailable.`);
  10701. return;
  10702. }
  10703.  
  10704. if (typeof cProto.dataChanged === 'function' && !cProto.dataChanged86 && '|0.169.106|'.includes(`|${fnIntegrity(cProto.dataChanged)}|`)) {
  10705.  
  10706. cProto.dataChanged86 = cProto.dataChanged;
  10707. cProto.dataChanged = function () {
  10708.  
  10709. /* 2024.12.15 */
  10710. /*
  10711. zO.prototype.dataChanged = function() {
  10712. for (var a = Ov(R(this.hostElement).querySelector("#image")); a.firstChild; )
  10713. a.removeChild(a.firstChild);
  10714. if (this.data)
  10715. if (this.data.icon) {
  10716. var b = document.createElement("yt-icon");
  10717. this.data.icon.iconType === "MODERATOR" && this.enableNewModeratorBadge ? (b.polymerController.icon = "yt-sys-icons:shield-filled",
  10718. b.polymerController.defaultToFilled = !0) : b.polymerController.icon = "live-chat-badges:" + this.data.icon.iconType.toLowerCase();
  10719. a.appendChild(b)
  10720. } else if (this.data.customThumbnail) {
  10721. b = document.createElement("img");
  10722. var c;
  10723. (c = (c = UA(this.data.customThumbnail.thumbnails, 16)) ? Yb(kc(c)) : null) ? (b.src = c,
  10724. a.appendChild(b),
  10725. b.setAttribute("alt", this.hostElement.ariaLabel || "")) : Fq(new Zn("Could not compute URL for thumbnail",this.data.customThumbnail))
  10726. }
  10727. }
  10728. */
  10729.  
  10730. const a = (this || 0).data;
  10731. const image = ((this || 0).$ || 0).image;
  10732. if (image && a && image.firstElementChild) {
  10733. const exisiting = image.firstElementChild;
  10734. if (exisiting === image.lastElementChild) {
  10735.  
  10736. if (a.icon && exisiting.nodeName.toUpperCase() === 'YT-ICON') {
  10737.  
  10738. const c = exisiting;
  10739. const t = insp(c);
  10740. const w = ('icon' in t || 'defaultToFilled' in t) ? t : c;
  10741. if ("MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge) {
  10742. if (w.icon !== "yt-sys-icons:shield-filled") w.icon = "yt-sys-icons:shield-filled";
  10743. if (w.defaultToFilled !== true) w.defaultToFilled = true;
  10744. } else {
  10745. const p = "live-chat-badges:" + a.icon.iconType.toLowerCase();;
  10746. if (w.icon !== p) w.icon = p;
  10747. if (w.defaultToFilled !== false) w.defaultToFilled = false;
  10748. }
  10749. return;
  10750.  
  10751.  
  10752. } else if (a.customThumbnail && exisiting.nodeName.toUpperCase() == 'IMG') {
  10753.  
  10754. const c = exisiting;
  10755. if (a.customThumbnail.thumbnails.map(e => e.url).includes(c.src)) {
  10756.  
  10757. c.setAttribute("alt", this.hostElement.ariaLabel || "");
  10758. return;
  10759. }
  10760. /*
  10761.  
  10762. var d;
  10763. (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null) ? (c.src = d,
  10764.  
  10765. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : lq(new tm("Could not compute URL for thumbnail", a.customThumbnail))
  10766. */
  10767. }
  10768.  
  10769. }
  10770. }
  10771. return this.dataChanged86.apply(this, arguments)
  10772.  
  10773. }
  10774. console1.log("cProto.dataChanged - OK");
  10775.  
  10776. } else if (typeof cProto.dataChanged === 'function' && !cProto.dataChanged86 && '|1.163.100|1.162.100|1.160.97|1.159.97|'.includes(`|${fnIntegrity(cProto.dataChanged)}|`)) {
  10777.  
  10778. cProto.dataChanged86 = cProto.dataChanged;
  10779. cProto.dataChanged = function (a) {
  10780.  
  10781. /*
  10782.  
  10783. for (var b = xC(Z(this.hostElement).querySelector("#image")); b.firstChild; )
  10784. b.removeChild(b.firstChild);
  10785. if (a)
  10786. if (a.icon) {
  10787. var c = document.createElement("yt-icon");
  10788. "MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge ? (c.icon = "yt-sys-icons:shield-filled",
  10789. c.defaultToFilled = !0) : c.icon = "live-chat-badges:" + a.icon.iconType.toLowerCase();
  10790. b.appendChild(c)
  10791. } else if (a.customThumbnail) {
  10792. c = document.createElement("img");
  10793. var d;
  10794. (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null) ? (c.src = d,
  10795. b.appendChild(c),
  10796. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : lq(new tm("Could not compute URL for thumbnail",a.customThumbnail))
  10797. }
  10798.  
  10799. */
  10800.  
  10801.  
  10802. /* 2024.04.20 */
  10803. /*
  10804. for (var b = Tx(N(this.hostElement).querySelector("#image")); b.firstChild; )
  10805. b.removeChild(b.firstChild);
  10806. if (a)
  10807. if (a.icon) {
  10808. var c = document.createElement("yt-icon");
  10809. "MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge ? (c.polymerController.icon = "yt-sys-icons:shield-filled",
  10810. c.polymerController.defaultToFilled = !0) : c.polymerController.icon = "live-chat-badges:" + a.icon.iconType.toLowerCase();
  10811. b.appendChild(c)
  10812. } else if (a.customThumbnail) {
  10813. c = document.createElement("img");
  10814. var d;
  10815. (d = (d = WD(a.customThumbnail.thumbnails, 16)) ? Sb(ec(d)) : null) ? (c.src = d,
  10816. b.appendChild(c),
  10817. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : nr(new mn("Could not compute URL for thumbnail",a.customThumbnail))
  10818. }
  10819. */
  10820.  
  10821. const image = ((this || 0).$ || 0).image
  10822. if (image && a && image.firstElementChild) {
  10823. const exisiting = image.firstElementChild;
  10824. if (exisiting === image.lastElementChild) {
  10825.  
  10826. if (a.icon && exisiting.nodeName.toUpperCase() === 'YT-ICON') {
  10827.  
  10828. const c = exisiting;
  10829. const t = insp(c);
  10830. const w = ('icon' in t || 'defaultToFilled' in t) ? t : c;
  10831. if ("MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge) {
  10832. if (w.icon !== "yt-sys-icons:shield-filled") w.icon = "yt-sys-icons:shield-filled";
  10833. if (w.defaultToFilled !== true) w.defaultToFilled = true;
  10834. } else {
  10835. const p = "live-chat-badges:" + a.icon.iconType.toLowerCase();;
  10836. if (w.icon !== p) w.icon = p;
  10837. if (w.defaultToFilled !== false) w.defaultToFilled = false;
  10838. }
  10839. return;
  10840.  
  10841.  
  10842. } else if (a.customThumbnail && exisiting.nodeName.toUpperCase() == 'IMG') {
  10843.  
  10844. const c = exisiting;
  10845. if (a.customThumbnail.thumbnails.map(e => e.url).includes(c.src)) {
  10846.  
  10847. c.setAttribute("alt", this.hostElement.ariaLabel || "");
  10848. return;
  10849. }
  10850. /*
  10851.  
  10852. var d;
  10853. (d = (d = KC(a.customThumbnail.thumbnails, 16)) ? lc(oc(d)) : null) ? (c.src = d,
  10854.  
  10855. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : lq(new tm("Could not compute URL for thumbnail", a.customThumbnail))
  10856. */
  10857. }
  10858.  
  10859. }
  10860. }
  10861. return this.dataChanged86.apply(this, arguments)
  10862.  
  10863. }
  10864. console1.log("cProto.dataChanged - OK");
  10865.  
  10866. } else {
  10867. assertor(() => fnIntegrity(cProto.dataChanged, '0.169.106'));
  10868. console1.log("cProto.dataChanged - NG");
  10869.  
  10870. }
  10871.  
  10872. })();
  10873.  
  10874. console1.log("[End]");
  10875.  
  10876. groupEnd();
  10877.  
  10878. }).catch(console.warn);
  10879.  
  10880.  
  10881. }
  10882.  
  10883. if (USE_ADVANCED_TICKING) {
  10884. // leading the emoji cannot be rendered.
  10885.  
  10886. // const qz38 = lcrPromiseFn();
  10887.  
  10888. // qz38.then((lcrGet) => {
  10889.  
  10890. // const tag = "yt-live-chat-renderer"
  10891. // const dummy = lcrGet();
  10892.  
  10893. const lcrFn2 = (lcrDummy) => {
  10894.  
  10895. const tag = "yt-live-chat-renderer"
  10896. const dummy = lcrDummy;
  10897.  
  10898.  
  10899. const cProto = getProto(dummy);
  10900.  
  10901. // dummy.usePatchedLifecycles = false;
  10902. // dummy.data = null;
  10903. // dummy.__data = null;
  10904. // Object.setPrototypeOf(dummy, Object.prototype);
  10905. if (!cProto || !cProto.attached) {
  10906. console.warn(`proto.attached for ${tag} is unavailable.`);
  10907. return;
  10908. }
  10909.  
  10910. /*
  10911. <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;
  10912. */
  10913.  
  10914. if (cProto && typeof cProto.immediatelyApplyLiveChatActions === 'function' && cProto.immediatelyApplyLiveChatActions.length === 1 && !cProto.immediatelyApplyLiveChatActions82) {
  10915. cProto.immediatelyApplyLiveChatActions82 = cProto.immediatelyApplyLiveChatActions;
  10916. cProto.immediatelyApplyLiveChatActions = function (arr) {
  10917.  
  10918.  
  10919. // console.log(1237)
  10920. try {
  10921. preprocessChatLiveActions(arr);
  10922. } catch (e) {
  10923. console.warn(e);
  10924. }
  10925. return this.immediatelyApplyLiveChatActions82(arr);
  10926. };
  10927. }
  10928.  
  10929.  
  10930. if (cProto && typeof cProto.preprocessActions_ === 'function' && cProto.preprocessActions_.length === 1 && !cProto.preprocessActions82_) {
  10931. cProto.preprocessActions82_ = cProto.preprocessActions_;
  10932. cProto.preprocessActions_ = function (arr) {
  10933.  
  10934. const ct_ = Date.now();
  10935.  
  10936. arr = this.preprocessActions82_(arr);
  10937.  
  10938. try {
  10939. preprocessChatLiveActions(arr, ct_);
  10940. } catch (e) {
  10941. console.warn(e);
  10942. }
  10943. return arr;
  10944. };
  10945. }
  10946.  
  10947.  
  10948.  
  10949. };
  10950. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  10951. getLCRDummy().then(lcrFn2);
  10952. }
  10953.  
  10954. if (MODIFY_EMIT_MESSAGES_FOR_BOOST_CHAT) {
  10955.  
  10956. const lcrFn2 = (lcrDummy) => {
  10957.  
  10958. const tag = "yt-live-chat-renderer"
  10959. const dummy = lcrDummy;
  10960.  
  10961.  
  10962. const cProto = getProto(dummy);
  10963.  
  10964. // dummy.usePatchedLifecycles = false;
  10965. // dummy.data = null;
  10966. // dummy.__data = null;
  10967. // Object.setPrototypeOf(dummy, Object.prototype);
  10968. if (!cProto || !cProto.attached) {
  10969. console.warn(`proto.attached for ${tag} is unavailable.`);
  10970. return;
  10971. }
  10972.  
  10973. /*
  10974.  
  10975. // https://www.youtube.com/s/desktop/c01ea7e3/jsbin/live_chat_polymer.vflset/live_chat_polymer.js
  10976.  
  10977.  
  10978. YP.prototype.emitSmoothedMessages = function() {
  10979. this.JSC$10797_nextUpdateId = null;
  10980. if (this.JSC$10797_messageQueue.length) {
  10981. var a = 1E4;
  10982. this.JSC$10797_estimatedUpdateInterval !== null && this.JSC$10797_lastUpdateTime !== null && (a = this.JSC$10797_estimatedUpdateInterval - Date.now() + this.JSC$10797_lastUpdateTime);
  10983. var b = this.JSC$10797_messageQueue.length < a / 80 ? 1 : Math.ceil(this.JSC$10797_messageQueue.length / (a / 80));
  10984. var c = aba(this.JSC$10797_messageQueue.splice(0, b));
  10985. this.callback && this.callback(c);
  10986. this.JSC$10797_messageQueue.length && (b === 1 ? (b = a / this.JSC$10797_messageQueue.length,
  10987. b *= Math.random() + .5,
  10988. b = Math.min(1E3, b),
  10989. b = Math.max(80, b)) : b = 80,
  10990. this.JSC$10797_nextUpdateId = window.setTimeout(this.emitSmoothedMessages.bind(this), b))
  10991. }
  10992. }
  10993. // emitSmoothedMessages: say b = 1000, 858.24, 529.49, 357.15, 194.96, 82.12, 80, 80, 80 ....
  10994.  
  10995. */
  10996.  
  10997.  
  10998. const _flag0281_ = window._flag0281_;
  10999.  
  11000.  
  11001. if ((_flag0281_ & 0x40000) === 0x40000 && cProto && typeof cProto.preprocessActions_ === 'function' && cProto.preprocessActions_.length === 1 && !cProto.preprocessActions92_) {
  11002. // we can disable smooth message emitting if boost chat is enabled (0x40000)
  11003. let byPass = false;
  11004. let q33 = false;
  11005. let key_estimatedUpdateInterval = '';
  11006. let key_lastUpdateTime = '';
  11007. let key_messageQueue = '';
  11008. const emitSmoothedMessagesInstantFn = function () {
  11009. if (byPass) return this.emitSmoothedMessages018();
  11010. byPass = true;
  11011. try {
  11012. if (!q33) {
  11013. const keys = Object.getOwnPropertyNames(this);
  11014. for (const key of keys) {
  11015. if (`${key}`.endsWith('_estimatedUpdateInterval')) key_estimatedUpdateInterval = key;
  11016. else if (`${key}`.endsWith('_lastUpdateTime')) key_lastUpdateTime = key;
  11017. else if (`${key}`.endsWith('_messageQueue')) key_messageQueue = key;
  11018. else continue;
  11019. if (key_estimatedUpdateInterval && key_lastUpdateTime && key_messageQueue) break;
  11020. }
  11021. if (key_estimatedUpdateInterval && key_lastUpdateTime && key_messageQueue) {
  11022. q33 = true;
  11023. }
  11024. }
  11025. if (key_estimatedUpdateInterval && key_lastUpdateTime) {
  11026. this[key_estimatedUpdateInterval] = 78; // 80 - 2
  11027. this[key_lastUpdateTime] = Date.now() - 1;
  11028. }
  11029. } catch (e) { }
  11030. // console.log(19893,key_estimatedUpdateInterval, key_lastUpdateTime)
  11031. // make a = this.JSC$10797_estimatedUpdateInterval - Date.now() + this.JSC$10797_lastUpdateTime small
  11032.  
  11033. // this.JSC$10797_estimatedUpdateInterval = Date.now() + 1
  11034. // this.JSC$10797_lastUpdateTime = Date.now()
  11035.  
  11036. // if (!window.setTimeout837) {
  11037. // window.setTimeout837 = window.setTimeout;
  11038. // window.setTimeout838 = function (f, d) {
  11039. // if (arguments.length !== 2) return window.setTimeout837(...arguments);
  11040. // console.log(12883, d)
  11041. // return window.setTimeout837(f, d > 80 ? 80 : d)
  11042. // }
  11043. // }
  11044. // else if (window.setTimeout837 !== window.setTimeout) {
  11045. // window.setTimeout837 = window.setTimeout;
  11046. // }
  11047. // let r;
  11048. // if (window.setTimeout837 && window.setTimeout838) {
  11049. // window.setTimeout = window.setTimeout838;
  11050. // r = this.emitSmoothedMessages018();
  11051. // window.setTimeout = window.setTimeout837;
  11052. // } else {
  11053. // r = this.emitSmoothedMessages018();
  11054. // }
  11055. let doInNextCall = false;
  11056. try {
  11057. const messageQueue = key_messageQueue ? this[key_messageQueue] : null;
  11058. if (!messageQueue || !messageQueue.length) {
  11059.  
  11060. } else if (messageQueue.length > 255) {
  11061.  
  11062. } else if (!document.hidden) {
  11063.  
  11064. } else {
  11065. doInNextCall = true;
  11066. }
  11067. } catch (e) { }
  11068.  
  11069. let r;
  11070. if (doInNextCall) {
  11071. setTimeout_(() => this.emitSmoothedMessages019(), 250);
  11072. } else {
  11073. r = this.emitSmoothedMessages018();
  11074. }
  11075. byPass = false;
  11076. return r;
  11077. };
  11078. cProto.preprocessActions92_ = cProto.preprocessActions_;
  11079. cProto.preprocessActions_ = function (arr) {
  11080.  
  11081. arr = this.preprocessActions92_(arr);
  11082.  
  11083. try {
  11084.  
  11085. const smoothedQueue_ = this.smoothedQueue_;
  11086. if (smoothedQueue_ && !smoothedQueue_.__fix018__) {
  11087. smoothedQueue_.__fix018__ = true;
  11088. if (!smoothedQueue_.emitSmoothedMessages018 && typeof smoothedQueue_.emitSmoothedMessages === 'function' && smoothedQueue_.emitSmoothedMessages.length === 0) {
  11089. smoothedQueue_.emitSmoothedMessages018 = smoothedQueue_.emitSmoothedMessages;
  11090. smoothedQueue_.emitSmoothedMessages019 = emitSmoothedMessagesInstantFn;
  11091. smoothedQueue_.emitSmoothedMessages = emitSmoothedMessagesInstantFn;
  11092. }
  11093. }
  11094. } catch (e) {
  11095. console.warn(e);
  11096. }
  11097. return arr;
  11098. };
  11099. }
  11100.  
  11101.  
  11102.  
  11103.  
  11104. };
  11105. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  11106. getLCRDummy().then(lcrFn2);
  11107. }
  11108.  
  11109.  
  11110. if (FIX_TOOLTIP_DISPLAY) {
  11111.  
  11112. // ----------------------------------------------------------------------------------------------------
  11113.  
  11114. const checkPDGet = (pd) => {
  11115. return pd && pd.get && !pd.set && pd.enumerable && pd.configurable;
  11116. }
  11117.  
  11118. const tooltipUIWM = new WeakMap();
  11119. const tooltipInitProps = {};
  11120. const createTooltipIfRequired_ = function () {
  11121. let r;
  11122. if (tooltipUIWM.get(this) === void 0) {
  11123. const w = document.createElement;
  11124. let EU = null;
  11125. tooltipUIWM.set(this, null);
  11126. document.createElement = function () {
  11127. let r = w.apply(this, arguments);
  11128. EU = r;
  11129. return r;
  11130. };
  11131. r = this.createTooltipIfRequired14_();
  11132. document.createElement = w;
  11133. if (EU instanceof HTMLElement_ && EU.is) {
  11134. tooltipUIWM.set(this, EU);
  11135. EU.setAttribute('__nogc__', ''); // avoid gc process script
  11136.  
  11137. if (typeof EU.offset === 'number') tooltipInitProps['offset'] = EU.offset;
  11138. if (typeof EU.fitToVisibleBounds === 'boolean') tooltipInitProps['fitToVisibleBounds'] = EU.fitToVisibleBounds;
  11139. if (typeof EU.position === 'string') tooltipInitProps['position'] = EU.position;
  11140. if (typeof EU.for === 'string') tooltipInitProps['for'] = EU.for;
  11141.  
  11142. // this.__mcT__ = EU.outerHTML;
  11143. // EU.__dataX = JSON.stringify(EU.__data);
  11144. // EU.__dataY = Object.entries(EU);
  11145.  
  11146. // <<< FOR DEBUG >>>
  11147. // let kx;
  11148. // Object.defineProperty(EU, '_target', {
  11149. // get(){
  11150. // return kx;
  11151. // },
  11152. // set(nv){
  11153. // kx= nv;
  11154. // debugger;
  11155. // return true;
  11156. // }
  11157. // });
  11158. // <<< FOR DEBUG >>>
  11159.  
  11160. if (typeof Polymer !== 'undefined' && Polymer.__fixedGetOwnerRoot__ && Polymer.__fixedQuerySelector__) {
  11161.  
  11162. } else {
  11163. let eProto = null;
  11164. const euCnt = insp(EU);
  11165. if (checkPDGet(Object.getOwnPropertyDescriptor(euCnt.constructor.prototype || {}, 'target'))) {
  11166.  
  11167. eProto = euCnt.constructor.prototype;
  11168. } else if (checkPDGet(Object.getOwnPropertyDescriptor(EU.constructor.prototype || {}, 'target'))) {
  11169.  
  11170. eProto = EU.constructor.prototype;
  11171. }
  11172. if (eProto) {
  11173. delete eProto.target;
  11174. /*
  11175.  
  11176. get target() {
  11177. var a = Pv(this).parentNode, b = Pv(this).getOwnerRoot(), c;
  11178. this.for ? c = Pv(b).querySelector("#" + this.for) : c = a.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? b.host : a;
  11179. return c
  11180. },
  11181. */
  11182. Object.defineProperty(eProto, 'target', {
  11183. get() {
  11184. const cnt = insp(this);
  11185. const hostElement = cnt.hostElement || cnt;
  11186. let a = hostElement.parentNode, b = hostElement.getRootNode();
  11187. const fr = cnt.for || hostElement.for;
  11188. return (fr ? b.querySelector("#" + fr) : a)
  11189. }
  11190. })
  11191. }
  11192. }
  11193. // setInterval(()=>EU.updatePosition(), 100)
  11194.  
  11195. } else {
  11196. tooltipUIWM.set(this, null);
  11197. }
  11198. } else {
  11199. r = this.createTooltipIfRequired14_();
  11200. }
  11201.  
  11202. const EU = tooltipUIWM.get(this);
  11203. if (EU) {
  11204. EU.remove();
  11205. if (typeof tooltipInitProps.offset === 'number') EU['offset'] = tooltipInitProps.offset;
  11206. if (typeof tooltipInitProps.fitToVisibleBounds === 'boolean') EU['fitToVisibleBounds'] = tooltipInitProps.fitToVisibleBounds;
  11207. try {
  11208. if (typeof tooltipInitProps.position === 'string') EU['position'] = tooltipInitProps.position;
  11209. if (typeof tooltipInitProps.for === 'string') EU['for'] = tooltipInitProps.for; else delete EU.for;
  11210. } catch (e) { }
  11211. }
  11212.  
  11213. // 2025.01.10 fix
  11214. const CS = EU;
  11215. if (!CS._showing && CS.__shady_parentNode && CS.__shady_parentNode !== CS.parentNode) {
  11216. if (CS.__shady_parentNode) {
  11217. try {
  11218. CS.__shady_parentNode.__shady_removeChild(CS);
  11219. } catch (e) { }
  11220. }
  11221. if (CS.__shady_parentNode) {
  11222. try {
  11223. CS.__shady_parentNode.removeChild(CS);
  11224. } catch (e) { }
  11225. }
  11226. if (CS.__shady_parentNode) {
  11227. try {
  11228. CS.__shady_parentNode.__shady_native_removeChild(CS);
  11229. } catch (e) { }
  11230. }
  11231. if (CS.__shady_parentNode) {
  11232. try {
  11233. __shady_native_removeChild.call(CS.__shady_parentNode, CS);
  11234. } catch (e) { }
  11235. }
  11236. if (CS.parentNode && !CS.__shady_parentNode) {
  11237. try {
  11238. __shady_native_removeChild.call(CS.parentNode, CS);
  11239. } catch (e) { }
  11240. }
  11241. }
  11242.  
  11243. return r;
  11244. };
  11245.  
  11246.  
  11247. // added in 2024.05.02
  11248. const lcrFn2 = (lcrDummy) => {
  11249.  
  11250. // console.log(8171, 99);
  11251. const tag = "yt-live-chat-renderer"
  11252. const dummy = lcrDummy;
  11253.  
  11254. const cProto = getProto(dummy);
  11255. if (!cProto || !cProto.attached) {
  11256. console.warn(`proto.attached for ${tag} is unavailable.`);
  11257. return;
  11258. }
  11259.  
  11260. /*
  11261. <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;
  11262. */
  11263.  
  11264. if (cProto && typeof cProto.createTooltipIfRequired_ === 'function' && cProto.createTooltipIfRequired_.length === 0 && !cProto.createTooltipIfRequired14_) {
  11265. cProto.createTooltipIfRequired14_ = cProto.createTooltipIfRequired_;
  11266. cProto.createTooltipIfRequired_ = createTooltipIfRequired_;
  11267. }
  11268.  
  11269. };
  11270. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  11271. getLCRDummy().then(lcrFn2);
  11272.  
  11273. // ----------------------------------------------------------------------------------------------------
  11274.  
  11275. customElements.whenDefined("tp-yt-paper-tooltip").then(() => {
  11276.  
  11277. mightFirstCheckOnYtInit();
  11278. groupCollapsed("YouTube Super Fast Chat", " | tp-yt-paper-tooltip hacks");
  11279. console1.log("[Begin]");
  11280. (() => {
  11281.  
  11282. const tag = "tp-yt-paper-tooltip"
  11283. const dummy = document.createElement(tag);
  11284.  
  11285. const cProto = getProto(dummy);
  11286. if (!cProto || !cProto.attached) {
  11287. console1.warn(`proto.attached for ${tag} is unavailable.`);
  11288. return;
  11289. }
  11290.  
  11291. if (typeof cProto.attached === 'function' && typeof cProto.detached === 'function' && cProto._readyClients && cProto._attachDom && cProto.ready && !cProto._readyClients43) {
  11292.  
  11293. cProto._readyClients43 = cProto._readyClients;
  11294. cProto._readyClients = function () {
  11295. // console.log(1238)
  11296.  
  11297. let r = cProto._readyClients43.apply(this, arguments);
  11298. if (this.$ && this.$$ && this.$.tooltip) this.root = null; // fix this.root = null != (b = a.root) ? b : this.host
  11299. return r;
  11300. }
  11301.  
  11302. console1.log("_readyClients - OK");
  11303.  
  11304. } else {
  11305. console1.log("_readyClients - NG");
  11306.  
  11307. }
  11308.  
  11309. if (typeof cProto.show === 'function' && !cProto.show17) {
  11310. cProto.show17 = cProto.show;
  11311. cProto.show = function () {
  11312.  
  11313. let r = this.show17.apply(this, arguments);
  11314. this._showing === true && Promise.resolve(this).then((cnt) => {
  11315. const tooltip = (cnt.$ || 0).tooltip;
  11316.  
  11317. if (tooltip && tooltip.firstElementChild === null) {
  11318. let text = tooltip.textContent;
  11319. if (typeof text === 'string' && text.length >= 2) {
  11320. tooltip.textContent = text.trim();
  11321. }
  11322. }
  11323. cnt = null;
  11324. }).catch(console.warn)
  11325. return r;
  11326. }
  11327.  
  11328. console1.log("trim tooltip content - OK");
  11329.  
  11330. } else {
  11331. console1.log("trim tooltip content - NG");
  11332.  
  11333. }
  11334.  
  11335.  
  11336. })();
  11337.  
  11338. console1.log("[End]");
  11339.  
  11340. groupEnd();
  11341.  
  11342. }).catch(console.warn);
  11343.  
  11344. }
  11345.  
  11346.  
  11347. if (FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK) {
  11348.  
  11349. const hookDocumentMouseDownSetupFn = () => {
  11350.  
  11351. let muzTimestamp = 0;
  11352. let nszDropdown = null;
  11353.  
  11354. const handlerObject = {
  11355.  
  11356. muHandler282: function (evt) {
  11357. // console.log(evt, 7, document.querySelector('tp-yt-iron-dropdown[focused].style-scope.yt-live-chat-app'))
  11358. if (!evt || !evt.isTrusted || !muzTimestamp) return;
  11359. const dropdown = nszDropdown;
  11360. muzTimestamp = 0;
  11361. nszDropdown = null;
  11362.  
  11363. const kurMPCe = kRef(currentMenuPivotWR) || 0;
  11364. const hostElement = kurMPCe.hostElement || kurMPCe; // should be always hostElement === kurMPCe ?
  11365. if (!hostElement.hasAttribute('menu-visible')) return;
  11366.  
  11367. const chatBanner = HTMLElement_.prototype.closest.call(hostElement, 'yt-live-chat-banner-renderer') || 0;
  11368. if (chatBanner) return;
  11369.  
  11370. if (dropdown && dropdown.positionTarget && hostElement.contains(dropdown.positionTarget)) {
  11371. muzTimestamp = Date.now();
  11372. evt.stopImmediatePropagation();
  11373. evt.stopPropagation();
  11374. Promise.resolve(dropdown).then((dropdown) => {
  11375. dropdown.cancel();
  11376. dropdown = null;
  11377. });
  11378. }
  11379.  
  11380. },
  11381.  
  11382. mlHandler282: function (evt) {
  11383. muzTimestamp = 0;
  11384. nszDropdown = null;
  11385. },
  11386.  
  11387. ckHandler282: function (evt) {
  11388. if (!evt || !evt.isTrusted || !muzTimestamp) return;
  11389. if (Date.now() - muzTimestamp < 40) {
  11390. muzTimestamp = Date.now();
  11391. evt.stopImmediatePropagation();
  11392. evt.stopPropagation();
  11393. }
  11394. },
  11395.  
  11396. tapHandler282: function (evt) {
  11397. if (!evt || !evt.isTrusted || !muzTimestamp) return;
  11398. if (Date.now() - muzTimestamp < 40) {
  11399. muzTimestamp = Date.now();
  11400. evt.stopImmediatePropagation();
  11401. evt.stopPropagation();
  11402. }
  11403. },
  11404.  
  11405. handleEvent(evt) {
  11406. if (evt) {
  11407. const kurMPCe = kRef(currentMenuPivotWR) || 0;
  11408. const kurMPCc = insp(kurMPCe);
  11409. const hostElement = kurMPCc.hostElement || kurMPCc;
  11410. if (!kurMPCc || kurMPCc.isAttached !== true || hostElement.isConnected !== true) return;
  11411. switch (evt.type) {
  11412. case 'mouseup':
  11413. return this.muHandler282(evt);
  11414. case 'mouseleave':
  11415. return this.mlHandler282(evt);
  11416. case 'tap':
  11417. return this.tapHandler282(evt);
  11418. case 'click':
  11419. return this.ckHandler282(evt);
  11420. }
  11421. }
  11422. }
  11423.  
  11424. }
  11425.  
  11426. document.addEventListener('mousedown', function (evt) {
  11427.  
  11428. if (!evt || !evt.isTrusted || !evt.target) return;
  11429.  
  11430. muzTimestamp = 0;
  11431. nszDropdown = null;
  11432.  
  11433. /** @type {HTMLElement | null} */
  11434. const kurMP = kRef(currentMenuPivotWR);
  11435. if (!kurMP) return;
  11436. const kurMPCe = HTMLElement_.prototype.closest.call(kurMP, '[menu-visible]') || 0; // element
  11437.  
  11438. if (!kurMPCe || !kurMPCe.hasAttribute('whole-message-clickable')) return;
  11439.  
  11440. const kurMPCc = insp(kurMPCe); // controller
  11441.  
  11442. if (!kurMPCc.isClickableChatRow111 || !kurMPCc.isClickableChatRow111() || !HTMLElement_.prototype.contains.call(kurMPCe, evt.target)) return;
  11443.  
  11444. const chatBanner = HTMLElement_.prototype.closest.call(kurMPCe, 'yt-live-chat-banner-renderer') || 0;
  11445. if (chatBanner) return;
  11446.  
  11447. let targetDropDown = null;
  11448. for (const dropdown of document.querySelectorAll('tp-yt-iron-dropdown.style-scope.yt-live-chat-app')) {
  11449. if (dropdown && dropdown.positionTarget === kurMP) {
  11450. targetDropDown = dropdown;
  11451. }
  11452. }
  11453.  
  11454. if (!targetDropDown) return;
  11455.  
  11456. if (evt.target.closest('ytd-menu-popup-renderer')) return;
  11457.  
  11458. if ((nszDropdown = targetDropDown)) {
  11459. muzTimestamp = Date.now();
  11460. evt.stopImmediatePropagation();
  11461. evt.stopPropagation();
  11462. currentMenuPivotWR = mWeakRef(kurMPCe);
  11463.  
  11464. const listenOpts = { capture: true, passive: false, once: true };
  11465.  
  11466. // remove unexcecuted eventHandler
  11467. document.removeEventListener('mouseup', handlerObject, listenOpts);
  11468. document.removeEventListener('mouseleave', handlerObject, listenOpts);
  11469. document.removeEventListener('tap', handlerObject, listenOpts);
  11470. document.removeEventListener('click', handlerObject, listenOpts);
  11471.  
  11472. // inject one time eventHandler to by pass events
  11473. document.addEventListener('mouseup', handlerObject, listenOpts);
  11474. document.addEventListener('mouseleave', handlerObject, listenOpts);
  11475. document.addEventListener('tap', handlerObject, listenOpts);
  11476. document.addEventListener('click', handlerObject, listenOpts);
  11477.  
  11478. }
  11479.  
  11480. }, true);
  11481.  
  11482. }
  11483.  
  11484.  
  11485. // yt-live-chat-paid-message-renderer ??
  11486.  
  11487. /*
  11488.  
  11489. [...(new Set([...document.querySelectorAll('*')].filter(e=>e.is&&('shouldSupportWholeItemClick' in e)).map(e=>e.is))).keys()]
  11490.  
  11491.  
  11492. "yt-live-chat-ticker-paid-message-item-renderer"
  11493. "yt-live-chat-ticker-paid-sticker-item-renderer"
  11494. "yt-live-chat-paid-message-renderer"
  11495. "yt-live-chat-text-message-renderer"
  11496. "yt-live-chat-paid-sticker-renderer"
  11497.  
  11498. */
  11499.  
  11500.  
  11501. whenDefinedMultiple([
  11502.  
  11503. "yt-live-chat-paid-message-renderer",
  11504. "yt-live-chat-membership-item-renderer",
  11505. "yt-live-chat-paid-sticker-renderer",
  11506. "yt-live-chat-text-message-renderer",
  11507. "yt-live-chat-auto-mod-message-renderer",
  11508.  
  11509. /*
  11510. "yt-live-chat-ticker-paid-message-item-renderer",
  11511. "yt-live-chat-ticker-paid-sticker-item-renderer",
  11512. "yt-live-chat-paid-message-renderer",
  11513. "yt-live-chat-text-message-renderer",
  11514. "yt-live-chat-paid-sticker-renderer",
  11515.  
  11516. "yt-live-chat-ticker-sponsor-item-renderer",
  11517. "yt-live-chat-banner-header-renderer",
  11518. "ytd-sponsorships-live-chat-gift-purchase-announcement-renderer",
  11519. "ytd-sponsorships-live-chat-header-renderer",
  11520. "ytd-sponsorships-live-chat-gift-redemption-announcement-renderer",
  11521.  
  11522.  
  11523.  
  11524.  
  11525. "yt-live-chat-auto-mod-message-renderer",
  11526. "yt-live-chat-text-message-renderer",
  11527. "yt-live-chat-paid-message-renderer",
  11528.  
  11529. "yt-live-chat-legacy-paid-message-renderer",
  11530. "yt-live-chat-membership-item-renderer",
  11531. "yt-live-chat-paid-sticker-renderer",
  11532. "yt-live-chat-donation-announcement-renderer",
  11533. "yt-live-chat-moderation-message-renderer",
  11534. "ytd-sponsorships-live-chat-gift-purchase-announcement-renderer",
  11535. "ytd-sponsorships-live-chat-gift-redemption-announcement-renderer",
  11536. "yt-live-chat-viewer-engagement-message-renderer",
  11537.  
  11538. */
  11539.  
  11540.  
  11541. ]).then(sTags => {
  11542. // return; // M33
  11543.  
  11544. mightFirstCheckOnYtInit();
  11545. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-message-renderer(s)... hacks");
  11546. console1.log("[Begin]");
  11547. let doMouseHook = false;
  11548.  
  11549. const dProto = {
  11550. isClickableChatRow111: function () {
  11551. return (
  11552. this.data && typeof this.shouldSupportWholeItemClick === 'function' && typeof this.hasModerationOverlayVisible === 'function' &&
  11553. this.data.contextMenuEndpoint && this.wholeMessageClickable && this.shouldSupportWholeItemClick() && !this.hasModerationOverlayVisible()
  11554. ); // follow .onItemTap(a)
  11555. }
  11556. };
  11557.  
  11558. for (const sTag of sTags) { // ##tag##
  11559.  
  11560.  
  11561. (() => {
  11562.  
  11563. const tag = sTag;
  11564. const dummy = document.createElement(tag);
  11565.  
  11566. const cProto = getProto(dummy);
  11567. if (!cProto || !cProto.attached) {
  11568. console1.warn(`proto.attached for ${tag} is unavailable.`);
  11569. return;
  11570. }
  11571.  
  11572. const dCnt = insp(dummy);
  11573. if ('wholeMessageClickable' in dCnt && typeof dCnt.hasModerationOverlayVisible === 'function' && typeof dCnt.shouldSupportWholeItemClick === 'function') {
  11574.  
  11575. cProto.isClickableChatRow111 = dProto.isClickableChatRow111;
  11576.  
  11577. const toHookDocumentMouseDown = typeof cProto.shouldSupportWholeItemClick === 'function' && typeof cProto.hasModerationOverlayVisible === 'function';
  11578.  
  11579. if (toHookDocumentMouseDown) {
  11580. doMouseHook = true;
  11581. }
  11582.  
  11583. console1.log("shouldSupportWholeItemClick - OK", tag);
  11584.  
  11585. } else {
  11586.  
  11587. console1.log("shouldSupportWholeItemClick - NG", tag);
  11588. }
  11589.  
  11590.  
  11591. })();
  11592.  
  11593. }
  11594.  
  11595.  
  11596. if (doMouseHook) {
  11597.  
  11598. hookDocumentMouseDownSetupFn();
  11599.  
  11600. console1.log("FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK - Doc MouseEvent OK");
  11601. }
  11602.  
  11603. console1.log("[End]");
  11604.  
  11605. groupEnd();
  11606.  
  11607.  
  11608. }).catch(console.warn);
  11609.  
  11610.  
  11611. // https://www.youtube.com/watch?v=oQzFi1NO7io
  11612.  
  11613.  
  11614. }
  11615.  
  11616. if (NO_ITEM_TAP_FOR_NON_STATIONARY_TAP) {
  11617. let targetElementCntWR = null;
  11618. let _e0 = null;
  11619. document.addEventListener('mousedown', (e) => {
  11620. if (!e || !e.isTrusted) return;
  11621. let element = e.target;
  11622. for (; element instanceof HTMLElement_; element = element.parentNode) {
  11623. if (element.is) break;
  11624. }
  11625. if (!element || !element.is) return;
  11626. if (element.closest('ytd-menu-popup-renderer')) return;
  11627. const cnt = insp(element);
  11628. if (typeof cnt.onItemTap === 'function') {
  11629. cnt._onItemTap_isNonStationary = 0;
  11630. const cProto = getProto(element);
  11631. if (!cProto.onItemTap366 && typeof cProto.onItemTap === 'function' && cProto.onItemTap.length === 1) {
  11632. cProto.onItemTap366 = cProto.onItemTap; // note: [onItemTap] .some(function(){...})
  11633. cProto.onItemTap = function (a) {
  11634. const t = this._onItemTap_isNonStationary;
  11635. this._onItemTap_isNonStationary = 0;
  11636. if (t > Date.now()) return;
  11637. return this.onItemTap366.apply(this, arguments)
  11638. }
  11639. }
  11640. _e0 = e;
  11641. targetElementCntWR = mWeakRef(cnt);
  11642. } else {
  11643. _e0 = null;
  11644. targetElementCntWR = null;
  11645. }
  11646. }, { capture: true, passive: true });
  11647.  
  11648. document.addEventListener('mouseup', (e) => {
  11649. if (!e || !e.isTrusted) return;
  11650. const e0 = _e0;
  11651. _e0 = null;
  11652. if (!e0) return;
  11653. const cnt = kRef(targetElementCntWR);
  11654. targetElementCntWR = null;
  11655. if (!cnt) return;
  11656. if (e.timeStamp - e0.timeStamp > TAP_ACTION_DURATION) {
  11657. cnt._onItemTap_isNonStationary = Date.now() + 40;
  11658. } else if (`${window.getSelection()}`.trim().replace(/[\u2000-\u200a\u202f\u2800\u200B\u200C\u200D\uFEFF]+/g, '').length >= 1) {
  11659. cnt._onItemTap_isNonStationary = Date.now() + 40;
  11660. } else {
  11661. const dx = e.clientX - e0.clientX;
  11662. const dy = e.clientY - e0.clientY;
  11663. const dd = Math.sqrt(dx * dx + dy * dy);
  11664. const ddmm = px2mm(dd);
  11665. if (ddmm > 1.0) {
  11666. cnt._onItemTap_isNonStationary = Date.now() + 40;
  11667. } else {
  11668. cnt._onItemTap_isNonStationary = 0;
  11669. }
  11670. }
  11671. }, { capture: true, passive: true });
  11672.  
  11673. }
  11674.  
  11675.  
  11676. const __showContextMenu_assign_lock_with_external_unlock_ = function (targetCnt) {
  11677.  
  11678. let rr = null;
  11679. const p1 = new Promise(resolve => {
  11680. rr = resolve;
  11681. });
  11682.  
  11683. const p1unlock = () => {
  11684. const f = rr;
  11685. if (f) {
  11686. rr = null;
  11687. f();
  11688. }
  11689. }
  11690.  
  11691. return {
  11692. p1,
  11693. p1unlock,
  11694. assignLock: (targetCnt, timeout) => {
  11695. targetCnt.__showContextMenu_assign_lock__(p1);
  11696. if (timeout) setTimeout(p1unlock, timeout);
  11697. }
  11698. }
  11699.  
  11700. }
  11701.  
  11702. if (PREREQUEST_CONTEXT_MENU_ON_MOUSE_DOWN) {
  11703.  
  11704. document.addEventListener('mousedown', function (evt) {
  11705.  
  11706. const maxloopDOMTreeElements = 4;
  11707. const maxloopYtCompontents = 4;
  11708. let j1 = 0;
  11709. let j2 = 0;
  11710. let target = (evt || 0).target || 0;
  11711. if (!target) return;
  11712. if (target.closest('ytd-menu-popup-renderer')) return;
  11713.  
  11714. while (target instanceof HTMLElement_) {
  11715. if (++j1 > maxloopDOMTreeElements) break;
  11716. if (typeof (target.is || insp(target).is || null) === 'string') break;
  11717. target = nodeParent(target);
  11718. }
  11719. const components = [];
  11720. while (target instanceof HTMLElement_) {
  11721. if (++j2 > maxloopYtCompontents) break;
  11722. const cnt = insp(target);
  11723. if (typeof (target.is || cnt.is || null) === 'string') {
  11724. components.push(target);
  11725. }
  11726. if (typeof cnt.showContextMenu === 'function') break;
  11727. target = target.parentComponent || cnt.parentComponent || null;
  11728. }
  11729. if (!(target instanceof HTMLElement_)) return;
  11730. const targetCnt = insp(target);
  11731. if (typeof targetCnt.handleGetContextMenuResponse_ !== 'function' || typeof targetCnt.handleGetContextMenuError !== 'function') {
  11732. console.log('Error Found: handleGetContextMenuResponse_ OR handleGetContextMenuError is not defined on a component with showContextMenu')
  11733. return;
  11734. }
  11735.  
  11736. const endpoint = (targetCnt.data || 0).contextMenuEndpoint
  11737. if (!endpoint) return;
  11738. if (targetCnt.opened || !targetCnt.isAttached) return;
  11739.  
  11740. if (typeof targetCnt.__cacheResolvedEndpointData__ !== 'function') {
  11741. console.log(`preRequest for showContextMenu in ${targetCnt.is} is not yet supported.`)
  11742. }
  11743.  
  11744. const targetDollar = indr(target);
  11745.  
  11746. let doPreRequest = false;
  11747. if (components.length >= 2 && components[0].id === 'menu-button' && (targetDollar || 0)['menu-button'] === components[0]) {
  11748. doPreRequest = true;
  11749. } else if (components.length === 1 && components[0] === target) {
  11750. doPreRequest = true;
  11751. } else if (components.length >= 2 && components[0].id === 'author-photo' && (targetDollar || 0)['author-photo'] === components[0]) {
  11752. doPreRequest = true;
  11753. }
  11754. if (doPreRequest === false) {
  11755. console.log('doPreRequest = fasle on showContextMenu', components);
  11756. return;
  11757. }
  11758.  
  11759. if (typeof targetCnt.__getCachedEndpointData__ !== 'function' || targetCnt.__getCachedEndpointData__(endpoint)) return;
  11760.  
  11761. if ((typeof targetCnt.__showContextMenu_mutex_unlock_isEmpty__ === 'function') && !targetCnt.__showContextMenu_mutex_unlock_isEmpty__()) {
  11762. console.log('preRequest on showContextMenu aborted due to stacked network request');
  11763. return;
  11764. }
  11765.  
  11766.  
  11767. const onSuccess = (a) => {
  11768. /*
  11769.  
  11770. dQ() && (a = a.response);
  11771. a.liveChatItemContextMenuSupportedRenderers && a.liveChatItemContextMenuSupportedRenderers.menuRenderer && this.showContextMenu_(a.liveChatItemContextMenuSupportedRenderers.menuRenderer);
  11772. a.actions && Eu(this.hostElement, "yt-live-chat-actions", [a.actions])
  11773.  
  11774. */
  11775.  
  11776. a = a.response || a;
  11777.  
  11778. if (!a) {
  11779. console.log('unexpected error in prerequest for showContextMenu.onSuccess');
  11780. return;
  11781. }
  11782.  
  11783. let z = null;
  11784. a.liveChatItemContextMenuSupportedRenderers && a.liveChatItemContextMenuSupportedRenderers.menuRenderer && (z = a.liveChatItemContextMenuSupportedRenderers.menuRenderer);
  11785.  
  11786. if (z) {
  11787. a = z;
  11788. targetCnt.__cacheResolvedEndpointData__(endpoint, a, true);
  11789. }
  11790.  
  11791. };
  11792. const onFailure = (a) => {
  11793.  
  11794. /*
  11795.  
  11796. if (a instanceof Error || a instanceof Object || a instanceof String)
  11797. var b = a;
  11798. hq(new xm("Error encountered calling GetLiveChatItemContextMenu",b))
  11799.  
  11800. */
  11801.  
  11802. targetCnt.__cacheResolvedEndpointData__(endpoint, null);
  11803. // console.log('onFailure', a)
  11804.  
  11805. };
  11806.  
  11807. if (doPreRequest) {
  11808.  
  11809. let propertyCounter = 0;
  11810. const pm1 = __showContextMenu_assign_lock_with_external_unlock_(targetCnt);
  11811. const p1Timeout = 800;
  11812. const proxyKey = '__$$__proxy_to_this__$$__' + Date.now();
  11813.  
  11814. try {
  11815.  
  11816. const onSuccessHelperFn = function () {
  11817. pm1.p1unlock();
  11818. if (propertyCounter !== 5) {
  11819. console.log('Error in prerequest for showContextMenu.onSuccessHelperFn')
  11820. return;
  11821. }
  11822. if (this[proxyKey] !== targetCnt) {
  11823. console.log('Error in prerequest for showContextMenu.this');
  11824. return;
  11825. }
  11826. onSuccess(...arguments);
  11827. };
  11828. const onFailureHelperFn = function () {
  11829. pm1.p1unlock();
  11830. if (propertyCounter !== 5) {
  11831. console.log('Error in prerequest for showContextMenu.onFailureHelperFn')
  11832. return;
  11833. }
  11834. if (this[proxyKey] !== targetCnt) {
  11835. console.log('Error in prerequest for showContextMenu.this');
  11836. return;
  11837. }
  11838. onFailure(...arguments);
  11839.  
  11840. }
  11841. const fakeTargetCnt = new Proxy({
  11842. __showContextMenu_forceNativeRequest__: 1,
  11843. get handleGetContextMenuResponse_() {
  11844. propertyCounter += 2;
  11845. return onSuccessHelperFn;
  11846. },
  11847. get handleGetContextMenuError() {
  11848. propertyCounter += 3;
  11849. return onFailureHelperFn;
  11850. }
  11851. }, {
  11852. get(_, key, receiver) {
  11853. if (key in _) return _[key];
  11854. if (key === proxyKey) return targetCnt;
  11855.  
  11856. let giveNative = false;
  11857. if (key in targetCnt) {
  11858. if (key === 'data') giveNative = true;
  11859. else if (typeof targetCnt[key] === 'function') giveNative = true;
  11860. }
  11861. if (giveNative) return targetCnt[key];
  11862. }
  11863. });
  11864.  
  11865. const fakeEvent = (() => {
  11866. const { target, bubbles, cancelable, cancelBubble, srcElement, timeStamp, defaultPrevented, currentTarget, composed } = evt;
  11867. const nf = function () { }
  11868. const [stopPropagation, stopImmediatePropagation, preventDefault] = [nf, nf, nf];
  11869.  
  11870. return {
  11871. type: 'tap',
  11872. eventPhase: 0,
  11873. isTrusted: false,
  11874. __composed: true,
  11875. bubbles, cancelable, cancelBubble, timeStamp,
  11876. target, srcElement, defaultPrevented, currentTarget, composed,
  11877. stopPropagation, stopImmediatePropagation, preventDefault
  11878. };
  11879. })(evt);
  11880. targetCnt.showContextMenu.call(fakeTargetCnt, fakeEvent);
  11881.  
  11882.  
  11883. } catch (e) {
  11884. console.warn(e);
  11885. propertyCounter = 7;
  11886.  
  11887. }
  11888. if (propertyCounter !== 5) {
  11889. console.log('Error in prerequest for showContextMenu', propertyCounter);
  11890. return;
  11891. }
  11892.  
  11893. pm1.assignLock(targetCnt, p1Timeout);
  11894.  
  11895. }
  11896.  
  11897.  
  11898.  
  11899.  
  11900.  
  11901.  
  11902. }, true);
  11903.  
  11904.  
  11905. }
  11906.  
  11907.  
  11908.  
  11909. /*
  11910.  
  11911. const w=new Set(); for(const a of document.getElementsByTagName('*')) if(a.showContextMenu && a.showContextMenu_) w.add(a.is||''); console.log([...w.keys()])
  11912.  
  11913. */
  11914.  
  11915. whenDefinedMultiple([
  11916. "yt-live-chat-ticker-sponsor-item-renderer",
  11917. "yt-live-chat-ticker-paid-message-item-renderer",
  11918.  
  11919. "yt-live-chat-banner-header-renderer",
  11920. "yt-live-chat-text-message-renderer",
  11921. "ytd-sponsorships-live-chat-gift-purchase-announcement-renderer",
  11922. "ytd-sponsorships-live-chat-header-renderer",
  11923. "ytd-sponsorships-live-chat-gift-redemption-announcement-renderer",
  11924.  
  11925. "yt-live-chat-paid-sticker-renderer",
  11926. "yt-live-chat-viewer-engagement-message-renderer",
  11927. "yt-live-chat-paid-message-renderer"
  11928.  
  11929.  
  11930.  
  11931.  
  11932. ]).then(sTags => {
  11933.  
  11934. mightFirstCheckOnYtInit();
  11935. groupCollapsed("YouTube Super Fast Chat", " | fixShowContextMenu");
  11936. console1.log("[Begin]");
  11937.  
  11938.  
  11939. const __showContextMenu_mutex__ = new Mutex();
  11940. let __showContextMenu_mutex_unlock__ = null;
  11941. let lastShowMenuTarget = null;
  11942.  
  11943.  
  11944.  
  11945.  
  11946. const wm37 = new WeakMap();
  11947.  
  11948. const dProto = {
  11949.  
  11950.  
  11951. // CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN
  11952.  
  11953. __cacheResolvedEndpointData__: (endpoint, a, doDeepCopy) => {
  11954. if (a) {
  11955. if (doDeepCopy) a = deepCopy(a);
  11956. wm37.set(endpoint, a);
  11957. } else {
  11958. wm37.remove(endpoint);
  11959. }
  11960. },
  11961. __getCachedEndpointData__: function (endpoint) {
  11962. endpoint = endpoint || (this.data || 0).contextMenuEndpoint || 0;
  11963. if (endpoint) return wm37.get(endpoint);
  11964. return null;
  11965. },
  11966. /** @type {(resolvedEndpoint: any) => void 0} */
  11967. __showCachedContextMenu__: function (resolvedEndpoint) { // non-null
  11968.  
  11969. resolvedEndpoint = deepCopy(resolvedEndpoint);
  11970. // let b = deepCopy(resolvedEndpoint, ['trackingParams', 'clickTrackingParams'])
  11971. Promise.resolve(resolvedEndpoint).then((resolvedEndpoint) => {
  11972. this.__showContextMenu_skip_cacheResolvedEndpointData__ = 1;
  11973. this.showContextMenu_(resolvedEndpoint);
  11974. this.__showContextMenu_skip_cacheResolvedEndpointData__ = 0;
  11975. resolvedEndpoint = null;
  11976. });
  11977.  
  11978.  
  11979. },
  11980.  
  11981.  
  11982.  
  11983. showContextMenuForCacheReopen: function (a) {
  11984. if (this && this.__showContextMenu_forceNativeRequest__) return this.showContextMenu37(a);
  11985. if (!this || !this.isAttached) return; // in case; avoid Error: No provider for: InjectionToken(NETWORK_TOKEN) in _.showContextMenu
  11986. if (!this.__showContextMenu_forceNativeRequest__) {
  11987. const endpoint = (this.data || 0).contextMenuEndpoint || 0;
  11988. if (endpoint) {
  11989. const resolvedEndpoint = this.__getCachedEndpointData__(endpoint);
  11990. if (resolvedEndpoint) {
  11991. this.__showCachedContextMenu__(resolvedEndpoint);
  11992. a && a.stopPropagation()
  11993. return;
  11994. }
  11995. }
  11996. }
  11997. return this.showContextMenu37(a);
  11998. },
  11999.  
  12000. showContextMenuForCacheReopen_: function (a) {
  12001. if (this && this.__showContextMenu_forceNativeRequest__) return this.showContextMenu37_(a);
  12002. if (!this || !this.isAttached) return; // in case; avoid Error: No provider for: InjectionToken(NETWORK_TOKEN) in _.showContextMenu
  12003. if (!this.__showContextMenu_skip_cacheResolvedEndpointData__) {
  12004. const endpoint = (this.data || 0).contextMenuEndpoint || 0;
  12005. if (endpoint) {
  12006. const f = this.__cacheResolvedEndpointData__;
  12007. if (typeof f === 'function') f(endpoint, a, true);
  12008. }
  12009. }
  12010. return this.showContextMenu37_(a);
  12011. },
  12012.  
  12013. // ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU
  12014.  
  12015. showContextMenuWithDisableScroll: function (a) {
  12016.  
  12017. const endpoint = (this.data || 0).contextMenuEndpoint || 0;
  12018. if (endpoint && typeof this.is === 'string' && this.menuVisible === false && this.menuOpen === false) {
  12019.  
  12020. const parentComponent = this.parentComponent;
  12021. if (parentComponent && parentComponent.is === 'yt-live-chat-item-list-renderer' && parentComponent.contextMenuOpen === false && parentComponent.allowScroll === true) {
  12022. parentComponent.contextMenuOpen = true; // computeAllowScroll_(contextMenuOpen, moderationModeEnabled): allowScroll = !(contextMenuOpen || moderationModeEnabled)
  12023. }
  12024. }
  12025.  
  12026. return this.showContextMenu48.apply(this, arguments);
  12027.  
  12028. },
  12029.  
  12030. // ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU
  12031.  
  12032. __showContextMenu_mutex_unlock_isEmpty__: () => {
  12033. return __showContextMenu_mutex_unlock__ === null;
  12034. },
  12035.  
  12036. __showContextMenu_assign_lock__: function (p) {
  12037.  
  12038. const mutex = __showContextMenu_mutex__;
  12039.  
  12040. mutex.lockWith(unlock => {
  12041. p.then(unlock);
  12042. p = null;
  12043. unlock = null;
  12044. });
  12045.  
  12046. },
  12047.  
  12048. showContextMenuWithMutex: function (a) {
  12049. if (this.__showContextMenu_forceNativeRequest__) return this.showContextMenu47(a);
  12050. if (!this || !this.isAttached) return; // in case; avoid Error: No provider for: InjectionToken(NETWORK_TOKEN) in _.showContextMenu
  12051. lastShowMenuTarget = this;
  12052. const wNode = mWeakRef(this);
  12053.  
  12054.  
  12055. const mutex = __showContextMenu_mutex__;
  12056.  
  12057. mutex.lockWith(unlock => {
  12058. const cnt = kRef(wNode);
  12059. if (lastShowMenuTarget !== cnt || !cnt) {
  12060. unlock();
  12061. return;
  12062. }
  12063.  
  12064. setTimeout(unlock, 800); // in case network failure
  12065. __showContextMenu_mutex_unlock__ = unlock;
  12066. try {
  12067. cnt.showContextMenu47(a);
  12068. } catch (e) {
  12069. console.warn(e);
  12070. unlock(); // in case function script error
  12071. }
  12072.  
  12073. });
  12074.  
  12075.  
  12076. },
  12077.  
  12078. showContextMenuWithMutex_: function (a) {
  12079.  
  12080. if (__showContextMenu_mutex_unlock__ && this === lastShowMenuTarget) {
  12081. __showContextMenu_mutex_unlock__();
  12082. __showContextMenu_mutex_unlock__ = null;
  12083. }
  12084. return this.showContextMenu47_(a);
  12085.  
  12086. }
  12087.  
  12088. }
  12089.  
  12090. for (const tag of sTags) { // ##tag##
  12091.  
  12092. (() => {
  12093.  
  12094. const dummy = document.createElement(tag);
  12095.  
  12096. const cProto = getProto(dummy);
  12097. if (!cProto || !cProto.attached) {
  12098. console1.warn(`proto.attached for ${tag} is unavailable.`);
  12099. return;
  12100. }
  12101.  
  12102.  
  12103. 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) {
  12104. cProto.showContextMenu37_ = cProto.showContextMenu_;
  12105. cProto.showContextMenu37 = cProto.showContextMenu;
  12106. cProto.__showContextMenu_forceNativeRequest__ = 0;
  12107. cProto.__cacheResolvedEndpointData__ = dProto.__cacheResolvedEndpointData__
  12108. cProto.__getCachedEndpointData__ = dProto.__getCachedEndpointData__
  12109. cProto.__showCachedContextMenu__ = dProto.__showCachedContextMenu__
  12110. cProto.showContextMenu = dProto.showContextMenuForCacheReopen;
  12111. cProto.showContextMenu_ = dProto.showContextMenuForCacheReopen_;
  12112. console1.log("CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN - OK", tag);
  12113. } else {
  12114. console1.log("CACHE_SHOW_CONTEXT_MENU_FOR_REOPEN - NG", tag);
  12115. }
  12116.  
  12117. 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) {
  12118. cProto.showContextMenu48 = cProto.showContextMenu;
  12119. cProto.showContextMenu = dProto.showContextMenuWithDisableScroll;
  12120. console1.log("ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU - OK", tag);
  12121. } else if (!ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU) {
  12122. DEBUG_skipLog001 || console1.log("ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU - N/A", tag);
  12123. } else {
  12124. console1.log("ADVANCED_NOT_ALLOW_SCROLL_FOR_SHOW_CONTEXT_MENU - NG", tag);
  12125. }
  12126.  
  12127.  
  12128. 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) {
  12129. cProto.showContextMenu47_ = cProto.showContextMenu_;
  12130. cProto.showContextMenu47 = cProto.showContextMenu;
  12131. cProto.__showContextMenu_mutex_unlock_isEmpty__ = dProto.__showContextMenu_mutex_unlock_isEmpty__;
  12132. cProto.__showContextMenu_assign_lock__ = dProto.__showContextMenu_assign_lock__;
  12133. cProto.showContextMenu = dProto.showContextMenuWithMutex;
  12134. cProto.showContextMenu_ = dProto.showContextMenuWithMutex_;
  12135. console1.log("ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU - OK", tag);
  12136. } else {
  12137. console1.log("ENABLE_MUTEX_FOR_SHOW_CONTEXT_MENU - NG", tag);
  12138. }
  12139.  
  12140. })();
  12141.  
  12142. }
  12143.  
  12144. console1.log("[End]");
  12145.  
  12146. groupEnd();
  12147.  
  12148. }).catch(console.warn);
  12149.  
  12150.  
  12151.  
  12152. if (FIX_UNKNOWN_BUG_FOR_OVERLAY) {
  12153. // this is to fix " TypeError: this.backdropElement.prepare is not a function "
  12154.  
  12155. customElements.whenDefined('tp-yt-paper-dialog').then(() => {
  12156.  
  12157.  
  12158. mightFirstCheckOnYtInit();
  12159. groupCollapsed("YouTube Super Fast Chat", " | tp-yt-paper-dialog hacks");
  12160. console1.log("[Begin]");
  12161. (() => {
  12162.  
  12163. const tag = "tp-yt-paper-dialog";
  12164. const dummy = document.createElement(tag);
  12165.  
  12166. const cProto = getProto(dummy);
  12167. if (!cProto || !cProto.attached) {
  12168. console1.warn(`proto.attached for ${tag} is unavailable.`);
  12169. return;
  12170. }
  12171.  
  12172. if (typeof cProto.__openedChanged === 'function' && !cProto.__openedChanged49 && cProto.__openedChanged.length === 0) {
  12173.  
  12174.  
  12175. cProto.__openedChanged49 = cProto.__openedChanged;
  12176.  
  12177. cProto.__openedChanged = function () {
  12178. const manager = (this || 0)._manager || 0;
  12179. if (manager && !manager.trackBackdrop49 && manager.trackBackdrop) {
  12180. manager.trackBackdrop49 = manager.trackBackdrop;
  12181. if (manager.trackBackdrop.length === 0) {
  12182. manager.trackBackdrop = function () {
  12183. try {
  12184. return this.trackBackdrop49();
  12185. } catch (e) {
  12186. let showMessage = true;
  12187. if (e instanceof TypeError && e.message === 'this.backdropElement.prepare is not a function') {
  12188. // this is well known issue.
  12189. showMessage = false;
  12190. }
  12191. showMessage && console.log('manager.trackBackdrop', e);
  12192. }
  12193. }
  12194. }
  12195. }
  12196. return this.__openedChanged49();
  12197. };
  12198.  
  12199.  
  12200. }
  12201.  
  12202.  
  12203. })();
  12204.  
  12205.  
  12206. console1.log("[End]");
  12207.  
  12208. groupEnd();
  12209.  
  12210.  
  12211. }).catch(console.warn);
  12212.  
  12213. }
  12214.  
  12215.  
  12216. customElements.whenDefined('tp-yt-iron-dropdown').then(() => {
  12217.  
  12218. mightFirstCheckOnYtInit();
  12219. groupCollapsed("YouTube Super Fast Chat", " | tp-yt-iron-dropdown hacks");
  12220. console1.log("[Begin]");
  12221. (() => {
  12222.  
  12223. const tag = "tp-yt-iron-dropdown";
  12224. const dummy = document.createElement(tag);
  12225.  
  12226. const cProto = getProto(dummy);
  12227. if (!cProto || !cProto.attached) {
  12228. console1.warn(`proto.attached for ${tag} is unavailable.`);
  12229. return;
  12230. }
  12231.  
  12232. if (USE_VANILLA_DEREF && typeof cProto.__deraf === 'function' && cProto.__deraf.length === 2 && !cProto.__deraf34 && fnIntegrity(cProto.__deraf) === '2.42.24') {
  12233. cProto.__deraf_hn__ = function (sId, fn) {
  12234. const rhKey = `_rafHandler_${sId}`;
  12235. const m = this[rhKey] || (this[rhKey] = new WeakMap());
  12236. if (m.has(fn)) return m.get(fn);
  12237. const resFn = () => {
  12238. this.__rafs[sId] = null;
  12239. fn.call(this)
  12240. };
  12241. m.set(fn, resFn);
  12242. m.set(resFn, resFn);
  12243. return resFn;
  12244. };
  12245. cProto.__deraf34 = cProto.__deraf;
  12246. cProto.__deraf = function (a, b) { // sId, fn
  12247. let c = this.__rafs;
  12248. null !== c[a] && cancelAnimationFrame(c[a]);
  12249. c[a] = requestAnimationFrame(this.__deraf_hn__(a, b));
  12250. };
  12251. console1.log("USE_VANILLA_DEREF - OK");
  12252. } else {
  12253. console1.log("USE_VANILLA_DEREF - NG");
  12254. }
  12255.  
  12256. if (FIX_DROPDOWN_DERAF && typeof cProto.__deraf === 'function' && cProto.__deraf.length === 2 && !cProto.__deraf66) {
  12257. cProto.__deraf66 = cProto.__deraf;
  12258. cProto.__deraf = function (sId, fn) {
  12259. if (this.__byPassRAF__) {
  12260. Promise.resolve(this).then((cnt) => {
  12261. fn.call(cnt);
  12262. cnt = null;
  12263. });
  12264. }
  12265. let r = this.__deraf66.apply(this, arguments);
  12266. return r;
  12267. }
  12268. console1.log("FIX_DROPDOWN_DERAF - OK");
  12269. } else {
  12270. console1.log("FIX_DROPDOWN_DERAF - NG");
  12271. }
  12272.  
  12273.  
  12274. if (BOOST_MENU_OPENCHANGED_RENDERING && typeof cProto.__openedChanged === 'function' && !cProto.__mtChanged__ && fnIntegrity(cProto.__openedChanged) === '0.46.20') {
  12275.  
  12276. let lastClose = null;
  12277. let lastOpen = null;
  12278. let cid = 0;
  12279.  
  12280. cProto.__mtChanged__ = function (b) {
  12281.  
  12282. Promise.resolve(this).then((cnt) => {
  12283. cnt._applyFocus();
  12284. return cnt;
  12285. }).then((cnt) => {
  12286. b ? cnt._renderOpened() : cnt._renderClosed();
  12287. cnt = null;
  12288. }).catch(console.warn);
  12289.  
  12290. };
  12291.  
  12292. const __moChanged__ = () => {
  12293. if (!cid) return;
  12294. // console.log(553, !!lastOpen, !!lastClose);
  12295. cid = 0;
  12296. if (lastOpen && !lastClose && lastOpen.isAttached) {
  12297. lastOpen.__mtChanged__(1)
  12298. } else if (lastClose && !lastOpen && lastClose.isAttached) {
  12299. lastClose.__mtChanged__(0);
  12300. }
  12301. lastOpen = null;
  12302. lastClose = null;
  12303. };
  12304.  
  12305.  
  12306. if (typeof cProto._openedChanged === 'function' && !cProto._openedChanged66) {
  12307. cProto._openedChanged66 = cProto._openedChanged;
  12308. cProto._openedChanged = function () {
  12309. // this.__byPassRAF__ = !lastOpen ? true : false; // or just true?
  12310. this.__byPassRAF__ = true;
  12311. let r = this._openedChanged66.apply(this, arguments);
  12312. this.__byPassRAF__ = false;
  12313. return r;
  12314. }
  12315. }
  12316.  
  12317. const pSetGet = (key, pdThis, pdBase) => {
  12318. // note: this is not really a standard way for the getOwnPropertyDescriptors; but it is sufficient to make the job done
  12319. return {
  12320. get: (pdThis[key] || 0).get || (pdBase[key] || 0).get,
  12321. set: (pdThis[key] || 0).set || (pdBase[key] || 0).set
  12322. };
  12323. };
  12324.  
  12325. cProto.__modifiedMenuPropsFn__ = function () {
  12326. const pdThis = Object.getOwnPropertyDescriptors(this.constructor.prototype)
  12327. const pdBase = Object.getOwnPropertyDescriptors(this)
  12328.  
  12329. const pdAutoFitOnAttach = pSetGet('autoFitOnAttach', pdThis, pdBase);
  12330. const pdExpandSizingTargetForScrollbars = pSetGet('expandSizingTargetForScrollbars', pdThis, pdBase);
  12331. const pdAllowOutsideScroll = pSetGet('allowOutsideScroll', pdThis, pdBase);
  12332.  
  12333. if (pdAutoFitOnAttach.get || pdAutoFitOnAttach.set) {
  12334. console.warn('there is setter/getter for autoFitOnAttach');
  12335. return;
  12336. }
  12337. if (pdExpandSizingTargetForScrollbars.get || pdExpandSizingTargetForScrollbars.set) {
  12338. console.warn('there is setter/getter for expandSizingTargetForScrollbars');
  12339. return;
  12340. }
  12341. if (!pdAllowOutsideScroll.get || !pdAllowOutsideScroll.set) {
  12342. console.warn('there is NO setter-getter for allowOutsideScroll');
  12343. return;
  12344. }
  12345.  
  12346. let { autoFitOnAttach, expandSizingTargetForScrollbars, allowOutsideScroll } = this;
  12347.  
  12348. this.__AllowOutsideScrollPD__ = pdAllowOutsideScroll;
  12349.  
  12350. const fitEnable = CHAT_MENU_REFIT_ALONG_SCROLLING === 2;
  12351.  
  12352. Object.defineProperties(this, {
  12353. autoFitOnAttach: {
  12354. get() {
  12355. if (fitEnable && this._modifiedMenuPropOn062__) return true;
  12356. return autoFitOnAttach;
  12357. },
  12358. set(nv) {
  12359. autoFitOnAttach = nv;
  12360. return true;
  12361. },
  12362. enumerable: true,
  12363. configurable: true
  12364. }, expandSizingTargetForScrollbars: {
  12365. get() {
  12366. if (fitEnable && this._modifiedMenuPropOn062__) return true;
  12367. return expandSizingTargetForScrollbars;
  12368. },
  12369. set(nv) {
  12370. expandSizingTargetForScrollbars = nv;
  12371. return true;
  12372. },
  12373. enumerable: true,
  12374. configurable: true
  12375. }, allowOutsideScroll: {
  12376. get() {
  12377. if (this._modifiedMenuPropOn062__) return true;
  12378. return allowOutsideScroll;
  12379. },
  12380. set(nv) {
  12381. allowOutsideScroll = nv;
  12382. this.__AllowOutsideScrollPD__.set.call(this, nv);
  12383. return true;
  12384. },
  12385. enumerable: true,
  12386. configurable: true
  12387. }
  12388. })
  12389. };
  12390.  
  12391. /*
  12392. // ***** position() to be changed. *****
  12393. tp-yt-iron-dropdown[class], tp-yt-iron-dropdown[class] #contentWrapper, tp-yt-iron-dropdown[class] ytd-menu-popup-renderer[class] {
  12394.  
  12395. overflow: visible !important;
  12396. min-width: max-content !important;
  12397. max-width: max-content !important;
  12398. max-height: max-content !important;
  12399. min-height: max-content !important;
  12400. white-space: nowrap;
  12401. }
  12402.  
  12403. */
  12404. if (FIX_MENU_POSITION_N_SIZING_ON_SHOWN && typeof cProto.position === 'function' && !cProto.position34 && typeof cProto.refit === 'function') {
  12405.  
  12406. let m34 = 0;
  12407. cProto.__refitByPosition__ = function () {
  12408. m34++;
  12409. if (m34 <= 0) m34 = 0;
  12410. if (m34 !== 1) return;
  12411. const hostElement = this.hostElement || this;
  12412. if (document.visibilityState === 'visible') {
  12413. const sizingTarget = this.sizingTarget;
  12414. if (!sizingTarget) {
  12415. m34 = 0;
  12416. return;
  12417. }
  12418. hostElement.setAttribute('rNgzQ', '');
  12419. sizingTarget.setAttribute('rNgzQ', '');
  12420.  
  12421. const gn = () => {
  12422. hostElement.removeAttribute('rNgzQ');
  12423. sizingTarget.removeAttribute('rNgzQ');
  12424. }
  12425.  
  12426. const an = async () => {
  12427. while (m34 >= 1) {
  12428. await renderReadyPn(sizingTarget);
  12429. if (this.opened && this.isAttached && sizingTarget.isConnected === true && sizingTarget === this.sizingTarget) {
  12430. if (sizingTarget.matches('ytd-menu-popup-renderer[slot="dropdown-content"].yt-live-chat-app')) this.refit();
  12431. }
  12432. m34--;
  12433. }
  12434. m34 = 0;
  12435. Promise.resolve().then(gn);
  12436. }
  12437. setTimeout(an, 4); // wait those resizing function calls
  12438.  
  12439.  
  12440. } else {
  12441. m34 = 0;
  12442. }
  12443. }
  12444. cProto.position34 = cProto.position
  12445. cProto.position = function () {
  12446. if (this._positionInitialize_) {
  12447. this._positionInitialize_ = 0;
  12448. this.__refitByPosition__();
  12449. }
  12450. let r = cProto.position34.apply(this, arguments);
  12451. return r;
  12452. }
  12453. console1.log("FIX_MENU_POSITION_ON_SHOWN - OK");
  12454.  
  12455. } else {
  12456.  
  12457. console1.log("FIX_MENU_POSITION_ON_SHOWN - NG");
  12458.  
  12459. }
  12460.  
  12461.  
  12462.  
  12463. cProto.__openedChanged = function () {
  12464. // console.log(123445)
  12465. this._positionInitialize_ = 1;
  12466. // this.removeAttribute('horizontal-align')
  12467. // this.removeAttribute('vertical-align')
  12468. if (typeof this.__menuTypeCheck__ !== 'boolean') {
  12469. this.__menuTypeCheck__ = true;
  12470. if (CHAT_MENU_SCROLL_UNLOCKING) {
  12471. this._modifiedMenuPropOn062__ = false;
  12472. // console.log(513, this.positionTarget && this.positionTarget.classList.contains('yt-live-chat-text-message-renderer'))
  12473. // this.autoFitOnAttach = true;
  12474. // this.expandSizingTargetForScrollbars = true;
  12475. // this.allowOutsideScroll = true;
  12476. // console.log(519,Object.getOwnPropertyDescriptors(this.constructor.prototype))
  12477. this.__modifiedMenuPropsFn__();
  12478. // this.constrain= function(){}
  12479. // this.position= function(){}
  12480.  
  12481. // this.autoFitOnAttach = true;
  12482. // this.expandSizingTargetForScrollbars = true;
  12483. // this.allowOutsideScroll = true;
  12484. }
  12485. }
  12486. if (CHAT_MENU_SCROLL_UNLOCKING && this.opened) {
  12487. let newValue = null;
  12488. const positionTarget = this.positionTarget;
  12489. if (positionTarget && positionTarget.classList.contains('yt-live-chat-text-message-renderer')) {
  12490. if (this._modifiedMenuPropOn062__ === false) {
  12491. newValue = true;
  12492. }
  12493. } else if (this._modifiedMenuPropOn062__ === true) {
  12494. newValue = false;
  12495. }
  12496. if (newValue !== null) {
  12497. const beforeAllowOutsideScroll = this.allowOutsideScroll;
  12498. this._modifiedMenuPropOn062__ = newValue;
  12499. const afterAllowOutsideScroll = this.allowOutsideScroll;
  12500. if (beforeAllowOutsideScroll !== afterAllowOutsideScroll) this.__AllowOutsideScrollPD__.set.call(this, afterAllowOutsideScroll);
  12501. }
  12502. }
  12503.  
  12504. if (this.opened) {
  12505.  
  12506. Promise.resolve().then(() => {
  12507.  
  12508. this._prepareRenderOpened();
  12509. }).then(() => {
  12510. // console.log('[yt-chat-dialog]', this._manager)
  12511. try{
  12512. this._manager.addOverlay(this);
  12513. }catch(e){
  12514. console.log('this._manager.addOverlay(this) fails.')
  12515. }
  12516. if (this._manager._overlays.length === 1) {
  12517. lastOpen = this;
  12518. lastClose = null;
  12519. } else {
  12520. return 1;
  12521. }
  12522. // if (cid) {
  12523. // clearTimeout(cid);
  12524. // cid = -1;
  12525. // this.__moChanged__();
  12526. // cid = 0;
  12527. // } else {
  12528. // cid = -1;
  12529. // this.__moChanged__();
  12530. // cid = 0;
  12531. // }
  12532. // cid = cid > 0 ? clearTimeout(cid) : 0;
  12533. // console.log(580, this.positionTarget && this.positionTarget.classList.contains('yt-live-chat-text-message-renderer'))
  12534. // cid = cid || setTimeout(__moChanged__, delay1);
  12535. cid = cid || requestAnimationFrame(__moChanged__);
  12536. }).then((r) => {
  12537.  
  12538. if (r) this.__mtChanged__(1);
  12539. }).catch(console.warn);
  12540.  
  12541. } else {
  12542. Promise.resolve().then(() => {
  12543. // console.log('[yt-chat-dialog]', this._manager)
  12544. try{
  12545. this._manager.removeOverlay(this);
  12546. }catch(e){
  12547. console.log('this._manager.removeOverlay(this) fails.')
  12548. }
  12549. if (this._manager._overlays.length === 0) {
  12550. lastClose = this;
  12551. lastOpen = null;
  12552. } else {
  12553. return 1;
  12554. }
  12555. // cid = cid > 0 ? clearTimeout(cid) : 0;
  12556. // console.log(581, this.positionTarget && this.positionTarget.classList.contains('yt-live-chat-text-message-renderer'))
  12557. // cid = cid || setTimeout(__moChanged__, delay1);
  12558. cid = cid || requestAnimationFrame(__moChanged__);
  12559. }).then((r) => {
  12560. if (r) this.__mtChanged__(0);
  12561. }).catch(console.warn);
  12562.  
  12563. }
  12564.  
  12565. }
  12566. console1.log("BOOST_MENU_OPENCHANGED_RENDERING - OK");
  12567.  
  12568. } else {
  12569.  
  12570. assertor(() => fnIntegrity(cProto.__openedChanged, '0.46.20'));
  12571. console1.log("FIX_MENU_REOPEN_RENDER_PERFORMANC_1 - NG");
  12572.  
  12573. }
  12574.  
  12575.  
  12576. if (FIX_CLICKING_MESSAGE_MENU_DISPLAY_ON_MOUSE_CLICK && typeof cProto.__openedChanged === 'function' && !cProto.__openedChanged82) {
  12577.  
  12578. cProto.__openedChanged82 = cProto.__openedChanged;
  12579.  
  12580.  
  12581. cProto.__openedChanged = function () {
  12582. const positionTarget = this.positionTarget;
  12583. currentMenuPivotWR = positionTarget ? mWeakRef(positionTarget) : null;
  12584. return this.__openedChanged82.apply(this, arguments);
  12585. }
  12586. }
  12587.  
  12588.  
  12589. })();
  12590.  
  12591. console1.log("[End]");
  12592.  
  12593. groupEnd();
  12594.  
  12595. }).catch(console.warn);
  12596.  
  12597.  
  12598.  
  12599. FIX_ToggleRenderPolymerControllerExtractionBug && customElements.whenDefined('yt-live-chat-toggle-renderer').then(() => {
  12600.  
  12601. mightFirstCheckOnYtInit();
  12602. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-toggle-renderer hacks");
  12603. console1.log("[Begin]");
  12604. (() => {
  12605.  
  12606. const tag = "yt-live-chat-toggle-renderer";
  12607. const dummy = document.createElement(tag);
  12608.  
  12609. const cProto = getProto(dummy);
  12610. if (!cProto || !cProto.attached) {
  12611. console1.warn(`proto.attached for ${tag} is unavailable.`);
  12612. return;
  12613. }
  12614.  
  12615. })();
  12616.  
  12617. console1.log("[End]");
  12618. groupEnd();
  12619.  
  12620. });
  12621.  
  12622. FIX_MOUSEOVER_FN && (() => {
  12623.  
  12624. // this is to show tooltip for emoji
  12625.  
  12626.  
  12627. let lastShow = 0;
  12628.  
  12629. const wm = new WeakSet();
  12630. const mo1 = new MutationObserver((mutations) => {
  12631.  
  12632. for (const p of document.querySelectorAll('[shared-tooltip-text]:not([__a6cwm__])')) {
  12633. p.setAttribute('__a6cwm__', '');
  12634. }
  12635.  
  12636. });
  12637. mo1.observe(document, { subtree: true, attributes: true, attributeFilter: ['shared-tooltip-text'], childList: true });
  12638.  
  12639. const mo2 = new MutationObserver((mutations) => {
  12640.  
  12641. for (const mutation of mutations) {
  12642. const p = mutation.target;
  12643. if (mutation.attributeName) {
  12644. if (p.getAttribute('shared-tooltip-text')) { // allow hack
  12645. wm.add(p);
  12646. for (const e of p.getElementsByTagName('*')) {
  12647. wm.add(e);
  12648. }
  12649. } else {
  12650. if (wm.has(p)) {
  12651. wm.remove(p);
  12652. for (const e of p.getElementsByTagName('*')) {
  12653. wm.remove(e);
  12654. }
  12655. }
  12656. }
  12657. }
  12658. }
  12659. });
  12660. mo2.observe(document, { subtree: true, attributes: true, attributeFilter: ['__a6cwm__', 'shared-tooltip-text'], childList: false });
  12661.  
  12662.  
  12663. let done = 0;
  12664. // lcrFn2 will run twice to ensure the method is successfully injected.
  12665. const lcrFn2 = (lcrDummy) => {
  12666. // make minimal function overhead by pre-defining all possible outside.
  12667.  
  12668. const tag = "yt-live-chat-renderer"
  12669. const dummy = lcrDummy;
  12670.  
  12671. const cProto = getProto(dummy);
  12672. if (!cProto || !cProto.attached) {
  12673. console.warn(`proto.attached for ${tag} is unavailable.`);
  12674. return;
  12675. }
  12676.  
  12677. // mightFirstCheckOnYtInit();
  12678. // groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-renderer hacks");
  12679. // console.log("[Begin]");
  12680.  
  12681.  
  12682.  
  12683. if (done !== 1 && typeof cProto.onMouseOver_ === 'function' && !cProto.onMouseOver37_ && typeof cProto.createTooltipIfRequired_ === 'function' && cProto.createTooltipIfRequired_.length === 0) {
  12684.  
  12685. done = 1;
  12686. const onMouseOver37_ = cProto.onMouseOver37_ = cProto.onMouseOver_;
  12687.  
  12688. const checkMatch = (() => {
  12689.  
  12690.  
  12691. let accessList = [];
  12692. let withError = false;
  12693. try {
  12694.  
  12695. onMouseOver37_.call(lcrDummy, {
  12696. type: 'mouseover',
  12697. target: new Proxy({
  12698. nodeName: 'DIV',
  12699. tagName: 'DIV',
  12700. getAttribute: function () { },
  12701. parentNode: null
  12702. }, {
  12703. get(target, p) {
  12704. accessList.push(`getter:${p}`);
  12705. if (!(p in target)) throw Error(`getter ${p} is not found`);
  12706. },
  12707. set(target, p, v) {
  12708. accessList.push(`setter:${p}`);
  12709. throw Error(`setter ${p} is not found`);
  12710. }
  12711. })
  12712. });
  12713. } catch (e) {
  12714. withError = true;
  12715. // console.warn(e);
  12716. }
  12717.  
  12718. if (withError) return false;
  12719.  
  12720. if (accessList.join(',') !== 'getter:getAttribute,getter:parentNode') return false;
  12721.  
  12722. accessList.length = 0;
  12723.  
  12724. let parent;
  12725. try {
  12726.  
  12727. parent = new Proxy({
  12728. nodeName: 'DIV',
  12729. tagName: 'DIV',
  12730. getAttribute: function (e) {
  12731.  
  12732. accessList.push(`getter:getAttribute(${e})`);
  12733. return e === 'shared-tooltip-text' ? ':cherry_blossom:' : null;
  12734.  
  12735. },
  12736. parentNode: null
  12737. }, {
  12738. get(target, p) {
  12739. accessList.push(`getter:${p}`);
  12740. if (!(p in target)) throw Error(`getter ${p} is not found`);
  12741. return target[p]
  12742. },
  12743. set(target, p, v) {
  12744. accessList.push(`setter:${p}`);
  12745. throw Error(`setter ${p} is not found`);
  12746. }
  12747. });
  12748.  
  12749. onMouseOver37_.call(lcrDummy, {
  12750. type: 'mouseover',
  12751. target: new Proxy({
  12752. nodeName: 'IMG',
  12753. tagName: 'IMG',
  12754. id: 'img',
  12755. getAttribute: function (e) {
  12756.  
  12757. accessList.push(`getter:getAttribute(${e})`);
  12758. return e === 'shared-tooltip-text' ? ':cherry_blossom:' : null;
  12759.  
  12760. },
  12761. get parentNode() {
  12762. return parent
  12763. },
  12764. get parentElement() {
  12765. return parent
  12766. }
  12767. }, {
  12768. get(target, p) {
  12769. accessList.push(`getter:${p}`);
  12770. if (!(p in target)) throw Error(`getter ${p} is not found`);
  12771. return target[p]
  12772. },
  12773. set(target, p, v) {
  12774. accessList.push(`setter:${p}`);
  12775. throw Error(`setter ${p} is not found`);
  12776. }
  12777. })
  12778. });
  12779. } catch (e) {
  12780. withError = true;
  12781. // console.warn(e);
  12782. }
  12783. parent = null;
  12784.  
  12785. if (withError && accessList.join(',') === 'getter:getAttribute,getter:getAttribute,getter:getAttribute(shared-tooltip-text),getter:getAttribute,getter:getAttribute(shared-tooltip-text),getter:tagName,getter:parentElement,getter:id,getter:id,getter:$$') {
  12786. return true;
  12787. }
  12788.  
  12789.  
  12790.  
  12791. })();
  12792. if (checkMatch) {
  12793.  
  12794. cProto.onMouseOver_ = function (evt) {
  12795. const p = (evt || 0).target || 0;
  12796. if (p.nodeType === 1 && wm.has(p)) {
  12797. const ct = Date.now();
  12798. if (lastShow + 18 > ct) return;
  12799. const cnt = insp(this);
  12800. lastShow = ct;
  12801. try {
  12802. cnt.onMouseOver37_.call(this, evt);
  12803. } catch (e) {
  12804. console.warn(e);
  12805. }
  12806. }
  12807. };
  12808.  
  12809. const lcrs = toUniqueArr([lcrDummy, ...document.querySelectorAll('yt-live-chat-renderer')]);
  12810. for (const lcr of lcrs) {
  12811. const cnt = insp(lcr);
  12812. const hostElement = cnt.hostElement;
  12813. if (hostElement && cnt.isAttached === true && cnt.onMouseOver37_ === cProto.onMouseOver37_ && typeof cProto.onMouseOver_ === 'function' && cProto.onMouseOver_ !== cProto.onMouseOver37_ && cnt.onMouseOver_ === cProto.onMouseOver_) {
  12814. hostElement.removeEventListener("mouseover", cProto.onMouseOver37_, !0)
  12815. hostElement.addEventListener("mouseover", cProto.onMouseOver_, !0)
  12816. }
  12817. }
  12818.  
  12819. console.log('[yt-chat-lcr] FIX_MOUSEOVER_FN - OK')
  12820.  
  12821. } else {
  12822.  
  12823. console.log('[yt-chat-lcr] FIX_MOUSEOVER_FN - NG')
  12824.  
  12825. }
  12826.  
  12827. } else if (done !== 1) {
  12828. done = 2;
  12829. console.log('[yt-chat-lcr] FIX_MOUSEOVER_FN - NG')
  12830. }
  12831.  
  12832. // console.log("[End]");
  12833. // groupEnd();
  12834.  
  12835.  
  12836. };
  12837. !__LCRInjection__ && LCRImmedidates.push(lcrFn2);
  12838. // getLCRDummy() must be called for injection
  12839. getLCRDummy().then(lcrFn2);
  12840.  
  12841. })();
  12842.  
  12843.  
  12844. /*
  12845.  
  12846.  
  12847.  
  12848.  
  12849.  
  12850. var FU = function() {
  12851. var a = this;
  12852. this.nextHandle_ = 1;
  12853. this.clients_ = {};
  12854. this.JSC$10323_callbacks_ = {};
  12855. this.unsubscribeAsyncHandles_ = {};
  12856. this.subscribe = vl(function(b, c, d) {
  12857. var e = Geb(b);
  12858. if (e in a.clients_)
  12859. e in a.unsubscribeAsyncHandles_ && Jq.cancel(a.unsubscribeAsyncHandles_[e]);
  12860. else {
  12861. a: {
  12862. var h = Geb(b), l;
  12863. for (l in a.unsubscribeAsyncHandles_) {
  12864. var m = a.clients_[l];
  12865. if (m instanceof KO) {
  12866. delete a.clients_[l];
  12867. delete a.JSC$10323_callbacks_[l];
  12868. Jq.cancel(a.unsubscribeAsyncHandles_[l]);
  12869. delete a.unsubscribeAsyncHandles_[l];
  12870. i6a(m);
  12871. m.objectId_ = new FQa(h);
  12872. m.register();
  12873. d = m;
  12874. break a
  12875. }
  12876. }
  12877. d.objectSource = b.invalidationId.objectSource;
  12878. d.objectId = h;
  12879. if (b = b.webAuthConfigurationData)
  12880. b.multiUserSessionIndex && (d.sessionIndex = parseInt(b.multiUserSessionIndex, 10)),
  12881. b.pageId && (d.pageId = b.pageId);
  12882. d = new KO(d,a.handleInvalidationData_.bind(a));
  12883. d.register()
  12884. }
  12885. a.clients_[e] = d;
  12886. a.JSC$10323_callbacks_[e] = {}
  12887. }
  12888. d = a.nextHandle_++;
  12889. a.JSC$10323_callbacks_[e][d] = c;
  12890. return d
  12891. })
  12892. };
  12893. FU.prototype.unsubscribe = function(a, b) {
  12894. var c = Geb(a);
  12895. if (c in this.JSC$10323_callbacks_ && (delete this.JSC$10323_callbacks_[c][b],
  12896. !this.JSC$10323_callbacks_[c].length)) {
  12897. var d = this.clients_[c];
  12898. b = Jq.run(function() {
  12899. ei(d);
  12900. delete this.clients_[c];
  12901. delete this.unsubscribeAsyncHandles_[c]
  12902. }
  12903. .bind(this));
  12904. this.unsubscribeAsyncHandles_[c] = b
  12905. }
  12906. }
  12907. ;
  12908.  
  12909.  
  12910. */
  12911.  
  12912.  
  12913. const onManagerFound = (dummyManager) => {
  12914. if (!dummyManager || typeof dummyManager !== 'object') return;
  12915.  
  12916. const mgrProto = dummyManager.constructor.prototype;
  12917.  
  12918. let keyCallbackStore = '';
  12919. for (const [key, v] of Object.entries(dummyManager)) {
  12920. if (key.includes('_callbacks_')) keyCallbackStore = key;
  12921. }
  12922.  
  12923. if (!keyCallbackStore || typeof mgrProto.unsubscribe !== 'function' || mgrProto.unsubscribe.length !== 2) return;
  12924.  
  12925. if (mgrProto.unsubscribe16) return;
  12926.  
  12927. mgrProto.unsubscribe16 = mgrProto.unsubscribe;
  12928.  
  12929. groupCollapsed("YouTube Super Fast Chat", " | *live-chat-manager* hacks");
  12930. console1.log("[Begin]");
  12931.  
  12932. const idMapper = new Map();
  12933.  
  12934. const convertId = function (objectId) {
  12935. if (!objectId || typeof objectId !== 'string') return null;
  12936.  
  12937. let result = idMapper.get(objectId)
  12938. if (result) return result;
  12939. result = atob(objectId.replace(/-/g, "+").replace(/_/g, "/"));
  12940. idMapper.set(objectId, result)
  12941. return result;
  12942. }
  12943.  
  12944.  
  12945. const rafHandleHolder = [];
  12946.  
  12947. let pzw = 0;
  12948. let lza = 0;
  12949. const rafHandlerFn = () => {
  12950. pzw = 0;
  12951. if (rafHandleHolder.length === 1) {
  12952. const f = rafHandleHolder[0];
  12953. rafHandleHolder.length = 0;
  12954. f();
  12955. } else if (rafHandleHolder.length > 1) {
  12956. const arr = rafHandleHolder.slice(0);
  12957. rafHandleHolder.length = 0;
  12958. for (const fn of arr) fn();
  12959. }
  12960. };
  12961.  
  12962.  
  12963. if (CHANGE_MANAGER_UNSUBSCRIBE) {
  12964.  
  12965. const checkIntegrityForSubscribe = (mgr) => {
  12966. if (mgr
  12967. && typeof mgr.unsubscribe16 === 'function' && mgr.unsubscribe16.length === 2
  12968. && typeof mgr.subscribe18 === 'function' && (mgr.subscribe18.length === 0 || mgr.subscribe18.length === 3)) {
  12969.  
  12970. const ns = new Set(Object.keys(mgr));
  12971. const ms = new Set(Object.keys(mgr.constructor.prototype));
  12972.  
  12973. if (ns.size >= 6 && ms.size >= 4) {
  12974. // including 'subscribe18'
  12975. // 'unsubscribe16', 'subscribe19'
  12976.  
  12977. let r = 0;
  12978. for (const k of ['nextHandle_', 'clients_', keyCallbackStore, 'unsubscribeAsyncHandles_', 'subscribe', 'subscribe18']) {
  12979. r += ns.has(k) ? 1 : 0;
  12980. }
  12981. for (const k of ['unsubscribe', 'handleInvalidationData_', 'unsubscribe16', 'subscribe19']) {
  12982. r += ms.has(k) ? 1 : 0;
  12983. }
  12984. if (r === 10) {
  12985. const isObject = (c) => (c || 0).constructor === Object;
  12986.  
  12987. if (isObject(mgr['clients_']) && isObject(mgr[keyCallbackStore]) && isObject(mgr['unsubscribeAsyncHandles_'])) {
  12988.  
  12989. return true;
  12990. }
  12991.  
  12992.  
  12993. }
  12994.  
  12995. }
  12996.  
  12997.  
  12998. }
  12999. return false;
  13000. }
  13001.  
  13002. mgrProto.subscribe19 = function (o, f, opts) {
  13003.  
  13004. const ct_clients_ = this.clients_ || 0;
  13005. const ct_handles_ = this.unsubscribeAsyncHandles_ || 0;
  13006.  
  13007. if (this.__doCustomSubscribe__ !== true || !ct_clients_ || !ct_handles_) return this.subscribe18.apply(this, arguments);
  13008.  
  13009. let objectId = ((o || 0).invalidationId || 0).objectId;
  13010. if (!objectId) return this.subscribe18.apply(this, arguments);
  13011. objectId = convertId(objectId);
  13012.  
  13013. // console.log('subscribe', objectId, ct_clients_[objectId], arguments);
  13014.  
  13015. if (ct_clients_[objectId]) {
  13016. if (ct_handles_[objectId] < 0) delete ct_handles_[objectId];
  13017. }
  13018.  
  13019. return this.subscribe18.apply(this, arguments);
  13020. }
  13021.  
  13022. mgrProto.unsubscribe = function (o, d) {
  13023. if (!this.subscribe18 && typeof this.subscribe === 'function') {
  13024. this.subscribe18 = this.subscribe;
  13025. this.subscribe = this.subscribe19;
  13026. this.__doCustomSubscribe__ = checkIntegrityForSubscribe(this);
  13027. }
  13028. const ct_clients_ = this.clients_;
  13029. const ct_handles_ = this.unsubscribeAsyncHandles_;
  13030. if (this.__doCustomSubscribe__ !== true || !ct_clients_ || !ct_handles_) return this.unsubscribe16.apply(this, arguments);
  13031.  
  13032. let objectId = ((o || 0).invalidationId || 0).objectId;
  13033. if (!objectId) return this.unsubscribe16.apply(this, arguments);
  13034.  
  13035. objectId = convertId(objectId);
  13036.  
  13037.  
  13038. // console.log('unsubscribe', objectId, ct_clients_[objectId], arguments);
  13039.  
  13040. const callbacks = this[keyCallbackStore] || 0;
  13041. const callbackObj = callbacks[objectId] || 0;
  13042.  
  13043.  
  13044. if (callbackObj && (delete callbackObj[d], isEmptyObject(callbackObj))) {
  13045. const w = ct_clients_[objectId];
  13046. lza = (lza & 1073741823) + 1;
  13047. const qta = -lza;
  13048. rafHandleHolder.push(() => {
  13049. if (qta === ct_handles_[objectId]) {
  13050. const o = {
  13051. callbacks, callbackObj,
  13052. client: ct_clients_[objectId],
  13053. handle: ct_handles_[objectId]
  13054. };
  13055. let p = 0;
  13056. try {
  13057. if (ct_clients_[objectId] === w) {
  13058. w && "function" === typeof w.dispose && w.dispose();
  13059. delete ct_clients_[objectId];
  13060. delete ct_handles_[objectId];
  13061. p = 1;
  13062. } else {
  13063. // w && "function" === typeof w.dispose && w.dispose();
  13064. // delete ct_clients_[objectId];
  13065. // delete ct_handles_[objectId];
  13066. p = 2;
  13067. }
  13068. } catch (e) {
  13069. console.warn(e);
  13070. }
  13071. console.log(`unsubscribed: ${p}`, this, o);
  13072. }
  13073. });
  13074. ct_handles_[objectId] = qta;
  13075. if (pzw === 0) {
  13076. pzw = requestAnimationFrame(rafHandlerFn);
  13077. }
  13078. }
  13079. }
  13080.  
  13081.  
  13082. console1.log("CHANGE_MANAGER_UNSUBSCRIBE - OK")
  13083.  
  13084. } else {
  13085.  
  13086. console1.log("CHANGE_MANAGER_UNSUBSCRIBE - NG")
  13087. }
  13088.  
  13089. console1.log("[End]");
  13090.  
  13091. groupEnd();
  13092.  
  13093. }
  13094.  
  13095.  
  13096.  
  13097. /*
  13098.  
  13099.  
  13100. a.prototype.async = function(e, h) {
  13101. return 0 < h ? Iq.run(e.bind(this), h) : ~Kq.run(e.bind(this))
  13102. }
  13103. ;
  13104. a.prototype.cancelAsync = function(e) {
  13105. 0 > e ? Kq.cancel(~e) : Iq.cancel(e)
  13106. }
  13107.  
  13108. */
  13109.  
  13110.  
  13111. (FASTER_ICON_RENDERING && Promise.all(
  13112. [
  13113. customElements.whenDefined("yt-icon-shape"),
  13114. customElements.whenDefined("yt-icon")
  13115. // document.createElement('icon-shape'),
  13116. ]
  13117. )).then(() => {
  13118. let cq = 0;
  13119. let dummys = [document.createElement('yt-icon-shape'), document.createElement('yt-icon')]
  13120. for (const dummy of dummys) {
  13121. let cProto = getProto(dummy);
  13122. if (cProto && typeof cProto.shouldRenderIconShape === 'function' && !cProto.shouldRenderIconShape571 && cProto.shouldRenderIconShape.length === 1) {
  13123. assertor(() => fnIntegrity(cProto.shouldRenderIconShape, '1.70.38'));
  13124. cq++;
  13125. cProto.shouldRenderIconShape571 = cProto.shouldRenderIconShape;
  13126. cProto.shouldRenderIconShape = function (a) {
  13127. if (this.isAnimatedIcon) return this.shouldRenderIconShape571(a);
  13128. if (!this.iconType || !this.iconShapeData) return this.shouldRenderIconShape571(a);
  13129. if (!this.iconName) return this.shouldRenderIconShape571(a);
  13130. return false;
  13131. // console.log(1051, this.iconType)
  13132. // console.log(1052, this.iconShapeData)
  13133. // console.log(1053, this.isAnimatedIcon)
  13134. }
  13135. }
  13136. // if(cProto && cProto.switchTemplateAtRegistration){
  13137. // cProto.switchTemplateAtRegistration = false;
  13138. // }
  13139. }
  13140. if (cq === 1) {
  13141. console.log("modified shouldRenderIconShape - Y")
  13142. } else {
  13143. console.log("modified shouldRenderIconShape - N", cq)
  13144. }
  13145. });
  13146.  
  13147. customElements.whenDefined("yt-invalidation-continuation").then(() => {
  13148.  
  13149. let __dummyManager__ = null;
  13150.  
  13151. mightFirstCheckOnYtInit();
  13152. groupCollapsed("YouTube Super Fast Chat", " | yt-invalidation-continuation hacks");
  13153. console1.log("[Begin]");
  13154. (() => {
  13155.  
  13156. const tag = "yt-invalidation-continuation"
  13157. const dummy = document.createElement(tag);
  13158.  
  13159. const cProto = getProto(dummy);
  13160. if (!cProto || !cProto.attached) {
  13161. console1.warn(`proto.attached for ${tag} is unavailable.`);
  13162. return;
  13163. }
  13164.  
  13165. const dummyManager = insp(dummy).manager_ || 0;
  13166. __dummyManager__ = dummyManager;
  13167.  
  13168.  
  13169. })();
  13170.  
  13171. console1.log("[End]");
  13172.  
  13173. groupEnd();
  13174.  
  13175.  
  13176.  
  13177. onManagerFound(__dummyManager__);
  13178.  
  13179. }).catch(console.warn);
  13180.  
  13181.  
  13182. if (INTERACTIVITY_BACKGROUND_ANIMATION >= 1) {
  13183.  
  13184. customElements.whenDefined("yt-live-interactivity-component-background").then(() => {
  13185.  
  13186. mightFirstCheckOnYtInit();
  13187. groupCollapsed("YouTube Super Fast Chat", " | yt-live-interactivity-component-background hacks");
  13188. console1.log("[Begin]");
  13189. (() => {
  13190.  
  13191. const tag = "yt-live-interactivity-component-background"
  13192. const dummy = document.createElement(tag);
  13193.  
  13194. const cProto = getProto(dummy);
  13195. if (!cProto || !cProto.attached) {
  13196. console1.warn(`proto.attached for ${tag} is unavailable.`);
  13197. return;
  13198. }
  13199.  
  13200. cProto.__toStopAfterRun__ = function (hostElement) {
  13201. let mo = new MutationObserver(() => {
  13202. mo.disconnect();
  13203. mo.takeRecords();
  13204. mo = null;
  13205. this.lottieAnimation && this.lottieAnimation.stop(); // primary
  13206. foregroundPromiseFn().then(() => { // if the lottieAnimation is started with rAf triggering
  13207. this.lottieAnimation && this.lottieAnimation.stop(); // fallback
  13208. });
  13209. });
  13210. mo.observe(hostElement, { subtree: true, childList: true });
  13211. }
  13212.  
  13213. if (INTERACTIVITY_BACKGROUND_ANIMATION >= 1 && typeof cProto.maybeLoadAnimationBackground === 'function' && !cProto.maybeLoadAnimationBackground77 && cProto.maybeLoadAnimationBackground.length === 0) {
  13214.  
  13215. cProto.maybeLoadAnimationBackground77 = cProto.maybeLoadAnimationBackground;
  13216. cProto.maybeLoadAnimationBackground = function () {
  13217. let toRun = true;
  13218. let stopAfterRun = false;
  13219. if (!this.__bypassDisableAnimationBackground__) {
  13220. let doFix = false;
  13221. if (INTERACTIVITY_BACKGROUND_ANIMATION === 1) {
  13222. if (!this.lottieAnimation) {
  13223. doFix = true;
  13224. }
  13225. } else if (INTERACTIVITY_BACKGROUND_ANIMATION === 2) {
  13226. doFix = true;
  13227. }
  13228. if (doFix) {
  13229. if (this.useAnimationBackground === true) {
  13230. console.log('DISABLE_INTERACTIVITY_BACKGROUND_ANIMATION', this.lottieAnimation);
  13231. }
  13232. toRun = true;
  13233. stopAfterRun = true;
  13234. }
  13235. }
  13236. if (toRun) {
  13237. if (stopAfterRun && (this.hostElement instanceof HTMLElement_)) {
  13238. this.__toStopAfterRun__(this.hostElement); // primary
  13239. }
  13240. const r = this.maybeLoadAnimationBackground77.apply(this, arguments);
  13241. if (stopAfterRun && this.lottieAnimation) {
  13242. this.lottieAnimation.stop(); // fallback if no mutation
  13243. }
  13244. return r;
  13245. }
  13246. }
  13247.  
  13248. console1.log(`INTERACTIVITY_BACKGROUND_ANIMATION(${INTERACTIVITY_BACKGROUND_ANIMATION}) - OK`);
  13249.  
  13250. } else {
  13251. console1.log(`INTERACTIVITY_BACKGROUND_ANIMATION(${INTERACTIVITY_BACKGROUND_ANIMATION}) - NG`);
  13252.  
  13253. }
  13254.  
  13255. })();
  13256.  
  13257. console1.log("[End]");
  13258.  
  13259. groupEnd();
  13260.  
  13261.  
  13262. }).catch(console.warn);
  13263.  
  13264. }
  13265.  
  13266.  
  13267. if (DELAY_FOCUSEDCHANGED) {
  13268.  
  13269. customElements.whenDefined("yt-live-chat-text-input-field-renderer").then(() => {
  13270.  
  13271.  
  13272. mightFirstCheckOnYtInit();
  13273. groupCollapsed("YouTube Super Fast Chat", " | yt-live-chat-text-input-field-renderer hacks");
  13274. console1.log("[Begin]");
  13275. (() => {
  13276.  
  13277. const tag = "yt-live-chat-text-input-field-renderer"
  13278. const dummy = document.createElement(tag);
  13279.  
  13280. const cProto = getProto(dummy);
  13281. if (!cProto || !cProto.attached) {
  13282. console1.warn(`proto.attached for ${tag} is unavailable.`);
  13283. return;
  13284. }
  13285.  
  13286. if (DELAY_FOCUSEDCHANGED && typeof cProto.focusedChanged === 'function' && cProto.focusedChanged.length === 0 && !cProto.focusedChanged372) {
  13287. cProto.focusedChanged372 = cProto.focusedChanged;
  13288. cProto.focusedChanged = function () {
  13289. Promise.resolve(this).then((cnt) => {
  13290. if (cnt.isAttached === true) cnt.focusedChanged372();
  13291. });
  13292. }
  13293. }
  13294.  
  13295. })();
  13296.  
  13297. console1.log("[End]");
  13298.  
  13299. groupEnd();
  13300.  
  13301. });
  13302.  
  13303. }
  13304.  
  13305. }
  13306.  
  13307.  
  13308.  
  13309.  
  13310. promiseForCustomYtElementsReady.then(onRegistryReadyForDOMOperations);
  13311.  
  13312. const fixJsonParse = () => {
  13313.  
  13314. let p1 = window.onerror;
  13315.  
  13316. try {
  13317. JSON.parse("{}");
  13318. } catch (e) {
  13319. console.warn(e);
  13320. }
  13321.  
  13322. let p2 = window.onerror;
  13323.  
  13324. if (p1 !== p2) {
  13325.  
  13326.  
  13327. console.groupCollapsed(`%c${"YouTube Super Fast Chat"}%c${" | JS Engine Issue Found"}`,
  13328. "background-color: #010502; color: #fe806a; font-weight: 700; padding: 2px;",
  13329. "background-color: #010502; color: #fe806a; font-weight: 300; padding: 2px;"
  13330. );
  13331.  
  13332. 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");
  13333.  
  13334. console.groupEnd();
  13335.  
  13336. }
  13337.  
  13338. }
  13339.  
  13340. if (CHECK_JSONPRUNE) {
  13341. promiseForCustomYtElementsReady.then(fixJsonParse);
  13342. }
  13343.  
  13344. });
  13345.  
  13346.  
  13347.  
  13348. })({ IntersectionObserver });