diff --git a/package.json b/package.json
index 70124a0ae4329bfe99c234d06215244c11c5f7dd..775c997e55dc7c23fec31e63f462bfbc98b2b6e5 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
 	"name": "misskey",
 	"author": "syuilo <i@syuilo.com>",
-	"version": "8.26.0",
+	"version": "9.0.0",
 	"clientVersion": "1.0.9358",
 	"codename": "nighthike",
 	"main": "./built/index.js",
diff --git a/src/client/app/common/scripts/parse-search-query.ts b/src/client/app/common/scripts/parse-search-query.ts
deleted file mode 100644
index 5f6ae3320ad235b28bfcabc90d295d8b45232d3e..0000000000000000000000000000000000000000
--- a/src/client/app/common/scripts/parse-search-query.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-export default function(qs: string) {
-	const q = {
-		text: ''
-	};
-
-	qs.split(' ').forEach(x => {
-		if (/^([a-z_]+?):(.+?)$/.test(x)) {
-			const [key, value] = x.split(':');
-			switch (key) {
-				case 'user':
-					q['includeUserUsernames'] = value.split(',');
-					break;
-				case 'exclude_user':
-					q['excludeUserUsernames'] = value.split(',');
-					break;
-				case 'follow':
-					q['following'] = value == 'null' ? null : value == 'true';
-					break;
-				case 'reply':
-					q['reply'] = value == 'null' ? null : value == 'true';
-					break;
-				case 'renote':
-					q['renote'] = value == 'null' ? null : value == 'true';
-					break;
-				case 'media':
-					q['media'] = value == 'null' ? null : value == 'true';
-					break;
-				case 'poll':
-					q['poll'] = value == 'null' ? null : value == 'true';
-					break;
-				case 'until':
-				case 'since':
-					// YYYY-MM-DD
-					if (/^[0-9]+\-[0-9]+\-[0-9]+$/) {
-						const [yyyy, mm, dd] = value.split('-');
-						q[`${key}_date`] = (new Date(parseInt(yyyy, 10), parseInt(mm, 10) - 1, parseInt(dd, 10))).getTime();
-					}
-					break;
-				default:
-					q[key] = value;
-					break;
-			}
-		} else {
-			q.text += x + ' ';
-		}
-	});
-
-	if (q.text) {
-		q.text = q.text.trim();
-	}
-
-	return q;
-}
diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue
index d4e7902c7bae991c266f9194bfa02ce65e11f246..b427721d37a365be9b8f929c6d476c48809daaf4 100644
--- a/src/client/app/common/views/components/welcome-timeline.vue
+++ b/src/client/app/common/views/components/welcome-timeline.vue
@@ -63,7 +63,7 @@ export default Vue.extend({
 				local: true,
 				reply: false,
 				renote: false,
-				media: false,
+				file: false,
 				poll: false
 			}).then(notes => {
 				this.notes = notes;
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index 1ba4a9a4470c71f519f85a8acba040595c9cdfb2..a61a004a85372ca0b7bbce9e77288924c6cc5d56 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -42,8 +42,8 @@
 				<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
 				<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 			</div>
-			<div class="media" v-if="p.media.length > 0">
-				<mk-media-list :media-list="p.media" :raw="true"/>
+			<div class="files" v-if="p.files.length > 0">
+				<mk-media-list :media-list="p.files" :raw="true"/>
 			</div>
 			<mk-poll v-if="p.poll" :note="p"/>
 			<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
@@ -114,7 +114,7 @@ export default Vue.extend({
 		isRenote(): boolean {
 			return (this.note.renote &&
 				this.note.text == null &&
-				this.note.mediaIds.length == 0 &&
+				this.note.fileIds.length == 0 &&
 				this.note.poll == null);
 		},
 		p(): any {
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 7592ae390585d766ca45c4d726677d2f79f330fa..1d6b2048ba84b981eb4a090773ce126ee95f1c5e 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -28,8 +28,8 @@
 						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
 						<a class="rp" v-if="p.renote">RP:</a>
 					</div>
-					<div class="media" v-if="p.media.length > 0">
-						<mk-media-list :media-list="p.media"/>
+					<div class="files" v-if="p.files.length > 0">
+						<mk-media-list :media-list="p.files"/>
 					</div>
 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
 					<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
@@ -110,7 +110,7 @@ export default Vue.extend({
 		isRenote(): boolean {
 			return (this.note.renote &&
 				this.note.text == null &&
-				this.note.mediaIds.length == 0 &&
+				this.note.fileIds.length == 0 &&
 				this.note.poll == null);
 		},
 
diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index a1c1207a7beb0f4b31298de3ab59e6738d47cb0f..f19ecf8f9a47f30996aa47d83340a5b1c424acdd 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -122,7 +122,7 @@ export default Vue.extend({
 		prepend(note, silent = false) {
 			//#region 弾く
 			const isMyNote = note.userId == this.$store.state.i.id;
-			const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
+			const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
 
 			if (this.$store.state.settings.showMyRenotes === false) {
 				if (isMyNote && isPureRenote) {
diff --git a/src/client/app/desktop/views/components/post-form-window.vue b/src/client/app/desktop/views/components/post-form-window.vue
index 51a416e281cb7854031fa808dcc9a083d71e1333..a88c96d1bfef901af7d6213fd6b9d72d15eb7003 100644
--- a/src/client/app/desktop/views/components/post-form-window.vue
+++ b/src/client/app/desktop/views/components/post-form-window.vue
@@ -4,7 +4,7 @@
 		<span class="icon" v-if="geo">%fa:map-marker-alt%</span>
 		<span v-if="!reply">%i18n:@note%</span>
 		<span v-if="reply">%i18n:@reply%</span>
-		<span class="count" v-if="media.length != 0">{{ '%i18n:@attaches%'.replace('{}', media.length) }}</span>
+		<span class="count" v-if="files.length != 0">{{ '%i18n:@attaches%'.replace('{}', files.length) }}</span>
 		<span class="count" v-if="uploadings.length != 0">{{ '%i18n:@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span>
 	</span>
 
@@ -14,7 +14,7 @@
 			:reply="reply"
 			@posted="onPosted"
 			@change-uploadings="onChangeUploadings"
-			@change-attached-media="onChangeMedia"
+			@change-attached-files="onChangeFiles"
 			@geo-attached="onGeoAttached"
 			@geo-dettached="onGeoDettached"/>
 	</div>
@@ -29,7 +29,7 @@ export default Vue.extend({
 	data() {
 		return {
 			uploadings: [],
-			media: [],
+			files: [],
 			geo: null
 		};
 	},
@@ -42,8 +42,8 @@ export default Vue.extend({
 		onChangeUploadings(files) {
 			this.uploadings = files;
 		},
-		onChangeMedia(media) {
-			this.media = media;
+		onChangeFiles(files) {
+			this.files = files;
 		},
 		onGeoAttached(geo) {
 			this.geo = geo;
diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue
index 2ca54846100c09ad9eee39b3203efa2933baf715..f6f52c8f1f85ca97aa3e90e8c05603bdcf8811ab 100644
--- a/src/client/app/desktop/views/components/post-form.vue
+++ b/src/client/app/desktop/views/components/post-form.vue
@@ -20,7 +20,7 @@
 			@keydown="onKeydown" @paste="onPaste" :placeholder="placeholder"
 			v-autocomplete="'text'"
 		></textarea>
-		<div class="medias" :class="{ with: poll }" v-show="files.length != 0">
+		<div class="files" :class="{ with: poll }" v-show="files.length != 0">
 			<x-draggable :list="files" :options="{ animation: 150 }">
 				<div v-for="file in files" :key="file.id">
 					<div class="img" :style="{ backgroundImage: `url(${file.thumbnailUrl})` }" :title="file.name"></div>
@@ -188,7 +188,7 @@ export default Vue.extend({
 							(this.$refs.poll as any).set(draft.data.poll);
 						});
 					}
-					this.$emit('change-attached-media', this.files);
+					this.$emit('change-attached-files', this.files);
 				}
 			}
 
@@ -225,12 +225,12 @@ export default Vue.extend({
 
 		attachMedia(driveFile) {
 			this.files.push(driveFile);
-			this.$emit('change-attached-media', this.files);
+			this.$emit('change-attached-files', this.files);
 		},
 
 		detachMedia(id) {
 			this.files = this.files.filter(x => x.id != id);
-			this.$emit('change-attached-media', this.files);
+			this.$emit('change-attached-files', this.files);
 		},
 
 		onChangeFile() {
@@ -249,7 +249,7 @@ export default Vue.extend({
 			this.text = '';
 			this.files = [];
 			this.poll = false;
-			this.$emit('change-attached-media', this.files);
+			this.$emit('change-attached-files', this.files);
 		},
 
 		onKeydown(e) {
@@ -297,7 +297,7 @@ export default Vue.extend({
 			if (driveFile != null && driveFile != '') {
 				const file = JSON.parse(driveFile);
 				this.files.push(file);
-				this.$emit('change-attached-media', this.files);
+				this.$emit('change-attached-files', this.files);
 				e.preventDefault();
 			}
 			//#endregion
@@ -354,7 +354,7 @@ export default Vue.extend({
 
 			(this as any).api('notes/create', {
 				text: this.text == '' ? undefined : this.text,
-				mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
+				fileIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
 				replyId: this.reply ? this.reply.id : undefined,
 				renoteId: this.renote ? this.renote.id : undefined,
 				poll: this.poll ? (this.$refs.poll as any).get() : undefined,
@@ -514,7 +514,7 @@ root(isDark)
 				margin-right 8px
 				white-space nowrap
 
-		> .medias
+		> .files
 			margin 0
 			padding 0
 			background isDark ? #181b23 : lighten($theme-color, 98%)
diff --git a/src/client/app/desktop/views/components/sub-note-content.vue b/src/client/app/desktop/views/components/sub-note-content.vue
index cb0374b910136f93c029f940dbbaeb40e2a89018..6889dc231e303ea4d9ceb9adad6a3c622f0eb7b3 100644
--- a/src/client/app/desktop/views/components/sub-note-content.vue
+++ b/src/client/app/desktop/views/components/sub-note-content.vue
@@ -7,9 +7,9 @@
 		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
 		<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a>
 	</div>
-	<details v-if="note.media.length > 0">
-		<summary>({{ '%i18n:@media-count%'.replace('{}', note.media.length) }})</summary>
-		<mk-media-list :media-list="note.media"/>
+	<details v-if="note.files.length > 0">
+		<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
+		<mk-media-list :media-list="note.files"/>
 	</details>
 	<details v-if="note.poll">
 		<summary>%i18n:@poll%</summary>
diff --git a/src/client/app/desktop/views/pages/deck/deck.list-tl.vue b/src/client/app/desktop/views/pages/deck/deck.list-tl.vue
index 70048f99e3d87c59761191acd60d04437d372daf..e82e76e4d0da6d74cd32717d117e4ea65acb25f9 100644
--- a/src/client/app/desktop/views/pages/deck/deck.list-tl.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.list-tl.vue
@@ -68,7 +68,7 @@ export default Vue.extend({
 				(this as any).api('notes/user-list-timeline', {
 					listId: this.list.id,
 					limit: fetchLimit + 1,
-					mediaOnly: this.mediaOnly,
+					withFiles: this.mediaOnly,
 					includeMyRenotes: this.$store.state.settings.showMyRenotes,
 					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 					includeLocalRenotes: this.$store.state.settings.showLocalRenotes
@@ -90,7 +90,7 @@ export default Vue.extend({
 				listId: this.list.id,
 				limit: fetchLimit + 1,
 				untilId: (this.$refs.timeline as any).tail().id,
-				mediaOnly: this.mediaOnly,
+				withFiles: this.mediaOnly,
 				includeMyRenotes: this.$store.state.settings.showMyRenotes,
 				includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 				includeLocalRenotes: this.$store.state.settings.showLocalRenotes
@@ -109,7 +109,7 @@ export default Vue.extend({
 			return promise;
 		},
 		onNote(note) {
-			if (this.mediaOnly && note.media.length == 0) return;
+			if (this.mediaOnly && note.files.length == 0) return;
 
 			// Prepend a note
 			(this.$refs.timeline as any).prepend(note);
diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue
index 2615c0d0902d8397abca1e2547b7d6cd3934588f..b42df1f3477502be0fcf7964c09228ca4dd8ce22 100644
--- a/src/client/app/desktop/views/pages/deck/deck.note.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.note.vue
@@ -28,8 +28,8 @@
 						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 						<a class="rp" v-if="p.renote != null">RP:</a>
 					</div>
-					<div class="media" v-if="p.media.length > 0">
-						<mk-media-list :media-list="p.media"/>
+					<div class="files" v-if="p.files.length > 0">
+						<mk-media-list :media-list="p.files"/>
 					</div>
 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
 					<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
@@ -54,11 +54,11 @@
 	</article>
 </div>
 <div v-else class="srwrkujossgfuhrbnvqkybtzxpblgchi">
-	<div v-if="note.media.length > 0">
-		<mk-media-list :media-list="note.media"/>
+	<div v-if="note.files.length > 0">
+		<mk-media-list :media-list="note.files"/>
 	</div>
-	<div v-if="note.renote && note.renote.media.length > 0">
-		<mk-media-list :media-list="note.renote.media"/>
+	<div v-if="note.renote && note.renote.files.length > 0">
+		<mk-media-list :media-list="note.renote.files"/>
 	</div>
 </div>
 </template>
@@ -100,7 +100,7 @@ export default Vue.extend({
 		isRenote(): boolean {
 			return (this.note.renote &&
 				this.note.text == null &&
-				this.note.mediaIds.length == 0 &&
+				this.note.fileIds.length == 0 &&
 				this.note.poll == null);
 		},
 
@@ -371,7 +371,7 @@ root(isDark)
 					.mk-url-preview
 						margin-top 8px
 
-					> .media
+					> .files
 						> img
 							display block
 							max-width 100%
diff --git a/src/client/app/desktop/views/pages/deck/deck.notes.vue b/src/client/app/desktop/views/pages/deck/deck.notes.vue
index f7fca5de923b7bdeb2c317d5da4c8bf7ceefbf3b..2e7e30f12ab6f6543a24d79c3e553a814948e680 100644
--- a/src/client/app/desktop/views/pages/deck/deck.notes.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.notes.vue
@@ -127,7 +127,7 @@ export default Vue.extend({
 		prepend(note, silent = false) {
 			//#region 弾く
 			const isMyNote = note.userId == this.$store.state.i.id;
-			const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
+			const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
 
 			if (this.$store.state.settings.showMyRenotes === false) {
 				if (isMyNote && isPureRenote) {
diff --git a/src/client/app/desktop/views/pages/deck/deck.tl.vue b/src/client/app/desktop/views/pages/deck/deck.tl.vue
index a9e4d489c3333bfceefc5b8c2cd06edc55418b4e..120ceb7fc2d8f00c96480fc87f71ed4b4cc66083 100644
--- a/src/client/app/desktop/views/pages/deck/deck.tl.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.tl.vue
@@ -96,7 +96,7 @@ export default Vue.extend({
 			(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
 				(this as any).api(this.endpoint, {
 					limit: fetchLimit + 1,
-					mediaOnly: this.mediaOnly,
+					withFiles: this.mediaOnly,
 					includeMyRenotes: this.$store.state.settings.showMyRenotes,
 					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 					includeLocalRenotes: this.$store.state.settings.showLocalRenotes
@@ -117,7 +117,7 @@ export default Vue.extend({
 
 			const promise = (this as any).api(this.endpoint, {
 				limit: fetchLimit + 1,
-				mediaOnly: this.mediaOnly,
+				withFiles: this.mediaOnly,
 				untilId: (this.$refs.timeline as any).tail().id,
 				includeMyRenotes: this.$store.state.settings.showMyRenotes,
 				includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
@@ -138,7 +138,7 @@ export default Vue.extend({
 		},
 
 		onNote(note) {
-			if (this.mediaOnly && note.media.length == 0) return;
+			if (this.mediaOnly && note.files.length == 0) return;
 
 			// Prepend a note
 			(this.$refs.timeline as any).prepend(note);
diff --git a/src/client/app/desktop/views/pages/user/user.photos.vue b/src/client/app/desktop/views/pages/user/user.photos.vue
index 64c537f1edb994e015a802acd477c39ca7d4a1c7..c5cd9e24fe0315bb7c6a3721b1b7280212113f27 100644
--- a/src/client/app/desktop/views/pages/user/user.photos.vue
+++ b/src/client/app/desktop/views/pages/user/user.photos.vue
@@ -24,12 +24,12 @@ export default Vue.extend({
 	mounted() {
 		(this as any).api('users/notes', {
 			userId: this.user.id,
-			withMedia: true,
+			withFiles: true,
 			limit: 9
 		}).then(notes => {
 			notes.forEach(note => {
-				note.media.forEach(media => {
-					if (this.images.length < 9) this.images.push(media);
+				note.files.forEach(file => {
+					if (this.images.length < 9) this.images.push(file);
 				});
 			});
 			this.fetching = false;
diff --git a/src/client/app/desktop/views/pages/user/user.timeline.vue b/src/client/app/desktop/views/pages/user/user.timeline.vue
index 67987fcb94eb26fea396a6f0424be8949804eb9e..54221380a710f897394a6cb214559b47453d468a 100644
--- a/src/client/app/desktop/views/pages/user/user.timeline.vue
+++ b/src/client/app/desktop/views/pages/user/user.timeline.vue
@@ -66,7 +66,7 @@ export default Vue.extend({
 					limit: fetchLimit + 1,
 					untilDate: this.date ? this.date.getTime() : undefined,
 					includeReplies: this.mode == 'with-replies',
-					withMedia: this.mode == 'with-media'
+					withFiles: this.mode == 'with-media'
 				}).then(notes => {
 					if (notes.length == fetchLimit + 1) {
 						notes.pop();
@@ -86,7 +86,7 @@ export default Vue.extend({
 				userId: this.user.id,
 				limit: fetchLimit + 1,
 				includeReplies: this.mode == 'with-replies',
-				withMedia: this.mode == 'with-media',
+				withFiles: this.mode == 'with-media',
 				untilId: (this.$refs.timeline as any).tail().id
 			});
 
diff --git a/src/client/app/desktop/views/widgets/trends.vue b/src/client/app/desktop/views/widgets/trends.vue
index c33bf2f2f2f0352e404b71ddddbcfc6b8533f990..aeaab63ac4e71396ed6499dd0584710316a03efa 100644
--- a/src/client/app/desktop/views/widgets/trends.vue
+++ b/src/client/app/desktop/views/widgets/trends.vue
@@ -49,7 +49,7 @@ export default define({
 				offset: this.offset,
 				renote: false,
 				reply: false,
-				media: false,
+				file: false,
 				poll: false
 			}).then(notes => {
 				const note = notes ? notes[0] : null;
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 786e57bb224330655f6379b88d39d43f3e9f6aaa..10ff3fcc096db5585de307f3d147332a40c9e124 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -40,8 +40,8 @@
 				<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
 				<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 			</div>
-			<div class="media" v-if="p.media.length > 0">
-				<mk-media-list :media-list="p.media" :raw="true"/>
+			<div class="files" v-if="p.files.length > 0">
+				<mk-media-list :media-list="p.files" :raw="true"/>
 			</div>
 			<mk-poll v-if="p.poll" :note="p"/>
 			<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
@@ -113,7 +113,7 @@ export default Vue.extend({
 		isRenote(): boolean {
 			return (this.note.renote &&
 				this.note.text == null &&
-				this.note.mediaIds.length == 0 &&
+				this.note.fileIds.length == 0 &&
 				this.note.poll == null);
 		},
 
@@ -369,7 +369,7 @@ root(isDark)
 			> .mk-url-preview
 				margin-top 8px
 
-			> .media
+			> .files
 				> img
 					display block
 					max-width 100%
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 258433cb3f8f82ee86b37e853fd010e3aeceaab2..9bd4a83ecbdb77cf016c53d19e2bfc28ba0dfcd2 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -28,8 +28,8 @@
 						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
 						<a class="rp" v-if="p.renote != null">RP:</a>
 					</div>
-					<div class="media" v-if="p.media.length > 0">
-						<mk-media-list :media-list="p.media"/>
+					<div class="files" v-if="p.files.length > 0">
+						<mk-media-list :media-list="p.files"/>
 					</div>
 					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
 					<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
@@ -90,7 +90,7 @@ export default Vue.extend({
 		isRenote(): boolean {
 			return (this.note.renote &&
 				this.note.text == null &&
-				this.note.mediaIds.length == 0 &&
+				this.note.fileIds.length == 0 &&
 				this.note.poll == null);
 		},
 
@@ -414,7 +414,7 @@ root(isDark)
 					.mk-url-preview
 						margin-top 8px
 
-					> .media
+					> .files
 						> img
 							display block
 							max-width 100%
diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue
index 714e521c0f2704d77106d2bddaffcb17e803cf97..ce2670dc52967fadd87eed997061b98ca519621f 100644
--- a/src/client/app/mobile/views/components/notes.vue
+++ b/src/client/app/mobile/views/components/notes.vue
@@ -125,7 +125,7 @@ export default Vue.extend({
 		prepend(note, silent = false) {
 			//#region 弾く
 			const isMyNote = note.userId == this.$store.state.i.id;
-			const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
+			const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
 
 			if (this.$store.state.settings.showMyRenotes === false) {
 				if (isMyNote && isPureRenote) {
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index 8b1f7b08c8ec7c57e88e5a3b8ea30b7880fdb6c4..644e27cce88c020068ef8d9b98844339c299724f 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -200,12 +200,12 @@ export default Vue.extend({
 
 		attachMedia(driveFile) {
 			this.files.push(driveFile);
-			this.$emit('change-attached-media', this.files);
+			this.$emit('change-attached-files', this.files);
 		},
 
 		detachMedia(file) {
 			this.files = this.files.filter(x => x.id != file.id);
-			this.$emit('change-attached-media', this.files);
+			this.$emit('change-attached-files', this.files);
 		},
 
 		onChangeFile() {
@@ -269,7 +269,7 @@ export default Vue.extend({
 			this.text = '';
 			this.files = [];
 			this.poll = false;
-			this.$emit('change-attached-media');
+			this.$emit('change-attached-files');
 		},
 
 		post() {
@@ -277,7 +277,7 @@ export default Vue.extend({
 			const viaMobile = this.$store.state.settings.disableViaMobile !== true;
 			(this as any).api('notes/create', {
 				text: this.text == '' ? undefined : this.text,
-				mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
+				fileIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
 				replyId: this.reply ? this.reply.id : undefined,
 				renoteId: this.renote ? this.renote.id : undefined,
 				poll: this.poll ? (this.$refs.poll as any).get() : undefined,
diff --git a/src/client/app/mobile/views/components/sub-note-content.vue b/src/client/app/mobile/views/components/sub-note-content.vue
index a4ce49786eb38b4412d6b2622e931635ec26387c..4d0aa25f3470e1d8054c2578a4413f80712d5e20 100644
--- a/src/client/app/mobile/views/components/sub-note-content.vue
+++ b/src/client/app/mobile/views/components/sub-note-content.vue
@@ -7,9 +7,9 @@
 		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
 		<a class="rp" v-if="note.renoteId">RP: ...</a>
 	</div>
-	<details v-if="note.media.length > 0">
-		<summary>({{ '%i18n:@media-count%'.replace('{}', note.media.length) }})</summary>
-		<mk-media-list :media-list="note.media"/>
+	<details v-if="note.files.length > 0">
+		<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
+		<mk-media-list :media-list="note.files"/>
 	</details>
 	<details v-if="note.poll">
 		<summary>%i18n:@poll%</summary>
diff --git a/src/client/app/mobile/views/components/user-timeline.vue b/src/client/app/mobile/views/components/user-timeline.vue
index 6be675c0a718da03559e43f5c0175c1681788e4d..7cd23d66555bb2d9375bc61f75f4a6d04c59890d 100644
--- a/src/client/app/mobile/views/components/user-timeline.vue
+++ b/src/client/app/mobile/views/components/user-timeline.vue
@@ -41,7 +41,7 @@ export default Vue.extend({
 			(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
 				(this as any).api('users/notes', {
 					userId: this.user.id,
-					withMedia: this.withMedia,
+					withFiles: this.withMedia,
 					limit: fetchLimit + 1
 				}).then(notes => {
 					if (notes.length == fetchLimit + 1) {
@@ -62,7 +62,7 @@ export default Vue.extend({
 
 			const promise = (this as any).api('users/notes', {
 				userId: this.user.id,
-				withMedia: this.withMedia,
+				withFiles: this.withMedia,
 				limit: fetchLimit + 1,
 				untilId: (this.$refs.timeline as any).tail().id
 			});
diff --git a/src/client/app/mobile/views/pages/user/home.photos.vue b/src/client/app/mobile/views/pages/user/home.photos.vue
index 73ff1d5173f232eb93e612d8dbfa2408dfcd336f..e9025ec81613b430ad82ad86f544d748a70fe974 100644
--- a/src/client/app/mobile/views/pages/user/home.photos.vue
+++ b/src/client/app/mobile/views/pages/user/home.photos.vue
@@ -26,7 +26,7 @@ export default Vue.extend({
 	mounted() {
 		(this as any).api('users/notes', {
 			userId: this.user.id,
-			withMedia: true,
+			withFiles: true,
 			limit: 6
 		}).then(notes => {
 			notes.forEach(note => {
diff --git a/src/docs/api/entities/note.yaml b/src/docs/api/entities/note.yaml
index cae9a53f82cbfd4e4a87be9f3989f80045aa6d61..6654be2b021c465c7a1c4ef76c37752a9aee57a0 100644
--- a/src/docs/api/entities/note.yaml
+++ b/src/docs/api/entities/note.yaml
@@ -33,19 +33,19 @@ props:
       ja-JP: "投稿の本文"
       en-US: "The text of this note"
 
-  mediaIds:
+  fileIds:
     type: "id(DriveFile)[]"
     optional: true
     desc:
-      ja-JP: "添付されているメディアのID (なければレスポンスでは空配列)"
-      en-US: "The IDs of the attached media (empty array for response if no media is attached)"
+      ja-JP: "添付されているファイルのID (なければレスポンスでは空配列)"
+      en-US: "The IDs of the attached files (empty array for response if no files is attached)"
 
-  media:
+  files:
     type: "entity(DriveFile)[]"
     optional: true
     desc:
-      ja-JP: "添付されているメディア"
-      en-US: "The attached media"
+      ja-JP: "添付されているファイル"
+      en-US: "The attached files"
 
   userId:
     type: "id(User)"
diff --git a/src/misc/get-note-summary.ts b/src/misc/get-note-summary.ts
index ec7c74cf9f2541266f28f86a600f08cf1aa0468e..3c6f2dd3d6264de88437762cf64b241f80a7c925 100644
--- a/src/misc/get-note-summary.ts
+++ b/src/misc/get-note-summary.ts
@@ -16,9 +16,9 @@ const summarize = (note: any): string => {
 	// 本文
 	summary += note.text ? note.text : '';
 
-	// メディアが添付されているとき
-	if (note.media.length != 0) {
-		summary += ` (${note.media.length}つのメディア)`;
+	// ファイルが添付されているとき
+	if (note.files.length != 0) {
+		summary += ` (${note.files.length}つのファイル)`;
 	}
 
 	// 投票が添付されているとき
diff --git a/src/misc/is-quote.ts b/src/misc/is-quote.ts
index 420f03a489d5c5c53401087378ecff96f64c5dad..a99b8f64348541131eeca0f3b7d3138e94ee234a 100644
--- a/src/misc/is-quote.ts
+++ b/src/misc/is-quote.ts
@@ -1,5 +1,5 @@
 import { INote } from '../models/note';
 
 export default function(note: INote): boolean {
-	return note.renoteId != null && (note.text != null || note.poll != null || (note.mediaIds != null && note.mediaIds.length > 0));
+	return note.renoteId != null && (note.text != null || note.poll != null || (note.fileIds != null && note.fileIds.length > 0));
 }
diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts
index 698ef092a6ea4e2b876cdd6a823c389f10b52ed0..215b49b30548e2a65287573788496d4e444cd601 100644
--- a/src/models/drive-file.ts
+++ b/src/models/drive-file.ts
@@ -92,7 +92,7 @@ export async function deleteDriveFile(driveFile: string | mongo.ObjectID | IDriv
 
 	// このDriveFileを添付しているNoteをすべて削除
 	await Promise.all((
-		await Note.find({ mediaIds: d._id })
+		await Note.find({ fileIds: d._id })
 	).map(x => deleteNote(x)));
 
 	// このDriveFileを添付しているMessagingMessageをすべて削除
diff --git a/src/models/note.ts b/src/models/note.ts
index 9d2e23d9015a812fb60ba8fccc1791fd5b9c8b61..98d37caf2289e03dfef7783024c162d40206e9cc 100644
--- a/src/models/note.ts
+++ b/src/models/note.ts
@@ -6,7 +6,7 @@ import { IUser, pack as packUser } from './user';
 import { pack as packApp } from './app';
 import PollVote, { deletePollVote } from './poll-vote';
 import Reaction, { deleteNoteReaction } from './note-reaction';
-import { pack as packFile } from './drive-file';
+import { pack as packFile, IDriveFile } from './drive-file';
 import NoteWatching, { deleteNoteWatching } from './note-watching';
 import NoteReaction from './note-reaction';
 import Favorite, { deleteFavorite } from './favorite';
@@ -17,9 +17,20 @@ const Note = db.get<INote>('notes');
 Note.createIndex('uri', { sparse: true, unique: true });
 Note.createIndex('userId');
 Note.createIndex('tagsLower');
+Note.createIndex('_files.contentType');
 Note.createIndex({
 	createdAt: -1
 });
+
+// 後方互換性のため
+Note.update({}, {
+	$rename: {
+		mediaIds: 'fileIds'
+	}
+}, {
+	multi: true
+});
+
 export default Note;
 
 export function isValidText(text: string): boolean {
@@ -34,7 +45,7 @@ export type INote = {
 	_id: mongo.ObjectID;
 	createdAt: Date;
 	deletedAt: Date;
-	mediaIds: mongo.ObjectID[];
+	fileIds: mongo.ObjectID[];
 	replyId: mongo.ObjectID;
 	renoteId: mongo.ObjectID;
 	poll: {
@@ -92,6 +103,7 @@ export type INote = {
 		inbox?: string;
 	};
 	_replyIds?: mongo.ObjectID[];
+	_files?: IDriveFile[];
 };
 
 /**
@@ -271,11 +283,15 @@ export const pack = async (
 		_note.app = packApp(_note.appId);
 	}
 
-	// Populate media
-	_note.media = hide ? [] : Promise.all(_note.mediaIds.map((fileId: mongo.ObjectID) =>
+	// Populate files
+	_note.files = hide ? [] : Promise.all(_note.fileIds.map((fileId: mongo.ObjectID) =>
 		packFile(fileId)
 	));
 
+	// 後方互換性のため
+	_note.mediaIds = _note.fileIds;
+	_note.media = _note.files;
+
 	// When requested a detailed note data
 	if (opts.detail) {
 		//#region 重いので廃止
@@ -344,7 +360,7 @@ export const pack = async (
 	}
 
 	if (hide) {
-		_note.mediaIds = [];
+		_note.fileIds = [];
 		_note.text = null;
 		_note.poll = null;
 		_note.cw = null;
diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts
index 1dfeebfdf7d75360affee17689ecb296345ccc71..97188b44a622c6e9abcb077f3d4ba0787f7343a2 100644
--- a/src/remote/activitypub/models/note.ts
+++ b/src/remote/activitypub/models/note.ts
@@ -78,11 +78,11 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 	}
 	//#endergion
 
-	// 添付メディア
+	// 添付ファイル
 	// TODO: attachmentは必ずしもImageではない
 	// TODO: attachmentは必ずしも配列ではない
 	// Noteがsensitiveなら添付もsensitiveにする
-	const media = note.attachment
+	const files = note.attachment
 		.map(attach => attach.sensitive = note.sensitive)
 		? await Promise.all(note.attachment.map(x => resolveImage(actor, x)))
 		: [];
@@ -100,7 +100,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 
 	return await post(actor, {
 		createdAt: new Date(note.published),
-		media,
+		files: files,
 		reply,
 		renote: undefined,
 		cw: note.summary,
diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts
index 1d169d3088332180db1a898ef09b10d57f68c274..6b30324ae7d4cf4220cfe8153eb7ddd2ca1a7c55 100644
--- a/src/remote/activitypub/renderer/note.ts
+++ b/src/remote/activitypub/renderer/note.ts
@@ -8,8 +8,8 @@ import User from '../../../models/user';
 import toHtml from '../misc/get-note-html';
 
 export default async function renderNote(note: INote, dive = true): Promise<any> {
-	const promisedFiles: Promise<IDriveFile[]> = note.mediaIds
-		? DriveFile.find({ _id: { $in: note.mediaIds } })
+	const promisedFiles: Promise<IDriveFile[]> = note.fileIds
+		? DriveFile.find({ _id: { $in: note.fileIds } })
 		: Promise.resolve([]);
 
 	let inReplyTo;
diff --git a/src/server/activitypub/outbox.ts b/src/server/activitypub/outbox.ts
index 37df1908803e3fe5932b65b0f4b27c504ceb4cef..cc7e55b5df09f8c1fab45cfe76a0bcd77635cf20 100644
--- a/src/server/activitypub/outbox.ts
+++ b/src/server/activitypub/outbox.ts
@@ -58,7 +58,7 @@ export default async (ctx: Router.IRouterContext) => {
 				$or: [{
 					text: { $ne: null }
 				}, {
-					mediaIds: { $ne: [] }
+					fileIds: { $ne: [] }
 				}]
 			}]
 		} as any;
diff --git a/src/server/api/endpoints/notes.ts b/src/server/api/endpoints/notes.ts
index 029bc1a95e4c9805a7f65ee2a9f68f630271f4e0..4d15e9483fe36186e66309029b6367d8401321fc 100644
--- a/src/server/api/endpoints/notes.ts
+++ b/src/server/api/endpoints/notes.ts
@@ -20,9 +20,9 @@ export default (params: any) => new Promise(async (res, rej) => {
 	const [renote, renoteErr] = $.bool.optional.get(params.renote);
 	if (renoteErr) return rej('invalid renote param');
 
-	// Get 'media' parameter
-	const [media, mediaErr] = $.bool.optional.get(params.media);
-	if (mediaErr) return rej('invalid media param');
+	// Get 'files' parameter
+	const [files, filesErr] = $.bool.optional.get(params.files);
+	if (filesErr) return rej('invalid files param');
 
 	// Get 'poll' parameter
 	const [poll, pollErr] = $.bool.optional.get(params.poll);
@@ -79,8 +79,8 @@ export default (params: any) => new Promise(async (res, rej) => {
 		query.renoteId = renote ? { $exists: true, $ne: null } : null;
 	}
 
-	if (media != undefined) {
-		query.mediaIds = media ? { $exists: true, $ne: null } : [];
+	if (files != undefined) {
+		query.fileIds = files ? { $exists: true, $ne: null } : [];
 	}
 
 	if (poll != undefined) {
diff --git a/src/server/api/endpoints/notes/create.ts b/src/server/api/endpoints/notes/create.ts
index 04f5f7562e8d8be9186f4bff63ddd45da1e9cd39..47b53c943b6e673de19bb45b542b5615fe09de57 100644
--- a/src/server/api/endpoints/notes/create.ts
+++ b/src/server/api/endpoints/notes/create.ts
@@ -71,9 +71,15 @@ export const meta = {
 			ref: 'geo'
 		}),
 
+		fileIds: $.arr($.type(ID)).optional.unique().range(1, 4).note({
+			desc: {
+				'ja-JP': '添付するファイル'
+			}
+		}),
+
 		mediaIds: $.arr($.type(ID)).optional.unique().range(1, 4).note({
 			desc: {
-				'ja-JP': '添付するメディア'
+				'ja-JP': '添付するファイル (このパラメータは廃止予定です。代わりに fileIds を使ってください。)'
 			}
 		}),
 
@@ -124,15 +130,16 @@ export default (params: any, user: ILocalUser, app: IApp) => new Promise(async (
 	}
 
 	let files: IDriveFile[] = [];
-	if (ps.mediaIds !== undefined) {
+	const fileIds = ps.fileIds != null ? ps.fileIds : ps.mediaIds != null ? ps.mediaIds : null;
+	if (fileIds != null) {
 		// Fetch files
 		// forEach だと途中でエラーなどがあっても return できないので
 		// 敢えて for を使っています。
-		for (const mediaId of ps.mediaIds) {
+		for (const fileId of fileIds) {
 			// Fetch file
 			// SELECT _id
 			const entity = await DriveFile.findOne({
-				_id: mediaId,
+				_id: fileId,
 				'metadata.userId': user._id
 			});
 
@@ -155,7 +162,7 @@ export default (params: any, user: ILocalUser, app: IApp) => new Promise(async (
 
 		if (renote == null) {
 			return rej('renoteee is not found');
-		} else if (renote.renoteId && !renote.text && !renote.mediaIds) {
+		} else if (renote.renoteId && !renote.text && !renote.fileIds) {
 			return rej('cannot renote to renote');
 		}
 	}
@@ -176,7 +183,7 @@ export default (params: any, user: ILocalUser, app: IApp) => new Promise(async (
 		}
 
 		// 返信対象が引用でないRenoteだったらエラー
-		if (reply.renoteId && !reply.text && !reply.mediaIds) {
+		if (reply.renoteId && !reply.text && !reply.fileIds) {
 			return rej('cannot reply to renote');
 		}
 	}
@@ -191,13 +198,13 @@ export default (params: any, user: ILocalUser, app: IApp) => new Promise(async (
 
 	// テキストが無いかつ添付ファイルが無いかつRenoteも無いかつ投票も無かったらエラー
 	if ((ps.text === undefined || ps.text === null) && files === null && renote === null && ps.poll === undefined) {
-		return rej('text, mediaIds, renoteId or poll is required');
+		return rej('text, fileIds, renoteId or poll is required');
 	}
 
 	// 投稿を作成
 	const note = await create(user, {
 		createdAt: new Date(),
-		media: files,
+		files: files,
 		poll: ps.poll,
 		text: ps.text,
 		reply,
diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts
index 8f7233e308903972c517cee6a3fad08cf8550e35..554245a0f408584f27b6b10848fc423f3d0d9459 100644
--- a/src/server/api/endpoints/notes/global-timeline.ts
+++ b/src/server/api/endpoints/notes/global-timeline.ts
@@ -33,9 +33,9 @@ export default async (params: any, user: ILocalUser) => {
 		throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
 	}
 
-	// Get 'mediaOnly' parameter
-	const [mediaOnly, mediaOnlyErr] = $.bool.optional.get(params.mediaOnly);
-	if (mediaOnlyErr) throw 'invalid mediaOnly param';
+	// Get 'withFiles' parameter
+	const [withFiles, withFilesErr] = $.bool.optional.get(params.withFiles);
+	if (withFilesErr) throw 'invalid withFiles param';
 
 	// ミュートしているユーザーを取得
 	const mutedUserIds = user ? (await Mute.find({
@@ -68,8 +68,8 @@ export default async (params: any, user: ILocalUser) => {
 		};
 	}
 
-	if (mediaOnly) {
-		query.mediaIds = { $exists: true, $ne: [] };
+	if (withFiles) {
+		query.fileIds = { $exists: true, $ne: [] };
 	}
 
 	if (sinceId) {
diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts
index 2dbb1190c157ece9201fdf5ce66e693cad24b41c..106079268354eb1d4c84150ff3e3e02144769118 100644
--- a/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ b/src/server/api/endpoints/notes/hybrid-timeline.ts
@@ -66,7 +66,7 @@ export const meta = {
 			}
 		}),
 
-		mediaOnly: $.bool.optional.note({
+		withFiles: $.bool.optional.note({
 			desc: {
 				'ja-JP': 'true にすると、メディアが添付された投稿だけ取得します'
 			}
@@ -164,7 +164,7 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
@@ -180,7 +180,7 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
@@ -196,16 +196,16 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
 		});
 	}
 
-	if (ps.mediaOnly) {
+	if (ps.withFiles) {
 		query.$and.push({
-			mediaIds: { $exists: true, $ne: [] }
+			fileIds: { $exists: true, $ne: [] }
 		});
 	}
 
diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts
index bbcc6303ca792c89678101403ce55140fc1de6f7..018e636ab5eb5e5890e0fc49e1a341cde3c52ac3 100644
--- a/src/server/api/endpoints/notes/local-timeline.ts
+++ b/src/server/api/endpoints/notes/local-timeline.ts
@@ -33,9 +33,9 @@ export default async (params: any, user: ILocalUser) => {
 		throw 'only one of sinceId, untilId, sinceDate, untilDate can be specified';
 	}
 
-	// Get 'mediaOnly' parameter
-	const [mediaOnly, mediaOnlyErr] = $.bool.optional.get(params.mediaOnly);
-	if (mediaOnlyErr) throw 'invalid mediaOnly param';
+	// Get 'withFiles' parameter
+	const [withFiles, withFilesErr] = $.bool.optional.get(params.withFiles);
+	if (withFilesErr) throw 'invalid withFiles param';
 
 	// ミュートしているユーザーを取得
 	const mutedUserIds = user ? (await Mute.find({
@@ -69,8 +69,8 @@ export default async (params: any, user: ILocalUser) => {
 		};
 	}
 
-	if (mediaOnly) {
-		query.mediaIds = { $exists: true, $ne: [] };
+	if (withFiles) {
+		query.fileIds = { $exists: true, $ne: [] };
 	}
 
 	if (sinceId) {
diff --git a/src/server/api/endpoints/notes/search_by_tag.ts b/src/server/api/endpoints/notes/search_by_tag.ts
index e092275fe801a4ce6e0031856419a7be56a58198..317a0726d36f3318d117a5483f7d286de5788e62 100644
--- a/src/server/api/endpoints/notes/search_by_tag.ts
+++ b/src/server/api/endpoints/notes/search_by_tag.ts
@@ -247,7 +247,7 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
 	if (media != null) {
 		if (media) {
 			push({
-				mediaIds: {
+				fileIds: {
 					$exists: true,
 					$ne: null
 				}
@@ -255,11 +255,11 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
 		} else {
 			push({
 				$or: [{
-					mediaIds: {
+					fileIds: {
 						$exists: false
 					}
 				}, {
-					mediaIds: null
+					fileIds: null
 				}]
 			});
 		}
diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts
index 099bf2010b4a89dff1e8c0bc5766c9d423e79ca3..145f648c560eb93e6940b864601c1266f73333a4 100644
--- a/src/server/api/endpoints/notes/timeline.ts
+++ b/src/server/api/endpoints/notes/timeline.ts
@@ -67,7 +67,7 @@ export const meta = {
 			}
 		}),
 
-		mediaOnly: $.bool.optional.note({
+		withFiles: $.bool.optional.note({
 			desc: {
 				'ja-JP': 'true にすると、メディアが添付された投稿だけ取得します'
 			}
@@ -154,7 +154,7 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
@@ -170,7 +170,7 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
@@ -186,16 +186,16 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
 		});
 	}
 
-	if (ps.mediaOnly) {
+	if (ps.withFiles) {
 		query.$and.push({
-			mediaIds: { $exists: true, $ne: [] }
+			fileIds: { $exists: true, $ne: [] }
 		});
 	}
 
diff --git a/src/server/api/endpoints/notes/trend.ts b/src/server/api/endpoints/notes/trend.ts
index 7a0a098f28e7aab66fa52bca2efa55929f94f67e..9f55ed32433de54262a21e4645b794e062b6d10b 100644
--- a/src/server/api/endpoints/notes/trend.ts
+++ b/src/server/api/endpoints/notes/trend.ts
@@ -52,7 +52,7 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
 	}
 
 	if (media != undefined) {
-		query.mediaIds = media ? { $exists: true, $ne: null } : null;
+		query.fileIds = media ? { $exists: true, $ne: null } : null;
 	}
 
 	if (poll != undefined) {
diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts
index a7b43014edd379bad1bf0482321193d8854312e1..e00a7de3717cea1baaea8b5651f5d5c91a376968 100644
--- a/src/server/api/endpoints/notes/user-list-timeline.ts
+++ b/src/server/api/endpoints/notes/user-list-timeline.ts
@@ -73,7 +73,7 @@ export const meta = {
 			}
 		}),
 
-		mediaOnly: $.bool.optional.note({
+		withFiles: $.bool.optional.note({
 			desc: {
 				'ja-JP': 'true にすると、メディアが添付された投稿だけ取得します'
 			}
@@ -160,7 +160,7 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
@@ -176,7 +176,7 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
@@ -192,16 +192,16 @@ export default async (params: any, user: ILocalUser) => {
 			}, {
 				text: { $ne: null }
 			}, {
-				mediaIds: { $ne: [] }
+				fileIds: { $ne: [] }
 			}, {
 				poll: { $ne: null }
 			}]
 		});
 	}
 
-	if (ps.mediaOnly) {
+	if (ps.withFiles) {
 		query.$and.push({
-			mediaIds: { $exists: true, $ne: [] }
+			fileIds: { $exists: true, $ne: [] }
 		});
 	}
 
diff --git a/src/server/api/endpoints/users/notes.ts b/src/server/api/endpoints/users/notes.ts
index ff7855bde0b79a5392ebbac334ad077eb4392bd6..d894e52dba47380a17785659302177ad821c2a51 100644
--- a/src/server/api/endpoints/users/notes.ts
+++ b/src/server/api/endpoints/users/notes.ts
@@ -27,9 +27,9 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
 	const [includeReplies = true, includeRepliesErr] = $.bool.optional.get(params.includeReplies);
 	if (includeRepliesErr) return rej('invalid includeReplies param');
 
-	// Get 'withMedia' parameter
-	const [withMedia = false, withMediaErr] = $.bool.optional.get(params.withMedia);
-	if (withMediaErr) return rej('invalid withMedia param');
+	// Get 'withFiles' parameter
+	const [withFiles = false, withFilesErr] = $.bool.optional.get(params.withFiles);
+	if (withFilesErr) return rej('invalid withFiles param');
 
 	// Get 'limit' parameter
 	const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit);
@@ -104,8 +104,8 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
 		query.replyId = null;
 	}
 
-	if (withMedia) {
-		query.mediaIds = {
+	if (withFiles) {
+		query.fileIds = {
 			$exists: true,
 			$ne: []
 		};
diff --git a/src/services/note/create.ts b/src/services/note/create.ts
index 63e355782819424c24df49c2cf002500923de6c3..11e3755863123862aedc63ef83823b8989b5412d 100644
--- a/src/services/note/create.ts
+++ b/src/services/note/create.ts
@@ -84,7 +84,7 @@ type Option = {
 	text?: string;
 	reply?: INote;
 	renote?: INote;
-	media?: IDriveFile[];
+	files?: IDriveFile[];
 	geo?: any;
 	poll?: any;
 	viaMobile?: boolean;
@@ -135,7 +135,7 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
 
 	const mentionedUsers = await extractMentionedUsers(tokens);
 
-	const note = await insertNote(user, data, tokens, tags, mentionedUsers);
+	const note = await insertNote(user, data, tags, mentionedUsers);
 
 	res(note);
 
@@ -309,10 +309,10 @@ async function publish(user: IUser, note: INote, noteObj: any, reply: INote, ren
 	publishToUserLists(note, noteObj);
 }
 
-async function insertNote(user: IUser, data: Option, tokens: ReturnType<typeof parse>, tags: string[], mentionedUsers: IUser[]) {
+async function insertNote(user: IUser, data: Option, tags: string[], mentionedUsers: IUser[]) {
 	const insert: any = {
 		createdAt: data.createdAt,
-		mediaIds: data.media ? data.media.map(file => file._id) : [],
+		fileIds: data.files ? data.files.map(file => file._id) : [],
 		replyId: data.reply ? data.reply._id : null,
 		renoteId: data.renote ? data.renote._id : null,
 		text: data.text,
@@ -347,7 +347,8 @@ async function insertNote(user: IUser, data: Option, tokens: ReturnType<typeof p
 		_user: {
 			host: user.host,
 			inbox: isRemoteUser(user) ? user.inbox : undefined
-		}
+		},
+		_files: data.files ? data.files : []
 	};
 
 	if (data.uri != null) insert.uri = data.uri;
diff --git a/src/services/note/delete.ts b/src/services/note/delete.ts
index dea306feec96732d5b832b7805332f20c44b421b..32e736b7a5ebf1cceb7edb252435148712bff92e 100644
--- a/src/services/note/delete.ts
+++ b/src/services/note/delete.ts
@@ -23,7 +23,7 @@ export default async function(user: IUser, note: INote) {
 			deletedAt: new Date(),
 			text: null,
 			tags: [],
-			mediaIds: [],
+			fileIds: [],
 			poll: null,
 			geo: null
 		}