Mastodon: websocket token and card
This commit is contained in:
parent
74935ced6c
commit
a97ffb491b
12
package.json
12
package.json
|
@ -21,12 +21,6 @@
|
||||||
"@vue/cli-plugin-typescript": "^3.0.3",
|
"@vue/cli-plugin-typescript": "^3.0.3",
|
||||||
"@vue/cli-service": "^3.0.3",
|
"@vue/cli-service": "^3.0.3",
|
||||||
"babel-plugin-transform-decorators": "^6.24.1",
|
"babel-plugin-transform-decorators": "^6.24.1",
|
||||||
"pug": "^2.0.3",
|
|
||||||
"pug-plain-loader": "^1.0.0",
|
|
||||||
"sass-loader": "^7.0.1",
|
|
||||||
"tslint-config-prettier": "^1.15.0",
|
|
||||||
"tslint-plugin-prettier": "^1.3.0",
|
|
||||||
"typescript": "^3.0.0",
|
|
||||||
"core-js": "^2.6.5",
|
"core-js": "^2.6.5",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^0.28.11",
|
||||||
"eslint": "^5.16.0",
|
"eslint": "^5.16.0",
|
||||||
|
@ -37,6 +31,12 @@
|
||||||
"less-loader": "^4.1.0",
|
"less-loader": "^4.1.0",
|
||||||
"node-sass": "^4.11.0",
|
"node-sass": "^4.11.0",
|
||||||
"optimize-css-assets-webpack-plugin": "^4.0.0",
|
"optimize-css-assets-webpack-plugin": "^4.0.0",
|
||||||
|
"pug": "^2.0.3",
|
||||||
|
"pug-plain-loader": "^1.0.0",
|
||||||
|
"sass-loader": "^7.0.1",
|
||||||
|
"tslint-config-prettier": "^1.15.0",
|
||||||
|
"tslint-plugin-prettier": "^1.3.0",
|
||||||
|
"typescript": "^3.0.0",
|
||||||
"url-loader": "^1.0.1",
|
"url-loader": "^1.0.1",
|
||||||
"vue-loader": "^15.4.2",
|
"vue-loader": "^15.4.2",
|
||||||
"vue-style-loader": "^4.1.2",
|
"vue-style-loader": "^4.1.2",
|
||||||
|
|
|
@ -24,7 +24,7 @@ import ServiceClient from '@/components/ServiceClient'
|
||||||
import Lists from '@/helpers/lists/Lists'
|
import Lists from '@/helpers/lists/Lists'
|
||||||
import AxiosLodable from '@/helpers/loadable/AxiosLoadable'
|
import AxiosLodable from '@/helpers/loadable/AxiosLoadable'
|
||||||
import AxiosLodableMore from '@/helpers/loadable/AxiosLoadableMore'
|
import AxiosLodableMore from '@/helpers/loadable/AxiosLoadableMore'
|
||||||
import { AUTH, getRest } from './Mastodon.vue'
|
import { AUTH, getHeaders, getRest } from './Mastodon.vue'
|
||||||
import Notification from './Notification.vue'
|
import Notification from './Notification.vue'
|
||||||
import Status from './Status.vue'
|
import Status from './Status.vue'
|
||||||
import { MarkMessage, Notification as INotification, Options, Status as IStatus } from './Types'
|
import { MarkMessage, Notification as INotification, Options, Status as IStatus } from './Types'
|
||||||
|
@ -98,36 +98,40 @@ export default class Client extends Mixins<ServiceClient<Options>>(ServiceClient
|
||||||
}
|
}
|
||||||
|
|
||||||
setupStream() {
|
setupStream() {
|
||||||
const ws = new WebSocket(
|
this.get('/instance').then(res => {
|
||||||
`wss://${this.auth.get(AUTH.SERVER)}/api/v1/streaming?access_token=${this.auth.get(AUTH.TOKEN)}&stream=user`
|
const oldAuth = res.data.version < '2.8.4' ? `access_token=${this.auth.get(AUTH.TOKEN)}&` : ''
|
||||||
)
|
const ws = new WebSocket(
|
||||||
ws.onmessage = event => {
|
`wss://${this.auth.get(AUTH.SERVER)}/api/v1/streaming?${oldAuth}stream=user`,
|
||||||
const data = JSON.parse(event.data)
|
this.auth.get(AUTH.TOKEN)
|
||||||
const payload = JSON.parse(data.payload)
|
|
||||||
switch (data.event) {
|
|
||||||
case 'update':
|
|
||||||
this.statues.with(s => s.unshift(payload))
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'notification':
|
|
||||||
this.notifications.with(n => n.unshift(payload))
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'delete':
|
|
||||||
this.statues.with(st => Lists.removeFirstBy(st, s => s.id, payload.id))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ws.onerror = ev => this.emitError(ev.type)
|
|
||||||
ws.onclose = () => {
|
|
||||||
this.emitError(
|
|
||||||
'Mastodon stream disconnected !' +
|
|
||||||
(this.options.reconnect ? ' Reconnecting...' : '')
|
|
||||||
)
|
)
|
||||||
if (this.options.reconnect) {
|
ws.onmessage = event => {
|
||||||
setTimeout(() => this.setupStream(), this.options.timeout)
|
const data = JSON.parse(event.data)
|
||||||
|
const payload = JSON.parse(data.payload)
|
||||||
|
switch (data.event) {
|
||||||
|
case 'update':
|
||||||
|
this.statues.with(s => s.unshift(payload))
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'notification':
|
||||||
|
this.notifications.with(n => n.unshift(payload))
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'delete':
|
||||||
|
this.statues.with(st => Lists.removeFirstBy(st, s => s.id, payload.id))
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
ws.onerror = ev => this.emitError(ev.type)
|
||||||
|
ws.onclose = () => {
|
||||||
|
this.emitError(
|
||||||
|
'Mastodon stream disconnected !' +
|
||||||
|
(this.options.reconnect ? ' Reconnecting...' : '')
|
||||||
|
)
|
||||||
|
if (this.options.reconnect) {
|
||||||
|
setTimeout(() => this.setupStream(), this.options.timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -191,6 +195,12 @@ export default class Client extends Mixins<ServiceClient<Options>>(ServiceClient
|
||||||
background-color: #00000044
|
background-color: #00000044
|
||||||
color: white
|
color: white
|
||||||
padding: .5em
|
padding: .5em
|
||||||
|
.card
|
||||||
|
@include tile
|
||||||
|
padding: .2em
|
||||||
|
display: block
|
||||||
|
.provider
|
||||||
|
float: right
|
||||||
.meta
|
.meta
|
||||||
margin-left: 1em + $avatarSize
|
margin-left: 1em + $avatarSize
|
||||||
font-size: .8em
|
font-size: .8em
|
||||||
|
|
|
@ -38,10 +38,13 @@ import { ParseEmojisMixin } from './ParseEmojisMixin'
|
||||||
import { Account, Options } from './Types'
|
import { Account, Options } from './Types'
|
||||||
|
|
||||||
export const AUTH = { SERVER: 'server', TOKEN: 'token' }
|
export const AUTH = { SERVER: 'server', TOKEN: 'token' }
|
||||||
|
export function getHeaders(auth: Auth) {
|
||||||
|
return { headers: { Authorization: 'Bearer ' + auth.get(AUTH.TOKEN) } }
|
||||||
|
}
|
||||||
export function getRest(auth: Auth, timeout: number) {
|
export function getRest(auth: Auth, timeout: number) {
|
||||||
return axios.create({
|
return axios.create({
|
||||||
baseURL: `https://${auth.get(AUTH.SERVER)}/api/v1/`, timeout,
|
baseURL: `https://${auth.get(AUTH.SERVER)}/api/v1/`, timeout,
|
||||||
headers: { Authorization: 'Bearer ' + auth.get(AUTH.TOKEN) },
|
...getHeaders(auth)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,15 @@
|
||||||
img(v-if="media.type == 'image' || media.type == 'gifv'" :src="media.preview_url" :alt="media.description" :title="media.description")
|
img(v-if="media.type == 'image' || media.type == 'gifv'" :src="media.preview_url" :alt="media.description" :title="media.description")
|
||||||
template(v-else) Wrong type
|
template(v-else) Wrong type
|
||||||
.gif(v-if="media.type == 'gifv'") GIF
|
.gif(v-if="media.type == 'gifv'") GIF
|
||||||
template(v-else) Hidden media
|
template(v-else) Hidden media {{ media.description }}
|
||||||
|
.poll(v-if="status.poll") {{ renderPoll(status.poll) }}
|
||||||
|
a.card(v-if="status.card" :href="status.card.url" target="_blank")
|
||||||
|
a.provider(v-if="status.card.provider_name" :src="status.card.provider_url" target="_blank") {{ status.card.provider_name }}
|
||||||
|
.title {{ status.card.title }}
|
||||||
|
.descr {{ status.card.description }}
|
||||||
|
template(v-if="status.card.image")
|
||||||
|
img(v-if="showMedia" :src="status.card.image")
|
||||||
|
a(v-else-if="status.card.type == 'photo'" :src="status.card.image" target="_blank") Hidden media
|
||||||
status.reblog(v-else :status="status.reblog" :showMedia="showMedia")
|
status.reblog(v-else :status="status.reblog" :showMedia="showMedia")
|
||||||
|
|
||||||
.meta(v-if="!status.reblog")
|
.meta(v-if="!status.reblog")
|
||||||
|
@ -41,7 +49,7 @@ import FromNowMixin from '@/components/FromNowMixin'
|
||||||
import ShowMediaMixin from '@/components/ShowMediaMixin'
|
import ShowMediaMixin from '@/components/ShowMediaMixin'
|
||||||
import Account from './Account.vue'
|
import Account from './Account.vue'
|
||||||
import { ParseEmojisMixin } from './ParseEmojisMixin'
|
import { ParseEmojisMixin } from './ParseEmojisMixin'
|
||||||
import { MarkMessage, Status as IStatus } from './Types'
|
import { Card, MarkMessage, Poll, Status as IStatus } from './Types'
|
||||||
|
|
||||||
@Component({ components: { Account } })
|
@Component({ components: { Account } })
|
||||||
export default class Status extends Mixins(ParseEmojisMixin, ShowMediaMixin, FromNowMixin) {
|
export default class Status extends Mixins(ParseEmojisMixin, ShowMediaMixin, FromNowMixin) {
|
||||||
|
@ -60,6 +68,10 @@ export default class Status extends Mixins(ParseEmojisMixin, ShowMediaMixin, Fro
|
||||||
throw status.id // TODO:
|
throw status.id // TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderPoll(poll: Poll) {
|
||||||
|
throw poll // TODO:
|
||||||
|
}
|
||||||
|
|
||||||
@Emit('mark')
|
@Emit('mark')
|
||||||
emitMark(status: IStatus, action: 'reblog' | 'favourite', callback: CallableFunction, undo = false): MarkMessage {
|
emitMark(status: IStatus, action: 'reblog' | 'favourite', callback: CallableFunction, undo = false): MarkMessage {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -34,7 +34,36 @@ export interface Status {
|
||||||
replies_count: number
|
replies_count: number
|
||||||
in_reply_to_id?: number
|
in_reply_to_id?: number
|
||||||
reblog?: Status
|
reblog?: Status
|
||||||
spoiler_text?: string
|
spoiler_text?: string,
|
||||||
|
card?: Card,
|
||||||
|
poll?: Poll
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CardType = 'link' | 'photo' | 'video' | 'rich'
|
||||||
|
export interface Card {
|
||||||
|
url: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
image?: string
|
||||||
|
type: CardType
|
||||||
|
author_name?: string
|
||||||
|
author_url?: string
|
||||||
|
provider_name?: string
|
||||||
|
provider_url?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PollOption {
|
||||||
|
title: string
|
||||||
|
votes_count?: number
|
||||||
|
}
|
||||||
|
export interface Poll {
|
||||||
|
id: string
|
||||||
|
expires_at?: string
|
||||||
|
expired: boolean
|
||||||
|
multiple: boolean
|
||||||
|
votes_count: number
|
||||||
|
options: PollOption[]
|
||||||
|
voted?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Media {
|
export interface Media {
|
||||||
|
|
Loading…
Reference in New Issue