diff --git a/src/components/Settings/components/SettingNotifications.tsx b/src/components/Settings/components/SettingNotifications.tsx
index 3f481e9d..4ce5bef5 100644
--- a/src/components/Settings/components/SettingNotifications.tsx
+++ b/src/components/Settings/components/SettingNotifications.tsx
@@ -1,56 +1,64 @@
+import type { Notification } from "@/src/types";
+
import { useNotifications } from "@/src/hooks";
import { cn } from "@/src/utils/utilities";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useSettings } from "../Settings";
-
-export default function SettingsNotifications() {
- const { notifications, removeNotification } = useNotifications();
- const [parentRef] = useAutoAnimate({ duration: 300 });
+function NotificationCloseButton({ notification }: { notification: Notification }) {
+ const { removeNotification } = useNotifications();
+ return (
+
+ );
+}
+function ToastNotification({ key, notification }: { key: number; notification: Notification }) {
const {
i18nInstance: { t }
} = useSettings();
+ const message: string = t(notification.message);
return (
-
- {notifications.map((notification, index) => {
- const message: string = t(notification.message);
- return (
-
- {notification.action ?
- notification.action === "reset_settings" ?
- <>
- {message.split("\n").map((line, index) => (
-
{line}
- ))}
-
removeNotification(notification)}>
- ×
-
- >
- : null
- : <>
- {message}
-
removeNotification(notification)}>
- ×
-
- >
- }
-
-
- );
+
+ {notification.action ?
+ notification.action === "reset_settings" ?
+ <>
+ {message.split("\n").map((line, index) => (
+
{line}
+ ))}
+
+ >
+ : null
+ : <>
+ {message}
+
+ >
+ }
+
+
+ );
+}
+export default function SettingsNotifications() {
+ const { notifications } = useNotifications();
+ const [parentRef] = useAutoAnimate({ duration: 300 });
+ return (
+
+ {notifications.map((notification, index) => (
+
+ ))}
);
}
diff --git a/src/components/Settings/components/SettingSection.tsx b/src/components/Settings/components/SettingSection.tsx
index 58ecf4d4..e3a2b775 100644
--- a/src/components/Settings/components/SettingSection.tsx
+++ b/src/components/Settings/components/SettingSection.tsx
@@ -1,6 +1,9 @@
+import { cn } from "@/src/utils/utilities";
+
interface SettingSectionProps {
children: React.ReactNode;
+ className?: string;
}
-export default function SettingSection({ children }: SettingSectionProps) {
- return
{children} ;
+export default function SettingSection({ children, className }: SettingSectionProps) {
+ return
{children} ;
}
diff --git a/src/deepDarkMaterialCSS.ts b/src/deepDarkMaterialCSS.ts
new file mode 100644
index 00000000..3facd007
--- /dev/null
+++ b/src/deepDarkMaterialCSS.ts
@@ -0,0 +1,4298 @@
+/**
+ * Version 4.1.8
+ * Author: https://github.com/RaitaroH
+ * Co-authors: https://github.com/MechaLynx
+ * Repository: https://github.com/RaitaroH/YouTube-DeepDark
+ */
+export const deepDarkMaterial = `
+/* Author : Theme made by RaitaroH */
+/* Co-authors : https://github.com/MechaLynx */
+/* Home : https://github.com/RaitaroH/YouTube-DeepDark */
+/* License : GNU General Public License v3.0 */
+
+/*Error page*/
+#error-page {
+ background-color: var(--main-background) !important;
+ color: var(--main-text) !important;
+}
+
+* {
+ /*Scrollbar for firefox*/
+ scrollbar-color: rgba(79, 80, 85, 1) transparent !important;
+ scrollbar-width: 8px !important;
+
+ --yt-spec-text-primary: var(--main-text) !important;
+ --yt-spec-text-secondary: var(--dimmer-text) !important;
+ --paper-spinner-color: var(--dimmer-text) !important;
+
+ --paper-input-container-color: var(--dimmer-text) !important;
+
+ --paper-radio-button-unchecked-color: var(--dimmer-text) !important;
+ --paper-radio-button-unchecked-background-color: transparent !important;
+ --paper-radio-button-checked-color: var(--main-color) !important;
+ --paper-radio-button-checked-ink-color: var(--main-color) !important;
+ --paper-radio-button-unchecked-ink-color: var(--main-color) !important;
+
+ --paper-checkbox-unchecked-color: var(--dimmer-text) !important;
+ --paper-checkbox-checked-color: var(--main-color) !important;
+ --paper-checkbox-checkmark-color: none !important;
+ --paper-checkbox-checked-ink-color: var(--main-color) !important;
+ --paper-checkbox-unchecked-ink-color: var(--main-color) !important;
+ --yt-spec-call-to-action: var(--main-color) !important;
+ --yt-spec-suggested-action: var(--hover-background) !important;
+ --yt-spec-outline: var(--hover-background) !important;
+ --yt-spec-brand-button-background: var(--main-color) !important;
+ /*in incognito this may be used as subscribe button but is inconsistent .yt-spec-button-shape-next--brand.yt-spec-button-shape-next--filled*/
+
+ --yt-formatted-string-bold-color: var(--dimmer-text) !important;
+ /*this affects number of views*/
+
+ --yt-lightsource-section1-color: var(--main-background) !important;
+ /* watch history header */
+
+ /*clip icon hover*/
+ --yt-spec-icon-active-other: var(--main-text) !important;
+ --iron-icon-fill-color: var(--main-text) !important;
+
+ --yt-spec-base-background: var(--second-background) !important;
+}
+
+/*Scrollbar fix for chrome*/
+*:not([hide-scrollbar]) ::-webkit-scrollbar-thumb {
+ background: rgba(79, 80, 85, 1) !important;
+}
+
+*:not([hide-scrollbar]) ::-webkit-scrollbar {
+ width: 8px !important;
+}
+
+::-webkit-scrollbar-track {
+ background: transparent !important;
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--main-color) !important;
+}
+
+/*Background for the entire page*/
+html,
+ytd-browse,
+ytd-watch,
+ytd-search,
+ytd-app,
+ytd-app[is-watch-page],
+[class*="ytd-watch-flexy"]:not(#engagement-panel-scrim),
+.style-scope.ytd-page-manager.hide-skeleton,
+.account-container {
+ background-color: var(--main-background) !important;
+}
+
+/*Border for the sidemenu*/
+#guide-content.ytd-app {
+ border-right: 1px solid var(--yt-border-color) !important;
+}
+
+/*Changed text highlight*/
+::selection {
+ background: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+::-moz-selection {
+ background: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+/*Outline for links*/
+a {
+ outline-color: var(--main-color) !important;
+}
+
+a:hover {
+ color: var(--main-color) !important;
+ fill: var(--main-color) !important;
+}
+
+/*Outline for comments*/
+#content-text.ytd-comment-renderer {
+ outline: none !important;
+}
+
+/*Placeholder image on pages that need an account - such as Subscriptions*/
+ytd-background-promo-renderer .image.ytd-background-promo-renderer,
+ytd-message-renderer yt-icon.ytd-message-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Nav bar*/
+ytd-masthead,
+#yt-masthead-container,
+#masthead-positioner-height-offset
+
+/*account page*/
+ {
+ background-color: var(--second-background) !important;
+ border-bottom-color: var(--hover-background) !important;
+}
+
+yt-icon-button svg {
+ fill: var(--dimmer-text) !important;
+}
+
+yt-icon-button:hover svg {
+ fill: var(--main-color) !important;
+}
+
+#logo-icon-container.ytd-topbar-logo-renderer #youtube-paths.ytd-topbar-logo-renderer path.ytd-topbar-logo-renderer,
+#youtube-red-paths
+
+/*premium*/
+ {
+ fill: var(--main-text) !important;
+}
+
+/*acount settings page*/
+/*logo*/
+.exp-invert-logo.inverted-hdpi #header::before,
+.exp-invert-logo.inverted-hdpi .ypc-join-family-header .logo,
+.exp-invert-logo.inverted-hdpi #footer-logo .footer-logo-icon,
+.exp-invert-logo.inverted-hdpi #yt-masthead #logo-container .logo,
+.exp-invert-logo.inverted-hdpi #masthead #logo-container,
+.exp-invert-logo.inverted-hdpi .admin-masthead-logo a,
+.exp-invert-logo.inverted-hdpi #yt-sidebar-styleguide-logo #logo {
+ filter: invert(1) grayscale(1);
+}
+
+/*buttons*/
+#yt-masthead-creation-button {
+ filter: brightness(220%);
+}
+
+#yt-masthead-notifications .yt-uix-button-icon-bell {
+ filter: invert(1) brightness(720%);
+}
+
+#sections.ytd-multi-page-menu-renderer>.ytd-multi-page-menu-renderer:not(:last-child) {
+ border-color: var(--hover-background) !important;
+}
+
+/*Chat in the header*/
+ytd-conversation-switcher-item-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#last-post.ytd-conversation-switcher-item-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*invite friends*/
+#bar.ytd-copy-connection-invite-url-renderer {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+#icon.ytd-copy-connection-invite-url-renderer {
+ color: var(--main-text) !important;
+}
+
+/*chat popup*/
+ytd-conversation-section-renderer {
+ background: var(--second-background) !important;
+}
+
+#title-bar.ytd-conversation-section-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+ytd-conversation-text-item-renderer[justification-style="JUSTIFICATION_START"] #post-text.ytd-conversation-text-item-renderer,
+ytd-conversation-link-item-renderer[justification-style="JUSTIFICATION_START"] #link.ytd-conversation-link-item-renderer,
+#bar.ytd-conversation-link-item-renderer,
+#thumbnail.ytd-inline-playback-renderer,
+#video-data.ytd-inline-playback-renderer {
+ border-color: var(--hover-background) !important;
+ background: var(--hover-background) !important;
+}
+
+#post-text.ytd-conversation-text-item-renderer,
+textarea.iron-autogrow-textarea {
+ color: var(--main-text) !important;
+}
+
+#displayed-text.ytd-conversation-link-item-renderer,
+#icon.ytd-conversation-link-item-renderer {
+ color: var(--main-color) !important;
+}
+
+#metadata.ytd-conversation-metadata-item-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Backgrounds*/
+#like-bar.ytd-sentiment-bar-renderer,
+#progress.ytd-thumbnail-overlay-resume-playback-renderer,
+#selectionBar.paper-tabs {
+ background-color: var(--main-color) !important;
+}
+
+/*Sidebar*/
+#guide-content.ytd-app,
+#contentContainer.app-drawer,
+#guide-wrapper.ytd-app {
+ background: var(--second-background) !important;
+}
+
+#endpoint.yt-simple-endpoint.ytd-guide-entry-renderer,
+#guide-section-title.ytd-guide-section-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-guide-entry-renderer:hover #endpoint.yt-simple-endpoint.ytd-guide-entry-renderer,
+ytd-guide-entry-renderer:hover svg {
+ color: var(--main-color) !important;
+ fill: var(--main-color) !important;
+}
+
+ytd-guide-entry-renderer[active] {
+ background-color: var(--hover-background) !important;
+}
+
+#sections.ytd-guide-renderer>.ytd-guide-renderer:not(:last-child),
+#guide-links-primary.ytd-guide-renderer,
+#guide-content.ytd-app {
+ border-color: var(--hover-background) !important;
+}
+
+#guide-links-primary.ytd-guide-renderer>a,
+#guide-links-secondary.ytd-guide-renderer>a,
+#footer.ytd-guide-renderer>#copyright,
+yt-formatted-string.ytd-guide-signin-promo-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#guide-links-primary.ytd-guide-renderer>a:hover,
+#guide-links-secondary.ytd-guide-renderer>a:hover {
+ color: var(--main-color) !important;
+}
+
+/*Compact sidebar fix*/
+ytd-mini-guide-renderer,
+a.ytd-mini-guide-entry-renderer,
+a.ytd-mini-guide-entry-renderer:hover,
+a.ytd-mini-guide-entry-renderer:focus {
+ background-color: var(--second-background) !important;
+}
+
+ytd-mini-guide-entry-renderer .guide-icon.ytd-mini-guide-entry-renderer,
+a.ytd-mini-guide-entry-renderer .guide-icon,
+a.ytd-mini-guide-entry-renderer.title.ytd-mini-guide-entry-renderer,
+ytd-mini-guide-entry-renderer .title.ytd-mini-guide-entry-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-mini-guide-entry-renderer[active] .guide-icon.ytd-mini-guide-entry-renderer,
+a.ytd-mini-guide-entry-renderer:hover .guide-icon,
+a.ytd-mini-guide-entry-renderer:hover .title.ytd-mini-guide-entry-renderer,
+ytd-mini-guide-entry-renderer[active] .title.ytd-mini-guide-entry-renderer {
+ color: var(--main-color) !important;
+}
+
+#newness-dot.ytd-guide-entry-renderer {
+ background-color: var(--main-color) !important;
+}
+
+/*Latest YouTube posts*/
+ytd-post-renderer[surface_="backstage-surface-type-home"],
+ytd-post-renderer[uses-compact-lockup] {
+ background-color: var(--second-background) !important;
+}
+
+ytd-post-renderer[surface_="backstage-surface-type-home"] #home-content-text.ytd-post-renderer,
+ytd-post-renderer[surface_="backstage-surface-type-home"][attachment="poll"] #vote-count-text.ytd-post-renderer,
+ytd-post-renderer[uses-compact-lockup] #home-content-text.ytd-post-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-post-renderer[surface_="backstage-surface-type-home"] #author-text.yt-simple-endpoint.ytd-post-renderer {
+ color: var(--main-color) !important;
+}
+
+ytd-post-renderer[uses-compact-lockup][attachment="poll"] #vote-count-text.ytd-post-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*vote now button*/
+ytd-post-renderer[uses-compact-lockup] ytd-button-renderer.style-suggestive[is-paper-button] #button.ytd-button-renderer {
+ background-color: var(--main-color) !important;
+}
+
+/*Main page video hover preview*/
+#video-preview-container.ytd-video-preview {
+ background: var(--second-background) !important;
+}
+
+/*Feed filter*/
+#home-chips
+
+/*skeleton*/
+,
+#chips-wrapper.ytd-feed-filter-chip-bar-renderer {
+ background-color: var(--main-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+yt-chip-cloud-chip-renderer:not([selected]) {
+ background-color: var(--main-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+yt-chip-cloud-chip-renderer[selected],
+yt-chip-cloud-chip-renderer:hover {
+ background-color: var(--hover-background) !important;
+}
+
+yt-chip-cloud-renderer {
+ background: transparent !important;
+}
+
+#text.yt-chip-cloud-chip-renderer {
+ color: var(--main-text) !important;
+}
+
+#scroll-container.ytd-feed-filter-chip-bar-renderer::after,
+#scroll-container.ytd-feed-filter-chip-bar-renderer::before {
+ background: transparent !important;
+}
+
+#left-arrow-button.ytd-feed-filter-chip-bar-renderer,
+#right-arrow-button.ytd-feed-filter-chip-bar-renderer,
+#left-arrow.yt-chip-cloud-renderer,
+#right-arrow.yt-chip-cloud-renderer,
+#left-arrow-button.yt-chip-cloud-renderer,
+#right-arrow-button.yt-chip-cloud-renderer {
+ background: var(--main-background) !important;
+}
+
+#left-arrow.ytd-feed-filter-chip-bar-renderer::after,
+#right-arrow.ytd-feed-filter-chip-bar-renderer::before,
+yt-chip-cloud-renderer #right-arrow.yt-chip-cloud-renderer::before,
+yt-chip-cloud-renderer #left-arrow.yt-chip-cloud-renderer::after {
+ display: none;
+}
+
+/*new to you filter on video*/
+#content-wrapper.ytd-feed-nudge-renderer {
+ background-color: var(--second-background) !important;
+}
+
+yt-chip-cloud-chip-renderer[chip-style="STYLE_REFRESH_TO_NOVEL_CHIP"][selected] {
+ background-image: none !important;
+}
+
+/*Covid19 big posts aka rich shelves*/
+/*also other borders*/
+ytd-rich-shelf-renderer,
+#show-more-button.ytd-rich-shelf-renderer,
+ytd-rich-shelf-renderer[is-show-more-hidden] #dismissible.ytd-rich-shelf-renderer,
+#contents.ytd-rich-shelf-renderer,
+ytd-compact-promoted-item-renderer[view-style="COMPACT_PROMOTED_ITEM_STYLE_RICH_GRID"] #dismissible.ytd-compact-promoted-item-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/* poll results */
+/*your selection*/
+tp-yt-paper-item.ytd-backstage-poll-renderer[selected] .progress-bar.ytd-backstage-poll-renderer {
+ background-color: var(--main-color) !important;
+}
+
+/*other bars*/
+.progress-bar.ytd-backstage-poll-renderer {
+ background-color: var(--second-background) !important;
+}
+
+ytd-backstage-poll-renderer:not([is-image-poll]) tp-yt-paper-item.ytd-backstage-poll-renderer .choice-info.ytd-backstage-poll-renderer {
+ border-color: transparent !important;
+}
+
+#title.ytd-grid-channel-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Channel page*/
+/*header*/
+#channel-header.ytd-c4-tabbed-header-renderer,
+#tabs-inner-container.ytd-c4-tabbed-header-renderer {
+ background: var(--hover-background) !important;
+}
+
+#channel-title.ytd-c4-tabbed-header-renderer {
+ color: var(--main-text) !important;
+}
+
+#subscriber-count.ytd-c4-tabbed-header-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+.tab-content.paper-tab,
+.tab-content.tp-yt-paper-tab,
+.yt-tab-shape-wiz__tab {
+ color: var(--main-text) !important;
+}
+
+paper-tab:hover .tab-content.paper-tab,
+tp-yt-paper-tab:hover>.tab-content.tp-yt-paper-tab,
+.yt-tab-shape-wiz__tab--tab-selected {
+ color: var(--main-color) !important;
+}
+
+tp-yt-paper-tabs {
+ --paper-tabs-selection-bar-color: var(--main-color) !important;
+}
+
+/* for tab selected */
+.yt-tab-group-shape-wiz__slider {
+ background-color: var(--main-color) !important;
+}
+
+/* Join button, Sign In, Show Transcript */
+.yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--outline {
+ color: var(--main-text);
+ background-color: var(--second-background) !important;
+}
+
+/* vote now / answer now posts */
+.style-scope.ytd-post-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--outline {
+ background: var(--hover-background) !important;
+}
+
+/*search*/
+.input-content.paper-input-container label,
+.input-content.paper-input-container .paper-input-label,
+#subtitle,
+.style-scope.tp-yt-paper-input {
+ color: var(--dimmer-text) !important;
+}
+
+/*arrow button*/
+iron-icon {
+ fill: var(--main-text) !important;
+}
+
+iron-icon:hover {
+ fill: var(--main-color) !important;
+}
+
+/*side channels*/
+#title:not([class*="ytd-labs"]):not([class*="upsell-offer"]) {
+ color: var(--main-text) !important;
+}
+
+.title {
+ color: var(--main-text) !important;
+}
+
+.title:hover {
+ color: var(--main-color) !important;
+}
+
+#contents>.ytd-browse-secondary-contents-renderer:not(:first-child) {
+ border-color: var(--hover-background) !important;
+}
+
+/*videos - uploads*/
+#label-text.yt-dropdown-menu {
+ color: var(--main-text) !important;
+}
+
+paper-menu-button.yt-dropdown-menu:hover #label-text.yt-dropdown-menu,
+paper-menu-button.yt-dropdown-menu:hover #label-icon.yt-dropdown-menu svg,
+paper-menu-button.yt-dropdown-menu:hover #icon-label.yt-dropdown-menu {
+ color: var(--main-color) !important;
+ fill: var(--main-color) !important;
+}
+
+/*community*/
+#message.ytd-message-renderer,
+#content-text.ytd-backstage-post-renderer,
+#repost-content-text.ytd-shared-post-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#author-text,
+.more-button,
+.less-button,
+.align-by-text.ytd-backstage-comments-renderer,
+#toggle.ytd-grid-renderer,
+#repost-author-text.yt-simple-endpoint.ytd-shared-post-renderer {
+ color: var(--main-text) !important;
+}
+
+.more-button:hover,
+.less-button:hover,
+.align-by-text.ytd-backstage-comments-renderer:hover,
+#toggle.ytd-grid-renderer:hover,
+#author-text.yt-simple-endpoint.ytd-backstage-post-renderer:hover,
+#repost-author-text.yt-simple-endpoint.ytd-shared-post-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+#content-attachment.ytd-backstage-post-renderer ytd-video-renderer.ytd-backstage-post-renderer,
+/*normal video*/
+#content-attachment.ytd-backstage-post-renderer ytd-playlist-renderer.ytd-backstage-post-renderer,
+/*playlist*/
+#content-attachment.ytd-post-renderer ytd-video-renderer.ytd-post-renderer,
+/*normal video, but in cards on home page*/
+#content-attachment.ytd-post-renderer ytd-playlist-renderer.ytd-post-renderer
+
+/*playlist, but in cards on home page*/
+ {
+ background: var(--hover-background) !important;
+}
+
+#poll-votes.ytd-backstage-poll-renderer {
+ background: transparent !important;
+}
+
+.vote-percentage.ytd-backstage-poll-renderer,
+.choice-text.ytd-backstage-poll-renderer,
+#poll-choice-text.ytd-commentbox,
+yt-icon.ytd-backstage-poll-renderer {
+ color: var(--main-text) !important;
+}
+
+paper-item[selected].ytd-backstage-poll-renderer #progress-bar.ytd-backstage-poll-renderer {
+ background: var(--main-color) !important;
+}
+
+/*about*/
+.subheadline,
+#right-column .subheadline {
+ color: var(--main-text) !important;
+}
+
+#description:not([class*="yt-music"]),
+#bio,
+#right-column>yt-formatted-string {
+ color: var(--dimmer-text) !important;
+}
+
+#right-column>yt-formatted-string,
+#description-container.ytd-channel-about-metadata-renderer,
+#bio-container.ytd-channel-about-metadata-renderer,
+#photos-container.ytd-channel-about-metadata-renderer,
+#details-container.ytd-channel-about-metadata-renderer,
+#links-container.ytd-channel-about-metadata-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#link-list-container a {
+ color: var(--main-color) !important;
+}
+
+#link-list-container:hover a {
+ filter: brightness(110%);
+}
+
+/*private message*/
+ytd-form-popup-renderer[dialog][dialog][dialog] {
+ background: var(--main-background) !important;
+}
+
+#buttons.ytd-form-popup-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+ytd-toggle-menu-service-item-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-toggle-menu-service-item-renderer:hover .style-scope.ytd-toggle-menu-service-item-renderer {
+ color: var(--main-color) !important;
+}
+
+ytd-toggle-menu-service-item-renderer:hover {
+ background: var(--hover-background) !important;
+}
+
+/*Video page*/
+/*title*/
+.title.ytd-video-primary-info-renderer yt-formatted-string.ytd-video-primary-info-renderer {
+ color: var(--main-text) !important;
+}
+
+/*views*/
+span.yt-view-count-renderer,
+span.ytd-video-view-count-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*published date*/
+#date.ytd-video-primary-info-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+ytd-video-primary-info-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+.content-text.ytd-metadata-with-image-row-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Share*/
+paper-dialog,
+tp-yt-paper-dialog {
+ background: var(--main-background) !important;
+}
+
+#share-url {
+ color: var(--main-text) !important;
+}
+
+#copy-button:hover #text {
+ color: var(--main-color) !important;
+}
+
+#bar.yt-copy-link-renderer {
+ background-color: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+ytd-third-party-network-section-renderer ytd-copy-link-renderer.ytd-third-party-network-section-renderer,
+yt-start-at-renderer.yt-third-party-network-section-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+yt-formatted-string.yt-start-at-renderer,
+#text.ytd-sender-id-section-renderer {
+ color: var(--main-text) !important;
+}
+
+/*share embed*/
+#embed-panel.yt-sharing-embed-renderer {
+ background: var(--second-background) !important;
+}
+
+#close-panel-icon.yt-sharing-embed-renderer {
+ color: var(--main-text) !important;
+}
+
+#close-panel-icon.yt-sharing-embed-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+#title-bar.yt-sharing-embed-renderer,
+#additional-info.yt-sharing-embed-renderer,
+#action-buttons.yt-sharing-embed-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#privacy-mode-info.yt-sharing-embed-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*search for people*/
+#to-field-header.ytd-contact-search-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#name.ytd-suggested-contact-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Make a clip*/
+#container.yt-clip-creation-renderer {
+ background-color: transparent !important;
+}
+
+input.yt-clip-creation-scrubber-renderer
+
+/*time*/
+ {
+ border-color: var(--dimmer-text) !important;
+}
+
+#handles.yt-clip-creation-scrubber-view
+
+/*preview*/
+ {
+ border-color: var(--main-color) !important;
+}
+
+.handle.yt-clip-creation-scrubber-view
+
+/*preview*/
+ {
+ background-color: var(--main-color) !important;
+}
+
+/*buttons*/
+#footer.yt-clip-creation-renderer {
+ background-color: var(--second-background) !important;
+}
+
+yt-clip-section-renderer yt-button-renderer.style-primary[is-paper-button],
+yt-clip-creation-renderer yt-button-renderer.style-primary[is-paper-button],
+yt-clip-section-footer-renderer yt-button-renderer.style-primary[is-paper-button] {
+ background-color: transparent !important;
+}
+
+yt-button-renderer.style-primary[disabled][is-paper-button] yt-formatted-string.yt-button-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+yt-button-renderer.yt-clip-creation-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled,
+ytd-button-renderer.ytd-clip-section-footer-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ background-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+/*Join this channel panel > Join button,
+ Settings > Advanced settings > Copy button*/
+yt-button-renderer.ytd-sponsorships-tier-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled,
+yt-button-renderer.yt-copy-link-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ background-color: var(--main-color) !important;
+}
+
+/*Playlist creation*/
+#subtext.yt-live-chat-message-renderer,
+#label.yt-live-chat-text-input-field-renderer,
+.input-content.paper-input-container input,
+.input-content.paper-input-container textarea,
+.input-content.paper-input-container iron-autogrow-textarea,
+.input-content.paper-input-container .paper-input-input {
+ color: var(--dimmer-text) !important;
+}
+
+.add-on-content.is-highlighted.paper-input-container *,
+paper-input-char-counter {
+ color: var(--dimmer-text) !important;
+}
+
+/*Video cards*/
+/*ttile*/
+ytd-grid-video-renderer.use-ellipsis #details.ytd-grid-video-renderer a.ytd-grid-video-renderer,
+ytd-compact-video-renderer.use-ellipsis #video-title.ytd-compact-video-renderer,
+#video-title.ytd-video-renderer,
+h3.ytd-playlist-renderer,
+#video-title.ytd-child-video-renderer,
+#length.ytd-child-video-renderer,
+#video-title,
+#unplayableText,
+#length,
+#details {
+ color: var(--main-text) !important;
+}
+
+#items.yt-horizontal-list-renderer>.yt-horizontal-list-renderer:hover a.ytd-grid-video-renderer,
+ytd-compact-video-renderer:hover #video-title.ytd-compact-video-renderer,
+ytd-video-renderer:hover #video-title.ytd-video-renderer,
+ytd-playlist-renderer:hover h3.ytd-playlist-renderer,
+#content.ytd-playlist-video-renderer:hover #video-title,
+a.yt-simple-endpoint.ytd-playlist-panel-video-renderer:hover #video-title,
+a.yt-simple-endpoint.ytd-playlist-panel-video-renderer:hover #unplayableText,
+.style-scope.ytd-grid-renderer.use-ellipsis:hover #video-title,
+#video-title:hover,
+ytd-grid-video-renderer:hover #video-title.yt-simple-endpoint.ytd-grid-video-renderer {
+ color: var(--main-color) !important;
+}
+
+/*author*/
+yt-formatted-string[ellipsis-truncate] a.yt-formatted-string:last-child,
+#byline.ytd-video-meta-block,
+#channel-title.ytd-channel-renderer span.ytd-channel-renderer,
+#text.ytd-channel-name {
+ color: var(--main-color) !important;
+}
+
+/*metadata*/
+#metadata-line.ytd-grid-video-renderer,
+#metadata-line.ytd-video-meta-block span.ytd-video-meta-block,
+#metadata.ytd-channel-renderer,
+#description.ytd-channel-renderer,
+#thumbnail-attribution.ytd-grid-channel-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*2022 Nov like button*/
+/*not liked yet*/
+yt-animated-icon[animated-icon-type="LIKE"]>ytd-lottie-player>lottie-component>svg>g:nth-child(2)>g:nth-child(2)>g:nth-child(2)>path:nth-child(1),
+yt-animated-icon[animated-icon-type="LIKE"]>ytd-lottie-player>lottie-component>svg>g:nth-child(2)>g:nth-child(2)>g:nth-child(4)>path:nth-child(1) {
+ stroke: var(--main-text) !important;
+}
+
+/*liked*/
+yt-animated-icon[animated-icon-type="LIKE"]>ytd-lottie-player>lottie-component>svg>g:nth-child(2)>g:nth-child(2)>g:nth-child(1)>path:nth-child(1),
+yt-animated-icon[animated-icon-type="LIKE"]>ytd-lottie-player>lottie-component>svg>g:nth-child(2)>g:nth-child(2)>g:nth-child(3)>path:nth-child(1) {
+ fill: var(--main-color) !important;
+}
+
+yt-animated-icon[animated-icon-type="LIKE"]>ytd-lottie-player>lottie-component>svg>g:nth-child(2)>g:nth-child(2)>g:nth-child(1)>path:nth-child(2),
+yt-animated-icon[animated-icon-type="LIKE"]>ytd-lottie-player>lottie-component>svg>g:nth-child(2)>g:nth-child(2)>g:nth-child(3)>path:nth-child(2) {
+ stroke: var(--main-color) !important
+}
+
+/*on shorts - so here is filled by default, thus above I am using main-color instead to keep it consistent*/
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--filled>div>yt-icon>svg>g>path {
+ fill: var(--main-color) !important;
+}
+
+/*description and other metadata*/
+ytd-watch-metadata[modern-metapanel] #description.ytd-watch-metadata {
+ background: var(--second-background) !important;
+ /*--yt-spec-button-chip-background-hover*/
+}
+
+ytd-watch-metadata[clickable-description][description-collapsed] #description.ytd-watch-metadata:hover {
+ background: var(--hover-background) !important;
+ /*--yt-spec-badge-chip-background*/
+}
+
+ytd-watch-metadata[modern-metapanel] #description.ytd-watch-metadata .yt-simple-endpoint.style-scope.yt-formatted-string,
+.yt-core-attributed-string__link--call-to-action-color {
+ color: var(--main-color) !important;
+}
+
+/*show more / less*/
+#expand.ytd-text-inline-expander:hover,
+#collapse.ytd-text-inline-expander:hover {
+ color: var(--main-color) !important;
+}
+
+/*Recommandation page*/
+/*author*/
+#title.ytd-shelf-renderer {
+ color: var(--main-color) !important;
+}
+
+#title-annotation.ytd-shelf-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+a.yt-simple-endpoint.yt-formatted-string:only-of-type:hover {
+ color: var(--main-color) !important;
+}
+
+a.yt-simple-endpoint.yt-formatted-string:only-of-type {
+ color: var(--main-text) !important;
+}
+
+/*Borders*/
+#contents.ytd-section-list-renderer>.ytd-section-list-renderer:not(:last-child):not(ytd-page-introduction-renderer) {
+ border-color: var(--hover-background) !important;
+}
+
+/*Next and prev buttons*/
+.arrow.yt-horizontal-list-renderer,
+#scroll-button-forward,
+.arrow.ytd-horizontal-card-list-renderer,
+.ytd-horizontal-card-list-renderer[arrow],
+.scroll-button.yt-third-party-share-target-section-renderer
+
+/*share link*/
+ {
+ background-color: var(--hover-background) !important;
+}
+
+/*For the outline around the channel name*/
+.style-scope.ytd-comment-renderer.creator {
+ background-color: var(--main-color) !important;
+}
+
+.style-scope.ytd-comment-renderer.creator:hover {
+ background-color: var(--hover-background) !important;
+}
+
+#name.ytd-author-comment-badge-renderer {
+ color: var(--main-text) !important;
+}
+
+#name:hover {
+ color: var(--main-color) !important;
+}
+
+/*Accounts*/
+yt-formatted-string.ytd-account-item-section-header-renderer a {
+ color: var(--dimmer-text) !important;
+}
+
+.style-scope.ytd-account-item-section-renderer:hover #channel-title.ytd-account-item-renderer {
+ color: var(--main-color) !important;
+}
+
+app-drawer.ytd-app:not([persistent]) #header.ytd-app {
+ border-color: var(--main-color) !important;
+}
+
+/*How is youtube today*/
+ytd-single-option-survey-renderer[dialog][dialog][dialog],
+ytd-single-option-survey-renderer,
+ytd-survey-follow-up-renderer[dialog][dialog][dialog],
+ytd-survey-follow-up-renderer,
+ytd-checkbox-survey-renderer[dialog][dialog][dialog]
+
+/*TODO: forgot to test if the [dialog] is even needed*/
+ {
+ background-color: var(--hover-background) !important;
+ box-shadow: var(--shadow) !important;
+}
+
+#header.ytd-single-option-survey-renderer,
+#header.ytd-survey-follow-up-renderer,
+#header.ytd-checkbox-survey-renderer {
+ color: var(--main-color) !important;
+}
+
+ytd-single-option-survey-option-renderer,
+#checkboxLabel.paper-checkbox {
+ color: var(--main-text) !important;
+}
+
+ytd-single-option-survey-option-renderer:hover {
+ background-color: var(--hover-background) !important;
+}
+
+/*rate a video to improve youtube*/
+#star-survey.ytd-inline-survey-renderer,
+.survey-wrapper.ytd-inline-survey-renderer {
+ background-color: var(--second-background) !important;
+}
+
+#inline-survey-compact-video-renderer.ytd-inline-survey-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+ytd-primetime-promo-renderer.ytd-rich-section-renderer,
+ytd-inline-survey-renderer.ytd-rich-section-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#follow-up-survey.ytd-inline-survey-renderer {
+ border-left: 4px solid var(--hover-background) !important;
+}
+
+/*submit button*/
+#submit-btn-footer.ytd-inline-survey-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ background-color: var(--main-color) !important;
+}
+
+/*not sure tell us why followup*/
+#title.ytd-inline-survey-renderer,
+#follow-up-title.ytd-inline-survey-renderer,
+#selected-response-text.ytd-rating-survey-renderer {
+ color: var(--main-color) !important;
+}
+
+/*checkboxes cards*/
+tp-yt-paper-checkbox.ytd-checkbox-survey-option-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+/*background and close button*/
+ytd-inline-survey-renderer[expanded] #dismissable.ytd-inline-survey-renderer,
+#dismiss-button.ytd-inline-survey-renderer {
+ background-color: var(--second-background) !important;
+}
+
+paper-checkbox.ytd-checkbox-survey-option-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+/*thanks*/
+#dismissed.ytd-inline-survey-renderer ytd-message-renderer.ytd-inline-survey-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+/*info warning - covid19*/
+ytd-clarification-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+ytd-clarification-renderer[has-action-button] .content.ytd-clarification-renderer,
+ytd-clarification-renderer[background-style="info"] {
+ border-color: var(--hover-background) !important;
+}
+
+.content-title.ytd-clarification-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-clarification-renderer[clarify-style="medium"] .description.ytd-clarification-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+.source.ytd-clarification-renderer {
+ color: var(--main-color) !important;
+}
+
+ytd-clarification-renderer yt-button-renderer.style-suggestive[is-paper-button] paper-button.yt-button-renderer {
+ border-color: var(--main-color) !important;
+}
+
+/*Change subtitles settings tooltip*/
+.ytp-promotooltip-container {
+ background-color: var(--hover-background) !important;
+ box-shadow: var(--shadow) !important;
+ color: var(--main-text) !important;
+}
+
+.ytp-promotooltip-pointer {
+ border-color: var(--hover-background) !important;
+}
+
+/*You are not logged in tooltip*/
+#tooltip.tp-yt-paper-tooltip,
+yt-tooltip-renderer {
+ background-color: var(--hover-background) !important;
+ box-shadow: var(--shadow) !important;
+ color: var(--main-text) !important;
+}
+
+yt-tooltip-renderer::before {
+ border-color: transparent transparent var(--hover-background) transparent !important;
+}
+
+/*Join button tooltip*/
+yt-bubble-hint-renderer[style_="BUBBLE_HINT_STYLE_BLUE_TOOLTIP"] {
+ background-color: var(--second-background) !important;
+ box-shadow: var(--shadow) !important;
+}
+
+yt-bubble-hint-renderer[style_="BUBBLE_HINT_STYLE_BLUE_TOOLTIP"] #text.yt-bubble-hint-renderer:not(:empty),
+yt-bubble-hint-renderer[style_="BUBBLE_HINT_STYLE_BLUE_TOOLTIP"] #details-text.yt-bubble-hint-renderer {
+ background-color: var(--second-background) !important;
+}
+
+yt-bubble-hint-renderer[position-type="OPEN_POPUP_POSITION_LEFT"][style_="BUBBLE_HINT_STYLE_BLUE_TOOLTIP"]::before {
+ border-color: transparent transparent transparent var(--second-background) !important;
+}
+
+/*window*/
+ytd-sponsorships-offer-renderer[dialog][dialog][dialog] {
+ background-color: var(--main-background) !important;
+}
+
+#background-image-layer.ytd-sponsorships-offer-renderer {
+ background-image: unset !important;
+ background-color: var(--hover-background) !important;
+}
+
+/*title*/
+#top-bar.ytd-sponsorships-offer-renderer {
+ color: var(--main-text) !important;
+}
+
+/*price*/
+#above-purchase-button-text.ytd-sponsorships-tier-renderer {
+ color: var(--main-color) !important;
+}
+
+/*fine print*/
+.disclaimer.ytd-sponsorships-tier-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Super Thanks donations*/
+ytd-pdg-buy-flow-renderer {
+ background-color: var(--main-background) !important;
+}
+
+/*remove white image in the header*/
+yt-pdg-buy-flow-header-renderer {
+ background: transparent !important;
+}
+
+#container.ytd-pdg-comment-preview-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#container.ytd-pdg-comment-preview-renderer:focus-within {
+ border-color: var(--main-color) !important;
+}
+
+/*bonus*/
+#title-background.ytd-pdg-comment-preview-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+/*Progress bar*/
+#progress {
+ background-color: var(--main-color) !important;
+ border-color: var(--main-color) !important;
+}
+
+yt-page-navigation-progress {
+ background-color: transparent !important;
+}
+
+/*Button tooltips*/
+#tooltip.paper-tooltip {
+ background-color: var(--hover-background) !important;
+ color: var(--main-color) !important;
+}
+
+/*Active grid icon*/
+button.ytd-button-renderer[is="paper-icon-button-light"][disabled] {
+ color: rgb(255, 255, 255) !important;
+}
+
+/*2022 Nov changes*/
+/*subscribe button*/
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--filled,
+/*Show more on home page*/
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--outline,
+/* as of oct 2023 */
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--tonal,
+/*NOTE: this affects other material buttons - I would say desired effect*/
+.yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--filled,
+.yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--filled:hover,
+/*on shorts*/
+.yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--tonal,
+.yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--tonal:hover,
+/*on shorts*/
+.ytp-sb-subscribe,
+a.ytp-sb-subscribe
+
+/*in cards... why yt why*/
+ {
+ background-color: var(--second-background) !important;
+ border-color: var(--second-background) !important;
+ box-shadow: var(--shadow) !important;
+ color: var(--main-text) !important;
+}
+
+/*2024 March*/
+ytd-live-chat-frame #show-hide-button.ytd-live-chat-frame>ytd-button-renderer.ytd-live-chat-frame {
+ background-color: transparent !important;
+}
+
+/*fix black "personalized" icon*/
+.yt-spec-button-shape-next--icon-leading-trailing svg>g:nth-child(2)>g>g:nth-child(2)>path:nth-child(2) {
+ fill: var(--main-text) !important;
+}
+
+/* to fix white corners for .yt-spec-button-shape-next--mono.yt-spec-button-shape-next--filled */
+.button-container.ytd-rich-shelf-renderer {
+ background-color: transparent;
+}
+
+/*unsubscribe confirm dialog*/
+.yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text {
+ color: var(--main-color) !important;
+}
+
+.yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text:hover,
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--tonal:hover {
+ background-color: var(--yt-spec-10-percent-layer) !important;
+}
+
+/*join button*/
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--tonal[aria-label="Join this channel"],
+.yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled
+
+/*in window*/
+ {
+ background-color: var(--second-background) !important;
+ border-color: var(--second-background) !important;
+}
+
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--outline:hover {
+ background-color: var(--yt-spec-10-percent-layer) !important;
+}
+
+/*comment button*/
+ytd-button-renderer#submit-button.ytd-commentbox .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ background-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+/* button labels */
+.yt-spec-button-shape-with-label__label {
+ color: var(--main-text) !important;
+}
+
+/*download panel > get trial button*/
+/*share panel > copy button*/
+ytd-offline-promo-renderer.ytd-popup-container yt-button-renderer#action-button .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled,
+yt-third-party-network-section-renderer.ytd-unified-share-panel-renderer yt-button-renderer#copy-button .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ background-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+/*Thanks panel > "Buy and Send" button*/
+/*Thanks panel > About Super Thanks panel > "Got it" button*/
+ytd-button-renderer#buy-button.yt-super-vod-buy-flow-content-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled,
+yt-button-renderer#confirm-button.yt-confirm-dialog-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ background-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+/*Toast notification*/
+yt-notification-action-renderer yt-button-renderer.yt-notification-action-renderer .yt-spec-button-shape-next--call-to-action-inverse.yt-spec-button-shape-next--text {
+ color: var(--main-color) !important;
+}
+
+/*Toast notification hover*/
+yt-notification-action-renderer yt-button-renderer.yt-notification-action-renderer .yt-spec-button-shape-next--call-to-action-inverse.yt-spec-button-shape-next--text:hover {
+ background-color: var(--main-background) !important;
+}
+
+if join-color
+
+/*overwriting the above*/
+ {
+
+ .yt-spec-button-shape-next--mono.yt-spec-button-shape-next--tonal[aria-label="Join this channel"],
+ yt-button-shape:nth-child(1)>.yt-spec-button-shape-next--size-m.yt-spec-button-shape-next--outline {
+ background-color: var(--main-color) !important;
+ border-color: var(--main-color) !important;
+ }
+}
+
+if subscribe-color
+
+/*overwriting the above*/
+ {
+ .yt-spec-button-shape-next--mono.yt-spec-button-shape-next--filled,
+ .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--filled,
+ .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--filled:hover,
+ /*on shorts*/
+ .ytp-sb-subscribe,
+ a.ytp-sb-subscribe
+
+ /*in cards*/
+ {
+ background-color: var(--main-color) !important;
+ border-color: var(--main-color) !important;
+ }
+}
+
+ytd-button-renderer.style-primary[is-paper-button] {
+ background-color: transparent !important;
+}
+
+/*Sponsor button*/
+ytd-modal-with-title-and-button-renderer {
+ background: var(--second-background) !important;
+}
+
+#content.ytd-modal-with-title-and-button-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+.buttons.ytd-modal-with-title-and-button-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/*sponsor popup*/
+#sponsor-button.ytd-membership-offer-renderer ytd-button-renderer.ytd-membership-offer-renderer {
+ background-color: var(--main-color) !important;
+}
+
+#sponsor-button.ytd-membership-offer-renderer ytd-button-renderer.ytd-membership-offer-renderer:hover {
+ filter: brightness(110%) !important;
+}
+
+#header.ytd-membership-offer-renderer {
+ background: var(--main-background) !important;
+}
+
+ytd-perks-section-renderer,
+ytd-membership-offer-renderer[dialog][dialog][dialog],
+paper-dialog-scrollable.can-scroll:not(.scrolled-to-bottom):not(:last-child)::after,
+paper-dialog-scrollable.is-scrolled:not(:first-child)::before {
+ background: var(--second-background) !important;
+}
+
+.extra-content.ytd-offer-perk-extra {
+ border-color: var(--hover-background) !important;
+ background: var(--hover-background) !important;
+ color: var(--dimmer-text) !important;
+}
+
+.footer.ytd-membership-offer-renderer {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+ytd-membership-offer-renderer * {
+ border-color: var(--hover-background) !important;
+}
+
+.price.ytd-membership-offer-renderer {
+ color: var(--main-color) !important;
+}
+
+.style-title.ytd-offer-text-item,
+.style-subtitle.ytd-offer-text-item,
+.payment-clause.ytd-membership-offer-renderer {
+ color: var(--main-text) !important;
+}
+
+.perk-item-title.ytd-perk-item-renderer,
+.perk-item-public-description.ytd-perk-item-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Edit button in channel page*/
+#edit-buttons.ytd-c4-tabbed-header-renderer ytd-button-renderer.ytd-c4-tabbed-header-renderer {
+ background-color: transparent !important;
+}
+
+/*Toggle button to play next*/
+paper-toggle-button[checked]:not([disabled]) .toggle-bar.paper-toggle-button {
+ background-color: var(--main-color) !important;
+ opacity: 0.9 !important;
+}
+
+paper-toggle-button[checked]:not([disabled]) .toggle-button.paper-toggle-button {
+ --paper-toggle-button-checked-button-color: rgb(255, 255, 255) !important;
+}
+
+/*Hover for toggle button*/
+.toggle-button.paper-toggle-button:hover,
+paper-toggle-button[checked]:not([disabled]) .toggle-button.paper-toggle-button:hover {
+ background-color: var(--main-color) !important;
+}
+
+yt-bubble-hint-renderer {
+ background: var(--hover-background) !important;
+}
+
+yt-bubble-hint-renderer::after {
+ border-top-color: var(--second-background) !important;
+}
+
+#text.yt-bubble-hint-renderer {
+ background: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+#details-text.yt-bubble-hint-renderer {
+ background: var(--hover-background) !important;
+ color: var(--dimmer-text) !important;
+}
+
+.buttons.yt-bubble-hint-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/*Filter active*/
+paper-button.ytd-toggle-button-renderer {
+ color: rgba(255, 255, 255, 0.5) !important;
+}
+
+/*Badges*/
+.badge-style-type-simple.ytd-badge-supported-renderer,
+.badge-style-type-disabled.ytd-badge-supported-renderer,
+yt-icon.ytd-badge-supported-renderer {
+ background: transparent !important;
+ color: var(--main-color) !important;
+ padding-left: 0px !important;
+ opacity: .7 !important;
+}
+
+.badge-style-type-simple-strikethrough.ytd-badge-supported-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Trending badge*/
+.badge-style-type-featured.ytd-badge-supported-renderer {
+ background: var(--main-color) !important;
+}
+
+/*Author verified badge in comments*/
+ytd-author-comment-badge-renderer:not(.creator) #icon.ytd-author-comment-badge-renderer {
+ fill: var(--main-color) !important;
+}
+
+/*Live now badge*/
+.badge-style-type-live-now.ytd-badge-supported-renderer,
+.badge-style-type-live-now-alternate.ytd-badge-supported-renderer {
+ color: var(--main-color) !important;
+ background: transparent !important;
+ border-color: var(--main-color) !important;
+}
+
+/*Premium*/
+.badge-style-type-red.ytd-badge-supported-renderer {
+ color: #DA4453 !important;
+ background: transparent !important;
+ border-color: var(--main-color) !important;
+}
+
+/*Series name*/
+.badge-style-type-collection.ytd-badge-supported-renderer {
+ color: var(--main-color) !important;
+}
+
+.yt-simple-endpoint.style-scope.yt-formatted-string {
+ color: var(--dimmer-text) !important;
+}
+
+/*video hashtags & links in settings page*/
+#super-title .yt-simple-endpoint.style-scope.yt-formatted-string,
+ytd-section-list-renderer[page-subtype="WEB_PAGE_TYPE_SETTINGS"] .yt-simple-endpoint.style-scope.yt-formatted-string {
+ color: var(--main-color) !important;
+}
+
+/*panel links*/
+tp-yt-paper-dialog.ytd-popup-container .yt-simple-endpoint.style-scope.yt-formatted-string {
+ color: var(--main-color) !important;
+}
+
+/*Dropdown*/
+.dropdown-content.style-scope.ytd-popup-container>*,
+tp-yt-paper-listbox,
+ytd-menu-popup-renderer {
+ background: var(--second-background) !important;
+ color: var(--main-text) !important;
+}
+
+ytd-menu-service-item-renderer:hover,
+a.ytd-menu-navigation-item-renderer:hover,
+tp-yt-paper-listbox.yt-dropdown-menu .iron-selected.yt-dropdown-menu,
+tp-yt-paper-listbox.yt-dropdown-menu tp-yt-paper-item.yt-dropdown-menu:hover,
+ytd-menu-service-item-renderer[is-selected] {
+ background: var(--hover-background) !important;
+}
+
+yt-formatted-string.ytd-menu-service-item-renderer,
+yt-formatted-string.ytd-menu-navigation-item-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-menu-service-item-renderer:hover yt-formatted-string.ytd-menu-service-item-renderer,
+a.ytd-menu-navigation-item-renderer:hover yt-formatted-string.ytd-menu-navigation-item-renderer,
+tp-yt-paper-listbox a.yt-simple-endpoint.yt-dropdown-menu:hover .item.yt-dropdown-menu {
+ color: var(--main-color) !important;
+}
+
+#owner-name.ytd-video-owner-renderer a {
+ color: var(--main-color) !important;
+ opacity: .9;
+}
+
+/*share*/
+#header.ytd-add-to-playlist-renderer {
+ color: var(--main-text) !important;
+}
+
+#label.ytd-playlist-add-to-option-renderer,
+paper-item.ytd-compact-link-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#header.ytd-add-to-playlist-renderer,
+#playlists.ytd-add-to-playlist-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+paper-item.ytd-compact-link-renderer:hover #label.ytd-compact-link-renderer,
+paper-item.ytd-compact-link-renderer:hover yt-icon.ytd-compact-link-renderer {
+ color: var(--main-color) !important;
+ fill: var(--main-color) !important;
+}
+
+ytd-playlist-add-to-option-renderer paper-checkbox:hover #label.ytd-playlist-add-to-option-renderer,
+ytd-playlist-add-to-option-renderer paper-checkbox[checked] #label.ytd-playlist-add-to-option-renderer,
+yt-icon.ytd-playlist-add-to-option-renderer {
+ color: var(--main-color) !important;
+}
+
+/*Avatars and thumbnails opacity */
+img.yt-img-shadow {
+ opacity: 0.9 !important;
+}
+
+img.yt-img-shadow:hover {
+ opacity: 1 !important;
+}
+
+/*Very specific hover for thumbnails*/
+#dismissable.ytd-compact-video-renderer:hover img.yt-img-shadow,
+#items.yt-horizontal-list-renderer>.yt-horizontal-list-renderer:hover img.yt-img-shadow,
+#items.ytd-grid-renderer>ytd-grid-video-renderer.ytd-grid-renderer:hover img.yt-img-shadow,
+ytd-video-renderer.ytd-item-section-renderer:hover img.yt-img-shadow,
+.style-scope.ytd-channel-featured-content-renderer:hover img.yt-img-shadow,
+#grid-container.ytd-expanded-shelf-contents-renderer>.ytd-expanded-shelf-contents-renderer:hover img.yt-img-shadow,
+ytd-playlist-video-renderer:hover img.yt-img-shadow,
+iron-list:not([grid]) #items.iron-list>*:hover img.yt-img-shadow {
+ opacity: 1 !important;
+}
+
+/*Video section*/
+/*2022 Nov*/
+/*this seems to be only in dark mode? */
+#cinematics.ytd-watch-flexy {
+ display: none !important;
+}
+
+/*Video title hover in html5 video*/
+.html5-video-player a:hover {
+ color: var(--main-text) !important;
+ text-shadow: none !important;
+}
+
+/* Code takken from https://userstyles.org/styles/95280 */
+/* scrubber button */
+.html5-scrubber-button:hover,
+.ytp-chrome-controls .ytp-button[aria-pressed]::after,
+.ytp-scrubber-button:hover,
+.html5-video-player:not(.ytp-color-party) .ytp-swatch-background-color,
+.ytp-swatch-background-color-secondary,
+.PlayerControlsProgressBarHostProgressBarPlayheadDot
+
+/*shorts*/
+ {
+ background: var(--main-color) !important;
+}
+
+/* progress bar */
+.html5-video-player:not(.ytp-color-party) .html5-play-progress,
+.html5-video-player:not(.ytp-color-party) .ytp-play-progress,
+.progress-bar-played.ytd-progress-bar-line,
+.PlayerControlsProgressBarHostProgressBarPlayed
+
+/* on shorts*/
+ {
+ background: var(--main-color) !important;
+}
+
+.ytp-volume-slider-track,
+.ytp-volume-slider-handle:before {
+ background: var(--main-color) !important;
+ z-index: -117;
+}
+
+.ytp-settings-button.ytp-hd-quality-badge::after,
+.ytp-settings-button.ytp-4k-quality-badge::after,
+.ytp-settings-button.ytp-5k-quality-badge::after,
+.ytp-settings-button.ytp-8k-quality-badge::after,
+.ytp-settings-button.ytp-3d-badge::after {
+ background-color: var(--main-color) !important;
+}
+
+.ytp-swatch-color {
+ color: var(--main-color) !important;
+}
+
+.ytp-menuitem[aria-checked="true"] .ytp-menuitem-toggle-checkbox {
+ background-color: var(--main-color) !important;
+}
+
+.ytp-chrome-controls .ytp-button.ytp-youtube-button:hover:not([aria-disabled="true"]):not([disabled]) .ytp-svg-fill-logo-tube-lozenge {
+ fill: var(--main-color) !important;
+}
+
+.ytp-cued-thumbnail-overlay:hover .ytp-large-play-button-bg,
+.ytp-large-play-button.ytp-touch-device .ytp-large-play-button-bg {
+ fill: var(--main-color) !important;
+}
+
+.ytp-large-play-button.ytp-button.ytp-red2:hover,
+.ytp-cued-thumbnail-overlay:hover .ytp-large-play-button.ytp-button.ytp-red2 {
+ /*background-image: url(https://github.com/RaitaroH/YouTube-DeepDark/raw/master/YT_Images/large_play_button_hover_ringo-vfl7vEehF.png) !important;*/
+ background-image: url(https://s.ytimg.com/yts/img/large_play_button_ringo-vfljWXIdx.png) !important;
+ filter: invert(100%) brightness(300%);
+}
+
+.resume-playback-progress-bar {
+ background: var(--main-color) !important;
+}
+
+/*Added because of this: https://forum.userstyles.org/discussion/53368/solved-fix-this-annoying-youtube-tab-select-bug-thats-been-there-forever#latest*/
+.ytp-keyboard-focus .ytp-progress-bar:focus {
+ box-shadow: none !important;
+}
+
+/*Video menu - might have issues with lighter colors*/
+.ytp-popup {
+ background: var(--second-background) !important;
+ opacity: .9 !important;
+}
+
+.ytp-menuitem:hover:not([aria-disabled="true"]) {
+ background-color: var(--hover-background) !important;
+}
+
+/*Text*/
+.iv-branding .iv-branding-context-name,
+.ytp-menuitem-label,
+.ytp-menuitem-label-count,
+.ytp-menuitem-content,
+.ytp-menu-label-secondary,
+.ytp-panel-header {
+ color: var(--main-text) !important;
+ text-shadow: none !important;
+}
+
+/*Keyboard focus*/
+.ytp-probably-keyboard-focus .ytp-menuitem:focus .ytp-menuitem-content,
+.ytp-probably-keyboard-focus .ytp-menuitem:focus .ytp-menuitem-label {
+ box-shadow: inset -2px -2px 0 var(--main-color), inset 0 2px 0 var(--main-color) !important;
+}
+
+.ytp-probably-keyboard-focus .ytp-button:focus {
+ box-shadow: inset 0 0 0 2px var(--main-color) !important;
+}
+
+.ytp-probably-keyboard-focus .ytp-progress-bar:focus {
+ box-shadow: 0 0 0 2px var(--main-color) !important;
+}
+
+/*Miniplayer*/
+#info-bar.ytd-miniplayer .metadata.ytd-miniplayer,
+#info-bar.ytd-miniplayer {
+ background-color: var(--main-background) !important;
+}
+
+#info-bar.ytd-miniplayer .channel.ytd-miniplayer {
+ color: var(--main-color) !important;
+}
+
+.ytd-miniplayer .ytp-button:not([aria-disabled="true"]):not([disabled]):not([aria-hidden="true"]):hover svg path {
+ fill: var(--main-color) !important;
+}
+
+/*added to queue*/
+ytd-miniplayer-toast[opened] {
+ background-color: var(--second-background) !important;
+}
+
+#label.ytd-miniplayer-toast {
+ color: var(--main-color) !important;
+}
+
+/*queue / playlist panel closed*/
+ytd-playlist-panel-renderer[collapsible][collapsed][use-color-palette] .title.ytd-playlist-panel-renderer,
+ytd-playlist-panel-renderer[collapsible][collapsed][use-color-palette] #next-video-title.ytd-playlist-panel-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-playlist-panel-renderer[collapsible][collapsed][use-color-palette] .byline-title.ytd-playlist-panel-renderer,
+ytd-playlist-panel-renderer[collapsible][collapsed][use-color-palette] .publisher.ytd-playlist-panel-renderer,
+ytd-playlist-panel-renderer[collapsible][collapsed][use-color-palette] .publisher.ytd-playlist-panel-renderer:not([is-empty]).ytd-playlist-panel-renderer+.index-message-wrapper.ytd-playlist-panel-renderer::before,
+ytd-playlist-panel-renderer[collapsible][collapsed][use-color-palette] .index-message-wrapper.ytd-playlist-panel-renderer {
+ color: var(--main-color) !important;
+}
+
+/*Watch later svg*/
+.style-scope.ytd-thumbnail-overlay-toggle-button-renderer:hover {
+ fill: var(--main-color) !important;
+}
+
+ytd-thumbnail-overlay-toggle-button-renderer:focus yt-icon.ytd-thumbnail-overlay-toggle-button-renderer {
+ outline-color: var(--main-color) !important;
+}
+
+/*This channel is watched by others*/
+ytd-thumbnail-overlay-endorsement-renderer {
+ background-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*Popup for when you hover over the channel avatar in the video*/
+.iv-branding .branding-context-container-inner {
+ background-color: var(--main-background) !important;
+}
+
+/*Changing icon for unavailable video*/
+#img.ytd-player-error-message-renderer {
+ display: block !important;
+ -moz-box-sizing: border-box !important;
+ box-sizing: border-box !important;
+ background: url(https://github.com/RaitaroH/YouTube-DeepDark/raw/master/YT_Images/404.png) no-repeat !important;
+ width: 140px !important;
+ height: 100px !important;
+ padding-left: 140px !important;
+ position: relative !important;
+}
+
+/*Changing icon for unavailable page (404)*/
+#error-page-hh-illustration {
+ display: block !important;
+ -moz-box-sizing: border-box !important;
+ box-sizing: border-box !important;
+ background: url(https://github.com/RaitaroH/YouTube-DeepDark/raw/master/YT_Images/404.png) no-repeat !important;
+ width: 140px !important;
+ height: 100px !important;
+ padding-left: 140px !important;
+ right: -175px !important;
+ position: relative !important;
+}
+
+/*Some spacing for the logo*/
+#yt-masthead #logo-container {
+ margin-right: 20px !important;
+}
+
+/*consent page (cookie page)*/
+/*cookies consent dialog*/
+ytd-consent-bump-v2-lightbox ytd-button-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ color: var(--main-color) !important;
+}
+
+ytd-consent-bump-v2-lightbox[darker-dark-theme] .loading-overlay.ytd-consent-bump-v2-lightbox {
+ background: var(--hover-background) !important;
+}
+
+/*Border color for terms and conditions*/
+ytd-consent-bump-renderer {
+ border-bottom: 1px solid var(--main-color) !important;
+}
+
+/*New logo*/
+#logo-icon-container.ytd-topbar-logo-renderer svg g path[fill*="#FF0000"],
+ytd-topbar-logo-renderer.style-scope>a>div>ytd-logo>yt-icon>yt-icon-shape>icon-shape>div>svg>svg:nth-child(1)>g:nth-child(1)>path:nth-child(1),
+/*cookie version*/
+svg.ytd-consent-bump-v2-lightbox>g:nth-child(1)>g:nth-child(1)>path:nth-child(1) {
+ fill: var(--main-color) !important;
+}
+
+ytd-topbar-logo-renderer.style-scope>a>div>ytd-logo>yt-icon>yt-icon-shape>icon-shape>div>svg>svg:nth-child(1)>g:nth-child(2)
+
+/*cookie version*/
+g.ytd-consent-bump-v2-lightbox:nth-child(2)>g:nth-child(1)>* {
+ fill: var(--main-text) !important;
+}
+
+ytd-topbar-logo-renderer.style-scope a svg>g>g:nth-child(2)>g,
+#country-code.ytd-topbar-logo-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Logo hover*/
+#logo-icon:hover {
+ --yt-swatch-logo-override: var(--main-color) !important;
+}
+
+/*Rewind logo*/
+#animated-yoodle {
+ filter: invert(90%) grayscale(1);
+}
+
+/*Shorts logo*/
+/*on home page*/
+ytd-rich-section-renderer.style-scope>div>ytd-rich-shelf-renderer yt-icon-shape>icon-shape>div>svg>g>path:nth-child(1),
+/*on video page*/
+yt-icon.ytd-reel-shelf-renderer>yt-icon-shape>icon-shape>div>svg>g>path:nth-child(1) {
+ fill: var(--main-color) !important;
+}
+
+/*Playlist page*/
+/*sidebar*/
+ytd-playlist-sidebar-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+#stats.ytd-playlist-sidebar-primary-info-renderer,
+#description.ytd-playlist-sidebar-primary-info-renderer .bold.yt-formatted-string,
+#owner-sub-count.ytd-video-owner-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#items.ytd-playlist-sidebar-renderer>.ytd-playlist-sidebar-renderer:not(:last-child) {
+ border-color: var(--hover-background) !important;
+}
+
+#primary.ytd-two-column-browse-results-renderer {
+ background-color: var(--main-background) !important;
+}
+
+ytd-button-renderer[is-paper-button] yt-icon.ytd-button-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#content.ytd-playlist-video-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/*buttons*/
+ytd-playlist-sidebar-renderer ytd-toggle-button-renderer.style-suggestive[is-paper-button],
+ytd-playlist-sidebar-renderer paper-button.ytd-toggle-button-renderer {
+ background-color: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+a.yt-simple-endpoint.ytd-button-renderer:hover *,
+ytd-playlist-sidebar-renderer ytd-button-renderer #button.ytd-button-renderer:hover,
+ytd-playlist-sidebar-renderer ytd-button-renderer #button.ytd-button-renderer:hover>yt-formatted-string.ytd-button-renderer {
+ color: var(--main-color) !important;
+}
+
+/*playlist page*/
+ytd-browse[page-subtype="playlist"] ytd-two-column-browse-results-renderer.ytd-browse {
+ background-color: var(--main-background) !important;
+}
+
+.index-message.ytd-playlist-panel-renderer,
+.light-text.ytd-playlist-segment-renderer,
+#contributor.ytd-playlist-video-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#title-container.ytd-playlist-segment-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#title-container.ytd-playlist-segment-renderer:hover #title.ytd-playlist-segment-renderer {
+ color: var(--main-color) !important;
+}
+
+/*Playlist changes*/
+ytd-playlist-panel-video-renderer:hover {
+ background-color: var(--hover-background) !important;
+}
+
+ytd-playlist-panel-video-renderer[selected] #index.ytd-playlist-panel-video-renderer,
+#byline.ytd-playlist-panel-video-renderer,
+.ytp-video-menu-item[aria-checked="true"] .ytp-video-menu-item-now-playing,
+.ytp-video-menu-item-author {
+ color: var(--main-color) !important;
+}
+
+ytd-playlist-video-renderer:hover,
+ytd-playlist-video-renderer:hover:not(.dragging) {
+ background-color: var(--second-background) !important;
+}
+
+ytd-playlist-panel-video-renderer[selected][use-color-palette],
+ytd-playlist-panel-video-renderer[selected][use-color-palette]:hover:not(.dragging) {
+ background-color: var(--hover-background) !important;
+}
+
+.header.ytd-playlist-panel-renderer,
+.playlist-items.ytd-playlist-panel-renderer,
+#header.ytd-engagement-panel-title-header-renderer,
+#content.ytd-engagement-panel-section-list-renderer,
+ytd-transcript-footer-renderer,
+ytd-transcript-segment-list-renderer {
+ background-color: var(--second-background) !important;
+}
+
+.cue.ytd-transcript-body-renderer,
+.cue-group-start-offset.ytd-transcript-body-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+.cue-group.active.ytd-transcript-body-renderer {
+ border-left-color: var(--main-color) !important;
+ background-color: var(--hover-background) !important;
+}
+
+.cue-group.active.ytd-transcript-body-renderer .cue-group-start-offset.ytd-transcript-body-renderer,
+.cue.ytd-transcript-body-renderer.active {
+ color: var(--main-text) !important;
+}
+
+.cue-group.ytd-transcript-body-renderer:hover .cue-group-start-offset.ytd-transcript-body-renderer,
+.cue-group.ytd-transcript-body-renderer:hover .cue.ytd-transcript-body-renderer {
+ color: var(--main-color) !important;
+}
+
+.cue.ytd-transcript-body-renderer:hover,
+ytd-transcript-body-renderer:not([refresh]) .cue.active.ytd-transcript-body-renderer {
+ background-color: transparent !important;
+ color: var(--main-color) !important
+}
+
+.segment-timestamp.ytd-transcript-segment-renderer {
+ background-color: var(--hover-background) !important;
+ color: var(--main-color) !important
+}
+
+/*search transcript*/
+ytd-transcript-search-panel-renderer,
+ytd-transcript-search-box-renderer {
+ background-color: var(--second-background) !important;
+}
+
+.input-container.ytd-transcript-search-box-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+/*magnifing glass icon*/
+.icon.ytd-transcript-search-box-renderer {
+ --iron-icon-fill-color: var(--dimmer-text) !important;
+ --iron-icon-stroke-color: var(--dimmer-text) !important;
+}
+
+#transcript-search-box-input.ytd-transcript-search-box-renderer {
+ color: var(--main-text) !important;
+ caret-color: var(--main-color) !important;
+}
+
+.ytp-video-menu-item[aria-checked="true"] .ytp-video-menu-item-thumbnail {
+ border-color: var(--main-color) !important;
+}
+
+#index.ytd-playlist-video-renderer,
+#index.ytd-playlist-panel-video-renderer,
+.badge-style-type-medium-grey.ytd-badge-supported-renderer
+
+/*unlisted*/
+ {
+ color: var(--dimmer-text) !important;
+}
+
+#container.ytd-playlist-panel-renderer {
+ border-color: var(--second-background) !important;
+}
+
+/*Playlist creation*/
+#create-playlist-form .input-content.paper-input-container label {
+ color: var(--main-text) !important;
+}
+
+#create-playlist-form input.style-scope.paper-input::placeholder {
+ color: var(--dimmer-text) !important;
+}
+
+#create-playlist-form .underline.is-highlighted.paper-input-container .focused-line.paper-input-container {
+ border-bottom-color: var(--main-text) !important;
+}
+
+#create-playlist-form #label.ytd-privacy-dropdown-item-renderer {
+ color: var(--main-text) !important;
+}
+
+#create-playlist-form ytd-privacy-dropdown-item-renderer.iron-selected {
+ background-color: var(--hover-background) !important;
+}
+
+/*Chapters*/
+/*title*/
+h4.ytd-macro-markers-list-item-renderer {
+ color: var(--main-text) !important;
+}
+
+/*timestamp*/
+#time.ytd-macro-markers-list-item-renderer {
+ color: var(--main-color) !important;
+ background-color: transparent !important;
+ padding: 0px !important;
+}
+
+/*show current chapter*/
+#sync-button.ytd-macro-markers-list-renderer {
+ background-color: var(--main-background) !important;
+ color: var(--main-text) !important;
+}
+
+#sync-button.ytd-macro-markers-list-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+/*active indicators*/
+ytd-macro-markers-list-item-renderer[active] #thumbnail.ytd-macro-markers-list-item-renderer {
+ outline-color: var(--main-color) !important;
+}
+
+#active-indicator.ytd-macro-markers-list-item-renderer {
+ background-color: var(--main-color) !important;
+}
+
+/*hover for item*/
+ytd-macro-markers-list-item-renderer:hover,
+ytd-macro-markers-list-item-renderer[active] {
+ background-color: var(--hover-background) !important;
+}
+
+ytd-macro-markers-list-item-renderer:hover {
+ box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.4);
+}
+
+ytd-macro-markers-list-item-renderer:hover h4.ytd-macro-markers-list-item-renderer {
+ color: var(--main-color) !important;
+}
+
+/*chapter images in description*/
+ytd-macro-markers-list-item-renderer[active][layout="MACRO_MARKERS_LIST_ITEM_RENDERER_LAYOUT_VERTICAL"] {
+ border-color: var(--main-color) !important;
+}
+
+ytd-horizontal-card-list-renderer.ytd-structured-description-content-renderer:not(:first-child),
+ytd-metadata-row-container-renderer.ytd-structured-description-content-renderer:not(:first-child),
+ytd-structured-description-content-renderer[inline-structured-description] ytd-horizontal-card-list-renderer.ytd-structured-description-content-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/*chapter times in search description*/
+.metadata-snippet-container-one-line.ytd-video-renderer #time.ytd-video-renderer {
+ color: var(--main-color) !important;
+ background: var(--second-background) !important;
+}
+
+/*chapter metadata in search results*/
+ytd-expandable-metadata-renderer {
+ /*this is used on hover, might as well*/
+ background-color: var(--yt-spec-badge-chip-background) !important;
+}
+
+/*expanded chapters in search results*/
+ytd-macro-markers-list-item-renderer[layout="MACRO_MARKERS_LIST_ITEM_RENDERER_LAYOUT_VERTICAL"] {
+ border-color: var(--second-background) !important;
+}
+
+/*chapter buttons button, 🔁 and close*/
+ytd-engagement-panel-section-list-renderer .yt-spec-button-shape-next--mono.yt-spec-button-shape-next--text yt-icon {
+ fill: var(--dimmer-text) !important;
+ stroke: var(--dimmer-text) !important;
+}
+
+/*Search bar*/
+ytd-searchbox[mode="legacy"] #container.ytd-searchbox,
+ytd-searchbox[mode="material-centered"] #container.ytd-searchbox,
+ytd-searchbox[mode="legacy"] #container.ytd-searchbox,
+ytd-searchbox[mode="legacy-centered"] #container.ytd-searchbox,
+#container.ytd-searchbox,
+#masthead-search-terms
+
+/*account settings page*/
+ {
+ background: var(--main-background) !important;
+ border-color: var(--main-background) !important;
+ box-shadow: none !important;
+}
+
+ytd-searchbox[mode="legacy"] #container.ytd-searchbox:hover,
+ytd-searchbox[mode=legacy][has-focus] #container.ytd-searchbox,
+ytd-searchbox[mode="material-left"] #container.ytd-searchbox,
+ytd-searchbox.style-scope[has-focus=""] #container.ytd-searchbox,
+ytd-searchbox[mode="material-centered"]:hover #container.ytd-searchbox,
+#masthead-search-terms.masthead-search-terms-border
+
+/*error page*/
+ {
+ border: 1px solid var(--main-color) !important;
+ box-shadow: none !important;
+}
+
+ytd-searchbox[mode="legacy"] #container.ytd-searchbox input.ytd-searchbox,
+#container.ytd-searchbox>input,
+ytd-searchbox input,
+#masthead-search-terms.masthead-search-terms-border input
+
+/*error page*/
+ {
+ color: var(--main-text) !important;
+}
+
+/*Right search icon 🔎 */
+#search-icon-legacy.ytd-searchbox,
+#masthead-search .search-btn-component,
+#masthead-search .search-btn-component .start
+
+/*account*/
+ {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+#search-icon-legacy.ytd-searchbox:hover yt-icon.ytd-searchbox {
+ color: var(--main-color) !important;
+}
+
+#masthead-search .search-btn-component .yt-uix-button-content
+
+/*account*/
+ {
+ filter: invert(1);
+}
+
+/*left 🔎 icon - shown on focus*/
+#search-icon.ytd-searchbox {
+ color: var(--main-text) !important;
+}
+
+#search-icon.ytd-searchbox:hover,
+#search-icon.ytd-searchbox:hover {
+ color: var(--main-color) !important;
+}
+
+/*results 🔎 icon*/
+.sbqs_c::before {
+ filter: invert(1);
+}
+
+/*Results backgrounds*/
+.sbsb_a,
+.sbdd_b {
+ background: var(--second-background) !important;
+ border: none !important;
+}
+
+/*Text color*/
+.gsfs {
+ color: var(--dimmer-text) !important;
+}
+
+/*Hover and keyboard select background*/
+.sbsb_c.gsfs:hover,
+.sbsb_d {
+ background-color: var(--hover-background) !important;
+}
+
+.sbfl_b {
+ background-color: var(--second-background) !important;
+}
+
+.sbfl_b:hover {
+ background-color: var(--hover-background) !important;
+ color: var(--main-color) !important;
+}
+
+.sbpqs_a {
+ color: var(--main-color) !important;
+}
+
+/*Keyboard select text color and hover text color*/
+.sbsb_c:hover .sbqs_c,
+.sbsb_c.gsfs.sbsb_d .sbqs_c {
+ color: var(--main-color) !important;
+}
+
+/*Keyboard icon in the search bar*/
+#gs_ok50 {
+ filter: invert(100%);
+}
+
+/*Microphone search*/
+ytd-masthead #voice-search-button.ytd-masthead {
+ background-color: var(--hover-background) !important;
+}
+
+ytd-voice-search-dialog-renderer[dialog] {
+ background-color: var(--second-background) !important;
+}
+
+#header-text.ytd-voice-search-dialog-renderer,
+#microphone-label.ytd-voice-search-dialog-renderer,
+#microphone.ytd-voice-search-dialog-renderer[state="try-again"] #microphone-circle.ytd-voice-search-dialog-renderer yt-icon.ytd-voice-search-dialog-renderer .yt-spec-button-shape-next--mono.yt-spec-button-shape-next--text {
+ color: var(--main-text) !important;
+}
+
+/*Search results correction*/
+.style-scope.yt-search-query-correction {
+ color: var(--main-text) !important;
+}
+
+.style-scope.yt-search-query-correction .italic.yt-formatted-string,
+.style-scope.yt-search-query-correction:hover {
+ color: var(--main-color) !important;
+}
+
+/*Similar results*/
+#title.ytd-exploratory-results-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*search results filter border*/
+#filter-menu.ytd-search-sub-menu-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#watch-card-header.ytd-generic-watch-card,
+#img-endpoint.ytd-watch-card-collage-renderer #overlay-button.ytd-watch-card-collage-renderer {
+ background: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+paper-tab,
+paper-tab.iron-selected.ytd-generic-watch-card {
+ color: var(--main-color) !important;
+}
+
+paper-item:hover {
+ background-color: var(--second-background) !important;
+}
+
+#img-endpoint.ytd-watch-card-collage-renderer #overlay-button.ytd-watch-card-collage-renderer {
+ opacity: .9;
+}
+
+#img-endpoint.ytd-watch-card-collage-renderer #overlay-button.ytd-watch-card-collage-renderer:hover {
+ opacity: 1 !important;
+}
+
+/*album*/
+#watch-card-subtitle.ytd-watch-card-rich-header-renderer {
+ color: var(--main-text) !important;
+}
+
+.duration.ytd-watch-card-compact-video-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Buttom border for different fields*/
+.unfocused-line.paper-input-container {
+ background-color: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+.focused-line.paper-input-container {
+ background-color: var(--main-color) !important;
+ border-color: var(--main-color) !important;
+}
+
+/*Search page*/
+#result-count.ytd-search-sub-menu-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+ytd-search-sub-menu-renderer,
+ytd-exploratory-results-renderer.ytd-item-section-renderer,
+ytd-shelf-renderer.ytd-item-section-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/*no results*/
+.promo-title.ytd-background-promo-renderer,
+.promo-body-text.ytd-background-promo-renderer {
+ color: var(--main-text) !important;
+}
+
+/*show more*/
+#more.ytd-vertical-list-renderer yt-formatted-string.ytd-vertical-list-renderer,
+#all.ytd-vertical-list-renderer yt-formatted-string.ytd-vertical-list-renderer {
+ color: var(--main-text) !important;
+}
+
+#more.ytd-vertical-list-renderer yt-formatted-string.ytd-vertical-list-renderer:hover,
+#all.ytd-vertical-list-renderer yt-formatted-string.ytd-vertical-list-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+ytd-search-filter-renderer yt-formatted-string.ytd-search-filter-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+ytd-search-filter-renderer.selected yt-formatted-string.ytd-search-filter-renderer,
+ytd-search-filter-renderer.selected #dismiss-x.ytd-search-filter-renderer,
+ytd-search-filter-renderer yt-formatted-string.ytd-search-filter-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+/*Search music suggestions*/
+ytd-watch-card-rich-header-renderer {
+ background: var(--hover-background) !important;
+}
+
+#overlay-button {
+ background: var(--main-color) !important;
+}
+
+#overlay-button:hover {
+ filter: brightness(110%) !important;
+}
+
+#watch-card-title,
+#view-all-endpoint:hover {
+ color: var(--main-color) !important;
+}
+
+ytd-watch-card-compact-video-renderer[is-condensed],
+#view-all-endpoint {
+ border-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*Search results related to item searched*/
+a.ytd-search-refinement-card-renderer {
+ background-color: var(--second-background) !important;
+ border-color: var(--hover-background) !important;
+ border-radius: 8px !important;
+}
+
+a.ytd-search-refinement-card-renderer:hover #card-title.ytd-search-refinement-card-renderer div.ytd-search-refinement-card-renderer {
+ color: var(--main-color) !important;
+}
+
+#card-title.ytd-search-refinement-card-renderer div.ytd-search-refinement-card-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Next button*/
+.center-aligned.ytd-horizontal-card-list-renderer {
+ background-color: var(--second-background) !important;
+ color: var(--main-text) !important;
+}
+
+.center-aligned.ytd-horizontal-card-list-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+/*filter*/
+a.yt-simple-endpoint.ytd-toggle-button-renderer:hover * {
+ color: var(--main-color) !important;
+ /* fill: var(--main-color) !important; */
+}
+
+#filter-group-name.ytd-search-filter-group-renderer {
+ color: var(--main-text) !important;
+ border-color: var(--hover-background) !important;
+}
+
+#description-text.ytd-video-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Comments*/
+yt-formatted-string.ytd-comments-header-renderer,
+#contenteditable-root.yt-formatted-string[aria-label].yt-formatted-string:empty::before,
+#contenteditable-textarea.ytd-commentbox {
+ color: var(--dimmer-text) !important;
+}
+
+/*sort by*/
+#icon-label.yt-dropdown-menu,
+#label-icon.yt-dropdown-menu {
+ color: var(--main-text) !important;
+ fill: var(--main-text) !important;
+}
+
+yt-sort-filter-sub-menu-renderer.ytd-comments-header-renderer:hover #icon-label.yt-dropdown-menu,
+yt-sort-filter-sub-menu-renderer.ytd-comments-header-renderer:hover #label-icon.yt-dropdown-menu {
+ color: var(--main-color) !important;
+ fill: var(--main-color) !important;
+}
+
+/*sort by dropdown*/
+paper-listbox.yt-dropdown-menu {
+ background: var(--second-background) !important;
+}
+
+.item.yt-dropdown-menu {
+ color: var(--main-text) !important;
+}
+
+paper-listbox.yt-dropdown-menu paper-item.yt-dropdown-menu:hover,
+paper-listbox.yt-dropdown-menu paper-item.yt-dropdown-menu:hover .item.yt-dropdown-menu {
+ background: var(--hover-background) !important;
+ color: var(--main-color) !important;
+}
+
+paper-listbox.yt-dropdown-menu .yt-dropdown-menu.iron-selected {
+ background-color: var(--second-background) !important;
+}
+
+paper-listbox.yt-dropdown-menu .yt-dropdown-menu.iron-selected .item.yt-dropdown-menu {
+ color: var(--main-color) !important;
+}
+
+/*text box*/
+#simplebox-placeholder.ytd-comment-simplebox-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#placeholder-area.ytd-comment-simplebox-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+#input-container.ytd-commentbox,
+ytd-commentbox {
+ --paper-input-container-underline-color: var(--hover-background) !important;
+ --paper-input-container-underline-focus-color: var(--main-color) !important;
+}
+
+.focused-line.tp-yt-paper-input-container {
+ border-color: var(--main-color) !important;
+}
+
+.unfocused-line.tp-yt-paper-input-container {
+ border-color: var(--dimmer-text) !important;
+}
+
+/*emoji selector*/
+#emojis.ytd-commentbox {
+ background-color: var(--second-background) !important;
+}
+
+/*comments themselves*/
+#author-text.yt-simple-endpoint.ytd-comment-renderer {
+ color: var(--main-text) !important;
+}
+
+#author-text.yt-simple-endpoint.ytd-comment-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+ytd-author-comment-badge-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+#content-text.ytd-comment-renderer,
+ytd-expander[should-use-number-of-lines][collapsed]>#content.ytd-expander {
+ color: var(--dimmer-text) !important;
+}
+
+/*read more*/
+.more-button-exp.ytd-comment-renderer,
+.less-button-exp.ytd-comment-renderer {
+ color: var(--main-text) !important;
+}
+
+.more-button-exp.ytd-comment-renderer:hover,
+.less-button-exp.ytd-comment-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+/*view replies*/
+paper-button.ytd-comment-replies-renderer,
+yt-next-continuation.ytd-comment-replies-renderer,
+yt-icon.ytd-comment-replies-renderer {
+ color: var(--main-text) !important;
+}
+
+.more-button.style-scope.ytd-comment-replies-renderer:hover paper-button.ytd-comment-replies-renderer,
+.more-button.style-scope.ytd-comment-replies-renderer:hover yt-next-continuation.ytd-comment-replies-renderer,
+.more-button.style-scope.ytd-comment-replies-renderer:hover yt-icon.ytd-comment-replies-renderer {
+ color: var(--main-color) !important;
+}
+
+/*likes*/
+#vote-count-middle.ytd-comment-action-buttons-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+ytd-button-renderer yt-formatted-string.ytd-button-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--text:hover {
+ /*background-color: var(--hover-background) !important;*/
+ background-color: var(--yt-spec-10-percent-layer) !important;
+}
+
+/*Show more videos*/
+yt-next-continuation.ytd-watch-next-secondary-results-renderer {
+ --paper-button_-_background-color: transparent !important;
+ --paper-button_-_color: var(--dimmer-text) !important;
+}
+
+.style-scope.yt-next-continuation {
+ border-color: transparent !important;
+}
+
+.style-scope.yt-next-continuation:hover {
+ background-color: transparent !important;
+ color: var(--main-color) !important;
+}
+
+yt-formatted-string.ytd-expanded-shelf-contents-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+yt-formatted-string.ytd-expanded-shelf-contents-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+/*View more comments*/
+paper-button.yt-next-continuation {
+ color: var(--dimmer-text) !important;
+}
+
+/*Links in description and published date for comments*/
+#content.ytd-expander a,
+.yt-core-attributed-string--link-inherit-color .yt-core-attributed-string__link--call-to-action-color {
+ color: var(--main-color) !important;
+ opacity: 0.9;
+}
+
+#published-time-text.ytd-comment-renderer,
+#published-time-text.ytd-comment-renderer a {
+ --yt-endpoint-color: var(--dimmer-text) !important;
+ color: var(--dimmer-text) !important;
+ opacity: .8;
+}
+
+#content.ytd-expander a:hover,
+#published-time-text.ytd-comment-renderer a:hover,
+#content.ytd-expander #name.ytd-author-comment-badge-renderer:hover,
+.yt-core-attributed-string--link-inherit-color .yt-core-attributed-string__link--call-to-action-color:hover {
+ color: var(--main-color) !important;
+ opacity: 1 !important;
+}
+
+#content.ytd-expander #name.ytd-author-comment-badge-renderer {
+ color: var(--main-text) !important;
+}
+
+/*video description text*/
+.yt-core-attributed-string--link-inherit-color {
+ color: var(--dimmer-text) !important;
+}
+
+/*Heart icon in comments*/
+#hearted-border.ytd-creator-heart-renderer,
+#hearted.ytd-creator-heart-renderer {
+ color: var(--main-color) !important;
+ fill: var(--main-color) !important;
+}
+
+yt-icon-button#creator-heart-button svg {
+ fill: var(--main-color) !important;
+}
+
+/*Pinned by*/
+#label.ytd-pinned-comment-badge-renderer {
+ color: var(--main-color) !important;
+ opacity: 0.5;
+}
+
+yt-icon.ytd-pinned-comment-badge-renderer {
+ fill: var(--main-color) !important;
+ opacity: 0.5;
+}
+
+/*shorts comments background*/
+.watch-while-engagement-panel.ytd-reel-video-renderer,
+/*comment window background*/
+ytd-item-section-renderer[static-comments-header] #header.ytd-item-section-renderer
+
+/*add comment background*/
+ {
+ background-color: var(--second-background) !important;
+}
+
+/*Fundraiser message*/
+#wrapper.ytd-donation-unavailable-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+/*Chat*/
+/*header*/
+yt-live-chat-header-renderer,
+#header.yt-live-chat-participant-list-renderer,
+yt-live-chat-message-renderer,
+yt-live-chat-ticker-renderer {
+ background: var(--hover-background) !important;
+}
+
+yt-live-chat-banner-manager[has-active-banner] {
+ background: linear-gradient(var(--hover-background) 0%, var(--second-background) 100%) !important;
+}
+
+/*live replay*/
+#card.yt-live-chat-viewer-engagement-message-renderer,
+yt-live-chat-text-message-renderer[is-highlighted] {
+ background: var(--hover-background) !important;
+}
+
+#chat,
+#participants,
+yt-live-chat-renderer {
+ background: var(--second-background) !important;
+}
+
+/*show mode was enabled*/
+#container.yt-live-chat-restricted-participation-renderer {
+ background: var(--second-background) !important;
+}
+
+#contents.yt-live-chat-mode-change-message-renderer {
+ background: var(--hover-background) !important;
+}
+
+#contents.yt-live-chat-mode-change-message-renderer,
+#subtext.yt-live-chat-mode-change-message-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+yt-live-chat-toast-renderer[is-showing-message]
+
+/*info for show mode*/
+ {
+ background: var(--hover-background) !important;
+}
+
+/*dropmenu*/
+#menu.yt-live-chat-text-message-renderer {
+ background: transparent !important;
+}
+
+paper-listbox {
+ background: var(--second-background) !important;
+}
+
+yt-icon.ytd-menu-navigation-item-renderer,
+yt-icon.ytd-menu-service-item-renderer,
+#header.yt-live-chat-participant-list-renderer,
+#author-name.yt-live-chat-author-chip:not(.member):not(.moderator),
+.style-scope.yt-live-chat-ninja-message-renderer {
+ color: var(--main-text) !important;
+}
+
+#deleted-state,
+#show-original,
+yt-live-chat-text-message-renderer[is-deleted] #message.yt-live-chat-text-message-renderer,
+#timestamp {
+ color: var(--dimmer-text) !important;
+}
+
+/*paid messages*/
+#content.yt-live-chat-paid-message-renderer #message {
+ color: black !important;
+}
+
+#message.yt-live-chat-text-message-renderer a.yt-live-chat-text-message-renderer {
+ color: var(--main-color) !important;
+ text-decoration: none !important;
+}
+
+yt-live-chat-author-chip[is-highlighted] #author-name {
+ background: var(--main-color) !important;
+}
+
+/*paid arrows*/
+yt-icon.yt-live-chat-ticker-renderer {
+ background: var(--main-background) !important;
+ color: var(--main-text) !important;
+}
+
+yt-icon.yt-live-chat-ticker-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+#right-arrow-container.yt-live-chat-ticker-renderer,
+#left-arrow-container.yt-live-chat-ticker-renderer {
+ background: transparent !important;
+}
+
+/*channel messages*/
+yt-live-chat-text-message-renderer[author-is-owner] {
+ background: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*pinned*/
+yt-live-chat-banner-manager[has-visible-banner] {
+ background: var(--second-background) !important;
+}
+
+#contents.yt-live-chat-banner-renderer>.yt-live-chat-banner-renderer {
+ background: transparent !important;
+}
+
+/*Confirmantion popup*/
+paper-toast {
+ background-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*button*/
+yt-icon-button.yt-live-chat-item-list-renderer,
+yt-live-chat-ninja-message-renderer.yt-live-chat-renderer paper-button.yt-button-renderer,
+yt-live-chat-message-renderer.yt-live-chat-message-input-renderer yt-button-renderer.style-dark[is-paper-button] {
+ background: var(--main-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*input*/
+yt-live-chat-message-input-renderer {
+ background-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+#focused.yt-live-chat-text-input-field-renderer {
+ background: var(--main-color) !important;
+}
+
+#count {
+ color: var(--dimmer-text) !important;
+}
+
+/*hide chat*/
+#show-hide-button.ytd-live-chat-frame>ytd-toggle-button-renderer.ytd-live-chat-frame {
+ background: var(--hover-background) !important;
+}
+
+/*emoji*/
+yt-formatted-string.yt-emoji-picker-category-renderer {
+ background: var(--hover-background) !important;
+}
+
+#search-panel.yt-emoji-picker-renderer {
+ background: var(--main-background) !important;
+ color: var(--main-text) !important;
+}
+
+#search-empty {
+ color: var(--dimmer-text) !important;
+}
+
+/*donations superchats cards*/
+#card.yt-live-chat-donation-announcement-renderer {
+ background-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+#menu.yt-live-chat-donation-announcement-renderer {
+ background: transparent !important;
+}
+
+/*for actually donating*/
+#subtext.yt-live-chat-product-button-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#container.yt-live-chat-product-button-renderer .yt-icon {
+ fill: var(--dimmer-text) !important;
+}
+
+/*Fund raiser*/
+#header-section.ytd-donation-shelf-renderer,
+#collapse-controls-section.ytd-donation-shelf-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+#header-text.ytd-donation-shelf-renderer,
+#collapse-controls-section.ytd-donation-shelf-renderer {
+ color: var(--main-text) !important;
+}
+
+#collapse-controls-section.ytd-donation-shelf-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+#header-section.ytd-donation-shelf-renderer .style-scope.ytd-donation-shelf-renderer.no-transition {
+ filter: invert(.8);
+}
+
+#donate-section.ytd-donation-shelf-renderer,
+#creator-messages-section.ytd-donation-shelf-renderer,
+#nonprofit-section.ytd-donation-shelf-renderer,
+#nonprofit-title.ytd-donation-shelf-renderer {
+ background-color: var(--second-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+#campaign-title.ytd-donation-shelf-renderer,
+.creator-message.ytd-donation-shelf-renderer,
+#campaign-subtitle.ytd-donation-shelf-renderer,
+.creator-message-name.ytd-donation-shelf-renderer,
+#nonprofit-title.ytd-donation-shelf-renderer {
+ color: var(--main-text) !important;
+}
+
+.creator-message.ytd-donation-shelf-renderer,
+#campaign-subtitle.ytd-donation-shelf-renderer,
+#nonprofit-subtitle.ytd-donation-shelf-renderer,
+#nonprofit-description.ytd-donation-shelf-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#amount-raised.ytd-donation-shelf-renderer,
+#nonprofit-title.ytd-donation-shelf-renderer yt-icon.ytd-donation-shelf-renderer {
+ color: var(--main-color) !important;
+}
+
+#nonprofit-link.ytd-donation-shelf-renderer .inline-icon.ytd-donation-shelf-renderer {
+ fill: var(--main-color) !important;
+}
+
+/*progress*/
+#progress-bar-start.ytd-donation-shelf-renderer,
+#progress-bar-end.ytd-donation-shelf-renderer {
+ color: var(--main-text) !important;
+}
+
+#matching-label.ytd-donation-shelf-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#progress-bar.ytd-donation-shelf-renderer {
+ background-color: var(--dimmer-text) !important;
+}
+
+#progress-bar-fill.ytd-donation-shelf-renderer {
+ background-color: var(--main-color) !important;
+}
+
+/*donate button*/
+.style-scope.ytd-donation-shelf-renderer .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--filled {
+ background-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+/*donate window*/
+#top-box.ytd-donation-amount-picker-renderer {
+ background-color: var(--second-background) !important;
+}
+
+#campaign-title.ytd-donation-amount-picker-renderer,
+#nonprofit-title.ytd-donation-amount-picker-renderer {
+ color: var(--main-color) !important;
+}
+
+#campaign-subtitle.ytd-donation-amount-picker-renderer,
+#nonprofit-subtitle.ytd-donation-amount-picker-renderer {
+ color: var(--main-text) !important;
+}
+
+/*amount buttons*/
+#suggested-amount-buttons-row.ytd-donation-amount-picker-renderer ytd-button-renderer.ytd-donation-amount-picker-renderer[is-paper-button] paper-button.ytd-button-renderer {
+ background-color: var(--second-background) !important;
+}
+
+#suggested-amount-buttons-row.ytd-donation-amount-picker-renderer ytd-button-renderer.ytd-donation-amount-picker-renderer[is-paper-button] paper-button.ytd-button-renderer {
+ background-color: var(--second-background) !important;
+ border-color: var(--second-background) !important;
+}
+
+#suggested-amount-buttons-row.ytd-donation-amount-picker-renderer ytd-button-renderer.ytd-donation-amount-picker-renderer[is-paper-button][selected] paper-button.ytd-button-renderer,
+.ytd-donation-amount-picker-renderer ytd-button-renderer.style-primary[is-paper-button] {
+ background-color: var(--main-color) !important;
+}
+
+/*curency for other amount*/
+span.prefix.style-scope.paper-input-container>div.ytd-donation-amount-picker-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Payment window*/
+.popup-mode .b3-page-header {
+ background-color: var(--main-background) !important;
+}
+
+.b3-line-items-mundane-items-container,
+.b3-line-items-mundane-items-container {
+ background-color: var(--hover-background) !important;
+}
+
+.b3-separator {
+ display: none !important;
+}
+
+.b3-line-item-value {
+ color: var(--main-color) !important;
+}
+
+.b3-line-item-name,
+.b3-line-item-infomessage,
+.b3-line-item-subvalue {
+ color: var(--main-text) !important;
+}
+
+.b3-single-option-form-selector-option-content .b3-existing-instrument-option-label-without-image,
+.b3-dropdown-form-selector .b3-existing-instrument-option-label-without-image,
+.b3-single-option-form-selector-option-content .b3-additional-instrument-option-label,
+.b3-dropdown-form-selector .b3-additional-instrument-option-label,
+.b3-input.focused .b3-input-label,
+.b3-input.focused .b3-input-label-text,
+.b3-input input[type="tel"],
+.b3-input input[type="text"],
+.b3-input input[type="password"],
+.b3-input input[type="email"],
+.b3-input.populated .b3-input-label,
+.b3-input.invalid .b3-input-label,
+.b3-input.autofilled .b3-input-label,
+.b3-input-field>.b3-input-label,
+.b3-input-field>.b3-input-label.accessible,
+.b3-collapsing-form-placeholder-text {
+ color: var(--main-text) !important;
+}
+
+.countryselector .goog-flat-menu-button-caption,
+.countryselector .goog-flat-menu-button-caption .goog-menuitem-content {
+ color: var(--dimmer-text) !important;
+}
+
+/*icons*/
+.b3-single-option-form-selector-icon,
+.b3-collapsing-form-icon {
+ fill: var(--main-text) !important;
+}
+
+.b3-collapsing-form.focused .b3-collapsing-form-icon {
+ fill: var(--main-color) !important;
+}
+
+.b3-tooltip-icon {
+ filter: invert(1) !important;
+}
+
+/*border*/
+.b3-input-status-indicator {
+ background-color: var(--main-color) !important;
+}
+
+.b3-input-accent {
+ border-color: var(--hover-background) !important;
+}
+
+/*tooltip*/
+.b3-inline-tooltip-popup-wrapper,
+.help-Helpwidgets-TooltipWidget-content-html {
+ background-color: var(--hover-background) !important;
+ color: var(--dimmer-text) !important;
+}
+
+.b3-inline-tooltip-popup-wrapper a,
+.help-Helpwidgets-TooltipWidget-content-html a {
+ color: var(--main-color) !important;
+}
+
+/*country choice*/
+.goog-menu,
+.goog-menuitem:hover {
+ background-color: var(--hover-background) !important;
+}
+
+.goog-menuitem,
+.goog-tristatemenuitem,
+.goog-filterobsmenuitem {
+ color: var(--main-text) !important;
+}
+
+.goog-menuitem-highlight .goog-menuitem-content {
+ color: var(--main-color) !important;
+}
+
+.goog-menuitem .countryselector-flag {
+ border-radius: 4px !important;
+ /*hiding ugly white corners*/
+}
+
+/*footer*/
+.b3-legal-message-content,
+.b3-info-message-list.b3-buyflow-extra-messages .b3-info-message-component.b3-info-message-unknown,
+.b3-info-message-component.b3-info-message-unknown.b3-buyflow-extra-messages .b3-info-message-html {
+ color: var(--dimmer-text) !important;
+}
+
+.b3-legal-message-content a,
+.b3-info-message-component.b3-info-message-unknown.b3-buyflow-extra-messages .b3-info-message-html a {
+ color: var(--main-color) !important;
+}
+
+/*Notification*/
+/*bell icon notification count*/
+.yt-spec-icon-badge-shape--type-notification .yt-spec-icon-badge-shape__badge {
+ background-color: var(--main-color) !important;
+ border: none !important;
+}
+
+button.yt-icon-button:hover .yt-spec-icon-badge-shape--type-notification .yt-spec-icon-badge-shape__badge {
+ color: var(--main-text) !important;
+}
+
+/*load spinner - also for comments*/
+.spinner-layer.layer-1.tp-yt-paper-spinner,
+.spinner-layer.layer-2.tp-yt-paper-spinner,
+.spinner-layer.layer-3.tp-yt-paper-spinner,
+.spinner-layer.layer-4.tp-yt-paper-spinner {
+ color: var(--dimmer-text) !important;
+}
+
+#notification-count.ytd-notification-topbar-button-renderer,
+ytd-notification-renderer.unread #new.ytd-notification-renderer,
+.yt-lockup-notification .unread-dot
+
+/*account settings*/
+ {
+ background: var(--main-color) !important;
+ border-color: var(--main-color) !important;
+}
+
+.text.ytd-notification-renderer,
+.message.ytd-notification-renderer #yt-masthead-notifications-title,
+.yt-lockup-notification .yt-lockup-title a
+/*account settings*/
+h2.yt-multi-page-menu-section-renderer
+
+/*comments and notifications headers*/
+ {
+ color: var(--main-text) !important;
+}
+
+/*gear icon*/
+ytd-simple-menu-header-renderer .yt-spec-button-shape-next__icon {
+ color: var(--main-text) !important;
+}
+
+ytd-simple-menu-header-renderer .yt-spec-button-shape-next--mono.yt-spec-button-shape-next--text:hover .yt-spec-button-shape-next__icon {
+ color: var(--main-color) !important;
+}
+
+.metadata.ytd-notification-renderer,
+.exp-responsive .yt-lockup-tile .yt-lockup-byline
+
+/*account settings*/
+ {
+ color: var(--dimmer-text) !important;
+}
+
+ytd-notification-renderer:hover .message.ytd-notification-renderer {
+ color: var(--main-color) !important;
+}
+
+ytd-watch:not([flexy-fit-to-video_]) #chat.ytd-watch,
+ytd-watch:not([flexy-fit-to-video_]) #transcript.ytd-watch {
+ padding-left: 0 !important;
+}
+
+ytd-simple-menu-header-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+h2.ytd-simple-menu-header-renderer {
+ color: var(--main-text) !important;
+}
+
+#sections.ytd-multi-page-menu-renderer>ytd-background-promo-renderer.ytd-multi-page-menu-renderer,
+ytd-multi-page-menu-renderer,
+#yt-masthead-notifications-content .item-section>li>.yt-lockup-tile,
+#yt-masthead-notifications-content .yt-ui-ellipsis,
+/*account settings*/
+#yt-masthead-notifications-content
+
+/*bottom thing - account settings*/
+ {
+ background: var(--second-background) !important;
+ border-color: var(--second-background) !important;
+}
+
+.browse-items-load-more-button {
+ background-color: var(--main-background) !important;
+ border-color: var(--main-background) !important;
+ color: var(--main-text) !important;
+}
+
+.browse-items-load-more-button:hover {
+ color: var(--main-color) !important;
+}
+
+.promo-message.ytd-background-promo-renderer,
+#message:not([class*="yt-music"]) {
+ color: var(--dimmer-text) !important;
+}
+
+/*triangle*/
+.yt-uix-clickcard-card-reverse .yt-uix-card-body-arrow-vertical,
+.yt-uix-hovercard-card-reverse .yt-uix-card-body-arrow-vertical
+
+/*account settings*/
+ {
+ border-bottom-color: var(--hover-background) !important;
+}
+
+/*menu*/
+.yt-ui-menu-content
+
+/*account settings*/
+ {
+ background-color: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+.yt-ui-menu-item
+
+/*account settings*/
+ {
+ background-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+.yt-ui-menu-item:hover
+
+/*account settings*/
+ {
+ color: var(--main-color) !important;
+}
+
+/*gear icon*/
+.yt-uix-button-icon-icon-account-settings
+
+/*account settings*/
+ {
+ filter: brightness(250%) invert(1);
+}
+
+/*Cards*/
+.iv-card-content,
+.ytp-ce-expanding-overlay-background,
+.ytp-cards-teaser .ytp-cards-teaser-text,
+.ytp-cards-teaser .ytp-cards-teaser-box {
+ background-color: var(--main-background) !important;
+}
+
+.ytp-cards-teaser .ytp-cards-teaser-box,
+.iv-card-image {
+ border: 0px !important;
+}
+
+.iv-card-content> :first-child,
+.html5-video-player a,
+.iv-card h2,
+.ytp-cards-teaser .ytp-cards-teaser-text {
+ color: var(--main-text) !important;
+}
+
+.iv-card:hover .iv-card-primary-link,
+.ytp-ce-website-title {
+ color: var(--main-color) !important;
+}
+
+.ytp-ce-element:hover {
+ border-color: var(--main-color) !important;
+}
+
+.ytp-ce-channel-title.ytp-ce-link {
+ color: var(--main-color) !important;
+ opacity: 0.9 !important;
+}
+
+.ytp-ce-channel-title.ytp-ce-link:hover,
+.ytp-cards-teaser .ytp-cards-teaser-text:hover {
+ color: var(--main-color) !important;
+ opacity: 1 !important;
+}
+
+.ytp-ce-channel-metadata.yt-ui-ellipsis.yt-ui-ellipsis-3 {
+ background: transparent;
+ color: var(--dimmer-text) !important;
+}
+
+/*Cards border color*/
+.iv-card-message {
+ border-bottom: 1px solid var(--main-color) !important;
+}
+
+.ytp-ce-channel-this .ytp-ce-channel-metadata {
+ border-color: var(--hover-background) !important;
+}
+
+/*Poll*/
+.iv-card-poll label,
+.iv-card-poll.iv-card-poll-voted label.iv-card-poll-choice-checked,
+.iv-card-poll.iv-card-poll-voted label {
+ color: var(--main-text) !important;
+}
+
+#vote-info.ytd-backstage-poll-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+.iv-card-poll .iv-card-poll-result .iv-card-poll-result-bar {
+ background-color: var(--main-color) !important;
+}
+
+ytd-backstage-post-thread-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+ytd-backstage-poll-renderer[show-poll-choice-border] .choice-info.ytd-backstage-poll-renderer {
+ border-color: transparent !important;
+}
+
+/*Account menu header*/
+ytd-active-account-header-renderer {
+ background: var(--second-background) !important;
+}
+
+ytd-active-account-header-renderer:hover {
+ background-color: var(--hover-background) !important;
+}
+
+#account-name.ytd-active-account-header-renderer,
+#channel-title.ytd-account-item-renderer {
+ color: var(--main-text) !important;
+}
+
+#email.ytd-active-account-header-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*subentries*/
+#label.ytd-toggle-theme-compact-link-renderer,
+tp-yt-paper-item.ytd-compact-link-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+ytd-toggle-theme-compact-link-renderer:hover #label.ytd-toggle-theme-compact-link-renderer,
+ytd-toggle-theme-compact-link-renderer:hover yt-icon,
+paper-item.ytd-compact-link-renderer:hover #subtitle,
+paper-item.ytd-compact-link-renderer:hover .deemphasize.yt-formatted-string,
+tp-yt-paper-item.ytd-compact-link-renderer:hover *,
+tp-yt-paper-item.ytd-compact-link-renderer:hover #subtitle.ytd-compact-link-renderer {
+ color: var(--main-color) !important;
+}
+
+#footer.ytd-multi-page-menu-renderer>.ytd-multi-page-menu-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+.description.ytd-toggle-item-renderer,
+#caption.ytd-toggle-item-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*language*/
+#language.ytd-account-settings,
+#country.ytd-account-settings,
+#restricted.ytd-account-settings,
+.container.ytd-account-settings {
+ background-color: var(--second-background) !important;
+}
+
+paper-item.ytd-account-settings {
+ color: var(--dimmer-text) !important;
+}
+
+paper-item.ytd-account-settings:hover {
+ color: var(--main-color) !important;
+}
+
+/*swich account*/
+yt-formatted-string.ytd-account-item-renderer[secondary] {
+ color: var(--dimmer-text) !important;
+}
+
+#selected.ytd-account-item-renderer {
+ color: var(--main-color) !important;
+}
+
+/*theme*/
+ytd-compact-link-renderer[compact-link-style="compact-link-style-type-disclaimer"] #label.ytd-compact-link-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Live background color*/
+ytd-thumbnail-overlay-time-status-renderer[overlay-style="LIVE"] {
+ background-color: var(--main-color) !important;
+}
+
+.guide-entry-badge.ytd-guide-entry-renderer {
+ color: var(--main-color) !important;
+ fill: var(--main-color) !important;
+}
+
+.ytp-live-badge[disabled]:before {
+ background: var(--main-color) !important;
+}
+
+/*Recolored sidepane icons, menu icons and filter button*/
+.guide-icon.ytd-guide-entry-renderer,
+paper-button.ytd-toggle-button-renderer,
+yt-icon.ytd-compact-link-renderer,
+yt-icon.ytd-toggle-theme-compact-link-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Sidepane titles*/
+#guide-section-title a {
+ color: var(--dimmer-text) !important;
+}
+
+#guide-section-title a:hover {
+ color: var(--main-color) !important;
+}
+
+
+/*Autoplay text*/
+#upnext.ytd-compact-autoplay-renderer,
+#autoplay.ytd-compact-autoplay-renderer {
+ color: var(--dimmer-text) !important;
+ opacity: .8;
+}
+
+ytd-compact-autoplay-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/*Video was removed by user - not interested*/
+#text.ytd-notification-multi-action-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Video was added/removed to/from a playlist by user*/
+yt-notification-action-renderer[ui-refresh] #text.yt-notification-action-renderer,
+yt-notification-action-renderer[ui-refresh] #sub-text.yt-notification-action-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Links in video description*/
+.description.ytd-video-secondary-info-renderer a {
+ color: var(--main-color) !important;
+ opacity: .9;
+}
+
+/*Game cards*/
+ytd-rich-metadata-renderer {
+ background-color: var(--second-background) !important;
+}
+
+#call-to-action.ytd-rich-metadata-renderer {
+ color: var(--main-text) !important;
+}
+
+#title.ytd-rich-metadata-renderer,
+#call-to-action.ytd-rich-metadata-renderer:hover {
+ color: var(--main-color) !important;
+}
+
+/*Movie cards*/
+#header.ytd-movie-offer-module-renderer {
+ background-color: var(--second-background) !important;
+}
+
+ytd-button-renderer.ytd-movie-offer-module-renderer.style-primary[is-paper-button] {
+ background-color: var(--main-color) !important;
+}
+
+#wide-clickable-area.ytd-movie-offer-module-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+#info.ytd-movie-offer-module-renderer {
+ color: var(--main-text) !important;
+}
+
+h3.ytd-compact-movie-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Tour/ticket cards*/
+ytd-ticket-shelf-renderer {
+ background-color: var(--second-background) !important;
+}
+
+#primary-event.ytd-ticket-shelf-renderer #meta.ytd-ticket-shelf-renderer #tickets-button.ytd-ticket-shelf-renderer {
+ background: var(--main-color) !important;
+ color: var(--main-text) !important;
+}
+
+#primary-event.ytd-ticket-shelf-renderer #meta-info.ytd-ticket-shelf-renderer #nearest.ytd-ticket-shelf-renderer,
+#primary-event.ytd-ticket-shelf-renderer #meta-info.ytd-ticket-shelf-renderer #subtitle1.ytd-ticket-shelf-renderer,
+#primary-event.ytd-ticket-shelf-renderer #meta-info.ytd-ticket-shelf-renderer #subtitle2.ytd-ticket-shelf-renderer,
+.where-column-td.ytd-ticket-shelf-renderer .where-column.ytd-ticket-shelf-renderer {
+ color: var(--main-text) !important;
+}
+
+.when-date-column.ytd-ticket-shelf-renderer,
+.link.ytd-ticket-shelf-renderer,
+.when-weekday-column.ytd-ticket-shelf-renderer {
+ color: var(--main-color) !important;
+}
+
+/*separator*/
+#seperator.ytd-ticket-shelf-renderer,
+ytd-ticket-shelf-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+
+/*Author name*/
+#owner-name.ytd-video-owner-renderer {
+ opacity: .9;
+}
+
+#owner-name.ytd-video-owner-renderer:hover {
+ opacity: 1 !important;
+}
+
+/*Set a memento*/
+ytd-toggle-button-renderer.style-compact-gray[is-paper-button] {
+ background-color: var(--second-background) !important;
+ color: var(--dimmer-text) !important;
+}
+
+/*Series name*/
+.super-title.ytd-video-primary-info-renderer a,
+#additional-metadata-line.ytd-video-meta-block {
+ color: var(--dimmer-text) !important;
+ opacity: .8;
+}
+
+#selectionBar.paper-tabs {
+ border-color: var(--main-color) !important;
+}
+
+/*"Best" of YouTube icons in sidepane*/
+/*.style-scope.ytd-guide-entry-renderer.no-transition
+ {
+ filter: grayscale(100%);
+ }*/
+
+/* Promo page */
+body.yt-new-promo-page-use-launched-copy .yt-new-promo-page-header {
+ background: var(--main-background) !important;
+}
+
+.yt-new-promo-page-section-text,
+.yt-new-promo-page-header {
+ color: var(--dimmer-text);
+}
+
+.yt-new-promo-page-button {
+ background-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+ opacity: .9;
+}
+
+.yt-new-promo-page-button:hover {
+ opacity: 1;
+}
+
+/* Crude logo fix */
+.yt-new-promo-page-logo {
+ filter: grayscale(100%) invert(100%);
+}
+
+/* Fix for active like/dislike buttons */
+ytd-toggle-button-renderer.style-grey-text[is-icon-button] {
+ color: var(--yt-button-color);
+}
+
+ytd-toggle-button-renderer #button.ytd-toggle-button-renderer {
+ color: inherit;
+}
+
+/*like/dislike buttons in nested replies*/
+/*.style-scope.ytd-toggle-button-renderer svg
+ {
+ fill: var(--dimmer-text) !important;
+ }
+ .style-scope.ytd-toggle-button-renderer yt-icon-button.style-default-active svg
+ {
+ fill: var(--main-color) !important;
+ }*/
+ytd-toggle-button-renderer.ytd-comment-action-buttons-renderer #button.ytd-toggle-button-renderer {
+ color: var(--yt-button-color);
+}
+
+ytd-toggle-button-renderer.ytd-comment-action-buttons-renderer .style-default-active {
+ color: var(--main-color) !important;
+}
+
+/* Fix for placeholders/skeletons */
+/*ytd-masthead.shell
+ {
+ background-color: var(--main-background);
+ }
+ ytd-masthead.shell [class*='skeleton'], [id*='skeleton'] [class*='skeleton'], [id*='skeleton'], .shelf-videos, .skeleton-bg-color
+ {
+ background-color: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+ }*/
+/*homepage skeleton*/
+#home-container-skeleton,
+html[dark] #home-container-skeleton {
+ background-color: var(--main-background) !important;
+}
+
+/*sidebar skeleton*/
+#guide-skeleton,
+html[dark] #guide-skeleton {
+ background-color: var(--second-background) !important;
+}
+
+/*homepage videos skeleton*/
+#home-page-skeleton .skeleton-bg-color,
+html[dark] #home-page-skeleton .skeleton-bg-color {
+ background-color: var(--hover-background) !important;
+}
+
+.masthead-skeleton-icon,
+html[dark] .masthead-skeleton-icon,
+/*ytd-masthead.shell [class*='skeleton'], html[dark] ytd-masthead.shell,
+ .shelf-videos, html[dark] .shelf-videos,*/
+.skeleton-bg-color,
+html[dark] .skeleton-bg-color {
+ background-color: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+.skeleton-light-border-bottom,
+html[dark] .skeleton-light-border-bottom {
+ border-bottom: 1px solid var(--hover-background) !important;
+}
+
+ytd-alert-with-button-renderer[type="INFO"],
+#content-wrapper.yt-alert-with-actions-renderer
+
+/*TOS*/
+ {
+ background-color: var(--hover-background) !important;
+}
+
+#content-wrapper.yt-alert-with-actions-renderer yt-button-renderer[is-paper-button] yt-icon.yt-button-renderer {
+ color: var(--main-color) !important;
+}
+
+ytd-alert-with-button-renderer[type="INFO"] #text.ytd-alert-with-button-renderer {
+ color: var(--main-text) !important;
+}
+
+#alert-message.ytd-consent-bump-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Paid membership*/
+yt-subscription-product-header-renderer.ytd-item-section-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Reporting*/
+.introduction-header {
+ color: var(--main-text) !important;
+}
+
+.introduction-body,
+.introduction-bullet-items {
+ color: var(--dimmer-text) !important;
+}
+
+yt-report-form-modal-renderer[dialog][dialog][dialog] {
+ background: var(--main-background) !important;
+}
+
+yt-options-renderer[increased-tooltip-target] yt-icon.yt-options-renderer {
+ color: var(--main-text) !important;
+}
+
+/*Help*/
+.ghp-header-searchBox,
+.ghp-autocomplete-label {
+ color: var(--dimmer-text) !important;
+}
+
+/*
+ .ghp-header-searchIcon.ghpv-loaded, .ghp-iconTextComponent-icon, .ghp-autocomplete-icon
+ {
+ filter: invert(100%) grayscale(100%) brightness(150%);
+ }
+ .ghp-autocompleteGlass
+ {
+ background: rgba(0,0,0,3) !important;
+ }
+ .ghp-card-title
+ {
+ color: var(--main-text) !important;
+ }
+ .ghp-card, .ghp-content, .ghp-iconTextComponent, .ghp-contentFrame, .hcfe
+ {
+ background-color: var(--second-background) !important;
+ border-color: var(--hover-background) !important;
+ }
+ .ghp-iconTextComponent:hover .ghp-iconTextComponent-label,
+ .ghp-iconTextComponent:hover .ghp-separator
+ {
+ color: var(--main-color) !important;
+ border-color: var(--hover-background) !important;
+ }
+ .ghp-separator
+ {
+ border-color: var(--hover-background) !important;
+ }
+ .ghp-iconTextComponent-label, .hcfe
+ {
+ color: var(--dimmer-text) !important;
+ }
+ */
+
+/*Trending page*/
+ytd-destination-button-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+#destination-label.ytd-destination-button-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-destination-button-renderer:hover #destination-label.ytd-destination-button-renderer {
+ color: var(--main-color) !important;
+}
+
+/*more - shown on low width*/
+ytd-destination-shelf-renderer[is-show-more-visible] #show-more-button.ytd-destination-shelf-renderer,
+#show-more-button.ytd-destination-shelf-renderer {
+ background: var(--hover-background) !important;
+}
+
+#show-more-button-icon.ytd-destination-shelf-renderer {
+ color: var(--main-text) !important;
+}
+
+ytd-destination-shelf-renderer[is-show-more-visible] #show-more-button.ytd-destination-shelf-renderer:hover #show-more-button-icon.ytd-destination-shelf-renderer {
+ color: var(--main-color) !important;
+}
+
+/*Learning*/
+ytd-carousel-header-renderer {
+ background: var(--main-background) !important;
+}
+
+/*Music*/
+.flex-container.ytd-compact-station-renderer {
+ background-color: var(--second-background) !important;
+}
+
+h3.ytd-compact-station-renderer {
+ color: var(--main-text) !important;
+}
+
+.flex-container.ytd-compact-station-renderer:hover h3.ytd-compact-station-renderer {
+ color: var(--main-color) !important;
+}
+
+#video-count-text.ytd-compact-station-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Gaming*/
+#live-viewers-count.ytd-game-details-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*History*/
+.page-header-view-model-wiz__page-header-title {
+ color: var(--main-text) !important;
+}
+
+#channel-header.ytd-tabbed-page-header {
+ --yt-lightsource-section1-color: var(--main-background);
+}
+
+#channel-header.ytd-tabbed-page-header h1 {
+ color: var(--main-text) !important;
+}
+
+yt-formatted-string.ytd-sub-feed-option-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#title.ytd-sub-feed-selector-renderer,
+ytd-sub-feed-option-renderer.ytd-sub-feed-selector-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+ytd-two-column-browse-results-renderer #secondary.ytd-two-column-browse-results-renderer {
+ background-color: var(--second-background) !important;
+}
+
+ytd-two-column-browse-results-renderer #primary ytd-text-header-renderer {
+ color: var(--main-text) !important;
+}
+
+/*dialog confirm*/
+yt-confirm-dialog-renderer[dialog][dialog][dialog] {
+ background-color: var(--second-background) !important;
+}
+
+#scroller.yt-confirm-dialog-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#cancel-button.yt-confirm-dialog-renderer {
+ color: var(--main-text) !important;
+}
+
+.buttons.yt-confirm-dialog-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+/*Premium*/
+/*video*/
+#main-title.ytd-unlimited-offer-module-renderer {
+ color: var(--main-text) !important;
+}
+
+#sub-title.ytd-unlimited-offer-module-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*popup*/
+.ytd-mealbar-promo-renderer-message-title.ytd-mealbar-promo-renderer {
+ color: var(--main-text) !important;
+}
+
+.ytd-mealbar-promo-renderer-message-text.ytd-mealbar-promo-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+.button-container.ytd-mealbar-promo-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+ytd-grid-video-renderer[is-dismissed] #dismissed {
+ border-color: var(--hover-background) !important;
+}
+
+ytd-grid-video-renderer[is-dismissed] #dismissed .ytd-notification-multi-action-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+ytd-dismissal-follow-up-renderer[dialog][dialog][dialog] {
+ background: var(--main-background) !important;
+}
+
+#content.ytd-dismissal-follow-up-renderer #checkboxLabel.paper-checkbox,
+#content.ytd-dismissal-follow-up-renderer #label.ytd-dismissal-reason-video-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+#buttons.ytd-dismissal-follow-up-renderer {
+ border-top-color: var(--hover-background) !important;
+}
+
+/*New TOS*/
+yt-alert-with-actions-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+#text.yt-alert-with-actions-renderer,
+#alert-message.yt-alert-with-actions-renderer {
+ color: var(--main-text) !important;
+}
+
+yt-button-renderer yt-formatted-string.yt-button-renderer,
+#icon.yt-alert-with-actions-renderer {
+ color: var(--main-color) !important;
+}
+
+/*actual page for TOS*/
+#yts-article #article-container.ytg-box #summary {
+ background-color: var(--hover-background) !important;
+}
+
+.separator,
+.with-divider,
+.header,
+#yts-article #header,
+#yts-nav {
+ border-color: var(--hover-background) !important;
+}
+
+#yts-nav .indented .sub-level a,
+#yts-nav .top-level a,
+#yts-article #header {
+ color: var(--main-text) !important;
+}
+
+/*Premium page (https://www.youtube.com/premium)*/
+yt-button-renderer#manage-subscription-button yt-formatted-string.yt-button-renderer {
+ color: inherit !important;
+}
+
+.yt-unlimited-page-header-renderer a.yt-simple-endpoint.yt-formatted-string {
+ color: var(--main-color) !important;
+}
+
+#header.yt-music-pass-small-feature-info-renderer,
+.question.yt-generic-faq-question-renderer,
+.answer-arrow.yt-generic-faq-question-renderer {
+ color: var(--main-text) !important;
+}
+
+#description.yt-music-pass-small-feature-info-renderer,
+.container.yt-faq-section-renderer,
+.answer.yt-generic-faq-question-renderer,
+.text.ytd-simple-text-section-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+yt-generic-faq-question-renderer .yt-simple-endpoint.style-scope.yt-formatted-string,
+yt-generic-faq-question-renderer a.yt-simple-endpoint.yt-formatted-string:only-of-type,
+.text.ytd-simple-text-section-renderer a.yt-simple-endpoint.yt-formatted-string:only-of-type {
+ color: var(--main-color) !important;
+}
+
+/*Paid memberships*/
+paper-card.yt-subscription-product-upsell-offer-renderer {
+ background-color: var(--second-background) !important;
+}
+
+#title.yt-subscription-product-upsell-offer-renderer,
+#description.yt-subscription-product-upsell-offer-renderer,
+#additional-info.yt-subscription-product-upsell-offer-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Gaming page (https://www.youtube.com/gaming) and gaming channels*/
+#channel-details.ytd-carousel-header-renderer,
+#channel-header-container.ytd-topic-channel-details-renderer {
+ background-color: var(--main-background) !important;
+}
+
+#bg.ytd-interactive-tabbed-header-renderer {
+ fill: var(--main-background) !important;
+}
+
+#tabs-inner-container.ytd-interactive-tabbed-header-renderer {
+ background-color: transparent !important;
+}
+
+/*Acount page specific*/
+/*Sidebar*/
+#creator-page.account-page,
+ytd-settings-sidebar-renderer {
+ background-color: var(--second-background) !important;
+}
+
+.exp-kevlar-settings .account-page #creator-sidebar h3 {
+ color: var(--main-text) !important;
+}
+
+.exp-kevlar-settings .account-page #creator-sidebar .creator-sidebar-item a {
+ color: var(--dimmer-text) !important;
+}
+
+.exp-kevlar-settings .account-page #creator-sidebar .creator-sidebar-item.selected>a,
+.exp-kevlar-settings .account-page #creator-sidebar .creator-sidebar-item.selected>a:hover,
+.exp-kevlar-settings .account-page #creator-sidebar .creator-sidebar-item:hover a {
+ background-color: var(--hover-background) !important;
+ color: var(--main-color) !important;
+}
+
+ytd-compact-link-renderer[compact-link-style="compact-link-style-type-settings-sidebar"][active],
+ytd-compact-link-renderer[compact-link-style="compact-link-style-type-settings-sidebar"][active]:hover {
+ background-color: var(--hover-background) !important;
+}
+
+/*Burger sidebar*/
+#appbar-guide-menu,
+.guide-flyout {
+ background-color: var(--second-background) !important;
+}
+
+#guide-container .guide-item {
+ color: var(--main-text) !important;
+}
+
+#guide-container .guide-item:hover {
+ background-color: var(--hover-background) !important;
+ color: var(--main-color) !important;
+}
+
+/*headers*/
+.exp-invert-logo li.guide-section h3,
+.exp-invert-logo li.guide-section h3 a {
+ color: var(--main-color) !important;
+}
+
+.guide-section-separator
+
+/*divider*/
+ {
+ border-color: var(--hover-background) !important;
+}
+
+/*Contents - account*/
+.account-page-header,
+ytd-section-list-renderer[page-subtype="account-settings"] a.yt-simple-endpoint.yt-formatted-string {
+ color: var(--main-color) !important;
+}
+
+#account-page-header-title,
+h2.account-section-header {
+ color: var(--main-text) !important;
+}
+
+/*title of the page*/
+#name.ytd-page-introduction-renderer,
+#name.ytd-channel-options-renderer,
+ytd-settings-options-renderer .yt-formatted-string:not(a).bold {
+ color: var(--main-text) !important;
+}
+
+.exp-kevlar-settings #account-page-header-subtitle,
+.account-info-item .account-info-label,
+.account-section .account-email,
+.account-content,
+.account-section-subtext {
+ color: var(--dimmer-text) !important;
+}
+
+/*other text*/
+#text.ytd-page-introduction-renderer,
+/*email*/
+#text.ytd-settings-options-renderer,
+/*descriptions, metadata, below text*/
+#label.ytd-settings-checkbox-renderer,
+#label.ytd-settings-radio-option-renderer,
+/*playback*/
+#text.ytd-connected-app-renderer
+
+/*connected accounts*/
+ {
+ color: var(--dimmer-text) !important;
+}
+
+.yt-horizontal-rule
+
+/*divider*/
+ {
+ border-color: var(--hover-background) !important;
+}
+
+.account-info .account-photo .yt-thumb
+
+/*avatar*/
+ {
+ border-radius: 100%;
+}
+
+.account-content a,
+.account-header a
+
+/*various links*/
+ {
+ color: var(--main-color) !important;
+}
+
+.yt-thumb {
+ background-color: var(--hover-background) !important;
+}
+
+/*Notifications*/
+.setting-reminder,
+h3.account-section-header {
+ color: var(--main-text) !important;
+}
+
+.yt-uix-form-input-checkbox-container input:checked+.yt-uix-form-input-checkbox-element {
+ border-color: #000;
+ filter: invert(1);
+}
+
+.desktop-notifications .browser {
+ background-color: var(--hover-background) !important;
+ color: var(--main-color) !important;
+ border-color: var(--hover-background) !important;
+}
+
+.desktop-notifications .browser .yt-uix-button.turn-on,
+.desktop-notifications .browser .yt-uix-button.turn-off,
+.resume-setting-button,
+.undo-setting-button-section,
+.resume-all-settings-button
+
+/*turn off*/
+ {
+ background: var(--main-background) !important;
+ border-color: var(--main-background) !important;
+ color: var(--main-color) !important;
+}
+
+.yt-uix-form-input-select
+
+/*dropdowns*/
+ {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*checkboxes*/
+tp-yt-paper-toggle-button[checked]:not([disabled]) .toggle-bar.tp-yt-paper-toggle-button {
+ background-color: var(--main-color) !important;
+ opacity: 1 !important;
+}
+
+tp-yt-paper-toggle-button[checked]:not([disabled]) .toggle-button.tp-yt-paper-toggle-button {
+ background-color: var(--main-text) !important;
+}
+
+/*language*/
+ytd-dropdown-renderer[has-background] tp-yt-paper-dropdown-menu-light.ytd-dropdown-renderer {
+ background-color: var(--hover-background) !important;
+}
+
+label.label-is-floating.tp-yt-paper-dropdown-menu-light,
+#label.ytd-dropdown-item-renderer {
+ color: var(--main-text) !important;
+}
+
+#input.tp-yt-paper-dropdown-menu-light {
+ color: var(--dimmer-text) !important;
+}
+
+/*Playback*/
+.yt-help-icon {
+ filter: invert(1);
+}
+
+.yt-uix-clickcard-card-content,
+.yt-uix-hovercard-card-content {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+.yt-uix-clickcard-card-border,
+.yt-uix-hovercard-card-border {
+ border-color: var(--hover-background) !important;
+}
+
+.yt-uix-clickcard-card-flip .yt-uix-card-body-arrow-horizontal,
+.yt-uix-hovercard-card-flip .yt-uix-card-body-arrow-horizontal {
+ border-right-color: var(--hover-background) !important;
+}
+
+.exp-kevlar-settings .account-page .yt-uix-button
+
+/*save buttons*/
+ {
+ background: var(--main-color) !important;
+ border-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+ opacity: .9;
+}
+
+.exp-kevlar-settings .account-page .yt-uix-button:hover {
+ opacity: 1 !important;
+}
+
+/*Social*/
+.social-connector {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*TV*/
+.howto-circle {
+ background-color: var(--hover-background) !important;
+ color: var(--main-color) !important;
+}
+
+.howto-text {
+ color: var(--dimmer-text) !important;
+}
+
+.remote-icon {
+ filter: invert(1) brightness(200%);
+}
+
+h3.pairing-section-header {
+ color: var(--main-text)
+}
+
+.yt-uix-form-input-select,
+.yt-uix-form-input-text,
+.yt-uix-form-input-textarea {
+ border-color: var(--hover-background) !important;
+}
+
+#account-page-header-avatar.howto-promo-image {
+ filter: invert(1) grayscale(1);
+}
+
+/*TV code*/
+.yt-uix-form-input-select,
+.yt-uix-form-input-text,
+.yt-uix-form-input-textarea {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+/*Footer*/
+body #footer-container {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+ color: var(--main-text) !important;
+}
+
+#footer-main
+
+/*divider*/
+ {
+ border-color: var(--hover-background) !important;
+}
+
+/*links*/
+#footer-links-primary a {
+ color: var(--main-text) !important;
+}
+
+#footer-links-secondary a {
+ color: var(--dimmer-text) !important;
+}
+
+#footer-links-primary a:hover,
+#footer-links-secondary a:hover {
+ color: var(--main-color) !important;
+}
+
+/*buttons*/
+#footer .yt-uix-button-group .yt-uix-button,
+#footer .pickers li,
+#footer .footer-history,
+#footer #google-help {
+ background: var(--second-background) !important;
+ border-color: var(--second-background) !important;
+ color: var(--main-text) !important;
+ box-shadow: none !important;
+}
+
+.yt-uix-button-default.yt-uix-button-toggled:hover {
+ box-shadow: none !important;
+}
+
+#footer .yt-uix-button-icon-footer-language,
+#footer .yt-uix-button-icon-footer-history,
+#footer .yt-uix-button-icon-questionmark {
+ filter: invert(1);
+}
+
+.yt-uix-button-arrow {
+ border-top-color: var(--main-text) !important;
+}
+
+#yt-picker-country-footer,
+#yt-picker-language-footer,
+#yt-picker-safetymode-footer {
+ background: var(--second-background) !important;
+ border-color: var(--second-background) !important;
+ color: var(--main-text) !important;
+}
+
+.yt-picker-header,
+#safety-form p.safety-submit
+
+/*divider*/
+ {
+ border-color: var(--hover-background) !important;
+}
+
+.yt-picker-header h3.yt,
+.yt-picker-content strong {
+ color: var(--main-text) !important;
+}
+
+#yt-picker-country-footer .yt-default .yt-notes,
+p.yt-notes,
+#safety-mode-description li {
+ color: var(--dimmer-text) !important;
+}
+
+#yt-picker-country-footer .yt-picker-content a,
+.yt-picker-content button {
+ color: var(--main-color) !important;
+}
+
+#yt-picker-safetymode-footer button
+
+/*save*/
+ {
+ background: var(--main-color) !important;
+ border-color: var(--main-color) !important;
+ color: var(--main-text) !important;
+ opacity: .9;
+}
+
+/*Notification buttom corner - for settings, watch later etc*/
+tp-yt-paper-toast {
+ background: var(--hover-background) !important;
+ color: var(--main-text) !important;
+ box-shadow: var(--shadow) !important;
+}
+
+/*Topic auto-generated by youtube*/
+#auto-generated.ytd-interactive-tabbed-header-renderer,
+#metadata.ytd-interactive-tabbed-header-renderer {
+ color: var(--dimmer-text) !important;
+}
+
+/*Keyboard shortcuts Shift-/ */
+ytd-hotkey-dialog-renderer[dialog][dialog][dialog] {
+ background-color: var(--main-background) !important;
+}
+
+ytd-hotkey-dialog-section-option-renderer {
+ border-color: var(--hover-background) !important;
+}
+
+
+/*SponsorBlock*/
+/*logo change*/
+#sponsorBlockPopupLogo,
+.sponsorSkipLogo {
+ display: block !important;
+ -moz-box-sizing: border-box !important;
+ box-sizing: border-box !important;
+ background: url(https://raw.githubusercontent.com/RaitaroH/YouTube-DeepDark/master/YT_Images/IconSponsorBlocker256px.png) top left no-repeat !important;
+ background-size: 100% !important;
+ position: relative !important;
+}
+
+#sponsorBlockPopupLogo {
+ width: 40px !important;
+ height: 40px !important;
+ padding-left: 40px !important;
+}
+
+/*for overlays*/
+.sponsorSkipLogo {
+ width: 18px !important;
+ height: 18px !important;
+ padding-left: 18px !important;
+}
+
+.sponsorBlockTooltip {
+ background-color: var(--hover-background) !important;
+}
+
+/*Are you sure you want to leave YouTube? redirect*/
+/*seems like youtube will never update this page so, yeah*/
+#invalid-token-redirect-warning-text
+
+/*h1*/
+ {
+ color: var(--main-text) !important;
+}
+
+/*span*/
+#redirect-main-text {
+ color: var(--dimmer-text) !important;
+}
+
+#redirect-main-text .bolded {
+ color: var(--main-color);
+}
+
+/*search*/
+#masthead-search-terms-border {
+ border-color: var(--hover-background) !important;
+ background-color: var(--hover-background) !important;
+ box-shadow: var(--shadow) !important;
+}
+
+#masthead-search-terms {
+ color: var(--main-text);
+}
+
+.search-button {
+ background: var(--hover-background) !important;
+ border-color: var(--hover-background) !important;
+}
+
+/*🔍 is missing, nice*/
+.search-button-content {
+ background: no-repeat url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNy4zOTE3IDE2LjgwODNMMTIuNzMzMyAxMi4xNUMxMy42MjUgMTEuMTI1IDE0LjE2NjcgOS43OTE2NyAxNC4xNjY3IDguMzMzMzNDMTQuMTY2NyA1LjEwODMzIDExLjU1ODMgMi41IDguMzMzMzMgMi41QzUuMTA4MzMgMi41IDIuNSA1LjEwODMzIDIuNSA4LjMzMzMzQzIuNSAxMS41NTgzIDUuMTA4MzMgMTQuMTY2NyA4LjMzMzMzIDE0LjE2NjdDOS43OTE2NyAxNC4xNjY3IDExLjEyNSAxMy42MjUgMTIuMTUgMTIuNzQxN0wxNi44MDgzIDE3LjRMMTcuMzkxNyAxNi44MDgzWk04LjMzMzMzIDEzLjMzMzNDNS41NzUgMTMuMzMzMyAzLjMzMzMzIDExLjA5MTcgMy4zMzMzMyA4LjMzMzMzQzMuMzMzMzMgNS41NzUgNS41NzUgMy4zMzMzMyA4LjMzMzMzIDMuMzMzMzNDMTEuMDkxNyAzLjMzMzMzIDEzLjMzMzMgNS41NzUgMTMuMzMzMyA4LjMzMzMzQzEzLjMzMzMgMTEuMDkxNyAxMS4wOTE3IDEzLjMzMzMgOC4zMzMzMyAxMy4zMzMzWiIgZmlsbD0iIzAzMDMwMyIvPjwvc3ZnPg==") !important;
+ filter: invert(1);
+}
+
+#redirect-backto-safety-button:hover {
+ color: var(--main-text) !important;
+}
+
+/*logo icon is also missing, but this __should__ change in the future*/
+.logo {
+ background: no-repeat url("https://raw.githubusercontent.com/RaitaroH/YouTube-DeepDark/master/YT_Images/Logo.png") !important;
+ background-size: 70% !important;
+ padding: 10px;
+ width: 120px !important;
+ height: 33px !important;
+ box-sizing: border-box !important;
+ position: relative;
+ right: -30px;
+}
+
+#logo-container .content-region {
+ color: var(--main-text) !important;
+}`;
diff --git a/src/deepDarkPresets.ts b/src/deepDarkPresets.ts
new file mode 100644
index 00000000..cf9daff5
--- /dev/null
+++ b/src/deepDarkPresets.ts
@@ -0,0 +1,349 @@
+/**
+ * Theme presets are adapted from the "YouTube DeepDark" Stylus theme by RaitaroH.
+ * Author: https://github.com/RaitaroH
+ * Co-authors: https://github.com/MechaLynx
+ * Repository: https://github.com/RaitaroH/YouTube-DeepDark
+ */
+export const deepDarkPreset = [
+ "9anime",
+ "Adapta-Breath-Nokto",
+ "Adapta-Nokto",
+ "Arc-Dark",
+ "Black-and-White",
+ "Breeze-Dark",
+ "Custom",
+ "Deep-Dark",
+ "Discord",
+ "Dracula",
+ "Firefox-57",
+ "Firefox-Alpenglow-Dark",
+ "Firefox-Dark",
+ "Firefox-Dark-91",
+ "Gruvbox-Dark",
+ "Gruvbox-Light",
+ "HavocOS",
+ "Inspired-Dark",
+ "Jisho",
+ "Mint-Y-Dark",
+ "NierAutomata-Dark",
+ "NierAutomata-Light",
+ "Orange",
+ "Solarized-Dark",
+ "Solarized-Light",
+ "Ubuntu-Grey",
+ "Ubuntu-Purple",
+ "Vertex-Dark",
+ "Yellow",
+ "Yellow-2",
+ "YouTube-Dark"
+] as const;
+export type DeepDarkPreset = (typeof deepDarkPreset)[number];
+export type DeepDarkPresets = Record
, string>;
+/**
+ * Theme presets are adapted from the "YouTube DeepDark" Stylus theme by RaitaroH.
+ * Author: RaitaroH
+ * Co-authors: https://github.com/MechaLynx
+ * Repository: https://github.com/RaitaroH/YouTube-DeepDark
+ */
+export const deepDarkPresets = {
+ "9anime": `
+ :root {
+ --main-color: #723f8c;
+ --main-background: #0b0a0d;
+ --second-background: #17151c;
+ --hover-background: #1E1c25;
+ --main-text: #f9f6fb;
+ --dimmer-text: #cac0cf;
+ --shadow: 0 1px 0.5px rgba(54, 54, 54, .13);
+ }`,
+ "Adapta-Breath-Nokto": `
+ :root {
+ --main-color: #1abc9c;
+ --main-background: #222d32;
+ --second-background: #263238;
+ --hover-background: #2a353b;
+ --main-text: #fff;
+ --dimmer-text: #9b9b9b;
+ --shadow: 0 1px 0.5px rgba(42, 53, 59, .32);
+ }`,
+ "Adapta-Nokto": `
+ :root {
+ --main-color: #00bcd4;
+ --main-background: #222d32;
+ --second-background: #263238;
+ --hover-background: #2a353b;
+ --main-text: #fff;
+ --dimmer-text: #9b9b9b;
+ --shadow: 0 1px 0.5px rgba(61, 77, 86, .2);
+ }`,
+ "Arc-Dark": `
+ :root {
+ --main-color: #5294e2;
+ --main-background: #343944;
+ --second-background: #383c4a;
+ --hover-background: #414a59;
+ --main-text: #c1c8d1;
+ --dimmer-text: #b3bac5;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .13);
+ }`,
+ "Black-and-White": `
+ :root {
+ --main-color: #fff;
+ --main-background: #000;
+ --second-background: #1e1e1e;
+ --hover-background: #313131;
+ --main-text: #fff;
+ --dimmer-text: #aaa;
+ --shadow: 0 1px 0.5px rgba(54 ,54 ,54, .2);
+ }`,
+ "Breeze-Dark": `
+ :root {
+ --main-color: #3daee9;
+ --main-background: #232629;
+ --second-background: #2a2e32;
+ --hover-background: #31363b;
+ --main-text: #eff0f1;
+ --dimmer-text: #bdc3c7;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .13);
+ }`,
+ "Deep-Dark": `
+ :root {
+ --main-color: #00adee;
+ --main-background: #111;
+ --second-background: #181818;
+ --hover-background: #232323;
+ --main-text: #eff0f1;
+ --dimmer-text: #ccc;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .3);
+ }`,
+ Discord: `
+ :root {
+ --main-color: #7289da;
+ --main-background: #1e2124;
+ --second-background: #2f3136;
+ --hover-background: #484b51;
+ --main-text: #fff;
+ --dimmer-text: #ada8aa;
+ --shadow: 0 1px 0.5px rgba(47, 49, 54, .23);
+ }`,
+ Dracula: `
+ :root {
+ --main-color: #bd93f9; /*Purple*/
+ --main-background: hsl(231, 15%, 18%); /*Background*/
+ --second-background: hsl(231, 15%, 22%); /*Manually generated from Background*/
+ --hover-background: #44475a; /*Selection*/
+ --main-text:#f8f8f2; /*Foreground*/
+ --dimmer-text: #bcc2cd; /*From .app-title https://draculatheme.com/*/
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .15);
+ }`,
+ "Firefox-57": `
+ :root {
+ --main-color: #4080fb;
+ --main-background: #0c0c0d;
+ --second-background: #252526;
+ --hover-background: #323234;
+ --main-text: #f9f9fa;
+ --dimmer-text: #d0d0d0;
+ --shadow: 0 1px 0.5px rgba(54, 54, 54, .2);
+ }`,
+ "Firefox-Alpenglow-Dark": `
+ :root {
+ --main-color: #C488FC;
+ --main-background: #21133d;
+ --second-background: #2a1e52;
+ --hover-background: #2d245b;
+ --main-text: #ffffff;
+ --dimmer-text: #E3DBFA;
+ --shadow: 0 1px .5px rgba(35, 22, 65, .5);
+ }`,
+ "Firefox-Dark": `
+ :root {
+ --main-color: #5675b9;
+ --main-background: #272b35;
+ --second-background: #181d20;
+ --hover-background: #353a44;
+ --main-text: #e3eef9;
+ --dimmer-text: #bec0cc;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .13);
+ }`,
+ "Firefox-Dark-91": `
+ :root {
+ --main-color: #00ddff;
+ --main-background: #1c1b22;
+ --second-background: #23222b;
+ --hover-background: #2b2a33;
+ --main-text: #fbfbfe;
+ --dimmer-text: #b8b7bb;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .13);
+ }`,
+ "Gruvbox-Dark": `
+ :root {
+ --main-color: #fe8019;
+ --main-background: #1d2021;
+ --second-background: #282828;
+ --hover-background: #3c3836;
+ --main-text: #fbf1c7;
+ --dimmer-text: #ebdbb2;
+ --shadow: 0 1px 0.5px rgba(60, 56, 54, .22);
+ }`,
+ "Gruvbox-Light": `
+ :root {
+ --main-color: #af3a03;
+ --main-background: #f9f5d7;
+ --second-background: #fbf1c7;
+ --hover-background: #ebdbb2;
+ --main-text: #282828;
+ --dimmer-text: #3c3836;
+ --shadow: 0 1px 0.5px rgba(235, 219, 178, .33);
+ }`,
+ HavocOS: `
+ :root {
+ --main-color: #0794d4;
+ --main-background: #141618;
+ --second-background: #1c1e20;
+ --hover-background: #212528;
+ --main-text: #fff;
+ --dimmer-text: #b9baba;
+ --shadow: 0 1px 0.5px rgba(185, 186, 186, .04);
+ }`,
+ "Inspired-Dark": `
+ :root {
+ --main-color: #5e8acc;
+ --main-background: #232629;
+ --second-background: #181818;
+ --hover-background: #515254;
+ --main-text: #eee;
+ --dimmer-text: #ccc;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .13);
+ }`,
+ Jisho: `
+ :root {
+ --main-color: #ef7d6c;
+ --main-background: #332222;
+ --second-background: #2a1b1b;
+ --hover-background: #863b2f;
+ --main-text: #EFB26C;
+ --dimmer-text: #986E3F;
+ --shadow: 0 1px 0.5px rgba(37, 19, 5, .19);
+ }`,
+ "Mint-Y-Dark": `
+ :root {
+ --main-color: #9ab87c;
+ --main-background: #2f2f2f;
+ --second-background: #383838;
+ --hover-background: #404040;
+ --main-text: #fff;
+ --dimmer-text: #d5dada;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .13);
+ }`,
+ "NierAutomata-Dark": `
+ :root {
+ --main-color: #fe8019;
+ --main-background: #33302a;
+ --second-background: #48453c;
+ --hover-background: #7c6f64;
+ --main-text: #dad4bb;
+ --dimmer-text: #bab5a1;
+ --shadow: 0 1px 0.5px rgba(124, 111, 100, .15);
+ }`,
+ "NierAutomata-Light": `
+ :root {
+ --main-color: #fe8019;
+ --main-background: #d1cdb7;
+ --second-background: #dcd8c0;
+ --hover-background: #bab5a1;
+ --main-text: #48453c;
+ --dimmer-text: #33302a;
+ --shadow: 0 1px 0.5px rgba(186, 181, 161, 2);
+ }`,
+ Orange: `
+ :root {
+ --main-color: #ff6905;
+ --main-background: #0a0400;
+ --second-background: #0e0702;
+ --hover-background: #110903;
+ --main-text: #fff9f5;
+ --dimmer-text: #ffede1;
+ --shadow: 0 1px 0.5px rgba(255, 105, 5, .1);
+ }`,
+ "Solarized-Dark": `
+ :root {
+ --main-color: #268bd2;
+ --main-background: #073642;
+ --second-background: #03303c;
+ --hover-background: #002b36;
+ --main-text: #fdf6E3;
+ --dimmer-text: #eee8d5;
+ --shadow: 0 1px 0.5px rgba(0, 43, 54, .3);
+ }`,
+ "Solarized-Light": `
+ :root {
+ --main-color: #268bd2;
+ --main-background: #fdf6e3;
+ --second-background: #f5efdc;
+ --hover-background: #eee8d5;
+ --main-text: #073642;
+ --dimmer-text: #586e75;
+ --shadow: 0 1px 0.5px rgba(222, 216, 196, .2);
+ }`,
+ "Ubuntu-Grey": `
+ :root {
+ --main-color: #ef7847;
+ --main-background: #312d2a;
+ --second-background: #3d3c38;
+ --hover-background: #59564d;
+ --main-text: #f2f1ef;
+ --dimmer-text: #e6e5e3;
+ --shadow: 0 1px 0.5px rgba(89, 86, 77, .12);
+ }`,
+ "Ubuntu-Purple": `
+ :root {
+ --main-color: #ef7847;
+ --main-background: #2c071a;
+ --second-background: #430b28;
+ --hover-background: #520D30;
+ --main-text: #f2f1ef;
+ --dimmer-text: #e6e5e3;
+ --shadow: 0 1px 0.5px rgba(82, 13, 48, .2);
+ }`,
+ "Vertex-Dark": `
+ :root {
+ --main-color: #4080fb;
+ --main-background: #2b2b2c;
+ --second-background: #353638;
+ --hover-background: #515254;
+ --main-text: #f3f3f5;
+ --dimmer-text: #aeafb0;
+ --shadow: 0 1px 0.5px rgba(0, 0, 0, .13);
+ }`,
+ Yellow: `
+ :root {
+ --main-color: #ffc700;
+ --main-background: #141414;
+ --second-background: #202222;
+ --hover-background: #353838;
+ --main-text: #eff0f1;
+ --dimmer-text: #9f9999;
+ --shadow: 0 1px 0.5px rgba(34, 34, 34, .2);
+ }`,
+ "Yellow-2": `
+ :root {
+ --main-color: #ffc700;
+ --main-background: #0a0800;
+ --second-background: #0c0a04;
+ --hover-background: #0f0d05;
+ --main-text: #fffdf5;
+ --dimmer-text: #fff8e1;
+ --shadow: 0 1px 0.5px rgba(34, 34, 34, .2);
+ }`,
+ "YouTube-Dark": `
+ :root {
+ --main-color: #e52117;
+ --main-background: #111;
+ --second-background: #232323;
+ --hover-background: #343434;
+ --main-text: #e1e1e1;
+ --dimmer-text: #7f7f7f;
+ --shadow: 0 1px 0.5px rgba(54, 54, 54, .2);
+ }`
+} as const satisfies DeepDarkPresets;
diff --git a/src/defaults.ts b/src/defaults.ts
index af235a85..26a11801 100644
--- a/src/defaults.ts
+++ b/src/defaults.ts
@@ -1,17 +1,45 @@
-import type { configuration } from "./types";
+import { deepMerge } from "@/src/utils/utilities";
import { defaultConfiguration } from "./utils/constants";
-Object.keys(defaultConfiguration).forEach((option) => {
- // If the option was not previously stored in localStorage
- if (localStorage[option] === undefined) {
- // then set it to the default value
+function setDefaultValues() {
+ // Iterate over each option in the default configuration
+ for (const option of Object.keys(defaultConfiguration)) {
+ // Get the stored value from local storage
+ const storedValueString = localStorage.getItem(option);
+ // Destructure the default value for the current option
const { [option]: defaultValue } = defaultConfiguration;
- localStorage[option] = typeof defaultValue === "string" ? defaultValue : JSON.stringify(defaultValue);
-
- // and also set it in the Chrome Storage API.
- void chrome.storage.local.set({
- [option]: localStorage[option] as configuration[typeof option]
- });
+ // Check if the stored value is missing or an empty string
+ if (storedValueString === null) {
+ // Set the default value in localStorage after stringifying
+ localStorage.setItem(option, typeof defaultValue === "string" ? defaultValue : JSON.stringify(defaultValue));
+ // Set the default value in chrome storage
+ void chrome.storage.local.set({ [option]: defaultValue });
+ } else {
+ try {
+ // Parse the stored value to check its type
+ const storedValue =
+ (
+ typeof defaultConfiguration[option] === "object" ||
+ typeof defaultConfiguration[option] === "boolean" ||
+ typeof defaultConfiguration[option] === "number"
+ ) ?
+ JSON.parse(storedValueString)
+ : storedValueString;
+ // Check if the parsed value is an object and has properties
+ if (typeof storedValue === "object" && storedValue !== null) {
+ // Deep merge missing keys with their default values
+ const updatedValue = deepMerge(defaultValue as Record, storedValue as Record);
+ // Set the updated value in localStorage
+ localStorage.setItem(option, JSON.stringify(updatedValue));
+ // Set the updated value in chrome storage
+ void chrome.storage.local.set({ [option]: updatedValue });
+ }
+ } catch (error) {
+ // Handle errors during JSON parsing
+ console.error(`Error parsing stored value for option ${option}:`, error);
+ }
+ }
}
-});
+}
+setDefaultValues();
diff --git a/src/features/buttonPlacement/index.ts b/src/features/buttonPlacement/index.ts
index dbfaefe1..d093cfee 100644
--- a/src/features/buttonPlacement/index.ts
+++ b/src/features/buttonPlacement/index.ts
@@ -1,57 +1,60 @@
import type { GetIconType } from "@/src/icons";
-import type { ButtonPlacement, FeaturesThatHaveButtons } from "@/src/types";
+import type { AllButtonNames, ButtonPlacement, MultiButtonNames, SingleButtonFeatureNames } from "@/src/types";
import { addFeatureItemToMenu, removeFeatureItemFromMenu } from "@/src/features/featureMenu/utils";
-import { removeTooltip, waitForSpecificMessage } from "@/src/utils/utilities";
+import { findKeyByValue, removeTooltip, waitForSpecificMessage } from "@/src/utils/utilities";
import { type ListenerType, getFeatureButtonId, makeFeatureButton, placeButton } from "./utils";
-export const featuresInControls = new Set();
+export const featuresInControls = new Set();
-export async function addFeatureButton<
- Name extends FeaturesThatHaveButtons,
- Placement extends ButtonPlacement,
- Label extends string,
- Toggle extends boolean
->(featureName: Name, placement: Placement, label: Label, icon: GetIconType, listener: ListenerType, isToggle: boolean) {
+export async function addFeatureButton(
+ buttonName: Name,
+ placement: Placement,
+ label: Label,
+ icon: GetIconType,
+ listener: ListenerType,
+ isToggle: boolean
+) {
switch (placement) {
case "feature_menu": {
- if (icon instanceof SVGSVGElement) await addFeatureItemToMenu(featureName, label, icon, listener, isToggle);
+ if (icon instanceof SVGSVGElement) await addFeatureItemToMenu(buttonName, label, icon, listener, isToggle);
break;
}
case "below_player":
case "player_controls_left":
case "player_controls_right": {
// Add the feature name to the set of features in the controls
- featuresInControls.add(featureName);
- const button = makeFeatureButton(featureName, placement, label, icon, listener, isToggle);
+ featuresInControls.add(buttonName);
+ const button = makeFeatureButton(buttonName, placement, label, icon, listener, isToggle);
placeButton(button, placement);
break;
}
}
}
-export async function removeFeatureButton(featureName: Name, placement?: ButtonPlacement) {
+export async function removeFeatureButton(buttonName: Name, placement?: ButtonPlacement) {
+ const featureName = findKeyByValue(buttonName as MultiButtonNames) ?? (buttonName as SingleButtonFeatureNames);
if (placement === undefined) {
// Wait for the "options" message from the content script
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
({
data: {
options: {
- button_placements: { [featureName]: placement }
+ button_placements: { [buttonName]: placement }
}
}
} = optionsData);
}
switch (placement) {
case "feature_menu": {
- removeFeatureItemFromMenu(featureName);
+ removeFeatureItemFromMenu(buttonName);
break;
}
case "below_player":
case "player_controls_left":
case "player_controls_right": {
// Remove the feature name from the set of features in the controls
- featuresInControls.delete(featureName);
- const button = document.querySelector(`#${getFeatureButtonId(featureName)}`);
+ featuresInControls.delete(buttonName);
+ const button = document.querySelector(`#${getFeatureButtonId(buttonName)}`);
if (!button) return;
button.remove();
removeTooltip(`yte-feature-${featureName}-tooltip`);
diff --git a/src/features/buttonPlacement/utils.ts b/src/features/buttonPlacement/utils.ts
index 4d312be9..0e7bb3a4 100644
--- a/src/features/buttonPlacement/utils.ts
+++ b/src/features/buttonPlacement/utils.ts
@@ -1,12 +1,12 @@
import { getFeatureIds, getFeatureMenuItem } from "@/src/features/featureMenu/utils";
import { type GetIconType } from "@/src/icons";
-import { type ButtonPlacement, type FeaturesThatHaveButtons } from "@/src/types";
+import { type AllButtonNames, type ButtonPlacement, type MultiButtonNames, type SingleButtonFeatureNames } from "@/src/types";
import eventManager from "@/src/utils/EventManager";
-import { createStyledElement, createTooltip } from "@/src/utils/utilities";
+import { createStyledElement, createTooltip, findKeyByValue } from "@/src/utils/utilities";
export type ListenerType = Toggle extends true ? (checked?: boolean) => void : () => void;
-function buttonClickListener(
+function buttonClickListener(
button: HTMLButtonElement,
icon: GetIconType,
listener: ListenerType,
@@ -25,19 +25,20 @@ function buttonClickListener(
- featureName: Name,
+export function makeFeatureButton(
+ buttonName: Name,
placement: Placement,
label: string,
icon: GetIconType,
listener: ListenerType,
isToggle: boolean
) {
+ const featureName = findKeyByValue(buttonName as MultiButtonNames) ?? (buttonName as SingleButtonFeatureNames);
if (placement === "feature_menu") throw new Error("Cannot make a feature button for the feature menu");
- const buttonExists = document.querySelector(`button#${getFeatureButtonId(featureName)}`) !== null;
+ const buttonExists = document.querySelector(`button#${getFeatureButtonId(buttonName)}`) !== null;
const button = createStyledElement({
classlist: ["ytp-button"],
- elementId: `${getFeatureButtonId(featureName)}`,
+ elementId: `${getFeatureButtonId(buttonName)}`,
elementType: "button",
styles: {
alignContent: "center",
@@ -46,10 +47,12 @@ export function makeFeatureButton(`#${getFeatureButtonId(featureName)}`);
+export function updateFeatureButtonTitle(buttonName: AllButtonNames, title: string) {
+ const button = document.querySelector(`#${getFeatureButtonId(buttonName)}`);
if (!button) return;
button.dataset.title = title;
}
@@ -142,34 +145,34 @@ export function placeButton(button: HTMLButtonElement, placement: Exclude(`#${buttonContainerId}`);
if (!buttonContainer) return false;
- return buttonContainer.querySelector(`#${getFeatureButtonId(featureName)}`) !== null;
+ return buttonContainer.querySelector(`#${getFeatureButtonId(buttonName)}`) !== null;
}
case "player_controls_left": {
const leftControls = document.querySelector(".ytp-left-controls");
if (!leftControls) return false;
- return leftControls.querySelector(`#${getFeatureButtonId(featureName)}`) !== null;
+ return leftControls.querySelector(`#${getFeatureButtonId(buttonName)}`) !== null;
}
case "player_controls_right": {
const rightControls = document.querySelector(".ytp-right-controls");
if (!rightControls) return false;
- return rightControls.querySelector(`#${getFeatureButtonId(featureName)}`) !== null;
+ return rightControls.querySelector(`#${getFeatureButtonId(buttonName)}`) !== null;
}
case "feature_menu": {
const featureMenu = document.querySelector("#yte-feature-menu");
if (!featureMenu) return false;
- return featureMenu.querySelector(`#${getFeatureIds(featureName).featureMenuItemId}`) !== null;
+ return featureMenu.querySelector(`#${getFeatureIds(buttonName).featureMenuItemId}`) !== null;
}
}
}
-export function getFeatureButtonId(featureName: FeaturesThatHaveButtons) {
- return `yte-feature-${featureName}-button` as const;
+export function getFeatureButtonId(buttonName: AllButtonNames) {
+ return `yte-feature-${buttonName}-button` as const;
}
-export function getFeatureButton(featureName: FeaturesThatHaveButtons) {
- return getFeatureMenuItem(featureName) ?? document.querySelector(`#${getFeatureButtonId(featureName)}`);
+export function getFeatureButton(buttonName: AllButtonNames) {
+ return getFeatureMenuItem(buttonName) ?? document.querySelector(`#${getFeatureButtonId(buttonName)}`);
}
export const buttonContainerId = "yte-button-container";
diff --git a/src/features/customCSS/index.ts b/src/features/customCSS/index.ts
index 54f13653..c43f1eef 100644
--- a/src/features/customCSS/index.ts
+++ b/src/features/customCSS/index.ts
@@ -1,7 +1,7 @@
import { waitForSpecificMessage } from "@/src/utils/utilities";
-import { createCustomCSSElement } from "./utils";
-
+import { createCustomCSSElement, customCSSExists, updateCustomCSS } from "./utils";
+export const customCssID = "yte-custom-css";
export async function enableCustomCSS() {
// Wait for the "options" message from the content script
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
@@ -12,6 +12,12 @@ export async function enableCustomCSS() {
} = optionsData;
// Check if custom CSS is enabled
if (!enable_custom_css) return;
+ if (customCSSExists()) {
+ updateCustomCSS({
+ custom_css_code
+ });
+ return;
+ }
// Create the custom CSS style element
const customCSSStyleElement = createCustomCSSElement({
custom_css_code
@@ -21,7 +27,7 @@ export async function enableCustomCSS() {
}
export function disableCustomCSS() {
// Get the custom CSS style element
- const customCSSStyleElement = document.querySelector("#yte-custom-css");
+ const customCSSStyleElement = document.querySelector(`#${customCssID}`);
// Check if the custom CSS style element exists
if (!customCSSStyleElement) return;
// Remove the custom CSS style element
diff --git a/src/features/customCSS/utils.ts b/src/features/customCSS/utils.ts
index 18f01aaa..a62bc45e 100644
--- a/src/features/customCSS/utils.ts
+++ b/src/features/customCSS/utils.ts
@@ -1,8 +1,10 @@
import type { configuration } from "@/src/types";
+import { customCssID } from "@/src/features/customCSS";
+
export function updateCustomCSS({ custom_css_code }: Pick) {
// Get the custom CSS style element
- const customCSSStyleElement = document.querySelector("#yte-custom-css");
+ const customCSSStyleElement = document.querySelector(`#${customCssID}`);
// Check if the custom CSS style element exists
if (!customCSSStyleElement) return;
customCSSStyleElement.replaceWith(createCustomCSSElement({ custom_css_code }));
@@ -10,13 +12,13 @@ export function updateCustomCSS({ custom_css_code }: Pick) {
// Create the custom CSS style element
const customCSSStyleElement = document.createElement("style");
- customCSSStyleElement.id = "yte-custom-css";
+ customCSSStyleElement.id = customCssID;
customCSSStyleElement.textContent = custom_css_code;
return customCSSStyleElement;
}
export function customCSSExists() {
// Get the custom CSS style element
- const customCSSStyleElement = document.querySelector("#yte-custom-css");
+ const customCSSStyleElement = document.querySelector(`#${customCssID}`);
// Check if the custom CSS style element exists
if (!customCSSStyleElement) return false;
return true;
diff --git a/src/features/deepDarkCSS/index.ts b/src/features/deepDarkCSS/index.ts
new file mode 100644
index 00000000..118c5320
--- /dev/null
+++ b/src/features/deepDarkCSS/index.ts
@@ -0,0 +1,35 @@
+import { deepDarkPresets } from "@/src/deepDarkPresets";
+import { waitForSpecificMessage } from "@/src/utils/utilities";
+
+import { createDeepDarkCSSElement, deepDarkCSSExists, getDeepDarkCustomThemeStyle, updateDeepDarkCSS } from "./utils";
+export const deepDarkCssID = "yte-deep-dark-css";
+export async function enableDeepDarkCSS() {
+ // Wait for the "options" message from the content script
+ const optionsData = await waitForSpecificMessage("options", "request_data", "content");
+ const {
+ data: {
+ options: { deep_dark_custom_theme_colors, deep_dark_preset, enable_deep_dark_theme }
+ }
+ } = optionsData;
+ // Check if deep dark theme is enabled
+ if (!enable_deep_dark_theme) return;
+ if (deepDarkCSSExists()) {
+ updateDeepDarkCSS(deep_dark_preset === "Custom" ? getDeepDarkCustomThemeStyle(deep_dark_custom_theme_colors) : deepDarkPresets[deep_dark_preset]);
+ return;
+ }
+ // Create the deep dark theme style element
+ const deepDarkThemeStyleElement = createDeepDarkCSSElement(
+ deep_dark_preset === "Custom" ? getDeepDarkCustomThemeStyle(deep_dark_custom_theme_colors) : deepDarkPresets[deep_dark_preset]
+ );
+ // Insert the deep dark theme style element
+ document.head.appendChild(deepDarkThemeStyleElement);
+}
+
+export function disableDeepDarkCSS() {
+ // Get the deep dark theme style element
+ const deepDarkThemeStyleElement = document.querySelector(`#${deepDarkCssID}`);
+ // Check if the deep dark theme style element exists
+ if (!deepDarkThemeStyleElement) return;
+ // Remove the deep dark theme style element
+ deepDarkThemeStyleElement.remove();
+}
diff --git a/src/features/deepDarkCSS/utils.ts b/src/features/deepDarkCSS/utils.ts
new file mode 100644
index 00000000..75c9c32c
--- /dev/null
+++ b/src/features/deepDarkCSS/utils.ts
@@ -0,0 +1,46 @@
+import type { DeepDarkCustomThemeColors } from "@/src/types";
+
+import { deepDarkMaterial } from "@/src/deepDarkMaterialCSS";
+import { deepDarkCssID } from "@/src/features/deepDarkCSS";
+
+export function updateDeepDarkCSS(css_code: string) {
+ // Get the custom CSS style element
+ const customCSSStyleElement = document.querySelector(`#${deepDarkCssID}`);
+ // Check if the custom CSS style element exists
+ if (!customCSSStyleElement) return;
+ customCSSStyleElement.replaceWith(createDeepDarkCSSElement(css_code));
+}
+export function createDeepDarkCSSElement(css_code: string) {
+ // Create the custom CSS style element
+ const customCSSStyleElement = document.createElement("style");
+ customCSSStyleElement.id = deepDarkCssID;
+ customCSSStyleElement.textContent = `${deepDarkMaterial}\n${css_code}`;
+ return customCSSStyleElement;
+}
+export function deepDarkCSSExists() {
+ // Get the custom CSS style element
+ const customCSSStyleElement = document.querySelector(`#${deepDarkCssID}`);
+ // Check if the custom CSS style element exists
+ if (!customCSSStyleElement) return false;
+ return true;
+}
+
+export function getDeepDarkCustomThemeStyle({
+ colorShadow,
+ dimmerText,
+ hoverBackground,
+ mainBackground,
+ mainColor,
+ mainText,
+ secondBackground
+}: DeepDarkCustomThemeColors) {
+ return `:root {
+ --main-color: ${mainColor};
+ --main-background: ${mainBackground};
+ --second-background: ${secondBackground};
+ --hover-background: ${hoverBackground};
+ --main-text: ${mainText};
+ --dimmer-text: ${dimmerText};
+ --shadow: 0 1px 0.5px ${colorShadow};
+ }`;
+}
diff --git a/src/features/featureMenu/index.ts b/src/features/featureMenu/index.ts
index 18c55040..13e4704c 100644
--- a/src/features/featureMenu/index.ts
+++ b/src/features/featureMenu/index.ts
@@ -46,7 +46,7 @@ async function createFeatureMenuButton() {
elementType: "button",
styles: { display: "none" }
});
- featureMenuButton.dataset.title = window.i18nextInstance.t("pages.content.features.featureMenu.label");
+ featureMenuButton.dataset.title = window.i18nextInstance.t("pages.content.features.featureMenu.button.label");
// Create the SVG icon for the button
const featureButtonSVG = makeFeatureMenuIcon();
featureMenuButton.appendChild(featureButtonSVG);
diff --git a/src/features/featureMenu/utils.ts b/src/features/featureMenu/utils.ts
index 5a1141d2..017e3151 100644
--- a/src/features/featureMenu/utils.ts
+++ b/src/features/featureMenu/utils.ts
@@ -1,11 +1,20 @@
import type { ListenerType } from "@/src/features/buttonPlacement/utils";
import type { BasicIcon } from "@/src/icons";
-import type { FeatureMenuItemIconId, FeatureMenuItemId, FeatureMenuItemLabelId, FeaturesThatHaveButtons, WithId } from "@/src/types";
-import eventManager, { type FeatureName } from "@/src/utils/EventManager";
-import { waitForAllElements } from "@/src/utils/utilities";
-
-export const featuresInMenu = new Set();
+import {
+ type AllButtonNames,
+ type FeatureMenuItemIconId,
+ type FeatureMenuItemId,
+ type FeatureMenuItemLabelId,
+ type MultiButtonNames,
+ type Nullable,
+ type SingleButtonFeatureNames,
+ type WithId
+} from "@/src/types";
+import eventManager from "@/src/utils/EventManager";
+import { findKeyByValue, waitForAllElements } from "@/src/utils/utilities";
+
+export const featuresInMenu = new Set();
function featureMenuClickListener(menuItem: HTMLDivElement, listener: ListenerType, isToggle: boolean) {
if (isToggle) {
@@ -17,21 +26,22 @@ function featureMenuClickListener(menuItem: HTML
}
/**
* Adds a feature item to the feature menu.
- * @param featureName The name of the feature
+ * @param buttonName The name of the button
* @param label The label for the feature
* @param icon The icon for the feature
* @param listener The listener for the feature
* @param isToggle Whether the feature is a toggle
*/
-export async function addFeatureItemToMenu(
- featureName: Name,
+export async function addFeatureItemToMenu(
+ buttonName: Name,
label: string,
icon: BasicIcon,
listener: ListenerType,
isToggle: boolean
) {
+ const featureName = findKeyByValue(buttonName as MultiButtonNames) ?? (buttonName as SingleButtonFeatureNames);
// Add the feature name to the set of features in the menu
- featuresInMenu.add(featureName);
+ featuresInMenu.add(buttonName);
// Wait for the feature menu to exist
await waitForAllElements(["#yte-feature-menu"]);
@@ -41,9 +51,9 @@ export async function addFeatureItemToMenu(`#${getFeatureIds(featureName).featureMenuItemId}`);
+ const featureExistsInMenu = featureMenu.querySelector(`#${getFeatureIds(buttonName).featureMenuItemId}`);
if (featureExistsInMenu) {
- const menuItem = getFeatureMenuItem(featureName);
+ const menuItem = getFeatureMenuItem(buttonName);
if (!menuItem) return;
eventManager.removeEventListener(menuItem, "click", featureName);
eventManager.addEventListener(menuItem, "click", () => featureMenuClickListener(menuItem, listener, isToggle), featureName);
@@ -55,7 +65,7 @@ export async function addFeatureItemToMenu("#yte-feature-menu");
if (!featureMenu) return;
@@ -146,12 +156,12 @@ export function removeFeatureItemFromMenu(featureName: FeaturesThatHaveButtons)
}
/**
* Updates the label for a feature item.
- * @param featureName the name of the feature
+ * @param buttonName the name of the button
* @param label the label to set
* @returns
*/
-export function updateFeatureMenuItemLabel(featureName: FeaturesThatHaveButtons, label: string) {
- const featureMenuItemLabel = getFeatureMenuItemLabel(featureName);
+export function updateFeatureMenuItemLabel(buttonName: AllButtonNames, label: string) {
+ const featureMenuItemLabel = getFeatureMenuItemLabel(buttonName);
if (!featureMenuItemLabel) return;
featureMenuItemLabel.textContent = label;
}
@@ -167,32 +177,32 @@ export function updateFeatureMenuTitle(title: string) {
}
/**
* Gets the IDs for a feature item.
- * @param featureName the name of the feature
+ * @param buttonName the name of the button
* @returns { featureMenuItemIconId, featureMenuItemId, featureMenuItemLabelId}
*/
-export function getFeatureIds(featureName: FeatureName): {
+export function getFeatureIds(buttonName: AllButtonNames): {
featureMenuItemIconId: FeatureMenuItemIconId;
featureMenuItemId: FeatureMenuItemId;
featureMenuItemLabelId: FeatureMenuItemLabelId;
} {
- const featureMenuItemIconId: FeatureMenuItemIconId = `yte-${featureName}-icon`;
- const featureMenuItemId: FeatureMenuItemId = `yte-feature-${featureName}-menuitem`;
- const featureMenuItemLabelId: FeatureMenuItemLabelId = `yte-${featureName}-label`;
+ const featureMenuItemIconId: FeatureMenuItemIconId = `yte-${buttonName}-icon`;
+ const featureMenuItemId: FeatureMenuItemId = `yte-feature-${buttonName}-menuitem`;
+ const featureMenuItemLabelId: FeatureMenuItemLabelId = `yte-${buttonName}-label`;
return {
featureMenuItemIconId,
featureMenuItemId,
featureMenuItemLabelId
};
}
-export function getFeatureMenuItemIcon(featureName: FeatureName): HTMLDivElement | null {
- const selector: WithId = `#yte-${featureName}-icon`;
+export function getFeatureMenuItemIcon(buttonName: AllButtonNames): Nullable {
+ const selector: WithId = `#yte-${buttonName}-icon`;
return document.querySelector(selector);
}
-export function getFeatureMenuItemLabel(featureName: FeatureName): HTMLDivElement | null {
- const selector: WithId = `#yte-${featureName}-label`;
+export function getFeatureMenuItemLabel(buttonName: AllButtonNames): Nullable {
+ const selector: WithId = `#yte-${buttonName}-label`;
return document.querySelector(selector);
}
-export function getFeatureMenuItem(featureName: FeatureName): HTMLDivElement | null {
- const selector: WithId = `#yte-feature-${featureName}-menuitem`;
+export function getFeatureMenuItem(buttonName: AllButtonNames): Nullable {
+ const selector: WithId = `#yte-feature-${buttonName}-menuitem`;
return document.querySelector(`#yte-panel-menu > ${selector}`);
}
diff --git a/src/features/hideShorts/index.ts b/src/features/hideShorts/index.ts
index e4246d22..49d6f035 100644
--- a/src/features/hideShorts/index.ts
+++ b/src/features/hideShorts/index.ts
@@ -1,6 +1,7 @@
import { hideShorts, observeShortsElements, showShorts } from "@/src/features/hideShorts/utils";
+import { type Nullable } from "@/src/types";
import { waitForSpecificMessage } from "@/src/utils/utilities";
-let shortsObserver: MutationObserver | null = null;
+let shortsObserver: Nullable = null;
export async function enableHideShorts() {
// Wait for the "options" message from the content script
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
diff --git a/src/features/hideShorts/utils.ts b/src/features/hideShorts/utils.ts
index d7a887d0..576cf95d 100644
--- a/src/features/hideShorts/utils.ts
+++ b/src/features/hideShorts/utils.ts
@@ -1,10 +1,10 @@
-const sideBarOpenedShortsButtonSelector = "ytd-guide-entry-renderer:has(a[title=Shorts])";
-const sideBarClosedShortsButtonSelector = "ytd-guide-entry-renderer:has(a[title=Shorts])";
-const homePageShortsSectionSelector = "ytd-rich-section-renderer:has(#rich-shelf-header)";
-const channelHomePageShortsSectionSelector = "ytd-reel-shelf-renderer:has(#title-container)";
-const channelPageShortsTabSelector = "yt-tab-shape[tab-title=Shorts]";
-const searchResultsShortsTabSelector = "yt-chip-cloud-chip-renderer:has(yt-formatted-string[title=Shorts])";
-const shortsVideoRendererSelector = "ytd-video-renderer:has([overlay-style=SHORTS])";
+export const sideBarOpenedShortsButtonSelector = "ytd-guide-entry-renderer:has(a[title=Shorts])";
+export const sideBarClosedShortsButtonSelector = "ytd-mini-guide-entry-renderer:has(a[title=Shorts])";
+export const homePageShortsSectionSelector = "ytd-rich-section-renderer:has(#rich-shelf-header)";
+export const channelHomePageShortsSectionSelector = "ytd-reel-shelf-renderer:has(#title-container)";
+export const channelPageShortsTabSelector = "yt-tab-shape[tab-title=Shorts]";
+export const searchResultsShortsTabSelector = "yt-chip-cloud-chip-renderer:has(yt-formatted-string[title=Shorts])";
+export const shortsVideoRendererSelector = "ytd-video-renderer:has([overlay-style=SHORTS])";
type ElementVisibilityAction = (element: HTMLElement) => void;
diff --git a/src/features/index.ts b/src/features/index.ts
index a8f8562f..9034da11 100644
--- a/src/features/index.ts
+++ b/src/features/index.ts
@@ -1,8 +1,14 @@
-import type { ButtonPlacement, FeaturesThatHaveButtons } from "@/src/types";
+import type { AllButtonNames, ButtonPlacement } from "@/src/types";
import { addLoopButton, removeLoopButton } from "@/src/features/loopButton";
import { addMaximizePlayerButton, removeMaximizePlayerButton } from "@/src/features/maximizePlayerButton";
import { addOpenTranscriptButton, removeOpenTranscriptButton } from "@/src/features/openTranscriptButton/utils";
+import {
+ addDecreasePlaybackSpeedButton,
+ addIncreasePlaybackSpeedButton,
+ removeDecreasePlaybackSpeedButton,
+ removeIncreasePlaybackSpeedButton
+} from "@/src/features/playbackSpeedButtons";
import { addScreenshotButton, removeScreenshotButton } from "@/src/features/screenshotButton";
import { addVolumeBoostButton, removeVolumeBoostButton } from "@/src/features/volumeBoost";
@@ -12,6 +18,14 @@ export type FeatureFuncRecord = {
};
export const featureButtonFunctions = {
+ decreasePlaybackSpeedButton: {
+ add: addDecreasePlaybackSpeedButton,
+ remove: removeDecreasePlaybackSpeedButton
+ },
+ increasePlaybackSpeedButton: {
+ add: addIncreasePlaybackSpeedButton,
+ remove: removeIncreasePlaybackSpeedButton
+ },
loopButton: {
add: addLoopButton,
remove: removeLoopButton
@@ -32,6 +46,6 @@ export const featureButtonFunctions = {
add: addVolumeBoostButton,
remove: removeVolumeBoostButton
}
-} satisfies Record;
+} satisfies Record;
export type AddButtonFunction = () => Promise;
export type RemoveButtonFunction = (placement?: ButtonPlacement) => Promise;
diff --git a/src/features/loopButton/index.ts b/src/features/loopButton/index.ts
index 4dc1bc53..3ec163e6 100644
--- a/src/features/loopButton/index.ts
+++ b/src/features/loopButton/index.ts
@@ -1,8 +1,10 @@
+import type { SingleButtonFeatureNames } from "@/src/types";
+
import { addFeatureButton, removeFeatureButton } from "@/src/features/buttonPlacement";
import { getFeatureButton, getFeatureButtonId } from "@/src/features/buttonPlacement/utils";
import { getFeatureIds } from "@/src/features/featureMenu/utils";
import { getFeatureIcon } from "@/src/icons";
-import eventManager, { type FeatureName } from "@/src/utils/EventManager";
+import eventManager from "@/src/utils/EventManager";
import { waitForSpecificMessage } from "@/src/utils/utilities";
import type { AddButtonFunction, RemoveButtonFunction } from "../index";
@@ -33,8 +35,8 @@ export const addLoopButton: AddButtonFunction = async () => {
"loopButton",
loopButtonPlacement,
loopButtonPlacement === "feature_menu" ?
- window.i18nextInstance.t("pages.content.features.loopButton.label")
- : window.i18nextInstance.t("pages.content.features.loopButton.toggle.off"),
+ window.i18nextInstance.t("pages.content.features.loopButton.button.label")
+ : window.i18nextInstance.t("pages.content.features.loopButton.button.toggle.off"),
getFeatureIcon("loopButton", loopButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"),
loopButtonClickListener,
true
@@ -46,7 +48,7 @@ export const addLoopButton: AddButtonFunction = async () => {
const { attributeName, target } = mutation;
if (attributeName === "loop") {
const { loop } = target as HTMLVideoElement;
- const featureName: FeatureName = "loopButton";
+ const featureName: SingleButtonFeatureNames = "loopButton";
// Get the feature menu
const featureMenu = document.querySelector("#yte-feature-menu");
// Check if the feature item already exists in the menu
diff --git a/src/features/loopButton/utils.ts b/src/features/loopButton/utils.ts
index bde9613a..1173d1a9 100644
--- a/src/features/loopButton/utils.ts
+++ b/src/features/loopButton/utils.ts
@@ -2,7 +2,7 @@ import { updateFeatureButtonTitle } from "@/src/features/buttonPlacement/utils";
export function loopButtonClickListener(checked?: boolean) {
if (checked !== undefined) {
- updateFeatureButtonTitle("loopButton", window.i18nextInstance.t(`pages.content.features.loopButton.toggle.${checked ? "on" : "off"}`));
+ updateFeatureButtonTitle("loopButton", window.i18nextInstance.t(`pages.content.features.loopButton.button.toggle.${checked ? "on" : "off"}`));
}
const videoElement = document.querySelector("video.html5-main-video");
if (!videoElement) return;
diff --git a/src/features/maximizePlayerButton/index.ts b/src/features/maximizePlayerButton/index.ts
index 9aaa8611..888ef762 100644
--- a/src/features/maximizePlayerButton/index.ts
+++ b/src/features/maximizePlayerButton/index.ts
@@ -1,5 +1,5 @@
import type { AddButtonFunction, RemoveButtonFunction } from "@/src/features";
-import type { YouTubePlayerDiv } from "@/src/types";
+import type { Nullable, YouTubePlayerDiv } from "@/src/types";
import { addFeatureButton, removeFeatureButton } from "@/src/features/buttonPlacement";
import { getFeatureButton, updateFeatureButtonIcon, updateFeatureButtonTitle } from "@/src/features/buttonPlacement/utils";
@@ -37,7 +37,7 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => {
if (checked) remove();
updateFeatureButtonTitle(
"maximizePlayerButton",
- window.i18nextInstance.t(`pages.content.features.maximizePlayerButton.toggle.${checked ? "on" : "off"}`)
+ window.i18nextInstance.t(`pages.content.features.maximizePlayerButton.button.toggle.${checked ? "on" : "off"}`)
);
}
maximizePlayer();
@@ -45,9 +45,9 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => {
setupVideoPlayerTimeUpdate();
}
- const pipElement: HTMLButtonElement | null = document.querySelector("button.ytp-pip-button");
- const sizeElement: HTMLButtonElement | null = document.querySelector("button.ytp-size-button");
- const miniPlayerElement: HTMLButtonElement | null = document.querySelector("button.ytp-miniplayer-button");
+ const pipElement: Nullable = document.querySelector("button.ytp-pip-button");
+ const sizeElement: Nullable = document.querySelector("button.ytp-size-button");
+ const miniPlayerElement: Nullable = document.querySelector("button.ytp-miniplayer-button");
function otherElementClickListener() {
// Get the video element
const videoElement = document.querySelector("video.video-stream.html5-main-video");
@@ -64,7 +64,7 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => {
const icon = getFeatureIcon("maximizePlayerButton", "shared_icon_position");
if (button && button instanceof HTMLButtonElement) {
if (typeof icon === "object" && "off" in icon && "on" in icon) updateFeatureButtonIcon(button, icon.off);
- updateFeatureButtonTitle("maximizePlayerButton", window.i18nextInstance.t("pages.content.features.maximizePlayerButton.toggle.off"));
+ updateFeatureButtonTitle("maximizePlayerButton", window.i18nextInstance.t("pages.content.features.maximizePlayerButton.button.toggle.off"));
}
}
}
@@ -72,8 +72,8 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => {
"maximizePlayerButton",
maximizePlayerButtonPlacement,
maximizePlayerButtonPlacement === "feature_menu" ?
- window.i18nextInstance.t("pages.content.features.maximizePlayerButton.label")
- : window.i18nextInstance.t("pages.content.features.maximizePlayerButton.toggle.off"),
+ window.i18nextInstance.t("pages.content.features.maximizePlayerButton.button.label")
+ : window.i18nextInstance.t("pages.content.features.maximizePlayerButton.button.toggle.off"),
getFeatureIcon("maximizePlayerButton", maximizePlayerButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"),
maximizePlayerButtonClickListener,
true
diff --git a/src/features/openTranscriptButton/utils.ts b/src/features/openTranscriptButton/utils.ts
index 49c749c5..fe688baf 100644
--- a/src/features/openTranscriptButton/utils.ts
+++ b/src/features/openTranscriptButton/utils.ts
@@ -23,7 +23,7 @@ export const addOpenTranscriptButton: AddButtonFunction = async () => {
await addFeatureButton(
"openTranscriptButton",
openTranscriptButtonPlacement,
- window.i18nextInstance.t("pages.content.features.openTranscriptButton.label"),
+ window.i18nextInstance.t("pages.content.features.openTranscriptButton.button.label"),
getFeatureIcon("openTranscriptButton", openTranscriptButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"),
transcriptButtonClickerListener,
false
diff --git a/src/features/openYouTubeSettingsOnHover/index.ts b/src/features/openYouTubeSettingsOnHover/index.ts
index ff031088..20a8b451 100644
--- a/src/features/openYouTubeSettingsOnHover/index.ts
+++ b/src/features/openYouTubeSettingsOnHover/index.ts
@@ -1,4 +1,4 @@
-import type { YouTubePlayerDiv } from "@/src/types";
+import type { Nullable, YouTubePlayerDiv } from "@/src/types";
import eventManager from "@/src/utils/EventManager";
import { isWatchPage, waitForSpecificMessage } from "@/src/utils/utilities";
@@ -36,7 +36,7 @@ export async function enableOpenYouTubeSettingsOnHover() {
};
const settingsButtonMouseLeaveListener = (event: Event) => {
if (event.target === settingsButton) return;
- if (settingsMenu.contains(event.target as Node | null)) return;
+ if (settingsMenu.contains(event.target as Nullable)) return;
hideSettings(event);
};
eventManager.addEventListener(settingsButton, "mouseenter", showSettings, "openYouTubeSettingsOnHover");
diff --git a/src/features/pauseBackgroundPlayers/index.ts b/src/features/pauseBackgroundPlayers/index.ts
new file mode 100644
index 00000000..f39c2551
--- /dev/null
+++ b/src/features/pauseBackgroundPlayers/index.ts
@@ -0,0 +1,59 @@
+import { browserColorLog, sendContentToBackgroundMessage, waitForSpecificMessage } from "@/src/utils/utilities";
+
+const PauseBackgroundPlayers = () => {
+ sendContentToBackgroundMessage("pauseBackgroundPlayers").catch((error) => {
+ throw new Error(`Failed to pause background players: ${error}`);
+ });
+};
+
+export async function enablePauseBackgroundPlayers() {
+ const optionsData = await waitForSpecificMessage("options", "request_data", "content");
+ const {
+ data: {
+ options: { enable_pausing_background_players: pauseBackgroundPlayersEnabled }
+ }
+ } = optionsData;
+ if (!pauseBackgroundPlayersEnabled) return;
+ // ignore home page
+ if (window.location.href.match(/^https?:\/\/(?:www\.)?youtube\.com\/?$/gm)) return;
+ browserColorLog("Enabling pauseBackgroundPlayers", "FgMagenta");
+
+ let videoPlayerContainer: HTMLVideoElement | null = null;
+ if (!videoPlayerContainer) {
+ videoPlayerContainer = document.querySelector(".html5-main-video");
+ }
+ function detectPlaying() {
+ if (videoPlayerContainer) {
+ videoPlayerContainer.addEventListener("playing", PauseBackgroundPlayers);
+ }
+ }
+
+ let debounceTimeout: null | number = null;
+ const observer = new MutationObserver((mutationsList: MutationRecord[]) => {
+ if (debounceTimeout) clearTimeout(debounceTimeout);
+ // @ts-expect-error - doesn't recognize browser environment properly
+ debounceTimeout = setTimeout(() => {
+ for (const mutation of mutationsList) {
+ if (mutation.addedNodes.length) {
+ detectPlaying();
+ }
+ }
+ }, 100);
+ });
+
+ if (videoPlayerContainer) {
+ observer.observe(videoPlayerContainer, { childList: true, subtree: true });
+ }
+ if (!videoPlayerContainer?.paused) {
+ PauseBackgroundPlayers();
+ }
+ detectPlaying();
+}
+
+export function disablePauseBackgroundPlayers() {
+ const videoPlayerContainer: HTMLElement | null = document.querySelector(".html5-main-video");
+ if (videoPlayerContainer) {
+ videoPlayerContainer.removeEventListener("playing", PauseBackgroundPlayers);
+ }
+ browserColorLog("Disabling pauseBackgroundPlayers", "FgMagenta");
+}
diff --git a/src/features/playbackSpeedButtons/index.ts b/src/features/playbackSpeedButtons/index.ts
new file mode 100644
index 00000000..77ca191b
--- /dev/null
+++ b/src/features/playbackSpeedButtons/index.ts
@@ -0,0 +1,117 @@
+import type { YouTubePlayerDiv } from "@/src/types";
+
+import { addFeatureButton, removeFeatureButton } from "@/src/features/buttonPlacement";
+//import { getFeatureButton, getFeatureButtonId } from "@/src/features/buttonPlacement/utils";
+import { setPlayerSpeed } from "@/src/features/playerSpeed";
+import { getFeatureIcon } from "@/src/icons";
+import eventManager from "@/src/utils/EventManager";
+import OnScreenDisplayManager from "@/src/utils/OnScreenDisplayManager";
+import { isShortsPage, isWatchPage, waitForSpecificMessage } from "@/src/utils/utilities";
+
+import type { AddButtonFunction, RemoveButtonFunction } from "../index";
+//import { loopButtonClickListener } from "./utils";
+
+function playbackSpeedButtonClickListener(amount: number): () => void {
+ return () => {
+ void (async () => {
+ // Get the video element
+ const videoElement = document.querySelector("video");
+ // If video element is not available, return
+ if (!videoElement) return;
+ try {
+ const { playbackRate: currentPlaybackSpeed } = videoElement;
+ const playerContainer =
+ isWatchPage() ? document.querySelector("div#movie_player")
+ : isShortsPage() ? document.querySelector("div#shorts-player")
+ : null;
+ // If player element is not available, return
+ if (!playerContainer) return;
+ const optionsData = await waitForSpecificMessage("options", "request_data", "content");
+ const {
+ data: {
+ options: { osd_display_color, osd_display_hide_time, osd_display_opacity, osd_display_padding, osd_display_position }
+ }
+ } = optionsData;
+ new OnScreenDisplayManager(
+ {
+ displayColor: osd_display_color,
+ displayHideTime: osd_display_hide_time,
+ displayOpacity: osd_display_opacity,
+ displayPadding: osd_display_padding,
+ displayPosition: osd_display_position,
+ displayType: "text", // TODO: support for line/round? currently buggy
+ playerContainer: playerContainer
+ },
+ "yte-osd",
+ {
+ max: 4,
+ type: "speed",
+ value: currentPlaybackSpeed + amount
+ }
+ );
+ await setPlayerSpeed(currentPlaybackSpeed + amount);
+ } catch (error) {
+ console.error(error);
+ }
+ })();
+ };
+}
+
+export const addIncreasePlaybackSpeedButton: AddButtonFunction = async () => {
+ // Wait for the "options" message from the content script
+ const optionsData = await waitForSpecificMessage("options", "request_data", "content");
+ const {
+ data: {
+ options: {
+ button_placements: { increasePlaybackSpeedButton: increasePlaybackSpeedButtonPlacement },
+ enable_playback_speed_buttons,
+ playback_buttons_speed: playbackSpeedPerClick
+ }
+ }
+ } = optionsData;
+ if (!enable_playback_speed_buttons) return;
+ await addFeatureButton(
+ "increasePlaybackSpeedButton",
+ increasePlaybackSpeedButtonPlacement,
+ window.i18nextInstance.t("pages.content.features.playbackSpeedButtons.buttons.increasePlaybackSpeedButton.label", {
+ SPEED: playbackSpeedPerClick
+ }),
+ getFeatureIcon("increasePlaybackSpeedButton", increasePlaybackSpeedButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"),
+ playbackSpeedButtonClickListener(playbackSpeedPerClick),
+ false
+ );
+};
+
+export const addDecreasePlaybackSpeedButton: AddButtonFunction = async () => {
+ // Wait for the "options" message from the content script
+ const optionsData = await waitForSpecificMessage("options", "request_data", "content");
+ const {
+ data: {
+ options: {
+ button_placements: { decreasePlaybackSpeedButton: decreasePlaybackSpeedButtonPlacement },
+ enable_playback_speed_buttons,
+ playback_buttons_speed: playbackSpeedPerClick
+ }
+ }
+ } = optionsData;
+ if (!enable_playback_speed_buttons) return;
+ await addFeatureButton(
+ "decreasePlaybackSpeedButton",
+ decreasePlaybackSpeedButtonPlacement,
+ window.i18nextInstance.t("pages.content.features.playbackSpeedButtons.buttons.decreasePlaybackSpeedButton.label", {
+ SPEED: playbackSpeedPerClick
+ }),
+ getFeatureIcon("decreasePlaybackSpeedButton", decreasePlaybackSpeedButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"),
+ playbackSpeedButtonClickListener(-playbackSpeedPerClick),
+ false
+ );
+};
+
+export const removeDecreasePlaybackSpeedButton: RemoveButtonFunction = async (placement) => {
+ await removeFeatureButton("decreasePlaybackSpeedButton", placement);
+ eventManager.removeEventListeners("playbackSpeedButtons");
+};
+export const removeIncreasePlaybackSpeedButton: RemoveButtonFunction = async (placement) => {
+ await removeFeatureButton("increasePlaybackSpeedButton", placement);
+ eventManager.removeEventListeners("playbackSpeedButtons");
+};
diff --git a/src/features/removeRedirect/index.ts b/src/features/removeRedirect/index.ts
index 3a782caa..77e235a4 100644
--- a/src/features/removeRedirect/index.ts
+++ b/src/features/removeRedirect/index.ts
@@ -1,7 +1,7 @@
+import { type Nullable } from "@/src/types";
import { browserColorLog, waitForSpecificMessage } from "@/src/utils/utilities";
export default async function removeRedirect() {
- browserColorLog(`Enabling removeRedirect`, "FgMagenta");
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
const {
data: {
@@ -9,9 +9,12 @@ export default async function removeRedirect() {
}
} = optionsData;
if (!removeRedirectEnabled) return;
+ browserColorLog(`Enabling removeRedirect`, "FgMagenta");
const regex = /https\:\/\/www\.youtube\.com\/redirect\?.+/gm;
- const links: NodeListOf = document.querySelectorAll(".yt-core-attributed-string__link, .yt-simple-endpoint.style-scope.yt-formatted-string");
+ const links: NodeListOf = document.querySelectorAll(
+ ".yt-core-attributed-string__link, .yt-simple-endpoint.style-scope.yt-formatted-string"
+ );
links.forEach((link: HTMLElement) => {
const href: null | string = link.getAttribute("href");
if (href && href.match(regex)) {
@@ -23,7 +26,7 @@ export default async function removeRedirect() {
const callback: MutationCallback = (mutationsList: MutationRecord[]) => {
for (const mutation of mutationsList) {
if (mutation.type === "childList") {
- mutation.addedNodes.forEach((node: Node | null) => {
+ mutation.addedNodes.forEach((node: Nullable) => {
if (node instanceof Element && node.hasAttribute("href")) {
const href: null | string = node.getAttribute("href");
if (href !== null && href.match(regex)) {
diff --git a/src/features/screenshotButton/index.ts b/src/features/screenshotButton/index.ts
index a1472c99..5b27ec7a 100644
--- a/src/features/screenshotButton/index.ts
+++ b/src/features/screenshotButton/index.ts
@@ -3,6 +3,7 @@ import type { AddButtonFunction, RemoveButtonFunction } from "@/src/features";
import { addFeatureButton, removeFeatureButton } from "@/src/features/buttonPlacement";
import { getFeatureButton } from "@/src/features/buttonPlacement/utils";
import { getFeatureIcon } from "@/src/icons";
+import { type Nullable } from "@/src/types";
import eventManager from "@/src/utils/EventManager";
import { createTooltip, waitForSpecificMessage } from "@/src/utils/utilities";
@@ -32,7 +33,7 @@ async function takeScreenshot(videoElement: HTMLVideoElement) {
// Get the data URL of the canvas and create a blob from it
const dataUrl = canvas.toDataURL(format);
- const blob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
+ const blob = await new Promise>((resolve) => canvas.toBlob(resolve, "image/png"));
if (!blob) return;
switch (screenshot_save_as) {
@@ -99,7 +100,7 @@ export const addScreenshotButton: AddButtonFunction = async () => {
await addFeatureButton(
"screenshotButton",
screenshotButtonPlacement,
- window.i18nextInstance.t("pages.content.features.screenshotButton.label"),
+ window.i18nextInstance.t("pages.content.features.screenshotButton.button.label"),
getFeatureIcon("screenshotButton", screenshotButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"),
screenshotButtonClickListener,
false
diff --git a/src/features/shareShortener/index.ts b/src/features/shareShortener/index.ts
index 459cabae..f5bb3ea0 100644
--- a/src/features/shareShortener/index.ts
+++ b/src/features/shareShortener/index.ts
@@ -1,6 +1,48 @@
import { browserColorLog, waitForSpecificMessage } from "@/src/utils/utilities";
+const regexp: RegExp = new RegExp("(\\?|&)(si|feature|pp)=[^&]*", "g");
+let intervalId: NodeJS.Timeout | null = null;
+let input: HTMLInputElement | null;
+function cleanUrl(url: string): string {
+ return url.replace(regexp, "");
+}
+
+function cleanAndUpdateUrl() {
+ if (intervalId) {
+ clearInterval(intervalId);
+ intervalId = null;
+ input = null;
+ }
+ intervalId = setInterval(() => {
+ if (!input) {
+ input = document.querySelector("#share-url");
+ }
+ if (input) {
+ if (!input.value.match(regexp)) return;
+ console.log("cleanAndUpdateUrl");
+ input.value = cleanUrl(input.value);
+ }
+ }, 50);
+}
+
+function cleanSearchPage(url: string) {
+ if (!url.match(/https?:\/\/(?:www\.)?youtube\.com\/results\?search\_query\=.+/gm)) return;
+ const allElements = Array.from(document.querySelectorAll("*"));
+ allElements.forEach((e) => {
+ const href: null | string = e.getAttribute("href");
+ if (href && href.match(/^\/watch\?v\=.+$/gm)) {
+ e.setAttribute("href", href.replace(regexp, ""));
+ }
+ });
+}
+
+function handleInput(event: MouseEvent) {
+ const element = event.target as Element;
+ if (!element.classList.contains("yt-spec-touch-feedback-shape__fill")) {
+ return;
+ }
+ cleanAndUpdateUrl();
+}
-let observer: MutationObserver | null = null;
export async function enableShareShortener() {
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
const {
@@ -9,70 +51,15 @@ export async function enableShareShortener() {
}
} = optionsData;
if (!enable_share_shortener) return;
-
- const regexp: RegExp = new RegExp("(\\?|&)(si|feature|pp)=[^&]*", "g");
-
- function attachEventListener(): void {
- const checkbox = document.querySelector(".style-scope.tp-yt-paper-checkbox");
- const tsInput = document.querySelector(".style-scope.tp-yt-paper-input .input-element input");
- const allElements = Array.from(document.querySelectorAll("*"));
- allElements.forEach((e) => {
- const href: null | string = e.getAttribute("href");
- if (href && href.match(/^\/watch\?v\=.+$/gm)) {
- e.setAttribute("href", href.replace(regexp, ""));
- }
- });
-
- if (checkbox && tsInput) {
- checkbox.addEventListener("DOMAttrModified", function (this: HTMLInputElement) {
- const shareUrlInput = document.querySelector("#share-url");
- if (shareUrlInput) {
- setTimeout(() => {
- shareUrlInput.value = shareUrlInput.value.replace(regexp, "");
- }, 0);
- }
- });
-
- tsInput.addEventListener("keypress", function (event: KeyboardEvent) {
- if (event.key === "Enter") {
- setTimeout(() => {
- const shareUrlInput = document.querySelector("#share-url");
- if (shareUrlInput) {
- const cleanUrl: string = shareUrlInput.value.replace(regexp, "");
- shareUrlInput.value = cleanUrl;
- }
- }, 0);
- }
- });
- }
- }
-
- function monitorUrl(mutationsList: MutationRecord[]): void {
- for (const mutation of mutationsList) {
- if (mutation.target !== document.getElementById("share-url")) {
- const shareUrlInput = document.querySelector("#share-url");
- if (shareUrlInput) {
- const cleanUrl: string = shareUrlInput.value.replace(regexp, "");
- shareUrlInput.value = cleanUrl;
- }
- }
- }
- }
-
- observer = new MutationObserver(function (mutationsList: MutationRecord[]) {
- attachEventListener();
- if (observer) {
- monitorUrl(mutationsList);
- }
- });
-
- observer.observe(document, { childList: true, subtree: true });
+ cleanSearchPage(window.location.href);
+ document.addEventListener("click", handleInput);
}
export function disableShareShortener() {
browserColorLog(`Disabling share shortener`, "FgMagenta");
- if (observer) {
- observer.disconnect();
- observer = null;
+ document.removeEventListener("click", handleInput);
+ if (intervalId) {
+ clearInterval(intervalId);
+ intervalId = null;
}
}
diff --git a/src/features/skipContinueWatching/index.ts b/src/features/skipContinueWatching/index.ts
new file mode 100644
index 00000000..53c71f00
--- /dev/null
+++ b/src/features/skipContinueWatching/index.ts
@@ -0,0 +1,20 @@
+import { browserColorLog, waitForSpecificMessage } from "@/src/utils/utilities";
+
+interface YtdWatchFlexyElement extends Element {
+ youthereDataChanged_: () => void;
+}
+
+export async function enableSkipContinueWatching() {
+ const optionsData = await waitForSpecificMessage("options", "request_data", "content");
+ const {
+ data: {
+ options: { enable_skip_continue_watching }
+ }
+ } = optionsData;
+ if (!enable_skip_continue_watching) return;
+ browserColorLog("Enabling skipContinueWatching", "FgMagenta");
+ const ytdWatchFlexyElement = document.querySelector("ytd-watch-flexy");
+ if (ytdWatchFlexyElement) {
+ (ytdWatchFlexyElement as YtdWatchFlexyElement).youthereDataChanged_ = function () {};
+ }
+}
diff --git a/src/features/volumeBoost/index.ts b/src/features/volumeBoost/index.ts
index 20480bd9..8baeaf1c 100644
--- a/src/features/volumeBoost/index.ts
+++ b/src/features/volumeBoost/index.ts
@@ -7,14 +7,15 @@ import eventManager from "@/src/utils/EventManager";
import { browserColorLog, formatError, waitForSpecificMessage } from "@/src/utils/utilities";
export default async function volumeBoost() {
- setupVolumeBoost();
const optionsData = await waitForSpecificMessage("options", "request_data", "content");
const {
data: {
- options: { volume_boost_amount, volume_boost_mode }
+ options: { enable_volume_boost, volume_boost_amount, volume_boost_mode }
}
} = optionsData;
+ if (!enable_volume_boost) return;
+ setupVolumeBoost();
if (volume_boost_mode === "per_video") {
await addVolumeBoostButton();
@@ -59,6 +60,7 @@ export function disableVolumeBoost() {
}
export function applyVolumeBoost(volume_boost_amount: number) {
browserColorLog(`Setting volume boost to ${Math.pow(10, volume_boost_amount / 20)}`, "FgMagenta");
+ if (!window.gainNode) setupVolumeBoost();
window.gainNode.gain.value = Math.pow(10, volume_boost_amount / 20);
}
export const addVolumeBoostButton: AddButtonFunction = async () => {
@@ -75,15 +77,15 @@ export const addVolumeBoostButton: AddButtonFunction = async () => {
"volumeBoostButton",
volumeBoostButtonPlacement,
volumeBoostButtonPlacement === "feature_menu" ?
- window.i18nextInstance.t("pages.content.features.volumeBoostButton.label")
- : window.i18nextInstance.t(`pages.content.features.volumeBoostButton.toggle.off`),
+ window.i18nextInstance.t("pages.content.features.volumeBoostButton.button.label")
+ : window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.off`),
getFeatureIcon("volumeBoostButton", volumeBoostButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"),
(checked) => {
void (async () => {
if (checked !== undefined) {
updateFeatureButtonTitle(
"volumeBoostButton",
- window.i18nextInstance.t(`pages.content.features.volumeBoostButton.toggle.${checked ? "on" : "off"}`)
+ window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.${checked ? "on" : "off"}`)
);
if (checked) {
await enableVolumeBoost();
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 97e47964..c1b8b312 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -1,6 +1,5 @@
+import useClickOutside from "./useClickOutside";
import useComponentVisible from "./useComponentVisible";
-import { useNotifications } from "./useNotifications";
-import useOuterClick from "./useOuterClick";
-import { useRunAfterUpdate } from "./useRunAfterUpdate";
-
-export { useComponentVisible, useNotifications, useOuterClick, useRunAfterUpdate };
+import useNotifications from "./useNotifications";
+import useRunAfterUpdate from "./useRunAfterUpdate";
+export { useClickOutside, useComponentVisible, useNotifications, useRunAfterUpdate };
diff --git a/src/hooks/useClickOutside.ts b/src/hooks/useClickOutside.ts
new file mode 100644
index 00000000..364f78c8
--- /dev/null
+++ b/src/hooks/useClickOutside.ts
@@ -0,0 +1,51 @@
+import type { Nullable } from "@/src/types";
+
+import { type RefObject, useEffect } from "react";
+
+// Improved version of https://usehooks.com/useOnClickOutside/
+
+const useClickOutside = (
+ ref: RefObject,
+
+ handler: (event: FocusEvent | MouseEvent | TouchEvent) => void
+) => {
+ useEffect(() => {
+ let startedInside: Nullable | boolean> = false;
+
+ let startedWhenMounted: Nullable["current"] | boolean> = false;
+
+ const listener = (event: FocusEvent | MouseEvent | TouchEvent) => {
+ // Do nothing if `mousedown` or `touchstart` started inside ref element
+
+ if (startedInside || !startedWhenMounted) return;
+
+ // Do nothing if clicking ref's element or descendent elements
+
+ if (!ref.current || ref.current.contains(event.target as Node)) return;
+
+ handler(event);
+ };
+
+ const validateEventStart = (event: FocusEvent | MouseEvent | TouchEvent) => {
+ ({ current: startedWhenMounted } = ref);
+
+ startedInside = event.target && ref.current && ref.current.contains(event.target as Node);
+ };
+
+ document.addEventListener("mousedown", validateEventStart);
+
+ document.addEventListener("touchstart", validateEventStart);
+
+ document.addEventListener("click", listener);
+
+ return () => {
+ document.removeEventListener("mousedown", validateEventStart);
+
+ document.removeEventListener("touchstart", validateEventStart);
+
+ document.removeEventListener("click", listener);
+ };
+ }, [ref, handler]);
+};
+
+export default useClickOutside;
diff --git a/src/hooks/useComponentVisible.ts b/src/hooks/useComponentVisible.ts
index 059d7c4e..263ad075 100644
--- a/src/hooks/useComponentVisible.ts
+++ b/src/hooks/useComponentVisible.ts
@@ -1,21 +1,26 @@
-import { useEffect, useRef, useState } from "react";
+import { type RefObject, useCallback, useEffect, useState } from "react";
-export default function useComponentVisible(initialIsVisible: boolean) {
+export default function useComponentVisible(
+ ref: RefObject,
+ initialIsVisible: boolean
+) {
const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible);
- const ref = useRef(null);
- const handleClickOutside = (event: MouseEvent) => {
- if (ref.current && !ref.current.contains(event.target as Node)) {
- setIsComponentVisible(false);
- }
- };
+ const handleClickOutside = useCallback(
+ (event: MouseEvent) => {
+ if (ref.current && !ref.current.contains(event.target as Node)) {
+ setIsComponentVisible(false);
+ }
+ },
+ [ref]
+ );
useEffect(() => {
document.addEventListener("click", handleClickOutside, true);
return () => {
document.removeEventListener("click", handleClickOutside, true);
};
- }, []);
+ }, [handleClickOutside]);
- return { isComponentVisible, ref, setIsComponentVisible };
+ return { isComponentVisible, setIsComponentVisible };
}
diff --git a/src/hooks/useNotifications/index.ts b/src/hooks/useNotifications/index.ts
index 4870a39f..5728e3f0 100644
--- a/src/hooks/useNotifications/index.ts
+++ b/src/hooks/useNotifications/index.ts
@@ -1,8 +1,7 @@
import { useContext } from "react";
import { NotificationsContext } from "./context";
-
-export const useNotifications = () => {
+const useNotifications = () => {
const context = useContext(NotificationsContext);
if (!context) {
throw new Error("useNotifications must be used within a NotificationsProvider");
@@ -10,3 +9,4 @@ export const useNotifications = () => {
return context;
};
+export default useNotifications;
diff --git a/src/hooks/useOuterClick.ts b/src/hooks/useOuterClick.ts
deleted file mode 100644
index d1ed0979..00000000
--- a/src/hooks/useOuterClick.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { type MutableRefObject, useEffect, useRef } from "react";
-
-export default function useOuterClick(
- callback: (...args: unknown[]) => unknown
-) {
- const callbackRef: MutableRefObject<((...args: unknown[]) => unknown) | undefined> = useRef(); // initialize mutable ref, which stores callback
- const innerRef: MutableRefObject = useRef(null); // returned to client, who marks "border" element
-
- // update cb on each render, so second useEffect has access to current value
- useEffect(() => {
- callbackRef.current = callback;
- });
-
- useEffect(() => {
- document.addEventListener("click", handleClick);
- return () => document.removeEventListener("click", handleClick);
- function handleClick(e: unknown) {
- if (
- e !== null &&
- typeof e === "object" &&
- "target" in e &&
- e.target !== null &&
- typeof e.target === "object" &&
- "contains" in e.target &&
- typeof e.target.contains === "function"
- ) {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
- if (innerRef && innerRef.current && callbackRef.current && !innerRef.current.contains(e.target as Node)) callbackRef.current(e);
- }
- }
- }, [innerRef]); // no dependencies -> stable click listener
-
- return innerRef; // convenience for client (doesn't need to init ref himself)
-}
diff --git a/src/hooks/useRunAfterUpdate.ts b/src/hooks/useRunAfterUpdate.ts
index 00bcfd48..27f35a19 100644
--- a/src/hooks/useRunAfterUpdate.ts
+++ b/src/hooks/useRunAfterUpdate.ts
@@ -2,7 +2,7 @@ import { useLayoutEffect, useRef } from "react";
import type { AnyFunction } from "../types";
-export const useRunAfterUpdate = () => {
+const useRunAfterUpdate = () => {
const handlersRef = useRef([]);
useLayoutEffect(() => {
@@ -14,3 +14,4 @@ export const useRunAfterUpdate = () => {
handlersRef.current.push(handler);
};
};
+export default useRunAfterUpdate;
diff --git a/src/hooks/useStorage.ts b/src/hooks/useStorage.ts
index 2cba957c..12a776b2 100644
--- a/src/hooks/useStorage.ts
+++ b/src/hooks/useStorage.ts
@@ -28,7 +28,7 @@ export function useStorage(key: string, initialValue: T, area: StorageArea =
if (changes[key].newValue) setStoredValue(changes[key].newValue as unknown as T);
}
});
- }, []);
+ }, [area, key]);
const setValueRef = useRef>();
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
index 9ae4ff3f..d5b6e7bc 100644
--- a/src/i18n/index.ts
+++ b/src/i18n/index.ts
@@ -2,49 +2,52 @@ import { type Resource, createInstance } from "i18next";
import { waitForSpecificMessage } from "../utils/utilities";
export const availableLocales = [
- "ca-ES",
- "cs-CZ",
- "de-DE",
- "en-US",
- "es-ES",
- "fa-IR",
- "fr-FR",
- "he-IL",
- "hi-IN",
- "it-IT",
- "ja-JP",
- "pl-PL",
- "pt-BR",
- "ru-RU",
- "sv-SE",
- "tr-TR",
- "zh-CN",
- "zh-TW"
+ "ca-ES",
+ "cs-CZ",
+ "de-DE",
+ "en-GB",
+ "en-US",
+ "es-ES",
+ "fa-IR",
+ "fr-FR",
+ "he-IL",
+ "hi-IN",
+ "it-IT",
+ "ja-JP",
+ "pl-PL",
+ "pt-BR",
+ "ru-RU",
+ "sv-SE",
+ "tr-TR",
+ "zh-CN",
+ "zh-TW"
] as const;
export const localePercentages: Record = {
"ca-ES": 0,
"cs-CZ": 0,
- "de-DE": 43,
+ "de-DE": 37,
+ "en-GB": 0,
"en-US": 100,
- "es-ES": 76,
+ "es-ES": 65,
"fa-IR": 0,
- "fr-FR": 80,
+ "fr-FR": 69,
"he-IL": 0,
"hi-IN": 0,
"it-IT": 0,
- "ja-JP": 99,
- "pl-PL": 1,
- "pt-BR": 90,
- "ru-RU": 99,
- "sv-SE": 99,
- "tr-TR": 63,
- "zh-CN": 99,
- "zh-TW": 99
+ "ja-JP": 92,
+ "pl-PL": 0,
+ "pt-BR": 76,
+ "ru-RU": 92,
+ "sv-SE": 85,
+ "tr-TR": 74,
+ "zh-CN": 92,
+ "zh-TW": 89
};
export const localeDirection: Record = {
"ca-ES": "ltr",
"cs-CZ": "ltr",
"de-DE": "ltr",
+ "en-GB": "ltr",
"en-US": "ltr",
"es-ES": "ltr",
"fa-IR": "rtl",
diff --git a/src/icons.ts b/src/icons.ts
index e2708191..52c4c085 100644
--- a/src/icons.ts
+++ b/src/icons.ts
@@ -1,19 +1,19 @@
-import type { ButtonPlacement, FeaturesThatHaveButtons } from "./types";
+import type { AllButtonNames, ButtonPlacement } from "./types";
import { createSVGElement } from "./utils/utilities";
export type ToggleIcon = { off: SVGSVGElement; on: SVGSVGElement };
export type BasicIcon = SVGSVGElement;
export const toggleFeatures = Object.keys({ loopButton: "", maximizePlayerButton: "", volumeBoostButton: "" } satisfies Partial<
- Record
+ Record
>);
export type ToggleFeatures = (typeof toggleFeatures)[number];
-export type IconType = T extends ToggleFeatures ? ToggleIcon : BasicIcon;
+export type IconType = T extends ToggleFeatures ? ToggleIcon : BasicIcon;
export type GetPlacementKey = Placement extends "feature_menu" ? "feature_menu" : "shared_icon_position";
-export type GetIconType = FeatureIconsType[Name][GetPlacementKey];
-export type FeatureIconsType = {
- [Feature in FeaturesThatHaveButtons]: {
+export type GetIconType = FeatureIconMap[Name][GetPlacementKey];
+export type FeatureIconMap = {
+ [ButtonName in AllButtonNames]: {
feature_menu: BasicIcon;
- shared_icon_position: IconType;
+ shared_icon_position: IconType;
};
};
@@ -195,7 +195,51 @@ const minimizePlayerSVG = createSVGElement(
"stroke-width": "1.5"
})
);
+const decreasePlaybackSpeedButtonSVG = createSVGElement(
+ "svg",
+ {
+ height: "24px",
+ stroke: "white",
+ "stroke-width": "1",
+ viewBox: "0 0 24 24",
+ width: "24px"
+ },
+ createSVGElement("path", {
+ d: "M10,8v8l6-4L10,8L10,8z M6.3,5L5.7,4.2C7.2,3,9,2.2,11,2l0.1,1C9.3,3.2,7.7,3.9,6.3,5z M5,6.3L4.2,5.7C3,7.2,2.2,9,2,11 l1,.1C3.2,9.3,3.9,7.7,5,6.3z M5,17.7c-1.1-1.4-1.8-3.1-2-4.8L2,13c0.2,2,1,3.8,2.2,5.4L5,17.7z M11.1,21c-1.8-0.2-3.4-0.9-4.8-2 l-0.6,.8C7.2,21,9,21.8,11,22L11.1,21z M22,12c0-5.2-3.9-9.4-9-10l-0.1,1c4.6,.5,8.1,4.3,8.1,9s-3.5,8.5-8.1,9l0.1,1 C18.2,21.5,22,17.2,22,12z",
+ fill: "white"
+ }),
+ createSVGElement("path", {
+ d: "M16 4.5a.75.75 0 000 1.5h6.5a.75.75 0 000-1.5h-6.5z",
+ fill: "white"
+ })
+);
+const increasePlaybackSpeedButtonSVG = createSVGElement(
+ "svg",
+ {
+ height: "24px",
+ stroke: "white",
+ "stroke-width": "1",
+ viewBox: "0 0 24 24",
+ width: "24px"
+ },
+ createSVGElement("path", {
+ d: "M10,8v8l6-4L10,8L10,8z M6.3,5L5.7,4.2C7.2,3,9,2.2,11,2l0.1,1C9.3,3.2,7.7,3.9,6.3,5z M5,6.3L4.2,5.7C3,7.2,2.2,9,2,11 l1,.1C3.2,9.3,3.9,7.7,5,6.3z M5,17.7c-1.1-1.4-1.8-3.1-2-4.8L2,13c0.2,2,1,3.8,2.2,5.4L5,17.7z M11.1,21c-1.8-0.2-3.4-0.9-4.8-2 l-0.6,.8C7.2,21,9,21.8,11,22L11.1,21z M22,12c0-5.2-3.9-9.4-9-10l-0.1,1c4.6,.5,8.1,4.3,8.1,9s-3.5,8.5-8.1,9l0.1,1 C18.2,21.5,22,17.2,22,12z",
+ fill: "white"
+ }),
+ createSVGElement("path", {
+ d: "M20 2a.75.75 0 00-1.5 0v2.5h-2.5a.75.75 0 000 1.5h2.5v2.5a.75.75 0 001.5 0v-2.5h2.5a.75.75 0 000-1.5h-2.5v-2.5z",
+ fill: "white"
+ })
+);
export const featureIcons = {
+ decreasePlaybackSpeedButton: {
+ feature_menu: decreasePlaybackSpeedButtonSVG,
+ shared_icon_position: decreasePlaybackSpeedButtonSVG
+ },
+ increasePlaybackSpeedButton: {
+ feature_menu: increasePlaybackSpeedButtonSVG,
+ shared_icon_position: increasePlaybackSpeedButtonSVG
+ },
loopButton: {
feature_menu: loopOnSVG,
shared_icon_position: {
@@ -225,8 +269,8 @@ export const featureIcons = {
on: volumeBoostOnSVG
}
}
-} satisfies FeatureIconsType;
-export function getFeatureIcon(
+} satisfies FeatureIconMap;
+export function getFeatureIcon(
featureName: Name,
placement: GetPlacementKey
) {
diff --git a/src/manifest.ts b/src/manifest.ts
index e97df952..b8034413 100755
--- a/src/manifest.ts
+++ b/src/manifest.ts
@@ -2,12 +2,30 @@ import type { Manifest } from "webextension-polyfill";
import pkg from "../package.json";
import { availableLocales } from "./i18n";
-
+const permissions: Manifest.Permission[] = ["activeTab", "webRequest", "storage", "tabs", "scripting"];
+const hostPermissions: Manifest.MatchPattern[] = ["https://www.youtube.com/*"];
+const resources = [
+ "contentStyle.css",
+ "/icons/icon_128.png",
+ "/icons/icon_48.png",
+ "/icons/icon_16.png",
+ "src/pages/content/index.js",
+ "src/pages/embedded/index.js",
+ ...availableLocales.map((locale) => `/locales/${locale}.json`)
+];
+const icons = {
+ "16": "/icons/icon_16.png",
+ "19": "/icons/icon_19.png",
+ "38": "/icons/icon_38.png",
+ "48": "/icons/icon_48.png",
+ "128": "/icons/icon_128.png"
+};
+const action = {
+ default_icon: "/icons/icon_48.png",
+ default_popup: "src/pages/popup/index.html"
+};
const manifestV3: Manifest.WebExtensionManifest = {
- action: {
- default_icon: "/icons/icon_48.png",
- default_popup: "src/pages/popup/index.html"
- },
+ action,
author: pkg.author.name,
background: {
service_worker: "src/pages/background/index.js",
@@ -17,38 +35,25 @@ const manifestV3: Manifest.WebExtensionManifest = {
{
all_frames: true,
css: ["contentStyle.css"],
- js: ["src/pages/inject/index.js"],
+ js: ["src/pages/content/index.js"],
matches: ["https://www.youtube.com/*"],
run_at: "document_start"
}
],
description: pkg.description,
- icons: {
- "16": "/icons/icon_16.png",
- "19": "/icons/icon_19.png",
- "38": "/icons/icon_38.png",
- "48": "/icons/icon_48.png",
- "128": "/icons/icon_128.png"
- },
+ host_permissions: hostPermissions,
+ icons,
manifest_version: 3,
name: pkg.displayName,
options_ui: {
page: "src/pages/options/index.html"
},
- permissions: ["activeTab", "webRequest", "storage", "tabs"],
+ permissions,
version: pkg.version,
web_accessible_resources: [
{
matches: ["https://www.youtube.com/*"],
- resources: [
- "contentStyle.css",
- "/icons/icon_128.png",
- "/icons/icon_48.png",
- "/icons/icon_16.png",
- "src/pages/content/index.js",
- "src/pages/inject/index.js",
- ...availableLocales.map((locale) => `/locales/${locale}.json`)
- ]
+ resources
}
]
};
@@ -57,10 +62,7 @@ const manifestV2: Manifest.WebExtensionManifest = {
background: {
scripts: ["src/pages/background/index.js"]
},
- browser_action: {
- default_icon: "/icons/icon_48.png",
- default_popup: "src/pages/popup/index.html"
- },
+ browser_action: action,
browser_specific_settings: {
gecko: {
id: "{c49b13b1-5dee-4345-925e-0c793377e3fa}"
@@ -69,35 +71,21 @@ const manifestV2: Manifest.WebExtensionManifest = {
content_scripts: [
{
css: ["contentStyle.css"],
- js: ["src/pages/inject/index.js"],
+ js: ["src/pages/content/index.js"],
matches: ["https://www.youtube.com/*"],
run_at: "document_start"
}
],
description: pkg.description,
- icons: {
- "16": "/icons/icon_16.png",
- "19": "/icons/icon_19.png",
- "38": "/icons/icon_38.png",
- "48": "/icons/icon_48.png",
- "128": "/icons/icon_128.png"
- },
+ icons,
manifest_version: 2,
name: pkg.displayName,
options_ui: {
page: "src/pages/options/index.html"
},
- permissions: ["activeTab", "webRequest", "storage", "tabs"],
+ permissions: permissions.concat(hostPermissions),
version: pkg.version,
- web_accessible_resources: [
- "contentStyle.css",
- "/icons/icon_128.png",
- "/icons/icon_48.png",
- "/icons/icon_16.png",
- "src/pages/content/index.js",
- "src/pages/inject/index.js",
- ...availableLocales.map((locale) => `/locales/${locale}.json`)
- ]
+ web_accessible_resources: resources
};
export { manifestV2, manifestV3 };
diff --git a/src/pages/background/index.ts b/src/pages/background/index.ts
index d8a31dd2..02cd4daa 100644
--- a/src/pages/background/index.ts
+++ b/src/pages/background/index.ts
@@ -1,3 +1,8 @@
+import type { ContentToBackgroundSendOnlyMessageMappings, configuration, configurationKeys } from "@/src/types";
+
+import { defaultConfiguration } from "@/src/utils/constants";
+import { parseStoredValue } from "@/src/utils/utilities";
+
import pkg from "../../../package.json";
chrome.runtime.onInstalled.addListener((details) => {
@@ -18,6 +23,7 @@ chrome.runtime.onInstalled.addListener((details) => {
// Open options page if a new major or minor version is released
void chrome.tabs.create({ url: "/src/pages/options/index.html" });
}
+ void updateStoredSettings();
break;
}
}
@@ -34,3 +40,101 @@ function isNewMajorVersion(oldVersion: VersionString, newVersion: VersionString)
const [newMajorVersion] = newVersion.split(".");
return oldMajorVersion !== newMajorVersion;
}
+chrome.runtime.onMessage.addListener((message: ContentToBackgroundSendOnlyMessageMappings[keyof ContentToBackgroundSendOnlyMessageMappings]) => {
+ switch (message.type) {
+ case "pauseBackgroundPlayers": {
+ // Get the active tab's ID
+ chrome.tabs.query({ active: true, currentWindow: true }, (activeTabs) => {
+ const [activeTab] = activeTabs;
+ const { id: activeTabId } = activeTab;
+ // Query all tabs except the active one
+ chrome.tabs.query({ url: "https://www.youtube.com/*" }, (tabs) => {
+ for (const tab of tabs) {
+ // Skip the active tab
+ if (tab.id === activeTabId) continue;
+ if (tab.id !== undefined) {
+ chrome.scripting.executeScript(
+ {
+ func: () => {
+ const videos = document.querySelectorAll("video");
+ videos.forEach((video) => {
+ if (!video.paused) {
+ video.pause();
+ }
+ });
+ const audios = document.querySelectorAll("audio");
+ audios.forEach((audio) => {
+ if (!audio.paused) {
+ audio.pause();
+ }
+ });
+ },
+ target: { tabId: tab.id }
+ },
+ (results) => {
+ if (chrome.runtime.lastError) {
+ console.error(chrome.runtime.lastError.message);
+ } else {
+ if (results[0].result) {
+ console.log(results);
+ }
+ }
+ }
+ );
+ }
+ }
+ });
+ });
+ break;
+ }
+ }
+});
+const changedKeys = Object.keys({
+ osd_display_type: ""
+} satisfies Partial>);
+async function updateStoredSettings() {
+ try {
+ const settings = await getStoredSettings();
+ const removedKeys = Object.keys(settings).filter((key) => !Object.keys(defaultConfiguration).includes(key));
+ for (const changedKey of changedKeys) {
+ switch (changedKey) {
+ case "osd_display_type": {
+ if ((settings.osd_display_type as unknown as string) === "round") {
+ settings.osd_display_type = "circle";
+ }
+ break;
+ }
+ }
+ }
+ for (const key of removedKeys) {
+ delete settings[key];
+ }
+ await setModifiedSettings(settings);
+ } catch (error) {
+ console.error("Failed to update stored settings:", error);
+ }
+}
+async function setModifiedSettings(settings: Partial) {
+ const updates: Record = {};
+ for (const [key, value] of Object.entries(settings)) {
+ updates[key] = typeof value !== "string" ? JSON.stringify(value) : value;
+ }
+ await chrome.storage.local.set(updates);
+}
+async function getStoredSettings(): Promise {
+ return new Promise((resolve, reject) => {
+ chrome.storage.local.get((settings) => {
+ try {
+ const storedSettings: Partial = (
+ Object.keys(settings)
+ .filter((key) => typeof key === "string")
+ .filter((key) => Object.keys(defaultConfiguration).includes(key as unknown as string)) as configurationKeys[]
+ ).reduce((acc, key) => Object.assign(acc, { [key]: parseStoredValue(settings[key] as string) }), {});
+ const castedSettings = storedSettings as configuration;
+ resolve(castedSettings);
+ } catch (error) {
+ reject(error);
+ }
+ });
+ });
+}
diff --git a/src/pages/inject/index.tsx b/src/pages/content/index.ts
similarity index 67%
rename from src/pages/inject/index.tsx
rename to src/pages/content/index.ts
index 777b5c02..8a9eb621 100644
--- a/src/pages/inject/index.tsx
+++ b/src/pages/content/index.ts
@@ -2,15 +2,16 @@ import type { AvailableLocales } from "@/src/i18n";
import { getVideoHistory, setVideoHistory } from "@/src/features/videoHistory/utils";
import {
+ type AllButtonNames,
type ButtonPlacement,
type ContentSendOnlyMessageMappings,
- type FeaturesThatHaveButtons,
+ type ContentToBackgroundSendOnlyMessageMappings,
type Messages,
type RememberedVolumes,
type StorageChanges,
+ buttonNames,
type configuration,
- type configurationKeys,
- featuresThatHaveButtons
+ type configurationKeys
} from "@/src/types";
import { defaultConfiguration } from "@/src/utils/constants";
import { parseStoredValue, sendExtensionMessage, sendExtensionOnlyMessage } from "@/src/utils/utilities";
@@ -20,7 +21,7 @@ import { parseStoredValue, sendExtensionMessage, sendExtensionOnlyMessage } from
* Also creates a hidden div element with a specific ID to receive messages from the extension.
*/
const script = document.createElement("script");
-script.src = chrome.runtime.getURL("src/pages/content/index.js");
+script.src = chrome.runtime.getURL("src/pages/embedded/index.js");
script.type = "text/javascript";
function initializeCommunicationElement() {
const element = document.createElement("div");
@@ -30,6 +31,7 @@ function initializeCommunicationElement() {
}
initializeCommunicationElement();
document.documentElement.appendChild(script);
+
void (async () => {
/**
* Retrieves the options from the local storage and sends them back to the youtube page.
@@ -62,37 +64,44 @@ document.addEventListener("yte-message-from-youtube", () => {
if (!stringifiedMessage) return;
let message;
try {
- message = JSON.parse(stringifiedMessage) as ContentSendOnlyMessageMappings[keyof ContentSendOnlyMessageMappings] | Messages["request"];
+ message = JSON.parse(stringifiedMessage) as
+ | ContentSendOnlyMessageMappings[keyof ContentSendOnlyMessageMappings]
+ | ContentToBackgroundSendOnlyMessageMappings[keyof ContentToBackgroundSendOnlyMessageMappings]
+ | Messages["request"];
} catch (error) {
console.error(error);
return;
}
if (!message) return;
- switch (message.type) {
- case "options": {
- /**
- * Retrieves the options from the local storage and sends them back to the youtube page.
- *
- * @type {configuration}
- */
- const options: configuration = await new Promise((resolve) => {
- chrome.storage.local.get((settings) => {
- const storedSettings: Partial = (
- Object.keys(settings)
- .filter((key) => typeof key === "string")
- .filter((key) => Object.keys(defaultConfiguration).includes(key as unknown as string)) as configurationKeys[]
- ).reduce((acc, key) => Object.assign(acc, { [key]: parseStoredValue(settings[key] as string) }), {});
- resolve(storedSettings as configuration);
- });
- });
- void sendExtensionMessage("options", "data_response", { options });
+ switch (message.action) {
+ case "request_action": {
+ await chrome.runtime.sendMessage(message);
break;
}
- case "videoHistoryOne": {
- const { action, data } = message;
- if (!data) return;
- switch (action) {
- case "request_data": {
+ case "request_data": {
+ switch (message.type) {
+ case "options": {
+ /**
+ * Retrieves the options from the local storage and sends them back to the youtube page.
+ *
+ * @type {configuration}
+ */
+ const options: configuration = await new Promise((resolve) => {
+ chrome.storage.local.get((settings) => {
+ const storedSettings: Partial = (
+ Object.keys(settings)
+ .filter((key) => typeof key === "string")
+ .filter((key) => Object.keys(defaultConfiguration).includes(key as unknown as string)) as configurationKeys[]
+ ).reduce((acc, key) => Object.assign(acc, { [key]: parseStoredValue(settings[key] as string) }), {});
+ resolve(storedSettings as configuration);
+ });
+ });
+ void sendExtensionMessage("options", "data_response", { options });
+ break;
+ }
+ case "videoHistoryOne": {
+ const { data } = message;
+ if (!data) return;
const { id } = data;
const videoHistory = getVideoHistory();
void sendExtensionMessage("videoHistoryOne", "data_response", {
@@ -100,7 +109,53 @@ document.addEventListener("yte-message-from-youtube", () => {
});
break;
}
- case "send_data": {
+ case "videoHistoryAll": {
+ const videoHistory = getVideoHistory();
+ void sendExtensionMessage("videoHistoryAll", "data_response", {
+ video_history_entries: videoHistory
+ });
+ break;
+ }
+ case "extensionURL": {
+ void sendExtensionMessage("extensionURL", "data_response", {
+ extensionURL: chrome.runtime.getURL("")
+ });
+ break;
+ }
+
+ case "language": {
+ const language = await new Promise((resolve) => {
+ chrome.storage.local.get("language", (o) => {
+ resolve(o.language as AvailableLocales);
+ });
+ });
+ void sendExtensionMessage("language", "data_response", {
+ language
+ });
+ break;
+ }
+ }
+ break;
+ }
+ case "send_data": {
+ switch (message.type) {
+ case "setRememberedVolume": {
+ const { remembered_volumes: existingRememberedVolumeStringified } = await chrome.storage.local.get("remembered_volumes");
+ const existingRememberedVolumes = parseStoredValue(existingRememberedVolumeStringified as string) as RememberedVolumes;
+ void chrome.storage.local.set({ remembered_volumes: JSON.stringify({ ...existingRememberedVolumes, ...message.data }) });
+ break;
+ }
+
+ case "pageLoaded": {
+ chrome.storage.onChanged.addListener(storageListeners);
+ window.onunload = () => {
+ chrome.storage.onChanged.removeListener(storageListeners);
+ };
+ break;
+ }
+ case "videoHistoryOne": {
+ const { data } = message;
+ if (!data) return;
const { video_history_entry } = data;
if (!video_history_entry) return;
const { id, status, timestamp } = video_history_entry;
@@ -108,43 +163,6 @@ document.addEventListener("yte-message-from-youtube", () => {
break;
}
}
- break;
- }
- case "videoHistoryAll": {
- const videoHistory = getVideoHistory();
- void sendExtensionMessage("videoHistoryAll", "data_response", {
- video_history_entries: videoHistory
- });
- break;
- }
- case "setRememberedVolume": {
- const { remembered_volumes: existingRememberedVolumeStringified } = await chrome.storage.local.get("remembered_volumes");
- const existingRememberedVolumes = parseStoredValue(existingRememberedVolumeStringified as string) as RememberedVolumes;
- void chrome.storage.local.set({ remembered_volumes: JSON.stringify({ ...existingRememberedVolumes, ...message.data }) });
- break;
- }
- case "extensionURL": {
- void sendExtensionMessage("extensionURL", "data_response", {
- extensionURL: chrome.runtime.getURL("")
- });
- break;
- }
- case "language": {
- const language = await new Promise((resolve) => {
- chrome.storage.local.get("language", (o) => {
- resolve(o.language as AvailableLocales);
- });
- });
- void sendExtensionMessage("language", "data_response", {
- language
- });
- break;
- }
- case "pageLoaded": {
- chrome.storage.onChanged.addListener(storageListeners);
- window.onunload = () => {
- chrome.storage.onChanged.removeListener(storageListeners);
- };
}
}
})();
@@ -201,7 +219,7 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) =
} = {
button_placements: (oldValue, newValue) => {
sendExtensionOnlyMessage("buttonPlacementChange", {
- buttonPlacement: featuresThatHaveButtons.reduce(
+ buttonPlacement: buttonNames.reduce(
(acc, feature) => {
const { [feature]: oldPlacement } = oldValue;
const { [feature]: newPlacement } = newValue;
@@ -212,7 +230,7 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) =
}
});
},
- {} as Record
+ {} as Record
)
});
},
@@ -222,6 +240,20 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) =
customCSSEnabled: options.enable_custom_css
});
},
+ deep_dark_custom_theme_colors: (__oldValue, newValue) => {
+ sendExtensionOnlyMessage("deepDarkThemeChange", {
+ deepDarkCustomThemeColors: newValue,
+ deepDarkPreset: options.deep_dark_preset,
+ deepDarkThemeEnabled: options.enable_deep_dark_theme
+ });
+ },
+ deep_dark_preset: (__oldValue, newValue) => {
+ sendExtensionOnlyMessage("deepDarkThemeChange", {
+ deepDarkCustomThemeColors: options.deep_dark_custom_theme_colors,
+ deepDarkPreset: newValue,
+ deepDarkThemeEnabled: options.enable_deep_dark_theme
+ });
+ },
enable_automatic_theater_mode: (__oldValue, newValue) => {
sendExtensionOnlyMessage("automaticTheaterModeChange", {
automaticTheaterModeEnabled: newValue
@@ -230,6 +262,13 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) =
enable_custom_css: (__oldValue, newValue) => {
sendExtensionOnlyMessage("customCSSChange", { customCSSCode: options.custom_css_code, customCSSEnabled: newValue });
},
+ enable_deep_dark_theme: (__oldValue, newValue) => {
+ sendExtensionOnlyMessage("deepDarkThemeChange", {
+ deepDarkCustomThemeColors: options.deep_dark_custom_theme_colors,
+ deepDarkPreset: options.deep_dark_preset,
+ deepDarkThemeEnabled: newValue
+ });
+ },
enable_forced_playback_speed: (__oldValue, newValue) => {
sendExtensionOnlyMessage("playerSpeedChange", {
enableForcedPlaybackSpeed: newValue,
@@ -266,6 +305,17 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) =
openYouTubeSettingsOnHoverEnabled: newValue
});
},
+ enable_pausing_background_players: (__oldValue, newValue) => {
+ sendExtensionOnlyMessage("pauseBackgroundPlayersChange", {
+ pauseBackgroundPlayersEnabled: newValue
+ });
+ },
+ enable_playback_speed_buttons: (__oldValue, newValue) => {
+ sendExtensionOnlyMessage("playbackSpeedButtonsChange", {
+ playbackButtonsSpeed: options.playback_buttons_speed,
+ playbackSpeedButtonsEnabled: newValue
+ });
+ },
enable_redirect_remover: (__oldValue, newValue) => {
sendExtensionOnlyMessage("removeRedirectChange", {
removeRedirectEnabled: newValue
@@ -306,6 +356,11 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) =
shortsAutoScrollEnabled: newValue
});
},
+ enable_skip_continue_watching: (__oldValue, newValue) => {
+ sendExtensionOnlyMessage("skipContinueWatchingChange", {
+ skipContinueWatchingEnabled: newValue
+ });
+ },
enable_video_history: (__oldValue, newValue) => {
sendExtensionOnlyMessage("videoHistoryChange", {
videoHistoryEnabled: newValue
@@ -327,6 +382,12 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) =
language: newValue
});
},
+ playback_buttons_speed: (__oldValue, newValue) => {
+ sendExtensionOnlyMessage("playbackSpeedButtonsChange", {
+ playbackButtonsSpeed: newValue,
+ playbackSpeedButtonsEnabled: options.enable_playback_speed_buttons
+ });
+ },
player_speed: (__oldValue, newValue) => {
sendExtensionOnlyMessage("playerSpeedChange", {
enableForcedPlaybackSpeed: options.enable_forced_playback_speed,
diff --git a/src/pages/content/index.tsx b/src/pages/embedded/index.ts
similarity index 81%
rename from src/pages/content/index.tsx
rename to src/pages/embedded/index.ts
index ef98a96a..c90cb003 100644
--- a/src/pages/content/index.tsx
+++ b/src/pages/embedded/index.ts
@@ -1,11 +1,13 @@
-import type { ExtensionSendOnlyMessageMappings, Messages, YouTubePlayerDiv } from "@/src/types";
-
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+import { deepDarkPresets } from "@/src/deepDarkPresets";
import { type FeatureFuncRecord, featureButtonFunctions } from "@/src/features";
import { automaticTheaterMode } from "@/src/features/automaticTheaterMode";
import { featuresInControls } from "@/src/features/buttonPlacement";
import { checkIfFeatureButtonExists, getFeatureButton, updateFeatureButtonTitle } from "@/src/features/buttonPlacement/utils";
import { disableCustomCSS, enableCustomCSS } from "@/src/features/customCSS";
import { customCSSExists, updateCustomCSS } from "@/src/features/customCSS/utils";
+import { disableDeepDarkCSS, enableDeepDarkCSS } from "@/src/features/deepDarkCSS";
+import { deepDarkCSSExists, getDeepDarkCustomThemeStyle, updateDeepDarkCSS } from "@/src/features/deepDarkCSS/utils";
import { enableFeatureMenu, setupFeatureMenuEventListeners } from "@/src/features/featureMenu";
import { featuresInMenu, updateFeatureMenuItemLabel, updateFeatureMenuTitle } from "@/src/features/featureMenu/utils";
import { enableHideScrollBar } from "@/src/features/hideScrollBar";
@@ -17,6 +19,13 @@ import { maximizePlayer } from "@/src/features/maximizePlayerButton/utils";
import { openTranscriptButton } from "@/src/features/openTranscriptButton";
import { removeOpenTranscriptButton } from "@/src/features/openTranscriptButton/utils";
import { disableOpenYouTubeSettingsOnHover, enableOpenYouTubeSettingsOnHover } from "@/src/features/openYouTubeSettingsOnHover";
+import { disablePauseBackgroundPlayers, enablePauseBackgroundPlayers } from "@/src/features/pauseBackgroundPlayers";
+import {
+ addDecreasePlaybackSpeedButton,
+ addIncreasePlaybackSpeedButton,
+ removeDecreasePlaybackSpeedButton,
+ removeIncreasePlaybackSpeedButton
+} from "@/src/features/playbackSpeedButtons";
import setPlayerQuality from "@/src/features/playerQuality";
import { restorePlayerSpeed, setPlayerSpeed, setupPlaybackSpeedChangeListener } from "@/src/features/playerSpeed";
import { removeRemainingTimeDisplay, setupRemainingTime } from "@/src/features/remainingTime";
@@ -27,6 +36,7 @@ import adjustSpeedOnScrollWheel from "@/src/features/scrollWheelSpeedControl";
import adjustVolumeOnScrollWheel from "@/src/features/scrollWheelVolumeControl";
import { disableShareShortener, enableShareShortener } from "@/src/features/shareShortener";
import { disableShortsAutoScroll, enableShortsAutoScroll } from "@/src/features/shortsAutoScroll";
+import { enableSkipContinueWatching } from "@/src/features/skipContinueWatching";
import { promptUserToResumeVideo, setupVideoHistory } from "@/src/features/videoHistory";
import volumeBoost, {
addVolumeBoostButton,
@@ -37,9 +47,20 @@ import volumeBoost, {
} from "@/src/features/volumeBoost";
import { i18nService } from "@/src/i18n";
import { type ToggleFeatures, toggleFeatures } from "@/src/icons";
+import {
+ type ExtensionSendOnlyMessageMappings,
+ type Messages,
+ type MultiButtonFeatureNames,
+ type MultiButtonNames,
+ type SingleButtonFeatureNames,
+ type SingleButtonNames,
+ type YouTubePlayerDiv,
+ featureToMultiButtonsMap
+} from "@/src/types";
import eventManager from "@/utils/EventManager";
import {
browserColorLog,
+ findKeyByValue,
formatError,
isShortsPage,
isWatchPage,
@@ -106,9 +127,12 @@ const enableFeatures = () => {
enableHideShorts(),
removeRedirect(),
enableShareShortener(),
+ enableSkipContinueWatching(),
+ enablePauseBackgroundPlayers(),
enableRememberVolume(),
enableHideScrollBar(),
- enableCustomCSS()
+ enableCustomCSS(),
+ enableDeepDarkCSS()
]);
// Use a guard clause to reduce amount of times nesting code happens
@@ -128,6 +152,8 @@ const enableFeatures = () => {
setPlayerSpeed(),
openTranscriptButton(),
addLoopButton(),
+ addIncreasePlaybackSpeedButton(),
+ addDecreasePlaybackSpeedButton(),
addMaximizePlayerButton(),
addScreenshotButton(),
volumeBoost(),
@@ -275,6 +301,19 @@ window.addEventListener("DOMContentLoaded", function () {
}
break;
}
+ case "playbackSpeedButtonsChange": {
+ const {
+ data: { playbackSpeedButtonsEnabled }
+ } = message;
+ if (playbackSpeedButtonsEnabled) {
+ await addDecreasePlaybackSpeedButton();
+ await addIncreasePlaybackSpeedButton();
+ } else {
+ await removeDecreasePlaybackSpeedButton();
+ await removeIncreasePlaybackSpeedButton();
+ }
+ break;
+ }
case "scrollWheelVolumeControlChange": {
const {
data: { scrollWheelVolumeControlEnabled }
@@ -341,24 +380,50 @@ window.addEventListener("DOMContentLoaded", function () {
} = message;
window.i18nextInstance = await i18nService(language);
if (featuresInMenu.size > 0) {
- updateFeatureMenuTitle(window.i18nextInstance.t("pages.content.features.featureMenu.label"));
+ updateFeatureMenuTitle(window.i18nextInstance.t("pages.content.features.featureMenu.button.label"));
for (const feature of featuresInMenu) {
- updateFeatureMenuItemLabel(feature, window.i18nextInstance.t(`pages.content.features.${feature}.label`));
+ const featureName = findKeyByValue(feature as MultiButtonNames) ?? (feature as SingleButtonFeatureNames);
+ if (featureToMultiButtonsMap.has(featureName)) {
+ updateFeatureMenuItemLabel(
+ feature,
+ window.i18nextInstance.t(
+ `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label`
+ )
+ );
+ } else {
+ updateFeatureMenuItemLabel(
+ feature,
+ window.i18nextInstance.t(`pages.content.features.${featureName as SingleButtonNames}.button.label`)
+ );
+ }
}
}
if (featuresInControls.size > 0) {
for (const feature of featuresInControls) {
+ const featureName = findKeyByValue(feature as MultiButtonNames) ?? (feature as SingleButtonFeatureNames);
if (toggleFeatures.includes(feature)) {
const toggleFeature = feature as ToggleFeatures;
const featureButton = getFeatureButton(toggleFeature);
if (!featureButton) return;
const buttonChecked = JSON.parse(featureButton.ariaChecked ?? "false") as boolean;
updateFeatureButtonTitle(
- feature,
- window.i18nextInstance.t(`pages.content.features.${toggleFeature}.toggle.${buttonChecked ? "on" : "off"}`)
+ toggleFeature,
+ window.i18nextInstance.t(`pages.content.features.${toggleFeature}.button.toggle.${buttonChecked ? "on" : "off"}`)
);
} else {
- updateFeatureButtonTitle(feature, window.i18nextInstance.t(`pages.content.features.${feature}.label`));
+ if (featureToMultiButtonsMap.has(featureName)) {
+ updateFeatureMenuItemLabel(
+ feature,
+ window.i18nextInstance.t(
+ `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label`
+ )
+ );
+ } else {
+ updateFeatureButtonTitle(
+ feature,
+ window.i18nextInstance.t(`pages.content.features.${featureName as SingleButtonNames}.button.label`)
+ );
+ }
}
}
}
@@ -418,6 +483,17 @@ window.addEventListener("DOMContentLoaded", function () {
}
break;
}
+ case "pauseBackgroundPlayersChange": {
+ const {
+ data: { pauseBackgroundPlayersEnabled }
+ } = message;
+ if (pauseBackgroundPlayersEnabled) {
+ await enablePauseBackgroundPlayers();
+ } else {
+ disablePauseBackgroundPlayers();
+ }
+ break;
+ }
case "shareShortenerChange": {
const {
data: { shareShortenerEnabled }
@@ -429,6 +505,32 @@ window.addEventListener("DOMContentLoaded", function () {
}
break;
}
+ case "skipContinueWatchingChange": {
+ const {
+ data: { skipContinueWatchingEnabled }
+ } = message;
+ if (skipContinueWatchingEnabled) {
+ await enableSkipContinueWatching();
+ }
+ break;
+ }
+ case "deepDarkThemeChange": {
+ const {
+ data: { deepDarkCustomThemeColors, deepDarkPreset, deepDarkThemeEnabled }
+ } = message;
+ if (deepDarkThemeEnabled) {
+ if (deepDarkCSSExists()) {
+ updateDeepDarkCSS(
+ deepDarkPreset === "Custom" ? getDeepDarkCustomThemeStyle(deepDarkCustomThemeColors) : deepDarkPresets[deepDarkPreset]
+ );
+ } else {
+ await enableDeepDarkCSS();
+ }
+ } else {
+ disableDeepDarkCSS();
+ }
+ break;
+ }
case "customCSSChange": {
const {
data: { customCSSCode, customCSSEnabled }
diff --git a/src/pages/content/style.css b/src/pages/embedded/style.css
similarity index 100%
rename from src/pages/content/style.css
rename to src/pages/embedded/style.css
diff --git a/src/types/index.ts b/src/types/index.ts
index cebbb0a4..9d6deefd 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -3,20 +3,90 @@ import type { YouTubePlayer } from "youtube-player/dist/types";
import z, { ZodType } from "zod";
+import type { DeepDarkPreset } from "../deepDarkPresets";
import type { AvailableLocales } from "../i18n";
-import type { FeatureName } from "../utils/EventManager";
+// #region Utility types
+export type Nullable = T | null;
export type AnyFunction = (...args: any[]) => void;
export type Writeable = { -readonly [P in keyof T]: T[P] };
export type DeepWriteable = { -readonly [P in keyof T]: DeepWriteable };
-export const onScreenDisplayColor = ["red", "green", "blue", "yellow", "orange", "purple", "pink", "white"] as const;
-export type OnScreenDisplayColor = (typeof onScreenDisplayColor)[number];
-export const onScreenDisplayType = ["no_display", "text", "line", "round"] as const;
-export type OnScreenDisplayType = (typeof onScreenDisplayType)[number];
-export const onScreenDisplayPosition = ["top_left", "top_right", "bottom_left", "bottom_right", "center"] as const;
-export type OnScreenDisplayPosition = (typeof onScreenDisplayPosition)[number];
-export const youtubePlayerQualityLabel = ["144p", "240p", "360p", "480p", "720p", "1080p", "1440p", "2160p", "2880p", "4320p", "auto"] as const;
-export type YoutubePlayerQualityLabel = (typeof youtubePlayerQualityLabel)[number];
-export const youtubePlayerQualityLevel = [
+export type WithId = `#${S}`;
+export type Prettify = {
+ [K in keyof T]: T[K];
+};
+export type ExtractButtonFeatureNames =
+ T extends `pages.content.features.${infer FeatureName}.button.label` ? FeatureName
+ : T extends `pages.content.features.${infer FeatureName}.buttons.${string}.label` ? FeatureName
+ : never;
+export type ExtractButtonNames =
+ T extends `pages.content.features.${infer ButtonName}.button.label` ? ButtonName
+ : T extends `pages.content.features.${string}.buttons.${infer ButtonName}.label` ? ButtonName
+ : never;
+// Taken from https://github.com/colinhacks/zod/issues/53#issuecomment-1681090113
+type TypeToZod = {
+ [K in keyof T]: T[K] extends boolean | null | number | string | undefined ?
+ undefined extends T[K] ?
+ z.ZodOptional>>
+ : z.ZodType
+ : z.ZodObject>;
+};
+export type TypeToZodSchema = z.ZodObject<{
+ [K in keyof T]: T[K] extends any[] ? z.ZodArray>
+ : T[K] extends object ? z.ZodObject>
+ : z.ZodType;
+}>;
+export type TypeToPartialZodSchema<
+ Input,
+ Omitted extends keyof Input = never,
+ Override extends { [Key in Omitted]: ZodType } = never,
+ Omit = false
+> = z.ZodObject<
+ Omit extends true ? OmitAndOverride
+ : {
+ [K in keyof Input]: Input[K] extends any[] ? z.ZodOptionalType>
+ : Input[K] extends object ? z.ZodOptionalType>>
+ : z.ZodOptionalType>;
+ }
+>;
+type PathImpl =
+ Key extends string ?
+ T[Key] extends Record ?
+ T[Key] extends ArrayLike ?
+ `${Key}.${PathImpl>}` | Key
+ : `${Key}.${PathImpl}` | Key
+ : Key
+ : never;
+export type Path = PathImpl | keyof T;
+export type PathValue> =
+ P extends `${infer Key}.${infer Rest}` ?
+ Key extends keyof T ?
+ Rest extends Path ?
+ PathValue
+ : never
+ : never
+ : P extends keyof T ? T[P]
+ : never;
+export type OmitAndOverride = {
+ [K in keyof Omit ]: Omit [K] extends any[] ? z.ZodOptionalType[K]>>
+ : Omit [K] extends object ? z.ZodOptionalType[K]>>>
+ : z.ZodOptionalType[K]>>;
+} & Override;
+export type FilterKeysByValueType = {
+ [K in keyof O]: O[K] extends ValueType ? K
+ : O[K] extends Record ? K
+ : never;
+}[keyof O];
+// #endregion Utility types
+// #region Constants
+export const onScreenDisplayColors = ["red", "green", "blue", "yellow", "orange", "purple", "pink", "white"] as const;
+export type OnScreenDisplayColor = (typeof onScreenDisplayColors)[number];
+export const onScreenDisplayTypes = ["no_display", "text", "line", "circle"] as const;
+export type OnScreenDisplayType = (typeof onScreenDisplayTypes)[number];
+export const onScreenDisplayPositions = ["top_left", "top_right", "bottom_left", "bottom_right", "center"] as const;
+export type OnScreenDisplayPosition = (typeof onScreenDisplayPositions)[number];
+export const youtubePlayerQualityLabels = ["144p", "240p", "360p", "480p", "720p", "1080p", "1440p", "2160p", "2880p", "4320p", "auto"] as const;
+export type YoutubePlayerQualityLabel = (typeof youtubePlayerQualityLabels)[number];
+export const youtubePlayerQualityLevels = [
"tiny",
"small",
"medium",
@@ -29,88 +99,58 @@ export const youtubePlayerQualityLevel = [
"highres",
"auto"
] as const;
-export type YoutubePlayerQualityLevel = (typeof youtubePlayerQualityLevel)[number];
-export const youtubePlayerSpeedRateExtended = [2.25, 2.5, 2.75, 3, 3.25, 3.75, 4] as const;
-export const youtubePlayerSpeedRate = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, ...youtubePlayerSpeedRateExtended] as const;
-
-export const screenshotType = ["file", "clipboard"] as const;
-export type ScreenshotType = (typeof screenshotType)[number];
-export const screenshotFormat = ["png", "jpg", "webp"] as const;
-
-export type ScreenshotFormat = (typeof screenshotFormat)[number];
-export const modifierKey = ["altKey", "ctrlKey", "shiftKey"] as const;
-export type ModifierKey = (typeof modifierKey)[number];
-export type RememberedVolumes = { shortsPageVolume?: number; watchPageVolume?: number };
-export const volumeBoostMode = ["global", "per_video"] as const;
-export type VolumeBoostMode = (typeof volumeBoostMode)[number];
-export const buttonPlacement = ["below_player", "feature_menu", "player_controls_left", "player_controls_right"] as const;
-export type ButtonPlacement = (typeof buttonPlacement)[number];
-export type ExtractFeatureName = T extends `pages.content.features.${infer FeatureName}.label` ? FeatureName : never;
-export type FeaturesThatHaveButtons = Exclude<
- ExtractFeatureName & `pages.content.features.${FeatureName}.label`>,
- "featureMenu"
->;
-export type FeatureButtonId = `yte-feature-${FeatureName}-button`;
-export const featuresThatHaveButtons = Object.keys({
+export type YoutubePlayerQualityLevel = (typeof youtubePlayerQualityLevels)[number];
+export const youtubePlayerSpeedRatesExtended = [2.25, 2.5, 2.75, 3, 3.25, 3.75, 4] as const;
+export const youtubePlayerSpeedRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, ...youtubePlayerSpeedRatesExtended] as const;
+export const youtubePlaybackSpeedButtonsRates = [0.25, 0.5, 0.75, 1] as const;
+export const screenshotTypes = ["file", "clipboard"] as const;
+export type ScreenshotType = (typeof screenshotTypes)[number];
+export const screenshotFormats = ["png", "jpeg", "webp"] as const;
+export type ScreenshotFormat = (typeof screenshotFormats)[number];
+export const modifierKeys = ["altKey", "ctrlKey", "shiftKey"] as const;
+export type ModifierKey = (typeof modifierKeys)[number];
+export const volumeBoostModes = ["global", "per_video"] as const;
+export type VolumeBoostMode = (typeof volumeBoostModes)[number];
+export const videoHistoryResumeTypes = ["automatic", "prompt"] as const;
+export type VideoHistoryResumeType = (typeof videoHistoryResumeTypes)[number];
+export const buttonPlacements = ["below_player", "feature_menu", "player_controls_left", "player_controls_right"] as const;
+export type ButtonPlacement = (typeof buttonPlacements)[number];
+export const featureMenuOpenTypes = ["click", "hover"] as const;
+export type FeatureMenuOpenType = (typeof featureMenuOpenTypes)[number];
+export type DeepDarkCustomThemeColors = {
+ colorShadow: string;
+ dimmerText: string;
+ hoverBackground: string;
+ mainBackground: string;
+ mainColor: string;
+ mainText: string;
+ secondBackground: string;
+};
+type TOptionsKeys = ParseKeys<"en-US", TOptions, undefined>;
+export type AllButtonNames = Exclude, "featureMenu">;
+export type SingleButtonNames = Exclude;
+export type SingleButtonFeatureNames = Exclude, "featureMenu">;
+export type MultiButtonNames = Exclude;
+export type MultiButtonFeatureNames = Exclude;
+export const featureToMultiButtonsMap: Map = new Map([
+ ["playbackSpeedButtons", ["increasePlaybackSpeedButton", "decreasePlaybackSpeedButton"]]
+]);
+export type FeatureMenuItemIconId = `yte-${AllButtonNames}-icon`;
+export type FeatureMenuItemId = `yte-feature-${AllButtonNames}-menuitem`;
+export type FeatureMenuItemLabelId = `yte-${AllButtonNames}-label`;
+export const buttonNames = Object.keys({
+ decreasePlaybackSpeedButton: "",
+ increasePlaybackSpeedButton: "",
loopButton: "",
maximizePlayerButton: "",
openTranscriptButton: "",
screenshotButton: "",
volumeBoostButton: ""
-} satisfies Record);
-export type ButtonPlacementConfiguration = {
- [Key in FeaturesThatHaveButtons]: ButtonPlacement;
+} satisfies Record);
+export type ButtonPlacementConfigurationMap = {
+ [ButtonName in AllButtonNames]: ButtonPlacement;
};
-export const videoHistoryResumeType = ["automatic", "prompt"] as const;
-export type VideoHistoryResumeType = (typeof videoHistoryResumeType)[number];
-export type configuration = {
- button_placements: ButtonPlacementConfiguration;
- custom_css_code: string;
- enable_automatic_theater_mode: boolean;
- enable_automatically_set_quality: boolean;
- enable_custom_css: boolean;
- enable_forced_playback_speed: boolean;
- enable_hide_scrollbar: boolean;
- enable_hide_shorts: boolean;
- enable_loop_button: boolean;
- enable_maximize_player_button: boolean;
- enable_open_transcript_button: boolean;
- enable_open_youtube_settings_on_hover: boolean;
- enable_redirect_remover: boolean;
- enable_remaining_time: boolean;
- enable_remember_last_volume: boolean;
- enable_screenshot_button: boolean;
- enable_scroll_wheel_speed_control: boolean;
- enable_scroll_wheel_volume_control: boolean;
- enable_scroll_wheel_volume_control_hold_modifier_key: boolean;
- enable_scroll_wheel_volume_control_hold_right_click: boolean;
- enable_share_shortener: boolean;
- enable_shorts_auto_scroll: boolean;
- enable_video_history: boolean;
- enable_volume_boost: boolean;
- feature_menu_open_type: FeatureMenuOpenType;
- language: AvailableLocales;
- osd_display_color: OnScreenDisplayColor;
- osd_display_hide_time: number;
- osd_display_opacity: number;
- osd_display_padding: number;
- osd_display_position: OnScreenDisplayPosition;
- osd_display_type: OnScreenDisplayType;
- player_quality: YoutubePlayerQualityLevel;
- player_speed: number;
- remembered_volumes: RememberedVolumes;
- screenshot_format: ScreenshotFormat;
- screenshot_save_as: ScreenshotType;
- scroll_wheel_speed_control_modifier_key: ModifierKey;
- scroll_wheel_volume_control_modifier_key: ModifierKey;
- speed_adjustment_steps: number;
- video_history_resume_type: VideoHistoryResumeType;
- volume_adjustment_steps: number;
- volume_boost_amount: number;
- volume_boost_mode: VolumeBoostMode;
-};
-export type configurationKeys = keyof configuration;
-export type configurationId = Path