diff --git a/package-lock.json b/package-lock.json index a156598..830eaf2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "GPL-3.0-only", "dependencies": { "@babel/runtime-corejs3": "^7.26.7", + "@twemoji/api": "^15.1.0", "core-js-pure": "^3.40.0", "regenerator-runtime": "^0.14.1", "tiny-sha256": "^1.0.2", @@ -3184,6 +3185,24 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@twemoji/api": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@twemoji/api/-/api-15.1.0.tgz", + "integrity": "sha512-CySXR4/e6vY0z9lC2tW9EVjsH6zzz2/LQvLRMwwpHsDI4xcaweSIP+LcESf1Mq7w2/zcrrhG4ozniMvpSsEXag==", + "license": "MIT AND CC-BY-4.0", + "dependencies": { + "@twemoji/parser": "15.1.0", + "fs-extra": "^8.0.1", + "jsonfile": "^5.0.0", + "universalify": "^0.1.2" + } + }, + "node_modules/@twemoji/parser": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@twemoji/parser/-/parser-15.1.0.tgz", + "integrity": "sha512-3HTiSxPvkWUJ4kZeCvwyKlIwkpTUfBOk6igpBBRQni58ceQMv5YK4smkc8vX/eqOlMMNER/9qobv+Q6Q8LVrqA==", + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -10695,6 +10714,29 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-extra/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -10792,8 +10834,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/hasown": { "version": "2.0.2", @@ -11137,6 +11178,18 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-5.0.0.tgz", + "integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==", + "license": "MIT", + "dependencies": { + "universalify": "^0.1.2" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -13646,6 +13699,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", diff --git a/package.json b/package.json index 1199d26..abd11d7 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "homepage": "https://github.com/webosbrew/youtube-webos#readme", "dependencies": { "@babel/runtime-corejs3": "^7.26.7", + "@twemoji/api": "^15.1.0", "core-js-pure": "^3.40.0", "regenerator-runtime": "^0.14.1", "tiny-sha256": "^1.0.2", diff --git a/src/emoji-font.css b/src/emoji-font.css new file mode 100644 index 0000000..5bc44f4 --- /dev/null +++ b/src/emoji-font.css @@ -0,0 +1,6 @@ +img.emoji { + height: 1em; + width: 1em; + margin: 0 0.05em 0 0.1em; + vertical-align: -0.1em; +} diff --git a/src/emoji-font.ts b/src/emoji-font.ts new file mode 100644 index 0000000..90590c9 --- /dev/null +++ b/src/emoji-font.ts @@ -0,0 +1,24 @@ +import twemoji from '@twemoji/api'; + +import './emoji-font.css'; + +const YT_FORMATTED_STR_TAG = 'yt-formatted-string'; + +const emojiObs = new MutationObserver((mutations) => { + mutations + .flatMap((mut) => Array.from(mut.addedNodes)) + .filter((node) => node instanceof HTMLElement) + .flatMap((elem) => + Array.from( + elem.querySelectorAll(YT_FORMATTED_STR_TAG) as NodeListOf + ) + ) + .forEach((elem) => void twemoji.parse(elem, { size: '72x72' })); +}); + +// twemoji expects the charset to be UTF-8 +if (document.characterSet === 'UTF-8') { + emojiObs.observe(document.body, { childList: true, subtree: true }); +} else { + console.warn('document charset not utf-8. Emoji replacement disabled.'); +} diff --git a/src/userScript.js b/src/userScript.js index b035e04..5d072aa 100644 --- a/src/userScript.js +++ b/src/userScript.js @@ -20,3 +20,4 @@ import './font-fix.css'; import './thumbnail-quality'; import './screensaver-fix'; import './yt-fixes.css'; +import './emoji-font.ts';