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) => {