From 3b8c40287322e2a06ae1f892184c2a87cd0648d8 Mon Sep 17 00:00:00 2001 From: zomo Date: Sat, 18 Apr 2026 23:44:01 -0500 Subject: [PATCH] functional ttv-obfuscated-names --- dist/ttv-obfuscated-names.user.js | 335 +++++++++++++++++++++ readme.md | 4 + scripts/ttv-obfuscated-names/dom.ts | 193 ++++++++++++ scripts/ttv-obfuscated-names/main.ts | 60 ++++ scripts/ttv-obfuscated-names/meta.json | 9 + scripts/ttv-obfuscated-names/obfuscator.ts | 25 ++ scripts/ttv-obfuscated-names/options.ts | 42 +++ scripts/ttv-obfuscated-names/storage.ts | 130 ++++++++ scripts/ttv-obfuscated-names/todo.md | 48 +++ scripts/ttv-obfuscated-names/tsconfig.json | 17 ++ scripts/ttv-obfuscated-names/util.ts | 31 ++ 11 files changed, 894 insertions(+) create mode 100644 dist/ttv-obfuscated-names.user.js create mode 100644 scripts/ttv-obfuscated-names/dom.ts create mode 100644 scripts/ttv-obfuscated-names/main.ts create mode 100644 scripts/ttv-obfuscated-names/meta.json create mode 100644 scripts/ttv-obfuscated-names/obfuscator.ts create mode 100644 scripts/ttv-obfuscated-names/options.ts create mode 100644 scripts/ttv-obfuscated-names/storage.ts create mode 100644 scripts/ttv-obfuscated-names/todo.md create mode 100644 scripts/ttv-obfuscated-names/tsconfig.json create mode 100644 scripts/ttv-obfuscated-names/util.ts diff --git a/dist/ttv-obfuscated-names.user.js b/dist/ttv-obfuscated-names.user.js new file mode 100644 index 0000000..19c5e1a --- /dev/null +++ b/dist/ttv-obfuscated-names.user.js @@ -0,0 +1,335 @@ +// ==UserScript== +// @name ttv obfuscated names +// @namespace zomo.dev +// @match https://www.twitch.tv/* +// @version 0.1 +// @runat document-end +// @downloadURL https://git.zomo.dev/zomo/browser-scripts/raw/branch/main/dist/ttv-obfuscated-names.user.js +// @supportURL https://git.zomo.dev/zomo/browser-scripts/issues +// @homepageURL https://git.zomo.dev/zomo/browser-scripts +// ==/UserScript== +var ignoreMod = false +var nameImages = { + personimage1: + 'data:image/jpeg;base64,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bnRGI1JsdAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBuAAAAAAAAAAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVudEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkAAAAAAAA4QklNA+0AAAAAABAA8AAAAAEAAQDwAAAAAQABOEJJTQQmAAAAAAAOAAAAAAAAAAAAAD+AAAA4QklNBA0AAAAAAAQAAAAeOEJJTQQZAAAAAAAEAAAAHjhCSU0D8wAAAAAACQAAAAAAAAAAAQA4QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0EAAAAAAAAAgAFOEJJTQQCAAAAAAAOAAAAAAAAAAAAAAAAAAA4QklNBDAAAAAAAAcBAQEBAQEBADhCSU0ELQAAAAAABgABAAAADzhCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAANPAAAABgAAAAAAAAAAAAAKbgAAC9YAAAANAEIAYQBuAGEAbgBhAC0AUwBpAG4AZwBsAGUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAC9YAAApuAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAApuAAAAAFJnaHRsb25nAAAL1gAAAAZz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ZG9iZS5jb20vZXhpZi8xLjAvYXV4LyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOmNycz0iaHR0cDovL25zLmFkb2JlLmNvbS9jYW1lcmEtcmF3LXNldHRpbmdzLzEuMC8iIGRjOmZvcm1hdD0iaW1hZ2UvanBlZyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcDpNb2RpZnlEYXRlPSIyMDE1LTAzLTE4VDE5OjM0OjAxLTA0OjAwIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxMi0wMy0yMFQxNjoyMjoxMCIgeG1wOlJhdGluZz0iMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxNS0wMy0xOFQxOTozNDowMS0wNDowMCIgYXV4OkxlbnNJbmZvPSI3MC8xIDIxMC8xIDQvMSA0LzEiIGF1eDpMZW5zPSI3MC0yMTBtbSBGNCIgYXV4OkxlbnNJRD0iMjU1NTEiIHBob3Rvc2hvcDpEYXRlQ3JlYXRlZD0iMjAxMi0wMy0yMFQxNjoyMjoxMCIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9IkFkb2JlIFJHQiAoMTk5OCkiIHBob3Rvc2hvcDpIaXN0b3J5PSIyMDE1LTAzLTE4VDE5OjE3OjQzLTA0OjAwCUZpbGUgRFNDMDMwNDUuQVJXIG9wZW5lZCYjeEE7MjAxNS0wMy0xOFQxOTozMzo1My0wNDowMAlGaWxlIEQ6XFdpa2lwZWRpYSAtIFBob3Rvc1xGb29kIC0gRnJ1aXQgJmFtcDsgVmVnZXRhYmxlc1xCYW5hbmEtU2luZ2xlLnBzZCBzYXZlZCYjeEE7MjAxNS0wMy0xOFQxOTozNDowMS0wNDowMAlGaWxlIEQ6XFdpa2lwZWRpYSAtIFBob3Rvc1xGb29kIC0gRnJ1aXQgJmFtcDsgVmVnZXRhYmxlc1xCYW5hbmEtU2luZ2xlLmpwZyBzYXZlZCYjeEE7IiB4bXBNTTpEb2N1bWVudElEPSIwNDE3MjAyMDFBNjMzQTdCMjFBOTNGQTM2OTA0RjY1MSIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSIwNDE3MjAyMDFBNjMzQTdCMjFBOTNGQTM2OTA0RjY1MSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2RTc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgY3JzOlJhd0ZpbGVOYW1lPSJEU0MwMzA0NS5BUlciIGNyczpWZXJzaW9uPSI2LjciIGNyczpQcm9jZXNzVmVyc2lvbj0iNS43IiBjcnM6V2hpdGVCYWxhbmNlPSJDdXN0b20iIGNyczpUZW1wZXJhdHVyZT0iNDg1MCIgY3JzOlRpbnQ9Iis4IiBjcnM6RXhwb3N1cmU9Ii0xLjMwIiBjcnM6U2hhZG93cz0iMTgiIGNyczpCcmlnaHRuZXNzPSIrNDUiIGNyczpDb250cmFzdD0iKzQ0IiBjcnM6U2F0dXJhdGlvbj0iKzIiIGNyczpTaGFycG5lc3M9IjI1IiBjcnM6THVtaW5hbmNlU21vb3RoaW5nPSIwIiBjcnM6Q29sb3JOb2lzZVJlZHVjdGlvbj0iMjUiIGNyczpWaWduZXR0ZUFtb3VudD0iMCIgY3JzOlNoYWRvd1RpbnQ9IjAiIGNyczpSZWRIdWU9IjAiIGNyczpSZWRTYXR1cmF0aW9uPSIwIiBjcnM6R3JlZW5IdWU9IjAiIGNyczpHcmVlblNhdHVyYXRpb249IjAiIGNyczpCbHVlSHVlPSIwIiBjcnM6Qmx1ZVNhdHVyYXRpb249IjAiIGNyczpGaWxsTGlnaHQ9IjAiIGNyczpWaWJyYW5jZT0iKzE4IiBjcnM6SGlnaGxpZ2h0UmVjb3Zlcnk9IjE1IiBjcnM6Q2xhcml0eT0iKzMzIiBjcnM6RGVmcmluZ2U9IjAiIGNyczpIdWVBZGp1c3RtZW50UmVkPSIwIiBjcnM6SHVlQWRqdXN0bWVudE9yYW5nZT0iMCIgY3JzOkh1ZUFkanVzdG1lbnRZZWxsb3c9IjAiIGNyczpIdWVBZGp1c3RtZW50R3JlZW49IjAiIGNyczpIdWVBZGp1c3RtZW50QXF1YT0iMCIgY3JzOkh1ZUFkanVzdG1lbnRCbHVlPSIwIiBjcnM6SHVlQWRqdXN0bWVudFB1cnBsZT0iMCIgY3JzOkh1ZUFkanVzdG1lbnRNYWdlbnRhPSIwIiBjcnM6U2F0dXJhdGlvbkFkanVzdG1lbnRSZWQ9IjAiIGNyczpTYXR1cmF0aW9uQWRqdXN0bWVudE9yYW5nZT0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50WWVsbG93PSIwIiBjcnM6U2F0dXJhdGlvbkFkanVzdG1lbnRHcmVlbj0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50QXF1YT0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50Qmx1ZT0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50UHVycGxlPSIwIiBjcnM6U2F0dXJhdGlvbkFkanVzdG1lbnRNYWdlbnRhPSIwIiBjcnM6THVtaW5hbmNlQWRqdXN0bWVudFJlZD0iMCIgY3JzOkx1bWluYW5jZUFkanVzdG1lbnRPcmFuZ2U9IjAiIGNyczpMdW1pbmFuY2VBZGp1c3RtZW50WWVsbG93PSIwIiBjcnM6THVtaW5hbmNlQWRqdXN0bWVudEdyZWVuPSIwIiBjcnM6THVtaW5hbmNlQWRqdXN0bWVudEFxdWE9IjAiIGNyczpMdW1pbmFuY2VBZGp1c3RtZW50Qmx1ZT0iMCIgY3JzOkx1bWluYW5jZUFkanVzdG1lbnRQdXJwbGU9IjAiIGNyczpMdW1pbmFuY2VBZGp1c3RtZW50TWFnZW50YT0iMCIgY3JzOlNwbGl0VG9uaW5nU2hhZG93SHVlPSIwIiBjcnM6U3BsaXRUb25pbmdTaGFkb3dTYXR1cmF0aW9uPSIwIiBjcnM6U3BsaXRUb25pbmdIaWdobGlnaHRIdWU9IjAiIGNyczpTcGxpdFRvbmluZ0hpZ2hsaWdodFNhdHVyYXRpb249IjAiIGNyczpTcGxpdFRvbmluZ0JhbGFuY2U9IjAiIGNyczpQYXJhbWV0cmljU2hhZG93cz0iMCIgY3JzOlBhcmFtZXRyaWNEYXJrcz0iMCIgY3JzOlBhcmFtZXRyaWNMaWdodHM9IjAiIGNyczpQYXJhbWV0cmljSGlnaGxpZ2h0cz0iMCIgY3JzOlBhcmFtZXRyaWNTaGFkb3dTcGxpdD0iMjUiIGNyczpQYXJhbWV0cmljTWlkdG9uZVNwbGl0PSI1MCIgY3JzOlBhcmFtZXRyaWNIaWdobGlnaHRTcGxpdD0iNzUiIGNyczpTaGFycGVuUmFkaXVzPSIrMS4wIiBjcnM6U2hhcnBlbkRldGFpbD0iMjUiIGNyczpTaGFycGVuRWRnZU1hc2tpbmc9IjAiIGNyczpQb3N0Q3JvcFZpZ25ldHRlQW1vdW50PSIwIiBjcnM6R3JhaW5BbW91bnQ9IjAiIGNyczpDb2xvck5vaXNlUmVkdWN0aW9uRGV0YWlsPSI1MCIgY3JzOkxlbnNQcm9maWxlRW5hYmxlPSIwIiBjcnM6TGVuc01hbnVhbERpc3RvcnRpb25BbW91bnQ9IjAiIGNyczpQZXJzcGVjdGl2ZVZlcnRpY2FsPSIwIiBjcnM6UGVyc3BlY3RpdmVIb3Jpem9udGFsPSIwIiBjcnM6UGVyc3BlY3RpdmVSb3RhdGU9IjAuMCIgY3JzOlBlcnNwZWN0aXZlU2NhbGU9IjEwMCIgY3JzOkF1dG9MYXRlcmFsQ0E9IjEiIGNyczpFeHBvc3VyZTIwMTI9IjAuMDAiIGNyczpDb250cmFzdDIwMTI9IjAiIGNyczpIaWdobGlnaHRzMjAxMj0iMCIgY3JzOlNoYWRvd3MyMDEyPSIwIiBjcnM6V2hpdGVzMjAxMj0iMCIgY3JzOkJsYWNrczIwMTI9IjAiIGNyczpDbGFyaXR5MjAxMj0iMCIgY3JzOkNvbnZlcnRUb0dyYXlzY2FsZT0iRmFsc2UiIGNyczpUb25lQ3VydmVOYW1lPSJNZWRpdW0gQ29udHJhc3QiIGNyczpUb25lQ3VydmVOYW1lMjAxMj0iTGluZWFyIiBjcnM6Q2FtZXJhUHJvZmlsZT0iQWRvYmUgU3RhbmRhcmQiIGNyczpDYW1lcmFQcm9maWxlRGlnZXN0PSI2NjJEM0M0OUE2MTNFMDc0Mjk1RUUxODhBN0U5OEJCNiIgY3JzOkxlbnNQcm9maWxlU2V0dXA9IkxlbnNEZWZhdWx0cyIgY3JzOkhhc1NldHRpbmdzPSJUcnVlIiBjcnM6SGFzQ3JvcD0iRmFsc2UiIGNyczpBbHJlYWR5QXBwbGllZD0iVHJ1ZSI+DQoJCQk8ZGM6ZGVzY3JpcHRpb24+DQoJCQkJPHJkZjpBbHQ+DQoJCQkJCTxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+U09OWSBEU0M8L3JkZjpsaT4NCgkJCQk8L3JkZjpBbHQ+DQoJCQk8L2RjOmRlc2NyaXB0aW9uPg0KCQkJPHhtcE1NOkhpc3Rvcnk+DQoJCQkJPHJkZjpTZXE+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpCMTY3RkZGRjk5Q0JFNDExOUY0NUZCQ0MwMTgzODI0QiIgc3RFdnQ6d2hlbj0iMjAxNS0wMy0xOFQxOToxNzo0Mi0wNDowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENhbWVyYSBSYXcgNi43IChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPg0KCQkJCQk8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NkI3NjY3NThDMkNERTQxMThBREZBNDg0RjQ5NjUwNjciIHN0RXZ0OndoZW49IjIwMTUtMDMtMThUMTk6MzM6NTMtMDQ6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIgc3RFdnQ6Y2hhbmdlZD0iLyIvPg0KCQkJCQk8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL3RpZmYgdG8gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCIvPg0KCQkJCQk8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iZGVyaXZlZCIgc3RFdnQ6cGFyYW1ldGVycz0iY29udmVydGVkIGZyb20gaW1hZ2UvdGlmZiB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2Qzc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgc3RFdnQ6d2hlbj0iMjAxNS0wMy0xOFQxOTozMzo1My0wNDowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2RDc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgc3RFdnQ6d2hlbj0iMjAxNS0wMy0xOFQxOTozNDowMS0wNDowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9qcGVnIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL2pwZWciLz4NCgkJCQkJPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjZFNzY2NzU4QzJDREU0MTE4QURGQTQ4NEY0OTY1MDY3IiBzdEV2dDp3aGVuPSIyMDE1LTAzLTE4VDE5OjM0OjAxLTA0OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L3htcE1NOkhpc3Rvcnk+DQoJCQk8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2RDc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgc3RSZWY6ZG9jdW1lbnRJRD0iMDQxNzIwMjAxQTYzM0E3QjIxQTkzRkEzNjkwNEY2NTEiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0iMDQxNzIwMjAxQTYzM0E3QjIxQTkzRkEzNjkwNEY2NTEiLz4NCgkJCTxjcnM6VG9uZUN1cnZlPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4zMiwgMjI8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT42NCwgNTY8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4xMjgsIDEyODwvcmRmOmxpPg0KCQkJCQk8cmRmOmxpPjE5MiwgMTk2PC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmU+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVJlZD4NCgkJCQk8cmRmOlNlcT4NCgkJCQkJPHJkZjpsaT4wLCAwPC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmVSZWQ+DQoJCQk8Y3JzOlRvbmVDdXJ2ZUdyZWVuPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZUdyZWVuPg0KCQkJPGNyczpUb25lQ3VydmVCbHVlPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZUJsdWU+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVBWMjAxMj4NCgkJCQk8cmRmOlNlcT4NCgkJCQkJPHJkZjpsaT4wLCAwPC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmVQVjIwMTI+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVBWMjAxMlJlZD4NCgkJCQk8cmRmOlNlcT4NCgkJCQkJPHJkZjpsaT4wLCAwPC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmVQVjIwMTJSZWQ+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVBWMjAxMkdyZWVuPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZVBWMjAxMkdyZWVuPg0KCQkJPGNyczpUb25lQ3VydmVQVjIwMTJCbHVlPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZVBWMjAxMkJsdWU+DQoJCTwvcmRmOkRlc2NyaXB0aW9uPg0KCTwvcmRmOlJERj4NCjwveDp4bXBtZXRhPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0ndyc/Pv/iAkBJQ0NfUFJPRklMRQABAQAAAjBBREJFAhAAAG1udHJSR0IgWFlaIAfPAAYAAwAAAAAAAGFjc3BBUFBMAAAAAG5vbmUAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMtQURCRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmNwcnQAAAD8AAAAMmRlc2MAAAEwAAAAa3d0cHQAAAGcAAAAFGJrcHQAAAGwAAAAFHJUUkMAAAHEAAAADmdUUkMAAAHUAAAADmJUUkMAAAHkAAAADnJYWVoAAAH0AAAAFGdYWVoAAAIIAAAAFGJYWVoAAAIcAAAAFHRleHQAAAAAQ29weXJpZ2h0IDE5OTkgQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQAAABkZXNjAAAAAAAAABFBZG9iZSBSR0IgKDE5OTgpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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', +} +var colorList = ['#ddd', '#444', '#400', '#040', '#004'] +var nameList = [ + { + username: 'person', + color: '#f00', + image: 'personimage1', + }, + // { + // username: 'bot', + // color: ['#0f0', '#00f'], + // image: 'personimage1', + // }, + // { + // username: 'other', + // color: null, + // image: 'personimage1', + // }, +] + +var { storedUsers, nameListUsed, nameListCount } = loadStoredUserData() +function getStoredUser(name) { + if (name in storedUsers) { + return storedUsers[name] + } + return null +} +function setStoredUser(name, details) { + storedUsers[name] = details + updateStorageData() +} +function increaseNameListUsed(name) { + nameListUsed[name] = (nameListUsed[name] ?? 0) + 1 + updateStorageData() +} +function increaseNameListCount() { + nameListCount++ + updateStorageData() +} +function updateStorageData() { + localStorage.setItem( + 'obf-data', + JSON.stringify({ + storedUsers, + nameListUsed, + nameListCount, + }) + ) +} +function loadStoredUserData() { + const dataStr = localStorage.getItem('obf-data') + if (dataStr === null) { + return { + storedUsers: {}, + nameListUsed: {}, + nameListCount: 0, + } + } + try { + const data = JSON.parse(dataStr) + return data + } catch (e) { + return { + storedUsers: {}, + nameListUsed: {}, + nameListCount: 0, + } + } +} +function getRandomName() { + const startingIndex = Math.round(Math.random() * (nameList.length - 1)) + let foundName = false + let currentIndex = startingIndex + for (let i = 0; i < nameList.length; i++) { + currentIndex = (startingIndex + i) % nameList.length + let isUsed = nameListUsed[nameList[currentIndex].username] ?? 0 + if (isUsed === nameListCount) { + foundName = true + break + } + } + if (!foundName) { + increaseNameListCount() + currentIndex = startingIndex + } + increaseNameListUsed(nameList[currentIndex].username) + const newName = nameList[currentIndex] + const newNameInstance = { + username: newName.username, + image: newName.image, + color: '', + nameCount: nameListCount, + } + if (Array.isArray(newName.color)) { + const color = + newName.color[ + Math.round(Math.random() * (newName.color.length - 1)) + ] + newNameInstance.color = color + return newNameInstance + } + if (newName.color === null) { + const color = + colorList[Math.round(Math.random() * (colorList.length - 1))] + newNameInstance.color = color + return newNameInstance + } + newNameInstance.color = newName.color + return newNameInstance +} + +function obfuscator(chatMessage) { + if (ignoreMod && chatMessage.isMod) { + return null + } + chatMessage.username = chatMessage.username.toLowerCase() + const userData = getStoredUser(chatMessage.username) + if (userData !== null) { + return userData + } + const newName = getRandomName() + setStoredUser(chatMessage.username, newName) + return newName +} + +function innermostElement(elem) { + if (elem.children.length === 0) { + return elem + } + return innermostElement(elem.children[0]) +} +function usernameTemplateSuffix(newChatMessage) { + if (newChatMessage.nameCount === 0) { + return '' + } + return `${newChatMessage.nameCount}` +} +function usernameImageTemplateSuffix(newChatMessage) { + if (newChatMessage.nameCount === 0) { + return '' + } + return `${newChatMessage.nameCount}` +} + +function loadChatMessage(chatboxMessage) { + const chatboxMessageInner = chatboxMessage.querySelector( + '.chat-line__message' + ) + if (!chatboxMessageInner) { + return + } + const chatboxBadgeContainer = chatboxMessage.querySelector( + '.chat-line__message--badges' + ) + if (!chatboxBadgeContainer) { + console.error("found message, couldn't find badges") + return + } + const chatboxUser = chatboxMessage.querySelector('.chat-line__username') + if (!chatboxUser) { + console.error("found message, couldn't find user") + return + } + const chatboxUserInner = chatboxUser.querySelector( + '.chat-author__display-name' + ) + if (!chatboxUserInner) { + console.error("found message, couldn't find userInner") + return + } + chatboxMessage.classList.add('obf-loaded') + if (chatboxUser.classList.contains('seventv-paint')) { + chatboxUser.classList.remove('seventv-paint') + } + let isMod = false + for (const badge of chatboxBadgeContainer.children) { + if ( + badge.hasAttribute('data-badge') && + (badge.getAttribute('data-badge') === 'moderator' || + badge.getAttribute('data-badge') === 'broadcaster') + ) { + isMod = true + chatboxMessage.classList.add('ismod') + } + } + const chatMessage = { + username: chatboxUserInner.textContent, + isMod, + } + const newChatMessage = obfuscator(chatMessage) + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, chatboxUserInner, chatboxUser) + } + loadReplyLine(chatboxMessage) + loadMessageMentions(chatboxMessage) +} +function loadReplyLine(chatboxMessage) { + const replyline = chatboxMessage.querySelector('.ffz--fix-reply-line') + const replyUsername = replyline?.querySelector('p > span:nth-child(1)') + if (!replyUsername) { + return + } + const chatMessage = { + username: replyUsername.textContent.replace(/^@/, ''), + isMod: false, + } + const newChatMessage = obfuscator(chatMessage) + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, replyUsername, void 0, '@') + } +} +function loadMessageMentions(chatboxMessage) { + function eachMention(messageMention) { + const chatMessage = { + username: messageMention.textContent.replace(/^@/, ''), + isMod: false, + } + const newChatMessage = obfuscator(chatMessage) + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, messageMention, void 0, '@') + } + } + const messageMentions = chatboxMessage.querySelectorAll( + '.chat-line__message-mention' + ) + for (const messageMention of messageMentions) { + eachMention(messageMention) + } +} +function loadAdditionalUserNames(chatboxMessage) { + const chatterNames = chatboxMessage.querySelectorAll('.chatter-name') + for (const chatterName of chatterNames) { + chatboxMessage.classList.add('obf-loaded') + const chatterNameBox = innermostElement(chatterName) + const username = chatterNameBox.textContent + if (!username) { + continue + } + const chatMessage = { + username, + isMod: false, + } + const newChatMessage = obfuscator(chatMessage) + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, chatterNameBox) + } + } +} +function setUsernameDetails(newChatMessage, textbox, colorbox, prefixStr = '') { + const username = `${newChatMessage.username}${usernameTemplateSuffix(newChatMessage)}` + const imageName = newChatMessage.image + if (imageName) { + const image = nameImages[imageName] + const img = document.createElement('img') + img.classList.add('obf-image', 'ffz--pointer-events', 'ffz-tooltip') + img.setAttribute('data-tooltip-type', 'html') + img.setAttribute('data-title', username) + img.setAttribute('alt', username) + img.setAttribute('src', image) + const prefix = document.createElement('span') + prefix.textContent = prefixStr + const suffix = document.createElement('span') + suffix.textContent = usernameImageTemplateSuffix(newChatMessage) + textbox.replaceChildren(prefix, img, suffix) + } else { + textbox.textContent = `${prefixStr}${username}` + } + if (colorbox) { + colorbox.style.color = newChatMessage.color + } +} + +var OBSERVER_RATE_LIMIT = 1 +var observerLastRun = 0 +function observerCallback() { + if (Date.now() - observerLastRun < OBSERVER_RATE_LIMIT) { + return + } + observerLastRun = Date.now() + const chatbox = document.querySelector( + '.chat-scrollable-area__message-container' + ) + const chatboxMessages = Array.from(chatbox?.children ?? []) + for (const chatboxMessage of chatboxMessages) { + if (chatboxMessage.classList.contains('obf-loaded')) { + continue + } + loadChatMessage(chatboxMessage) + loadAdditionalUserNames(chatboxMessage) + } +} +var observer = new MutationObserver(observerCallback) +observer.observe(document, { attributes: true, childList: true, subtree: true }) +var styleAddition = document.createElement('style') +styleAddition.innerHTML = ` +.chat-line__message--badges { + display: none; +} +.ismod .chat-line__message--badges { + display: inline; +} +.ismod .chat-line__message--badges > span { + display: none; +} +.ismod .chat-line__message--badges > span[data-badge="moderator"], +.ismod .chat-line__message--badges > span[data-badge="broadcaster"] { + display: inline-block; +} + +.seventv-paint { + background-image: none !important; +} + +img.obf-image { + vertical-align: middle; + margin: -0.5rem 0; + + height: 1.8rem; +} +` +document.head.appendChild(styleAddition) diff --git a/readme.md b/readme.md index e972cb0..d2832be 100644 --- a/readme.md +++ b/readme.md @@ -17,6 +17,10 @@ Requires Violentmonkey (or Tampermonkey etc): [Chrome](https://chrome.google.com - **zomo.dev** v1.0 - `https://optifine.net/*` - automatically grab optifine links through the ads +- [ttv obfuscated names](https://git.zomo.dev/zomo/browser-scripts/raw/branch/main/dist/ttv-obfuscated-names.user.js) + - **zomo.dev** v0.1 + - `https://www.twitch.tv/*` + - - [Twitch Clickable Video](https://git.zomo.dev/zomo/browser-scripts/raw/branch/main/dist/twitch-clickable-video.user.js) - **zomo.dev** v1.1 - `https://www.twitch.tv/*` diff --git a/scripts/ttv-obfuscated-names/dom.ts b/scripts/ttv-obfuscated-names/dom.ts new file mode 100644 index 0000000..5e41cb4 --- /dev/null +++ b/scripts/ttv-obfuscated-names/dom.ts @@ -0,0 +1,193 @@ +import { obfuscator } from './obfuscator' +import { NameConfigInstance, nameImages } from './options' +import { + ChatMessage, + innermostElement, + usernameImageTemplateSuffix, + usernameTemplateSuffix, +} from './util' + +export function loadChatMessage(chatboxMessage: Element) { + // only chat messages + const chatboxMessageInner = chatboxMessage.querySelector( + '.chat-line__message' + ) + if (!chatboxMessageInner) { + return + } + + // get chatbox details + const chatboxBadgeContainer = chatboxMessage.querySelector( + '.chat-line__message--badges' + ) + if (!chatboxBadgeContainer) { + console.error("found message, couldn't find badges") + return + } + + const chatboxUser = chatboxMessage.querySelector( + '.chat-line__username' + ) + if (!chatboxUser) { + console.error("found message, couldn't find user") + return + } + + const chatboxUserInner = chatboxUser.querySelector( + '.chat-author__display-name' + ) + if (!chatboxUserInner) { + console.error("found message, couldn't find userInner") + return + } + + // got the data, so we're loaded + chatboxMessage.classList.add('obf-loaded') + + // hide 7tv extra colors + if (chatboxUser.classList.contains('seventv-paint')) { + chatboxUser.classList.remove('seventv-paint') + } + + // check if mod + let isMod = false + for (const badge of chatboxBadgeContainer.children) { + if ( + badge.hasAttribute('data-badge') && + (badge.getAttribute('data-badge') === 'moderator' || + badge.getAttribute('data-badge') === 'broadcaster') + ) { + isMod = true + chatboxMessage.classList.add('ismod') + } + } + + // combine details into object + const chatMessage: ChatMessage = { + username: chatboxUserInner.textContent, + isMod, + } + + // run main script (process chatMessage), return new ChatMessage + const newChatMessage = obfuscator(chatMessage) + + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, chatboxUserInner, chatboxUser) + } + + loadReplyLine(chatboxMessage) + loadMessageMentions(chatboxMessage) +} + +function loadReplyLine(chatboxMessage: Element) { + const replyline = chatboxMessage.querySelector('.ffz--fix-reply-line') + const replyUsername = replyline?.querySelector( + 'p > span:nth-child(1)' + ) + + if (!replyUsername) { + return + } + + const chatMessage: ChatMessage = { + username: replyUsername.textContent.replace(/^@/, ''), + isMod: false, + } + + // run main script (process chatMessage), return new ChatMessage + const newChatMessage = obfuscator(chatMessage) + + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, replyUsername, undefined, '@') + } +} + +function loadMessageMentions(chatboxMessage: Element) { + function eachMention(messageMention: HTMLElement) { + const chatMessage: ChatMessage = { + username: messageMention.textContent.replace(/^@/, ''), + isMod: false, + } + + // run main script (process chatMessage), return new ChatMessage + const newChatMessage = obfuscator(chatMessage) + + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, messageMention, undefined, '@') + } + } + + const messageMentions = chatboxMessage.querySelectorAll( + '.chat-line__message-mention' + ) + + for (const messageMention of messageMentions) { + eachMention(messageMention) + } +} + +export function loadAdditionalUserNames(chatboxMessage: Element) { + // look for additional chat member names + const chatterNames = + chatboxMessage.querySelectorAll('.chatter-name') + + for (const chatterName of chatterNames) { + chatboxMessage.classList.add('obf-loaded') + + const chatterNameBox = innermostElement(chatterName) + const username = chatterNameBox.textContent + if (!username) { + continue + } + + // combine details into object + const chatMessage: ChatMessage = { + username, + isMod: false, + } + + // run main script (process chatMessage), return new ChatMessage + const newChatMessage = obfuscator(chatMessage) + + if (newChatMessage !== null) { + setUsernameDetails(newChatMessage, chatterNameBox) + } + } +} + +function setUsernameDetails( + newChatMessage: NameConfigInstance, + textbox: HTMLElement, + colorbox?: HTMLElement, + prefixStr: string = '' +) { + const username = `${newChatMessage.username}${usernameTemplateSuffix(newChatMessage)}` + + const imageName = newChatMessage.image + if (imageName) { + // image name + const image = nameImages[imageName] + + const img = document.createElement('img') + img.classList.add('obf-image', 'ffz--pointer-events', 'ffz-tooltip') + img.setAttribute('data-tooltip-type', 'html') + img.setAttribute('data-title', username) + img.setAttribute('alt', username) + img.setAttribute('src', image) + + const prefix = document.createElement('span') + prefix.textContent = prefixStr + + const suffix = document.createElement('span') + suffix.textContent = usernameImageTemplateSuffix(newChatMessage) + + textbox.replaceChildren(prefix, img, suffix) + } else { + // text name only + textbox.textContent = `${prefixStr}${username}` + } + + if (colorbox) { + colorbox.style.color = newChatMessage.color + } +} diff --git a/scripts/ttv-obfuscated-names/main.ts b/scripts/ttv-obfuscated-names/main.ts new file mode 100644 index 0000000..5441501 --- /dev/null +++ b/scripts/ttv-obfuscated-names/main.ts @@ -0,0 +1,60 @@ +import { loadAdditionalUserNames, loadChatMessage } from './dom' + +const OBSERVER_RATE_LIMIT = 1 +let observerLastRun: number = 0 + +function observerCallback() { + if (Date.now() - observerLastRun < OBSERVER_RATE_LIMIT) { + return + } + observerLastRun = Date.now() + + const chatbox = document.querySelector( + '.chat-scrollable-area__message-container' + ) + const chatboxMessages = Array.from(chatbox?.children ?? []) + + for (const chatboxMessage of chatboxMessages) { + // set flag on message + if (chatboxMessage.classList.contains('obf-loaded')) { + continue + } + + loadChatMessage(chatboxMessage) + loadAdditionalUserNames(chatboxMessage) + } +} + +// attach observer +const observer = new MutationObserver(observerCallback) +observer.observe(document, { attributes: true, childList: true, subtree: true }) + +// attach styles +const styleAddition = document.createElement('style') +styleAddition.innerHTML = ` +.chat-line__message--badges { + display: none; +} +.ismod .chat-line__message--badges { + display: inline; +} +.ismod .chat-line__message--badges > span { + display: none; +} +.ismod .chat-line__message--badges > span[data-badge="moderator"], +.ismod .chat-line__message--badges > span[data-badge="broadcaster"] { + display: inline-block; +} + +.seventv-paint { + background-image: none !important; +} + +img.obf-image { + vertical-align: middle; + margin: -0.5rem 0; + + height: 1.8rem; +} +` +document.head.appendChild(styleAddition) diff --git a/scripts/ttv-obfuscated-names/meta.json b/scripts/ttv-obfuscated-names/meta.json new file mode 100644 index 0000000..31384cd --- /dev/null +++ b/scripts/ttv-obfuscated-names/meta.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://git.zomo.dev/zomo/browser-scripts-builder/raw/branch/main/meta.schema.json", + "name": "ttv obfuscated names", + "description": "", + "namespace": "zomo.dev", + "match": ["https://www.twitch.tv/*"], + "version": "0.1", + "runat": "document-end" +} diff --git a/scripts/ttv-obfuscated-names/obfuscator.ts b/scripts/ttv-obfuscated-names/obfuscator.ts new file mode 100644 index 0000000..94f1867 --- /dev/null +++ b/scripts/ttv-obfuscated-names/obfuscator.ts @@ -0,0 +1,25 @@ +import { NameConfigInstance, ignoreMod } from './options' +import { getRandomName, getStoredUser, setStoredUser } from './storage' +import { ChatMessage } from './util' + +export function obfuscator( + chatMessage: ChatMessage +): NameConfigInstance | null { + if (ignoreMod && chatMessage.isMod) { + return null + } + + chatMessage.username = chatMessage.username.toLowerCase() + + // return stored data + const userData = getStoredUser(chatMessage.username) + if (userData !== null) { + return userData + } + + // store new data + const newName = getRandomName() + setStoredUser(chatMessage.username, newName) + + return newName +} diff --git a/scripts/ttv-obfuscated-names/options.ts b/scripts/ttv-obfuscated-names/options.ts new file mode 100644 index 0000000..1147f55 --- /dev/null +++ b/scripts/ttv-obfuscated-names/options.ts @@ -0,0 +1,42 @@ +/** + * @property color specific color, random color option, or random color option from global list + */ +export interface NameConfig { + username: string + color: string | string[] | null + image?: keyof typeof nameImages +} + +export interface NameConfigInstance { + username: string + color: string + image?: keyof typeof nameImages + nameCount: number +} + +export const ignoreMod: boolean = false + +export const nameImages = { + personimage1: + 'data:image/jpeg;base64,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bnRGI1JsdAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBuAAAAAAAAAAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVudEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkAAAAAAAA4QklNA+0AAAAAABAA8AAAAAEAAQDwAAAAAQABOEJJTQQmAAAAAAAOAAAAAAAAAAAAAD+AAAA4QklNBA0AAAAAAAQAAAAeOEJJTQQZAAAAAAAEAAAAHjhCSU0D8wAAAAAACQAAAAAAAAAAAQA4QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0EAAAAAAAAAgAFOEJJTQQCAAAAAAAOAAAAAAAAAAAAAAAAAAA4QklNBDAAAAAAAAcBAQEBAQEBADhCSU0ELQAAAAAABgABAAAADzhCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAANPAAAABgAAAAAAAAAAAAAKbgAAC9YAAAANAEIAYQBuAGEAbgBhAC0AUwBpAG4AZwBsAGUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAC9YAAApuAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAApuAAAAAFJnaHRsb25nAAAL1gAAAAZz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ZG9iZS5jb20vZXhpZi8xLjAvYXV4LyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOmNycz0iaHR0cDovL25zLmFkb2JlLmNvbS9jYW1lcmEtcmF3LXNldHRpbmdzLzEuMC8iIGRjOmZvcm1hdD0iaW1hZ2UvanBlZyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcDpNb2RpZnlEYXRlPSIyMDE1LTAzLTE4VDE5OjM0OjAxLTA0OjAwIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxMi0wMy0yMFQxNjoyMjoxMCIgeG1wOlJhdGluZz0iMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxNS0wMy0xOFQxOTozNDowMS0wNDowMCIgYXV4OkxlbnNJbmZvPSI3MC8xIDIxMC8xIDQvMSA0LzEiIGF1eDpMZW5zPSI3MC0yMTBtbSBGNCIgYXV4OkxlbnNJRD0iMjU1NTEiIHBob3Rvc2hvcDpEYXRlQ3JlYXRlZD0iMjAxMi0wMy0yMFQxNjoyMjoxMCIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9IkFkb2JlIFJHQiAoMTk5OCkiIHBob3Rvc2hvcDpIaXN0b3J5PSIyMDE1LTAzLTE4VDE5OjE3OjQzLTA0OjAwCUZpbGUgRFNDMDMwNDUuQVJXIG9wZW5lZCYjeEE7MjAxNS0wMy0xOFQxOTozMzo1My0wNDowMAlGaWxlIEQ6XFdpa2lwZWRpYSAtIFBob3Rvc1xGb29kIC0gRnJ1aXQgJmFtcDsgVmVnZXRhYmxlc1xCYW5hbmEtU2luZ2xlLnBzZCBzYXZlZCYjeEE7MjAxNS0wMy0xOFQxOTozNDowMS0wNDowMAlGaWxlIEQ6XFdpa2lwZWRpYSAtIFBob3Rvc1xGb29kIC0gRnJ1aXQgJmFtcDsgVmVnZXRhYmxlc1xCYW5hbmEtU2luZ2xlLmpwZyBzYXZlZCYjeEE7IiB4bXBNTTpEb2N1bWVudElEPSIwNDE3MjAyMDFBNjMzQTdCMjFBOTNGQTM2OTA0RjY1MSIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSIwNDE3MjAyMDFBNjMzQTdCMjFBOTNGQTM2OTA0RjY1MSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2RTc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgY3JzOlJhd0ZpbGVOYW1lPSJEU0MwMzA0NS5BUlciIGNyczpWZXJzaW9uPSI2LjciIGNyczpQcm9jZXNzVmVyc2lvbj0iNS43IiBjcnM6V2hpdGVCYWxhbmNlPSJDdXN0b20iIGNyczpUZW1wZXJhdHVyZT0iNDg1MCIgY3JzOlRpbnQ9Iis4IiBjcnM6RXhwb3N1cmU9Ii0xLjMwIiBjcnM6U2hhZG93cz0iMTgiIGNyczpCcmlnaHRuZXNzPSIrNDUiIGNyczpDb250cmFzdD0iKzQ0IiBjcnM6U2F0dXJhdGlvbj0iKzIiIGNyczpTaGFycG5lc3M9IjI1IiBjcnM6THVtaW5hbmNlU21vb3RoaW5nPSIwIiBjcnM6Q29sb3JOb2lzZVJlZHVjdGlvbj0iMjUiIGNyczpWaWduZXR0ZUFtb3VudD0iMCIgY3JzOlNoYWRvd1RpbnQ9IjAiIGNyczpSZWRIdWU9IjAiIGNyczpSZWRTYXR1cmF0aW9uPSIwIiBjcnM6R3JlZW5IdWU9IjAiIGNyczpHcmVlblNhdHVyYXRpb249IjAiIGNyczpCbHVlSHVlPSIwIiBjcnM6Qmx1ZVNhdHVyYXRpb249IjAiIGNyczpGaWxsTGlnaHQ9IjAiIGNyczpWaWJyYW5jZT0iKzE4IiBjcnM6SGlnaGxpZ2h0UmVjb3Zlcnk9IjE1IiBjcnM6Q2xhcml0eT0iKzMzIiBjcnM6RGVmcmluZ2U9IjAiIGNyczpIdWVBZGp1c3RtZW50UmVkPSIwIiBjcnM6SHVlQWRqdXN0bWVudE9yYW5nZT0iMCIgY3JzOkh1ZUFkanVzdG1lbnRZZWxsb3c9IjAiIGNyczpIdWVBZGp1c3RtZW50R3JlZW49IjAiIGNyczpIdWVBZGp1c3RtZW50QXF1YT0iMCIgY3JzOkh1ZUFkanVzdG1lbnRCbHVlPSIwIiBjcnM6SHVlQWRqdXN0bWVudFB1cnBsZT0iMCIgY3JzOkh1ZUFkanVzdG1lbnRNYWdlbnRhPSIwIiBjcnM6U2F0dXJhdGlvbkFkanVzdG1lbnRSZWQ9IjAiIGNyczpTYXR1cmF0aW9uQWRqdXN0bWVudE9yYW5nZT0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50WWVsbG93PSIwIiBjcnM6U2F0dXJhdGlvbkFkanVzdG1lbnRHcmVlbj0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50QXF1YT0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50Qmx1ZT0iMCIgY3JzOlNhdHVyYXRpb25BZGp1c3RtZW50UHVycGxlPSIwIiBjcnM6U2F0dXJhdGlvbkFkanVzdG1lbnRNYWdlbnRhPSIwIiBjcnM6THVtaW5hbmNlQWRqdXN0bWVudFJlZD0iMCIgY3JzOkx1bWluYW5jZUFkanVzdG1lbnRPcmFuZ2U9IjAiIGNyczpMdW1pbmFuY2VBZGp1c3RtZW50WWVsbG93PSIwIiBjcnM6THVtaW5hbmNlQWRqdXN0bWVudEdyZWVuPSIwIiBjcnM6THVtaW5hbmNlQWRqdXN0bWVudEFxdWE9IjAiIGNyczpMdW1pbmFuY2VBZGp1c3RtZW50Qmx1ZT0iMCIgY3JzOkx1bWluYW5jZUFkanVzdG1lbnRQdXJwbGU9IjAiIGNyczpMdW1pbmFuY2VBZGp1c3RtZW50TWFnZW50YT0iMCIgY3JzOlNwbGl0VG9uaW5nU2hhZG93SHVlPSIwIiBjcnM6U3BsaXRUb25pbmdTaGFkb3dTYXR1cmF0aW9uPSIwIiBjcnM6U3BsaXRUb25pbmdIaWdobGlnaHRIdWU9IjAiIGNyczpTcGxpdFRvbmluZ0hpZ2hsaWdodFNhdHVyYXRpb249IjAiIGNyczpTcGxpdFRvbmluZ0JhbGFuY2U9IjAiIGNyczpQYXJhbWV0cmljU2hhZG93cz0iMCIgY3JzOlBhcmFtZXRyaWNEYXJrcz0iMCIgY3JzOlBhcmFtZXRyaWNMaWdodHM9IjAiIGNyczpQYXJhbWV0cmljSGlnaGxpZ2h0cz0iMCIgY3JzOlBhcmFtZXRyaWNTaGFkb3dTcGxpdD0iMjUiIGNyczpQYXJhbWV0cmljTWlkdG9uZVNwbGl0PSI1MCIgY3JzOlBhcmFtZXRyaWNIaWdobGlnaHRTcGxpdD0iNzUiIGNyczpTaGFycGVuUmFkaXVzPSIrMS4wIiBjcnM6U2hhcnBlbkRldGFpbD0iMjUiIGNyczpTaGFycGVuRWRnZU1hc2tpbmc9IjAiIGNyczpQb3N0Q3JvcFZpZ25ldHRlQW1vdW50PSIwIiBjcnM6R3JhaW5BbW91bnQ9IjAiIGNyczpDb2xvck5vaXNlUmVkdWN0aW9uRGV0YWlsPSI1MCIgY3JzOkxlbnNQcm9maWxlRW5hYmxlPSIwIiBjcnM6TGVuc01hbnVhbERpc3RvcnRpb25BbW91bnQ9IjAiIGNyczpQZXJzcGVjdGl2ZVZlcnRpY2FsPSIwIiBjcnM6UGVyc3BlY3RpdmVIb3Jpem9udGFsPSIwIiBjcnM6UGVyc3BlY3RpdmVSb3RhdGU9IjAuMCIgY3JzOlBlcnNwZWN0aXZlU2NhbGU9IjEwMCIgY3JzOkF1dG9MYXRlcmFsQ0E9IjEiIGNyczpFeHBvc3VyZTIwMTI9IjAuMDAiIGNyczpDb250cmFzdDIwMTI9IjAiIGNyczpIaWdobGlnaHRzMjAxMj0iMCIgY3JzOlNoYWRvd3MyMDEyPSIwIiBjcnM6V2hpdGVzMjAxMj0iMCIgY3JzOkJsYWNrczIwMTI9IjAiIGNyczpDbGFyaXR5MjAxMj0iMCIgY3JzOkNvbnZlcnRUb0dyYXlzY2FsZT0iRmFsc2UiIGNyczpUb25lQ3VydmVOYW1lPSJNZWRpdW0gQ29udHJhc3QiIGNyczpUb25lQ3VydmVOYW1lMjAxMj0iTGluZWFyIiBjcnM6Q2FtZXJhUHJvZmlsZT0iQWRvYmUgU3RhbmRhcmQiIGNyczpDYW1lcmFQcm9maWxlRGlnZXN0PSI2NjJEM0M0OUE2MTNFMDc0Mjk1RUUxODhBN0U5OEJCNiIgY3JzOkxlbnNQcm9maWxlU2V0dXA9IkxlbnNEZWZhdWx0cyIgY3JzOkhhc1NldHRpbmdzPSJUcnVlIiBjcnM6SGFzQ3JvcD0iRmFsc2UiIGNyczpBbHJlYWR5QXBwbGllZD0iVHJ1ZSI+DQoJCQk8ZGM6ZGVzY3JpcHRpb24+DQoJCQkJPHJkZjpBbHQ+DQoJCQkJCTxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+U09OWSBEU0M8L3JkZjpsaT4NCgkJCQk8L3JkZjpBbHQ+DQoJCQk8L2RjOmRlc2NyaXB0aW9uPg0KCQkJPHhtcE1NOkhpc3Rvcnk+DQoJCQkJPHJkZjpTZXE+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpCMTY3RkZGRjk5Q0JFNDExOUY0NUZCQ0MwMTgzODI0QiIgc3RFdnQ6d2hlbj0iMjAxNS0wMy0xOFQxOToxNzo0Mi0wNDowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENhbWVyYSBSYXcgNi43IChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPg0KCQkJCQk8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NkI3NjY3NThDMkNERTQxMThBREZBNDg0RjQ5NjUwNjciIHN0RXZ0OndoZW49IjIwMTUtMDMtMThUMTk6MzM6NTMtMDQ6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIgc3RFdnQ6Y2hhbmdlZD0iLyIvPg0KCQkJCQk8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY29udmVydGVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJmcm9tIGltYWdlL3RpZmYgdG8gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCIvPg0KCQkJCQk8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iZGVyaXZlZCIgc3RFdnQ6cGFyYW1ldGVycz0iY29udmVydGVkIGZyb20gaW1hZ2UvdGlmZiB0byBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2Qzc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgc3RFdnQ6d2hlbj0iMjAxNS0wMy0xOFQxOTozMzo1My0wNDowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2RDc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgc3RFdnQ6d2hlbj0iMjAxNS0wMy0xOFQxOTozNDowMS0wNDowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiBzdEV2dDpjaGFuZ2VkPSIvIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjb252ZXJ0ZWQiIHN0RXZ0OnBhcmFtZXRlcnM9ImZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9qcGVnIi8+DQoJCQkJCTxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJkZXJpdmVkIiBzdEV2dDpwYXJhbWV0ZXJzPSJjb252ZXJ0ZWQgZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL2pwZWciLz4NCgkJCQkJPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjZFNzY2NzU4QzJDREU0MTE4QURGQTQ4NEY0OTY1MDY3IiBzdEV2dDp3aGVuPSIyMDE1LTAzLTE4VDE5OjM0OjAxLTA0OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L3htcE1NOkhpc3Rvcnk+DQoJCQk8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2RDc2Njc1OEMyQ0RFNDExOEFERkE0ODRGNDk2NTA2NyIgc3RSZWY6ZG9jdW1lbnRJRD0iMDQxNzIwMjAxQTYzM0E3QjIxQTkzRkEzNjkwNEY2NTEiIHN0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD0iMDQxNzIwMjAxQTYzM0E3QjIxQTkzRkEzNjkwNEY2NTEiLz4NCgkJCTxjcnM6VG9uZUN1cnZlPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4zMiwgMjI8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT42NCwgNTY8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4xMjgsIDEyODwvcmRmOmxpPg0KCQkJCQk8cmRmOmxpPjE5MiwgMTk2PC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmU+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVJlZD4NCgkJCQk8cmRmOlNlcT4NCgkJCQkJPHJkZjpsaT4wLCAwPC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmVSZWQ+DQoJCQk8Y3JzOlRvbmVDdXJ2ZUdyZWVuPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZUdyZWVuPg0KCQkJPGNyczpUb25lQ3VydmVCbHVlPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZUJsdWU+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVBWMjAxMj4NCgkJCQk8cmRmOlNlcT4NCgkJCQkJPHJkZjpsaT4wLCAwPC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmVQVjIwMTI+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVBWMjAxMlJlZD4NCgkJCQk8cmRmOlNlcT4NCgkJCQkJPHJkZjpsaT4wLCAwPC9yZGY6bGk+DQoJCQkJCTxyZGY6bGk+MjU1LCAyNTU8L3JkZjpsaT4NCgkJCQk8L3JkZjpTZXE+DQoJCQk8L2NyczpUb25lQ3VydmVQVjIwMTJSZWQ+DQoJCQk8Y3JzOlRvbmVDdXJ2ZVBWMjAxMkdyZWVuPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZVBWMjAxMkdyZWVuPg0KCQkJPGNyczpUb25lQ3VydmVQVjIwMTJCbHVlPg0KCQkJCTxyZGY6U2VxPg0KCQkJCQk8cmRmOmxpPjAsIDA8L3JkZjpsaT4NCgkJCQkJPHJkZjpsaT4yNTUsIDI1NTwvcmRmOmxpPg0KCQkJCTwvcmRmOlNlcT4NCgkJCTwvY3JzOlRvbmVDdXJ2ZVBWMjAxMkJsdWU+DQoJCTwvcmRmOkRlc2NyaXB0aW9uPg0KCTwvcmRmOlJERj4NCjwveDp4bXBtZXRhPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0ndyc/Pv/iAkBJQ0NfUFJPRklMRQABAQAAAjBBREJFAhAAAG1udHJSR0IgWFlaIAfPAAYAAwAAAAAAAGFjc3BBUFBMAAAAAG5vbmUAAAAAAAAAAAAAAAAAAAAAAAD21gABAAAAANMtQURCRQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACmNwcnQAAAD8AAAAMmRlc2MAAAEwAAAAa3d0cHQAAAGcAAAAFGJrcHQAAAGwAAAAFHJUUkMAAAHEAAAADmdUUkMAAAHUAAAADmJUUkMAAAHkAAAADnJYWVoAAAH0AAAAFGdYWVoAAAIIAAAAFGJYWVoAAAIcAAAAFHRleHQAAAAAQ29weXJpZ2h0IDE5OTkgQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQAAABkZXNjAAAAAAAAABFBZG9iZSBSR0IgKDE5OTgpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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', +} + +export const colorList: string[] = ['#ddd', '#444', '#400', '#040', '#004'] + +export const nameList: NameConfig[] = [ + { + username: 'person', + color: '#f00', + image: 'personimage1', + }, + // { + // username: 'bot', + // color: ['#0f0', '#00f'], + // image: 'personimage1', + // }, + // { + // username: 'other', + // color: null, + // image: 'personimage1', + // }, +] diff --git a/scripts/ttv-obfuscated-names/storage.ts b/scripts/ttv-obfuscated-names/storage.ts new file mode 100644 index 0000000..89a58f9 --- /dev/null +++ b/scripts/ttv-obfuscated-names/storage.ts @@ -0,0 +1,130 @@ +import { NameConfigInstance, NameConfig, nameList, colorList } from './options' + +type StoredUsers = { + [username: string]: NameConfigInstance +} +type NameListUsed = { + [username: string]: number +} + +interface StoredData { + storedUsers: StoredUsers + nameListUsed: NameListUsed + nameListCount: number +} + +let { storedUsers, nameListUsed, nameListCount } = loadStoredUserData() + +export function getStoredUser(name: string): NameConfigInstance | null { + if (name in storedUsers) { + return storedUsers[name] + } + + return null +} + +export function setStoredUser(name: string, details: NameConfigInstance) { + storedUsers[name] = details + updateStorageData() +} + +export function increaseNameListUsed(name: string) { + nameListUsed[name] = (nameListUsed[name] ?? 0) + 1 + updateStorageData() +} + +export function increaseNameListCount() { + nameListCount++ + updateStorageData() +} + +function updateStorageData() { + localStorage.setItem( + 'obf-data', + JSON.stringify({ + storedUsers, + nameListUsed, + nameListCount, + }) + ) +} + +function loadStoredUserData(): StoredData { + const dataStr = localStorage.getItem('obf-data') + if (dataStr === null) { + return { + storedUsers: {}, + nameListUsed: {}, + nameListCount: 0, + } + } + + try { + const data = JSON.parse(dataStr) + return data as StoredData + } catch (e) { + return { + storedUsers: {}, + nameListUsed: {}, + nameListCount: 0, + } + } +} + +// TODO will be useful for better options +export function clearStoredUsers() {} + +export function getRandomName(): NameConfigInstance { + const startingIndex = Math.round(Math.random() * (nameList.length - 1)) + let foundName = false + let currentIndex = startingIndex + + for (let i = 0; i < nameList.length; i++) { + currentIndex = (startingIndex + i) % nameList.length + + let isUsed = nameListUsed[nameList[currentIndex].username] ?? 0 + if (isUsed === nameListCount) { + foundName = true + break + } + } + + if (!foundName) { + increaseNameListCount() + currentIndex = startingIndex + } + + increaseNameListUsed(nameList[currentIndex].username) + + const newName = nameList[currentIndex] + const newNameInstance: NameConfigInstance = { + username: newName.username, + image: newName.image, + color: '', + nameCount: nameListCount, + } + + // choose a random color from the list + if (Array.isArray(newName.color)) { + const color = + newName.color[ + Math.round(Math.random() * (newName.color.length - 1)) + ] + + newNameInstance.color = color + return newNameInstance + } + + // choose a random color from the global list + if (newName.color === null) { + const color = + colorList[Math.round(Math.random() * (colorList.length - 1))] + + newNameInstance.color = color + return newNameInstance + } + + // copy individual carbing + newNameInstance.color = newName.color + return newNameInstance +} diff --git a/scripts/ttv-obfuscated-names/todo.md b/scripts/ttv-obfuscated-names/todo.md new file mode 100644 index 0000000..f111c25 --- /dev/null +++ b/scripts/ttv-obfuscated-names/todo.md @@ -0,0 +1,48 @@ +# obfuscator todo list + +- can i detect when ffz loads? +- better options + +## known issues + +watch streaks + +- name is just in a string +- there's no good ways to traverse the dom to reach the name's node + +```html +
+
+
+
+
+
+
+ + + +
+
+
+ + + + + person5 + 2 + + +
+
+
+
+
+
+ +``` diff --git a/scripts/ttv-obfuscated-names/tsconfig.json b/scripts/ttv-obfuscated-names/tsconfig.json new file mode 100644 index 0000000..0314104 --- /dev/null +++ b/scripts/ttv-obfuscated-names/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2021", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "strict": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "types": [ + "../../node_modules/@types/greasemonkey", + "../../node_modules/browser-scripts-builder" + ] + } +} diff --git a/scripts/ttv-obfuscated-names/util.ts b/scripts/ttv-obfuscated-names/util.ts new file mode 100644 index 0000000..3df257c --- /dev/null +++ b/scripts/ttv-obfuscated-names/util.ts @@ -0,0 +1,31 @@ +import { NameConfigInstance } from './options' + +export interface ChatMessage { + username: string + isMod: boolean +} + +export function innermostElement(elem: T) { + if (elem.children.length === 0) { + return elem + } + return innermostElement(elem.children[0]) +} + +export function usernameTemplateSuffix(newChatMessage: NameConfigInstance) { + if (newChatMessage.nameCount === 0) { + return '' + } + + return `${newChatMessage.nameCount}` +} + +export function usernameImageTemplateSuffix( + newChatMessage: NameConfigInstance +) { + if (newChatMessage.nameCount === 0) { + return '' + } + + return `${newChatMessage.nameCount}` +}