Thread viewer for Bluesky
at 2.0 257 lines 5.0 kB view raw
1import { ATProtoRecord } from './records.js'; 2import { PostDataError, parseViewRecord } from './posts.js'; 3 4/** 5 * Base class for embed objects. 6 */ 7 8export class Embed { 9 10 /** @type {json} */ 11 json; 12 13 /** 14 * More hydrated view of an embed, taken from a full post view (#postView). 15 * 16 * @param {json} json, @returns {Embed} 17 */ 18 19 static parseInlineEmbed(json) { 20 switch (json.$type) { 21 case 'app.bsky.embed.record#view': 22 return new InlineRecordEmbed(json); 23 24 case 'app.bsky.embed.recordWithMedia#view': 25 return new InlineRecordWithMediaEmbed(json); 26 27 case 'app.bsky.embed.images#view': 28 return new InlineImageEmbed(json); 29 30 case 'app.bsky.embed.external#view': 31 return new InlineLinkEmbed(json); 32 33 case 'app.bsky.embed.video#view': 34 return new InlineVideoEmbed(json); 35 36 default: 37 if (location.protocol == 'file:') { 38 throw new PostDataError(`Unexpected embed type: ${json.$type}`); 39 } else { 40 console.warn('Unexpected embed type:', json.$type); 41 return new Embed(json); 42 } 43 } 44 } 45 46 /** 47 * Raw embed extracted from raw record data of a post. Does not include quoted post contents. 48 * 49 * @param {json} json, @returns {Embed} 50 */ 51 52 static parseRawEmbed(json) { 53 switch (json.$type) { 54 case 'app.bsky.embed.record': 55 return new RawRecordEmbed(json); 56 57 case 'app.bsky.embed.recordWithMedia': 58 return new RawRecordWithMediaEmbed(json); 59 60 case 'app.bsky.embed.images': 61 return new RawImageEmbed(json); 62 63 case 'app.bsky.embed.external': 64 return new RawLinkEmbed(json); 65 66 case 'app.bsky.embed.video': 67 return new RawVideoEmbed(json); 68 69 default: 70 if (location.protocol == 'file:') { 71 throw new PostDataError(`Unexpected embed type: ${json.$type}`); 72 } else { 73 console.warn('Unexpected embed type:', json.$type); 74 return new Embed(json); 75 } 76 } 77 } 78 79 /** @param {json} json */ 80 constructor(json) { 81 this.json = json; 82 } 83 84 /** @returns {string} */ 85 get type() { 86 return this.json.$type; 87 } 88} 89 90export class RawImageEmbed extends Embed { 91 92 /** @type {json[]} */ 93 images; 94 95 /** @param {json} json */ 96 constructor(json) { 97 super(json); 98 this.images = json.images; 99 } 100} 101 102export class RawLinkEmbed extends Embed { 103 104 /** @type {string | undefined} */ 105 url; 106 107 /** @type {string | undefined} */ 108 title; 109 110 /** @type {json | undefined} */ 111 thumb; 112 113 /** @param {json} json */ 114 constructor(json) { 115 super(json); 116 117 this.url = json.external.uri; 118 this.title = json.external.title; 119 this.thumb = json.external.thumb; 120 } 121} 122 123export class RawVideoEmbed extends Embed { 124 125 /** @type {json | undefined} */ 126 video; 127 128 /** @param {json} json */ 129 constructor(json) { 130 super(json); 131 this.video = json.video; 132 } 133} 134 135export class RawRecordEmbed extends Embed { 136 137 /** @type {ATProtoRecord} */ 138 record; 139 140 /** @param {json} json */ 141 constructor(json) { 142 super(json); 143 this.record = new ATProtoRecord(json.record); 144 } 145} 146 147export class RawRecordWithMediaEmbed extends Embed { 148 149 /** @type {ATProtoRecord} */ 150 record; 151 152 /** @type {Embed} */ 153 media; 154 155 /** @param {json} json */ 156 constructor(json) { 157 super(json); 158 this.record = new ATProtoRecord(json.record.record); 159 this.media = Embed.parseRawEmbed(json.media); 160 } 161} 162 163export class InlineRecordEmbed extends Embed { 164 165 /** @type {ATProtoRecord} */ 166 record; 167 168 /** 169 * app.bsky.embed.record#view 170 * @param {json} json 171 */ 172 constructor(json) { 173 super(json); 174 this.record = parseViewRecord(json.record); 175 } 176} 177 178export class InlineRecordWithMediaEmbed extends Embed { 179 180 /** @type {ATProtoRecord} */ 181 record; 182 183 /** @type {Embed} */ 184 media; 185 186 /** 187 * app.bsky.embed.recordWithMedia#view 188 * @param {json} json 189 */ 190 constructor(json) { 191 super(json); 192 this.record = parseViewRecord(json.record.record); 193 this.media = Embed.parseInlineEmbed(json.media); 194 } 195} 196 197export class InlineLinkEmbed extends Embed { 198 199 /** @type {string | undefined} */ 200 url; 201 202 /** @type {string | undefined} */ 203 title; 204 205 /** @type {string | undefined} */ 206 description; 207 208 /** @type {json | undefined} */ 209 thumb; 210 211 /** 212 * app.bsky.embed.external#view 213 * @param {json} json 214 */ 215 constructor(json) { 216 super(json); 217 218 this.url = json.external.uri; 219 this.title = json.external.title; 220 this.description = json.external.description; 221 this.thumb = json.external.thumb; 222 } 223} 224 225export class InlineImageEmbed extends Embed { 226 227 /** @type {json[]} */ 228 images; 229 230 /** 231 * app.bsky.embed.images#view 232 * @param {json} json 233 */ 234 constructor(json) { 235 super(json); 236 this.images = json.images; 237 } 238} 239 240export class InlineVideoEmbed extends Embed { 241 242 /** @type {string | undefined} */ 243 playlistURL; 244 245 /** @type {string | undefined} */ 246 alt; 247 248 /** 249 * app.bsky.embed.video#view 250 * @param {json} json 251 */ 252 constructor(json) { 253 super(json); 254 this.playlistURL = json.playlist; 255 this.alt = json.alt; 256 } 257}