diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 92f27a2bf0..4064f3f352 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -121,7 +121,7 @@ common: use-avatar-reversi-stones: "リバーシの石にアバターを使う" verified-user: "公式アカウント" disable-animated-mfm: "投稿内の動きのあるテキストを無効にする" - do-not-autoplay-animation: "アニメーションを自動再生しない" + do-not-autoplay-animation: "アニメーション画像を再生しない" suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" always-show-nsfw: "常に閲覧注意のメディアを表示する" always-mark-nsfw: "常にメディアを閲覧注意として投稿" diff --git a/src/client/app/common/scripts/get-static-image-url.ts b/src/client/app/common/scripts/get-static-image-url.ts new file mode 100644 index 0000000000..f84adf709c --- /dev/null +++ b/src/client/app/common/scripts/get-static-image-url.ts @@ -0,0 +1,9 @@ +import { url as instanceUrl } from '../../config'; + +export function getStaticImageUrl(url: string): string { + const u = new URL(url); + const dummy = `${u.host}${u.pathname}`; // 拡張子がないとキャッシュしてくれないCDNがあるので + let result = `${instanceUrl}/proxy/${dummy}?url=${encodeURIComponent(u.href)}`; + result += '&static=1'; + return result; +} diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue index 698873833d..205b4a6d79 100644 --- a/src/client/app/common/views/components/avatar.vue +++ b/src/client/app/common/views/components/avatar.vue @@ -15,6 +15,7 @@ <script lang="ts"> import Vue from 'vue'; +import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url'; export default Vue.extend({ props: { @@ -47,6 +48,11 @@ export default Vue.extend({ borderRadius: this.$store.state.settings.circleIcons ? '100%' : null }; }, + url(): string { + return this.$store.state.device.doNotAutoplayAnimation + ? getStaticImageUrl(this.user.avatarUrl) + : this.user.avatarUrl; + }, icon(): any { return { backgroundColor: this.lightmode @@ -54,7 +60,7 @@ export default Vue.extend({ : this.user.avatarColor && this.user.avatarColor.length == 3 ? `rgb(${this.user.avatarColor.join(',')})` : null, - backgroundImage: this.lightmode ? null : `url(${this.user.avatarUrl})`, + backgroundImage: this.lightmode ? null : `url(${this.url})`, borderRadius: this.$store.state.settings.circleIcons ? '100%' : null }; } diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue index 29b09947e4..b791dcab6a 100644 --- a/src/client/app/common/views/components/emoji.vue +++ b/src/client/app/common/views/components/emoji.vue @@ -9,6 +9,7 @@ import Vue from 'vue'; // スクリプトサイズがデカい //import { lib } from 'emojilib'; +import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url'; export default Vue.extend({ props: { @@ -54,7 +55,9 @@ export default Vue.extend({ const customEmoji = this.customEmojis.find(x => x.name == this.name); if (customEmoji) { this.customEmoji = customEmoji; - this.url = customEmoji.url; + this.url = this.$store.state.device.doNotAutoplayAnimation + ? getStaticImageUrl(customEmoji.url) + : customEmoji.url; } else { //const emoji = lib[this.name]; //if (emoji) { diff --git a/src/client/app/common/views/components/media-image.vue b/src/client/app/common/views/components/media-image.vue index 01187465f1..4433ec2afc 100644 --- a/src/client/app/common/views/components/media-image.vue +++ b/src/client/app/common/views/components/media-image.vue @@ -17,6 +17,7 @@ import Vue from 'vue'; import i18n from '../../../i18n'; import ImageViewer from './image-viewer.vue'; +import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url'; export default Vue.extend({ i18n: i18n('common/views/components/media-image.vue'), @@ -36,7 +37,11 @@ export default Vue.extend({ } computed: { style(): any { - let url = `url(${this.image.thumbnailUrl})`; + let url = `url(${ + this.$store.state.device.doNotAutoplayAnimation + ? getStaticImageUrl(this.image.thumbnailUrl) + : this.image.thumbnailUrl + })`; if (this.$store.state.device.loadRemoteMedia || this.$store.state.device.lightmode) { url = null; diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue index 8ab956830e..be0244ee00 100644 --- a/src/client/app/desktop/views/components/settings.vue +++ b/src/client/app/desktop/views/components/settings.vue @@ -518,8 +518,8 @@ export default Vue.extend({ }, doNotAutoplayAnimation: { - get() { return !!this.$store.state.settings.doNotAutoplayAnimation; }, - set(value) { this.$store.dispatch('settings/set', { key: 'doNotAutoplayAnimation', value }); } + get() { return this.$store.state.device.doNotAutoplayAnimation; }, + set(value) { this.$store.commit('device/set', { key: 'doNotAutoplayAnimation', value }); } }, remainDeletedNote: { diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index f7ddefc5f0..8c01b6ac26 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -315,8 +315,8 @@ export default Vue.extend({ }, doNotAutoplayAnimation: { - get() { return !!this.$store.state.settings.doNotAutoplayAnimation; }, - set(value) { this.$store.dispatch('settings/set', { key: 'doNotAutoplayAnimation', value }); } + get() { return this.$store.state.device.doNotAutoplayAnimation; }, + set(value) { this.$store.commit('device/set', { key: 'doNotAutoplayAnimation', value }); } }, showReplyTarget: { diff --git a/src/client/app/store.ts b/src/client/app/store.ts index 8cde2d3595..ef2e57170e 100644 --- a/src/client/app/store.ts +++ b/src/client/app/store.ts @@ -3,7 +3,6 @@ import createPersistedState from 'vuex-persistedstate'; import * as nestedProperty from 'nested-property'; import MiOS from './mios'; -import { hostname } from './config'; import { erase } from '../../prelude/array'; import getNoteSummary from '../../misc/get-note-summary'; @@ -70,7 +69,8 @@ const defaultDeviceSettings = { mobileNotificationPosition: 'bottom', deckTemporaryColumn: null, deckDefault: false, - useOsDefaultEmojis: false + useOsDefaultEmojis: false, + doNotAutoplayAnimation: false }; export default (os: MiOS) => new Vuex.Store({ diff --git a/src/misc/wrap-url.ts b/src/misc/wrap-url.ts deleted file mode 100644 index 25fda4d96a..0000000000 --- a/src/misc/wrap-url.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { URL } from 'url'; -import config from '../config'; - -/** - * avatar, thumbnail, custom-emoji 等のURLをクライアント設定等によって置き換える - */ -export default function(url: string, me: any) { - if (url == null) return url; - - // アニメーション再生無効 - if (me && me.clientSettings && me.clientSettings.doNotAutoplayAnimation) { - const u = new URL(url); - const dummy = `${u.host}${u.pathname}`; // 拡張子がないとキャッシュしてくれないCDNがあるので - let result = `${config.url}/proxy/${dummy}?url=${encodeURI(u.href)}`; - result += '&static=1'; - return result; - } - - return url; -} diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts index e788ac2b2f..62a544c214 100644 --- a/src/models/drive-file.ts +++ b/src/models/drive-file.ts @@ -1,11 +1,10 @@ import * as mongo from 'mongodb'; import * as deepcopy from 'deepcopy'; import { pack as packFolder } from './drive-folder'; -import { pack as packUser, IUser } from './user'; +import { pack as packUser } from './user'; import monkDb, { nativeDbConn, dbLogger } from '../db/mongodb'; import isObjectId from '../misc/is-objectid'; import getDriveFileUrl, { getOriginalUrl } from '../misc/get-drive-file-url'; -import wrapUrl from '../misc/wrap-url'; const DriveFile = monkDb.get<IDriveFile>('driveFiles.files'); DriveFile.createIndex('md5'); @@ -134,7 +133,6 @@ export const packMany = ( detail?: boolean self?: boolean, withUser?: boolean, - me?: string | mongo.ObjectID | IUser, } ) => { return Promise.all(files.map(f => pack(f, options))); @@ -149,7 +147,6 @@ export const pack = ( detail?: boolean, self?: boolean, withUser?: boolean, - me?: string | mongo.ObjectID | IUser, } ) => new Promise<any>(async (resolve, reject) => { const opts = Object.assign({ @@ -192,11 +189,6 @@ export const pack = ( _target.url = getDriveFileUrl(_file); _target.thumbnailUrl = getDriveFileUrl(_file, true); - - if (_target.thumbnailUrl != null) { - _target.thumbnailUrl = wrapUrl(_target.thumbnailUrl, options.me); - } - _target.isRemote = _file.metadata.isRemote; if (_target.properties == null) _target.properties = {}; diff --git a/src/models/note.ts b/src/models/note.ts index b1031d3e9b..352de4f8d6 100644 --- a/src/models/note.ts +++ b/src/models/note.ts @@ -11,7 +11,6 @@ import Reaction from './note-reaction'; import { packMany as packFileMany, IDriveFile } from './drive-file'; import Following from './following'; import Emoji from './emoji'; -import wrapUrl from '../misc/wrap-url'; const Note = db.get<INote>('notes'); Note.createIndex('uri', { sparse: true, unique: true }); @@ -248,14 +247,11 @@ export const pack = async ( fields: { _id: false } }); } else { - _note.emojis = (await Emoji.find({ + _note.emojis = Emoji.find({ name: { $in: _note.emojis }, host: host }, { fields: { _id: false } - })).map(emoji => async () => { - emoji.url = await wrapUrl(emoji.url, me); - return emoji; }); } } @@ -278,7 +274,7 @@ export const pack = async ( if (_note.geo) delete _note.geo.type; // Populate user - _note.user = packUser(_note.userId, me); + _note.user = packUser(_note.userId, meId); // Populate app if (_note.appId) { @@ -286,7 +282,7 @@ export const pack = async ( } // Populate files - _note.files = packFileMany(_note.fileIds || [], { me }); + _note.files = packFileMany(_note.fileIds || []); // Some counts _note.renoteCount = _note.renoteCount || 0; diff --git a/src/models/user.ts b/src/models/user.ts index cba1d98c46..2453a2ed15 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -12,7 +12,6 @@ import config from '../config'; import FollowRequest from './follow-request'; import fetchMeta from '../misc/fetch-meta'; import Emoji from './emoji'; -import wrapUrl from '../misc/wrap-url'; const User = db.get<IUser>('users'); @@ -345,8 +344,6 @@ export const pack = ( if (_user.avatarUrl == null) { _user.avatarUrl = `${config.drive_url}/default-avatar.jpg`; - } else { - _user.avatarUrl = wrapUrl(_user.avatarUrl, me); } if (!meId || !meId.equals(_user.id) || !opts.detail) { @@ -371,7 +368,7 @@ export const pack = ( if (opts.detail) { if (_user.pinnedNoteIds) { // Populate pinned notes - _user.pinnedNotes = packNoteMany(_user.pinnedNoteIds, me, { + _user.pinnedNotes = packNoteMany(_user.pinnedNoteIds, meId, { detail: true }); } @@ -400,14 +397,11 @@ export const pack = ( // カスタム絵文字添付 if (_user.emojis) { - _user.emojis = (await Emoji.find({ + _user.emojis = Emoji.find({ name: { $in: _user.emojis }, host: _user.host }, { fields: { _id: false } - })).map(emoji => { - emoji.url = wrapUrl(emoji.url, me); - return emoji; }); } diff --git a/src/server/api/endpoints/drive/stream.ts b/src/server/api/endpoints/drive/stream.ts index d364f62778..c8342c66b5 100644 --- a/src/server/api/endpoints/drive/stream.ts +++ b/src/server/api/endpoints/drive/stream.ts @@ -65,5 +65,5 @@ export default define(meta, (ps, user) => new Promise(async (res, rej) => { sort: sort }); - res(await packMany(files, { self: true, me: user })); + res(await packMany(files, { self: true })); })); diff --git a/src/server/proxy/proxy-media.ts b/src/server/proxy/proxy-media.ts index a0b65fbcfc..0e8db5f82b 100644 --- a/src/server/proxy/proxy-media.ts +++ b/src/server/proxy/proxy-media.ts @@ -11,7 +11,6 @@ import { IImage, ConvertToPng } from '../../services/drive/image-processor'; export async function proxyMedia(ctx: Koa.BaseContext) { const url = 'url' in ctx.query ? ctx.query.url : 'https://' + ctx.params.url; - console.log(url); // Create temp file const [path, cleanup] = await new Promise<[string, any]>((res, rej) => {