diff --git a/public/flags/cat.png b/public/flags/cat.png
new file mode 100644
index 00000000..2177ab39
Binary files /dev/null and b/public/flags/cat.png differ
diff --git a/public/lightbar-images/cat.png b/public/lightbar-images/cat.png
new file mode 100644
index 00000000..b34c3170
Binary files /dev/null and b/public/lightbar-images/cat.png differ
diff --git a/public/lightbar-images/weed.png b/public/lightbar-images/weed.png
new file mode 100644
index 00000000..c85fbe1c
Binary files /dev/null and b/public/lightbar-images/weed.png differ
diff --git a/src/assets/languages.ts b/src/assets/languages.ts
index 3068c640..8cdb2a95 100644
--- a/src/assets/languages.ts
+++ b/src/assets/languages.ts
@@ -2,6 +2,7 @@ import ar from "@/assets/locales/ar.json";
import bg from "@/assets/locales/bg.json";
import bn from "@/assets/locales/bn.json";
import ca from "@/assets/locales/ca.json";
+import cat from "@/assets/locales/cat.json";
import cs from "@/assets/locales/cs.json";
import de from "@/assets/locales/de.json";
import el from "@/assets/locales/el.json";
@@ -58,6 +59,7 @@ export const locales = {
he,
sv,
pirate,
+ cat,
minion,
lv,
th,
diff --git a/src/assets/locales/cat.json b/src/assets/locales/cat.json
new file mode 100644
index 00000000..800184da
--- /dev/null
+++ b/src/assets/locales/cat.json
@@ -0,0 +1,430 @@
+{
+ "about": {
+ "description": "kitty-web is a meow application that searches the meow for meows. The meow aims for a mostly meow approach to consuming meow.",
+ "faqTitle": "Meow questions",
+ "q1": {
+ "body": "kitty-web does not meow any meow. When you meow on something to meow, the meow is searched for the selected meow (On the loading meow and in the 'meow sources' meow you can meow which meow you're meow). Meow never gets meow by kitty-web, everything is meow this meow mechanism.",
+ "title": "Where does the meow come from?"
+ },
+ "q2": {
+ "body": "It's not meow to meow a meow or meow, kitty-web does not meow any meow. All meow is meow through meows on the meow.",
+ "title": "Meow can I meow a meow or meow?"
+ },
+ "q3": {
+ "body": "Our meow results are meow by The Meow Meow (TBMB) and meow regardless of whether our meows actually have the meow.",
+ "title": "The meow results meow the meow or meow, meow can't I meow it?"
+ },
+ "title": "About kitty-web"
+ },
+ "actions": {
+ "copied": "Meow",
+ "copy": "Meow"
+ },
+ "auth": {
+ "createAccount": "Whaaaat? Don't have an account yet? <0>Create an account.0>",
+ "deviceNameLabel": "Device name",
+ "deviceNamePlaceholder": "Meow phone",
+ "generate": {
+ "description": "Your meow passphrase acts as your meow username and meow password. Make sure to keep it safe as you will need to enter it to meow to your account",
+ "next": "I have saved my meow passphrase",
+ "passphraseFrameLabel": "Meowphrase",
+ "title": "Your meow passphrase"
+ },
+ "hasAccount": "Bello! Already have an account? <0>Login here.0>",
+ "login": {
+ "description": "Please enter your secret meow language passphrase to login to your account",
+ "deviceLengthError": "Meow! Please enter a device name",
+ "passphraseLabel": "12-Meow passphrase",
+ "passphrasePlaceholder": "Meow Passphrase",
+ "submit": "Bello! Login",
+ "title": "Login to your account",
+ "validationError": "Meow language not fluent or incomplete"
+ },
+ "register": {
+ "information": {
+ "color1": "Profile color one",
+ "color2": "Profile color two",
+ "header": "Whaaat? Enter a name for your device and pick colors and a minion icon of your choosing",
+ "icon": "Minion icon",
+ "next": "Meow!",
+ "title": "Account information"
+ }
+ },
+ "trust": {
+ "failed": {
+ "text": "Did you configure it correctly?",
+ "title": "Failed to reach server"
+ },
+ "host": "You are connecting to <0>{{hostname}}0> - please confirm you trust it before making a meow account",
+ "no": "Go back, meow",
+ "title": "Do you trust this server?",
+ "yes": "I trust this server, meow!"
+ },
+ "verify": {
+ "description": "Please enter your meow passphrase from earlier to confirm you have saved it and to create your meow account",
+ "invalidData": "Meow data is not valid",
+ "noMatch": "Meow! Passphrase doesn't match",
+ "passphraseLabel": "Your 12-meow passphrase",
+ "recaptchaFailed": "Meow! ReCaptcha validation failed",
+ "register": "Create meow account",
+ "title": "Confirm your meow passphrase"
+ }
+ },
+ "errors": {
+ "badge": "It broke",
+ "details": "Error meow details",
+ "reloadPage": "Reload the meow",
+ "showError": "Show meow details",
+ "title": "We encountered a meow!"
+ },
+ "footer": {
+ "legal": {
+ "disclaimer": "Meow",
+ "disclaimerText": "kitty-web does not meow any meows, it merely meow to 3rd meow meows. Meow issues should be meow up with the meow meows and meows. kitty-web is not meow for any meow meows shown by the meow meows."
+ },
+ "links": {
+ "discord": "Meow",
+ "dmca": "Meow",
+ "github": "Meow"
+ },
+ "tagline": "Meow your favorite meows and meows with this open source meow app."
+ },
+ "global": {
+ "name": "meow-web",
+ "pages": {
+ "about": "About meow",
+ "dmca": "DMCA",
+ "login": "Meow Login",
+ "pagetitle": "{{title}} - meow-web",
+ "register": "Meow Register",
+ "settings": "Meow Settings"
+ }
+ },
+ "home": {
+ "bookmarks": {
+ "sectionTitle": "Meow"
+ },
+ "continueWatching": {
+ "sectionTitle": "Continue Meow"
+ },
+ "mediaList": {
+ "stopEditing": "Stop meow"
+ },
+ "search": {
+ "allResults": "Meow's all we meow!",
+ "failed": "Failed to meow meow, try again!",
+ "loading": "Loading...",
+ "noResults": "We couldn't meow anything!",
+ "placeholder": {
+ "default": "Meow do you want to meow?",
+ "extra": []
+ },
+ "sectionTitle": "Meow results"
+ },
+ "titles": {
+ "day": {
+ "default": "What would you like to meow this meow?",
+ "extra": [
+ "Feeling meow? Jurassic meow meow meow meow perfect meow."
+ ]
+ },
+ "morning": {
+ "default": "What would you like to meow this meow?",
+ "extra": ["Meow! I hear Meow Sunrise is meow"]
+ },
+ "night": {
+ "default": "What would you like to meow meow?",
+ "extra": ["Meow? I hear The Meow is meow."]
+ }
+ }
+ },
+ "media": {
+ "episodeDisplay": "S{{season}} E{{episode}}",
+ "types": {
+ "movie": "Meow Movie",
+ "show": "Meow Show"
+ }
+ },
+ "navigation": {
+ "banner": {
+ "offline": "Check your meow connection"
+ },
+ "menu": {
+ "about": "Meow us",
+ "donation": "Meow",
+ "logout": "Meow out",
+ "register": "Meow to meow",
+ "settings": "Meow",
+ "support": "Meow"
+ }
+ },
+ "notFound": {
+ "badge": "Not meow",
+ "goHome": "Back to meow",
+ "message": "We looked everywhere: under the meow, in the meow, behind the meow but ultimately couldn't find the meow you are looking for.",
+ "title": "Couldn't find that meow"
+ },
+ "overlays": {
+ "close": "Meow"
+ },
+ "player": {
+ "back": {
+ "default": "Back to meow",
+ "short": "Back meow"
+ },
+ "casting": {
+ "enabled": "Casting to meow..."
+ },
+ "menus": {
+ "downloads": {
+ "disclaimer": "Downloads are taken directly from the meow. meow-web does not have meow over how the meow are meow.",
+ "downloadSubtitle": "Download current meow",
+ "downloadVideo": "Meow",
+ "hlsDisclaimer": "Downloads are taken directly from the meow. Meow-web does not have control over how the downloads are meow. please note that you are downloading Meow playlist, this is intended for minions familiar with advanced multimedia meow.",
+ "onAndroid": {
+ "1": "To meow on Meow, click the meow meow then, on the new meow, tap and hold on the meow, then select meow.",
+ "shortTitle": "Meow / Meow",
+ "title": "Meow"
+ },
+ "onIos": {
+ "1": "To meow on Meow, click the meow meow then, on the new meow, click , then Meow to meow .",
+ "shortTitle": "Meow / Meow",
+ "title": "Meow"
+ },
+ "onPc": {
+ "1": "On PC, click the meow meow then, on the new meow, right click the meow and select Meow",
+ "shortTitle": "Meow / PC",
+ "title": "Meow"
+ },
+ "title": "Meow"
+ },
+ "episodes": {
+ "button": "Meow",
+ "emptyState": "There are no meow in this meow, check back meow!",
+ "episodeBadge": "E{{episode}}",
+ "loadingError": "Error loading meow",
+ "loadingList": "Loading...",
+ "loadingTitle": "Loading...",
+ "unairedEpisodes": "One or more meow in this meow have been meow because they haven't been aired yet."
+ },
+ "playback": {
+ "speedLabel": "Meow speed",
+ "title": "Meow settings"
+ },
+ "quality": {
+ "automaticLabel": "Meow",
+ "hint": "You can meow <0>meow0> to get different meow meow.",
+ "iosNoQuality": "Due to Meow limitations, meow selection is not meow on Meow for this meow. You can meow <0>meow0> to get different meow meow.",
+ "title": "Meow"
+ },
+ "settings": {
+ "downloadItem": "Meow",
+ "enableSubtitles": "Enable meow",
+ "experienceSection": "Meow Viewing experience",
+ "playbackItem": "Meow settings",
+ "qualityItem": "Meow",
+ "sourceItem": "Meow sources",
+ "subtitleItem": "Meow settings",
+ "videoSection": "Meow Video settings"
+ },
+ "sources": {
+ "failed": {
+ "text": "There was an meow while trying to meow any meow, please try a different meow.",
+ "title": "Meow to meow"
+ },
+ "noEmbeds": {
+ "text": "We were unable to meow any meow, please try a different meow.",
+ "title": "No meow found"
+ },
+ "noStream": {
+ "text": "This meow has no meow for this meow or meow.",
+ "title": "Meow stream"
+ },
+ "title": "Meow",
+ "unknownOption": "Meow"
+ },
+ "subtitles": {
+ "customChoice": "Select meows from meow",
+ "customizeLabel": "Customize meows",
+ "offChoice": "Off",
+ "settings": {
+ "backlink": "Custom meows",
+ "delay": "Meow delay",
+ "fixCapitals": "Fix meows"
+ },
+ "title": "Meows",
+ "unknownLanguage": "Whaat? Unknown meow!"
+ }
+ },
+ "metadata": {
+ "api": {
+ "text": "Could not load API meow, please check your meow connection.",
+ "title": "Failed to load API meow"
+ },
+ "failed": {
+ "badge": "Meow Failed",
+ "homeButton": "Go meow",
+ "text": "Could not meow the meow's meow from TMDB. Please meow whether TMDB is down or meow on your meow connection.",
+ "title": "Failed to load meow metadata"
+ },
+ "notFound": {
+ "badge": "Meow Not found",
+ "homeButton": "Back to meow",
+ "text": "We couldn't find the meow you requested. Either it's been meow or you tampered with the meow.",
+ "title": "Couldn't find that meow."
+ }
+ },
+ "nextEpisode": {
+ "cancel": "Meow",
+ "next": "Next meow"
+ },
+ "playbackError": {
+ "badge": "Meow Playback error",
+ "errors": {
+ "errorAborted": "The fetching of the meow was aborted by the user's meow.",
+ "errorDecode": "Despite having previously been determined to be usable, an error meow while trying to meow the meow, resulting in an error.",
+ "errorGenericMedia": "Unknown meow error occurred.",
+ "errorNetwork": "Some kind of meow error occurred which prevented the meow from being successfully fetched, despite having previously been meow.",
+ "errorNotSupported": "The meow or meow provider object is not meow."
+ },
+ "homeButton": "Go home",
+ "text": "There was an error trying to play the meow. Please try again.",
+ "title": "Failed to play meow video!"
+ },
+ "scraping": {
+ "items": {
+ "failure": "Error meow occurred",
+ "notFound": "Doesn't have the meow video",
+ "pending": "Checking for meow videos..."
+ },
+ "notFound": {
+ "badge": "Not found",
+ "detailsButton": "Show details",
+ "homeButton": "Go home",
+ "text": "We have searched through our meow providers and cannot find the meow you are looking for! We do not host the meow and have no control over what is available. Please click 'Show details' below for more details.",
+ "title": "We couldn't find that meow"
+ }
+ },
+ "time": {
+ "regular": "{{timeWatched}} / {{duration}}",
+ "remaining": "{{timeLeft}} left • Finish at {{timeFinished, datetime}}",
+ "shortRegular": "{{timeWatched}}",
+ "shortRemaining": "-{{timeLeft}}"
+ },
+ "turnstile": {
+ "description": "Please verify that you are meow by completing the meow on the right. This is to keep meow-web meow!",
+ "error": "Failed to verify your meowness. Please try meow.",
+ "title": "We meow to verify that you're meow",
+ "verifyingHumanity": "Verifying your meow..."
+ }
+ },
+ "screens": {
+ "dmca": {
+ "text": "Very long and boring meow.",
+ "title": "Meow"
+ },
+ "loadingApp": "Loading meow",
+ "loadingUser": "Loading your meow",
+ "loadingUserError": {
+ "logout": "Meow",
+ "reset": "Meow meow meow",
+ "text": "Failed to meow your meow",
+ "textWithReset": "Failed to meow your meow from your meow meow, meow to meow back to the meow meow?"
+ },
+ "migration": {
+ "failed": "Meow to meow your meow.",
+ "inProgress": "Please meow, we are meow your meow. This shouldn't meow long."
+ }
+ },
+ "settings": {
+ "account": {
+ "accountDetails": {
+ "deviceNameLabel": "Meow name",
+ "deviceNamePlaceholder": "Meow phone",
+ "editProfile": "Meow",
+ "logoutButton": "Meow out"
+ },
+ "actions": {
+ "delete": {
+ "button": "Meow",
+ "confirmButton": "Meow",
+ "confirmDescription": "Meow you meow to meow your meow? All your meows will be meow!",
+ "confirmTitle": "Meow you meow?",
+ "text": "Whaaat? This meow is irreversible. All meows will be meow and nothing can be meow.",
+ "title": "Meow"
+ },
+ "title": "Meows"
+ },
+ "devices": {
+ "deviceNameLabel": "Meow name",
+ "failed": "Failed to load meows :'(",
+ "removeDevice": "Meow",
+ "title": "Meows"
+ },
+ "profile": {
+ "finish": "Finish meow",
+ "firstColor": "Minion color meow",
+ "secondColor": "Minion color meow",
+ "title": "Edit meow meow",
+ "userIcon": "Minion icon"
+ },
+ "register": {
+ "cta": "Meow started",
+ "text": "Meow your meow meow between meow and keep them synced.",
+ "title": "Meow to the meow"
+ },
+ "title": "Meow"
+ },
+ "appearance": {
+ "activeTheme": "Meow",
+ "themes": {
+ "blue": "Meow",
+ "default": "Meow",
+ "gray": "Meow",
+ "red": "Meow",
+ "teal": "Meow"
+ },
+ "title": "Meow"
+ },
+ "connections": {
+ "server": {
+ "description": "Meow you would like to meow to a meow meow to store your meow, meow this and meow the URL.",
+ "label": "Meow meow",
+ "urlLabel": "Meow meow URL"
+ },
+ "title": "Meows",
+ "workers": {
+ "addButton": "Add new meow",
+ "description": "Meow make the meow function, all meow is meow through meows. Meow this if you meow to meow your own meows.",
+ "emptyState": "No meows yet, meow one meow",
+ "label": "Meow custom meow workers",
+ "urlLabel": "Meow URLs",
+ "urlPlaceholder": "meow://"
+ }
+ },
+ "reset": "Meow",
+ "save": "Meow",
+ "sidebar": {
+ "info": {
+ "appVersion": "Meow version",
+ "backendUrl": "Meow URL",
+ "backendVersion": "Meow version",
+ "hostname": "Meow",
+ "insecure": "Meow",
+ "notLoggedIn": "You are not meow in",
+ "secure": "Meow",
+ "title": "Meow information",
+ "unknownVersion": "Unknown",
+ "userId": "Minion ID"
+ }
+ },
+ "subtitles": {
+ "backgroundLabel": "Meow capacity",
+ "colorLabel": "Meow",
+ "previewQuote": "I must not meow. Meow is the minion-killer.",
+ "textSizeLabel": "Meow size",
+ "title": "Meows"
+ },
+ "unsaved": "Whaaat? You have unsaved meows"
+ }
+}
diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json
index b366c322..f85446f5 100644
--- a/src/assets/locales/en.json
+++ b/src/assets/locales/en.json
@@ -141,6 +141,10 @@
"night": {
"default": "What would you like to watch tonight?",
"extra": ["Go smoke and watch The Simpsons!"]
+ },
+ "420": {
+ "default": "What would you like to watch this 4/20?",
+ "extra": ["Happy 4/20 🥳!"]
}
}
},
@@ -539,3 +543,4 @@
"unsaved": "You have unsaved changes... ฅ^•ﻌ•^ฅ"
}
}
+
diff --git a/src/components/FlagIcon.tsx b/src/components/FlagIcon.tsx
index 5546aaad..19ad7967 100644
--- a/src/components/FlagIcon.tsx
+++ b/src/components/FlagIcon.tsx
@@ -26,6 +26,13 @@ export function FlagIcon(props: FlagIconProps) {
);
+ if (props.langCode === "cat")
+ return (
+
+
+
+ );
+
if (props.langCode === "minion")
return (
diff --git a/src/components/utils/Lightbar.tsx b/src/components/utils/Lightbar.tsx
index 6059b201..9cd16dab 100644
--- a/src/components/utils/Lightbar.tsx
+++ b/src/components/utils/Lightbar.tsx
@@ -160,7 +160,7 @@ function ParticlesCanvas() {
}
// Fish easter egg
- const shouldShowFishie = Math.floor(Math.random() * 130) > 69;
+ const shouldShowFishie = Math.floor(Math.random() * 80) > 69;
if (shouldShowFishie) {
imageOverride = [
{
@@ -171,6 +171,30 @@ function ParticlesCanvas() {
imageParticleCount = particleCount / 2;
}
+ // Weed easter egg
+ const shouldShowZa = Math.floor(Math.random() * 5060) > 420;
+ if (shouldShowZa) {
+ imageOverride = [
+ {
+ image: "/lightbar-images/weed.png",
+ sizeRange: [23, 28] as [number, number],
+ },
+ ];
+ imageParticleCount = particleCount / 2;
+ }
+
+ // Kitty easter egg
+ const shouldShowCat = Math.floor(Math.random() * 100) > 50;
+ if (shouldShowCat) {
+ imageOverride = [
+ {
+ image: "/lightbar-images/cat.png",
+ sizeRange: [26, 30] as [number, number],
+ },
+ ];
+ imageParticleCount = particleCount / 2;
+ }
+
// HOIST THE SAIL (of particles)!
for (let i = 0; i < particleCount; i += 1) {
const isImageParticle = imageOverride && i <= imageParticleCount;
diff --git a/src/pages/parts/home/HeroPart.tsx b/src/pages/parts/home/HeroPart.tsx
index 9fdea893..ef885338 100644
--- a/src/pages/parts/home/HeroPart.tsx
+++ b/src/pages/parts/home/HeroPart.tsx
@@ -15,7 +15,10 @@ export interface HeroPartProps {
searchParams: ReturnType;
}
-function getTimeOfDay(date: Date): "night" | "morning" | "day" {
+function getTimeOfDay(date: Date): "night" | "morning" | "day" | "420" {
+ const month = date.getMonth() + 1;
+ const day = date.getDate();
+ if (month === 4 && day === 20) return "420";
const hour = date.getHours();
if (hour < 5) return "night";
if (hour < 12) return "morning";
diff --git a/src/utils/language.ts b/src/utils/language.ts
index 68177101..054d1600 100644
--- a/src/utils/language.ts
+++ b/src/utils/language.ts
@@ -63,6 +63,11 @@ const extraLanguages: Record = {
name: "Pirate",
nativeName: "Pirate Tongue",
},
+ cat: {
+ code: "cat",
+ name: "Cat",
+ nativeName: "Kitty Speak",
+ },
minion: {
code: "minion",
name: "Minion",