A simple AtProto app to read pet.mewsse.link records on my PDS.

Add embed types + fix render

Mewsse ea9dbac4 1b2d4175

Changed files
+145 -19
lexicons
src
lexicons
types
pet
lib
views
+17
lexicons/pet/mewsse/embed/external.json
···
+
{
+
"lexicon": 1,
+
"id": "pet.mewsse.embed.external",
+
"description": "An external integration (card)",
+
"defs": {
+
"main": {
+
"type": "object",
+
"required": ["uri"],
+
"properties": {
+
"uri": {
+
"type": "string",
+
"format": "uri"
+
}
+
}
+
}
+
}
+
}
+13 -4
lexicons/pet/mewsse/embed/video.json
···
{
"lexicon": 1,
"id": "pet.mewsse.embed.video",
-
"description": "An video to embed in a link",
+
"description": "A video to illustrate a link",
"defs": {
"main": {
"type": "object",
-
"required": ["uri"],
+
"required": ["video"],
"properties": {
-
"uri": {
+
"video": {
+
"type": "blob",
+
"description": "A video to illustrate a link",
+
"accept": [
+
"video/*"
+
],
+
"maxSize": 1000000
+
},
+
"alt": {
"type": "string",
-
"format": "uri"
+
"maxLength": 3000,
+
"description": "A alt text to describe the video."
}
}
}
+2 -1
lexicons/pet/mewsse/link.json
···
"refs": [
"pet.mewsse.embed.image",
"pet.mewsse.embed.post",
-
"pet.mewsse.embed.video"
+
"pet.mewsse.embed.video",
+
"pet.mewsse.embed.external"
]
},
"nsfw": {
+1
src/db.ts
···
export type Embed = {
'$type': string,
image?: Blob | LegacyBlob,
+
video?: Blob | LegacyBlob,
alt?: string,
uri?: string
} | null
+1
src/lexicons/index.ts
···
+
export * as PetMewsseEmbedExternal from "./types/pet/mewsse/embed/external.ts";
export * as PetMewsseEmbedImage from "./types/pet/mewsse/embed/image.ts";
export * as PetMewsseEmbedPost from "./types/pet/mewsse/embed/post.ts";
export * as PetMewsseEmbedVideo from "./types/pet/mewsse/embed/video.ts";
+17
src/lexicons/types/pet/mewsse/embed/external.ts
···
+
import type {} from "@atcute/lexicons";
+
import * as v from "@atcute/lexicons/validations";
+
+
const _mainSchema = /*#__PURE__*/ v.object({
+
$type: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.literal("pet.mewsse.embed.external"),
+
),
+
uri: /*#__PURE__*/ v.genericUriString(),
+
});
+
+
type main$schematype = typeof _mainSchema;
+
+
export interface mainSchema extends main$schematype {}
+
+
export const mainSchema = _mainSchema as mainSchema;
+
+
export interface Main extends v.InferInput<typeof mainSchema> {}
+15 -1
src/lexicons/types/pet/mewsse/embed/video.ts
···
$type: /*#__PURE__*/ v.optional(
/*#__PURE__*/ v.literal("pet.mewsse.embed.video"),
),
-
uri: /*#__PURE__*/ v.genericUriString(),
+
/**
+
* A alt text to describe the video.
+
* @maxLength 3000
+
*/
+
alt: /*#__PURE__*/ v.optional(
+
/*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [
+
/*#__PURE__*/ v.stringLength(0, 3000),
+
]),
+
),
+
/**
+
* A video to illustrate a link
+
* @accept video/*
+
* @maxSize 1000000
+
*/
+
video: /*#__PURE__*/ v.blob(),
});
type main$schematype = typeof _mainSchema;
+2
src/lexicons/types/pet/mewsse/link.ts
···
import type {} from "@atcute/lexicons";
import * as v from "@atcute/lexicons/validations";
import type {} from "@atcute/lexicons/ambient";
+
import * as PetMewsseEmbedExternal from "./embed/external.ts";
import * as PetMewsseEmbedImage from "./embed/image.ts";
import * as PetMewsseEmbedPost from "./embed/post.ts";
import * as PetMewsseEmbedVideo from "./embed/video.ts";
···
get embed() {
return /*#__PURE__*/ v.optional(
/*#__PURE__*/ v.variant([
+
PetMewsseEmbedExternal.mainSchema,
PetMewsseEmbedImage.mainSchema,
PetMewsseEmbedPost.mainSchema,
PetMewsseEmbedVideo.mainSchema,
+49
src/lib/embed.ts
···
+
import { isBlob } from '@atcute/lexicons/interfaces'
+
import type { Did } from '@atcute/lexicons/syntax'
+
import type { Embed } from '../db.ts'
+
+
export function findEmbed(did: Did<"web"> | Did<"plc">, pds: string): Function {
+
return async (embed: Embed): Promise<{url?: string, html?:string, $type:string} | null> => {
+
if (!embed) return null
+
+
if (embed.$type === "pet.mewsse.embed.image" || embed.$type === "pet.mewsse.embed.video") {
+
if (!embed.image && !embed.video) return null
+
+
const embedType = embed.image || embed.video
+
+
if (!embedType) return null
+
+
const cid = isBlob(embedType) ? embedType.ref.$link : embedType.cid
+
+
// let the user pull the blob with their browser directly fomr the pds
+
// decreasing space needed to run the service and prevent duplication
+
// if hosted at the same place as the pds (self host anyone ?)
+
return {
+
'$type': embed.$type,
+
url: `${pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`
+
}
+
}
+
+
if (embed.$type === "pet.mewsse.embed.post" && embed.uri) {
+
const at = embed.uri.split("at://").pop()
+
+
return {
+
'$type': embed.$type,
+
url: `https://embed.bsky.app/embed/${at}`
+
}
+
}
+
+
if (embed.$type === "pet.mewsse.embed.external" && embed.uri) {
+
if (embed.uri.indexOf('youtube') != -1) {
+
const id = embed.uri.split("?v=").pop()
+
+
return {
+
'$type': embed.$type,
+
url: `http://www.youtube.com/embed/${id}`
+
}
+
}
+
}
+
+
return null
+
}
+
}
+8 -1
src/routes.ts
···
.executeTakeFirstOrThrow()
const pages = Math.ceil(parseInt(totalLink.count.toString(), 10) / itemPerPages)
+
+
const items = await Promise.all(links.map(async (link) => {
+
return {
+
...link,
+
embed: await embed(link.embed)
+
}
+
}))
const body = eta.render("./main", {
-
items: links,
+
items: items,
pages: Array.from(Array(pages).keys()),
selected: parseInt(params?.page || "0", 10),
embed: embed
+20 -12
src/views/link.eta
···
<div class="description"><%~ it.description %></div>
<% } %>
</section>
-
<% if (it.nsfw) { %>
-
<label class="aside <% if (!it.image) { %>empty<% } %>" target="<%= it.rkey %>">
-
<input type="checkbox" id="<%= it.rkey %>">
-
<% if (it.image) { %>
-
<img src="<%= it.image %>" <% if (it.alt) { %>alt="<%= it.alt %>"<% } %>>
-
<% } %>
-
</label>
-
<% } else { %>
-
<a class="aside <% if (!it.image) { %>empty<% } %>" href="<%= it.link %>">
-
<% if (it.image) { %>
-
<img src="<%= it.image %>" <% if (it.alt) { %>alt="<%= it.alt %>"<% } %>>
-
<% } %>
+
<% if (it.embed) { %>
+
<% if (it.embed.$type == "pet.mewsse.embed.image") { %>
+
<a class="aside" href="<%= it.link %>">
+
<img src="<%= it.embed.url %>" alt="<%= it.embed.alt || "" %>">
</a>
+
<% } %>
+
+
<% if (it.embed.$type == "pet.mewsse.embed.video") { %>
+
<video controls>
+
<source src="<%= it.embed.url %>">
+
</video>
+
<% } %>
+
+
<% if (it.embed.$type == "pet.mewsse.embed.post") { %>
+
<iframe frameborder="0" src="<%= it.embed.url %>"></iframe>
+
<% } %>
+
+
<% if (it.embed.$type == "pet.mewsse.embed.external") {%>
+
<iframe frameborder="0" allowfullscreen src="<%= it.embed.url %>"></iframe>
+
<% } %>
+
<% } %>
</div>