diff --git a/src/domain/session/room/timeline/tiles/ImageTile.js b/src/domain/session/room/timeline/tiles/ImageTile.js index 8bdaa514..e72d28e4 100644 --- a/src/domain/session/room/timeline/tiles/ImageTile.js +++ b/src/domain/session/room/timeline/tiles/ImageTile.js @@ -20,15 +20,10 @@ const MAX_HEIGHT = 300; const MAX_WIDTH = 400; export class ImageTile extends MessageTile { - constructor(options, room) { - super(options); - this._room = room; - } - get thumbnailUrl() { const mxcUrl = this._getContent()?.url; if (typeof mxcUrl === "string") { - return this._room.mxcUrlThumbnail(mxcUrl, this.thumbnailWidth, this.thumbnailHeight, "scale"); + return this._mediaRepository.mxcUrlThumbnail(mxcUrl, this.thumbnailWidth, this.thumbnailHeight, "scale"); } return null; } @@ -36,7 +31,7 @@ export class ImageTile extends MessageTile { get url() { const mxcUrl = this._getContent()?.url; if (typeof mxcUrl === "string") { - return this._room.mxcUrl(mxcUrl); + return this._mediaRepository.mxcUrl(mxcUrl); } return null; } diff --git a/src/domain/session/room/timeline/tiles/MessageTile.js b/src/domain/session/room/timeline/tiles/MessageTile.js index 550764c7..3c5e5b56 100644 --- a/src/domain/session/room/timeline/tiles/MessageTile.js +++ b/src/domain/session/room/timeline/tiles/MessageTile.js @@ -20,6 +20,7 @@ import {getIdentifierColorNumber} from "../../../../avatar.js"; export class MessageTile extends SimpleTile { constructor(options) { super(options); + this._mediaRepository = options.mediaRepository; this._clock = options.clock; this._isOwn = this._entry.sender === options.ownUserId; this._date = this._entry.timestamp ? new Date(this._entry.timestamp) : null; diff --git a/src/domain/session/room/timeline/tilesCreator.js b/src/domain/session/room/timeline/tilesCreator.js index 1ae17bdc..567e9e7d 100644 --- a/src/domain/session/room/timeline/tilesCreator.js +++ b/src/domain/session/room/timeline/tilesCreator.js @@ -24,7 +24,8 @@ import {EncryptedEventTile} from "./tiles/EncryptedEventTile.js"; export function tilesCreator({room, ownUserId, clock}) { return function tilesCreator(entry, emitUpdate) { - const options = {entry, emitUpdate, ownUserId, clock}; + const options = {entry, emitUpdate, ownUserId, clock, + mediaRepository: room.mediaRepository}; if (entry.isGap) { return new GapTile(options, room); } else if (entry.eventType) { @@ -38,7 +39,7 @@ export function tilesCreator({room, ownUserId, clock}) { case "m.emote": return new TextTile(options); case "m.image": - return new ImageTile(options, room); + return new ImageTile(options); case "m.location": return new LocationTile(options); default: diff --git a/src/matrix/net/HomeServerApi.js b/src/matrix/net/HomeServerApi.js index 992bcd4a..ba4adb7f 100644 --- a/src/matrix/net/HomeServerApi.js +++ b/src/matrix/net/HomeServerApi.js @@ -45,6 +45,18 @@ class RequestWrapper { } } +function encodeQueryParams(queryParams) { + return Object.entries(queryParams || {}) + .filter(([, value]) => value !== undefined) + .map(([name, value]) => { + if (typeof value === "object") { + value = JSON.stringify(value); + } + return `${encodeURIComponent(name)}=${encodeURIComponent(value)}`; + }) + .join("&"); +} + export class HomeServerApi { constructor({homeServer, accessToken, request, createTimeout, reconnector}) { // store these both in a closure somehow so it's harder to get at in case of XSS? @@ -54,26 +66,15 @@ export class HomeServerApi { this._requestFn = request; this._createTimeout = createTimeout; this._reconnector = reconnector; + this._mediaRepository = new MediaRepository(homeServer); } _url(csPath) { return `${this._homeserver}/_matrix/client/r0${csPath}`; } - _encodeQueryParams(queryParams) { - return Object.entries(queryParams || {}) - .filter(([, value]) => value !== undefined) - .map(([name, value]) => { - if (typeof value === "object") { - value = JSON.stringify(value); - } - return `${encodeURIComponent(name)}=${encodeURIComponent(value)}`; - }) - .join("&"); - } - _request(method, url, queryParams, body, options) { - const queryString = this._encodeQueryParams(queryParams); + const queryString = encodeQueryParams(queryParams); url = `${url}?${queryString}`; let bodyString; const headers = new Map(); @@ -154,13 +155,14 @@ export class HomeServerApi { return this._request("GET", `${this._homeserver}/_matrix/client/versions`, null, null, options); } - _parseMxcUrl(url) { - const prefix = "mxc://"; - if (url.startsWith(prefix)) { - return url.substr(prefix.length).split("/", 2); - } else { - return null; - } + get mediaRepository() { + return this._mediaRepository; + } +} + +class MediaRepository { + constructor(homeserver) { + this._homeserver = homeserver; } mxcUrlThumbnail(url, width, height, method) { @@ -168,7 +170,7 @@ export class HomeServerApi { if (parts) { const [serverName, mediaId] = parts; const httpUrl = `${this._homeserver}/_matrix/media/r0/thumbnail/${encodeURIComponent(serverName)}/${encodeURIComponent(mediaId)}`; - return httpUrl + "?" + this._encodeQueryParams({width, height, method}); + return httpUrl + "?" + encodeQueryParams({width, height, method}); } return null; } @@ -182,6 +184,15 @@ export class HomeServerApi { return null; } } + + _parseMxcUrl(url) { + const prefix = "mxc://"; + if (url.startsWith(prefix)) { + return url.substr(prefix.length).split("/", 2); + } else { + return null; + } + } } export function tests() { diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index 44d021f8..7bea8362 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -201,14 +201,8 @@ export class Room extends EventEmitter { return this._timeline; } - /** @public */ - mxcUrlThumbnail(url, width, height, method) { - return this._hsApi.mxcUrlThumbnail(url, width, height, method); - } - - /** @public */ - mxcUrl(url) { - return this._hsApi.mxcUrl(url); + get mediaRepository() { + return this._hsApi.mediaRepository; } }