From c45825922a9c3373456685cb466558e1961df1e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 22:11:41 +0000 Subject: [PATCH 01/51] Bump tornado from 6.4.1 to 6.4.2 Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.4.1 to 6.4.2. - [Changelog](https://github.com/tornadoweb/tornado/blob/v6.4.2/docs/releases.rst) - [Commits](https://github.com/tornadoweb/tornado/compare/v6.4.1...v6.4.2) --- updated-dependencies: - dependency-name: tornado dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b966f5ce..387e0caa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,4 @@ cachetools==5.3.1 circuitbreaker==2.0.0 pycryptodome==3.19.1 sqlalchemy==2.0.19 -tornado==6.4.1 +tornado==6.4.2 From faf272c8a76f62be2033267659bdb0daeb5e1c71 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sat, 23 Nov 2024 17:31:03 +0800 Subject: [PATCH 02/51] =?UTF-8?q?=E6=95=B4=E7=90=86=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E9=83=A8=E5=88=86=E7=BB=84=E4=BB=B6CSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ChatRenderer/TextMessage.vue | 6 ++--- frontend/src/layout/Sidebar.vue | 10 +++++--- frontend/src/layout/index.vue | 23 ++++++++----------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/ChatRenderer/TextMessage.vue b/frontend/src/components/ChatRenderer/TextMessage.vue index 266adbc7..393b7acf 100644 --- a/frontend/src/components/ChatRenderer/TextMessage.vue +++ b/frontend/src/components/ChatRenderer/TextMessage.vue @@ -84,12 +84,12 @@ export default { } - diff --git a/frontend/src/layout/index.vue b/frontend/src/layout/index.vue index 60e94f1e..aef30714 100644 --- a/frontend/src/layout/index.vue +++ b/frontend/src/layout/index.vue @@ -12,7 +12,7 @@ - + @@ -51,8 +51,8 @@ export default { } - From e27955b8b5e31ca69258f8b9341617665d7dcfa9 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sat, 23 Nov 2024 17:32:38 +0800 Subject: [PATCH 03/51] =?UTF-8?q?=E5=8E=9F=E7=89=88YouTube=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E6=94=BE=E5=85=A5@layer=EF=BC=8C=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A0=B7=E5=BC=8F=E4=B8=8D=E7=94=A8=E5=8A=A0!importan?= =?UTF-8?q?t=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/css/youtube/yt-html.css | 4 ++++ frontend/src/assets/css/youtube/yt-icon.css | 4 ++++ frontend/src/assets/css/youtube/yt-img-shadow.css | 4 ++++ .../assets/css/youtube/yt-live-chat-author-badge-renderer.css | 4 ++++ frontend/src/assets/css/youtube/yt-live-chat-author-chip.css | 4 ++++ .../assets/css/youtube/yt-live-chat-item-list-renderer.css | 4 ++++ .../css/youtube/yt-live-chat-membership-item-renderer.css | 4 ++++ .../assets/css/youtube/yt-live-chat-paid-message-renderer.css | 4 ++++ frontend/src/assets/css/youtube/yt-live-chat-renderer.css | 4 ++++ .../assets/css/youtube/yt-live-chat-text-message-renderer.css | 4 ++++ .../yt-live-chat-ticker-paid-message-item-renderer.css | 4 ++++ .../src/assets/css/youtube/yt-live-chat-ticker-renderer.css | 4 ++++ 12 files changed, 48 insertions(+) diff --git a/frontend/src/assets/css/youtube/yt-html.css b/frontend/src/assets/css/youtube/yt-html.css index 75dc6fce..1c4a78ac 100644 --- a/frontend/src/assets/css/youtube/yt-html.css +++ b/frontend/src/assets/css/youtube/yt-html.css @@ -1,3 +1,5 @@ +@layer yt { + html:not(.style-scope) { --yt-live-chat-background-color: hsl(0, 0%, 100%); --yt-live-chat-action-panel-background-color: hsla(0, 0%, 93.3%, .4); @@ -360,3 +362,5 @@ html:not(.style-scope) { --layout-fixed-left_-_left: 0; ; } + +} diff --git a/frontend/src/assets/css/youtube/yt-icon.css b/frontend/src/assets/css/youtube/yt-icon.css index c21acf27..6af70c6e 100644 --- a/frontend/src/assets/css/youtube/yt-icon.css +++ b/frontend/src/assets/css/youtube/yt-icon.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-icon, caption.yt-icon, center.yt-icon, cite.yt-icon, code.yt-icon, dd.yt-icon, del.yt-icon, dfn.yt-icon, div.yt-icon, dl.yt-icon, dt.yt-icon, em.yt-icon, embed.yt-icon, fieldset.yt-icon, font.yt-icon, form.yt-icon, h1.yt-icon, h2.yt-icon, h3.yt-icon, h4.yt-icon, h5.yt-icon, h6.yt-icon, hr.yt-icon, i.yt-icon, iframe.yt-icon, img.yt-icon, ins.yt-icon, kbd.yt-icon, label.yt-icon, legend.yt-icon, li.yt-icon, menu.yt-icon, object.yt-icon, ol.yt-icon, p.yt-icon, pre.yt-icon, q.yt-icon, s.yt-icon, samp.yt-icon, small.yt-icon, span.yt-icon, strike.yt-icon, strong.yt-icon, sub.yt-icon, sup.yt-icon, table.yt-icon, tbody.yt-icon, td.yt-icon, tfoot.yt-icon, th.yt-icon, thead.yt-icon, tr.yt-icon, tt.yt-icon, u.yt-icon, ul.yt-icon, var.yt-icon { margin: 0; padding: 0; @@ -28,3 +30,5 @@ yt-icon, .yt-icon-container.yt-icon { yt-icon.external-container { display: none !important; } + +} diff --git a/frontend/src/assets/css/youtube/yt-img-shadow.css b/frontend/src/assets/css/youtube/yt-img-shadow.css index e4ea828e..eac9967d 100644 --- a/frontend/src/assets/css/youtube/yt-img-shadow.css +++ b/frontend/src/assets/css/youtube/yt-img-shadow.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-img-shadow, caption.yt-img-shadow, center.yt-img-shadow, cite.yt-img-shadow, code.yt-img-shadow, dd.yt-img-shadow, del.yt-img-shadow, dfn.yt-img-shadow, div.yt-img-shadow, dl.yt-img-shadow, dt.yt-img-shadow, em.yt-img-shadow, embed.yt-img-shadow, fieldset.yt-img-shadow, font.yt-img-shadow, form.yt-img-shadow, h1.yt-img-shadow, h2.yt-img-shadow, h3.yt-img-shadow, h4.yt-img-shadow, h5.yt-img-shadow, h6.yt-img-shadow, hr.yt-img-shadow, i.yt-img-shadow, iframe.yt-img-shadow, img.yt-img-shadow, ins.yt-img-shadow, kbd.yt-img-shadow, label.yt-img-shadow, legend.yt-img-shadow, li.yt-img-shadow, menu.yt-img-shadow, object.yt-img-shadow, ol.yt-img-shadow, p.yt-img-shadow, pre.yt-img-shadow, q.yt-img-shadow, s.yt-img-shadow, samp.yt-img-shadow, small.yt-img-shadow, span.yt-img-shadow, strike.yt-img-shadow, strong.yt-img-shadow, sub.yt-img-shadow, sup.yt-img-shadow, table.yt-img-shadow, tbody.yt-img-shadow, td.yt-img-shadow, tfoot.yt-img-shadow, th.yt-img-shadow, thead.yt-img-shadow, tr.yt-img-shadow, tt.yt-img-shadow, u.yt-img-shadow, ul.yt-img-shadow, var.yt-img-shadow { margin: 0; padding: 0; @@ -66,3 +68,5 @@ img.yt-img-shadow { max-width: 100%; border-radius: none; } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-author-badge-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-author-badge-renderer.css index 9a0b8409..59013081 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-author-badge-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-author-badge-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-live-chat-author-badge-renderer, caption.yt-live-chat-author-badge-renderer, center.yt-live-chat-author-badge-renderer, cite.yt-live-chat-author-badge-renderer, code.yt-live-chat-author-badge-renderer, dd.yt-live-chat-author-badge-renderer, del.yt-live-chat-author-badge-renderer, dfn.yt-live-chat-author-badge-renderer, div.yt-live-chat-author-badge-renderer, dl.yt-live-chat-author-badge-renderer, dt.yt-live-chat-author-badge-renderer, em.yt-live-chat-author-badge-renderer, embed.yt-live-chat-author-badge-renderer, fieldset.yt-live-chat-author-badge-renderer, font.yt-live-chat-author-badge-renderer, form.yt-live-chat-author-badge-renderer, h1.yt-live-chat-author-badge-renderer, h2.yt-live-chat-author-badge-renderer, h3.yt-live-chat-author-badge-renderer, h4.yt-live-chat-author-badge-renderer, h5.yt-live-chat-author-badge-renderer, h6.yt-live-chat-author-badge-renderer, hr.yt-live-chat-author-badge-renderer, i.yt-live-chat-author-badge-renderer, iframe.yt-live-chat-author-badge-renderer, img.yt-live-chat-author-badge-renderer, ins.yt-live-chat-author-badge-renderer, kbd.yt-live-chat-author-badge-renderer, label.yt-live-chat-author-badge-renderer, legend.yt-live-chat-author-badge-renderer, li.yt-live-chat-author-badge-renderer, menu.yt-live-chat-author-badge-renderer, object.yt-live-chat-author-badge-renderer, ol.yt-live-chat-author-badge-renderer, p.yt-live-chat-author-badge-renderer, pre.yt-live-chat-author-badge-renderer, q.yt-live-chat-author-badge-renderer, s.yt-live-chat-author-badge-renderer, samp.yt-live-chat-author-badge-renderer, small.yt-live-chat-author-badge-renderer, span.yt-live-chat-author-badge-renderer, strike.yt-live-chat-author-badge-renderer, strong.yt-live-chat-author-badge-renderer, sub.yt-live-chat-author-badge-renderer, sup.yt-live-chat-author-badge-renderer, table.yt-live-chat-author-badge-renderer, tbody.yt-live-chat-author-badge-renderer, td.yt-live-chat-author-badge-renderer, tfoot.yt-live-chat-author-badge-renderer, th.yt-live-chat-author-badge-renderer, thead.yt-live-chat-author-badge-renderer, tr.yt-live-chat-author-badge-renderer, tt.yt-live-chat-author-badge-renderer, u.yt-live-chat-author-badge-renderer, ul.yt-live-chat-author-badge-renderer, var.yt-live-chat-author-badge-renderer { margin: 0; padding: 0; @@ -34,3 +36,5 @@ img.yt-live-chat-author-badge-renderer, yt-icon.yt-live-chat-author-badge-render width: 16px; height: 16px; } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-author-chip.css b/frontend/src/assets/css/youtube/yt-live-chat-author-chip.css index 2ce7ed44..ff3dbab4 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-author-chip.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-author-chip.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-live-chat-author-chip, caption.yt-live-chat-author-chip, center.yt-live-chat-author-chip, cite.yt-live-chat-author-chip, code.yt-live-chat-author-chip, dd.yt-live-chat-author-chip, del.yt-live-chat-author-chip, dfn.yt-live-chat-author-chip, div.yt-live-chat-author-chip, dl.yt-live-chat-author-chip, dt.yt-live-chat-author-chip, em.yt-live-chat-author-chip, embed.yt-live-chat-author-chip, fieldset.yt-live-chat-author-chip, font.yt-live-chat-author-chip, form.yt-live-chat-author-chip, h1.yt-live-chat-author-chip, h2.yt-live-chat-author-chip, h3.yt-live-chat-author-chip, h4.yt-live-chat-author-chip, h5.yt-live-chat-author-chip, h6.yt-live-chat-author-chip, hr.yt-live-chat-author-chip, i.yt-live-chat-author-chip, iframe.yt-live-chat-author-chip, img.yt-live-chat-author-chip, ins.yt-live-chat-author-chip, kbd.yt-live-chat-author-chip, label.yt-live-chat-author-chip, legend.yt-live-chat-author-chip, li.yt-live-chat-author-chip, menu.yt-live-chat-author-chip, object.yt-live-chat-author-chip, ol.yt-live-chat-author-chip, p.yt-live-chat-author-chip, pre.yt-live-chat-author-chip, q.yt-live-chat-author-chip, s.yt-live-chat-author-chip, samp.yt-live-chat-author-chip, small.yt-live-chat-author-chip, span.yt-live-chat-author-chip, strike.yt-live-chat-author-chip, strong.yt-live-chat-author-chip, sub.yt-live-chat-author-chip, sup.yt-live-chat-author-chip, table.yt-live-chat-author-chip, tbody.yt-live-chat-author-chip, td.yt-live-chat-author-chip, tfoot.yt-live-chat-author-chip, th.yt-live-chat-author-chip, thead.yt-live-chat-author-chip, tr.yt-live-chat-author-chip, tt.yt-live-chat-author-chip, u.yt-live-chat-author-chip, ul.yt-live-chat-author-chip, var.yt-live-chat-author-chip { margin: 0; padding: 0; @@ -62,3 +64,5 @@ yt-live-chat-author-chip[is-highlighted] #chip-badges.yt-live-chat-author-chip y #chip-badges.yt-live-chat-author-chip yt-live-chat-author-badge-renderer.yt-live-chat-author-chip:last-of-type { margin-right: -2px; } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-item-list-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-item-list-renderer.css index 7eaad8b4..078270c4 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-item-list-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-item-list-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-live-chat-item-list-renderer, caption.yt-live-chat-item-list-renderer, center.yt-live-chat-item-list-renderer, cite.yt-live-chat-item-list-renderer, code.yt-live-chat-item-list-renderer, dd.yt-live-chat-item-list-renderer, del.yt-live-chat-item-list-renderer, dfn.yt-live-chat-item-list-renderer, div.yt-live-chat-item-list-renderer, dl.yt-live-chat-item-list-renderer, dt.yt-live-chat-item-list-renderer, em.yt-live-chat-item-list-renderer, embed.yt-live-chat-item-list-renderer, fieldset.yt-live-chat-item-list-renderer, font.yt-live-chat-item-list-renderer, form.yt-live-chat-item-list-renderer, h1.yt-live-chat-item-list-renderer, h2.yt-live-chat-item-list-renderer, h3.yt-live-chat-item-list-renderer, h4.yt-live-chat-item-list-renderer, h5.yt-live-chat-item-list-renderer, h6.yt-live-chat-item-list-renderer, hr.yt-live-chat-item-list-renderer, i.yt-live-chat-item-list-renderer, iframe.yt-live-chat-item-list-renderer, img.yt-live-chat-item-list-renderer, ins.yt-live-chat-item-list-renderer, kbd.yt-live-chat-item-list-renderer, label.yt-live-chat-item-list-renderer, legend.yt-live-chat-item-list-renderer, li.yt-live-chat-item-list-renderer, menu.yt-live-chat-item-list-renderer, object.yt-live-chat-item-list-renderer, ol.yt-live-chat-item-list-renderer, p.yt-live-chat-item-list-renderer, pre.yt-live-chat-item-list-renderer, q.yt-live-chat-item-list-renderer, s.yt-live-chat-item-list-renderer, samp.yt-live-chat-item-list-renderer, small.yt-live-chat-item-list-renderer, span.yt-live-chat-item-list-renderer, strike.yt-live-chat-item-list-renderer, strong.yt-live-chat-item-list-renderer, sub.yt-live-chat-item-list-renderer, sup.yt-live-chat-item-list-renderer, table.yt-live-chat-item-list-renderer, tbody.yt-live-chat-item-list-renderer, td.yt-live-chat-item-list-renderer, tfoot.yt-live-chat-item-list-renderer, th.yt-live-chat-item-list-renderer, thead.yt-live-chat-item-list-renderer, tr.yt-live-chat-item-list-renderer, tt.yt-live-chat-item-list-renderer, u.yt-live-chat-item-list-renderer, ul.yt-live-chat-item-list-renderer, var.yt-live-chat-item-list-renderer { margin: 0; padding: 0; @@ -138,3 +140,5 @@ yt-live-chat-paid-sticker-renderer.yt-live-chat-item-list-renderer { yt-live-chat-paid-sticker-renderer.yt-live-chat-item-list-renderer[dashboard-money-feed] { padding: 8px 16px; } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-membership-item-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-membership-item-renderer.css index 6a1c2caa..b09a8cdd 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-membership-item-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-membership-item-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + #timestamp.yt-live-chat-membership-item-renderer { display: var(--yt-live-chat-item-timestamp-display, inline); margin: var(--yt-live-chat-item-timestamp-margin, 0 8px 0 0); @@ -360,3 +362,5 @@ yt-live-chat-membership-item-renderer[dashboard-money-feed] #menu.yt-live-chat-m margin-top: 8px; background: linear-gradient(to right, transparent, var(--yt-live-chat-background-color) 40%); } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-paid-message-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-paid-message-renderer.css index 639d609d..a6c51f10 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-paid-message-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-paid-message-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-live-chat-paid-message-renderer, caption.yt-live-chat-paid-message-renderer, center.yt-live-chat-paid-message-renderer, cite.yt-live-chat-paid-message-renderer, code.yt-live-chat-paid-message-renderer, dd.yt-live-chat-paid-message-renderer, del.yt-live-chat-paid-message-renderer, dfn.yt-live-chat-paid-message-renderer, div.yt-live-chat-paid-message-renderer, dl.yt-live-chat-paid-message-renderer, dt.yt-live-chat-paid-message-renderer, em.yt-live-chat-paid-message-renderer, embed.yt-live-chat-paid-message-renderer, fieldset.yt-live-chat-paid-message-renderer, font.yt-live-chat-paid-message-renderer, form.yt-live-chat-paid-message-renderer, h1.yt-live-chat-paid-message-renderer, h2.yt-live-chat-paid-message-renderer, h3.yt-live-chat-paid-message-renderer, h4.yt-live-chat-paid-message-renderer, h5.yt-live-chat-paid-message-renderer, h6.yt-live-chat-paid-message-renderer, hr.yt-live-chat-paid-message-renderer, i.yt-live-chat-paid-message-renderer, iframe.yt-live-chat-paid-message-renderer, img.yt-live-chat-paid-message-renderer, ins.yt-live-chat-paid-message-renderer, kbd.yt-live-chat-paid-message-renderer, label.yt-live-chat-paid-message-renderer, legend.yt-live-chat-paid-message-renderer, li.yt-live-chat-paid-message-renderer, menu.yt-live-chat-paid-message-renderer, object.yt-live-chat-paid-message-renderer, ol.yt-live-chat-paid-message-renderer, p.yt-live-chat-paid-message-renderer, pre.yt-live-chat-paid-message-renderer, q.yt-live-chat-paid-message-renderer, s.yt-live-chat-paid-message-renderer, samp.yt-live-chat-paid-message-renderer, small.yt-live-chat-paid-message-renderer, span.yt-live-chat-paid-message-renderer, strike.yt-live-chat-paid-message-renderer, strong.yt-live-chat-paid-message-renderer, sub.yt-live-chat-paid-message-renderer, sup.yt-live-chat-paid-message-renderer, table.yt-live-chat-paid-message-renderer, tbody.yt-live-chat-paid-message-renderer, td.yt-live-chat-paid-message-renderer, tfoot.yt-live-chat-paid-message-renderer, th.yt-live-chat-paid-message-renderer, thead.yt-live-chat-paid-message-renderer, tr.yt-live-chat-paid-message-renderer, tt.yt-live-chat-paid-message-renderer, u.yt-live-chat-paid-message-renderer, ul.yt-live-chat-paid-message-renderer, var.yt-live-chat-paid-message-renderer { margin: 0; padding: 0; @@ -378,3 +380,5 @@ yt-live-chat-paid-message-renderer[show-footer-divider] #footer.yt-live-chat-pai yt-live-chat-paid-message-renderer[is-user-editable] #footer.yt-live-chat-paid-message-renderer:not(:empty) { padding-top: 8px; } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-renderer.css index 5e805f6c..0bc15fc5 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + yt-live-chat-renderer, yt-live-chat-item-list-renderer #item-scroller { height: 100%; } @@ -250,3 +252,5 @@ yt-live-chat-renderer[collapsed] .hide-on-collapse.yt-live-chat-renderer { background-color: rgba(0, 0, 0, 0.60); } } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-text-message-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-text-message-renderer.css index bf1ed283..12679ab8 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-text-message-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-text-message-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-live-chat-text-message-renderer, caption.yt-live-chat-text-message-renderer, center.yt-live-chat-text-message-renderer, cite.yt-live-chat-text-message-renderer, code.yt-live-chat-text-message-renderer, dd.yt-live-chat-text-message-renderer, del.yt-live-chat-text-message-renderer, dfn.yt-live-chat-text-message-renderer, div.yt-live-chat-text-message-renderer, dl.yt-live-chat-text-message-renderer, dt.yt-live-chat-text-message-renderer, em.yt-live-chat-text-message-renderer, embed.yt-live-chat-text-message-renderer, fieldset.yt-live-chat-text-message-renderer, font.yt-live-chat-text-message-renderer, form.yt-live-chat-text-message-renderer, h1.yt-live-chat-text-message-renderer, h2.yt-live-chat-text-message-renderer, h3.yt-live-chat-text-message-renderer, h4.yt-live-chat-text-message-renderer, h5.yt-live-chat-text-message-renderer, h6.yt-live-chat-text-message-renderer, hr.yt-live-chat-text-message-renderer, i.yt-live-chat-text-message-renderer, iframe.yt-live-chat-text-message-renderer, img.yt-live-chat-text-message-renderer, ins.yt-live-chat-text-message-renderer, kbd.yt-live-chat-text-message-renderer, label.yt-live-chat-text-message-renderer, legend.yt-live-chat-text-message-renderer, li.yt-live-chat-text-message-renderer, menu.yt-live-chat-text-message-renderer, object.yt-live-chat-text-message-renderer, ol.yt-live-chat-text-message-renderer, p.yt-live-chat-text-message-renderer, pre.yt-live-chat-text-message-renderer, q.yt-live-chat-text-message-renderer, s.yt-live-chat-text-message-renderer, samp.yt-live-chat-text-message-renderer, small.yt-live-chat-text-message-renderer, span.yt-live-chat-text-message-renderer, strike.yt-live-chat-text-message-renderer, strong.yt-live-chat-text-message-renderer, sub.yt-live-chat-text-message-renderer, sup.yt-live-chat-text-message-renderer, table.yt-live-chat-text-message-renderer, tbody.yt-live-chat-text-message-renderer, td.yt-live-chat-text-message-renderer, tfoot.yt-live-chat-text-message-renderer, th.yt-live-chat-text-message-renderer, thead.yt-live-chat-text-message-renderer, tr.yt-live-chat-text-message-renderer, tt.yt-live-chat-text-message-renderer, u.yt-live-chat-text-message-renderer, ul.yt-live-chat-text-message-renderer, var.yt-live-chat-text-message-renderer { margin: 0; padding: 0; @@ -230,3 +232,5 @@ yt-live-chat-text-message-renderer[is-dimmed] #message.yt-live-chat-text-message yt-live-chat-text-message-renderer[is-dimmed]::before { background: var(--yt-live-chat-error-message-color, #f44336); } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-ticker-paid-message-item-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-ticker-paid-message-item-renderer.css index 4844b66c..d6b41918 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-ticker-paid-message-item-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-ticker-paid-message-item-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-live-chat-ticker-paid-message-item-renderer, caption.yt-live-chat-ticker-paid-message-item-renderer, center.yt-live-chat-ticker-paid-message-item-renderer, cite.yt-live-chat-ticker-paid-message-item-renderer, code.yt-live-chat-ticker-paid-message-item-renderer, dd.yt-live-chat-ticker-paid-message-item-renderer, del.yt-live-chat-ticker-paid-message-item-renderer, dfn.yt-live-chat-ticker-paid-message-item-renderer, div.yt-live-chat-ticker-paid-message-item-renderer, dl.yt-live-chat-ticker-paid-message-item-renderer, dt.yt-live-chat-ticker-paid-message-item-renderer, em.yt-live-chat-ticker-paid-message-item-renderer, embed.yt-live-chat-ticker-paid-message-item-renderer, fieldset.yt-live-chat-ticker-paid-message-item-renderer, font.yt-live-chat-ticker-paid-message-item-renderer, form.yt-live-chat-ticker-paid-message-item-renderer, h1.yt-live-chat-ticker-paid-message-item-renderer, h2.yt-live-chat-ticker-paid-message-item-renderer, h3.yt-live-chat-ticker-paid-message-item-renderer, h4.yt-live-chat-ticker-paid-message-item-renderer, h5.yt-live-chat-ticker-paid-message-item-renderer, h6.yt-live-chat-ticker-paid-message-item-renderer, hr.yt-live-chat-ticker-paid-message-item-renderer, i.yt-live-chat-ticker-paid-message-item-renderer, iframe.yt-live-chat-ticker-paid-message-item-renderer, img.yt-live-chat-ticker-paid-message-item-renderer, ins.yt-live-chat-ticker-paid-message-item-renderer, kbd.yt-live-chat-ticker-paid-message-item-renderer, label.yt-live-chat-ticker-paid-message-item-renderer, legend.yt-live-chat-ticker-paid-message-item-renderer, li.yt-live-chat-ticker-paid-message-item-renderer, menu.yt-live-chat-ticker-paid-message-item-renderer, object.yt-live-chat-ticker-paid-message-item-renderer, ol.yt-live-chat-ticker-paid-message-item-renderer, p.yt-live-chat-ticker-paid-message-item-renderer, pre.yt-live-chat-ticker-paid-message-item-renderer, q.yt-live-chat-ticker-paid-message-item-renderer, s.yt-live-chat-ticker-paid-message-item-renderer, samp.yt-live-chat-ticker-paid-message-item-renderer, small.yt-live-chat-ticker-paid-message-item-renderer, span.yt-live-chat-ticker-paid-message-item-renderer, strike.yt-live-chat-ticker-paid-message-item-renderer, strong.yt-live-chat-ticker-paid-message-item-renderer, sub.yt-live-chat-ticker-paid-message-item-renderer, sup.yt-live-chat-ticker-paid-message-item-renderer, table.yt-live-chat-ticker-paid-message-item-renderer, tbody.yt-live-chat-ticker-paid-message-item-renderer, td.yt-live-chat-ticker-paid-message-item-renderer, tfoot.yt-live-chat-ticker-paid-message-item-renderer, th.yt-live-chat-ticker-paid-message-item-renderer, thead.yt-live-chat-ticker-paid-message-item-renderer, tr.yt-live-chat-ticker-paid-message-item-renderer, tt.yt-live-chat-ticker-paid-message-item-renderer, u.yt-live-chat-ticker-paid-message-item-renderer, ul.yt-live-chat-ticker-paid-message-item-renderer, var.yt-live-chat-ticker-paid-message-item-renderer { margin: 0; padding: 0; @@ -78,3 +80,5 @@ yt-img-shadow.yt-live-chat-ticker-paid-message-item-renderer { yt-live-chat-ticker-paid-message-item-renderer[is-deleted] #author-photo.yt-live-chat-ticker-paid-message-item-renderer { display: none; } + +} diff --git a/frontend/src/assets/css/youtube/yt-live-chat-ticker-renderer.css b/frontend/src/assets/css/youtube/yt-live-chat-ticker-renderer.css index 029720d1..598a207b 100644 --- a/frontend/src/assets/css/youtube/yt-live-chat-ticker-renderer.css +++ b/frontend/src/assets/css/youtube/yt-live-chat-ticker-renderer.css @@ -1,3 +1,5 @@ +@layer yt { + canvas.yt-live-chat-ticker-renderer, caption.yt-live-chat-ticker-renderer, center.yt-live-chat-ticker-renderer, cite.yt-live-chat-ticker-renderer, code.yt-live-chat-ticker-renderer, dd.yt-live-chat-ticker-renderer, del.yt-live-chat-ticker-renderer, dfn.yt-live-chat-ticker-renderer, div.yt-live-chat-ticker-renderer, dl.yt-live-chat-ticker-renderer, dt.yt-live-chat-ticker-renderer, em.yt-live-chat-ticker-renderer, embed.yt-live-chat-ticker-renderer, fieldset.yt-live-chat-ticker-renderer, font.yt-live-chat-ticker-renderer, form.yt-live-chat-ticker-renderer, h1.yt-live-chat-ticker-renderer, h2.yt-live-chat-ticker-renderer, h3.yt-live-chat-ticker-renderer, h4.yt-live-chat-ticker-renderer, h5.yt-live-chat-ticker-renderer, h6.yt-live-chat-ticker-renderer, hr.yt-live-chat-ticker-renderer, i.yt-live-chat-ticker-renderer, iframe.yt-live-chat-ticker-renderer, img.yt-live-chat-ticker-renderer, ins.yt-live-chat-ticker-renderer, kbd.yt-live-chat-ticker-renderer, label.yt-live-chat-ticker-renderer, legend.yt-live-chat-ticker-renderer, li.yt-live-chat-ticker-renderer, menu.yt-live-chat-ticker-renderer, object.yt-live-chat-ticker-renderer, ol.yt-live-chat-ticker-renderer, p.yt-live-chat-ticker-renderer, pre.yt-live-chat-ticker-renderer, q.yt-live-chat-ticker-renderer, s.yt-live-chat-ticker-renderer, samp.yt-live-chat-ticker-renderer, small.yt-live-chat-ticker-renderer, span.yt-live-chat-ticker-renderer, strike.yt-live-chat-ticker-renderer, strong.yt-live-chat-ticker-renderer, sub.yt-live-chat-ticker-renderer, sup.yt-live-chat-ticker-renderer, table.yt-live-chat-ticker-renderer, tbody.yt-live-chat-ticker-renderer, td.yt-live-chat-ticker-renderer, tfoot.yt-live-chat-ticker-renderer, th.yt-live-chat-ticker-renderer, thead.yt-live-chat-ticker-renderer, tr.yt-live-chat-ticker-renderer, tt.yt-live-chat-ticker-renderer, u.yt-live-chat-ticker-renderer, ul.yt-live-chat-ticker-renderer, var.yt-live-chat-ticker-renderer { margin: 0; padding: 0; @@ -63,3 +65,5 @@ yt-icon.yt-live-chat-ticker-renderer { padding: 4px; width: 24px; } + +} From 3976aa79ede44ff05c4df959f9f552d32d030b7a Mon Sep 17 00:00:00 2001 From: John Smith Date: Sat, 23 Nov 2024 18:49:27 +0800 Subject: [PATCH 04/51] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=99=A8=E9=A2=84=E8=A7=88=E7=9A=84=E6=80=A7?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/Room.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/Room.vue b/frontend/src/views/Room.vue index a43a2079..a79d24b6 100644 --- a/frontend/src/views/Room.vue +++ b/frontend/src/views/Room.vue @@ -242,7 +242,7 @@ export default { let { type, data } = event.data switch (type) { case 'roomSetCustomStyle': - this.customStyleElement.innerText = data.css + this.customStyleElement.textContent = data.css break case 'roomStartClient': if (this.chatClient) { From 1244210bfe2a6309f315f721a3cf05da164fe624 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 24 Nov 2024 18:06:41 +0800 Subject: [PATCH 05/51] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=99=A8=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/package.json | 2 +- frontend/src/lang/zh.js | 6 +- frontend/src/views/StyleGenerator/Legacy.vue | 726 +++++++++--------- .../src/views/StyleGenerator/LineLike.vue | 634 +++++++-------- frontend/src/views/StyleGenerator/index.vue | 10 +- 5 files changed, 706 insertions(+), 672 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 762016f6..94006fdc 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "blivechat", - "version": "1.9.3", + "version": "1.10.0-dev", "private": true, "scripts": { "serve": "vue-cli-service serve", diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index 9a58247a..8dfe91fd 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -79,8 +79,8 @@ export default { legacy: '经典', lineLike: '仿微信', - light: '明亮', - dark: '黑暗', + light: '亮色', + dark: '暗色', outlines: '描边', showOutlines: '显示描边', @@ -150,7 +150,7 @@ export default { fadeOutTime: '淡出时间(毫秒)', slide: '滑动', reverseSlide: '反向滑动', - playAnimation: '播放动画', + playAnimation: '生成消息', result: '结果', copy: '复制', diff --git a/frontend/src/views/StyleGenerator/Legacy.vue b/frontend/src/views/StyleGenerator/Legacy.vue index 865b3c75..52e25a13 100644 --- a/frontend/src/views/StyleGenerator/Legacy.vue +++ b/frontend/src/views/StyleGenerator/Legacy.vue @@ -1,360 +1,378 @@ + + From 79f070fc26066a6a1191c2a340398bc01181c116 Mon Sep 17 00:00:00 2001 From: John Smith Date: Thu, 3 Apr 2025 19:58:45 +0800 Subject: [PATCH 19/51] =?UTF-8?q?web=E6=8E=A5=E5=8F=A3=E6=8D=A2=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E5=88=9D=E5=A7=8B=E5=8C=96=E6=88=BF=E9=97=B4=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/chat.py | 4 ++-- blivedm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/chat.py b/api/chat.py index 9bd979ec..64bc3457 100644 --- a/api/chat.py +++ b/api/chat.py @@ -375,8 +375,8 @@ async def _get_room_info(room_id) -> Tuple[int, int]: logger.warning('room=%d _get_room_info failed: %s', room_id, data['message']) return room_id, 0 - room_info = data['data']['room_info'] - return room_info['room_id'], room_info['uid'] + data = data['data'] + return data['room_id'], data['uid'] async def _get_server_host_list_and_token(self, room_id) -> Tuple[dict, Optional[str]]: try: diff --git a/blivedm b/blivedm index 30fcd4bf..a45ee8f6 160000 --- a/blivedm +++ b/blivedm @@ -1 +1 @@ -Subproject commit 30fcd4bf6275d0921a6e38d53f95d3f85cae570f +Subproject commit a45ee8f6774064978ba062621475cb78d6e27df8 From 7b91cbae3f1de6ee4541630b97cb2486f8f26623 Mon Sep 17 00:00:00 2001 From: John Smith Date: Fri, 4 Apr 2025 23:26:12 +0800 Subject: [PATCH 20/51] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E8=87=AA=E5=AE=9A=E4=B9=89=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 2 + api/main.py | 63 +++++++++++++++++++++++++++ data/custom_public/templates/.gitkeep | 0 3 files changed, 65 insertions(+) create mode 100644 data/custom_public/templates/.gitkeep diff --git a/.dockerignore b/.dockerignore index 2fc3c4ef..7321a3e1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -24,6 +24,8 @@ data/* !data/custom_public/ data/custom_public/* !data/custom_public/README.txt +!data/custom_public/templates/ +data/custom_public/templates/* !data/emoticons/ data/emoticons/* !data/plugins/ diff --git a/api/main.py b/api/main.py index 92085769..e9314f49 100644 --- a/api/main.py +++ b/api/main.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- import asyncio import hashlib +import json import logging import os +import cachetools import tornado.web +import yarl import api.base import config @@ -15,6 +18,10 @@ EMOTICON_UPLOAD_PATH = os.path.join(config.DATA_PATH, 'emoticons') EMOTICON_BASE_URL = '/emoticons' CUSTOM_PUBLIC_PATH = os.path.join(config.DATA_PATH, 'custom_public') +TEMPLATE_PATH = os.path.join(CUSTOM_PUBLIC_PATH, 'templates') +TEMPLATE_BASE_URL = '/custom_public/templates' + +_templates_cache = cachetools.TTLCache(1, 10) class StaticHandler(tornado.web.StaticFileHandler): @@ -100,6 +107,61 @@ def _save_file(body, client): return f'{EMOTICON_BASE_URL}/{filename}' +class TemplatesHandler(api.base.ApiHandler): + async def get(self): + templates = _templates_cache.get('templates', None) + if templates is None: + templates = await asyncio.get_running_loop().run_in_executor(None, self._get_templates) + _templates_cache['templates'] = templates + + self.set_header('Cache-Control', 'private, max-age=10') + self.write({'templates': templates}) + + @staticmethod + def _get_templates(): + template_ids = [] + try: + with os.scandir(TEMPLATE_PATH) as it: + for entry in it: + if entry.is_dir() and os.path.isfile(os.path.join(entry.path, 'template.json')): + template_ids.append(entry.name) + except OSError: + logger.exception('Failed to discover templates:') + return [] + if not template_ids: + return [] + + templates = [] + for template_id in template_ids: + try: + config_path = os.path.join(TEMPLATE_PATH, template_id, 'template.json') + with open(config_path, encoding='utf-8') as f: + cfg = json.load(f) + if not isinstance(cfg, dict): + raise TypeError(f'Config type error, type={type(cfg)}') + + url_str = str(cfg.get('url', '')) + url = yarl.URL(url_str) + if not url.absolute: + # 相对于模板目录 + base_url = yarl.URL(f'{TEMPLATE_BASE_URL}/{template_id}/') + url = base_url.join(url) + url_str = str(url) + + template = { + 'id': template_id, + 'name': str(cfg.get('name', '')), + 'version': str(cfg.get('version', '')), + 'author': str(cfg.get('author', '')), + 'description': str(cfg.get('description', '')), + 'url': url_str, + } + templates.append(template) + except (OSError, json.JSONDecodeError, TypeError, ValueError): + logger.exception('template_id=%s failed to load config:', template_id) + return templates + + class NoCacheStaticFileHandler(tornado.web.StaticFileHandler): def set_extra_headers(self, path): self.set_header('Cache-Control', 'no-cache') @@ -110,6 +172,7 @@ def set_extra_headers(self, path): (r'/api/endpoints', ServiceDiscoveryHandler), (r'/api/ping', PingHandler), (r'/api/emoticon', UploadEmoticonHandler), + (r'/api/templates', TemplatesHandler), ] # 通配的放在最后 LAST_ROUTES = [ diff --git a/data/custom_public/templates/.gitkeep b/data/custom_public/templates/.gitkeep new file mode 100644 index 00000000..e69de29b From 22d80e3af2dda7b1a9ca7eab326e17cb99a8a142 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 6 Apr 2025 16:23:52 +0800 Subject: [PATCH 21/51] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E6=A8=A1=E6=9D=BF=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/main.js | 4 + frontend/src/lang/en.js | 7 + frontend/src/lang/ja.js | 7 + frontend/src/lang/zh.js | 7 + frontend/src/views/Home/TemplateSelect.vue | 177 ++++++++++++++++++ .../src/views/{Home.vue => Home/index.vue} | 6 + 6 files changed, 208 insertions(+) create mode 100644 frontend/src/views/Home/TemplateSelect.vue rename frontend/src/views/{Home.vue => Home/index.vue} (98%) diff --git a/frontend/src/api/main.js b/frontend/src/api/main.js index 4fd822a3..bec9d781 100644 --- a/frontend/src/api/main.js +++ b/frontend/src/api/main.js @@ -9,3 +9,7 @@ export async function uploadEmoticon(file) { body.set('file', file) return (await axios.post('/api/emoticon', body)).data } + +export async function getTemplates() { + return (await axios.get('/api/templates')).data +} diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js index 8b1bb4c2..f9bd4349 100644 --- a/frontend/src/lang/en.js +++ b/frontend/src/lang/en.js @@ -65,6 +65,13 @@ export default { addEmoticon: 'Add emote', emoticonFileTooLarge: 'File size is too large. Max size is 1MB', + template: 'Custom HTML Templates', + templateDefaultTitle: 'Default', + templateDefaultDescription: 'A YouTube-style template that can be styled with custom CSS. Choose this if you are unfamiliar with custom HTML templates, otherwise your custom CSS will not take effect', + templateCustomUrlTitle: 'Enter template URL', + templateCustomUrlDescription: 'For templates not listed, you can manually enter the URL provided by the author here', + author: 'Author: ', + urlTooLong: 'The room URL is too long, and will be truncated by Livehime (but not by OBS)', roomUrlUpdated: 'The room URL is updated. Remember to copy it again', roomUrl: 'Room URL', diff --git a/frontend/src/lang/ja.js b/frontend/src/lang/ja.js index dddf0ec8..957c4f0a 100644 --- a/frontend/src/lang/ja.js +++ b/frontend/src/lang/ja.js @@ -65,6 +65,13 @@ export default { addEmoticon: 'スタンプを追加', emoticonFileTooLarge: 'ファイルサイズが大きすぎます。最大サイズは1MBです', + template: 'カスタムHTMLテンプレート', + templateDefaultTitle: 'デフォルト', + templateDefaultDescription: 'YouTube風のテンプレートで、カスタムCSSでスタイルを変更できます。カスタムHTMLテンプレートの機能に慣れていない場合はこれを選択してください。そうでない場合、カスタムCSSが適用されない', + templateCustomUrlTitle: 'テンプレートURLを入力', + templateCustomUrlDescription: 'リストにないテンプレートは、作者が提供するURLをここで手動で入力できます', + author: '作者:', + urlTooLong: 'ルームのURLが長すぎて、直播姬によって切り詰められます(ただし、OBSでは切り詰められません)', roomUrlUpdated: 'ルームのURLが更新されました。再度コピーすることをお忘れなく', roomUrl: 'ルームのURL', diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index 8dfe91fd..2cf83554 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -65,6 +65,13 @@ export default { addEmoticon: '添加表情', emoticonFileTooLarge: '文件尺寸太大,最大1MB', + template: '自定义HTML模板', + templateDefaultTitle: '默认', + templateDefaultDescription: '仿YouTube风格的模板,可以用自定义CSS修改样式。如果你不了解自定义HTML模板的功能,就选择这个,否则自定义CSS不会生效', + templateCustomUrlTitle: '输入模板URL', + templateCustomUrlDescription: '没有列出的模板,也可以在这里手动输入作者提供的URL', + author: '作者:', + urlTooLong: '房间URL太长了,会被直播姬截断(OBS不会)', roomUrlUpdated: '房间URL已更新,记得重新复制', roomUrl: '房间URL', diff --git a/frontend/src/views/Home/TemplateSelect.vue b/frontend/src/views/Home/TemplateSelect.vue new file mode 100644 index 00000000..cfdeda05 --- /dev/null +++ b/frontend/src/views/Home/TemplateSelect.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home/index.vue similarity index 98% rename from frontend/src/views/Home.vue rename to frontend/src/views/Home/index.vue index 7ccf991a..2957112d 100644 --- a/frontend/src/views/Home.vue +++ b/frontend/src/views/Home/index.vue @@ -217,6 +217,10 @@ {{$t('home.addEmoticon')}}

+ + + +

@@ -249,12 +253,14 @@ import _ from 'lodash' import download from 'downloadjs' +import TemplateSelect from './TemplateSelect' import { mergeConfig } from '@/utils' import * as mainApi from '@/api/main' import * as chatConfig from '@/api/chatConfig' export default { name: 'Home', + components: { TemplateSelect }, data() { return { serverConfig: { From 8c3dfa902ca58cc409c6eb079e923be32a233243 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 6 Apr 2025 18:35:10 +0800 Subject: [PATCH 22/51] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A8=A1=E6=9D=BF=E7=BC=A9=E7=95=A5=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/main.py | 62 +++++++++++++--------- frontend/src/views/Help.vue | 20 ++----- frontend/src/views/Home/TemplateSelect.vue | 51 +++++++++++++++--- 3 files changed, 87 insertions(+), 46 deletions(-) diff --git a/api/main.py b/api/main.py index e9314f49..0b9ecb1d 100644 --- a/api/main.py +++ b/api/main.py @@ -117,8 +117,7 @@ async def get(self): self.set_header('Cache-Control', 'private, max-age=10') self.write({'templates': templates}) - @staticmethod - def _get_templates(): + def _get_templates(self): template_ids = [] try: with os.scandir(TEMPLATE_PATH) as it: @@ -134,33 +133,48 @@ def _get_templates(): templates = [] for template_id in template_ids: try: - config_path = os.path.join(TEMPLATE_PATH, template_id, 'template.json') - with open(config_path, encoding='utf-8') as f: - cfg = json.load(f) - if not isinstance(cfg, dict): - raise TypeError(f'Config type error, type={type(cfg)}') - - url_str = str(cfg.get('url', '')) - url = yarl.URL(url_str) - if not url.absolute: - # 相对于模板目录 - base_url = yarl.URL(f'{TEMPLATE_BASE_URL}/{template_id}/') - url = base_url.join(url) - url_str = str(url) - - template = { - 'id': template_id, - 'name': str(cfg.get('name', '')), - 'version': str(cfg.get('version', '')), - 'author': str(cfg.get('author', '')), - 'description': str(cfg.get('description', '')), - 'url': url_str, - } + template = self._load_template_config(template_id) templates.append(template) except (OSError, json.JSONDecodeError, TypeError, ValueError): logger.exception('template_id=%s failed to load config:', template_id) return templates + @staticmethod + def _load_template_config(template_id): + config_path = os.path.join(TEMPLATE_PATH, template_id, 'template.json') + with open(config_path, encoding='utf-8') as f: + cfg = json.load(f) + if not isinstance(cfg, dict): + raise TypeError(f'Config type error, type={type(cfg)}') + + # 相对于模板目录 + base_url = yarl.URL(f'{TEMPLATE_BASE_URL}/{template_id}/') + + def ensure_abs_url(url_str_): + url_ = yarl.URL(url_str_) + if not url_.absolute: + url_ = base_url.join(url_) + url_str_ = str(url_) + return url_str_ + + thumbnail_url_str = str(cfg.get('thumbnail', '')) + if thumbnail_url_str != '': + thumbnail_url_str = ensure_abs_url(thumbnail_url_str) + + url_str = str(cfg.get('url', '')) + url_str = ensure_abs_url(url_str) + + template = { + 'id': template_id, + 'name': str(cfg.get('name', '')), + 'version': str(cfg.get('version', '')), + 'author': str(cfg.get('author', '')), + 'description': str(cfg.get('description', '')), + 'thumbnail': thumbnail_url_str, + 'url': url_str, + } + return template + class NoCacheStaticFileHandler(tornado.web.StaticFileHandler): def set_extra_headers(self, path): diff --git a/frontend/src/views/Help.vue b/frontend/src/views/Help.vue index cb8c7cab..c2fb36aa 100644 --- a/frontend/src/views/Help.vue +++ b/frontend/src/views/Help.vue @@ -2,15 +2,15 @@

{{ $t('help.help') }}

{{ $t('help.p1_1') }} https://play-live.bilibili.com/ {{ $t('help.p1_2') }}

-

+

{{ $t('help.p2') }}

-

+

{{ $t('help.p3') }}

-

+

{{ $t('help.p4') }}

-

+

{{ $t('help.p5') }}

-

+









--------------------------------------------------------------------------------------------------------

使用前必看:注意事项和常见问题

喜欢的话可以推荐给别人 _(:з」∠)_

@@ -22,13 +22,3 @@ export default { name: 'Help' } - - diff --git a/frontend/src/views/Home/TemplateSelect.vue b/frontend/src/views/Home/TemplateSelect.vue index cfdeda05..8e56d711 100644 --- a/frontend/src/views/Home/TemplateSelect.vue +++ b/frontend/src/views/Home/TemplateSelect.vue @@ -6,7 +6,11 @@

{{ $t('home.templateDefaultTitle') }}

-
{{ $t('home.templateDefaultDescription') }}
+
+
+

{{ $t('home.templateDefaultDescription') }}

+
+
@@ -15,7 +19,11 @@

{{ $t('home.templateCustomUrlTitle') }}

-
{{ $t('home.templateCustomUrlDescription') }}
+
+
+

{{ $t('home.templateCustomUrlDescription') }}

+
+
@@ -29,8 +37,13 @@ {{ template.version }} {{ $t('home.author') }}{{ template.author }} -
{{ template.description }}
-
URL: {{ template.url }}
+
+ +
+

{{ template.description }}

+

URL: {{ template.url }}

+
+
@@ -140,13 +153,12 @@ export default { } .card-body { - max-height: 200px; display: flex; flex-flow: column nowrap; + gap: 1em; } .title-line { - margin-block-end: 1em; flex: none; display: flex; flex-flow: row nowrap; @@ -168,10 +180,35 @@ export default { color: #606266; } +.description-line { + flex: none; + display: flex; + flex-flow: row nowrap; + gap: 1em; + max-height: 300px; +} + +.thumbnail { + flex: none; + width: 400px; + height: 300px; +} + .description { - margin-block-end: 1em; flex: auto; overflow-y: auto; text-wrap: wrap; + word-wrap: break-word; +} + +@media only screen and (max-width: 992px) { + .description-line { + flex-wrap: wrap; + max-height: unset; + } + + .thumbnail { + max-width: 100%; + } } From d2990ba8d8f14dcb0c3fd81a0e92ff1f65cae364 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 13 Apr 2025 17:01:01 +0800 Subject: [PATCH 23/51] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A8=A1=E6=9D=BFSDK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.eslintignore | 1 + frontend/src/blcsdk.js | 312 ++++++++++++++++++++++++++++++++++++ frontend/src/views/Room.vue | 89 ++++++++-- 3 files changed, 392 insertions(+), 10 deletions(-) create mode 100644 frontend/src/blcsdk.js diff --git a/frontend/.eslintignore b/frontend/.eslintignore index 96be2c3a..e684bb40 100644 --- a/frontend/.eslintignore +++ b/frontend/.eslintignore @@ -1,2 +1,3 @@ brotli_decode.js pronunciation/dict*.js +blcsdk.js diff --git a/frontend/src/blcsdk.js b/frontend/src/blcsdk.js new file mode 100644 index 00000000..22f017a2 --- /dev/null +++ b/frontend/src/blcsdk.js @@ -0,0 +1,312 @@ +/** @module blcsdk */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define([], factory) + } else { + root.blcsdk = factory() + } +}(typeof self !== 'undefined' ? self : this, function() { + const exports = {} + + const VERSION = '1.0.0' + /** + * 取SDK版本 + * @returns {string} "1.0.0" + */ + exports.getVersion = () => VERSION + + // 初始化消息的Promise {promise, resolve, reject} + let initPromise = null + // 初始化消息,包含版本、配置等信息 + let initMsg = null + + /** + * 消息处理器 + * @type {MsgHandler} + */ + let msgHandler = null + /** + * 用户设置的消息处理器 + * @type {MsgHandler} + */ + let rawMsgHandler = null + + /** + * @typedef InitOptions + * @property {boolean} noMsgDelay 去掉消息延迟,但会导致消息不平滑 + */ + + /** + * 初始化SDK + * + * 在调用除了setMsgHandler以外的其他接口之前必须先调用这个 + */ + async function init( + /** @type {?InitOptions} */ + {noMsgDelay = false} = {} + ) { + if (initPromise) { + throw new Error('Cannot call init() again') + } + // initPromise = Promise.withResolvers() + initPromise = {} + initPromise.promise = new Promise((resolve, reject) => { + initPromise.resolve = resolve + initPromise.reject = reject + }) + + if (window.parent === window) { + initPromise.reject(new Error('No parent window')) + return initPromise.promise + } + + msgHandler = noMsgDelay ? new SdkMsgHandler() : new SmoothedSdkMsgHandler() + window.addEventListener('message', onWindowMessage) + + // 连接blivechat + blcSendMsg('blcTemplateConnect') + setTimeout(() => initPromise.reject(new Error('Timed out waiting for blcInit message')), 10 * 1000) + + // 等待初始化消息 + initMsg = await initPromise.promise + console.debug('blcsdk initialized, init_msg=', initMsg) + } + exports.init = init + + /** + * 设置消息处理器 + * @param {?MsgHandler} handler 消息处理器 + */ + function setMsgHandler(handler) { + rawMsgHandler = handler + } + exports.setMsgHandler = setMsgHandler + + /** + * 取blivechat前端版本 + * @returns {string} "v1.10.0-dev" + */ + function getBlcVersion() { + if (!initMsg) { + throw new Error('Please call init() first') + } + return initMsg.blcVersion + } + exports.getBlcVersion = getBlcVersion + + /** + * 取blivechat前端用的SDK版本。是父窗口用的版本,不是这个包的getVersion返回值" + * @returns {string} "1.0.0" + */ + function getBlcSdkVersion() { + if (!initMsg) { + throw new Error('Please call init() first') + } + return initMsg.sdkVersion + } + exports.getBlcSdkVersion = getBlcSdkVersion + + /** + * @typedef Config + * @property {boolean} showGiftName 显示礼物名 + * @property {boolean} mergeSimilarDanmaku 合并相似弹幕 + * @property {boolean} mergeGift 合并礼物 + * @property {number} maxNumber 最大弹幕数 + */ + + /** + * 取blivechat前端房间部分配置 + * @returns {Config} + */ + function getConfig() { + if (!initMsg) { + throw new Error('Please call init() first') + } + return Object.freeze(initMsg.config) + } + exports.getConfig = getConfig + + function blcSendMsg(type, data = null) { + if (window.parent === window) { + return + } + let msg = { type, data } + window.parent.postMessage(msg, '*') + } + + function onWindowMessage(event) { + if (event.source !== window.parent) { + return + } + + let { type, data } = event.data + switch (type) { + case 'blcInit': + initPromise.resolve(data) + break + case 'blcAddMsg': + msgHandler.addMsg(data) + break + case 'blcDelMsgs': + msgHandler.delMsgs(data.ids) + break + case 'blcUpdateMsg': + msgHandler.updateMsg(data.id, data.newValuesObj) + break + } + } + + /** 模板消息处理器接口 */ + class MsgHandler { + /** + * 添加消息 + * @param {Object} msg + */ + addMsg(msg) {} + + /** + * 删除消息,主要用于撤回醒目留言 + * @param {string[]} ids 要删除的消息ID + */ + delMsgs(ids) {} + + /** + * 更新消息字段,主要用于更新翻译结果 + * @param {string} id 要更新的消息ID + * @param {Object} newValuesObj 字段和对应的新值 + */ + updateMsg(id, newValuesObj) {} + } + exports.MsgHandler = MsgHandler + + class SdkMsgHandler extends MsgHandler { + addMsg(msg) { this._callRawHandler('addMsg', msg) } + delMsgs(ids) { this._callRawHandler('delMsgs', ids) } + updateMsg(id, newValuesObj) { this._callRawHandler('updateMsg', id, newValuesObj) } + _callRawHandler(...args) { doCallRawHandler(...args) } + } + + function doCallRawHandler(funcName, ...args) { + if (!rawMsgHandler) { + return + } + try { + let func = rawMsgHandler[funcName] + return func.call(rawMsgHandler, ...args) + } catch (e) { + console.error(e) + } + } + + // 发送消息时间间隔范围 + const MSG_MIN_INTERVAL = 80 + const MSG_MAX_INTERVAL = 1000 + + class SmoothedSdkMsgHandler extends SdkMsgHandler { + constructor() { + super() + // 消息队列 + this._queue = [] + // 消费消息队列的定时器ID + this._emitSmoothedMsgTimerId = null + // 最近进队列的时间间隔,用来估计下次进队列的时间 + this._enqueueIntervals = [] + // 上次进队列的时间 + this._lastEnqueueTime = null + // 估计的下次进队列时间间隔 + this._estimatedEnqueueInterval = null + + this._boundEmitSmoothedMsgs = this._emitSmoothedMsgs.bind(this) + } + + _callRawHandler(funcName, ...args) { + let msg = {funcName, args} + this._enqueueMsg(msg) + } + + _enqueueMsg(msg) { + // 估计进队列时间间隔 + if (!this._lastEnqueueTime) { + this._lastEnqueueTime = new Date() + } else { + let curTime = new Date() + let interval = curTime - this._lastEnqueueTime + // 真实的进队列时间间隔模式大概是这样:2500, 300, 300, 300, 2500, 300, ... + // B站消息有缓冲,会一次发多条消息。这里把波峰视为发送了一次真实的WS消息,所以要过滤掉间隔太小的 + if (interval > 1000 || this._enqueueIntervals.length < 5) { + this._enqueueIntervals.push(interval) + if (this._enqueueIntervals.length > 5) { + this._enqueueIntervals.splice(0, this._enqueueIntervals.length - 5) + } + // 这边估计得尽量大,只要不太早把消息缓冲发完就是平滑的。有MESSAGE_MAX_INTERVAL保底,不会让消息延迟太大 + // 其实可以用单调队列求最大值,偷懒不写了 + this._estimatedEnqueueInterval = Math.max(...this._enqueueIntervals) + } + // 上次入队时间还是要设置,否则会太早把消息缓冲发完,然后较长时间没有新消息 + this._lastEnqueueTime = curTime + } + + this._queue.push(msg) + + if (!this._emitSmoothedMsgTimerId) { + this._emitSmoothedMsgTimerId = setTimeout(this._boundEmitSmoothedMsgs) + } + } + + _emitSmoothedMsgs() { + this._emitSmoothedMsgTimerId = null + if (this._queue.length <= 0) { + return + } + + // 估计的下次进队列剩余时间 + let estimatedNextEnqueueRemainTime = 10 * 1000 + if (this._estimatedEnqueueInterval) { + estimatedNextEnqueueRemainTime = Math.max(this._lastEnqueueTime - new Date() + this._estimatedEnqueueInterval, 1) + } + // 计算发送的消息数,保证在下次进队列之前发完 + // 下次进队列之前应该发多少条消息 + let shouldEmitNum = Math.max(this._queue.length, 0) + // 下次进队列之前最多能发多少次 + let maxCanEmitCount = estimatedNextEnqueueRemainTime / MSG_MIN_INTERVAL + // 这次发多少条消息 + let numToEmit + if (shouldEmitNum < maxCanEmitCount) { + // 队列中消息数很少,每次发1条也能发完 + numToEmit = 1 + } else { + // 每次发1条以上,保证按最快速度能发完 + numToEmit = Math.ceil(shouldEmitNum / maxCanEmitCount) + } + + // 发消息 + let msgs = this._queue.splice(0, numToEmit) + for (let msg of msgs) { + doCallRawHandler(msg.funcName, ...msg.args) + } + + if (this._queue.length <= 0) { + return + } + // 消息没发完,计算下次发消息时间 + let sleepTime + if (numToEmit === 1) { + // 队列中消息数很少,随便定个[MESSAGE_MIN_INTERVAL, MESSAGE_MAX_INTERVAL]的时间 + sleepTime = estimatedNextEnqueueRemainTime / this._queue.length + sleepTime *= 0.5 + Math.random() + if (sleepTime > MSG_MAX_INTERVAL) { + sleepTime = MSG_MAX_INTERVAL + } else if (sleepTime < MSG_MIN_INTERVAL) { + sleepTime = MSG_MIN_INTERVAL + } + } else { + // 按最快速度发 + sleepTime = MSG_MIN_INTERVAL + } + this._emitSmoothedMsgTimerId = window.setTimeout(this._boundEmitSmoothedMsgs, sleepTime) + } + } + + return exports +})) diff --git a/frontend/src/views/Room.vue b/frontend/src/views/Room.vue index 3a5c66a2..1c21c17e 100644 --- a/frontend/src/views/Room.vue +++ b/frontend/src/views/Room.vue @@ -16,23 +16,62 @@ import * as chatModels from '@/api/chat/models' import ChatRenderer from '@/components/ChatRenderer' import * as constants from '@/components/ChatRenderer/constants' +class DefaultRenderer { + constructor(rendererVm) { + this.addMessage = rendererVm.addMessage + this.delMessages = rendererVm.delMessages + this.updateMessage = rendererVm.updateMessage + this.mergeSimilarText = rendererVm.mergeSimilarText + this.mergeSimilarGift = rendererVm.mergeSimilarGift + } + + destroy() { + let dummyFunc = () => {} + this.addMessage = dummyFunc + this.delMessages = dummyFunc + this.updateMessage = dummyFunc + this.mergeSimilarText = dummyFunc + this.mergeSimilarGift = dummyFunc + } +} + +const BLC_SDK_VERSION = '1.0.0' + class CustomTemplateRenderer { - constructor(templateIframe) { - this.templateIframe = templateIframe + constructor(templateIframe, config) { + this._templateIframe = templateIframe + this._config = config + + this._enabledSendMessageToTemplate = (type, data) => { + let msg = { type, data } + templateIframe.contentWindow.postMessage(msg, '*') + } + this._sendMessageToTemplate = () => {} + + this._boundOnWindowMessage = this._onWindowMessage.bind(this) + window.addEventListener('message', this._boundOnWindowMessage) + } + + destroy() { + window.removeEventListener('message', this._boundOnWindowMessage) + + let dummyFunc = () => {} + this._enabledSendMessageToTemplate = dummyFunc + this._sendMessageToTemplate = dummyFunc } addMessage(message) { - this.sendMessageToTemplate('blcAddMsg', message) + this._sendMessageToTemplate('blcAddMsg', message) } delMessages(ids) { let data = { ids } - this.sendMessageToTemplate('blcDelMsgs', data) + this._sendMessageToTemplate('blcDelMsgs', data) } updateMessage(id, newValuesObj) { let data = { id, newValuesObj } - this.sendMessageToTemplate('blcUpdateMsg', data) + this._sendMessageToTemplate('blcUpdateMsg', data) } mergeSimilarText() { @@ -43,9 +82,31 @@ class CustomTemplateRenderer { return false } - sendMessageToTemplate(cmd, data) { - let msg = { cmd, data } - this.templateIframe.contentWindow.postMessage(msg, '*') + _onWindowMessage(event) { + if (event.source !== this._templateIframe.contentWindow) { + return + } + + let { type } = event.data + switch (type) { + case 'blcTemplateConnect': { + this._sendMessageToTemplate = this._enabledSendMessageToTemplate + + // 发送初始化消息 + let initData = { + blcVersion: process.env.APP_VERSION, + sdkVersion: BLC_SDK_VERSION, + config: { + showGiftName: this._config.showGiftName, + mergeSimilarDanmaku: this._config.mergeSimilarDanmaku, + mergeGift: this._config.mergeGift, + maxNumber: this._config.maxNumber, + } + } + this._sendMessageToTemplate('blcInit', initData) + break + } + } } } @@ -78,7 +139,7 @@ export default { textEmoticons: [], // 官方的文本表情(后端配置的) pronunciationConverter: null, - customStyleElement, // 仅用于样式生成器中预览样式 + customStyleElement, // 仅用于样式生成器中预览样式和使用自定义模板时 presetCssLinkElement: null, renderer: null, @@ -124,7 +185,11 @@ export default { } }, mounted() { - this.renderer = !this.useCustomTemplate ? this.$refs.renderer : new CustomTemplateRenderer(this.$refs.templateIframe) + if (this.useCustomTemplate) { + this.renderer = new CustomTemplateRenderer(this.$refs.templateIframe, this.config) + } else { + this.renderer = new DefaultRenderer(this.$refs.renderer) + } if (document.visibilityState === 'visible') { if (this.roomKeyValue === null) { @@ -152,6 +217,10 @@ export default { if (this.presetCssLinkElement) { document.head.removeChild(this.presetCssLinkElement) } + + if (this.renderer) { + this.renderer.destroy() + } }, methods: { onVisibilityChange() { From 491dbb4fd96200f2e76007bd41746b3a5aa35f82 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 13 Apr 2025 17:31:10 +0800 Subject: [PATCH 24/51] =?UTF-8?q?=E5=89=8D=E7=AB=AFrichContent=E6=94=B9?= =?UTF-8?q?=E5=90=8D=E4=B8=BAcontentParts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ChatRenderer/TextMessage.vue | 12 ++--- .../src/components/ChatRenderer/constants.js | 14 +++--- .../src/components/ChatRenderer/index.vue | 4 +- frontend/src/views/Room.vue | 48 +++++++++---------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/frontend/src/components/ChatRenderer/TextMessage.vue b/frontend/src/components/ChatRenderer/TextMessage.vue index 393b7acf..39135dd8 100644 --- a/frontend/src/components/ChatRenderer/TextMessage.vue +++ b/frontend/src/components/ChatRenderer/TextMessage.vue @@ -9,10 +9,10 @@ :isInMemberMessage="false" :authorName="authorName" :authorType="authorType" :privilegeType="privilegeType" > -