// ==UserScript== // @name Flow Youtube Chat // @version 1.15.8 // @description Youtubeのチャットをニコニコ風に画面上へ流す(再アップ) Make youtube chats move in danmaku-style. // @match https://www.youtube.com/* // @namespace FlowYoutubeChatScript // @run-at document-end // @grant GM.setValue // @grant GM.getValue // @grant GM.deleteValue // @grant GM.listValues // @grant GM.setClipboard // @noframes // @license AGPL-3.0-or-later // @require https://cdn.jsdelivr.net/npm/sweetalert2@11.0.18/dist/sweetalert2.all.min.js#sha384-EoPspU1QiQ0II6WaHKy5pERCBPBD1VqZByJ29O7fDUJxGXwWLyEREDpvym8c4v2S // @require https://unpkg.com/loglevel@1.7.0/dist/loglevel.min.js#sha384-7gGuWfek8Ql6j/uNDFrS0BCe4x2ZihD4B68w9Eu580OVHJBV+bl3rZmEWC7q5/Gj // @require https://unpkg.com/rxjs@7.3.0/dist/bundles/rxjs.umd.min.js#sha384-B2HMABdZA26zJ9QwbG/c5zrcdr6+Zs8J4MgKs7udycjXgvRDA5nZKLzJ1vXWzJyH // @require https://unpkg.com/mithril@2.0.4/mithril.min.js#sha384-vo9crXih40MlEv6JWHqS7SsPiFp+76csaWQFOF2UU0/xI58Jm/ZvK/1UtpaicJT9 // @require https://cdn.jsdelivr.net/npm/check-types@11.1.2/src/check-types.min.js#sha384-KGnImnhVjA5llfqKEbjBiY+1Mp6oa+NvW/TEY1XTPAKWNgrAwa3Qvn//MXL07wBM // @require https://cdn.jsdelivr.net/npm/deep-diff@1.0.2/index.min.js#sha384-Q/uiWfFlwn9XjOpL49VpFKn01EkScmaC3hh1prAn7S++WoZgXRrrjQvZ7cI7C7Zn // @require https://cdn.jsdelivr.net/npm/astring@1.7.5/dist/astring.min.js#sha384-mGnfE+xZkK7mo04MqU0t7DI1ZTFZSKwfPNjrLFeibz94N4lJgdHXh5+kI6rf5x10 // @require https://cdn.jsdelivr.net/npm/jsep@0.4.0/build/jsep.min.js#sha384-89PRdfFVlT2bC9VxvLdvlByyVGml9l14DjpPqZYVI9umfvV24KPZ5dY6qBOeKf2z // @require https://cdn.jsdelivr.net/npm/hash-it@5.0.2/dist/hash-it.min.js#sha384-biRMep0zr/5fw/hIdnBIb56UHRgiIyhAagZrngd9dSxxQ9aDFMP0hbYR8PEj5lVu // @require https://cdn.jsdelivr.net/npm/micro-memoize@4.0.9/dist/micro-memoize.min.js#sha384-aGxbSIH2oMTKxZ93i+/iQKx5xefR8mHJW3mkbRaiSZizVoCvKS6wzndlLeQzMv9B // @downloadURL none // ==/UserScript== /* jshint esversion: 6 */ ;(() => { var __webpack_modules__ = { 142: ( __unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__ ) => { "use strict" const external_log_namespaceObject = log var external_log_default = __webpack_require__.n( external_log_namespaceObject ) const lib = observer => value => { observer.next(value) } function sleep(time) { time || (time = 0) return new Promise(function (res) { return setTimeout(res, time) }) } function randomToken() { return Math.random().toString(36).substring(2) } var lastMs = 0, additional = 0 function microSeconds() { var ms = new Date().getTime() if (ms === lastMs) return 1e3 * ms + ++additional lastMs = ms additional = 0 return 1e3 * ms } var isNode = "[object process]" === Object.prototype.toString.call( "undefined" != typeof process ? process : 0 ) const methods_native = { create: function (channelName) { var state = { messagesCallback: null, bc: new BroadcastChannel(channelName), subFns: [], } state.bc.onmessage = function (msg) { state.messagesCallback && state.messagesCallback(msg.data) } return state }, close: function (channelState) { channelState.bc.close() channelState.subFns = [] }, onMessage: function (channelState, fn) { channelState.messagesCallback = fn }, postMessage: function (channelState, messageJson) { try { channelState.bc.postMessage(messageJson, !1) return Promise.resolve() } catch (err) { return Promise.reject(err) } }, canBeUsed: function () { if (isNode && "undefined" == typeof window) return !1 if ("function" == typeof BroadcastChannel) { if (BroadcastChannel._pubkey) throw new Error( "BroadcastChannel: Do not overwrite window.BroadcastChannel with this module, this is not a polyfill" ) return !0 } return !1 }, type: "native", averageResponseTime: function () { return 150 }, microSeconds, } var ObliviousSet = (function () { function ObliviousSet(ttl) { this.ttl = ttl this.set = new Set() this.timeMap = new Map() } ObliviousSet.prototype.has = function (value) { return this.set.has(value) } ObliviousSet.prototype.add = function (value) { var _this = this this.timeMap.set(value, now()) this.set.add(value) setTimeout(function () { !(function (obliviousSet) { for ( var olderThen = now() - obliviousSet.ttl, iterator = obliviousSet.set[Symbol.iterator](); ; ) { var value = iterator.next().value if (!value) return if (!(obliviousSet.timeMap.get(value) < olderThen)) return obliviousSet.timeMap.delete(value) obliviousSet.set.delete(value) } })(_this) }, 0) } ObliviousSet.prototype.clear = function () { this.set.clear() this.timeMap.clear() } return ObliviousSet })() function now() { return new Date().getTime() } function options_fillOptionsWithDefaults() { var originalOptions = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, options = JSON.parse(JSON.stringify(originalOptions)) void 0 === options.webWorkerSupport && (options.webWorkerSupport = !0) options.idb || (options.idb = {}) options.idb.ttl || (options.idb.ttl = 45e3) options.idb.fallbackInterval || (options.idb.fallbackInterval = 150) originalOptions.idb && "function" == typeof originalOptions.idb.onclose && (options.idb.onclose = originalOptions.idb.onclose) options.localstorage || (options.localstorage = {}) options.localstorage.removeTimeout || (options.localstorage.removeTimeout = 6e4) originalOptions.methods && (options.methods = originalOptions.methods) options.node || (options.node = {}) options.node.ttl || (options.node.ttl = 12e4) void 0 === options.node.useFastPath && (options.node.useFastPath = !0) return options } function getIdb() { if ("undefined" != typeof indexedDB) return indexedDB if ("undefined" != typeof window) { if (void 0 !== window.mozIndexedDB) return window.mozIndexedDB if (void 0 !== window.webkitIndexedDB) return window.webkitIndexedDB if (void 0 !== window.msIndexedDB) return window.msIndexedDB } return !1 } function _readLoop(state) { state.closed || readNewMessages(state) .then(function () { return sleep(state.options.idb.fallbackInterval) }) .then(function () { return _readLoop(state) }) } function readNewMessages(state) { return state.closed ? Promise.resolve() : state.messagesCallback ? ((db = state.db), (lastCursorId = state.lastCursorId), (objectStore = db .transaction("messages") .objectStore("messages")), (ret = []), new Promise(function (res) { ;(function () { try { var keyRangeValue = IDBKeyRange.bound( lastCursorId + 1, 1 / 0 ) return objectStore.openCursor(keyRangeValue) } catch (e) { return objectStore.openCursor() } })().onsuccess = function (ev) { var cursor = ev.target.result if (cursor) if (cursor.value.id < lastCursorId + 1) cursor.continue(lastCursorId + 1) else { ret.push(cursor.value) cursor.continue() } else res(ret) } })).then(function (newerMessages) { newerMessages .filter(function (msgObj) { return !!msgObj }) .map(function (msgObj) { msgObj.id > state.lastCursorId && (state.lastCursorId = msgObj.id) return msgObj }) .filter(function (msgObj) { return (function (msgObj, state) { return !( msgObj.uuid === state.uuid || state.eMIs.has(msgObj.id) || msgObj.data.time < state.messagesCallbackTime ) })(msgObj, state) }) .sort(function (msgObjA, msgObjB) { return msgObjA.time - msgObjB.time }) .forEach(function (msgObj) { if (state.messagesCallback) { state.eMIs.add(msgObj.id) state.messagesCallback(msgObj.data) } }) return Promise.resolve() }) : Promise.resolve() var db, lastCursorId, objectStore, ret } const indexed_db = { create: function (channelName, options) { options = options_fillOptionsWithDefaults(options) return (function (channelName) { var dbName = "pubkey.broadcast-channel-0-" + channelName, openRequest = getIdb().open(dbName, 1) openRequest.onupgradeneeded = function (ev) { ev.target.result.createObjectStore("messages", { keyPath: "id", autoIncrement: !0, }) } return new Promise(function (res, rej) { openRequest.onerror = function (ev) { return rej(ev) } openRequest.onsuccess = function () { res(openRequest.result) } }) })(channelName).then(function (db) { var state = { closed: !1, lastCursorId: 0, channelName, options, uuid: randomToken(), eMIs: new ObliviousSet(2 * options.idb.ttl), writeBlockPromise: Promise.resolve(), messagesCallback: null, readQueuePromises: [], db, } db.onclose = function () { state.closed = !0 options.idb.onclose && options.idb.onclose() } _readLoop(state) return state }) }, close: function (channelState) { channelState.closed = !0 channelState.db.close() }, onMessage: function (channelState, fn, time) { channelState.messagesCallbackTime = time channelState.messagesCallback = fn readNewMessages(channelState) }, postMessage: function (channelState, messageJson) { channelState.writeBlockPromise = channelState.writeBlockPromise .then(function () { return (function (db, readerUuid, messageJson) { var writeObject = { uuid: readerUuid, time: new Date().getTime(), data: messageJson, }, transaction = db.transaction(["messages"], "readwrite") return new Promise(function (res, rej) { transaction.oncomplete = function () { return res() } transaction.onerror = function (ev) { return rej(ev) } transaction.objectStore("messages").add(writeObject) }) })(channelState.db, channelState.uuid, messageJson) }) .then(function () { 0 === Math.floor(11 * Math.random() + 0) && ((db = channelState.db), (ttl = channelState.options.idb.ttl), (function (db, ttl) { var olderThen = new Date().getTime() - ttl, objectStore = db .transaction("messages") .objectStore("messages"), ret = [] return new Promise(function (res) { objectStore.openCursor().onsuccess = function (ev) { var cursor = ev.target.result if (cursor) { var msgObk = cursor.value if (!(msgObk.time < olderThen)) { res(ret) return } ret.push(msgObk) cursor.continue() } else res(ret) } }) })(db, ttl).then(function (tooOld) { return Promise.all( tooOld.map(function (msgObj) { return (function (db, id) { var request = db .transaction(["messages"], "readwrite") .objectStore("messages") .delete(id) return new Promise(function (res) { request.onsuccess = function () { return res() } }) })(db, msgObj.id) }) ) })) var db, ttl }) return channelState.writeBlockPromise }, canBeUsed: function () { return !isNode && !!getIdb() }, type: "idb", averageResponseTime: function (options) { return 2 * options.idb.fallbackInterval }, microSeconds, } function getLocalStorage() { var localStorage if ("undefined" == typeof window) return null try { localStorage = window.localStorage localStorage = window["ie8-eventlistener/storage"] || window.localStorage } catch (e) {} return localStorage } function storageKey(channelName) { return "pubkey.broadcastChannel-" + channelName } function localstorage_canBeUsed() { if (isNode) return !1 var ls = getLocalStorage() if (!ls) return !1 try { var key = "__broadcastchannel_check" ls.setItem(key, "works") ls.removeItem(key) } catch (e) { return !1 } return !0 } const localstorage = { create: function (channelName, options) { options = options_fillOptionsWithDefaults(options) if (!localstorage_canBeUsed()) throw new Error("BroadcastChannel: localstorage cannot be used") var uuid = randomToken(), eMIs = new ObliviousSet(options.localstorage.removeTimeout), state = { channelName, uuid, eMIs } state.listener = (function (channelName, fn) { var key = storageKey(channelName), listener = function (ev) { ev.key === key && (function (msgObj) { if ( state.messagesCallback && msgObj.uuid !== uuid && msgObj.token && !eMIs.has(msgObj.token) && !( msgObj.data.time && msgObj.data.time < state.messagesCallbackTime ) ) { eMIs.add(msgObj.token) state.messagesCallback(msgObj.data) } })(JSON.parse(ev.newValue)) } window.addEventListener("storage", listener) return listener })(channelName) return state }, close: function (channelState) { ;(listener = channelState.listener), window.removeEventListener("storage", listener) var listener }, onMessage: function (channelState, fn, time) { channelState.messagesCallbackTime = time channelState.messagesCallback = fn }, postMessage: function (channelState, messageJson) { return new Promise(function (res) { sleep().then(function () { var key = storageKey(channelState.channelName), writeObj = { token: randomToken(), time: new Date().getTime(), data: messageJson, uuid: channelState.uuid, }, value = JSON.stringify(writeObj) getLocalStorage().setItem(key, value) var ev = document.createEvent("Event") ev.initEvent("storage", !0, !0) ev.key = key ev.newValue = value window.dispatchEvent(ev) res() }) }) }, canBeUsed: localstorage_canBeUsed, type: "localstorage", averageResponseTime: function () { var userAgent = navigator.userAgent.toLowerCase() return userAgent.includes("safari") && !userAgent.includes("chrome") ? 240 : 120 }, microSeconds, } var simulate_microSeconds = microSeconds, SIMULATE_CHANNELS = new Set() const simulate = { create: function (channelName) { var state = { name: channelName, messagesCallback: null } SIMULATE_CHANNELS.add(state) return state }, close: function (channelState) { SIMULATE_CHANNELS.delete(channelState) }, onMessage: function (channelState, fn) { channelState.messagesCallback = fn }, postMessage: function (channelState, messageJson) { return new Promise(function (res) { return setTimeout(function () { Array.from(SIMULATE_CHANNELS) .filter(function (channel) { return channel.name === channelState.name }) .filter(function (channel) { return channel !== channelState }) .filter(function (channel) { return !!channel.messagesCallback }) .forEach(function (channel) { return channel.messagesCallback(messageJson) }) res() }, 5) }) }, canBeUsed: function () { return !0 }, type: "simulate", averageResponseTime: function () { return 5 }, microSeconds: simulate_microSeconds, } var METHODS = [methods_native, indexed_db, localstorage] if (isNode) { var NodeMethod = __webpack_require__(633) "function" == typeof NodeMethod.canBeUsed && METHODS.push(NodeMethod) } var broadcast_channel_BroadcastChannel = function (name, options) { this.name = name this.options = options_fillOptionsWithDefaults(options) this.method = (function (options) { var chooseMethods = [] .concat(options.methods, METHODS) .filter(Boolean) if (options.type) { if ("simulate" === options.type) return simulate var ret = chooseMethods.find(function (m) { return m.type === options.type }) if (ret) return ret throw new Error("method-type " + options.type + " not found") } options.webWorkerSupport || isNode || (chooseMethods = chooseMethods.filter(function (m) { return "idb" !== m.type })) var useMethod = chooseMethods.find(function (method) { return method.canBeUsed() }) if (useMethod) return useMethod throw new Error( "No useable methode found:" + JSON.stringify( METHODS.map(function (m) { return m.type }) ) ) })(this.options) this._iL = !1 this._onML = null this._addEL = { message: [], internal: [] } this._uMP = new Set() this._befC = [] this._prepP = null !(function (channel) { var obj, maybePromise = channel.method.create( channel.name, channel.options ) if ((obj = maybePromise) && "function" == typeof obj.then) { channel._prepP = maybePromise maybePromise.then(function (s) { channel._state = s }) } else channel._state = maybePromise })(this) } broadcast_channel_BroadcastChannel._pubkey = !0 broadcast_channel_BroadcastChannel.prototype = { postMessage: function (msg) { if (this.closed) throw new Error( "BroadcastChannel.postMessage(): Cannot post message after channel has closed" ) return _post(this, "message", msg) }, postInternal: function (msg) { return _post(this, "internal", msg) }, set onmessage(fn) { var listenObj = { time: this.method.microSeconds(), fn } _removeListenerObject(this, "message", this._onML) if (fn && "function" == typeof fn) { this._onML = listenObj _addListenerObject(this, "message", listenObj) } else this._onML = null }, addEventListener: function (type, fn) { _addListenerObject(this, type, { time: this.method.microSeconds(), fn, }) }, removeEventListener: function (type, fn) { _removeListenerObject( this, type, this._addEL[type].find(function (obj) { return obj.fn === fn }) ) }, close: function () { var _this = this if (!this.closed) { this.closed = !0 var awaitPrepare = this._prepP ? this._prepP : Promise.resolve() this._onML = null this._addEL.message = [] return awaitPrepare .then(function () { return Promise.all(Array.from(_this._uMP)) }) .then(function () { return Promise.all( _this._befC.map(function (fn) { return fn() }) ) }) .then(function () { return _this.method.close(_this._state) }) } }, get type() { return this.method.type }, get isClosed() { return this.closed }, } function _post(broadcastChannel, type, msg) { var msgObj = { time: broadcastChannel.method.microSeconds(), type, data: msg, } return ( broadcastChannel._prepP ? broadcastChannel._prepP : Promise.resolve() ).then(function () { var sendPromise = broadcastChannel.method.postMessage( broadcastChannel._state, msgObj ) broadcastChannel._uMP.add(sendPromise) sendPromise.catch().then(function () { return broadcastChannel._uMP.delete(sendPromise) }) return sendPromise }) } function _hasMessageListeners(channel) { return ( channel._addEL.message.length > 0 || channel._addEL.internal.length > 0 ) } function _addListenerObject(channel, type, obj) { channel._addEL[type].push(obj) !(function (channel) { if (!channel._iL && _hasMessageListeners(channel)) { var listenerFn = function (msgObj) { channel._addEL[msgObj.type].forEach(function (obj) { msgObj.time >= obj.time && obj.fn(msgObj.data) }) }, time = channel.method.microSeconds() if (channel._prepP) channel._prepP.then(function () { channel._iL = !0 channel.method.onMessage(channel._state, listenerFn, time) }) else { channel._iL = !0 channel.method.onMessage(channel._state, listenerFn, time) } } })(channel) } function _removeListenerObject(channel, type, obj) { channel._addEL[type] = channel._addEL[type].filter(function (o) { return o !== obj }) !(function (channel) { if (channel._iL && !_hasMessageListeners(channel)) { channel._iL = !1 var time = channel.method.microSeconds() channel.method.onMessage(channel._state, null, time) } })(channel) } const external_DeepDiff_namespaceObject = DeepDiff function function_identity(a) { return a } function constant(a) { return function () { return a } } var constTrue = constant(!0), constFalse = constant(!1), constUndefined = constant(void 0) function function_flow(ab, bc, cd, de, ef, fg, gh, hi, ij) { switch (arguments.length) { case 1: return ab case 2: return function () { return bc(ab.apply(this, arguments)) } case 3: return function () { return cd(bc(ab.apply(this, arguments))) } case 4: return function () { return de(cd(bc(ab.apply(this, arguments)))) } case 5: return function () { return ef(de(cd(bc(ab.apply(this, arguments))))) } case 6: return function () { return fg(ef(de(cd(bc(ab.apply(this, arguments)))))) } case 7: return function () { return gh(fg(ef(de(cd(bc(ab.apply(this, arguments))))))) } case 8: return function () { return hi(gh(fg(ef(de(cd(bc(ab.apply(this, arguments)))))))) } case 9: return function () { return ij(hi(gh(fg(ef(de(cd(bc(ab.apply(this, arguments))))))))) } } } function function_pipe(a, ab, bc, cd, de, ef, fg, gh, hi) { switch (arguments.length) { case 1: return a case 2: return ab(a) case 3: return bc(ab(a)) case 4: return cd(bc(ab(a))) case 5: return de(cd(bc(ab(a)))) case 6: return ef(de(cd(bc(ab(a))))) case 7: return fg(ef(de(cd(bc(ab(a)))))) case 8: return gh(fg(ef(de(cd(bc(ab(a))))))) case 9: return hi(gh(fg(ef(de(cd(bc(ab(a)))))))) default: for (var ret = arguments[0], i = 1; i < arguments.length; i++) ret = arguments[i](ret) return ret } } var isSome = function (fa) { return "Some" === fa._tag }, none = { _tag: "None" }, some = function (a) { return { _tag: "Some", value: a } }, isNonEmpty = function (as) { return as.length > 0 }, head = function (as) { return as[0] }, emptyReadonlyArray = [], Predicate_not = (Object.prototype.hasOwnProperty, function (predicate) { return function (a) { return !predicate(a) } }), Separated_separated = function (left, right) { return { left, right } } function Witherable_wiltDefault(T, C) { return function (F) { var traverseF = T.traverse(F) return function (wa, f) { return F.map(traverseF(wa, f), C.separate) } } } function Witherable_witherDefault(T, C) { return function (F) { var traverseF = T.traverse(F) return function (wa, f) { return F.map(traverseF(wa, f), C.compact) } } } var Option_none = none, Option_some = some function fromPredicate(predicate) { return function (a) { return predicate(a) ? Option_some(a) : Option_none } } var getLeft = function (ma) { return "Right" === ma._tag ? Option_none : Option_some(ma.left) }, getRight = function (ma) { return "Left" === ma._tag ? Option_none : Option_some(ma.right) }, Option_map = function (fa, f) { return function_pipe(fa, es6_Option_map(f)) }, _ap = function (fab, fa) { return function_pipe(fab, ap(fa)) }, _reduce = function (fa, b, f) { return function_pipe(fa, reduce(b, f)) }, _foldMap = function (M) { var foldMapM = foldMap(M) return function (fa, f) { return function_pipe(fa, foldMapM(f)) } }, _reduceRight = function (fa, b, f) { return function_pipe(fa, reduceRight(b, f)) }, _traverse = function (F) { var traverseF = traverse(F) return function (ta, f) { return function_pipe(ta, traverseF(f)) } }, _filter = function (fa, predicate) { return function_pipe(fa, filter(predicate)) }, es6_Option_map = function (f) { return function (fa) { return Option_isNone(fa) ? Option_none : Option_some(f(fa.value)) } }, Option_Functor = { URI: "Option", map: Option_map }, of = Option_some, ap = function (fa) { return function (fab) { return Option_isNone(fab) || Option_isNone(fa) ? Option_none : Option_some(fab.value(fa.value)) } }, Apply = { URI: "Option", map: Option_map, ap: _ap }, chain = function (f) { return function (ma) { return Option_isNone(ma) ? Option_none : f(ma.value) } }, reduce = function (b, f) { return function (fa) { return Option_isNone(fa) ? b : f(b, fa.value) } }, foldMap = function (M) { return function (f) { return function (fa) { return Option_isNone(fa) ? M.empty : f(fa.value) } } }, reduceRight = function (b, f) { return function (fa) { return Option_isNone(fa) ? b : f(fa.value, b) } }, alt = function (that) { return function (fa) { return Option_isNone(fa) ? that() : fa } }, extend = function (f) { return function (wa) { return Option_isNone(wa) ? Option_none : Option_some(f(wa)) } }, compact = chain(function_identity), defaultSeparated = Separated_separated(Option_none, Option_none), separate = function (ma) { return Option_isNone(ma) ? defaultSeparated : Separated_separated(getLeft(ma.value), getRight(ma.value)) }, Compactable = { URI: "Option", compact, separate }, filter = function (predicate) { return function (fa) { return Option_isNone(fa) ? Option_none : predicate(fa.value) ? fa : Option_none } }, filterMap = function (f) { return function (fa) { return Option_isNone(fa) ? Option_none : f(fa.value) } }, partition = function (predicate) { return function (fa) { return Separated_separated( _filter(fa, Predicate_not(predicate)), _filter(fa, predicate) ) } }, partitionMap = function (f) { return function_flow(es6_Option_map(f), separate) }, traverse = function (F) { return function (f) { return function (ta) { return Option_isNone(ta) ? F.of(Option_none) : F.map(f(ta.value), Option_some) } } }, sequence = function (F) { return function (ta) { return Option_isNone(ta) ? F.of(Option_none) : F.map(ta.value, Option_some) } }, Traversable = { URI: "Option", map: Option_map, reduce: _reduce, foldMap: _foldMap, reduceRight: _reduceRight, traverse: _traverse, sequence, }, _wither = Witherable_witherDefault(Traversable, Compactable), _wilt = Witherable_wiltDefault(Traversable, Compactable), Option_isSome = isSome, Option_isNone = function (fa) { return "None" === fa._tag }, match = function (onNone, onSome) { return function (ma) { return Option_isNone(ma) ? onNone() : onSome(ma.value) } }, getOrElseW = function (onNone) { return function (ma) { return Option_isNone(ma) ? onNone() : ma.value } }, getOrElse = getOrElseW, fromNullable = function (a) { return null == a ? Option_none : Option_some(a) }, chainNullableK = function (f) { return function (ma) { return Option_isNone(ma) ? Option_none : fromNullable(f(ma.value)) } }, toUndefined = match(constUndefined, function_identity), Option_option = { URI: "Option", map: Option_map, of, ap: _ap, chain: function (ma, f) { return function_pipe(ma, chain(f)) }, reduce: _reduce, foldMap: _foldMap, reduceRight: _reduceRight, traverse: _traverse, sequence, zero: function () { return Option_none }, alt: function (fa, that) { return function_pipe(fa, alt(that)) }, extend: function (wa, f) { return function_pipe(wa, extend(f)) }, compact, separate, filter: _filter, filterMap: function (fa, f) { return function_pipe(fa, filterMap(f)) }, partition: function (fa, predicate) { return function_pipe(fa, partition(predicate)) }, partitionMap: function (fa, f) { return function_pipe(fa, partitionMap(f)) }, wither: _wither, wilt: _wilt, throwError: function () { return Option_none }, } function Apply_apSecond(A) { return function (second) { return function (first) { return A.ap( A.map(first, function () { return function (b) { return b } }), second ) } } } function Apply_apS(F) { return function (name, fb) { return function (fa) { return F.ap( F.map(fa, function (a) { return function (b) { var _a return Object.assign({}, a, (((_a = {})[name] = b), _a)) } }), fb ) } } } function Functor_map(F, G) { return function (f) { return function (fa) { return F.map(fa, function (ga) { return G.map(ga, f) }) } } } function Functor_bindTo(F) { return function (name) { return function (fa) { return F.map(fa, function (a) { var _a return ((_a = {})[name] = a), _a }) } } } function OptionT_some(F) { return function_flow(Option_some, F.of) } function OptionT_zero(F) { return constant(F.of(Option_none)) } function Compactable_compact(F, G) { return function (fga) { return F.map(fga, G.compact) } } function Filterable_filter(F, G) { return function (predicate) { return function (fga) { return F.map(fga, function (ga) { return G.filter(ga, predicate) }) } } } function Filterable_filterMap(F, G) { return function (f) { return function (fga) { return F.map(fga, function (ga) { return G.filterMap(ga, f) }) } } } function Chain_chainFirst(M) { return function (f) { return function (first) { return M.chain(first, function (a) { return M.map(f(a), function () { return a }) }) } } } function Chain_bind(M) { return function (name, f) { return function (ma) { return M.chain(ma, function (a) { return M.map(f(a), function (b) { var _a return Object.assign({}, a, (((_a = {})[name] = b), _a)) }) }) } } } var M, apM, mapM, chainM, altM, foldM, getOrElseM, zeroM, IO_map = function (ma, f) { return function () { return f(ma()) } }, IO_ap = function (mab, ma) { return function () { return mab()(ma()) } }, IO_chain = function (ma, f) { return function () { return f(ma())() } }, es6_IO_map = function (f) { return function (fa) { return IO_map(fa, f) } }, IO_of = constant, es6_IO_chain = function (f) { return function (ma) { return IO_chain(ma, f) } }, IO_Functor = { URI: "IO", map: IO_map }, IO_Apply = { URI: "IO", map: IO_map, ap: IO_ap }, IO_apSecond = Apply_apSecond(IO_Apply), IO_Chain = { URI: "IO", map: IO_map, ap: IO_ap, chain: IO_chain }, IO_chainFirst = Chain_chainFirst(IO_Chain), fromIO = function_identity, IO_bindTo = Functor_bindTo(IO_Functor), IO_bind = Chain_bind(IO_Chain), IO_apS = Apply_apS(IO_Apply), IO_ApT = IO_of(emptyReadonlyArray), IO_sequenceArray = (function (f) { return (function (f) { var g = (function (f) { return function (as) { return function () { for ( var out = [f(0, head(as))()], i = 1; i < as.length; i++ ) out.push(f(i, as[i])()) return out } } })(f) return function (as) { return isNonEmpty(as) ? g(as) : IO_ApT } })(function (_, a) { return f(a) }) })(function_identity), IO_io = { URI: "IO", map: IO_map, of: IO_of, ap: IO_ap, chain: IO_chain, fromIO, chainRec: function (a, f) { return function () { for (var e = f(a)(); "Left" === e._tag; ) e = f(e.left)() return e.right } }, }, __assign = function () { return (__assign = Object.assign || function (t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i] for (var p in s) Object.prototype.hasOwnProperty.call(s, p) && (t[p] = s[p]) } return t }).apply(this, arguments) }, T = ((apM = (function (F) { return (function (F, G) { return function (fa) { return function (fab) { return F.ap( F.map(fab, function (gab) { return function (ga) { return G.ap(gab, ga) } }), fa ) } } })(F, Apply) })((M = IO_io))), (mapM = (function (F) { return Functor_map(F, Option_Functor) })(M)), (chainM = (function (M) { var zeroM = OptionT_zero(M) return function (f) { return function (ma) { return M.chain( ma, match(function () { return zeroM() }, f) ) } } })(M)), (altM = (function (M) { var _some = OptionT_some(M) return function (second) { return function (first) { return M.chain(first, match(second, _some)) } } })(M)), (foldM = (function (M) { return function (onNone, onSome) { return function (ma) { return M.chain(ma, match(onNone, onSome)) } } })(M)), (getOrElseM = (function (M) { return function (onNone) { return function (fa) { return M.chain(fa, match(onNone, M.of)) } } })(M)), (zeroM = OptionT_zero(M)), { map: function (fa, f) { return function_pipe(fa, mapM(f)) }, ap: function (fab, fa) { return function_pipe(fab, apM(fa)) }, of: OptionT_some(M), chain: function (ma, f) { return function_pipe(ma, chainM(f)) }, alt: function (fa, that) { return function_pipe(fa, altM(that)) }, fold: function (fa, onNone, onSome) { return function_pipe(fa, foldM(onNone, onSome)) }, getOrElse: function (fa, onNone) { return function_pipe(fa, getOrElseM(onNone)) }, fromM: (function (F) { return function (ma) { return F.map(ma, Option_some) } })(M), none: function () { return zeroM() }, }), F = (function (F, G) { var map = (function (F, G) { var _map = Functor_map(F, G) return { map: function (fga, f) { return function_pipe(fga, _map(f)) }, } })(F, G).map, _compact = Compactable_compact(F, G), _separate = (function (F, C, G) { var _compact = Compactable_compact(F, C), _map = Functor_map(F, G) return function (fge) { return Separated_separated( _compact(function_pipe(fge, _map(getLeft))), _compact(function_pipe(fge, _map(getRight))) ) } })(F, G, G), _filter = Filterable_filter(F, G), _filterMap = Filterable_filterMap(F, G), _partition = (function (F, G) { var _filter = Filterable_filter(F, G) return function (predicate) { var left = _filter(Predicate_not(predicate)), right = _filter(predicate) return function (fgb) { return Separated_separated(left(fgb), right(fgb)) } } })(F, G), _partitionMap = (function (F, G) { var _filterMap = Filterable_filterMap(F, G) return function (f) { return function (fga) { return Separated_separated( function_pipe( fga, _filterMap(function (a) { return getLeft(f(a)) }) ), function_pipe( fga, _filterMap(function (a) { return getRight(f(a)) }) ) ) } } })(F, G) return { map, compact: _compact, separate: _separate, filter: function (fga, f) { return function_pipe(fga, _filter(f)) }, filterMap: function (fga, f) { return function_pipe(fga, _filterMap(f)) }, partition: function (fga, p) { return function_pipe(fga, _partition(p)) }, partitionMap: function (fga, f) { return function_pipe(fga, _partitionMap(f)) }, } })(IO_io, Option_option), IOOption_some = (T.none(), T.of), IOOption_fromIO = T.fromM, fromOption = IO_of, IOOption_map = function (f) { return function (fa) { return T.map(fa, f) } }, IOOption_chain = function (f) { return function (ma) { return T.chain(ma, f) } }, IOOption_chainFirst = function (f) { return function (ma) { return T.chain(ma, function (a) { return T.map(f(a), function () { return a }) }) } }, IOOption_filter = (F.compact, F.separate, function (predicate) { return function (fa) { return F.filter(fa, predicate) } }), eqStrict = (T.map, T.map, T.ap, T.map, T.ap, T.map, T.ap, T.chain, T.map, T.alt, T.map, T.ap, T.alt, T.map, F.filter, F.filterMap, F.partition, F.partitionMap, __assign( { URI: "IOOption", of: IOOption_some, ap: T.ap, chain: T.chain, alt: T.alt, fromIO: IOOption_fromIO, }, F ), { equals: function (a, b) { return a === b }, }), es6_Reader_map = function (f) { return function (fa) { return function (r) { return f(fa(r)) } } }, Reader_ApT = constant(emptyReadonlyArray), Reader_sequenceArray = (function (f) { return (function (f) { var g = (function (f) { return function (as) { return function (r) { for ( var out = [f(0, head(as))(r)], i = 1; i < as.length; i++ ) out.push(f(i, as[i])(r)) return out } } })(f) return function (as) { return isNonEmpty(as) ? g(as) : Reader_ApT } })(function (_, a) { return f(a) }) })(function_identity), ReadonlyNonEmptyArray_spreadArray = function (to, from) { for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) to[j] = from[i] return to }, ReadonlyNonEmptyArray_empty = emptyReadonlyArray, ReadonlyNonEmptyArray_isNonEmpty = isNonEmpty, ReadonlyNonEmptyArray_head = head, ReadonlyNonEmptyArray_tail = function (as) { return as.slice(1) }, ReadonlyArray_isNonEmpty = ReadonlyNonEmptyArray_isNonEmpty, ReadonlyArray_append = function (end) { return function (init) { return ReadonlyNonEmptyArray_spreadArray( ReadonlyNonEmptyArray_spreadArray([], init), [end] ) } }, ReadonlyArray_makeBy = function (n, f) { return n <= 0 ? ReadonlyArray_empty : (function (f) { return function (n) { for ( var j = Math.max(0, Math.floor(n)), out = [f(0)], i = 1; i < j; i++ ) out.push(f(i)) return out } })(f)(n) }, ReadonlyArray_isOutOfBound = function (i, as) { return i < 0 || i >= as.length }, findIndex = function (predicate) { return function (as) { for (var i = 0; i < as.length; i++) if (predicate(as[i])) return some(i) return none } }, ReadonlyArray_reverse = function (as) { return as.length <= 1 ? as : as.slice().reverse() }, ReadonlyArray_map = function (fa, f) { return function_pipe(fa, es6_ReadonlyArray_map(f)) }, ReadonlyArray_reduce = function (fa, b, f) { return function_pipe(fa, es6_ReadonlyArray_reduce(b, f)) }, ReadonlyArray_zero = function () { return ReadonlyArray_empty }, es6_ReadonlyArray_map = function (f) { return function (fa) { return fa.map(function (a) { return f(a) }) } }, es6_ReadonlyArray_mapWithIndex = function (f) { return function (fa) { return fa.map(function (a, i) { return f(i, a) }) } }, es6_ReadonlyArray_filter = function (predicate) { return function (as) { return as.filter(predicate) } }, ReadonlyArray_compact = (function (f) { return (function (f) { return function (fa) { for (var out = [], i = 0; i < fa.length; i++) { var optionB = f(i, fa[i]) isSome(optionB) && out.push(optionB.value) } return out } })(function (_, a) { return f(a) }) })(function_identity), es6_ReadonlyArray_reduce = function (b, f) { return es6_ReadonlyArray_reduceWithIndex(b, function (_, b, a) { return f(b, a) }) }, es6_ReadonlyArray_foldMap = function (M) { var foldMapWithIndexM = (function (M) { return function (f) { return function (fa) { return fa.reduce(function (b, a, i) { return M.concat(b, f(i, a)) }, M.empty) } } })(M) return function (f) { return foldMapWithIndexM(function (_, a) { return f(a) }) } }, es6_ReadonlyArray_reduceWithIndex = function (b, f) { return function (fa) { for (var len = fa.length, out = b, i = 0; i < len; i++) out = f(i, out, fa[i]) return out } }, es6_ReadonlyArray_reduceRight = function (b, f) { return es6_ReadonlyArray_reduceRightWithIndex( b, function (_, a, b) { return f(a, b) } ) }, es6_ReadonlyArray_reduceRightWithIndex = function (b, f) { return function (fa) { return fa.reduceRight(function (b, a, i) { return f(i, a, b) }, b) } }, es6_ReadonlyArray_traverse = function (F) { var traverseWithIndexF = es6_ReadonlyArray_traverseWithIndex(F) return function (f) { return traverseWithIndexF(function (_, a) { return f(a) }) } }, es6_ReadonlyArray_traverseWithIndex = function (F) { return function (f) { return es6_ReadonlyArray_reduceWithIndex( F.of(ReadonlyArray_zero()), function (i, fbs, a) { return F.ap( F.map(fbs, function (bs) { return function (b) { return function_pipe(bs, ReadonlyArray_append(b)) } }), f(i, a) ) } ) } }, ReadonlyArray_Functor = { URI: "ReadonlyArray", map: ReadonlyArray_map, }, ReadonlyArray_Compactable = { URI: "ReadonlyArray", compact: ReadonlyArray_compact, separate: function (fa) { for ( var left = [], right = [], _i = 0, fa_1 = fa; _i < fa_1.length; _i++ ) { var e = fa_1[_i] "Left" === e._tag ? left.push(e.left) : right.push(e.right) } return Separated_separated(left, right) }, }, ReadonlyArray_Traversable = { URI: "ReadonlyArray", map: ReadonlyArray_map, reduce: ReadonlyArray_reduce, foldMap: function (M) { var foldMapM = es6_ReadonlyArray_foldMap(M) return function (fa, f) { return function_pipe(fa, foldMapM(f)) } }, reduceRight: function (fa, b, f) { return function_pipe(fa, es6_ReadonlyArray_reduceRight(b, f)) }, traverse: function (F) { var traverseF = es6_ReadonlyArray_traverse(F) return function (ta, f) { return function_pipe(ta, traverseF(f)) } }, sequence: function (F) { return function (ta) { return ReadonlyArray_reduce( ta, F.of(ReadonlyArray_zero()), function (fas, fa) { return F.ap( F.map(fas, function (as) { return function (a) { return function_pipe(as, ReadonlyArray_append(a)) } }), fa ) } ) } }, }, toArray = (Witherable_witherDefault( ReadonlyArray_Traversable, ReadonlyArray_Compactable ), Witherable_wiltDefault( ReadonlyArray_Traversable, ReadonlyArray_Compactable ), function (as) { return as.slice() }), ReadonlyArray_empty = ReadonlyNonEmptyArray_empty, ReadonlyArray_bindTo = Functor_bindTo(ReadonlyArray_Functor) function chainFirstIOK(F, M) { var chainFirstM = Chain_chainFirst(M) return function (f) { return chainFirstM(function_flow(f, F.fromIO)) } } var Task_fromIO = function (ma) { return function () { return Promise.resolve().then(ma) } }, Task_map = function (fa, f) { return function_pipe(fa, es6_Task_map(f)) }, _apPar = function (fab, fa) { return function_pipe(fab, Task_ap(fa)) }, es6_Task_map = function (f) { return function (fa) { return function () { return Promise.resolve().then(fa).then(f) } } }, Task_ap = function (fa) { return function (fab) { return function () { return Promise.all([ Promise.resolve().then(fab), Promise.resolve().then(fa), ]).then(function (_a) { return (0, _a[0])(_a[1]) }) } } }, Task_of = function (a) { return function () { return Promise.resolve(a) } }, es6_Task_chain = function (f) { return function (ma) { return function () { return Promise.resolve() .then(ma) .then(function (a) { return f(a)() }) } } }, Task_Functor = { URI: "Task", map: Task_map }, ApplyPar = { URI: "Task", map: Task_map, ap: _apPar }, Task_Chain = { URI: "Task", map: Task_map, ap: _apPar, chain: function (ma, f) { return function_pipe(ma, es6_Task_chain(f)) }, }, Task_chainFirstIOK = chainFirstIOK( { URI: "Task", fromIO: Task_fromIO }, Task_Chain ), Task_bindTo = Functor_bindTo(Task_Functor), Task_bind = Chain_bind(Task_Chain), Task_apS = Apply_apS(ApplyPar) const external_rxjs_namespaceObject = rxjs, appendLog = log => ([a, ...b]) => function_pipe( [...log, `${a}${b.length > 0 ? ": " : ""}${b.join(", ")}`], x => (x.length > 1e3 ? x.slice(0, 100) : x) ), consoleLog = (...[a, ...b]) => function_pipe( () => external_log_default().info( ...("string" == typeof a ? [`【FYC】 ${a}`] : ["【FYC】", a]) ), IO_apSecond( b.length > 0 ? () => external_log_default().info(...b) : () => {} ) ), createChatScreen = () => { const element = document.createElement("div") element.style.pointerEvents = "none" element.style.zIndex = "30" element.style.position = "absolute" element.style.overflow = "hidden" element.style.height = "100%" element.style.width = "100%" return element }, external_jsep_namespaceObject = jsep var external_jsep_default = __webpack_require__.n( external_jsep_namespaceObject ), u = { "||": function (r, e) { return r || e }, "&&": function (r, e) { return r && e }, "|": function (r, e) { return r | e }, "^": function (r, e) { return r ^ e }, "&": function (r, e) { return r & e }, "==": function (r, e) { return r == e }, "!=": function (r, e) { return r != e }, "===": function (r, e) { return r === e }, "!==": function (r, e) { return r !== e }, "<": function (r, e) { return r < e }, ">": function (r, e) { return r > e }, "<=": function (r, e) { return r <= e }, ">=": function (r, e) { return r >= e }, "<<": function (r, e) { return r << e }, ">>": function (r, e) { return r >> e }, ">>>": function (r, e) { return r >>> e }, "+": function (r, e) { return r + e }, "-": function (r, e) { return r - e }, "*": function (r, e) { return r * e }, "/": function (r, e) { return r / e }, "%": function (r, e) { return r % e }, }, i = { "-": function (r) { return -r }, "+": function (r) { return +r }, "~": function (r) { return ~r }, "!": function (r) { return !r }, } function s(r, e) { return r.map(function (r) { return a(r, e) }) } function c(r, e) { var n, t = a(r.object, e) if ( ((n = r.computed ? a(r.property, e) : r.property.name), /^__proto__|prototype|constructor$/.test(n)) ) throw Error('Access to member "' + n + '" disallowed.') return [t, t[n]] } function a(r, e) { var n = r switch (n.type) { case "ArrayExpression": return s(n.elements, e) case "BinaryExpression": return u[n.operator](a(n.left, e), a(n.right, e)) case "CallExpression": var t, o, l if ( ("MemberExpression" === n.callee.type ? ((t = (l = c(n.callee, e))[0]), (o = l[1])) : (o = a(n.callee, e)), "function" != typeof o) ) return return o.apply(t, s(n.arguments, e)) case "ConditionalExpression": return a(n.test, e) ? a(n.consequent, e) : a(n.alternate, e) case "Identifier": return e[n.name] case "Literal": return n.value case "LogicalExpression": return "||" === n.operator ? a(n.left, e) || a(n.right, e) : "&&" === n.operator ? a(n.left, e) && a(n.right, e) : u[n.operator](a(n.left, e), a(n.right, e)) case "MemberExpression": return c(n, e)[1] case "ThisExpression": return e case "UnaryExpression": return i[n.operator](a(n.argument, e)) default: return } } var Eq = { equals: function (first, second) { return first === second }, }, string_isEmpty = function (s) { return 0 === s.length }, split = function (separator) { return function (s) { var out = s.split(separator) return ReadonlyNonEmptyArray_isNonEmpty(out) ? out : [s] } } const fycKey = key => `FYC_${key}`, stringsArgs = [ [], function_flow( split(/\r\n|\n/), es6_ReadonlyArray_filter(Predicate_not(string_isEmpty)) ), x => x.join("\n"), ], sc = (k, d) => (async (key, defaultVal) => ({ gmKey: key, val: (await GM.getValue(key)) ?? defaultVal, defaultVal, toGm: function_identity, }))(fycKey(k), d), ic = (k, d, i, g) => (async (key, defaultVal, toItem, toGm) => { const val = await GM.getValue(key) return { gmKey: key, val: void 0 !== val ? toItem(val) : defaultVal, defaultVal, toGm, } })(fycKey(k), d, i, g), defaultUserConfig = async () => ({ lang: await sc("LANG", "FYC_EN"), font: await sc("FONT", "MS PGothic"), chatOpacity: await sc("OPACITY", 0.8), color: await sc("COLOR", "#ffffff"), ownerColor: await sc("COLOR_OWNER", "#ffd600"), moderatorColor: await sc("COLOR_MODERATOR", "#c564ff"), memberColor: await sc("COLOR_MEMBER", "#9fffff"), fontSize: await sc("SIZE", 1), fontWeight: await sc("WEIGHT", 730), shadowFontWeight: await sc("WEIGHT_SHADOW", 1), maxChatCount: await sc("LIMIT", 40), flowSpeed: await sc("SPEED", 18), maxChatLength: await sc("MAX", 100), laneCount: await sc("LANE_DIV", 12), bannedWords: await ic("NG_WORDS", ...stringsArgs), bannedWordRegexs: await ic("NG_REG_WORDS", ...stringsArgs), bannedUsers: await ic("NG_USERS", ...stringsArgs), createChats: await sc("TOGGLE_CREATE_COMMENTS", !0), noOverlap: await sc("NO_OVERLAP", !0), createBanButton: await sc("NG_BUTTON", !0), simplifyChatField: await sc("SIMPLE_CHAT_FIELD", !1), displayModName: await sc("DISPLAY_MODERATOR_NAME", !0), displaySuperChatAuthor: await sc("DISPLAY_SUPER_CHAT_AUTHOR", !0), textOnly: await sc("TEXT_ONLY", !1), timingFunction: await sc("TIMING_FUNCTION", "linear"), displayChats: await sc("DISPLAY_COMMENTS", !0), minSpacing: await sc("MIN_SPACING", 0.5), fieldScale: await sc("FIELD_SCALE", 1), flowY1: await sc("flowY1", 0), flowY2: await sc("flowY2", 1), flowX1: await sc("flowX1", 0), flowX2: await sc("flowX2", 1), shadowColor: await sc("shadowColor", "#000000"), }), chatApp = () => function_pipe( fromNullable(document.querySelector("#chatframe")), filter(x => { const state = x.contentDocument?.readyState return "loading" === state || "complete" === state }), chainNullableK(x => x.contentDocument), alt(() => Option_some(document)), chainNullableK(x => x.querySelector("yt-live-chat-app")) ), livePageYt = () => ({ toggleChatBtnParent: () => fromNullable(document.querySelector(".ytp-right-controls")), settingNextElement: () => fromNullable( document.querySelector( "#menu-container .dropdown-trigger.ytd-menu-renderer" ) ), player: () => fromNullable(document.querySelector("#movie_player")), video: () => fromNullable( document.querySelector("video.video-stream.html5-main-video") ), chatField: () => function_pipe( chatApp(), chainNullableK(x => x.querySelector("#items.yt-live-chat-item-list-renderer") ) ), chatTicker: () => function_pipe( chatApp(), chainNullableK(x => x.querySelector("#items.yt-live-chat-ticker-renderer") ) ), chatScroller: () => function_pipe( chatApp(), chainNullableK(x => x.querySelector( "#item-scroller.yt-live-chat-item-list-renderer" ) ) ), offlineSlate: () => fromNullable(document.querySelector(".ytp-offline-slate")), }), mainCss = () => { const element = document.createElement("style") element.innerHTML = ".fyc_chat {\n line-height: 1;\n z-index: 30;\n position: absolute;\n user-select: none;\n white-space: nowrap;\n will-change: transform;\n }\n .fyc_button {\n display: inline-block;\n border-style: none;\n z-index: 4;\n font-weight: 500;\n color: var(--yt-spec-text-secondary);\n }" return element }, observePair = con => function_pipe( () => new external_rxjs_namespaceObject.Subject(), IO_bindTo("subject"), IO_bind("observer", x => () => new con(lib(x.subject))) ), external_Swal_namespaceObject = Swal var external_Swal_default = __webpack_require__.n( external_Swal_namespaceObject ) const addBanButton_button = document.createElement("button") addBanButton_button.classList.add( "style-scope", "yt-icon-button", "fyc_button" ) Object.assign(addBanButton_button.style, { padding: "0px", width: "20px", height: "20px", fill: "#fff", }) addBanButton_button.setAttribute( "aria-label", "NGに入れる(Ban this user)" ) addBanButton_button.innerHTML = '' const addBanButton = (chat, id, getConfig, setConfig) => chat.children.namedItem("card") ? () => {} : () => { const clone = addBanButton_button.cloneNode(!0) clone.onclick = function_pipe( getConfig.bannedUsers, IOOption_fromIO, IOOption_filter(x => !x.includes(id)), IOOption_map( function_flow( ((f = (function (E) { return function (as) { if (1 === as.length) return as for ( var out = [ReadonlyNonEmptyArray_head(as)], _loop_1 = function (a) { out.every(function (o) { return !E.equals(o, a) }) && out.push(a) }, _i = 0, rest_1 = ReadonlyNonEmptyArray_tail(as); _i < rest_1.length; _i++ ) _loop_1(rest_1[_i]) return out } })(Eq)), function (as) { return ReadonlyArray_isNonEmpty(as) ? f(as) : as }), ReadonlyArray_append(id), toArray ) ), IOOption_chain(x => IOOption_fromIO(() => { setConfig.bannedUsers(x) external_Swal_default() .mixin({ toast: !0, position: "bottom-left", timer: 2500, timerProgressBar: !0, showConfirmButton: !1, didOpen: toast => { toast.addEventListener( "pointerenter", external_Swal_default().stopTimer ) toast.addEventListener( "pointerleave", external_Swal_default().resumeTimer ) }, }) .fire({ title: `Added Banned User: ${id}`, icon: "success", }) }) ), IO_apSecond(() => { chat.style.display = "none" }) ) var f chat.querySelector("#content #message")?.append(clone) }, getChatFontSize = mainState => Math.round( ((Math.max(mainState.getConfig.fontSize() - 0.2, 0.01) * mainState.playerRect.height) / mainState.getConfig.laneCount()) * (mainState.getConfig.flowY2() - mainState.getConfig.flowY1()) * 100 ) / 100 var equalsDefault = function (compare) { return function (first, second) { return first === second || 0 === compare(first, second) } }, Ord_contramap = function (f) { return function (fa) { return { equals: equalsDefault( (compare = function (first, second) { return fa.compare(f(first), f(second)) }) ), compare: function (first, second) { return first === second ? 0 : compare(first, second) }, } var compare } }, number_Ord = { equals: function (first, second) { return first === second }, compare: function (first, second) { return first < second ? -1 : first > second ? 1 : 0 }, }, number_Show_show = function (n) { return JSON.stringify(n) } const external_window_micro_memoize_namespaceObject = window["micro-memoize"] var external_window_micro_memoize_default = __webpack_require__.n( external_window_micro_memoize_namespaceObject ) const getFlowChatProgress = chat => function_pipe( chat.animation, chainNullableK(x => x.currentTime), getOrElse(() => 0) ) / chat.animationDuration, getFlowChatRect = (chat, mainState) => { const { getConfig } = mainState, x = mainState.playerRect.width * getConfig.flowX2() - (chat.width + mainState.playerRect.width * (getConfig.flowX2() - getConfig.flowX1())) * getFlowChatProgress(chat) return new DOMRect(x, chat.y, chat.width, chat.height) }, getChatLane = (flowChat, progress, flowChats) => mainState => { const flowWidth = mainState.playerRect.width * (mainState.getConfig.flowX2() - mainState.getConfig.flowX1()), chatRect = getFlowChatRect(flowChat, mainState), chatWidth = chatRect.width, chatHeight = chatRect.height, chatX = chatRect.x, chatIndex = flowChats.indexOf(flowChat), movingChats = function_pipe( flowChats, ((n = chatIndex >= 0 ? chatIndex : -1), function (as) { return ReadonlyArray_isOutOfBound(n, as) ? as : 0 === n ? ReadonlyArray_empty : as.slice(0, n) }), es6_ReadonlyArray_filter( chat => !chat.animationEnded && chat.width > 0 ), ((O = Ord_contramap(x => x.lane)(number_Ord)), function (as) { return as.length <= 1 ? as : as.slice().sort(O.compare) }) ), tooCloseTo = external_window_micro_memoize_default()( i => { const otherRect = getFlowChatRect(movingChats[i], mainState), otherWidth = otherRect.width, otherX = otherRect.x, gap = (chatHeight * otherWidth * chatWidth) ** 0.333 * mainState.getConfig.minSpacing() return ( (flowWidth - otherX) / (flowWidth + otherWidth) - progress < (chatWidth + gap) / (flowWidth + chatWidth) || otherX + otherWidth + gap > chatX ) }, { maxSize: 1e3 } ), occupyInfo = function_pipe( movingChats, es6_ReadonlyArray_mapWithIndex((i, x) => ({ tooClose: () => tooCloseTo(i), lane: x.lane, })), ReadonlyArray_append({ tooClose: () => !0, lane: mainState.getConfig.laneCount(), }) ), index = occupyInfo.findIndex(x => x.lane >= flowChat.lane), rightFreeLane = function_pipe( occupyInfo.slice(index), ((predicate = x => x.tooClose()), function (as) { for (var i = 0; i < as.length; i++) if (predicate(as[i])) return some(as[i]) return none }), es6_Option_map(x => x.lane), getOrElse(() => mainState.getConfig.laneCount()) ) var O, n, predicate const leftFreeLane = function_pipe( occupyInfo.slice(0, index), function (as) { for (var i = as.length - 1; i >= 0; i--) if (as[i].tooClose()) return some(as[i]) return none }, es6_Option_map(x => x.lane), getOrElse(() => -1) ), formerLaneInterval = Math.min( flowChat.lane - leftFreeLane, rightFreeLane - flowChat.lane, 1 ) return function_pipe( occupyInfo, es6_ReadonlyArray_reduce( { maxInterval: 0, maxIntervalLane: 0, lastLane: -1 }, ({ maxInterval, maxIntervalLane, lastLane }, info) => maxInterval > 0.999 || !info.tooClose() ? { maxInterval, maxIntervalLane, lastLane } : (() => { const nextLane = info.lane, interLane = Math.min( Math.max((lastLane + nextLane) / 2, 0), mainState.getConfig.laneCount() - 1 ), newInterval = Math.min( interLane - lastLane, nextLane - interLane, 1 ) return newInterval - maxInterval > 0.001 ? { maxInterval: newInterval, maxIntervalLane: Math.max( lastLane + newInterval, 0 ), lastLane: nextLane, } : { maxInterval, maxIntervalLane, lastLane: nextLane } })() ), x => ({ lane: Math.abs(formerLaneInterval - x.maxInterval) < 0.001 ? flowChat.lane : x.maxIntervalLane, interval: x.maxInterval, }) ) }, intervalTooSmall = interval => getConfig => getConfig.noOverlap() && interval < 0.999, external_m_namespaceObject = m var external_m_default = __webpack_require__.n( external_m_namespaceObject ) const textShadow = shadowColor => function_flow( x => `${x}px`, x => (a, b) => `${a}${x} ${b}${x} ${shadowColor}99`, x => [x("-", "-"), x("", "-"), x("-", ""), x("", "")].join(", ") ), textStyle = { fontFamily: "inherit" }, renderChat = chat => mainState => () => external_m_default().render( chat.element, ((chat, mainState) => { const { getConfig } = mainState, data = chat.getData(getConfig) return external_m_default()( "span", { style: { fontSize: `${getChatFontSize(mainState)}px`, visibility: getConfig.displayChats() ? "visible" : "hidden", color: "owner" === data.authorType ? getConfig.ownerColor() : "moderator" === data.authorType ? getConfig.moderatorColor() : "member" === data.authorType ? getConfig.memberColor() : getConfig.color(), fontWeight: getConfig.fontWeight().toString(), fontFamily: getConfig.font(), opacity: getConfig.chatOpacity().toString(), textShadow: textShadow(getConfig.shadowColor())( getConfig.shadowFontWeight() ), }, }, function_pipe( [ function_pipe( data.authorName, filter(x => x.visible), es6_Option_map(x => external_m_default()( "span", { style: { color: toUndefined(data.textColor), fontSize: "0.84em", ...textStyle, }, }, `${x.content}: ` ) ) ), function_pipe( data.messageElement, es6_Option_map(x => ((message, getConfig) => { const eleWin = message.ownerDocument.defaultView ?? window, maxChatLength = getConfig.maxChatLength() return function_pipe( Array.from(message.childNodes), es6_ReadonlyArray_reduce( { vnodes: [], length: 0 }, ({ vnodes, length }, node) => { return length >= maxChatLength ? { vnodes, length } : !getConfig.textOnly() && node instanceof eleWin.HTMLImageElement ? { vnodes: [ ...vnodes, external_m_default()("img", { style: { height: "1em", width: "1em", verticalAlign: "text-top", }, src: node.src, alt: node.alt, }), ], length: length + 1, } : function_pipe( node.textContent ?? "", ((end = maxChatLength), function (s) { return s.slice(0, end) }), x => node instanceof eleWin.HTMLAnchorElement ? { vnodes: [ ...vnodes, external_m_default()( "span", { style: { fontSize: "0.84em", textDecoration: "underline", ...textStyle, }, }, x ), ], length: length + x.length, } : { vnodes: [ ...vnodes, external_m_default().fragment( {}, x ), ], length: length + x.length, } ) var end } ) ) })(x, getConfig) ), es6_Option_map(x => external_m_default()( "span", { style: { color: toUndefined(data.textColor), ...textStyle, }, }, x.vnodes ) ) ), function_pipe( data.paymentInfo, filter(x => x.visible), es6_Option_map(x => external_m_default()( "span", { style: { color: toUndefined(data.paidColor), fontSize: "0.84em", ...textStyle, }, }, external_m_default()( "strong", { style: textStyle }, x.content ) ) ) ), ], ReadonlyArray_compact, toArray ) ) })(chat, mainState) ), external_window_hash_it_namespaceObject = window["hash-it"] var external_window_hash_it_default = __webpack_require__.n( external_window_hash_it_namespaceObject ) const getLaneY = (lane, mainState) => mainState.playerRect.height * ((lane / mainState.getConfig.laneCount() + 0.005) * (mainState.getConfig.flowY2() - mainState.getConfig.flowY1()) + mainState.getConfig.flowY1()), setChatPlayState = chat => mainState => function_pipe( chat, fromPredicate(x => !x.animationEnded), fromOption, IOOption_chain( (function (f) { return function () { for (var a = [], _i = 0; _i < arguments.length; _i++) a[_i] = arguments[_i] return fromOption(f.apply(void 0, a)) } })(x => x.animation) ), IOOption_chainFirst(x => IOOption_fromIO( mainState.chatPlaying ? () => x.play() : () => x.pause() ) ), IOOption_chain(x => IOOption_fromIO(() => { x.playbackRate = mainState.getConfig.flowSpeed() / 15 }) ) ), getWidth = external_window_micro_memoize_default()( ele => ele?.getBoundingClientRect().width ?? 0, { maxSize: 2e3, transformKey: function_flow( es6_ReadonlyArray_map(external_window_hash_it_default()), toArray ), } ), setChatAnimation = (chat, chats) => mainState => function_pipe( { fontSize: getChatFontSize(mainState) }, IO_of, IO_chainFirst(x => () => { chat.element.style.transform = `translate(${ mainState.playerRect.width * (mainState.getConfig.flowX2() - mainState.getConfig.flowX1()) }px, -${2 * x.fontSize}px)` }), IOOption_fromIO, IOOption_filter(() => !chat.animationEnded), IOOption_chainFirst(x => IOOption_fromIO(() => { chat.animationDuration = 6400 chat.width = getWidth(chat.element.firstElementChild) chat.height = x.fontSize }) ), IOOption_map(() => ({ progress: getFlowChatProgress(chat) })), IOOption_map(x => ({ ...x, ...getChatLane(chat, x.progress, chats)(mainState), })), IOOption_chain(ctx => intervalTooSmall(ctx.interval)(mainState.getConfig) ? function_pipe( chat.animation, fromOption, IOOption_chain(x => IOOption_fromIO(() => { x.finish() chat.animation = Option_none }) ), es6_IO_map(() => Option_none) ) : IOOption_some(ctx) ), IOOption_chainFirst(x => IOOption_fromIO(() => { chat.lane = x.lane }) ), IOOption_map(x => ({ ...x, laneY: getLaneY(chat.lane, mainState), })), IOOption_chain(ctx => function_pipe( [ function_pipe( chat.animation, fromOption, IOOption_chain(x => IOOption_fromIO(() => x.cancel())) ), function_pipe( [ [ mainState.playerRect.width * (mainState.getConfig.flowX2() - mainState.getConfig.flowX1()), ctx.laneY, ], [-chat.width, ctx.laneY], ], es6_ReadonlyArray_map( es6_ReadonlyArray_map(x => `${x}px`) ), es6_ReadonlyArray_map( ([x, y]) => `translate(${x}, ${y})` ), ReadonlyArray_bindTo("transform"), toArray, x => chat.element.animate(x, { duration: 6400, easing: mainState.getConfig.timingFunction(), }), x => { x.onfinish = () => { chat.animationEnded = !0 } chat.y = ctx.laneY const newTime = 6400 * ctx.progress x.currentTime = newTime return x }, Option_some, x => () => { chat.animation = x }, IO_apSecond(setChatPlayState(chat)(mainState)) ), ], IO_sequenceArray, IOOption_fromIO ) ), es6_IO_map(Option_isSome) ), emptyElement = document.createElement("span") var Monoid_concatAll = function (M) { return (function (M) { return function (startWith) { return function (as) { return as.reduce(function (a, acc) { return M.concat(a, acc) }, startWith) } } })(M)(M.empty) }, MonoidAny = { concat: function (first, second) { return first || second }, empty: !1, } const operators = { flip: x => b => a => x(a)(b), flow: fns => function_flow(...fns), and: Monoid_concatAll({ concat: function (first, second) { return first && second }, empty: !0, }), or: Monoid_concatAll(MonoidAny), RA: { some: function (predicate) { return function (as) { return as.some(predicate) } }, compact: ReadonlyArray_compact, }, O: { exists: function (predicate) { return function (ma) { return !Option_isNone(ma) && predicate(ma.value) } }, }, allPreds: Monoid_concatAll({ concat: function (first, second) { return function_pipe( first, (function (second) { return function (first) { return function (a) { return first(a) && second(a) } } })(second) ) }, empty: constTrue, }), anyPreds: Monoid_concatAll({ concat: function (first, second) { return function_pipe( first, (function (second) { return function (first) { return function (a) { return first(a) || second(a) } } })(second) ) }, empty: constFalse, }), inText: text => x => text.content.includes(x), eqText: text => x => text.content === x, matchedByText: text => x => Boolean(text.content.match(RegExp(x, "u"))), isVisible: x => x.visible, }, assert_lib = check.assert, tapNonNull = x => { assert_lib(null != x) return x }, onChatFieldMutate = ( chatScrn, flowChats, mainState, setConfig, mainLog ) => { return function_flow( ((f = e => Array.from(e.addedNodes)), function (ma) { return function_pipe( ma, (function (f) { return function (as) { if ( (function (as) { return 0 === as.length })(as) ) return ReadonlyArray_empty for (var out = [], i = 0; i < as.length; i++) out.push.apply(out, f(0, as[i])) return out } })(function (_, a) { return f(a) }) ) }), es6_ReadonlyArray_filter(x => x.children.length > 0), ReadonlyArray_reverse, es6_ReadonlyArray_map(chat => () => { const getData = (chat => { const chatType = chat.querySelector( ".yt-live-chat-ticker-paid-message-item-renderer" ) ? "ticker" : chat.querySelector( ".yt-live-chat-membership-item-renderer" ) ? "membership" : chat.querySelector( ".yt-live-chat-viewer-engagement-message-renderer" ) ? "engagement" : "normal", isPaid = "ticker" === chatType || Boolean(chat.querySelector("#card")), paymentInfo = function_pipe( fromNullable( isPaid ? chat.querySelector( [ "#purchase-amount", "#purchase-amount-chip", "#content>#text", ].join(",") )?.textContent : void 0 ), es6_Option_map(x => ({ visible: !0, content: x })) ), authorType = chat.querySelector(".owner") ? "owner" : chat.querySelector(".moderator") ? "moderator" : chat.querySelector(".member") ? "member" : "normal", messageElement = fromNullable( chat.querySelector("#message") ), isPaidNormal = !!Option_isSome(paymentInfo) && Boolean( chat.querySelector( ".yt-live-chat-paid-message-renderer" ) ), isPaidSticker = !(!Option_isSome(paymentInfo) || isPaidNormal) && Boolean( chat.querySelector( ".yt-live-chat-paid-sticker-renderer" ) ), textColor = fromNullable( isPaidNormal ? window .getComputedStyle( tapNonNull(chat.querySelector("#header")) ) .getPropertyValue("background-color") : isPaidSticker ? window .getComputedStyle(chat) .getPropertyValue( "--yt-live-chat-paid-sticker-chip-background-color" ) : void 0 ), paidColor = fromNullable( isPaidNormal ? window .getComputedStyle( tapNonNull(chat.querySelector("#content")) ) .getPropertyValue("background-color") : isPaidSticker ? window .getComputedStyle(chat) .getPropertyValue( "--yt-live-chat-paid-sticker-background-color" ) : void 0 ), authorPhotoMatches = chat .querySelector(["#author-photo", "img"].join(" ")) ?.src.match(/ytc\/(.*)=/), authorID = fromNullable( authorPhotoMatches?.[authorPhotoMatches.length - 1] ), authorName = fromNullable( chat.querySelector("#author-name")?.textContent ), message = function_pipe( messageElement, es6_Option_map(x => ({ visible: !0, content: x.innerHTML, })) ), messageText = function_pipe( messageElement, es6_Option_map(x => ({ visible: !0, content: x.textContent ?? "", })) ) return getConfig => ({ chatType, authorType, authorID, authorName: function_pipe( authorName, es6_Option_map(x => ({ visible: ("moderator" === authorType && getConfig.displayModName()) || (Option_isSome(paymentInfo) && getConfig.displaySuperChatAuthor()), content: x, })) ), messageElement, message, messageText, paymentInfo, textColor, paidColor, }) })(chat), { getConfig } = mainState, data = getData(getConfig) ;(((data, mainState, mainLog) => function_pipe( data, fromPredicate(() => function_pipe( mainState.filterExp, es6_Option_map(x => a( x, (data => ({ ...operators, authorName: data.authorName, message: data.message, messageText: data.messageText, paymentInfo: data.paymentInfo, authorID: function_pipe( data.authorID, es6_Option_map(x => ({ visible: !1, content: x, })) ), }))(data) ) ), getOrElse(() => !1) ) ), es6_Option_map(x => [ function_pipe( x.message, es6_Option_map(m => m.content) ), function_pipe( x.paymentInfo, es6_Option_map(p => p.content) ), ]), es6_Option_map(es6_ReadonlyArray_map(getOrElse(() => ""))), es6_Option_map(JSON.stringify), es6_Option_map(x => mainLog([`Banned: ${x}`])), match( () => () => !1, es6_IO_map(() => !0) ) )())(data, mainState, mainLog) ? () => { chat.style.display = "none" } : function_pipe( [ function_pipe( void 0, fromPredicate(getConfig.createChats), filter(() => "normal" === data.chatType), fromOption, IOOption_chain(() => IOOption_fromIO( ((getData, flowChats, chatScrn, mainState) => function_pipe( { getData, element: emptyElement, lane: -1, animation: Option_none, animationDuration: 0, animationEnded: !1, width: 2, height: getChatFontSize(mainState), y: 0, }, x => getChatLane(x, 0, flowChats)(mainState) .interval, intervalTooSmall, x => x(mainState.getConfig) ) ? () => {} : () => { const offScreenIndex = function_pipe( flowChats, findIndex( chat => chat.animationEnded || flowChats.length >= mainState.getConfig.maxChatCount() ) ), element = function_pipe( offScreenIndex, es6_Option_map( x => flowChats[x].element ), getOrElseW(() => document.createElement("span") ) ) function_pipe( offScreenIndex, match( () => () => { external_log_default().debug( "CreateFlowChat" ) chatScrn.append(element) }, i => function_pipe( () => flowChats.splice(i, 1)[0] .animation, IOOption_chain(oldAnimation => IOOption_fromIO(() => oldAnimation.cancel() ) ) ) ) )() const flowChat = { getData, element, lane: -1, animation: Option_none, animationDuration: 0, animationEnded: !1, width: 2, height: getChatFontSize(mainState), y: 0, } element.classList.add("fyc_chat") function_pipe( mainState, IO_of, IO_chainFirst(renderChat(flowChat)), es6_IO_chain( setChatAnimation(flowChat, flowChats) ), es6_IO_chain(x => x ? () => flowChats.push(flowChat) : () => flowChat.element.remove() ) )() })(getData, flowChats, chatScrn, mainState) ) ) ), function_pipe( data.authorID, fromOption, IOOption_filter(getConfig.createBanButton), IOOption_chain(x => IOOption_fromIO( addBanButton(chat, x, getConfig, setConfig) ) ), es6_IO_map(() => Option_some(void 0)), IOOption_filter(getConfig.simplifyChatField), IOOption_chain(() => IOOption_fromIO( (chat => chat.querySelector( ".style-scope.yt-live-chat-paid-message-renderer" ) ? () => {} : function_pipe( [ "#author-photo", "yt-live-chat-author-chip.style-scope.yt-live-chat-text-message-renderer", ], es6_ReadonlyArray_map(x => fromNullable(chat.querySelector(x)) ), ReadonlyArray_compact, es6_ReadonlyArray_map(x => () => { x.style.display = "none" }), ReadonlyArray_append(() => { chat.style.borderBottom = "1px solid var(--yt-spec-text-secondary)" }), IO_sequenceArray ))(chat) ) ) ), ], IO_sequenceArray ))() }), IO_sequenceArray ) var f }, removeOldChats = maxChatCount => flowChats => function_pipe( () => flowChats.sort((a, b) => a.animationEnded === b.animationEnded ? 0 : a.animationEnded ? -1 : 1 ), IO_apSecond(() => flowChats.splice( 0, Math.max(0, flowChats.length - maxChatCount) ) ), es6_IO_chain( removed => () => removed.forEach(x => { external_log_default().debug("RemoveChat") x.element.remove() }) ) ) var EMPTY_OBJ = {}, EMPTY_ARR = [], hyperapp_id = a => a, hyperapp_map = EMPTY_ARR.map, isArray = Array.isArray, enqueue = "undefined" != typeof requestAnimationFrame ? requestAnimationFrame : setTimeout, createClass = obj => { var out = "" if ("string" == typeof obj) return obj if (isArray(obj)) for (var tmp, k = 0; k < obj.length; k++) (tmp = createClass(obj[k])) && (out += (out && " ") + tmp) else for (var k in obj) obj[k] && (out += (out && " ") + k) return out }, shouldRestart = (a, b) => { for (var k in { ...a, ...b }) if ("function" == typeof (isArray(a[k]) ? a[k][0] : a[k])) b[k] = a[k] else if (a[k] !== b[k]) return !0 }, getKey = vdom => (null == vdom ? vdom : vdom.key), patchProperty = (node, key, oldValue, newValue, listener, isSvg) => { if ("key" === key); else if ("style" === key) for (var k in { ...oldValue, ...newValue }) { oldValue = null == newValue || null == newValue[k] ? "" : newValue[k] "-" === k[0] ? node[key].setProperty(k, oldValue) : (node[key][k] = oldValue) } else "o" === key[0] && "n" === key[1] ? ((node.events || (node.events = {}))[(key = key.slice(2))] = newValue) ? oldValue || node.addEventListener(key, listener) : node.removeEventListener(key, listener) : !isSvg && "list" !== key && "form" !== key && key in node ? (node[key] = newValue ?? "") : null == newValue || !1 === newValue || ("class" === key && !(newValue = createClass(newValue))) ? node.removeAttribute(key) : node.setAttribute(key, newValue) }, createNode = (vdom, listener, isSvg) => { var props = vdom.props, node = 3 === vdom.type ? document.createTextNode(vdom.tag) : (isSvg = isSvg || "svg" === vdom.tag) ? document.createElementNS( "http://www.w3.org/2000/svg", vdom.tag, { is: props.is } ) : document.createElement(vdom.tag, { is: props.is }) for (var k in props) patchProperty(node, k, null, props[k], listener, isSvg) for (var i = 0; i < vdom.children.length; i++) node.appendChild( createNode( (vdom.children[i] = maybeVNode(vdom.children[i])), listener, isSvg ) ) return (vdom.node = node) }, patch = (parent, node, oldVNode, newVNode, listener, isSvg) => { if (oldVNode === newVNode); else if ( null != oldVNode && 3 === oldVNode.type && 3 === newVNode.type ) oldVNode.tag !== newVNode.tag && (node.nodeValue = newVNode.tag) else if (null == oldVNode || oldVNode.tag !== newVNode.tag) { node = parent.insertBefore( createNode((newVNode = maybeVNode(newVNode)), listener, isSvg), node ) null != oldVNode && parent.removeChild(oldVNode.node) } else { var tmpVKid, oldVKid, oldKey, newKey, oldProps = oldVNode.props, newProps = newVNode.props, oldVKids = oldVNode.children, newVKids = newVNode.children, oldHead = 0, newHead = 0, oldTail = oldVKids.length - 1, newTail = newVKids.length - 1 isSvg = isSvg || "svg" === newVNode.tag for (var i in { ...oldProps, ...newProps }) ("value" === i || "selected" === i || "checked" === i ? node[i] : oldProps[i]) !== newProps[i] && patchProperty( node, i, oldProps[i], newProps[i], listener, isSvg ) for ( ; newHead <= newTail && oldHead <= oldTail && null != (oldKey = getKey(oldVKids[oldHead])) && oldKey === getKey(newVKids[newHead]); ) patch( node, oldVKids[oldHead].node, oldVKids[oldHead], (newVKids[newHead] = maybeVNode( newVKids[newHead++], oldVKids[oldHead++] )), listener, isSvg ) for ( ; newHead <= newTail && oldHead <= oldTail && null != (oldKey = getKey(oldVKids[oldTail])) && oldKey === getKey(newVKids[newTail]); ) patch( node, oldVKids[oldTail].node, oldVKids[oldTail], (newVKids[newTail] = maybeVNode( newVKids[newTail--], oldVKids[oldTail--] )), listener, isSvg ) if (oldHead > oldTail) for (; newHead <= newTail; ) node.insertBefore( createNode( (newVKids[newHead] = maybeVNode(newVKids[newHead++])), listener, isSvg ), (oldVKid = oldVKids[oldHead]) && oldVKid.node ) else if (newHead > newTail) for (; oldHead <= oldTail; ) node.removeChild(oldVKids[oldHead++].node) else { var keyed = {}, newKeyed = {} for (i = oldHead; i <= oldTail; i++) null != (oldKey = oldVKids[i].key) && (keyed[oldKey] = oldVKids[i]) for (; newHead <= newTail; ) { oldKey = getKey((oldVKid = oldVKids[oldHead])) newKey = getKey( (newVKids[newHead] = maybeVNode(newVKids[newHead], oldVKid)) ) if ( newKeyed[oldKey] || (null != newKey && newKey === getKey(oldVKids[oldHead + 1])) ) { null == oldKey && node.removeChild(oldVKid.node) oldHead++ } else if (null == newKey || 1 === oldVNode.type) { if (null == oldKey) { patch( node, oldVKid && oldVKid.node, oldVKid, newVKids[newHead], listener, isSvg ) newHead++ } oldHead++ } else { if (oldKey === newKey) { patch( node, oldVKid.node, oldVKid, newVKids[newHead], listener, isSvg ) newKeyed[newKey] = !0 oldHead++ } else if (null != (tmpVKid = keyed[newKey])) { patch( node, node.insertBefore( tmpVKid.node, oldVKid && oldVKid.node ), tmpVKid, newVKids[newHead], listener, isSvg ) newKeyed[newKey] = !0 } else patch( node, oldVKid && oldVKid.node, null, newVKids[newHead], listener, isSvg ) newHead++ } } for (; oldHead <= oldTail; ) null == getKey((oldVKid = oldVKids[oldHead++])) && node.removeChild(oldVKid.node) for (var i in keyed) null == newKeyed[i] && node.removeChild(keyed[i].node) } } return (newVNode.node = node) }, maybeVNode = (newVNode, oldVNode) => !0 !== newVNode && !1 !== newVNode && newVNode ? "function" == typeof newVNode.tag ? ((!oldVNode || null == oldVNode.memo || ((a, b) => { for (var k in a) if (a[k] !== b[k]) return !0 for (var k in b) if (a[k] !== b[k]) return !0 })(oldVNode.memo, newVNode.memo)) && ((oldVNode = newVNode.tag(newVNode.memo)).memo = newVNode.memo), oldVNode) : newVNode : hyperapp_text(""), recycleNode = node => 3 === node.nodeType ? hyperapp_text(node.nodeValue, node) : createVNode( node.nodeName.toLowerCase(), EMPTY_OBJ, hyperapp_map.call(node.childNodes, recycleNode), 1, node ), createVNode = (tag, props, children, type, node) => ({ tag, props, key: props.key, children, type, node, }), hyperapp_text = (value, node) => createVNode(value, EMPTY_OBJ, EMPTY_ARR, 3, node), h = (tag, props, children = EMPTY_ARR) => createVNode(tag, props, isArray(children) ? children : [children]), app = ({ node, view, subscriptions, dispatch = hyperapp_id, init = EMPTY_OBJ, }) => { var state, busy, vdom = node && recycleNode(node), subs = [], update = newState => { if (state !== newState) { null == (state = newState) && (dispatch = subscriptions = render = hyperapp_id) subscriptions && (subs = ((oldSubs, newSubs = EMPTY_ARR, dispatch) => { for ( var oldSub, newSub, subs = [], i = 0; i < oldSubs.length || i < newSubs.length; i++ ) { oldSub = oldSubs[i] newSub = newSubs[i] subs.push( newSub && !0 !== newSub ? !oldSub || newSub[0] !== oldSub[0] || shouldRestart(newSub[1], oldSub[1]) ? [ newSub[0], newSub[1], (oldSub && oldSub[2](), newSub[0](dispatch, newSub[1])), ] : oldSub : oldSub && oldSub[2]() ) } return subs })(subs, subscriptions(state), dispatch)) view && !busy && enqueue(render, (busy = !0)) } }, render = () => (node = patch( node.parentNode, node, vdom, (vdom = view(state)), listener, (busy = !1) )), listener = function (event) { dispatch(this.events[event.type], event) } return ( (dispatch = dispatch((action, props) => "function" == typeof action ? dispatch(action(state, props)) : isArray(action) ? "function" == typeof action[0] ? dispatch(action[0], action[1]) : action .slice(1) .map( fx => fx && !0 !== fx && fx[0](dispatch, fx[1]), update(action[0]) ) : update(action) ))(init), dispatch ) } const src_defaultSettingText = { setting: ["Settings", "設定"], font: ["Font", "フォント"], color: ["Color(Normal)", "色(通常)"], ownerColor: ["Color(Owner)", "色(オーナー)"], moderatorColor: ["Color(Moderator)", "色(モデレーター)"], memberColor: ["Color(Member)", "色(メンバー)"], feedback: ["Feedback", "バグ報告と要望"], eventLog: ["Event log", "イベントログ"], giveFeedback: [ "Give your feedbacks here(Please attach the event log if they're bug related)", "バグ報告、要望はこちら(バグの場合は、イベントログを添付してください)", ], chatOpacity: ["Opacity", "不透明度"], fontSize: ["Size", "サイズ"], fontWeight: ["Weight", "太さ"], shadowFontWeight: ["Weight(Shadow)", "太さ(影)"], flowSpeed: ["Speed", "速度"], maxChatCount: ["Max number of chats", "最大表示数"], maxChatLength: ["Max number of characters", "最大文字数"], laneCount: ["Number of rows", "行数"], bannedWords: ["Banned Words", "NGワード"], bannedWordRegexs: ["Banned Words(Regex)", "NGワード(正規表現)"], bannedUsers: ["Banned Users", "NGユーザー"], simplifyChatField: ["Simplify", "簡略化する"], createBanButton: ["Show ban button", "NGボタンを表示する"], displayModName: [ "Show moderator's name", "モデレーターの名前を表示する", ], displaySuperChatAuthor: [ "Show super chat author", "スパチャの作成者を表示する", ], createChats: ["Display flowing chats", "チャットを流す"], textOnly: [ "Text only(ignore emojis)", "文字のみ(絵文字を無視する)", ], error: ["Error", "エラー"], video: ["Video", "画面"], chatField: ["Chat Window", "チャット欄"], useStepTiming: ["Move chat in steps", "チャットを段階的に動かす"], timingStepCount: ["└Step Count", "└段階数"], chatFilter: ["Chat Filter", "チャットフィルター"], flowChat: ["Flow Chat", "チャット流れ"], clearFlowChats: [ "Clear Flowing Chats", "流れるチャットをクリアする", ], flowNewChatIf: [ "A new chat will appear if all of the followings are met:", "新しいチャットは以下のすべてを満たす場合に流れます:", ], noOverlap: ["└Chats won't overlap", "└他のチャットと重ならない"], minSpacing: ["Min spacing between chats", "チャットの最小間隔"], fieldScale: ["Scale", "拡大率"], copy: ["Copy", "コピーする"], showChat: ["Show chats", "チャット非表示"], hideChat: ["Hide chats", "チャット表示"], flowY1: ["Flow area top edge", "流れ範囲の上端"], flowY2: ["Flow area bottom edge", "流れ範囲の下端"], flowX1: ["Flow area left edge", "流れ範囲の左端"], flowX2: ["Flow area right edge", "流れ範囲の右端"], shadowColor: ["Color(Shadow)", "色(影)"], }, getLang = lang => key => src_defaultSettingText[key]["FYC_EN" === lang ? 0 : 1], colorInput = action => color => h("input", { style: { verticalAlign: "middle", width: "5.5em" }, maxlength: 20, value: color, ...action, }), colorPicker = action => color => h("input", { style: { width: "36px", verticalAlign: "middle" }, type: "color", value: color, oninput: action.onchange, }), colorTextOutput = textStyle => color => h( "span", { style: { ...textStyle, color } }, hyperapp_text("Aa1あア亜") ), tapIs = (constructor, x) => { assert_lib(x instanceof constructor) return x }, getValue = e => { const target = e.currentTarget ?? e.__target if ( target instanceof HTMLSelectElement || target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement ) return target.value throw Error("Event target type isn't acceptable.") }, ui_option = (value, label, selected) => h("option", { value, selected }, hyperapp_text(label)), rangeRow = (min, max, step, value, editing, action) => h("div", {}, [ h("input", { style: { width: "150px", verticalAlign: "middle" }, type: "range", min, max, step, value, oninput: action.onchange, }), h("input", { style: { width: "30px", backgroundColor: "transparent", color: "inherit", borderWidth: "1px", verticalAlign: "middle", }, inputmode: "decimal", value: editing ? value : Number.parseFloat(value) .toFixed(4) .replace(/\.?0+$/, ""), ...action, }), ]), settingRow = (label, content) => h("div", {}, [ h("span", {}, hyperapp_text(label)), h("div", {}, content), ]), tabContainer = (style, labels, tabs, mainTab, ontabSelect) => h("div", {}, [ h( "div", {}, function_pipe( labels, es6_ReadonlyArray_mapWithIndex((i, x) => h( "span", { style: { ...style.label, ...(mainTab === i ? style.labelFocus : {}), display: "inline-block", }, onpointerdown: [ontabSelect, i], }, hyperapp_text(x) ) ) ) ), h( "div", { style: { ...style.container, overflow: "hidden auto" } }, h( "div", { style: { ...style.tab } }, tabs.find((_, i) => i === mainTab)?.() ) ), ]), style = { resize: "horizontal", boxSizing: "border-box", width: "100%", }, textAreaRow = (rows, value, action) => h("textarea", { rows, value, style, ...action }), textColorRow = colorNodes => function_pipe( colorNodes, Reader_sequenceArray, es6_Reader_map(x => h("div", {}, x)) ), panelBoxStyle = width => ({ flex: `0 0 ${width}px`, margin: "2px" }), textRowStyle = { width: "70%", boxSizing: "border-box" }, langs = [ ["FYC_EN", "English"], ["FYC_JA", "日本語"], ], exampleTextStyle = s => ({ fontFamily: s.font, fontWeight: s.fontWeight.toString(), textShadow: textShadow(s.shadowColor)(s.shadowFontWeight), }), computed = { useStepTiming: s => Boolean(s.timingFunction.match(/^steps\(.+/)), }, stepTiming = stepCount => `steps(${stepCount}, jump-end)`, settingPanel = command => { const { setConfig, act } = command, configFx = (k, v) => [() => setConfig[k](v), void 0], setState = { flowY1: (s, v) => function_pipe(Math.max(s.flowY2, v + 0.05), flowY2 => [ { ...s, flowY1: v, flowY2 }, configFx("flowY1", v), configFx("flowY2", flowY2), ]), flowY2: (s, v) => function_pipe(Math.min(s.flowY1, v - 0.05), flowY1 => [ { ...s, flowY2: v, flowY1 }, configFx("flowY2", v), configFx("flowY1", flowY1), ]), flowX1: (s, v) => function_pipe(Math.max(s.flowX2, v + 0.05), flowX2 => [ { ...s, flowX1: v, flowX2 }, configFx("flowX1", v), configFx("flowX2", flowX2), ]), flowX2: (s, v) => function_pipe(Math.min(s.flowX1, v - 0.05), flowX1 => [ { ...s, flowX2: v, flowX1 }, configFx("flowX2", v), configFx("flowX1", flowX1), ]), timingStepCount: (s, v) => function_pipe(stepTiming(v), timingFunction => [ { ...s, timingStepCount: v, timingFunction }, configFx("timingFunction", timingFunction), ]), bannedWordRegexs: (s, v) => function_pipe( v, es6_ReadonlyArray_reduce( { valid: !0, error: "" }, (acc, cur) => { try { RegExp(cur, "u") return acc } catch (e) { return { valid: !1, error: `${acc.error}${e} in ${cur};`, } } } ), x => [ { ...s, bannedWordRegexs: v, bannedWordRegexsError: x.error, bannedWordRegexsValid: x.valid, }, ...(x.valid ? [configFx("bannedWordRegexs", v)] : []), ] ), }, setComputed = { useStepTiming: (s, v) => { const timingFunction = v ? stepTiming(s.timingStepCount) : "linear" return [ { ...s, timingFunction }, configFx("timingFunction", timingFunction), ] }, }, doAct = { copy: async s => { GM.setClipboard(s.eventLog.join("\n")) }, clearFlowChats: async s => { act.clearFlowChats() }, }, getTrueState = (k, s) => (k in computed ? computed[k](s) : s[k]), getState = (k, s) => s.editingInput.id === k ? s.editingInput.committedState : getTrueState(k, s), updateAt = (k, v, s) => k in setComputed ? setComputed[k](s, v) : k in setState ? setState[k](s, v) : [ { ...s, [k]: v }, ...(k in setConfig ? [configFx(k, v)] : []), ], updateString = key => (s, e) => function_pipe(getValue(e), x => updateAt(key, x, s)), updateNumber = key => (s, e) => function_pipe(getValue(e), parseFloat, x => updateAt(key, x, s) ), updateInt = key => (s, e) => function_pipe( getValue(e), x => parseInt(x, 10), x => updateAt(key, x, s) ), updateStrings = key => (s, e) => function_pipe( getValue(e), function_flow( split(/\r\n|\n/), es6_ReadonlyArray_filter(Predicate_not(string_isEmpty)) ), x => updateAt(key, x, s) ), editAction = (key, onchange) => ({ onfocus: (s, e) => updateAt( "editingInput", { id: key, committedState: getTrueState(key, s), value: getValue(e), }, s ), onblur: s => updateAt( "editingInput", { id: "", committedState: "", value: "" }, s ), oninput: (s, e) => updateAt( "editingInput", { id: key, committedState: s.editingInput.committedState, value: getValue(e), }, s ), onchange: (s, e) => { const [s1, ...es1] = onchange(key)(s, e), x = s1.editingInput.id === key ? { id: key, committedState: getTrueState(key, s1), value: getValue(e), } : s1.editingInput, [s2, ...es2] = updateAt("editingInput", x, s1) return [s2, ...es1, ...es2] }, }), getEditValue = (s, k, t) => s.editingInput.id === k ? s.editingInput.value : t(getState(k, s)) return state => { const getText = getLang(state.lang), checkboxNode = label => { return ((label, checked, onchange) => h( "div", {}, h("label", {}, [ hyperapp_text(label), h("input", { type: "checkbox", checked, onchange }), ]) ))( getText(label), getState(label, state), ((key = label), (s, e) => function_pipe( (e => tapIs(HTMLInputElement, e.currentTarget).checked)( e ), x => updateAt(key, x, s) )) ) var key }, textColorNode = label => settingRow(getText(label), [ textColorRow( function_pipe(editAction(label, updateString), x => [ colorPicker(x), colorInput(x), colorTextOutput(exampleTextStyle(state)), ]) )(getEditValue(state, label, function_identity)), ]), intNode = (label, min, max, step) => settingRow(getText(label), [ rangeRow( min, max, step, getEditValue(state, label, number_Show_show), state.editingInput.id === label, editAction(label, updateInt) ), ]), numberNode = (label, min, max, step) => settingRow(getText(label), [ rangeRow( min, max, step, getEditValue(state, label, number_Show_show), state.editingInput.id === label, editAction(label, updateNumber) ), ]), buttonNode = label => h( "button", { type: "button", onclick: s => [s, [() => doAct[label](s), void 0]], }, hyperapp_text(getText(label)) ), textAreaNode = (label, rows) => settingRow(getText(label), [ textAreaRow( rows, getEditValue(state, label, x => x.join("\n")), editAction(label, updateStrings) ), ]), currentFonts = [ ["", "Default", "デフォルト"], ["arial", "Arial", "Arial"], ["arial black", "Arial Black", "Arial Black"], ["arial narrow", "Arial Narrow", "Arial Narrow"], ["Century", "Century", "Century"], ["Comic Sans MS", "Comic Sans MS", "Comic Sans MS"], ["Courier", "Courier", "Courier"], ["cursive", "cursive", "cursive"], ["fantasy", "fantasy", "fantasy"], ["Impact", "Impact", "Impact"], ["Meiryo", "Meiryo", "メイリオ"], ["Meiryo UI", "Meiryo UI", "メイリオ UI"], ["monospace", "monospace", "monospace"], ["Monotype Corsiva", "Monotype Corsiva", "Monotype Corsiva"], ["MS PGothic", "MS PGothic", "MS Pゴシック"], ["MS Gothic", "MS Gothic", "MS ゴシック"], ["MS Sans Serif", "MS Sans Serif", "MS Sans Serif"], ["MS Serif", "MS Serif", "MS Serif"], ["MS UI Gothic", "MS UI Gothic", "MS UI Gothic"], ["sans-serif", "Sans-serif", "Sans-serif"], ["serif", "Serif", "Serif"], ["Times New Roman", "Times New Roman", "Times New Roman"], ["Yu Gothic", "Yu Gothic", "遊ゴシック"], ["YuGothic", "YuGothic", "游ゴシック体"], [state.font, "Custom", "カスタム"], ], logPageLength = Math.trunc(getState("eventLog", state).length / 100) + 1 return state.showPanel ? h( "div", { class: "fyc_panel", style: { backgroundColor: "rgba(30,30,30,0.9)", zIndex: "10000", position: "absolute", bottom: "40px", right: "0px", color: "#fff", fontSize: "14px", width: "660px", border: "solid 1px #666", fontFamily: "MS PGothic", lineHeight: "1.2", }, }, [ h( "div", { style: { float: "right", margin: "3px 3px 0 0" } }, [ hyperapp_text("🌐"), h( "select", { onchange: updateString("lang") }, function_pipe( langs, es6_ReadonlyArray_map(x => ui_option(...x, x[0] === state.lang) ) ) ), ] ), tabContainer( { container: { height: "364px" }, label: { padding: "6px" }, labelFocus: { background: "#666" }, tab: { display: "flex", padding: "6px" }, }, [ getText("flowChat"), getText("chatFilter"), getText("chatField"), getText("feedback"), ], [ () => { return [ h("div", { style: panelBoxStyle(212) }, [ settingRow(getText("font"), [ h( "select", { style: textRowStyle, onchange: updateString("font"), }, function_pipe( currentFonts, findIndex(x => x[0] === state.font), getOrElse(() => 0), index => function_pipe( currentFonts, es6_ReadonlyArray_mapWithIndex( (i, x) => ui_option( x[0], "FYC_JA" === state.lang ? x[2] : x[1], i === index ) ) ) ) ), ]), h("input", { style: textRowStyle, maxlength: 20, value: state.font, oninput: updateString("font"), }), textColorNode("color"), textColorNode("ownerColor"), textColorNode("moderatorColor"), textColorNode("memberColor"), ((label = "shadowColor"), settingRow(getText(label), [ textColorRow( function_pipe( [colorPicker, colorInput], es6_ReadonlyArray_map(f => f(editAction(label, updateString)) ) ) )( getEditValue( state, label, function_identity ) ), ])), ]), h("div", { style: panelBoxStyle(212) }, [ numberNode("chatOpacity", 0, 1, 0.05), numberNode("fontSize", 0.3, 2, 0.05), numberNode("fontWeight", 10, 1e3, 10), numberNode("shadowFontWeight", 0, 3, 0.1), numberNode("flowSpeed", 1, 50, 1), intNode("maxChatCount", 5, 200, 5), intNode("maxChatLength", 5, 200, 5), intNode("laneCount", 1, 25, 1), ]), h("div", { style: panelBoxStyle(212) }, [ numberNode("flowY1", 0, 0.95, 0.05), numberNode("flowY2", 0.05, 1, 0.05), numberNode("flowX1", 0, 0.95, 0.05), numberNode("flowX2", 0.05, 1, 0.05), numberNode("minSpacing", 0, 2.5, 0.1), checkboxNode("useStepTiming"), h( "div", { style: { ...(getState("useStepTiming", state) ? {} : { opacity: "0.5" }), }, }, intNode("timingStepCount", 1, 400, 1) ), checkboxNode("createChats"), checkboxNode("displayModName"), checkboxNode("displaySuperChatAuthor"), checkboxNode("textOnly"), hyperapp_text(getText("flowNewChatIf")), checkboxNode("noOverlap"), buttonNode("clearFlowChats"), ]), ] var label }, () => [ h( "div", { style: panelBoxStyle(212) }, textAreaNode("bannedWords", 18) ), h( "div", { style: panelBoxStyle(212) }, settingRow(getText("bannedWordRegexs"), [ h( "span", {}, hyperapp_text( state.bannedWordRegexsValid ? "" : `${getText("error")}: ${ state.bannedWordRegexsError }` ) ), textAreaRow( 18, getEditValue(state, "bannedWordRegexs", x => x.join("\n") ), editAction("bannedWordRegexs", updateStrings) ), ]) ), h( "div", { style: panelBoxStyle(212) }, textAreaNode("bannedUsers", 18) ), ], () => [ h("div", { style: panelBoxStyle(644) }, [ numberNode("fieldScale", 0.7, 1.5, 0.05), checkboxNode("simplifyChatField"), checkboxNode("createBanButton"), ]), ], () => [ h("div", { style: panelBoxStyle(644) }, [ h( "div", { style: { float: "right" } }, h( "a", { style: { color: "#f0f" }, href: "https://greasyfork.org/en/scripts/411442-flow-youtube-chat/feedback", target: "_blank", }, hyperapp_text(getText("giveFeedback")) ) ), h("div", {}, [ h( "span", {}, hyperapp_text(getText("eventLog")) ), buttonNode("copy"), tabContainer( { container: { height: "276px" }, label: { padding: "4px", width: "2em", textAlign: "center", }, labelFocus: { background: "#666" }, tab: { display: "flex", flexDirection: "column", padding: "6px", }, }, function_pipe( ReadonlyArray_makeBy( logPageLength, number_Show_show ) ), function_pipe( ReadonlyArray_makeBy( logPageLength, i => () => function_pipe( getState("eventLog", state).slice( 100 * i, 100 * (i + 1) ), es6_ReadonlyArray_mapWithIndex( (j, x) => h( "div", { style: { display: "flex" } }, [ h( "div", { style: { userSelect: "none", flex: "0 0 2em", }, }, hyperapp_text(100 * i + j) ), h( "div", { style: { background: j % 2 == 0 ? "#fff" : "#ddd", color: "#000", flex: "auto", wordBreak: "break-all", padding: "0 2px", }, }, hyperapp_text(x) ), ] ) ) ) ) ), getState("logTab", state), (s, n) => updateAt("logTab", n, s) ), ]), ]), ], ], getState("mainTab", state), (s, n) => updateAt("mainTab", n, s) ), ] ) : h("div", {}) } }, togglePanel = (x, e) => [ { ...x, showPanel: !x.showPanel }, [ x.showPanel ? () => tapIs(HTMLElement, e.currentTarget).blur() : () => {}, void 0, ], ], simpleWrap = (comp, init) => { const node = document.createElement(comp.tag) return { node, dispatch: app({ init, view: comp.view, node }) } } ;(async () => { external_log_namespaceObject.setLevel("info") try { await function_pipe( defaultUserConfig, function_flow( Task_bindTo("userConfig"), Task_bind("configKeys", x => Task_of(Object.keys(x.userConfig)) ), Task_bind("getConfig", ctx => Task_of( function_pipe( ctx.configKeys, es6_ReadonlyArray_map(x => [ x, () => ctx.userConfig[x].val, ]), Object.fromEntries ) ) ), Task_bind("mainState", x => Task_of({ chatPlaying: !0, playerRect: new DOMRect(0, 0, 600, 400), filterExp: Option_none, getConfig: x.getConfig, }) ), Task_bind("configSubject", ctx => Task_of( function_pipe( ctx.configKeys, es6_ReadonlyArray_map(x => [ x, new external_rxjs_namespaceObject.Subject(), ]), Object.fromEntries ) ) ), Task_bind("setConfigPlain", ctx => Task_of( function_pipe( ctx.configKeys, es6_ReadonlyArray_map(x => [ x, async val => { ctx.userConfig[x].val = val ctx.configSubject[x].next(val) }, ]), Object.fromEntries ) ) ), Task_apS( "channel", Task_fromIO( () => new broadcast_channel_BroadcastChannel( "fyc-0615654655528523" ) ) ), Task_bind("setConfig", ctx => Task_of( function_pipe( ctx.configKeys, es6_ReadonlyArray_map(x => [ x, async val => { ctx.setConfigPlain[x](val) const item = ctx.userConfig[x] ctx.channel.postMessage([x, val]) GM.setValue(item.gmKey, item.toGm(val)) }, ]), Object.fromEntries ) ) ) ), function_flow( Task_apS( "reinitSubject", Task_fromIO(() => new external_rxjs_namespaceObject.Subject()) ), Task_bind("reinitialize", ctx => Task_of(() => { requestAnimationFrame(() => lib(ctx.reinitSubject)()) }) ), Task_bind("toggleChatButtonInit", ctx => Task_of({ lang: ctx.getConfig.lang(), displayChats: ctx.getConfig.displayChats(), }) ), Task_bind("wrappedToggleChatBtn", ctx => { return Task_of( simpleWrap( ((setConfig = ctx.setConfig), { tag: "button", view: state => { const label = getLang(state.lang)( state.displayChats ? "hideChat" : "showChat" ) return h( "button", { class: "ytp-button", style: { background: "none", border: "none", cursor: "pointer", float: "left", fontSize: "1em", height: "4em", outline: "none", overflow: "visible", padding: "0 0 0em", position: "relative", width: "3em", }, type: "button", "aria-label": label, title: label, onclick: s => { const displayChats = !s.displayChats return [ { ...s, displayChats }, [ () => setConfig.displayChats(displayChats), void 0, ], ] }, }, [ h( "svg", { style: { width: "100%" }, viewBox: "0 0 36 36", }, [ h("path", { class: "chat-button-path", d: "m11 12h17q1 0 1 1v9q0 1-1 1h-1v2l-4-2h-12q-1 0-1-1v-9q0-1 1-1z", fill: "#fff", "fill-opacity": state.displayChats ? "1" : "0", stroke: "#fff", "stroke-width": "2", }), ] ), ] ) }, }), ctx.toggleChatButtonInit ) ) var setConfig }), Task_apS("flowChats", Task_of([])), Task_bind("wrappedSetting", ctx => { return Task_of( simpleWrap( (command => { const panel = settingPanel(command) return { tag: "span", view: s => { return h( "span", { style: { display: "contents" } }, [ panel(s), ((state = s), h( "button", { class: "fyc_button", style: { background: "rgba(0,0,0,0)", marginLeft: "10px", whiteSpace: "nowrap", }, onclick: togglePanel, }, [ h( "svg", { preserveAspectRatio: "xMidYMid meet", viewBox: "0 0 640 640", width: "15", height: "15", style: { position: "relative", top: "1px", }, }, [ h( "defs", {}, h("path", { id: "d1TbzTC1zI", d: "M135 58c25 14 67 30 82 35-7 49 16 109-15 149-50 71-19 184 64 213 74 31 165-18 183-95-3-38 23-62 58-36l120 55c-39 10-106 35-72 85 40 38 1 71-29 98-29 53-70-17-109-5-46 22-25 109-96 85h-55c-24-31-21-103-80-84-32 32-70 31-93-9l-35-36c4-40 57-96-6-120-45 5-58-32-52-68 2-19-4-41 3-59 35-15 100-22 77-79-48-43 1-84 35-115 5-6 12-12 20-14zM577 2c52 3 72 62 62 106-5 51 19 117-27 155-18 24 8 49 11 74-39-8-98-46-146-60-55-1-111 2-167-2-52-15-57-76-52-121S242 52 282 18c38-30 88-11 132-16h163z", }) ), h("use", { href: "#d1TbzTC1zI", opacity: "1", fill: "var(--iron-icon-fill-color, currentcolor)", "fill-opacity": "1", }), ] ), h( "span", { style: { position: "relative", top: "-2px", marginLeft: "8px,", }, }, hyperapp_text( getLang(state.lang)("setting") ) ), ] )), ] ) var state }, } })({ setConfig: ctx.setConfig, act: { clearFlowChats: async () => removeOldChats(0)(ctx.flowChats)(), }, }), ((getConfig = ctx.getConfig), { ...function_pipe( Object.entries(getConfig), es6_ReadonlyArray_map(([k, v]) => [k, v()]), Object.fromEntries ), showPanel: !1, bannedWordRegexsValid: !0, bannedWordRegexsError: "", mainTab: 0, logTab: 0, timingStepCount: parseInt( getConfig .timingFunction() .match(/^steps\((\d+),.+/)?.[1] ?? "150", 10 ), eventLog: [], editingInput: { id: "", committedState: void 0, value: "", }, }) ) ) var getConfig }), Task_bind("mainLog", ctx => Task_of( x => () => ctx.wrappedSetting.dispatch(s => ({ ...s, eventLog: appendLog(s.eventLog)(x), })) ) ), Task_bind("mixLog", ctx => Task_of( function_pipe( [ctx.mainLog, consoleLog], Reader_sequenceArray, es6_Reader_map(IO_sequenceArray) ) ) ) ), Task_chainFirstIOK(ctx => function_pipe( [ ["Version", "1.15.8"], ["User Agent", window.navigator.userAgent], ["UserConfig", JSON.stringify(ctx.userConfig)], ], es6_ReadonlyArray_map(ctx.mainLog), IO_sequenceArray ) ), Task_bind("cs", ctx => Task_of( function_pipe( ctx.configSubject, Object.entries, es6_ReadonlyArray_map(([k, value]) => [ k, function_pipe( value, (0, external_rxjs_namespaceObject.tap)(v => function_pipe( v, x => s => ({ ...s, [k]: x }), IO_of, IO_chainFirst( x => () => ctx.wrappedSetting.dispatch(x) ), es6_IO_chain(x => k in ctx.toggleChatButtonInit ? () => ctx.wrappedToggleChatBtn.dispatch(x) : () => {} ), x => () => requestAnimationFrame(x) )() ) ), ]), Object.fromEntries ) ) ), Task_apS("livePage", Task_fromIO(livePageYt)), Task_bind("liveElementKeys", ctx => Task_of(Object.keys(ctx.livePage)) ), Task_bind("live", ctx => Task_of( function_pipe( key => ({ ele: Option_none, read: ctx.livePage[key] }), initState => function_pipe( ctx.liveElementKeys, es6_ReadonlyArray_map(x => [x, initState(x)]), Object.fromEntries ) ) ) ), Task_apS("chatScreen", Task_fromIO(createChatScreen)), Task_bind("config$", ctx => function_pipe( ctx.cs, cs => (0, external_rxjs_namespaceObject.merge)( function_pipe( (0, external_rxjs_namespaceObject.merge)( cs.bannedWordRegexs, cs.bannedWords, cs.bannedUsers ), (0, external_rxjs_namespaceObject.startWith)(void 0), (0, external_rxjs_namespaceObject.tap)(() => { ctx.mainState.filterExp = Option_some( ((getConfig = ctx.getConfig), external_jsep_default()( `\nor([\nRA.some(anyPreds([\n flip(flow([matchedByText, RA.some]))(${JSON.stringify( getConfig.bannedWordRegexs() )}),\n flip(flow([inText, RA.some]))(${JSON.stringify( getConfig.bannedWords() )})\n]))(RA.compact([\n messageText,\n paymentInfo\n])),\nO.exists(\n flip(flow([eqText, RA.some]))(${JSON.stringify( getConfig.bannedUsers() )})\n)(authorID)\n])\n` )) ) var getConfig }) ), function_pipe( cs.fieldScale, (0, external_rxjs_namespaceObject.startWith)( ctx.getConfig.fieldScale() ), (0, external_rxjs_namespaceObject.tap)(scale => function_pipe( ctx.live.chatField.ele, fromOption, IOOption_chain(field => IOOption_fromIO(() => function_pipe( [ function_pipe( fromNullable(field.parentElement), es6_Option_map(x => () => { x.style.transformOrigin = (scale >= 1 ? "top" : "bottom") + " left" x.style.transform = `scale(${scale})` x.style.width = 100 / scale + "%" x.style.height = `${field.offsetHeight}px` }) ), function_pipe( ctx.live.chatScroller.ele, es6_Option_map(scroller => () => { scroller.scrollTop = scroller.scrollHeight }) ), ], ReadonlyArray_compact, IO_sequenceArray ) ) ) )() ) ), function_pipe( (0, external_rxjs_namespaceObject.merge)( function_pipe( (0, external_rxjs_namespaceObject.merge)( cs.font, cs.fontSize, cs.fontWeight, cs.laneCount, cs.minSpacing, cs.flowY1, cs.flowY2, function_pipe( cs.flowX1, (0, external_rxjs_namespaceObject.startWith)( ctx.getConfig.flowX1() ), (0, external_rxjs_namespaceObject.tap)(x => { ctx.chatScreen.style.left = 100 * x + "%" ctx.chatScreen.style.width = 100 * (ctx.getConfig.flowX2() - x) + "%" }) ), function_pipe( cs.flowX2, (0, external_rxjs_namespaceObject.tap)(x => { ctx.chatScreen.style.left = 100 * ctx.getConfig.flowX1() + "%" ctx.chatScreen.style.width = 100 * (x - ctx.getConfig.flowX1()) + "%" }) ), cs.textOnly ), (0, external_rxjs_namespaceObject.mapTo)({ render: !0, setAnimation: !0, }) ), function_pipe( (0, external_rxjs_namespaceObject.merge)( cs.color, cs.ownerColor, cs.moderatorColor, cs.memberColor, cs.shadowColor, cs.chatOpacity, cs.shadowFontWeight, cs.displayChats ), (0, external_rxjs_namespaceObject.mapTo)({ render: !0, }) ), function_pipe( cs.flowSpeed, (0, external_rxjs_namespaceObject.mapTo)({ setPlayState: !0, }) ), function_pipe( (0, external_rxjs_namespaceObject.merge)( function_pipe( cs.maxChatCount, (0, external_rxjs_namespaceObject.tap)(x => removeOldChats(x)(ctx.flowChats)() ) ), cs.noOverlap, cs.timingFunction ), (0, external_rxjs_namespaceObject.mapTo)({ setAnimation: !0, }) ) ), (0, external_rxjs_namespaceObject.throttleTime)( 180, void 0, { leading: !0, trailing: !0 } ), (0, external_rxjs_namespaceObject.tap)(config => function_pipe( ctx.flowChats, es6_ReadonlyArray_filter(x => !x.animationEnded), es6_ReadonlyArray_map(chat => function_pipe( { render: !1, setAnimation: !1, setPlayState: !1, ...config, }, x => function_pipe( [ function_pipe( renderChat(chat), fromPredicate(() => x.render) ), function_pipe( setChatAnimation(chat, ctx.flowChats), fromPredicate(() => x.setAnimation), alt(() => function_pipe( setChatPlayState(chat), fromPredicate(() => x.setPlayState) ) ) ), ], ReadonlyArray_compact, es6_ReadonlyArray_map( (function (a) { return function (f) { return f(a) } })(ctx.mainState) ), IO_sequenceArray ) ) ), IO_sequenceArray )() ) ), cs.lang, cs.maxChatLength, cs.simplifyChatField, cs.createBanButton, cs.createChats, cs.displayModName, cs.displaySuperChatAuthor, cs.fieldScale, cs.bannedWords, cs.bannedWordRegexs, cs.bannedUsers ), Task_of ) ), Task_apS( "documentMutationPair", Task_fromIO(observePair(MutationObserver)) ), Task_apS( "chatMutationPair", Task_fromIO(observePair(MutationObserver)) ), Task_apS( "playerResizePair", Task_fromIO(observePair(ResizeObserver)) ), Task_bind("all$", ctx => { return function_pipe( { css: mainCss(), eq: ((E = eqStrict), { equals: function (x, y) { return ( x === y || (Option_isNone(x) ? Option_isNone(y) : !Option_isNone(y) && E.equals(x.value, y.value)) ) }, }).equals, initDelay: 100, urlDelay: 1700, changeDetectInterval: 700, }, IO_of, IO_apS("chatScreen", createChatScreen), IO_apS("documentMutationPair", observePair(MutationObserver)), IO_apS("chatMutationPair", observePair(MutationObserver)), IO_apS("playerResizePair", observePair(ResizeObserver)), es6_IO_map(c => function_pipe( ctx.reinitSubject, (0, external_rxjs_namespaceObject.observeOn)( external_rxjs_namespaceObject.asyncScheduler ), (0, external_rxjs_namespaceObject.delay)(c.initDelay), (0, external_rxjs_namespaceObject.tap)( ctx.mixLog(["Init"]) ), (0, external_rxjs_namespaceObject.switchMap)(() => function_pipe( (0, external_rxjs_namespaceObject.interval)( c.changeDetectInterval ), (0, external_rxjs_namespaceObject.filter)(() => function_pipe( ctx.liveElementKeys, es6_ReadonlyArray_map(key => function_pipe( ctx.live[key].read(), fromPredicate( newEle => !c.eq(ctx.live[key].ele, newEle) ), es6_Option_map(x => () => { ctx.live[key].ele = x }), es6_Option_map( IO_apSecond(ctx.mixLog([`${key} changed`])) ) ) ), ReadonlyArray_compact, IO_sequenceArray, es6_IO_map(ReadonlyArray_isNonEmpty) )() ), (0, external_rxjs_namespaceObject.startWith)(0) ) ), (0, external_rxjs_namespaceObject.tap)( ctx.mixLog(["Loading..."]) ), (0, external_rxjs_namespaceObject.tap)(() => { removeOldChats(0)(ctx.flowChats)() ctx.documentMutationPair.observer.disconnect() ctx.documentMutationPair.observer.observe(document, { childList: !0, subtree: !0, }) ctx.chatMutationPair.observer.disconnect() ctx.playerResizePair.observer.disconnect() document.head.append(c.css) function_pipe( [ function_pipe( ctx.live.chatField.ele, es6_Option_map(x => () => { ;((chatField = x), () => function_pipe( fromNullable(chatField.parentElement), es6_Option_map(x => () => { x.style.overflow = "unset" }) ))() var chatField ctx.chatMutationPair.observer.observe(x, { childList: !0, }) }) ), function_pipe( ctx.live.chatTicker.ele, es6_Option_map( x => () => ctx.chatMutationPair.observer.observe(x, { childList: !0, }) ) ), function_pipe( ctx.live.player.ele, es6_Option_map(x => () => { ctx.playerResizePair.observer.observe(x) x.insertAdjacentElement( "afterbegin", ctx.chatScreen ) }) ), function_pipe( ctx.live.toggleChatBtnParent.ele, es6_Option_map( x => () => x.append(ctx.wrappedToggleChatBtn.node) ) ), function_pipe( ctx.live.settingNextElement.ele, es6_Option_map(x => () => { x.insertAdjacentElement( "beforebegin", ctx.wrappedSetting.node ) }) ), ], ReadonlyArray_compact, ReadonlyArray_append( function_pipe( ctx.live.video.ele, filter(x => !x.paused), alt(() => ctx.live.offlineSlate.ele), Option_isSome, x => () => { ctx.mainState.chatPlaying = x } ) ), IO_sequenceArray )() }), (0, external_rxjs_namespaceObject.switchMap)(() => (0, external_rxjs_namespaceObject.merge)( function_pipe( (0, external_rxjs_namespaceObject.fromEvent)( ctx.channel, "message" ), (0, external_rxjs_namespaceObject.tap)( ([key, val]) => function_pipe( [ "lang", "bannedWords", "bannedWordRegexs", "bannedUsers", "simplifyChatField", "createBanButton", "fieldScale", ].includes(key), x => x ? () => ctx.setConfigPlain[key](val) : () => {} )() ) ), ...function_pipe( ctx.configKeys, es6_ReadonlyArray_map(key => function_pipe( ctx.cs[key], (0, external_rxjs_namespaceObject.startWith)( ctx.getConfig[key]() ), (0, external_rxjs_namespaceObject.bufferCount)( 2, 1 ), (0, external_rxjs_namespaceObject.map)( ([x, y]) => (0, external_DeepDiff_namespaceObject.diff)( x, y ) ), (0, external_rxjs_namespaceObject.tap)(x => ctx.mainLog([ `Config ${key}`, JSON.stringify(x, void 0, 2), ])() ) ) ) ), ctx.config$, function_pipe( ctx.live.video.ele, match( () => external_rxjs_namespaceObject.EMPTY, x => { return function_pipe( ((video = x), (0, external_rxjs_namespaceObject.merge)( function_pipe( (0, external_rxjs_namespaceObject.fromEvent)( video, "playing" ), (0, external_rxjs_namespaceObject.mapTo)( !0 ) ), function_pipe( (0, external_rxjs_namespaceObject.fromEvent)( video, "waiting" ), (0, external_rxjs_namespaceObject.mapTo)( !1 ) ), function_pipe( (0, external_rxjs_namespaceObject.fromEvent)( video, "pause" ), (0, external_rxjs_namespaceObject.mapTo)( !1 ) ) )), (0, external_rxjs_namespaceObject.map)( playing => playing || Option_isSome(ctx.live.offlineSlate.ele) ), (0, external_rxjs_namespaceObject.tap)( chatPlaying => { ctx.mainState.chatPlaying = chatPlaying ctx.flowChats.forEach(chat => setChatPlayState(chat)(ctx.mainState)() ) } ) ) var video } ) ), function_pipe( ctx.chatMutationPair.subject, (0, external_rxjs_namespaceObject.map)( onChatFieldMutate( ctx.chatScreen, ctx.flowChats, ctx.mainState, ctx.setConfig, ctx.mainLog ) ), (0, external_rxjs_namespaceObject.tap)(x => x()) ), function_pipe( ctx.documentMutationPair.subject, (0, external_rxjs_namespaceObject.map)( () => window.location.href ), (0, external_rxjs_namespaceObject.distinctUntilChanged)(), (0, external_rxjs_namespaceObject.skip)(1), (0, external_rxjs_namespaceObject.tap)(x => { ctx.mixLog(["URL Changed", x])() removeOldChats(0)(ctx.flowChats)() ctx.mixLog([`Wait for ${c.urlDelay}ms...`])() }), (0, external_rxjs_namespaceObject.delay)( c.urlDelay ), (0, external_rxjs_namespaceObject.tap)( ctx.reinitialize ) ), function_pipe( ctx.playerResizePair.subject, (0, external_rxjs_namespaceObject.throttleTime)( 500, void 0, { leading: !0, trailing: !0 } ), (0, external_rxjs_namespaceObject.startWith)([]), (0, external_rxjs_namespaceObject.map)( () => ctx.live.player.ele ), (0, external_rxjs_namespaceObject.map)( es6_Option_map(x => x.getBoundingClientRect()) ), (0, external_rxjs_namespaceObject.tap)(x => { return ( (rect = x), (flowChats = ctx.flowChats), (mainState = ctx.mainState), (mainLog = ctx.mainLog), function_pipe( rect, match( () => () => {}, x => () => { mainLog(["Resize detected"])() mainState.playerRect = x flowChats.forEach(chat => { renderChat(chat)(mainState)() setChatAnimation( chat, flowChats )(mainState)() }) } ) )() ) var rect, flowChats, mainState, mainLog }) ) ) ), (0, external_rxjs_namespaceObject.retryWhen)(e => function_pipe( e, (0, external_rxjs_namespaceObject.tap)( ctx.mixLog(["Errored", e]) ), (0, external_rxjs_namespaceObject.delay)(5e3), (0, external_rxjs_namespaceObject.tap)(x => ctx.mixLog(x)() ), (0, external_rxjs_namespaceObject.tap)( ctx.reinitialize ) ) ) ) ), Task_fromIO ) var E }), Task_chainFirstIOK( ctx => () => ctx.all$.subscribe({ error: x => ctx.mixLog(["Stream error", x])(), complete: ctx.mixLog(["Stream complete"]), }) ), Task_chainFirstIOK(ctx => ctx.reinitialize) )() } catch (error) { external_log_namespaceObject.info("【FYC】 Error", error) } })() }, 633: () => {}, }, __webpack_module_cache__ = {} function __webpack_require__(moduleId) { var cachedModule = __webpack_module_cache__[moduleId] if (void 0 !== cachedModule) return cachedModule.exports var module = (__webpack_module_cache__[moduleId] = { exports: {} }) __webpack_modules__[moduleId](module, module.exports, __webpack_require__) return module.exports } __webpack_require__.n = module => { var getter = module && module.__esModule ? () => module.default : () => module __webpack_require__.d(getter, { a: getter }) return getter } __webpack_require__.d = (exports, definition) => { for (var key in definition) __webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key) && Object.defineProperty(exports, key, { enumerable: !0, get: definition[key], }) } __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop) __webpack_require__(142) })()