Schedule posts to Bluesky with Cloudflare workers. skyscheduler.work
cf tool bsky-tool cloudflare bluesky schedule bsky service social-media cloudflare-workers
at main 123 lines 6.5 kB view raw
1import { 2 BSKY_IMG_FILE_EXTS, BSKY_IMG_SIZE_LIMIT_IN_MB, 3 BSKY_VIDEO_FILE_EXTS, BSKY_VIDEO_MAX_DURATION, 4 CF_IMAGES_FILE_SIZE_LIMIT_IN_MB, 5 CF_IMAGES_MAX_DIMENSION, 6 MAX_LENGTH, MAX_THUMBNAIL_SIZE, 7 R2_FILE_SIZE_LIMIT_IN_MB 8} from "../limits"; 9import { APP_NAME } from "../siteinfo"; 10import { ConstScriptStr } from "../utils/constScriptGen"; 11import { IncludeDependencyTags, PreloadRules } from "./helpers/includesTags"; 12import ContentLabelOptions from "./options/contentLabelOptions"; 13import RetweetOptions from "./options/retweetOptions"; 14import ScheduleOptions from "./options/scheduleOptions"; 15 16export const PreloadPostCreation: PreloadRules[] = [ 17 {type: "script", href: ConstScriptStr }, 18 {type: "script", href: "/dep/dropzone.min.js"}, 19 {type: "style", href: "/dep/dropzone.min.css"}, 20 {type: "style", href: "/css/dropzoneMods.css"}, 21 {type: "style", href: "/dep/tribute.css"}, 22 {type: "script", href: "/dep/tribute.min.js"} 23]; 24 25export function PostCreation({ctx}: any) { 26 const maxWidth: number|undefined = ctx.env.IMAGE_SETTINGS.max_width; 27 const bskyImageLimits = `Max file size of ${BSKY_IMG_SIZE_LIMIT_IN_MB}MB`; 28 return (<section> 29 <IncludeDependencyTags scripts={PreloadPostCreation} /> 30 <article> 31 <form id="postForm" novalidate> 32 <header> 33 <h4 id="postFormTitle"></h4> 34 <small class="thread-cancel hidden" data-placement="left" data-tooltip="Cancel adding post to highlighted thread"> 35 <a id="cancelThreadPost" tabindex={0} class="contrast" role="button">Cancel Thread Post</a> 36 </small> 37 </header> 38 <div> 39 <article> 40 <section role="form"> 41 <textarea id="content" rows={8} placeholder="Post Content" required aria-labelledby="post-content-label"></textarea> 42 <label id="post-content-label" for="content">Post Content</label> 43 <small class="smallLabel">Character Count: <span id="count">0/{MAX_LENGTH}</span></small> 44 </section> 45 </article> 46 47 <details> 48 <summary role="button" title="click to toggle section" class="secondary outline">Attach Media/Link</summary> 49 <section id="section-imageAttachment"> 50 <article> 51 <header>Files</header> 52 <div> 53 <div id="fileUploads" class="dropzone"> 54 <center class="dz-message">Drag or click here to upload files</center> 55 </div> 56 </div> 57 <footer> 58 <div class="uploadGuidelines"><small><b>Note</b>: <ul> 59 <li><span data-tooltip={BSKY_IMG_FILE_EXTS}>Images</span>: 60 <ul> 61 <li>must be less than {CF_IMAGES_MAX_DIMENSION}x{CF_IMAGES_MAX_DIMENSION} pixels</li> 62 <li>must have a file size smaller than {CF_IMAGES_FILE_SIZE_LIMIT_IN_MB}MB ({APP_NAME} will attempt to compress images to fit <span data-tooltip={bskyImageLimits}>BlueSky's requirements</span>) 63 {maxWidth ? 64 <ol> 65 <li>images over {BSKY_IMG_SIZE_LIMIT_IN_MB}MB with a width greater than <b>{maxWidth}px</b> will also <u data-tooltip="will preserve aspect ratio">be resized</u> in addition to being compressed</li> 66 </ol> : null} 67 </li> 68 <li>thumbnails will only be shown here for images that are smaller than {MAX_THUMBNAIL_SIZE}MB</li> 69 <li>if an image fails to upload, you'll need to manually adjust the file to fit it properly</li> 70 </ul></li> 71 <li><span data-tooltip={BSKY_VIDEO_FILE_EXTS}>Videos</span>: 72 <ul> 73 <li>must be shorter than {BSKY_VIDEO_MAX_DURATION} minutes</li> 74 <li>must be smaller than {R2_FILE_SIZE_LIMIT_IN_MB}MB</li> 75 <li>will be processed on your PDS after they're posted. This may show a temporary <i>"Video not Found"</i> message for a bit after posting.</li> 76 </ul></li> 77 </ul></small></div> 78 </footer> 79 </article> 80 </section> 81 <section id="section-weblink"> 82 <article> 83 <header><label for="urlCard">Link Embed</label></header> 84 <input type="text" id="urlCard" placeholder="https://" value="" /> 85 <small>Add a social embed card for a link to your post. This link will not count against the {MAX_LENGTH} character limit.<br /> 86 Thumbnails may get automatically resized down to fit 1280x720.</small> 87 <footer><div class="uploadGuidelines"><small><b>NOTE</b>: File uploads will <b>always supersede</b> any link embeds.</small></div></footer> 88 </article> 89 </section> 90 <section id="content-label-selector" class="hidden"> 91 <ContentLabelOptions id="contentLabels" /> 92 </section> 93 </details> 94 <details> 95 <summary title="click to toggle section" role="button" class="outline secondary">Add Record (Quote Post)</summary> 96 <section> 97 <article> 98 <header><label for="recordBox">Insert Post/Feed/List Link</label></header> 99 <input id="recordBox" placeholder="https://" title="Must be a link to a ATProto based record" /> 100 <small>Posts must be quotable and all record types must be resolvable (exist) upon the scheduled time. If it does not exist, it will not be attached to your post.</small> 101 </article> 102 </section> 103 </details> 104 <details id="section-postSchedule" open> 105 <summary title="click to toggle section" role="button" class="outline secondary">Post Scheduling</summary> 106 <ScheduleOptions allowNow={true} timeID="scheduledDate" checkboxID="postNow" type="post" /> 107 </details> 108 109 <details id="section-retweet"> 110 <summary role="button" title="click to toggle section" class="secondary outline">Auto-Retweet</summary> 111 <RetweetOptions id="makeReposts" contentType="post" /> 112 </details> 113 <input type="hidden" id="threadInfo" /> 114 </div> 115 <footer> 116 <button id="makingPostRequest" type="submit" class="w-full primary"> 117 Schedule Post 118 </button> 119 </footer> 120 </form> 121 </article> 122 </section>); 123}