Compare commits
88 Commits
Author | SHA1 | Date | |
---|---|---|---|
2a1def3cce | |||
938fe05fef | |||
5db5bbd1cd | |||
ba7e05837c | |||
9dd06a7621 | |||
2f4434b0d8 | |||
350328770b | |||
17e1b49bff | |||
266c31981d | |||
803fb0898a | |||
01983da514 | |||
6f473aa64a | |||
574747b9d4 | |||
dff1122bd5 | |||
43cb12930a | |||
8129d4dc23 | |||
9b780dff04 | |||
11a0ef485b | |||
83b2aa72b1 | |||
c71b24987d | |||
78d22dbd22 | |||
8961dab137 | |||
bcc549fd8e | |||
5a6c3fc11c | |||
7d730f676d | |||
6bda571660 | |||
d3c7129e1f | |||
3709ba95cd | |||
4162981081 | |||
7b7359fbdc | |||
70c01c52a8 | |||
443006c868 | |||
7c1db1fea5 | |||
7c2b704bef | |||
368c3f1e29 | |||
dd39d6ea37 | |||
ef618b2431 | |||
861302f0fd | |||
f014b7ae0e | |||
00b2d89f1a | |||
5410efe9ca | |||
1d814ba0e1 | |||
c107333f56 | |||
06707705bf | |||
68ee9a008e | |||
3a035c481e | |||
23a0aead9f | |||
6cd41f9860 | |||
baf861ac79 | |||
0ae1190c08 | |||
d3b3426ebe | |||
4982ea8f14 | |||
3be89e9702 | |||
4275af2324 | |||
84d42be090 | |||
c4c7783691 | |||
d6dba7fd71 | |||
30b1b1a5ed | |||
90b6688057 | |||
b536ee4dcd | |||
11101a6aca | |||
b4a3e5aa4f | |||
874c0eae6a | |||
9950b6fbc6 | |||
42d6ed62f6 | |||
beb1b570d4 | |||
ba1b5a8ede | |||
99d8d0a484 | |||
5891135ac1 | |||
c4f7491322 | |||
206b57b962 | |||
1b0e03704e | |||
8f2f4b6d2d | |||
6e0c055faf | |||
893a3b527d | |||
fe13c17fcb | |||
5049870b6e | |||
ce576dea8f | |||
ceda3dd72a | |||
014b58cb40 | |||
b4859be098 | |||
df54da9510 | |||
b97f788d71 | |||
edd1baa9f4 | |||
4a23ebe534 | |||
64c1075b06 | |||
217e4ee39c | |||
7e2a7cdff8 |
@ -2,7 +2,7 @@
|
|||||||
# __MISSKEY_BEARER_TOKEN=
|
# __MISSKEY_BEARER_TOKEN=
|
||||||
# __MISSKEY_CAMPAIGN_ID=
|
# __MISSKEY_CAMPAIGN_ID=
|
||||||
# __MISSKEY_GITHUB_TOKEN=
|
# __MISSKEY_GITHUB_TOKEN=
|
||||||
# __MISSKEY_HEAD=acid-chicken:patch-autogen
|
# __MISSKEY_HEAD=syuilo:patch-autogen
|
||||||
# __MISSKEY_REPO=syuilo/misskey
|
# __MISSKEY_REPO=syuilo/misskey
|
||||||
# __MISSKEY_BRANCH=develop
|
# __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
|
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
|
||||||
|
@ -134,12 +134,14 @@ workflows:
|
|||||||
only:
|
only:
|
||||||
- l10n_develop
|
- l10n_develop
|
||||||
- imgbot
|
- imgbot
|
||||||
|
- patch-autogen
|
||||||
- build:
|
- build:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
ignore:
|
ignore:
|
||||||
- l10n_develop
|
- l10n_develop
|
||||||
- imgbot
|
- imgbot
|
||||||
|
- patch-autogen
|
||||||
- test:
|
- test:
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
@ -149,13 +151,20 @@ workflows:
|
|||||||
# - master
|
# - master
|
||||||
- l10n_develop
|
- l10n_develop
|
||||||
- imgbot
|
- imgbot
|
||||||
|
- patch-autogen
|
||||||
- test:
|
- test:
|
||||||
without_redis: "true"
|
without_redis: "true"
|
||||||
requires:
|
requires:
|
||||||
- build
|
- build
|
||||||
filters:
|
filters:
|
||||||
|
# branches:
|
||||||
|
# only: master
|
||||||
branches:
|
branches:
|
||||||
only: master
|
ignore:
|
||||||
|
# - master
|
||||||
|
- l10n_develop
|
||||||
|
- imgbot
|
||||||
|
- patch-autogen
|
||||||
# - docker:
|
# - docker:
|
||||||
# filters:
|
# filters:
|
||||||
# branches:
|
# branches:
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
10.82.0
|
||||||
|
----------
|
||||||
|
* 自分の投稿情報をエクスポートできるように
|
||||||
|
* アニメーションする画像を再生しないで表示するオプションを実装
|
||||||
|
* 個別に投稿のウォッチ/ウォッチ解除をできるように
|
||||||
|
|
||||||
10.81.0
|
10.81.0
|
||||||
----------
|
----------
|
||||||
* 動画のサムネイルを作成するように
|
* 動画のサムネイルを作成するように
|
||||||
|
@ -12,7 +12,6 @@ RUN unlink /usr/bin/free
|
|||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
autoconf \
|
autoconf \
|
||||||
automake \
|
automake \
|
||||||
ffmpeg \
|
|
||||||
file \
|
file \
|
||||||
g++ \
|
g++ \
|
||||||
gcc \
|
gcc \
|
||||||
@ -36,7 +35,9 @@ RUN node-gyp configure \
|
|||||||
|
|
||||||
FROM base AS runner
|
FROM base AS runner
|
||||||
|
|
||||||
RUN apk add --no-cache tini
|
RUN apk add --no-cache \
|
||||||
|
ffmpeg \
|
||||||
|
tini
|
||||||
ENTRYPOINT ["/sbin/tini", "--"]
|
ENTRYPOINT ["/sbin/tini", "--"]
|
||||||
|
|
||||||
COPY --from=builder /misskey/node_modules ./node_modules
|
COPY --from=builder /misskey/node_modules ./node_modules
|
||||||
|
@ -85,12 +85,11 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
:heart: Backers & Sponsors
|
:heart: Backers
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
<!-- PATREON_START -->
|
<!-- PATREON_START -->
|
||||||
<table><tr>
|
<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://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/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://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>
|
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
|
||||||
@ -99,7 +98,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>
|
<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>
|
</tr><tr>
|
||||||
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
|
<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/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=12913507">Melilot</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
|
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
|
||||||
@ -138,7 +136,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
|
|||||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
|
|
||||||
**Last updated:** Tue, 29 Jan 2019 04:42:06 UTC
|
**Last updated:** Sun, 03 Feb 2019 10:13:06 UTC
|
||||||
<!-- PATREON_END -->
|
<!-- PATREON_END -->
|
||||||
|
|
||||||
:four_leaf_clover: Copyright
|
:four_leaf_clover: Copyright
|
||||||
|
@ -29,6 +29,7 @@ Please install and setup these softwares:
|
|||||||
* [Redis](https://redis.io/)
|
* [Redis](https://redis.io/)
|
||||||
* Redis is optional, but we strongly recommended to install it
|
* Redis is optional, but we strongly recommended to install it
|
||||||
* [Elasticsearch](https://www.elastic.co/) - required to enable the search feature
|
* [Elasticsearch](https://www.elastic.co/) - required to enable the search feature
|
||||||
|
* [FFmpeg](https://www.ffmpeg.org/)
|
||||||
|
|
||||||
*3.* Setup MongoDB
|
*3.* Setup MongoDB
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
@ -54,6 +55,11 @@ As root:
|
|||||||
*6.* Build Misskey
|
*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:
|
Build misskey with the following:
|
||||||
|
|
||||||
`npm run build`
|
`npm run build`
|
||||||
|
@ -29,6 +29,7 @@ Installez les paquets suivants :
|
|||||||
* [Redis](https://redis.io/)
|
* [Redis](https://redis.io/)
|
||||||
* Redis est optionnel mais nous vous recommandons vivement de l'installer
|
* Redis est optionnel mais nous vous recommandons vivement de l'installer
|
||||||
* [Elasticsearch](https://www.elastic.co/) - requis pour pouvoir activer la fonctionnalité de recherche
|
* [Elasticsearch](https://www.elastic.co/) - requis pour pouvoir activer la fonctionnalité de recherche
|
||||||
|
* [FFmpeg](https://www.ffmpeg.org/)
|
||||||
|
|
||||||
*3.* Paramètrage de MongoDB
|
*3.* Paramètrage de MongoDB
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
@ -32,9 +32,11 @@ adduser --disabled-password --disabled-login misskey
|
|||||||
* 具体的には、Redisをインストールしないと、次の事が出来なくなります:
|
* 具体的には、Redisをインストールしないと、次の事が出来なくなります:
|
||||||
* Misskeyプロセスを複数起動しての負荷分散
|
* Misskeyプロセスを複数起動しての負荷分散
|
||||||
* レートリミット
|
* レートリミット
|
||||||
|
* ジョブキュー
|
||||||
* Twitter連携
|
* Twitter連携
|
||||||
* [Elasticsearch](https://www.elastic.co/)
|
* [Elasticsearch](https://www.elastic.co/)
|
||||||
* 検索機能を有効にするためにはインストールが必要です。
|
* 検索機能を有効にするためにはインストールが必要です。
|
||||||
|
* [FFmpeg](https://www.ffmpeg.org/)
|
||||||
|
|
||||||
*3.* MongoDBの設定
|
*3.* MongoDBの設定
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
@ -60,6 +62,11 @@ adduser --disabled-password --disabled-login misskey
|
|||||||
*6.* Misskeyのビルド
|
*6.* Misskeyのビルド
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
ビルドする前に、`NODE_ENV`を`production`にする必要があります。例:
|
||||||
|
* Linux: `export NODE_ENV=production`
|
||||||
|
* Windows (PowerShell): `$env:NODE_ENV="production"`
|
||||||
|
* Windows (CMD): `set NODE_ENV=production`
|
||||||
|
|
||||||
次のコマンドでMisskeyをビルドしてください:
|
次のコマンドでMisskeyをビルドしてください:
|
||||||
|
|
||||||
`npm run build`
|
`npm run build`
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "公式アカウント"
|
verified-user: "公式アカウント"
|
||||||
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "Verifizierter Benutzer"
|
verified-user: "Verifizierter Benutzer"
|
||||||
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Diese Notiz favorisieren"
|
favorite: "Diese Notiz favorisieren"
|
||||||
unfavorite: "Aus Favoriten entfernen"
|
unfavorite: "Aus Favoriten entfernen"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "An die Profilseite pinnen"
|
pin: "An die Profilseite pinnen"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "Löschen"
|
delete: "Löschen"
|
||||||
|
@ -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?"
|
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:
|
intro:
|
||||||
title: "What is Misskey?"
|
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"
|
features: "Features"
|
||||||
rich-contents: "Post"
|
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: "Reactions"
|
||||||
reaction-desc: "Easiest way to tell your emotions. Misskey allows you to add various type of reactions to other’s post. The emotional experience on Misskey will never be on other SNSs which only able to push “likes”."
|
reaction-desc: "Easiest way to tell your emotions. Misskey allows you to add various type of reactions to other’s post. The emotional experience on Misskey will never be on other SNSs which only able to push “likes”."
|
||||||
ui: "Interface"
|
ui: "Interface"
|
||||||
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "Use avatar as a stone in reversi"
|
use-avatar-reversi-stones: "Use avatar as a stone in reversi"
|
||||||
verified-user: "Verified account"
|
verified-user: "Verified account"
|
||||||
disable-animated-mfm: "Disable animated texts in a post"
|
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"
|
suggest-recent-hashtags: "Suggest recently used hashtags within the post composition area"
|
||||||
always-show-nsfw: "Always show NSFW contents"
|
always-show-nsfw: "Always show NSFW contents"
|
||||||
always-mark-nsfw: "Always mark posts with media attachments as NSFW"
|
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"
|
copy-link: "Copy link"
|
||||||
favorite: "Favorite this note"
|
favorite: "Favorite this note"
|
||||||
unfavorite: "Unfavorite"
|
unfavorite: "Unfavorite"
|
||||||
|
watch: "Watch"
|
||||||
|
unwatch: "Unwatch"
|
||||||
pin: "Pin to your profile"
|
pin: "Pin to your profile"
|
||||||
unpin: "Unpin"
|
unpin: "Unpin"
|
||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
@ -360,8 +363,8 @@ common/views/components/user-menu.vue:
|
|||||||
report-abuse: "Report abuse"
|
report-abuse: "Report abuse"
|
||||||
report-abuse-detail: "What kind of nuisance did you encounter?"
|
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."
|
report-abuse-reported: "The issue has been reported to the administrator. Your cooperation is much appreciated."
|
||||||
silence: "Make Silence"
|
silence: "Mute"
|
||||||
unsilence: "Unsilence"
|
unsilence: "Unmute"
|
||||||
suspend: "Suspend"
|
suspend: "Suspend"
|
||||||
unsuspend: "Unsuspend"
|
unsuspend: "Unsuspend"
|
||||||
common/views/components/poll.vue:
|
common/views/components/poll.vue:
|
||||||
@ -1147,8 +1150,8 @@ admin/views/users.vue:
|
|||||||
unsuspend: "Unsuspend"
|
unsuspend: "Unsuspend"
|
||||||
unsuspend-confirm: "Are you sure you want to unsuspend this account?"
|
unsuspend-confirm: "Are you sure you want to unsuspend this account?"
|
||||||
unsuspended: "The user has successfully unsuspended."
|
unsuspended: "The user has successfully unsuspended."
|
||||||
make-silence: "Make Silence"
|
make-silence: "Mute"
|
||||||
unmake-silence: "Unmake Silence"
|
unmake-silence: "Unmute"
|
||||||
verify: "Verify account"
|
verify: "Verify account"
|
||||||
verify-confirm: "Do you want this to be a verified account?"
|
verify-confirm: "Do you want this to be a verified account?"
|
||||||
verified: "The account is now being verified"
|
verified: "The account is now being verified"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "Cuenta verificada"
|
verified-user: "Cuenta verificada"
|
||||||
disable-animated-mfm: "Desactivar texto animado en una publicación"
|
disable-animated-mfm: "Desactivar texto animado en una publicación"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "Copiar enlace"
|
copy-link: "Copiar enlace"
|
||||||
favorite: "Me gusta esta nota"
|
favorite: "Me gusta esta nota"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "Fijar en el perfil"
|
pin: "Fijar en el perfil"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "Borrar"
|
delete: "Borrar"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "Utiliser l’avatar comme pion dans Reversi"
|
use-avatar-reversi-stones: "Utiliser l’avatar comme pion dans Reversi"
|
||||||
verified-user: "Compte vérifié"
|
verified-user: "Compte vérifié"
|
||||||
disable-animated-mfm: "Désactiver les textes animés dans les publications"
|
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"
|
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-show-nsfw: "Toujours afficher les contenus sensibles"
|
||||||
always-mark-nsfw: "Toujours marquer les notes ayant des attachements comme 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"
|
copy-link: "Copier le lien"
|
||||||
favorite: "Mettre cette note en favoris"
|
favorite: "Mettre cette note en favoris"
|
||||||
unfavorite: "Retirer des favoris"
|
unfavorite: "Retirer des favoris"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "Épingler sur votre profil"
|
pin: "Épingler sur votre profil"
|
||||||
unpin: "Désépingler"
|
unpin: "Désépingler"
|
||||||
delete: "Supprimer"
|
delete: "Supprimer"
|
||||||
|
5
locales/index.d.ts
vendored
Normal file
5
locales/index.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
type Locale = { [key: string]: string };
|
||||||
|
|
||||||
|
declare const locales: { [lang: string]: Locale };
|
||||||
|
|
||||||
|
export default locales;
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "公式アカウント"
|
verified-user: "公式アカウント"
|
||||||
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
|
@ -121,6 +121,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "公式アカウント"
|
verified-user: "公式アカウント"
|
||||||
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -374,6 +375,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
@ -554,6 +557,9 @@ common/views/components/profile-editor.vue:
|
|||||||
email-address: "メールアドレス"
|
email-address: "メールアドレス"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "メールアドレスが確認されました"
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
|
export: "エクスポート"
|
||||||
|
export-notes: "すべての投稿のエクスポート"
|
||||||
|
export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
|
||||||
|
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "アメちゃん付きアカウント"
|
verified-user: "アメちゃん付きアカウント"
|
||||||
disable-animated-mfm: "投稿内のちょろちょろ動いてんのを止める"
|
disable-animated-mfm: "投稿内のちょろちょろ動いてんのを止める"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "閲覧注意?見せたらあかん?そんなん知らんわ、見せろや!"
|
always-show-nsfw: "閲覧注意?見せたらあかん?そんなん知らんわ、見せろや!"
|
||||||
always-mark-nsfw: "わからんからとりあえずメディアは見せたらあかん"
|
always-mark-nsfw: "わからんからとりあえずメディアは見せたらあかん"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
unfavorite: "お気に入りやめる"
|
unfavorite: "お気に入りやめる"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留めやめる"
|
unpin: "ピン留めやめる"
|
||||||
delete: "ほかす"
|
delete: "ほかす"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "리버시의 돌로 아바타를 사용"
|
use-avatar-reversi-stones: "리버시의 돌로 아바타를 사용"
|
||||||
verified-user: "공식 계정"
|
verified-user: "공식 계정"
|
||||||
disable-animated-mfm: "글의 문자 애니메이션을 비활성화"
|
disable-animated-mfm: "글의 문자 애니메이션을 비활성화"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "최근 해시태그를 글 작성란에 표시"
|
suggest-recent-hashtags: "최근 해시태그를 글 작성란에 표시"
|
||||||
always-show-nsfw: "항상 열람주의 미디어를 표시"
|
always-show-nsfw: "항상 열람주의 미디어를 표시"
|
||||||
always-mark-nsfw: "항상 미디어를 열람주의로 설정하여 게시"
|
always-mark-nsfw: "항상 미디어를 열람주의로 설정하여 게시"
|
||||||
@ -129,7 +130,7 @@ common:
|
|||||||
show-password: "비밀번호 표시"
|
show-password: "비밀번호 표시"
|
||||||
do-not-use-in-production: "이것은 개발 빌드입니다. 프로덕션 환경에서 사용하지 마십시오."
|
do-not-use-in-production: "이것은 개발 빌드입니다. 프로덕션 환경에서 사용하지 마십시오."
|
||||||
user-suspended: "이 사용자는 정지된 상태입니다."
|
user-suspended: "이 사용자는 정지된 상태입니다."
|
||||||
is-remote-user: "このユーザー情報は不正確な可能性があります。"
|
is-remote-user: "이 사용자 정보는 정확하지 않을 수 있습니다."
|
||||||
is-remote-post: "이 글 정보는 복사본입니다."
|
is-remote-post: "이 글 정보는 복사본입니다."
|
||||||
view-on-remote: "정확한 정보 보기"
|
view-on-remote: "정확한 정보 보기"
|
||||||
renoted-by: "{user}이(가) 리노트"
|
renoted-by: "{user}이(가) 리노트"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "링크 복사"
|
copy-link: "링크 복사"
|
||||||
favorite: "이 노트 즐겨찾기"
|
favorite: "이 노트 즐겨찾기"
|
||||||
unfavorite: "즐겨찾기에서 제거"
|
unfavorite: "즐겨찾기에서 제거"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "프로필에 고정"
|
pin: "프로필에 고정"
|
||||||
unpin: "프로필에서 고정 해제"
|
unpin: "프로필에서 고정 해제"
|
||||||
delete: "삭제"
|
delete: "삭제"
|
||||||
@ -360,10 +363,10 @@ common/views/components/user-menu.vue:
|
|||||||
report-abuse: "스팸 신고"
|
report-abuse: "스팸 신고"
|
||||||
report-abuse-detail: "어떤 스팸 행위를 하고 있습니까?"
|
report-abuse-detail: "어떤 스팸 행위를 하고 있습니까?"
|
||||||
report-abuse-reported: "관리자에게 보고되었습니다. 협조해주셔서 감사합니다."
|
report-abuse-reported: "관리자에게 보고되었습니다. 협조해주셔서 감사합니다."
|
||||||
silence: "サイレンス"
|
silence: "침묵"
|
||||||
unsilence: "サイレンス解除"
|
unsilence: "침묵 해제"
|
||||||
suspend: "凍結"
|
suspend: "정지"
|
||||||
unsuspend: "凍結解除"
|
unsuspend: "정지 해제"
|
||||||
common/views/components/poll.vue:
|
common/views/components/poll.vue:
|
||||||
vote-to: "\"{}\"에 투표하기"
|
vote-to: "\"{}\"에 투표하기"
|
||||||
vote-count: "{}표"
|
vote-count: "{}표"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "公式アカウント"
|
verified-user: "公式アカウント"
|
||||||
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Deze notitie toevoegen aan favorieten"
|
favorite: "Deze notitie toevoegen aan favorieten"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "Vastmaken aan profielpagina"
|
pin: "Vastmaken aan profielpagina"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "公式アカウント"
|
verified-user: "公式アカウント"
|
||||||
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "Merket som favoritt"
|
favorite: "Merket som favoritt"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "Fest til profilen din"
|
pin: "Fest til profilen din"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "Slett"
|
delete: "Slett"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "Zweryfikowane konto"
|
verified-user: "Zweryfikowane konto"
|
||||||
disable-animated-mfm: "Wyłącz animowany tekst we wpisach"
|
disable-animated-mfm: "Wyłącz animowany tekst we wpisach"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "Zawszę pokazuj zawartość NSFW"
|
always-show-nsfw: "Zawszę pokazuj zawartość NSFW"
|
||||||
always-mark-nsfw: "Zawsze oznaczaj posty z multimediami jako 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"
|
copy-link: "Skopiuj adres"
|
||||||
favorite: "Dodaj do ulubionych"
|
favorite: "Dodaj do ulubionych"
|
||||||
unfavorite: "Usuń z ulubionych"
|
unfavorite: "Usuń z ulubionych"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "Przypnij do profilu"
|
pin: "Przypnij do profilu"
|
||||||
unpin: "Odepnij"
|
unpin: "Odepnij"
|
||||||
delete: "Usuń"
|
delete: "Usuń"
|
||||||
@ -356,7 +359,7 @@ common/views/components/user-menu.vue:
|
|||||||
block: "Zablokuj"
|
block: "Zablokuj"
|
||||||
unblock: "Odblokuj"
|
unblock: "Odblokuj"
|
||||||
push-to-list: "Dodaj do listy"
|
push-to-list: "Dodaj do listy"
|
||||||
select-list: "リストを選択してください"
|
select-list: "Wybierz listę"
|
||||||
report-abuse: "Zgłoś nadużycie"
|
report-abuse: "Zgłoś nadużycie"
|
||||||
report-abuse-detail: "どのような迷惑行為を行っていますか?"
|
report-abuse-detail: "どのような迷惑行為を行っていますか?"
|
||||||
report-abuse-reported: "管理者に報告されました。ご協力ありがとうございました。"
|
report-abuse-reported: "管理者に報告されました。ご協力ありがとうございました。"
|
||||||
@ -395,11 +398,11 @@ common/views/components/signin.vue:
|
|||||||
token: "Token"
|
token: "Token"
|
||||||
signing-in: "Logowanie…"
|
signing-in: "Logowanie…"
|
||||||
signin: "Zaloguj"
|
signin: "Zaloguj"
|
||||||
or: "または"
|
or: "lub"
|
||||||
signin-with-twitter: "Zaloguj się za pomocą Twittera"
|
signin-with-twitter: "Zaloguj się za pomocą Twittera"
|
||||||
signin-with-github: "Zaloguj się za pomocą GitHuba"
|
signin-with-github: "Zaloguj się za pomocą GitHuba"
|
||||||
signin-with-discord: "Zaloguj się za pomocą Discorda"
|
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:
|
common/views/components/signup.vue:
|
||||||
invitation-code: "Kod zaproszenia"
|
invitation-code: "Kod zaproszenia"
|
||||||
invitation-info: "招待コードをお持ちでない方は、<a href=\"{}\">管理者</a>までご連絡ください。"
|
invitation-info: "招待コードをお持ちでない方は、<a href=\"{}\">管理者</a>までご連絡ください。"
|
||||||
@ -472,13 +475,13 @@ common/views/components/visibility-chooser.vue:
|
|||||||
local-followers: "Dla śledzących (tylko lokalnie)"
|
local-followers: "Dla śledzących (tylko lokalnie)"
|
||||||
common/views/components/trends.vue:
|
common/views/components/trends.vue:
|
||||||
count: "{}人が投稿"
|
count: "{}人が投稿"
|
||||||
empty: "トレンドなし"
|
empty: "Brak popularnych hashtagów"
|
||||||
common/views/components/language-settings.vue:
|
common/views/components/language-settings.vue:
|
||||||
title: "Język"
|
title: "Język"
|
||||||
pick-language: "Wybierz język"
|
pick-language: "Wybierz język"
|
||||||
recommended: "Zalecane"
|
recommended: "Zalecane"
|
||||||
auto: "Automatyczny"
|
auto: "Automatyczny"
|
||||||
specify-language: "言語を指定"
|
specify-language: "Wybierz język"
|
||||||
info: "Musisz odświeżyć stronę, aby zmiany zostały uwzględnione."
|
info: "Musisz odświeżyć stronę, aby zmiany zostały uwzględnione."
|
||||||
common/views/components/profile-editor.vue:
|
common/views/components/profile-editor.vue:
|
||||||
title: "Twój profil"
|
title: "Twój profil"
|
||||||
@ -504,15 +507,15 @@ common/views/components/profile-editor.vue:
|
|||||||
upload-failed: "Wysyłanie nie powiodło się"
|
upload-failed: "Wysyłanie nie powiodło się"
|
||||||
email: "Ustawienia e-mail"
|
email: "Ustawienia e-mail"
|
||||||
email-address: "Adres e-mail"
|
email-address: "Adres e-mail"
|
||||||
email-verified: "メールアドレスが確認されました"
|
email-verified: "Twój adres e-mail został zweryfikowany."
|
||||||
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
|
||||||
common/views/components/user-list-editor.vue:
|
common/views/components/user-list-editor.vue:
|
||||||
users: "Użytkownicy"
|
users: "Użytkownicy"
|
||||||
rename: "Zmień nazwę listy"
|
rename: "Zmień nazwę listy"
|
||||||
delete: "Usuń listę"
|
delete: "Usuń listę"
|
||||||
remove-user: "Usuń z tej listy"
|
remove-user: "Usuń z tej listy"
|
||||||
delete-are-you-sure: "リスト「$1」を削除しますか?"
|
delete-are-you-sure: "Usunąć listę \"$1\"?"
|
||||||
deleted: "削除しました"
|
deleted: "Usunięto"
|
||||||
common/views/widgets/broadcast.vue:
|
common/views/widgets/broadcast.vue:
|
||||||
fetching: "Sprawdzanie"
|
fetching: "Sprawdzanie"
|
||||||
no-broadcasts: "Brak transmisji"
|
no-broadcasts: "Brak transmisji"
|
||||||
@ -595,7 +598,7 @@ desktop/views/components/activity.vue:
|
|||||||
title: "Aktywność"
|
title: "Aktywność"
|
||||||
toggle: "Przełącz widok"
|
toggle: "Przełącz widok"
|
||||||
desktop/views/components/calendar.vue:
|
desktop/views/components/calendar.vue:
|
||||||
title: "{year}年 {month}月"
|
title: "{year} / {month}"
|
||||||
prev: "Poprzedni miesiąc"
|
prev: "Poprzedni miesiąc"
|
||||||
next: "Następny miesiąc"
|
next: "Następny miesiąc"
|
||||||
go: "Naciśnij, aby przejść"
|
go: "Naciśnij, aby przejść"
|
||||||
@ -706,7 +709,7 @@ desktop/views/components/note.vue:
|
|||||||
add-reaction: "Dodaj reakcję"
|
add-reaction: "Dodaj reakcję"
|
||||||
undo-reaction: "リアクション解除"
|
undo-reaction: "リアクション解除"
|
||||||
detail: "Szczegóły"
|
detail: "Szczegóły"
|
||||||
private: "この投稿は非公開です"
|
private: "Ten wpis jest prywatny"
|
||||||
deleted: "この投稿は削除されました"
|
deleted: "この投稿は削除されました"
|
||||||
desktop/views/components/notes.vue:
|
desktop/views/components/notes.vue:
|
||||||
error: "Ładowanie nie powiodło się."
|
error: "Ładowanie nie powiodło się."
|
||||||
@ -1011,7 +1014,7 @@ admin/views/abuse.vue:
|
|||||||
target: "対象"
|
target: "対象"
|
||||||
reporter: "報告者"
|
reporter: "報告者"
|
||||||
details: "詳細"
|
details: "詳細"
|
||||||
remove-report: "削除"
|
remove-report: "Usuń"
|
||||||
admin/views/instance.vue:
|
admin/views/instance.vue:
|
||||||
instance: "インスタンス"
|
instance: "インスタンス"
|
||||||
instance-name: "インスタンス名"
|
instance-name: "インスタンス名"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "Conta verificada"
|
verified-user: "Conta verificada"
|
||||||
disable-animated-mfm: "Desativar texto animado nas publicações"
|
disable-animated-mfm: "Desativar texto animado nas publicações"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
always-show-nsfw: "常に閲覧注意のメディアを表示する"
|
||||||
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
always-mark-nsfw: "常にメディアを閲覧注意として投稿"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
use-avatar-reversi-stones: "リバーシの石にアバターを使う"
|
||||||
verified-user: "公式アカウント"
|
verified-user: "公式アカウント"
|
||||||
disable-animated-mfm: "Отключить анимированный текст в постах"
|
disable-animated-mfm: "Отключить анимированный текст в постах"
|
||||||
|
disable-showing-animated-images: "アニメーション画像を再生しない"
|
||||||
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
|
||||||
always-show-nsfw: "Всегда показывать NSFW контент"
|
always-show-nsfw: "Всегда показывать NSFW контент"
|
||||||
always-mark-nsfw: "Всегда помечать посты с медиафайлами как NSFW"
|
always-mark-nsfw: "Всегда помечать посты с медиафайлами как NSFW"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "リンクをコピー"
|
copy-link: "リンクをコピー"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
unfavorite: "お気に入り解除"
|
unfavorite: "お気に入り解除"
|
||||||
|
watch: "ウォッチ"
|
||||||
|
unwatch: "ウォッチ解除"
|
||||||
pin: "ピン留め"
|
pin: "ピン留め"
|
||||||
unpin: "ピン留め解除"
|
unpin: "ピン留め解除"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
|
@ -113,6 +113,7 @@ common:
|
|||||||
use-avatar-reversi-stones: "用头像作为黑白棋的棋子"
|
use-avatar-reversi-stones: "用头像作为黑白棋的棋子"
|
||||||
verified-user: "认证用户"
|
verified-user: "认证用户"
|
||||||
disable-animated-mfm: "在帖子中禁用动画文本"
|
disable-animated-mfm: "在帖子中禁用动画文本"
|
||||||
|
disable-showing-animated-images: "不播放动画"
|
||||||
suggest-recent-hashtags: "在帖子表单上显示最近流行的主题标签"
|
suggest-recent-hashtags: "在帖子表单上显示最近流行的主题标签"
|
||||||
always-show-nsfw: "总是显示 NSFW 的内容"
|
always-show-nsfw: "总是显示 NSFW 的内容"
|
||||||
always-mark-nsfw: "总是用 NSFW 来标记附件"
|
always-mark-nsfw: "总是用 NSFW 来标记附件"
|
||||||
@ -344,6 +345,8 @@ common/views/components/note-menu.vue:
|
|||||||
copy-link: "复制链接"
|
copy-link: "复制链接"
|
||||||
favorite: "收藏这个投稿"
|
favorite: "收藏这个投稿"
|
||||||
unfavorite: "取消收藏"
|
unfavorite: "取消收藏"
|
||||||
|
watch: "关注"
|
||||||
|
unwatch: "取消关注"
|
||||||
pin: "固定个人资料"
|
pin: "固定个人资料"
|
||||||
unpin: "解除固定"
|
unpin: "解除固定"
|
||||||
delete: "删除"
|
delete: "删除"
|
||||||
|
43
package.json
43
package.json
@ -1,14 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "10.81.0",
|
"version": "10.82.0",
|
||||||
"clientVersion": "2.0.14026",
|
"clientVersion": "2.0.14114",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/syuilo/misskey.git"
|
||||||
|
},
|
||||||
|
"main": "./index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./built",
|
"start": "node ./index.js",
|
||||||
"debug": "DEBUG=misskey:* node ./built",
|
"debug": "DEBUG=misskey:* node ./index.js",
|
||||||
"build": "webpack && gulp build",
|
"build": "webpack && gulp build",
|
||||||
"webpack": "webpack",
|
"webpack": "webpack",
|
||||||
"watch": "webpack --watch",
|
"watch": "webpack --watch",
|
||||||
@ -48,6 +52,7 @@
|
|||||||
"@types/is-svg": "3.0.0",
|
"@types/is-svg": "3.0.0",
|
||||||
"@types/is-url": "1.2.28",
|
"@types/is-url": "1.2.28",
|
||||||
"@types/js-yaml": "3.12.0",
|
"@types/js-yaml": "3.12.0",
|
||||||
|
"@types/jsdom": "12.2.1",
|
||||||
"@types/katex": "0.5.0",
|
"@types/katex": "0.5.0",
|
||||||
"@types/koa": "2.0.48",
|
"@types/koa": "2.0.48",
|
||||||
"@types/koa-bodyparser": "5.0.2",
|
"@types/koa-bodyparser": "5.0.2",
|
||||||
@ -94,7 +99,7 @@
|
|||||||
"@types/websocket": "0.0.40",
|
"@types/websocket": "0.0.40",
|
||||||
"@types/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
"animejs": "3.0.1",
|
"animejs": "3.0.1",
|
||||||
"apexcharts": "2.5.1",
|
"apexcharts": "3.2.1",
|
||||||
"autobind-decorator": "2.4.0",
|
"autobind-decorator": "2.4.0",
|
||||||
"autosize": "4.0.2",
|
"autosize": "4.0.2",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
@ -107,7 +112,7 @@
|
|||||||
"chalk": "2.4.2",
|
"chalk": "2.4.2",
|
||||||
"commander": "2.19.0",
|
"commander": "2.19.0",
|
||||||
"crc-32": "1.2.0",
|
"crc-32": "1.2.0",
|
||||||
"css-loader": "1.0.1",
|
"css-loader": "2.1.0",
|
||||||
"cssnano": "4.1.8",
|
"cssnano": "4.1.8",
|
||||||
"dateformat": "3.0.3",
|
"dateformat": "3.0.3",
|
||||||
"deep-equal": "1.0.1",
|
"deep-equal": "1.0.1",
|
||||||
@ -121,7 +126,7 @@
|
|||||||
"eslint-plugin-vue": "5.1.0",
|
"eslint-plugin-vue": "5.1.0",
|
||||||
"eventemitter3": "3.1.0",
|
"eventemitter3": "3.1.0",
|
||||||
"feed": "2.0.2",
|
"feed": "2.0.2",
|
||||||
"file-type": "10.7.0",
|
"file-type": "10.7.1",
|
||||||
"fuckadblock": "3.2.1",
|
"fuckadblock": "3.2.1",
|
||||||
"gulp": "4.0.0",
|
"gulp": "4.0.0",
|
||||||
"gulp-cssnano": "2.1.3",
|
"gulp-cssnano": "2.1.3",
|
||||||
@ -148,7 +153,7 @@
|
|||||||
"json5": "2.1.0",
|
"json5": "2.1.0",
|
||||||
"json5-loader": "1.0.1",
|
"json5-loader": "1.0.1",
|
||||||
"katex": "0.10.0",
|
"katex": "0.10.0",
|
||||||
"koa": "2.6.2",
|
"koa": "2.7.0",
|
||||||
"koa-bodyparser": "4.2.1",
|
"koa-bodyparser": "4.2.1",
|
||||||
"koa-compress": "3.0.0",
|
"koa-compress": "3.0.0",
|
||||||
"koa-favicon": "2.0.1",
|
"koa-favicon": "2.0.1",
|
||||||
@ -163,12 +168,12 @@
|
|||||||
"langmap": "0.0.16",
|
"langmap": "0.0.16",
|
||||||
"loader-utils": "1.2.3",
|
"loader-utils": "1.2.3",
|
||||||
"lookup-dns-cache": "2.1.0",
|
"lookup-dns-cache": "2.1.0",
|
||||||
"minio": "7.0.3",
|
"minio": "7.0.5",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"mocha": "5.2.0",
|
"mocha": "5.2.0",
|
||||||
"moji": "0.5.1",
|
"moji": "0.5.1",
|
||||||
"moment": "2.23.0",
|
"moment": "2.24.0",
|
||||||
"mongodb": "3.1.10",
|
"mongodb": "3.1.13",
|
||||||
"monk": "6.0.6",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.12.1",
|
"nan": "2.12.1",
|
||||||
@ -183,7 +188,7 @@
|
|||||||
"portscanner": "2.2.0",
|
"portscanner": "2.2.0",
|
||||||
"postcss-loader": "3.0.0",
|
"postcss-loader": "3.0.0",
|
||||||
"prismjs": "1.15.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-any": "0.2.0",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
"promise-sequential": "1.1.1",
|
"promise-sequential": "1.1.1",
|
||||||
@ -213,14 +218,14 @@
|
|||||||
"summaly": "2.2.0",
|
"summaly": "2.2.0",
|
||||||
"systeminformation": "3.54.0",
|
"systeminformation": "3.54.0",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"terser-webpack-plugin": "1.2.1",
|
"terser-webpack-plugin": "1.2.2",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"tinycolor2": "1.4.1",
|
"tinycolor2": "1.4.1",
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"ts-loader": "5.3.3",
|
"ts-loader": "5.3.3",
|
||||||
"ts-node": "7.0.1",
|
"ts-node": "7.0.1",
|
||||||
"tslint": "5.12.0",
|
"tslint": "5.12.0",
|
||||||
"tslint-sonarts": "1.8.0",
|
"tslint-sonarts": "1.9.0",
|
||||||
"typescript": "3.2.4",
|
"typescript": "3.2.4",
|
||||||
"typescript-eslint-parser": "21.0.2",
|
"typescript-eslint-parser": "21.0.2",
|
||||||
"uglify-es": "3.3.9",
|
"uglify-es": "3.3.9",
|
||||||
@ -228,23 +233,23 @@
|
|||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"v-animate-css": "0.0.3",
|
"v-animate-css": "0.0.3",
|
||||||
"video-thumbnail-generator": "1.1.3",
|
"video-thumbnail-generator": "1.1.3",
|
||||||
"vue": "2.5.17",
|
"vue": "2.6.2",
|
||||||
"vue-color": "2.7.0",
|
"vue-color": "2.7.0",
|
||||||
"vue-content-loading": "1.5.3",
|
"vue-content-loading": "1.5.3",
|
||||||
"vue-cropperjs": "3.0.0",
|
"vue-cropperjs": "3.0.0",
|
||||||
"vue-i18n": "8.8.0",
|
"vue-i18n": "8.8.0",
|
||||||
"vue-js-modal": "1.3.28",
|
"vue-js-modal": "1.3.28",
|
||||||
"vue-loader": "15.5.1",
|
"vue-loader": "15.6.2",
|
||||||
"vue-marquee-text-component": "1.1.1",
|
"vue-marquee-text-component": "1.1.1",
|
||||||
"vue-prism-component": "1.1.1",
|
"vue-prism-component": "1.1.1",
|
||||||
"vue-router": "3.0.2",
|
"vue-router": "3.0.2",
|
||||||
"vue-sequential-entrance": "1.1.3",
|
"vue-sequential-entrance": "1.1.3",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-svg-inline-loader": "1.2.10",
|
"vue-svg-inline-loader": "1.2.10",
|
||||||
"vue-template-compiler": "2.5.17",
|
"vue-template-compiler": "2.6.2",
|
||||||
"vuedraggable": "2.17.0",
|
"vuedraggable": "2.17.0",
|
||||||
"vuewordcloud": "18.7.11",
|
"vuewordcloud": "18.7.11",
|
||||||
"vuex": "3.0.1",
|
"vuex": "3.1.0",
|
||||||
"vuex-persistedstate": "2.5.4",
|
"vuex-persistedstate": "2.5.4",
|
||||||
"web-push": "3.3.3",
|
"web-push": "3.3.3",
|
||||||
"webfinger.js": "2.7.0",
|
"webfinger.js": "2.7.0",
|
||||||
|
3
src/@types/const.json.d.ts
vendored
Normal file
3
src/@types/const.json.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
declare module '*/const.json' {
|
||||||
|
const copyright: string;
|
||||||
|
}
|
2
src/@types/deepcopy.d.ts
vendored
2
src/@types/deepcopy.d.ts
vendored
@ -8,7 +8,7 @@ declare namespace deepcopy {
|
|||||||
valueType: DeepcopyCustomizerValueType) => T;
|
valueType: DeepcopyCustomizerValueType) => T;
|
||||||
|
|
||||||
interface DeepcopyOptions<T> {
|
interface DeepcopyOptions<T> {
|
||||||
customizer: DeepcopyCustomizer<T>
|
customizer: DeepcopyCustomizer<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deepcopy<T>(
|
export function deepcopy<T>(
|
||||||
|
7
src/@types/escape-regexp.d.ts
vendored
Normal file
7
src/@types/escape-regexp.d.ts
vendored
Normal 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
14
src/@types/koa-slow.d.ts
vendored
Normal 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
10
src/@types/langmap.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
declare module 'langmap' {
|
||||||
|
type Lang = {
|
||||||
|
nativeName: string;
|
||||||
|
englishName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const langmap: { [lang: string]: Lang };
|
||||||
|
|
||||||
|
export = langmap;
|
||||||
|
}
|
10
src/@types/nested-property.d.ts
vendored
10
src/@types/nested-property.d.ts
vendored
@ -1,3 +1,5 @@
|
|||||||
|
type Obj = { [key: string]: any };
|
||||||
|
|
||||||
declare module 'nested-property' {
|
declare module 'nested-property' {
|
||||||
interface IHasNestedPropertyOptions {
|
interface IHasNestedPropertyOptions {
|
||||||
own?: boolean;
|
own?: boolean;
|
||||||
@ -9,11 +11,11 @@ declare module 'nested-property' {
|
|||||||
|
|
||||||
export function set<T>(object: T, property: string, value: any): T;
|
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
30
src/@types/os-utils.d.ts
vendored
Normal 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;
|
||||||
|
}
|
9
src/@types/package.json.d.ts
vendored
9
src/@types/package.json.d.ts
vendored
@ -1,3 +1,10 @@
|
|||||||
declare module '*/package.json' {
|
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
16
src/@types/recaptcha-promise.d.ts
vendored
Normal 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;
|
||||||
|
}
|
15
src/argv.ts
Normal file
15
src/argv.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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-queue', 'Disable job queue')
|
||||||
|
.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);
|
||||||
|
|
||||||
|
export { program };
|
@ -21,7 +21,7 @@ export type Partial<T> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type ArrayValue<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';
|
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 collection: ICollection<Log<T>>;
|
||||||
protected abstract async getTemplate(init: boolean, latest?: T, group?: any): Promise<T>;
|
protected abstract async getTemplate(init: boolean, latest?: T, group?: any): Promise<T>;
|
||||||
private name: string;
|
private name: string;
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import * as tinycolor from 'tinycolor2';
|
import * as tinycolor from 'tinycolor2';
|
||||||
import * as ApexCharts from 'apexcharts';
|
import ApexCharts from 'apexcharts';
|
||||||
|
|
||||||
const limit = 90;
|
const limit = 90;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import * as ApexCharts from 'apexcharts';
|
import ApexCharts from 'apexcharts';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['connection'],
|
props: ['connection'],
|
||||||
|
@ -62,11 +62,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (settings && settings.device.lang &&
|
if (settings && settings.device.lang &&
|
||||||
langs.includes(settings.device.lang)) {
|
langs.includes(settings.device.lang))
|
||||||
|
{
|
||||||
lang = settings.device.lang;
|
lang = settings.device.lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.lang = lang;
|
localStorage.setItem('lang', lang);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Fetch locale data
|
//#region Fetch locale data
|
||||||
|
9
src/client/app/common/scripts/get-static-image-url.ts
Normal file
9
src/client/app/common/scripts/get-static-image-url.ts
Normal 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;
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
@ -47,6 +48,11 @@ export default Vue.extend({
|
|||||||
borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
|
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 {
|
icon(): any {
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.lightmode
|
backgroundColor: this.lightmode
|
||||||
@ -54,7 +60,7 @@ export default Vue.extend({
|
|||||||
: this.user.avatarColor && this.user.avatarColor.length == 3
|
: this.user.avatarColor && this.user.avatarColor.length == 3
|
||||||
? `rgb(${this.user.avatarColor.join(',')})`
|
? `rgb(${this.user.avatarColor.join(',')})`
|
||||||
: null,
|
: null,
|
||||||
backgroundImage: this.lightmode ? null : `url(${this.user.avatarUrl})`,
|
backgroundImage: this.lightmode ? null : `url(${this.url})`,
|
||||||
borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
|
borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import * as tinycolor from 'tinycolor2';
|
import * as tinycolor from 'tinycolor2';
|
||||||
import * as ApexCharts from 'apexcharts';
|
import ApexCharts from 'apexcharts';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('common/views/components/drive-settings.vue'),
|
i18n: i18n('common/views/components/drive-settings.vue'),
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
// スクリプトサイズがデカい
|
// スクリプトサイズがデカい
|
||||||
//import { lib } from 'emojilib';
|
//import { lib } from 'emojilib';
|
||||||
|
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: {
|
props: {
|
||||||
@ -54,7 +55,9 @@ export default Vue.extend({
|
|||||||
const customEmoji = this.customEmojis.find(x => x.name == this.name);
|
const customEmoji = this.customEmojis.find(x => x.name == this.name);
|
||||||
if (customEmoji) {
|
if (customEmoji) {
|
||||||
this.customEmoji = customEmoji;
|
this.customEmoji = customEmoji;
|
||||||
this.url = customEmoji.url;
|
this.url = this.$store.state.device.disableShowingAnimatedImages
|
||||||
|
? getStaticImageUrl(customEmoji.url)
|
||||||
|
: customEmoji.url;
|
||||||
} else {
|
} else {
|
||||||
//const emoji = lib[this.name];
|
//const emoji = lib[this.name];
|
||||||
//if (emoji) {
|
//if (emoji) {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
:title="media.name"
|
:title="media.name"
|
||||||
controls
|
controls
|
||||||
ref="audio"
|
ref="audio"
|
||||||
|
@volumechange="volumechange"
|
||||||
preload="metadata" />
|
preload="metadata" />
|
||||||
</div>
|
</div>
|
||||||
<a class="download" v-else
|
<a class="download" v-else
|
||||||
@ -40,7 +41,17 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
hide: true
|
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>
|
</script>
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import ImageViewer from './image-viewer.vue';
|
import ImageViewer from './image-viewer.vue';
|
||||||
|
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('common/views/components/media-image.vue'),
|
i18n: i18n('common/views/components/media-image.vue'),
|
||||||
@ -36,7 +37,11 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
computed: {
|
computed: {
|
||||||
style(): any {
|
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) {
|
if (this.$store.state.device.loadRemoteMedia || this.$store.state.device.lightmode) {
|
||||||
url = null;
|
url = null;
|
||||||
|
@ -10,73 +10,91 @@ import i18n from '../../../i18n';
|
|||||||
import { url } from '../../../config';
|
import { url } from '../../../config';
|
||||||
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
|
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
|
||||||
import { concat, intersperse } from '../../../../../prelude/array';
|
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({
|
export default Vue.extend({
|
||||||
i18n: i18n('common/views/components/note-menu.vue'),
|
i18n: i18n('common/views/components/note-menu.vue'),
|
||||||
props: ['note', 'source'],
|
props: ['note', 'source'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isFavorited: false,
|
||||||
|
isWatching: false
|
||||||
|
};
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
items(): any[] {
|
items(): any[] {
|
||||||
return concat(intersperse([null], [
|
return [{
|
||||||
[
|
|
||||||
[{
|
|
||||||
icon: 'at',
|
icon: 'at',
|
||||||
text: this.$t('mention'),
|
text: this.$t('mention'),
|
||||||
action: this.mention
|
action: this.mention
|
||||||
}]
|
}, null, {
|
||||||
],
|
|
||||||
[
|
|
||||||
[{
|
|
||||||
icon: 'info-circle',
|
icon: 'info-circle',
|
||||||
text: this.$t('detail'),
|
text: this.$t('detail'),
|
||||||
action: this.detail
|
action: this.detail
|
||||||
}], [{
|
}, {
|
||||||
icon: faCopy,
|
icon: faCopy,
|
||||||
text: this.$t('copy-content'),
|
text: this.$t('copy-content'),
|
||||||
action: this.copyContent
|
action: this.copyContent
|
||||||
}], [{
|
}, {
|
||||||
icon: 'link',
|
icon: 'link',
|
||||||
text: this.$t('copy-link'),
|
text: this.$t('copy-link'),
|
||||||
action: this.copyLink
|
action: this.copyLink
|
||||||
}], this.note.uri ? [{
|
}, this.note.uri ? {
|
||||||
icon: 'external-link-square-alt',
|
icon: 'external-link-square-alt',
|
||||||
text: this.$t('remote'),
|
text: this.$t('remote'),
|
||||||
action: () => {
|
action: () => {
|
||||||
window.open(this.note.uri, '_blank');
|
window.open(this.note.uri, '_blank');
|
||||||
}
|
}
|
||||||
}] : []
|
} : undefined,
|
||||||
],
|
null,
|
||||||
[
|
this.isFavorited ? {
|
||||||
this.note.isFavorited ? [{
|
|
||||||
icon: 'star',
|
icon: 'star',
|
||||||
text: this.$t('unfavorite'),
|
text: this.$t('unfavorite'),
|
||||||
action: this.unfavorite
|
action: () => this.toggleFavorite(false)
|
||||||
}] : [{
|
} : {
|
||||||
icon: 'star',
|
icon: 'star',
|
||||||
text: this.$t('favorite'),
|
text: this.$t('favorite'),
|
||||||
action: this.favorite
|
action: () => this.toggleFavorite(true)
|
||||||
}], this.note.userId == this.$store.state.i.id ? [
|
},
|
||||||
(this.$store.state.i.pinnedNoteIds || []).includes(this.note.id) ? {
|
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',
|
icon: 'thumbtack',
|
||||||
text: this.$t('unpin'),
|
text: this.$t('unpin'),
|
||||||
action: this.unpin
|
action: () => this.togglePin(false)
|
||||||
} : {
|
} : {
|
||||||
icon: 'thumbtack',
|
icon: 'thumbtack',
|
||||||
text: this.$t('pin'),
|
text: this.$t('pin'),
|
||||||
action: this.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, {
|
||||||
this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin || this.$store.state.i.isModerator ? [{
|
|
||||||
icon: ['far', 'trash-alt'],
|
icon: ['far', 'trash-alt'],
|
||||||
text: this.$t('delete'),
|
text: this.$t('delete'),
|
||||||
action: this.del
|
action: this.del
|
||||||
}] : []
|
}]
|
||||||
]
|
: []
|
||||||
].map(concat).filter(x => x.length > 0)));
|
)]
|
||||||
|
.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: {
|
methods: {
|
||||||
mention() {
|
mention() {
|
||||||
this.$post({ mention: this.note.user });
|
this.$post({ mention: this.note.user });
|
||||||
@ -102,8 +120,8 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
pin() {
|
togglePin(pin: boolean) {
|
||||||
this.$root.api('i/pin', {
|
this.$root.api(pin ? 'i/pin' : 'i/unpin', {
|
||||||
noteId: this.note.id
|
noteId: this.note.id
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$root.dialog({
|
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() {
|
del() {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
@ -138,8 +148,8 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
favorite() {
|
toggleFavorite(favorite: boolean) {
|
||||||
this.$root.api('notes/favorites/create', {
|
this.$root.api(favorite ? 'notes/favorites/create' : 'notes/favorites/delete', {
|
||||||
noteId: this.note.id
|
noteId: this.note.id
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
@ -150,8 +160,8 @@ export default Vue.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
unfavorite() {
|
toggleWatch(watch: boolean) {
|
||||||
this.$root.api('notes/favorites/delete', {
|
this.$root.api(watch ? 'notes/watching/create' : 'notes/watching/delete', {
|
||||||
noteId: this.note.id
|
noteId: this.note.id
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.$root.dialog({
|
this.$root.dialog({
|
||||||
|
@ -87,6 +87,14 @@
|
|||||||
<ui-button @click="updateEmail()">{{ $t('save') }}</ui-button>
|
<ui-button @click="updateEmail()">{{ $t('save') }}</ui-button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>{{ $t('export') }}</header>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<ui-button @click="exportNotes()">{{ $t('export-notes') }}</ui-button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</ui-card>
|
</ui-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -252,6 +260,15 @@ export default Vue.extend({
|
|||||||
email: this.email == '' ? null : this.email
|
email: this.email == '' ? null : this.email
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
exportNotes() {
|
||||||
|
this.$root.api('i/export-notes', {});
|
||||||
|
|
||||||
|
this.$root.dialog({
|
||||||
|
type: 'info',
|
||||||
|
text: this.$t('export-requested')
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
<p :class="$style.fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
|
<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 :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"
|
:class="$style.img"
|
||||||
:style="`background-image: url(${image.thumbnailUrl || image.url})`"
|
:style="`background-image: url(${thumbnail(image)})`"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
@dragstart="onDragstart(image, $event)"
|
@dragstart="onDragstart(image, $event)"
|
||||||
></div>
|
></div>
|
||||||
@ -20,6 +20,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import define from '../../../common/define-widget';
|
import define from '../../../common/define-widget';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
|
import { getStaticImageUrl } from '../../scripts/get-static-image-url';
|
||||||
|
|
||||||
export default define({
|
export default define({
|
||||||
name: 'photo-stream',
|
name: 'photo-stream',
|
||||||
@ -77,6 +78,12 @@ export default define({
|
|||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
e.dataTransfer.setData('mk_drive_file', JSON.stringify(file));
|
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>
|
</script>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
declare const _LANGS_: string[];
|
declare const _LANGS_: string[];
|
||||||
declare const _THEME_COLOR_: string;
|
|
||||||
declare const _COPYRIGHT_: string;
|
declare const _COPYRIGHT_: string;
|
||||||
declare const _VERSION_: string;
|
declare const _VERSION_: string;
|
||||||
declare const _CLIENT_VERSION_: string;
|
declare const _CLIENT_VERSION_: string;
|
||||||
@ -13,7 +12,7 @@ export const hostname = address.hostname;
|
|||||||
export const url = address.origin;
|
export const url = address.origin;
|
||||||
export const apiUrl = url + '/api';
|
export const apiUrl = url + '/api';
|
||||||
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
|
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 langs = _LANGS_;
|
||||||
export const locale = JSON.parse(localStorage.getItem('locale'));
|
export const locale = JSON.parse(localStorage.getItem('locale'));
|
||||||
export const copyright = _COPYRIGHT_;
|
export const copyright = _COPYRIGHT_;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-media-video-dialog">
|
<div class="mk-media-video-dialog">
|
||||||
<div class="bg" @click="close"></div>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -18,8 +18,9 @@ export default Vue.extend({
|
|||||||
duration: 100,
|
duration: 100,
|
||||||
easing: 'linear'
|
easing: 'linear'
|
||||||
});
|
});
|
||||||
const videoTag = this.$refs.video as HTMLVideoElement
|
const videoTag = this.$refs.video as HTMLVideoElement;
|
||||||
if (this.start) videoTag.currentTime = this.start
|
if (this.start) videoTag.currentTime = this.start
|
||||||
|
videoTag.volume = this.$store.state.device.mediaVolume;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
close() {
|
close() {
|
||||||
@ -30,7 +31,11 @@ export default Vue.extend({
|
|||||||
easing: 'linear',
|
easing: 'linear',
|
||||||
complete: () => this.destroyDom()
|
complete: () => this.destroyDom()
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
volumechange() {
|
||||||
|
const videoTag = this.$refs.video as HTMLVideoElement;
|
||||||
|
this.$store.commit('device/set', { key: 'mediaVolume', value: videoTag.volume });
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -49,6 +49,7 @@ export default Vue.extend({
|
|||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.qiziqtywpuaucsgarwajitwaakggnisj
|
.qiziqtywpuaucsgarwajitwaakggnisj
|
||||||
display flex
|
display flex
|
||||||
|
overflow hidden
|
||||||
font-size 0.9em
|
font-size 0.9em
|
||||||
|
|
||||||
> .avatar
|
> .avatar
|
||||||
|
@ -144,11 +144,12 @@ export default Vue.extend({
|
|||||||
.note
|
.note
|
||||||
margin 0
|
margin 0
|
||||||
padding 0
|
padding 0
|
||||||
|
overflow hidden
|
||||||
background var(--face)
|
background var(--face)
|
||||||
border-bottom solid var(--lineWidth) var(--faceDivider)
|
border-bottom solid var(--lineWidth) var(--faceDivider)
|
||||||
|
|
||||||
&.mini
|
&.mini
|
||||||
font-size 13px
|
font-size 14px
|
||||||
|
|
||||||
> .renote
|
> .renote
|
||||||
padding 8px 16px 0 16px
|
padding 8px 16px 0 16px
|
||||||
|
@ -117,6 +117,7 @@
|
|||||||
<ui-switch v-model="showReplyTarget">{{ $t('show-reply-target') }}</ui-switch>
|
<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="showMaps">{{ $t('show-maps') }}</ui-switch>
|
||||||
<ui-switch v-model="disableAnimatedMfm">{{ $t('@.disable-animated-mfm') }}</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>
|
<ui-switch v-model="remainDeletedNote">{{ $t('remain-deleted-note') }}</ui-switch>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
@ -516,6 +517,11 @@ export default Vue.extend({
|
|||||||
set(value) { this.$store.dispatch('settings/set', { key: 'disableAnimatedMfm', value }); }
|
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: {
|
remainDeletedNote: {
|
||||||
get() { return this.$store.state.settings.remainDeletedNote; },
|
get() { return this.$store.state.settings.remainDeletedNote; },
|
||||||
set(value) { this.$store.dispatch('settings/set', { key: 'remainDeletedNote', value }); }
|
set(value) { this.$store.dispatch('settings/set', { key: 'remainDeletedNote', value }); }
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import XColumn from './deck.column.vue';
|
import XColumn from './deck.column.vue';
|
||||||
import XHashtagTl from './deck.hashtag-tl.vue';
|
import XHashtagTl from './deck.hashtag-tl.vue';
|
||||||
import * as ApexCharts from 'apexcharts';
|
import ApexCharts from 'apexcharts';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
|
@ -99,7 +99,7 @@ import XNotes from './deck.notes.vue';
|
|||||||
import XNote from '../../components/note.vue';
|
import XNote from '../../components/note.vue';
|
||||||
import XUserMenu from '../../../../common/views/components/user-menu.vue';
|
import XUserMenu from '../../../../common/views/components/user-menu.vue';
|
||||||
import { concat } from '../../../../../../prelude/array';
|
import { concat } from '../../../../../../prelude/array';
|
||||||
import * as ApexCharts from 'apexcharts';
|
import ApexCharts from 'apexcharts';
|
||||||
|
|
||||||
const fetchLimit = 10;
|
const fetchLimit = 10;
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<p class="title"><fa icon="camera"/>{{ $t('title') }}</p>
|
<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>
|
<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 class="stream" v-if="!fetching && images.length > 0">
|
||||||
<div v-for="image in images" class="img"
|
<div v-for="(image, i) in images" :key="i" class="img"
|
||||||
:style="`background-image: url(${image.thumbnailUrl})`"
|
:style="`background-image: url(${thumbnail(image)})`"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="empty" v-if="!fetching && images.length == 0">{{ $t('no-photos') }}</p>
|
<p class="empty" v-if="!fetching && images.length == 0">{{ $t('no-photos') }}</p>
|
||||||
@ -14,6 +14,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../../i18n';
|
import i18n from '../../../../i18n';
|
||||||
|
import { getStaticImageUrl } from '../../../../common/scripts/get-static-image-url';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('desktop/views/pages/user/user.photos.vue'),
|
i18n: i18n('desktop/views/pages/user/user.photos.vue'),
|
||||||
props: ['user'],
|
props: ['user'],
|
||||||
@ -44,7 +46,14 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
methods: {
|
||||||
|
thumbnail(image: any): string {
|
||||||
|
return this.$store.state.device.disableShowingAnimatedImages
|
||||||
|
? getStaticImageUrl(image.thumbnailUrl)
|
||||||
|
: image.thumbnailUrl;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { EventEmitter } from 'eventemitter3';
|
|||||||
import * as uuid from 'uuid';
|
import * as uuid from 'uuid';
|
||||||
|
|
||||||
import initStore from './store';
|
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 Progress from './common/scripts/loading';
|
||||||
|
|
||||||
import Err from './common/views/components/connect-failed.vue';
|
import Err from './common/views/components/connect-failed.vue';
|
||||||
@ -172,7 +172,7 @@ export default class MiOS extends EventEmitter {
|
|||||||
callback();
|
callback();
|
||||||
|
|
||||||
// Init service worker
|
// Init service worker
|
||||||
//if (this.shouldRegisterSw) this.registerSw();
|
if (this.shouldRegisterSw) this.registerSw();
|
||||||
};
|
};
|
||||||
|
|
||||||
// キャッシュがあったとき
|
// キャッシュがあったとき
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import * as ApexCharts from 'apexcharts';
|
import ApexCharts from 'apexcharts';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['user'],
|
props: ['user'],
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="mk-note-card">
|
<div class="mk-note-card">
|
||||||
<a :href="note | notePage">
|
<a :href="note | notePage">
|
||||||
<header>
|
<header>
|
||||||
<img :src="note.user.avatarUrl" alt="avatar"/>
|
<img :src="avator" alt="avatar"/>
|
||||||
<h3><mk-user-name :user="note.user"/></h3>
|
<h3><mk-user-name :user="note.user"/></h3>
|
||||||
</header>
|
</header>
|
||||||
<div>
|
<div>
|
||||||
@ -16,13 +16,19 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import summary from '../../../../../misc/get-note-summary';
|
import summary from '../../../../../misc/get-note-summary';
|
||||||
|
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['note'],
|
props: ['note'],
|
||||||
computed: {
|
computed: {
|
||||||
text(): string {
|
text(): string {
|
||||||
return summary(this.note);
|
return summary(this.note);
|
||||||
}
|
},
|
||||||
|
avator(): string {
|
||||||
|
return this.$store.state.device.disableShowingAnimatedImages
|
||||||
|
? getStaticImageUrl(this.note.user.avatarUrl)
|
||||||
|
: this.note.user.avatarUrl;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -40,6 +40,7 @@ export default Vue.extend({
|
|||||||
display flex
|
display flex
|
||||||
margin 0
|
margin 0
|
||||||
padding 0
|
padding 0
|
||||||
|
overflow hidden
|
||||||
font-size 10px
|
font-size 10px
|
||||||
|
|
||||||
@media (min-width 350px)
|
@media (min-width 350px)
|
||||||
|
@ -102,6 +102,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.note
|
.note
|
||||||
|
overflow hidden
|
||||||
font-size 12px
|
font-size 12px
|
||||||
border-bottom solid var(--lineWidth) var(--faceDivider)
|
border-bottom solid var(--lineWidth) var(--faceDivider)
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
<ui-switch v-model="useOsDefaultEmojis">{{ $t('@.use-os-default-emojis') }}</ui-switch>
|
<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="iLikeSushi">{{ $t('@.i-like-sushi') }}</ui-switch>
|
||||||
<ui-switch v-model="disableAnimatedMfm">{{ $t('@.disable-animated-mfm') }}</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="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>
|
<ui-switch v-model="alwaysShowNsfw">{{ $t('@.always-show-nsfw') }} ({{ $t('@.this-setting-is-this-device-only') }})</ui-switch>
|
||||||
</section>
|
</section>
|
||||||
@ -313,6 +314,11 @@ export default Vue.extend({
|
|||||||
set(value) { this.$store.dispatch('settings/set', { key: 'disableAnimatedMfm', value }); }
|
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: {
|
showReplyTarget: {
|
||||||
get() { return this.$store.state.settings.showReplyTarget; },
|
get() { return this.$store.state.settings.showReplyTarget; },
|
||||||
set(value) { this.$store.dispatch('settings/set', { key: 'showReplyTarget', value }); }
|
set(value) { this.$store.dispatch('settings/set', { key: 'showReplyTarget', value }); }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<mk-ui>
|
<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"/>
|
<mk-user-name :user="user"/>
|
||||||
</template>
|
</template>
|
||||||
<main v-if="!fetching">
|
<main v-if="!fetching">
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<a class="avatar">
|
<a class="avatar">
|
||||||
<img :src="user.avatarUrl" alt="avatar"/>
|
<img :src="avator" alt="avatar"/>
|
||||||
</a>
|
</a>
|
||||||
<button class="menu" ref="menu" @click="menu"><fa icon="ellipsis-h"/></button>
|
<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"/>
|
<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 Progress from '../../../common/scripts/loading';
|
||||||
import XUserMenu from '../../../common/views/components/user-menu.vue';
|
import XUserMenu from '../../../common/views/components/user-menu.vue';
|
||||||
import XHome from './user/home.vue';
|
import XHome from './user/home.vue';
|
||||||
|
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('mobile/views/pages/user.vue'),
|
i18n: i18n('mobile/views/pages/user.vue'),
|
||||||
@ -99,6 +100,11 @@ export default Vue.extend({
|
|||||||
age(): number {
|
age(): number {
|
||||||
return age(this.user.profile.birthday);
|
return age(this.user.profile.birthday);
|
||||||
},
|
},
|
||||||
|
avator(): string {
|
||||||
|
return this.$store.state.device.disableShowingAnimatedImages
|
||||||
|
? getStaticImageUrl(this.user.avatarUrl)
|
||||||
|
: this.user.avatarUrl;
|
||||||
|
},
|
||||||
style(): any {
|
style(): any {
|
||||||
if (this.user.bannerUrl == null) return {};
|
if (this.user.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
<div class="root photos">
|
<div class="root photos">
|
||||||
<p class="initializing" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></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 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"
|
class="img"
|
||||||
:style="`background-image: url(${image.media.thumbnailUrl})`"
|
:style="`background-image: url(${thumbnail(image.media)})`"
|
||||||
:href="image.note | notePage"
|
:href="image.note | notePage"
|
||||||
></a>
|
></a>
|
||||||
</div>
|
</div>
|
||||||
@ -15,6 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../../i18n';
|
import i18n from '../../../../i18n';
|
||||||
|
import { getStaticImageUrl } from '../../../../common/scripts/get-static-image-url';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('mobile/views/pages/user/home.photos.vue'),
|
i18n: i18n('mobile/views/pages/user/home.photos.vue'),
|
||||||
@ -50,7 +51,14 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
methods: {
|
||||||
|
thumbnail(image: any): string {
|
||||||
|
return this.$store.state.device.disableShowingAnimatedImages
|
||||||
|
? getStaticImageUrl(image.thumbnailUrl)
|
||||||
|
: image.thumbnailUrl;
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ import createPersistedState from 'vuex-persistedstate';
|
|||||||
import * as nestedProperty from 'nested-property';
|
import * as nestedProperty from 'nested-property';
|
||||||
|
|
||||||
import MiOS from './mios';
|
import MiOS from './mios';
|
||||||
import { hostname } from './config';
|
|
||||||
import { erase } from '../../prelude/array';
|
import { erase } from '../../prelude/array';
|
||||||
import getNoteSummary from '../../misc/get-note-summary';
|
import getNoteSummary from '../../misc/get-note-summary';
|
||||||
|
|
||||||
@ -56,6 +55,7 @@ const defaultDeviceSettings = {
|
|||||||
themes: [],
|
themes: [],
|
||||||
enableSounds: true,
|
enableSounds: true,
|
||||||
soundVolume: 0.5,
|
soundVolume: 0.5,
|
||||||
|
mediaVolume: 0.5,
|
||||||
lang: null,
|
lang: null,
|
||||||
preventUpdate: false,
|
preventUpdate: false,
|
||||||
debug: false,
|
debug: false,
|
||||||
@ -69,7 +69,8 @@ const defaultDeviceSettings = {
|
|||||||
mobileNotificationPosition: 'bottom',
|
mobileNotificationPosition: 'bottom',
|
||||||
deckTemporaryColumn: null,
|
deckTemporaryColumn: null,
|
||||||
deckDefault: false,
|
deckDefault: false,
|
||||||
useOsDefaultEmojis: false
|
useOsDefaultEmojis: false,
|
||||||
|
disableShowingAnimatedImages: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (os: MiOS) => new Vuex.Store({
|
export default (os: MiOS) => new Vuex.Store({
|
||||||
|
@ -3,7 +3,7 @@ import * as sysUtils from 'systeminformation';
|
|||||||
import * as diskusage from 'diskusage';
|
import * as diskusage from 'diskusage';
|
||||||
import * as Deque from 'double-ended-queue';
|
import * as Deque from 'double-ended-queue';
|
||||||
import Xev from 'xev';
|
import Xev from 'xev';
|
||||||
const osUtils = require('os-utils');
|
import * as osUtils from 'os-utils';
|
||||||
|
|
||||||
const ev = new Xev();
|
const ev = new Xev();
|
||||||
|
|
||||||
|
87
src/index.ts
87
src/index.ts
@ -12,9 +12,6 @@ import chalk from 'chalk';
|
|||||||
import * as portscanner from 'portscanner';
|
import * as portscanner from 'portscanner';
|
||||||
import * as isRoot from 'is-root';
|
import * as isRoot from 'is-root';
|
||||||
import Xev from 'xev';
|
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 Logger from './misc/logger';
|
||||||
import serverStats from './daemons/server-stats';
|
import serverStats from './daemons/server-stats';
|
||||||
@ -23,21 +20,15 @@ import loadConfig from './config/load';
|
|||||||
import { Config } from './config/types';
|
import { Config } from './config/types';
|
||||||
import { lessThan } from './prelude/array';
|
import { lessThan } from './prelude/array';
|
||||||
import * as pkg from '../package.json';
|
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 logger = new Logger('core', 'cyan');
|
||||||
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
||||||
const clusterLog = logger.createSubLogger('cluster', 'orange');
|
const clusterLog = logger.createSubLogger('cluster', 'orange');
|
||||||
const ev = new Xev();
|
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
|
* Init process
|
||||||
*/
|
*/
|
||||||
@ -70,16 +61,20 @@ async function masterMain() {
|
|||||||
|
|
||||||
if (!program.quiet) {
|
if (!program.quiet) {
|
||||||
//#region Misskey logo
|
//#region Misskey logo
|
||||||
|
const v = `v${pkg.version}`;
|
||||||
console.log(' _____ _ _ ');
|
console.log(' _____ _ _ ');
|
||||||
console.log('| |_|___ ___| |_ ___ _ _ ');
|
console.log(' | |_|___ ___| |_ ___ _ _ ');
|
||||||
console.log('| | | | |_ -|_ -| \'_| -_| | |');
|
console.log(' | | | | |_ -|_ -| \'_| -_| | |');
|
||||||
console.log('|_|_|_|_|___|___|_,_|___|_ |');
|
console.log(' |_|_|_|_|___|___|_,_|___|_ |');
|
||||||
console.log(' |___|\n');
|
console.log(' ' + chalk.gray(v) + (' |___|\n'.substr(v.length)));
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(chalk`${os.hostname()} {gray (PID: ${process.pid.toString()})}`);
|
||||||
|
|
||||||
bootLogger.info('Welcome to Misskey!');
|
bootLogger.info('Welcome to Misskey!');
|
||||||
bootLogger.info(`Misskey v${pkg.version}`, true);
|
bootLogger.info(`Misskey v${pkg.version}`, true);
|
||||||
|
bootLogger.info('Misskey is maintained by @syuilo, @AyaMorisawa, @mei23, and @acid-chicken.');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// initialize app
|
// initialize app
|
||||||
@ -105,6 +100,9 @@ async function workerMain() {
|
|||||||
// start server
|
// start server
|
||||||
await require('./server').default();
|
await require('./server').default();
|
||||||
|
|
||||||
|
// start processor
|
||||||
|
require('./queue').default();
|
||||||
|
|
||||||
if (cluster.isWorker) {
|
if (cluster.isWorker) {
|
||||||
// Send a 'ready' message to parent process
|
// Send a 'ready' message to parent process
|
||||||
process.send('ready');
|
process.send('ready');
|
||||||
@ -123,18 +121,6 @@ async function isPortAvailable(port: number): Promise<boolean> {
|
|||||||
return await portscanner.checkPortStatus(port, '127.0.0.1') === 'closed';
|
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 {
|
function showEnvironment(): void {
|
||||||
const env = process.env.NODE_ENV;
|
const env = process.env.NODE_ENV;
|
||||||
const logger = bootLogger.createSubLogger('env');
|
const logger = bootLogger.createSubLogger('env');
|
||||||
@ -159,11 +145,11 @@ async function init(): Promise<Config> {
|
|||||||
nodejsLogger.info(`Version ${runningNodejsVersion.join('.')}`);
|
nodejsLogger.info(`Version ${runningNodejsVersion.join('.')}`);
|
||||||
|
|
||||||
if (!satisfyNodejsVersion) {
|
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);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
await showMachine();
|
await showMachineInfo(bootLogger);
|
||||||
|
|
||||||
const configLogger = bootLogger.createSubLogger('config');
|
const configLogger = bootLogger.createSubLogger('config');
|
||||||
let config;
|
let config;
|
||||||
@ -176,7 +162,7 @@ async function init(): Promise<Config> {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (exception.code === 'ENOENT') {
|
if (exception.code === 'ENOENT') {
|
||||||
configLogger.error('Configuration file not found');
|
configLogger.error('Configuration file not found', true);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
throw exception;
|
throw exception;
|
||||||
@ -185,12 +171,12 @@ async function init(): Promise<Config> {
|
|||||||
configLogger.succ('Loaded');
|
configLogger.succ('Loaded');
|
||||||
|
|
||||||
if (config.port == null) {
|
if (config.port == null) {
|
||||||
bootLogger.error('The port is not configured. Please configure port.');
|
bootLogger.error('The port is not configured. Please configure port.', true);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
|
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
|
||||||
bootLogger.error('You need root privileges to listen on well-known port on Linux');
|
bootLogger.error('You need root privileges to listen on well-known port on Linux', true);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,33 +186,14 @@ async function init(): Promise<Config> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try to connect to MongoDB
|
// Try to connect to MongoDB
|
||||||
await checkMongoDB(config);
|
try {
|
||||||
|
await checkMongoDB(config, bootLogger);
|
||||||
return config;
|
} catch (e) {
|
||||||
}
|
bootLogger.error('Cannot connect to database', true);
|
||||||
|
|
||||||
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);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}).catch(err => {
|
return config;
|
||||||
mongoDBLogger.error(err.message);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function spawnWorkers(limit: number = Infinity) {
|
async function spawnWorkers(limit: number = Infinity) {
|
||||||
@ -250,12 +217,12 @@ function spawnWorker(): Promise<void> {
|
|||||||
|
|
||||||
// Listen new workers
|
// Listen new workers
|
||||||
cluster.on('fork', worker => {
|
cluster.on('fork', worker => {
|
||||||
clusterLog.info(`Process forked: [${worker.id}]`);
|
clusterLog.debug(`Process forked: [${worker.id}]`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen online workers
|
// Listen online workers
|
||||||
cluster.on('online', worker => {
|
cluster.on('online', worker => {
|
||||||
clusterLog.succ(`Process is now online: [${worker.id}]`);
|
clusterLog.debug(`Process is now online: [${worker.id}]`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for dying workers
|
// Listen for dying workers
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
const jsdom = require('jsdom');
|
import { JSDOM } from 'jsdom';
|
||||||
const { JSDOM } = jsdom;
|
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { INote } from '../models/note';
|
import { INote } from '../models/note';
|
||||||
import { intersperse } from '../prelude/array';
|
import { intersperse } from '../prelude/array';
|
||||||
@ -158,9 +157,9 @@ export function toHtml(tokens: MfmForest, mentionedRemoteUsers: INote['mentioned
|
|||||||
|
|
||||||
text(token) {
|
text(token) {
|
||||||
const el = doc.createElement('span');
|
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);
|
el.appendChild(x === 'br' ? doc.createElement('br') : x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
export default (acct: string) => {
|
import Acct from './type';
|
||||||
|
|
||||||
|
export default (acct: string): Acct => {
|
||||||
if (acct.startsWith('@')) acct = acct.substr(1);
|
if (acct.startsWith('@')) acct = acct.substr(1);
|
||||||
const split = acct.split('@', 2);
|
const split = acct.split('@', 2);
|
||||||
return { username: split[0], host: split[1] || null };
|
return { username: split[0], host: split[1] || null };
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
type UserLike = {
|
import Acct from './type';
|
||||||
host: string;
|
|
||||||
username: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default (user: UserLike) => {
|
export default (user: Acct) => {
|
||||||
return user.host === null ? user.username : `${user.username}@${user.host}`;
|
return user.host === null ? user.username : `${user.username}@${user.host}`;
|
||||||
};
|
};
|
||||||
|
6
src/misc/acct/type.ts
Normal file
6
src/misc/acct/type.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
type Acct = {
|
||||||
|
username: string;
|
||||||
|
host: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Acct;
|
37
src/misc/check-mongodb.ts
Normal file
37
src/misc/check-mongodb.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
import * as cluster from 'cluster';
|
import * as cluster from 'cluster';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import * as dateformat from 'dateformat';
|
import * as dateformat from 'dateformat';
|
||||||
|
import { program } from '../argv';
|
||||||
const quiet = process.argv.find(x => x == '--quiet');
|
|
||||||
|
|
||||||
export default class Logger {
|
export default class Logger {
|
||||||
private domain: string;
|
private domain: string;
|
||||||
@ -20,21 +19,22 @@ export default class Logger {
|
|||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public log(level: string, message: string, important = false): void {
|
private log(level: string, message: string, important = false, subDomains: string[] = []): void {
|
||||||
if (quiet) return;
|
if (program.quiet) return;
|
||||||
const domain = this.color ? chalk.keyword(this.color)(this.domain) : chalk.white(this.domain);
|
const domain = this.color ? chalk.keyword(this.color)(this.domain) : chalk.white(this.domain);
|
||||||
|
const domains = [domain].concat(subDomains);
|
||||||
if (this.parentLogger) {
|
if (this.parentLogger) {
|
||||||
this.parentLogger.log(level, `[${domain}]\t${message}`, important);
|
this.parentLogger.log(level, message, important, domains);
|
||||||
} else {
|
} else {
|
||||||
const time = dateformat(new Date(), 'HH:MM:ss');
|
const time = dateformat(new Date(), 'HH:MM:ss');
|
||||||
const process = cluster.isMaster ? '*' : cluster.worker.id;
|
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);
|
console.log(important ? chalk.bold(log) : log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public error(message: string | Error, important = false): void { // 実行を継続できない状況で使う
|
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 { // 実行を継続できるが改善すべき状況で使う
|
public warn(message: string, important = false): void { // 実行を継続できるが改善すべき状況で使う
|
||||||
@ -42,16 +42,16 @@ export default class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public succ(message: string, important = false): void { // 何かに成功した状況で使う
|
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 { // それ以外
|
public info(message: string, important = false): void { // それ以外
|
||||||
this.log(chalk.blue('INFO'), message, important);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
15
src/misc/show-machine-info.ts
Normal file
15
src/misc/show-machine-info.ts
Normal 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)`);
|
||||||
|
}
|
@ -27,11 +27,11 @@ export interface IReversiGame {
|
|||||||
isEnded: boolean;
|
isEnded: boolean;
|
||||||
winnerId: mongo.ObjectID;
|
winnerId: mongo.ObjectID;
|
||||||
surrendered: mongo.ObjectID;
|
surrendered: mongo.ObjectID;
|
||||||
logs: Array<{
|
logs: {
|
||||||
at: Date;
|
at: Date;
|
||||||
color: boolean;
|
color: boolean;
|
||||||
pos: number;
|
pos: number;
|
||||||
}>;
|
}[];
|
||||||
settings: {
|
settings: {
|
||||||
map: string[];
|
map: string[];
|
||||||
bw: string | number;
|
bw: string | number;
|
||||||
|
@ -209,7 +209,7 @@ export type IMeta = {
|
|||||||
remoteDriveCapacityMb?: number;
|
remoteDriveCapacityMb?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Max allowed note text length in charactors
|
* Max allowed note text length in characters
|
||||||
*/
|
*/
|
||||||
maxNoteTextLength?: number;
|
maxNoteTextLength?: number;
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import { pack as packApp } from './app';
|
|||||||
import PollVote from './poll-vote';
|
import PollVote from './poll-vote';
|
||||||
import Reaction from './note-reaction';
|
import Reaction from './note-reaction';
|
||||||
import { packMany as packFileMany, IDriveFile } from './drive-file';
|
import { packMany as packFileMany, IDriveFile } from './drive-file';
|
||||||
import Favorite from './favorite';
|
|
||||||
import Following from './following';
|
import Following from './following';
|
||||||
import Emoji from './emoji';
|
import Emoji from './emoji';
|
||||||
|
|
||||||
@ -52,11 +51,11 @@ export type INote = {
|
|||||||
repliesCount: number;
|
repliesCount: number;
|
||||||
reactionCounts: any;
|
reactionCounts: any;
|
||||||
mentions: mongo.ObjectID[];
|
mentions: mongo.ObjectID[];
|
||||||
mentionedRemoteUsers: Array<{
|
mentionedRemoteUsers: {
|
||||||
uri: string;
|
uri: string;
|
||||||
username: string;
|
username: string;
|
||||||
host: string;
|
host: string;
|
||||||
}>;
|
}[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* public ... 公開
|
* public ... 公開
|
||||||
@ -346,19 +345,6 @@ export const pack = async (
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// isFavorited
|
|
||||||
_note.isFavorited = (async () => {
|
|
||||||
const favorite = await Favorite
|
|
||||||
.count({
|
|
||||||
userId: meId,
|
|
||||||
noteId: id
|
|
||||||
}, {
|
|
||||||
limit: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
return favorite === 1;
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,43 @@
|
|||||||
import http from './processors/http';
|
import * as Queue from 'bee-queue';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
import { ILocalUser } from '../models/user';
|
import { ILocalUser } from '../models/user';
|
||||||
import Logger from '../misc/logger';
|
import { program } from '../argv';
|
||||||
|
import handler from './processors';
|
||||||
|
|
||||||
|
const enableQueue = config.redis != null && !program.disableQueue;
|
||||||
|
|
||||||
|
const queue = initializeQueue();
|
||||||
|
|
||||||
|
function initializeQueue() {
|
||||||
|
if (enableQueue) {
|
||||||
|
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 createHttpJob(data: any) {
|
export function createHttpJob(data: any) {
|
||||||
return http({ data }, () => {});
|
if (enableQueue) {
|
||||||
|
return queue.createJob(data)
|
||||||
|
.retries(4)
|
||||||
|
.backoff('exponential', 16384) // 16s
|
||||||
|
.save();
|
||||||
|
} else {
|
||||||
|
return handler({ data }, () => {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deliver(user: ILocalUser, content: any, to: any) {
|
export function deliver(user: ILocalUser, content: any, to: any) {
|
||||||
@ -17,4 +51,18 @@ export function deliver(user: ILocalUser, content: any, to: any) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const queueLogger = new Logger('queue');
|
export function createExportNotesJob(user: ILocalUser) {
|
||||||
|
if (!enableQueue) throw 'queue disabled';
|
||||||
|
|
||||||
|
return queue.createJob({
|
||||||
|
type: 'exportNotes',
|
||||||
|
user: user
|
||||||
|
})
|
||||||
|
.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function() {
|
||||||
|
if (enableQueue) {
|
||||||
|
queue.process(128, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
3
src/queue/logger.ts
Normal file
3
src/queue/logger.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Logger from '../misc/logger';
|
||||||
|
|
||||||
|
export const queueLogger = new Logger('queue', 'orange');
|
128
src/queue/processors/export-notes.ts
Normal file
128
src/queue/processors/export-notes.ts
Normal 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
|
||||||
|
};
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import * as bq from 'bee-queue';
|
import * as bq from 'bee-queue';
|
||||||
|
|
||||||
import request from '../../../remote/activitypub/request';
|
import request from '../../../remote/activitypub/request';
|
||||||
import { queueLogger } from '../..';
|
import { queueLogger } from '../../logger';
|
||||||
|
|
||||||
export default async (job: bq.Job, done: any): Promise<void> => {
|
export default async (job: bq.Job, done: any): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
|
@ -6,7 +6,7 @@ import perform from '../../../remote/activitypub/perform';
|
|||||||
import { resolvePerson, updatePerson } from '../../../remote/activitypub/models/person';
|
import { resolvePerson, updatePerson } from '../../../remote/activitypub/models/person';
|
||||||
import { toUnicode } from 'punycode';
|
import { toUnicode } from 'punycode';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
import { publishApLogStream } from '../../../stream';
|
import { publishApLogStream } from '../../../services/stream';
|
||||||
import Logger from '../../../misc/logger';
|
import Logger from '../../../misc/logger';
|
||||||
|
|
||||||
const logger = new Logger('inbox');
|
const logger = new Logger('inbox');
|
||||||
@ -20,7 +20,7 @@ export default async (job: bq.Job, done: any): Promise<void> => {
|
|||||||
const info = Object.assign({}, activity);
|
const info = Object.assign({}, activity);
|
||||||
delete info['@context'];
|
delete info['@context'];
|
||||||
delete info['signature'];
|
delete info['signature'];
|
||||||
logger.info(info);
|
logger.debug(JSON.stringify(info, null, 2));
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
const keyIdLower = signature.keyId.toLowerCase();
|
const keyIdLower = signature.keyId.toLowerCase();
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import deliver from './deliver';
|
import deliver from './http/deliver';
|
||||||
import processInbox from './process-inbox';
|
import processInbox from './http/process-inbox';
|
||||||
import { queueLogger } from '../..';
|
import { exportNotes } from './export-notes';
|
||||||
|
import { queueLogger } from '../logger';
|
||||||
|
|
||||||
const handlers: any = {
|
const handlers: any = {
|
||||||
deliver,
|
deliver,
|
||||||
processInbox,
|
processInbox,
|
||||||
|
exportNotes,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (job: any, done: any) => {
|
export default (job: any, done: any) => {
|
@ -7,7 +7,7 @@ import * as promiseAny from 'promise-any';
|
|||||||
|
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import { ILocalUser } from '../../models/user';
|
import { ILocalUser } from '../../models/user';
|
||||||
import { publishApLogStream } from '../../stream';
|
import { publishApLogStream } from '../../services/stream';
|
||||||
import { apLogger } from './logger';
|
import { apLogger } from './logger';
|
||||||
|
|
||||||
export const logger = apLogger.createSubLogger('deliver');
|
export const logger = apLogger.createSubLogger('deliver');
|
||||||
|
@ -78,9 +78,13 @@ export default async (username: string, _host: string, option?: any, resync?: bo
|
|||||||
|
|
||||||
async function resolveSelf(acctLower: string) {
|
async function resolveSelf(acctLower: string) {
|
||||||
logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
|
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');
|
const self = finger.links.find(link => link.rel && link.rel.toLowerCase() === 'self');
|
||||||
if (!self) {
|
if (!self) {
|
||||||
|
logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`);
|
||||||
throw new Error('self link not found');
|
throw new Error('self link not found');
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { ObjectID } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import * as Router from 'koa-router';
|
import * as Router from 'koa-router';
|
||||||
import config from '../../config';
|
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 User from '../../models/user';
|
||||||
import Following from '../../models/following';
|
import Following from '../../models/following';
|
||||||
import { renderActivity } from '../../remote/activitypub/renderer';
|
import { renderActivity } from '../../remote/activitypub/renderer';
|
||||||
|
@ -2,9 +2,9 @@ import * as mongo from 'mongodb';
|
|||||||
import isObjectId from '../../../misc/is-objectid';
|
import isObjectId from '../../../misc/is-objectid';
|
||||||
import Message from '../../../models/messaging-message';
|
import Message from '../../../models/messaging-message';
|
||||||
import { IMessagingMessage as IMessage } from '../../../models/messaging-message';
|
import { IMessagingMessage as IMessage } from '../../../models/messaging-message';
|
||||||
import { publishMainStream } from '../../../stream';
|
import { publishMainStream } from '../../../services/stream';
|
||||||
import { publishMessagingStream } from '../../../stream';
|
import { publishMessagingStream } from '../../../services/stream';
|
||||||
import { publishMessagingIndexStream } from '../../../stream';
|
import { publishMessagingIndexStream } from '../../../services/stream';
|
||||||
import User from '../../../models/user';
|
import User from '../../../models/user';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import isObjectId from '../../../misc/is-objectid';
|
import isObjectId from '../../../misc/is-objectid';
|
||||||
import { default as Notification, INotification } from '../../../models/notification';
|
import { default as Notification, INotification } from '../../../models/notification';
|
||||||
import { publishMainStream } from '../../../stream';
|
import { publishMainStream } from '../../../services/stream';
|
||||||
import Mute from '../../../models/mute';
|
import Mute from '../../../models/mute';
|
||||||
import User from '../../../models/user';
|
import User from '../../../models/user';
|
||||||
|
|
||||||
|
@ -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 Report, { packMany } from '../../../../models/abuse-user-report';
|
||||||
import define from '../../define';
|
import define from '../../define';
|
||||||
|
|
||||||
|
@ -29,22 +29,22 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
|
|||||||
$group: {
|
$group: {
|
||||||
_id: { tag: '$tagsLower', userId: '$userId' }
|
_id: { tag: '$tagsLower', userId: '$userId' }
|
||||||
}
|
}
|
||||||
}]) as Array<{
|
}]) as {
|
||||||
_id: {
|
_id: {
|
||||||
tag: string;
|
tag: string;
|
||||||
userId: any;
|
userId: any;
|
||||||
}
|
}
|
||||||
}>;
|
}[];
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
if (data.length == 0) {
|
if (data.length == 0) {
|
||||||
return res([]);
|
return res([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tags: Array<{
|
let tags: {
|
||||||
name: string;
|
name: string;
|
||||||
count: number;
|
count: number;
|
||||||
}> = [];
|
}[] = [];
|
||||||
|
|
||||||
// カウント
|
// カウント
|
||||||
for (const x of data.map(x => x._id).filter(x => !hidedTags.includes(x.tag))) {
|
for (const x of data.map(x => x._id).filter(x => !hidedTags.includes(x.tag))) {
|
||||||
|
@ -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 App, { pack } from '../../../../models/app';
|
import App, { pack } from '../../../../models/app';
|
||||||
import define from '../../define';
|
import define from '../../define';
|
||||||
|
|
||||||
|
@ -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 * as ms from 'ms';
|
import * as ms from 'ms';
|
||||||
import User, { pack } from '../../../../models/user';
|
import User, { pack } from '../../../../models/user';
|
||||||
import Blocking from '../../../../models/blocking';
|
import Blocking from '../../../../models/blocking';
|
||||||
|
@ -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 * as ms from 'ms';
|
import * as ms from 'ms';
|
||||||
import User, { pack } from '../../../../models/user';
|
import User, { pack } from '../../../../models/user';
|
||||||
import Blocking from '../../../../models/blocking';
|
import Blocking from '../../../../models/blocking';
|
||||||
|
@ -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 Blocking, { packMany } from '../../../../models/blocking';
|
import Blocking, { packMany } from '../../../../models/blocking';
|
||||||
import define from '../../define';
|
import define from '../../define';
|
||||||
|
|
||||||
|
@ -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 DriveFile, { packMany } from '../../../../models/drive-file';
|
import DriveFile, { packMany } from '../../../../models/drive-file';
|
||||||
import define from '../../define';
|
import define from '../../define';
|
||||||
|
|
||||||
|
@ -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 DriveFile from '../../../../../models/drive-file';
|
import DriveFile from '../../../../../models/drive-file';
|
||||||
import define from '../../../define';
|
import define from '../../../define';
|
||||||
import { packMany } from '../../../../../models/note';
|
import { packMany } from '../../../../../models/note';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as ms from 'ms';
|
import * as ms from 'ms';
|
||||||
import $ from 'cafy'; import ID, { transform } from '../../../../../misc/cafy-id';
|
import $ from 'cafy';
|
||||||
|
import ID, { transform } from '../../../../../misc/cafy-id';
|
||||||
import { validateFileName, pack } from '../../../../../models/drive-file';
|
import { validateFileName, pack } from '../../../../../models/drive-file';
|
||||||
import create from '../../../../../services/drive/add-file';
|
import create from '../../../../../services/drive/add-file';
|
||||||
import define from '../../../define';
|
import define from '../../../define';
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import $ from 'cafy'; import ID, { transform } from '../../../../../misc/cafy-id';
|
import $ from 'cafy';
|
||||||
|
import ID, { transform } from '../../../../../misc/cafy-id';
|
||||||
import DriveFile from '../../../../../models/drive-file';
|
import DriveFile from '../../../../../models/drive-file';
|
||||||
import del from '../../../../../services/drive/delete-file';
|
import del from '../../../../../services/drive/delete-file';
|
||||||
import { publishDriveStream } from '../../../../../stream';
|
import { publishDriveStream } from '../../../../../services/stream';
|
||||||
import define from '../../../define';
|
import define from '../../../define';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -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 DriveFile, { pack } from '../../../../../models/drive-file';
|
import DriveFile, { pack } from '../../../../../models/drive-file';
|
||||||
import define from '../../../define';
|
import define from '../../../define';
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user