The weeb for the next gen discord boat - Wamellow wamellow.com
bot discord
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

support youtube shorts

Luna f46d2eae f0e1babf

+84 -46
+17 -5
app/dashboard/[guildId]/notifications/page.tsx
··· 21 21 import { ScreenMessage } from "@/components/screen-message"; 22 22 import { Button } from "@/components/ui/button"; 23 23 import { cacheOptions } from "@/lib/api"; 24 - import { type ApiV1GuildsModulesNotificationsGetResponse, GuildFlags, NotificationFlags, NotificationType } from "@/typings"; 24 + import { type ApiV1GuildsModulesNotificationsGetResponse, BlueskyNotificationFlags, GuildFlags, NotificationType, YoutubeNotificationFlags } from "@/typings"; 25 25 import { BitfieldManager, bitfieldToArray } from "@/utils/bitfields"; 26 26 import { createSelectableItems } from "@/utils/create-selectable-items"; 27 27 import { getCanonicalUrl } from "@/utils/urls"; ··· 50 50 error 51 51 } = useList<ApiV1GuildsModulesNotificationsGetResponse>({ url }); 52 52 53 + const platformFlags = getFlags(item?.type || 0); 53 54 const flags = useMemo(() => new BitfieldManager(item?.flags || 0), [item?.flags]); 54 55 55 56 if (error) { ··· 208 209 showClear 209 210 /> 210 211 211 - {item.type === NotificationType.Bluesky 212 + {platformFlags 212 213 ? <MultiSelectMenu 213 214 className="md:w-1/2 w-full" 214 215 name="Filter" 215 216 url={url + "/" + item.id} 216 217 dataName="flags" 217 - items={bitfieldToArray(NotificationFlags)} 218 - description="Select the types of posts to send in addition to regular posts." 218 + items={bitfieldToArray(platformFlags)} 219 + description={item.type === NotificationType.Bluesky 220 + ? "Select the types of posts to send in addition to regular posts." 221 + : "Select the types of content to send." 222 + } 219 223 defaultState={flags.toArray()} 220 224 onSave={(o) => { 221 225 const flags = o.map((flag) => Number(flag.value)); ··· 234 238 } 235 239 </div> 236 240 237 - {item.type === NotificationType.Bluesky && ( 241 + {platformFlags && ( 238 242 <TextInput 239 243 className="md:w-1/2 w-full" 240 244 name="Ignore regex" ··· 323 327 } 324 328 325 329 return children; 330 + } 331 + 332 + function getFlags(type: NotificationType) { 333 + switch (type) { 334 + case NotificationType.Bluesky: return BlueskyNotificationFlags; 335 + case NotificationType.YouTube: return YoutubeNotificationFlags; 336 + default: return null; 337 + } 326 338 }
+37 -35
app/dashboard/[guildId]/notifications/style.component.tsx
··· 34 34 <div className="w-full relative overflow-hidden rounded-lg border border-border group p-px mt-5"> 35 35 <span className="absolute inset-[-1000%] animate-[spin_5s_linear_infinite_reverse] bg-[conic-gradient(from_90deg_at_0%_50%,#8b5cf6_50%,var(--wamellow-rgb)_100%)]" /> 36 36 37 - <div className="backdrop-blur-3xl backdrop-brightness-[25%] rounded-[6px] pr-4 py-4 pl-6 md:py-8 md:pl-10 flex gap-6 items-center"> 38 - <UserAvatar 39 - alt={premium && item.username ? item.username : "Wamellow"} 40 - className="size-24" 41 - src={premium && item.username && item.avatar ? `https://r2.wamellow.com/avatars/webhooks/${item.avatar}` : "/waya-v3.webp"} 42 - /> 37 + <div className="backdrop-blur-3xl backdrop-brightness-[25%] rounded-[6px] p-5 md:py-8 md:pl-10 flex flex-col md:flex-row gap-5 md:gap-0"> 38 + <div className="flex gap-6 items-center"> 39 + <UserAvatar 40 + alt={premium && item.username ? item.username : "Wamellow"} 41 + className="size-24" 42 + src={premium && item.username && item.avatar ? `https://r2.wamellow.com/avatars/webhooks/${item.avatar}` : "/waya-v3.webp"} 43 + /> 43 44 44 - <div className="space-y-2"> 45 - <span className="text-3xl font-medium text-primary-foreground"> 46 - {premium && item.username ? item.username : "Wamellow"} 47 - </span> 48 - <div className="flex"> 49 - {premium 50 - ? <Button onClick={() => setOpen(true)}> 51 - <HiPencil /> 52 - Change Style 53 - </Button> 54 - : <Button asChild> 55 - <Link 56 - href={`/premium?utm_source=${window.location.hostname}&utm_medium=notification-styles`} 57 - target="_blank" 58 - > 59 - <HiSparkles /> 45 + <div className="space-y-2"> 46 + <span className="text-3xl font-medium text-primary-foreground"> 47 + {premium && item.username ? item.username : "Wamellow"} 48 + </span> 49 + <div className="flex"> 50 + {premium 51 + ? <Button onClick={() => setOpen(true)}> 52 + <HiPencil /> 60 53 Change Style 61 - </Link> 62 - </Button> 63 - } 64 - {premium && (item.username || item.avatar) && ( 65 - <DeleteStyleButton 66 - id={item.id} 67 - guildId={guildId} 68 - onDelete={() => onEdit({ username: null, avatar: null })} 69 - /> 70 - )} 54 + </Button> 55 + : <Button asChild> 56 + <Link 57 + href={`/premium?utm_source=${window.location.hostname}&utm_medium=notification-styles`} 58 + target="_blank" 59 + > 60 + <HiSparkles /> 61 + Upgrade to change style 62 + </Link> 63 + </Button> 64 + } 65 + {premium && (item.username || item.avatar) && ( 66 + <DeleteStyleButton 67 + id={item.id} 68 + guildId={guildId} 69 + onDelete={() => onEdit({ username: null, avatar: null })} 70 + /> 71 + )} 72 + </div> 71 73 </div> 72 74 </div> 73 75 ··· 92 94 function ExampleMessages() { 93 95 return ( 94 96 <div className="w-full relative"> 95 - <ExampleMessage className="bottom-0 right-0 rotate-2" username="Kurzgesagt" avatarUrl="https://yt3.googleusercontent.com/ytc/AIdro_n1Ribd7LwdP_qKtqWL3ZDfIgv9M1d6g78VwpHGXVR2Ir4=s176-c-k-c0x00ffffff-no-rj-mo" /> 96 - <ExampleMessage className="top-0 right-0" username="DarkViperAU" avatarUrl="https://yt3.googleusercontent.com/ytc/AIdro_lpNK9jpdw9D63LuUYt3SLbFpIQ5yD4DV0D5mwPrCp7cEw=s176-c-k-c0x00ffffff-no-rj-mo" /> 97 + <ExampleMessage className="top-1 md:-top-3 md:right-1 rotate-1 md:rotate-2 z-10" username="Kurzgesagt" avatarUrl="https://yt3.googleusercontent.com/ytc/AIdro_n1Ribd7LwdP_qKtqWL3ZDfIgv9M1d6g78VwpHGXVR2Ir4=s176-c-k-c0x00ffffff-no-rj-mo" /> 98 + <ExampleMessage className="md:-bottom-3 right-0 md:-rotate-1" username="DarkViperAU" avatarUrl="https://yt3.googleusercontent.com/ytc/AIdro_lpNK9jpdw9D63LuUYt3SLbFpIQ5yD4DV0D5mwPrCp7cEw=s176-c-k-c0x00ffffff-no-rj-mo" /> 97 99 </div> 98 100 ); 99 101 } 100 102 101 103 function ExampleMessage({ className, username, avatarUrl }: { className?: string; username?: string; avatarUrl?: string; }) { 102 104 return ( 103 - <div className={cn("bg-discord-gray px-3 py-2 rounded-lg w-full max-w-sm absolute border border-wamellow shadow-lg", className)}> 105 + <div className={cn("bg-discord-gray px-3 py-2 rounded-lg w-full md:max-w-sm relative md:absolute border border-wamellow shadow-lg", className)}> 104 106 <DiscordMessage 105 107 mode="DARK" 106 108 user={{
public/docs-assets/notifications-style.webp

This is a binary file and will not be displayed.

+23 -5
public/docs/notifications.md
··· 42 42 **Note:** If Wamellow does not have the `Mention Everyone` permissions inside the channel, it might not be able to actually notify members with those roles. 43 43 44 44 ### 📫 Filter 45 - Allows you to select additional types or filter notifications for Bluesky: 45 + Allows you to select additional types or filter notifications for **Bluesky**: 46 46 - `Send Reposts` will also notify when the user reposts any post. 47 47 - `Send Replies` will also notify when the user replies to any post. 48 48 - `Send Quotes` will also notify when the user quotes any post. ··· 50 50 <br /> 51 51 <br /> 52 52 53 - For all other services, you can take advantage of a regex to blacklist posts: 53 + Allows you to select additional types or filter notifications for **YouTube**: 54 + - `Send Videos` will notify when the creator uploads a new video or stream. 55 + - `Send Shorts` will also notify when the creator uploads a new short. 56 + <br /> 57 + <br /> 58 + 59 + For every service, you can take advantage of a regex to blacklist posts: 54 60 - `^\[live\]` will not post anything starting with `[live]`. 55 61 - `insult|badword` will not post anything that includes either `insult` or `badword`. 56 - - `^(?!support$).+$` will only post that are `support`. (useful for reddit flairs) 62 + - `^(?!support$).+$` will only post that are `support`. (useful for Reddit flairs) 57 63 <br /> 58 64 <br /> 59 65 60 66 You can use [regexr.com](https://regexr.com/) or [ChatGPT](https://chatgpt.com/) to create (JavaScript-like) regexs. 61 - You can use regex keywords to negate the condition, in order to create a whitelist filter. 62 - The flags used for string matching are `gi`, only the titles and reddit flairs are checked. 67 + Keep in mind that the regex is inverted, meaning, everything that matches the regex will be ignored. 68 + You can use a negative lookahead to negate the condition, in order to create a whitelist filter. 69 + The flags used for string matching are `gi`, only the YouTube and Twitch titles, Bluesky post bodies, and Reddit flairs are checked. 70 + 71 + ### 🕵️‍♀️ Styles (whitelabel / webhook) 72 + Notification styles allow you to customise (or whitelabel) the username and avatar of the author (i.e. the sender of the message) separately for each notification. Wamellow will automatically manage the webhooks for you. 73 + <br /> 74 + <br /> 75 + 76 + The username must follow the [name constraints set by Discord](https://discord.com/developers/docs/resources/user#usernames-and-nicknames). The avatar must be a `.png`, `.jpg`, `.jpeg`, or `.webp` file and be less than 8MiB in size. (Animated formats like GIFs and APNGs are not supported by Discord) 77 + <br /> 78 + <br /> 79 + 80 + ![wamellow whitelabeled notification](/docs-assets/notifications-style.webp) 63 81 64 82 ### 🥳 Test notification 65 83 Test notifications let you see how your message will look like when a video is uploaded or a streamer goes live, etc.
+7 -1
typings.ts
··· 44 44 channelId: string | null; 45 45 announceUser: boolean; 46 46 logChannelId: string | null; 47 + blacklistRoleId: string | null; 47 48 priorityRoleId: string | null; 48 49 maxLength?: number | null; 49 50 queue: boolean | null; ··· 433 434 Reddit = 3 434 435 } 435 436 436 - export enum NotificationFlags { 437 + export enum BlueskyNotificationFlags { 437 438 SendReposts = 1 << 0, 438 439 SendReplies = 1 << 1, 439 440 SendQuotes = 1 << 2, 440 441 MustContainImage = 1 << 3 442 + } 443 + 444 + export enum YoutubeNotificationFlags { 445 + SendVideos = 1 << 5, 446 + SendShorts = 1 << 6 441 447 } 442 448 443 449 export interface ApiV1GuildsModulesNotificationsGetResponse {