Skip to content

Instantly share code, notes, and snippets.

@n0mimono
Last active March 13, 2025 07:17
Show Gist options
  • Save n0mimono/f352bfcd45244ca6d197e536564ce56b to your computer and use it in GitHub Desktop.
Save n0mimono/f352bfcd45244ca6d197e536564ce56b to your computer and use it in GitHub Desktop.
YouTubeLiveChat for Chrome extension
const background = {
store: {
messages: [],
},
interval: 1000,
update: function () {
console.log(this.store.messages)
if (this.store.messages.length > 0) {
chrome.action.setBadgeText({ text: this.store.messages.length.toString() });
chrome.action.setBadgeBackgroundColor({ color: '#00FF00' });
} else {
chrome.action.setBadgeText({ text: '' });
}
},
contentChanged: function (messages) {
this.store.messages = messages
},
popupChanged: function () {
// nop
},
init: function () {
setInterval(() => {
this.update()
}, this.interval)
}
}
background.init()
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
// content.js -> background.js
if (request.type === 'content_changed') {
background.contentChanged(request.data.messages)
sendResponse({
status: 'ok',
data: {},
})
}
// popup.js -> background.js
if (request.type === 'popup_changed') {
background.popupChanged()
sendResponse({
status: 'ok',
data: {
messages: background.store.messages,
}
})
}
return true
})
const app = {
items: undefined,
messages: [],
interval: 1000,
updateItems: function () {
if (this.items && this.items.isConnected) return
this.items = undefined
let iframe = document.getElementById('live-chat') || document.getElementById('chatframe')
if (!iframe) return
const chat = iframe.contentDocument.getElementById('chat')
if (!chat) return
const items = chat.querySelector('#items')
if (!items) return
if (!items.children) return
this.items = items
},
updateMessages: function () {
if (!this.items) return
const contents = this.items.querySelectorAll('#content')
let messages = []
for (const content of contents) {
const parent = content.parentElement
if (!parent) continue
const id = parent.id
if (!id) continue
const timestamp = content.querySelector("#timestamp")?.innerText.trim() || ''
const author = content.querySelector("#author-name")?.innerText.trim() || ''
const message = content.querySelector("#message")?.innerText.trim() || ''
messages.push({
id: id,
timestamp: timestamp,
author: author,
message: message,
})
}
this.messages = messages
},
contentChanged: function (messages) {
chrome.runtime.sendMessage({
type: 'content_changed',
data: {
messages: messages,
},
}, (response) => {
const error = chrome.runtime.lastError
if (error) {
console.error(error)
return
}
// nop
})
},
main: function () {
setInterval(() => {
this.updateItems()
this.updateMessages()
this.contentChanged(this.messages)
}, this.interval)
},
}
app.main()
{
"name": "__MSG_appName__",
"version": "0.1",
"manifest_version": 3,
"description": "__MSG_appDesc__",
"default_locale": "ja",
"icons": {
"128": "img/icon_128.png"
},
"content_scripts": [
{
"matches": [
"https://studio.youtube.com/video/*",
"https://www.youtube.com/watch?v=*"
],
"js": [
"js/content.js"
],
"run_at": "document_start"
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"storage"
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"128": "img/icon_128.png"
}
},
"offline_enabled": true
}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Popup</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 10px;
}
#log {
margin-top: 20px;
}
</style>
</head>
<body>
<div>
<h1>LiveWatch</h1>
</div>
<div>
<h2>Messages</h2>
<div id="messages"></div>
</div>
<script src="js/popup.js"></script>
</body>
</html>
function updatePopup(messages) {
const container = document.getElementById('messages')
if (!container) return
container.innerHTML = messages.map(message => {
return `<div>${message.message}</div>`
}).join('')
}
window.onload = () => {
chrome.runtime.sendMessage({
type: 'popup_changed',
data: {},
}, (response) => {
const error = chrome.runtime.lastError
if (error) {
console.error(error)
return
}
updatePopup(response.data.messages)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment