YouTube Boost Chat

Full Replacement of YouTube Chat Message List

  1. // ==UserScript==
  2. // @name YouTube Boost Chat
  3. // @namespace UserScripts
  4. // @version 0.3.11
  5. // @license MIT
  6. // @match https://*.youtube.com/live_chat*
  7. // @grant none
  8. // @author CY Fung
  9. // @run-at document-start
  10. // @grant none
  11. // @unwrap
  12. // @allFrames true
  13. // @inject-into page
  14. // @require https://cdn.jsdelivr.net/gh/cyfung1031/userscript-supports@5d83d154956057bdde19e24f95b332cb9a78fcda/library/default-trusted-type-policy.js
  15. // @require https://cdn.jsdelivr.net/gh/cyfung1031/userscript-supports@b020bbb73dfa65d72b4656596f8e9ff1549becd6/library/solid-js-prod.js
  16. // @description Full Replacement of YouTube Chat Message List
  17. // @description:ja YouTubeチャットメッセージリストの完全置き換え
  18. // @description:zh-TW 完全替換 YouTube 聊天訊息列表
  19. // @description:zh-CN 完全替换 YouTube 聊天消息列表
  20. // ==/UserScript==
  21.  
  22. /*
  23.  
  24. MIT License
  25.  
  26. Copyright 2024 CY Fung
  27.  
  28. Permission is hereby granted, free of charge, to any person obtaining a copy
  29. of this software and associated documentation files (the "Software"), to deal
  30. in the Software without restriction, including without limitation the rights
  31. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  32. copies of the Software, and to permit persons to whom the Software is
  33. furnished to do so, subject to the following conditions:
  34.  
  35. The above copyright notice and this permission notice shall be included in all
  36. copies or substantial portions of the Software.
  37.  
  38. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  39. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  40. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  41. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  42. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  43. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  44. SOFTWARE.
  45.  
  46. */
  47.  
  48. (() => {
  49.  
  50. const USE_SHADOWROOT = false;
  51.  
  52. const MAX_ITEMS_FOR_TOTAL_DISPLAY = 90;
  53. // const RENDER_MESSAGES_ONE_BY_ONE = true;
  54. const LOGTIME_FLUSHITEMS = false;
  55. const DEBUG_windowVars = false;
  56.  
  57. // ----------------------------------------------------------------------------------------------------------
  58.  
  59. /** @type {WeakMapConstructor} */
  60. const WeakMap = window.WeakMapOriginal || window.WeakMap;
  61.  
  62.  
  63.  
  64.  
  65. let isThisBrowserSupported = true;
  66. let DO_scrollIntoViewIfNeeded = false;
  67.  
  68. const CAN_USE_SHADOWROOT = typeof Element.prototype.attachShadow !== 'function';
  69. const SHOULD_USE_SHADOWROOT = USE_SHADOWROOT && CAN_USE_SHADOWROOT;
  70.  
  71. if (isThisBrowserSupported && (typeof IntersectionObserver === 'undefined' || typeof CSS === 'undefined' || typeof CSS.supports === 'undefined')) {
  72. isThisBrowserSupported = false;
  73. } else {
  74. const isOverflowAnchorSupported = CSS.supports("overflow-anchor", "auto") && CSS.supports("overflow-anchor", "none");
  75. const isScrollIntoViewIfNeededSupported = typeof Element.prototype.scrollIntoViewIfNeeded === 'function';
  76.  
  77. if (isThisBrowserSupported && !isOverflowAnchorSupported && isScrollIntoViewIfNeededSupported) {
  78. DO_scrollIntoViewIfNeeded = true; // for webkit (Safari, Orion)
  79. } else if (isThisBrowserSupported && !isOverflowAnchorSupported && !isScrollIntoViewIfNeededSupported) {
  80. isThisBrowserSupported = false;
  81. }
  82. }
  83.  
  84. if (!isThisBrowserSupported) {
  85. console.warn('Your browser does not support YouTube Boost Chat');
  86. return;
  87. }
  88.  
  89. const _flag0281_ = window._flag0281_ = 0x2 | 0x4 | 0x8 | 0x40 | 0x80 | 0x100 | 0x40000;
  90.  
  91.  
  92.  
  93. const defaultPolicy = (typeof trustedTypes !== 'undefined' && trustedTypes.defaultPolicy) || { createHTML: s => s };
  94. function createHTML(s) {
  95. return defaultPolicy.createHTML(s);
  96. }
  97.  
  98. const { appendChild: fragmentAppendChild } = ((h0) => h0)(new DocumentFragment());
  99.  
  100. /* globals WeakRef:false */
  101.  
  102. /** @type {(o: Object | null) => WeakRef | null} */
  103. const mWeakRef = typeof WeakRef === 'function' ? (o => o ? new WeakRef(o) : null) : (o => o || null); // typeof InvalidVar == 'undefined'
  104.  
  105. /** @type {(wr: Object | null) => Object | null} */
  106. const kRef = (wr => (wr && wr.deref) ? wr.deref() : wr);
  107.  
  108. /** @type {globalThis.PromiseConstructor} */
  109. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  110.  
  111. const PromiseExternal = ((resolve_, reject_) => {
  112. const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
  113. return class PromiseExternal extends Promise {
  114. constructor(cb = h) {
  115. super(cb);
  116. if (cb === h) {
  117. /** @type {(value: any) => void} */
  118. this.resolve = resolve_;
  119. /** @type {(reason?: any) => void} */
  120. this.reject = reject_;
  121. }
  122. }
  123. };
  124. })();
  125.  
  126. if (!HTMLElement.prototype.getAttribute23751 && !HTMLElement.prototype.getAttribute23752 && typeof HTMLElement.prototype.getAttribute === 'function') {
  127.  
  128. HTMLElement.prototype.getAttribute23751 = HTMLElement.prototype.getAttribute;
  129. HTMLElement.prototype.getAttribute23752 = function (x) {
  130. if (x === 'shared-tooltip-text' && arguments.length === 1) {
  131. return null;
  132. }
  133. return this.getAttribute23751(x)
  134. };
  135.  
  136. }
  137.  
  138. const isCtrl = (e) => !!((e.ctrlKey && !e.metaKey) || (!e.ctrlKey && e.metaKey));
  139. const isAlt = (e) => !!(e.altKey);
  140.  
  141. const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);
  142. const indr = o => insp(o).$ || o.$ || 0;
  143.  
  144. const nullSet = (e) => { }
  145. const nullGet = () => { }
  146. const nullFn = () => { }
  147. const nullMemo = () => { }
  148.  
  149. const [setIntervalX0, clearIntervalX0] = [setInterval, clearInterval];
  150.  
  151. let chkVisibleItemList = () => { };
  152. class VisibleItemList extends Array {
  153. constructor(...args) {
  154. super(...args);
  155. R(this);
  156. Promise.resolve().then(chkVisibleItemList);
  157. }
  158.  
  159. reverse() {
  160. return W(this) && super.reverse();
  161. }
  162. flat(depth = 1) {
  163. return W(this) && super.flat(...arguments);
  164. }
  165. flatMap(callbackFn, thisArg = undefined) {
  166. return W(this) && super.flatMap(...arguments);
  167. }
  168. fill(value, start = undefined, end = undefined) {
  169. return W(this) && super.fill(...arguments);
  170. }
  171. sort(compareFn = undefined) {
  172. return W(this) && super.sort(...arguments);
  173. }
  174.  
  175. push(...elements) {
  176. return W(this) && super.push(...arguments);
  177. }
  178.  
  179. pop() {
  180. return W(this) && super.pop();
  181. }
  182.  
  183. unshift(...elements) {
  184. return W(this) && super.unshift(...arguments);
  185. }
  186.  
  187. shift() {
  188. return W(this) && super.shift();
  189. }
  190. splice(start, deleteCount, ...items) {
  191. return W(this) && super.splice(...arguments);
  192. }
  193.  
  194.  
  195. setLength(n) {
  196. W(this).length = n;
  197. }
  198.  
  199. getLength(){
  200. return this.length;
  201. }
  202.  
  203. filter(...args) {
  204. /*
  205.  
  206. f.handleRemoveChatItemByAuthorAction = function(a) {
  207. var b = function(d) {
  208. var e = Object.keys(d)[0];
  209. return (d = d[e]) && d.authorExternalChannelId ? d.authorExternalChannelId !== a.externalChannelId : !0
  210. }
  211. , c = this.visibleItems.filter(b);
  212. this.activeItems_ = this.activeItems_.filter(b);
  213. this.visibleItems = c;
  214. this.resetSmoothScroll_();
  215. this.setAtBottom();
  216. this.maybeScrollToBottom_()
  217. }
  218.  
  219. */
  220.  
  221. const r = super.filter(...args);
  222. Promise.resolve().then(chkVisibleItemList); // just in case
  223. return r;
  224. }
  225.  
  226. checkIntegrity(listControllerWR) {
  227. const cnt = kRef(listControllerWR);
  228. const bstVisibleItemList = cnt?.bstVisibleItemList;
  229. const visibleItems_ = cnt?.visibleItems;
  230. if (bstVisibleItemList !== visibleItems_ && bstVisibleItemList === this) {
  231. this.length = 0;
  232. const n = visibleItems_.length;
  233. if (n > 0) inPlaceArrayPush(this, visibleItems_);
  234. cnt.visibleItems = this;
  235. cnt.bstVisibleItemList = this;
  236. this.setLength(n);
  237. }
  238. }
  239.  
  240.  
  241.  
  242. }
  243.  
  244.  
  245.  
  246. function getCodeLocation() {
  247. let p = new Error().stack;
  248.  
  249. if (p.includes('solid')) return 'solid';
  250. if (p.includes('VisibleItemList.')) return 'solid';
  251. let q = p.match(/Array\.\w+[^\n\r]+[\r\n]+([^\n\r]+)/)
  252. q = q ? q[1] : p
  253. return q;
  254. // const callstack = new Error().stack.split("\n");
  255. // callstack.shift();
  256. // while (callstack.length && callstack[0].includes("-extension://")) {
  257. // callstack.shift();
  258. // }
  259. // if (!callstack.length) {
  260. // return "";
  261. // }
  262. // return '\n' + callstack[0].trim();
  263. }
  264.  
  265.  
  266. const { _setAttribute, _insertBefore, _removeAttribute, replaceWith, appendChild } = (() => {
  267. let _setAttribute = Element.prototype.setAttribute;
  268. try {
  269. _setAttribute = ShadyDOM.nativeMethods.setAttribute || _setAttribute;
  270. } catch (e) { }
  271. let _insertBefore = Node.prototype.insertBefore;
  272. try {
  273. _insertBefore = ShadyDOM.nativeMethods.insertBefore || _insertBefore;
  274. } catch (e) { }
  275. let _removeAttribute = Element.prototype.removeAttribute;
  276. try {
  277. _removeAttribute = ShadyDOM.nativeMethods.removeAttribute || _removeAttribute;
  278. } catch (e) { }
  279. let replaceWith = Element.prototype.replaceWith;
  280. try {
  281. replaceWith = ShadyDOM.nativeMethods.replaceWith || replaceWith;
  282. } catch (e) { }
  283. let appendChild = Node.prototype.appendChild;
  284. try {
  285. appendChild = ShadyDOM.nativeMethods.appendChild || appendChild;
  286. } catch (e) { }
  287. return { _setAttribute, _insertBefore, _removeAttribute, replaceWith, appendChild };
  288. })();
  289.  
  290. const isCustomElementsProvided = typeof customElements !== "undefined" && typeof (customElements || 0).whenDefined === "function";
  291.  
  292. const promiseForCustomYtElementsReady = isCustomElementsProvided ? Promise.resolve(0) : new Promise((callback) => {
  293. const EVENT_KEY_ON_REGISTRY_READY = "ytI-ce-registry-created";
  294. if (typeof customElements === 'undefined') {
  295. if (!('__CE_registry' in document)) {
  296. // https://github.com/webcomponents/polyfills/
  297. Object.defineProperty(document, '__CE_registry', {
  298. get() {
  299. // return undefined
  300. },
  301. set(nv) {
  302. if (typeof nv == 'object') {
  303. delete this.__CE_registry;
  304. this.__CE_registry = nv;
  305. this.dispatchEvent(new CustomEvent(EVENT_KEY_ON_REGISTRY_READY));
  306. }
  307. return true;
  308. },
  309. enumerable: false,
  310. configurable: true
  311. })
  312. }
  313. let eventHandler = (evt) => {
  314. document.removeEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  315. const f = callback;
  316. callback = null;
  317. eventHandler = null;
  318. f();
  319. };
  320. document.addEventListener(EVENT_KEY_ON_REGISTRY_READY, eventHandler, false);
  321. } else {
  322. callback();
  323. }
  324. });
  325.  
  326. const whenCEDefined = isCustomElementsProvided
  327. ? (nodeName) => customElements.whenDefined(nodeName)
  328. : (nodeName) => promiseForCustomYtElementsReady.then(() => customElements.whenDefined(nodeName));
  329.  
  330.  
  331. const inPlaceArrayPush = (() => {
  332. // for details, see userscript-supports/library/misc.js
  333. const LIMIT_N = typeof AbortSignal !== 'undefined' && typeof (AbortSignal || 0).timeout === 'function' ? 50000 : 10000;
  334. return function (dest, source) {
  335. let index = 0;
  336. const len = source.length;
  337. while (index < len) {
  338. let chunkSize = len - index; // chunkSize > 0
  339. if (chunkSize > LIMIT_N) {
  340. chunkSize = LIMIT_N;
  341. dest.push(...source.slice(index, index + chunkSize));
  342. } else if (index > 0) { // to the end
  343. dest.push(...source.slice(index));
  344. } else { // normal push.apply
  345. dest.push(...source);
  346. }
  347. index += chunkSize;
  348. }
  349. }
  350.  
  351. })();
  352.  
  353. const createPipeline = () => {
  354. let pipelineMutex = Promise.resolve();
  355. const pipelineExecution = fn => {
  356. return new Promise((resolve, reject) => {
  357. pipelineMutex = pipelineMutex.then(async () => {
  358. let res;
  359. try {
  360. res = await fn(); // performance concern? (8.6ms)
  361. } catch (e) {
  362. console.log('[yt-bst] error_F1', e);
  363. reject(e);
  364. }
  365. resolve(res);
  366. }).catch(console.warn);
  367. });
  368. };
  369. return pipelineExecution;
  370. };
  371.  
  372.  
  373.  
  374. const firstObjectKey = (obj) => { // performance concern? (8.6ms)
  375. for (const key in obj) {
  376. if (obj.hasOwnProperty(key) && typeof obj[key] === 'object') return key;
  377. }
  378. return null;
  379. }
  380.  
  381. const flushPE = createPipeline();
  382.  
  383. const mutableWM = new WeakMap();
  384.  
  385. const canScrollIntoViewWithOptions = (() => {
  386.  
  387. const element = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
  388. let i = 0;
  389. try {
  390. element.scrollIntoView({
  391. get behavior() { i++ },
  392. get block() { i++ }
  393. });
  394. } catch (e) {
  395.  
  396. }
  397. return i === 2;
  398.  
  399.  
  400. })();
  401.  
  402. if (!canScrollIntoViewWithOptions) {
  403. throw '[BST] Your browser is not supported.'
  404. }
  405.  
  406.  
  407. const cssTexts = {
  408. "outer": `
  409.  
  410.  
  411. .bst-yt-main ~ #items[id][class] {
  412. display: none !important;
  413. }
  414. .bst-yt-main ~ #item-scroller[id][class] {
  415. display: none !important;
  416. }
  417. .bst-yt-main{
  418. position: absolute;
  419. display: flex;
  420. flex-direction: column;
  421. gap: 0;
  422. top:0;
  423. left:0;
  424. bottom:0;
  425. right:0;
  426. contain: strict;
  427. overflow: auto;
  428. }
  429.  
  430. `,
  431. "inner": `
  432.  
  433.  
  434. .bst-message-list {
  435.  
  436. --bst-hyperlink-color: #3ea6ff;
  437.  
  438. --color-transparent: rgba(0, 0, 0, 0);
  439. --color-opac-b-1: rgba(0, 0, 0, 0.05);
  440. --color-opac-b-2: rgba(0, 0, 0, 0.08);
  441. --color-opac-b-3: rgba(0, 0, 0, 0.13);
  442. --color-opac-b-4: rgba(0, 0, 0, 0.16);
  443. --color-opac-b-5: rgba(0, 0, 0, 0.22);
  444. --color-opac-b-6: rgba(0, 0, 0, 0.28);
  445. --color-opac-b-7: rgba(0, 0, 0, 0.4);
  446. --color-opac-b-8: rgba(0, 0, 0, 0.5);
  447. --color-opac-b-9: rgba(0, 0, 0, 0.6);
  448. --color-opac-b-10: rgba(0, 0, 0, 0.7);
  449. --color-opac-b-11: rgba(0, 0, 0, 0.75);
  450. --color-opac-b-12: rgba(0, 0, 0, 0.8);
  451. --color-opac-b-13: rgba(0, 0, 0, 0.85);
  452. --color-opac-b-14: rgba(0, 0, 0, 0.9);
  453. --color-opac-b-15: rgba(0, 0, 0, 0.95);
  454. --color-opac-gd-1: rgba(83, 83, 95, 0.38);
  455. --color-opac-gd-2: rgba(83, 83, 95, 0.48);
  456. --color-opac-gd-3: rgba(83, 83, 95, 0.55);
  457. --color-opac-gd-4: rgba(50, 50, 57, 0.62);
  458. --color-opac-gd-5: rgba(50, 50, 57, 0.95);
  459.  
  460. --shadow-elevation-umbra: 0.34;
  461. --shadow-elevation-penumbra: 0.26;
  462. --shadow-elevation-ambient: 0.28;
  463. --shadow-elevation-1: 0 1px 2px var(--color-opac-b-14), 0 0px 2px var(--color-opac-b-14);
  464. --shadow-elevation-2: 0 4px 8px var(--color-opac-b-7), 0 0px 4px var(--color-opac-b-7);
  465. --shadow-elevation-3: 0 6px 16px var(--color-opac-b-8), 0 0px 4px var(--color-opac-b-7);
  466. --shadow-elevation-4: 0 12px 32px var(--color-opac-b-8), 0 0px 8px var(--color-opac-b-7);
  467. --shadow-elevation-5: 0 32px 64px var(--color-opac-b-9), 0 0px 16px var(--color-opac-b-7);
  468. --shadow-button-focus: 0 0 6px 0 var(--color-twitch-purple-8);
  469. --shadow-button-active: 0 0 6px 0 var(--color-twitch-purple-8);
  470. --shadow-button-disabled: none;
  471. --shadow-button-overlay-focus: 0 0 6px 0 var(--color-opac-w-6);
  472. --shadow-button-overlay-active: 0 0 6px 0 var(--color-opac-w-6);
  473. --shadow-tab-focus: 0 4px 6px -4px var(--color-twitch-purple-11);
  474. --shadow-balloon: 0 1px 1px var(--color-opac-b-5);
  475. --shadow-scrollbar: 0 0 1px 1px var(--color-opac-w-5);
  476.  
  477.  
  478. --color-opac-w-1: rgba(255, 255, 255, 0.05);
  479. --color-opac-w-2: rgba(255, 255, 255, 0.08);
  480. --color-opac-w-3: rgba(255, 255, 255, 0.13);
  481. --color-opac-w-4: rgba(255, 255, 255, 0.16);
  482. --color-opac-w-5: rgba(255, 255, 255, 0.22);
  483. --color-opac-w-6: rgba(255, 255, 255, 0.28);
  484. --color-opac-w-7: rgba(255, 255, 255, 0.4);
  485. --color-opac-w-8: rgba(255, 255, 255, 0.5);
  486. --color-opac-w-9: rgba(255, 255, 255, 0.6);
  487. --color-opac-w-10: rgba(255, 255, 255, 0.7);
  488. --color-opac-w-11: rgba(255, 255, 255, 0.75);
  489. --color-opac-w-12: rgba(255, 255, 255, 0.8);
  490. --color-opac-w-13: rgba(255, 255, 255, 0.85);
  491. --color-opac-w-14: rgba(255, 255, 255, 0.9);
  492. --color-opac-w-15: rgba(255, 255, 255, 0.95);
  493.  
  494. --color-background-interactable-overlay-hover: var(--color-opac-w-3);
  495.  
  496. --color-white: #ffffff;
  497. --color-black: #000000;
  498. --color-text-button-overlay-hover: var(--color-white);
  499. --color-background-button-icon-overlay-default: var(--color-transparent);
  500. --color-background-button-icon-overlay-hover: var(--color-background-interactable-overlay-hover);
  501. --color-background-button-icon-overlay-active: var(--color-background-interactable-overlay-active);
  502. --color-background-image-selector-overlay: var(--color-transparent);
  503.  
  504.  
  505. --opacity-pulse-animation: 0.7;
  506. --button-size-small: 2.4rem;
  507. --button-size-default: 3rem;
  508. --button-size-large: 3.6rem;
  509.  
  510. --loading-spinner-size-small: 1.6rem;
  511. --loading-spinner-size-default: 2.2rem;
  512. --loading-spinner-size-large: 2.8rem;
  513. --progress-bar-size-extra-small: 0.3rem;
  514. --progress-bar-size-small: 0.5rem;
  515. --progress-bar-size-default: 1rem;
  516. --range-size: 0.2rem;
  517. --range-thumb-size: 1.6rem;
  518. --toggle-height: 2rem;
  519. --toggle-width: 3.5rem;
  520. --toggle-handle-size: 1.2rem;
  521. --toggle-handle-shadow: none;
  522. --toggle-handle-offset: 0.2rem;
  523. --border-width-default: 1px;
  524. --border-width-button: 2px;
  525. --border-width-checkbox: 2px;
  526. --border-width-drop-zone: 2px;
  527. --border-width-marked: 3px;
  528. --border-width-selectable: 2px;
  529. --border-width-spinner: 2px;
  530. --border-width-tag: 2px;
  531. --border-radius-none: 0;
  532. --border-radius-small: 0.2rem;
  533. --border-radius-medium: 0.4rem;
  534. --border-radius-large: 0.6rem;
  535. --border-radius-extra-large: 1rem;
  536. --border-radius-extra-extra-large: 1.6rem;
  537. --border-radius-rounded: 9000px;
  538.  
  539. }
  540.  
  541. .bst-message-list {
  542.  
  543. --yt-spec-base-background: #fff;
  544. --yt-spec-raised-background: #fff;
  545. --yt-spec-menu-background: #fff;
  546. --yt-spec-inverted-background: #0f0f0f;
  547. --yt-spec-additive-background: rgba(0,0,0,0.05);
  548.  
  549. --yt-deprecated-blue-light: hsl(205.9,80%,43.1%);
  550. --yt-deprecated-opalescence-grey-opacity-lighten-3: hsla(0,0%,53.3%,0.4);
  551. --yt-deprecated-opalescence-soft-grey-opacity-lighten-3: hsla(0,0%,93.3%,0.4);
  552. --yt-deprecated-luna-black-opacity-lighten-2: hsla(0,0%,6.7%,0.6);
  553. --yt-deprecated-luna-black-opacity-lighten-3: hsla(0,0%,6.7%,0.4);
  554. --yt-deprecated-luna-black-opacity-lighten-4: hsla(0,0%,6.7%,0.2);
  555. --yt-opalescence-dark-grey: hsl(0,0%,20%);
  556. --yt-deprecated-luna-black: hsl(0,0%,6.7%);
  557. --yt-deprecated-white-opacity-lighten-4: hsla(0,0%,100%,0.2);
  558. --yt-deprecated-opalescence-soft-grey-opacity-lighten-1: hsla(0,0%,93.3%,0.8);
  559. --yt-deprecated-opalescence-soft-grey: hsl(0,0%,93.3%);
  560. --yt-live-chat-background-color: var(--yt-spec-base-background);
  561. --yt-live-chat-secondary-background-color: var( --yt-deprecated-opalescence-soft-grey );
  562. --yt-live-chat-action-panel-background-color: var(--yt-spec-base-background);
  563. --yt-live-chat-action-panel-background-color-transparent: hsla(0,0%,97%,0.8);
  564. --yt-live-chat-additive-background-inverse: var(--yt-spec-white-1-alpha-10);
  565. --yt-live-chat-mode-change-background-color: var( --yt-deprecated-opalescence-soft-grey-opacity-lighten-3 );
  566. --yt-live-chat-primary-text-color: var(--yt-spec-text-primary);
  567. --yt-live-chat-secondary-text-color: var( --yt-deprecated-luna-black-opacity-lighten-2 );
  568. --yt-live-chat-secondary-text-color-inverse: var(--yt-spec-grey-2);
  569. --yt-live-chat-tertiary-text-color: var( --yt-deprecated-luna-black-opacity-lighten-3 );
  570. --yt-live-chat-tertiary-text-color-inverse: var(--yt-spec-white-1-alpha-30);
  571. --yt-live-chat-text-input-field-inactive-underline-color: #b8b8b8;
  572. --yt-live-chat-text-input-field-placeholder-color: var( --yt-deprecated-luna-black-opacity-lighten-2 );
  573. --yt-live-chat-text-input-field-underline-transition-duration: 0.25s;
  574. --yt-live-chat-icon-button-color: var(--yt-live-chat-primary-text-color);
  575. --yt-live-chat-enabled-send-button-color: #4285f4;
  576. --yt-live-chat-disabled-icon-button-color: var( --yt-deprecated-luna-black-opacity-lighten-4 );
  577. --yt-live-chat-picker-button-color: var( --yt-deprecated-luna-black-opacity-lighten-3 );
  578. --yt-live-chat-picker-button-active-color: var( --yt-deprecated-luna-black-opacity-lighten-1 );
  579. --yt-live-chat-picker-button-disabled-color: var( --yt-live-chat-disabled-icon-button-color );
  580. --yt-live-chat-picker-button-hover-color: var( --yt-deprecated-luna-black-opacity-lighten-2 );
  581. --yt-live-chat-mention-background-color: #ff5722;
  582. --yt-live-chat-mention-text-color: var(--yt-spec-static-overlay-text-primary);
  583. --yt-live-chat-deleted-message-color: rgba(0,0,0,0.5);
  584. --yt-live-chat-deleted-message-bar-color: rgba(11,11,11,0.2);
  585. --yt-live-chat-disabled-button-background-color: var( --yt-deprecated-opalescence-soft-grey );
  586. --yt-live-chat-disabled-button-text-color: var( --yt-deprecated-luna-black-opacity-lighten-3 );
  587. --yt-live-chat-sub-panel-background-color: var(--yt-spec-base-background);
  588. --yt-live-chat-sub-panel-background-color-transparent: var( --yt-spec-base-background );
  589. --yt-live-chat-header-background-color: var(--yt-spec-base-background);
  590. --yt-live-chat-header-button-color: var(--yt-deprecated-luna-black);
  591. --yt-live-chat-header-bottom-border: 1px solid var(--yt-spec-10-percent-layer);
  592. --yt-live-chat-count-color-early-warning: hsl(40,76%,55%);
  593. --yt-live-chat-count-color-error: hsl(10,51%,49%);
  594. --yt-live-chat-error-message-color: hsl(10,51%,49%);
  595. --yt-live-chat-reconnect-message-color: hsla(0,0%,7%,0.2);
  596. --yt-live-chat-moderator-color: hsl(225,84%,66%);
  597. --yt-live-chat-new-moderator-color: var(--yt-spec-call-to-action);
  598. --yt-live-chat-owner-color: hsl(40,76%,55%);
  599. --yt-live-chat-author-chip-owner-background-color: #ffd600;
  600. --yt-live-chat-author-chip-owner-text-color: rgba(0,0,0,0.87);
  601. --yt-live-chat-author-chip-verified-background-color: var(--yt-spec-grey-1);
  602. --yt-live-chat-author-chip-verified-text-color: var(--yt-spec-grey-5);
  603. --yt-live-chat-message-highlight-background-color: var( --yt-spec-raised-background );
  604. --yt-live-chat-sponsor-color: #107516;
  605. --yt-live-chat-overlay-color: hsla(0,0%,0%,0.6);
  606. --yt-live-chat-dialog-background-color: var( --yt-spec-static-white-background );
  607. --yt-live-chat-dialog-text-color: var( --yt-deprecated-luna-black-opacity-lighten-2 );
  608. --yt-live-chat-banner-border-color: var(--yt-spec-10-percent-layer);
  609. --yt-live-chat-banner-animation-duration: 0.35s;
  610. --yt-live-chat-banner-animation-fast-duration: 0.25s;
  611. --yt-live-chat-banner-gradient-scrim: linear-gradient(rgba(255,255,255,0.95),transparent);
  612. --yt-live-chat-banner-indeterminate-bar-background: repeating-linear-gradient(90deg,#fff,#fff 6px,#aaa 6px,#aaa 9px);
  613. --yt-live-chat-banner-bar-animation-duration: 1s;
  614. --yt-live-chat-action-panel-gradient-scrim: linear-gradient(to top,rgba(255,255,255,0.95),transparent);
  615. --yt-live-chat-call-for-questions-primary-text-color: var( --yt-spec-static-overlay-text-primary );
  616. --yt-live-chat-call-for-questions-secondary-text-color: var( --yt-spec-static-overlay-text-secondary );
  617. --yt-live-chat-call-for-questions-ask-question-button-color: var( --yt-spec-static-overlay-text-primary );
  618. --yt-live-chat-call-to-action-primary-text-color: var( --yt-spec-static-overlay-text-primary );
  619. --yt-live-chat-call-to-action-secondary-text-color: var( --yt-spec-static-overlay-text-secondary );
  620. --yt-live-chat-call-to-action-ask-question-button-color: var( --yt-spec-static-overlay-text-primary );
  621. --yt-live-chat-qna-primary-text-color: var( --yt-spec-static-overlay-text-primary );
  622. --yt-live-chat-qna-start-panel-header-border-color: var( --yt-spec-10-percent-layer );
  623. --yt-live-chat-qna-panel-start-button-background-color: var( --yt-spec-call-to-action );
  624. --yt-live-chat-qna-panel-start-button-color: var( --yt-spec-general-background-b );
  625. --yt-live-chat-qna-start-panel-button-background-color-disabled: var( --yt-spec-badge-chip-background );
  626. --yt-live-chat-qna-panel-start-button-color-disabled: var( --yt-spec-text-disabled );
  627. --yt-live-chat-poll-primary-text-color: var( --yt-spec-static-overlay-text-primary );
  628. --yt-live-chat-poll-secondary-text-color: var( --yt-spec-static-overlay-text-secondary );
  629. --yt-live-chat-poll-tertiary-text-color: var( --yt-spec-static-overlay-text-disabled );
  630. --yt-live-chat-poll-choice-text-color: var( --yt-live-chat-poll-primary-text-color );
  631. --yt-live-chat-poll-choice-additive-background-color: var( --yt-spec-black-pure-alpha-10 );
  632. --yt-live-chat-poll-choice-additive-background-color-inverse: var( --yt-spec-white-1-alpha-20 );
  633. --yt-live-chat-poll-banner-border-highlight-color: var(--yt-spec-white-3);
  634. --yt-live-chat-poll-choice-background-color: transparent;
  635. --yt-live-chat-poll-choice-border-radius: 2px;
  636. --yt-live-chat-poll-choice-border: 1px solid var(--yt-live-chat-poll-tertiary-text-color);
  637. --yt-live-chat-poll-choice-min-height: 16px;
  638. --yt-live-chat-poll-choice-vote-bar-background-color: var( --yt-spec-static-overlay-button-secondary );
  639. --yt-live-chat-poll-choice-hover-color: rgba(17,17,16,0.1);
  640. --yt-live-chat-poll-choice-animation-duration: 0.5s;
  641. --yt-live-chat-poll-choice-text-padding: 0 16px;
  642. --yt-live-chat-poll-editor-panel-header-border-color: var( --yt-spec-10-percent-layer );
  643. --yt-live-chat-poll-editor-start-button-color: var( --yt-spec-text-primary-inverse );
  644. --yt-live-chat-poll-editor-start-button-background-color: var( --yt-spec-call-to-action );
  645. --yt-live-chat-poll-editor-start-button-color-disabled: var( --yt-spec-text-disabled );
  646. --yt-live-chat-poll-editor-start-button-background-color-disabled: var( --yt-spec-badge-chip-background );
  647. --yt-live-interactivity-component-background-color: #264c8a;
  648. --yt-live-chat-panel-animation-duration: 0.5s;
  649. --yt-live-chat-universal-motion-curve: cubic-bezier(0.05,0,0,1);
  650. --yt-live-chat-moderation-mode-hover-background-color: var( --yt-deprecated-luna-black-opacity-lighten-4 );
  651. --yt-live-chat-additional-inline-action-button-color: var( --yt-spec-static-overlay-text-primary );
  652. --yt-live-chat-additional-inline-action-button-background-color: hsla(0,0%,26%,0.8);
  653. --yt-live-chat-additional-inline-action-button-background-color-hover: hsla(0,0%,26%,1);
  654. --yt-formatted-string-emoji-size: 24px;
  655. --yt-live-chat-emoji-size: 24px;
  656. --yt-live-chat-text-input-field-suggestion-background-color: var( --yt-spec-static-white-background );
  657. --yt-live-chat-text-input-field-suggestion-background-color-hover: #eee;
  658. --yt-live-chat-text-input-field-suggestion-text-color: #666;
  659. --yt-live-chat-text-input-field-suggestion-text-color-hover: #333;
  660. --yt-live-chat-ticker-arrow-background: hsl(0,0%,97.3%);
  661. --yt-emoji-picker-category-background-color: var( --yt-live-chat-action-panel-background-color-transparent );
  662. --yt-emoji-picker-category-color: var(--yt-live-chat-secondary-text-color);
  663. --yt-emoji-picker-category-button-color: var(--yt-spec-text-disabled);
  664. --yt-emoji-picker-search-background-color: var(--yt-spec-white-2);
  665. --yt-emoji-picker-search-color: var( --yt-deprecated-luna-black-opacity-lighten-1 );
  666. --yt-emoji-picker-search-placeholder-color: var( --yt-deprecated-luna-black-opacity-lighten-2 );
  667. --yt-emoji-picker-base-with-variants-border: var( --yt-spec-black-pure-alpha-15 );
  668. --yt-emoji-picker-variant-selector-bg-color: #e0e0e0;
  669. --yt-live-chat-slider-active-color: #2196f3;
  670. --yt-live-chat-slider-container-color: #c8c8c8;
  671. --yt-live-chat-slider-markers-color: #505050;
  672. --yt-live-chat-toast-action-color: #2196f3;
  673. --yt-live-chat-toast-background-color: var(--yt-opalescence-dark-grey);
  674. --yt-live-chat-toast-text-color: var(--yt-spec-static-overlay-text-primary);
  675. --yt-live-chat-automod-button-background-color: var( --yt-deprecated-opalescence-soft-grey );
  676. --yt-live-chat-automod-button-background-color-hover: var( --yt-deprecated-luna-black-opacity-lighten-4 );
  677. --yt-live-chat-creator-support-button-border-radius: 2px;
  678. --yt-live-chat-creator-support-button-padding: 10px 16px;
  679. --yt-live-chat-creator-support-button-font-size: inherit;
  680. --yt-live-chat-countdown-opacity: 0.3;
  681. --yt-live-chat-shimmer-background-color: rgba(136,136,136,0.2);
  682. --yt-live-chat-shimmer-linear-gradient: linear-gradient(0deg,rgba(255,255,255,0) 40%,rgba(255,255,255,0.5) 50%,rgba(255,255,255,0) 65%);
  683. --yt-live-chat-vem-background-color: var( --yt-deprecated-opalescence-soft-grey );
  684. --yt-live-chat-upsell-dialog-renderer-button-padding: 10px 16px;
  685. --yt-live-chat-product-picker-icon-color: rgba(17,17,17,0.6);
  686. --yt-live-chat-product-picker-hover-color: rgba(17,17,16,0.1);
  687. --yt-live-chat-product-picker-disabled-icon-color: rgba(17,17,17,0.4);
  688. --yt-pdg-paid-stickers-tab-selection-bar-color: var(--yt-spec-dark-blue);
  689. --yt-pdg-paid-stickers-author-name-font-size: 14px;
  690. --yt-pdg-paid-stickers-author-subtext-font-size: 13px;
  691. --yt-pdg-paid-stickers-margin-left: 38px;
  692. --yt-live-chat-ninja-message-background-color: var(--yt-spec-base-background);
  693. --yt-live-chat-panel-pages-border-color: var(--yt-spec-10-percent-layer)
  694. }
  695.  
  696. .bst-message-list[dark] {
  697.  
  698. --yt-spec-base-background: #0f0f0f;
  699. --yt-spec-raised-background: #212121;
  700. --yt-spec-menu-background: #282828;
  701. --yt-spec-inverted-background: #f1f1f1;
  702. --yt-spec-additive-background: rgba(255,255,255,0.1);
  703.  
  704. --yt-live-chat-background-color: var(--yt-spec-base-background);
  705. --yt-live-chat-action-panel-background-color: var(--yt-spec-base-background);
  706. --yt-live-chat-action-panel-background-color-transparent: rgba(40,40,40,0.8);
  707. --yt-live-chat-additive-background-inverse: var(--yt-spec-black-pure-alpha-5);
  708. --yt-live-chat-secondary-background-color: #282828;
  709. --yt-live-chat-toast-text-color: var(--yt-spec-static-overlay-text-primary);
  710. --yt-live-chat-toast-background-color: #323232;
  711. --yt-live-chat-mode-change-background-color: #333;
  712. --yt-live-chat-primary-text-color: var(--yt-spec-static-overlay-text-primary);
  713. --yt-live-chat-secondary-text-color: rgba(255,255,255,0.7);
  714. --yt-live-chat-secondary-text-color-inverse: var(--yt-spec-grey-5);
  715. --yt-live-chat-tertiary-text-color: rgba(255,255,255,0.54);
  716. --yt-live-chat-tertiary-text-color-inverse: var( --yt-spec-black-pure-alpha-30 );
  717. --yt-live-chat-text-input-field-inactive-underline-color: #666;
  718. --yt-live-chat-text-input-field-placeholder-color: #666;
  719. --yt-live-chat-icon-button-color: var(--yt-live-chat-primary-text-color);
  720. --yt-live-chat-enabled-send-button-color: #fff;
  721. --yt-live-chat-disabled-icon-button-color: rgba(255,255,255,0.3);
  722. --yt-live-chat-picker-button-color: var(--yt-live-chat-tertiary-text-color);
  723. --yt-live-chat-picker-button-active-color: var( --yt-spec-static-overlay-text-primary );
  724. --yt-live-chat-picker-button-disabled-color: var( --yt-live-chat-disabled-icon-button-color );
  725. --yt-live-chat-picker-button-hover-color: rgba(255,255,255,0.74);
  726. --yt-live-chat-mention-background-color: #ff5722;
  727. --yt-live-chat-mention-text-color: #fff;
  728. --yt-live-chat-deleted-message-color: rgba(255,255,255,0.5);
  729. --yt-live-chat-deleted-message-bar-color: rgba(255,255,255,0.5);
  730. --yt-live-chat-error-message-color: var(--yt-spec-brand-link-text);
  731. --yt-live-chat-error-message-color-refresh: var(--yt-spec-error-indicator);
  732. --yt-live-chat-reconnect-message-color: #fff;
  733. --yt-live-chat-disabled-button-background-color: #444;
  734. --yt-live-chat-disabled-button-text-color: var( --yt-live-chat-secondary-text-color );
  735. --yt-live-chat-sub-panel-background-color: var(--yt-spec-base-background);
  736. --yt-live-chat-sub-panel-background-color-transparent: var( --yt-spec-base-background );
  737. --yt-live-chat-header-background-color: var(--yt-spec-base-background);
  738. --yt-live-chat-header-button-color: var(--yt-live-chat-secondary-text-color);
  739. --yt-live-chat-moderator-color: #5e84f1;
  740. --yt-live-chat-owner-color: #ffd600;
  741. --yt-live-chat-message-highlight-background-color: var( --yt-spec-raised-background );
  742. --yt-live-chat-author-chip-owner-text-color: var(--yt-deprecated-luna-black);
  743. --yt-live-chat-author-chip-verified-background-color: var(--yt-spec-grey-5);
  744. --yt-live-chat-author-chip-verified-text-color: var(--yt-spec-white-4);
  745. --yt-live-chat-sponsor-color: #2ba640;
  746. --yt-live-chat-overlay-color: rgba(0,0,0,0.5);
  747. --yt-live-chat-dialog-background-color: #424242;
  748. --yt-live-chat-dialog-text-color: var(--yt-spec-static-overlay-text-primary);
  749. --yt-live-chat-button-default-text-color: var( --yt-spec-static-overlay-text-primary );
  750. --yt-live-chat-button-default-background-color: var( --yt-deprecated-white-opacity-lighten-4 );
  751. --yt-live-chat-button-dark-text-color: var( --yt-spec-static-overlay-text-primary );
  752. --yt-live-chat-button-dark-background-color: var( --yt-deprecated-white-opacity-lighten-4 );
  753. --yt-emoji-picker-variant-selector-bg-color: #2f2f2f;
  754. --yt-live-chat-moderation-mode-hover-background-color: rgba(255,255,255,0.3);
  755. --yt-live-chat-additional-inline-action-button-color: var(--yt-grey);
  756. --yt-live-chat-additional-inline-action-button-background-color: var( --yt-deprecated-opalescence-soft-grey-opacity-lighten-1 );
  757. --yt-live-chat-additional-inline-action-button-background-color-hover: var( --yt-deprecated-opalescence-soft-grey );
  758. --yt-formatted-string-emoji-size: 24px;
  759. --yt-live-chat-emoji-size: 24px;
  760. --yt-live-chat-text-input-field-suggestion-background-color: #3e3e3e;
  761. --yt-live-chat-text-input-field-suggestion-background-color-hover: #343434;
  762. --yt-live-chat-text-input-field-suggestion-text-color: var( --yt-spec-static-overlay-text-primary );
  763. --yt-live-chat-text-input-field-suggestion-text-color-hover: var( --yt-spec-static-overlay-text-primary );
  764. --yt-live-chat-text-input-field-placeholder-color: var( --yt-live-chat-secondary-text-color );
  765. --yt-live-chat-ticker-arrow-background: var( --yt-live-chat-action-panel-background-color );
  766. --yt-emoji-picker-category-background-color: var( --yt-live-chat-action-panel-background-color-transparent );
  767. --yt-emoji-picker-category-color: var(--yt-live-chat-secondary-text-color);
  768. --yt-emoji-picker-search-background-color: #444;
  769. --yt-emoji-picker-search-color: #fff;
  770. --yt-emoji-picker-search-placeholder-color: #999;
  771. --yt-emoji-picker-base-with-variants-border: var(--yt-spec-white-1-alpha-25);
  772. --yt-live-chat-slider-active-color: #2196f3;
  773. --yt-live-chat-slider-container-color: #515151;
  774. --yt-live-chat-slider-markers-color: #fff;
  775. --yt-live-chat-banner-gradient-scrim: linear-gradient(rgba(40,40,40,0.95),transparent);
  776. --yt-live-chat-action-panel-gradient-scrim: linear-gradient(to top,rgba(40,40,40,0.95),transparent);
  777. --yt-live-chat-poll-choice-additive-background-color: var( --yt-spec-white-1-alpha-20 );
  778. --yt-live-chat-poll-choice-additive-background-color-inverse: var( --yt-spec-black-pure-alpha-10 );
  779. --yt-live-chat-poll-banner-border-highlight-color: var(--yt-spec-black-3);
  780. --yt-live-chat-poll-editor-start-button-background-color-disabled: var( --yt-spec-grey-1 );
  781. --yt-live-chat-automod-button-background-color: var( --yt-deprecated-opalescence-grey-opacity-lighten-3 );
  782. --yt-live-chat-automod-button-background-color-hover: rgba(255,255,255,0.5);
  783. --yt-live-chat-automod-button-explanation-color: rgba(255,255,255,0.7);
  784. --yt-live-chat-countdown-opacity: 0.5;
  785. --yt-live-chat-shimmer-background-color: rgba(17,17,17,0.4);
  786. --yt-live-chat-shimmer-linear-gradient: linear-gradient(0deg,rgba(0,0,0,0.1) 40%,rgba(100,100,100,0.3) 50%,rgba(0,0,0,0.1) 60%);
  787. --yt-live-chat-vem-background-color: #3e3e3e;
  788. --yt-live-chat-product-picker-icon-color: rgba(255,255,255,0.5);
  789. --yt-live-chat-product-picker-hover-color: rgba(68,68,68,1);
  790. --yt-live-chat-product-picker-disabled-icon-color: rgba(255,255,255,0.3);
  791. --yt-pdg-paid-stickers-tab-selection-bar-color: var(--yt-spec-light-blue)
  792. }
  793.  
  794. /*
  795.  
  796. yt-icon, .yt-icon-container.yt-icon {
  797. display: inline-flexbox;
  798. display: -moz-inline-box;
  799. display: inline-flex;
  800. -moz-box-align: center;
  801. align-items: center;
  802. -moz-box-pack: center;
  803. justify-content: center;
  804. position: relative;
  805. vertical-align: middle;
  806. fill: var(--iron-icon-fill-color,currentcolor);
  807. stroke: var(--iron-icon-stroke-color,none);
  808. width: var(--iron-icon-width,24px);
  809. height: var(--iron-icon-height,24px);
  810. animation: var(--iron-icon-animation);
  811. margin-top: var(--iron-icon-margin-top);
  812. margin-right: var(--iron-icon-margin-right);
  813. margin-bottom: var(--iron-icon-margin-bottom);
  814. margin-left: var(--iron-icon-margin-left);
  815. padding: var(--iron-icon-padding);
  816. contain: strict;
  817. }
  818.  
  819. */
  820.  
  821.  
  822.  
  823. .bst-message-list {
  824.  
  825. --bst-default-text-color: #000;
  826. --bst-username-color: var(--yt-live-chat-secondary-text-color);
  827. --bst-name-field-background-default: rgba(127, 127, 127, 0.15);
  828.  
  829. --yt-live-chat-first-line-height: calc( var(--yt-live-chat-emoji-size) + 2px );
  830. --yt-live-chat-profile-icon-size: 20px;
  831. --bst-message-entry-pl: calc( var(--yt-live-chat-profile-icon-size) + 6px );
  832. --yt-live-chat-tooltip-max-width: 60vw;
  833.  
  834. --bst-list-pl: 20px;
  835. --bst-list-pr: 20px;
  836. --bst-list-pt: 8px;
  837. --bst-list-pb: 8px;
  838.  
  839. --bst-list-gap: 10px;
  840.  
  841. --bst-author-badge-mb: .2rem;
  842. /* --bst-author-badge-va: text-bottom; */
  843. --bst-author-badge-va: middle;
  844. --bst-author-badge-size: 16px;
  845.  
  846. padding-left: var(--bst-list-pl);
  847. padding-right: var(--bst-list-pr);
  848. padding-top: var(--bst-list-pt);
  849. padding-bottom: var(--bst-list-pb);
  850. display: flex;
  851. gap: var(--bst-list-gap);
  852. flex-direction: column;
  853. background-color: var(--yt-live-chat-background-color);
  854.  
  855.  
  856. --yt-live-chat-sponsor-color-ori: var(--yt-live-chat-sponsor-color);
  857. --yt-live-chat-moderator-color-ori: var(--yt-live-chat-moderator-color);
  858. --yt-live-chat-author-chip-owner-background-color-ori: var(--yt-live-chat-author-chip-owner-background-color);
  859.  
  860.  
  861. overflow-anchor: none;
  862.  
  863. }
  864.  
  865. .bst-message-list[dark] {
  866. --bst-default-text-color: #fff;
  867. --bst-username-color: #a3e3e3;
  868. --bst-name-field-background-default: rgba(255, 255, 255, 0.15);
  869. }
  870.  
  871. .bst-message-list[dark] .bst-message-entry:not(.bst-membership-message) {
  872. --yt-live-chat-sponsor-color: #71ff8c;
  873. --yt-live-chat-moderator-color: #70a7ff;
  874. --yt-live-chat-author-chip-owner-background-color: #ffff3c;
  875. }
  876.  
  877. .bst-overflow-anchor{
  878. contain: strict;
  879. display:block;
  880. background: transparent;
  881. position: relative;
  882. flex-shrink: 0;
  883. top:-4px;
  884. border: 1px solid transparent;
  885. z-index: -1;
  886. visibility: collapse;
  887. overflow-anchor: auto;
  888. }
  889.  
  890. @keyframes bstMessageListIssueBackground {
  891. 0% {
  892. background-color: var(--yt-spec-menu-background);
  893. }
  894. 100% {
  895. background-color: var(--yt-live-chat-background-color);
  896. }
  897. }
  898. .bst-message-list.bst-message-list-issue {
  899. animation: bstMessageListIssueBackground ease-in 1.74s infinite alternate;
  900. }
  901.  
  902. .bst-message-username {
  903. box-sizing: border-box;
  904. border-radius: 2px;
  905. color: var(--bst-username-color);
  906. font-weight: 500;
  907. }
  908.  
  909. yt-live-chat-renderer[hide-timestamps] {
  910. --yt-live-chat-item-timestamp-display: none;
  911. }
  912. .bst-message-time:empty {
  913. --yt-live-chat-item-timestamp-display: none;
  914. }
  915.  
  916. .bst-message-time {
  917. display:inline;
  918. white-space: nowrap;
  919. vertical-align: baseline;
  920. display: var(--yt-live-chat-item-timestamp-display, inline);
  921. /* margin: var(--yt-live-chat-item-timestamp-margin, 0 8px 0 0); */
  922. color: var(--yt-live-chat-tertiary-text-color);
  923. font-size: 11px;
  924. display: var(--yt-live-chat-item-timestamp-display, inline-block);
  925. min-width: 3em;
  926. box-sizing: border-box;
  927. padding-right: 8px;
  928. }
  929.  
  930. .bst-message-username {
  931. display:inline;
  932. vertical-align: baseline;
  933. }
  934. .bst-message-badges {
  935. display:inline;
  936. white-space: nowrap;
  937. vertical-align: baseline;
  938.  
  939. }
  940. .bst-message-badges{
  941. margin-left: 2px;
  942. }
  943. .bst-message-badges:empty{
  944. margin:0;
  945. }
  946. .bst-message-badges::before{
  947. content:'';
  948. contain: strict;
  949. display:inline;
  950. user-select:none !important;
  951. pointer-events:none !important;
  952. line-height: var(--yt-live-chat-first-line-height);
  953. vertical-align: baseline;
  954. }
  955. .bst-message-badges img.bst-author-badge{
  956. display: inline;
  957. margin-bottom: var(--bst-author-badge-mb);
  958. vertical-align: var(--bst-author-badge-va);
  959. width: var(--bst-author-badge-size);
  960. height: var(--bst-author-badge-size);
  961. max-height: 2rem;
  962. max-width: 2rem;
  963. contain: strict;
  964. margin: 0;
  965. margin-top: -4px;
  966. margin-top: -0.5rem;
  967. contain: strict;
  968. }
  969. .bst-message-badge-yt-icon{
  970. display: inline-flex;
  971. width: 16px;
  972. height: 16px;
  973. margin-bottom: var(--bst-author-badge-mb);
  974. vertical-align: var(--bst-author-badge-va);
  975. margin:0;
  976. contain: strict;
  977. fill: currentColor;
  978. }
  979. .bst-message-badge-yt-icon *{
  980. pointer-events: none;
  981. }
  982. .bst-message-head-colon{
  983. display:inline;
  984. vertical-align: baseline;
  985. }
  986. .bst-message-head-colon::after{
  987. content: ': ';
  988. }
  989.  
  990. .bst-name-field {
  991. display: inline;
  992. --bst-name-field-background: transparent;
  993. position: relative;
  994. }
  995.  
  996. .bst-name-field:hover {
  997. --bst-name-field-background: var(--bst-name-field-background-default);
  998. background-color: var(--bst-name-field-background);
  999. border-radius: 0.3rem;
  1000. box-shadow: 0 0 0 0.3rem var(--bst-name-field-background);
  1001. cursor: pointer;
  1002. }
  1003. .bst-message-body::before {
  1004. content: '\u200b';
  1005. opacity: 0;
  1006. user-select: none;
  1007. }
  1008.  
  1009. .bst-message-profile-holder::before{
  1010. content: '\u200b';
  1011. opacity: 0;
  1012. user-select: none;
  1013. }
  1014.  
  1015. [author-type="owner"] .bst-name-field {
  1016. --bst-name-field-background: var(--yt-live-chat-author-chip-owner-background-color);
  1017. background-color: var(--bst-name-field-background);
  1018. border-radius: 0.3rem;
  1019. box-shadow: 0 0 0 0.3rem var(--bst-name-field-background);
  1020. }
  1021. .bst-message-entry {
  1022. display:block;
  1023. position: relative;
  1024. padding-left: var(--bst-message-entry-pl);
  1025. box-sizing: border-box;
  1026. min-height: 2.7rem;
  1027. overflow-wrap: anywhere;
  1028.  
  1029. /* transform-origin: bottom right; */
  1030. /* transition: transform 160ms ease-in-out 16ms; */
  1031. contain: layout style;
  1032. --bst-message-entry-opacity-v: 0.3; /* .bst-message-entry > .bst-message-container */
  1033.  
  1034. }
  1035.  
  1036. .bst-message-entry[view-pos] {
  1037. /* transform: scale(1); */
  1038. --bst-message-entry-opacity-v: 1.0;
  1039. }
  1040.  
  1041. .bst-message-entry.bst-viewer-engagement-message {
  1042. --bst-message-entry-pl: 0;
  1043. }
  1044.  
  1045. .bst-message-profile-anchor {
  1046. margin-left: calc( -1 * var(--yt-live-chat-profile-icon-size) );
  1047. position:absolute;
  1048. left: -8px;
  1049. display:inline-flex;
  1050. align-items: center;
  1051.  
  1052. vertical-align: super;
  1053. width: var(--yt-live-chat-profile-icon-size);
  1054. box-sizing:border-box;
  1055. }
  1056.  
  1057.  
  1058. .bst-message-head{
  1059. flex-shrink: 0;
  1060. display:inline;
  1061. flex-direction:row;
  1062. vertical-align: baseline;
  1063. position: relative;
  1064. }
  1065.  
  1066. .bst-message-entry[author-type="owner"] .bst-message-head-colon {
  1067. display: none;
  1068. }
  1069. .bst-message-entry[author-type="owner"] .bst-message-head{
  1070. margin-right: 8px;
  1071. margin-left: 4px;
  1072. }
  1073.  
  1074. .bst-message-list {
  1075. --color-opac-w-4: rgba(255, 255, 255, 0.16);
  1076. --border-radius-none: 0;
  1077. --border-radius-small: 0.2rem;
  1078. --border-radius-medium: 0.4rem;
  1079. --border-radius-large: 0.6rem;
  1080. --border-radius-extra-large: 1rem;
  1081. --border-radius-extra-extra-large: 1.6rem;
  1082. --border-radius-rounded: 9000px;
  1083. }
  1084.  
  1085. .bst-message-entry-highlight {
  1086. bottom: -0.36rem;
  1087. left: -0.86rem;
  1088. right: -0.86rem;
  1089. top: -0.36rem;
  1090. border-radius: var(--border-radius-medium);
  1091. position: absolute;
  1092. --color-background-interactable-alpha-hover: var(--color-opac-w-4);
  1093. --bst-highlight-color: var(--color-background-interactable-alpha-hover);
  1094. pointer-events: none !important;
  1095. }
  1096.  
  1097. .bst-message-entry-holding .bst-message-entry-highlight{
  1098. --color-background-interactable-alpha-hover: var(--color-opac-w-5);
  1099. }
  1100.  
  1101. .bst-message-entry-line {
  1102. position: relative;
  1103. display: inline;
  1104. }
  1105.  
  1106. .bst-message-entry:hover .bst-message-entry-highlight{
  1107. background-color: var(--bst-highlight-color);
  1108. }
  1109.  
  1110. .bst-message-entry-holding .bst-message-entry-highlight{
  1111. background-color: var(--bst-highlight-color);
  1112. }
  1113.  
  1114. .bst-message-before-content-button-container{
  1115. flex-shrink: 0;
  1116. display:inline;
  1117. flex-direction:column;
  1118. max-width:100%;
  1119. vertical-align: baseline;
  1120. }
  1121.  
  1122. .bst-message-body{
  1123. flex-shrink: 0;
  1124. display:inline; /* block ? inline-block? */
  1125. flex-direction:column;
  1126. max-width:100%;
  1127. vertical-align: baseline;
  1128. }
  1129.  
  1130. /* avoid "~" operator */ /* [^\s"']\s*[~\+]\s*[a-zA-Z] */
  1131. .bst-message-body-next-to-head{
  1132. line-height: var(--yt-live-chat-first-line-height);
  1133. }
  1134.  
  1135. .bst-message-body a{
  1136. color: inherit;
  1137. }
  1138.  
  1139.  
  1140. .bst-profile-img{
  1141. display: inline;
  1142. max-width: 100%;
  1143. border-style: solid;
  1144. border-width: 1.5px;
  1145. border-radius: 9999px;
  1146. vertical-align: middle;
  1147. position: absolute;
  1148. box-sizing:border-box;
  1149. contain: content;
  1150. }
  1151.  
  1152. .bst-message-profile-holder{
  1153. display:inline-flex;
  1154. align-items:center;
  1155. position:relative;
  1156. width:0;
  1157. height:1rem;
  1158. z-index: 1;
  1159. }
  1160.  
  1161. .bst-message-body .emoji {
  1162. contain: strict;
  1163. width: var(--yt-live-chat-emoji-size);
  1164. height: var(--yt-live-chat-emoji-size);
  1165. max-height: 4rem;
  1166. max-width: 4rem;
  1167. margin: -1px 2px 1px;
  1168. vertical-align: middle;
  1169. margin-bottom: .1rem;
  1170. }
  1171.  
  1172. bst-tooltip {
  1173. all: unset;
  1174. contain: content;
  1175. position: absolute;
  1176. background-color: var(--paper-tooltip-background, #616161);
  1177. color: var(--paper-tooltip-text-color, white);
  1178. padding: 6px 8px;
  1179. outline: none;
  1180. user-select: none;
  1181. cursor: default;
  1182. border-radius: 4px;
  1183. margin-left: calc(-0.5 * var(--yt-live-chat-emoji-size));
  1184.  
  1185. white-space: nowrap;
  1186. max-width: var(--yt-live-chat-tooltip-max-width);
  1187. text-overflow: ellipsis;
  1188. overflow: hidden;
  1189. z-index: 2;
  1190. pointer-events: none !important;
  1191.  
  1192. transform: var(--bst-tooltip-transform, translate(-50%, 100%));
  1193. margin-top: var(--bst-tooltip-mt, 0);
  1194. margin-bottom: var(--bst-tooltip-mb, -4px);
  1195.  
  1196. }
  1197. bst-tooltip:empty{
  1198. display: none;
  1199. }
  1200.  
  1201. .bst-message-entry:hover{
  1202. z-index:1;
  1203. }
  1204. .bst-message-entry-holding{
  1205. z-index:2;
  1206. }
  1207.  
  1208. .bst-message-entry[view-pos="down"] {
  1209. --bst-tooltip-transform: translate(-50%, -100%);
  1210. --bst-tooltip-mt: -4px;
  1211. --bst-tooltip-mb: 0;
  1212. --bst-message-menu-container-bottom: 100%;
  1213. }
  1214.  
  1215. .bst-message-menu-container tp-yt-paper-listbox{
  1216. display: var(--bst-message-menu-listbox-display, flex) !important;
  1217. flex-direction: var(--bst-message-menu-listbox-flex-direction, column) !important;
  1218. }
  1219.  
  1220. .bst-message-entry{
  1221. --bst-message-menu-listbox-display: flex;
  1222. --bst-message-menu-listbox-flex-direction: column;
  1223. }
  1224.  
  1225. .bst-message-entry[view-pos="down"]{
  1226. --bst-message-menu-listbox-flex-direction: column-reverse;
  1227. }
  1228.  
  1229. .bst-message-entry[author-type="member"] .bst-message-name-color{
  1230. --bst-username-color: var(--yt-live-chat-sponsor-color);
  1231. color: var(--bst-username-color);
  1232. }
  1233. .bst-message-entry[author-type="moderator"] .bst-message-name-color{
  1234. --bst-username-color: var(--yt-live-chat-moderator-color);
  1235. color: var(--bst-username-color);
  1236. }
  1237. .bst-message-entry[author-type="owner"] .bst-message-name-color{
  1238. --bst-username-color: var(--yt-live-chat-author-chip-owner-text-color);
  1239. color: var(--bst-username-color);
  1240. }
  1241.  
  1242.  
  1243. .bst-message-entry .bst-message-name-color .bst-message-badge-yt-icon[icon-type="verified"] {
  1244. color: var(--yt-live-chat-verified-color, inherit);
  1245. }
  1246.  
  1247.  
  1248.  
  1249. .bst-viewer-engagement-message .bst-message-entry-line{
  1250. display: flex;
  1251. flex-direction: row;
  1252. padding: 12px 8px;
  1253. }
  1254.  
  1255. .bst-viewer-engagement-message .bst-message-body {
  1256. flex: none;
  1257. flex-shrink: initial;
  1258. }
  1259.  
  1260. .bst-system-message-yt-icon{
  1261. display:inline-block;
  1262. }
  1263.  
  1264. .bst-viewer-engagement-message yt-icon {
  1265. width: var(--iron-icon-width,24px);
  1266. height: var(--iron-icon-height,24px);
  1267. contain: strict;
  1268. }
  1269. .bst-system-message-icon-column {
  1270. flex: none;
  1271. margin-right: 12px;
  1272. }
  1273.  
  1274. .bst-viewer-engagement-message .bst-message-entry-highlight{
  1275. margin-left:0;
  1276. background-color: var(--bst-highlight-color);
  1277. }
  1278.  
  1279. .bst-paid-message{
  1280.  
  1281. --yt-live-chat-paid-message-background-color: var( --yt-live-chat-paid-message-primary-color );
  1282. --yt-live-chat-paid-message-header-background-color: var( --yt-live-chat-paid-message-secondary-color );
  1283. --yt-live-chat-text-input-field-placeholder-color: var( --yt-live-chat-paid-message-color );
  1284. --yt-live-chat-item-timestamp-display: var( --yt-live-chat-paid-message-timestamp-display,none )
  1285. }
  1286.  
  1287.  
  1288. .bst-paid-message .bst-message-body{
  1289. display: block;
  1290. }
  1291. .bst-paid-message .bst-message-body:empty{
  1292. display: none;
  1293. }
  1294.  
  1295. .bst-paid-message .bst-message-name-color .bst-message-username[class]{
  1296. color: var(--yt-live-chat-disable-highlight-message-author-name-color,rgba(255,255,255,.7));
  1297. font-size: 110%;
  1298. }
  1299. .bst-paid-sticker .bst-message-name-color .bst-message-username[class]{
  1300. color: var(--yt-live-chat-disable-highlight-message-author-name-color,rgba(255,255,255,.7));
  1301. font-size: 110%;
  1302. }
  1303.  
  1304.  
  1305. .bst-paid-message, .bst-paid-sticker{
  1306. --bst-paid-amount-font-size: 115%;
  1307. }
  1308.  
  1309. .bst-paid-amount{
  1310. display: inline;
  1311. white-space: nowrap;
  1312. margin-left: 12px;
  1313. font-size: var(--bst-paid-amount-font-size, inherit);
  1314. }
  1315.  
  1316. .bst-paid-message .bst-message-entry-highlight[class]{
  1317. --bst-highlight-color: var(--yt-live-chat-paid-message-background-color,#1565c0);
  1318. background-color: var(--bst-highlight-color);
  1319. }
  1320. .bst-paid-message .bst-message-head{
  1321.  
  1322. color: var(--yt-live-chat-paid-message-header-color,var(--bst-default-text-color));
  1323. }
  1324.  
  1325. .bst-paid-message .bst-message-body{
  1326. background-color: var(--yt-live-chat-paid-message-background-color,#1565c0);
  1327. color: var(--yt-live-chat-paid-message-color,var(--bst-default-text-color));
  1328. }
  1329.  
  1330. .bst-message-list[class] .bst-membership-message[class],
  1331. .bst-message-list[class] .bst-sponsorship-purchase[class],
  1332. .bst-message-list[class] .bst-paid-sticker[class] {
  1333. --yt-live-chat-sponsor-header-color: #0a8043;
  1334. --yt-live-chat-sponsor-color: #0f9d58;
  1335. }
  1336.  
  1337. .bst-membership-message[class]{
  1338.  
  1339. --yt-live-chat-sponsor-text-color: var(--bst-default-text-color);
  1340. --yt-live-chat-item-timestamp-display: var( --yt-live-chat-paid-message-timestamp-display,none );
  1341. --yt-live-chat-moderator-color: var(--yt-spec-static-overlay-text-secondary);
  1342. --yt-live-chat-footer-button-text-color: #030303;
  1343. --yt-live-chat-footer-button-text-background-color: var(--bst-default-text-color);
  1344. }
  1345.  
  1346.  
  1347.  
  1348.  
  1349.  
  1350. .bst-membership-message .bst-message-username[class]{
  1351. color: var(--bst-default-text-color);
  1352. }
  1353.  
  1354.  
  1355. .bst-gift-message .bst-message-body{
  1356. color: var(--yt-live-chat-secondary-text-color);
  1357. font-style: italic;
  1358. margin-left: 2px;
  1359. }
  1360.  
  1361.  
  1362.  
  1363. .bst-message-entry-holding{
  1364. --bst-message-menu-display: block;
  1365. }
  1366.  
  1367. .bst-message-menu-container{
  1368.  
  1369. pointer-events: none !important;
  1370.  
  1371. display: var(--bst-message-menu-display, none);
  1372.  
  1373. position: absolute;
  1374. left: 0;
  1375. right: 0;
  1376. padding: 8px;
  1377.  
  1378. bottom: var(--bst-message-menu-container-bottom, initial);
  1379.  
  1380. }
  1381.  
  1382. .bst-message-menu-item{
  1383. padding: 4px 8px;
  1384. background-color: var(--color-opac-w-4);
  1385. margin:2px;
  1386. cursor: pointer;
  1387.  
  1388. }
  1389.  
  1390. .bst-message-menu-item:hover{
  1391. background-color: var(--color-opac-w-6);
  1392.  
  1393. }
  1394.  
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400. .bst-sponsorship-purchase .bst-message-body{
  1401. display:block;
  1402. }
  1403. .bst-sponsorship-purchase .bst-message-body:empty{
  1404. display: none;
  1405. }
  1406.  
  1407.  
  1408. .bst-sponsorship-purchase{
  1409. padding-right: 6rem;
  1410. min-height: 6.6rem;
  1411. }
  1412.  
  1413. .bst-sponsorship-purchase .bst-message-entry-highlight {
  1414. --bst-highlight-color: var(--yt-live-chat-sponsor-color);
  1415. background: url(https://www.gstatic.com/youtube/img/sponsorships/sponsorships_gift_purchase_announcement_artwork.png); /* to be reviewed? */
  1416. background-repeat: no-repeat;
  1417. background-size: contain;
  1418. background-position: 100% 50%;
  1419. background-color: var(--bst-highlight-color);
  1420. background-size: 6rem;
  1421. }
  1422.  
  1423.  
  1424.  
  1425.  
  1426. .bst-paid-sticker .bst-message-body{
  1427. display:block;
  1428. }
  1429. .bst-paid-sticker .bst-message-body:empty{
  1430. display: none;
  1431. }
  1432.  
  1433.  
  1434. .bst-paid-sticker{
  1435. padding-right: 6rem;
  1436. min-height: 6.6rem;
  1437. }
  1438.  
  1439. .bst-paid-sticker .bst-message-entry-highlight {
  1440. --bst-highlight-color: var(--yt-live-chat-paid-sticker-background-color);
  1441. background: var(--bst-paid-sticker-bg, initial);
  1442. /* background: url(https://www.gstatic.com/youtube/img/sponsorships/sponsorships_gift_purchase_announcement_artwork.png);*/
  1443. background-repeat: no-repeat;
  1444. background-size: contain;
  1445. background-position: 100% 50%;
  1446. background-color: var(--bst-highlight-color);
  1447. background-size: 6rem;
  1448. }
  1449.  
  1450. .bst-paid-sticker .bst-message-head {
  1451. color: var(--yt-live-chat-paid-sticker-chip-text-color, var(--bst-default-text-color));
  1452. }
  1453.  
  1454. .bst-message-entry.bst-message-entry-ll {
  1455. --bst-message-entry-pl:0;
  1456. }
  1457. .bst-message-entry-header {
  1458. --bst-message-entry-pl: calc( var(--yt-live-chat-profile-icon-size) + 6px );
  1459. padding-left: var(--bst-message-entry-pl);
  1460.  
  1461. }
  1462.  
  1463. .bst-membership-message .bst-message-entry-header .bst-message-entry-highlight[class]{
  1464. --bst-highlight-color: var(--yt-live-chat-sponsor-header-color);
  1465. background-color: var(--bst-highlight-color);
  1466. }
  1467. .bst-membership-message .bst-message-entry-body .bst-message-entry-highlight[class]{
  1468. --bst-highlight-color: var(--yt-live-chat-sponsor-color);
  1469. background-color: var(--bst-highlight-color);
  1470. }
  1471.  
  1472. .bst-membership-message .bst-message-entry-header .bst-message-entry-highlight.bst-message-entry-followed-by-body {
  1473. bottom: 0;
  1474. border-bottom-left-radius: 0;
  1475. border-bottom-right-radius: 0;
  1476. }
  1477.  
  1478. .bst-membership-message .bst-message-entry-body .bst-message-entry-highlight {
  1479. top: 0;
  1480. border-top-left-radius: 0;
  1481. border-top-right-radius: 0;
  1482. }
  1483.  
  1484. .bst-message-entry-header, .bst-message-entry-body {
  1485. position: relative;
  1486. }
  1487.  
  1488. .bst-membership-message .bst-message-entry-body .bst-message-body::before {
  1489. content: '';
  1490. contain: strict;
  1491. display: inline;
  1492. user-select: none !important;
  1493. pointer-events: none !important;
  1494. line-height: var(--yt-live-chat-first-line-height);
  1495. vertical-align: baseline;
  1496. }
  1497.  
  1498. .bst-membership-message .bst-message-entry-header .bst-message-head {
  1499. margin-right: 8px;
  1500. }
  1501.  
  1502. .bst-membership-message .bst-message-entry-header .bst-message-body {
  1503. margin-left: 0px;
  1504. display: inline-block;
  1505. }
  1506.  
  1507. .bst-membership-message .bst-message-entry-body .bst-message-body {
  1508. margin-left: 8px;
  1509. color: var(--yt-live-chat-sponsor-text-color)
  1510. }
  1511.  
  1512. .bst-name-field-box {
  1513. pointer-events: none;
  1514. display: none;
  1515. position: absolute;
  1516. left: 0;
  1517. top: calc(100% + 4px);
  1518. background: white;
  1519. color: black;
  1520. z-index: 1;
  1521. contain: content;
  1522. }
  1523.  
  1524. .bst-name-field:hover .bst-name-field-box {
  1525. pointer-events: none;
  1526. }
  1527.  
  1528. bst-live-chat-placeholder {
  1529. display: none;
  1530. }
  1531.  
  1532. .bst-live-chat-element[class] {
  1533. padding:0;
  1534. margin:0;
  1535. }
  1536.  
  1537. bst-live-chat-unknownitem {
  1538. display: block;
  1539. height: 3.4rem;
  1540. background-color: rgb(127, 127, 127);
  1541. cursor: not-allowed;
  1542. opacity: 0.6;
  1543. }
  1544. bst-live-chat-unknownitem:hover{
  1545. opacity: 1;
  1546. }
  1547.  
  1548. .bst-profile-card {
  1549. position: absolute;
  1550. display: none;
  1551. position: absolute;
  1552. left: 0;
  1553. right: 0;
  1554. height: 100px; /* border: 3px solid white; */
  1555. box-sizing: border-box;
  1556. z-index: 3;
  1557. display: flex;
  1558. flex-direction: row;
  1559. border-top-left-radius: var(--border-radius-medium);
  1560. border-top-right-radius: var(--border-radius-medium);
  1561. box-shadow: var(--shadow-elevation-2);
  1562. margin-left: 1.5rem;
  1563. margin-right: 1.5rem;
  1564. background: var(--yt-live-chat-background-color);
  1565. top: calc(var(--fBottom) + 4px);
  1566. transform: initial;
  1567. margin-top: 0;
  1568. margin-bottom: 0;
  1569. max-height: 38vh;
  1570. }
  1571.  
  1572. .bst-profile-card-on-top {
  1573. top: calc(var(--fTop) - 4px);
  1574. transform: translateY(-100%);
  1575. margin-top: 0;
  1576. margin-bottom: 0;
  1577. }
  1578.  
  1579. .bst-profile-card-overlay {
  1580. position: absolute;
  1581. z-index: -1;
  1582. left: 0;
  1583. right: 0;
  1584. top: 0;
  1585. bottom: 0;
  1586. background: var(--yt-spec-menu-background);
  1587. pointer-events: none;
  1588. opacity: 0.45;
  1589. }
  1590.  
  1591. .bst-profile-card-icon {
  1592. margin: 1rem;
  1593. margin-right: 0;
  1594. }
  1595.  
  1596. .bst-profile-card-icon-img {
  1597. max-height: 50px;
  1598. max-width: 50px;
  1599. }
  1600.  
  1601. .bst-profile-card-main {
  1602. flex-grow: 1;
  1603. margin: 1rem;
  1604. }
  1605.  
  1606. .bst-profile-card-main a[href] {
  1607. --bst-hyperlink-color: var(--bst-default-text-color);
  1608. color: var(--bst-hyperlink-color);
  1609. text-decoration: none;
  1610. display: inline;
  1611. }
  1612.  
  1613. .bst-profile-card-main a[href]:link,
  1614. .bst-profile-card-main a[href]:visited,
  1615. .bst-profile-card-main a[href]:hover,
  1616. .bst-profile-card-main a[href]:active,
  1617. .bst-profile-card-main a[href]:focus {
  1618. color: var(--bst-hyperlink-color);
  1619. }
  1620.  
  1621. .bst-profile-card-cross {
  1622. display: inline-flex;
  1623. -webkit-box-align: center;
  1624. align-items: center;
  1625. -webkit-box-pack: center;
  1626. justify-content: center;
  1627. user-select: none;
  1628. border-radius: var(--border-radius-medium);
  1629. height: var(--button-size-default);
  1630. width: var(--button-size-default);
  1631. border: var(--border-width-default) solid transparent;
  1632. cursor: pointer;
  1633. margin: 0.5rem;
  1634. font-family: system-ui;
  1635. font-size: large;
  1636. contain: strict;
  1637. }
  1638.  
  1639. .bst-profile-card-cross:hover {
  1640. background-color: var(--color-background-button-icon-overlay-hover);
  1641. color: var(--color-text-button-overlay-hover);
  1642. }
  1643.  
  1644. .bst-message-before-content-button-container button {
  1645. border-radius: 12px;
  1646. position: relative;
  1647. margin: 0;
  1648. white-space: nowrap;
  1649. min-width: 0;
  1650. text-transform: none;
  1651. border: none;
  1652. cursor: pointer;
  1653. outline-width: 0;
  1654. box-sizing: border-box;
  1655. background: none;
  1656. text-decoration: none;
  1657. margin: 0;
  1658. padding: 0;
  1659. padding: 2px 6px;
  1660. vertical-align: middle;
  1661. margin-bottom: .1rem;
  1662. margin-right: 2px;
  1663. contain: content;
  1664. }
  1665.  
  1666. .bst-message-before-content-button-container button div {
  1667. pointer-events: none !important;
  1668. }
  1669.  
  1670. .bst-message-before-content-button-container button .yt-spec-button-shape-next__icon {
  1671. margin: 0;
  1672. padding: 0;
  1673. border: 0;
  1674. width: 16px;
  1675. height: 16px;
  1676. line-height: 0;
  1677. fill: currentColor;
  1678. contain: strict;
  1679. }
  1680.  
  1681. .bst-message-before-content-button-container yt-touch-feedback-shape {
  1682. display: none !important;
  1683. }
  1684.  
  1685. .bst-message-container {
  1686. opacity: var(--bst-message-entry-opacity-v, 1.0);
  1687. transition: opacity 80ms ease-in-out 8ms;
  1688. }
  1689.  
  1690. .bst-message-container-f {
  1691. --bst-message-entry-opacity-v: 1.0; /* just opacity effect for the last message */
  1692. transition: initial;
  1693. }
  1694.  
  1695.  
  1696. .bst-message-menu-list{
  1697. display: flex;
  1698. justify-content: end;
  1699. pointer-events: none !important;
  1700. }
  1701.  
  1702. .bst-message-menu-list ytd-menu-popup-renderer{
  1703. max-width: initial !important;
  1704. min-width: initial !important;
  1705. max-height: initial !important;
  1706. min-height: initial !important;
  1707. pointer-events: initial !important;
  1708. }
  1709.  
  1710. `
  1711. }
  1712.  
  1713. /** @type {import('./library/html').SolidJS}.SolidJS */
  1714. const { createSignal, onMount, createStore, html, render, Switch, Match, For, createEffect, createMemo, Show, onCleanup, createComputed, createRenderEffect, unwrap } = SolidJS;
  1715.  
  1716. const { R, W ,rwWrap } = (() => {
  1717.  
  1718. /*
  1719. const sWrapper = (w) => {
  1720. const [singalGet, singalSet] = createSignal(1);
  1721. return function (e = 0) {
  1722. e ? Promise.resolve(x => (x & 1073741823) + e).then(singalSet) : singalGet();
  1723. return w;
  1724. };
  1725. };
  1726. */
  1727.  
  1728. const sWrapper = (w) => {
  1729. let u = 2;
  1730. const [singalGet, singalSet] = createSignal(1);
  1731. const p = (m) => singalSet(u); // first Promise
  1732. // const p = (m) => m === u && singalSet(u); // last Promise
  1733. // const p = (m) => singalSet(u + (m === u)); // first and last Promise
  1734. return function (e = 0) {
  1735. e
  1736. ? Promise.resolve((u = (u & 1073741823) + e)).then(p)
  1737. : singalGet();
  1738. (this !== w && this)?.valueOf?.(e);
  1739. return w;
  1740. };
  1741. };
  1742.  
  1743. const op = Object.prototype;
  1744. const R = (x) => {
  1745. let valueOf = x.valueOf;
  1746. if (valueOf === op.valueOf) valueOf = x.valueOf = sWrapper(x);
  1747. return valueOf();
  1748. };
  1749. const W = (x) => {
  1750. let valueOf = x.valueOf;
  1751. if (valueOf === op.valueOf) valueOf = x.valueOf = sWrapper(x);
  1752. return valueOf(3);
  1753. }
  1754. const rwWrap = (x) => {
  1755. if(typeof x === 'function') return x;
  1756. let valueOf = x.valueOf;
  1757. if (valueOf === op.valueOf) valueOf = x.valueOf = sWrapper(x);
  1758. return x.valueOf;
  1759. }
  1760.  
  1761. return { R, W, rwWrap };
  1762.  
  1763. })();
  1764.  
  1765. window.MMR = R;
  1766. window.MMW = W;
  1767.  
  1768. const memoStore = new WeakMap();
  1769.  
  1770.  
  1771. // -------------------------------------------------------------------------------------------
  1772. let rcKt = 0; // without rcKt, rcSignal() > rcValue => deadlock
  1773.  
  1774. let rcPromise = null;
  1775. const [rcSignal ,rcSignalSet]=createSignal(1);
  1776. let rcValue = 1;
  1777.  
  1778. const rcSignalAdd = (p) => {
  1779. if (p) {
  1780. rcValue = (rcValue & 1073741823) + 1;
  1781. }
  1782. const tkt = rcKt;
  1783. rcSignalSet(r => {
  1784. if (tkt !== rcKt) return r;
  1785. return (r & 1073741823) + 1;
  1786. });
  1787. };
  1788.  
  1789.  
  1790. createEffect(() => {
  1791. const m = rcSignal();
  1792. if (rcValue === m) {
  1793. rcPromise && rcPromise.resolve();
  1794. rcPromise = null;
  1795. rcKt = (rcKt & 1073741823) + 1;
  1796. }
  1797. });
  1798.  
  1799. // --- to avoid dead lock ---
  1800.  
  1801. let rcPromiseN = 0;
  1802. let rcPromiseT = null;
  1803. const rcPromiseUnlockFn = () => {
  1804. if (!rcPromise) { // rcPromise null
  1805. rcPromiseN = 0;
  1806. rcPromiseT = null;
  1807. } else if (rcPromiseT !== rcPromise) { // rcPromise not null and rcPromise!==rcPromiseT; rcPromiseT can be not null
  1808. if (rcPromiseT) rcPromiseT.resolve();
  1809. rcPromiseT = rcPromise;
  1810. rcPromiseN = 1;
  1811. } else { // rcPromise not null and rcPromise===rcPromiseT
  1812. console.log('[yt-bst] ERROR 0xFE02 - rcPromise deadlock', rcPromiseN);
  1813. if (rcPromiseN < 8) rcPromiseN++;
  1814. rcPromise.resolve();
  1815. rcPromise = null;
  1816. rcPromiseT = null;
  1817. rcKt = (rcKt & 1073741823) + 1;
  1818. }
  1819. };
  1820.  
  1821.  
  1822. // --- to avoid dead lock ---
  1823.  
  1824. // -------------------------------------------------------------------------------------------
  1825.  
  1826.  
  1827.  
  1828. const MEMO = (obj, key, val) => {
  1829.  
  1830. if (key === null) {
  1831. memoStore.delete(obj);
  1832. return;
  1833. } else if (!key) {
  1834. return memoStore.get(obj);
  1835. }
  1836.  
  1837. const m = `${key}`;
  1838. if (val === null) {
  1839. let s = memoStore.get(obj);
  1840. if (s && s[m]) s[m] = null;
  1841. } else if (val) {
  1842. let s = memoStore.get(obj);
  1843. if (!s) memoStore.set(obj, s = {});
  1844. if (!s[m]) {
  1845. s[m] = createMemo(val);
  1846. } else {
  1847. console.warn('MEMO setter: duplicated');
  1848. }
  1849. return s[m];
  1850. } else {
  1851. let s = memoStore.get(obj);
  1852. let r = s ? s[m] : null;
  1853. if (!r) {
  1854. console.warn('MEMO getter: duplicated');
  1855. }
  1856. return r;
  1857. }
  1858. }
  1859.  
  1860. function getThumbnail(thumbnails, min, max) {
  1861.  
  1862. for (const thumbnail of thumbnails) {
  1863. if (min >= 0 && thumbnail.width < min) {
  1864. continue;
  1865. }
  1866. if (max >= 0 && thumbnail.width > max) {
  1867. continue;
  1868. }
  1869. if (typeof thumbnail.url !== 'string') continue;
  1870. return thumbnail.url;
  1871. }
  1872. return thumbnails?.[0]?.url || '';
  1873.  
  1874. }
  1875.  
  1876. function removeEntry(o) {
  1877.  
  1878. /*
  1879.  
  1880.  
  1881. aObj.uid = aObj.uid || createMemo(() => {
  1882. })
  1883.  
  1884. if (aKey && typeof aKey === 'string') W(aObj).aKey = aKey;
  1885.  
  1886. MEMO(aObj, 'rendererFlag', ()=>{
  1887. });
  1888.  
  1889. MEMO(aObj, 'authorName', () => {
  1890. });
  1891. aObj.getProfilePic = getProfilePic;
  1892. aObj.getStickerURL = getStickerURL;
  1893. aObj.bst = bst;
  1894.  
  1895. MEMO(aObj, 'messageXT', () =>{
  1896. });
  1897.  
  1898.  
  1899. */
  1900.  
  1901. if (o.uid) {
  1902. o.uid = null;
  1903. }
  1904.  
  1905. MEMO(o, 'rendererFlag', null);
  1906.  
  1907. MEMO(o, 'authorName', null);
  1908.  
  1909. MEMO(o, 'messageXT', null);
  1910.  
  1911. MEMO(o, null);
  1912.  
  1913. const dataMutable = mutableWM.get(o);
  1914. dataMutable && dataMutable.removeEntry();
  1915. }
  1916.  
  1917. function colorFromDecimal(a) {
  1918. if (a === void 0 || a === null) return null;
  1919. a = Number(a);
  1920. if (!(a >= 0)) return null;
  1921. const k = (a >> 24 & 255) / 255;
  1922. let t = `${k}`;
  1923. if (t.length > 9) t = k.toFixed(5);
  1924. if (t === '1') {
  1925. return "rgb(" + [a >> 16 & 255, a >> 8 & 255, a & 255].join() + ")"
  1926. } else {
  1927. return "rgba(" + [a >> 16 & 255, a >> 8 & 255, a & 255, t].join() + ")"
  1928. }
  1929. }
  1930.  
  1931.  
  1932. const formatters = {
  1933. authorBadges(badge, data) { // performance concern? (11.0ms)
  1934.  
  1935.  
  1936. try {
  1937. const fk = firstObjectKey(badge) || '';
  1938. const ek = badge[fk];
  1939.  
  1940. /**
  1941. *
  1942.  
  1943. if (a.icon) {
  1944. var c = document.createElement("yt-icon");
  1945. "MODERATOR" === a.icon.iconType && this.enableNewModeratorBadge ? (c.polymerController.icon = "yt-sys-icons:shield-filled",
  1946. c.polymerController.defaultToFilled = !0) : c.polymerController.icon = "live-chat-badges:" + a.icon.iconType.toLowerCase();
  1947. b.appendChild(c)
  1948. } else if (a.customThumbnail) {
  1949. c = document.createElement("img");
  1950. var d;
  1951. (d = (d = eD(a.customThumbnail.thumbnails, 16)) ? Vb(ic(d)) : null) ? (c.src = d,
  1952. b.appendChild(c),
  1953. c.setAttribute("alt", this.hostElement.ariaLabel || "")) : qr(new sn("Could not compute URL for thumbnail",a.customThumbnail))
  1954. }
  1955. *
  1956. */
  1957.  
  1958. if (ek.icon && typeof ek.icon === 'object') {
  1959.  
  1960. const icon = ek.icon;
  1961. const type = icon.iconType.toLowerCase();
  1962. if (type === 'owner' && R(data).bst('shouldHighlight')) {
  1963.  
  1964. } else {
  1965.  
  1966. let tooltipText = () => ek.tooltip || ek.accessibility?.accessibilityData?.label || '';
  1967.  
  1968. let [tooltipDisplay, tooltipDisplaySet] = createSignal('');
  1969. let elmWR = null;
  1970. let onYtIconCreated = (el) => {
  1971. const cnt = insp(el);
  1972. cnt.icon = "live-chat-badges:" + type;
  1973. _setAttribute.call(el, 'icon-type', type);
  1974. tooltipText = tooltipText();
  1975. _setAttribute.call(el, 'shared-tooltip-text', tooltipText);
  1976. tooltipDisplaySet(tooltipText);
  1977. if (el.getAttribute23752) {
  1978. el.getAttribute = el.getAttribute23752;
  1979. }
  1980. elmWR = mWeakRef(el);
  1981. onYtIconCreated = null;
  1982. }
  1983. onCleanup(() => {
  1984. elmWR = null;
  1985. tooltipDisplay = nullGet;
  1986. tooltipDisplaySet = nullSet;
  1987. });
  1988. return html`<yt-icon class="bst-message-badge-yt-icon" ref="${onYtIconCreated}"></yt-icon><bst-tooltip>${() => (kRef(tooltipTarget()) || 1) === (kRef(elmWR) || 2) ? tooltipDisplay() : ''}</bst-tooltip>`;
  1989.  
  1990. }
  1991.  
  1992. } else if (typeof (ek.customThumbnail || 0) === 'object') {
  1993.  
  1994. // const className = `style-scope yt-live-chat-author-badge-renderer bst-author-badge`
  1995. const className = `bst-author-badge`;
  1996. const src = () => getThumbnail(ek.customThumbnail.thumbnails, 32, 64); // 16, 32
  1997. const alt = () => ek.accessibility?.accessibilityData?.label || '';
  1998.  
  1999.  
  2000.  
  2001.  
  2002. let tooltipText = () => ek.tooltip || ek.accessibility?.accessibilityData?.label || '';
  2003.  
  2004. let [tooltipDisplay, tooltipDisplaySet] = createSignal('');
  2005. let elmWR = null;
  2006. let onImgCreated = (el) => {
  2007. tooltipText = tooltipText();
  2008. tooltipDisplaySet(tooltipText);
  2009. if (el.getAttribute23752) {
  2010. el.getAttribute = el.getAttribute23752;
  2011. }
  2012. elmWR = mWeakRef(el);
  2013. onImgCreated = null;
  2014. }
  2015. onCleanup(() => {
  2016. elmWR = null;
  2017. tooltipDisplay = nullGet;
  2018. tooltipDisplaySet = nullSet;
  2019. });
  2020. return html`<img ref="${onImgCreated}" class="${className}" src="${src}" alt="${alt}" shared-tooltip-text="${tooltipText}" /><bst-tooltip>${() => (kRef(tooltipTarget()) || 1) === (kRef(elmWR) || 2) ? tooltipDisplay() : ''}</bst-tooltip>`
  2021.  
  2022.  
  2023.  
  2024.  
  2025.  
  2026. }
  2027.  
  2028.  
  2029. } catch (e) {
  2030. console.warn(e);
  2031. }
  2032.  
  2033. }
  2034. // messageBody(message, data) {
  2035.  
  2036. // if (typeof message === 'string') return html`<span>${() => message}</span>`
  2037. // if (typeof message.text === 'string') {
  2038. // if (message.navigationEndpoint?.urlEndpoint?.url) {
  2039. // const urlEndpoint = message.navigationEndpoint.urlEndpoint;
  2040. // return html`<a href="${() => R(urlEndpoint).url}" rel="${() => R(urlEndpoint).nofollow === true ? 'nofollow' : null}" target="${() => R(urlEndpoint).target === "TARGET_NEW_WINDOW" ? '_blank' : null}">${() => R(message).text}</span>`
  2041. // }
  2042. // return html`<span>${() => R(message).text}</span>`
  2043. // }
  2044.  
  2045.  
  2046.  
  2047.  
  2048. // if (typeof message.emoji !== 'undefined' && typeof (message.emoji||0) === 'object') {
  2049.  
  2050.  
  2051. // try {
  2052.  
  2053. // const emoji = message.emoji;
  2054.  
  2055.  
  2056. // const className = `small-emoji emoji yt-formatted-string style-scope yt-live-chat-text-message-renderer`
  2057.  
  2058.  
  2059. // const src = () => `${emoji.image.thumbnails[0].url}` // performance concern? (3.3ms)
  2060. // const alt = () => emoji.image?.accessibility?.accessibilityData?.label || ''; // performance concern? (1.7ms)
  2061. // let tooltipText = () => emoji.shortcuts?.[0] || ''; // performance concern? (1.7ms)
  2062. // const emojiId = () => emoji.emojiId || '';
  2063. // const isCustomEmoji = () => emoji.isCustomEmoji || false;
  2064.  
  2065.  
  2066.  
  2067.  
  2068.  
  2069.  
  2070. // let [tooltipDisplay, tooltipDisplaySet] = createSignal('');
  2071. // let elmWR = null;
  2072. // let onImgCreated = (el) => {
  2073. // tooltipText = tooltipText();
  2074. // tooltipDisplaySet(tooltipText);
  2075. // if (el.getAttribute23752) {
  2076. // el.getAttribute = el.getAttribute23752;
  2077. // }
  2078. // elmWR = mWeakRef(el);
  2079. // }
  2080. // onCleanup(()=>{
  2081. // tooltipDisplay = tooltipDisplaySet = onImgCreated = null;
  2082. // });
  2083. // return html`<img ref="${onImgCreated}" class="${className}" src="${src}" alt="${alt}" shared-tooltip-text="${tooltipText}" data-emoji-id="${emojiId}" is-custom-emoji="${isCustomEmoji}" /><bst-tooltip>${() => (kRef(tooltipTarget()) || 1) === (kRef(elmWR) || 2) ? tooltipDisplay() : ''}</bst-tooltip>`
  2084.  
  2085.  
  2086.  
  2087. // } catch (e) {
  2088. // console.warn(e);
  2089. // }
  2090.  
  2091. // }
  2092.  
  2093.  
  2094. // }
  2095. };
  2096.  
  2097. let sharedButtonViewModel = null;
  2098. let sharedNoscript = null;
  2099.  
  2100. function simulateClickOnBody() {
  2101. // Create and dispatch pointerdown
  2102. const pointerDownEvent = new PointerEvent('pointerdown', {
  2103. bubbles: true,
  2104. cancelable: true,
  2105. composed: true,
  2106. // You can add more PointerEvent-specific properties as needed
  2107. });
  2108. document.body.dispatchEvent(pointerDownEvent);
  2109. // Create and dispatch mousedown
  2110. const mouseDownEvent = new MouseEvent('mousedown', {
  2111. bubbles: true,
  2112. cancelable: true,
  2113. composed: true,
  2114. // You can add coordinates, modifiers, etc. as needed
  2115. });
  2116. document.body.dispatchEvent(mouseDownEvent);
  2117. // Create and dispatch pointerup
  2118. const pointerUpEvent = new PointerEvent('pointerup', {
  2119. bubbles: true,
  2120. cancelable: true,
  2121. composed: true,
  2122. });
  2123. document.body.dispatchEvent(pointerUpEvent);
  2124. // Create and dispatch mouseup
  2125. const mouseUpEvent = new MouseEvent('mouseup', {
  2126. bubbles: true,
  2127. cancelable: true,
  2128. composed: true,
  2129. });
  2130. document.body.dispatchEvent(mouseUpEvent);
  2131. // Finally, create and dispatch click
  2132. const clickEvent = new MouseEvent('click', {
  2133. bubbles: true,
  2134. cancelable: true,
  2135. composed: true,
  2136. });
  2137. document.body.dispatchEvent(clickEvent);
  2138. }
  2139.  
  2140. const SolidBeforeContentButton0 = (props) => {
  2141.  
  2142. const onButtonContainerCreated = (div) => {
  2143. let data = props.entryData;
  2144.  
  2145. if (!sharedNoscript) return;
  2146. const beforeContentButtons = data.beforeContentButtons;
  2147. if (!beforeContentButtons || beforeContentButtons.length !== 1) return;
  2148. const buttonViewModel = beforeContentButtons[0].buttonViewModel;
  2149. if (!buttonViewModel) return;
  2150.  
  2151. const bvData = Object.assign({}, buttonViewModel, { title: "", trackingParams: "", title_: buttonViewModel.title });
  2152.  
  2153. if (!sharedButtonViewModel) {
  2154. sharedButtonViewModel = document.createElement('yt-button-view-model');
  2155. sharedNoscript.appendChild(sharedButtonViewModel);
  2156. let cloneNode = sharedButtonViewModel.cloneNode(false, false);
  2157. sharedButtonViewModel.replaceWith(cloneNode);
  2158. sharedButtonViewModel = cloneNode;
  2159. }
  2160.  
  2161. const modelNode = sharedButtonViewModel.cloneNode(false, false);
  2162. insp(modelNode).data = bvData;
  2163.  
  2164. div.appendChild(modelNode);
  2165.  
  2166. data = null;
  2167. props = null;
  2168. div = null;
  2169.  
  2170. };
  2171. return html`
  2172. <div ref=${onButtonContainerCreated} class="bst-message-before-content-button-container">
  2173. </div>
  2174. `
  2175. };
  2176.  
  2177. let createIdx = 0;
  2178. let ux302 = null;
  2179. let popupKey302 = '';
  2180. const onSolidMenuListCreated_ = async (items, div, ytLiveChatAppCnt) => {
  2181.  
  2182. const createIdx_ = createIdx = (createIdx & 1073741823) + 1;
  2183.  
  2184. let ux0 = null;
  2185.  
  2186. const popups_ = ytLiveChatAppCnt.popups_;
  2187.  
  2188.  
  2189. const popupKey = popupKey302;
  2190. const ux = ux302;
  2191.  
  2192. if (ux && popupKey) {
  2193. ux0 = popups_[popupKey];
  2194. popups_[popupKey] = ux;
  2195. }
  2196.  
  2197. const ud = {
  2198. "items": [
  2199. ...items
  2200. ],
  2201. "openImmediately": true,
  2202. "__iwme848__": true,
  2203. };
  2204.  
  2205.  
  2206. const openPopupActionObj = {
  2207. "popupType": "DROPDOWN",
  2208. "popup": {
  2209. "menuPopupRenderer": ud
  2210. }
  2211. };
  2212.  
  2213.  
  2214. let pr = new PromiseExternal();
  2215. let mo = new MutationObserver(() => {
  2216.  
  2217. if (createIdx_ !== createIdx) {
  2218. mo && mo.disconnect();
  2219. mo = null
  2220. return;
  2221. }
  2222.  
  2223.  
  2224. const elements = [...document.querySelectorAll('ytd-menu-popup-renderer[class]')].filter(e => {
  2225. return !!insp(e)?.data?.__iwme848__;
  2226. })
  2227.  
  2228. if (elements[0]) {
  2229. pr && pr.resolve(elements[0]);
  2230. pr = null;
  2231. }
  2232.  
  2233. });
  2234.  
  2235. mo && mo.observe(document, { subtree: true, childList: true });
  2236.  
  2237. if (ux && popupKey) {
  2238.  
  2239. const contentWrapper = ux?.popup?.$?.contentWrapper;
  2240. const popupContent = ux.popupContent;
  2241.  
  2242. if (contentWrapper instanceof Node && popupContent instanceof Node && typeof ytLiveChatAppCnt.completeOpenPopupAction_ === 'function' && ytLiveChatAppCnt.completeOpenPopupAction_.length === 3) {
  2243. contentWrapper?.appendChild(popupContent);
  2244.  
  2245. ytLiveChatAppCnt.completeOpenPopupAction_(openPopupActionObj, div, ux);
  2246.  
  2247. } else {
  2248.  
  2249. if (ux.rendererName && ux.openPopupAction.uniqueId && typeof ytLiveChatAppCnt.handleClosePopupAction_ === 'function' && ytLiveChatAppCnt.handleClosePopupAction_.length === 2) {
  2250. ytLiveChatAppCnt.handleClosePopupAction_(ux.rendererName, ux.openPopupAction.uniqueId);
  2251. }
  2252.  
  2253. delete ytLiveChatAppCnt.popups_[popupKey];
  2254.  
  2255. ytLiveChatAppCnt.handleOpenPopupAction({
  2256. "openPopupAction": openPopupActionObj,
  2257. }, div);
  2258. }
  2259.  
  2260.  
  2261. } else {
  2262.  
  2263. ytLiveChatAppCnt.handleOpenPopupAction({
  2264. "openPopupAction": openPopupActionObj,
  2265. }, div);
  2266.  
  2267. }
  2268.  
  2269. const elm = pr ? await pr.then() : null;
  2270. pr = null;
  2271. mo && mo.disconnect();
  2272.  
  2273. if (elm && createIdx_ === createIdx) {
  2274. div.appendChild(elm);
  2275. }
  2276.  
  2277. (() => {
  2278. popupKey302 = '';
  2279. const popups_ = ytLiveChatAppCnt.popups_;
  2280. if (popups_) {
  2281. for (const k of Object.keys(popups_)) {
  2282. const v = popups_[k];
  2283. if (v && v.popupContent && insp(v.popupContent).data?.__iwme848__) {
  2284. popupKey302 = k;
  2285. ux302 = v;
  2286. break;
  2287. }
  2288. }
  2289. }
  2290. if (popupKey302) {
  2291. if (ux0) {
  2292. popups_[popupKey302] = ux0;
  2293. } else {
  2294. delete popups_[popupKey302];
  2295. }
  2296. }
  2297. })();
  2298.  
  2299. setTimeout(simulateClickOnBody, 1);
  2300. setTimeout(simulateClickOnBody, 80); // play-safe
  2301.  
  2302.  
  2303.  
  2304.  
  2305. };
  2306. const SolidMenuList = (props) => {
  2307.  
  2308.  
  2309. const onSolidMenuListCreated = (div) => {
  2310.  
  2311. let items = props.items;
  2312. /*
  2313.  
  2314. if (!sharedNoscript) return;
  2315. const beforeContentButtons = data.beforeContentButtons;
  2316. if (!beforeContentButtons || beforeContentButtons.length !== 1) return;
  2317. const buttonViewModel = beforeContentButtons[0].buttonViewModel;
  2318. if (!buttonViewModel) return;
  2319.  
  2320. const bvData = Object.assign({}, buttonViewModel, { title: "", trackingParams: "", title_: buttonViewModel.title });
  2321.  
  2322. if (!sharedButtonViewModel) {
  2323. sharedButtonViewModel = document.createElement('yt-button-view-model');
  2324. sharedNoscript.appendChild(sharedButtonViewModel);
  2325. let cloneNode = sharedButtonViewModel.cloneNode(false, false);
  2326. sharedButtonViewModel.replaceWith(cloneNode);
  2327. sharedButtonViewModel = cloneNode;
  2328. }
  2329.  
  2330. const modelNode = sharedButtonViewModel.cloneNode(false, false);
  2331. insp(modelNode).data = bvData;
  2332.  
  2333. */
  2334.  
  2335. /*
  2336.  
  2337. let ytdMenu = document.querySelector('#bst-menu-popup-renderer');
  2338. if(!ytdMenu){
  2339.  
  2340. ytdMenu = document.createElement('ytd-menu-popup-renderer');
  2341. ytdMenu.id='bst-menu-popup-renderer';
  2342. sharedNoscript.appendChild(ytdMenu);
  2343. }
  2344.  
  2345. insp(ytdMenu).data=Object.assign({}, {items: items, openImmediately: true})
  2346.  
  2347. */
  2348.  
  2349. const ytLiveChatAppElm = document.querySelector('yt-live-chat-app');
  2350. const ytLiveChatAppCnt = insp(ytLiveChatAppElm);
  2351.  
  2352.  
  2353. if (!ytLiveChatAppCnt) return;
  2354. if (!ytLiveChatAppCnt.handleOpenPopupAction || ytLiveChatAppCnt.handleOpenPopupAction.length !== 2) return;
  2355.  
  2356. // ytLiveChatAppCnt.handleCloseAllPopupsAction_();
  2357. onSolidMenuListCreated_(items, div, ytLiveChatAppCnt);
  2358.  
  2359. // div.appendChild(ytdMenu);
  2360. data = null;
  2361. props = null;
  2362. div = null;
  2363.  
  2364. };
  2365. return html`
  2366. <div ref=${onSolidMenuListCreated} class="bst-message-menu-list">
  2367. </div>
  2368. `
  2369. };
  2370.  
  2371. const replaceAll = String.prototype.replaceAll ? function (str, pattern, replacement) {
  2372. return str.replaceAll(pattern, replacement);
  2373. } : function (str, search, replace) {
  2374. if (typeof search === 'string') {
  2375. return str.split(search).join(replace);
  2376. } else if (search instanceof RegExp) {
  2377. const newRegExp = new RegExp(search.source, search.flags + 'g');
  2378. return str.replace(newRegExp, replace);
  2379. }
  2380. throw new TypeError('The search argument must be a string or a RegExp');
  2381. };
  2382. const emojiIdSymbol = Symbol();
  2383. const messageFlattenIcons = new Map();
  2384.  
  2385. const messageUnflatten = (str) => {
  2386.  
  2387. const b1 = String.fromCharCode(0xE274);
  2388. let p = str.includes(`${b1}@`);
  2389. return str.split(`${b1};`).map(s => {
  2390.  
  2391. const r = s.split(`${b1},`);
  2392. if (p && s.includes(`${b1}@`)) {
  2393. for (let i = 0; i < r.length; i++) {
  2394. r[i] = r[i].replace(`${b1}@`, `${b1}`);
  2395. }
  2396.  
  2397. }
  2398. return r;
  2399.  
  2400. });
  2401.  
  2402. }
  2403. let fixMessages = null;
  2404. const messageFlatten = (message) => {
  2405.  
  2406. // E${b1},${emojiId}${b1};T${b1},${text}${b1};E${b1},${emojiId}
  2407.  
  2408. let runs = null;
  2409.  
  2410. // ------ convertMessage ------
  2411. let t;
  2412. if (typeof (message || 0) !== 'object') runs = [];
  2413. else if ((t = message.simpleText) && typeof t === 'string') {
  2414. runs = [{ text: t }];
  2415. } else if ((t = message.runs) && t.length >= 0) {
  2416. runs = t;
  2417. } else {
  2418. runs = [];
  2419. }
  2420. // ------ convertMessage ------
  2421.  
  2422. // ------ fixMessages ------
  2423.  
  2424. fixMessages && (runs = fixMessages(runs));
  2425.  
  2426. // ------ fixMessages ------
  2427.  
  2428. const resultArr = new Array(runs.length);
  2429. let i = 0;
  2430. const b1 = String.fromCharCode(0xE274);
  2431.  
  2432. for (const run of runs) {
  2433. const wKey = typeof run.text === 'string' ? 'text' : firstObjectKey(run);
  2434. const wVal = wKey ? run[wKey] : null;
  2435. if (wKey === 'emoji' && typeof wVal === 'object') {
  2436. let emojiId = wVal[emojiIdSymbol] || wVal.emojiId;
  2437. if (typeof (emojiId || 0) !== 'string') {
  2438. emojiId = wVal[emojiIdSymbol] = `$$${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
  2439. }
  2440. let iconStored = messageFlattenIcons.get(emojiId);
  2441. if (!iconStored) {
  2442. messageFlattenIcons.set(emojiId, iconStored = wVal);
  2443. }
  2444. if (emojiId.includes(b1)) {
  2445. // invalid. just skip
  2446. console.warn('Error 0481', run);
  2447. } else {
  2448. t = `E${b1},${emojiId}`;
  2449. resultArr[i++] = t
  2450. }
  2451. } else if (wKey === 'text' && typeof wVal === 'string') {
  2452. t = wVal;
  2453. if (t.includes(b1)) {
  2454. t = replaceAll(t, b1, `${b1}@`);
  2455. }
  2456. const urlEndpoint = run.navigationEndpoint?.urlEndpoint;
  2457. const url = urlEndpoint?.url;
  2458. if (url) {
  2459. const { nofollow, target } = urlEndpoint;
  2460. t = `T${b1},${t}${b1},A${b1},${url}${b1},${nofollow || ''}${b1},${target || ''}`;
  2461. } else {
  2462. t = `T${b1},${t}`;
  2463. }
  2464. resultArr[i++] = t;
  2465. } else {
  2466. console.warn('Error 0482', run);
  2467. }
  2468. }
  2469.  
  2470.  
  2471. resultArr.length = i;
  2472. return resultArr.join(`${b1};`);
  2473.  
  2474.  
  2475.  
  2476.  
  2477. /*
  2478. [
  2479. {
  2480. "text": "大好き"
  2481. },
  2482. {
  2483. "emoji": {
  2484. "emojiId": "UCz1RAeb7dVaUcd-4rEgyxPw/M72iZYbCHr2k_9EP9fGUmAo",
  2485. "shortcuts": [
  2486. ":_にぱぁ:",
  2487. ":にぱぁ:"
  2488. ],
  2489. "searchTerms": [
  2490. "_にぱぁ",
  2491. "にぱぁ"
  2492. ],
  2493. "image": {
  2494. "thumbnails": [
  2495. {
  2496. "url": "https://yt3.ggpht.com/4Q8_RUaekNbE6XTkylSGx2IEbXp7OalBZB7IDLu_zGT0tyDjY8Mi8zTfS4f6CE1mN0Us0_nm=w48-h48-c-k-nd",
  2497. "width": 48,
  2498. "height": 48
  2499. }
  2500. ],
  2501. "accessibility": {
  2502. "accessibilityData": {
  2503. "label": "にぱぁ"
  2504. }
  2505. }
  2506. },
  2507. "isCustomEmoji": true
  2508. }
  2509. }
  2510. ]
  2511.  
  2512. */
  2513.  
  2514. /*
  2515.  
  2516. [
  2517. {
  2518. "emoji": {
  2519. "emojiId": "🌭",
  2520. "shortcuts": [
  2521. ":hot_dog:"
  2522. ],
  2523. "searchTerms": [
  2524. "hot",
  2525. "dog"
  2526. ],
  2527. "image": {
  2528. "thumbnails": [
  2529. {
  2530. "url": "https://fonts.gstatic.com/s/e/notoemoji/15.1/1f32d/72.png"
  2531. }
  2532. ],
  2533. "accessibility": {
  2534. "accessibilityData": {
  2535. "label": "🌭"
  2536. }
  2537. }
  2538. }
  2539. }
  2540. },
  2541. {
  2542. "emoji": {
  2543. "emojiId": "🧜‍♀",
  2544. "shortcuts": [
  2545. ":mermaid:"
  2546. ],
  2547. "searchTerms": [
  2548. "mermaid"
  2549. ],
  2550. "image": {
  2551. "thumbnails": [
  2552. {
  2553. "url": "https://fonts.gstatic.com/s/e/notoemoji/15.1/1f9dc_200d_2640/72.png"
  2554. }
  2555. ],
  2556. "accessibility": {
  2557. "accessibilityData": {
  2558. "label": "🧜‍♀"
  2559. }
  2560. }
  2561. }
  2562. }
  2563. },
  2564. {
  2565. "emoji": {
  2566. "emojiId": "🥖",
  2567. "shortcuts": [
  2568. ":baguette_bread:"
  2569. ],
  2570. "searchTerms": [
  2571. "baguette",
  2572. "bread"
  2573. ],
  2574. "image": {
  2575. "thumbnails": [
  2576. {
  2577. "url": "https://fonts.gstatic.com/s/e/notoemoji/15.1/1f956/72.png"
  2578. }
  2579. ],
  2580. "accessibility": {
  2581. "accessibilityData": {
  2582. "label": "🥖"
  2583. }
  2584. }
  2585. }
  2586. }
  2587. },
  2588. {
  2589. "emoji": {
  2590. "emojiId": "💗",
  2591. "shortcuts": [
  2592. ":growing_heart:",
  2593. ":heartpulse:"
  2594. ],
  2595. "searchTerms": [
  2596. "growing",
  2597. "heart",
  2598. "heartpulse"
  2599. ],
  2600. "image": {
  2601. "thumbnails": [
  2602. {
  2603. "url": "https://fonts.gstatic.com/s/e/notoemoji/15.1/1f497/72.png"
  2604. }
  2605. ],
  2606. "accessibility": {
  2607. "accessibilityData": {
  2608. "label": "💗"
  2609. }
  2610. }
  2611. }
  2612. }
  2613. }
  2614. ]
  2615.  
  2616.  
  2617.  
  2618.  
  2619. [
  2620. {
  2621. "emoji": {
  2622. "emojiId": "UCz1RAeb7dVaUcd-4rEgyxPw/lf4nZJyyLYnWgwODzpuQBA",
  2623. "shortcuts": [
  2624. ":_ペンライト:",
  2625. ":ペンライト:"
  2626. ],
  2627. "searchTerms": [
  2628. "_ペンライト",
  2629. "ペンライト"
  2630. ],
  2631. "image": {
  2632. "thumbnails": [
  2633. {
  2634. "url": "https://yt3.ggpht.com/qFvk19WffG348lFrdIk2ACLc8tn5_OIqyNINCfHCjz83vl1z8ITziwKIxOD06skW_aHQHAwWk0M=w48-h48-c-k-nd",
  2635. "width": 48,
  2636. "height": 48
  2637. }
  2638. ],
  2639. "accessibility": {
  2640. "accessibilityData": {
  2641. "label": "ペンライト"
  2642. }
  2643. }
  2644. },
  2645. "isCustomEmoji": true
  2646. }
  2647. },
  2648. {
  2649. "emoji": {
  2650. "emojiId": "UCz1RAeb7dVaUcd-4rEgyxPw/M72iZbzDHr2k_9EP9fGUmAo",
  2651. "shortcuts": [
  2652. ":_クラッチ:",
  2653. ":クラッチ:"
  2654. ],
  2655. "searchTerms": [
  2656. "_クラッチ",
  2657. "クラッチ"
  2658. ],
  2659. "image": {
  2660. "thumbnails": [
  2661. {
  2662. "url": "https://yt3.ggpht.com/Oi2sH_kWkyq4_dJbdsYKyTA68sZsCtYqq58_cfwmf2NHgq5_-lEyiOQW6myBhFnIBCiSWqSMYvY=w48-h48-c-k-nd",
  2663. "width": 48,
  2664. "height": 48
  2665. }
  2666. ],
  2667. "accessibility": {
  2668. "accessibilityData": {
  2669. "label": "クラッチ"
  2670. }
  2671. }
  2672. },
  2673. "isCustomEmoji": true
  2674. }
  2675. },
  2676. {
  2677. "emoji": {
  2678. "emojiId": "UCz1RAeb7dVaUcd-4rEgyxPw/M72iZenDHr2k_9EP9fGUmAo",
  2679. "shortcuts": [
  2680. ":_ゲーミングペンライト:",
  2681. ":ゲーミングペンライト:"
  2682. ],
  2683. "searchTerms": [
  2684. "_ゲーミングペンライト",
  2685. "ゲーミングペンライト"
  2686. ],
  2687. "image": {
  2688. "thumbnails": [
  2689. {
  2690. "url": "https://yt3.ggpht.com/mFhN5NK8Qm-Lu_QN3iTukx--9_hfHs_C3GTpoQzUdyc3JwwCXGtJ0ffuPWvL4rY67nCfRgZ5T-U=w48-h48-c-k-nd",
  2691. "width": 48,
  2692. "height": 48
  2693. }
  2694. ],
  2695. "accessibility": {
  2696. "accessibilityData": {
  2697. "label": "ゲーミングペンライト"
  2698. }
  2699. }
  2700. },
  2701. "isCustomEmoji": true
  2702. }
  2703. },
  2704. {
  2705. "emoji": {
  2706. "emojiId": "UCz1RAeb7dVaUcd-4rEgyxPw/lf4nZJyyLYnWgwODzpuQBA",
  2707. "shortcuts": [
  2708. ":_ペンライト:",
  2709. ":ペンライト:"
  2710. ],
  2711. "searchTerms": [
  2712. "_ペンライト",
  2713. "ペンライト"
  2714. ],
  2715. "image": {
  2716. "thumbnails": [
  2717. {
  2718. "url": "https://yt3.ggpht.com/qFvk19WffG348lFrdIk2ACLc8tn5_OIqyNINCfHCjz83vl1z8ITziwKIxOD06skW_aHQHAwWk0M=w48-h48-c-k-nd",
  2719. "width": 48,
  2720. "height": 48
  2721. }
  2722. ],
  2723. "accessibility": {
  2724. "accessibilityData": {
  2725. "label": "ペンライト"
  2726. }
  2727. }
  2728. },
  2729. "isCustomEmoji": true
  2730. }
  2731. },
  2732. {
  2733. "emoji": {
  2734. "emojiId": "UCz1RAeb7dVaUcd-4rEgyxPw/M72iZbzDHr2k_9EP9fGUmAo",
  2735. "shortcuts": [
  2736. ":_クラッチ:",
  2737. ":クラッチ:"
  2738. ],
  2739. "searchTerms": [
  2740. "_クラッチ",
  2741. "クラッチ"
  2742. ],
  2743. "image": {
  2744. "thumbnails": [
  2745. {
  2746. "url": "https://yt3.ggpht.com/Oi2sH_kWkyq4_dJbdsYKyTA68sZsCtYqq58_cfwmf2NHgq5_-lEyiOQW6myBhFnIBCiSWqSMYvY=w48-h48-c-k-nd",
  2747. "width": 48,
  2748. "height": 48
  2749. }
  2750. ],
  2751. "accessibility": {
  2752. "accessibilityData": {
  2753. "label": "クラッチ"
  2754. }
  2755. }
  2756. },
  2757. "isCustomEmoji": true
  2758. }
  2759. },
  2760. {
  2761. "emoji": {
  2762. "emojiId": "UCz1RAeb7dVaUcd-4rEgyxPw/M72iZenDHr2k_9EP9fGUmAo",
  2763. "shortcuts": [
  2764. ":_ゲーミングペンライト:",
  2765. ":ゲーミングペンライト:"
  2766. ],
  2767. "searchTerms": [
  2768. "_ゲーミングペンライト",
  2769. "ゲーミングペンライト"
  2770. ],
  2771. "image": {
  2772. "thumbnails": [
  2773. {
  2774. "url": "https://yt3.ggpht.com/mFhN5NK8Qm-Lu_QN3iTukx--9_hfHs_C3GTpoQzUdyc3JwwCXGtJ0ffuPWvL4rY67nCfRgZ5T-U=w48-h48-c-k-nd",
  2775. "width": 48,
  2776. "height": 48
  2777. }
  2778. ],
  2779. "accessibility": {
  2780. "accessibilityData": {
  2781. "label": "ゲーミングペンライト"
  2782. }
  2783. }
  2784. },
  2785. "isCustomEmoji": true
  2786. }
  2787. }
  2788. ]
  2789.  
  2790.  
  2791. */
  2792.  
  2793.  
  2794. }
  2795.  
  2796. let timelineResolve;
  2797.  
  2798. const ojWrap = (obj => {
  2799. return typeof obj === 'function' ? obj : () => obj;
  2800. });
  2801. const ojUnwrap = (obj => {
  2802. return typeof obj === 'function' ? obj() : obj;
  2803. });
  2804.  
  2805. let convertAObj, showMenu, messageListWR_;
  2806.  
  2807. /** @type {IntersectionObserver} */
  2808. let ioMessageList = null;
  2809.  
  2810. const setupMutable = (bObj_) =>{
  2811.  
  2812. const bObj = bObj_;
  2813. if(mutableWM.has(bObj)) return;
  2814.  
  2815. let bObjWR = mWeakRef(bObj);
  2816. let mutableWR;
  2817. let createdPromise = new PromiseExternal();
  2818.  
  2819. let messageEntryWR = null;
  2820.  
  2821.  
  2822. const bObjChange = (val) => {
  2823. const f = kRef(mutableWR)?.bObjChange
  2824. if (f) f(val);
  2825. }
  2826.  
  2827. const mutable = {
  2828. getDataObj() {
  2829. return kRef(bObjWR);
  2830. },
  2831. removeEntryFuncs: new Map(),
  2832. tooltips: new Map(),
  2833. createdPromise: createdPromise,
  2834. removeEntry() {
  2835.  
  2836. this.removeEntryFuncs.forEach((f) => {
  2837. f.call(this);
  2838. });
  2839. this.removeEntryFuncs.clear();
  2840. this.tooltips.clear();
  2841.  
  2842. this.createdPromise = null;
  2843. this.removeEntryFuncs = null;
  2844. this.tooltips = null;
  2845. this.removeEntry = null;
  2846. this.setupFn = null;
  2847. this.bObjChange = null;
  2848.  
  2849. },
  2850. bObjChange(val, aKey) {
  2851. let bObj = kRef(bObjWR);
  2852. if (!bObj) return;
  2853. if (typeof (val || 0) === 'object') {
  2854. for (const s of ['authorBadges', 'message']) {
  2855. Reflect.has(val, s) || (val[s] = undefined);
  2856. Reflect.has(val, s) || (val[s] = undefined);
  2857. }
  2858. }
  2859. convertAObj(val, aKey || val.aKey || undefined);
  2860. Object.assign(W(bObj), val);
  2861. },
  2862. setupFn(_messageEntry) {
  2863.  
  2864. if (messageEntryWR) {
  2865. console.warn('setupFn warning 01');
  2866. return;
  2867. }
  2868.  
  2869. /** @type {HTMLElement} */
  2870. messageEntryWR = mWeakRef(_messageEntry);
  2871. const messageListWR__ = messageListWR_;
  2872.  
  2873. if (!kRef(bObjWR) || !kRef(mutableWR)) {
  2874. console.warn('setupFn warning 02');
  2875. return;
  2876. }
  2877.  
  2878. const [interceptionRatio, interceptionRatioChange] = createSignal(null);
  2879. const [viewVisible, viewVisibleChange] = createSignal(null);
  2880. const [viewVisibleIdx, viewVisibleIdxChange] = createSignal(null); // 1 to n
  2881.  
  2882. const baseRemoveFn = () => {
  2883. const bObj = kRef(bObjWR);
  2884. const messageEntry = kRef(messageEntryWR);
  2885. mutableWM.delete(bObj);
  2886. mutableWM.delete(messageEntry);
  2887. };
  2888.  
  2889. {
  2890. const messageEntry = _messageEntry;
  2891. let mutable = kRef(mutableWR);
  2892. mutable.viewVisible = viewVisible;
  2893. mutable.viewVisibleChange = viewVisibleChange;
  2894. mutable.viewVisibleIdx = viewVisibleIdx;
  2895. mutable.viewVisibleIdxChange = viewVisibleIdxChange;
  2896. mutable.interceptionRatioChange = interceptionRatioChange;
  2897. mutableWM.set(messageEntry, mutable);
  2898. messageEntry.showMenu = showMenu;
  2899. mutable.removeEntryFuncs.set('baseRemove', baseRemoveFn);
  2900. mutable = null;
  2901. }
  2902.  
  2903.  
  2904. const polymerController = {
  2905. set(prop, val) {
  2906. if (prop === 'data') {
  2907. bObjChange(val);
  2908. }
  2909. },
  2910. get data() {
  2911. return kRef(bObjWR);
  2912. },
  2913. set data(val) {
  2914. bObjChange(val);
  2915. },
  2916. get dataRaw() {
  2917. return kRef(bObjWR);
  2918. },
  2919. get dataMutable() {
  2920. return kRef(mutableWR);
  2921. },
  2922. get authorType() {
  2923. const bObj = kRef(bObjWR);
  2924. return getAuthorBadgeType(bObj.authorBadges);
  2925. }
  2926. };
  2927.  
  2928.  
  2929. {
  2930.  
  2931. const messageEntry = _messageEntry;
  2932. messageEntry.polymerController =polymerController;
  2933.  
  2934. }
  2935.  
  2936. {
  2937.  
  2938. let bObj = kRef(bObjWR);
  2939.  
  2940. if (!!(bObj.aKey && bObj.aKey !== 'liveChatTextMessageRenderer')) {
  2941.  
  2942. const messageEntry = kRef(messageEntryWR);
  2943. const a = bObj;
  2944. const entries = Object.entries({
  2945.  
  2946. "--yt-live-chat-disable-highlight-message-author-name-color": colorFromDecimal(a.authorNameTextColor),
  2947. "--yt-live-chat-text-input-background-color": colorFromDecimal(a.textInputBackgroundColor),
  2948.  
  2949. ...(a.aKey === "liveChatPaidMessageRenderer" ? {
  2950.  
  2951. "--yt-live-chat-paid-message-primary-color": colorFromDecimal(a.bodyBackgroundColor),
  2952. "--yt-live-chat-paid-message-secondary-color": colorFromDecimal(a.headerBackgroundColor),
  2953. "--yt-live-chat-paid-message-header-color": colorFromDecimal(a.headerTextColor),
  2954. "--yt-live-chat-paid-message-timestamp-color": colorFromDecimal(a.timestampColor),
  2955. "--yt-live-chat-paid-message-color": colorFromDecimal(a.bodyTextColor),
  2956. } : {
  2957.  
  2958. }),
  2959.  
  2960. ...(a.aKey === "liveChatPaidStickerRenderer" ? {
  2961. "--yt-live-chat-paid-sticker-chip-background-color": colorFromDecimal(a.moneyChipBackgroundColor),
  2962. "--yt-live-chat-paid-sticker-chip-text-color": colorFromDecimal(a.moneyChipTextColor),
  2963. "--yt-live-chat-paid-sticker-background-color": colorFromDecimal(a.backgroundColor),
  2964. } : {
  2965.  
  2966. })
  2967.  
  2968.  
  2969. });
  2970.  
  2971. if (entries.length >= 1) {
  2972. for (const [key, value] of entries) {
  2973. if (value) messageEntry.style.setProperty(key, value);
  2974. }
  2975. }
  2976.  
  2977. }
  2978.  
  2979. }
  2980.  
  2981. // change on state
  2982. createEffect(() => {
  2983.  
  2984. const visible = interceptionRatio();
  2985. if (visible > 0.9) {
  2986. viewVisibleChange(1);
  2987. } else if (visible < 0.1) {
  2988. viewVisibleChange(0);
  2989. }
  2990.  
  2991. });
  2992.  
  2993. // change on state
  2994. const viewVisiblePos = createMemo(() => {
  2995. const messageList = kRef(messageListWR__);
  2996. if (!messageList) return;
  2997. const viewCount = messageList.visibleCount();
  2998. const num = viewVisibleIdx();
  2999. if (num >= 1 && viewCount >= 1) {
  3000. return (num > (viewCount / 2)) ? 'down' : 'up';
  3001. // messageEntry.setAttribute('view-pos', (num > (viewCount / 2)) ? 'down' : 'up');
  3002. } else {
  3003. return null;
  3004. // messageEntry.removeAttribute('view-pos');
  3005. }
  3006. });
  3007.  
  3008. // change on state -> change on DOM
  3009. createEffect(() => {
  3010. const v = viewVisiblePos();
  3011. const messageEntry = kRef(messageEntryWR);
  3012. if (v === null) {
  3013. _removeAttribute.call(messageEntry, 'view-pos');
  3014. } else {
  3015. _setAttribute.call(messageEntry, 'view-pos', v);
  3016. }
  3017. });
  3018.  
  3019. {
  3020. const messageEntry = _messageEntry;
  3021. let mutable = kRef(mutableWR);
  3022. mutable.viewVisiblePos = viewVisiblePos;
  3023. ioMessageList && ioMessageList.observe(messageEntry);
  3024. createdPromise && createdPromise.resolve(messageEntry);
  3025. createdPromise = null;
  3026. }
  3027. rcSignalAdd(1);
  3028.  
  3029. }
  3030. }
  3031. mutableWR = mWeakRef(mutable);
  3032. mutableWM.set(bObj, mutable);
  3033.  
  3034.  
  3035. };
  3036.  
  3037. const SolidMessageElementTags = window.SolidMessageElementTags = new Set();
  3038.  
  3039. let SolidMessageElementTagsSizeCached = 0;
  3040.  
  3041. const SolidMessageListEntry = (props) =>{
  3042.  
  3043. // rcSignalAdd(1);
  3044. rcValue++;
  3045. const tkt = rcKt;
  3046. onMount(async () => {
  3047. if (tkt !== rcKt) return;
  3048. timelineResolve && (await timelineResolve());
  3049. if (tkt !== rcKt) return;
  3050. rcSignalAdd(0);
  3051. });
  3052. onCleanup(() => {
  3053. props = null;
  3054. });
  3055.  
  3056. const data = props.data();
  3057. const aKey = props.aKey();
  3058.  
  3059. setupMutable(data);
  3060.  
  3061. convertAObj && convertAObj(data, aKey);
  3062.  
  3063. switch (aKey) { // performance concern? (1.5ms)
  3064. case 'liveChatViewerEngagementMessageRenderer':
  3065. return SolidSystemMessage(props);
  3066. case 'liveChatPaidMessageRenderer':
  3067. return SolidPaidMessage(props);
  3068. case 'liveChatMembershipItemRenderer':
  3069. return SolidMembershipMessage(props);
  3070. case 'liveChatSponsorshipsGiftRedemptionAnnouncementRenderer':
  3071. return SolidGiftText(props);
  3072. case 'liveChatSponsorshipsGiftPurchaseAnnouncementRenderer':
  3073. return SolidSponsorshipPurchase(props);
  3074. case 'liveChatPaidStickerRenderer':
  3075. /** https://www.youtube.com/watch?v=97_KLlaUICQ&t=3600s */
  3076. /* https://www.youtube.com/live/BDjEOkw_iOA?t=6636s */
  3077. return SolidPaidSticker(props);
  3078. case 'liveChatPlaceholderItemRenderer':
  3079. return SolidMessagePlaceHolder(props);
  3080.  
  3081. case 'liveChatTextMessageRenderer':
  3082. return SolidMessageText(props); // liveChatTextMessageRenderer
  3083.  
  3084. case 'liveChatOfferClickCountMessageRenderer':
  3085. // return SolidOfferClick(props); // just append the native element. might have memory leakage
  3086.  
  3087. default:
  3088.  
  3089. SolidMessageElementTags.add(aKey);
  3090. const size = SolidMessageElementTags.size;
  3091. if (size !== SolidMessageElementTagsSizeCached) {
  3092. SolidMessageElementTagsSizeCached = size;
  3093. if (size > 0 && aKey !== 'liveChatOfferClickCountMessageRenderer') {
  3094. console.warn(`SolidMessageElementTags: ${[...SolidMessageElementTags].join(', ')}`);
  3095. }
  3096. }
  3097. return SolidDefaultElement(props); // just append the native element. might have memory leakage
  3098.  
  3099. }
  3100.  
  3101. }
  3102.  
  3103. const SolidMessageList = (props) => {
  3104. onCleanup(() => {
  3105. console.log('SolidMessageList cleanup 0001')
  3106. });
  3107.  
  3108. return html`
  3109. <${Show} when=(${() => typeof R(profileCard).username === 'string'})>
  3110. <div classList=(${() => ({ "bst-profile-card": true, "bst-profile-card-on-top": R(profileCard).showOnTop })}) style=(${() => ({ "--fTop": R(profileCard).fTop + "px", "--fBottom": R(profileCard).fBottom + "px" })})>
  3111. <div class="bst-profile-card-overlay"></div>
  3112. <div class="bst-profile-card-icon">
  3113. <img class="bst-profile-card-icon-img" src="${() => R(profileCard).iconUrl}">
  3114. </div>
  3115. <div class="bst-profile-card-main">
  3116. <a target="_blank" href="${() => R(profileCard).profileUrl}">${() => R(profileCard).username}</a>
  3117. </div>
  3118. <div class="bst-profile-card-cross" onClick="${profileCard_onCrossClick}">
  3119. X
  3120. </div>
  3121. </div>
  3122. <//>
  3123. <${For} each=(${() => R(sbSignal())})>${(qItem) => {
  3124.  
  3125.  
  3126. let aKeyMemo = createMemo(() => {
  3127. const wKey = qItem ? firstObjectKey(qItem) : '';
  3128. const wItem = wKey ? qItem[wKey] : null;
  3129. let item = wItem ? R(wItem) : null;
  3130. return item.aKey_ = wKey;
  3131. });
  3132. let itemMemo = createMemo(()=>{
  3133. return qItem[aKeyMemo()];
  3134. });
  3135.  
  3136.  
  3137. onCleanup(() => {
  3138. removeEntry(itemMemo())
  3139. qItem = null;
  3140. aKeyMemo = nullMemo;
  3141. itemMemo = nullMemo;
  3142. });
  3143.  
  3144. return html`<${SolidMessageListEntry} data=(${()=>rwWrap(itemMemo())}) aKey=(${()=>aKeyMemo}) />`;
  3145.  
  3146. }}<//>
  3147. `
  3148. };
  3149.  
  3150.  
  3151.  
  3152. const SolidMessageRenderer = (props) => {
  3153.  
  3154. const data = props.entryData;
  3155. const messageXT = R(data).bst('messageXM');
  3156.  
  3157. onCleanup(() => {
  3158. props = null;
  3159. });
  3160.  
  3161. return html`<${For} each=(${() => messageXT()})>${(arr => {
  3162.  
  3163. // console.log(1338, arr)
  3164. const [p1, v1, p2, v2, ...args] = arr;
  3165.  
  3166. // console.log(21392, p1,v1,p2,v2, ...args)
  3167. if (p1 === 'T') {
  3168.  
  3169. if (p2 === 'A' && v2) {
  3170.  
  3171. const text = v1;
  3172. const url = v2;
  3173. const [nofollow, target] = args;
  3174.  
  3175. return html`<a href="${() => url}" rel="${() => nofollow === 'true' ? 'nofollow' : null}" target="${() => target === "TARGET_NEW_WINDOW" ? '_blank' : null}">${() => text}</span>`
  3176.  
  3177. }
  3178.  
  3179. return html`<span>${() => v1}</span>`;
  3180.  
  3181. } else if (p1 === 'E') {
  3182. const emojiId = v1;
  3183.  
  3184. const emoji = messageFlattenIcons.get(emojiId);
  3185. if (emoji) {
  3186.  
  3187. const className = `small-emoji emoji yt-formatted-string style-scope yt-live-chat-text-message-renderer`
  3188.  
  3189. const src = () => `${emoji.image.thumbnails[0].url}` // performance concern? (3.3ms)
  3190. const alt = () => emoji.image?.accessibility?.accessibilityData?.label || ''; // performance concern? (1.7ms)
  3191. let tooltipText = () => emoji.shortcuts?.[0] || ''; // performance concern? (1.7ms)
  3192. const emojiId = () => emoji.emojiId || '';
  3193. const isCustomEmoji = () => emoji.isCustomEmoji || false;
  3194.  
  3195. let [tooltipDisplay, tooltipDisplaySet] = createSignal('');
  3196. let elmWR = null;
  3197. let onImgCreated = (el) => {
  3198. tooltipText = tooltipText();
  3199. tooltipDisplaySet(tooltipText);
  3200. if (el.getAttribute23752) {
  3201. el.getAttribute = el.getAttribute23752;
  3202. }
  3203. elmWR = mWeakRef(el);
  3204. }
  3205. onCleanup(() => {
  3206. tooltipDisplay = nullGet;
  3207. tooltipDisplaySet = nullSet;
  3208. onImgCreated = nullFn;
  3209. });
  3210. return html`<img ref="${onImgCreated}" class="${className}" src="${src}" alt="${alt}" shared-tooltip-text="${tooltipText}" data-emoji-id="${emojiId}" is-custom-emoji="${isCustomEmoji}" /><bst-tooltip>${() => (kRef(tooltipTarget()) || 1) === (kRef(elmWR) || 2) ? tooltipDisplay() : ''}</bst-tooltip>`;
  3211.  
  3212. }
  3213. }
  3214.  
  3215. return '';
  3216.  
  3217. })}
  3218. <//>`
  3219.  
  3220. };
  3221.  
  3222. const SolidSystemMessage = (props) => {
  3223. let data = props.data();
  3224.  
  3225. const { rendererFlag, authorName, messageXT } = MEMO(data);
  3226.  
  3227. const dataMutable = mutableWM.get(data);
  3228. if (!dataMutable) return '';
  3229.  
  3230. let icon = data.icon;
  3231. let onYtIconCreated = null;
  3232. if (icon) {
  3233. const type = icon.iconType.toLowerCase();
  3234. onYtIconCreated = (el) => {
  3235. const cnt = insp(el);
  3236. cnt.icon = type;
  3237. _setAttribute.call(el, 'icon-type', type);
  3238. onYtIconCreated = null;
  3239. }
  3240. }
  3241.  
  3242. onCleanup(() => {
  3243. removeEntry(data)
  3244. props = data = null;
  3245. icon = null;
  3246. });
  3247.  
  3248. return html`
  3249. <div class="bst-message-entry bst-viewer-engagement-message" message-uid="${() => R(data).uid()}" message-id="${() => R(data).id}" ref="${mutableWM.get(data).setupFn}" author-type="${() => R(data).bst('authorType')}">
  3250. <div classList=(${() => ({ 'bst-message-container': true, 'bst-message-container-f': mf() !== R(data).uid() })})>
  3251. <div class="bst-message-entry-highlight"></div>
  3252. <div class="bst-message-entry-line">
  3253. <${Show} when=(${() => typeof onYtIconCreated === 'function'})>
  3254. <div class="bst-system-message-icon-column"><yt-icon class="bst-system-message-yt-icon" ref="${onYtIconCreated}"></yt-icon></div>
  3255. <//>
  3256. <${Show} when=(${() => R(data).beforeContentButtons?.length === 1})>
  3257. <${SolidBeforeContentButton0} entryData=(${()=>data}) />
  3258. <//>
  3259. <div class="bst-message-body">
  3260. <${SolidMessageRenderer} entryData=(${()=>data}) />
  3261. </div>
  3262. </div>
  3263. <div class="bst-message-menu-container">
  3264. <${Show} when=(${() => R(menuRenderObj).messageUid === R(data).uid() && !R(menuRenderObj).loading })>
  3265. <${SolidMenuList} items=(${() => R(menuRenderObj).menuListXd()}) />
  3266. <//>
  3267. </div>
  3268. </div>
  3269. </div>`
  3270.  
  3271. };
  3272.  
  3273. const SolidProfileImg = (props) => {
  3274.  
  3275. let profileUrl = props.profileImgSrc;
  3276. let cleaned = false;
  3277.  
  3278. // either createMemo or createEffect can be used.
  3279. // fasten flushing -> createEffect
  3280. let [mImg, mImgSet] = createSignal(null); // updated in createMemo (pre-caching)
  3281. let [sImg, sImgSet] = createSignal(null); // updated in createEffect (after mounting)
  3282. let f = function () {
  3283. mImgSet(this); // cleanup -> img load finished -> error => nullSet
  3284. }
  3285. createMemo(() => {
  3286. if (cleaned) return;
  3287. const img = document.createElement('IMG');
  3288. img.src = profileUrl();
  3289. if (img.complete) {
  3290. mImgSet(img);
  3291. } else {
  3292. img.addEventListener('load', f);
  3293. }
  3294. });
  3295. createEffect(() => {
  3296. if (cleaned) return;
  3297. const img = mImg();
  3298. if (img) {
  3299. img.classList.add('bst-profile-img');
  3300. sImgSet(img);
  3301. }
  3302. });
  3303. onCleanup(() => {
  3304. cleaned = true;
  3305. profileUrl = nullGet;
  3306. mImg = nullGet;
  3307. mImgSet = nullSet;
  3308. sImg = nullGet;
  3309. sImgSet = nullSet;
  3310. f = nullFn;
  3311. });
  3312. return sImg;
  3313. }
  3314.  
  3315. const SolidPaidMessage = (props) => {
  3316.  
  3317. let data = props.data();
  3318.  
  3319. const { rendererFlag, authorName, messageXT } = MEMO(data);
  3320.  
  3321. // const {authorNameTextColor, bodyBackgroundColor, bodyTextColor, headerBackgroundColor, headerTextColor, textInputBackgroundColor,timestampColor} = data;
  3322.  
  3323. onCleanup(() => {
  3324. removeEntry(data)
  3325. props = data = null;
  3326. });
  3327.  
  3328. const profileUrl = createMemo(() => {
  3329. return R(data).getProfilePic(64, -1)
  3330. });
  3331.  
  3332.  
  3333.  
  3334.  
  3335. return html`
  3336. <div classList=(${() => ({ 'bst-message-entry': true, [`bst-paid-message`]: true, 'bst-message-entry-holding': entryHolding() === R(data).uid() })}) message-uid="${() => R(data).uid()}" message-id="${() => R(data).id}" ref="${mutableWM.get(data).setupFn}" author-type="${() => R(data).bst('authorType')}">
  3337. <div classList=(${() => ({ 'bst-message-container': true, 'bst-message-container-f': mf() !== R(data).uid() })})>
  3338. <span class="bst-message-profile-holder"><a class="bst-message-profile-anchor"><${SolidProfileImg} profileImgSrc=(${() => profileUrl}) /></a></span>
  3339. <div class="bst-message-entry-highlight"></div>
  3340. <div class="bst-message-entry-line">
  3341. <div class="bst-message-head">
  3342. <div class="bst-message-time">${() => R(data).bst('timestampText')}</div>
  3343. <div class="bst-name-field bst-message-name-color">
  3344. <div class="bst-message-username">${() => R(data).bst('getUsername')}</div>
  3345. <div class="bst-message-badges">
  3346. <${For} each=(${() => R(data).bst('authorBadges')})>${(badge) => {
  3347.  
  3348. return formatters.authorBadges(badge, data);
  3349.  
  3350. }}<//>
  3351. </div>
  3352. </div>
  3353. <div class="bst-paid-amount">${() => convertYTtext(R(data).purchaseAmountText)}</div>
  3354. </div>
  3355. <${Show} when=(${() => R(data).beforeContentButtons?.length === 1})>
  3356. <${SolidBeforeContentButton0} entryData=(${()=>data}) />
  3357. <//>
  3358. <div class="bst-message-body bst-message-body-next-to-head">
  3359. <${SolidMessageRenderer} entryData=(${()=>data}) />
  3360. </div>
  3361. </div>
  3362. <div class="bst-message-menu-container">
  3363. <${Show} when=(${() => R(menuRenderObj).messageUid === R(data).uid() && !R(menuRenderObj).loading })>
  3364. <${SolidMenuList} items=(${() => R(menuRenderObj).menuListXd()}) />
  3365. <//>
  3366. </div>
  3367. </div>
  3368. </div>
  3369. `;
  3370. };
  3371.  
  3372. const SolidMembershipMessage = (props) => {
  3373. let data = props.data();
  3374.  
  3375. const { rendererFlag, authorName, messageXT } = MEMO(data);
  3376.  
  3377. onCleanup(() => {
  3378. removeEntry(data)
  3379. props = data = null;
  3380. });
  3381.  
  3382. const profileUrl = createMemo(() => {
  3383. return R(data).getProfilePic(64, -1)
  3384. });
  3385.  
  3386. return html`
  3387. <div classList=(${() => ({ 'bst-message-entry': true, [`bst-message-entry-ll`]: true, [`bst-membership-message`]: true, 'bst-message-entry-holding': entryHolding() === R(data).uid() })}) message-uid="${() => R(data).uid()}" message-id="${() => R(data).id}" ref="${mutableWM.get(data).setupFn}" author-type="${() => R(data).bst('authorType')}">
  3388. <div classList=(${() => ({ 'bst-message-container': true, 'bst-message-container-f': mf() !== R(data).uid() })})>
  3389. <div classList=(${() => ({ "bst-message-entry-header": true, "bst-message-entry-followed-by-body": R(data).bst('hasMessageBody') })})>
  3390. <span class="bst-message-profile-holder"><a class="bst-message-profile-anchor"><${SolidProfileImg} profileImgSrc=(${() => profileUrl}) /></a></span>
  3391. <div class="bst-message-entry-highlight"></div>
  3392. <div class="bst-message-entry-line">
  3393. <div class="bst-message-head">
  3394. <div class="bst-message-time">${() => R(data).bst('timestampText')}</div>
  3395. <div class="bst-name-field bst-message-name-color">
  3396. <div class="bst-message-username">${() => R(data).bst('getUsername')}</div>
  3397. <div class="bst-message-badges">
  3398. <${For} each=(${() => R(data).bst('authorBadges')})>${(badge) => {
  3399.  
  3400. return formatters.authorBadges(badge, data);
  3401.  
  3402. }}<//>
  3403. </div>
  3404. </div>
  3405. </div>
  3406. <div class="bst-message-body bst-message-body-next-to-head">${() => {
  3407. return convertYTtext(R(data).headerPrimaryText || R(data).headerSubtext);
  3408. // new member - only data.headerSubtext
  3409. // return convertYTtext(data.headerSubtext)
  3410. }}</div>
  3411. </div>
  3412. <div class="bst-message-menu-container">
  3413. <${Show} when=(${() => R(menuRenderObj).messageUid === R(data).uid() && !R(menuRenderObj).loading })>
  3414. <${SolidMenuList} items=(${() => R(menuRenderObj).menuListXd()}) />
  3415. <//>
  3416. </div>
  3417. </div>
  3418. <${Show} when=(${() => R(data).bst('hasMessageBody')})>
  3419. <div class="bst-message-entry-body">
  3420. <div class="bst-message-entry-highlight"></div>
  3421. <div class="bst-message-entry-line">
  3422. <div class="bst-message-body">
  3423. <${SolidMessageRenderer} entryData=(${() => data}) />
  3424. </div>
  3425. </div>
  3426. </div>
  3427. <//>
  3428. </div>
  3429. </div>
  3430. `;
  3431. };
  3432.  
  3433.  
  3434.  
  3435. const SolidGiftText = (props) => {
  3436. let data = props.data();
  3437.  
  3438. const { rendererFlag, authorName, messageXT } = MEMO(data);
  3439.  
  3440. onCleanup(() => {
  3441. removeEntry(data)
  3442. props = data = null;
  3443. });
  3444.  
  3445. const profileUrl = createMemo(() => {
  3446. return R(data).getProfilePic(64, -1)
  3447. });
  3448.  
  3449. return html`
  3450. <div classList=(${() => ({ 'bst-message-entry': true, [`bst-gift-message`]: true, 'bst-message-entry-holding': entryHolding() === R(data).uid() })}) message-uid="${() => R(data).uid()}" message-id="${() => R(data).id}" ref="${mutableWM.get(data).setupFn}" author-type="${() => R(data).bst('authorType')}">
  3451. <div classList=(${() => ({ 'bst-message-container': true, 'bst-message-container-f': mf() !== R(data).uid() })})>
  3452. <span class="bst-message-profile-holder"><a class="bst-message-profile-anchor"><${SolidProfileImg} profileImgSrc=(${() => profileUrl}) /></a></span>
  3453. <div class="bst-message-entry-highlight"></div>
  3454. <div class="bst-message-entry-line">
  3455. <div class="bst-message-head">
  3456. <div class="bst-message-time">${() => R(data).bst('timestampText')}</div>
  3457. <div class="bst-name-field bst-message-name-color">
  3458. <div class="bst-message-username">${() => R(data).bst('getUsername')}</div>
  3459. <div class="bst-message-badges">
  3460. <${For} each=(${() => R(data).bst('authorBadges')})>${(badge) => {
  3461.  
  3462. return formatters.authorBadges(badge, data);
  3463.  
  3464. }}<//>
  3465. </div>
  3466. </div>
  3467. </div>
  3468. <${Show} when=(${() => R(data).beforeContentButtons?.length === 1})>
  3469. <${SolidBeforeContentButton0} entryData=(${() => data}) />
  3470. <//>
  3471. <div class="bst-message-body bst-message-body-next-to-head">
  3472. <${SolidMessageRenderer} entryData=(${() => data}) />
  3473. </div>
  3474. </div>
  3475. <div class="bst-message-menu-container">
  3476. <${Show} when=(${() => R(menuRenderObj).messageUid === R(data).uid() && !R(menuRenderObj).loading })>
  3477. <${SolidMenuList} items=(${() => R(menuRenderObj).menuListXd()}) />
  3478. <//>
  3479. </div>
  3480. </div>
  3481. </div>
  3482. `;
  3483. };
  3484.  
  3485.  
  3486.  
  3487.  
  3488. const SolidSponsorshipPurchase = (props) => {
  3489.  
  3490. let data = props.data();
  3491.  
  3492. const { rendererFlag, authorName, messageXT } = MEMO(data);
  3493.  
  3494.  
  3495. onCleanup(() => {
  3496. removeEntry(data)
  3497. props = data = null;
  3498. });
  3499.  
  3500. // const {authorNameTextColor, bodyBackgroundColor, bodyTextColor, headerBackgroundColor, headerTextColor, textInputBackgroundColor,timestampColor} = data;
  3501.  
  3502.  
  3503. const profileUrl = createMemo(() => {
  3504. return R(data).getProfilePic(64, -1)
  3505. });
  3506.  
  3507. return html`
  3508. <div classList=(${() => ({ 'bst-message-entry': true, [`bst-sponsorship-purchase`]: true, 'bst-message-entry-holding': entryHolding() === R(data).uid() })}) message-uid="${() => R(data).uid()}" message-id="${() => R(data).id}" ref="${mutableWM.get(data).setupFn}" author-type="${() => R(data).bst('authorType')}">
  3509. <div classList=(${() => ({ 'bst-message-container': true, 'bst-message-container-f': mf() !== R(data).uid() })})>
  3510. <span class="bst-message-profile-holder"><a class="bst-message-profile-anchor"><${SolidProfileImg} profileImgSrc=(${() => profileUrl}) /></a></span>
  3511. <div class="bst-message-entry-highlight"></div>
  3512. <div class="bst-message-entry-line">
  3513. <div class="bst-message-head">
  3514. <div class="bst-message-time">${() => R(data).bst('timestampText')}</div>
  3515. <div class="bst-name-field bst-message-name-color">
  3516. <div class="bst-message-username">${() => R(data).bst('getUsername')}</div>
  3517. <div class="bst-message-badges">
  3518. <${For} each=(${() => R(data).bst('authorBadges')})>${(badge) => {
  3519.  
  3520. return formatters.authorBadges(badge, data);
  3521.  
  3522. }}<//>
  3523. </div>
  3524. </div>
  3525. </div>
  3526. <${Show} when=(${() => R(data).beforeContentButtons?.length === 1})>
  3527. <${SolidBeforeContentButton0} entryData=(${() => data}) />
  3528. <//>
  3529. <div class="bst-message-body bst-message-body-next-to-head">
  3530. <${SolidMessageRenderer} entryData=(${() => data}) />
  3531. </div>
  3532. </div>
  3533. <div class="bst-message-menu-container">
  3534. <${Show} when=(${() => R(menuRenderObj).messageUid === R(data).uid() && !R(menuRenderObj).loading })>
  3535. <${SolidMenuList} items=(${() => R(menuRenderObj).menuListXd()}) />
  3536. <//>
  3537. </div>
  3538. </div>
  3539. </div>
  3540. `;
  3541. };
  3542.  
  3543. const SolidPaidSticker = (props) => {
  3544. /* https://www.youtube.com/live/BDjEOkw_iOA?si=CGG7boBJvfT2KLFT&t=6636 */
  3545.  
  3546. let data = props.data();
  3547.  
  3548. onCleanup(() => {
  3549. removeEntry(data)
  3550. props = data = null;
  3551. });
  3552.  
  3553.  
  3554. const profileUrl = createMemo(() => {
  3555. return R(data).getProfilePic(64, -1)
  3556. });
  3557.  
  3558. return html`
  3559. <div classList=(${() => ({ 'bst-message-entry': true, [`bst-paid-sticker`]: true, 'bst-message-entry-holding': entryHolding() === R(data).uid() })}) message-uid="${() => R(data).uid()}" message-id="${() => R(data).id}" ref="${mutableWM.get(data).setupFn}" author-type="${() => R(data).bst('authorType')}">
  3560. <div classList=(${() => ({ 'bst-message-container': true, 'bst-message-container-f': mf() !== R(data).uid() })})>
  3561. <span class="bst-message-profile-holder"><a class="bst-message-profile-anchor"><${SolidProfileImg} profileImgSrc=(${() => profileUrl}) /></a></span>
  3562. <div class="bst-message-entry-highlight" style="${() => ({ '--bst-paid-sticker-bg': `url(${R(data).getStickerURL(80, 256)})` })}"></div>
  3563. <div class="bst-message-entry-line">
  3564. <div class="bst-message-head">
  3565. <div class="bst-message-time">${() => R(data).bst('timestampText')}</div>
  3566. <div class="bst-name-field bst-message-name-color">
  3567. <div class="bst-message-username">${() => R(data).bst('getUsername')}</div>
  3568. <div class="bst-message-badges">
  3569. <${For} each=(${() => R(data).bst('authorBadges')})>${(badge) => {
  3570.  
  3571. return formatters.authorBadges(badge, data);
  3572.  
  3573. }}<//>
  3574. </div>
  3575. </div>
  3576. <div class="bst-paid-amount">${() => convertYTtext(R(data).purchaseAmountText)}</div>
  3577. </div>
  3578. <${Show} when=(${() => R(data).beforeContentButtons?.length === 1})>
  3579. <${SolidBeforeContentButton0} entryData=(${()=>data}) />
  3580. <//>
  3581. <div class="bst-message-body bst-message-body-next-to-head">
  3582. <${SolidMessageRenderer} entryData=(${()=>data}) />
  3583. </div>
  3584. </div>
  3585. <div class="bst-message-menu-container">
  3586. <${Show} when=(${() => R(menuRenderObj).messageUid === R(data).uid() && !R(menuRenderObj).loading })>
  3587. <${SolidMenuList} items=(${() => R(menuRenderObj).menuListXd()}) />
  3588. <//>
  3589. </div>
  3590. </div>
  3591. </div>
  3592. `;
  3593. }
  3594.  
  3595.  
  3596.  
  3597. const SolidMessageText = (props) => {
  3598.  
  3599.  
  3600. let data = props.data();
  3601.  
  3602. const { rendererFlag, authorName, messageXT } = MEMO(data);
  3603.  
  3604.  
  3605. onCleanup(() => {
  3606. removeEntry(data)
  3607. props = data = null;
  3608. });
  3609. const profileUrl = createMemo(() => {
  3610. return R(data).getProfilePic(64, -1)
  3611. });
  3612.  
  3613.  
  3614. return html`
  3615. <div classList=(${() => ({ 'bst-message-entry': true, [`bst-${R(data).aKey}`]: true, 'bst-message-entry-holding': entryHolding() === R(data).uid() })}) message-uid="${() => R(data).uid()}" message-id="${() => R(data).id}" ref="${mutableWM.get(data).setupFn}" author-type="${() => R(data).bst('authorType')}">
  3616. <div classList=(${() => ({ 'bst-message-container': true, 'bst-message-container-f': mf() !== R(data).uid() })})>
  3617. <span class="bst-message-profile-holder"><a class="bst-message-profile-anchor"><${SolidProfileImg} profileImgSrc=(${() => profileUrl}) /></a></span>
  3618. <div class="bst-message-entry-highlight"></div>
  3619. <div class="bst-message-entry-line">
  3620. <div class="bst-message-head">
  3621. <div class="bst-message-time">${() => R(data).bst('timestampText')}</div>
  3622. <div class="bst-name-field bst-message-name-color">
  3623. <div class="bst-name-field-box">
  3624. <div>Icon</div>
  3625. <div>Name</div>
  3626. </div>
  3627. <div class="bst-message-username">${() => R(data).bst('getUsername')}</div>
  3628. <div class="bst-message-badges">
  3629. <${For} each=(${() => R(data).bst('authorBadges')})>${(badge) => {
  3630.  
  3631. return formatters.authorBadges(badge, data);
  3632.  
  3633. }}<//>
  3634. </div>
  3635. </div>
  3636. <span class="bst-message-head-colon" aria-hidden="true"></span>
  3637. </div>
  3638. <${Show} when=(${() => R(data).beforeContentButtons?.length === 1})>
  3639. <${SolidBeforeContentButton0} entryData=(${() => data}) />
  3640. <//>
  3641. <div class="bst-message-body bst-message-body-next-to-head">
  3642. <${SolidMessageRenderer} entryData=(${() => data}) />
  3643. </div>
  3644. </div>
  3645. <div class="bst-message-menu-container">
  3646. <${Show} when=(${() => R(menuRenderObj).messageUid === R(data).uid() && !R(menuRenderObj).loading })>
  3647. <${SolidMenuList} items=(${() => R(menuRenderObj).menuListXd()}) />
  3648. <//>
  3649. </div>
  3650. </div>
  3651. </div>
  3652. `;
  3653. };
  3654.  
  3655. const SolidMessagePlaceHolder = (props) => {
  3656.  
  3657. let data = props.data();
  3658.  
  3659. const { rendererFlag, authorName, messageXT } = MEMO(data);
  3660.  
  3661. onCleanup(() => {
  3662. removeEntry(data)
  3663. props = data = null;
  3664. });
  3665.  
  3666. return html`<bst-live-chat-placeholder ref="${mutableWM.get(data).setupFn}"></bst-live-chat-placeholder>`;
  3667.  
  3668. };
  3669.  
  3670. const SolidOfferClick = (props)=>{
  3671.  
  3672.  
  3673. let data = props.data();
  3674. const setupFn_ = (elm)=>{
  3675.  
  3676.  
  3677. const mElm = document.createElement('yt-live-chat-offer-click-count-message-renderer')
  3678. sharedNoscript.appendChild(mElm);
  3679. mElm.data = data;
  3680.  
  3681. mElm.classList.add('bst-live-chat-element');
  3682.  
  3683. elm.appendChild(mElm);
  3684.  
  3685. return mutableWM.get(data).setupFn(elm);
  3686.  
  3687.  
  3688. }
  3689.  
  3690. /*
  3691. // https://www.youtube.com/watch?v=TeLstIBwC6M
  3692.  
  3693. {
  3694. "id": "ChwKGkNPaW5fUHpUZzRrREZlb0oxZ0FkOGZ3SG5n",
  3695. "timestampUsec": "1728557900305443",
  3696. "messageTitle": {
  3697. "runs": [
  3698. {
  3699. "text": "Popular · 50 product views"
  3700. }
  3701. ]
  3702. },
  3703. "productTitle": "hololive closet 姫森ルーナ ワンピース衣装 グッズ / 【旧価格】姫森ルーナ ワンピース衣装",
  3704. "ctaTitle": "View details",
  3705. "onClickCommand": {
  3706. "clickTrackingParams": "CEZQvHwLGEbQwHjMoJcY9ayKAyXC31wCHe8FQF5=",
  3707. "commandExecutorCommand": {
  3708. "commands": [
  3709. {
  3710. "clickTrackingParams": "CEZQvHwLGEbQwHjMoJcY9ayKAyXC31wCHe8FQF5=",
  3711. "commandMetadata": {
  3712. "webCommandMetadata": {
  3713. "sendPost": true,
  3714. "apiUrl": "/youtubei/v1/feedback"
  3715. }
  3716. },
  3717. "feedbackEndpoint": {
  3718. "feedbackToken": "AB4yrpHVTUG7-rpeiRCAr9ZWG5BYET3y"
  3719. }
  3720. },
  3721. {
  3722. "clickTrackingParams": "CEZQvHwLGEbQwHjMoJcY9ayKAyXC31wCHe8FQF5=",
  3723. "commandMetadata": {
  3724. "webCommandMetadata": {
  3725. "url": "https://shop.hololivepro.com/products/hololivecloset_himemoriluna_1?variant=44046847443164&country=JP&currency=JPY&utm_campaign=sag_organic&srsltid=AfmBOLW3QuMFovsS&utm_term=UCa9YHRVrnw&utm_medium=product_shelf&utm_source=youtube",
  3726. "webPageType": "WEB_PAGE_TYPE_UNKNOWN",
  3727. "rootVe": 83769
  3728. }
  3729. },
  3730. "urlEndpoint": {
  3731. "url": "https://shop.hololivepro.com/products/hololivecloset_himemoriluna_1?variant=44046847443164&country=JP&currency=JPY&utm_campaign=sag_organic&srsltid=Afm8wkUDmFuA4&utm_content=YT3-0jm-H1Z2sZRVrnw&utm_medium=product_shelf&utm_source=youtube",
  3732. "target": "TARGET_NEW_WINDOW"
  3733. }
  3734. }
  3735. ]
  3736. }
  3737. },
  3738. "trackingParams": "CEZQvHwLGEbQwHjMoJcY9ayKAyXC31wCHe8FQF5=",
  3739. "__clientId__": "COin_PzWg5kDFeoJ2gAd9fwSmg",
  3740. "uid": "undefined:1728557900305443",
  3741. "aKey": "liveChatOfferClickCountMessageRenderer",
  3742. "rendererFlag": 0,
  3743. "messageFixed": []
  3744. }
  3745. */
  3746.  
  3747.  
  3748. return html`<bst-live-chat-elementholder ref="${setupFn_}"></bst-live-chat-elementholder>`;
  3749.  
  3750. };
  3751.  
  3752. /*
  3753.  
  3754.  
  3755. // yt-live-chat-mode-change-message-renderer
  3756. // https://www.youtube.com/watch?v=jVvqOgUqBjY
  3757.  
  3758. {
  3759. "id": "ChwJHgMWEss0OPd6QXlvREYeFG2H9VeKKMMEGeC",
  3760. "timestampUsec": "1737004399054300",
  3761. "icon": {
  3762. "iconType": "TAB_SUBSCRIPTIONS"
  3763. },
  3764. "text": {
  3765. "runs": [
  3766. {
  3767. "text": "御神楽すずめ / Mikagura Suzume",
  3768. "bold": true
  3769. },
  3770. {
  3771. "text": " さんは、チャンネル登録者のみモードをオンにしました",
  3772. "bold": true
  3773. }
  3774. ]
  3775. },
  3776. "subtext": {
  3777. "runs": [
  3778. {
  3779. "text": "チャンネル登録者のみがメッセージを送信できます",
  3780. "italics": true
  3781. }
  3782. ]
  3783. },
  3784. "__timestampActionRequest__": 1737020610950,
  3785. "aKey_": "liveChatModeChangeMessageRenderer",
  3786. "aKey": "liveChatModeChangeMessageRenderer"
  3787. }
  3788.  
  3789. */
  3790.  
  3791. /*
  3792.  
  3793. // yt-live-chat-mode-change-message-renderer
  3794. // https://www.youtube.com/watch?v=jVvqOgUqBjY
  3795.  
  3796.  
  3797. {
  3798. "id": "ChwJHgMWEss0OPd6QXlvREYeFG2H9VeKKMMEGeC",
  3799. "timestampUsec": "1737004399053988",
  3800. "icon": {
  3801. "iconType": "SLOW_MODE"
  3802. },
  3803. "text": {
  3804. "runs": [
  3805. {
  3806. "text": "低速モードが有効です",
  3807. "bold": true
  3808. }
  3809. ]
  3810. },
  3811. "subtext": {
  3812. "runs": [
  3813. {
  3814. "text": "5 秒",
  3815. "italics": true
  3816. },
  3817. {
  3818. "text": "ごとにメッセージを送信します",
  3819. "italics": true
  3820. }
  3821. ]
  3822. },
  3823. "__timestampActionRequest__": 1737020610950,
  3824. "aKey_": "liveChatModeChangeMessageRenderer",
  3825. "aKey": "liveChatModeChangeMessageRenderer"
  3826. }
  3827.  
  3828. */
  3829.  
  3830.  
  3831. const mapToElementTag = new Map(Object.entries({
  3832. liveChatAutoModMessageRenderer: "yt-live-chat-auto-mod-message-renderer",
  3833. liveChatPaidMessageRenderer: "yt-live-chat-paid-message-renderer",
  3834. liveChatLegacyPaidMessageRenderer: "yt-live-chat-legacy-paid-message-renderer",
  3835. liveChatMembershipItemRenderer: "yt-live-chat-membership-item-renderer",
  3836. liveChatTextMessageRenderer: "yt-live-chat-text-message-renderer",
  3837. liveChatPaidStickerRenderer: "yt-live-chat-paid-sticker-renderer",
  3838. liveChatDonationAnnouncementRenderer: "yt-live-chat-donation-announcement-renderer",
  3839. liveChatModeChangeMessageRenderer: "yt-live-chat-mode-change-message-renderer",
  3840. liveChatModerationMessageRenderer: "yt-live-chat-moderation-message-renderer",
  3841. liveChatOfferClickCountMessageRenderer: "yt-live-chat-offer-click-count-message-renderer",
  3842. liveChatPlaceholderItemRenderer: "yt-live-chat-placeholder-item-renderer",
  3843. liveChatPurchasedProductMessageRenderer: "ytd-live-chat-purchased-product-message-renderer",
  3844. liveChatSponsorshipsGiftPurchaseAnnouncementRenderer: "ytd-sponsorships-live-chat-gift-purchase-announcement-renderer",
  3845. liveChatSponsorshipsGiftRedemptionAnnouncementRenderer: "ytd-sponsorships-live-chat-gift-redemption-announcement-renderer",
  3846. liveChatViewerEngagementMessageRenderer: "yt-live-chat-viewer-engagement-message-renderer",
  3847. serverErrorMessage: "yt-live-chat-server-error-message"
  3848. }));
  3849. // mapToElementTag.set('liveChatOfferClickCountMessageRenderer' ,'yt-live-chat-offer-click-count-message-renderer');
  3850.  
  3851.  
  3852. const SolidDefaultElement = (props) => {
  3853.  
  3854. let data = props.data();
  3855. const aKey = data.aKey;
  3856. let elementTag = '';
  3857.  
  3858. if (aKey) {
  3859. elementTag = mapToElementTag.get(aKey);
  3860. if (!elementTag) {
  3861. const lcrCnt = getLcRendererCnt();
  3862. if (lcrCnt) {
  3863. const mapping = lcrCnt.configureRendererStamper()?.visibleItems?.mapping;
  3864. if (mapping && typeof mapping === 'object') {
  3865. elementTag = mapping[aKey];
  3866. elementTag = (elementTag && elementTag.component) || elementTag;
  3867. if (typeof (elementTag || 0) !== 'string') elementTag = '';
  3868. }
  3869. }
  3870. mapToElementTag.set(aKey, (elementTag || ''));
  3871. }
  3872. }
  3873.  
  3874. const setupFn_ = (elm) => {
  3875. if (elementTag) {
  3876. const mElm = document.createElement(elementTag)
  3877. sharedNoscript.appendChild(mElm);
  3878. mElm.data = data;
  3879. mElm.classList.add('bst-live-chat-element');
  3880. elm.appendChild(mElm);
  3881. } else {
  3882. const mElm = document.createElement('bst-live-chat-unknownitem')
  3883. mElm.classList.add('bst-live-chat-element');
  3884. mElm.setAttribute('title', 'unknown');
  3885. elm.appendChild(mElm);
  3886. }
  3887. const r = mutableWM.get(data).setupFn(elm);
  3888. data = null;
  3889. elm = null;
  3890. elementTag = '';
  3891. props = null;
  3892. return r;
  3893. };
  3894.  
  3895. return html`<bst-live-chat-elementholder ref="${setupFn_}"></bst-live-chat-elementholder>`;
  3896.  
  3897. };
  3898.  
  3899.  
  3900. /**
  3901. *
  3902. * test links
  3903. *
  3904. *
  3905. * moderator
  3906. * https://www.youtube.com/watch?v=1-D4z79ZUV4
  3907. *
  3908. *
  3909. * owner (long text)
  3910. * https://www.youtube.com/watch?v=A930eAQYQog&t=1h32m50s
  3911. *
  3912. */
  3913.  
  3914.  
  3915. function convertYTtext(val) {
  3916.  
  3917. if (typeof (val || 0) !== 'object') return null;
  3918. if (val.simpleText) return val.simpleText
  3919.  
  3920. const runs = val.runs;
  3921. if (runs && runs.length === 1) {
  3922. let r = runs[0];
  3923. return typeof r === 'string' ? r : typeof (r || 0).text === 'string' ? r.text : null;
  3924. } else if (runs && runs.length >= 0) {
  3925. return runs.map(r => (typeof r === 'string' ? r : typeof (r || 0).text === 'string' ? r.text : null)).join('');
  3926. }
  3927. return null;
  3928. }
  3929.  
  3930. const fixMessagesForEmoji = (() => {
  3931.  
  3932. let Vkb = 0
  3933. , Wkb = /tone[1-5]/
  3934. , Xkb = " \uD83C\uDFFB \uD83C\uDFFC \uD83C\uDFFD \uD83C\uDFFE \uD83C\uDFFF".split(" ")
  3935. , Ykb = "UCzC5CNksIBaiT-NdMJjJNOQ/COLRg9qOwdQCFce-qgodrbsLaA UCzC5CNksIBaiT-NdMJjJNOQ/CMKC7uKOwdQCFce-qgodqbsLaA UCzC5CNksIBaiT-NdMJjJNOQ/CJiQ8uiOwdQCFcx9qgodysAOHg UCzC5CNksIBaiT-NdMJjJNOQ/CI3h3uDJitgCFdARTgodejsFWg UCzC5CNksIBaiT-NdMJjJNOQ/CI69oYTKitgCFdaPTgodsHsP5g UCzC5CNksIBaiT-NdMJjJNOQ/CKzQr47KitgCFdCITgodq6EJZg UCzC5CNksIBaiT-NdMJjJNOQ/CPGD8Iu8kN4CFREChAod9OkLmg".split(" ")
  3936. , Zkb = Number.MAX_SAFE_INTEGER
  3937. , $kb = RegExp("\uFE0F", "g")
  3938.  
  3939. let dQ = function (a, b, c) {
  3940. return (a = a.emojiMap[b]) && (!a.isLocked || void 0 !== c && c) ? a : void 0
  3941. }
  3942.  
  3943. let gQ = function (a, b) {
  3944. a = a.emojiShortcutMap[b.toLocaleLowerCase()];
  3945. return !a || a.isLocked ? null : a
  3946. }
  3947.  
  3948. function resultAddText(r, text) {
  3949. if (typeof text === 'string' && text.length >= 1) {
  3950. r.push({ text: text });
  3951. }
  3952. }
  3953. function resultAddEmoji(r, emoji) {
  3954. if (emoji && typeof emoji === 'object') {
  3955. r.push({ emoji: emoji });
  3956. }
  3957. }
  3958.  
  3959. /*
  3960.  
  3961. cQ.prototype.createDocumentFragment = function(a, b, c, d) {
  3962. b = void 0 === b ? !1 : b;
  3963. c = void 0 === c ? !0 : c;
  3964. d = void 0 === d ? !1 : d;
  3965. a = a.replace($kb, "");
  3966. for (var e = document.createDocumentFragment(), g = 0, k, m = 0; null != (k = this.emojiRegex.exec(a)); ) {
  3967. var p = dQ(this, k[0]) || gQ(this, k[0]);
  3968. !p || p.isCustomEmoji && !b || (p = this.createEmoji(p, c),
  3969. g !== k.index && e.appendChild(document.createTextNode(a.substring(g, k.index))),
  3970. e.appendChild(p),
  3971. g = k.index + k[0].length,
  3972. m++)
  3973. }
  3974. if (!d || m)
  3975. return e.appendChild(document.createTextNode(a.substr(g))),
  3976. e
  3977. }
  3978.  
  3979. */
  3980.  
  3981. /*
  3982.  
  3983. cQ.prototype.createEmoji = function(a, b) {
  3984. b = void 0 === b ? !0 : b;
  3985. var c = document.createElement("img");
  3986. a.isCustomEmoji && !x("render_custom_emojis_as_small_images") || c.classList.add("small-emoji");
  3987. c.classList.add("emoji");
  3988. c.classList.add("yt-formatted-string");
  3989. c.src = a.image ? $C(a.image.thumbnails, this.emojiSize) || "" : "";
  3990. var d = void 0;
  3991. a.image && a.image.accessibility && a.image.accessibility.accessibilityData && (d = a.image.accessibility.accessibilityData.label);
  3992. c.alt = d ? d : (a.isCustomEmoji && a.shortcuts ? a.shortcuts[0] : a.emojiId) || "";
  3993. a.isCustomEmoji && (c.dataset.emojiId = a.emojiId);
  3994. ce && (c.setAttribute("contenteditable", "false"),
  3995. c.setAttribute("unselectable", "on"));
  3996. b && (a.shortcuts && a.shortcuts.length && c.setAttribute("shared-tooltip-text", a.shortcuts[0]),
  3997. c.id = "emoji-" + Vkb++);
  3998. return c
  3999. }
  4000. */
  4001. function fixMessagesForEmoji(a, b, c, d) {
  4002. b = void 0 === b ? !1 : b; // false
  4003. c = void 0 === c ? !0 : c; // true
  4004. d = void 0 === d ? !1 : d; // false
  4005. a = a.replace($kb, "");
  4006. // let e = document.createDocumentFragment();
  4007. const r = [];
  4008. let g = 0;
  4009. let k;
  4010. let m = 0;
  4011. for (; null != (k = this.emojiRegex.exec(a));) {
  4012. var p = dQ(this, k[0]) || gQ(this, k[0]);
  4013. !p || p.isCustomEmoji && !b || (p = p,
  4014. g !== k.index && resultAddText(r, a.substring(g, k.index)),
  4015. resultAddEmoji(r, p),
  4016. g = k.index + k[0].length,
  4017. m++)
  4018. }
  4019. // if (!d || m) return e.appendChild(document.createTextNode(a.substr(g))), e;
  4020. return resultAddText(r, a.substr(g)), r;
  4021. }
  4022. return fixMessagesForEmoji;
  4023.  
  4024. })();
  4025.  
  4026.  
  4027. // class StoreType {
  4028.  
  4029. // }
  4030.  
  4031. // const storeTypeFn = ()=>{
  4032. // let p = {};
  4033. // let q = '';
  4034. // return function(x){
  4035. // if(typeof x === 'object'){
  4036. // let id = q = `${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}|${Date.now()}`;
  4037. // p = {[id]: x};
  4038. // return true;
  4039. // }
  4040. // return p[`${x || q}`] || null;
  4041. // }
  4042. // }
  4043.  
  4044. const storeTypeFn = (key) => {
  4045. let obj = {};
  4046. let ud = false;
  4047. const resFn = function () {
  4048. return obj[this[key]];
  4049. };
  4050. resFn.update = (nv) => {
  4051. ud = !ud;
  4052. const id = `${ud}`;
  4053. obj = { [id]: nv };
  4054. return id;
  4055. }
  4056. return resFn;
  4057.  
  4058. }
  4059.  
  4060. const menuRenderObj = {
  4061.  
  4062. menuListXp: '',
  4063. messageUid: '',
  4064. loading: false,
  4065. error: 0,
  4066. menuListXd: storeTypeFn('menuListXp')
  4067.  
  4068. };
  4069.  
  4070.  
  4071. const profileCard = {
  4072. wElement: null,
  4073. top: -1,
  4074. showOnTop: null,
  4075. iconUrl: null,
  4076. username: null,
  4077. profileUrl: null
  4078. };
  4079.  
  4080. const profileCard_onCrossClick = (e) => {
  4081. !e?.button && Object.assign(W(profileCard), {
  4082. wElement: null,
  4083. top: -1,
  4084. showOnTop: null,
  4085. iconUrl: null,
  4086. username: null,
  4087. profileUrl: null,
  4088. });
  4089. };
  4090.  
  4091. const solidContextMenuOpened = createMemo(() => {
  4092. const e1 = !!R(menuRenderObj).menuListXd();
  4093. const e2 = !!R(menuRenderObj).messageUid;
  4094. const e3 = R(profileCard).wElement;
  4095. return (e1 && e2) || kRef(e3);
  4096. });
  4097.  
  4098. const [atBottom0, atBottom0Set] = createSignal(true);
  4099. const [atBottom1, atBottom1Set] = createSignal(true);
  4100. const [bottomPauseAt, bottomPauseAtSet] = createSignal(0); // solely by the atBottom change
  4101. const [bottomKeepAt, bottomKeepAtSet] = createSignal(0);
  4102. createEffect(() => {
  4103. atBottom1Set(atBottom0() ? true : false);
  4104. });
  4105.  
  4106. let lcRendererWR = null;
  4107.  
  4108. const getLcRendererCnt = () => {
  4109.  
  4110. lcRendererWR = lcRendererWR || mWeakRef(document.querySelector('yt-live-chat-item-list-renderer'));
  4111. const lcrElement = kRef(lcRendererWR);
  4112. if (!lcrElement) lcRendererWR = null;
  4113. const lcrCnt = insp(lcrElement);
  4114. return lcrCnt;
  4115.  
  4116. }
  4117.  
  4118. const onContextMenuOpened_ = () => {
  4119.  
  4120. const lcrCnt = getLcRendererCnt();
  4121. if (!lcrCnt) return;
  4122.  
  4123. if (typeof lcrCnt.onContextMenuOpened_ === 'function' && lcrCnt.onContextMenuOpened_.length === 0) {
  4124. lcrCnt.onContextMenuOpened_();
  4125. } else {
  4126. lcrCnt.contextMenuOpen = !0;
  4127. }
  4128.  
  4129.  
  4130. }
  4131.  
  4132.  
  4133. const onContextMenuClosed_ = () => {
  4134. const lcrCnt = getLcRendererCnt();
  4135.  
  4136. if (!lcrCnt) return;
  4137.  
  4138. if (typeof lcrCnt.onContextMenuClosed_ === 'function' && lcrCnt.onContextMenuClosed_.length === 0) {
  4139. lcrCnt.onContextMenuClosed_();
  4140. } else {
  4141. lcrCnt.contextMenuOpen = !1;
  4142. }
  4143.  
  4144.  
  4145. }
  4146.  
  4147.  
  4148.  
  4149. createEffect(() => {
  4150. const p = solidContextMenuOpened();
  4151. if (p) {
  4152. onContextMenuOpened_();
  4153. } else if (!p) {
  4154. onContextMenuClosed_();
  4155. }
  4156.  
  4157. })
  4158.  
  4159. const [entryHolding, entryHoldingChange] = createSignal("");
  4160. const [mf, mfChange] = createSignal("");
  4161. const [tooltipTarget, tooltipTargetChange] = createSignal(null);
  4162. // let mouseActionP = null;
  4163. // let noFlushTP = false;
  4164.  
  4165. const delayPn = delay => new Promise((fn => setTimeout(fn, delay)));
  4166.  
  4167. const getElementText = function (el) {
  4168. let text = '';
  4169. const tagName = el.nodeType === 1 ? el.nodeName.toLocaleLowerCase() : '';
  4170. switch (tagName) {
  4171. case '':
  4172. // Text node (3) or CDATA node (4) - return its text
  4173. if ((el.nodeType === 3) || (el.nodeType === 4)) text = el.nodeValue;
  4174. break;
  4175. case 'tp-yt-paper-tooltip':
  4176. case 'bst-tooltip':
  4177. case 'script':
  4178. case 'style':
  4179. case 'meta':
  4180. case 'noscript':
  4181. case 'link':
  4182. case 'audio':
  4183. case 'video':
  4184. case 'object':
  4185. break;
  4186. case 'img':
  4187. // If node is an element (1) and an img, input[type=image], or area element, return its alt text
  4188. text = el.getAttribute('shared-tooltip-text', 1) || el.getAttribute('alt') || '';
  4189. break;
  4190. case 'area':
  4191. // If node is an element (1) and an img, input[type=image], or area element, return its alt text
  4192. text = el.getAttribute('alt') || '';
  4193. break;
  4194. case 'input':
  4195. // If node is an element (1) and an img, input[type=image], or area element, return its alt text
  4196. if (
  4197. (el.getAttribute('type') && el.getAttribute('type').toLowerCase() == 'image')
  4198. ) {
  4199. text = el.getAttribute('alt') || '';
  4200. break;
  4201. }
  4202. default:
  4203. // Traverse children unless this is a script or style element
  4204. if ((el.nodeType === 1)) {
  4205. let node = el.__shady_native_firstChild || el.firstChild;
  4206. for (; node; node = node.__shady_native_nextSibling || node.nextSibling) {
  4207. text += getElementText(node);
  4208. }
  4209. }
  4210. }
  4211. return text;
  4212. };
  4213.  
  4214. const solidBuildAt = (sb, x)=>{
  4215.  
  4216. const qItem = sb[x];
  4217. const wKey = qItem ? firstObjectKey(qItem) : null;
  4218. const wItem = wKey ? qItem[wKey] : null;
  4219. const item = wItem;
  4220.  
  4221. return item;
  4222. }
  4223.  
  4224. const [sbSignal, sbSignalSet] = createSignal(null);
  4225.  
  4226. whenCEDefined('yt-live-chat-item-list-renderer').then(() => {
  4227. let dummy;
  4228. let cProto;
  4229. dummy = document.createElement('yt-live-chat-item-list-renderer');
  4230. if (!(dummy instanceof Element)) return;
  4231. cProto = insp(dummy).constructor.prototype;
  4232. cProto.connectedCallback882 = cProto.connectedCallback;
  4233.  
  4234. // share same objects
  4235.  
  4236. /** @type {HTMLElement} */
  4237. let wliveChatTextMessageRenderer = null;
  4238. /** @type {HTMLElement} */
  4239. let wliveChatTextInputRenderer = null;
  4240.  
  4241. // ....
  4242.  
  4243. /** @type {HTMLElement} */
  4244. let messageList;
  4245. /** @type {HTMLElement} */
  4246. let _messageOverflowAnchor = null;
  4247. /** @type {HTMLElement} */
  4248. let _bstMain = null;
  4249. const wAttachRoot = new WeakMap();
  4250. let _flushed = 0; // 0 no flushed; 1 flushed; 2 flushing
  4251. // let bstMainScrollCount = 0;
  4252.  
  4253. let pointerHoldingAt = 0; // DateTiem for the pointer holding
  4254. let pointerReleasedAt = 0; // DateTime for the pointer release
  4255. let pointerReleasedWithSelection = false; // checked result of the selection existence
  4256. let pointerReleaseNotReady = false; // avoid canScrollToBottom_ when the selection is checking
  4257. let flushPEHoldingUntil = 0; // limit the flushPE holding time (avoid conflict with user action)
  4258. let flushPEHoldingMaxTimelineResolve = 0; // limit the number of `await timelineResolve()`
  4259.  
  4260. const ioMessageListCallback = (entries) => { // performance concern? (6.1ms)
  4261. for (const entry of entries) { // performance concern? (1.1ms)
  4262. const target = entry?.target;
  4263. const mutable = target ? mutableWM.get(target) : null;
  4264. const interceptionRatioChange = mutable?.interceptionRatioChange || 0;
  4265. if (typeof interceptionRatioChange === 'function') {
  4266. if (entry.rootBounds && (entry.rootBounds.height > 1 && entry.rootBounds.width > 1)) { // performance concern? (2.2ms)
  4267.  
  4268. interceptionRatioChange(entry.intersectionRatio);
  4269. }
  4270. }
  4271. }
  4272. };
  4273.  
  4274. const ioMessageListCleanup = () => {
  4275. if (ioMessageList) {
  4276. ioMessageList.disconnect();
  4277. ioMessageList.takeRecords();
  4278. ioMessageList = null;
  4279. }
  4280. }
  4281.  
  4282. const addMessageOverflowAnchorToShadow = function (attachRoot) {
  4283.  
  4284. const messageOverflowAnchor = document.createElement('div');
  4285. messageOverflowAnchor.className = 'bst-overflow-anchor';
  4286. attachRoot.appendChild(messageOverflowAnchor);
  4287.  
  4288. let anchorVisible = false;
  4289. let rct = 0;
  4290. const ioof = (tct) => {
  4291. if (tct !== rct) return;
  4292. if (!anchorVisible) {
  4293. if (bottomKeepAt() + 80 > Date.now()) {
  4294. this.scrollToBottom_();
  4295. } else {
  4296. this.setAtBottomFalse();
  4297. }
  4298. } else if (!hasAnySelection()) {
  4299. this.setAtBottomTrue();
  4300. }
  4301. };
  4302. const iooa = new IntersectionObserver((entries) => {
  4303. if (!_flushed) return; // avoid initial check (not yet flushed)
  4304. anchorVisible = entries[entries.length - 1].isIntersecting === true;
  4305. const tct = rct = (rct & 1073741823) + 1;
  4306. Promise.resolve(tct).then(ioof);
  4307. }, { root: null, threshold: [0.05, 0.95], rootMargin: '0px' });
  4308. iooa.observe(messageOverflowAnchor);
  4309.  
  4310. _messageOverflowAnchor = messageOverflowAnchor;
  4311. }
  4312.  
  4313. if (!cProto.canScrollToBottom581_ && typeof cProto.canScrollToBottom_ === 'function' && cProto.canScrollToBottom_.length === 0) {
  4314.  
  4315.  
  4316. cProto.canScrollToBottom581_ = cProto.canScrollToBottom_;
  4317.  
  4318. cProto.canScrollToBottom_ = function () {
  4319. if (pointerHoldingAt > 0 || pointerReleasedWithSelection || pointerReleaseNotReady) return false;
  4320. if (hasAnySelection()) return false; // rely on ".allowScroll"
  4321. // if (pointerReleasedAt > 0 && pointerReleasedAt + 800 > Date.now() && hasAnySelection()) return false; // allowScroll will become false after menu is shown
  4322. // if (hasAnySelection()) return false; // rely on ".allowScroll"
  4323. return this.canScrollToBottom581_();
  4324. };
  4325.  
  4326. }
  4327.  
  4328. cProto.computeIsEmpty_ = function () {
  4329. return !(this.visibleItems?.length || 0);
  4330. }
  4331. // cProto._flag0281_ = _flag0281_;
  4332.  
  4333. const resetSelection = () => {
  4334. if (profileCard.wElement) {
  4335. Object.assign(W(profileCard), {
  4336. wElement: null,
  4337. top: -1,
  4338. showOnTop: null,
  4339. iconUrl: null,
  4340. username: null,
  4341. profileUrl: null,
  4342. });
  4343. }
  4344. if (menuRenderObj.messageUid) {
  4345. Object.assign(W(menuRenderObj), {
  4346. menuListXp: '',
  4347. messageUid: '',
  4348. loading: false,
  4349. });
  4350. }
  4351. if (entryHolding()) {
  4352. entryHoldingChange('');
  4353. }
  4354. }
  4355.  
  4356. const hasAnySelection = () => {
  4357. return !!(profileCard.wElement || menuRenderObj.messageUid || entryHolding());
  4358. }
  4359.  
  4360. cProto.setupBoostChat = function () {
  4361. let targetElement = (this.$.items || this.$['item-offset']);
  4362. if (!targetElement) return;
  4363. // if(!this.visibleItems__) this.visibleItems__ = [];
  4364. ioMessageListCleanup();
  4365.  
  4366. // this.visibleItemsCount = 0;
  4367. targetElement = targetElement.closest('#item-offset.yt-live-chat-item-list-renderer') || targetElement;
  4368. const bstMain = document.createElement('div');
  4369. const hostElement = this.hostElement;
  4370.  
  4371. {
  4372. const fragment = new DocumentFragment();
  4373. const noscript = document.createElement('noscript');
  4374. noscript.id = 'bst-noscript';
  4375. appendChild.call(noscript, (wliveChatTextMessageRenderer || (wliveChatTextMessageRenderer = document.createElement('yt-live-chat-text-message-renderer'))));
  4376. appendChild.call(noscript, (wliveChatTextInputRenderer || (wliveChatTextInputRenderer = document.createElement('yt-live-chat-text-input-field-renderer'))));
  4377.  
  4378. const div0 = document.createElement('div');
  4379. div0.id = 'bst-noscript-div';
  4380. appendChild.call(noscript, div0);
  4381. const shadowDiv0 = CAN_USE_SHADOWROOT ? div0.attachShadow({ mode: "open" }) : null;
  4382. const attachDiv0 = CAN_USE_SHADOWROOT ? shadowDiv0 : div0;
  4383. attachDiv0.appendChild(wliveChatTextMessageRenderer);
  4384. attachDiv0.appendChild(wliveChatTextInputRenderer);
  4385.  
  4386. fragmentAppendChild.call(fragment, noscript);
  4387. fragmentAppendChild.call(fragment, bstMain);
  4388. const dummyItems = document.createElement('div');
  4389. dummyItems.id = 'items';
  4390. dummyItems.style.display = 'none';
  4391.  
  4392. const dummyItemOffset = document.createElement('div');
  4393. dummyItemOffset.id = 'item-offset';
  4394. dummyItemOffset.style.display = 'none';
  4395. appendChild.call(dummyItemOffset, dummyItems);
  4396.  
  4397.  
  4398. fragmentAppendChild.call(fragment, dummyItemOffset);
  4399.  
  4400. replaceWith.call(targetElement, fragment);
  4401. sharedNoscript = noscript;
  4402. }
  4403.  
  4404. const shadowRoot = SHOULD_USE_SHADOWROOT ? bstMain.attachShadow({ mode: "open" }) : null;
  4405. const attachRoot = (SHOULD_USE_SHADOWROOT ? shadowRoot : bstMain);
  4406. const intersectionObserver = new IntersectionObserver(ioMessageListCallback, { root: bstMain, threshold: [0.05, 0.95] });
  4407. wAttachRoot.set(hostElement, {
  4408. shadowRoot,
  4409. bstMain
  4410. });
  4411. bstMain.classList.add('bst-yt-main');
  4412. bstMain.addEventListener('wheel', () => {
  4413. bottomKeepAtSet(0);
  4414. });
  4415. bstMain.addEventListener('touchmove', () => {
  4416. bottomKeepAtSet(0);
  4417. });
  4418. bstMain.addEventListener('scroll', (a) => {
  4419. // bstMainScrollCount++;
  4420. this.onScrollItems_(a);
  4421. }, false);
  4422. {
  4423. // const mListenerQ27 = async () => {
  4424. // // noFlushTP = true;
  4425. // }
  4426. // const mListenerQ28 = () => {
  4427. // // noFlushTP = false;
  4428. // const p = mouseActionP;
  4429. // if (p) {
  4430. // mouseActionP = null;
  4431. // p.resolve();
  4432. // }
  4433. // };
  4434.  
  4435. // const mListenerQ29 = (evt) => {
  4436. // if (evt.target === bstMain) {
  4437. // // noFlushTP = false;
  4438. // const p = mouseActionP;
  4439. // if (p) {
  4440. // mouseActionP = null;
  4441. // p.resolve();
  4442. // }
  4443. // }
  4444. // };
  4445. // bstMain.addEventListener('pointerdown', mListenerQ27, { passive: true, capture: true });
  4446. // bstMain.addEventListener('pointerup', mListenerQ28, { passive: true, capture: true });
  4447. // bstMain.addEventListener('pointercancel', mListenerQ28, { passive: true, capture: true });
  4448. // bstMain.addEventListener('pointerleave', mListenerQ29, { passive: true, capture: false });
  4449. // bstMain.addEventListener('pointerenter', mListenerQ29, { passive: true, capture: false });
  4450. // bstMain.addEventListener('mouseenter', mListenerQ28, { passive: true, capture: true });
  4451. // bstMain.addEventListener('mouseleave', mListenerQ28, { passive: true, capture: true });
  4452.  
  4453. if (typeof ResizeObserver !== 'undefined') {
  4454. const ro = new ResizeObserver(() => {
  4455. const dt = bottomPauseAt();
  4456. let ct;
  4457. if (!dt || dt + 60 < (ct = Date.now())) {
  4458. bottomKeepAtSet(ct || Date.now());
  4459. }
  4460. });
  4461. ro.observe(bstMain);
  4462. }
  4463.  
  4464. }
  4465. _bstMain = bstMain;
  4466.  
  4467. document.head.appendChild(document.createElement('style')).textContent = `${cssTexts.outer}`;
  4468.  
  4469. attachRoot.appendChild(document.createElement('style')).textContent = `${cssTexts.inner}`;
  4470. messageList = document.createElement('div')
  4471. messageList.className = 'bst-message-list';
  4472. attachRoot.appendChild(messageList);
  4473. messageListWR_ = mWeakRef(messageList);
  4474.  
  4475. messageList.getListRendererCnt = () => {
  4476.  
  4477. let cnt = wliveChatTextMessageRenderer ? insp(wliveChatTextMessageRenderer) : null;
  4478. while (cnt && cnt.is) {
  4479. if (cnt.emojiManager) break;
  4480. cnt = cnt.parentComponent;
  4481. if (!cnt) break;
  4482. cnt = insp(cnt);
  4483. }
  4484. return cnt;
  4485. }
  4486.  
  4487. messageList.getInputRendererCnt = () => {
  4488. let cnt = wliveChatTextInputRenderer ? insp(wliveChatTextInputRenderer) : null;
  4489. return cnt;
  4490. }
  4491.  
  4492.  
  4493. const [visibleCount, visibleCountChange] = createSignal();
  4494.  
  4495.  
  4496. messageList.visibleCount = visibleCount;
  4497.  
  4498.  
  4499. const solidBuild = new VisibleItemList();
  4500.  
  4501.  
  4502. this.setupVisibleItemsList(solidBuild);
  4503.  
  4504. messageList.solidBuild = solidBuild;
  4505. createMemo((prev) => {
  4506. const list = R(solidBuild);
  4507. (list.length !== prev) && Promise.resolve().then(resetSelection);
  4508. return list.length;
  4509. }, 0);
  4510.  
  4511.  
  4512. // createEffect(() => {
  4513. // solidBuild() && (ezPr !== null) && Promise.resolve([ezPr]).then(h => h[0].resolve());
  4514. // });
  4515.  
  4516. const isListEmpty = createMemo(() => R(solidBuild).length < 1);
  4517. createEffect(() => {
  4518. const cEmpty = isListEmpty();
  4519. const change = (cEmpty) ^ (!!this.isEmpty);
  4520. if (change) {
  4521. this._setPendingProperty('isEmpty', cEmpty, !0) && this._invalidateProperties()
  4522. }
  4523. });
  4524.  
  4525.  
  4526.  
  4527. messageList.profileCard = profileCard;
  4528. sbSignalSet(solidBuild);
  4529. render(SolidMessageList, messageList);
  4530.  
  4531. addMessageOverflowAnchorToShadow.call(this, attachRoot);
  4532.  
  4533. {
  4534.  
  4535. let mouseEntered = null;
  4536.  
  4537.  
  4538.  
  4539. messageList.addEventListener('mouseenter', function (evt) {
  4540.  
  4541. const target = evt?.target;
  4542.  
  4543.  
  4544. if (mouseEntered) {
  4545. tooltipTargetChange(null)
  4546. mouseEntered = null;
  4547. }
  4548. if ((target instanceof HTMLImageElement) || (target instanceof HTMLElement && target.nodeName === 'YT-ICON')) {
  4549. if (target.hasAttribute('shared-tooltip-text')) {
  4550. mouseEntered = target;
  4551. tooltipTargetChange(mWeakRef(target));
  4552. evt.stopPropagation();
  4553. evt.stopImmediatePropagation();
  4554. return;
  4555. }
  4556. }
  4557.  
  4558.  
  4559. }, true);
  4560. messageList.addEventListener('mouseleave', function (evt) {
  4561.  
  4562.  
  4563. const target = evt?.target;
  4564.  
  4565. if (target === mouseEntered && mouseEntered) {
  4566. mouseEntered = null;
  4567. tooltipTargetChange(null);
  4568.  
  4569.  
  4570. // console.log(12, evt.target.getAttribute('shared-tooltip-text'))
  4571. evt.stopPropagation();
  4572. evt.stopImmediatePropagation();
  4573. return;
  4574. }
  4575.  
  4576. }, true);
  4577.  
  4578. }
  4579.  
  4580. const onNameFieldClick = (target, messageEntry, nameField) => {
  4581. const data = mutableWM.get(messageEntry)?.getDataObj();
  4582. if (!data) return;
  4583.  
  4584. entryHoldingChange(messageEntry.getAttribute('message-uid') || '');
  4585. // if (this.atBottom === true && this.allowScroll === true && this.contextMenuOpen === false) this.contextMenuOpen = true;
  4586.  
  4587. let r1 = nameField.getBoundingClientRect();
  4588. let fTop = r1.top - messageList.getBoundingClientRect().top;
  4589. let fBottom = fTop + r1.height;
  4590. Object.assign(W(profileCard), {
  4591. wElement: mWeakRef(messageEntry),
  4592. fTop,
  4593. fBottom,
  4594. showOnTop: messageEntry.getAttribute('view-pos') === 'down',
  4595. iconUrl: data.getProfilePic(64, -1),
  4596. username: data.bst('getUsername'),
  4597. profileUrl: data.bst('authorAboutPage')
  4598. });
  4599.  
  4600. console.log('[yt-bst] onNameFieldClick', Object.assign({}, (data)));
  4601.  
  4602. }
  4603.  
  4604.  
  4605. let pointerDown = -1;
  4606. let waitingToShowMenu = null;
  4607. let waitingToCloseMenu = null;
  4608. // let qcz7 = 0;
  4609.  
  4610. const dblClickMessage = async (messageEntry, target) => {
  4611.  
  4612. const ct = Date.now();
  4613. if (lastSingleClick + 180 > ct) return;
  4614.  
  4615. resetSelection();
  4616.  
  4617. const singleEmoji = target.closest('img.emoji');
  4618. let text;
  4619. if (singleEmoji) {
  4620.  
  4621.  
  4622. text = getElementText(singleEmoji).trim();
  4623. } else {
  4624.  
  4625. const body = messageEntry.querySelector('.bst-message-body');
  4626. text = body ? getElementText(body).trim() : '';
  4627. }
  4628. if (text) {
  4629.  
  4630.  
  4631. const renderer = document
  4632. .querySelector('yt-live-chat-text-input-field-renderer[class]');
  4633. const input = renderer
  4634. ?.querySelector('#input');
  4635.  
  4636. if (input && !input.closest('[hidden]')) {
  4637.  
  4638. await delayPn(40);
  4639.  
  4640. const cnt = getLcRendererCnt();
  4641. const isAtBottom = cnt ? cnt.atBottom && cnt.canScrollToBottom_() : null;
  4642. if (isAtBottom) bottomKeepAtSet(Date.now());
  4643.  
  4644. await input.focus();
  4645.  
  4646. // await delayPn(1);
  4647.  
  4648. insp(renderer).setText('');
  4649. insp(renderer).onInputChange();
  4650.  
  4651. // await delayPn(1);
  4652.  
  4653. const textSplit = text.split(/(:+[^:]+:)/g);
  4654. const data = new DataTransfer();
  4655. for (const s of textSplit) {
  4656. if (!s) continue;
  4657. data.setData('text/plain', s);
  4658. input.dispatchEvent(
  4659. new ClipboardEvent('paste', { bubbles: true, clipboardData: data })
  4660. );
  4661. insp(renderer).onInputChange();
  4662. }
  4663.  
  4664. const range = document.createRange();//Create a range (a range is a like the selection but invisible)
  4665. range.selectNodeContents(input);//Select the entire contents of the element with the range
  4666. range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
  4667. const selection = window.getSelection();//get the selection object (allows you to change selection)
  4668. selection.removeAllRanges();//remove any selections already made
  4669. selection.addRange(range);//make the range you have just created the visible selection
  4670.  
  4671. // if (isAtBottom) {
  4672.  
  4673. // const pcz = qcz7 = (qcz7 & 1073741823) + 1;
  4674. // flushPE(async () => {
  4675. // if (pcz !== qcz7) return;
  4676. // setTimeout(() => {
  4677. // if (pcz !== qcz7) return;
  4678. // const cnt = getLcRendererCnt();
  4679. // if (cnt && (!cnt.atBottom || !cnt.canScrollToBottom_())) cnt.scrollToBottom_();
  4680. // }, 80);
  4681. // });
  4682. // }
  4683. if (isAtBottom) bottomKeepAtSet(Date.now());
  4684.  
  4685. setTimeout(() => {
  4686. input.scrollTop += 1e9;
  4687. }, 1);
  4688.  
  4689. }
  4690.  
  4691. }
  4692.  
  4693.  
  4694. }
  4695.  
  4696. messageList.addEventListener('dblclick', function (evt) {
  4697.  
  4698.  
  4699. if (evt.button) return;
  4700. const target = evt?.target;
  4701.  
  4702.  
  4703. if (target instanceof Element) {
  4704.  
  4705. const testElement = target.closest('.bst-message-entry, .bst-message-head, .bst-message-profile-holder, .bst-message-menu-container');
  4706.  
  4707.  
  4708. if (testElement?.classList?.contains('bst-message-entry')) {
  4709.  
  4710. dblClickMessage(testElement, target);
  4711.  
  4712. }
  4713. }
  4714.  
  4715.  
  4716. });
  4717.  
  4718.  
  4719. let cancelPointerHolderFnBusy = false;
  4720.  
  4721.  
  4722. /*
  4723. const pointerReleaseProcess = async () => {
  4724. pointerReleasedAt = Date.now();
  4725. flushPEHoldingUntil = Date.now() + 400;
  4726. if (flushPEHoldingMaxTimelineResolve < 4) flushPEHoldingMaxTimelineResolve = 4;
  4727. pointerHoldingAt = 0;
  4728. pointerReleaseNotReady = true;
  4729. if (pointerReleasedAt > 0 && !cancelPointerHolderFnBusy) {
  4730. cancelPointerHolderFnBusy = true;
  4731. await timelineResolve();
  4732. cancelPointerHolderFnBusy = false;
  4733. pointerReleaseNotReady = false;
  4734. if (pointerReleasedAt > 0 && `${window.getSelection()}`) {
  4735. pointerReleasedWithSelection = true;
  4736. } else {
  4737. pointerReleasedWithSelection = false;
  4738. }
  4739. }
  4740. };
  4741. */
  4742.  
  4743. const pointerReleaseProcess = async () => {
  4744. if (!pointerHoldingAt) return;
  4745. pointerReleasedAt = Date.now();
  4746. flushPEHoldingUntil = Date.now() + 400;
  4747. if (flushPEHoldingMaxTimelineResolve < 4) flushPEHoldingMaxTimelineResolve = 4;
  4748. pointerHoldingAt = 0;
  4749. if (atBottom0() !== true) return;
  4750. pointerReleaseNotReady = true;
  4751. if (cancelPointerHolderFnBusy) return;
  4752. cancelPointerHolderFnBusy = true;
  4753. await timelineResolve();
  4754. cancelPointerHolderFnBusy = false;
  4755. pointerReleaseNotReady = false;
  4756. if (pointerReleasedAt > 0 && !pointerHoldingAt) {
  4757. pointerReleasedWithSelection = `${window.getSelection()}`.length > 0;
  4758. } else {
  4759. pointerReleasedWithSelection = false;
  4760. }
  4761. if (atBottom0() !== true) return;
  4762. const lcrCnt = getLcRendererCnt();
  4763. if (lcrCnt?.activeItems_?.length > 0 && lcrCnt.canScrollToBottom_()) {
  4764. lcrCnt.flushActiveItems_();
  4765. }
  4766. };
  4767.  
  4768. messageList.addEventListener('mouseover', function(evt){
  4769. if(pointerHoldingAt > 0 && evt.buttons === 0) {
  4770. pointerReleaseProcess();
  4771. }
  4772.  
  4773. }, true);
  4774. messageList.addEventListener('mouseout', function(evt){
  4775. if(pointerHoldingAt > 0 && evt.buttons === 0) {
  4776. pointerReleaseProcess();
  4777. }
  4778. }, true);
  4779.  
  4780. messageList.addEventListener('mouseenter', function(evt){
  4781. if(pointerHoldingAt > 0 && evt.buttons === 0) {
  4782. pointerReleaseProcess();
  4783. }
  4784. pointerReleasedWithSelection = false;
  4785. }, false);
  4786. messageList.addEventListener('mouseleave', function(evt){
  4787. if(pointerHoldingAt > 0 && evt.buttons === 0) {
  4788. pointerReleaseProcess();
  4789. }
  4790. pointerReleasedWithSelection = false;
  4791. }, false);
  4792.  
  4793. messageList.addEventListener('pointermove', function (evt) {
  4794.  
  4795. if (pointerHoldingAt > 0 && evt.buttons === 0) {
  4796. pointerReleaseProcess();
  4797. }
  4798.  
  4799. });
  4800.  
  4801. messageList.addEventListener('pointerdown', function (evt) {
  4802. if (evt.button || pointerDown >= 0) {
  4803. return;
  4804. }
  4805. pointerDown = -1;
  4806.  
  4807.  
  4808. dblClickDT = Date.now();
  4809. promiseForDblclick && promiseForDblclick.resolve();
  4810. if (promiseForDblclick) {
  4811. return;
  4812. }
  4813.  
  4814. pointerHoldingAt = Date.now();
  4815. pointerReleasedAt = 0;
  4816. pointerReleasedWithSelection = false;
  4817. flushPEHoldingUntil = Date.now() + 400;
  4818. if (flushPEHoldingMaxTimelineResolve < 4) flushPEHoldingMaxTimelineResolve = 4;
  4819.  
  4820. const target = evt?.target;
  4821. waitingToShowMenu = null;
  4822. waitingToCloseMenu = null;
  4823.  
  4824. if (target instanceof Element) {
  4825.  
  4826. const messageEntry0 = target.closest('.bst-message-entry');
  4827. const messageUid = messageEntry0 ? messageEntry0.getAttribute('message-uid') : '';
  4828.  
  4829. if (messageUid && messageEntry0 && kRef(profileCard.wElement) !== messageEntry0) {
  4830. profileCard_onCrossClick();
  4831. }
  4832.  
  4833.  
  4834. // console.log(389588, 1, messageUid);
  4835. if (messageUid) {
  4836.  
  4837.  
  4838. const testElement = target.closest('.bst-message-entry, .bst-message-head, .bst-message-profile-holder, .bst-message-menu-container');
  4839. if (testElement?.classList?.contains('bst-message-menu-container')) {
  4840. menuMenuCache.delete(messageUid); // menu action will change menu items
  4841. } else if (menuRenderObj.messageUid !== messageUid && testElement && testElement === messageEntry0) {
  4842.  
  4843. const shouldShowMenuAction = isCtrl(evt) || isAlt(evt);
  4844.  
  4845. if (shouldShowMenuAction) {
  4846. if (entryHolding() !== messageUid) entryHoldingChange(messageUid ? messageUid : '');
  4847.  
  4848. if (menuRenderObj.messageUid) {
  4849.  
  4850. Object.assign(W(menuRenderObj), {
  4851. menuListXp: '',
  4852. messageUid: '',
  4853. loading: false,
  4854. });
  4855.  
  4856. }
  4857.  
  4858. waitingToShowMenu = { pageX0: evt.pageX, pageY0: evt.pageY };
  4859. preShowMenu(messageEntry0);
  4860. } else {
  4861. if (entryHolding()) entryHoldingChange('');
  4862.  
  4863.  
  4864. if (menuRenderObj.messageUid) {
  4865.  
  4866. Object.assign(W(menuRenderObj), {
  4867. menuListXp: '',
  4868. messageUid: '',
  4869. loading: false,
  4870. });
  4871.  
  4872. }
  4873.  
  4874. }
  4875.  
  4876. } else if (menuRenderObj.messageUid && testElement && testElement !== messageEntry0) {
  4877.  
  4878.  
  4879.  
  4880. // console.log(389588, 3, messageUid);
  4881. // if (entryHolding() !== messageUid) entryHoldingChange(messageUid ? messageUid : '');
  4882.  
  4883. if (menuRenderObj.messageUid) {
  4884. Object.assign(W(menuRenderObj), {
  4885. menuListXp: '',
  4886. messageUid: '',
  4887. loading: false,
  4888. });
  4889.  
  4890. }
  4891. entryHoldingChange('');
  4892.  
  4893.  
  4894. } else if (menuRenderObj.messageUid && target.closest('.bst-message-entry, .bst-message-menu-container')?.classList?.contains('bst-message-entry')) {
  4895.  
  4896. // console.log(389588, 4, messageUid);
  4897. waitingToCloseMenu = { pageX0: evt.pageX, pageY0: evt.pageY };
  4898.  
  4899.  
  4900.  
  4901. } else if (entryHolding() !== messageUid) {
  4902.  
  4903. // console.log(389588, 5, messageUid);
  4904. // if(entryHolding()!==messageUid) entryHoldingChange(messageUid ? messageUid : '');
  4905.  
  4906. if (menuRenderObj.messageUid) {
  4907. Object.assign(W(menuRenderObj), {
  4908. menuListXp: '',
  4909. messageUid: '',
  4910. loading: false,
  4911. });
  4912. }
  4913.  
  4914. entryHoldingChange('');
  4915.  
  4916.  
  4917. } else {
  4918.  
  4919. // console.log(389588, 6, messageUid);
  4920. entryHoldingChange('');
  4921. }
  4922.  
  4923.  
  4924.  
  4925.  
  4926. } else if (entryHolding()) {
  4927.  
  4928. // console.log(389588, 7, messageUid);
  4929. if (entryHolding() !== messageUid) entryHoldingChange(messageUid ? messageUid : '');
  4930.  
  4931. if (menuRenderObj.messageUid) {
  4932.  
  4933. Object.assign(W(menuRenderObj), {
  4934. menuListXp: '',
  4935. messageUid: '',
  4936. loading: false,
  4937. });
  4938. }
  4939.  
  4940. }
  4941.  
  4942. }
  4943.  
  4944.  
  4945. });
  4946.  
  4947.  
  4948. messageList.addEventListener('pointerup', function (evt) {
  4949.  
  4950. if (pointerHoldingAt > 0) {
  4951. pointerReleaseProcess();
  4952. }
  4953. if (pointerDown >= 0) return;
  4954.  
  4955. pointerDown = -1;
  4956.  
  4957.  
  4958.  
  4959. });
  4960.  
  4961.  
  4962. messageList.addEventListener('pointercancel', function (evt) {
  4963.  
  4964. if (pointerHoldingAt > 0) {
  4965. pointerReleaseProcess();
  4966. }
  4967.  
  4968. if (pointerDown >= 0) return;
  4969.  
  4970. pointerDown = -1;
  4971.  
  4972.  
  4973.  
  4974. });
  4975.  
  4976. const distance = (x, y) => Math.sqrt(x * x + y * y);
  4977.  
  4978. let promiseForDblclick = null;
  4979. let dblClickDT = 0;
  4980. let lastSingleClick = 0;
  4981.  
  4982. messageList.addEventListener('click', async function (evt) {
  4983.  
  4984.  
  4985. const waitingToShowMenu_ = waitingToShowMenu;
  4986. waitingToShowMenu = null;
  4987.  
  4988. const waitingToCloseMenu_ = waitingToCloseMenu;
  4989. waitingToCloseMenu = null;
  4990.  
  4991.  
  4992. dblClickDT = 0;
  4993. promiseForDblclick = new PromiseExternal();
  4994. await Promise.race([promiseForDblclick, delayPn(140)]);
  4995. promiseForDblclick = null;
  4996. const ct = Date.now();
  4997. if (dblClickDT + 180 > ct) return;
  4998. lastSingleClick = ct;
  4999.  
  5000. const currentProfileCardElement = kRef(profileCard.wElement);
  5001.  
  5002. let b = false;
  5003. const target = evt?.target;
  5004. if (target instanceof Element) {
  5005. const messageEntry = target.closest('.bst-message-entry');
  5006. if (messageEntry) {
  5007. const nameField = target.closest('.bst-name-field');
  5008. if (nameField) {
  5009. onNameFieldClick(target, messageEntry, nameField);
  5010. b = true;
  5011. }
  5012. }
  5013. }
  5014.  
  5015. if (!b && currentProfileCardElement && !target.closest('.bst-profile-card')) {
  5016. profileCard_onCrossClick();
  5017. }
  5018.  
  5019. if (waitingToShowMenu_ && target instanceof Element) {
  5020. const { pageX0, pageY0 } = waitingToShowMenu_;
  5021. const { pageX, pageY } = evt;
  5022.  
  5023. const d = distance(pageX - pageX0, pageY - pageY0);
  5024.  
  5025. const messageEntry0 = target.closest('.bst-message-entry');
  5026. const messageUid = messageEntry0 ? messageEntry0.getAttribute('message-uid') : '';
  5027. if (d < 4 && messageUid) {
  5028.  
  5029. const elementRect = messageEntry0.getBoundingClientRect();
  5030.  
  5031. if (pageX >= elementRect.left && pageX <= elementRect.right && pageY >= elementRect.top && pageY <= elementRect.bottom) {
  5032.  
  5033. showMenu(messageEntry0);
  5034. } else if (menuRenderObj.messageUid) {
  5035.  
  5036. Object.assign(W(menuRenderObj),{
  5037. menuListXp: '',
  5038. messageUid: '',
  5039. loading: false,
  5040. });
  5041.  
  5042. entryHoldingChange('');
  5043. }
  5044. } else {
  5045.  
  5046. if (entryHolding() !== messageUid) entryHoldingChange(messageUid ? messageUid : '');
  5047. if (menuRenderObj.messageUid) {
  5048.  
  5049. Object.assign(W(menuRenderObj),{
  5050. menuListXp: '',
  5051. messageUid: '',
  5052. loading: false,
  5053. });
  5054.  
  5055. entryHoldingChange('');
  5056. }
  5057.  
  5058. }
  5059.  
  5060. }
  5061.  
  5062. if (waitingToCloseMenu_ && target instanceof Element) {
  5063.  
  5064. const messageEntry0 = target.closest('.bst-message-entry');
  5065. const messageUid = messageEntry0 ? messageEntry0.getAttribute('message-uid') : '';
  5066.  
  5067.  
  5068. if (messageUid) {
  5069.  
  5070. const testElement = target.closest('.bst-message-entry, .bst-message-head, .bst-message-profile-holder');
  5071. if (menuRenderObj.messageUid !== messageUid && testElement && testElement === messageEntry0) {
  5072.  
  5073. } else if (menuRenderObj.messageUid && testElement && testElement !== messageEntry0) {
  5074.  
  5075. } else if (menuRenderObj.messageUid && target.closest('.bst-message-entry, .bst-message-menu-container')?.classList?.contains('bst-message-entry')) {
  5076.  
  5077.  
  5078. const { pageX0, pageY0 } = waitingToCloseMenu_;
  5079. const { pageX, pageY } = evt;
  5080.  
  5081. const d = distance(pageX - pageX0, pageY - pageY0);
  5082.  
  5083.  
  5084. if (d < 4) {
  5085.  
  5086. // if (entryHolding() !== messageUid) entryHoldingChange(messageUid ? messageUid : '');
  5087. Object.assign(W(menuRenderObj),{
  5088. menuListXp: '',
  5089. messageUid: '',
  5090. loading: false,
  5091. });
  5092. entryHoldingChange('');
  5093.  
  5094. }
  5095. }
  5096.  
  5097. }
  5098. }
  5099.  
  5100.  
  5101. });
  5102.  
  5103. {
  5104. const attributeFn = () => {
  5105. if (!messageList) return;
  5106. const isDark = document.documentElement.hasAttribute('dark')
  5107. if (isDark) _setAttribute.call(messageList, 'dark', '');
  5108. else _removeAttribute.call(messageList, 'dark');
  5109. };
  5110. (new MutationObserver(attributeFn)).observe(document.documentElement, { attributes: true });
  5111. attributeFn();
  5112. }
  5113.  
  5114.  
  5115. // yt-live-chat-item-list-renderer
  5116. // const lcrAttributeFn = () => {
  5117. // // if (!messageList) return;
  5118. // // let isDark = document.documentElement.hasAttribute('dark')
  5119. // // if (isDark) _setAttribute.call(messageList, 'dark', '');
  5120. // // else _removeAttribute.call(messageList, 'dark');
  5121. // };
  5122. // (new MutationObserver(lcrAttributeFn)).observe(this.hostElement, { attributes: true });
  5123. // lcrAttributeFn();
  5124.  
  5125. ioMessageList = intersectionObserver;
  5126.  
  5127. createEffect(() => {
  5128. const list = R(solidBuild);
  5129. let j = 0;
  5130. for (let i = 0; i < list.length; i++) {
  5131. const listItem =solidBuildAt(list, i);
  5132. const mutable = mutableWM.get(listItem);
  5133. if (typeof mutable?.viewVisible === 'function' && typeof mutable?.viewVisibleIdxChange === 'function') {
  5134. if (mutable?.viewVisible()) {
  5135. j++;
  5136. mutable?.viewVisibleIdxChange(j);
  5137. } else {
  5138. mutable?.viewVisibleIdxChange(null);
  5139. }
  5140. }
  5141. }
  5142. visibleCountChange(j);
  5143. });
  5144.  
  5145.  
  5146. Promise.resolve().then(() => {
  5147.  
  5148. let qcz4 = 0;
  5149. document.addEventListener('keydown', (evt) => {
  5150. const target = (evt?.target || 0);
  5151. if (target instanceof HTMLElement && target.id === 'input') {
  5152. const cnt = getLcRendererCnt();
  5153. const isAtBottom = cnt ? cnt.atBottom && cnt.canScrollToBottom_() : null;
  5154. target.__ah46n__ = isAtBottom;
  5155. }
  5156. });
  5157. document.addEventListener('keyup', (evt) => {
  5158. const target = (evt?.target || 0);
  5159. const isAtBottom__ = target.__ah46n__;
  5160. if (isAtBottom__) {
  5161. target.__ah46n__ = null;
  5162. const pcz = ++qcz4;
  5163. flushPE(() => {
  5164. if (pcz !== qcz4) return;
  5165. setTimeout(() => {
  5166. if (pcz !== qcz4) return;
  5167. const cnt = getLcRendererCnt();
  5168. if (!cnt) return;
  5169. if (cnt.atBottom && cnt.canScrollToBottom_()) {
  5170. } else {
  5171. cnt.scrollToBottom_();
  5172. }
  5173. }, 80);
  5174. })
  5175. }
  5176. });
  5177.  
  5178.  
  5179. });
  5180.  
  5181.  
  5182. setIntervalX0(rcPromiseUnlockFn, 145); // 145ms ~ 290ms -> clear
  5183. console.log('[yt-bst] loaded')
  5184.  
  5185. }
  5186.  
  5187. // const
  5188. // shadow.appendChild(document.createElement('div')).className = 'bst-message-entry';
  5189.  
  5190.  
  5191.  
  5192.  
  5193.  
  5194. function getAuthor(o) {
  5195. if (MEMO(o, 'rendererFlag')() === 1) {
  5196. return o?.header?.liveChatSponsorshipsHeaderRenderer;
  5197. }
  5198. return o;
  5199. }
  5200.  
  5201. function getAuthorBadgeType(authorBadges) {
  5202. if (!authorBadges || !(authorBadges.length >= 1)) return ''; // performance concern? (1.8ms)
  5203. for (const badge of authorBadges) {
  5204. const r = badge ? badge.liveChatAuthorBadgeRenderer : null;
  5205. if (r) {
  5206. const b = r ? r.icon ? r.icon.iconType.toLowerCase() : r.customThumbnail ? "member" : "" : ""
  5207. if (b && "verified" !== b) {
  5208. return b;
  5209. }
  5210. }
  5211. }
  5212. return '';
  5213. }
  5214.  
  5215.  
  5216. function getProfilePic(min, max) {
  5217. let w = getAuthor(this)?.authorPhoto || 0;
  5218. w = w.thumbnails || w;
  5219. if (w) {
  5220.  
  5221. if (w.url) return w.url;
  5222. if (typeof w === 'string') return w;
  5223. if (w.length >= 0) {
  5224. const url = getThumbnail(w, min, max);
  5225. if (url) return url;
  5226. }
  5227. }
  5228. return null;
  5229. }
  5230.  
  5231. function getStickerURL(min, max) {
  5232. let w = this.sticker || 0;
  5233. w = w.thumbnails || w;
  5234. if (w) {
  5235.  
  5236. if (w.url) return w.url;
  5237. if (typeof w === 'string') return w;
  5238. if (w.length >= 0) {
  5239. const url = getThumbnail(w, min, max);
  5240. if (url) return url;
  5241. }
  5242. }
  5243. return null;
  5244. }
  5245.  
  5246. fixMessages = (messages) => {
  5247.  
  5248. const cnt = messageList?.getInputRendererCnt() || null;
  5249. if (!cnt) return messages;
  5250.  
  5251. let res = [];
  5252.  
  5253. for (const message of messages) {
  5254. if (typeof message.text === 'string') {
  5255. let r;
  5256. try {
  5257. r = fixMessagesForEmoji.call(cnt.emojiManager, message.text)
  5258. } catch (e) {
  5259. console.warn(e)
  5260. }
  5261. if (r && r.length === 1 && r[0].text) {
  5262. res.push(message); // eg. hyperlink
  5263. } else if (r && r.length >= 1) {
  5264. // res.push(...r);
  5265. inPlaceArrayPush(res, r);
  5266. } else {
  5267. res.push(message);
  5268. }
  5269.  
  5270. // console.log(199, r)
  5271.  
  5272. /*
  5273. ((a,b,c,d)=>{
  5274. let Wkb = /tone[1-5]/
  5275. , Xkb = " \uD83C\uDFFB \uD83C\uDFFC \uD83C\uDFFD \uD83C\uDFFE \uD83C\uDFFF".split(" ")
  5276. , Ykb = "UCzC5CNksIBaiT-NdMJjJNOQ/COLRg9qOwdQCFce-qgodrbsLaA UCzC5CNksIBaiT-NdMJjJNOQ/CMKC7uKOwdQCFce-qgodqbsLaA UCzC5CNksIBaiT-NdMJjJNOQ/CJiQ8uiOwdQCFcx9qgodysAOHg UCzC5CNksIBaiT-NdMJjJNOQ/CI3h3uDJitgCFdARTgodejsFWg UCzC5CNksIBaiT-NdMJjJNOQ/CI69oYTKitgCFdaPTgodsHsP5g UCzC5CNksIBaiT-NdMJjJNOQ/CKzQr47KitgCFdCITgodq6EJZg UCzC5CNksIBaiT-NdMJjJNOQ/CPGD8Iu8kN4CFREChAod9OkLmg".split(" ")
  5277. , Zkb = Number.MAX_SAFE_INTEGER
  5278. , $kb = RegExp("\uFE0F", "g")
  5279.  
  5280. let b = false;
  5281. let c= true;
  5282. let d = false;
  5283. a = a.replace($kb, "");
  5284. for (var e = document.createDocumentFragment(), g = 0, k, m = 0; null != (k = this.emojiRegex.exec(a)); ) {
  5285. var p = dQ(this, k[0]) || gQ(this, k[0]);
  5286. !p || p.isCustomEmoji && !b || (p = this.createEmoji(p, c),
  5287. g !== k.index && e.appendChild(document.createTextNode(a.substring(g, k.index))),
  5288. e.appendChild(p),
  5289. g = k.index + k[0].length,
  5290. m++)
  5291. }
  5292. if (!d || m)
  5293. return e.appendChild(document.createTextNode(a.substr(g))),
  5294. e
  5295.  
  5296.  
  5297. })(message.text)
  5298. */
  5299. } else {
  5300. res.push(message);
  5301. }
  5302. }
  5303.  
  5304. /*
  5305.  
  5306.  
  5307. cQ.prototype.createDocumentFragment = function(a, b, c, d) {
  5308. b = void 0 === b ? !1 : b;
  5309. c = void 0 === c ? !0 : c;
  5310. d = void 0 === d ? !1 : d;
  5311. a = a.replace($kb, "");
  5312. for (var e = document.createDocumentFragment(), g = 0, k, m = 0; null != (k = this.emojiRegex.exec(a)); ) {
  5313. var p = dQ(this, k[0]) || gQ(this, k[0]);
  5314. !p || p.isCustomEmoji && !b || (p = this.createEmoji(p, c),
  5315. g !== k.index && e.appendChild(document.createTextNode(a.substring(g, k.index))),
  5316. e.appendChild(p),
  5317. g = k.index + k[0].length,
  5318. m++)
  5319. }
  5320. if (!d || m)
  5321. return e.appendChild(document.createTextNode(a.substr(g))),
  5322. e
  5323. }
  5324.  
  5325. */
  5326.  
  5327. return res;
  5328.  
  5329.  
  5330. }
  5331.  
  5332.  
  5333. function bst(prop) {
  5334.  
  5335. if (prop === 'getUsername') {
  5336. return MEMO(this, 'authorName')();
  5337. } else if (prop === 'hasMessageBody') {
  5338.  
  5339. const message = MEMO(this, 'rendererFlag')() === 1 ? this.header?.liveChatSponsorshipsHeaderRenderer?.primaryText : this.message;
  5340. if (typeof (message || 0) !== 'object') return false;
  5341. if (message.simpleText) return true;
  5342.  
  5343. const runs = message.runs;
  5344. return runs && runs.length && runs[0];
  5345.  
  5346. } else if(prop === 'messageXM'){
  5347.  
  5348. return MEMO(this, 'messageXM');
  5349. } else if (prop === 'authorBadges') {
  5350.  
  5351.  
  5352. const badges = getAuthor(this)?.authorBadges;
  5353. if (typeof (badges || 0) !== 'object') return null; // performance concern? (31.1ms)
  5354. return badges;
  5355.  
  5356. } else if (prop === 'authorType') {
  5357.  
  5358. return getAuthorBadgeType(this.authorBadges);
  5359. } else if (prop === 'shouldHighlight') {
  5360. const authorType = this.bst('authorType');
  5361. return authorType === 'owner';
  5362. } else if (prop === 'timestampText') {
  5363. if (this.timestampText) return convertYTtext(this.timestampText);
  5364. const ts = +this.timestampUsec / 1000;
  5365. if (ts > 1107183600000) {
  5366. const now = Date.now();
  5367. if (ts < (now + 120000)) {
  5368. return new Date(ts).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }); // performance concern? (1.4ms)
  5369. }
  5370. }
  5371. return null;
  5372. } else if (prop === 'authorExternalChannelId') {
  5373. return this.authorExternalChannelId;
  5374. } else if (prop === 'authorAboutPage') {
  5375. return `https://www.youtube.com/channel/${this.authorExternalChannelId}/about`;
  5376. }
  5377.  
  5378.  
  5379. }
  5380.  
  5381.  
  5382. cProto.setAtBottomTrue = function () {
  5383.  
  5384.  
  5385. if (this.atBottom === false) {
  5386. resetSelection();
  5387. this.atBottom = true;
  5388. atBottom0Set(true);
  5389. bottomPauseAtSet(0);
  5390. if (this.activeItems_.length > 0) this.flushActiveItems_();
  5391. }
  5392.  
  5393. }
  5394.  
  5395. cProto.setAtBottomFalse = function () {
  5396.  
  5397. if (this.atBottom === true) {
  5398. this.atBottom = false;
  5399. atBottom0Set(false);
  5400. bottomPauseAtSet(Date.now());
  5401. }
  5402.  
  5403. }
  5404.  
  5405. cProto.__notRequired__ = (cProto.__notRequired__ || 0) | 256;
  5406. cProto.setAtBottom = (...args) => {
  5407.  
  5408. chkVisibleItemList();
  5409.  
  5410. console.log('[yt-bst] setAtBottom', 583, ...args)
  5411.  
  5412. }
  5413.  
  5414. const scrollToEnd = () => {
  5415. if (messageList && _messageOverflowAnchor && _bstMain) {
  5416. _bstMain.scrollTop = _messageOverflowAnchor.offsetTop + 5;
  5417. }
  5418. }
  5419.  
  5420. cProto.atBottomChanged_ = function (a) {
  5421.  
  5422. // var b = this;
  5423. // a ? this.hideShowMoreAsync_ || (this.hideShowMoreAsync_ = kw(function() {
  5424. // O(b.hostElement).querySelector("#show-more").style.visibility = "hidden"
  5425. // }, 200)) : (this.hideShowMoreAsync_ && lw(this.hideShowMoreAsync_),
  5426. // this.hideShowMoreAsync_ = null,
  5427. // O(this.hostElement).querySelector("#show-more").style.visibility = "visible")
  5428.  
  5429. // console.log('atBottomChanged_')
  5430.  
  5431. }
  5432.  
  5433. cProto.smoothScroll_ = function () {
  5434.  
  5435. }
  5436.  
  5437. cProto.resetSmoothScroll_ = function () {
  5438. chkVisibleItemList();
  5439. this.scrollTimeRemainingMs_ = this.scrollPixelsRemaining_ = 0;
  5440. this.lastSmoothScrollUpdate_ = null;
  5441. this.smoothScrollRafHandle_ && window.cancelAnimationFrame(this.smoothScrollRafHandle_);
  5442. this.smoothScrollRafHandle_ = null;
  5443.  
  5444. }
  5445.  
  5446. cProto.isSmoothScrollEnabled_ = function () {
  5447. return false;
  5448. }
  5449.  
  5450.  
  5451. cProto.maybeAddDockableMessage17_ = cProto.maybeAddDockableMessage_;
  5452. cProto.maybeAddDockableMessage_ = function (a) {
  5453. console.log('[yt-bst] maybeAddDockableMessage_', 791, a)
  5454. return this.maybeAddDockableMessage17_(a)
  5455. }
  5456.  
  5457. cProto.forEachItem_ = function (a) {
  5458. let status = 0;
  5459. let i;
  5460. try {
  5461. status = 1;
  5462. i = 0;
  5463. for (const t of this.visibleItems) { // performance concern? (2.1ms)
  5464. a.call(this, "visibleItems", t, i++) // performance concern? (12.8ms)
  5465. }
  5466. status = 2;
  5467. i = 0;
  5468. for (const t of this.activeItems_) {
  5469. a.call(this, "activeItems_", t, i++);
  5470. }
  5471. status = 3;
  5472. } catch (e) {
  5473. console.error('[yt-bst] forEachItem_', status, i, this.visibleItems.length, this.activeItems_.length)
  5474. console.error(e)
  5475. }
  5476. }
  5477.  
  5478. // if (!cProto.computeVisibleItems17 && typeof cProto.computeVisibleItems === 'function') {
  5479. // cProto.computeVisibleItems17 = cProto.computeVisibleItems;
  5480. // cProto.computeVisibleItems = function (a, b) {
  5481.  
  5482. // console.log('[yt-bst] computeVisibleItems', 791, a, b)
  5483. // // if(!this.visibleItems__) this.visibleItems__ = [];
  5484. // // return this.visibleItems__;
  5485. // return this.computeVisibleItems17(a, b);
  5486.  
  5487. // }
  5488. // }
  5489.  
  5490. const replaceObject = (dist, src) => {
  5491. if (!dist || !src) return;
  5492. const flushItem = dist;
  5493. if (flushItem) {
  5494. for (const k of Object.keys(flushItem)) {
  5495. flushItem[k] = undefined
  5496. }
  5497. Object.assign(flushItem, src);
  5498. return true;
  5499. }
  5500. return false;
  5501. }
  5502. function prettyPrint(obj, indent = 2) {
  5503. const cache = new Set();
  5504.  
  5505. function stringify(obj, level = 0) {
  5506. const indentStr = ' '.repeat(level * indent);
  5507. const nextIndentStr = ' '.repeat((level + 1) * indent);
  5508.  
  5509. if (obj === null) return 'null';
  5510. if (typeof obj === 'undefined') return 'undefined';
  5511. if (typeof obj === 'string') return `"${obj}"`;
  5512. if (typeof obj === 'number' || typeof obj === 'boolean') return String(obj);
  5513. if (typeof obj === 'function') return '[[ Function ]]';
  5514. if (typeof obj !== 'object') return String(obj);
  5515.  
  5516. if (cache.has(obj)) {
  5517. return '[Circular]';
  5518. }
  5519.  
  5520. if (obj instanceof Node) {
  5521. return `[[ ${obj.constructor.name} ]]`;
  5522. }
  5523.  
  5524.  
  5525. cache.add(obj);
  5526. const entries = Object.entries(obj);
  5527.  
  5528. if (Array.isArray(obj)) {
  5529. const items = entries.map(([key, value]) => {
  5530. return `${nextIndentStr}${stringify(value, level + 1)}`;
  5531. }).join(',\n');
  5532. return `[\n${items}\n${indentStr}]`;
  5533. } else {
  5534. const items = entries.map(([key, value]) => {
  5535. return `${nextIndentStr}${key}: ${stringify(value, level + 1)}`;
  5536. }).join(',\n');
  5537. return `{\n${items}\n${indentStr}}`;
  5538. }
  5539. }
  5540.  
  5541. return stringify(obj);
  5542. }
  5543.  
  5544.  
  5545.  
  5546.  
  5547. cProto.handleLiveChatActions_ = function (a) {
  5548. // console.log(883,a) // TODO
  5549. if (a.length) {
  5550. for (const t of a) {
  5551. this.handleLiveChatAction_(t);
  5552. }
  5553. // this.maybeResizeScrollContainer_(a);
  5554. if (this.activeItems_.length > 0) this.flushActiveItems_();
  5555. // kw(function() {
  5556. // b.maybeScrollToBottom_()
  5557. // });
  5558. }
  5559. }
  5560.  
  5561. if (!cProto.handleRemoveChatItemAction72_ && typeof cProto.handleRemoveChatItemAction_ === 'function' && cProto.handleRemoveChatItemAction_.length === 1) {
  5562. cProto.handleRemoveChatItemAction72_ = cProto.handleRemoveChatItemAction_;
  5563. cProto.handleRemoveChatItemAction_ = function (a) {
  5564. const aTargetItemId = a.targetItemId;
  5565. if (!aTargetItemId) return this.handleRemoveChatItemAction72_(a)
  5566. const entries = [];
  5567. this.forEachItem_(function (tag, p, idx) {
  5568. const k = p ? firstObjectKey(p) : null;
  5569. const aObj = k ? p[k] : null;
  5570. if (aObj && aObj.id === aTargetItemId) {
  5571. entries.push([tag, idx]);
  5572. }
  5573. });
  5574. if (entries.length >= 1) {
  5575. if (entries.length > 1) console.warn('entries.length >= 1');
  5576. for (const entry of entries) {
  5577. const [tag, idx] = entry;
  5578. this.splice(tag, idx, 1);
  5579. if (tag === "visibleItems") this.resetSmoothScroll_();
  5580. }
  5581. }
  5582. }
  5583. }
  5584. if (!cProto.handleAddChatItemAction72_ && typeof cProto.handleAddChatItemAction_ === 'function' && cProto.handleAddChatItemAction_.length === 1) {
  5585.  
  5586. cProto.handleAddChatItemAction72_ = cProto.handleAddChatItemAction_;
  5587. cProto.handleAddChatItemAction_ = function (a) {
  5588.  
  5589. const sb = messageList?.solidBuild;
  5590. if (!sb || !a) return this.handleAddChatItemAction72_(...arguments);
  5591.  
  5592. let c = a ? a.item : null
  5593. , fk = c ? (firstObjectKey(c) || '') : '';
  5594. let e = fk ? c[fk] : null
  5595. , replaceExistingItem = false;
  5596.  
  5597.  
  5598. if (!e) return this.handleAddChatItemAction72_(...arguments);
  5599.  
  5600. if (a && e && a.clientId && !e.__clientId__) e.__clientId__ = a.clientId;
  5601. if (a && e && a.clientMessageId && !e.__clientMessageId__) e.__clientMessageId__ = a.clientMessageId;
  5602.  
  5603. // to be reviewed for performance issue // TODO
  5604. const aClientId = a.clientId || ''; // for user client request
  5605. const eId = e.id || ''; // for network content update
  5606. const replacementTo = []; // expected number of entries - less than or equal to 1
  5607.  
  5608. this.forEachItem_(function (tag, p, idx) {
  5609. const aObjId = (p[fk] || 0).id || undefined;
  5610. if (aObjId === aClientId || aObjId === eId) {
  5611. replacementTo.push([tag, p, idx]);
  5612. }
  5613. });
  5614.  
  5615.  
  5616. if (replacementTo.length > 0) {
  5617.  
  5618. if (replacementTo.length > 1) {
  5619. console.error('[yt-bst] replacementTo.length > 1', replacementTo.slice(0));
  5620. // replacementTo.splice(0, replacementTo.length - 1);
  5621. }
  5622.  
  5623. for (const entry of replacementTo) {
  5624. const [tag, p, idx] = entry;
  5625. // const aObj = p[fk];
  5626.  
  5627. if ("visibleItems" === tag) {
  5628.  
  5629. e.__flushDiscarded__ = false;
  5630. sb.splice(idx, 1, c);
  5631. this.resetSmoothScroll_();
  5632. replaceExistingItem = true;
  5633.  
  5634.  
  5635. // ---------- do a full replacement ----------
  5636.  
  5637. // const list = messageList.solidBuild;
  5638. // const bObj = solidBuildAt(list, idx);
  5639. // const dataMutable = (bObj ? mutableWM.get(bObj) : null) || 0;
  5640.  
  5641. // if (typeof dataMutable.bObjChange === 'function') {
  5642. // // console.log(' ===== pV ====')
  5643. // // console.dir(prettyPrint(p))
  5644. // // console.log(' ===== cV ====')
  5645. // // console.dir(prettyPrint(c))
  5646. // if (replaceObject(p, c)) {
  5647. // dataMutable.bObjChange(e, fk);
  5648. // replaceExistingItem = true; // to be added if not matched
  5649. // // console.log('replaceObject(visibleItems)', p);
  5650. // }
  5651. // }
  5652.  
  5653. // ---------- do a full replacement ----------
  5654.  
  5655. } else if (tag === "activeItems_") { // activeItems_
  5656. // console.log(' ===== pA ====')
  5657. // console.dir(prettyPrint(p))
  5658. // console.log(' ===== cA ====')
  5659. // console.dir(prettyPrint(c))
  5660.  
  5661. e.__flushDiscarded__ = false;
  5662. if (_flushed === 2) {
  5663. replaceObject(p, c);
  5664. if (typeof (p[fk] || 0) === 'object') p[fk].__flushDiscarded__ = false;
  5665. replaceExistingItem = true;
  5666. } else {
  5667. this.activeItems_.splice(tag, idx, 1, c);
  5668. replaceExistingItem = true;
  5669. }
  5670. } else {
  5671. console.warn('[yt-bst] unexpected tag in replacementTo', `tag=${tag}`);
  5672. }
  5673.  
  5674. }
  5675. replacementTo.length = 0;
  5676. }
  5677.  
  5678. const d = this.get("stickinessParams.dockAtTopDurationMs", a) || 0;
  5679. if (d) {
  5680. const k = messageList ? messageList.querySelector(`[message-id="${e.id}"]`) : null;
  5681. k ? this.maybeAddDockableMessage_(k) : (this.itemIdToDockDurationMap[e.id] = d);
  5682. }
  5683. replaceExistingItem || this.activeItems_.push(c);
  5684. };
  5685.  
  5686. }
  5687. if (!cProto.handleReplaceChatItemAction72_ && typeof cProto.handleReplaceChatItemAction_ === 'function' && cProto.handleReplaceChatItemAction_.length === 1) {
  5688. cProto.handleReplaceChatItemAction72_ = cProto.handleReplaceChatItemAction_;
  5689. cProto.handleReplaceChatItemAction_ = function (a) {
  5690. const sb = messageList?.solidBuild;
  5691. if (!sb || !a) return this.handleReplaceChatItemAction72_(...arguments);
  5692. const aTargetItemId = a ? a.targetItemId : null;
  5693. const aReplacementItem = a ? a.replacementItem : null;
  5694. if (!aTargetItemId || !aReplacementItem) return this.handleReplaceChatItemAction72_(a)
  5695. const itemKey = firstObjectKey(aReplacementItem);
  5696. const rendererItem = itemKey ? aReplacementItem[itemKey] : null;
  5697. if (!rendererItem) return this.handleReplaceChatItemAction72_(a)
  5698. const entries = [];
  5699. this.forEachItem_(function (tag, p, idx) {
  5700. const k = p ? firstObjectKey(p) : null;
  5701. const aObj = k ? p[k] : null;
  5702. if (aObj && aObj.id === aTargetItemId) {
  5703. entries.push([tag, p, idx]);
  5704. }
  5705. });
  5706. if (entries.length >= 1) {
  5707. if (entries.length > 1) console.warn('entries.length >= 1');
  5708. for (const entry of entries) {
  5709. const [tag, p, idx] = entry;
  5710. if (tag === "visibleItems") {
  5711.  
  5712. rendererItem.__flushDiscarded__ = false;
  5713. sb.splice(idx, 1, aReplacementItem);
  5714. this.resetSmoothScroll_();
  5715.  
  5716.  
  5717. // ---------- do a full replacement ----------
  5718.  
  5719. // const list = messageList.solidBuild;
  5720. // const bObj = solidBuildAt(list, idx);
  5721.  
  5722. // const dataMutable = (bObj ? mutableWM.get(bObj) : null) || 0;
  5723.  
  5724. // if (typeof dataMutable.bObjChange === 'function') {
  5725. // if (replaceObject(p, aReplacementItem)) {
  5726. // dataMutable.bObjChange(rendererItem, itemKey);
  5727. // // replaceExistingItem = true;
  5728.  
  5729. // this.resetSmoothScroll_();
  5730. // }
  5731. // }
  5732.  
  5733. // ---------- do a full replacement ----------
  5734.  
  5735. } else if (tag === "activeItems_") { // activeItems_
  5736. // this.activeItems_[idx] = aReplacementItem;
  5737.  
  5738. rendererItem.__flushDiscarded__ = false;
  5739. if (_flushed === 2) {
  5740. replaceObject(p, aReplacementItem);
  5741. if (typeof (p[itemKey] || 0) === 'object') p[itemKey].__flushDiscarded__ = false;
  5742. } else {
  5743. this.activeItems_.splice(idx, 1, aReplacementItem);
  5744. }
  5745.  
  5746. } else {
  5747. console.warn('[yt-bst] unexpected tag in entries', `tag=${tag}`);
  5748. }
  5749. }
  5750. }
  5751.  
  5752. }
  5753.  
  5754.  
  5755. }
  5756.  
  5757. /*
  5758.  
  5759. f.handleReplaceChatItemAction_ = function(a) {
  5760. var b = this
  5761. , c = a.replacementItem;
  5762. this.forEachItem_(function(d, e, g) {
  5763. var k = Object.keys(e)[0];
  5764. (e = e[k]) && e.id === a.targetItemId && (d === "visibleItems" ? (b.splice(d, g, 1, c),
  5765. b.resetSmoothScroll_()) : b.activeItems_[g] = c)
  5766. })
  5767. }
  5768.  
  5769. 399 splice Error
  5770. at Array.splice (chrome-extension://fjkkdihifokoajcdnhdhmcdpifmkgeid/YouTube%20Boost%20Chat.user.js#204:136:31)
  5771. at a.splice (https://www.youtube.com/s/desktop/a7b1ec23/jsbin/live_chat_polymer.vflset/live_chat_polymer.js:2405:190)
  5772. at e.<anonymous> (https://www.youtube.com/s/desktop/a7b1ec23/jsbin/live_chat_polymer.vflset/live_chat_polymer.js:11638:148)
  5773. at cProto.forEachItem_ (chrome-extension://fjkkdihifokoajcdnhdhmcdpifmkgeid/YouTube%20Boost%20Chat.user.js#204:3219:13)
  5774. at f.handleRemoveChatItemAction_ (https://www.youtube.com/s/desktop/a7b1ec23/jsbin/live_chat_polymer.vflset/live_chat_polymer.js:11638:59)
  5775. at f.handleLiveChatAction_ (https://www.youtube.com/s/desktop/a7b1ec23/jsbin/live_chat_polymer.vflset/live_chat_polymer.js:11627:29)
  5776. at cProto.handleLiveChatActions_ (chrome-extension://fjkkdihifokoajcdnhdhmcdpifmkgeid/YouTube%20Boost%20Chat.user.js#204:3372:16)
  5777. at https://www.youtube.com/s/desktop/a7b1ec23/jsbin/live_chat_polymer.vflset/live_chat_polymer.js:1216:63
  5778. at https://www.youtube.com/s/desktop/a7b1ec23/jsbin/live_chat_polymer.vflset/live_chat_polymer.js:3173:62
  5779. at Map.forEach (<anonymous>)
  5780.  
  5781. f.handleRemoveChatItemAction_ = function(a) {
  5782. var b = this;
  5783. this.forEachItem_(function(c, d, e) {
  5784. var g = Object.keys(d)[0];
  5785. (d = d[g]) && d.id === a.targetItemId && (b.splice(c, e, 1),
  5786. c === "visibleItems" && b.resetSmoothScroll_())
  5787. })
  5788. }
  5789.  
  5790.  
  5791. */
  5792.  
  5793. cProto.setupVisibleItemsList = function (solidBuild) {
  5794. const q = this.visibleItems;
  5795. if (q instanceof Array && !(q instanceof VisibleItemList)) {
  5796. const p = q.slice();
  5797. const r = this.visibleItems = solidBuild;
  5798. p.length >= 1 && inPlaceArrayPush(r, p);
  5799. p.length = 0;
  5800. q.length = 0;
  5801. }
  5802. this.bstVisibleItemList = solidBuild;
  5803. const listControllerWR = mWeakRef(this);
  5804. const visibleItems_ = this.visibleItems;
  5805. if (visibleItems_ instanceof VisibleItemList && visibleItems_ === solidBuild) {
  5806. chkVisibleItemList = () => {
  5807. visibleItems_.checkIntegrity(listControllerWR);
  5808. }
  5809. }
  5810. }
  5811. cProto.bstClearCount = 0;
  5812. cProto.clearList = function () {
  5813. _flushed = 0;
  5814. this.bstClearCount = (this.bstClearCount & 1073741823) + 1;
  5815. const activeItems_ = this.activeItems_;
  5816. if (activeItems_) activeItems_.length = 0;
  5817. // this.setupVisibleItemsList();
  5818. const visibleItems = this.visibleItems;
  5819. if (visibleItems && (visibleItems.length > 0)) {
  5820. visibleItems.length = 0;
  5821. if (messageList) {
  5822. messageList.classList.remove('bst-listloaded');
  5823. const solidBuild = messageList.solidBuild;
  5824. solidBuild.setLength(0);
  5825. }
  5826. }
  5827. if (!activeItems_.length && !visibleItems.length) {
  5828. // condition check for just in case
  5829. this.setAtBottomTrue();
  5830. }
  5831. this.dockableMessages = [];
  5832. this.isSmoothed_ = !0;
  5833. this.lastSmoothChatMessageAddMs_ = null;
  5834. this.chatRateMs_ = 1E3;
  5835. this.lastSmoothScrollClockTime_ = this.lastSmoothScrollUpdate_ = null;
  5836. this.scrollTimeRemainingMs_ = this.scrollPixelsRemaining_ = 0;
  5837. this.smoothScrollRafHandle_ = null;
  5838. this.preinsertHeight_ = 0;
  5839. this.itemIdToDockDurationMap = {};
  5840. this.$['docked-messages'].clear();
  5841. this.bannerManager.reset();
  5842. // this.maybeResizeScrollContainer_([]);
  5843. // this.items.style.transform = "";
  5844. // this.atBottom || this.scrollToBottom_()
  5845. }
  5846.  
  5847. /*
  5848. cProto.clearList = function() {
  5849. window.cancelAnimationFrame(this.scrollClampRaf || 0);
  5850. // lw(this.scrollStopHandle || 0);
  5851. window.cancelAnimationFrame(this.asyncHandle || 0);
  5852. this.items = [];
  5853. this.asyncHandle = null;
  5854. this.shouldAnimateIn = !1;
  5855. this.scrollClampRaf = this.lastFrameTimestamp = null;
  5856. this.scrollStartTime = this.scrollRatePixelsPerSecond = 0;
  5857. this.scrollStopHandle = null
  5858. }
  5859. */
  5860.  
  5861. /*
  5862.  
  5863. onScroll: function() {
  5864. var a = Date.now();
  5865. 50 > a - this.lastHandledScroll_ || (this.lastHandledScroll_ = a,
  5866. this.markDirty())
  5867. },
  5868.  
  5869. // no need
  5870.  
  5871. */
  5872.  
  5873.  
  5874. cProto.onScrollItems_ = function (a) {
  5875.  
  5876. // console.log('onScrollItems_', 583, )
  5877. this.ytRendererBehavior.onScroll(a);
  5878. // this.setAtBottom();
  5879. // this.flushActiveItems_();
  5880. }
  5881. cProto.__notRequired__ = (cProto.__notRequired__ || 0) | 512;
  5882.  
  5883. let qcz9 = 0;
  5884. cProto.scrollToBottom_ = function () {
  5885. // console.log(1882)
  5886.  
  5887. const pcz = qcz9 = (qcz9 & 1073741823) + 1;
  5888. flushPE(async () => {
  5889. if (pcz !== qcz9) return;
  5890. resetSelection();
  5891. scrollToEnd();
  5892. this.setAtBottomTrue();
  5893. flushPEHoldingUntil = Date.now() + 200;
  5894. if (flushPEHoldingMaxTimelineResolve < 1) flushPEHoldingMaxTimelineResolve = 1;
  5895. });
  5896.  
  5897. // this.itemScroller.scrollTop = Math.pow(2, 24);
  5898. // this.atBottom = !0
  5899. }
  5900.  
  5901. cProto.showNewItems_ = function (...args) {
  5902.  
  5903. console.log('[yt-bst] showNewItems_', 583, ...args)
  5904.  
  5905. }
  5906.  
  5907. cProto.refreshOffsetContainerHeight_ = function () {
  5908.  
  5909. console.log('[yt-bst] refreshOffsetContainerHeight_', 583, ...args)
  5910. }
  5911.  
  5912. cProto.maybeResizeScrollContainer_ = function (...args) {
  5913.  
  5914.  
  5915. console.log('[yt-bst] maybeResizeScrollContainer_', 583, ...args)
  5916. }
  5917.  
  5918.  
  5919. /*
  5920.  
  5921. this.push.apply(this, this.activeItems_)
  5922.  
  5923. // c = visibleItems
  5924.  
  5925. a=Array of ... [pending visibleItems]
  5926.  
  5927. // g = this.visibleItems
  5928.  
  5929.  
  5930. a.prototype.push = function(c) {
  5931. var d = Ta.apply(1, arguments)
  5932. , e = {
  5933. path: ""
  5934. }
  5935. , g = lu(this, c, e)
  5936. , k = g.length
  5937. , m = g.push.apply(g, la(d));
  5938. d.length && pu(this, g, e.path, k, d.length, []);
  5939. return m
  5940. }
  5941.  
  5942. */
  5943.  
  5944.  
  5945. function getUID(aObj) {
  5946. return `${aObj.authorExternalChannelId || `${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`}:${aObj.timestampUsec || 0}`
  5947. }
  5948. convertAObj = (aObj, aKey) => {
  5949.  
  5950. if(!aObj || aObj.uid) {
  5951. console.warn('convertAObj warning')
  5952. }
  5953.  
  5954. aObj.uid = aObj.uid || createMemo(() => {
  5955. return getUID(R(aObj));
  5956. })
  5957.  
  5958. if (aKey && typeof aKey === 'string') W(aObj).aKey = aKey;
  5959.  
  5960. const memo_ = MEMO(aObj);
  5961.  
  5962. const rendererFlag = memo_?.rendererFlag || MEMO(aObj, 'rendererFlag', ()=>{
  5963. if(R(aObj).aKey === "liveChatSponsorshipsGiftPurchaseAnnouncementRenderer") return 1;
  5964. return 0;
  5965. });
  5966.  
  5967. memo_?.authorName || MEMO(aObj, 'authorName', () => {
  5968. const dx = R(aObj) && rendererFlag() === 1 ? aObj.header?.liveChatSponsorshipsHeaderRenderer : aObj
  5969. return convertYTtext(dx.authorName);
  5970. });
  5971. aObj.getProfilePic = getProfilePic;
  5972. aObj.getStickerURL = getStickerURL;
  5973. aObj.bst = bst;
  5974.  
  5975. if(!memo_?.messageXM){
  5976.  
  5977. const messageXT = createMemo(()=>{
  5978. const data = R(aObj);
  5979. const m1 = rendererFlag() === 1 ? data.header?.liveChatSponsorshipsHeaderRenderer?.primaryText : data.message;
  5980. return messageFlatten(m1);
  5981. })
  5982. MEMO(aObj, 'messageXM', () =>{
  5983. const str = messageXT();
  5984. return messageUnflatten(str);
  5985. })
  5986.  
  5987. }
  5988.  
  5989.  
  5990.  
  5991. }
  5992.  
  5993. let nyhaDPr = null;
  5994. const nyhaDId = `nyhaD${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
  5995. const nyhaDPost = window.postMessage.bind(window, nyhaDId);
  5996. window.addEventListener('message', (evt) => {
  5997. if ((evt || 0).data === nyhaDId) {
  5998. const t = nyhaDPr;
  5999. if (t !== null) {
  6000. nyhaDPr = null;
  6001. t.resolve();
  6002. }
  6003. }
  6004. });
  6005. timelineResolve = async () => {
  6006. let t = nyhaDPr;
  6007. if (t === null) {
  6008. t = nyhaDPr = new PromiseExternal();
  6009. nyhaDPost();
  6010. }
  6011. await t.then();
  6012. }
  6013.  
  6014.  
  6015.  
  6016. const menuMenuCache = new Map();
  6017.  
  6018. const preShowMenu = function (messageEntry_) {
  6019.  
  6020.  
  6021. const messageEntry = messageEntry_ || this;
  6022. const messageUid = (messageEntry.getAttribute('message-uid') || '');
  6023. if (messageUid) {
  6024.  
  6025.  
  6026. const resT = menuMenuCache.get(messageUid);
  6027.  
  6028.  
  6029. if (resT) return resT;
  6030.  
  6031. const resPR = new Promise(resolve => {
  6032.  
  6033.  
  6034. const cnt = insp(wliveChatTextMessageRenderer);
  6035. cnt.showContextMenu.call({
  6036. data: {
  6037. contextMenuEndpoint: messageEntry.polymerController.dataRaw.contextMenuEndpoint
  6038. },
  6039. isAttached: true,
  6040. is: cnt.is,
  6041. __showContextMenu_forceNativeRequest__: true,
  6042. showContextMenu37: cnt.showContextMenu37,
  6043. showContextMenu47: cnt.showContextMenu47,
  6044. showContextMenu47_: cnt.showContextMenu47_,
  6045. showContextMenu_: cnt.showContextMenu_,
  6046. showContextMenu: cnt.showContextMenu,
  6047.  
  6048. handleGetContextMenuResponse_: function (a) {
  6049. a.isSuccess = true;
  6050. menuMenuCache.set(messageUid, a);
  6051. resolve(a);
  6052. },
  6053. handleGetContextMenuError: function (a) {
  6054.  
  6055. a.isFailure = true;
  6056. menuMenuCache.set(messageUid, a);
  6057. resolve(a);
  6058.  
  6059. }
  6060. }, undefined);
  6061.  
  6062.  
  6063.  
  6064. });
  6065. menuMenuCache.set(messageUid, resPR);
  6066.  
  6067. return resPR;
  6068.  
  6069.  
  6070.  
  6071. }
  6072. return null;
  6073. }
  6074.  
  6075. showMenu = function (messageEntry_) {
  6076. const messageEntry = messageEntry_ || this;
  6077. const messageUid = (messageEntry.getAttribute('message-uid') || '');
  6078. if (messageUid) {
  6079.  
  6080. if (menuRenderObj.messageUid === messageUid) return;
  6081. entryHoldingChange(messageUid);
  6082. Object.assign(W(menuRenderObj),{
  6083. menuListXp: '',
  6084. messageUid: messageUid,
  6085. loading: true,
  6086. });
  6087.  
  6088. const callback = (a) => {
  6089.  
  6090. if (a && a.isSuccess) {
  6091.  
  6092. let menuRenderer = null;
  6093. if (a && typeof a === 'object') {
  6094. for (const [key, value] of Object.entries(a)) {
  6095. if (typeof (value || 0) === 'object' && value.menuRenderer) {
  6096. menuRenderer = value.menuRenderer;
  6097. break;
  6098. }
  6099. }
  6100. }
  6101.  
  6102.  
  6103. const items = menuRenderer ? menuRenderer.items : null; // no login -> no items; only {openImmediately: true, trackingParams: XXXX}
  6104. if (items) {
  6105.  
  6106. Object.assign(W(menuRenderObj),{
  6107. menuListXp: menuRenderObj.menuListXd.update(items.slice(0)),
  6108. messageUid: messageUid,
  6109. loading: false,
  6110. });
  6111. } else {
  6112.  
  6113. Object.assign(W(menuRenderObj),{
  6114. menuListXp: '',
  6115. messageUid: '',
  6116. loading: false,
  6117. });
  6118. if (entryHolding()) {
  6119. entryHoldingChange('');
  6120. }
  6121.  
  6122. }
  6123.  
  6124.  
  6125.  
  6126.  
  6127. } else {
  6128.  
  6129. Object.assign(W(menuRenderObj),{
  6130. menuListXp: '',
  6131. messageUid: '',
  6132. loading: false,
  6133. // error: 1
  6134. });
  6135. if (entryHolding()) {
  6136. entryHoldingChange('');
  6137. }
  6138. }
  6139.  
  6140.  
  6141. }
  6142.  
  6143. const resA = preShowMenu(messageEntry);
  6144. if (resA && typeof resA.then === 'function') {
  6145. resA.then(callback);
  6146. } else if (resA) {
  6147. callback(resA);
  6148. }
  6149.  
  6150. }
  6151. }
  6152.  
  6153. const [lastFpError, lastFpErrorSet] = createSignal(false);
  6154. createEffect(() => {
  6155. const b = lastFpError();
  6156. messageList?.classList?.toggle('bst-message-list-issue', b);
  6157. });
  6158.  
  6159.  
  6160. const freqMap = new Map(); // for temp use.
  6161. // const isOverflowAnchorSupported = CSS.supports("overflow-anchor", "auto") && CSS.supports("overflow-anchor", "none");
  6162. cProto.flushActiveItems37_ = cProto.flushActiveItems_;
  6163. cProto.flushActiveItems_ = function () {
  6164. const bstClearCount0 = this.bstClearCount;
  6165. const items = (this.$ || 0).items;
  6166. const hostElement = this.hostElement;
  6167. if (!(items instanceof Element)) return;
  6168. if (!wAttachRoot.has(hostElement)) {
  6169. this.setupBoostChat();
  6170. const thisData = this.data;
  6171. if (thisData.maxItemsToDisplay > 0) thisData.maxItemsToDisplay = MAX_ITEMS_FOR_TOTAL_DISPLAY;
  6172. }
  6173.  
  6174. if (!messageList) return;
  6175. if (DEBUG_windowVars) window.__bstFlush01__ = Date.now();
  6176.  
  6177.  
  6178. const generatePFC = () => {
  6179.  
  6180. freqMap.clear();
  6181.  
  6182. const visibleItems = this.visibleItems;
  6183.  
  6184. const fp = new Array(visibleItems.length);
  6185. let fpI = 0;
  6186.  
  6187. const pp = visibleItems.map(e => {
  6188. if (!e) return null;
  6189. if (typeof e === 'object') e = Object.values(e)[0] || 0;
  6190. const r = e.id || null;
  6191. if (typeof r === 'string') {
  6192. fp[fpI++] = r;
  6193. freqMap.set(r, freqMap.has(r) ? false : true);
  6194. }
  6195. return r;
  6196. }); // e.id (non-empty) or null
  6197.  
  6198. fp.length = fpI;
  6199.  
  6200. const cp = new Array(fpI);
  6201. let cpI = 0;
  6202. for (const [key, isUnique] of freqMap.entries()) {
  6203. if (isUnique) {
  6204. cp[cpI++] = key;
  6205. }
  6206. }
  6207. cp.length = cpI;
  6208.  
  6209. return { pp, fp, cp };
  6210.  
  6211. }
  6212.  
  6213. // if(this.hostElement.querySelectorAll('*').length > 40) return;
  6214. flushPE(async () => {
  6215. // let cd = 0;
  6216.  
  6217. while (flushPEHoldingUntil > 0 && flushPEHoldingMaxTimelineResolve-- > 0 && flushPEHoldingUntil > Date.now()) {
  6218. await timelineResolve(); // avoid rendering time warning in Chrome
  6219. // console.log(9593, ++cd);
  6220. }
  6221. // cd = 0;
  6222. flushPEHoldingMaxTimelineResolve = 0;
  6223. flushPEHoldingUntil = 0;
  6224.  
  6225. if (bstClearCount0 !== this.bstClearCount) return;
  6226.  
  6227. chkVisibleItemList();
  6228.  
  6229. let tmpError = false;
  6230.  
  6231. // while (noFlushTP) {
  6232. // mouseActionP = mouseActionP || new PromiseExternal();
  6233. // await mouseActionP.then();
  6234. // }
  6235.  
  6236. // add activeItems_ to visibleItems
  6237.  
  6238. // activeItems_ -> clear -> add to visibleItems
  6239.  
  6240.  
  6241. if (DEBUG_windowVars) window.__bstFlush02__ = Date.now();
  6242. const activeItems_ = this.activeItems_;
  6243. const _addLen = activeItems_.length;
  6244. // console.log(55, _addLen)
  6245. if (_addLen === 0) return;
  6246. // if(this.visibleItemsCount > 40) return;
  6247.  
  6248. const maxItemsToDisplay = this.data.maxItemsToDisplay;
  6249.  
  6250. if (!this.canScrollToBottom_()) {
  6251. _addLen > maxItemsToDisplay * 2 && activeItems_.splice(0, _addLen - maxItemsToDisplay)
  6252. return;
  6253. }
  6254.  
  6255. if (_addLen > maxItemsToDisplay) {
  6256. const visibleItems = this.visibleItems;
  6257. if (visibleItems && (visibleItems.length > 0)) {
  6258. visibleItems.length = 0;
  6259. if (messageList) {
  6260. const solidBuild = messageList.solidBuild;
  6261. solidBuild.setLength(0);
  6262. }
  6263. }
  6264. activeItems_.splice(0, _addLen - maxItemsToDisplay);
  6265. }
  6266.  
  6267. if (DEBUG_windowVars) window.__bstFlush03__ = Date.now();
  6268.  
  6269.  
  6270. {
  6271.  
  6272.  
  6273. const { pp, fp, cp } = generatePFC();
  6274. if (pp.length !== fp.length || fp.length !== cp.length || pp.length !== cp.length) {
  6275.  
  6276. console.log(`[yt-bst] flushItems; length mismatched (01); pp=${pp.length}, fp=${fp.length}, cp=${cp.length}`);
  6277. lastFpErrorSet(true);
  6278. tmpError = true;
  6279.  
  6280. // stuck in here. cannot flush more items
  6281. } else {
  6282.  
  6283. lastFpErrorSet(tmpError);
  6284. }
  6285.  
  6286. }
  6287.  
  6288. await Promise.resolve();
  6289.  
  6290. if (bstClearCount0 !== this.bstClearCount) return;
  6291. if (this.isAttached !== true) return;
  6292. if (activeItems_.length === 0) return;
  6293.  
  6294.  
  6295. const removeFromActiveItems = (flushItem) => {
  6296. if (activeItems_.length > 0) {
  6297. const index = activeItems_.indexOf(flushItem);
  6298. if (index > -1) {
  6299. if (index >= 1) {
  6300. activeItems_.splice(index, 1);
  6301. } else {
  6302. activeItems_.shift();
  6303. }
  6304. return true;
  6305. }
  6306. }
  6307. return false;
  6308. }
  6309.  
  6310.  
  6311. _flushed = 2;
  6312.  
  6313. const solidBuild = messageList.solidBuild;
  6314.  
  6315. let existingSet = new Set();
  6316. for (const entry of this.visibleItems) {
  6317. let k = entry ? firstObjectKey(entry) : null;
  6318. let p = k ? entry[k] : null;
  6319. p && p.id && existingSet.add(p.id);
  6320. }
  6321.  
  6322. let withFlushDiscarded = 0;
  6323.  
  6324. let rearrangedW = activeItems_.map(flushItem => {
  6325.  
  6326. const aKey = flushItem ? firstObjectKey(flushItem) : null;
  6327. const aObj = aKey ? flushItem[aKey] : null;
  6328. if (!aObj || aObj.__flushDiscarded__) return null;
  6329.  
  6330. const id = aObj.id
  6331. const uid = getUID(aObj);
  6332. if (existingSet.has(id)) {
  6333. aObj.__flushDiscarded__ = true;
  6334. withFlushDiscarded++;
  6335. return {
  6336. flushItem,
  6337. aKey, aObj, uid,
  6338. alreadyExist: true
  6339. };
  6340. }
  6341. existingSet.add(id);
  6342.  
  6343. return {
  6344. flushItem,
  6345. aKey, aObj, uid,
  6346. alreadyExist: false
  6347. };
  6348.  
  6349. });
  6350. existingSet.clear();
  6351. existingSet = null;
  6352.  
  6353. if (withFlushDiscarded > 0) {
  6354. for (let i = rearrangedW.length; i--;) {
  6355. const entry = rearrangedW[i];
  6356. if (!entry || entry.alreadyExist !== true) continue;
  6357. if (entry.flushItem === activeItems_[i]) {
  6358. activeItems_.splice(i, 1);
  6359. withFlushDiscarded--;
  6360. if (!withFlushDiscarded) break;
  6361. }
  6362. }
  6363. }
  6364.  
  6365. rearrangedW = rearrangedW.filter(e => e && e.alreadyExist === false);
  6366.  
  6367. const nd = rearrangedW.length;
  6368. if (nd === 0) return;
  6369.  
  6370.  
  6371. const visibleItems = this.visibleItems;
  6372. let wasEmpty = false;
  6373. // let needScrollToEnd = false;
  6374. if (visibleItems.length === 0) {
  6375. // needScrollToEnd = true;
  6376. wasEmpty = true;
  6377. }
  6378.  
  6379. // ---- ticker row appearance ----
  6380. // ensure atBottom keeps as true
  6381. // - example https://www.youtube.com/watch?v=18tiVN9sxMc&t=14m15s -> 14m21s
  6382. // - example https://www.youtube.com/watch?v=czgZWwziG9Y&t=48m5s -> 48m12s
  6383. // ---- ticker row appearance ----
  6384.  
  6385.  
  6386.  
  6387. let awaitTime = 0;
  6388.  
  6389. // console.log('[yt-bst] XX', '000000')
  6390. bottomKeepAtSet(Date.now() + 86400000);
  6391. if (DEBUG_windowVars) window.__bstFlush04__ = Date.now();
  6392. let mg = 0;
  6393. rcKt = (rcKt & 1073741823) + 1;
  6394. rcValue = rcSignal();
  6395. const t1 = performance.now();
  6396. let a2 = t1;
  6397. let b2 = 0;
  6398. for (let rJ = 0; rJ < nd; rJ++) {
  6399. if (bstClearCount0 !== this.bstClearCount || this.isAttached !== true) {
  6400. break;
  6401. }
  6402.  
  6403. rcSignalAdd(1);
  6404. const entry = rearrangedW[rJ];
  6405. {
  6406. const {
  6407. flushItem, // flushItem is object so it content can be replaced since rearrangedW
  6408. aKey, aObj, uid
  6409. } = entry;
  6410. const n = solidBuild.getLength() - maxItemsToDisplay + 1;
  6411. if (n >= 1) {
  6412. if (n > 1) {
  6413. visibleItems.splice(0, n);
  6414. } else {
  6415. visibleItems.shift();
  6416. }
  6417. }
  6418. removeFromActiveItems(flushItem);
  6419. mfChange(uid);
  6420. visibleItems.push(flushItem);
  6421. }
  6422.  
  6423. const c2 = performance.now();
  6424. // console.log('[yt-bst] XX', c2, mg, rcSignal(), rcValue )
  6425. b2++;
  6426. if ((c2 - a2) * (b2 + 1) - 14 * b2 > 0) { // // (c2-a2)*((b2+1)/b2)>14
  6427. await timelineResolve();
  6428. const t = performance.now();
  6429. awaitTime += Math.round(t - c2);
  6430. a2 = t;
  6431. b2 = 0;
  6432. mg++;
  6433. // console.log('[yt-bst] YY', t, mg)
  6434. } else {
  6435. await Promise.resolve();
  6436. }
  6437. }
  6438. rearrangedW.length = 0;
  6439. rearrangedW = null;
  6440.  
  6441. // console.log('[yt-bst] XX', '111111')
  6442. const rcPromise_ = rcPromise = new PromiseExternal();
  6443. // rcSignalAdd(1);
  6444. rcValue++;
  6445. await timelineResolve();
  6446. rcSignalAdd(0);
  6447. await rcPromise_.then(); // deadlock cleared by setInterval
  6448. if (rcPromise_ === rcPromise) rcPromise = null;
  6449. if (rcSignal() !== rcValue) {
  6450. console.log('[yt-bst] ERROR 0xFE01 - rcValue mismatched', rcValue, rcSignal());
  6451. rcKt = (rcKt & 1073741823) + 1;
  6452. rcSignalSet(rcValue);
  6453. }
  6454. rcKt = (rcKt & 1073741823) + 1;
  6455. resetSelection();
  6456. if (wasEmpty) messageList.classList.add('bst-listloaded');
  6457.  
  6458. if (DO_scrollIntoViewIfNeeded) {
  6459. _messageOverflowAnchor && _messageOverflowAnchor.scrollIntoViewIfNeeded();
  6460. await timelineResolve(); // play safe
  6461. } else {
  6462. await Promise.resolve();
  6463. }
  6464. _flushed = 1;
  6465.  
  6466. if (DEBUG_windowVars) window.__bstFlush05__ = Date.now();
  6467.  
  6468. const t2 = performance.now();
  6469.  
  6470. if (LOGTIME_FLUSHITEMS && t2 - t1 > 100) {
  6471. const T = Math.round(t2 - t1);
  6472. const t = T - awaitTime;
  6473. console.log(`[yt-bst] flushItems; n=${nd}; t=${T}-${awaitTime}=${t}; mg=${mg}`);
  6474. }
  6475.  
  6476. {
  6477.  
  6478.  
  6479. const { pp, fp, cp } = generatePFC();
  6480. if (pp.length !== fp.length || fp.length !== cp.length || pp.length !== cp.length) {
  6481.  
  6482. console.log(`[yt-bst] flushItems; length mismatched (02); pp=${pp.length}, fp=${fp.length}, cp=${cp.length}`);
  6483. lastFpErrorSet(true);
  6484. tmpError = true;
  6485. } else {
  6486. lastFpErrorSet(tmpError);
  6487. }
  6488.  
  6489. }
  6490.  
  6491. if (DEBUG_windowVars) window.__bstFlush06__ = Date.now();
  6492.  
  6493.  
  6494. bottomKeepAtSet(Date.now());
  6495.  
  6496.  
  6497. });
  6498.  
  6499.  
  6500. }
  6501.  
  6502.  
  6503. });
  6504.  
  6505. })();