Schedule posts to Bluesky with Cloudflare workers.
skyscheduler.work
cf
tool
bsky-tool
cloudflare
bluesky
schedule
bsky
service
social-media
cloudflare-workers
1import remove from "just-remove";
2
3/** APPLICATION CONFIGURATIONS **/
4
5// minimum length of a post
6export const MIN_LENGTH: number = 1;
7// max amount of times something can be reposted
8export const MAX_REPOST_INTERVAL: number = 15;
9// max amount of time something can be reposted over
10export const MAX_REPOST_DAYS: number = 10;
11// max length of an animated gif in minutes
12export const MAX_GIF_LENGTH: number = 1;
13// if gifs should be allowed to upload
14export const GIF_UPLOAD_ALLOWED: boolean = false;
15// max posts per thread
16export const MAX_POSTS_PER_THREAD: number = 10;
17
18// This is the length of how much we keep in the DB after a post has been made
19export const MAX_POSTED_LENGTH: number = 50;
20
21// Dashboard password length settings
22export const MIN_DASHBOARD_PASS: number = 8;
23export const MAX_DASHBOARD_PASS: number = 30;
24
25// max amount of returns from bsky handle search
26export const BSKY_NAME_LOOKUP_LIMIT: number = 8; // 8 is the same value bsky uses
27// number of characters to activate a bsky handle search
28export const BSKY_NAME_TYPE_AHEAD_CHARS: number = 2;
29
30// the maximum size of an image file to generate a thumbnail for, in MB.
31// generation is done on client side using canvas elements.
32export const MAX_THUMBNAIL_SIZE: number = 15;
33
34// the maximum amount of repost posts an account can have at any one time.
35// because some people went incredibly overboard.
36export const MAX_REPOST_POSTS: number = 40;
37
38// a limit for the maximum number of repost rules a single post can have
39export const MAX_REPOST_RULES_PER_POST: number = 5;
40
41/** INTERNAL LIMITS, DO NOT CHANGE **/
42// Maximums used internally, do not change these directly.
43export const MAX_REPOST_INTERVAL_LIMIT: number = MAX_REPOST_INTERVAL + 1;
44export const MAX_REPOST_IN_HOURS: number = (MAX_REPOST_DAYS * 24) + 1;
45
46// Helper conversion math
47export const MB_TO_BYTES: number = 1000 * 1000;
48export const TO_SEC: number = 60;
49export const TO_MS: number = TO_SEC*1000;
50
51// Max post length limit via
52// https://github.com/bluesky-social/social-app/blob/b38013a12ff22a3ebd3075baa0d98bc96302a316/src/lib/constants.ts#L63
53export const MAX_LENGTH: number = 300;
54
55// Alt text limit via
56// https://github.com/bluesky-social/social-app/blob/b38013a12ff22a3ebd3075baa0d98bc96302a316/src/lib/constants.ts#L69
57export const MAX_ALT_TEXT: number = 2000;
58
59// Image limit values via
60// https://github.com/bluesky-social/social-app/blob/b38013a12ff22a3ebd3075baa0d98bc96302a316/src/lib/constants.ts#L97
61export const BSKY_IMG_MAX_WIDTH: number = 2000;
62export const BSKY_IMG_MAX_HEIGHT: number = 2000;
63export const BSKY_IMG_SIZE_LIMIT_IN_MB: number = 1;
64export const BSKY_IMG_MIME_TYPES: string[] = [
65 "image/png",
66 "image/jpeg",
67 "image/webp",
68 "image/heic",
69 "image/bmp",
70 "image/avif",
71 "image/svg+xml"
72];
73
74// Used for human readable display
75export const BSKY_IMG_FILE_EXTS: string = [
76 "png",
77 "jpg",
78 "jpeg",
79 "bmp",
80 "webp",
81 "heic",
82 "svg"
83].join(", ");
84
85// BSky limits that are inferred
86export const BSKY_MIN_USERNAME_LENGTH: number = 4;
87export const BSKY_MAX_USERNAME_LENGTH: number = 256; // since these are domains, they should be about 256
88export const BSKY_MAX_APP_PASSWORD_LENGTH: number = 20;
89export const MAX_EMBEDS_PER_POST: number = 4;
90
91// Video limits values via
92// https://github.com/bluesky-social/social-app/blob/b38013a12ff22a3ebd3075baa0d98bc96302a316/src/lib/constants.ts#L184
93export const BSKY_VIDEO_MAX_DURATION: number = 3; // in minutes
94export const BSKY_VIDEO_MAX_SIZE_IN_MB: number = 100;
95export const BSKY_VIDEO_MIME_TYPES: string[] = [
96 "video/mp4",
97 "video/mpeg",
98 "video/webm",
99 "video/quicktime"
100];
101
102// Used for human readable display
103export const BSKY_GIF_MIME_TYPES: string[] = [
104 "image/gif"
105];
106
107// Used for human readable display
108export const BSKY_VIDEO_FILE_EXTS: string = remove([
109 "mp4",
110 "mpeg",
111 "mov",
112 "webm",
113 /* This is handled in a special case because bluesky */
114 (GIF_UPLOAD_ALLOWED ? "animated gif" : undefined)
115], [undefined]).join(", ");
116
117// Max size of files that can go to R2 without doing multipart uploads
118export const R2_FILE_SIZE_LIMIT_IN_MB: number = 100;
119export const R2_FILE_SIZE_LIMIT: number = R2_FILE_SIZE_LIMIT_IN_MB * MB_TO_BYTES;
120export const BSKY_IMG_SIZE_LIMIT: number = BSKY_IMG_SIZE_LIMIT_IN_MB * MB_TO_BYTES;
121export const BSKY_VIDEO_SIZE_LIMIT: number = BSKY_VIDEO_MAX_SIZE_IN_MB * MB_TO_BYTES;
122export const BSKY_VIDEO_LENGTH_LIMIT: number = BSKY_VIDEO_MAX_DURATION * TO_SEC;
123export const MAX_GIF_LENGTH_LIMIT: number = MAX_GIF_LENGTH * TO_SEC;
124// Max size of Cloudflare Images files
125export const CF_IMAGES_FILE_SIZE_LIMIT_IN_MB: number = 70;
126export const CF_IMAGES_FILE_SIZE_LIMIT: number = CF_IMAGES_FILE_SIZE_LIMIT_IN_MB * MB_TO_BYTES;
127export const CF_IMAGES_MAX_DIMENSION: number = 10000;