diff --git a/src/trubbel/index.js b/src/trubbel/index.js index aad6ae16..6514b5a9 100644 --- a/src/trubbel/index.js +++ b/src/trubbel/index.js @@ -9,6 +9,9 @@ import { Channel_ModView } from "./settings/channel/mod-view"; import { Channel_Player } from "./settings/channel/player"; import { Channel_VODs } from "./settings/channel/vods"; +// Dashboard +import { Dashboard } from "./settings/dashboard/dashboard"; + // Directory import { Directory_Following } from "./settings/directory/following"; import { Directory_Thumbnails } from "./settings/directory/thumbnails"; @@ -46,6 +49,9 @@ class Trubbel extends Addon { this.inject(Channel_Player); this.inject(Channel_VODs); + // Dashboard + this.inject(Dashboard); + // Directory this.inject(Directory_Following); this.inject(Directory_Thumbnails); diff --git a/src/trubbel/manifest.json b/src/trubbel/manifest.json index 326c5759..5f1ad701 100644 --- a/src/trubbel/manifest.json +++ b/src/trubbel/manifest.json @@ -5,15 +5,15 @@ "main", "clips" ], - "name": "Trubbel’s Utilities", + "name": "Trubbel\u2019s Utilities", "short_name": "Trubbel", - "description": "↓ Lots of features ↓\n\n**Chat:**\n\n– Clickable Steam Inspect Links\n\n– Custom Commands (accountage, followage, localmod/sub etc.)\n\n– BTTV-like Moderation\n\n– Channel Name in Popout Chat\n\n– Clickable Usernames in /mods, /vips and Raid Messages\n\n**Directory:**\n\n– Display Channel Follow Dates\n\n– Display Total Followed Channels\n\n– Live Thumbnail Previews\n\n**Inventory:**\n\n– Auto Claim Drops\n\n– Collapsible Drops\n\n**Livestream:**\n\n– Auto Mute/Pause Stream (in background tabs)\n\n**Mod View:**\n\n– Activity Feed Moderation\n\n– Auto Mod View\n\n**Overall:**\n\n– Live Sidebar Previews\n\n– Yet Another Prime Reminder\n\n**Player:**\n\n– Auto Reset Player\n\n**VODs:**\n\n– Auto Skip Muted Segments\n\n– Custom Seeking\n\n– Custom Progress Bar\n\n…among other things…", + "description": "↓ Lots of features ↓\n\n**Chat:**\n\n– Custom commands\n\n– First-time chatter indicator (for yourself)\n\n– Clickable Steam inspect links\n\n– Markdown support (bold, italic, underline, strikethrough, spoilers and timestamps)\n\n– Highlight messages\n\n– BTTV-like moderation\n\n– Raid preview (image, video)\n\n– Hide shared messages\n\n– Translate chat messages\n\n– Clickable usernames in /mods, /vips and raid messages\n\n– Display recent messages in viewer cards\n\n**Mod View:**\n\n– Activity feed moderation\n\n– Display emote and cheer tooltips in activity feed\n\n– Automatically enter mod view\n\n**Player:**\n\n– Automatically reset player on error\n\n**VODs:**\n\n– Custom progress bar\n\n– Custom seeking\n\n– Frame by frame seeking\n\n– Automatically skip muted segments\n\n**Dashboard:**\n\n– Show dashboard deletion date for past broadcasts\n\n**Directory:**\n\n– Display follow date in followed channels\n\n– Display total followed channels\n\n– Thumbnail previews\n\n**Inventory:**\n\n– Automatically claim drops\n\n– Collapsible drops\n\n**Overall:**\n\n– Yet Another Prime Reminder\n\n– Sidebar previews\n\n– Pinned sidebar channels\n\n– Automatically expand sidebar channels\n\n…among other things…", "author": "Trubbel", "maintainer": "Trubbel", - "version": "4.2.6", + "version": "4.2.7", "search_terms": "trubbel", "website": "https://twitch.tv/trubbel", "settings": "add_ons.trubbel_s_utilities", "created": "2025-01-06T23:29:54.496Z", - "updated": "2025-12-01T19:54:01.713Z" + "updated": "2026-01-17T16:15:04.277Z" } \ No newline at end of file diff --git a/src/trubbel/modules/appearance/declutter/index.js b/src/trubbel/modules/appearance/declutter/index.js index 0cdd2c79..b467f7e6 100644 --- a/src/trubbel/modules/appearance/declutter/index.js +++ b/src/trubbel/modules/appearance/declutter/index.js @@ -23,6 +23,7 @@ export default class Declutter { "hide-player-mrv": ".video-player__overlay :is(.player-overlay-background--darkness-3):has(.offline-recommendations-video-card)", "hide-stories": "#side-nav [class*=\"storiesLeftNavSection--\"],#side-nav :is([style]) :has([class*=\"storiesLeftNavSectionCollapsedButton--\"]),div[class^=\"Layout-sc-\"]:has(> .scrollable-area[style] > div[style] > h2.sr-only)", "hide-stream-monthly-recap": "div > div:has(> article a[href*=\"/recaps/\"])", + "hide-watch-streak": ".rewards-list > div:has([style*=\"cursor: pointer\"] svg [d*=\"M5.295 8.05 10 2l3 4 2-3 3.8 5.067a11 11 0 0 1 2.2 6.6A7.333 7.333 0 0 1 13.667 22h-3.405A7.262 7.262 0 0 1 3 14.738c0-2.423.807-4.776 2.295-6.688Zm7.801 1.411 2-3L17.2 9.267a9 9 0 0 1 1.8 5.4 5.334 5.334 0 0 1-4.826 5.31 3 3 0 0 0 .174-3.748L12 13l-2.348 3.229a3 3 0 0 0 .18 3.754A5.263 5.263 0 0 1 5 14.738c0-1.978.66-3.9 1.873-5.46l3.098-3.983 3.125 4.166Z\"])", "hide-vod-muted-segment-popup": ".video-player .muted-segments-alert__scroll-wrapper", }; } @@ -45,6 +46,7 @@ export default class Declutter { this.toggleHide("hide-player-mrv", this.settings.get("addon.trubbel.appearance.declutter.player.most_recent_video")); this.toggleHide("hide-stories", this.settings.get("addon.trubbel.appearance.declutter.stories")); this.toggleHide("hide-stream-monthly-recap", this.settings.get("addon.trubbel.appearance.declutter.stream.monthly_recap")); + this.toggleHide("hide-watch-streak", this.settings.get("addon.trubbel.appearance.declutter.stream.watch_streak")); this.toggleHide("hide-vod-muted-segment-popup", this.settings.get("addon.trubbel.appearance.declutter.vods.muted_segment_popup")); this.updateCSS(); @@ -119,5 +121,16 @@ export default class Declutter { } else { this.style.delete("hide-stream-power-ups"); } + // Appearance - Declutter - Stream - Hide sponsored player gradient + if (this.settings.get("addon.trubbel.appearance.declutter.stream.sponsored_gradient")) { + this.style.set("hide-sponsored-player-gradient", ` + .channel-page__video-player--with-border { + background: transparent !important; + padding: 0px !important; + } + `); + } else { + this.style.delete("hide-sponsored-player-gradient"); + } } } \ No newline at end of file diff --git a/src/trubbel/modules/appearance/tweaks/index.js b/src/trubbel/modules/appearance/tweaks/index.js index f25e8ac7..0aae009f 100644 --- a/src/trubbel/modules/appearance/tweaks/index.js +++ b/src/trubbel/modules/appearance/tweaks/index.js @@ -13,14 +13,13 @@ export default class Tweaks { // Appearance - Tweaks - Buttons, Input, Select, Textarea - Use old buttons with less border-radius if (this.settings.get("addon.trubbel.appearance.tweaks.form_control.border-radius")) { this.style.set("button-border-radius", ` - button[class*="ScCoreButton-sc-"], - a[class*="ScCoreButton-sc-"], - div:has(> button[data-test-selector="follow-button"]), - div:has(> div [style] button[data-test-selector="follow-button"]), - div:has(> button[data-test-selector="unfollow-button"]), - div:has(> div [style] button[data-test-selector="unfollow-button"]), - div:has(> button[data-a-target="notifications-toggle"]), - .metadata-layout__support div:has(> button[data-a-target="top-nav-get-bits-button"]) { + div:has(> div [style] button[data-a-target="follow-button"]), + div:has(> div [style] button[data-a-target="unfollow-button"]), + div:has(> [class^="ScCoreButton-"] [data-a-target="tw-core-button-label-text"]), + [class^="ScCoreButton-"]:has([data-a-target="tw-core-button-label-text"]), + button[data-test-selector="subscribe-button__dropdown"], + .metadata-layout__support div:has(> [class^="ScCoreButton-"][data-a-target="top-nav-get-bits-button"]), + .metadata-layout__support [class^="ScCoreButton-"][data-a-target="top-nav-get-bits-button"] { border-radius: 0.4rem !important; } `); @@ -98,6 +97,17 @@ export default class Tweaks { } else { this.style.delete("inv-big-img"); } + // Appearance - Tweaks - Scrollbars - Thinner scrollbars in chat and sidebar + if (this.settings.get("addon.trubbel.appearance.tweaks.scrollbar.thin")) { + this.style.set("scrollbar-thin", ` + .side-nav__scrollable_content, + .stream-chat .scrollable-area { + scrollbar-width: thin !important; + } + `); + } else { + this.style.delete("scrollbar-thin"); + } // Appearance - Tweaks - Titles - Display full titles for sidebar tooltips if (this.settings.get("addon.trubbel.appearance.tweaks.titles.full_sidebar_tooltip")) { this.style.set("display-full-sidebar-tooltip", ` diff --git a/src/trubbel/modules/channel/chat/commands/local-modes.js b/src/trubbel/modules/channel/chat/commands/local-modes.js index 6959927c..c1deeaf6 100644 --- a/src/trubbel/modules/channel/chat/commands/local-modes.js +++ b/src/trubbel/modules/channel/chat/commands/local-modes.js @@ -48,7 +48,7 @@ export class LocalModeManager { }); this.ctx.log.info(`[Local Mode] Mod mode disabled`); } else { - + const wasSubModeActive = this.currentMode === "sub"; if (wasSubModeActive) { this.disableCurrentMode(); @@ -76,7 +76,7 @@ export class LocalModeManager { priority: 0, process: (tokens, msg) => { const badges = msg.badges || {}; - const isSubscriber = "subscriber" in badges; + const isSubscriber = "subscriber" in badges || "founder" in badges; const isModOrHigher = this.isModeratorOrHigher(badges); if (!isSubscriber && !isModOrHigher) msg.ffz_removed = true; } @@ -121,7 +121,8 @@ export class LocalModeManager { "staff" in badges || "admin" in badges || "global_mod" in badges || - "moderator" in badges; + "moderator" in badges || + "lead_moderator" in badges; } getStatus() { diff --git a/src/trubbel/modules/channel/chat/raid-preview.js b/src/trubbel/modules/channel/chat/raid-preview.js index d3a65bc6..758f2e39 100644 --- a/src/trubbel/modules/channel/chat/raid-preview.js +++ b/src/trubbel/modules/channel/chat/raid-preview.js @@ -256,14 +256,21 @@ export default class RaidPreview { margin-bottom: 8px; opacity: 0.8; } - .trubbel-video-preview { - max-width: 440px; - max-height: 248px; - width: 100%; - height: 248px; - border: none; - border-radius: 4px; - display: block; + .trubbel-chat-settings { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 8px; + font-size: 12px; + opacity: 0.8; + } + .trubbel-chat-setting { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 2px 6px; + background: rgba(255, 255, 255, 0.1); + border-radius: 3px; } `); @@ -277,58 +284,73 @@ export default class RaidPreview { } const targetLogin = user.login; - let previewMedia = null; - if (user.stream && previewType > 0) { + const createBlurOverlay = () => { + if (!should_blur_image || !user.stream?.contentClassificationLabels) { + return null; + } + + return ( +
+ + + + +
+ May contain: {user.stream.contentClassificationLabels.map(f => f.localizedName || f.id).join(", ")} +
+
+ ); + }; + + const createPreviewMedia = () => { + if (!user.stream || previewType === 0) { + return null; + } + + const mediaStyle = { + maxWidth: "440px", + maxHeight: "248px", + width: "100%", + height: "auto", + objectFit: "contain", + borderRadius: "4px", + display: "block", + }; + + const blurOverlay = createBlurOverlay(); + if (previewType === 1) { - // image - previewMedia = ( + // Image preview + return (
Stream Preview - {should_blur_image && user.stream.contentClassificationLabels && ( -
- - - - -
- May contain: {user.stream.contentClassificationLabels.map(f => f.localizedName || f.id).join(", ")} -
-
- )} + {blurOverlay}
); } else if (previewType === 2) { - // video + // Video preview const params = new URLSearchParams({ channel: targetLogin, enableExtensions: false, @@ -341,68 +363,185 @@ export default class RaidPreview { }); const playerUrl = `https://player.twitch.tv/?${params}`; - previewMedia = ( + return (