ImageEvent.ts (6385B)
1 import { 2 ExtensibleEvents, 3 IPartialEvent, 4 Optional, 5 UnstableValue, 6 EventType, 7 isEventTypeSame, 8 isProvided, 9 M_TEXT, 10 InvalidEventError, 11 isOptionalAString, 12 NamespacedValue, 13 M_MESSAGE_EVENT_CONTENT, 14 EitherAnd, 15 M_TEXT_EVENT, 16 ExtensibleEvent 17 } from "matrix-events-sdk"; 18 19 export const M_IMAGE = new UnstableValue("m.image", "org.matrix.msc1767.image"); 20 export const M_FILE = new UnstableValue("m.file", "org.matrix.msc1767.file"); 21 export const M_THUMBNAIL = new UnstableValue("m.thumbnail", "org.matrix.msc1767.thumbnail"); 22 export const M_BLURHASH = new UnstableValue("blurhash", "xyz.amorgan.blurhash"); 23 export const MATRIX_ART_DESCRIPTION = new NamespacedValue("matrixart.description"); 24 export const MATRIX_ART_TAGS = new NamespacedValue("matrixart.tags"); 25 export const MATRIX_ART_NSFW = new NamespacedValue("matrixart.nsfw"); 26 export const MATRIX_ART_LICENSE = new NamespacedValue("matrixart.license"); 27 28 type ThumbnailFileEvent = ImageFields & { 29 url: string; 30 mimetype: string; 31 size: number; 32 }; 33 34 type ImageFields = { 35 width: number; 36 height: number; 37 }; 38 39 type FileEvent = { 40 url: string; 41 name: string; 42 mimetype: string; 43 size: number; 44 }; 45 46 export type M_IMAGE_EVENT = EitherAnd<{ [M_IMAGE.name]: ImageFields; }, { [M_IMAGE.altName]: ImageFields; }>; 47 export type M_FILE_EVENT = EitherAnd<{ [M_FILE.name]: FileEvent; }, { [M_FILE.altName]: FileEvent; }>; 48 export type M_THUMBNAIL_EVENT = EitherAnd<{ [M_THUMBNAIL.name]: ThumbnailFileEvent[]; }, { [M_THUMBNAIL.altName]: ThumbnailFileEvent[]; }>; 49 export type M_BLURHASH_EVENT = EitherAnd<{ [M_BLURHASH.name]: string; }, { [M_BLURHASH.altName]: string; }>; 50 export type MATRIX_ART_TAGS_EVENT = { ["matrixart.tags"]: string[]; }; 51 export type MATRIX_ART_DESCRIPTION_EVENT = { ["matrixart.description"]: string; }; 52 export type MATRIX_ART_NSFW_EVENT = { ["matrixart.nsfw"]: boolean; }; 53 export type MATRIX_ART_LICENSE_EVENT = { ["matrixart.license"]: string; }; 54 export type M_IMAGE_EVENT_CONTENT = M_MESSAGE_EVENT_CONTENT 55 & M_IMAGE_EVENT 56 & M_FILE_EVENT 57 & M_TEXT_EVENT 58 | M_BLURHASH_EVENT 59 | M_THUMBNAIL_EVENT 60 | MATRIX_ART_TAGS_EVENT 61 | MATRIX_ART_DESCRIPTION_EVENT 62 | MATRIX_ART_NSFW_EVENT 63 | MATRIX_ART_LICENSE_EVENT; 64 65 export class ImageEvent extends ExtensibleEvent<M_IMAGE_EVENT_CONTENT> { 66 public readonly image!: ImageFields; 67 public readonly text!: string; 68 public readonly thumbnails?: ThumbnailFileEvent[]; 69 public readonly blurhash?: string; 70 public readonly file!: FileEvent; 71 public readonly description?: string; 72 public readonly tags?: string[]; 73 public readonly nsfw: boolean = false; 74 public readonly license?: string; 75 76 77 public isEquivalentTo(primaryEventType: EventType): boolean { 78 return isEventTypeSame(primaryEventType, M_IMAGE); 79 } 80 public serialize(): IPartialEvent<object> { 81 const content: M_IMAGE_EVENT_CONTENT = { 82 [M_TEXT.name]: this.text, 83 [M_FILE.name]: this.file, 84 [M_IMAGE.name]: this.image, 85 [M_THUMBNAIL.name]: this.thumbnails, 86 [M_BLURHASH.name]: this.blurhash, 87 ["matrixart.description"]: this.description, 88 ["matrixart.tags"]: this.tags, 89 ["matrixart.nsfw"]: this.nsfw, 90 ["matrixart.license"]: this.license, 91 }; 92 93 return { 94 type: "m.image", 95 content: content, 96 }; 97 } 98 99 constructor(wireFormat: IPartialEvent<M_IMAGE_EVENT_CONTENT>) { 100 super(wireFormat); 101 102 const mimage = M_IMAGE.findIn<ImageFields>(this.wireContent); 103 // Probably wrong 104 const mtext = M_TEXT.findIn<string>(this.wireContent); 105 const mfile = M_FILE.findIn<FileEvent>(this.wireContent); 106 const mthumbnail = M_THUMBNAIL.findIn<ThumbnailFileEvent[]>(this.wireContent); 107 const mblurhash = M_BLURHASH.findIn<string>(this.wireContent); 108 const matrixart_description = MATRIX_ART_DESCRIPTION.findIn<string>(this.wireContent); 109 const matrixart_tags = MATRIX_ART_TAGS.findIn<string[]>(this.wireContent); 110 const matrixart_nsfw = MATRIX_ART_NSFW.findIn<boolean>(this.wireContent); 111 const matrixart_license = MATRIX_ART_LICENSE.findIn<string>(this.wireContent); 112 113 // Required fields 114 if (isProvided(mimage)) { 115 if (!mimage) { 116 throw new InvalidEventError("m.image is required to be present"); 117 } 118 this.image = mimage; 119 } 120 if (isProvided(mfile)) { 121 if (!mfile) { 122 throw new InvalidEventError("m.file is required to be present"); 123 } 124 this.file = mfile; 125 } 126 if (isOptionalAString(mtext)) { 127 if (!mimage) { 128 throw new InvalidEventError("m.text is required to be present"); 129 } 130 // Safe but ts is stupid here 131 this.text = mtext as string; 132 } 133 134 // Optional fields 135 if (isProvided(mthumbnail)) { 136 if (!Array.isArray(mthumbnail)) { 137 throw new InvalidEventError("m.thumbnail contents must be an array"); 138 } 139 this.thumbnails = mthumbnail; 140 } 141 if (isOptionalAString(mblurhash)) { 142 this.blurhash = mblurhash as string; 143 } 144 if (isOptionalAString(matrixart_description)) { 145 this.description = matrixart_description as string; 146 } 147 if (isProvided(matrixart_tags)) { 148 if (!Array.isArray(matrixart_tags)) { 149 throw new InvalidEventError("matrixart.tags contents must be an array"); 150 } 151 this.tags = matrixart_tags; 152 } 153 if (isProvided(matrixart_nsfw)) { 154 if (typeof matrixart_nsfw !== "boolean") { 155 throw new InvalidEventError("matrixart.tags contents must be an boolean"); 156 } 157 this.nsfw = matrixart_nsfw; 158 } 159 if (isOptionalAString(matrixart_license)) { 160 this.license = matrixart_license as string; 161 } 162 } 163 } 164 165 function parseImageEvent(wireEvent: IPartialEvent<object>): Optional<ImageEvent> { 166 const event = wireEvent as IPartialEvent<M_IMAGE_EVENT_CONTENT>; 167 return new ImageEvent(event); 168 } 169 170 ExtensibleEvents.registerInterpreter(M_IMAGE, parseImageEvent); 171 ExtensibleEvents.unknownInterpretOrder.push(M_IMAGE);