Add image/audio/file/location bridging. Fixes #9

This commit is contained in:
Tulir Asokan
2017-11-25 23:57:11 +02:00
parent 1caba73147
commit adeb271c1b
5 changed files with 151 additions and 32 deletions
+45 -7
View File
@@ -64,8 +64,36 @@ class Portal {
return true
}
async copyPhotoSize(telegramPOV, sender, photo) {
const size = photo.sizes.slice(-1)[0]
const uploaded = await this.copyFile(telegramPOV, sender, size.location, photo.id)
uploaded.info.h = size.h
uploaded.info.w = size.w
uploaded.info.size = size.size
uploaded.info.orientation = 0
return uploaded
}
async copyFile(telegramPOV, sender, location, id) {
console.log(JSON.stringify(location, "", " "))
id = id || location.id
const file = await telegramPOV.getFile(location)
const uploaded = await sender.intent.getClient().uploadContent({
stream: file.buffer,
name: `${id}.${file.extension}`,
type: file.mimetype,
}, { rawResponse: false })
uploaded.matrixtype = file.matrixtype
uploaded.info = {
mimetype: file.mimetype,
size: location.size,
}
return uploaded
}
async updateAvatar(telegramPOV, chat) {
if (!chat.photo) {
if (!chat.photo || this.peer.type === "user") {
return false
}
@@ -80,12 +108,11 @@ class Portal {
const file = await telegramPOV.getFile(photo)
const name = `${photo.volume_id}_${photo.local_id}.${file.extension}`
const uploaded = await this.app.botIntent.getClient()
.uploadContent({
stream: Buffer.from(file.bytes),
name,
type: file.mimetype,
}, { rawResponse: false })
const uploaded = await this.app.botIntent.getClient().uploadContent({
stream: file.buffer,
name,
type: file.mimetype,
}, { rawResponse: false })
this.avatarURL = uploaded.content_uri
this.photo = {
@@ -113,6 +140,17 @@ class Portal {
if (evt.text.length > 0) {
sender.sendText(this.roomID, evt.text)
}
if (evt.photo) {
const photo = await this.copyPhoto(evt.source, sender, evt.photo)
photo.name = evt.caption || "Photo"
sender.sendFile(this.roomID, photo)
} else if (evt.document) {
const file = await this.copyFile(evt.source, sender, evt.document)
file.name = evt.caption || "File upload"
sender.sendFile(this.roomID, file)
} else if (evt.geo) {
sender.sendLocation(this.roomID, evt.geo)
}
}
async handleMatrixEvent(sender, evt) {
+87 -20
View File
@@ -14,25 +14,56 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
const telegram = require("telegram-mtproto")
const fileType = require("file-type")
const pkg = require("../package.json")
const TelegramPeer = require("./telegram-peer")
/*
* Mapping from Telegram file types to MIME types and extensions.
*/
const META_FROM_FILETYPE = {
"storage.fileGif": {
mimetype: "image/gif",
extension: "gif",
},
"storage.fileJpeg": {
mimetype: "image/jpeg",
extension: "jpeg",
},
"storage.filePng": {
mimetype: "image/png",
extension: "png",
},
function metaFromFileType(type) {
const extension = type.substr("storage.file".length).toLowerCase()
let fileClass, mimetype, matrixtype
/*eslint no-fallthrough: "off"*/
switch (type) {
case "storage.fileGif":
case "storage.fileJpeg":
case "storage.filePng":
case "storage.fileWebp":
fileClass = "image"
break
case "storage.fileMov":
mimetype = "quicktime"
case "storage.fileMp4":
fileClass = "video"
break
case "storage.fileMp3":
mimetype = "mpeg"
fileClass = "audio"
break
case "storage.filePartial":
throw new Error("Partial files should be completed before fetching their type.")
case "storage.fileUnknown":
fileClass = "application"
mimetype = "octet-stream"
matrixtype = "m.file"
break
default:
return undefined
}
mimetype = `${fileClass}/${mimetype || extension}`
matrixtype = matrixtype || `m.${fileClass}`
return { mimetype, extension, matrixtype }
}
function matrixFromMime(mime) {
if (mime.startsWith("audio/")) {
return "m.audio"
} else if (mime.startsWith("video/")) {
return "m.video"
} else if (mime.startsWith("image/")) {
return "m.image"
}
return "m.file"
}
/**
@@ -278,6 +309,18 @@ class TelegramPuppet {
to,
source: this,
text: update.message,
photo: update.media && update.media._ === "messageMediaPhoto"
? update.media.photo
: undefined,
document: update.media && update.media._ === "messageMediaDocument"
? update.media.document
: undefined,
geo: update.media && update.media._ === "messageMediaGeo"
? update.media.geo
: undefined,
caption: update.media ?
update.media.caption
: undefined,
})
}
@@ -352,17 +395,41 @@ class TelegramPuppet {
}
async getFile(location) {
location = Object.assign({}, location, { _: "inputFileLocation" })
delete location.dc_id
if (location.volume_id && location.local_id) {
location = {
_: "inputFileLocation",
volume_id: location.volume_id,
local_id: location.local_id,
secret: location.secret,
}
} else if (location.id && location.access_hash) {
location = {
_: "inputDocumentFileLocation",
id: location.id,
access_hash: location.access_hash,
}
} else {
throw new Error("Unrecognized file location type.")
}
const file = await this.client("upload.getFile", {
location,
offset: 0,
// Max download size: 100mb
limit: 100 * 1024 * 1024,
})
const meta = META_FROM_FILETYPE[file.type._]
if (meta) {
file.mimetype = meta.mimetype
file.extension = meta.extension
file.buffer = Buffer.from(file.bytes)
if (file.type._ === "storage.filePartial") {
const { mime, ext } = fileType(file.buffer)
file.mimetype = mime
file.extension = ext
file.matrixtype = matrixFromMime(mime)
} else {
const meta = metaFromFileType(file.type._)
if (meta) {
file.mimetype = meta.mimetype
file.extension = meta.extension
file.matrixtype = meta.matrixtype
}
}
return file
}
+13 -5
View File
@@ -138,12 +138,20 @@ class TelegramUser {
return this.intent.sendText(roomID, text)
}
sendImage(roomID, opts) {
sendFile(roomID, file) {
return this.intent.sendMessage(roomID, {
msgtype: "m.image",
url: opts.content_uri,
body: opts.name,
info: opts.info,
msgtype: file.matrixtype || "m.file",
url: file.content_uri,
body: file.name || "Uploaded file",
info: file.info,
})
}
sendLocation(roomID, { long = 0.0, lat = 0.0, body = "Location" } = {}) {
return this.intent.sendMessage(roomID, {
msgtype: "m.location",
geo_uri: `geo:${lat},${long}`,
body,
})
}