From e6eb1b2ae1c38b335ff4755d35a33a0ca4450454 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 19 May 2018 07:33:34 +0900
Subject: [PATCH] Clean up

---
 locales/ja.yml                                |  13 -
 src/client/app/ch/script.ts                   |  15 -
 src/client/app/ch/style.styl                  |  10 -
 src/client/app/ch/tags/channel.tag            | 409 ------------------
 src/client/app/ch/tags/header.tag             |  20 -
 src/client/app/ch/tags/index.tag              |  37 --
 src/client/app/ch/tags/index.ts               |   3 -
 .../app/common/scripts/streaming/channel.ts   |  13 -
 .../app/common/views/widgets/access-log.vue   |  91 ----
 src/client/app/common/views/widgets/index.ts  |   2 -
 .../app/desktop/views/components/home.vue     |   2 -
 .../app/desktop/views/components/mentions.vue | 125 ------
 .../desktop/views/components/notes.note.vue   |   6 -
 .../views/widgets/channel.channel.form.vue    |  67 ---
 .../views/widgets/channel.channel.note.vue    |  65 ---
 .../desktop/views/widgets/channel.channel.vue | 106 -----
 .../app/desktop/views/widgets/channel.vue     | 108 -----
 src/client/app/desktop/views/widgets/index.ts |   2 -
 .../app/mobile/views/components/note.vue      |   4 -
 src/client/app/mobile/views/pages/widgets.vue |   1 -
 src/models/channel-watching.ts                |  13 -
 src/models/channel.ts                         |  75 ----
 src/models/note.ts                            |   7 -
 src/publishers/stream.ts                      |   5 -
 src/renderers/get-note-summary.ts             |   3 -
 src/server/api/endpoints.ts                   |  28 +-
 src/server/api/endpoints/channels.ts          |  58 ---
 src/server/api/endpoints/channels/create.ts   |  35 --
 src/server/api/endpoints/channels/notes.ts    |  74 ----
 src/server/api/endpoints/channels/show.ts     |  26 --
 src/server/api/endpoints/channels/unwatch.ts  |  56 ---
 src/server/api/endpoints/channels/watch.ts    |  54 ---
 src/server/api/endpoints/notes/create.ts      |  45 --
 src/server/api/endpoints/notes/timeline.ts    |  33 +-
 src/server/api/stream/channel.ts              |  14 -
 src/server/api/streaming.ts                   |   6 -
 36 files changed, 5 insertions(+), 1626 deletions(-)
 delete mode 100644 src/client/app/ch/script.ts
 delete mode 100644 src/client/app/ch/style.styl
 delete mode 100644 src/client/app/ch/tags/channel.tag
 delete mode 100644 src/client/app/ch/tags/header.tag
 delete mode 100644 src/client/app/ch/tags/index.tag
 delete mode 100644 src/client/app/ch/tags/index.ts
 delete mode 100644 src/client/app/common/scripts/streaming/channel.ts
 delete mode 100644 src/client/app/common/views/widgets/access-log.vue
 delete mode 100644 src/client/app/desktop/views/components/mentions.vue
 delete mode 100644 src/client/app/desktop/views/widgets/channel.channel.form.vue
 delete mode 100644 src/client/app/desktop/views/widgets/channel.channel.note.vue
 delete mode 100644 src/client/app/desktop/views/widgets/channel.channel.vue
 delete mode 100644 src/client/app/desktop/views/widgets/channel.vue
 delete mode 100644 src/models/channel-watching.ts
 delete mode 100644 src/models/channel.ts
 delete mode 100644 src/server/api/endpoints/channels.ts
 delete mode 100644 src/server/api/endpoints/channels/create.ts
 delete mode 100644 src/server/api/endpoints/channels/notes.ts
 delete mode 100644 src/server/api/endpoints/channels/show.ts
 delete mode 100644 src/server/api/endpoints/channels/unwatch.ts
 delete mode 100644 src/server/api/endpoints/channels/watch.ts
 delete mode 100644 src/server/api/stream/channel.ts

diff --git a/locales/ja.yml b/locales/ja.yml
index 5040c135d6..4563e9485b 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -324,8 +324,6 @@ desktop/views/components/home.vue:
   polls: "投票"
   post-form: "投稿フォーム"
   messaging: "メッセージ"
-  channel: "チャンネル"
-  access-log: "アクセスログ"
   server: "サーバー情報"
   donation: "寄付のお願い"
   nav: "ナビゲーション"
@@ -336,12 +334,6 @@ desktop/views/input-dialog.vue:
   cancel: "キャンセル"
   ok: "決定"
 
-desktop/views/components/mentions.vue:
-  all: "すべて"
-  followed: "フォロー中"
-  empty: "あなた宛ての投稿はありません。"
-  empty-followed: "あなたがフォローしているユーザーからの言及はありません。"
-
 desktop/views/components/messaging-room-window.vue:
   title: "メッセージ:"
 
@@ -660,11 +652,6 @@ desktop/views/widgets/users.vue:
   refresh: "他を見る"
   no-one: "いません!"
 
-desktop/views/widgets/channel.vue:
-  title: "チャンネル"
-  settings: "ウィジェットの設定"
-  get-started: "右上の歯車をクリックして受信するチャンネルを指定してください"
-
 mobile/views/components/drive.vue:
   drive: "ドライブ"
   used: "使用中"
diff --git a/src/client/app/ch/script.ts b/src/client/app/ch/script.ts
deleted file mode 100644
index 4c6b6dfd1b..0000000000
--- a/src/client/app/ch/script.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Channels
- */
-
-// Style
-import './style.styl';
-
-require('./tags');
-import init from '../init';
-
-/**
- * init
- */
-init(() => {
-});
diff --git a/src/client/app/ch/style.styl b/src/client/app/ch/style.styl
deleted file mode 100644
index 21ca648cbe..0000000000
--- a/src/client/app/ch/style.styl
+++ /dev/null
@@ -1,10 +0,0 @@
-@import "../app"
-
-html
-	padding 8px
-	background #efefef
-
-#wait
-	top auto
-	bottom 15px
-	left 15px
diff --git a/src/client/app/ch/tags/channel.tag b/src/client/app/ch/tags/channel.tag
deleted file mode 100644
index 74b1a9ba19..0000000000
--- a/src/client/app/ch/tags/channel.tag
+++ /dev/null
@@ -1,409 +0,0 @@
-<mk-channel>
-	<mk-header/>
-	<hr>
-	<main v-if="!fetching">
-		<h1>{ channel.title }</h1>
-
-		<div v-if="$root.$data.os.isSignedIn">
-			<p v-if="channel.isWatching">このチャンネルをウォッチしています <a @click="unwatch">ウォッチ解除</a></p>
-			<p v-if="!channel.isWatching"><a @click="watch">このチャンネルをウォッチする</a></p>
-		</div>
-
-		<div class="share">
-			<mk-twitter-button/>
-			<mk-line-button/>
-		</div>
-
-		<div class="body">
-			<p v-if="notesFetching">読み込み中<mk-ellipsis/></p>
-			<div v-if="!notesFetching">
-				<p v-if="notes == null || notes.length == 0">まだ投稿がありません</p>
-				<template v-if="notes != null">
-					<mk-channel-note each={ note in notes.slice().reverse() } note={ note } form={ parent.refs.form }/>
-				</template>
-			</div>
-		</div>
-		<hr>
-		<mk-channel-form v-if="$root.$data.os.isSignedIn" channel={ channel } ref="form"/>
-		<div v-if="!$root.$data.os.isSignedIn">
-			<p>参加するには<a href={ _URL_ }>ログインまたは新規登録</a>してください</p>
-		</div>
-		<hr>
-		<footer>
-			<small><a href={ _URL_ }>Misskey</a> ver { _VERSION_ } (葵 aoi)</small>
-		</footer>
-	</main>
-	<style lang="stylus" scoped>
-		:scope
-			display block
-
-			> main
-				> h1
-					font-size 1.5em
-					color #f00
-
-				> .share
-					> *
-						margin-right 4px
-
-				> .body
-					margin 8px 0 0 0
-
-				> mk-channel-form
-					max-width 500px
-
-	</style>
-	<script lang="typescript">
-		import Progress from '../../common/scripts/loading';
-		import ChannelStream from '../../common/scripts/streaming/channel-stream';
-
-		this.mixin('i');
-		this.mixin('api');
-
-		this.id = this.opts.id;
-		this.fetching = true;
-		this.notesFetching = true;
-		this.channel = null;
-		this.notes = null;
-		this.connection = new ChannelStream(this.id);
-		this.unreadCount = 0;
-
-		this.on('mount', () => {
-			document.documentElement.style.background = '#efefef';
-
-			Progress.start();
-
-			let fetched = false;
-
-			// チャンネル概要読み込み
-			this.$root.$data.os.api('channels/show', {
-				channelId: this.id
-			}).then(channel => {
-				if (fetched) {
-					Progress.done();
-				} else {
-					Progress.set(0.5);
-					fetched = true;
-				}
-
-				this.update({
-					fetching: false,
-					channel: channel
-				});
-
-				document.title = channel.title + ' | Misskey'
-			});
-
-			// 投稿読み込み
-			this.$root.$data.os.api('channels/notes', {
-				channelId: this.id
-			}).then(notes => {
-				if (fetched) {
-					Progress.done();
-				} else {
-					Progress.set(0.5);
-					fetched = true;
-				}
-
-				this.update({
-					notesFetching: false,
-					notes: notes
-				});
-			});
-
-			this.connection.on('note', this.onNote);
-			document.addEventListener('visibilitychange', this.onVisibilitychange, false);
-		});
-
-		this.on('unmount', () => {
-			this.connection.off('note', this.onNote);
-			this.connection.close();
-			document.removeEventListener('visibilitychange', this.onVisibilitychange);
-		});
-
-		this.onNote = note => {
-			this.notes.unshift(note);
-			this.update();
-
-			if (document.hidden && this.$root.$data.os.isSignedIn && note.userId !== this.$root.$data.os.i.id) {
-				this.unreadCount++;
-				document.title = `(${this.unreadCount}) ${this.channel.title} | Misskey`;
-			}
-		};
-
-		this.onVisibilitychange = () => {
-			if (!document.hidden) {
-				this.unreadCount = 0;
-				document.title = this.channel.title + ' | Misskey'
-			}
-		};
-
-		this.watch = () => {
-			this.$root.$data.os.api('channels/watch', {
-				channelId: this.id
-			}).then(() => {
-				this.channel.isWatching = true;
-				this.update();
-			}, e => {
-				alert('error');
-			});
-		};
-
-		this.unwatch = () => {
-			this.$root.$data.os.api('channels/unwatch', {
-				channelId: this.id
-			}).then(() => {
-				this.channel.isWatching = false;
-				this.update();
-			}, e => {
-				alert('error');
-			});
-		};
-	</script>
-</mk-channel>
-
-<mk-channel-note>
-	<header>
-		<a class="index" @click="reply">{ note.index }:</a>
-		<a class="name" href={ _URL_ + '/@' + acct }><b>{ getUserName(note.user) }</b></a>
-		<mk-time time={ note.createdAt }/>
-		<mk-time time={ note.createdAt } mode="detail"/>
-		<span>ID:<i>{ acct }</i></span>
-	</header>
-	<div>
-		<a v-if="note.reply">&gt;&gt;{ note.reply.index }</a>
-		{ note.text }
-		<div class="media" v-if="note.media">
-			<template each={ file in note.media }>
-				<a href={ file.url } target="_blank">
-					<img src={ file.url + '?thumbnail&size=512' } alt={ file.name } title={ file.name }/>
-				</a>
-			</template>
-		</div>
-	</div>
-	<style lang="stylus" scoped>
-		:scope
-			display block
-			margin 0
-			padding 0
-
-			> header
-				position -webkit-sticky
-				position sticky
-				z-index 1
-				top 0
-				background rgba(239, 239, 239, 0.9)
-
-				> .index
-					margin-right 0.25em
-					color #000
-
-				> .name
-					margin-right 0.5em
-					color #008000
-
-				> mk-time
-					margin-right 0.5em
-
-					&:first-of-type
-						display none
-
-				@media (max-width 600px)
-					> mk-time
-						&:first-of-type
-							display initial
-
-						&:last-of-type
-							display none
-
-			> div
-				padding 0 0 1em 2em
-
-				> .media
-					> a
-						display inline-block
-
-						> img
-							max-width 100%
-							vertical-align bottom
-
-	</style>
-	<script lang="typescript">
-		import getAcct from '../../../../acct/render';
-		import getUserName from '../../../../renderers/get-user-name';
-
-		this.note = this.opts.note;
-		this.form = this.opts.form;
-		this.acct = getAcct(this.note.user);
-		this.name = getUserName(this.note.user);
-
-		this.reply = () => {
-			this.form.update({
-				reply: this.note
-			});
-		};
-	</script>
-</mk-channel-note>
-
-<mk-channel-form>
-	<p v-if="reply"><b>&gt;&gt;{ reply.index }</b> ({ getUserName(reply.user) }): <a @click="clearReply">[x]</a></p>
-	<textarea ref="text" disabled={ wait } oninput={ update } onkeydown={ onkeydown } onpaste={ onpaste } placeholder="%i18n:ch.tags.mk-channel-form.textarea%"></textarea>
-	<div class="actions">
-		<button @click="selectFile">%fa:upload%%i18n:ch.tags.mk-channel-form.upload%</button>
-		<button @click="drive">%fa:cloud%%i18n:ch.tags.mk-channel-form.drive%</button>
-		<button :class="{ wait: wait }" ref="submit" disabled={ wait || (refs.text.value.length == 0) } @click="note">
-			<template v-if="!wait">%fa:paper-plane%</template>{ wait ? '%i18n:!ch.tags.mk-channel-form.posting%' : '%i18n:!ch.tags.mk-channel-form.note%' }<mk-ellipsis v-if="wait"/>
-		</button>
-	</div>
-	<mk-uploader ref="uploader"/>
-	<ol v-if="files">
-		<li each={ files }>{ name }</li>
-	</ol>
-	<input ref="file" type="file" accept="image/*" multiple="multiple" onchange={ changeFile }/>
-	<style lang="stylus" scoped>
-		:scope
-			display block
-
-			> textarea
-				width 100%
-				max-width 100%
-				min-width 100%
-				min-height 5em
-
-			> .actions
-				display flex
-
-				> button
-					> [data-fa]
-						margin-right 0.25em
-
-					&:last-child
-						margin-left auto
-
-					&.wait
-						cursor wait
-
-			> input[type='file']
-				display none
-
-	</style>
-	<script lang="typescript">
-		import getUserName from '../../../../renderers/get-user-name';
-
-		this.mixin('api');
-
-		this.channel = this.opts.channel;
-		this.files = null;
-
-		this.on('mount', () => {
-			this.$refs.uploader.on('uploaded', file => {
-				this.update({
-					files: [file]
-				});
-			});
-		});
-
-		this.upload = file => {
-			this.$refs.uploader.upload(file);
-		};
-
-		this.clearReply = () => {
-			this.update({
-				reply: null
-			});
-		};
-
-		this.clear = () => {
-			this.clearReply();
-			this.update({
-				files: null
-			});
-			this.$refs.text.value = '';
-		};
-
-		this.note = () => {
-			this.update({
-				wait: true
-			});
-
-			const files = this.files && this.files.length > 0
-				? this.files.map(f => f.id)
-				: undefined;
-
-			this.$root.$data.os.api('notes/create', {
-				text: this.$refs.text.value == '' ? undefined : this.$refs.text.value,
-				mediaIds: files,
-				replyId: this.reply ? this.reply.id : undefined,
-				channelId: this.channel.id
-			}).then(data => {
-				this.clear();
-			}).catch(err => {
-				alert('失敗した');
-			}).then(() => {
-				this.update({
-					wait: false
-				});
-			});
-		};
-
-		this.changeFile = () => {
-			Array.from(this.$refs.file.files).forEach(this.upload);
-		};
-
-		this.selectFile = () => {
-			this.$refs.file.click();
-		};
-
-		this.drive = () => {
-			window['cb'] = files => {
-				this.update({
-					files: files
-				});
-			};
-
-			window.open(_URL_ + '/selectdrive?multiple=true',
-				'drive_window',
-				'height=500,width=800');
-		};
-
-		this.onkeydown = e => {
-			if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey)) this.post();
-		};
-
-		this.onpaste = e => {
-			Array.from(e.clipboardData.items).forEach(item => {
-				if (item.kind == 'file') {
-					this.upload(item.getAsFile());
-				}
-			});
-		};
-
-		this.getUserName = getUserName;
-	</script>
-</mk-channel-form>
-
-<mk-twitter-button>
-	<a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-show-count="false">Tweet</a>
-	<script lang="typescript">
-		this.on('mount', () => {
-			const head = document.getElementsByTagName('head')[0];
-			const script = document.createElement('script');
-			script.setAttribute('src', 'https://platform.twitter.com/widgets.js');
-			script.setAttribute('async', 'async');
-			head.appendChild(script);
-		});
-	</script>
-</mk-twitter-button>
-
-<mk-line-button>
-	<div class="line-it-button" data-lang="ja" data-type="share-a" data-url={ _CH_URL_ } style="display: none;"></div>
-	<script lang="typescript">
-		this.on('mount', () => {
-			const head = document.getElementsByTagName('head')[0];
-			const script = document.createElement('script');
-			script.setAttribute('src', 'https://d.line-scdn.net/r/web/social-plugin/js/thirdparty/loader.min.js');
-			script.setAttribute('async', 'async');
-			head.appendChild(script);
-		});
-	</script>
-</mk-line-button>
diff --git a/src/client/app/ch/tags/header.tag b/src/client/app/ch/tags/header.tag
deleted file mode 100644
index 901123d63b..0000000000
--- a/src/client/app/ch/tags/header.tag
+++ /dev/null
@@ -1,20 +0,0 @@
-<mk-header>
-	<div>
-		<a href={ _CH_URL_ }>Index</a> | <a href={ _URL_ }>Misskey</a>
-	</div>
-	<div>
-		<a v-if="!$root.$data.os.isSignedIn" href={ _URL_ }>ログイン(新規登録)</a>
-		<a v-if="$root.$data.os.isSignedIn" href={ _URL_ + '/@' + I.username }>{ I.username }</a>
-	</div>
-	<style lang="stylus" scoped>
-		:scope
-			display flex
-
-			> div:last-child
-				margin-left auto
-
-	</style>
-	<script lang="typescript">
-		this.mixin('i');
-	</script>
-</mk-header>
diff --git a/src/client/app/ch/tags/index.tag b/src/client/app/ch/tags/index.tag
deleted file mode 100644
index 529b83b2c7..0000000000
--- a/src/client/app/ch/tags/index.tag
+++ /dev/null
@@ -1,37 +0,0 @@
-<mk-index>
-	<mk-header/>
-	<hr>
-	<button @click="n">%i18n:ch.tags.mk-index.new%</button>
-	<hr>
-	<ul v-if="channels">
-		<li each={ channels }><a href={ '/' + this.id }>{ this.title }</a></li>
-	</ul>
-	<style lang="stylus" scoped>
-		:scope
-			display block
-
-	</style>
-	<script lang="typescript">
-		this.mixin('api');
-
-		this.on('mount', () => {
-			this.$root.$data.os.api('channels', {
-				limit: 100
-			}).then(channels => {
-				this.update({
-					channels: channels
-				});
-			});
-		});
-
-		this.n = () => {
-			const title = window.prompt('%i18n:!ch.tags.mk-index.channel-title%');
-
-			this.$root.$data.os.api('channels/create', {
-				title: title
-			}).then(channel => {
-				location.href = '/' + channel.id;
-			});
-		};
-	</script>
-</mk-index>
diff --git a/src/client/app/ch/tags/index.ts b/src/client/app/ch/tags/index.ts
deleted file mode 100644
index 12ffdaeb84..0000000000
--- a/src/client/app/ch/tags/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-require('./index.tag');
-require('./channel.tag');
-require('./header.tag');
diff --git a/src/client/app/common/scripts/streaming/channel.ts b/src/client/app/common/scripts/streaming/channel.ts
deleted file mode 100644
index be68ec0997..0000000000
--- a/src/client/app/common/scripts/streaming/channel.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import Stream from './stream';
-import MiOS from '../../../mios';
-
-/**
- * Channel stream connection
- */
-export default class Connection extends Stream {
-	constructor(os: MiOS, channelId) {
-		super(os, 'channel', {
-			channel: channelId
-		});
-	}
-}
diff --git a/src/client/app/common/views/widgets/access-log.vue b/src/client/app/common/views/widgets/access-log.vue
deleted file mode 100644
index 8652e35645..0000000000
--- a/src/client/app/common/views/widgets/access-log.vue
+++ /dev/null
@@ -1,91 +0,0 @@
-<template>
-<div class="mkw-access-log">
-	<mk-widget-container :show-header="props.design == 0">
-		<template slot="header">%fa:server%%i18n:@title%</template>
-
-		<div :class="$style.logs" ref="log">
-			<p v-for="req in requests">
-				<span :class="$style.ip" :style="`color:${ req.fg }; background:${ req.bg }`">{{ req.ip }}</span>
-				<b>{{ req.method }}</b>
-				<span>{{ req.path }}</span>
-			</p>
-		</div>
-	</mk-widget-container>
-</div>
-</template>
-
-<script lang="ts">
-import define from '../../../common/define-widget';
-import * as seedrandom from 'seedrandom';
-
-export default define({
-	name: 'broadcast',
-	props: () => ({
-		design: 0
-	})
-}).extend({
-	data() {
-		return {
-			requests: [],
-			connection: null,
-			connectionId: null
-		};
-	},
-	mounted() {
-		this.connection = (this as any).os.streams.requestsStream.getConnection();
-		this.connectionId = (this as any).os.streams.requestsStream.use();
-		this.connection.on('request', this.onRequest);
-	},
-	beforeDestroy() {
-		this.connection.off('request', this.onRequest);
-		(this as any).os.streams.requestsStream.dispose(this.connectionId);
-	},
-	methods: {
-		onRequest(request) {
-			const random = seedrandom(request.ip);
-			const r = Math.floor(random() * 255);
-			const g = Math.floor(random() * 255);
-			const b = Math.floor(random() * 255);
-			const luma = (0.2126 * r) + (0.7152 * g) + (0.0722 * b); // SMPTE C, Rec. 709 weightings
-			request.bg = `rgb(${r}, ${g}, ${b})`;
-			request.fg = luma >= 165 ? '#000' : '#fff';
-
-			this.requests.push(request);
-			if (this.requests.length > 30) this.requests.shift();
-
-			(this.$refs.log as any).scrollTop = (this.$refs.log as any).scrollHeight;
-		},
-		func() {
-			if (this.props.design == 1) {
-				this.props.design = 0;
-			} else {
-				this.props.design++;
-			}
-			this.save();
-		}
-	}
-});
-</script>
-
-<style lang="stylus" module>
-.logs
-	max-height 250px
-	overflow auto
-
-	> p
-		margin 0
-		padding 8px
-		font-size 0.8em
-		color #555
-
-		&:nth-child(odd)
-			background rgba(#000, 0.025)
-
-		> b
-			margin-right 4px
-
-.ip
-	margin-right 4px
-	padding 0 4px
-
-</style>
diff --git a/src/client/app/common/views/widgets/index.ts b/src/client/app/common/views/widgets/index.ts
index e41030e85a..9107d90ce7 100644
--- a/src/client/app/common/views/widgets/index.ts
+++ b/src/client/app/common/views/widgets/index.ts
@@ -1,6 +1,5 @@
 import Vue from 'vue';
 
-import wAccessLog from './access-log.vue';
 import wVersion from './version.vue';
 import wRss from './rss.vue';
 import wServer from './server.vue';
@@ -22,4 +21,3 @@ Vue.component('mkw-broadcast', wBroadcast);
 Vue.component('mkw-server', wServer);
 Vue.component('mkw-rss', wRss);
 Vue.component('mkw-version', wVersion);
-Vue.component('mkw-access-log', wAccessLog);
diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue
index a3d7927cfc..87dae5a806 100644
--- a/src/client/app/desktop/views/components/home.vue
+++ b/src/client/app/desktop/views/components/home.vue
@@ -21,8 +21,6 @@
 					<option value="polls">%i18n:@polls%</option>
 					<option value="post-form">%i18n:@post-form%</option>
 					<option value="messaging">%i18n:@messaging%</option>
-					<option value="channel">%i18n:@channel%</option>
-					<option value="access-log">%i18n:@access-log%</option>
 					<option value="server">%i18n:@server%</option>
 					<option value="donation">%i18n:@donation%</option>
 					<option value="nav">%i18n:@nav%</option>
diff --git a/src/client/app/desktop/views/components/mentions.vue b/src/client/app/desktop/views/components/mentions.vue
deleted file mode 100644
index 23fb7cccd4..0000000000
--- a/src/client/app/desktop/views/components/mentions.vue
+++ /dev/null
@@ -1,125 +0,0 @@
-<template>
-<div class="mk-mentions">
-	<header>
-		<span :data-active="mode == 'all'" @click="mode = 'all'">%i18n:@all%</span>
-		<span :data-active="mode == 'following'" @click="mode = 'following'">%i18n:@followed%</span>
-	</header>
-	<div class="fetching" v-if="fetching">
-		<mk-ellipsis-icon/>
-	</div>
-	<p class="empty" v-if="notes.length == 0 && !fetching">
-		%fa:R comments%
-		<span v-if="mode == 'all'">%i18n:@empty%</span>
-		<span v-if="mode == 'following'">%i18n:@empty-followed%</span>
-	</p>
-	<mk-notes :notes="notes" ref="timeline"/>
-</div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-export default Vue.extend({
-	data() {
-		return {
-			fetching: true,
-			moreFetching: false,
-			mode: 'all',
-			notes: []
-		};
-	},
-	watch: {
-		mode() {
-			this.fetch();
-		}
-	},
-	mounted() {
-		document.addEventListener('keydown', this.onDocumentKeydown);
-		window.addEventListener('scroll', this.onScroll);
-
-		this.fetch(() => this.$emit('loaded'));
-	},
-	beforeDestroy() {
-		document.removeEventListener('keydown', this.onDocumentKeydown);
-		window.removeEventListener('scroll', this.onScroll);
-	},
-	methods: {
-		onDocumentKeydown(e) {
-			if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA') {
-				if (e.which == 84) { // t
-					(this.$refs.timeline as any).focus();
-				}
-			}
-		},
-		onScroll() {
-			const current = window.scrollY + window.innerHeight;
-			if (current > document.body.offsetHeight - 8) this.more();
-		},
-		fetch(cb?) {
-			this.fetching = true;
-			this.notes =  [];
-			(this as any).api('notes/mentions', {
-				following: this.mode == 'following'
-			}).then(notes => {
-				this.notes = notes;
-				this.fetching = false;
-				if (cb) cb();
-			});
-		},
-		more() {
-			if (this.moreFetching || this.fetching || this.notes.length == 0) return;
-			this.moreFetching = true;
-			(this as any).api('notes/mentions', {
-				following: this.mode == 'following',
-				untilId: this.notes[this.notes.length - 1].id
-			}).then(notes => {
-				this.notes = this.notes.concat(notes);
-				this.moreFetching = false;
-			});
-		}
-	}
-});
-</script>
-
-<style lang="stylus" scoped>
-@import '~const.styl'
-
-.mk-mentions
-	background #fff
-	border solid 1px rgba(#000, 0.075)
-	border-radius 6px
-
-	> header
-		padding 8px 16px
-		border-bottom solid 1px #eee
-
-		> span
-			margin-right 16px
-			line-height 27px
-			font-size 18px
-			color #555
-
-			&:not([data-active])
-				color $theme-color
-				cursor pointer
-
-				&:hover
-					text-decoration underline
-
-	> .fetching
-		padding 64px 0
-
-	> .empty
-		display block
-		margin 0 auto
-		padding 32px
-		max-width 400px
-		text-align center
-		color #999
-
-		> [data-fa]
-			display block
-			margin-bottom 16px
-			font-size 3em
-			color #ccc
-
-</style>
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index 8660a5f899..e23d3e5a52 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -33,9 +33,6 @@
 				</div>
 			</header>
 			<div class="body">
-				<p class="channel" v-if="p.channel">
-					<a :href="`${_CH_URL_}/${p.channel.id}`" target="_blank">{{ p.channel.title }}</a>:
-				</p>
 				<p v-if="p.cw != null" class="cw">
 					<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
 					<span class="toggle" @click="showContent = !showContent">{{ showContent ? '隠す' : 'もっと見る' }}</span>
@@ -574,9 +571,6 @@ root(isDark)
 					.mk-url-preview
 						margin-top 8px
 
-					> .channel
-						margin 0
-
 					> .mk-poll
 						font-size 80%
 
diff --git a/src/client/app/desktop/views/widgets/channel.channel.form.vue b/src/client/app/desktop/views/widgets/channel.channel.form.vue
deleted file mode 100644
index f2744268bb..0000000000
--- a/src/client/app/desktop/views/widgets/channel.channel.form.vue
+++ /dev/null
@@ -1,67 +0,0 @@
-<template>
-<div class="form">
-	<input v-model="text" :disabled="wait" @keydown="onKeydown" placeholder="書いて">
-</div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-export default Vue.extend({
-	data() {
-		return {
-			text: '',
-			wait: false
-		};
-	},
-	methods: {
-		onKeydown(e) {
-			if (e.which == 10 || e.which == 13) this.post();
-		},
-		post() {
-			this.wait = true;
-
-			let reply = null;
-
-			if (/^>>([0-9]+) /.test(this.text)) {
-				const index = this.text.match(/^>>([0-9]+) /)[1];
-				reply = (this.$parent as any).notes.find(p => p.index.toString() == index);
-				this.text = this.text.replace(/^>>([0-9]+) /, '');
-			}
-
-			(this as any).api('notes/create', {
-				text: this.text,
-				replyId: reply ? reply.id : undefined,
-				channelId: (this.$parent as any).channel.id
-			}).then(data => {
-				this.text = '';
-			}).catch(err => {
-				alert('失敗した');
-			}).then(() => {
-				this.wait = false;
-			});
-		}
-	}
-});
-</script>
-
-<style lang="stylus" scoped>
-.form
-	width 100%
-	height 38px
-	padding 4px
-	border-top solid 1px #ddd
-
-	> input
-		padding 0 8px
-		width 100%
-		height 100%
-		font-size 14px
-		color #55595c
-		border solid 1px #dadada
-		border-radius 4px
-
-		&:hover
-		&:focus
-			border-color #aeaeae
-
-</style>
diff --git a/src/client/app/desktop/views/widgets/channel.channel.note.vue b/src/client/app/desktop/views/widgets/channel.channel.note.vue
deleted file mode 100644
index 7767919066..0000000000
--- a/src/client/app/desktop/views/widgets/channel.channel.note.vue
+++ /dev/null
@@ -1,65 +0,0 @@
-<template>
-<div class="note">
-	<header>
-		<a class="index" @click="reply">{{ note.index }}:</a>
-		<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id"><b>{{ note.user | userName }}</b></router-link>
-		<span>ID:<i>{{ note.user | acct }}</i></span>
-	</header>
-	<div>
-		<a v-if="note.reply">&gt;&gt;{{ note.reply.index }}</a>
-		{{ note.text }}
-		<div class="media" v-if="note.media">
-			<a v-for="file in note.media" :href="file.url" target="_blank">
-				<img :src="`${file.url}?thumbnail&size=512`" :alt="file.name" :title="file.name"/>
-			</a>
-		</div>
-	</div>
-</div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-
-export default Vue.extend({
-	props: ['note'],
-	methods: {
-		reply() {
-			this.$emit('reply', this.note);
-		}
-	}
-});
-</script>
-
-<style lang="stylus" scoped>
-.note
-	margin 0
-	padding 0
-	color #444
-
-	> header
-		position -webkit-sticky
-		position sticky
-		z-index 1
-		top 0
-		padding 8px 4px 4px 16px
-		background rgba(255, 255, 255, 0.9)
-
-		> .index
-			margin-right 0.25em
-
-		> .name
-			margin-right 0.5em
-			color #008000
-
-	> div
-		padding 0 16px 16px 16px
-
-		> .media
-			> a
-				display inline-block
-
-				> img
-					max-width 100%
-					vertical-align bottom
-
-</style>
diff --git a/src/client/app/desktop/views/widgets/channel.channel.vue b/src/client/app/desktop/views/widgets/channel.channel.vue
deleted file mode 100644
index ea4d8f8454..0000000000
--- a/src/client/app/desktop/views/widgets/channel.channel.vue
+++ /dev/null
@@ -1,106 +0,0 @@
-<template>
-<div class="channel">
-	<p v-if="fetching">読み込み中<mk-ellipsis/></p>
-	<div v-if="!fetching" ref="notes" class="notes">
-		<p v-if="notes.length == 0">まだ投稿がありません</p>
-		<x-note class="note" v-for="note in notes.slice().reverse()" :note="note" :key="note.id" @reply="reply"/>
-	</div>
-	<x-form class="form" ref="form"/>
-</div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-import ChannelStream from '../../../common/scripts/streaming/channel';
-import XForm from './channel.channel.form.vue';
-import XNote from './channel.channel.note.vue';
-
-export default Vue.extend({
-	components: {
-		XForm,
-		XNote
-	},
-	props: ['channel'],
-	data() {
-		return {
-			fetching: true,
-			notes: [],
-			connection: null
-		};
-	},
-	watch: {
-		channel() {
-			this.zap();
-		}
-	},
-	mounted() {
-		this.zap();
-	},
-	beforeDestroy() {
-		this.disconnect();
-	},
-	methods: {
-		zap() {
-			this.fetching = true;
-
-			(this as any).api('channels/notes', {
-				channelId: this.channel.id
-			}).then(notes => {
-				this.notes = notes;
-				this.fetching = false;
-
-				this.$nextTick(() => {
-					this.scrollToBottom();
-				});
-
-				this.disconnect();
-				this.connection = new ChannelStream((this as any).os, this.channel.id);
-				this.connection.on('note', this.onNote);
-			});
-		},
-		disconnect() {
-			if (this.connection) {
-				this.connection.off('note', this.onNote);
-				this.connection.close();
-			}
-		},
-		onNote(note) {
-			this.notes.unshift(note);
-			this.scrollToBottom();
-		},
-		scrollToBottom() {
-			(this.$refs.notes as any).scrollTop = (this.$refs.notes as any).scrollHeight;
-		},
-		reply(note) {
-			(this.$refs.form as any).text = `>>${ note.index } `;
-		}
-	}
-});
-</script>
-
-<style lang="stylus" scoped>
-.channel
-
-	> p
-		margin 0
-		padding 16px
-		text-align center
-		color #aaa
-
-	> .notes
-		height calc(100% - 38px)
-		overflow auto
-		font-size 0.9em
-
-		> .note
-			border-bottom solid 1px #eee
-
-			&:last-child
-				border-bottom none
-
-	> .form
-		position absolute
-		left 0
-		bottom 0
-
-</style>
diff --git a/src/client/app/desktop/views/widgets/channel.vue b/src/client/app/desktop/views/widgets/channel.vue
deleted file mode 100644
index d21aed40fd..0000000000
--- a/src/client/app/desktop/views/widgets/channel.vue
+++ /dev/null
@@ -1,108 +0,0 @@
-<template>
-<div class="mkw-channel">
-	<template v-if="!props.compact">
-		<p class="title">%fa:tv%{{ channel ? channel.title : '%i18n:!@title%' }}</p>
-		<button @click="settings" title="%i18n:@settings%">%fa:cog%</button>
-	</template>
-	<p class="get-started" v-if="props.channel == null">%i18n:@get-started%</p>
-	<x-channel class="channel" :channel="channel" v-if="channel != null"/>
-</div>
-</template>
-
-<script lang="ts">
-import define from '../../../common/define-widget';
-import XChannel from './channel.channel.vue';
-
-export default define({
-	name: 'server',
-	props: () => ({
-		channel: null,
-		compact: false
-	})
-}).extend({
-	components: {
-		XChannel
-	},
-	data() {
-		return {
-			fetching: true,
-			channel: null
-		};
-	},
-	mounted() {
-		if (this.props.channel) {
-				this.zap();
-			}
-	},
-	methods: {
-		func() {
-			this.props.compact = !this.props.compact;
-			this.save();
-		},
-		settings() {
-			const id = window.prompt('チャンネルID');
-			if (!id) return;
-			this.props.channel = id;
-			this.zap();
-		},
-		zap() {
-			this.fetching = true;
-
-			(this as any).api('channels/show', {
-				channelId: this.props.channel
-			}).then(channel => {
-				this.channel = channel;
-				this.fetching = false;
-			});
-		}
-	}
-});
-</script>
-
-<style lang="stylus" scoped>
-.mkw-channel
-	background #fff
-	border solid 1px rgba(#000, 0.075)
-	border-radius 6px
-	overflow hidden
-
-	> .title
-		z-index 2
-		margin 0
-		padding 0 16px
-		line-height 42px
-		font-size 0.9em
-		font-weight bold
-		color #888
-		box-shadow 0 1px rgba(#000, 0.07)
-
-		> [data-fa]
-			margin-right 4px
-
-	> button
-		position absolute
-		z-index 2
-		top 0
-		right 0
-		padding 0
-		width 42px
-		font-size 0.9em
-		line-height 42px
-		color #ccc
-
-		&:hover
-			color #aaa
-
-		&:active
-			color #999
-
-	> .get-started
-		margin 0
-		padding 16px
-		text-align center
-		color #aaa
-
-	> .channel
-		height 200px
-
-</style>
diff --git a/src/client/app/desktop/views/widgets/index.ts b/src/client/app/desktop/views/widgets/index.ts
index 77d771d6b3..7c074080c1 100644
--- a/src/client/app/desktop/views/widgets/index.ts
+++ b/src/client/app/desktop/views/widgets/index.ts
@@ -8,7 +8,6 @@ import wUsers from './users.vue';
 import wPolls from './polls.vue';
 import wPostForm from './post-form.vue';
 import wMessaging from './messaging.vue';
-import wChannel from './channel.vue';
 import wProfile from './profile.vue';
 
 Vue.component('mkw-notifications', wNotifications);
@@ -19,5 +18,4 @@ Vue.component('mkw-users', wUsers);
 Vue.component('mkw-polls', wPolls);
 Vue.component('mkw-post-form', wPostForm);
 Vue.component('mkw-messaging', wMessaging);
-Vue.component('mkw-channel', wChannel);
 Vue.component('mkw-profile', wProfile);
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 8181bab0ac..83a957cfbd 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -32,7 +32,6 @@
 				</div>
 			</header>
 			<div class="body">
-				<p class="channel" v-if="p.channel != null"><a target="_blank">{{ p.channel.title }}</a>:</p>
 				<p v-if="p.cw != null" class="cw">
 					<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
 					<span class="toggle" @click="showContent = !showContent">{{ showContent ? '隠す' : 'もっと見る' }}</span>
@@ -470,9 +469,6 @@ root(isDark)
 					.mk-url-preview
 						margin-top 8px
 
-					> .channel
-						margin 0
-
 					> .tags
 						margin 4px 0 0 0
 
diff --git a/src/client/app/mobile/views/pages/widgets.vue b/src/client/app/mobile/views/pages/widgets.vue
index 509ce16eef..f0a0877862 100644
--- a/src/client/app/mobile/views/pages/widgets.vue
+++ b/src/client/app/mobile/views/pages/widgets.vue
@@ -15,7 +15,6 @@
 					<option value="photo-stream">フォトストリーム</option>
 					<option value="slideshow">スライドショー</option>
 					<option value="version">バージョン</option>
-					<option value="access-log">アクセスログ</option>
 					<option value="server">サーバー情報</option>
 					<option value="donation">寄付のお願い</option>
 					<option value="nav">ナビゲーション</option>
diff --git a/src/models/channel-watching.ts b/src/models/channel-watching.ts
deleted file mode 100644
index 44ca06883f..0000000000
--- a/src/models/channel-watching.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import * as mongo from 'mongodb';
-import db from '../db/mongodb';
-
-const ChannelWatching = db.get<IChannelWatching>('channelWatching');
-export default ChannelWatching;
-
-export interface IChannelWatching {
-	_id: mongo.ObjectID;
-	createdAt: Date;
-	deletedAt: Date;
-	channelId: mongo.ObjectID;
-	userId: mongo.ObjectID;
-}
diff --git a/src/models/channel.ts b/src/models/channel.ts
deleted file mode 100644
index 67386ac072..0000000000
--- a/src/models/channel.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import * as mongo from 'mongodb';
-import deepcopy = require('deepcopy');
-import { IUser } from './user';
-import Watching from './channel-watching';
-import db from '../db/mongodb';
-
-const Channel = db.get<IChannel>('channels');
-export default Channel;
-
-export type IChannel = {
-	_id: mongo.ObjectID;
-	createdAt: Date;
-	title: string;
-	userId: mongo.ObjectID;
-	index: number;
-	watchingCount: number;
-};
-
-/**
- * Pack a channel for API response
- *
- * @param channel target
- * @param me? serializee
- * @return response
- */
-export const pack = (
-	channel: string | mongo.ObjectID | IChannel,
-	me?: string | mongo.ObjectID | IUser
-) => new Promise<any>(async (resolve, reject) => {
-
-	let _channel: any;
-
-	// Populate the channel if 'channel' is ID
-	if (mongo.ObjectID.prototype.isPrototypeOf(channel)) {
-		_channel = await Channel.findOne({
-			_id: channel
-		});
-	} else if (typeof channel === 'string') {
-		_channel = await Channel.findOne({
-			_id: new mongo.ObjectID(channel)
-		});
-	} else {
-		_channel = deepcopy(channel);
-	}
-
-	// Rename _id to id
-	_channel.id = _channel._id;
-	delete _channel._id;
-
-	// Remove needless properties
-	delete _channel.userId;
-
-	// Me
-	const meId: mongo.ObjectID = me
-	? mongo.ObjectID.prototype.isPrototypeOf(me)
-		? me as mongo.ObjectID
-		: typeof me === 'string'
-			? new mongo.ObjectID(me)
-			: (me as IUser)._id
-	: null;
-
-	if (me) {
-		//#region Watchしているかどうか
-		const watch = await Watching.findOne({
-			userId: meId,
-			channelId: _channel.id,
-			deletedAt: { $exists: false }
-		});
-
-		_channel.isWatching = watch !== null;
-		//#endregion
-	}
-
-	resolve(_channel);
-});
diff --git a/src/models/note.ts b/src/models/note.ts
index f42bb2a49d..5070923363 100644
--- a/src/models/note.ts
+++ b/src/models/note.ts
@@ -4,7 +4,6 @@ import rap from '@prezzemolo/rap';
 import db from '../db/mongodb';
 import { IUser, pack as packUser } from './user';
 import { pack as packApp } from './app';
-import { pack as packChannel } from './channel';
 import PollVote, { deletePollVote } from './poll-vote';
 import Reaction, { deleteNoteReaction } from './note-reaction';
 import { pack as packFile } from './drive-file';
@@ -29,7 +28,6 @@ export function isValidCw(text: string): boolean {
 
 export type INote = {
 	_id: mongo.ObjectID;
-	channelId: mongo.ObjectID;
 	createdAt: Date;
 	deletedAt: Date;
 	mediaIds: mongo.ObjectID[];
@@ -258,11 +256,6 @@ export const pack = async (
 		_note.app = packApp(_note.appId);
 	}
 
-	// Populate channel
-	if (_note.channelId) {
-		_note.channel = packChannel(_note.channelId);
-	}
-
 	// Populate media
 	_note.media = hide ? [] : Promise.all(_note.mediaIds.map(fileId =>
 		packFile(fileId)
diff --git a/src/publishers/stream.ts b/src/publishers/stream.ts
index dcc03e39f1..58a6ef49aa 100644
--- a/src/publishers/stream.ts
+++ b/src/publishers/stream.ts
@@ -45,10 +45,6 @@ class MisskeyEvent {
 		this.publish(`othello-game-stream:${gameId}`, type, typeof value === 'undefined' ? null : value);
 	}
 
-	public publishChannelStream(channelId: ID, type: string, value?: any): void {
-		this.publish(`channel-stream:${channelId}`, type, typeof value === 'undefined' ? null : value);
-	}
-
 	public publishLocalTimelineStream(note: any): void {
 		this.redisClient.publish('misskey:local-timeline', JSON.stringify(note));
 	}
@@ -79,4 +75,3 @@ export const publishMessagingStream = ev.publishMessagingStream.bind(ev);
 export const publishMessagingIndexStream = ev.publishMessagingIndexStream.bind(ev);
 export const publishOthelloStream = ev.publishOthelloStream.bind(ev);
 export const publishOthelloGameStream = ev.publishOthelloGameStream.bind(ev);
-export const publishChannelStream = ev.publishChannelStream.bind(ev);
diff --git a/src/renderers/get-note-summary.ts b/src/renderers/get-note-summary.ts
index 0844c0b184..643e2d09ba 100644
--- a/src/renderers/get-note-summary.ts
+++ b/src/renderers/get-note-summary.ts
@@ -9,9 +9,6 @@ const summarize = (note: any): string => {
 
 	let summary = '';
 
-	// チャンネル
-	summary += note.channel ? `${note.channel.title}:` : '';
-
 	// 本文
 	summary += note.text ? note.text : '';
 
diff --git a/src/server/api/endpoints.ts b/src/server/api/endpoints.ts
index 734b8273f1..7647c76d3d 100644
--- a/src/server/api/endpoints.ts
+++ b/src/server/api/endpoints.ts
@@ -621,33 +621,7 @@ const endpoints: Endpoint[] = [
 		name: 'messaging/messages/create',
 		withCredential: true,
 		kind: 'messaging-write'
-	},
-	{
-		name: 'channels/create',
-		withCredential: true,
-		limit: {
-			duration: ms('1hour'),
-			max: 3,
-			minInterval: ms('10seconds')
-		}
-	},
-	{
-		name: 'channels/show'
-	},
-	{
-		name: 'channels/notes'
-	},
-	{
-		name: 'channels/watch',
-		withCredential: true
-	},
-	{
-		name: 'channels/unwatch',
-		withCredential: true
-	},
-	{
-		name: 'channels'
-	},
+	}
 ];
 
 export default endpoints;
diff --git a/src/server/api/endpoints/channels.ts b/src/server/api/endpoints/channels.ts
deleted file mode 100644
index ceef4b9cb9..0000000000
--- a/src/server/api/endpoints/channels.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Module dependencies
- */
-import $ from 'cafy'; import ID from '../../../cafy-id';
-import Channel, { pack } from '../../../models/channel';
-
-/**
- * Get all channels
- *
- * @param {any} params
- * @param {any} me
- * @return {Promise<any>}
- */
-module.exports = (params, me) => new Promise(async (res, rej) => {
-	// Get 'limit' parameter
-	const [limit = 10, limitErr] = $.num.optional().range(1, 100).get(params.limit);
-	if (limitErr) return rej('invalid limit param');
-
-	// Get 'sinceId' parameter
-	const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
-	if (sinceIdErr) return rej('invalid sinceId param');
-
-	// Get 'untilId' parameter
-	const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
-	if (untilIdErr) return rej('invalid untilId param');
-
-	// Check if both of sinceId and untilId is specified
-	if (sinceId && untilId) {
-		return rej('cannot set sinceId and untilId');
-	}
-
-	// Construct query
-	const sort = {
-		_id: -1
-	};
-	const query = {} as any;
-	if (sinceId) {
-		sort._id = 1;
-		query._id = {
-			$gt: sinceId
-		};
-	} else if (untilId) {
-		query._id = {
-			$lt: untilId
-		};
-	}
-
-	// Issue query
-	const channels = await Channel
-		.find(query, {
-			limit: limit,
-			sort: sort
-		});
-
-	// Serialize
-	res(await Promise.all(channels.map(async channel =>
-		await pack(channel, me))));
-});
diff --git a/src/server/api/endpoints/channels/create.ts b/src/server/api/endpoints/channels/create.ts
deleted file mode 100644
index 0e3c9dc5ac..0000000000
--- a/src/server/api/endpoints/channels/create.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Module dependencies
- */
-import $ from 'cafy';
-import Channel from '../../../../models/channel';
-import Watching from '../../../../models/channel-watching';
-import { pack } from '../../../../models/channel';
-
-/**
- * Create a channel
- */
-module.exports = async (params, user) => new Promise(async (res, rej) => {
-	// Get 'title' parameter
-	const [title, titleErr] = $.str.range(1, 100).get(params.title);
-	if (titleErr) return rej('invalid title param');
-
-	// Create a channel
-	const channel = await Channel.insert({
-		createdAt: new Date(),
-		userId: user._id,
-		title: title,
-		index: 0,
-		watchingCount: 1
-	});
-
-	// Response
-	res(await pack(channel));
-
-	// Create Watching
-	await Watching.insert({
-		createdAt: new Date(),
-		userId: user._id,
-		channelId: channel._id
-	});
-});
diff --git a/src/server/api/endpoints/channels/notes.ts b/src/server/api/endpoints/channels/notes.ts
deleted file mode 100644
index 463152e74a..0000000000
--- a/src/server/api/endpoints/channels/notes.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Module dependencies
- */
-import $ from 'cafy'; import ID from '../../../../cafy-id';
-import { default as Channel, IChannel } from '../../../../models/channel';
-import Note, { pack } from '../../../../models/note';
-
-/**
- * Show a notes of a channel
- */
-module.exports = (params, user) => new Promise(async (res, rej) => {
-	// Get 'limit' parameter
-	const [limit = 1000, limitErr] = $.num.optional().range(1, 1000).get(params.limit);
-	if (limitErr) return rej('invalid limit param');
-
-	// Get 'sinceId' parameter
-	const [sinceId, sinceIdErr] = $.type(ID).optional().get(params.sinceId);
-	if (sinceIdErr) return rej('invalid sinceId param');
-
-	// Get 'untilId' parameter
-	const [untilId, untilIdErr] = $.type(ID).optional().get(params.untilId);
-	if (untilIdErr) return rej('invalid untilId param');
-
-	// Check if both of sinceId and untilId is specified
-	if (sinceId && untilId) {
-		return rej('cannot set sinceId and untilId');
-	}
-
-	// Get 'channelId' parameter
-	const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
-	if (channelIdErr) return rej('invalid channelId param');
-
-	// Fetch channel
-	const channel: IChannel = await Channel.findOne({
-		_id: channelId
-	});
-
-	if (channel === null) {
-		return rej('channel not found');
-	}
-
-	//#region Construct query
-	const sort = {
-		_id: -1
-	};
-
-	const query = {
-		channelId: channel._id
-	} as any;
-
-	if (sinceId) {
-		sort._id = 1;
-		query._id = {
-			$gt: sinceId
-		};
-	} else if (untilId) {
-		query._id = {
-			$lt: untilId
-		};
-	}
-	//#endregion Construct query
-
-	// Issue query
-	const notes = await Note
-		.find(query, {
-			limit: limit,
-			sort: sort
-		});
-
-	// Serialize
-	res(await Promise.all(notes.map(async (note) =>
-		await pack(note, user)
-	)));
-});
diff --git a/src/server/api/endpoints/channels/show.ts b/src/server/api/endpoints/channels/show.ts
deleted file mode 100644
index 1bba63d490..0000000000
--- a/src/server/api/endpoints/channels/show.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Module dependencies
- */
-import $ from 'cafy'; import ID from '../../../../cafy-id';
-import Channel, { IChannel, pack } from '../../../../models/channel';
-
-/**
- * Show a channel
- */
-module.exports = (params, user) => new Promise(async (res, rej) => {
-	// Get 'channelId' parameter
-	const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
-	if (channelIdErr) return rej('invalid channelId param');
-
-	// Fetch channel
-	const channel: IChannel = await Channel.findOne({
-		_id: channelId
-	});
-
-	if (channel === null) {
-		return rej('channel not found');
-	}
-
-	// Serialize
-	res(await pack(channel, user));
-});
diff --git a/src/server/api/endpoints/channels/unwatch.ts b/src/server/api/endpoints/channels/unwatch.ts
deleted file mode 100644
index f7dddff461..0000000000
--- a/src/server/api/endpoints/channels/unwatch.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Module dependencies
- */
-import $ from 'cafy'; import ID from '../../../../cafy-id';
-import Channel from '../../../../models/channel';
-import Watching from '../../../../models/channel-watching';
-
-/**
- * Unwatch a channel
- */
-module.exports = (params, user) => new Promise(async (res, rej) => {
-	// Get 'channelId' parameter
-	const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
-	if (channelIdErr) return rej('invalid channelId param');
-
-	//#region Fetch channel
-	const channel = await Channel.findOne({
-		_id: channelId
-	});
-
-	if (channel === null) {
-		return rej('channel not found');
-	}
-	//#endregion
-
-	//#region Check whether not watching
-	const exist = await Watching.findOne({
-		userId: user._id,
-		channelId: channel._id,
-		deletedAt: { $exists: false }
-	});
-
-	if (exist === null) {
-		return rej('already not watching');
-	}
-	//#endregion
-
-	// Delete watching
-	await Watching.update({
-		_id: exist._id
-	}, {
-		$set: {
-			deletedAt: new Date()
-		}
-	});
-
-	// Send response
-	res();
-
-	// Decrement watching count
-	Channel.update(channel._id, {
-		$inc: {
-			watchingCount: -1
-		}
-	});
-});
diff --git a/src/server/api/endpoints/channels/watch.ts b/src/server/api/endpoints/channels/watch.ts
deleted file mode 100644
index 34243ff68b..0000000000
--- a/src/server/api/endpoints/channels/watch.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Module dependencies
- */
-import $ from 'cafy'; import ID from '../../../../cafy-id';
-import Channel from '../../../../models/channel';
-import Watching from '../../../../models/channel-watching';
-
-/**
- * Watch a channel
- */
-module.exports = (params, user) => new Promise(async (res, rej) => {
-	// Get 'channelId' parameter
-	const [channelId, channelIdErr] = $.type(ID).get(params.channelId);
-	if (channelIdErr) return rej('invalid channelId param');
-
-	//#region Fetch channel
-	const channel = await Channel.findOne({
-		_id: channelId
-	});
-
-	if (channel === null) {
-		return rej('channel not found');
-	}
-	//#endregion
-
-	//#region Check whether already watching
-	const exist = await Watching.findOne({
-		userId: user._id,
-		channelId: channel._id,
-		deletedAt: { $exists: false }
-	});
-
-	if (exist !== null) {
-		return rej('already watching');
-	}
-	//#endregion
-
-	// Create Watching
-	await Watching.insert({
-		createdAt: new Date(),
-		userId: user._id,
-		channelId: channel._id
-	});
-
-	// Send response
-	res();
-
-	// Increment watching count
-	Channel.update(channel._id, {
-		$inc: {
-			watchingCount: 1
-		}
-	});
-});
diff --git a/src/server/api/endpoints/notes/create.ts b/src/server/api/endpoints/notes/create.ts
index 429b6d370a..182359f637 100644
--- a/src/server/api/endpoints/notes/create.ts
+++ b/src/server/api/endpoints/notes/create.ts
@@ -4,7 +4,6 @@
 import $ from 'cafy'; import ID from '../../../../cafy-id';
 import Note, { INote, isValidText, isValidCw, pack } from '../../../../models/note';
 import User, { ILocalUser } from '../../../../models/user';
-import Channel, { IChannel } from '../../../../models/channel';
 import DriveFile from '../../../../models/drive-file';
 import create from '../../../../services/note/create';
 import { IApp } from '../../../../models/app';
@@ -89,7 +88,6 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
 	if (renoteIdErr) return rej('invalid renoteId');
 
 	let renote: INote = null;
-	let isQuote = false;
 	if (renoteId !== undefined) {
 		// Fetch renote to note
 		renote = await Note.findOne({
@@ -101,8 +99,6 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
 		} else if (renote.renoteId && !renote.text && !renote.mediaIds) {
 			return rej('cannot renote to renote');
 		}
-
-		isQuote = text != null || files != null;
 	}
 
 	// Get 'replyId' parameter
@@ -126,47 +122,6 @@ module.exports = (params, user: ILocalUser, app: IApp) => new Promise(async (res
 		}
 	}
 
-	// Get 'channelId' parameter
-	const [channelId, channelIdErr] = $.type(ID).optional().get(params.channelId);
-	if (channelIdErr) return rej('invalid channelId');
-
-	let channel: IChannel = null;
-	if (channelId !== undefined) {
-		// Fetch channel
-		channel = await Channel.findOne({
-			_id: channelId
-		});
-
-		if (channel === null) {
-			return rej('channel not found');
-		}
-
-		// 返信対象の投稿がこのチャンネルじゃなかったらダメ
-		if (reply && !channelId.equals(reply.channelId)) {
-			return rej('チャンネル内部からチャンネル外部の投稿に返信することはできません');
-		}
-
-		// Renote対象の投稿がこのチャンネルじゃなかったらダメ
-		if (renote && !channelId.equals(renote.channelId)) {
-			return rej('チャンネル内部からチャンネル外部の投稿をRenoteすることはできません');
-		}
-
-		// 引用ではないRenoteはダメ
-		if (renote && !isQuote) {
-			return rej('チャンネル内部では引用ではないRenoteをすることはできません');
-		}
-	} else {
-		// 返信対象の投稿がチャンネルへの投稿だったらダメ
-		if (reply && reply.channelId != null) {
-			return rej('チャンネル外部からチャンネル内部の投稿に返信することはできません');
-		}
-
-		// Renote対象の投稿がチャンネルへの投稿だったらダメ
-		if (renote && renote.channelId != null) {
-			return rej('チャンネル外部からチャンネル内部の投稿をRenoteすることはできません');
-		}
-	}
-
 	// Get 'poll' parameter
 	const [poll, pollErr] = $.obj.optional().strict()
 		.have('choices', $.arr($.str)
diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts
index 78786d4a16..9f32555649 100644
--- a/src/server/api/endpoints/notes/timeline.ts
+++ b/src/server/api/endpoints/notes/timeline.ts
@@ -4,7 +4,6 @@
 import $ from 'cafy'; import ID from '../../../../cafy-id';
 import Note from '../../../../models/note';
 import Mute from '../../../../models/mute';
-import ChannelWatching from '../../../../models/channel-watching';
 import { getFriends } from '../../common/get-friends';
 import { pack } from '../../../../models/note';
 
@@ -45,18 +44,11 @@ module.exports = async (params, user, app) => {
 	const [includeRenotedMyNotes = true, includeRenotedMyNotesErr] = $.bool.optional().get(params.includeRenotedMyNotes);
 	if (includeRenotedMyNotesErr) throw 'invalid includeRenotedMyNotes param';
 
-	const [followings, watchingChannelIds, mutedUserIds] = await Promise.all([
+	const [followings, mutedUserIds] = await Promise.all([
 		// フォローを取得
 		// Fetch following
 		getFriends(user._id),
 
-		// Watchしているチャンネルを取得
-		ChannelWatching.find({
-			userId: user._id,
-			// 削除されたドキュメントは除く
-			deletedAt: { $exists: false }
-		}).then(watches => watches.map(w => w.channelId)),
-
 		// ミュートしているユーザーを取得
 		Mute.find({
 			muterId: user._id
@@ -93,26 +85,9 @@ module.exports = async (params, user, app) => {
 
 	const query = {
 		$and: [{
-			$or: [{
-				$and: [{
-					// フォローしている人のタイムラインへの投稿
-					$or: followQuery
-				}, {
-					// 「タイムラインへの」投稿に限定するためにチャンネルが指定されていないもののみに限る
-					$or: [{
-						channelId: {
-							$exists: false
-						}
-					}, {
-						channelId: null
-					}]
-				}]
-			}, {
-				// Watchしているチャンネルへの投稿
-				channelId: {
-					$in: watchingChannelIds
-				}
-			}],
+			// フォローしている人の投稿
+			$or: followQuery,
+
 			// mute
 			userId: {
 				$nin: mutedUserIds
diff --git a/src/server/api/stream/channel.ts b/src/server/api/stream/channel.ts
deleted file mode 100644
index cb04278237..0000000000
--- a/src/server/api/stream/channel.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import * as websocket from 'websocket';
-import * as redis from 'redis';
-import { ParsedUrlQuery } from 'querystring';
-
-export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient): void {
-	const q = request.resourceURL.query as ParsedUrlQuery;
-	const channel = q.channel;
-
-	// Subscribe channel stream
-	subscriber.subscribe(`misskey:channel-stream:${channel}`);
-	subscriber.on('message', (_, data) => {
-		connection.send(data);
-	});
-}
diff --git a/src/server/api/streaming.ts b/src/server/api/streaming.ts
index e4884ed7c4..6825b6336a 100644
--- a/src/server/api/streaming.ts
+++ b/src/server/api/streaming.ts
@@ -14,7 +14,6 @@ import othelloGameStream from './stream/othello-game';
 import othelloStream from './stream/othello';
 import serverStream from './stream/server';
 import requestsStream from './stream/requests';
-import channelStream from './stream/channel';
 import { ParsedUrlQuery } from 'querystring';
 import authenticate from './authenticate';
 
@@ -48,11 +47,6 @@ module.exports = (server: http.Server) => {
 			subscriber.quit();
 		});
 
-		if (request.resourceURL.pathname === '/channel') {
-			channelStream(request, connection, subscriber);
-			return;
-		}
-
 		const q = request.resourceURL.query as ParsedUrlQuery;
 		const [user, app] = await authenticate(q.i as string);
 
-- 
GitLab