Compare commits

..

116 Commits

Author SHA1 Message Date
960f29ce81 10.82.2 2019-02-06 15:25:47 +09:00
20ee57931f Resolve #4165 2019-02-06 15:24:59 +09:00
71ba72e796 Better logs 2019-02-06 15:06:23 +09:00
9835945ee1 Improve queue option 2019-02-06 15:01:43 +09:00
4f2d52697d Update queue setting 2019-02-06 14:53:02 +09:00
46c258d77a 10.82.1 2019-02-06 14:01:52 +09:00
3b5b3cf521 Merge branches 'develop' and 'develop' of https://github.com/syuilo/misskey into develop 2019-02-06 13:56:21 +09:00
5e0bdd8a78 New Crowdin translations (#4147)
* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)
2019-02-06 13:56:00 +09:00
b299988bb5 Simplify comment (#4164) 2019-02-06 13:52:32 +09:00
e26bec6ab4 Improve queue configuration
Resolve #4157
Resolve #4158
2019-02-06 13:51:02 +09:00
e9955e01d6 Introduce option type (#4150)
* Introduce option type

* Improve test naming
2019-02-06 13:42:35 +09:00
1974d8f58b Add URL validation (#4148) 2019-02-06 13:37:20 +09:00
08c0be11b2 Merge pull request #4163 from syuilo/dependabot/npm_and_yarn/jsdom-13.2.0 2019-02-05 20:36:15 +00:00
87c7058494 Merge pull request #4162 from syuilo/dependabot/npm_and_yarn/@types/node-10.12.21 2019-02-05 20:31:01 +00:00
b92addffa9 Update jsdom requirement from 13.1.0 to 13.2.0
Updates the requirements on [jsdom](https://github.com/jsdom/jsdom) to permit the latest version.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/master/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/commits/13.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-05 20:26:19 +00:00
e8b49df842 Update @types/node requirement from 10.12.18 to 10.12.21
Updates the requirements on [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-05 20:22:20 +00:00
18fd39b335 proxyで400番台はそのステータスを返す (#4154) 2019-02-06 00:20:00 +09:00
8a11322802 Update README.md 2019-02-06 00:13:31 +09:00
31929dad61 [MFM] Better hashtag parsing: Ignore slash 2019-02-06 00:05:26 +09:00
4a41d2fddc Add logs 2019-02-06 00:01:37 +09:00
4c65b0cd6f 🎨 2019-02-05 23:45:27 +09:00
3e89dc603d Bye 'is-url' (#4113) 2019-02-05 19:54:41 +09:00
2a1def3cce 10.82.0 2019-02-05 19:53:31 +09:00
938fe05fef Update CHANGELOG.md 2019-02-05 19:52:22 +09:00
5db5bbd1cd 自分の投稿情報をエクスポートできるように (#4144)
* wip

* 正しいJSONを生成するように

* データを整形
2019-02-05 19:50:14 +09:00
ba7e05837c Add ffmpeg package for the runner container (#4145)
* Revert "Update Dockerfile (#4090)"

This reverts commit 6758b0f133.

* Docker: Add ffmpeg package for the runner container

Misskey 10.81.0 added thumbnail generation support.
However it did not work with Docker bacause ffmpeg has not been
installed in the runner container.
2019-02-05 19:32:53 +09:00
9dd06a7621 /.well-known 周りをいい感じに (#4141)
* Enhance /.well-known and their friends

* Fix bug
2019-02-05 17:42:55 +09:00
2f4434b0d8 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-02-05 17:30:25 +09:00
350328770b Improve readability 2019-02-05 17:30:17 +09:00
17e1b49bff New translations ja-JP.yml (Chinese Simplified) (#4140) 2019-02-05 15:16:53 +09:00
266c31981d Fix typo 2019-02-05 15:09:37 +09:00
803fb0898a Fix bug 2019-02-05 14:56:33 +09:00
01983da514 [Client] Use localStorage instead of window 2019-02-05 14:42:18 +09:00
6f473aa64a Update setup.ja.md 2019-02-05 14:25:03 +09:00
574747b9d4 Improve doc 2019-02-05 14:24:10 +09:00
dff1122bd5 Enable service worker 2019-02-05 14:22:52 +09:00
43cb12930a Remove unused declare 2019-02-05 14:22:35 +09:00
8129d4dc23 Refactoring 2019-02-05 14:14:23 +09:00
9b780dff04 Fix log 2019-02-05 14:04:40 +09:00
11a0ef485b Resolve #4139 2019-02-05 13:56:50 +09:00
83b2aa72b1 [Client] Clip note content 2019-02-05 13:54:40 +09:00
c71b24987d Make index.js for more convinience 2019-02-05 13:46:06 +09:00
78d22dbd22 Update vue to 2.6.2 🚀 2019-02-05 13:35:47 +09:00
8961dab137 Fix comment 2019-02-05 11:49:03 +09:00
bcc549fd8e Fix style 2019-02-05 11:48:08 +09:00
5a6c3fc11c Update css-loader to 2.1.0 🚀
Close #3961
2019-02-05 07:06:57 +09:00
7d730f676d Refactoring: Extract showMachineInfo function 2019-02-05 06:49:00 +09:00
6bda571660 Make some error logs important 2019-02-05 06:46:01 +09:00
d3c7129e1f Refactoring: Extract checkMongoDB function 2019-02-05 06:43:36 +09:00
3709ba95cd Improve doc 2019-02-05 06:29:56 +09:00
4162981081 アニメーション停止箇所の追加 (#4138) 2019-02-05 06:22:39 +09:00
7b7359fbdc [Client] Fix bug 2019-02-05 06:12:41 +09:00
70c01c52a8 Update Vue to 2.6 🚀 2019-02-05 06:07:23 +09:00
443006c868 Update terser-webpack-plugin requirement from 1.2.1 to 1.2.2 (#4137)
Updates the requirements on [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin) to permit the latest version.
- [Release notes](https://github.com/webpack-contrib/terser-webpack-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/terser-webpack-plugin/commits/v1.2.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-05 05:20:10 +09:00
7c1db1fea5 New Crowdin translations (#4130)
* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (English)
2019-02-05 04:58:07 +09:00
7c2b704bef Fix CHANGELOG 2019-02-05 04:23:28 +09:00
368c3f1e29 Update CHANGELOG.md 2019-02-05 04:22:24 +09:00
dd39d6ea37 Better key name 2019-02-05 04:09:44 +09:00
ef618b2431 [Client] Increase font size a little in the Deck view
Resolve #1821
2019-02-05 04:01:50 +09:00
861302f0fd アニメーション画像を無効にする際、サーバーサイドではなくクライアントサイドでURLを変更するように 2019-02-05 03:51:54 +09:00
f014b7ae0e アニメーションを自動再生しないオプション (#4131)
* Refactor

* settings

* Media Proxy

* Replace API response
2019-02-05 03:01:36 +09:00
00b2d89f1a Refactor: Better type definition 2019-02-05 01:52:09 +09:00
5410efe9ca Refactoring 2019-02-05 01:31:02 +09:00
1d814ba0e1 個別に投稿のウォッチ/ウォッチ解除をできるように
Resolve #161
2019-02-05 01:24:44 +09:00
c107333f56 [API] お気に入り状態は投稿情報に含めないように統一 2019-02-05 01:11:06 +09:00
9595a56346 Revert "Update load.ts"
This reverts commit cf9e8ed39e, commit 67792fcb5e, and commit c7e8c27ce6.
2019-02-04 22:30:24 +09:00
06707705bf Add dummy option for some libraries 2019-02-04 19:41:31 +09:00
68ee9a008e Resolve #4121 (#4122)
* Resolve #4121

* Update tslint.json
2019-02-04 18:27:45 +09:00
3a035c481e Fix fusion 2019-02-04 16:50:14 +09:00
23a0aead9f Update config.yml
Redis なしが帰ってきたぞっ!
2019-02-04 16:41:57 +09:00
6cd41f9860 Initialize queue only if queue is enabled (#4125) 2019-02-04 16:41:53 +09:00
baf861ac79 Update __MISSKEY_HEAD 2019-02-04 16:41:11 +09:00
0ae1190c08 Add --disable-queue option 2019-02-04 13:37:50 +09:00
d3b3426ebe Enable job queue
Resolve #3216
2019-02-04 13:35:58 +09:00
4982ea8f14 Add --verbose option 2019-02-04 12:14:07 +09:00
3be89e9702 Better logging 2019-02-04 12:09:59 +09:00
4275af2324 Make Logger#log method private 2019-02-04 11:51:23 +09:00
84d42be090 Fix MongoDB connectivity checking 2019-02-04 11:48:59 +09:00
c4c7783691 [Server] Enable slow option 2019-02-04 10:03:49 +09:00
d6dba7fd71 Update dependencies 🚀 2019-02-04 09:56:48 +09:00
30b1b1a5ed Fix imports 2019-02-04 09:37:15 +09:00
90b6688057 Update apexcharts requirement from 2.5.1 to 3.2.1 (#4124)
Updates the requirements on [apexcharts](https://github.com/apexcharts/apexcharts.js) to permit the latest version.
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Changelog](https://github.com/apexcharts/apexcharts.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/apexcharts/apexcharts.js/commits/v3.2.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-04 09:29:47 +09:00
b536ee4dcd Add collaborators credit 2019-02-04 09:09:45 +09:00
11101a6aca Better error log of WebFinger 2019-02-04 09:06:13 +09:00
b4a3e5aa4f Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-02-04 09:02:27 +09:00
874c0eae6a Better error log of WebFinger 2019-02-04 09:02:23 +09:00
9950b6fbc6 Update tslint-sonarts requirement from 1.8.0 to 1.9.0 (#3978)
Updates the requirements on [tslint-sonarts](https://github.com/SonarSource/SonarTS) to permit the latest version.
- [Release notes](https://github.com/SonarSource/SonarTS/releases)
- [Commits](https://github.com/SonarSource/SonarTS/commits/v1.9.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-02-04 07:16:01 +09:00
42d6ed62f6 New translations ja-JP.yml (English) (#4120) 2019-02-04 07:01:19 +09:00
c7e8c27ce6 Fix bug
C#っぽく使ってしまっていた。
2019-02-04 02:14:18 +09:00
67792fcb5e Update load.ts 2019-02-04 02:09:41 +09:00
353fc18f19 Merge branch 'develop' into acid-chicken-patch-10 2019-02-04 02:06:46 +09:00
cf9e8ed39e Update load.ts 2019-02-04 02:06:08 +09:00
beb1b570d4 New translations ja-JP.yml (Polish) (#4119) 2019-02-04 01:52:39 +09:00
ba1b5a8ede Update README.md 2019-02-04 01:51:01 +09:00
99d8d0a484 Create type definition for '*/const.json' (#4118) 2019-02-04 01:47:12 +09:00
5891135ac1 Create type definition for ./locales (#4117) 2019-02-04 01:46:59 +09:00
c4f7491322 Revert "Create new type definition for 'is-url' (#4013)"
This reverts commit 014b58cb40.
2019-02-04 01:30:33 +09:00
206b57b962 New translations ja-JP.yml (Polish) (#4116) 2019-02-04 01:22:37 +09:00
1b0e03704e New translations ja-JP.yml (Polish) (#4115) 2019-02-04 01:13:39 +09:00
8b71006fbe Bye 'is-url' 2019-02-04 00:09:24 +09:00
8f2f4b6d2d Add missing semicolons 2019-02-03 23:52:46 +09:00
6e0c055faf Module 'jsdom' as import syntax (#4016) 2019-02-03 23:49:00 +09:00
893a3b527d Create type definition for 'os-utils' (#4050) 2019-02-03 23:41:27 +09:00
fe13c17fcb Create type definition for 'langmap' (#4059)
* Create type definition for 'langmap'

* Follow lint
2019-02-03 23:41:05 +09:00
5049870b6e Create type definition for 'koa-slow' (#4072) 2019-02-03 23:01:03 +09:00
ce576dea8f Create type definition for 'recaptcha-promise' (#4068) 2019-02-03 22:21:55 +09:00
ceda3dd72a Create new type definition for 'escape-regexp' (#4058) 2019-02-03 22:21:47 +09:00
014b58cb40 Create new type definition for 'is-url' (#4013)
* Create new type definition for 'is-url'

* [Client] Resolve #3638

* 10.79.1

* New translations ja-JP.yml (Korean)

* Add missing semicolon

* Remove file-loader from dependencies (#4025)

* Update README.md [AUTOGEN] (#4028)

* Update README.md [AUTOGEN] (#4030)

* Add visibility test (#4029)

* Update ws requirement from 6.1.2 to 6.1.3 (#4027)

Updates the requirements on [ws](https://github.com/websockets/ws) to permit the latest version.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/commits/6.1.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Module 'web-push' as import syntax (#4017)

* Fix visibility test (#4031)

* Upgrade gulp version to 4.0.0

* Prevent typescript errors from crashing

* Remove duplicated dependencies

* Use parallel and task to specify dependencies

* Sort tasks by topological ordering

* リプライ/メンションされていれば非フォロワーへのフォロワー限定でも参照可能に (#4033)

* 非メンション/リプライ投稿がmentionsにあるかどうかはvisibilityと関係ないので削除

* リプライ/メンションされていれば非フォロワーでも参照可能に

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Simplified)

* Fix #4034 (#4037)

* Fix #4034

* improve

* Module 'crypto' as import syntax (#4011)

* Extract MFM normalize function

* Extract MFM types

* Rename html to toHtml

* Rename html-to-mfm to fromHtml

* Merge plainParser into mfm

* Extract parsePlain function

* Rename analyze to parse in MFM tests

* Update @types/mongodb requirement from 3.1.18 to 3.1.19 (#4041)

Updates the requirements on [@types/mongodb](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Update vue-svg-inline-loader requirement from 1.2.7 to 1.2.10 (#4040)

Updates the requirements on [vue-svg-inline-loader](https://github.com/oliverfindl/vue-svg-inline-loader) to permit the latest version.
- [Release notes](https://github.com/oliverfindl/vue-svg-inline-loader/releases)
- [Commits](https://github.com/oliverfindl/vue-svg-inline-loader/commits/v1.2.10)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Avoid export default

* Rename parser to language

* Fix import

* Introduce silence (#4043)

* Introduce silence

* Fix icon

* delete unnecessary key (#4045)

* delete unnecessary key

* Add note

* Update CHANGELOG.md

* [ActivityPub] Use microformats on mentions

To avoid pointless link previews.
see: https://misskey.xyz/notes/5c51ab5c2d85f2003248eddc

* Create type definition for '*/package.json' (#4014)

* Create type definition for '*/package.json'

* Update tsconfig.json

* Update index.ts

* Create type definition for 'is-root' (#4001)

* Update @types/sharp requirement from 0.21.0 to 0.21.1

Updates the requirements on [@types/sharp](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Add multiline math syntax

Co-authored-by: syuilo <syuilotan@yahoo.co.jp>

* New translations ja-JP.yml (Catalan)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (English)

* Create type definition for 'is-root'

* [MFM] Add spin syntax

Resolve #4003

* [MFM] Add flip syntax

Resolve #4002

* Fix test

* Update CHANGELOG.md

* 10.79.0

* Update @fortawesome/free-regular-svg-icons requirement (#3963)

Updates the requirements on [@fortawesome/free-regular-svg-icons](https://github.com/FortAwesome/Font-Awesome) to permit the latest version.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/master/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/commits/5.6.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Update @types/webpack requirement from 4.4.21 to 4.4.24 (#3976)

Updates the requirements on [@types/webpack](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Update @types/js-yaml requirement from 3.11.4 to 3.12.0 (#3977)

Updates the requirements on [@types/js-yaml](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Update debug requirement from 4.1.0 to 4.1.1 (#3964)

Updates the requirements on [debug](https://github.com/visionmedia/debug) to permit the latest version.
- [Release notes](https://github.com/visionmedia/debug/releases)
- [Commits](https://github.com/visionmedia/debug/commits/4.1.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (French)

* [MFM] spinの中でflipを使えるように

* Add jump syntax (#4007)

* Add jump syntax

* Fix typo: spin -> jump

* Fix typo

* [MFM] Resolve #4009

* Module 'nprogress' as import syntax (#4012)

* 🎨

* [Client] Fix #4008

* Use yarn instead of npm on CircleCI

* touch yarn.lock

* [Client] Resolve #3638

* 10.79.1

* New translations ja-JP.yml (Korean)

* Add missing semicolon

* Remove file-loader from dependencies (#4025)

* Update README.md [AUTOGEN] (#4028)

* Update README.md [AUTOGEN] (#4030)

* Add visibility test (#4029)

* Update ws requirement from 6.1.2 to 6.1.3 (#4027)

Updates the requirements on [ws](https://github.com/websockets/ws) to permit the latest version.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/commits/6.1.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Module 'web-push' as import syntax (#4017)

* Fix visibility test (#4031)

* Upgrade gulp version to 4.0.0

* Prevent typescript errors from crashing

* Remove duplicated dependencies

* Use parallel and task to specify dependencies

* Sort tasks by topological ordering

* リプライ/メンションされていれば非フォロワーへのフォロワー限定でも参照可能に (#4033)

* 非メンション/リプライ投稿がmentionsにあるかどうかはvisibilityと関係ないので削除

* リプライ/メンションされていれば非フォロワーでも参照可能に

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Chinese Simplified)

* Fix #4034 (#4037)

* Fix #4034

* improve

* Module 'crypto' as import syntax (#4011)

* Extract MFM normalize function

* Extract MFM types

* Rename html to toHtml

* Rename html-to-mfm to fromHtml

* Merge plainParser into mfm

* Extract parsePlain function

* Rename analyze to parse in MFM tests

* Update @types/mongodb requirement from 3.1.18 to 3.1.19 (#4041)

Updates the requirements on [@types/mongodb](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Update vue-svg-inline-loader requirement from 1.2.7 to 1.2.10 (#4040)

Updates the requirements on [vue-svg-inline-loader](https://github.com/oliverfindl/vue-svg-inline-loader) to permit the latest version.
- [Release notes](https://github.com/oliverfindl/vue-svg-inline-loader/releases)
- [Commits](https://github.com/oliverfindl/vue-svg-inline-loader/commits/v1.2.10)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Avoid export default

* Rename parser to language

* Fix import

* Introduce silence (#4043)

* Introduce silence

* Fix icon

* Update is-root.d.ts

* Update index.ts

* Create type definition for 'is-root'

* Update is-root.d.ts

* Update index.ts

* Fix path

refs: 7e3a8d56e6

* Re-fix path

refs: 4bb4903ee5, 7e3a8d56e6

*  Do not import as pack from AP renderer  (#4048)

* Do not import as pack from AP renderer

* rename

* Simplify MFM (#4046)

* [MFM] Make some syntax block

Resolve #3508

* [MFM] Better syntax parsing

Allow nesting by same tag

* [Client] MFMの制限を緩和

* 🎨

* Update CHANGELOG.md

* 10.80.0

* Update is-url.d.ts
2019-02-03 22:21:36 +09:00
b4859be098 Improve log readability 2019-02-03 21:42:52 +09:00
df54da9510 Fix type declaretion 2019-02-03 20:32:46 +09:00
b97f788d71 Display version in logo 2019-02-03 20:31:35 +09:00
edd1baa9f4 🎨 2019-02-03 20:23:53 +09:00
4a23ebe534 Refactoring 2019-02-03 20:10:20 +09:00
64c1075b06 Remember the media playback volume (#4089)
* Remember the media playback volume

* fix
2019-02-03 19:33:23 +09:00
217e4ee39c New translations ja-JP.yml (Korean) (#4110) 2019-02-03 19:13:56 +09:00
7e2a7cdff8 Update README.md [AUTOGEN] (#4111) 2019-02-03 19:13:41 +09:00
225 changed files with 1933 additions and 745 deletions

View File

@ -2,7 +2,7 @@
# __MISSKEY_BEARER_TOKEN=
# __MISSKEY_CAMPAIGN_ID=
# __MISSKEY_GITHUB_TOKEN=
# __MISSKEY_HEAD=acid-chicken:patch-autogen
# __MISSKEY_HEAD=syuilo:patch-autogen
# __MISSKEY_REPO=syuilo/misskey
# __MISSKEY_BRANCH=develop
test "$(curl -LSs -w '\n' -- "https://api.github.com/repos/$REPO/pulls?access_token=$__MISSKEY_GITHUB_TOKEN" | jq -r -f check_pr.jq | grep $__MISSKEY_HEAD)" && exit 1

View File

@ -134,12 +134,14 @@ workflows:
only:
- l10n_develop
- imgbot
- patch-autogen
- build:
filters:
branches:
ignore:
- l10n_develop
- imgbot
- patch-autogen
- test:
requires:
- build
@ -149,13 +151,20 @@ workflows:
# - master
- l10n_develop
- imgbot
- patch-autogen
- test:
without_redis: "true"
requires:
- build
filters:
# branches:
# only: master
branches:
only: master
ignore:
# - master
- l10n_develop
- imgbot
- patch-autogen
# - docker:
# filters:
# branches:

View File

@ -1,6 +1,21 @@
ChangeLog
=========
10.82.2
----------
* ジョブキューの動作を修正
10.82.1
----------
* クラスタリング環境でのジョブキューの動作を修正
* その他の軽微な改善
10.82.0
----------
* 自分の投稿情報をエクスポートできるように
* アニメーションする画像を再生しないで表示するオプションを実装
* 個別に投稿のウォッチ/ウォッチ解除をできるように
10.81.0
----------
* 動画のサムネイルを作成するように

View File

@ -12,7 +12,6 @@ RUN unlink /usr/bin/free
RUN apk add --no-cache \
autoconf \
automake \
ffmpeg \
file \
g++ \
gcc \
@ -36,7 +35,9 @@ RUN node-gyp configure \
FROM base AS runner
RUN apk add --no-cache tini
RUN apk add --no-cache \
ffmpeg \
tini
ENTRYPOINT ["/sbin/tini", "--"]
COPY --from=builder /misskey/node_modules ./node_modules

View File

@ -61,6 +61,10 @@ Organize and store your files! Want to post a picture you have already uploaded?
...and more! Experience Misskey with your own eyes at [misskey.xyz](https://misskey.xyz) or join one of the [other instances](https://joinmisskey.github.io/) that are available.
:new: What's new
----------------------------------------------------------------
Please see the [Release notes](./CHANGELOG.md).
:package: Create your own instance
----------------------------------------------------------------
Please see the [Setup and Installation Guide](./docs/setup.en.md).
@ -85,12 +89,11 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
</tr>
</table>
:heart: Backers & Sponsors
:heart: Backers
----------------------------------------------------------------
<!-- PATREON_START -->
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/1?token-time=2145916800&token-hash=WeuDzzz24cRXJogyIkU-mxARqkdyms-rcZKbO-GpGjw%3D" alt="weep" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/12059069" alt="naga_rus" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=prtYqPOiSHBulhM7NU0VzMaWx39-9ntdq25b6kafDNA%3D" alt="negao" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/3?token-time=2145916800&token-hash=c8HeVqLtmdgH-gSBJg8i10gmOcwllM87MDHeznl3el0%3D" alt="Melilot" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
@ -99,7 +102,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=1FlxS9MEgmNGH_RHUVHbO5hIXB5I1z0lvA33CTvYvjA%3D" alt="gutfuckllc" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
<td><a href="https://www.patreon.com/user?u=12059069">naga_rus</a></td>
<td><a href="https://www.patreon.com/negao">negao</a></td>
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
@ -138,7 +140,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
</tr></table>
**Last updated:** Tue, 29 Jan 2019 04:42:06 UTC
**Last updated:** Sun, 03 Feb 2019 10:13:06 UTC
<!-- PATREON_END -->
:four_leaf_clover: Copyright

View File

@ -29,6 +29,7 @@ Please install and setup these softwares:
* [Redis](https://redis.io/)
* Redis is optional, but we strongly recommended to install it
* [Elasticsearch](https://www.elastic.co/) - required to enable the search feature
* [FFmpeg](https://www.ffmpeg.org/)
*3.* Setup MongoDB
----------------------------------------------------------------
@ -54,6 +55,11 @@ As root:
*6.* Build Misskey
----------------------------------------------------------------
Before build, you need to set `NODE_ENV` to `production`. like this:
* Linux: `export NODE_ENV=production`
* Windows (PowerShell): `$env:NODE_ENV="production"`
* Windows (CMD): `set NODE_ENV=production`
Build misskey with the following:
`npm run build`

View File

@ -29,6 +29,7 @@ Installez les paquets suivants :
* [Redis](https://redis.io/)
* Redis est optionnel mais nous vous recommandons vivement de l'installer
* [Elasticsearch](https://www.elastic.co/) - requis pour pouvoir activer la fonctionnalité de recherche
* [FFmpeg](https://www.ffmpeg.org/)
*3.* Paramètrage de MongoDB
----------------------------------------------------------------

View File

@ -32,9 +32,11 @@ adduser --disabled-password --disabled-login misskey
* 具体的には、Redisをインストールしないと、次の事が出来なくなります:
* Misskeyプロセスを複数起動しての負荷分散
* レートリミット
* ジョブキュー
* Twitter連携
* [Elasticsearch](https://www.elastic.co/)
* 検索機能を有効にするためにはインストールが必要です。
* [FFmpeg](https://www.ffmpeg.org/)
*3.* MongoDBの設定
----------------------------------------------------------------
@ -60,6 +62,11 @@ adduser --disabled-password --disabled-login misskey
*6.* Misskeyのビルド
----------------------------------------------------------------
ビルドする前に、`NODE_ENV``production`にする必要があります。例:
* Linux: `export NODE_ENV=production`
* Windows (PowerShell): `$env:NODE_ENV="production"`
* Windows (CMD): `set NODE_ENV=production`
次のコマンドでMisskeyをビルドしてください:
`npm run build`

1
index.js Normal file
View File

@ -0,0 +1 @@
require('./built');

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "お気に入り"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "ピン留め"
unpin: "ピン留め解除"
delete: "削除"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "Verifizierter Benutzer"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "Diese Notiz favorisieren"
unfavorite: "Aus Favoriten entfernen"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "An die Profilseite pinnen"
unpin: "ピン留め解除"
delete: "Löschen"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -8,10 +8,10 @@ common:
about: "Thank you for finding Misskey. Misskey is a <b>decentralized microblogging platform</b> born on Earth. Since it exists within the Fediverse (a universe where various social media platforms are organized), it is mutually linked with other social media platforms. Why don't you take a short break from the hustle and bustle of the city, and dive into a new Internet?"
intro:
title: "What is Misskey?"
about: "Misskey is an open-source <b>decentralized microblogging service</b>. Sophisticated fully customizable UI, varieties of reactions for posts, free file storage providing an integrated management system and other advanced functions are available. In addition, Misskey connects to a network system called the “Fediverse” enables us to communicate with users on other SNSs. For example, when you post something it will be sent not only to Misskey but also Mastodon and Pleroma. Just imagine that the planet is sending a radio transmission to other planet to communicate."
about: "Misskey is an open-source, <b>decentralized microblogging service</b>. Sophisticated, fully customizable UI, varieties of reactions for posts, free file storage providing an integrated management system and other advanced features are available. In addition, Misskey connects to a network system called the “Fediverse”, that enables us to communicate with users on other SNSs. For example, when you post something, it will be sent not only to Misskey, but also to Mastodon, Osada and Pleroma. Just imagine that the planet is sending a radio transmission to another planet to communicate."
features: "Features"
rich-contents: "Post"
rich-contents-desc: "Just post your idea, hot topics and anything you want to share. You may want to decorate your words, attach your favorite pictures, send files including movies and create a poll - those are the things you can do on Misskey!"
rich-contents-desc: "Just post your idea, hot topics, and anything you want to share. You may want to decorate your words, attach your favorite pictures, send files, including videos, or create a poll - those are some of the things you can do with Misskey!"
reaction: "Reactions"
reaction-desc: "Easiest way to tell your emotions. Misskey allows you to add various type of reactions to others post. The emotional experience on Misskey will never be on other SNSs which only able to push “likes”."
ui: "Interface"
@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "Use avatar as a stone in reversi"
verified-user: "Verified account"
disable-animated-mfm: "Disable animated texts in a post"
disable-showing-animated-images: "Do not play animated images"
suggest-recent-hashtags: "Suggest recently used hashtags within the post composition area"
always-show-nsfw: "Always show NSFW contents"
always-mark-nsfw: "Always mark posts with media attachments as NSFW"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "Copy link"
favorite: "Favorite this note"
unfavorite: "Unfavorite"
watch: "Watch"
unwatch: "Unwatch"
pin: "Pin to your profile"
unpin: "Unpin"
delete: "Delete"
@ -360,8 +363,8 @@ common/views/components/user-menu.vue:
report-abuse: "Report abuse"
report-abuse-detail: "What kind of nuisance did you encounter?"
report-abuse-reported: "The issue has been reported to the administrator. Your cooperation is much appreciated."
silence: "Make Silence"
unsilence: "Unsilence"
silence: "Mute"
unsilence: "Unmute"
suspend: "Suspend"
unsuspend: "Unsuspend"
common/views/components/poll.vue:
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "Email Address"
email-verified: "Your email has been verified."
email-not-verified: "Email address is not confirmed. Please check your inbox."
export: "Export"
export-notes: "Export all of your Notes"
export-requested: "You have requested an export. This may take a while. After the export is complete, the resulting file will be added to the drive."
common/views/components/user-list-editor.vue:
users: "User"
rename: "Rename list"
@ -1147,8 +1153,8 @@ admin/views/users.vue:
unsuspend: "Unsuspend"
unsuspend-confirm: "Are you sure you want to unsuspend this account?"
unsuspended: "The user has successfully unsuspended."
make-silence: "Make Silence"
unmake-silence: "Unmake Silence"
make-silence: "Mute"
unmake-silence: "Unmute"
verify: "Verify account"
verify-confirm: "Do you want this to be a verified account?"
verified: "The account is now being verified"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "Cuenta verificada"
disable-animated-mfm: "Desactivar texto animado en una publicación"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "Copiar enlace"
favorite: "Me gusta esta nota"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "Fijar en el perfil"
unpin: "ピン留め解除"
delete: "Borrar"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "Correo electrónico"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "Usuarios"
rename: "リスト名を変更"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "Utiliser lavatar comme pion dans Reversi"
verified-user: "Compte vérifié"
disable-animated-mfm: "Désactiver les textes animés dans les publications"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "Suggérer les hashtags récemment utilisés dans le champs de saisie"
always-show-nsfw: "Toujours afficher les contenus sensibles"
always-mark-nsfw: "Toujours marquer les notes ayant des attachements comme sensibles"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "Copier le lien"
favorite: "Mettre cette note en favoris"
unfavorite: "Retirer des favoris"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "Épingler sur votre profil"
unpin: "Désépingler"
delete: "Supprimer"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "Adresse de courrier électronique"
email-verified: "Ladresse du courrier électronique a été vérifiée."
email-not-verified: "Adresse de courriel nest pas confirmée. Veuillez vérifier votre boite de réception."
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "Utilisateur·rice"
rename: "Renommer la liste"

5
locales/index.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
type Locale = { [key: string]: string };
declare const locales: { [lang: string]: Locale };
export default locales;

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "お気に入り"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "ピン留め"
unpin: "ピン留め解除"
delete: "削除"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -121,6 +121,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -374,6 +375,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "お気に入り"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "ピン留め"
unpin: "ピン留め解除"
delete: "削除"
@ -554,6 +557,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
@ -1123,6 +1129,7 @@ admin/views/index.vue:
announcements: "お知らせ"
hashtags: "ハッシュタグ"
abuse: "スパム報告"
queue: "ジョブキュー"
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
@ -1134,6 +1141,10 @@ admin/views/dashboard.vue:
this-instance: "このインスタンス"
federated: "連合"
admin/views/queue.vue:
operation: "操作"
remove-all-jobs: "すべてのジョブをクリア"
admin/views/abuse.vue:
title: "スパム報告"
target: "対象"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "アメちゃん付きアカウント"
disable-animated-mfm: "投稿内のちょろちょろ動いてんのを止める"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "閲覧注意?見せたらあかん?そんなん知らんわ、見せろや!"
always-mark-nsfw: "わからんからとりあえずメディアは見せたらあかん"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "お気に入り"
unfavorite: "お気に入りやめる"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "ピン留め"
unpin: "ピン留めやめる"
delete: "ほかす"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "このメールアドレスOKや"
email-not-verified: "メールアドレスが確認されとらん。メールボックスもっぺん見てくれへん?"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "리버시의 돌로 아바타를 사용"
verified-user: "공식 계정"
disable-animated-mfm: "글의 문자 애니메이션을 비활성화"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "최근 해시태그를 글 작성란에 표시"
always-show-nsfw: "항상 열람주의 미디어를 표시"
always-mark-nsfw: "항상 미디어를 열람주의로 설정하여 게시"
@ -129,7 +130,7 @@ common:
show-password: "비밀번호 표시"
do-not-use-in-production: "이것은 개발 빌드입니다. 프로덕션 환경에서 사용하지 마십시오."
user-suspended: "이 사용자는 정지된 상태입니다."
is-remote-user: "このユーザー情報は不正確な可能性があります。"
is-remote-user: "이 사용자 정보는 정확하지 않을 수 있습니다."
is-remote-post: "이 글 정보는 복사본입니다."
view-on-remote: "정확한 정보 보기"
renoted-by: "{user}이(가) 리노트"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "링크 복사"
favorite: "이 노트 즐겨찾기"
unfavorite: "즐겨찾기에서 제거"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "프로필에 고정"
unpin: "프로필에서 고정 해제"
delete: "삭제"
@ -360,10 +363,10 @@ common/views/components/user-menu.vue:
report-abuse: "스팸 신고"
report-abuse-detail: "어떤 스팸 행위를 하고 있습니까?"
report-abuse-reported: "관리자에게 보고되었습니다. 협조해주셔서 감사합니다."
silence: "サイレンス"
unsilence: "サイレンス解除"
suspend: "凍結"
unsuspend: "凍結解除"
silence: "침묵"
unsilence: "침묵 해제"
suspend: "정지"
unsuspend: "정지 해제"
common/views/components/poll.vue:
vote-to: "\"{}\"에 투표하기"
vote-count: "{}표"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "메일 주소"
email-verified: "매일 주소가 확인되었습니다"
email-not-verified: "메일 주소가 확인되지 않았습니다. 받은 편지함을 확인하여 주시기 바랍니다."
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "사용자"
rename: "리스트 이름 바꾸기"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "Deze notitie toevoegen aan favorieten"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "Vastmaken aan profielpagina"
unpin: "ピン留め解除"
delete: "削除"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "Merket som favoritt"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "Fest til profilen din"
unpin: "ピン留め解除"
delete: "Slett"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "Zweryfikowane konto"
disable-animated-mfm: "Wyłącz animowany tekst we wpisach"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "Zawszę pokazuj zawartość NSFW"
always-mark-nsfw: "Zawsze oznaczaj posty z multimediami jako NSFW"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "Skopiuj adres"
favorite: "Dodaj do ulubionych"
unfavorite: "Usuń z ulubionych"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "Przypnij do profilu"
unpin: "Odepnij"
delete: "Usuń"
@ -356,7 +359,7 @@ common/views/components/user-menu.vue:
block: "Zablokuj"
unblock: "Odblokuj"
push-to-list: "Dodaj do listy"
select-list: "リストを選択してください"
select-list: "Wybierz listę"
report-abuse: "Zgłoś nadużycie"
report-abuse-detail: "どのような迷惑行為を行っていますか?"
report-abuse-reported: "管理者に報告されました。ご協力ありがとうございました。"
@ -395,11 +398,11 @@ common/views/components/signin.vue:
token: "Token"
signing-in: "Logowanie…"
signin: "Zaloguj"
or: "または"
or: "lub"
signin-with-twitter: "Zaloguj się za pomocą Twittera"
signin-with-github: "Zaloguj się za pomocą GitHuba"
signin-with-discord: "Zaloguj się za pomocą Discorda"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
login-failed: "Logowanie nie powiodło się. Upewnij się, że podałeś prawidłową nazwę użytkownika i hasło."
common/views/components/signup.vue:
invitation-code: "Kod zaproszenia"
invitation-info: "招待コードをお持ちでない方は、<a href=\"{}\">管理者</a>までご連絡ください。"
@ -472,13 +475,13 @@ common/views/components/visibility-chooser.vue:
local-followers: "Dla śledzących (tylko lokalnie)"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
empty: "Brak popularnych hashtagów"
common/views/components/language-settings.vue:
title: "Język"
pick-language: "Wybierz język"
recommended: "Zalecane"
auto: "Automatyczny"
specify-language: "言語を指定"
specify-language: "Wybierz język"
info: "Musisz odświeżyć stronę, aby zmiany zostały uwzględnione."
common/views/components/profile-editor.vue:
title: "Twój profil"
@ -504,15 +507,18 @@ common/views/components/profile-editor.vue:
upload-failed: "Wysyłanie nie powiodło się"
email: "Ustawienia e-mail"
email-address: "Adres e-mail"
email-verified: "メールアドレスが確認されました"
email-verified: "Twój adres e-mail został zweryfikowany."
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "Użytkownicy"
rename: "Zmień nazwę listy"
delete: "Usuń listę"
remove-user: "Usuń z tej listy"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
delete-are-you-sure: "Usunąć listę \"$1\"?"
deleted: "Usunięto"
common/views/widgets/broadcast.vue:
fetching: "Sprawdzanie"
no-broadcasts: "Brak transmisji"
@ -595,7 +601,7 @@ desktop/views/components/activity.vue:
title: "Aktywność"
toggle: "Przełącz widok"
desktop/views/components/calendar.vue:
title: "{year} {month}"
title: "{year} / {month}"
prev: "Poprzedni miesiąc"
next: "Następny miesiąc"
go: "Naciśnij, aby przejść"
@ -706,7 +712,7 @@ desktop/views/components/note.vue:
add-reaction: "Dodaj reakcję"
undo-reaction: "リアクション解除"
detail: "Szczegóły"
private: "この投稿は非公開です"
private: "Ten wpis jest prywatny"
deleted: "この投稿は削除されました"
desktop/views/components/notes.vue:
error: "Ładowanie nie powiodło się."
@ -1011,7 +1017,7 @@ admin/views/abuse.vue:
target: "対象"
reporter: "報告者"
details: "詳細"
remove-report: "削除"
remove-report: "Usuń"
admin/views/instance.vue:
instance: "インスタンス"
instance-name: "インスタンス名"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "Conta verificada"
disable-animated-mfm: "Desativar texto animado nas publicações"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "常に閲覧注意のメディアを表示する"
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "お気に入り"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "ピン留め"
unpin: "ピン留め解除"
delete: "削除"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
verified-user: "公式アカウント"
disable-animated-mfm: "Отключить анимированный текст в постах"
disable-showing-animated-images: "アニメーション画像を再生しない"
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
always-show-nsfw: "Всегда показывать NSFW контент"
always-mark-nsfw: "Всегда помечать посты с медиафайлами как NSFW"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "リンクをコピー"
favorite: "お気に入り"
unfavorite: "お気に入り解除"
watch: "ウォッチ"
unwatch: "ウォッチ解除"
pin: "ピン留め"
unpin: "ピン留め解除"
delete: "削除"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "メールアドレス"
email-verified: "メールアドレスが確認されました"
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
export: "エクスポート"
export-notes: "すべての投稿のエクスポート"
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
common/views/components/user-list-editor.vue:
users: "ユーザー"
rename: "リスト名を変更"

View File

@ -113,6 +113,7 @@ common:
use-avatar-reversi-stones: "用头像作为黑白棋的棋子"
verified-user: "认证用户"
disable-animated-mfm: "在帖子中禁用动画文本"
disable-showing-animated-images: "不播放动画"
suggest-recent-hashtags: "在帖子表单上显示最近流行的主题标签"
always-show-nsfw: "总是显示 NSFW 的内容"
always-mark-nsfw: "总是用 NSFW 来标记附件"
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
copy-link: "复制链接"
favorite: "收藏这个投稿"
unfavorite: "取消收藏"
watch: "关注"
unwatch: "取消关注"
pin: "固定个人资料"
unpin: "解除固定"
delete: "删除"
@ -506,6 +509,9 @@ common/views/components/profile-editor.vue:
email-address: "电子邮件地址"
email-verified: "电子邮件地址已验证"
email-not-verified: "邮件地址尚未验证。 请检查您的邮箱。"
export: "导出"
export-notes: "导出所有帖子"
export-requested: "导出请求已提交。可能需要花一些时间。导出的文件将保存到网盘中。"
common/views/components/user-list-editor.vue:
users: "用户"
rename: "重命名列表"

View File

@ -1,14 +1,18 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.81.0",
"clientVersion": "2.0.14026",
"version": "10.82.2",
"clientVersion": "2.0.14142",
"codename": "nighthike",
"main": "./built/index.js",
"repository": {
"type": "git",
"url": "https://github.com/syuilo/misskey.git"
},
"main": "./index.js",
"private": true,
"scripts": {
"start": "node ./built",
"debug": "DEBUG=misskey:* node ./built",
"start": "node ./index.js",
"debug": "DEBUG=misskey:* node ./index.js",
"build": "webpack && gulp build",
"webpack": "webpack",
"watch": "webpack --watch",
@ -48,6 +52,7 @@
"@types/is-svg": "3.0.0",
"@types/is-url": "1.2.28",
"@types/js-yaml": "3.12.0",
"@types/jsdom": "12.2.1",
"@types/katex": "0.5.0",
"@types/koa": "2.0.48",
"@types/koa-bodyparser": "5.0.2",
@ -65,7 +70,7 @@
"@types/mkdirp": "0.5.2",
"@types/mocha": "5.2.5",
"@types/mongodb": "3.1.19",
"@types/node": "10.12.18",
"@types/node": "10.12.21",
"@types/nodemailer": "4.6.5",
"@types/nprogress": "0.0.29",
"@types/oauth": "0.9.1",
@ -94,7 +99,7 @@
"@types/websocket": "0.0.40",
"@types/ws": "6.0.1",
"animejs": "3.0.1",
"apexcharts": "2.5.1",
"apexcharts": "3.2.1",
"autobind-decorator": "2.4.0",
"autosize": "4.0.2",
"autwh": "0.1.0",
@ -107,7 +112,7 @@
"chalk": "2.4.2",
"commander": "2.19.0",
"crc-32": "1.2.0",
"css-loader": "1.0.1",
"css-loader": "2.1.0",
"cssnano": "4.1.8",
"dateformat": "3.0.3",
"deep-equal": "1.0.1",
@ -121,7 +126,7 @@
"eslint-plugin-vue": "5.1.0",
"eventemitter3": "3.1.0",
"feed": "2.0.2",
"file-type": "10.7.0",
"file-type": "10.7.1",
"fuckadblock": "3.2.1",
"gulp": "4.0.0",
"gulp-cssnano": "2.1.3",
@ -142,13 +147,12 @@
"insert-text-at-cursor": "0.1.1",
"is-root": "2.0.0",
"is-svg": "3.0.0",
"is-url": "1.2.4",
"js-yaml": "3.12.1",
"jsdom": "13.1.0",
"jsdom": "13.2.0",
"json5": "2.1.0",
"json5-loader": "1.0.1",
"katex": "0.10.0",
"koa": "2.6.2",
"koa": "2.7.0",
"koa-bodyparser": "4.2.1",
"koa-compress": "3.0.0",
"koa-favicon": "2.0.1",
@ -163,12 +167,12 @@
"langmap": "0.0.16",
"loader-utils": "1.2.3",
"lookup-dns-cache": "2.1.0",
"minio": "7.0.3",
"minio": "7.0.5",
"mkdirp": "0.5.1",
"mocha": "5.2.0",
"moji": "0.5.1",
"moment": "2.23.0",
"mongodb": "3.1.10",
"moment": "2.24.0",
"mongodb": "3.1.13",
"monk": "6.0.6",
"ms": "2.1.1",
"nan": "2.12.1",
@ -183,7 +187,7 @@
"portscanner": "2.2.0",
"postcss-loader": "3.0.0",
"prismjs": "1.15.0",
"progress-bar-webpack-plugin": "1.12.0",
"progress-bar-webpack-plugin": "1.12.1",
"promise-any": "0.2.0",
"promise-limit": "2.7.0",
"promise-sequential": "1.1.1",
@ -213,14 +217,14 @@
"summaly": "2.2.0",
"systeminformation": "3.54.0",
"syuilo-password-strength": "0.0.1",
"terser-webpack-plugin": "1.2.1",
"terser-webpack-plugin": "1.2.2",
"textarea-caret": "3.1.0",
"tinycolor2": "1.4.1",
"tmp": "0.0.33",
"ts-loader": "5.3.3",
"ts-node": "7.0.1",
"tslint": "5.12.0",
"tslint-sonarts": "1.8.0",
"tslint-sonarts": "1.9.0",
"typescript": "3.2.4",
"typescript-eslint-parser": "21.0.2",
"uglify-es": "3.3.9",
@ -228,23 +232,23 @@
"uuid": "3.3.2",
"v-animate-css": "0.0.3",
"video-thumbnail-generator": "1.1.3",
"vue": "2.5.17",
"vue": "2.6.2",
"vue-color": "2.7.0",
"vue-content-loading": "1.5.3",
"vue-cropperjs": "3.0.0",
"vue-i18n": "8.8.0",
"vue-js-modal": "1.3.28",
"vue-loader": "15.5.1",
"vue-loader": "15.6.2",
"vue-marquee-text-component": "1.1.1",
"vue-prism-component": "1.1.1",
"vue-router": "3.0.2",
"vue-sequential-entrance": "1.1.3",
"vue-style-loader": "4.1.2",
"vue-svg-inline-loader": "1.2.10",
"vue-template-compiler": "2.5.17",
"vue-template-compiler": "2.6.2",
"vuedraggable": "2.17.0",
"vuewordcloud": "18.7.11",
"vuex": "3.0.1",
"vuex": "3.1.0",
"vuex-persistedstate": "2.5.4",
"web-push": "3.3.3",
"webfinger.js": "2.7.0",

3
src/@types/const.json.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
declare module '*/const.json' {
const copyright: string;
}

View File

@ -8,7 +8,7 @@ declare namespace deepcopy {
valueType: DeepcopyCustomizerValueType) => T;
interface DeepcopyOptions<T> {
customizer: DeepcopyCustomizer<T>
customizer: DeepcopyCustomizer<T>;
}
export function deepcopy<T>(

7
src/@types/escape-regexp.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
declare module 'escape-regexp' {
function escapeRegExp(str: string): string;
namespace escapeRegExp {} // Hack
export = escapeRegExp;
}

14
src/@types/koa-slow.d.ts vendored Normal file
View File

@ -0,0 +1,14 @@
declare module 'koa-slow' {
import { Middleware } from 'koa';
interface ISlowOptions {
url?: RegExp;
delay?: number;
}
function slow(options?: ISlowOptions): Middleware;
namespace slow { } // Hack
export = slow;
}

10
src/@types/langmap.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
declare module 'langmap' {
type Lang = {
nativeName: string;
englishName: string;
};
const langmap: { [lang: string]: Lang };
export = langmap;
}

View File

@ -1,3 +1,5 @@
type Obj = { [key: string]: any };
declare module 'nested-property' {
interface IHasNestedPropertyOptions {
own?: boolean;
@ -9,11 +11,11 @@ declare module 'nested-property' {
export function set<T>(object: T, property: string, value: any): T;
export function get(object: object, property: string): any;
export function get(object: Obj, property: string): any;
export function has(object: object, property: string, options?: IHasNestedPropertyOptions): boolean;
export function has(object: Obj, property: string, options?: IHasNestedPropertyOptions): boolean;
export function hasOwn(object: object, property: string, options?: IHasNestedPropertyOptions): boolean;
export function hasOwn(object: Obj, property: string, options?: IHasNestedPropertyOptions): boolean;
export function isIn(object: object, property: string, objectInPath: object, options?: IIsInNestedPropertyOptions): boolean;
export function isIn(object: Obj, property: string, objectInPath: Obj, options?: IIsInNestedPropertyOptions): boolean;
}

30
src/@types/os-utils.d.ts vendored Normal file
View File

@ -0,0 +1,30 @@
declare module 'os-utils' {
type FreeCommandCallback = (usedmem: number) => void;
type HarddriveCallback = (total: number, free: number, used: number) => void;
type GetProcessesCallback = (result: string) => void;
type CPUCallback = (perc: number) => void;
export function platform(): NodeJS.Platform;
export function cpuCount(): number;
export function sysUptime(): number;
export function processUptime(): number;
export function freemem(): number;
export function totalmem(): number;
export function freememPercentage(): number;
export function freeCommand(callback: FreeCommandCallback): void;
export function harddrive(callback: HarddriveCallback): void;
export function getProcesses(callback: GetProcessesCallback): void;
export function getProcesses(nProcess: number, callback: GetProcessesCallback): void;
export function allLoadavg(): string;
export function loadavg(_time?: number): number;
export function cpuFree(callback: CPUCallback): void;
export function cpuUsage(callback: CPUCallback): void;
}

View File

@ -1,3 +1,10 @@
declare module '*/package.json' {
const version: string;
interface IRepository {
type: string;
url: string;
}
export const name: string;
export const version: string;
export const repository: IRepository;
}

16
src/@types/recaptcha-promise.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
declare module 'recaptcha-promise' {
interface IVerifyOptions {
secret_key?: string;
}
interface IVerify {
(response: string, remoteAddress?: string): Promise<boolean>;
init(options: IVerifyOptions): IVerify;
}
namespace recaptchaPromise {} // Hack
const verify: IVerify;
export = verify;
}

21
src/argv.ts Normal file
View File

@ -0,0 +1,21 @@
import * as program from 'commander';
import * as pkg from '../package.json';
program
.version(pkg.version)
.option('--no-daemons', 'Disable daemon processes (for debbuging)')
.option('--disable-clustering', 'Disable clustering')
.option('--disable-ap-queue', 'Disable creating job queue related to ap')
.option('--disable-queue', 'Disable job queue processing')
.option('--only-queue', 'Pocessing job queue only')
.option('--quiet', 'Suppress all logs')
.option('--verbose', 'Enable all logs')
.option('--slow', 'Delay all requests (for debbuging)')
.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.')
.parse(process.argv);
if (process.env.MK_DISABLE_AP_QUEUE) program.disableApQueue = true;
if (process.env.MK_DISABLE_QUEUE) program.disableQueue = true;
if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true;
export { program };

View File

@ -21,7 +21,7 @@ export type Partial<T> = {
};
type ArrayValue<T> = {
[P in keyof T]: T[P] extends number ? Array<T[P]> : ArrayValue<T[P]>;
[P in keyof T]: T[P] extends number ? T[P][] : ArrayValue<T[P]>;
};
type Span = 'day' | 'hour';
@ -58,7 +58,7 @@ type Log<T extends Obj> = {
/**
* 様々なチャートの管理を司るクラス
*/
export default abstract class Chart<T> {
export default abstract class Chart<T extends Obj> {
protected collection: ICollection<Log<T>>;
protected abstract async getTemplate(init: boolean, latest?: T, group?: any): Promise<T>;
private name: string;

View File

@ -42,7 +42,7 @@
import Vue from 'vue';
import i18n from '../../i18n';
import * as tinycolor from 'tinycolor2';
import * as ApexCharts from 'apexcharts';
import ApexCharts from 'apexcharts';
const limit = 90;

View File

@ -19,7 +19,7 @@
<script lang="ts">
import Vue from 'vue';
import * as ApexCharts from 'apexcharts';
import ApexCharts from 'apexcharts';
export default Vue.extend({
props: ['connection'],

View File

@ -20,6 +20,7 @@
<ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }"><fa icon="home" fixed-width/>{{ $t('dashboard') }}</li>
<li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>{{ $t('instance') }}</li>
<li @click="nav('queue')" :class="{ active: page == 'queue' }"><fa :icon="faTasks" fixed-width/>{{ $t('queue') }}</li>
<li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li>
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
<li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li>
@ -40,6 +41,7 @@
<div class="page">
<div v-if="page == 'dashboard'"><x-dashboard/></div>
<div v-if="page == 'instance'"><x-instance/></div>
<div v-if="page == 'queue'"><x-queue/></div>
<div v-if="page == 'moderators'"><x-moderators/></div>
<div v-if="page == 'users'"><x-users/></div>
<div v-if="page == 'emoji'"><x-emoji/></div>
@ -58,6 +60,7 @@ import i18n from '../../i18n';
import { version } from '../../config';
import XDashboard from "./dashboard.vue";
import XInstance from "./instance.vue";
import XQueue from "./queue.vue";
import XModerators from "./moderators.vue";
import XEmoji from "./emoji.vue";
import XAnnouncements from "./announcements.vue";
@ -65,7 +68,7 @@ import XHashtags from "./hashtags.vue";
import XUsers from "./users.vue";
import XDrive from "./drive.vue";
import XAbuse from "./abuse.vue";
import { faHeadset, faArrowLeft, faShareAlt, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
import { faHeadset, faArrowLeft, faShareAlt, faExclamationCircle, faTasks } from '@fortawesome/free-solid-svg-icons';
import { faGrin } from '@fortawesome/free-regular-svg-icons';
// Detect the user agent
@ -77,6 +80,7 @@ export default Vue.extend({
components: {
XDashboard,
XInstance,
XQueue,
XModerators,
XEmoji,
XAnnouncements,
@ -98,7 +102,8 @@ export default Vue.extend({
faArrowLeft,
faHeadset,
faShareAlt,
faExclamationCircle
faExclamationCircle,
faTasks
};
},
methods: {

View File

@ -0,0 +1,43 @@
<template>
<div>
<ui-card>
<div slot="title">{{ $t('operation') }}</div>
<section>
<ui-button @click="removeAllJobs">{{ $t('remove-all-jobs') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
export default Vue.extend({
i18n: i18n('admin/views/queue.vue'),
data() {
return {
};
},
methods: {
async removeAllJobs() {
const process = async () => {
await this.$root.api('admin/queue/clear');
this.$root.dialog({
type: 'success',
splash: true
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
},
}
});
</script>

View File

@ -62,11 +62,12 @@
}
if (settings && settings.device.lang &&
langs.includes(settings.device.lang)) {
langs.includes(settings.device.lang))
{
lang = settings.device.lang;
}
window.lang = lang;
localStorage.setItem('lang', lang);
//#endregion
//#region Fetch locale data

View File

@ -0,0 +1,9 @@
import { url as instanceUrl } from '../../config';
export function getStaticImageUrl(url: string): string {
const u = new URL(url);
const dummy = `${u.host}${u.pathname}`; // 拡張子がないとキャッシュしてくれないCDNがあるので
let result = `${instanceUrl}/proxy/${dummy}?url=${encodeURIComponent(u.href)}`;
result += '&static=1';
return result;
}

View File

@ -15,6 +15,7 @@
<script lang="ts">
import Vue from 'vue';
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
export default Vue.extend({
props: {
@ -47,6 +48,11 @@ export default Vue.extend({
borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
};
},
url(): string {
return this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(this.user.avatarUrl)
: this.user.avatarUrl;
},
icon(): any {
return {
backgroundColor: this.lightmode
@ -54,7 +60,7 @@ export default Vue.extend({
: this.user.avatarColor && this.user.avatarColor.length == 3
? `rgb(${this.user.avatarColor.join(',')})`
: null,
backgroundImage: this.lightmode ? null : `url(${this.user.avatarUrl})`,
backgroundImage: this.lightmode ? null : `url(${this.url})`,
borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
};
}

View File

@ -18,7 +18,7 @@
import Vue from 'vue';
import i18n from '../../../i18n';
import * as tinycolor from 'tinycolor2';
import * as ApexCharts from 'apexcharts';
import ApexCharts from 'apexcharts';
export default Vue.extend({
i18n: i18n('common/views/components/drive-settings.vue'),

View File

@ -9,6 +9,7 @@
import Vue from 'vue';
// スクリプトサイズがデカい
//import { lib } from 'emojilib';
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
export default Vue.extend({
props: {
@ -54,7 +55,9 @@ export default Vue.extend({
const customEmoji = this.customEmojis.find(x => x.name == this.name);
if (customEmoji) {
this.customEmoji = customEmoji;
this.url = customEmoji.url;
this.url = this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(customEmoji.url)
: customEmoji.url;
} else {
//const emoji = lib[this.name];
//if (emoji) {

View File

@ -11,6 +11,7 @@
:title="media.name"
controls
ref="audio"
@volumechange="volumechange"
preload="metadata" />
</div>
<a class="download" v-else
@ -40,7 +41,17 @@ export default Vue.extend({
return {
hide: true
};
}
},
mounted() {
const audioTag = this.$refs.audio as HTMLAudioElement;
audioTag.volume = this.$store.state.device.mediaVolume;
},
methods: {
volumechange() {
const audioTag = this.$refs.audio as HTMLAudioElement;
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume });
},
},
})
</script>

View File

@ -17,6 +17,7 @@
import Vue from 'vue';
import i18n from '../../../i18n';
import ImageViewer from './image-viewer.vue';
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
export default Vue.extend({
i18n: i18n('common/views/components/media-image.vue'),
@ -36,7 +37,11 @@ export default Vue.extend({
}
computed: {
style(): any {
let url = `url(${this.image.thumbnailUrl})`;
let url = `url(${
this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(this.image.thumbnailUrl)
: this.image.thumbnailUrl
})`;
if (this.$store.state.device.loadRemoteMedia || this.$store.state.device.lightmode) {
url = null;

View File

@ -10,73 +10,91 @@ import i18n from '../../../i18n';
import { url } from '../../../config';
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
import { concat, intersperse } from '../../../../../prelude/array';
import { faCopy } from '@fortawesome/free-regular-svg-icons';
import { faCopy, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/note-menu.vue'),
props: ['note', 'source'],
data() {
return {
isFavorited: false,
isWatching: false
};
},
computed: {
items(): any[] {
return concat(intersperse([null], [
[
[{
icon: 'at',
text: this.$t('mention'),
action: this.mention
}]
],
[
[{
icon: 'info-circle',
text: this.$t('detail'),
action: this.detail
}], [{
icon: faCopy,
text: this.$t('copy-content'),
action: this.copyContent
}], [{
icon: 'link',
text: this.$t('copy-link'),
action: this.copyLink
}], this.note.uri ? [{
icon: 'external-link-square-alt',
text: this.$t('remote'),
action: () => {
window.open(this.note.uri, '_blank');
}
}] : []
],
[
this.note.isFavorited ? [{
icon: 'star',
text: this.$t('unfavorite'),
action: this.unfavorite
}] : [{
icon: 'star',
text: this.$t('favorite'),
action: this.favorite
}], this.note.userId == this.$store.state.i.id ? [
(this.$store.state.i.pinnedNoteIds || []).includes(this.note.id) ? {
icon: 'thumbtack',
text: this.$t('unpin'),
action: this.unpin
} : {
icon: 'thumbtack',
text: this.$t('pin'),
action: this.pin
}
] : []
], [
this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin || this.$store.state.i.isModerator ? [{
icon: ['far', 'trash-alt'],
text: this.$t('delete'),
action: this.del
}] : []
]
].map(concat).filter(x => x.length > 0)));
return [{
icon: 'at',
text: this.$t('mention'),
action: this.mention
}, null, {
icon: 'info-circle',
text: this.$t('detail'),
action: this.detail
}, {
icon: faCopy,
text: this.$t('copy-content'),
action: this.copyContent
}, {
icon: 'link',
text: this.$t('copy-link'),
action: this.copyLink
}, this.note.uri ? {
icon: 'external-link-square-alt',
text: this.$t('remote'),
action: () => {
window.open(this.note.uri, '_blank');
}
} : undefined,
null,
this.isFavorited ? {
icon: 'star',
text: this.$t('unfavorite'),
action: () => this.toggleFavorite(false)
} : {
icon: 'star',
text: this.$t('favorite'),
action: () => this.toggleFavorite(true)
},
this.note.userId != this.$store.state.i.id ? this.isWatching ? {
icon: faEyeSlash,
text: this.$t('unwatch'),
action: () => this.toggleWatch(false)
} : {
icon: faEye,
text: this.$t('watch'),
action: () => this.toggleWatch(true)
} : undefined,
this.note.userId == this.$store.state.i.id ? (this.$store.state.i.pinnedNoteIds || []).includes(this.note.id) ? {
icon: 'thumbtack',
text: this.$t('unpin'),
action: () => this.togglePin(false)
} : {
icon: 'thumbtack',
text: this.$t('pin'),
action: () => this.togglePin(true)
} : undefined,
...(this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin || this.$store.state.i.isModerator ? [
null, {
icon: ['far', 'trash-alt'],
text: this.$t('delete'),
action: this.del
}]
: []
)]
.filter(x => x !== undefined)
}
},
created() {
this.$root.api('notes/state', {
noteId: this.note.id
}).then(state => {
this.isFavorited = state.isFavorited;
this.isWatching = state.isWatching;
});
},
methods: {
mention() {
this.$post({ mention: this.note.user });
@ -102,8 +120,8 @@ export default Vue.extend({
});
},
pin() {
this.$root.api('i/pin', {
togglePin(pin: boolean) {
this.$root.api(pin ? 'i/pin' : 'i/unpin', {
noteId: this.note.id
}).then(() => {
this.$root.dialog({
@ -114,14 +132,6 @@ export default Vue.extend({
});
},
unpin() {
this.$root.api('i/unpin', {
noteId: this.note.id
}).then(() => {
this.destroyDom();
});
},
del() {
this.$root.dialog({
type: 'warning',
@ -138,8 +148,8 @@ export default Vue.extend({
});
},
favorite() {
this.$root.api('notes/favorites/create', {
toggleFavorite(favorite: boolean) {
this.$root.api(favorite ? 'notes/favorites/create' : 'notes/favorites/delete', {
noteId: this.note.id
}).then(() => {
this.$root.dialog({
@ -150,8 +160,8 @@ export default Vue.extend({
});
},
unfavorite() {
this.$root.api('notes/favorites/delete', {
toggleWatch(watch: boolean) {
this.$root.api(watch ? 'notes/watching/create' : 'notes/watching/delete', {
noteId: this.note.id
}).then(() => {
this.$root.dialog({

View File

@ -87,6 +87,14 @@
<ui-button @click="updateEmail()">{{ $t('save') }}</ui-button>
</div>
</section>
<section>
<header>{{ $t('export') }}</header>
<div>
<ui-button @click="exportNotes()">{{ $t('export-notes') }}</ui-button>
</div>
</section>
</ui-card>
</template>
@ -252,6 +260,15 @@ export default Vue.extend({
email: this.email == '' ? null : this.email
});
});
},
exportNotes() {
this.$root.api('i/export-notes', {});
this.$root.dialog({
type: 'info',
text: this.$t('export-requested')
});
}
}
});

View File

@ -119,11 +119,11 @@ export default Vue.extend({
font-size 16px
cursor pointer
transition inherit
color var(--text)
> span
display block
line-height 20px
color var(--text)
transition inherit
> p

View File

@ -5,9 +5,9 @@
<p :class="$style.fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<div :class="$style.stream" v-if="!fetching && images.length > 0">
<div v-for="image in images"
<div v-for="(image, i) in images" :key="i"
:class="$style.img"
:style="`background-image: url(${image.thumbnailUrl || image.url})`"
:style="`background-image: url(${thumbnail(image)})`"
draggable="true"
@dragstart="onDragstart(image, $event)"
></div>
@ -20,6 +20,7 @@
<script lang="ts">
import define from '../../../common/define-widget';
import i18n from '../../../i18n';
import { getStaticImageUrl } from '../../scripts/get-static-image-url';
export default define({
name: 'photo-stream',
@ -77,6 +78,12 @@ export default define({
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('mk_drive_file', JSON.stringify(file));
},
thumbnail(image: any): string {
return this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(image.thumbnailUrl)
: image.thumbnailUrl;
},
}
});
</script>

View File

@ -1,5 +1,4 @@
declare const _LANGS_: string[];
declare const _THEME_COLOR_: string;
declare const _COPYRIGHT_: string;
declare const _VERSION_: string;
declare const _CLIENT_VERSION_: string;
@ -13,7 +12,7 @@ export const hostname = address.hostname;
export const url = address.origin;
export const apiUrl = url + '/api';
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
export const lang = window.lang;
export const lang = localStorage.getItem('lang');
export const langs = _LANGS_;
export const locale = JSON.parse(localStorage.getItem('locale'));
export const copyright = _COPYRIGHT_;

View File

@ -1,7 +1,7 @@
<template>
<div class="mk-media-video-dialog">
<div class="bg" @click="close"></div>
<video :src="video.url" :title="video.name" controls autoplay ref="video"/>
<video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange"/>
</div>
</template>
@ -18,8 +18,9 @@ export default Vue.extend({
duration: 100,
easing: 'linear'
});
const videoTag = this.$refs.video as HTMLVideoElement
const videoTag = this.$refs.video as HTMLVideoElement;
if (this.start) videoTag.currentTime = this.start
videoTag.volume = this.$store.state.device.mediaVolume;
},
methods: {
close() {
@ -30,7 +31,11 @@ export default Vue.extend({
easing: 'linear',
complete: () => this.destroyDom()
});
}
},
volumechange() {
const videoTag = this.$refs.video as HTMLVideoElement;
this.$store.commit('device/set', { key: 'mediaVolume', value: videoTag.volume });
},
}
});
</script>

View File

@ -49,6 +49,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
.qiziqtywpuaucsgarwajitwaakggnisj
display flex
overflow hidden
font-size 0.9em
> .avatar

View File

@ -144,11 +144,12 @@ export default Vue.extend({
.note
margin 0
padding 0
overflow hidden
background var(--face)
border-bottom solid var(--lineWidth) var(--faceDivider)
&.mini
font-size 13px
font-size 14px
> .renote
padding 8px 16px 0 16px

View File

@ -117,6 +117,7 @@
<ui-switch v-model="showReplyTarget">{{ $t('show-reply-target') }}</ui-switch>
<ui-switch v-model="showMaps">{{ $t('show-maps') }}</ui-switch>
<ui-switch v-model="disableAnimatedMfm">{{ $t('@.disable-animated-mfm') }}</ui-switch>
<ui-switch v-model="disableShowingAnimatedImages">{{ $t('@.disable-showing-animated-images') }}</ui-switch>
<ui-switch v-model="remainDeletedNote">{{ $t('remain-deleted-note') }}</ui-switch>
</section>
<section>
@ -516,6 +517,11 @@ export default Vue.extend({
set(value) { this.$store.dispatch('settings/set', { key: 'disableAnimatedMfm', value }); }
},
disableShowingAnimatedImages: {
get() { return this.$store.state.device.disableShowingAnimatedImages; },
set(value) { this.$store.commit('device/set', { key: 'disableShowingAnimatedImages', value }); }
},
remainDeletedNote: {
get() { return this.$store.state.settings.remainDeletedNote; },
set(value) { this.$store.dispatch('settings/set', { key: 'remainDeletedNote', value }); }

View File

@ -15,7 +15,7 @@
import Vue from 'vue';
import XColumn from './deck.column.vue';
import XHashtagTl from './deck.hashtag-tl.vue';
import * as ApexCharts from 'apexcharts';
import ApexCharts from 'apexcharts';
export default Vue.extend({
components: {

View File

@ -99,7 +99,7 @@ import XNotes from './deck.notes.vue';
import XNote from '../../components/note.vue';
import XUserMenu from '../../../../common/views/components/user-menu.vue';
import { concat } from '../../../../../../prelude/array';
import * as ApexCharts from 'apexcharts';
import ApexCharts from 'apexcharts';
const fetchLimit = 10;

View File

@ -3,8 +3,8 @@
<p class="title"><fa icon="camera"/>{{ $t('title') }}</p>
<p class="initializing" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('loading') }}<mk-ellipsis/></p>
<div class="stream" v-if="!fetching && images.length > 0">
<div v-for="image in images" class="img"
:style="`background-image: url(${image.thumbnailUrl})`"
<div v-for="(image, i) in images" :key="i" class="img"
:style="`background-image: url(${thumbnail(image)})`"
></div>
</div>
<p class="empty" v-if="!fetching && images.length == 0">{{ $t('no-photos') }}</p>
@ -14,6 +14,8 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
import { getStaticImageUrl } from '../../../../common/scripts/get-static-image-url';
export default Vue.extend({
i18n: i18n('desktop/views/pages/user/user.photos.vue'),
props: ['user'],
@ -44,7 +46,14 @@ export default Vue.extend({
}
this.fetching = false;
});
}
},
methods: {
thumbnail(image: any): string {
return this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(image.thumbnailUrl)
: image.thumbnailUrl;
},
},
});
</script>

View File

@ -4,7 +4,7 @@ import { EventEmitter } from 'eventemitter3';
import * as uuid from 'uuid';
import initStore from './store';
import { apiUrl, clientVersion as version, lang } from './config';
import { apiUrl, clientVersion as version } from './config';
import Progress from './common/scripts/loading';
import Err from './common/views/components/connect-failed.vue';
@ -172,7 +172,7 @@ export default class MiOS extends EventEmitter {
callback();
// Init service worker
//if (this.shouldRegisterSw) this.registerSw();
if (this.shouldRegisterSw) this.registerSw();
};
// キャッシュがあったとき

View File

@ -6,7 +6,7 @@
<script lang="ts">
import Vue from 'vue';
import * as ApexCharts from 'apexcharts';
import ApexCharts from 'apexcharts';
export default Vue.extend({
props: ['user'],

View File

@ -2,7 +2,7 @@
<div class="mk-note-card">
<a :href="note | notePage">
<header>
<img :src="note.user.avatarUrl" alt="avatar"/>
<img :src="avator" alt="avatar"/>
<h3><mk-user-name :user="note.user"/></h3>
</header>
<div>
@ -16,13 +16,19 @@
<script lang="ts">
import Vue from 'vue';
import summary from '../../../../../misc/get-note-summary';
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
export default Vue.extend({
props: ['note'],
computed: {
text(): string {
return summary(this.note);
}
},
avator(): string {
return this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(this.note.user.avatarUrl)
: this.note.user.avatarUrl;
},
}
});
</script>

View File

@ -40,6 +40,7 @@ export default Vue.extend({
display flex
margin 0
padding 0
overflow hidden
font-size 10px
@media (min-width 350px)

View File

@ -102,6 +102,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
.note
overflow hidden
font-size 12px
border-bottom solid var(--lineWidth) var(--faceDivider)

View File

@ -29,6 +29,7 @@
<ui-switch v-model="useOsDefaultEmojis">{{ $t('@.use-os-default-emojis') }}</ui-switch>
<ui-switch v-model="iLikeSushi">{{ $t('@.i-like-sushi') }}</ui-switch>
<ui-switch v-model="disableAnimatedMfm">{{ $t('@.disable-animated-mfm') }}</ui-switch>
<ui-switch v-model="disableShowingAnimatedImages">{{ $t('@.disable-showing-animated-images') }}</ui-switch>
<ui-switch v-model="suggestRecentHashtags">{{ $t('@.suggest-recent-hashtags') }}</ui-switch>
<ui-switch v-model="alwaysShowNsfw">{{ $t('@.always-show-nsfw') }} ({{ $t('@.this-setting-is-this-device-only') }})</ui-switch>
</section>
@ -313,6 +314,11 @@ export default Vue.extend({
set(value) { this.$store.dispatch('settings/set', { key: 'disableAnimatedMfm', value }); }
},
disableShowingAnimatedImages: {
get() { return this.$store.state.device.disableShowingAnimatedImages; },
set(value) { this.$store.commit('device/set', { key: 'disableShowingAnimatedImages', value }); }
},
showReplyTarget: {
get() { return this.$store.state.settings.showReplyTarget; },
set(value) { this.$store.dispatch('settings/set', { key: 'showReplyTarget', value }); }

View File

@ -1,6 +1,6 @@
<template>
<mk-ui>
<template slot="header" v-if="!fetching"><img :src="user.avatarUrl" alt="">
<template slot="header" v-if="!fetching"><img :src="avator" alt="">
<mk-user-name :user="user"/>
</template>
<main v-if="!fetching">
@ -11,7 +11,7 @@
<div class="body">
<div class="top">
<a class="avatar">
<img :src="user.avatarUrl" alt="avatar"/>
<img :src="avator" alt="avatar"/>
</a>
<button class="menu" ref="menu" @click="menu"><fa icon="ellipsis-h"/></button>
<mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
@ -82,6 +82,7 @@ import parseAcct from '../../../../../misc/acct/parse';
import Progress from '../../../common/scripts/loading';
import XUserMenu from '../../../common/views/components/user-menu.vue';
import XHome from './user/home.vue';
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
export default Vue.extend({
i18n: i18n('mobile/views/pages/user.vue'),
@ -99,6 +100,11 @@ export default Vue.extend({
age(): number {
return age(this.user.profile.birthday);
},
avator(): string {
return this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(this.user.avatarUrl)
: this.user.avatarUrl;
},
style(): any {
if (this.user.bannerUrl == null) return {};
return {

View File

@ -2,9 +2,9 @@
<div class="root photos">
<p class="initializing" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<div class="stream" v-if="!fetching && images.length > 0">
<a v-for="image in images"
<a v-for="(image, i) in images" :key="i"
class="img"
:style="`background-image: url(${image.media.thumbnailUrl})`"
:style="`background-image: url(${thumbnail(image.media)})`"
:href="image.note | notePage"
></a>
</div>
@ -15,6 +15,7 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
import { getStaticImageUrl } from '../../../../common/scripts/get-static-image-url';
export default Vue.extend({
i18n: i18n('mobile/views/pages/user/home.photos.vue'),
@ -50,7 +51,14 @@ export default Vue.extend({
}
this.fetching = false;
});
}
},
methods: {
thumbnail(image: any): string {
return this.$store.state.device.disableShowingAnimatedImages
? getStaticImageUrl(image.thumbnailUrl)
: image.thumbnailUrl;
},
},
});
</script>

View File

@ -3,7 +3,6 @@ import createPersistedState from 'vuex-persistedstate';
import * as nestedProperty from 'nested-property';
import MiOS from './mios';
import { hostname } from './config';
import { erase } from '../../prelude/array';
import getNoteSummary from '../../misc/get-note-summary';
@ -56,6 +55,7 @@ const defaultDeviceSettings = {
themes: [],
enableSounds: true,
soundVolume: 0.5,
mediaVolume: 0.5,
lang: null,
preventUpdate: false,
debug: false,
@ -69,7 +69,8 @@ const defaultDeviceSettings = {
mobileNotificationPosition: 'bottom',
deckTemporaryColumn: null,
deckDefault: false,
useOsDefaultEmojis: false
useOsDefaultEmojis: false,
disableShowingAnimatedImages: false
};
export default (os: MiOS) => new Vuex.Store({

View File

@ -6,7 +6,6 @@ import * as fs from 'fs';
import { URL } from 'url';
import * as yaml from 'js-yaml';
import { Source, Mixin } from './types';
import isUrl = require('is-url');
import * as pkg from '../../package.json';
/**
@ -26,10 +25,7 @@ export default function load() {
const mixin = {} as Mixin;
// Validate URLs
if (!isUrl(config.url)) throw `url="${config.url}" is not a valid URL`;
const url = new URL(config.url);
const url = validateUrl(config.url);
config.url = normalizeUrl(config.url);
mixin.host = url.host;
@ -51,6 +47,21 @@ export default function load() {
return Object.assign(config, mixin);
}
function tryCreateUrl(url: string) {
try {
return new URL(url);
} catch (e) {
throw `url="${url}" is not a valid URL.`;
}
}
function validateUrl(url: string) {
const result = tryCreateUrl(url);
if (result.pathname.replace('/', '').length) throw `url="${url}" is not a valid URL, has a pathname.`;
if (!url.includes(result.host)) throw `url="${url}" is not a valid URL, has an invalid hostname.`;
return result;
}
function normalizeUrl(url: string) {
return url.endsWith('/') ? url.substr(0, url.length - 1) : url;
}

View File

@ -3,7 +3,7 @@ import * as sysUtils from 'systeminformation';
import * as diskusage from 'diskusage';
import * as Deque from 'double-ended-queue';
import Xev from 'xev';
const osUtils = require('os-utils');
import * as osUtils from 'os-utils';
const ev = new Xev();

View File

@ -12,9 +12,6 @@ import chalk from 'chalk';
import * as portscanner from 'portscanner';
import * as isRoot from 'is-root';
import Xev from 'xev';
import * as program from 'commander';
import * as sysUtils from 'systeminformation';
import mongo, { nativeDbConn } from './db/mongodb';
import Logger from './misc/logger';
import serverStats from './daemons/server-stats';
@ -23,27 +20,26 @@ import loadConfig from './config/load';
import { Config } from './config/types';
import { lessThan } from './prelude/array';
import * as pkg from '../package.json';
import { program } from './argv';
import { checkMongoDB } from './misc/check-mongodb';
import { showMachineInfo } from './misc/show-machine-info';
const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta');
const clusterLog = logger.createSubLogger('cluster', 'orange');
const ev = new Xev();
//#region Command line argument definitions
program
.version(pkg.version)
.option('--no-daemons', 'Disable daemon processes (for debbuging)')
.option('--disable-clustering', 'Disable clustering')
.option('--quiet', 'Suppress all logs')
.parse(process.argv);
//#endregion
/**
* Init process
*/
function main() {
process.title = `Misskey (${cluster.isMaster ? 'master' : 'worker'})`;
if (program.onlyQueue) {
queueMain();
return;
}
if (cluster.isMaster || program.disableClustering) {
masterMain();
@ -62,28 +58,51 @@ function main() {
}
}
function greet() {
if (!program.quiet) {
//#region Misskey logo
const v = `v${pkg.version}`;
console.log(' _____ _ _ ');
console.log(' | |_|___ ___| |_ ___ _ _ ');
console.log(' | | | | |_ -|_ -| \'_| -_| | |');
console.log(' |_|_|_|_|___|___|_,_|___|_ |');
console.log(' ' + chalk.gray(v) + (' |___|\n'.substr(v.length)));
//#endregion
}
console.log(chalk`${os.hostname()} {gray (PID: ${process.pid.toString()})}`);
bootLogger.info('Welcome to Misskey!');
bootLogger.info(`Misskey v${pkg.version}`, true);
bootLogger.info('Misskey is maintained by @syuilo, @AyaMorisawa, @mei23, and @acid-chicken.');
}
/**
* Init master process
*/
async function masterMain() {
greet();
let config: Config;
if (!program.quiet) {
//#region Misskey logo
console.log(' _____ _ _ ');
console.log('| |_|___ ___| |_ ___ _ _ ');
console.log('| | | | |_ -|_ -| \'_| -_| | |');
console.log('|_|_|_|_|___|___|_,_|___|_ |');
console.log(' |___|\n');
//#endregion
}
bootLogger.info('Welcome to Misskey!');
bootLogger.info(`Misskey v${pkg.version}`, true);
try {
// initialize app
config = await init();
if (config.port == null) {
bootLogger.error('The port is not configured. Please configure port.', true);
process.exit(1);
}
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
bootLogger.error('You need root privileges to listen on well-known port on Linux', true);
process.exit(1);
}
if (!await isPortAvailable(config.port)) {
bootLogger.error(`Port ${config.port} is already in use`, true);
process.exit(1);
}
} catch (e) {
bootLogger.error('Fatal error occurred during initialization', true);
process.exit(1);
@ -95,6 +114,9 @@ async function masterMain() {
await spawnWorkers(config.clusterLimit);
}
// start queue
require('./queue').default();
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, true);
}
@ -111,6 +133,29 @@ async function workerMain() {
}
}
async function queueMain() {
greet();
try {
// initialize app
await init();
} catch (e) {
bootLogger.error('Fatal error occurred during initialization', true);
process.exit(1);
}
bootLogger.succ('Misskey initialized');
// start processor
const queue = require('./queue').default();
if (queue) {
bootLogger.succ('Queue started', true);
} else {
bootLogger.error('Queue not available');
}
}
const runningNodejsVersion = process.version.slice(1).split('.').map(x => parseInt(x, 10));
const requiredNodejsVersion = [10, 0, 0];
const satisfyNodejsVersion = !lessThan(runningNodejsVersion, requiredNodejsVersion);
@ -123,18 +168,6 @@ async function isPortAvailable(port: number): Promise<boolean> {
return await portscanner.checkPortStatus(port, '127.0.0.1') === 'closed';
}
async function showMachine() {
const logger = bootLogger.createSubLogger('machine');
logger.info(`Hostname: ${os.hostname()}`);
logger.info(`Platform: ${process.platform}`);
logger.info(`Architecture: ${process.arch}`);
logger.info(`CPU: ${os.cpus().length} core`);
const mem = await sysUtils.mem();
const totalmem = (mem.total / 1024 / 1024 / 1024).toFixed(1);
const availmem = (mem.available / 1024 / 1024 / 1024).toFixed(1);
logger.info(`MEM: ${totalmem}GB (available: ${availmem}GB)`);
}
function showEnvironment(): void {
const env = process.env.NODE_ENV;
const logger = bootLogger.createSubLogger('env');
@ -159,11 +192,11 @@ async function init(): Promise<Config> {
nodejsLogger.info(`Version ${runningNodejsVersion.join('.')}`);
if (!satisfyNodejsVersion) {
nodejsLogger.error(`Node.js version is less than ${requiredNodejsVersion.join('.')}. Please upgrade it.`);
nodejsLogger.error(`Node.js version is less than ${requiredNodejsVersion.join('.')}. Please upgrade it.`, true);
process.exit(1);
}
await showMachine();
await showMachineInfo(bootLogger);
const configLogger = bootLogger.createSubLogger('config');
let config;
@ -176,7 +209,7 @@ async function init(): Promise<Config> {
process.exit(1);
}
if (exception.code === 'ENOENT') {
configLogger.error('Configuration file not found');
configLogger.error('Configuration file not found', true);
process.exit(1);
}
throw exception;
@ -184,51 +217,17 @@ async function init(): Promise<Config> {
configLogger.succ('Loaded');
if (config.port == null) {
bootLogger.error('The port is not configured. Please configure port.');
process.exit(1);
}
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
bootLogger.error('You need root privileges to listen on well-known port on Linux');
process.exit(1);
}
if (!await isPortAvailable(config.port)) {
bootLogger.error(`Port ${config.port} is already in use`, true);
process.exit(1);
}
// Try to connect to MongoDB
await checkMongoDB(config);
try {
await checkMongoDB(config, bootLogger);
} catch (e) {
bootLogger.error('Cannot connect to database', true);
process.exit(1);
}
return config;
}
const requiredMongoDBVersion = [3, 6];
function checkMongoDB(config: Config) {
const mongoDBLogger = bootLogger.createSubLogger('db');
const u = config.mongodb.user ? encodeURIComponent(config.mongodb.user) : null;
const p = config.mongodb.pass ? encodeURIComponent(config.mongodb.pass) : null;
const uri = `mongodb://${u && p ? `${u}:****@` : ''}${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}`;
mongoDBLogger.info(`Connecting to ${uri}`);
mongo.then(() => {
mongoDBLogger.succ('Connectivity confirmed');
nativeDbConn().then(db => db.admin().serverInfo()).then(x => x.version).then((version: string) => {
mongoDBLogger.info(`Version: ${version}`);
if (lessThan(version.split('.').map(x => parseInt(x, 10)), requiredMongoDBVersion)) {
mongoDBLogger.error(`MongoDB version is less than ${requiredMongoDBVersion.join('.')}. Please upgrade it.`);
process.exit(1);
}
});
}).catch(err => {
mongoDBLogger.error(err.message);
});
}
async function spawnWorkers(limit: number = Infinity) {
const workers = Math.min(limit, os.cpus().length);
bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`);
@ -250,12 +249,12 @@ function spawnWorker(): Promise<void> {
// Listen new workers
cluster.on('fork', worker => {
clusterLog.info(`Process forked: [${worker.id}]`);
clusterLog.debug(`Process forked: [${worker.id}]`);
});
// Listen online workers
cluster.on('online', worker => {
clusterLog.succ(`Process is now online: [${worker.id}]`);
clusterLog.debug(`Process is now online: [${worker.id}]`);
});
// Listen for dying workers

View File

@ -142,7 +142,7 @@ export const mfmLanguage = P.createLanguage({
},
hashtag: () => P((input, i) => {
const text = input.substr(i);
const match = text.match(/^#([^\s\.,!\?'"#:]+)/i);
const match = text.match(/^#([^\s\.,!\?'"#:\/]+)/i);
if (!match) return P.makeFailure(i, 'not a hashtag');
let hashtag = match[1];
hashtag = removeOrphanedBrackets(hashtag);

View File

@ -1,5 +1,4 @@
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
import { JSDOM } from 'jsdom';
import config from '../config';
import { INote } from '../models/note';
import { intersperse } from '../prelude/array';
@ -158,9 +157,9 @@ export function toHtml(tokens: MfmForest, mentionedRemoteUsers: INote['mentioned
text(token) {
const el = doc.createElement('span');
const nodes = (token.node.props.text as string).split(/\r\n|\r|\n/).map(x => doc.createTextNode(x));
const nodes = (token.node.props.text as string).split(/\r\n|\r|\n/).map(x => doc.createTextNode(x) as Node);
for (const x of intersperse('br', nodes)) {
for (const x of intersperse<Node | 'br'>('br', nodes)) {
el.appendChild(x === 'br' ? doc.createElement('br') : x);
}

View File

@ -1,4 +1,6 @@
export default (acct: string) => {
import Acct from './type';
export default (acct: string): Acct => {
if (acct.startsWith('@')) acct = acct.substr(1);
const split = acct.split('@', 2);
return { username: split[0], host: split[1] || null };

View File

@ -1,8 +1,5 @@
type UserLike = {
host: string;
username: string;
};
import Acct from './type';
export default (user: UserLike) => {
export default (user: Acct) => {
return user.host === null ? user.username : `${user.username}@${user.host}`;
};

6
src/misc/acct/type.ts Normal file
View File

@ -0,0 +1,6 @@
type Acct = {
username: string;
host: string;
};
export default Acct;

37
src/misc/check-mongodb.ts Normal file
View File

@ -0,0 +1,37 @@
import { nativeDbConn } from '../db/mongodb';
import { Config } from '../config/types';
import Logger from './logger';
import { lessThan } from '../prelude/array';
const requiredMongoDBVersion = [3, 6];
export function checkMongoDB(config: Config, logger: Logger) {
return new Promise((res, rej) => {
const mongoDBLogger = logger.createSubLogger('db');
const u = config.mongodb.user ? encodeURIComponent(config.mongodb.user) : null;
const p = config.mongodb.pass ? encodeURIComponent(config.mongodb.pass) : null;
const uri = `mongodb://${u && p ? `${u}:****@` : ''}${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}`;
mongoDBLogger.info(`Connecting to ${uri} ...`);
nativeDbConn().then(db => {
mongoDBLogger.succ('Connectivity confirmed');
db.admin().serverInfo().then(x => {
const version = x.version as string;
mongoDBLogger.info(`Version: ${version}`);
if (lessThan(version.split('.').map(x => parseInt(x, 10)), requiredMongoDBVersion)) {
mongoDBLogger.error(`MongoDB version is less than ${requiredMongoDBVersion.join('.')}. Please upgrade it.`);
rej('outdated version');
} else {
res();
}
}).catch(err => {
mongoDBLogger.error(`Failed to fetch server info: ${err.message}`);
rej(err);
});
}).catch(err => {
mongoDBLogger.error(err.message);
rej(err);
});
});
}

View File

@ -1,8 +1,7 @@
import * as cluster from 'cluster';
import chalk from 'chalk';
import * as dateformat from 'dateformat';
const quiet = process.argv.find(x => x == '--quiet');
import { program } from '../argv';
export default class Logger {
private domain: string;
@ -20,21 +19,22 @@ export default class Logger {
return logger;
}
public log(level: string, message: string, important = false): void {
if (quiet) return;
private log(level: string, message: string, important = false, subDomains: string[] = []): void {
if (program.quiet) return;
const domain = this.color ? chalk.keyword(this.color)(this.domain) : chalk.white(this.domain);
const domains = [domain].concat(subDomains);
if (this.parentLogger) {
this.parentLogger.log(level, `[${domain}]\t${message}`, important);
this.parentLogger.log(level, message, important, domains);
} else {
const time = dateformat(new Date(), 'HH:MM:ss');
const process = cluster.isMaster ? '*' : cluster.worker.id;
const log = `${chalk.gray(time)} ${level} ${process}\t[${domain}]\t${message}`;
const log = `${chalk.gray(time)} ${level} ${process}\t[${domains.join(' ')}]\t${message}`;
console.log(important ? chalk.bold(log) : log);
}
}
public error(message: string | Error, important = false): void { // 実行を継続できない状況で使う
this.log(chalk.red('ERR '), chalk.red(message.toString()), important);
this.log(important ? chalk.bgRed.white('ERR ') : chalk.red('ERR '), chalk.red(message.toString()), important);
}
public warn(message: string, important = false): void { // 実行を継続できるが改善すべき状況で使う
@ -42,16 +42,16 @@ export default class Logger {
}
public succ(message: string, important = false): void { // 何かに成功した状況で使う
this.log(chalk.green('DONE'), chalk.green(message), important);
this.log(important ? chalk.bgGreen.white('DONE') : chalk.green('DONE'), chalk.green(message), important);
}
public debug(message: string, important = false): void { // デバッグ用に使う(開発者に必要だが利用者に不要な情報)
if (process.env.NODE_ENV != 'production' || program.verbose) {
this.log(chalk.gray('VERB'), chalk.gray(message), important);
}
}
public info(message: string, important = false): void { // それ以外
this.log(chalk.blue('INFO'), message, important);
}
public debug(message: string, important = false): void { // デバッグ用に使う
if (process.env.NODE_ENV != 'production') {
this.log(chalk.gray('VERB'), chalk.gray(message), important);
}
}
}

View File

@ -0,0 +1,15 @@
import * as os from 'os';
import * as sysUtils from 'systeminformation';
import Logger from "./logger";
export async function showMachineInfo(parentLogger: Logger) {
const logger = parentLogger.createSubLogger('machine');
logger.debug(`Hostname: ${os.hostname()}`);
logger.debug(`Platform: ${process.platform}`);
logger.debug(`Architecture: ${process.arch}`);
logger.debug(`CPU: ${os.cpus().length} core`);
const mem = await sysUtils.mem();
const totalmem = (mem.total / 1024 / 1024 / 1024).toFixed(1);
const availmem = (mem.available / 1024 / 1024 / 1024).toFixed(1);
logger.debug(`MEM: ${totalmem}GB (available: ${availmem}GB)`);
}

View File

@ -27,11 +27,11 @@ export interface IReversiGame {
isEnded: boolean;
winnerId: mongo.ObjectID;
surrendered: mongo.ObjectID;
logs: Array<{
logs: {
at: Date;
color: boolean;
pos: number;
}>;
}[];
settings: {
map: string[];
bw: string | number;

View File

@ -209,7 +209,7 @@ export type IMeta = {
remoteDriveCapacityMb?: number;
/**
* Max allowed note text length in charactors
* Max allowed note text length in characters
*/
maxNoteTextLength?: number;

View File

@ -9,7 +9,6 @@ import { pack as packApp } from './app';
import PollVote from './poll-vote';
import Reaction from './note-reaction';
import { packMany as packFileMany, IDriveFile } from './drive-file';
import Favorite from './favorite';
import Following from './following';
import Emoji from './emoji';
@ -52,11 +51,11 @@ export type INote = {
repliesCount: number;
reactionCounts: any;
mentions: mongo.ObjectID[];
mentionedRemoteUsers: Array<{
mentionedRemoteUsers: {
uri: string;
username: string;
host: string;
}>;
}[];
/**
* public ... 公開
@ -346,19 +345,6 @@ export const pack = async (
return null;
})();
// isFavorited
_note.isFavorited = (async () => {
const favorite = await Favorite
.count({
userId: meId,
noteId: id
}, {
limit: 1
});
return favorite === 1;
})();
}
}

20
src/prelude/maybe.ts Normal file
View File

@ -0,0 +1,20 @@
export interface Maybe<T> {
isJust(): this is Just<T>;
}
export type Just<T> = Maybe<T> & {
get(): T
};
export function just<T>(value: T): Just<T> {
return {
isJust: () => true,
get: () => value
};
}
export function nothing<T>(): Maybe<T> {
return {
isJust: () => false,
};
}

View File

@ -1,20 +1,95 @@
import http from './processors/http';
import { ILocalUser } from '../models/user';
import Logger from '../misc/logger';
import * as Queue from 'bee-queue';
import * as httpSignature from 'http-signature';
export function createHttpJob(data: any) {
return http({ data }, () => {});
import config from '../config';
import { ILocalUser } from '../models/user';
import { program } from '../argv';
import handler from './processors';
import { queueLogger } from './logger';
const enableQueue = !program.disableQueue;
const queueAvailable = config.redis != null;
const queue = initializeQueue();
function initializeQueue() {
if (queueAvailable) {
return new Queue('misskey', {
redis: {
port: config.redis.port,
host: config.redis.host,
password: config.redis.pass
},
removeOnSuccess: true,
removeOnFailure: true,
getEvents: false,
sendEvents: false,
storeJobs: false
});
} else {
return null;
}
}
export function deliver(user: ILocalUser, content: any, to: any) {
if (content == null) return;
createHttpJob({
const data = {
type: 'deliver',
user,
content,
to
});
};
if (queueAvailable && !program.disableApQueue) {
return queue.createJob(data)
.retries(8)
.backoff('exponential', 1000)
.save();
} else {
return handler({ data }, () => {});
}
}
export const queueLogger = new Logger('queue');
export function processInbox(activity: any, signature: httpSignature.IParsedSignature) {
const data = {
type: 'processInbox',
activity: activity,
signature
};
if (queueAvailable && !program.disableApQueue) {
return queue.createJob(data)
.retries(3)
.backoff('exponential', 500)
.save();
} else {
return handler({ data }, () => {});
}
}
export function createExportNotesJob(user: ILocalUser) {
if (!queueAvailable) throw 'queue unavailable';
return queue.createJob({
type: 'exportNotes',
user: user
})
.save();
}
export default function() {
if (queueAvailable && enableQueue) {
queue.process(128, handler);
queueLogger.succ('Processing started');
}
return queue;
}
export function destroy() {
queue.destroy().then(n => {
queueLogger.succ(`All job removed (${n} jobs)`);
});
}

3
src/queue/logger.ts Normal file
View File

@ -0,0 +1,3 @@
import Logger from '../misc/logger';
export const queueLogger = new Logger('queue', 'orange');

View File

@ -0,0 +1,128 @@
import * as bq from 'bee-queue';
import * as tmp from 'tmp';
import * as fs from 'fs';
import * as mongo from 'mongodb';
import { queueLogger } from '../logger';
import Note, { INote } from '../../models/note';
import addFile from '../../services/drive/add-file';
import User from '../../models/user';
import dateFormat = require('dateformat');
const logger = queueLogger.createSubLogger('export-notes');
export async function exportNotes(job: bq.Job, done: any): Promise<void> {
logger.info(`Exporting notes of ${job.data.user._id} ...`);
const user = await User.findOne({
_id: new mongo.ObjectID(job.data.user._id.toString())
});
// Create temp file
const [path, cleanup] = await new Promise<[string, any]>((res, rej) => {
tmp.file((e, path, fd, cleanup) => {
if (e) return rej(e);
res([path, cleanup]);
});
});
logger.info(`Temp file is ${path}`);
const stream = fs.createWriteStream(path, { flags: 'a' });
await new Promise((res, rej) => {
stream.write('[', err => {
if (err) {
logger.error(err);
rej(err);
} else {
res();
}
});
});
let exportedNotesCount = 0;
let ended = false;
let cursor: any = null;
while (!ended) {
const notes = await Note.find({
userId: user._id,
...(cursor ? { _id: { $gt: cursor } } : {})
}, {
limit: 100,
sort: {
_id: 1
}
});
if (notes.length === 0) {
ended = true;
job.reportProgress(100);
break;
}
cursor = notes[notes.length - 1]._id;
for (const note of notes) {
const content = JSON.stringify(serialize(note));
await new Promise((res, rej) => {
stream.write(exportedNotesCount === 0 ? content : ',\n' + content, err => {
if (err) {
logger.error(err);
rej(err);
} else {
res();
}
});
});
exportedNotesCount++;
}
const total = await Note.count({
userId: user._id,
});
job.reportProgress(exportedNotesCount / total);
}
await new Promise((res, rej) => {
stream.write(']', err => {
if (err) {
logger.error(err);
rej(err);
} else {
res();
}
});
});
stream.end();
logger.succ(`Exported to: ${path}`);
const fileName = dateFormat(new Date(), 'yyyy-mm-dd-HH-MM-ss') + '.json';
const driveFile = await addFile(user, path, fileName);
logger.succ(`Exported to: ${driveFile._id}`);
cleanup();
done();
}
function serialize(note: INote): any {
return {
id: note._id,
text: note.text,
createdAt: note.createdAt,
fileIds: note.fileIds,
replyId: note.replyId,
renoteId: note.renoteId,
poll: note.poll,
cw: note.cw,
viaMobile: note.viaMobile,
visibility: note.visibility,
visibleUserIds: note.visibleUserIds,
appId: note.appId,
geo: note.geo,
localOnly: note.localOnly
};
}

View File

@ -1,7 +1,7 @@
import * as bq from 'bee-queue';
import request from '../../../remote/activitypub/request';
import { queueLogger } from '../..';
import { queueLogger } from '../../logger';
export default async (job: bq.Job, done: any): Promise<void> => {
try {

View File

@ -6,7 +6,7 @@ import perform from '../../../remote/activitypub/perform';
import { resolvePerson, updatePerson } from '../../../remote/activitypub/models/person';
import { toUnicode } from 'punycode';
import { URL } from 'url';
import { publishApLogStream } from '../../../stream';
import { publishApLogStream } from '../../../services/stream';
import Logger from '../../../misc/logger';
const logger = new Logger('inbox');
@ -20,7 +20,7 @@ export default async (job: bq.Job, done: any): Promise<void> => {
const info = Object.assign({}, activity);
delete info['@context'];
delete info['signature'];
logger.info(info);
logger.debug(JSON.stringify(info, null, 2));
//#endregion
const keyIdLower = signature.keyId.toLowerCase();

View File

@ -1,10 +1,12 @@
import deliver from './deliver';
import processInbox from './process-inbox';
import { queueLogger } from '../..';
import deliver from './http/deliver';
import processInbox from './http/process-inbox';
import { exportNotes } from './export-notes';
import { queueLogger } from '../logger';
const handlers: any = {
deliver,
processInbox,
exportNotes,
};
export default (job: any, done: any) => {

View File

@ -7,7 +7,7 @@ import * as promiseAny from 'promise-any';
import config from '../../config';
import { ILocalUser } from '../../models/user';
import { publishApLogStream } from '../../stream';
import { publishApLogStream } from '../../services/stream';
import { apLogger } from './logger';
export const logger = apLogger.createSubLogger('deliver');
@ -43,11 +43,11 @@ export default (user: ILocalUser, url: string, object: any) => new Promise(async
'Digest': `SHA-256=${hash}`
}
}, res => {
logger.info(`${url} --> ${res.statusCode}`);
if (res.statusCode >= 400) {
logger.warn(`${url} --> ${res.statusCode}`);
reject(res);
} else {
logger.succ(`${url} --> ${res.statusCode}`);
resolve();
}
});

View File

@ -19,16 +19,20 @@ export default class Resolver {
: value;
switch (collection.type) {
case 'Collection':
collection.objects = collection.items;
break;
case 'Collection': {
collection.objects = collection.items;
break;
}
case 'OrderedCollection':
collection.objects = collection.orderedItems;
break;
case 'OrderedCollection': {
collection.objects = collection.orderedItems;
break;
}
default:
throw new Error(`unknown collection type: ${collection.type}`);
default: {
logger.error(`unknown collection type: ${collection.type}`);
throw new Error(`unknown collection type: ${collection.type}`);
}
}
return collection;
@ -36,6 +40,7 @@ export default class Resolver {
public async resolve(value: any): Promise<IObject> {
if (value == null) {
logger.error('resolvee is null (or undefined)');
throw new Error('resolvee is null (or undefined)');
}
@ -44,6 +49,7 @@ export default class Resolver {
}
if (this.history.has(value)) {
logger.error(`cannot resolve already resolved one`);
throw new Error('cannot resolve already resolved one');
}
@ -59,6 +65,7 @@ export default class Resolver {
},
json: true
}).catch(e => {
logger.error(`request error: ${e.message}`);
throw new Error(`request error: ${e.message}`);
});

View File

@ -78,9 +78,13 @@ export default async (username: string, _host: string, option?: any, resync?: bo
async function resolveSelf(acctLower: string) {
logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
const finger = await webFinger(acctLower);
const finger = await webFinger(acctLower).catch(e => {
logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${e.message} (${e.status})`);
throw e;
});
const self = finger.links.find(link => link.rel && link.rel.toLowerCase() === 'self');
if (!self) {
logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`);
throw new Error('self link not found');
}
return self;

View File

@ -3,7 +3,6 @@ import * as Router from 'koa-router';
import * as json from 'koa-json-body';
import * as httpSignature from 'http-signature';
import { createHttpJob } from '../queue';
import { renderActivity } from '../remote/activitypub/renderer';
import Note from '../models/note';
import User, { isLocalUser, ILocalUser, IUser } from '../models/user';
@ -17,6 +16,7 @@ import Followers from './activitypub/followers';
import Following from './activitypub/following';
import Featured from './activitypub/featured';
import renderQuestion from '../remote/activitypub/renderer/question';
import { processInbox } from '../queue';
// Init router
const router = new Router();
@ -35,11 +35,7 @@ function inbox(ctx: Router.IRouterContext) {
return;
}
createHttpJob({
type: 'processInbox',
activity: ctx.request.body,
signature
});
processInbox(ctx.request.body, signature);
ctx.status = 202;
}

View File

@ -1,7 +1,8 @@
import { ObjectID } from 'mongodb';
import * as Router from 'koa-router';
import config from '../../config';
import $ from 'cafy'; import ID, { transform } from '../../misc/cafy-id';
import $ from 'cafy';
import ID, { transform } from '../../misc/cafy-id';
import User from '../../models/user';
import Following from '../../models/following';
import { renderActivity } from '../../remote/activitypub/renderer';

View File

@ -2,9 +2,9 @@ import * as mongo from 'mongodb';
import isObjectId from '../../../misc/is-objectid';
import Message from '../../../models/messaging-message';
import { IMessagingMessage as IMessage } from '../../../models/messaging-message';
import { publishMainStream } from '../../../stream';
import { publishMessagingStream } from '../../../stream';
import { publishMessagingIndexStream } from '../../../stream';
import { publishMainStream } from '../../../services/stream';
import { publishMessagingStream } from '../../../services/stream';
import { publishMessagingIndexStream } from '../../../services/stream';
import User from '../../../models/user';
/**

View File

@ -1,7 +1,7 @@
import * as mongo from 'mongodb';
import isObjectId from '../../../misc/is-objectid';
import { default as Notification, INotification } from '../../../models/notification';
import { publishMainStream } from '../../../stream';
import { publishMainStream } from '../../../services/stream';
import Mute from '../../../models/mute';
import User from '../../../models/user';

View File

@ -1,4 +1,5 @@
import $ from 'cafy'; import ID, { transform } from '../../../../misc/cafy-id';
import $ from 'cafy';
import ID, { transform } from '../../../../misc/cafy-id';
import Report, { packMany } from '../../../../models/abuse-user-report';
import define from '../../define';

View File

@ -0,0 +1,15 @@
import define from '../../../define';
import { destroy } from '../../../../../queue';
export const meta = {
requireCredential: true,
requireModerator: true,
params: {}
};
export default define(meta, (ps) => new Promise(async (res, rej) => {
destroy();
res();
}));

View File

@ -29,22 +29,22 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
$group: {
_id: { tag: '$tagsLower', userId: '$userId' }
}
}]) as Array<{
}]) as {
_id: {
tag: string;
userId: any;
}
}>;
}[];
//#endregion
if (data.length == 0) {
return res([]);
}
let tags: Array<{
let tags: {
name: string;
count: number;
}> = [];
}[] = [];
// カウント
for (const x of data.map(x => x._id).filter(x => !hidedTags.includes(x.tag))) {

Some files were not shown because too many files have changed in this diff Show More