From 02fa5ff2e08de529caaed2fba7409dcaa1cfe727 Mon Sep 17 00:00:00 2001 From: Dikran Samarjian Date: Fri, 3 Apr 2026 17:12:17 -0700 Subject: [PATCH] update examples in media uploads --- docs/capabilities/server/media-uploads.mdx | 192 ++++++++++++++---- .../capabilities/server/media-uploads.mdx | 192 ++++++++++++++---- 2 files changed, 306 insertions(+), 78 deletions(-) diff --git a/docs/capabilities/server/media-uploads.mdx b/docs/capabilities/server/media-uploads.mdx index 7316f1a7..eda4b7d1 100644 --- a/docs/capabilities/server/media-uploads.mdx +++ b/docs/capabilities/server/media-uploads.mdx @@ -1,15 +1,12 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - # Media Uploads :::warning -Apps can only display images hosted on Reddit +Apps can only display media hosted on Reddit ::: -You can upload images to Reddit at runtime using the `media` capability. This is different than static images, which are part of your [assets](../blocks/app_image_assets.md). +You can upload media to Reddit at runtime using the `media` capability. This is different than static images, which are part of your [assets](../blocks/app_image_assets.md). -Runtime images are useful for embedding images in RTJSON (Posts and Comments) as well as displaying them within an interactive post app. +Runtime media is useful for embedding media in RTJSON (Posts and Comments) as well as displaying it within an interactive post app. ## Enabling media uploads Enable the `media` permission in your `devvit.json` file. @@ -21,32 +18,152 @@ Enable the `media` permission in your `devvit.json` file. } ``` -## Using media uploads -On the server, you can pass the URL of any remotely hosted image (even if its not hosted on Reddit) to the `media.upload` function. This function will return a Reddit URL. Both HTTP and data URLs are supported. - - - - ```ts title="server/index.ts" - import { media } from '@devvit/media'; - function submitImage() { - const response = await media.upload({ - url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif', - type: 'gif', +## Media uploads (Devvit Web) +On the server, pass a remote URL or data URL to `media.upload()` to upload an image, GIF, or video and get a Reddit-hosted asset you can safely render in posts, comments, and rich text. + +### Response type +`media.upload()` returns: + +```ts +type MediaAsset = { + mediaId: string; + mediaUrl: string; +}; +``` + +- `mediaId`: Reddit media asset ID. +- `mediaUrl`: Reddit CDN URL (use this in rich text or UI). + +### `media.upload()` input +`media.upload()` expects an object with: + +- `url`: The media URL (remote URL or data URL). +- `type`: The media kind (`'image'`, `'gif'`, or `'video'`). + +```ts +type UploadMediaOptions = { + url: string; // remote URL or data URL + type: 'image' | 'gif' | 'video'; +}; +``` + +Use `type: 'image'` for PNG, JPEG, and WEBP uploads. + +### Basic server usage +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; + +const uploaded = await media.upload({ + url: 'https://example.com/my-image.png', + type: 'image', +}); + +// uploaded.mediaId +// uploaded.mediaUrl +``` + +### Example: API endpoint returning upload response +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; + +app.post('/api/upload', async (c) => { + const { url, type } = await c.req.json<{ + url: string; + type: 'image' | 'gif' | 'video'; + }>(); + + const uploaded = await media.upload({ url, type }); + + return c.json({ + mediaId: uploaded.mediaId, + mediaUrl: uploaded.mediaUrl, + }); +}); +``` + +### Example: submit a post with uploaded media using RichTextBuilder +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; +import { reddit, RichTextBuilder } from '@devvit/reddit'; + +const uploaded = await media.upload({ + url: 'https://example.com/cover.png', + type: 'image', +}); + +const richtext = new RichTextBuilder() + .paragraph((p) => { + p.text({ text: 'Uploaded image:' }); + }) + .paragraph((p) => { + p.image({ + mediaUrl: uploaded.mediaUrl, + caption: 'Rendered from media.upload()', }); - } - ``` - - - ```ts - import { Devvit } from '@devvit/public-api'; + }); - const response = await media.upload({ - url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif', - type: 'gif', +await reddit.submitPost({ + subredditName: 'my_subreddit', + title: 'Post with uploaded media', + richtext, +}); +``` + +### Example: submit a comment with uploaded media using RichTextBuilder +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; +import { reddit, RichTextBuilder } from '@devvit/reddit'; + +// Parent can be a post id (t3_...) or comment id (t1_...) +const parentId = 't3_abc123'; + +const uploaded = await media.upload({ + url: 'https://example.com/reply-image.png', + type: 'image', +}); + +const commentRichtext = new RichTextBuilder() + .paragraph((p) => { + p.text({ text: 'Here is the image:' }); + }) + .paragraph((p) => { + p.image({ mediaUrl: uploaded.mediaUrl }); }); - ``` - - + +await reddit.submitComment({ + id: parentId, + richtext: commentRichtext, +}); +``` + +### Example: raw RTJSON (without RichTextBuilder) +If you prefer raw RTJSON, pass an object directly to `richtext`: + +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; +import { reddit } from '@devvit/reddit'; + +const uploaded = await media.upload({ + url: 'https://example.com/raw-rtjson.png', + type: 'image', +}); + +await reddit.submitComment({ + id: 't3_abc123', + richtext: { + document: [ + { + e: 'par', + c: [{ e: 'text', t: 'Raw RTJSON image:' }], + }, + { + e: 'par', + c: [{ e: 'img', mediaUrl: uploaded.mediaUrl, c: 'RTJSON image node' }], + }, + ], + }, +}); +``` ## Canvas screenshots @@ -68,25 +185,22 @@ const response = await fetch('/api/upload-screenshot', { ``` ```ts title="server/index.ts" -import { media } from '@devvit/media'; +import { media } from '@devvit/web/server'; app.post('/api/upload-screenshot', async (c) => { const { image } = await c.req.json(); const response = await media.upload({ - url: image, // data URL from canvas - type: 'png', + url: image, // data URL from canvas + type: 'image', }); return c.json({ url: response.mediaUrl }); }); ``` -## Limitations - -- The formats supported are PNG, JPEG, WEBP, and GIF. -- The maximum file size allowed is 20 MB. - -### Notes +## Notes and limits -- When uploading a WEBP image, it will be converted to JPEG. As such, the Reddit URL returned points to a JPEG image. +- Supported image upload formats: PNG, JPEG, WEBP, and GIF. +- Maximum upload size: 20 MB. +- WEBP uploads may be converted to JPEG in the returned Reddit URL. diff --git a/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx b/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx index 7316f1a7..eda4b7d1 100644 --- a/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx +++ b/versioned_docs/version-0.12/capabilities/server/media-uploads.mdx @@ -1,15 +1,12 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - # Media Uploads :::warning -Apps can only display images hosted on Reddit +Apps can only display media hosted on Reddit ::: -You can upload images to Reddit at runtime using the `media` capability. This is different than static images, which are part of your [assets](../blocks/app_image_assets.md). +You can upload media to Reddit at runtime using the `media` capability. This is different than static images, which are part of your [assets](../blocks/app_image_assets.md). -Runtime images are useful for embedding images in RTJSON (Posts and Comments) as well as displaying them within an interactive post app. +Runtime media is useful for embedding media in RTJSON (Posts and Comments) as well as displaying it within an interactive post app. ## Enabling media uploads Enable the `media` permission in your `devvit.json` file. @@ -21,32 +18,152 @@ Enable the `media` permission in your `devvit.json` file. } ``` -## Using media uploads -On the server, you can pass the URL of any remotely hosted image (even if its not hosted on Reddit) to the `media.upload` function. This function will return a Reddit URL. Both HTTP and data URLs are supported. - - - - ```ts title="server/index.ts" - import { media } from '@devvit/media'; - function submitImage() { - const response = await media.upload({ - url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif', - type: 'gif', +## Media uploads (Devvit Web) +On the server, pass a remote URL or data URL to `media.upload()` to upload an image, GIF, or video and get a Reddit-hosted asset you can safely render in posts, comments, and rich text. + +### Response type +`media.upload()` returns: + +```ts +type MediaAsset = { + mediaId: string; + mediaUrl: string; +}; +``` + +- `mediaId`: Reddit media asset ID. +- `mediaUrl`: Reddit CDN URL (use this in rich text or UI). + +### `media.upload()` input +`media.upload()` expects an object with: + +- `url`: The media URL (remote URL or data URL). +- `type`: The media kind (`'image'`, `'gif'`, or `'video'`). + +```ts +type UploadMediaOptions = { + url: string; // remote URL or data URL + type: 'image' | 'gif' | 'video'; +}; +``` + +Use `type: 'image'` for PNG, JPEG, and WEBP uploads. + +### Basic server usage +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; + +const uploaded = await media.upload({ + url: 'https://example.com/my-image.png', + type: 'image', +}); + +// uploaded.mediaId +// uploaded.mediaUrl +``` + +### Example: API endpoint returning upload response +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; + +app.post('/api/upload', async (c) => { + const { url, type } = await c.req.json<{ + url: string; + type: 'image' | 'gif' | 'video'; + }>(); + + const uploaded = await media.upload({ url, type }); + + return c.json({ + mediaId: uploaded.mediaId, + mediaUrl: uploaded.mediaUrl, + }); +}); +``` + +### Example: submit a post with uploaded media using RichTextBuilder +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; +import { reddit, RichTextBuilder } from '@devvit/reddit'; + +const uploaded = await media.upload({ + url: 'https://example.com/cover.png', + type: 'image', +}); + +const richtext = new RichTextBuilder() + .paragraph((p) => { + p.text({ text: 'Uploaded image:' }); + }) + .paragraph((p) => { + p.image({ + mediaUrl: uploaded.mediaUrl, + caption: 'Rendered from media.upload()', }); - } - ``` - - - ```ts - import { Devvit } from '@devvit/public-api'; + }); - const response = await media.upload({ - url: 'https://media2.giphy.com/media/xTiN0CNHgoRf1Ha7CM/giphy.gif', - type: 'gif', +await reddit.submitPost({ + subredditName: 'my_subreddit', + title: 'Post with uploaded media', + richtext, +}); +``` + +### Example: submit a comment with uploaded media using RichTextBuilder +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; +import { reddit, RichTextBuilder } from '@devvit/reddit'; + +// Parent can be a post id (t3_...) or comment id (t1_...) +const parentId = 't3_abc123'; + +const uploaded = await media.upload({ + url: 'https://example.com/reply-image.png', + type: 'image', +}); + +const commentRichtext = new RichTextBuilder() + .paragraph((p) => { + p.text({ text: 'Here is the image:' }); + }) + .paragraph((p) => { + p.image({ mediaUrl: uploaded.mediaUrl }); }); - ``` - - + +await reddit.submitComment({ + id: parentId, + richtext: commentRichtext, +}); +``` + +### Example: raw RTJSON (without RichTextBuilder) +If you prefer raw RTJSON, pass an object directly to `richtext`: + +```ts title="server/index.ts" +import { media } from '@devvit/web/server'; +import { reddit } from '@devvit/reddit'; + +const uploaded = await media.upload({ + url: 'https://example.com/raw-rtjson.png', + type: 'image', +}); + +await reddit.submitComment({ + id: 't3_abc123', + richtext: { + document: [ + { + e: 'par', + c: [{ e: 'text', t: 'Raw RTJSON image:' }], + }, + { + e: 'par', + c: [{ e: 'img', mediaUrl: uploaded.mediaUrl, c: 'RTJSON image node' }], + }, + ], + }, +}); +``` ## Canvas screenshots @@ -68,25 +185,22 @@ const response = await fetch('/api/upload-screenshot', { ``` ```ts title="server/index.ts" -import { media } from '@devvit/media'; +import { media } from '@devvit/web/server'; app.post('/api/upload-screenshot', async (c) => { const { image } = await c.req.json(); const response = await media.upload({ - url: image, // data URL from canvas - type: 'png', + url: image, // data URL from canvas + type: 'image', }); return c.json({ url: response.mediaUrl }); }); ``` -## Limitations - -- The formats supported are PNG, JPEG, WEBP, and GIF. -- The maximum file size allowed is 20 MB. - -### Notes +## Notes and limits -- When uploading a WEBP image, it will be converted to JPEG. As such, the Reddit URL returned points to a JPEG image. +- Supported image upload formats: PNG, JPEG, WEBP, and GIF. +- Maximum upload size: 20 MB. +- WEBP uploads may be converted to JPEG in the returned Reddit URL.