Compare commits
	
		
			288 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 2b3687b3cb | ||
|   | 5d61c7c691 | ||
|   | 1bb266e7c7 | ||
|   | 1fca8d322c | ||
|   | 325cd03a59 | ||
|   | 2f7e6baa05 | ||
|   | d252e066fe | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | fe7bd9ab3c | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 84e3f41305 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 3e8cccad0d | ||
|   | a2b94d67f7 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 6ab61e73b0 | ||
|   | 051c6973af | ||
|   | 806a49ec3d | ||
|   | 3829fe128a | ||
|   | 649177985d | ||
|   | c15148b23c | ||
|   | 261a3f5d91 | ||
|   | 256ba78ba5 | ||
|   | 04aff8866e | ||
|   | 1a51b98700 | ||
|   | f64100226d | ||
|   | b7805e48a6 | ||
|   | 0d9556620d | ||
|   | a51828a7a2 | ||
|   | 7e2009f408 | ||
|   | 008d950a39 | ||
|   | 22d5862afb | ||
|   | de569147a5 | ||
|   | a82c3db750 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 80706d10af | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 93f01ed4df | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | a3a28e5557 | ||
|   | 8948a0d3a4 | ||
|   | d849ea9b41 | ||
|   | 0144575f3f | ||
|   | bdbe646ca7 | ||
|   | 1a1483a242 | ||
|   | 962346785b | ||
|   | a73da3cd70 | ||
|   | 9c27d0ae3f | ||
|   | 525d5218c1 | ||
|   | e23b13ec7f | ||
|   | 29b000e03c | ||
|   | 6a7b0df810 | ||
|   | 4142de9195 | ||
|   | 9195e1be00 | ||
|   | 75382d13fd | ||
|   | d444280a28 | ||
|   | 52fc0fe04a | ||
|   | 216bebadf1 | ||
|   | a5592931cb | ||
|   | a2228417ff | ||
|   | 3e1e292c3e | ||
|   | f2f039ae9e | ||
|   | 29dde1eda0 | ||
|   | 45d3792ce0 | ||
|   | 875d0aaebb | ||
|   | 26c9d8ff6f | ||
|   | 5e3372e932 | ||
|   | f7069dcd18 | ||
|   | 560bb65384 | ||
|   | 50cd6a036e | ||
|   | 441ab2b5f8 | ||
|   | ba5ed188a1 | ||
|   | 72e672f08d | ||
|   | 120474ec6a | ||
|   | eee57c47f5 | ||
|   | 4c160869b8 | ||
|   | 3720a7fbe0 | ||
|   | 7afa541a53 | ||
|   | 6f979c8275 | ||
|   | d399241e65 | ||
|   | e85dec030a | ||
|   | d0220764cc | ||
|   | 75c1df9531 | ||
|   | bca7156d6b | ||
|   | 64277b7157 | ||
|   | 4a72543f65 | ||
|   | 5b84d29807 | ||
|   | a11061ec2b | ||
|   | 24cfb93b2e | ||
|   | 502b42d63a | ||
|   | 612672b79c | ||
|   | abc670e1b1 | ||
|   | d589ccdd01 | ||
|   | acb07d9f7d | ||
|   | f4d2186719 | ||
|   | d0ede5c665 | ||
|   | 554cbb5e9b | ||
|   | dbd32a56bf | ||
|   | 7f500235c6 | ||
|   | 39a58084c8 | ||
|   | cde0fde836 | ||
|   | e70cca0fda | ||
|   | 919bd7eb82 | ||
|   | 312cff3d6f | ||
|   | 0d86eef3d7 | ||
|   | 13acf570e7 | ||
|   | fa17623fa8 | ||
|   | 06fd525950 | ||
|   | 4805b5115a | ||
|   | 108dcb3e61 | ||
|   | 780d272535 | ||
|   | 02ea4b81a5 | ||
|   | 7c1bdc6d36 | ||
|   | 78c7b8b836 | ||
|   | 227da30acb | ||
|   | 610805026f | ||
|   | c02399c3d2 | ||
|   | e0799d4153 | ||
|   | 6df83f1aa9 | ||
|   | efb5ad1d9b | ||
|   | 716976f016 | ||
|   | 7892f41b84 | ||
|   | d549e03b3f | ||
|   | c511ef21ff | ||
|   | d64dc45899 | ||
|   | bcb0588409 | ||
|   | 0975959eb9 | ||
|   | e985a6d9d3 | ||
|   | b893305974 | ||
|   | 724fdd44e4 | ||
|   | b480ef669c | ||
|   | 4b145da046 | ||
|   | 83d168ece3 | ||
|   | ae44fe7818 | ||
|   | f8981b3acb | ||
|   | 050b324885 | ||
|   | e74c0df6c6 | ||
|   | 22d0d11895 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 80d0c0cf74 | ||
|   | 518646b925 | ||
|   | 479d7e0087 | ||
|   | 8ea1a555f4 | ||
|   | 04024dc37c | ||
|   | 060ff9288f | ||
|   | 197116ee78 | ||
|   | a1e0015257 | ||
|   | 7e701ef9e0 | ||
|   | 3d6fb661bb | ||
|   | fc372496da | ||
|   | ad7258fe9c | ||
|   | bd707cb2a8 | ||
|   | 1839b5f205 | ||
|   | 02b47f963c | ||
|   | f8a7f9378a | ||
|   | 65cb253be4 | ||
|   | a12356b24b | ||
|   | 6a67ad7f93 | ||
|   | 140a7f0b1c | ||
|   | 00159bc6b5 | ||
|   | 9542260103 | ||
|   | 72074578df | ||
|   | 3b4750a988 | ||
|   | aeec5f0163 | ||
|   | 9c94d8c8d6 | ||
|   | 581712a2c8 | ||
|   | b25b51aaca | ||
|   | fb97e13a61 | ||
|   | 36e154fdb2 | ||
|   | ca273a24b4 | ||
|   | d828bf2889 | ||
|   | 87efccef18 | ||
|   | e0bf522e7f | ||
|   | 5b1cd3bd3c | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | f00489196d | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | dd53bf7e51 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 35a6da26d2 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | c8c8748a0b | ||
|   | 46d0065a90 | ||
|   | 990b0180a8 | ||
|   | f3bfb72251 | ||
|   | 0358a7edc6 | ||
|   | 37f99fca04 | ||
|   | 50dfc8ab82 | ||
|   | c70c739b0c | ||
|   | 5918285326 | ||
|   | b1dead1186 | ||
|   | 3e36e132c3 | ||
|   | fa8d1809e7 | ||
|   | e12b668d04 | ||
|   | e5506f7d8c | ||
|   | b1ac7e5cb3 | ||
|   | ffd164a5f3 | ||
|   | cb27414026 | ||
|   | e320912f33 | ||
|   | d23aaae698 | ||
|   | 120c0fe848 | ||
|   | 34857b9520 | ||
|   | a87dcece4c | ||
|   | 01e2479004 | ||
|   | 0fd63fe091 | ||
|   | cc98801c67 | ||
|   | 2724d74108 | ||
|   | 6d0c0d3a5f | ||
|   | 15f8f63317 | ||
|   | d970d65968 | ||
|   | 04d359691b | ||
|   | bfc519944a | ||
|   | 9f69fd14a2 | ||
|   | 85058787b2 | ||
|   | ec851623e0 | ||
|   | e05429a3ec | ||
|   | f651c41816 | ||
|   | 6b88d99ae2 | ||
|   | 814469cdca | ||
|   | 536bf8f141 | ||
|   | 6a27290815 | ||
|   | 7dde3465e2 | ||
|   | 0206a4ac83 | ||
|   | 380f5a972c | ||
|   | 407467a236 | ||
|   | bcfa9e18bf | ||
|   | 69b730e91a | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 6c6c003d68 | ||
|   | fd652b70d6 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 804a5ab6a8 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | d984a1aa19 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | e05b5a6ab8 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 3ff84db421 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 74ca73ecb4 | ||
|   | 37032f68ae | ||
|   | 21d3605737 | ||
|   | 0a7c1caf43 | ||
|   | 24b57335fa | ||
|   | 9f981d875a | ||
|   | 6dcc3800e0 | ||
|   | 44e9be5a1c | ||
|   | 6a8c560d21 | ||
|   | 0afe8c6b34 | ||
|   | 0f5d7f52a0 | ||
|   | aaaefa0ee2 | ||
|   | 276929bc7e | ||
|   | 32882f1397 | ||
|   | 7dc380c485 | ||
|   | 49aaa9a5d3 | ||
|   | 84462eb3f2 | ||
|   | 91709ca979 | ||
|   | 9ece71e652 | ||
|   | 4e93f6c6ff | ||
|   | ad9f1fb7c7 | ||
|   | abaeea6d8b | ||
|   | 8efbcc4c6b | ||
|   | 8ef31cab8c | ||
|   | 37ae53e55c | ||
|   | d01f06bdf4 | ||
|   | 0d4a8d118a | ||
|   | 7e6ec83b1f | ||
|   | 9eb515cfae | ||
|   | d0da019a21 | ||
|   | 57a13c9ad3 | ||
|   | 7f39100634 | ||
|   | 9ab96ef39a | ||
|   | ed21d797a6 | ||
|   | 15960746bb | ||
|   | e0f1e3ca71 | ||
|   | 51d0524182 | ||
|   | 16801aa5c4 | ||
|   | cd23f66834 | ||
|   | cc5d2b2875 | ||
|   | 94ef03db9e | ||
|   | 038bd100b2 | ||
|   | 3b5c3f086a | ||
|   | a136715111 | ||
|   | daa22d68fa | ||
|   | f24d202024 | ||
|   | d3e0b8574b | ||
|   | f4482cc34a | ||
|   | 3ff226cd6b | ||
|   | 5c0d37d021 | ||
|   | b958959cca | ||
|   | 762418d0fa | ||
|   | 6831f0c192 | ||
|   | 64635fff2d | ||
|   | e7e861fb5c | ||
|   | 08523ce271 | ||
|   | 833f63c1a9 | ||
|   | 1c05825bc8 | ||
|   | 26bb088a3d | ||
|   | 5c361cef23 | ||
|   | 04bef96aee | ||
|   | a791981da9 | ||
|   | 264c47e07a | ||
|   | 863c44d15c | ||
|   | cdec6f202e | ||
|   | bdf6c739a9 | ||
|   | 843dd5fb58 | 
| @@ -13,7 +13,3 @@ redis: | |||||||
|   host: localhost |   host: localhost | ||||||
|   port: 6379 |   port: 6379 | ||||||
|   pass: '' |   pass: '' | ||||||
| elasticsearch: |  | ||||||
|   host: localhost |  | ||||||
|   port: 9200 |  | ||||||
|   pass: '' |  | ||||||
| @@ -9,11 +9,8 @@ mongodb: | |||||||
|   db: test-misskey |   db: test-misskey | ||||||
|   user: admin |   user: admin | ||||||
|   pass: '' |   pass: '' | ||||||
|  | # __REDIS__ | ||||||
| redis: | redis: | ||||||
|   host: localhost |   host: localhost | ||||||
|   port: 6379 |   port: 6379 | ||||||
|   pass: '' |   pass: '' | ||||||
| elasticsearch: |  | ||||||
|   host: localhost |  | ||||||
|   port: 9200 |  | ||||||
|   pass: '' |  | ||||||
							
								
								
									
										137
									
								
								.circleci/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								.circleci/config.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | |||||||
|  | version: 2.1 | ||||||
|  |  | ||||||
|  | general: | ||||||
|  |   branches: | ||||||
|  |     ignore: | ||||||
|  |       - l10n_develop | ||||||
|  |       - imgbot | ||||||
|  |  | ||||||
|  | executors: | ||||||
|  |   default: | ||||||
|  |     working_directory: /tmp/workspace | ||||||
|  |     docker: | ||||||
|  |       - image: misskey/ci:latest | ||||||
|  |       - image: circleci/mongo:latest | ||||||
|  |       - image: circleci/redis:latest | ||||||
|  |   docker: | ||||||
|  |     working_directory: /tmp/workspace | ||||||
|  |     docker: | ||||||
|  |       - image: docker:latest | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     executor: default | ||||||
|  |     steps: | ||||||
|  |       - checkout | ||||||
|  |       - restore_cache: | ||||||
|  |           name: Restore npm package caches | ||||||
|  |           keys: | ||||||
|  |             - npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}- | ||||||
|  |             - npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}- | ||||||
|  |             - npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}- | ||||||
|  |             - npm-v1-arch-{{ arch }}- | ||||||
|  |             - npm-v1- | ||||||
|  |       - run: | ||||||
|  |           name: Install Dependencies | ||||||
|  |           command: | | ||||||
|  |             npm install | ||||||
|  |       - run: | ||||||
|  |           name: Configure | ||||||
|  |           command: | | ||||||
|  |             cp .ci/default.yml .config | ||||||
|  |             cp .ci/test.yml .config | ||||||
|  |       - run: | ||||||
|  |           name: Build | ||||||
|  |           command: | | ||||||
|  |             npm run build || (echo -e '\033[0;34mRebuild modules\033[0;39m' && ls -1A node_modules | grep '^[^@]' | xargs npm rebuild && ls -1A node_modules | grep '^@' | xargs -I%1 sh -c 'ls -1A node_modules/'%1' | xargs -P0 -I%2 npm rebuild node_modules/'%1'/%2' && npm run build) | ||||||
|  |             ls -1ARl node_modules > ls | ||||||
|  |       - save_cache: | ||||||
|  |           name: Cache npm packages | ||||||
|  |           key: npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}-ls-{{ checksum "ls" }} | ||||||
|  |           paths: | ||||||
|  |             - node_modules | ||||||
|  |       - store_artifacts: | ||||||
|  |           path: built | ||||||
|  |       - persist_to_workspace: | ||||||
|  |           root: . | ||||||
|  |           paths: | ||||||
|  |             - . | ||||||
|  |   test: | ||||||
|  |     parameters: | ||||||
|  |       without_redis: | ||||||
|  |         type: string | ||||||
|  |         default: "" | ||||||
|  |     executor: default | ||||||
|  |     steps: | ||||||
|  |       - attach_workspace: | ||||||
|  |           at: /tmp/workspace | ||||||
|  |       - when: | ||||||
|  |           condition: <<parameters.without_redis>> | ||||||
|  |           steps: | ||||||
|  |             - run: | ||||||
|  |                 name: Configure | ||||||
|  |                 command: | | ||||||
|  |                   mv .config/test.yml .config/test_redis.yml | ||||||
|  |                   touch .config/test.yml | ||||||
|  |                   cat .config/test_redis.yml | while IFS= read line; do if [[ "$line" = '# __REDIS__' ]]; then break; else echo "$line" >> .config/test.yml; fi; done | ||||||
|  |       - run: | ||||||
|  |           name: Test | ||||||
|  |           command: | | ||||||
|  |             npm run test || (npm rebuild && npm run test) || ((node-gyp configure && node-gyp build && npm run build || (echo -e '\033[0;34mRebuild modules\033[0;39m' && ls -1A node_modules | grep '^[^@]' | xargs npm rebuild && ls -1A node_modules | grep '^@' | xargs -I%1 sh -c 'ls -1A node_modules/'%1' | xargs -P0 -I%2 npm rebuild node_modules/'%1'/%2' && npm run build)) && npm run test) | ||||||
|  |             ls -1ARl node_modules > ls | ||||||
|  |       - save_cache: | ||||||
|  |           name: Cache npm packages | ||||||
|  |           key: npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}-ls-{{ checksum "ls" }} | ||||||
|  |           paths: | ||||||
|  |             - node_modules | ||||||
|  |  | ||||||
|  |   docker: | ||||||
|  |     parameters: | ||||||
|  |       with_deploy: | ||||||
|  |         type: string | ||||||
|  |         default: "" | ||||||
|  |     executor: docker | ||||||
|  |     steps: | ||||||
|  |       - checkout | ||||||
|  |       - setup_remote_docker | ||||||
|  |       - run: | ||||||
|  |           name: Build | ||||||
|  |           command: | | ||||||
|  |             docker build . | tee docker.log | ||||||
|  |             tail -n 1 docker.log | read __Successfully __built tag | ||||||
|  |       - when: | ||||||
|  |           condition: <<parameters.with_deploy>> | ||||||
|  |           steps: | ||||||
|  |             - run: | ||||||
|  |                 name: Deploy | ||||||
|  |                 command: | | ||||||
|  |                   if [ "$DOCKERHUB_USERNAME$DOCKERHUB_PASSWORD" ] | ||||||
|  |                    then | ||||||
|  |                     docker tag $tag misskey/misskey | ||||||
|  |                     docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD | ||||||
|  |                     docker push misskey/misskey | ||||||
|  |                    else | ||||||
|  |                     echo -e '\033[0;33mAborted deploying to Docker Hub\033[0;39m' | ||||||
|  |                   fi | ||||||
|  |  | ||||||
|  | workflows: | ||||||
|  |   version: 2 | ||||||
|  |   build-and-test: | ||||||
|  |     jobs: | ||||||
|  |       - build | ||||||
|  |       - test: | ||||||
|  |           requires: | ||||||
|  |             - build | ||||||
|  |       - test: | ||||||
|  |           without_redis: "true" | ||||||
|  |           requires: | ||||||
|  |             - build | ||||||
|  |       - docker: | ||||||
|  |           filters: | ||||||
|  |             branches: | ||||||
|  |               ignore: master | ||||||
|  |       - docker: | ||||||
|  |           with_deploy: "true" | ||||||
|  |           filters: | ||||||
|  |             branches: | ||||||
|  |               only: master | ||||||
| @@ -164,3 +164,6 @@ drive: | |||||||
| #  external: true | #  external: true | ||||||
| #  engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}} | #  engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}} | ||||||
| #  timeout: 300000 | #  timeout: 300000 | ||||||
|  |  | ||||||
|  | # Max allowed note text length in charactors | ||||||
|  | maxNoteTextLength: 1000 | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ branches: | |||||||
| language: node_js | language: node_js | ||||||
|  |  | ||||||
| node_js: | node_js: | ||||||
|   - 10.1.0 |   - 11.0.0 | ||||||
|  |  | ||||||
| env: | env: | ||||||
|   - CXX=g++-4.8 NODE_ENV=production |   - CXX=g++-4.8 NODE_ENV=production | ||||||
| @@ -35,7 +35,7 @@ before_script: | |||||||
|   - npm install |   - npm install | ||||||
|  |  | ||||||
|   # 設定ファイルを配置 |   # 設定ファイルを配置 | ||||||
|   - cp ./.travis/default.yml ./.config |   - cp ./.ci/default.yml ./.config | ||||||
|   - cp ./.travis/test.yml ./.config |   - cp ./.ci/test.yml ./.config | ||||||
|  |  | ||||||
|   - travis_wait npm run build |   - travis_wait npm run build | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,28 +1,44 @@ | |||||||
| FROM alpine:edge AS base | FROM alpine:3.8 AS base | ||||||
|  |  | ||||||
| ENV NODE_ENV=production | ENV NODE_ENV=production | ||||||
|  |  | ||||||
| RUN apk add --no-cache nodejs nodejs-npm | RUN apk add --no-cache nodejs nodejs-npm zlib | ||||||
| RUN apk add vips fftw --update-cache --repository https://dl-3.alpinelinux.org/alpine/edge/testing/ | RUN npm i -g npm@latest | ||||||
|  |  | ||||||
| WORKDIR /misskey | WORKDIR /misskey | ||||||
| COPY . ./ |  | ||||||
|  |  | ||||||
| FROM base AS builder | FROM base AS builder | ||||||
|  |  | ||||||
| RUN apk add --no-cache	gcc g++ python autoconf automake file make nasm | RUN apk add --no-cache \ | ||||||
| RUN apk add vips-dev fftw-dev --update-cache --repository https://dl-3.alpinelinux.org/alpine/edge/testing/ |     gcc \ | ||||||
| RUN npm install \ |     g++ \ | ||||||
|     && npm install -g node-gyp \ |     libc-dev \ | ||||||
|     && node-gyp configure \ |     python \ | ||||||
|  |     autoconf \ | ||||||
|  |     automake \ | ||||||
|  |     file \ | ||||||
|  |     make \ | ||||||
|  |     nasm \ | ||||||
|  |     pkgconfig \ | ||||||
|  |     libtool \ | ||||||
|  |     zlib-dev | ||||||
|  | RUN npm i -g node-gyp | ||||||
|  |  | ||||||
|  | COPY ./package.json ./ | ||||||
|  | RUN npm i | ||||||
|  |  | ||||||
|  | COPY . ./ | ||||||
|  | RUN node-gyp configure \ | ||||||
|  && node-gyp build \ |  && node-gyp build \ | ||||||
|  && npm run build |  && npm run build | ||||||
|  |  | ||||||
| FROM base AS runner | FROM base AS runner | ||||||
|  |  | ||||||
| COPY --from=builder /misskey/built ./built |  | ||||||
| COPY --from=builder /misskey/node_modules ./node_modules |  | ||||||
|  |  | ||||||
| RUN apk add --no-cache tini | RUN apk add --no-cache tini | ||||||
| ENTRYPOINT ["/sbin/tini", "--"] | ENTRYPOINT ["/sbin/tini", "--"] | ||||||
|  |  | ||||||
|  | COPY --from=builder /misskey/node_modules ./node_modules | ||||||
|  | COPY --from=builder /misskey/built ./built | ||||||
|  | COPY . ./ | ||||||
|  |  | ||||||
| CMD ["npm", "start"] | CMD ["npm", "start"] | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								README.md
									
									
									
									
									
								
							| @@ -3,9 +3,10 @@ | |||||||
| [](https://misskey.xyz/) | [](https://misskey.xyz/) | ||||||
| ================================================================ | ================================================================ | ||||||
|  |  | ||||||
|  | [](https://circleci.com/gh/syuilo/misskey) | ||||||
| [![][travis-badge]][travis-link] | [![][travis-badge]][travis-link] | ||||||
| [![][dependencies-badge]][dependencies-link] | [![][dependencies-badge]][dependencies-link] | ||||||
| [](http://makeapullrequest.com) [](https://greenkeeper.io/) | [](http://makeapullrequest.com) | ||||||
|  |  | ||||||
| **Sophisticated microblogging platform, evolving forever.** | **Sophisticated microblogging platform, evolving forever.** | ||||||
|  |  | ||||||
| @@ -71,39 +72,46 @@ Please see [Contribution guide](./CONTRIBUTING.md). | |||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| <!-- PATREON_START --> | <!-- PATREON_START --> | ||||||
| <table><tr> | <table><tr> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=CXe9AqlZy9AsYfiWd3OBYVOzvODoN47Litz0Tu4BFpU%3D" alt="Gargron"></td> |  | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1?token-time=2145916800&token-hash=d6P5MWHHsCMxUuBAEPAoVc5wLUR19mIhqAq7Ma9h9rI%3D" alt="ne_moni"></td> |  | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/2?token-time=2145916800&token-hash=mgPdX9TqZxEg4TTPuc477dxhIgYk9246qafjWZEqZ7g%3D" alt="Melilot"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/2?token-time=2145916800&token-hash=mgPdX9TqZxEg4TTPuc477dxhIgYk9246qafjWZEqZ7g%3D" alt="Melilot"></td> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/2?token-time=2145916800&token-hash=rwZ8qvbm_kpA4ib3kc07tVKupXeySpY5ATQFGxfL9v0%3D" alt="Xeltica"></td> |  | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td> | ||||||
|  | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1?token-time=2145916800&token-hash=I8lJVM8LeW6TSo5W6uIIRZ42cw83zp1wK_FsbzY0mcQ%3D" alt="mydarkstar"></td> | ||||||
| <td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td> | <td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td> |  | ||||||
| </tr><tr> | </tr><tr> | ||||||
| <td><a href="https://www.patreon.com/mastodon">Gargron</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=13099460">ne_moni</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/AxellaMC">Xeltica</a></td> |  | ||||||
| <td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td> | <td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td> | ||||||
| <td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td> | <td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td> | ||||||
|  | <td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td> | ||||||
| <td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td> | <td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td> | ||||||
| <td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td> |  | ||||||
| </tr></table> | </tr></table> | ||||||
| <table><tr> | <table><tr> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td> | ||||||
|  | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3?token-time=2145916800&token-hash=qsdn0-e6yLaLI6hUX9JAkyTR6a5UdnSp7T1foniBvGQ%3D" alt="YUKIMOCHI"></td> | ||||||
|  | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/8241184/39e18850e87a449e9c9a71acb3310ebd/2?token-time=2145916800&token-hash=iUXOQzRyJDv3PJxwS7Mjwg1459dzh2trOq6NFtXu_OM%3D" alt="Acid Chicken"></td> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td> | ||||||
|  | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/10789744/97175095d8f04c0f86225ff47cb98d40/1?token-time=2145916800&token-hash=P4BIzCX2I1CkEP66ottfhsC8Wr6BUSamjA-vq3pLqFI%3D" alt="Naoki Hirayama"></td> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td> | ||||||
|  | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=tB1e_r8RlZ5sFL0KV_e8dugapxatNBRK1Z3h67TO1g8%3D" alt="Gargron"></td> | ||||||
|  | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1?token-time=2145916800&token-hash=VZUtwrjQa8Jml4twCjHYQQZ64wHEY4oIlGl7Kc-VYUQ%3D" alt="Nokotaro Takeda"></td> | ||||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td> | <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td> | ||||||
| </tr><tr> | </tr><tr> | ||||||
| <td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td> | <td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td> | ||||||
|  | <td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td> | ||||||
|  | <td><a href="https://www.patreon.com/acid_chicken">Acid Chicken</a></td> | ||||||
| <td><a href="https://www.patreon.com/hiratake">Hiratake</a></td> | <td><a href="https://www.patreon.com/hiratake">Hiratake</a></td> | ||||||
|  | <td><a href="https://www.patreon.com/spinlock">Naoki Hirayama</a></td> | ||||||
| <td><a href="https://www.patreon.com/dansup">dansup</a></td> | <td><a href="https://www.patreon.com/dansup">dansup</a></td> | ||||||
|  | <td><a href="https://www.patreon.com/mastodon">Gargron</a></td> | ||||||
|  | <td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td> | ||||||
| <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> | ||||||
|  | <table><tr> | ||||||
|  | </tr><tr> | ||||||
|  | </tr></table> | ||||||
|  |  | ||||||
| **Last updated:** Tue, 02 Oct 2018 09:25:07 UTC | **Last updated:** Wed, 31 Oct 2018 23:21:06 UTC | ||||||
| <!-- PATREON_END --> | <!-- PATREON_END --> | ||||||
|  |  | ||||||
| :four_leaf_clover: Copyright | :four_leaf_clover: Copyright | ||||||
|   | |||||||
| @@ -1,13 +0,0 @@ | |||||||
| const deleteUser = require('../built/models/user').deleteUser; |  | ||||||
|  |  | ||||||
| const args = process.argv.slice(2); |  | ||||||
|  |  | ||||||
| const userId = args[0]; |  | ||||||
|  |  | ||||||
| console.log(`deleting ${userId}...`); |  | ||||||
|  |  | ||||||
| deleteUser(userId).then(() => { |  | ||||||
| 	console.log('done'); |  | ||||||
| }, e => { |  | ||||||
| 	console.error(e); |  | ||||||
| }); |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| const mongo = require('mongodb'); |  | ||||||
| const User = require('../built/models/user').default; |  | ||||||
|  |  | ||||||
| const args = process.argv.slice(2); |  | ||||||
|  |  | ||||||
| const user = args[0]; |  | ||||||
|  |  | ||||||
| const q = user.startsWith('@') ? { |  | ||||||
| 	username: user.split('@')[1], |  | ||||||
| 	host: user.split('@')[2] || null |  | ||||||
| } : { _id: new mongo.ObjectID(user) }; |  | ||||||
|  |  | ||||||
| console.log(`Mark as verfied ${user}...`); |  | ||||||
|  |  | ||||||
| User.update(q, { |  | ||||||
| 	$set: { |  | ||||||
| 		isVerified: true |  | ||||||
| 	} |  | ||||||
| }).then(() => { |  | ||||||
| 	console.log(`Done ${user}`); |  | ||||||
| }, e => { |  | ||||||
| 	console.error(e); |  | ||||||
| }); |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| const { default: Note } = require('../built/models/note'); |  | ||||||
| const { default: Meta } = require('../built/models/meta'); |  | ||||||
| const { default: User } = require('../built/models/user'); |  | ||||||
|  |  | ||||||
| async function main() { |  | ||||||
| 	const meta = await Meta.findOne({}); |  | ||||||
|  |  | ||||||
| 	const notesCount = await Note.count(); |  | ||||||
|  |  | ||||||
| 	const usersCount = await User.count(); |  | ||||||
|  |  | ||||||
| 	const originalNotesCount = await Note.count({ |  | ||||||
| 		'_user.host': null |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	const originalUsersCount = await User.count({ |  | ||||||
| 		host: null |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	const stats = { |  | ||||||
| 		notesCount, |  | ||||||
| 		usersCount, |  | ||||||
| 		originalNotesCount, |  | ||||||
| 		originalUsersCount |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	if (meta) { |  | ||||||
| 		await Meta.update({}, { |  | ||||||
| 			$set: { |  | ||||||
| 				stats |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		await Meta.insert({ |  | ||||||
| 			stats |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| main().then(() => { |  | ||||||
| 	console.log('done'); |  | ||||||
| }).catch(console.error); |  | ||||||
| @@ -6,7 +6,7 @@ services: | |||||||
|     restart: always |     restart: always | ||||||
|     links: |     links: | ||||||
|       - mongo |       - mongo | ||||||
|       - redis | #      - redis | ||||||
| #      - es | #      - es | ||||||
|     ports: |     ports: | ||||||
|       - "127.0.0.1:3000:3000" |       - "127.0.0.1:3000:3000" | ||||||
| @@ -14,18 +14,18 @@ services: | |||||||
|       - internal_network |       - internal_network | ||||||
|       - external_network |       - external_network | ||||||
|  |  | ||||||
|   redis: | #  redis: | ||||||
|     restart: always | #    restart: always | ||||||
|     image: redis:4.0-alpine | #    image: redis:4.0-alpine | ||||||
|     networks: | #    networks: | ||||||
|       - internal_network | #      - internal_network | ||||||
| ### Uncomment to enable Redis persistance | ### Uncomment to enable Redis persistance | ||||||
| #    volumes: | ##    volumes: | ||||||
| #      - ./redis:/data | ##      - ./redis:/data | ||||||
|  |  | ||||||
|   mongo: |   mongo: | ||||||
|     restart: always |     restart: always | ||||||
|     image: mongo:4.1-bionic |     image: mongo:4.1 | ||||||
|     networks: |     networks: | ||||||
|       - internal_network |       - internal_network | ||||||
|     environment: |     environment: | ||||||
|   | |||||||
| @@ -7,23 +7,29 @@ This guide describes how to install and setup Misskey with Docker. | |||||||
|  |  | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
|  |  | ||||||
| *1.* Make configuration files | *1.* Download Misskey | ||||||
|  | ---------------------------------------------------------------- | ||||||
|  | 1. `git clone -b master git://github.com/syuilo/misskey.git` Clone Misskey repository's master branch. | ||||||
|  | 2. `cd misskey` Move to misskey directory. | ||||||
|  | 3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag. | ||||||
|  |  | ||||||
|  | *2.* Make configuration files | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| 1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`. | 1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`. | ||||||
| 2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` Copy the `.config/mongo_initdb_example.js` and rename it to `mongo_initdb.js`. | 2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` Copy the `.config/mongo_initdb_example.js` and rename it to `mongo_initdb.js`. | ||||||
| 2. Edit `default.yml` and `mongo_initdb.js`. | 2. Edit `default.yml` and `mongo_initdb.js`. | ||||||
|  |  | ||||||
| *2.* Configure Docker | *3.* Configure Docker | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| Edit `docker-compose.yml`. | Edit `docker-compose.yml`. | ||||||
|  |  | ||||||
| *3.* Build Misskey | *4.* Build Misskey | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| Build misskey with the following: | Build misskey with the following: | ||||||
|  |  | ||||||
| `docker-compose build` | `docker-compose build` | ||||||
|  |  | ||||||
| *4.* That is it. | *5.* That is it. | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| Well done! Now, you have an environment that run to Misskey. | Well done! Now, you have an environment that run to Misskey. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,23 +7,29 @@ Dockerを使ったMisskey構築方法 | |||||||
|  |  | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
|  |  | ||||||
| *1.* 設定ファイルを作成する | *1.* Misskeyのダウンロード | ||||||
|  | ---------------------------------------------------------------- | ||||||
|  | 1. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン | ||||||
|  | 2. `cd misskey` misskeyディレクトリに移動 | ||||||
|  | 3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認 | ||||||
|  |  | ||||||
|  | *2.* 設定ファイルを作成する | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| 1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする | 1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする | ||||||
| 2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` `.config/mongo_initdb_example.js`をコピーし名前を`mongo_initdb.js`にする | 2. `cp .config/mongo_initdb_example.js .config/mongo_initdb.js` `.config/mongo_initdb_example.js`をコピーし名前を`mongo_initdb.js`にする | ||||||
| 3. `default.yml`と`mongo_initdb.js`を編集する | 3. `default.yml`と`mongo_initdb.js`を編集する | ||||||
|  |  | ||||||
| *2.* Dockerの設定 | *3.* Dockerの設定 | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| `docker-compose.yml`を編集してください。 | `docker-compose.yml`を編集してください。 | ||||||
|  |  | ||||||
| *3.* Misskeyのビルド | *4.* Misskeyのビルド | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| 次のコマンドでMisskeyをビルドしてください: | 次のコマンドでMisskeyをビルドしてください: | ||||||
|  |  | ||||||
| `docker-compose build` | `docker-compose build` | ||||||
|  |  | ||||||
| *4.* 以上です! | *5.* 以上です! | ||||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ||||||
| お疲れ様でした。これでMisskeyを動かす準備は整いました。 | お疲れ様でした。これでMisskeyを動かす準備は整いました。 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,6 +18,10 @@ If you find an untranslated part on Misskey: | |||||||
| 4. Add the text property using the `foo` keyword below the path that you found or created in step 2. Make sure to type your text in quotation marks. Text should always be inside of quotes. | 4. Add the text property using the `foo` keyword below the path that you found or created in step 2. Make sure to type your text in quotation marks. Text should always be inside of quotes. | ||||||
| 	-   For example, in this case we add timeline: `timeline: "タイムライン"` to `locales/ja-JP.yml`. | 	-   For example, in this case we add timeline: `timeline: "タイムライン"` to `locales/ja-JP.yml`. | ||||||
|  |  | ||||||
| 5. And done! | 5. When you add text to the ja-JP file (of syuilo/misskey), it will automatically be applied to all other local language files within 24-48 hours. Translations added in ja-JP file should contain the original Japanese strings (example see step 4).  | ||||||
|  |  | ||||||
|  | 6. The new strings will automatically appear in the localized language files in the original Japanese text. After that, please go to [CrowdIn](https://crowdin.com/project/misskey) to do the localized translations in your language. | ||||||
|  |  | ||||||
|  | 7. And done! | ||||||
|  |  | ||||||
| For more details, please refer to this [commit](https://github.com/syuilo/misskey/commit/10f6d5980fa7692ccb45fbc5f843458b69b7607c). | For more details, please refer to this [commit](https://github.com/syuilo/misskey/commit/10f6d5980fa7692ccb45fbc5f843458b69b7607c). | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}年前" |     years_ago: "{}年前" | ||||||
|   month-and-day: "{month}月 {day}日" |   month-and-day: "{month}月 {day}日" | ||||||
|   trash: "ゴミ箱" |   trash: "ゴミ箱" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "日" |     sunday: "日" | ||||||
|     monday: "月" |     monday: "月" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "決定" |   ok: "決定" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
|   banner: "バナー" |   banner: "バナー" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "名前を変更" |     rename: "名前を変更" | ||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "現在のパスワードを入力してください" |   enter-current-password: "現在のパスワードを入力してください" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   images: "画像" |   images: "画像" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "vor {} Jahr{0:en}" |     years_ago: "vor {} Jahr{0:en}" | ||||||
|   month-and-day: "{day}/{month}" |   month-and-day: "{day}/{month}" | ||||||
|   trash: "Papierkorb" |   trash: "Papierkorb" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "So" |     sunday: "So" | ||||||
|     monday: "Mo" |     monday: "Mo" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "Netzwerk" |   network: "Netzwerk" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "OK" |   ok: "OK" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "benutzt" |   used: "benutzt" | ||||||
|   drive: "Speicher" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "Avatar" |   avatar: "Avatar" | ||||||
|   banner: "Banner" |   banner: "Banner" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "Umbenennen" |     rename: "Umbenennen" | ||||||
|     rename-folder: "Ordner umbenennen" |     rename-folder: "Ordner umbenennen" | ||||||
|     input-new-folder-name: "Namen für neuen Ordner eingeben" |     input-new-folder-name: "Namen für neuen Ordner eingeben" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "Laufwerk" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "Suchen" |   search: "Suchen" | ||||||
|   load-more: "Mehr laden" |   load-more: "Mehr laden" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "Profil" |   profile: "Profil" | ||||||
|   notification: "Mitteilungen" |   notification: "Mitteilungen" | ||||||
|   apps: "In App öffnen" |   apps: "In App öffnen" | ||||||
|   mute: "Stummschalten" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "Dateien vom Drive anfügen" |   blocking: "ブロック" | ||||||
|   security: "Sicherheit" |   security: "Sicherheit" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "Passwort" |   password: "Passwort" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "Bitte Passwort eingeben" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "Passwort ändern" |   reset: "Passwort ändern" | ||||||
|   enter-current-password: "Derzeitiges Passwort eingeben" |   enter-current-password: "Derzeitiges Passwort eingeben" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "Dein Profil" |   profile: "Dein Profil" | ||||||
|   drive: "Speicher" |  | ||||||
|   favorites: "Favoriten" |   favorites: "Favoriten" | ||||||
|   lists: "Listen" |   lists: "Listen" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "Mehr laden" |   more: "Mehr laden" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   images: "画像" |   images: "画像" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}year(s) ago" |     years_ago: "{}year(s) ago" | ||||||
|   month-and-day: "{month}/{day}" |   month-and-day: "{month}/{day}" | ||||||
|   trash: "Trash" |   trash: "Trash" | ||||||
|  |   drive: "Drive" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "S" |     sunday: "S" | ||||||
|     monday: "M" |     monday: "M" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "Charts" |   title: "Charts" | ||||||
|   per-day: "per Day" |   per-day: "per Day" | ||||||
|   per-hour: "per Hour" |   per-hour: "per Hour" | ||||||
|  |   federation: "Federation" | ||||||
|   notes: "Posts" |   notes: "Posts" | ||||||
|   users: "Users" |   users: "Users" | ||||||
|   drive: "Drive" |   drive: "Drive" | ||||||
|   network: "Network" |   network: "Network" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "The number of instances: increase/decrease" | ||||||
|  |     federation-instances-total: "Total number of instances" | ||||||
|     notes: "The number of posts: increase/decrease (Combined)" |     notes: "The number of posts: increase/decrease (Combined)" | ||||||
|     local-notes: "The number of posts: increase/decrease (Local)" |     local-notes: "The number of posts: increase/decrease (Local)" | ||||||
|     remote-notes: "The number of posts: increase/decrease (Remote)" |     remote-notes: "The number of posts: increase/decrease (Remote)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "OK" |   ok: "OK" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "used" |   used: "used" | ||||||
|   drive: "Media storage" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "Avatar" |   avatar: "Avatar" | ||||||
|   banner: "Banner" |   banner: "Banner" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "Rename" |     rename: "Rename" | ||||||
|     rename-folder: "Rename folder" |     rename-folder: "Rename folder" | ||||||
|     input-new-folder-name: "Enter new name" |     input-new-folder-name: "Enter new name" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "Media storage" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "Search" |   search: "Search" | ||||||
|   load-more: "Load more" |   load-more: "Load more" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "Profile" |   profile: "Profile" | ||||||
|   notification: "Notification" |   notification: "Notification" | ||||||
|   apps: "Apps" |   apps: "Apps" | ||||||
|   mute: "Mute" |   mute-and-block: "Mute / Block" | ||||||
|   drive: "Drive" |   blocking: "Blocking" | ||||||
|   security: "Security" |   security: "Security" | ||||||
|   signin: "Sign in history" |   signin: "Sign in history" | ||||||
|   password: "Password" |   password: "Password" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "Settings saved!" |   success: "Settings saved!" | ||||||
|   failed: "Failed to setup. Please ensure that the token is correct." |   failed: "Failed to setup. Please ensure that the token is correct." | ||||||
|   info: "From the next time you sign in to Misskey, the token displayed on your device will be necessary too, as well as the password." |   info: "From the next time you sign in to Misskey, the token displayed on your device will be necessary too, as well as the password." | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "To access the API, set this token as the key 'i' of request parameters." |   intro: "To access the API, set this token as the key 'i' of request parameters." | ||||||
|   caution: "Do not enter this token to any apps nor tell this token to others otherwise your account may get compromised." |   caution: "Do not enter this token to any apps nor tell this token to others otherwise your account may get compromised." | ||||||
|   regeneration-of-token: "If your token gets leaked, you can regenerate it." |   regeneration-of-token: "If your token gets leaked, you can regenerate it." | ||||||
|   regenerate-token: "Regenerate the token" |   regenerate-token: "Regenerate the token" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "Please enter the password" |   enter-password: "Enter the password" | ||||||
|  |   console: | ||||||
|  |     title: 'API console' | ||||||
|  |     endpoint: 'Endpoint' | ||||||
|  |     parameter: 'Parameters' | ||||||
|  |     send: 'Send' | ||||||
|  |     sending: 'Sending' | ||||||
|  |     response: 'Result' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "No linked applications" |   no-apps: "No linked applications" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "Max" |   max: "Max" | ||||||
|   in-use: "In use" |   in-use: "In use" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "Statistics" | ||||||
|   no-users: "No muted users" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "Mute / Block" | ||||||
|  |   mute: "Mute" | ||||||
|  |   block: "Blocking" | ||||||
|  |   no-muted-users: "No muted users" | ||||||
|  |   no-blocked-users: "No blocked users" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "Change password" |   reset: "Change password" | ||||||
|   enter-current-password: "Enter the current password" |   enter-current-password: "Enter the current password" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "-san" |   adjective: "-san" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "Your profile" |   profile: "Your profile" | ||||||
|   drive: "Media storage" |  | ||||||
|   favorites: "Favorites" |   favorites: "Favorites" | ||||||
|   lists: "Lists" |   lists: "Lists" | ||||||
|   follow-requests: "Follow requests" |   follow-requests: "Follow requests" | ||||||
| @@ -936,11 +948,10 @@ desktop/views/components/window.vue: | |||||||
|   close: "Close" |   close: "Close" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "Dashboard" |   dashboard: "Dashboard" | ||||||
|   drive: "Drive" |  | ||||||
|   users: "Users" |   users: "Users" | ||||||
|   update: "Updates" |   update: "Updates" | ||||||
|   announcements: "お知らせ" |   announcements: "Announcements" | ||||||
|   hashtags: "ハッシュタグ" |   hashtags: "Hashtags" | ||||||
| desktop/views/pages/admin/admin.dashboard.vue: | desktop/views/pages/admin/admin.dashboard.vue: | ||||||
|   dashboard: "Dashboard" |   dashboard: "Dashboard" | ||||||
|   all-users: "All Users" |   all-users: "All Users" | ||||||
| @@ -968,7 +979,7 @@ desktop/views/pages/admin/admin.unverify-user.vue: | |||||||
|   unverify: "Unverify account" |   unverify: "Unverify account" | ||||||
|   unverified: "The account is now being unverified" |   unverified: "The account is now being unverified" | ||||||
| desktop/views/pages/admin/admin.announcements.vue: | desktop/views/pages/admin/admin.announcements.vue: | ||||||
|   announcements: "お知らせ" |   announcements: "Announcements" | ||||||
| desktop/views/pages/admin/admin.hashtags.vue: | desktop/views/pages/admin/admin.hashtags.vue: | ||||||
|   hided-tags: "Hidden Tags" |   hided-tags: "Hidden Tags" | ||||||
| desktop/views/pages/deck/deck.tl-column.vue: | desktop/views/pages/deck/deck.tl-column.vue: | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "Media view" |   is-media-view: "Media view" | ||||||
|   edit: "Options" |   edit: "Options" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "Posts" | ||||||
|  |   following: "Following" | ||||||
|  |   followers: "Followers" | ||||||
|  |   images: "Images" | ||||||
|  |   activity: "Activity" | ||||||
|  |   timeline: "Timeline" | ||||||
|   pinned-notes: "Pinned posts" |   pinned-notes: "Pinned posts" | ||||||
|   push-to-a-list: "Add to list" |   push-to-a-list: "Add to list" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "Mute" |   mute: "Mute" | ||||||
|   muted: "Muting" |   muted: "Muting" | ||||||
|   unmute: "Unmute" |   unmute: "Unmute" | ||||||
|  |   block: "Block" | ||||||
|  |   unblock: "Unblock" | ||||||
|  |   block-confirm: "Are you sure block this user?" | ||||||
|   push-to-a-list: "Add to list" |   push-to-a-list: "Add to list" | ||||||
|   list-pushed: "Successfully added {user} to {list}." |   list-pushed: "Successfully added {user} to {list}." | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "refresh" |   refresh: "refresh" | ||||||
|   no-one: "Anyone!" |   no-one: "Anyone!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "Media storage" |  | ||||||
|   used: "used" |   used: "used" | ||||||
|   folder-count: "Folder(s)" |   folder-count: "Folder(s)" | ||||||
|   count-separator: ", " |   count-separator: ", " | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "Messages" |   messaging: "Messages" | ||||||
|   follow-requests: "Follow requests" |   follow-requests: "Follow requests" | ||||||
|   search: "Search" |   search: "Search" | ||||||
|   drive: "Drive" |  | ||||||
|   favorites: "Favorites" |   favorites: "Favorites" | ||||||
|   user-lists: "Lists" |   user-lists: "Lists" | ||||||
|   widgets: "Widgets" |   widgets: "Widgets" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "Lists" |   title: "Lists" | ||||||
|   enter-list-name: "Enter a name of the list to make" |   enter-list-name: "Enter a name of the list to make" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "Drive" |  | ||||||
|   more: "Load more" |   more: "Load more" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "Your account is now ready! 📦" |   lets-start: "Your account is now ready! 📦" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "Timeline" |   timeline: "Timeline" | ||||||
|   media: "Media" |   media: "Media" | ||||||
|   is-suspended: "This account has been suspended." |   is-suspended: "This account has been suspended." | ||||||
|  |   mute: "Mute" | ||||||
|  |   unmute: "Unmute" | ||||||
|  |   block: "Block" | ||||||
|  |   unblock: "Unblock" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "Recent notes" |   recent-notes: "Recent notes" | ||||||
|   images: "Images" |   images: "Images" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "Hace {} año(s)" |     years_ago: "Hace {} año(s)" | ||||||
|   month-and-day: "{day} de {month}" |   month-and-day: "{day} de {month}" | ||||||
|   trash: "Papelera" |   trash: "Papelera" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "domingo" |     sunday: "domingo" | ||||||
|     monday: "lunes" |     monday: "lunes" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "Gráficos" |   title: "Gráficos" | ||||||
|   per-day: "por día" |   per-day: "por día" | ||||||
|   per-hour: "por hora" |   per-hour: "por hora" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "Publicaciones" |   notes: "Publicaciones" | ||||||
|   users: "Usuarios" |   users: "Usuarios" | ||||||
|   drive: "Unidad" |   drive: "Unidad" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "Número de publicaciones: aumentar/disminuir (Combinado)" |     notes: "Número de publicaciones: aumentar/disminuir (Combinado)" | ||||||
|     local-notes: "Número de publicaciones: aumentar/disminuir (Local)" |     local-notes: "Número de publicaciones: aumentar/disminuir (Local)" | ||||||
|     remote-notes: "Número de publicaciones: aumentar/disminuir (Remoto)" |     remote-notes: "Número de publicaciones: aumentar/disminuir (Remoto)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "OK" |   ok: "OK" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "usado" |   used: "usado" | ||||||
|   drive: "Disco" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "Avatar" |   avatar: "Avatar" | ||||||
|   banner: "Banner" |   banner: "Banner" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "Renombrar" |     rename: "Renombrar" | ||||||
|     rename-folder: "Renombrar carpeta" |     rename-folder: "Renombrar carpeta" | ||||||
|     input-new-folder-name: "Escribe el nombre nuevo" |     input-new-folder-name: "Escribe el nombre nuevo" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "Disco" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "Buscar" |   search: "Buscar" | ||||||
|   load-more: "Cargar más" |   load-more: "Cargar más" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "Perfil" |   profile: "Perfil" | ||||||
|   notification: "Notificación" |   notification: "Notificación" | ||||||
|   apps: "Aplicaciones" |   apps: "Aplicaciones" | ||||||
|   mute: "Silenciar" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "Disco" |   blocking: "ブロック" | ||||||
|   security: "Seguridad" |   security: "Seguridad" | ||||||
|   signin: "Historial de inicios de sesión" |   signin: "Historial de inicios de sesión" | ||||||
|   password: "Contraseña" |   password: "Contraseña" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "¡Configuraciones guardadas!" |   success: "¡Configuraciones guardadas!" | ||||||
|   failed: "Error al configurar. Por favor asegúrate de que el token es correcto." |   failed: "Error al configurar. Por favor asegúrate de que el token es correcto." | ||||||
|   info: "Desde ahora, ingresa el token que se muestra en tu dispositivo adicionalmente a tu contraseña cuando inicies sesión en Misskey" |   info: "Desde ahora, ingresa el token que se muestra en tu dispositivo adicionalmente a tu contraseña cuando inicies sesión en Misskey" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "Para acceder al API, configura este token como la letra \"i\" de los parámetros requeridos." |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "Por favor no muestres este token a otros (no lo ingreses en otro lugar que no sea aquí). De otra forma, tu cuenta puede llegar a ser comprometida." |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "En el caso no deseado de que este token lo tenga otra persona, puedes regenerarlo." |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "Regenerar el token" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "Por favor ingresa tu contraseña" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "No hay aplicaciones asociadas" |   no-apps: "No hay aplicaciones asociadas" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "Max" |   max: "容量" | ||||||
|   in-use: "en uso." |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "No hay usuarios silenciados" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "Cambiar contraseña" |   reset: "Cambiar contraseña" | ||||||
|   enter-current-password: "Ingresar contraseña actual" |   enter-current-password: "Ingresar contraseña actual" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "-san" |   adjective: "-san" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "Tu perfil" |   profile: "Tu perfil" | ||||||
|   drive: "Unidad" |  | ||||||
|   favorites: "Favoritos" |   favorites: "Favoritos" | ||||||
|   lists: "Listas" |   lists: "Listas" | ||||||
|   follow-requests: "Solicitudes de seguimiento" |   follow-requests: "Solicitudes de seguimiento" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   images: "画像" |   images: "画像" | ||||||
|   | |||||||
| @@ -28,11 +28,11 @@ common: | |||||||
|   BSoD: |   BSoD: | ||||||
|     fatal-error: ":( 致命的な問題が発生しました。" |     fatal-error: ":( 致命的な問題が発生しました。" | ||||||
|     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" |     update-browser-os: "お使いのブラウザ(またはOS)のバージョンを更新すると解決する可能性があります。" | ||||||
|     error-code: "エラーコード" |     error-code: "Code d’erreur" | ||||||
|     browser-version: "ブラウザ バージョン" |     browser-version: "Version du navigateur" | ||||||
|     client-version: "クライアント バージョン" |     client-version: "La version du client" | ||||||
|     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" |     email-support: "問題が解決しない場合は、上記の情報をお書き添えの上 syuilotan@yahoo.co.jp までご連絡ください。" | ||||||
|     thanks: "Thank you for using Misskey." |     thanks: "Merci d’avoir choisi d’utiliser Misskey." | ||||||
|   got-it: "J'ai compris !" |   got-it: "J'ai compris !" | ||||||
|   customization-tips: |   customization-tips: | ||||||
|     title: "Conseils de personnalisation" |     title: "Conseils de personnalisation" | ||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "Il y a {} an·s" |     years_ago: "Il y a {} an·s" | ||||||
|   month-and-day: "{month} mois/{day} jour" |   month-and-day: "{month} mois/{day} jour" | ||||||
|   trash: "Corbeille" |   trash: "Corbeille" | ||||||
|  |   drive: "Drive" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "D" |     sunday: "D" | ||||||
|     monday: "L" |     monday: "L" | ||||||
| @@ -123,12 +124,12 @@ common: | |||||||
|   reduce-motion: "Réduire les animations dans l’interface utilisateur" |   reduce-motion: "Réduire les animations dans l’interface utilisateur" | ||||||
|   this-setting-is-this-device-only: "Uniquement sur cet appareil" |   this-setting-is-this-device-only: "Uniquement sur cet appareil" | ||||||
|   do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.' |   do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.' | ||||||
|   is-remote-user: "このユーザー情報はコピーです。" |   is-remote-user: "Ces informations utilisateur ont été copiées." | ||||||
|   is-remote-post: "この投稿情報はコピーです。" |   is-remote-post: "この投稿情報はコピーです。" | ||||||
|   view-on-remote: "正確な情報を見る" |   view-on-remote: "Consulter le profil complet" | ||||||
|   error: |   error: | ||||||
|     title: '問題が発生しました' |     title: 'Une erreur est survenue' | ||||||
|     retry: 'やり直す' |     retry: 'Réessayer' | ||||||
|   reversi: |   reversi: | ||||||
|     drawn: "Partie nulle" |     drawn: "Partie nulle" | ||||||
|     my-turn: "C’est votre tour" |     my-turn: "C’est votre tour" | ||||||
| @@ -184,7 +185,7 @@ common: | |||||||
|     rename: "Renommer" |     rename: "Renommer" | ||||||
|     stack-left: "Vers la gauche" |     stack-left: "Vers la gauche" | ||||||
|     pop-right: "Vers la droite" |     pop-right: "Vers la droite" | ||||||
|   dev: "アプリの作成に失敗しました。再度お試しください。" |   dev: "Échec lors de la création de l’application. Veuillez réessayer." | ||||||
| auth/views/form.vue: | auth/views/form.vue: | ||||||
|   share-access: "Désirez-vous <b>autoriser</b> <i>{{ app.name }}</i> à avoir accès à votre compte ?" |   share-access: "Désirez-vous <b>autoriser</b> <i>{{ app.name }}</i> à avoir accès à votre compte ?" | ||||||
|   permission-ask: "Cette application nécessite les autorisations suivantes :" |   permission-ask: "Cette application nécessite les autorisations suivantes :" | ||||||
| @@ -541,21 +542,24 @@ desktop/views/components/charts.vue: | |||||||
|   title: "Graphiques" |   title: "Graphiques" | ||||||
|   per-day: "par jour" |   per-day: "par jour" | ||||||
|   per-hour: "par heure" |   per-hour: "par heure" | ||||||
|  |   federation: "Fédération" | ||||||
|   notes: "Publications" |   notes: "Publications" | ||||||
|   users: "Utilisateurs" |   users: "Utilisateurs" | ||||||
|   drive: "Drive" |   drive: "Drive" | ||||||
|   network: "Réseau" |   network: "Réseau" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "Nombre total d’instances" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
|     notes-total: "Total des notes" |     notes-total: "Total des notes" | ||||||
|     users: "Nombre d’utilisateurs·trices : augmentation/diminution" |     users: "Nombre d’utilisateurs·trices : augmentation/diminution" | ||||||
|     users-total: "ユーザーの積算" |     users-total: "Nombre total des utilisateurs·rices" | ||||||
|     drive: "ドライブ使用量の増減" |     drive: "ドライブ使用量の増減" | ||||||
|     drive-total: "ドライブ使用量の積算" |     drive-total: "Utilisation totale du lecteur" | ||||||
|     drive-files: "ドライブのファイル数の増減" |     drive-files: "ドライブのファイル数の増減" | ||||||
|     drive-files-total: "ドライブのファイル数の積算" |     drive-files-total: "Nombre total de fichiers sur le lecteur" | ||||||
|     network-requests: "Requêtes" |     network-requests: "Requêtes" | ||||||
|     network-time: "Temps de réponse" |     network-time: "Temps de réponse" | ||||||
|     network-usage: "Traffic" |     network-usage: "Traffic" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "OK" |   ok: "OK" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "utilisé" |   used: "utilisé" | ||||||
|   drive: "Drive" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "Avatar" |   avatar: "Avatar" | ||||||
|   banner: "Bannière" |   banner: "Bannière" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "Renommer" |     rename: "Renommer" | ||||||
|     rename-folder: "Renommer le dossier" |     rename-folder: "Renommer le dossier" | ||||||
|     input-new-folder-name: "Entrer un nouveau nom" |     input-new-folder-name: "Entrer un nouveau nom" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "Drive" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "Rechercher" |   search: "Rechercher" | ||||||
|   load-more: "Afficher plus" |   load-more: "Afficher plus" | ||||||
| @@ -678,10 +679,10 @@ desktop/views/components/note.vue: | |||||||
|   reposted-by: "Partagé par {}" |   reposted-by: "Partagé par {}" | ||||||
|   reply: "Répondre" |   reply: "Répondre" | ||||||
|   renote: "Partager" |   renote: "Partager" | ||||||
|   add-reaction: "リアクション" |   add-reaction: "Ajouter votre réaction" | ||||||
|   detail: "詳細" |   detail: "Détails" | ||||||
|   private: "この投稿は非公開です" |   private: "Cette publication est privée" | ||||||
|   deleted: "この投稿は削除されました" |   deleted: "Cette publication a été supprimée" | ||||||
| desktop/views/components/notes.vue: | desktop/views/components/notes.vue: | ||||||
|   error: "Échec du chargement." |   error: "Échec du chargement." | ||||||
|   retry: "Réessayer" |   retry: "Réessayer" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "Profil" |   profile: "Profil" | ||||||
|   notification: "Notification" |   notification: "Notification" | ||||||
|   apps: "Applications" |   apps: "Applications" | ||||||
|   mute: "Mettre en sourdine" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "Drive" |   blocking: "ブロック" | ||||||
|   security: "Sécurité" |   security: "Sécurité" | ||||||
|   signin: "Historique de connexion" |   signin: "Historique de connexion" | ||||||
|   password: "Mot de Passe" |   password: "Mot de Passe" | ||||||
| @@ -765,7 +766,7 @@ desktop/views/components/settings.vue: | |||||||
|   deck-default: "デッキをデフォルトのUIにする" |   deck-default: "デッキをデフォルトのUIにする" | ||||||
|   display: "Affichage et design" |   display: "Affichage et design" | ||||||
|   customize: "Personnaliser l'Accueil" |   customize: "Personnaliser l'Accueil" | ||||||
|   wallpaper: "壁紙" |   wallpaper: "Arrière plan" | ||||||
|   choose-wallpaper: "Sélectionner un fond d'écran" |   choose-wallpaper: "Sélectionner un fond d'écran" | ||||||
|   delete-wallpaper: "Supprimer le fond d'écran" |   delete-wallpaper: "Supprimer le fond d'écran" | ||||||
|   dark-mode: "Mode nuit" |   dark-mode: "Mode nuit" | ||||||
| @@ -777,14 +778,14 @@ desktop/views/components/settings.vue: | |||||||
|   suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie" |   suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie" | ||||||
|   show-clock-on-header: "Afficher l'horloge à droite sur le coté supérieur" |   show-clock-on-header: "Afficher l'horloge à droite sur le coté supérieur" | ||||||
|   show-reply-target: "Afficher les réponses" |   show-reply-target: "Afficher les réponses" | ||||||
|   timeline: "タイムライン" |   timeline: "Chronologie" | ||||||
|   show-my-renotes: "Afficher mes republications dans le fil" |   show-my-renotes: "Afficher mes republications dans le fil" | ||||||
|   show-renoted-my-notes: "Afficher mes republications dans les fils" |   show-renoted-my-notes: "Afficher mes republications dans les fils" | ||||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" |   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||||
|   show-maps: "Afficher la carte" |   show-maps: "Afficher la carte" | ||||||
|   deck-column-align: "デッキのカラムの位置" |   deck-column-align: "デッキのカラムの位置" | ||||||
|   deck-column-align-center: "中央" |   deck-column-align-center: "Centrer" | ||||||
|   deck-column-align-left: "左" |   deck-column-align-left: "À gauche" | ||||||
|   sound: "Son" |   sound: "Son" | ||||||
|   enable-sounds: "Activer le son" |   enable-sounds: "Activer le son" | ||||||
|   enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur." |   enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur." | ||||||
| @@ -825,7 +826,7 @@ desktop/views/components/settings.vue: | |||||||
|   tools: "Outils" |   tools: "Outils" | ||||||
|   task-manager: "Gestionnaire de tâches" |   task-manager: "Gestionnaire de tâches" | ||||||
|   third-parties: "Services tiers" |   third-parties: "Services tiers" | ||||||
|   navbar-position: "ナビゲーションバーの位置" |   navbar-position: "Position de la barre de navigation" | ||||||
|   navbar-position-top: "En haut" |   navbar-position-top: "En haut" | ||||||
|   navbar-position-left: "à gauche" |   navbar-position-left: "à gauche" | ||||||
|   navbar-position-right: "à droite" |   navbar-position-right: "à droite" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "L'operation a été complétée avec succès!" |   success: "L'operation a été complétée avec succès!" | ||||||
|   failed: "L'operation a échoué. Veuillez vous assurer que le token a été entrer correctement." |   failed: "L'operation a échoué. Veuillez vous assurer que le token a été entrer correctement." | ||||||
|   info: "À partir de maintenant, à chaque fois que vous vous connecter entrez votre mot de passe ainsi que le token généré sur votre appareil." |   info: "À partir de maintenant, à chaque fois que vous vous connecter entrez votre mot de passe ainsi que le token généré sur votre appareil." | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "Si votre jeton est compromis, vous pouvez le régénérer." |   regeneration-of-token: "Si votre jeton est compromis, vous pouvez le régénérer." | ||||||
|   regenerate-token: "Regenerer le token" |   regenerate-token: "Régénérer le jeton" | ||||||
|   token: "Jeton :" |   token: "Jeton :" | ||||||
|   enter-password: "Veuillez entrer le mot de passe" |   enter-password: "Entrez le mot de passe" | ||||||
|  |   console: | ||||||
|  |     title: 'Console API' | ||||||
|  |     endpoint: 'Point de terminaison' | ||||||
|  |     parameter: 'Paramètres' | ||||||
|  |     send: 'Envoyer' | ||||||
|  |     sending: 'Envoi en cours' | ||||||
|  |     response: 'Résultat' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "Aucune application autorisée" |   no-apps: "Aucune application autorisée" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "Maximum" |   max: "容量" | ||||||
|   in-use: "en cours d’utilisation" |   in-use: "utilisé" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "Statistiques" | ||||||
|   no-users: "Aucun utilisateurs mis en sourdine" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "Changer votre mot de passe" |   reset: "Changer votre mot de passe" | ||||||
|   enter-current-password: "Entrez votre mot de passe actuel" |   enter-current-password: "Entrez votre mot de passe actuel" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "M." |   adjective: "M." | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "Votre profil" |   profile: "Votre profil" | ||||||
|   drive: "Drive" |  | ||||||
|   favorites: "Favorites" |   favorites: "Favorites" | ||||||
|   lists: "Listes" |   lists: "Listes" | ||||||
|   follow-requests: "Demandes de suivi" |   follow-requests: "Demandes de suivi" | ||||||
| @@ -936,11 +948,10 @@ desktop/views/components/window.vue: | |||||||
|   close: "Fermer" |   close: "Fermer" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "Tableau de bord" |   dashboard: "Tableau de bord" | ||||||
|   drive: "Drive" |  | ||||||
|   users: "Utilisateur·rice·s" |   users: "Utilisateur·rice·s" | ||||||
|   update: "Mises à jour" |   update: "Mises à jour" | ||||||
|   announcements: "お知らせ" |   announcements: "Annonces" | ||||||
|   hashtags: "ハッシュタグ" |   hashtags: "Hashtags" | ||||||
| desktop/views/pages/admin/admin.dashboard.vue: | desktop/views/pages/admin/admin.dashboard.vue: | ||||||
|   dashboard: "Tableau de bord" |   dashboard: "Tableau de bord" | ||||||
|   all-users: "Toutes les utilisateurrices" |   all-users: "Toutes les utilisateurrices" | ||||||
| @@ -948,9 +959,9 @@ desktop/views/pages/admin/admin.dashboard.vue: | |||||||
|   all-notes: "Toutes les publications" |   all-notes: "Toutes les publications" | ||||||
|   original-notes: "Publications sur cette instance" |   original-notes: "Publications sur cette instance" | ||||||
|   invite: "Invitation" |   invite: "Invitation" | ||||||
|   banner-url: "Banner URL" |   banner-url: "URL de la bannière" | ||||||
|   disableRegistration: "Disable new user registration" |   disableRegistration: "Désactiver l’enregistrement de nouveaux utilisateurs·rices" | ||||||
|   disableLocalTimeline: "Disable the local timeline" |   disableLocalTimeline: "Désactiver le fil local" | ||||||
| desktop/views/pages/admin/admin.suspend-user.vue: | desktop/views/pages/admin/admin.suspend-user.vue: | ||||||
|   suspend-user: "Suspendre un·e utilisateur·rice" |   suspend-user: "Suspendre un·e utilisateur·rice" | ||||||
|   suspend: "Suspendre" |   suspend: "Suspendre" | ||||||
| @@ -968,16 +979,22 @@ desktop/views/pages/admin/admin.unverify-user.vue: | |||||||
|   unverify: "Ôter la vérification du compte" |   unverify: "Ôter la vérification du compte" | ||||||
|   unverified: "Ce compte n'est pas vérifié" |   unverified: "Ce compte n'est pas vérifié" | ||||||
| desktop/views/pages/admin/admin.announcements.vue: | desktop/views/pages/admin/admin.announcements.vue: | ||||||
|   announcements: "お知らせ" |   announcements: "Annonces" | ||||||
| desktop/views/pages/admin/admin.hashtags.vue: | desktop/views/pages/admin/admin.hashtags.vue: | ||||||
|   hided-tags: "Hidden Tags" |   hided-tags: "Tags cachés" | ||||||
| desktop/views/pages/deck/deck.tl-column.vue: | desktop/views/pages/deck/deck.tl-column.vue: | ||||||
|   is-media-only: "Les publications médias uniquement" |   is-media-only: "Les publications médias uniquement" | ||||||
|   is-media-view: "Vue média" |   is-media-view: "Vue média" | ||||||
|   edit: "Options" |   edit: "Options" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|   pinned-notes: "ピン留めされた投稿" |   posts: "Publications" | ||||||
|   push-to-a-list: "リストに追加" |   following: "Suit" | ||||||
|  |   followers: "Abonné·e·s" | ||||||
|  |   images: "Images" | ||||||
|  |   activity: "Activité" | ||||||
|  |   timeline: "Chronologie" | ||||||
|  |   pinned-notes: "Publications épinglées" | ||||||
|  |   push-to-a-list: "Ajouter à la liste" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
|   all-users: "Toutes les utilisateurrices" |   all-users: "Toutes les utilisateurrices" | ||||||
|   original-users: "Utilisateur·rice·s sur cette instance" |   original-users: "Utilisateur·rice·s sur cette instance" | ||||||
| @@ -1030,7 +1047,7 @@ desktop/views/pages/user/user.friends.vue: | |||||||
|   no-users: "Pas d'utilisateurs" |   no-users: "Pas d'utilisateurs" | ||||||
| desktop/views/pages/user/user.vue: | desktop/views/pages/user/user.vue: | ||||||
|   is-suspended: "Ce compte a été suspendu." |   is-suspended: "Ce compte a été suspendu." | ||||||
|   last-used-at: "最終アクセス" |   last-used-at: "Actif·ive pour la dernière fois" | ||||||
| desktop/views/pages/user/user.photos.vue: | desktop/views/pages/user/user.photos.vue: | ||||||
|   title: "Photos" |   title: "Photos" | ||||||
|   loading: "Chargement en cours" |   loading: "Chargement en cours" | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "Mettre en sourdine" |   mute: "Mettre en sourdine" | ||||||
|   muted: "Muting" |   muted: "Muting" | ||||||
|   unmute: "Enlever la sourdine" |   unmute: "Enlever la sourdine" | ||||||
|  |   block: "Bloquer" | ||||||
|  |   unblock: "Débloquer" | ||||||
|  |   block-confirm: "Bloquer cet utilisateur ?" | ||||||
|   push-to-a-list: "Ajouter à la liste" |   push-to-a-list: "Ajouter à la liste" | ||||||
|   list-pushed: "Vous avez ajouté {user} à la liste {list}." |   list-pushed: "Vous avez ajouté {user} à la liste {list}." | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1050,10 +1070,10 @@ desktop/views/pages/user/user.header.vue: | |||||||
|   following: "Suit" |   following: "Suit" | ||||||
|   followers: "Abonné·e·s" |   followers: "Abonné·e·s" | ||||||
|   is-bot: "Ce compte est un Bot" |   is-bot: "Ce compte est un Bot" | ||||||
|   years-old: "歳" |   years-old: "ans d’âge" | ||||||
|   year: "年" |   year: "Année" | ||||||
|   month: "月" |   month: "Mois" | ||||||
|   day: "日" |   day: "Jour" | ||||||
| desktop/views/pages/user/user.timeline.vue: | desktop/views/pages/user/user.timeline.vue: | ||||||
|   default: "Publications" |   default: "Publications" | ||||||
|   with-replies: "Publications et réponses" |   with-replies: "Publications et réponses" | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "Afficher d'autres" |   refresh: "Afficher d'autres" | ||||||
|   no-one: "Personne" |   no-one: "Personne" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "Drive" |  | ||||||
|   used: "utilisé" |   used: "utilisé" | ||||||
|   folder-count: "Dossier(s)" |   folder-count: "Dossier(s)" | ||||||
|   count-separator: ", " |   count-separator: ", " | ||||||
| @@ -1113,8 +1132,8 @@ mobile/views/components/drive.file-detail.vue: | |||||||
|   hash: "Hash (md5)" |   hash: "Hash (md5)" | ||||||
|   exif: "EXIF" |   exif: "EXIF" | ||||||
|   nsfw: "CW" |   nsfw: "CW" | ||||||
|   mark-as-sensitive: "閲覧注意に設定" |   mark-as-sensitive: "Marquer comme sensible" | ||||||
|   unmark-as-sensitive: "閲覧注意を解除" |   unmark-as-sensitive: "Ne pas marquer comme sensible" | ||||||
| mobile/views/components/media-image.vue: | mobile/views/components/media-image.vue: | ||||||
|   sensitive: "Le contenu est NSFW" |   sensitive: "Le contenu est NSFW" | ||||||
|   click-to-show: "Cliquer pour afficher" |   click-to-show: "Cliquer pour afficher" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "Messages" |   messaging: "Messages" | ||||||
|   follow-requests: "Demandes d'abonnement" |   follow-requests: "Demandes d'abonnement" | ||||||
|   search: "Rechercher" |   search: "Rechercher" | ||||||
|   drive: "Drive" |  | ||||||
|   favorites: "Favoris" |   favorites: "Favoris" | ||||||
|   user-lists: "Listes" |   user-lists: "Listes" | ||||||
|   widgets: "Modules" |   widgets: "Modules" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "Listes" |   title: "Listes" | ||||||
|   enter-list-name: "Nom de la liste" |   enter-list-name: "Nom de la liste" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "Drive" |  | ||||||
|   more: "Afficher plus ..." |   more: "Afficher plus ..." | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "Votre compte est prêt ! 📦" |   lets-start: "Votre compte est prêt ! 📦" | ||||||
| @@ -1276,8 +1293,8 @@ mobile/views/pages/settings.vue: | |||||||
|   timeline: "Fil d'actualité" |   timeline: "Fil d'actualité" | ||||||
|   show-reply-target: "Afficher les réponses" |   show-reply-target: "Afficher les réponses" | ||||||
|   show-my-renotes: "Afficher mes republications" |   show-my-renotes: "Afficher mes republications" | ||||||
|   show-renoted-my-notes: "自分の投稿のRenoteを表示する" |   show-renoted-my-notes: "Afficher mes publications partagées" | ||||||
|   show-local-renotes: "ローカルの投稿のRenoteを表示する" |   show-local-renotes: "Afficher les publications partagées localement" | ||||||
|   post-style: "Style de la publication" |   post-style: "Style de la publication" | ||||||
|   post-style-standard: "Standard" |   post-style-standard: "Standard" | ||||||
|   post-style-smart: "Intelligent" |   post-style-smart: "Intelligent" | ||||||
| @@ -1310,7 +1327,7 @@ mobile/views/pages/settings.vue: | |||||||
|   signout: "Déconnexion" |   signout: "Déconnexion" | ||||||
|   sound: "Sons" |   sound: "Sons" | ||||||
|   enable-sounds: "Activer les sons" |   enable-sounds: "Activer les sons" | ||||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" |   mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues" | ||||||
| mobile/views/pages/user.vue: | mobile/views/pages/user.vue: | ||||||
|   follows-you: "Vous suit" |   follows-you: "Vous suit" | ||||||
|   following: "Abonnements" |   following: "Abonnements" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "Fil d'actualité" |   timeline: "Fil d'actualité" | ||||||
|   media: "Media" |   media: "Media" | ||||||
|   is-suspended: "This account has been suspended." |   is-suspended: "This account has been suspended." | ||||||
|  |   mute: "Mettre en sourdine" | ||||||
|  |   unmute: "Enlever la sourdine" | ||||||
|  |   block: "Bloquer" | ||||||
|  |   unblock: "Débloquer" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "Notes récentes" |   recent-notes: "Notes récentes" | ||||||
|   images: "Images" |   images: "Images" | ||||||
| @@ -1366,28 +1387,28 @@ docs: | |||||||
| dev/views/index.vue: | dev/views/index.vue: | ||||||
|   manage-apps: "Gestion des applications" |   manage-apps: "Gestion des applications" | ||||||
| dev/views/apps.vue: | dev/views/apps.vue: | ||||||
|   manage-apps: "アプリを管理" |   manage-apps: "Gestion des applications" | ||||||
|   create-app: "アプリ作成" |   create-app: "Créer une app" | ||||||
|   app-missing: "アプリなし" |   app-missing: "Aucune application" | ||||||
| dev/views/new-app.vue: | dev/views/new-app.vue: | ||||||
|   create-app: "アプリケーションの作成" |   create-app: "Création d’une application" | ||||||
|   app-name: "アプリケーション名" |   app-name: "Nom de l’application" | ||||||
|   app-name-desc: "あなたのアプリの名称。" |   app-name-desc: "Le nom de votre application" | ||||||
|   app-name-ex: "ex) Misskey for iOS" |   app-name-ex: "p. ex. Misskey pour iOS" | ||||||
|   app-overview: "アプリの概要" |   app-overview: "Description courte de l’application" | ||||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" |   app-desc: "Brève description introductive à votre application." | ||||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" |   app-desc-ex: "p. ex) Misskey pour iOS" | ||||||
|   callback-url: "コールバックURL (オプション)" |   callback-url: "コールバックURL (オプション)" | ||||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" |   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" | ||||||
|   authority: "権限" |   authority: "Autorisations " | ||||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" |   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" | ||||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" |   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" | ||||||
|   account-read: "アカウントの情報を見る。" |   account-read: "Afficher les informations du compte" | ||||||
|   account-write: "アカウントの情報を操作する。" |   account-write: "Modifications des informations du compte" | ||||||
|   note-write: "投稿する。" |   note-write: "Publications." | ||||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" |   reaction-write: "Ajout et suppression de réactions." | ||||||
|   following-write: "フォローしたりフォロー解除する。" |   following-write: "S’abonner et se désabonner." | ||||||
|   drive-read: "ドライブを見る。" |   drive-read: "Lecture du Drive." | ||||||
|   drive-write: "ドライブを操作する。" |   drive-write: "Téléversement/suppression des fichiers de votre Lecteur." | ||||||
|   notification-read: "通知を見る。" |   notification-read: "Lire vos notifications." | ||||||
|   notification-write: "通知を操作する。" |   notification-write: "Gestion de vos notifications." | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}年前" |     years_ago: "{}年前" | ||||||
|   month-and-day: "{month}月 {day}日" |   month-and-day: "{month}月 {day}日" | ||||||
|   trash: "ゴミ箱" |   trash: "ゴミ箱" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "日" |     sunday: "日" | ||||||
|     monday: "月" |     monday: "月" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "決定" |   ok: "決定" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
|   banner: "バナー" |   banner: "バナー" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "名前を変更" |     rename: "名前を変更" | ||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "現在のパスワードを入力してください" |   enter-current-password: "現在のパスワードを入力してください" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   images: "画像" |   images: "画像" | ||||||
|   | |||||||
| @@ -64,6 +64,7 @@ common: | |||||||
|   month-and-day: "{month}月 {day}日" |   month-and-day: "{month}月 {day}日" | ||||||
|  |  | ||||||
|   trash: "ゴミ箱" |   trash: "ゴミ箱" | ||||||
|  |   drive: "ドライブ" | ||||||
|  |  | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "日" |     sunday: "日" | ||||||
| @@ -601,11 +602,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -639,7 +643,6 @@ desktop/views/components/crop-window.vue: | |||||||
|  |  | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   drive: "ドライブ" |  | ||||||
|  |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
| @@ -672,9 +675,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
|  |  | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
|  |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -832,8 +832,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -951,23 +951,35 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
|  |  | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
|  |  | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
|  |  | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
|  |   stats: "統計" | ||||||
|  |  | ||||||
| desktop/views/components/settings.mute.vue: | common/views/components/mute-and-block.vue: | ||||||
|   no-users: "ミュートしているユーザーはいません" |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
|  |  | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
| @@ -1005,7 +1017,6 @@ desktop/views/components/ui.header.vue: | |||||||
|  |  | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -1060,7 +1071,6 @@ desktop/views/components/window.vue: | |||||||
|  |  | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -1109,6 +1119,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
|  |  | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|  |  | ||||||
| @@ -1192,6 +1208,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
|  |  | ||||||
| @@ -1242,7 +1261,6 @@ desktop/views/widgets/users.vue: | |||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
|  |  | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1366,7 +1384,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1394,7 +1411,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
|  |  | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
|  |  | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
| @@ -1523,6 +1539,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |  | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}年前" |     years_ago: "{}年前" | ||||||
|   month-and-day: "{month}月 {day}日" |   month-and-day: "{month}月 {day}日" | ||||||
|   trash: "ゴミ箱" |   trash: "ゴミ箱" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "日" |     sunday: "日" | ||||||
|     monday: "月" |     monday: "月" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減(統合)" |     notes: "投稿の増減(統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "そうする" |   ok: "そうする" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使うとる" |   used: "使うとる" | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
|   banner: "バナー" |   banner: "バナー" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "名前を変えるで" |     rename: "名前を変えるで" | ||||||
|     rename-folder: "フォルダ名を変えるで" |     rename-folder: "フォルダ名を変えるで" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してや" |     input-new-folder-name: "新しいフォルダ名を入力してや" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっとあらへんのか!" |   load-more: "もっとあらへんのか!" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "守護神セキュリティ" |   security: "守護神セキュリティ" | ||||||
|   signin: "こんな感じでサインインしたらしいで" |   signin: "こんな感じでサインインしたらしいで" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了したで!" |   success: "設定が完了したで!" | ||||||
|   failed: "なんか設定に失敗したで。トークンを間違えとらんか確認してや。" |   failed: "なんか設定に失敗したで。トークンを間違えとらんか確認してや。" | ||||||
|   info: "次のサインインからは、パスワードに加えてデバイスに出とるトークンを入力してな。" |   info: "次のサインインからは、パスワードに加えてデバイスに出とるトークンを入力してな。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」っちゅうキーでパラメータに付加してリクエストしてや。" |   intro: "API使うんやったらこのトークンを「i」っちゅうパラメータにくっつけてリクエストできるで。" | ||||||
|   caution: "アカウントを不正利用されるかも知れんから、このトークンは第三者に教えたらあかんで(アプリなどにも入力しんといてな)。" |   caution: "アカウント勝手にいじられるかも知れんから、このトークンは教えたらあかんし、アプリにも書いたらあかんで(これはフリちゃうで)" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたとかその可能性があったらトークンを再生成できるで。" |   regeneration-of-token: "トークン漏れてもうたんやったらもっかい生成できるで。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンもっかい生成" | ||||||
|   token: "トークン:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してや" |   enter-password: "パスワードを入れてや" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送る' | ||||||
|  |     sending: '応答待っとる' | ||||||
|  |     response: 'こんなん返ってきたわ' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはあらへんで" |   no-apps: "連携しているアプリケーションはあらへんで" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使うとる" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはおらんで" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "今のパスワードを入れてや" |   enter-current-password: "今のパスワードを入れてや" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "はん" |   adjective: "はん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー許してくれや!言うてみる" |   follow-requests: "フォロー許してくれや!言うてみる" | ||||||
| @@ -936,10 +948,9 @@ desktop/views/components/window.vue: | |||||||
|   close: "さいなら" |   close: "さいなら" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "知っといてや" | ||||||
|   hashtags: "ハッシュタグ" |   hashtags: "ハッシュタグ" | ||||||
| desktop/views/pages/admin/admin.dashboard.vue: | desktop/views/pages/admin/admin.dashboard.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
| @@ -968,7 +979,7 @@ desktop/views/pages/admin/admin.unverify-user.vue: | |||||||
|   unverify: "公式アカウントにはさせへんで" |   unverify: "公式アカウントにはさせへんで" | ||||||
|   unverified: "公式アカウントを解除したで" |   unverified: "公式アカウントを解除したで" | ||||||
| desktop/views/pages/admin/admin.announcements.vue: | desktop/views/pages/admin/admin.announcements.vue: | ||||||
|   announcements: "お知らせ" |   announcements: "知っといてや" | ||||||
| desktop/views/pages/admin/admin.hashtags.vue: | desktop/views/pages/admin/admin.hashtags.vue: | ||||||
|   hided-tags: "Hidden Tags" |   hided-tags: "Hidden Tags" | ||||||
| desktop/views/pages/deck/deck.tl-column.vue: | desktop/views/pages/deck/deck.tl-column.vue: | ||||||
| @@ -976,8 +987,14 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|   pinned-notes: "ピン留めされた投稿" |   posts: "投稿" | ||||||
|   push-to-a-list: "リストに追加" |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "やっとること" | ||||||
|  |   timeline: "タイムライン" | ||||||
|  |   pinned-notes: "ピン留めしはった投稿" | ||||||
|  |   push-to-a-list: "リストに入れたる" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
|   all-users: "全てのユーザー" |   all-users: "全てのユーザー" | ||||||
|   original-users: "ここの人らだけ" |   original-users: "ここの人らだけ" | ||||||
| @@ -1030,7 +1047,7 @@ desktop/views/pages/user/user.friends.vue: | |||||||
|   no-users: "よう話すツレは居らん" |   no-users: "よう話すツレは居らん" | ||||||
| desktop/views/pages/user/user.vue: | desktop/views/pages/user/user.vue: | ||||||
|   is-suspended: "このユーザーはあかんわ。凍結されとる。" |   is-suspended: "このユーザーはあかんわ。凍結されとる。" | ||||||
|   last-used-at: "最終アクセス" |   last-used-at: "最後いつ来はった?" | ||||||
| desktop/views/pages/user/user.photos.vue: | desktop/views/pages/user/user.photos.vue: | ||||||
|   title: "写真" |   title: "写真" | ||||||
|   loading: "読み込んどります" |   loading: "読み込んどります" | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしとるで" |   muted: "ミュートしとるで" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加したで。" |   list-pushed: "{user}を{list}に追加したで。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "おらん!" |   no-one: "おらん!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使うとる" |   used: "使うとる" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1113,8 +1132,8 @@ mobile/views/components/drive.file-detail.vue: | |||||||
|   hash: "ハッシュ(md5)" |   hash: "ハッシュ(md5)" | ||||||
|   exif: "EXIF" |   exif: "EXIF" | ||||||
|   nsfw: "ちょっと見せられへんわ" |   nsfw: "ちょっと見せられへんわ" | ||||||
|   mark-as-sensitive: "閲覧注意に設定" |   mark-as-sensitive: "見たらあかん感じにしとく" | ||||||
|   unmark-as-sensitive: "閲覧注意を解除" |   unmark-as-sensitive: "やっぱ見せたるわ" | ||||||
| mobile/views/components/media-image.vue: | mobile/views/components/media-image.vue: | ||||||
|   sensitive: "見たらあかんで" |   sensitive: "見たらあかんで" | ||||||
|   click-to-show: "押してみ、見せたるわ" |   click-to-show: "押してみ、見せたるわ" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー許してくれや!言うてみる" |   follow-requests: "フォロー許してくれや!言うてみる" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してや" |   enter-list-name: "リスト名を入力してや" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっとあるやろ!" |   more: "もっとあるやろ!" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めようや" |   lets-start: "📦 始めようや" | ||||||
| @@ -1310,7 +1327,7 @@ mobile/views/pages/settings.vue: | |||||||
|   signout: "さいなら" |   signout: "さいなら" | ||||||
|   sound: "サウンド" |   sound: "サウンド" | ||||||
|   enable-sounds: "サウンド鳴らす" |   enable-sounds: "サウンド鳴らす" | ||||||
|   mark-as-read-all-unread-notes: "すべての投稿を既読にする" |   mark-as-read-all-unread-notes: "全部もう読んだわ" | ||||||
| mobile/views/pages/user.vue: | mobile/views/pages/user.vue: | ||||||
|   follows-you: "フォローされとるで" |   follows-you: "フォローされとるで" | ||||||
|   following: "フォロー" |   following: "フォロー" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーはあかんわ。凍結されとる。" |   is-suspended: "このユーザーはあかんわ。凍結されとる。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近儲かりまっか?" |   recent-notes: "最近儲かりまっか?" | ||||||
|   images: "画像" |   images: "画像" | ||||||
| @@ -1367,27 +1388,27 @@ dev/views/index.vue: | |||||||
|   manage-apps: "アプリの管理" |   manage-apps: "アプリの管理" | ||||||
| dev/views/apps.vue: | dev/views/apps.vue: | ||||||
|   manage-apps: "アプリを管理" |   manage-apps: "アプリを管理" | ||||||
|   create-app: "アプリ作成" |   create-app: "アプリ作る" | ||||||
|   app-missing: "アプリなし" |   app-missing: "アプリあらへん" | ||||||
| dev/views/new-app.vue: | dev/views/new-app.vue: | ||||||
|   create-app: "アプリケーションの作成" |   create-app: "アプリケーション作る" | ||||||
|   app-name: "アプリケーション名" |   app-name: "アプリケーションの名前" | ||||||
|   app-name-desc: "あなたのアプリの名称。" |   app-name-desc: "あんたのアプリの名前。" | ||||||
|   app-name-ex: "ex) Misskey for iOS" |   app-name-ex: "ex) 関西ミスキー保安協会" | ||||||
|   app-overview: "アプリの概要" |   app-overview: "このアプリどんなん?" | ||||||
|   app-desc: "あなたのアプリの簡単な説明や紹介。" |   app-desc: "あんたのアプリどんなんか教えて" | ||||||
|   app-desc-ex: "ex) Misskey iOSクライアント。" |   app-desc-ex: "ex) 関西人なら誰でも口ずさめるこのCMがついにMisskeyへ。" | ||||||
|   callback-url: "コールバックURL (オプション)" |   callback-url: "コールバックURL (無くてもええで)" | ||||||
|   callback-url-desc: "ユーザーが認証フォームで認証した際にリダイレクトするURLを設定できます。" |   callback-url-desc: "ユーザーが認証フォームで認証した後どこに連れてくかを設定できるで" | ||||||
|   authority: "権限" |   authority: "権限" | ||||||
|   authority-desc: "ここで要求した機能だけがAPIからアクセスできます。" |   authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな" | ||||||
|   authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。" |   authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。" | ||||||
|   account-read: "アカウントの情報を見る。" |   account-read: "アカウントの情報見せて" | ||||||
|   account-write: "アカウントの情報を操作する。" |   account-write: "アカウントの情報いじらせて" | ||||||
|   note-write: "投稿する。" |   note-write: "投稿させて" | ||||||
|   reaction-write: "リアクションしたりリアクションをキャンセルする。" |   reaction-write: "リアクションしたりそれをキャンセルさせて" | ||||||
|   following-write: "フォローしたりフォロー解除する。" |   following-write: "フォローとかフォロー解除させて" | ||||||
|   drive-read: "ドライブを見る。" |   drive-read: "ドライブ見せて" | ||||||
|   drive-write: "ドライブを操作する。" |   drive-write: "ドライブいじらせて" | ||||||
|   notification-read: "通知を見る。" |   notification-read: "通知見せて" | ||||||
|   notification-write: "通知を操作する。" |   notification-write: "通知いじらせて" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}년전" |     years_ago: "{}년전" | ||||||
|   month-and-day: "{month}월 {day}일" |   month-and-day: "{month}월 {day}일" | ||||||
|   trash: "휴지통" |   trash: "휴지통" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "일" |     sunday: "일" | ||||||
|     monday: "월" |     monday: "월" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "決定" |   ok: "決定" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
|   banner: "バナー" |   banner: "バナー" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "名前を変更" |     rename: "名前を変更" | ||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "現在のパスワードを入力してください" |   enter-current-password: "現在のパスワードを入力してください" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   images: "画像" |   images: "画像" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}jaar geleden" |     years_ago: "{}jaar geleden" | ||||||
|   month-and-day: "{month}月 {day}日" |   month-and-day: "{month}月 {day}日" | ||||||
|   trash: "ゴミ箱" |   trash: "ゴミ箱" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "Z" |     sunday: "Z" | ||||||
|     monday: "M" |     monday: "M" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "Oké" |   ok: "Oké" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "gebruikt" |   used: "gebruikt" | ||||||
|   drive: "Drive" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "Gebruikersafbeelding" |   avatar: "Gebruikersafbeelding" | ||||||
|   banner: "Omslagfoto" |   banner: "Omslagfoto" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "Naam wijzigen" |     rename: "Naam wijzigen" | ||||||
|     rename-folder: "Mapnaam wijzigen" |     rename-folder: "Mapnaam wijzigen" | ||||||
|     input-new-folder-name: "Voer een nieuwe naam in" |     input-new-folder-name: "Voer een nieuwe naam in" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "Drive" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "Zoeken" |   search: "Zoeken" | ||||||
|   load-more: "Meer laden" |   load-more: "Meer laden" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "Profiel" |   profile: "Profiel" | ||||||
|   notification: "Melding" |   notification: "Melding" | ||||||
|   apps: "Apps" |   apps: "Apps" | ||||||
|   mute: "Dempen" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "Drive" |   blocking: "ブロック" | ||||||
|   security: "Beveiliging" |   security: "Beveiliging" | ||||||
|   signin: "Inloggeschiedenis" |   signin: "Inloggeschiedenis" | ||||||
|   password: "Wachtwoord" |   password: "Wachtwoord" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "Instellen voltooid!" |   success: "Instellen voltooid!" | ||||||
|   failed: "Instellen mislukt. Zorg ervoor dat de sleutel juist is." |   failed: "Instellen mislukt. Zorg ervoor dat de sleutel juist is." | ||||||
|   info: "Vanaf nu moet je ook de op je apparaat getoonde sleutel tonen bij het inloggen op Misskey." |   info: "Vanaf nu moet je ook de op je apparaat getoonde sleutel tonen bij het inloggen op Misskey." | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "Als je toegang wilt tot de API, stel deze sleutel dan in als 'i' bij de verzoekparameters." |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "Laat deze sleutel niet zien aan derde partijen (en voer hem nergens anders in dan hier), anders kan je account gehackt worden." |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "Mocht deze sleutel tóch uitlekken, dan kun je hem opnieuw genereren." |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "Sleutel opnieuw genereren" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Sleutel:" |   token: "Token:" | ||||||
|   enter-password: "Voer je wachtwoord in" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "Geen gedempte gebruikers" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "Wachtwoord wijzigen" |   reset: "Wachtwoord wijzigen" | ||||||
|   enter-current-password: "Voer je huidige wachtwoord in" |   enter-current-password: "Voer je huidige wachtwoord in" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "Je profiel" |   profile: "Je profiel" | ||||||
|   drive: "Drive" |  | ||||||
|   favorites: "Favorieten" |   favorites: "Favorieten" | ||||||
|   lists: "Lijsten" |   lists: "Lijsten" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "Sluiten" |   close: "Sluiten" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "Dempen" |   mute: "Dempen" | ||||||
|   muted: "Dempend" |   muted: "Dempend" | ||||||
|   unmute: "Ontdempen" |   unmute: "Ontdempen" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "Anderen tonen" |   refresh: "Anderen tonen" | ||||||
|   no-one: "Niemand" |   no-one: "Niemand" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "Drive" |  | ||||||
|   used: "gebruikt" |   used: "gebruikt" | ||||||
|   folder-count: "Map(pen)" |   folder-count: "Map(pen)" | ||||||
|   count-separator: ", " |   count-separator: ", " | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "Gesprekken" |   messaging: "Gesprekken" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "Zoeken" |   search: "Zoeken" | ||||||
|   drive: "Drive" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "Drive" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "Tijdlijn" |   timeline: "Tijdlijn" | ||||||
|   media: "Media" |   media: "Media" | ||||||
|   is-suspended: "Dit account is geschorst." |   is-suspended: "Dit account is geschorst." | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "Recente notities" |   recent-notes: "Recente notities" | ||||||
|   images: "Afbeeldingen" |   images: "Afbeeldingen" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{} år siden" |     years_ago: "{} år siden" | ||||||
|   month-and-day: "{day}/{month}" |   month-and-day: "{day}/{month}" | ||||||
|   trash: "Papirkurv" |   trash: "Papirkurv" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "S" |     sunday: "S" | ||||||
|     monday: "M" |     monday: "M" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "Diagrammer" |   title: "Diagrammer" | ||||||
|   per-day: "per dag" |   per-day: "per dag" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "Innlegg" |   notes: "Innlegg" | ||||||
|   users: "Brukere" |   users: "Brukere" | ||||||
|   drive: "Disk" |   drive: "Disk" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "Ok" |   ok: "Ok" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "brukt" |   used: "brukt" | ||||||
|   drive: "Disk" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "Avatar" |   avatar: "Avatar" | ||||||
|   banner: "Banner" |   banner: "Banner" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "Endre navn" |     rename: "Endre navn" | ||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "Disk" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "Søk" |   search: "Søk" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "Notifikasjon" |   notification: "Notifikasjon" | ||||||
|   apps: "Apper" |   apps: "Apper" | ||||||
|   mute: "Demp" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "Disk" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "Passord" |   password: "Passord" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "Maks" |   max: "容量" | ||||||
|   in-use: "I bruk" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "現在のパスワードを入力してください" |   enter-current-password: "現在のパスワードを入力してください" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "-san" |   adjective: "-san" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "Disk" |  | ||||||
|   favorites: "Favoritter" |   favorites: "Favoritter" | ||||||
|   lists: "Lister" |   lists: "Lister" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "Lukk" |   close: "Lukk" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "Disk" |  | ||||||
|   users: "Brukere" |   users: "Brukere" | ||||||
|   update: "Oppdater" |   update: "Oppdater" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "Oppdater" |   refresh: "Oppdater" | ||||||
|   no-one: "Ingen" |   no-one: "Ingen" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "Disk" |  | ||||||
|   used: "brukt" |   used: "brukt" | ||||||
|   folder-count: "Mappe(r)" |   folder-count: "Mappe(r)" | ||||||
|   count-separator: "," |   count-separator: "," | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "Meldinger" |   messaging: "Meldinger" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "Søk" |   search: "Søk" | ||||||
|   drive: "Disk" |  | ||||||
|   favorites: "Favoritter" |   favorites: "Favoritter" | ||||||
|   user-lists: "Lister" |   user-lists: "Lister" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "Lister" |   title: "Lister" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "Disk" |  | ||||||
|   more: "Vis mer" |   more: "Vis mer" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "Media" |   media: "Media" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "Nylige innlegg" |   recent-notes: "Nylige innlegg" | ||||||
|   images: "Bilder" |   images: "Bilder" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{} lat temu" |     years_ago: "{} lat temu" | ||||||
|   month-and-day: "{month}-{day}" |   month-and-day: "{month}-{day}" | ||||||
|   trash: "Kosz" |   trash: "Kosz" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "N" |     sunday: "N" | ||||||
|     monday: "Pn" |     monday: "Pn" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "OK" |   ok: "OK" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "wykorzystane" |   used: "wykorzystane" | ||||||
|   drive: "Dysk" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "Awatar" |   avatar: "Awatar" | ||||||
|   banner: "Baner" |   banner: "Baner" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "Zmień nazwę" |     rename: "Zmień nazwę" | ||||||
|     rename-folder: "Zmień nazwę katalogu" |     rename-folder: "Zmień nazwę katalogu" | ||||||
|     input-new-folder-name: "Wprowadź nową nazwę" |     input-new-folder-name: "Wprowadź nową nazwę" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "Dysk" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "Szukaj" |   search: "Szukaj" | ||||||
|   load-more: "Załaduj więcej" |   load-more: "Załaduj więcej" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "Profil" |   profile: "Profil" | ||||||
|   notification: "Powiadomienia" |   notification: "Powiadomienia" | ||||||
|   apps: "Aplikacje" |   apps: "Aplikacje" | ||||||
|   mute: "Wyciszanie" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "Dysk" |   blocking: "ブロック" | ||||||
|   security: "Bezpieczeństwo" |   security: "Bezpieczeństwo" | ||||||
|   signin: "Historia logowań" |   signin: "Historia logowań" | ||||||
|   password: "Hasło" |   password: "Hasło" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "Pomyślnie ukończono konfigurację!" |   success: "Pomyślnie ukończono konfigurację!" | ||||||
|   failed: "Nie udało się skonfigurować uwierzytelniania dwuetapowego, upewnij się że wprowadziłeś prawidłowy token." |   failed: "Nie udało się skonfigurować uwierzytelniania dwuetapowego, upewnij się że wprowadziłeś prawidłowy token." | ||||||
|   info: "Od teraz, wprowadzaj token wyświetlany na urządzeniu przy każdym logowaniu do Misskey." |   info: "Od teraz, wprowadzaj token wyświetlany na urządzeniu przy każdym logowaniu do Misskey." | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "Aby uzyskać dostęp do API, ustaw ten token jako klucz 'i' parametrów żądań." |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "Nie pokazuj tego tokenu osobom trzecim (nie wprowadzaj go nigdzie indziej), aby konto nie trafiło w niepowołane ręce." |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "W przypadku wycieku tokenu, możesz wygenerować nowy." |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "Wygeneruj nowy token" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "Wprowadź hasło" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "Brak zautoryzowanych aplikacji" |   no-apps: "Brak zautoryzowanych aplikacji" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "Maksymalnie" |   max: "容量" | ||||||
|   in-use: " w użyciu." |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "Brak wyciszonych użytkowników" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "Zmień hasło" |   reset: "Zmień hasło" | ||||||
|   enter-current-password: "Wprowadź obecne hasło" |   enter-current-password: "Wprowadź obecne hasło" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "Twój profil" |   profile: "Twój profil" | ||||||
|   drive: "Dysk" |  | ||||||
|   favorites: "Ulubione" |   favorites: "Ulubione" | ||||||
|   lists: "Listy" |   lists: "Listy" | ||||||
|   follow-requests: "Prośby o śledzenie" |   follow-requests: "Prośby o śledzenie" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "Zamknij" |   close: "Zamknij" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "Widok multimediów" |   is-media-view: "Widok multimediów" | ||||||
|   edit: "Opcje" |   edit: "Opcje" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "Wycisz" |   mute: "Wycisz" | ||||||
|   muted: "Wyciszyłeś" |   muted: "Wyciszyłeś" | ||||||
|   unmute: "Cofnij wyciszenie" |   unmute: "Cofnij wyciszenie" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "Dodaj do listy" |   push-to-a-list: "Dodaj do listy" | ||||||
|   list-pushed: "Dodałeś(-aś) {user} do {list}." |   list-pushed: "Dodałeś(-aś) {user} do {list}." | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "Pokaż innych" |   refresh: "Pokaż innych" | ||||||
|   no-one: "Pusto" |   no-one: "Pusto" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "Dysk" |  | ||||||
|   used: "użyto" |   used: "użyto" | ||||||
|   folder-count: "Katalog(i)" |   folder-count: "Katalog(i)" | ||||||
|   count-separator: ", " |   count-separator: ", " | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "Wiadomości" |   messaging: "Wiadomości" | ||||||
|   follow-requests: "Prośby o śledzenie" |   follow-requests: "Prośby o śledzenie" | ||||||
|   search: "Szukaj" |   search: "Szukaj" | ||||||
|   drive: "Dysk" |  | ||||||
|   favorites: "Ulubione" |   favorites: "Ulubione" | ||||||
|   user-lists: "Listy" |   user-lists: "Listy" | ||||||
|   widgets: "Widżety" |   widgets: "Widżety" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "Listy" |   title: "Listy" | ||||||
|   enter-list-name: "Wprowadź nazwę listy" |   enter-list-name: "Wprowadź nazwę listy" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "Dysk" |  | ||||||
|   more: "Załaduj więcej" |   more: "Załaduj więcej" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "Rozpocznijmy! 📦" |   lets-start: "Rozpocznijmy! 📦" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "Oś czasu" |   timeline: "Oś czasu" | ||||||
|   media: "Multimedia" |   media: "Multimedia" | ||||||
|   is-suspended: "To konto zostało zablokowane" |   is-suspended: "To konto zostało zablokowane" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "Ostatnie wpisy" |   recent-notes: "Ostatnie wpisy" | ||||||
|   images: "Zdjęcia" |   images: "Zdjęcia" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{} ano(s) atrás" |     years_ago: "{} ano(s) atrás" | ||||||
|   month-and-day: "{day}/{month}" |   month-and-day: "{day}/{month}" | ||||||
|   trash: "Lixo" |   trash: "Lixo" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "Dom" |     sunday: "Dom" | ||||||
|     monday: "Seg" |     monday: "Seg" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "決定" |   ok: "決定" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
|   banner: "バナー" |   banner: "バナー" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "名前を変更" |     rename: "名前を変更" | ||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "現在のパスワードを入力してください" |   enter-current-password: "現在のパスワードを入力してください" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "Usuários" |   users: "Usuários" | ||||||
|   update: "Actualizações" |   update: "Actualizações" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "Linha do tempo" |   timeline: "Linha do tempo" | ||||||
|   media: "Mídia" |   media: "Mídia" | ||||||
|   is-suspended: "Esta conta foi suspensa" |   is-suspended: "Esta conta foi suspensa" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "Notas recentes" |   recent-notes: "Notas recentes" | ||||||
|   images: "Imagens" |   images: "Imagens" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}年前" |     years_ago: "{}年前" | ||||||
|   month-and-day: "{month}月 {day}日" |   month-and-day: "{month}月 {day}日" | ||||||
|   trash: "ゴミ箱" |   trash: "ゴミ箱" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "日" |     sunday: "日" | ||||||
|     monday: "月" |     monday: "月" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "決定" |   ok: "決定" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
|   banner: "バナー" |   banner: "バナー" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "名前を変更" |     rename: "名前を変更" | ||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "現在のパスワードを入力してください" |   enter-current-password: "現在のパスワードを入力してください" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   images: "画像" |   images: "画像" | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ common: | |||||||
|     years_ago: "{}年前" |     years_ago: "{}年前" | ||||||
|   month-and-day: "{month}月 {day}日" |   month-and-day: "{month}月 {day}日" | ||||||
|   trash: "ゴミ箱" |   trash: "ゴミ箱" | ||||||
|  |   drive: "ドライブ" | ||||||
|   weekday-short: |   weekday-short: | ||||||
|     sunday: "日" |     sunday: "日" | ||||||
|     monday: "月" |     monday: "月" | ||||||
| @@ -541,11 +542,14 @@ desktop/views/components/charts.vue: | |||||||
|   title: "チャート" |   title: "チャート" | ||||||
|   per-day: "1日ごと" |   per-day: "1日ごと" | ||||||
|   per-hour: "1時間ごと" |   per-hour: "1時間ごと" | ||||||
|  |   federation: "フェデレーション" | ||||||
|   notes: "投稿" |   notes: "投稿" | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   drive: "ドライブ" |   drive: "ドライブ" | ||||||
|   network: "ネットワーク" |   network: "ネットワーク" | ||||||
|   charts: |   charts: | ||||||
|  |     federation-instances: "インスタンスの増減" | ||||||
|  |     federation-instances-total: "インスタンスの積算" | ||||||
|     notes: "投稿の増減 (統合)" |     notes: "投稿の増減 (統合)" | ||||||
|     local-notes: "投稿の増減 (ローカル)" |     local-notes: "投稿の増減 (ローカル)" | ||||||
|     remote-notes: "投稿の増減 (リモート)" |     remote-notes: "投稿の増減 (リモート)" | ||||||
| @@ -575,7 +579,6 @@ desktop/views/components/crop-window.vue: | |||||||
|   ok: "決定" |   ok: "決定" | ||||||
| desktop/views/components/drive-window.vue: | desktop/views/components/drive-window.vue: | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.file.vue: | desktop/views/components/drive.file.vue: | ||||||
|   avatar: "アイコン" |   avatar: "アイコン" | ||||||
|   banner: "バナー" |   banner: "バナー" | ||||||
| @@ -605,8 +608,6 @@ desktop/views/components/drive.folder.vue: | |||||||
|     rename: "名前を変更" |     rename: "名前を変更" | ||||||
|     rename-folder: "フォルダ名の変更" |     rename-folder: "フォルダ名の変更" | ||||||
|     input-new-folder-name: "新しいフォルダ名を入力してください" |     input-new-folder-name: "新しいフォルダ名を入力してください" | ||||||
| desktop/views/components/drive.nav-folder.vue: |  | ||||||
|   drive: "ドライブ" |  | ||||||
| desktop/views/components/drive.vue: | desktop/views/components/drive.vue: | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   load-more: "もっと読み込む" |   load-more: "もっと読み込む" | ||||||
| @@ -740,8 +741,8 @@ desktop/views/components/settings.vue: | |||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   notification: "通知" |   notification: "通知" | ||||||
|   apps: "アプリ" |   apps: "アプリ" | ||||||
|   mute: "ミュート" |   mute-and-block: "ミュート/ブロック" | ||||||
|   drive: "ドライブ" |   blocking: "ブロック" | ||||||
|   security: "セキュリティ" |   security: "セキュリティ" | ||||||
|   signin: "サインイン履歴" |   signin: "サインイン履歴" | ||||||
|   password: "パスワード" |   password: "パスワード" | ||||||
| @@ -847,20 +848,32 @@ desktop/views/components/settings.2fa.vue: | |||||||
|   success: "設定が完了しました!" |   success: "設定が完了しました!" | ||||||
|   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" |   failed: "設定に失敗しました。トークンに誤りがないかご確認ください。" | ||||||
|   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" |   info: "次回サインインからは、同様にパスワードに加えてデバイスに表示されているトークンを入力します。" | ||||||
| desktop/views/components/settings.api.vue: | common/views/components/api-settings.vue: | ||||||
|   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" |   intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。" | ||||||
|   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" |   caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。" | ||||||
|   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" |   regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。" | ||||||
|   regenerate-token: "トークンを再生成" |   regenerate-token: "トークンを再生成" | ||||||
|   token: "Token:" |   token: "Token:" | ||||||
|   enter-password: "パスワードを入力してください" |   enter-password: "パスワードを入力してください" | ||||||
|  |   console: | ||||||
|  |     title: 'APIコンソール' | ||||||
|  |     endpoint: 'エンドポイント' | ||||||
|  |     parameter: 'パラメータ' | ||||||
|  |     send: '送信' | ||||||
|  |     sending: '応答待ち' | ||||||
|  |     response: '結果' | ||||||
| desktop/views/components/settings.apps.vue: | desktop/views/components/settings.apps.vue: | ||||||
|   no-apps: "連携しているアプリケーションはありません" |   no-apps: "連携しているアプリケーションはありません" | ||||||
| desktop/views/components/settings.drive.vue: | common/views/components/drive-settings.vue: | ||||||
|   max: "中" |   max: "容量" | ||||||
|   in-use: "使用中" |   in-use: "使用中" | ||||||
| desktop/views/components/settings.mute.vue: |   stats: "統計" | ||||||
|   no-users: "ミュートしているユーザーはいません" | common/views/components/mute-and-block.vue: | ||||||
|  |   mute-and-block: "ミュートとブロック" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   block: "ブロック" | ||||||
|  |   no-muted-users: "ミュートしているユーザーはいません" | ||||||
|  |   no-blocked-users: "ブロックしているユーザーはいません" | ||||||
| desktop/views/components/settings.password.vue: | desktop/views/components/settings.password.vue: | ||||||
|   reset: "パスワードを変更する" |   reset: "パスワードを変更する" | ||||||
|   enter-current-password: "現在のパスワードを入力してください" |   enter-current-password: "現在のパスワードを入力してください" | ||||||
| @@ -892,7 +905,6 @@ desktop/views/components/ui.header.vue: | |||||||
|   adjective: "さん" |   adjective: "さん" | ||||||
| desktop/views/components/ui.header.account.vue: | desktop/views/components/ui.header.account.vue: | ||||||
|   profile: "プロフィール" |   profile: "プロフィール" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   lists: "リスト" |   lists: "リスト" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
| @@ -936,7 +948,6 @@ desktop/views/components/window.vue: | |||||||
|   close: "閉じる" |   close: "閉じる" | ||||||
| desktop/views/pages/admin/admin.vue: | desktop/views/pages/admin/admin.vue: | ||||||
|   dashboard: "ダッシュボード" |   dashboard: "ダッシュボード" | ||||||
|   drive: "ドライブ" |  | ||||||
|   users: "ユーザー" |   users: "ユーザー" | ||||||
|   update: "更新" |   update: "更新" | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -976,6 +987,12 @@ desktop/views/pages/deck/deck.tl-column.vue: | |||||||
|   is-media-view: "メディアビュー" |   is-media-view: "メディアビュー" | ||||||
|   edit: "オプション" |   edit: "オプション" | ||||||
| desktop/views/pages/deck/deck.user-column.vue: | desktop/views/pages/deck/deck.user-column.vue: | ||||||
|  |   posts: "投稿" | ||||||
|  |   following: "フォロー" | ||||||
|  |   followers: "フォロワー" | ||||||
|  |   images: "画像" | ||||||
|  |   activity: "アクティビティ" | ||||||
|  |   timeline: "タイムライン" | ||||||
|   pinned-notes: "ピン留めされた投稿" |   pinned-notes: "ピン留めされた投稿" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
| desktop/views/pages/stats/stats.vue: | desktop/views/pages/stats/stats.vue: | ||||||
| @@ -1043,6 +1060,9 @@ desktop/views/pages/user/user.profile.vue: | |||||||
|   mute: "ミュートする" |   mute: "ミュートする" | ||||||
|   muted: "ミュートしています" |   muted: "ミュートしています" | ||||||
|   unmute: "ミュート解除" |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロックする" | ||||||
|  |   unblock: "ブロック解除" | ||||||
|  |   block-confirm: "このユーザーをブロックしますか?" | ||||||
|   push-to-a-list: "リストに追加" |   push-to-a-list: "リストに追加" | ||||||
|   list-pushed: "{user}を{list}に追加しました。" |   list-pushed: "{user}を{list}に追加しました。" | ||||||
| desktop/views/pages/user/user.header.vue: | desktop/views/pages/user/user.header.vue: | ||||||
| @@ -1083,7 +1103,6 @@ desktop/views/widgets/users.vue: | |||||||
|   refresh: "他を見る" |   refresh: "他を見る" | ||||||
|   no-one: "いません!" |   no-one: "いません!" | ||||||
| mobile/views/components/drive.vue: | mobile/views/components/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   used: "使用中" |   used: "使用中" | ||||||
|   folder-count: "フォルダ" |   folder-count: "フォルダ" | ||||||
|   count-separator: "、" |   count-separator: "、" | ||||||
| @@ -1187,7 +1206,6 @@ mobile/views/components/ui.nav.vue: | |||||||
|   messaging: "メッセージ" |   messaging: "メッセージ" | ||||||
|   follow-requests: "フォロー申請" |   follow-requests: "フォロー申請" | ||||||
|   search: "検索" |   search: "検索" | ||||||
|   drive: "ドライブ" |  | ||||||
|   favorites: "お気に入り" |   favorites: "お気に入り" | ||||||
|   user-lists: "リスト" |   user-lists: "リスト" | ||||||
|   widgets: "ウィジェット" |   widgets: "ウィジェット" | ||||||
| @@ -1210,7 +1228,6 @@ mobile/views/pages/user-lists.vue: | |||||||
|   title: "リスト" |   title: "リスト" | ||||||
|   enter-list-name: "リスト名を入力してください" |   enter-list-name: "リスト名を入力してください" | ||||||
| mobile/views/pages/drive.vue: | mobile/views/pages/drive.vue: | ||||||
|   drive: "ドライブ" |  | ||||||
|   more: "もっと見る" |   more: "もっと見る" | ||||||
| mobile/views/pages/signup.vue: | mobile/views/pages/signup.vue: | ||||||
|   lets-start: "📦 始めましょう" |   lets-start: "📦 始めましょう" | ||||||
| @@ -1320,6 +1337,10 @@ mobile/views/pages/user.vue: | |||||||
|   timeline: "タイムライン" |   timeline: "タイムライン" | ||||||
|   media: "メディア" |   media: "メディア" | ||||||
|   is-suspended: "このユーザーは凍結されています。" |   is-suspended: "このユーザーは凍結されています。" | ||||||
|  |   mute: "ミュート" | ||||||
|  |   unmute: "ミュート解除" | ||||||
|  |   block: "ブロック" | ||||||
|  |   unblock: "ブロック解除" | ||||||
| mobile/views/pages/user/home.vue: | mobile/views/pages/user/home.vue: | ||||||
|   recent-notes: "最近の投稿" |   recent-notes: "最近の投稿" | ||||||
|   images: "画像" |   images: "画像" | ||||||
|   | |||||||
							
								
								
									
										17367
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										17367
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										39
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | |||||||
| { | { | ||||||
| 	"name": "misskey", | 	"name": "misskey", | ||||||
| 	"author": "syuilo <i@syuilo.com>", | 	"author": "syuilo <i@syuilo.com>", | ||||||
| 	"version": "10.30.1", | 	"version": "10.36.1", | ||||||
| 	"clientVersion": "1.0.11023", | 	"clientVersion": "1.0.11311", | ||||||
| 	"codename": "nighthike", | 	"codename": "nighthike", | ||||||
| 	"main": "./built/index.js", | 	"main": "./built/index.js", | ||||||
| 	"private": true, | 	"private": true, | ||||||
| @@ -58,7 +58,7 @@ | |||||||
| 		"@types/koa__cors": "2.2.3", | 		"@types/koa__cors": "2.2.3", | ||||||
| 		"@types/minio": "7.0.0", | 		"@types/minio": "7.0.0", | ||||||
| 		"@types/mkdirp": "0.5.2", | 		"@types/mkdirp": "0.5.2", | ||||||
| 		"@types/mocha": "5.2.3", | 		"@types/mocha": "5.2.5", | ||||||
| 		"@types/mongodb": "3.1.12", | 		"@types/mongodb": "3.1.12", | ||||||
| 		"@types/ms": "0.7.30", | 		"@types/ms": "0.7.30", | ||||||
| 		"@types/node": "10.12.0", | 		"@types/node": "10.12.0", | ||||||
| @@ -74,7 +74,7 @@ | |||||||
| 		"@types/sharp": "0.21.0", | 		"@types/sharp": "0.21.0", | ||||||
| 		"@types/showdown": "1.7.5", | 		"@types/showdown": "1.7.5", | ||||||
| 		"@types/single-line-log": "1.1.0", | 		"@types/single-line-log": "1.1.0", | ||||||
| 		"@types/speakeasy": "2.0.2", | 		"@types/speakeasy": "2.0.3", | ||||||
| 		"@types/systeminformation": "3.23.0", | 		"@types/systeminformation": "3.23.0", | ||||||
| 		"@types/tinycolor2": "1.4.1", | 		"@types/tinycolor2": "1.4.1", | ||||||
| 		"@types/tmp": "0.0.33", | 		"@types/tmp": "0.0.33", | ||||||
| @@ -84,7 +84,7 @@ | |||||||
| 		"@types/websocket": "0.0.40", | 		"@types/websocket": "0.0.40", | ||||||
| 		"@types/ws": "6.0.1", | 		"@types/ws": "6.0.1", | ||||||
| 		"animejs": "2.2.0", | 		"animejs": "2.2.0", | ||||||
| 		"apexcharts": "2.1.5", | 		"apexcharts": "2.1.9", | ||||||
| 		"autobind-decorator": "2.1.0", | 		"autobind-decorator": "2.1.0", | ||||||
| 		"autosize": "4.0.2", | 		"autosize": "4.0.2", | ||||||
| 		"autwh": "0.1.0", | 		"autwh": "0.1.0", | ||||||
| @@ -104,17 +104,15 @@ | |||||||
| 		"deep-equal": "1.0.1", | 		"deep-equal": "1.0.1", | ||||||
| 		"deepcopy": "0.6.3", | 		"deepcopy": "0.6.3", | ||||||
| 		"diskusage": "0.2.5", | 		"diskusage": "0.2.5", | ||||||
| 		"dompurify": "1.0.5", |  | ||||||
| 		"double-ended-queue": "2.1.0-0", | 		"double-ended-queue": "2.1.0-0", | ||||||
| 		"elasticsearch": "15.1.1", | 		"elasticsearch": "15.1.1", | ||||||
| 		"emojilib": "2.3.0", | 		"emojilib": "2.3.0", | ||||||
| 		"escape-regexp": "0.0.1", | 		"escape-regexp": "0.0.1", | ||||||
| 		"eslint": "5.0.1", | 		"eslint": "5.8.0", | ||||||
| 		"eslint-plugin-vue": "4.7.1", | 		"eslint-plugin-vue": "4.7.1", | ||||||
| 		"eventemitter3": "3.1.0", | 		"eventemitter3": "3.1.0", | ||||||
| 		"exif-js": "2.3.0", |  | ||||||
| 		"file-loader": "2.0.0", | 		"file-loader": "2.0.0", | ||||||
| 		"file-type": "10.1.0", | 		"file-type": "10.2.0", | ||||||
| 		"fuckadblock": "3.2.1", | 		"fuckadblock": "3.2.1", | ||||||
| 		"gulp": "3.9.1", | 		"gulp": "3.9.1", | ||||||
| 		"gulp-cssnano": "2.1.3", | 		"gulp-cssnano": "2.1.3", | ||||||
| @@ -131,17 +129,16 @@ | |||||||
| 		"gulp-uglify": "3.0.1", | 		"gulp-uglify": "3.0.1", | ||||||
| 		"gulp-util": "3.0.8", | 		"gulp-util": "3.0.8", | ||||||
| 		"hard-source-webpack-plugin": "0.12.0", | 		"hard-source-webpack-plugin": "0.12.0", | ||||||
| 		"highlight.js": "9.12.0", | 		"html-minifier": "3.5.21", | ||||||
| 		"html-minifier": "3.5.20", |  | ||||||
| 		"http-signature": "1.2.0", | 		"http-signature": "1.2.0", | ||||||
| 		"insert-text-at-cursor": "0.1.1", | 		"insert-text-at-cursor": "0.1.1", | ||||||
| 		"is-root": "2.0.0", | 		"is-root": "2.0.0", | ||||||
| 		"is-url": "1.2.4", | 		"is-url": "1.2.4", | ||||||
| 		"js-yaml": "3.12.0", | 		"js-yaml": "3.12.0", | ||||||
| 		"jsdom": "12.2.0", | 		"jsdom": "13.0.0", | ||||||
| 		"json5": "2.1.0", | 		"json5": "2.1.0", | ||||||
| 		"json5-loader": "1.0.1", | 		"json5-loader": "1.0.1", | ||||||
| 		"koa": "2.5.1", | 		"koa": "2.6.1", | ||||||
| 		"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", | ||||||
| @@ -154,7 +151,6 @@ | |||||||
| 		"koa-slow": "2.1.0", | 		"koa-slow": "2.1.0", | ||||||
| 		"koa-views": "6.1.4", | 		"koa-views": "6.1.4", | ||||||
| 		"loader-utils": "1.1.0", | 		"loader-utils": "1.1.0", | ||||||
| 		"lodash.assign": "4.2.0", |  | ||||||
| 		"mecab-async": "0.1.2", | 		"mecab-async": "0.1.2", | ||||||
| 		"merge-options": "1.0.1", | 		"merge-options": "1.0.1", | ||||||
| 		"minio": "7.0.1", | 		"minio": "7.0.1", | ||||||
| @@ -205,11 +201,11 @@ | |||||||
| 		"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": "4.4.1", | 		"ts-loader": "5.3.0", | ||||||
| 		"ts-node": "7.0.1", | 		"ts-node": "7.0.1", | ||||||
| 		"tslint": "5.10.0", | 		"tslint": "5.10.0", | ||||||
| 		"typescript": "2.9.2", | 		"typescript": "3.1.4", | ||||||
| 		"typescript-eslint-parser": "20.0.0", | 		"typescript-eslint-parser": "20.1.1", | ||||||
| 		"uglify-es": "3.3.9", | 		"uglify-es": "3.3.9", | ||||||
| 		"url-loader": "1.1.2", | 		"url-loader": "1.1.2", | ||||||
| 		"uuid": "3.3.2", | 		"uuid": "3.3.2", | ||||||
| @@ -233,17 +229,10 @@ | |||||||
| 		"vuex-persistedstate": "2.5.4", | 		"vuex-persistedstate": "2.5.4", | ||||||
| 		"web-push": "3.3.3", | 		"web-push": "3.3.3", | ||||||
| 		"webfinger.js": "2.6.6", | 		"webfinger.js": "2.6.6", | ||||||
| 		"webpack": "4.22.0", | 		"webpack": "4.23.1", | ||||||
| 		"webpack-cli": "3.1.2", | 		"webpack-cli": "3.1.2", | ||||||
| 		"websocket": "1.0.28", | 		"websocket": "1.0.28", | ||||||
| 		"ws": "6.1.0", | 		"ws": "6.1.0", | ||||||
| 		"xev": "2.0.1" | 		"xev": "2.0.1" | ||||||
| 	}, |  | ||||||
| 	"greenkeeper": { |  | ||||||
| 		"ignore": [ |  | ||||||
| 			"deepcopy", |  | ||||||
| 			"cafy", |  | ||||||
| 			"@types/gulp" |  | ||||||
| 		] |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								src/chart/federation.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/chart/federation.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | import autobind from 'autobind-decorator'; | ||||||
|  | import Chart, { Obj } from '.'; | ||||||
|  | import Instance from '../models/instance'; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * フェデレーションに関するチャート | ||||||
|  |  */ | ||||||
|  | type FederationLog = { | ||||||
|  | 	instance: { | ||||||
|  | 		/** | ||||||
|  | 		 * インスタンス数の合計 | ||||||
|  | 		 */ | ||||||
|  | 		total: number; | ||||||
|  |  | ||||||
|  | 		/** | ||||||
|  | 		 * 増加インスタンス数 | ||||||
|  | 		 */ | ||||||
|  | 		inc: number; | ||||||
|  |  | ||||||
|  | 		/** | ||||||
|  | 		 * 減少インスタンス数 | ||||||
|  | 		 */ | ||||||
|  | 		dec: number; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class FederationChart extends Chart<FederationLog> { | ||||||
|  | 	constructor() { | ||||||
|  | 		super('federation'); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@autobind | ||||||
|  | 	protected async getTemplate(init: boolean, latest?: FederationLog): Promise<FederationLog> { | ||||||
|  | 		const [total] = init ? await Promise.all([ | ||||||
|  | 			Instance.count({}) | ||||||
|  | 		]) : [ | ||||||
|  | 			latest ? latest.instance.total : 0 | ||||||
|  | 		]; | ||||||
|  |  | ||||||
|  | 		return { | ||||||
|  | 			instance: { | ||||||
|  | 				total: total, | ||||||
|  | 				inc: 0, | ||||||
|  | 				dec: 0 | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@autobind | ||||||
|  | 	public async update(isAdditional: boolean) { | ||||||
|  | 		const update: Obj = {}; | ||||||
|  |  | ||||||
|  | 		update.total = isAdditional ? 1 : -1; | ||||||
|  | 		if (isAdditional) { | ||||||
|  | 			update.inc = 1; | ||||||
|  | 		} else { | ||||||
|  | 			update.dec = 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		await this.inc({ | ||||||
|  | 			instance: update | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default new FederationChart(); | ||||||
| @@ -20,7 +20,6 @@ type ArrayValue<T> = { | |||||||
|  |  | ||||||
| type Span = 'day' | 'hour'; | type Span = 'day' | 'hour'; | ||||||
|  |  | ||||||
| //#region Chart Core |  | ||||||
| type Log<T extends Obj> = { | type Log<T extends Obj> = { | ||||||
| 	_id: mongo.ObjectID; | 	_id: mongo.ObjectID; | ||||||
|  |  | ||||||
| @@ -87,13 +86,33 @@ export default abstract class Chart<T> { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@autobind | 	@autobind | ||||||
| 	private async getCurrentLog(span: Span, group?: any): Promise<Log<T>> { | 	private getCurrentDate(): [number, number, number, number] { | ||||||
| 		const now = new Date(); | 		const now = new Date(); | ||||||
|  |  | ||||||
| 		const y = now.getFullYear(); | 		const y = now.getFullYear(); | ||||||
| 		const m = now.getMonth(); | 		const m = now.getMonth(); | ||||||
| 		const d = now.getDate(); | 		const d = now.getDate(); | ||||||
| 		const h = now.getHours(); | 		const h = now.getHours(); | ||||||
|  |  | ||||||
|  | 		return [y, m, d, h]; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@autobind | ||||||
|  | 	private getLatestLog(span: Span, group?: any): Promise<Log<T>> { | ||||||
|  | 		return this.collection.findOne({ | ||||||
|  | 			group: group, | ||||||
|  | 			span: span | ||||||
|  | 		}, { | ||||||
|  | 			sort: { | ||||||
|  | 				date: -1 | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@autobind | ||||||
|  | 	private async getCurrentLog(span: Span, group?: any): Promise<Log<T>> { | ||||||
|  | 		const [y, m, d, h] = this.getCurrentDate(); | ||||||
|  |  | ||||||
| 		const current = | 		const current = | ||||||
| 			span == 'day' ? new Date(y, m, d) : | 			span == 'day' ? new Date(y, m, d) : | ||||||
| 			span == 'hour' ? new Date(y, m, d, h) : | 			span == 'hour' ? new Date(y, m, d, h) : | ||||||
| @@ -106,54 +125,56 @@ export default abstract class Chart<T> { | |||||||
| 			date: current | 			date: current | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
| 		if (currentLog) { | 		// ログがあればそれを返して終了 | ||||||
|  | 		if (currentLog != null) { | ||||||
| 			return currentLog; | 			return currentLog; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		let log: Log<T>; | ||||||
|  | 		let data: T; | ||||||
|  |  | ||||||
| 		// 集計期間が変わってから、初めてのチャート更新なら | 		// 集計期間が変わってから、初めてのチャート更新なら | ||||||
| 		// 最も最近のログを持ってくる | 		// 最も最近のログを持ってくる | ||||||
| 		// * 例えば集計期間が「日」である場合で考えると、 | 		// * 例えば集計期間が「日」である場合で考えると、 | ||||||
| 		// * 昨日何もチャートを更新するような出来事がなかった場合は、 | 		// * 昨日何もチャートを更新するような出来事がなかった場合は、 | ||||||
| 		// * ログがそもそも作られずドキュメントが存在しないということがあり得るため、 | 		// * ログがそもそも作られずドキュメントが存在しないということがあり得るため、 | ||||||
| 		// * 「昨日の」と決め打ちせずに「もっとも最近の」とします | 		// * 「昨日の」と決め打ちせずに「もっとも最近の」とします | ||||||
| 		const latest = await this.collection.findOne({ | 		const latest = await this.getLatestLog(span, group); | ||||||
| 			group: group, |  | ||||||
| 			span: span |  | ||||||
| 		}, { |  | ||||||
| 			sort: { |  | ||||||
| 				date: -1 |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		if (latest) { | 		if (latest != null) { | ||||||
| 			// 現在のログを初期挿入 | 			// 空ログデータを作成 | ||||||
| 			const data = await this.getTemplate(false, latest.data); | 			data = await this.getTemplate(false, latest.data); | ||||||
|  |  | ||||||
| 			const log = await this.collection.insert({ |  | ||||||
| 				group: group, |  | ||||||
| 				span: span, |  | ||||||
| 				date: current, |  | ||||||
| 				data: data |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 			return log; |  | ||||||
| 		} else { | 		} else { | ||||||
| 			// ログが存在しなかったら | 			// ログが存在しなかったら | ||||||
| 			// * Misskeyインスタンスを建てて初めてのチャート更新時など | 			// (Misskeyインスタンスを建てて初めてのチャート更新時など | ||||||
|  | 			// または何らかの理由でチャートコレクションを抹消した場合) | ||||||
|  |  | ||||||
| 			// 空のログを作成 | 			// 初期ログデータを作成 | ||||||
| 			const data = await this.getTemplate(true, null, group); | 			data = await this.getTemplate(true, null, group); | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 			const log = await this.collection.insert({ | 		try { | ||||||
|  | 			// 新規ログ挿入 | ||||||
|  | 			log = await this.collection.insert({ | ||||||
| 				group: group, | 				group: group, | ||||||
| 				span: span, | 				span: span, | ||||||
| 				date: current, | 				date: current, | ||||||
| 				data: data | 				data: data | ||||||
| 			}); | 			}); | ||||||
|  | 		} catch (e) { | ||||||
|  | 			// 11000 is duplicate key error | ||||||
|  | 			// 並列動作している他のチャートエンジンプロセスと処理が重なる場合がある | ||||||
|  | 			// その場合は再度最も新しいログを持ってくる | ||||||
|  | 			if (e.code === 11000) { | ||||||
|  | 				log = await this.getLatestLog(span, group); | ||||||
|  | 			} else { | ||||||
|  | 				console.error(e); | ||||||
|  | 				throw e; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return log; | 		return log; | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@autobind | 	@autobind | ||||||
| 	protected commit(query: Obj, group?: any, uniqueKey?: string, uniqueValue?: string): void { | 	protected commit(query: Obj, group?: any, uniqueKey?: string, uniqueValue?: string): void { | ||||||
| @@ -173,6 +194,7 @@ export default abstract class Chart<T> { | |||||||
| 				}; | 				}; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			// ログ更新 | ||||||
| 			this.collection.update({ | 			this.collection.update({ | ||||||
| 				_id: log._id | 				_id: log._id | ||||||
| 			}, query); | 			}, query); | ||||||
| @@ -200,16 +222,14 @@ export default abstract class Chart<T> { | |||||||
| 	public async getChart(span: Span, range: number, group?: any): Promise<ArrayValue<T>> { | 	public async getChart(span: Span, range: number, group?: any): Promise<ArrayValue<T>> { | ||||||
| 		const promisedChart: Promise<T>[] = []; | 		const promisedChart: Promise<T>[] = []; | ||||||
|  |  | ||||||
| 		const now = new Date(); | 		const [y, m, d, h] = this.getCurrentDate(); | ||||||
| 		const y = now.getFullYear(); |  | ||||||
| 		const m = now.getMonth(); |  | ||||||
| 		const d = now.getDate(); |  | ||||||
| 		const h = now.getHours(); |  | ||||||
|  |  | ||||||
| 		const gt = | 		const gt = | ||||||
| 			span == 'day' ? new Date(y, m, d - range) : | 			span == 'day' ? new Date(y, m, d - range) : | ||||||
| 			span == 'hour' ? new Date(y, m, d, h - range) : null; | 			span == 'hour' ? new Date(y, m, d, h - range) : | ||||||
|  | 			null; | ||||||
|  |  | ||||||
|  | 		// ログ取得 | ||||||
| 		const logs = await this.collection.find({ | 		const logs = await this.collection.find({ | ||||||
| 			group: group, | 			group: group, | ||||||
| 			span: span, | 			span: span, | ||||||
| @@ -225,6 +245,7 @@ export default abstract class Chart<T> { | |||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
|  | 		// 整形 | ||||||
| 		for (let i = (range - 1); i >= 0; i--) { | 		for (let i = (range - 1); i >= 0; i--) { | ||||||
| 			const current = | 			const current = | ||||||
| 				span == 'day' ? new Date(y, m, d - i) : | 				span == 'day' ? new Date(y, m, d - i) : | ||||||
| @@ -235,7 +256,8 @@ export default abstract class Chart<T> { | |||||||
|  |  | ||||||
| 			if (log) { | 			if (log) { | ||||||
| 				promisedChart.unshift(Promise.resolve(log.data)); | 				promisedChart.unshift(Promise.resolve(log.data)); | ||||||
| 			} else { // 隙間埋め | 			} else { | ||||||
|  | 				// 隙間埋め | ||||||
| 				const latest = logs.find(l => l.date.getTime() < current.getTime()); | 				const latest = logs.find(l => l.date.getTime() < current.getTime()); | ||||||
| 				promisedChart.unshift(this.getTemplate(false, latest ? latest.data : null)); | 				promisedChart.unshift(this.getTemplate(false, latest ? latest.data : null)); | ||||||
| 			} | 			} | ||||||
| @@ -282,4 +304,3 @@ export default abstract class Chart<T> { | |||||||
| 		return res; | 		return res; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| //#endregion |  | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								src/client/app/common/views/components/api-settings.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/client/app/common/views/components/api-settings.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | <template> | ||||||
|  | <ui-card> | ||||||
|  | 	<div slot="title">%fa:key% API</div> | ||||||
|  |  | ||||||
|  | 	<section class="fit-top"> | ||||||
|  | 		<ui-input :value="$store.state.i.token" readonly> | ||||||
|  | 			<span>%i18n:@token%</span> | ||||||
|  | 		</ui-input> | ||||||
|  | 		<p>%i18n:@intro%</p> | ||||||
|  | 		<ui-info warn>%i18n:@caution%</ui-info> | ||||||
|  | 		<p>%i18n:@regeneration-of-token%</p> | ||||||
|  | 		<ui-button @click="regenerateToken">%fa:sync-alt% %i18n:@regenerate-token%</ui-button> | ||||||
|  | 	</section> | ||||||
|  |  | ||||||
|  | 	<section> | ||||||
|  | 		<header>%fa:terminal% %i18n:@console.title%</header> | ||||||
|  | 		<ui-input v-model="endpoint"> | ||||||
|  | 			<span>%i18n:@console.endpoint%</span> | ||||||
|  | 		</ui-input> | ||||||
|  | 		<ui-textarea v-model="body"> | ||||||
|  | 			<span>%i18n:@console.parameter% (JSON or JSON5)</span> | ||||||
|  | 		</ui-textarea> | ||||||
|  | 		<ui-button @click="send" :disabled="sending"> | ||||||
|  | 			<template v-if="sending">%i18n:@console.sending%</template> | ||||||
|  | 			<template v-else>%fa:paper-plane% %i18n:@console.send%</template> | ||||||
|  | 		</ui-button> | ||||||
|  | 		<ui-textarea v-if="res" v-model="res" readonly tall> | ||||||
|  | 			<span>%i18n:@console.response%</span> | ||||||
|  | 		</ui-textarea> | ||||||
|  | 	</section> | ||||||
|  | </ui-card> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script lang="ts"> | ||||||
|  | import Vue from 'vue'; | ||||||
|  | import * as JSON5 from 'json5'; | ||||||
|  |  | ||||||
|  | export default Vue.extend({ | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			endpoint: '', | ||||||
|  | 			body: '{}', | ||||||
|  | 			res: null, | ||||||
|  | 			sending: false | ||||||
|  | 		}; | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	methods: { | ||||||
|  | 		regenerateToken() { | ||||||
|  | 			(this as any).apis.input({ | ||||||
|  | 				title: '%i18n:@enter-password%', | ||||||
|  | 				type: 'password' | ||||||
|  | 			}).then(password => { | ||||||
|  | 				(this as any).api('i/regenerate_token', { | ||||||
|  | 					password: password | ||||||
|  | 				}); | ||||||
|  | 			}); | ||||||
|  | 		}, | ||||||
|  |  | ||||||
|  | 		send() { | ||||||
|  | 			this.sending = true; | ||||||
|  | 			(this as any).api(this.endpoint, JSON5.parse(this.body)).then(res => { | ||||||
|  | 				this.sending = false; | ||||||
|  | 				this.res = JSON5.stringify(res, null, 2); | ||||||
|  | 			}, err => { | ||||||
|  | 				this.sending = false; | ||||||
|  | 				this.res = JSON5.stringify(err, null, 2); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | </script> | ||||||
							
								
								
									
										171
									
								
								src/client/app/common/views/components/drive-settings.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/client/app/common/views/components/drive-settings.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | |||||||
|  | <template> | ||||||
|  | <ui-card> | ||||||
|  | 	<div slot="title">%fa:cloud% %i18n:common.drive%</div> | ||||||
|  |  | ||||||
|  | 	<section v-if="!fetching" class="juakhbxthdewydyreaphkepoxgxvfogn"> | ||||||
|  | 		<div class="meter"><div :style="meterStyle"></div></div> | ||||||
|  | 		<p>%i18n:@max%: <b>{{ capacity | bytes }}</b> %i18n:@in-use%: <b>{{ usage | bytes }}</b></p> | ||||||
|  | 	</section> | ||||||
|  |  | ||||||
|  | 	<section> | ||||||
|  | 		<header>%i18n:@stats%</header> | ||||||
|  | 		<div ref="chart" style="margin-bottom: -16px; color: #000;"></div> | ||||||
|  | 	</section> | ||||||
|  | </ui-card> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script lang="ts"> | ||||||
|  | import Vue from 'vue'; | ||||||
|  | import * as tinycolor from 'tinycolor2'; | ||||||
|  | import * as ApexCharts from 'apexcharts'; | ||||||
|  |  | ||||||
|  | export default Vue.extend({ | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			fetching: true, | ||||||
|  | 			usage: null, | ||||||
|  | 			capacity: null | ||||||
|  | 		}; | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	computed: { | ||||||
|  | 		meterStyle(): any { | ||||||
|  | 			return { | ||||||
|  | 				width: `${this.usage / this.capacity * 100}%`, | ||||||
|  | 				background: tinycolor({ | ||||||
|  | 					h: 180 - (this.usage / this.capacity * 180), | ||||||
|  | 					s: 0.7, | ||||||
|  | 					l: 0.5 | ||||||
|  | 				}) | ||||||
|  | 			}; | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	mounted() { | ||||||
|  | 		(this as any).api('drive').then(info => { | ||||||
|  | 			this.capacity = info.capacity; | ||||||
|  | 			this.usage = info.usage; | ||||||
|  | 			this.fetching = false; | ||||||
|  |  | ||||||
|  | 			this.$nextTick(() => { | ||||||
|  | 				this.renderChart(); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	methods: { | ||||||
|  | 		renderChart() { | ||||||
|  | 			(this as any).api('charts/user/drive', { | ||||||
|  | 				userId: this.$store.state.i.id, | ||||||
|  | 				span: 'day', | ||||||
|  | 				limit: 21 | ||||||
|  | 			}).then(stats => { | ||||||
|  | 				const addition = []; | ||||||
|  | 				const deletion = []; | ||||||
|  |  | ||||||
|  | 				const now = new Date(); | ||||||
|  | 				const y = now.getFullYear(); | ||||||
|  | 				const m = now.getMonth(); | ||||||
|  | 				const d = now.getDate(); | ||||||
|  |  | ||||||
|  | 				for (let i = 0; i < 21; i++) { | ||||||
|  | 					const x = new Date(y, m, d - i); | ||||||
|  | 					addition.push([ | ||||||
|  | 						x, | ||||||
|  | 						stats.incSize[i] | ||||||
|  | 					]); | ||||||
|  | 					deletion.push([ | ||||||
|  | 						x, | ||||||
|  | 						-stats.decSize[i] | ||||||
|  | 					]); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				const chart = new ApexCharts(this.$refs.chart, { | ||||||
|  | 					chart: { | ||||||
|  | 						type: 'bar', | ||||||
|  | 						stacked: true, | ||||||
|  | 						height: 150, | ||||||
|  | 						zoom: { | ||||||
|  | 							enabled: false | ||||||
|  | 						} | ||||||
|  | 					}, | ||||||
|  | 					plotOptions: { | ||||||
|  | 						bar: { | ||||||
|  | 							columnWidth: '90%', | ||||||
|  | 							endingShape: 'rounded' | ||||||
|  | 						} | ||||||
|  | 					}, | ||||||
|  | 					grid: { | ||||||
|  | 						clipMarkers: false, | ||||||
|  | 						borderColor: 'rgba(0, 0, 0, 0.1)' | ||||||
|  | 					}, | ||||||
|  | 					tooltip: { | ||||||
|  | 						shared: true, | ||||||
|  | 						intersect: false | ||||||
|  | 					}, | ||||||
|  | 					dataLabels: { | ||||||
|  | 						enabled: false | ||||||
|  | 					}, | ||||||
|  | 					legend: { | ||||||
|  | 						show: false | ||||||
|  | 					}, | ||||||
|  | 					series: [{ | ||||||
|  | 						name: 'Additions', | ||||||
|  | 						data: addition | ||||||
|  | 					}, { | ||||||
|  | 						name: 'Deletions', | ||||||
|  | 						data: deletion | ||||||
|  | 					}], | ||||||
|  | 					xaxis: { | ||||||
|  | 						type: 'datetime', | ||||||
|  | 						labels: { | ||||||
|  | 							style: { | ||||||
|  | 								colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString() | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 						axisBorder: { | ||||||
|  | 							color: 'rgba(0, 0, 0, 0.1)' | ||||||
|  | 						}, | ||||||
|  | 						axisTicks: { | ||||||
|  | 							color: 'rgba(0, 0, 0, 0.1)' | ||||||
|  | 						}, | ||||||
|  | 						crosshairs: { | ||||||
|  | 							width: 1, | ||||||
|  | 							opacity: 1 | ||||||
|  | 						} | ||||||
|  | 					}, | ||||||
|  | 					yaxis: { | ||||||
|  | 						labels: { | ||||||
|  | 							formatter: v => Vue.filter('bytes')(v, 0), | ||||||
|  | 							style: { | ||||||
|  | 								color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString() | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				chart.render(); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="stylus" scoped> | ||||||
|  | .juakhbxthdewydyreaphkepoxgxvfogn | ||||||
|  | 	> .meter | ||||||
|  | 		$size = 12px | ||||||
|  |  | ||||||
|  | 		margin-bottom 16px | ||||||
|  | 		background rgba(0, 0, 0, 0.1) | ||||||
|  | 		border-radius ($size / 2) | ||||||
|  | 		overflow hidden | ||||||
|  |  | ||||||
|  | 		> div | ||||||
|  | 			height $size | ||||||
|  | 			border-radius ($size / 2) | ||||||
|  |  | ||||||
|  | 	> p | ||||||
|  | 		margin 0 | ||||||
|  |  | ||||||
|  | </style> | ||||||
							
								
								
									
										19
									
								
								src/client/app/common/views/components/error.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/client/app/common/views/components/error.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | <template> | ||||||
|  | <div class="wjqjnyhzogztorhrdgcpqlkxhkmuetgj"> | ||||||
|  | 	<p>%fa:exclamation-triangle% %i18n:common.error.title%</p> | ||||||
|  | 	<ui-button @click="() => $emit('retry')">%i18n:common.error.retry%</ui-button> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <style lang="stylus" scoped> | ||||||
|  | .wjqjnyhzogztorhrdgcpqlkxhkmuetgj | ||||||
|  | 	max-width 350px | ||||||
|  | 	margin 0 auto | ||||||
|  | 	padding 32px | ||||||
|  | 	text-align center | ||||||
|  | 	color var(--text) | ||||||
|  |  | ||||||
|  | 	> p | ||||||
|  | 		margin 0 0 8px 0 | ||||||
|  |  | ||||||
|  | </style> | ||||||
| @@ -1,5 +1,9 @@ | |||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
|  |  | ||||||
|  | import muteAndBlock from './mute-and-block.vue'; | ||||||
|  | import error from './error.vue'; | ||||||
|  | import apiSettings from './api-settings.vue'; | ||||||
|  | import driveSettings from './drive-settings.vue'; | ||||||
| import profileEditor from './profile-editor.vue'; | import profileEditor from './profile-editor.vue'; | ||||||
| import noteSkeleton from './note-skeleton.vue'; | import noteSkeleton from './note-skeleton.vue'; | ||||||
| import theme from './theme.vue'; | import theme from './theme.vue'; | ||||||
| @@ -43,9 +47,14 @@ import uiTextarea from './ui/textarea.vue'; | |||||||
| import uiSwitch from './ui/switch.vue'; | import uiSwitch from './ui/switch.vue'; | ||||||
| import uiRadio from './ui/radio.vue'; | import uiRadio from './ui/radio.vue'; | ||||||
| import uiSelect from './ui/select.vue'; | import uiSelect from './ui/select.vue'; | ||||||
|  | import uiInfo from './ui/info.vue'; | ||||||
| import formButton from './ui/form/button.vue'; | import formButton from './ui/form/button.vue'; | ||||||
| import formRadio from './ui/form/radio.vue'; | import formRadio from './ui/form/radio.vue'; | ||||||
|  |  | ||||||
|  | Vue.component('mk-mute-and-block', muteAndBlock); | ||||||
|  | Vue.component('mk-error', error); | ||||||
|  | Vue.component('mk-api-settings', apiSettings); | ||||||
|  | Vue.component('mk-drive-settings', driveSettings); | ||||||
| Vue.component('mk-profile-editor', profileEditor); | Vue.component('mk-profile-editor', profileEditor); | ||||||
| Vue.component('mk-note-skeleton', noteSkeleton); | Vue.component('mk-note-skeleton', noteSkeleton); | ||||||
| Vue.component('mk-theme', theme); | Vue.component('mk-theme', theme); | ||||||
| @@ -89,5 +98,6 @@ Vue.component('ui-textarea', uiTextarea); | |||||||
| Vue.component('ui-switch', uiSwitch); | Vue.component('ui-switch', uiSwitch); | ||||||
| Vue.component('ui-radio', uiRadio); | Vue.component('ui-radio', uiRadio); | ||||||
| Vue.component('ui-select', uiSelect); | Vue.component('ui-select', uiSelect); | ||||||
|  | Vue.component('ui-info', uiInfo); | ||||||
| Vue.component('form-button', formButton); | Vue.component('form-button', formButton); | ||||||
| Vue.component('form-radio', formRadio); | Vue.component('form-radio', formRadio); | ||||||
|   | |||||||
							
								
								
									
										52
									
								
								src/client/app/common/views/components/mute-and-block.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/client/app/common/views/components/mute-and-block.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | <template> | ||||||
|  | <ui-card> | ||||||
|  | 	<div slot="title">%fa:ban% %i18n:@mute-and-block%</div> | ||||||
|  |  | ||||||
|  | 	<section> | ||||||
|  | 		<header>%i18n:@mute%</header> | ||||||
|  | 		<ui-info v-if="!muteFetching && mute.length == 0">%i18n:@no-muted-users%</ui-info> | ||||||
|  | 		<div class="users" v-if="mute.length != 0"> | ||||||
|  | 			<div v-for="user in mute" :key="user.id"> | ||||||
|  | 				<p><b>{{ user | userName }}</b> @{{ user | acct }}</p> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 	</section> | ||||||
|  |  | ||||||
|  | 	<section> | ||||||
|  | 		<header>%i18n:@block%</header> | ||||||
|  | 		<ui-info v-if="!blockFetching && block.length == 0">%i18n:@no-blocked-users%</ui-info> | ||||||
|  | 		<div class="users" v-if="block.length != 0"> | ||||||
|  | 			<div v-for="user in block" :key="user.id"> | ||||||
|  | 				<p><b>{{ user | userName }}</b> @{{ user | acct }}</p> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 	</section> | ||||||
|  | </ui-card> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script lang="ts"> | ||||||
|  | import Vue from 'vue'; | ||||||
|  |  | ||||||
|  | export default Vue.extend({ | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			muteFetching: true, | ||||||
|  | 			blockFetching: true, | ||||||
|  | 			mute: [], | ||||||
|  | 			block: [] | ||||||
|  | 		}; | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	mounted() { | ||||||
|  | 		(this as any).api('mute/list').then(mute => { | ||||||
|  | 			this.mute = mute.map(x => x.mutee); | ||||||
|  | 			this.muteFetching = false; | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		(this as any).api('blocking/list').then(blocking => { | ||||||
|  | 			this.block = blocking.map(x => x.blockee); | ||||||
|  | 			this.blockFetching = false; | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | </script> | ||||||
| @@ -2,11 +2,11 @@ | |||||||
| <header class="bvonvjxbwzaiskogyhbwgyxvcgserpmu"> | <header class="bvonvjxbwzaiskogyhbwgyxvcgserpmu"> | ||||||
| 	<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle == 'smart'"/> | 	<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle == 'smart'"/> | ||||||
| 	<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link> | 	<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link> | ||||||
| 	<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%">%fa:star%</span> |  | ||||||
| 	<span class="is-admin" v-if="note.user.isAdmin">admin</span> | 	<span class="is-admin" v-if="note.user.isAdmin">admin</span> | ||||||
| 	<span class="is-bot" v-if="note.user.isBot">bot</span> | 	<span class="is-bot" v-if="note.user.isBot">bot</span> | ||||||
| 	<span class="is-cat" v-if="note.user.isCat">cat</span> | 	<span class="is-cat" v-if="note.user.isCat">cat</span> | ||||||
| 	<span class="username"><mk-acct :user="note.user"/></span> | 	<span class="username"><mk-acct :user="note.user"/></span> | ||||||
|  | 	<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%">%fa:star%</span> | ||||||
| 	<div class="info"> | 	<div class="info"> | ||||||
| 		<span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span> | 		<span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span> | ||||||
| 		<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span> | 		<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span> | ||||||
| @@ -68,10 +68,6 @@ export default Vue.extend({ | |||||||
| 		&:hover | 		&:hover | ||||||
| 			text-decoration underline | 			text-decoration underline | ||||||
|  |  | ||||||
| 	> .is-verified |  | ||||||
| 		margin-right 8px |  | ||||||
| 		color #4dabf7 |  | ||||||
|  |  | ||||||
| 	> .is-admin | 	> .is-admin | ||||||
| 	> .is-bot | 	> .is-bot | ||||||
| 	> .is-cat | 	> .is-cat | ||||||
| @@ -95,6 +91,10 @@ export default Vue.extend({ | |||||||
| 		color var(--noteHeaderAcct) | 		color var(--noteHeaderAcct) | ||||||
| 		flex-shrink 2147483647 | 		flex-shrink 2147483647 | ||||||
|  |  | ||||||
|  | 	> .is-verified | ||||||
|  | 		margin 0 .5em 0 0 | ||||||
|  | 		color #4dabf7 | ||||||
|  |  | ||||||
| 	> .info | 	> .info | ||||||
| 		margin-left auto | 		margin-left auto | ||||||
| 		font-size 0.9em | 		font-size 0.9em | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								src/client/app/common/views/components/ui/info.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/client/app/common/views/components/ui/info.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | <template> | ||||||
|  | <div class="ymxyweixqwsxauxldgpvecjepnwxbylu" :class="{ warn }"> | ||||||
|  | 	<i v-if="warn">%fa:exclamation-triangle%</i> | ||||||
|  | 	<i v-else>%fa:info-circle%</i> | ||||||
|  | 	<slot></slot> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script lang="ts"> | ||||||
|  | import Vue from 'vue'; | ||||||
|  | export default Vue.extend({ | ||||||
|  | 	props: { | ||||||
|  | 		warn: { | ||||||
|  | 			type: Boolean, | ||||||
|  | 			required: false, | ||||||
|  | 			default: false | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="stylus" scoped> | ||||||
|  | .ymxyweixqwsxauxldgpvecjepnwxbylu | ||||||
|  | 	margin 16px 0 | ||||||
|  | 	padding 16px | ||||||
|  | 	font-size 90% | ||||||
|  | 	background var(--infoBg) | ||||||
|  | 	color var(--infoFg) | ||||||
|  |  | ||||||
|  | 	&.warn | ||||||
|  | 		background var(--infoWarnBg) | ||||||
|  | 		color var(--infoWarnFg) | ||||||
|  |  | ||||||
|  | 	&:first-child | ||||||
|  | 		margin-top 0 | ||||||
|  |  | ||||||
|  | 	&:last-child | ||||||
|  | 		margin-bottom 0 | ||||||
|  |  | ||||||
|  | 	> i | ||||||
|  | 		margin-right 4px | ||||||
|  |  | ||||||
|  | </style> | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| <template> | <template> | ||||||
| <div class="ui-textarea" :class="{ focused, filled }"> | <div class="ui-textarea" :class="{ focused, filled, tall }"> | ||||||
| 	<div class="input"> | 	<div class="input"> | ||||||
| 		<span class="label" ref="label"><slot></slot></span> | 		<span class="label" ref="label"><slot></slot></span> | ||||||
| 		<textarea ref="input" | 		<textarea ref="input" | ||||||
| @@ -10,8 +10,8 @@ | |||||||
| 			:autocomplete="autocomplete" | 			:autocomplete="autocomplete" | ||||||
| 			@input="$emit('input', $event.target.value)" | 			@input="$emit('input', $event.target.value)" | ||||||
| 			@focus="focused = true" | 			@focus="focused = true" | ||||||
| 				@blur="focused = false"> | 			@blur="focused = false" | ||||||
| 		</textarea> | 		></textarea> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="text"><slot name="text"></slot></div> | 	<div class="text"><slot name="text"></slot></div> | ||||||
| </div> | </div> | ||||||
| @@ -41,7 +41,12 @@ export default Vue.extend({ | |||||||
| 		autocomplete: { | 		autocomplete: { | ||||||
| 			type: String, | 			type: String, | ||||||
| 			required: false | 			required: false | ||||||
| 		} | 		}, | ||||||
|  | 		tall: { | ||||||
|  | 			type: Boolean, | ||||||
|  | 			required: false, | ||||||
|  | 			default: false | ||||||
|  | 		}, | ||||||
| 	}, | 	}, | ||||||
| 	data() { | 	data() { | ||||||
| 		return { | 		return { | ||||||
| @@ -66,6 +71,9 @@ export default Vue.extend({ | |||||||
| root(fill) | root(fill) | ||||||
| 	margin 42px 0 32px 0 | 	margin 42px 0 32px 0 | ||||||
|  |  | ||||||
|  | 	&:last-child | ||||||
|  | 		margin-bottom 0 | ||||||
|  |  | ||||||
| 	> .input | 	> .input | ||||||
| 		padding 12px | 		padding 12px | ||||||
|  |  | ||||||
| @@ -157,6 +165,11 @@ root(fill) | |||||||
| 				left 0 !important | 				left 0 !important | ||||||
| 				transform scale(0.75) | 				transform scale(0.75) | ||||||
|  |  | ||||||
|  | 	&.tall | ||||||
|  | 		> .input | ||||||
|  | 			> textarea | ||||||
|  | 				min-height 200px | ||||||
|  |  | ||||||
| .ui-textarea.fill | .ui-textarea.fill | ||||||
| 	root(true) | 	root(true) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,10 @@ | |||||||
| 	<header> | 	<header> | ||||||
| 		<b>%i18n:@title%:</b> | 		<b>%i18n:@title%:</b> | ||||||
| 		<select v-model="chartType"> | 		<select v-model="chartType"> | ||||||
|  | 			<optgroup label="%i18n:@federation%"> | ||||||
|  | 				<option value="federation-instances">%i18n:@charts.federation-instances%</option> | ||||||
|  | 				<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option> | ||||||
|  | 			</optgroup> | ||||||
| 			<optgroup label="%i18n:@users%"> | 			<optgroup label="%i18n:@users%"> | ||||||
| 				<option value="users">%i18n:@charts.users%</option> | 				<option value="users">%i18n:@charts.users%</option> | ||||||
| 				<option value="users-total">%i18n:@charts.users-total%</option> | 				<option value="users-total">%i18n:@charts.users-total%</option> | ||||||
| @@ -79,6 +83,8 @@ export default Vue.extend({ | |||||||
| 		data(): any { | 		data(): any { | ||||||
| 			if (this.chart == null) return null; | 			if (this.chart == null) return null; | ||||||
| 			switch (this.chartType) { | 			switch (this.chartType) { | ||||||
|  | 				case 'federation-instances': return this.federationInstancesChart(false); | ||||||
|  | 				case 'federation-instances-total': return this.federationInstancesChart(true); | ||||||
| 				case 'users': return this.usersChart(false); | 				case 'users': return this.usersChart(false); | ||||||
| 				case 'users-total': return this.usersChart(true); | 				case 'users-total': return this.usersChart(true); | ||||||
| 				case 'notes': return this.notesChart('combined'); | 				case 'notes': return this.notesChart('combined'); | ||||||
| @@ -109,11 +115,13 @@ export default Vue.extend({ | |||||||
| 		this.now = new Date(); | 		this.now = new Date(); | ||||||
|  |  | ||||||
| 		const [perHour, perDay] = await Promise.all([Promise.all([ | 		const [perHour, perDay] = await Promise.all([Promise.all([ | ||||||
|  | 			(this as any).api('charts/federation', { limit: limit, span: 'hour' }), | ||||||
| 			(this as any).api('charts/users', { limit: limit, span: 'hour' }), | 			(this as any).api('charts/users', { limit: limit, span: 'hour' }), | ||||||
| 			(this as any).api('charts/notes', { limit: limit, span: 'hour' }), | 			(this as any).api('charts/notes', { limit: limit, span: 'hour' }), | ||||||
| 			(this as any).api('charts/drive', { limit: limit, span: 'hour' }), | 			(this as any).api('charts/drive', { limit: limit, span: 'hour' }), | ||||||
| 			(this as any).api('charts/network', { limit: limit, span: 'hour' }) | 			(this as any).api('charts/network', { limit: limit, span: 'hour' }) | ||||||
| 		]), Promise.all([ | 		]), Promise.all([ | ||||||
|  | 			(this as any).api('charts/federation', { limit: limit, span: 'day' }), | ||||||
| 			(this as any).api('charts/users', { limit: limit, span: 'day' }), | 			(this as any).api('charts/users', { limit: limit, span: 'day' }), | ||||||
| 			(this as any).api('charts/notes', { limit: limit, span: 'day' }), | 			(this as any).api('charts/notes', { limit: limit, span: 'day' }), | ||||||
| 			(this as any).api('charts/drive', { limit: limit, span: 'day' }), | 			(this as any).api('charts/drive', { limit: limit, span: 'day' }), | ||||||
| @@ -122,16 +130,18 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| 		const chart = { | 		const chart = { | ||||||
| 			perHour: { | 			perHour: { | ||||||
| 				users: perHour[0], | 				federation: perHour[0], | ||||||
| 				notes: perHour[1], | 				users: perHour[1], | ||||||
| 				drive: perHour[2], | 				notes: perHour[2], | ||||||
| 				network: perHour[3] | 				drive: perHour[3], | ||||||
|  | 				network: perHour[4] | ||||||
| 			}, | 			}, | ||||||
| 			perDay: { | 			perDay: { | ||||||
| 				users: perDay[0], | 				federation: perDay[0], | ||||||
| 				notes: perDay[1], | 				users: perDay[1], | ||||||
| 				drive: perDay[2], | 				notes: perDay[2], | ||||||
| 				network: perDay[3] | 				drive: perDay[3], | ||||||
|  | 				network: perDay[4] | ||||||
| 			} | 			} | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| @@ -156,6 +166,23 @@ export default Vue.extend({ | |||||||
| 			return arr.map((v, i) => ({ t: this.getDate(i).getTime(), y: v })); | 			return arr.map((v, i) => ({ t: this.getDate(i).getTime(), y: v })); | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|  | 		federationInstancesChart(total: boolean): any { | ||||||
|  | 			return [{ | ||||||
|  | 				datasets: [{ | ||||||
|  | 					label: 'Instances', | ||||||
|  | 					fill: true, | ||||||
|  | 					backgroundColor: rgba(colors.localPlus), | ||||||
|  | 					borderColor: colors.localPlus, | ||||||
|  | 					borderWidth: 2, | ||||||
|  | 					pointBackgroundColor: '#fff', | ||||||
|  | 					lineTension: 0, | ||||||
|  | 					data: this.format(total | ||||||
|  | 						? this.stats.federation.instance.total | ||||||
|  | 						: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec))) | ||||||
|  | 				}] | ||||||
|  | 			}]; | ||||||
|  | 		}, | ||||||
|  |  | ||||||
| 		notesChart(type: string): any { | 		notesChart(type: string): any { | ||||||
| 			return [{ | 			return [{ | ||||||
| 				datasets: [{ | 				datasets: [{ | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| <mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout"> | <mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout"> | ||||||
| 	<template slot="header"> | 	<template slot="header"> | ||||||
| 		<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:@used%</p> | 		<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:@used%</p> | ||||||
| 		<span :class="$style.title">%fa:cloud%%i18n:@drive%</span> | 		<span :class="$style.title">%fa:cloud%%i18n:common.drive%</span> | ||||||
| 	</template> | 	</template> | ||||||
| 	<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/> | 	<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/> | ||||||
| </mk-window> | </mk-window> | ||||||
|   | |||||||
| @@ -67,12 +67,12 @@ export default Vue.extend({ | |||||||
| 				text: '%i18n:@contextmenu.rename%', | 				text: '%i18n:@contextmenu.rename%', | ||||||
| 				icon: '%fa:i-cursor%', | 				icon: '%fa:i-cursor%', | ||||||
| 				action: this.rename | 				action: this.rename | ||||||
| 			}/*, null, { | 			}, null, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:common.delete%', | 				text: '%i18n:common.delete%', | ||||||
| 				icon: '%fa:R trash-alt%', | 				icon: '%fa:R trash-alt%', | ||||||
| 				action: this.deleteFolder | 				action: this.deleteFolder | ||||||
| 			}*/], { | 			}], { | ||||||
| 					closed: () => { | 					closed: () => { | ||||||
| 						this.isContextmenuShowing = false; | 						this.isContextmenuShowing = false; | ||||||
| 					} | 					} | ||||||
| @@ -207,7 +207,9 @@ export default Vue.extend({ | |||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
| 		deleteFolder() { | 		deleteFolder() { | ||||||
| 			alert('not implemented yet'); | 			(this as any).api('drive/folders/delete', { | ||||||
|  | 				folderId: this.folder.id | ||||||
|  | 			}); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ | |||||||
| 	@drop.stop="onDrop" | 	@drop.stop="onDrop" | ||||||
| > | > | ||||||
| 	<template v-if="folder == null">%fa:cloud%</template> | 	<template v-if="folder == null">%fa:cloud%</template> | ||||||
| 	<span>{{ folder == null ? '%i18n:@drive%' : folder.name }}</span> | 	<span>{{ folder == null ? '%i18n:common.drive%' : folder.name }}</span> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -98,7 +98,7 @@ export default Vue.extend({ | |||||||
| 			hierarchyFolders: [], | 			hierarchyFolders: [], | ||||||
| 			selectedFiles: [], | 			selectedFiles: [], | ||||||
| 			uploadings: [], | 			uploadings: [], | ||||||
| 			connection: null | 			connection: null, | ||||||
|  |  | ||||||
| 			/** | 			/** | ||||||
| 			 * ドロップされようとしているか | 			 * ドロップされようとしているか | ||||||
| @@ -122,6 +122,7 @@ export default Vue.extend({ | |||||||
| 		this.connection.on('fileDeleted', this.onStreamDriveFileDeleted); | 		this.connection.on('fileDeleted', this.onStreamDriveFileDeleted); | ||||||
| 		this.connection.on('folderCreated', this.onStreamDriveFolderCreated); | 		this.connection.on('folderCreated', this.onStreamDriveFolderCreated); | ||||||
| 		this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated); | 		this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated); | ||||||
|  | 		this.connection.on('folderDeleted', this.onStreamDriveFolderDeleted); | ||||||
|  |  | ||||||
| 		if (this.initFolder) { | 		if (this.initFolder) { | ||||||
| 			this.move(this.initFolder); | 			this.move(this.initFolder); | ||||||
| @@ -182,6 +183,10 @@ export default Vue.extend({ | |||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|  | 		onStreamDriveFolderDeleted(folderId) { | ||||||
|  | 			this.removeFolder(folderId); | ||||||
|  | 		}, | ||||||
|  |  | ||||||
| 		onChangeUploaderUploads(uploads) { | 		onChangeUploaderUploads(uploads) { | ||||||
| 			this.uploadings = uploads; | 			this.uploadings = uploads; | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -40,8 +40,8 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| 	mounted() { | 	mounted() { | ||||||
| 		this.connection = (this as any).os.stream.useSharedConnection('main'); | 		this.connection = (this as any).os.stream.useSharedConnection('main'); | ||||||
| 		this.connection.on('follow', this.onFollow); | 		this.connection.on('follow', this.onFollowChange); | ||||||
| 		this.connection.on('unfollow', this.onUnfollow); | 		this.connection.on('unfollow', this.onFollowChange); | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	beforeDestroy() { | 	beforeDestroy() { | ||||||
| @@ -49,17 +49,11 @@ export default Vue.extend({ | |||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	methods: { | 	methods: { | ||||||
| 		onFollow(user) { | 		onFollowChange(user) { | ||||||
| 			if (user.id == this.u.id) { |  | ||||||
| 				this.u.isFollowing = user.isFollowing; |  | ||||||
| 				this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou; |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		onUnfollow(user) { |  | ||||||
| 			if (user.id == this.u.id) { | 			if (user.id == this.u.id) { | ||||||
| 				this.u.isFollowing = user.isFollowing; | 				this.u.isFollowing = user.isFollowing; | ||||||
| 				this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou; | 				this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou; | ||||||
|  | 				this.$forceUpdate(); | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,10 +4,7 @@ | |||||||
|  |  | ||||||
| 	<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot> | 	<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot> | ||||||
|  |  | ||||||
| 	<div v-if="!fetching && requestInitPromise != null" class="error"> | 	<mk-error v-if="!fetching && requestInitPromise != null" @retry="resolveInitPromise"/> | ||||||
| 		<p>%fa:exclamation-triangle% %i18n:common.error.title%</p> |  | ||||||
| 		<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button> |  | ||||||
| 	</div> |  | ||||||
|  |  | ||||||
| 	<div class="placeholder" v-if="fetching"> | 	<div class="placeholder" v-if="fetching"> | ||||||
| 		<template v-for="i in 10"> | 		<template v-for="i in 10"> | ||||||
| @@ -215,16 +212,6 @@ export default Vue.extend({ | |||||||
| 		> * | 		> * | ||||||
| 			transition transform .3s ease, opacity .3s ease | 			transition transform .3s ease, opacity .3s ease | ||||||
|  |  | ||||||
| 	> .error |  | ||||||
| 		max-width 300px |  | ||||||
| 		margin 0 auto |  | ||||||
| 		padding 32px |  | ||||||
| 		text-align center |  | ||||||
| 		color var(--text) |  | ||||||
|  |  | ||||||
| 		> p |  | ||||||
| 			margin 0 0 8px 0 |  | ||||||
|  |  | ||||||
| 	> .placeholder | 	> .placeholder | ||||||
| 		padding 32px | 		padding 32px | ||||||
| 		opacity 0.3 | 		opacity 0.3 | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ | |||||||
| 		<span v-if="visibility === 'specified'">%fa:envelope%</span> | 		<span v-if="visibility === 'specified'">%fa:envelope%</span> | ||||||
| 		<span v-if="visibility === 'private'">%fa:lock%</span> | 		<span v-if="visibility === 'private'">%fa:lock%</span> | ||||||
| 	</button> | 	</button> | ||||||
| 	<p class="text-count" :class="{ over: this.trimmedLength(text) > 1000 }">{{ 1000 - this.trimmedLength(text) }}</p> | 	<p class="text-count" :class="{ over: this.trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - this.trimmedLength(text) }}</p> | ||||||
| 	<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post"> | 	<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post"> | ||||||
| 		{{ posting ? '%i18n:@posting%' : submitText }}<mk-ellipsis v-if="posting"/> | 		{{ posting ? '%i18n:@posting%' : submitText }}<mk-ellipsis v-if="posting"/> | ||||||
| 	</button> | 	</button> | ||||||
| @@ -107,10 +107,17 @@ export default Vue.extend({ | |||||||
| 			visibleUsers: [], | 			visibleUsers: [], | ||||||
| 			autocomplete: null, | 			autocomplete: null, | ||||||
| 			draghover: false, | 			draghover: false, | ||||||
| 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]') | 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'), | ||||||
|  | 			maxNoteTextLength: 1000 | ||||||
| 		}; | 		}; | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
|  | 	created() { | ||||||
|  | 		(this as any).os.getMeta().then(meta => { | ||||||
|  | 			this.maxNoteTextLength = meta.maxNoteTextLength; | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  |  | ||||||
| 	computed: { | 	computed: { | ||||||
| 		draftId(): string { | 		draftId(): string { | ||||||
| 			return this.renote | 			return this.renote | ||||||
| @@ -149,7 +156,7 @@ export default Vue.extend({ | |||||||
| 		canPost(): boolean { | 		canPost(): boolean { | ||||||
| 			return !this.posting && | 			return !this.posting && | ||||||
| 				(1 <= this.text.length || 1 <= this.files.length || this.poll || this.renote) && | 				(1 <= this.text.length || 1 <= this.files.length || this.poll || this.renote) && | ||||||
| 				(length(this.text.trim()) <= 1000); | 				(length(this.text.trim()) <= this.maxNoteTextLength); | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
| <div class="2fa"> | <div class="2fa"> | ||||||
| 	<p>%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p> | 	<p style="margin-top:0;">%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p> | ||||||
| 	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div> | 	<ui-info warn>%i18n:@caution%</ui-info> | ||||||
| 	<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">%i18n:@register%</ui-button></p> | 	<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">%i18n:@register%</ui-button></p> | ||||||
| 	<template v-if="$store.state.i.twoFactorEnabled"> | 	<template v-if="$store.state.i.twoFactorEnabled"> | ||||||
| 		<p>%i18n:@already-registered%</p> | 		<p>%i18n:@already-registered%</p> | ||||||
| @@ -72,9 +72,3 @@ export default Vue.extend({ | |||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .2fa |  | ||||||
| 	color #4a535a |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
|   | |||||||
| @@ -1,40 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="root api"> |  | ||||||
| 	<ui-input :value="$store.state.i.token" readonly> |  | ||||||
| 		<span>%i18n:@token%</span> |  | ||||||
| 	</ui-input> |  | ||||||
| 	<p>%i18n:@intro%</p> |  | ||||||
| 	<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div> |  | ||||||
| 	<p>%i18n:@regeneration-of-token%</p> |  | ||||||
| 	<ui-button @click="regenerateToken">%i18n:@regenerate-token%</ui-button> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	methods: { |  | ||||||
| 		regenerateToken() { |  | ||||||
| 			(this as any).apis.input({ |  | ||||||
| 				title: '%i18n:@enter-password%', |  | ||||||
| 				type: 'password' |  | ||||||
| 			}).then(password => { |  | ||||||
| 				(this as any).api('i/regenerate_token', { |  | ||||||
| 					password: password |  | ||||||
| 				}); |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .root.api |  | ||||||
| 	code |  | ||||||
| 		display inline-block |  | ||||||
| 		padding 4px 6px |  | ||||||
| 		color #555 |  | ||||||
| 		background #eee |  | ||||||
| 		border-radius 2px |  | ||||||
| </style> |  | ||||||
| @@ -1,8 +1,6 @@ | |||||||
| <template> | <template> | ||||||
| <div class="root"> | <div class="root"> | ||||||
| 	<div class="none ui info" v-if="!fetching && apps.length == 0"> | 	<ui-info v-if="!fetching && apps.length == 0">%i18n:@no-apps%</ui-info> | ||||||
| 		<p>%fa:info-circle%%i18n:@no-apps%</p> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="apps" v-if="apps.length != 0"> | 	<div class="apps" v-if="apps.length != 0"> | ||||||
| 		<div v-for="app in apps"> | 		<div v-for="app in apps"> | ||||||
| 			<p><b>{{ app.name }}</b></p> | 			<p><b>{{ app.name }}</b></p> | ||||||
|   | |||||||
| @@ -1,34 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="root"> |  | ||||||
| 	<template v-if="!fetching"> |  | ||||||
| 		<p><b>{{ capacity | bytes }}</b>%i18n:@max%<b>{{ usage | bytes }}</b>%i18n:@in-use%</p> |  | ||||||
| 	</template> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	data() { |  | ||||||
| 		return { |  | ||||||
| 			fetching: true, |  | ||||||
| 			usage: null, |  | ||||||
| 			capacity: null |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
| 	mounted() { |  | ||||||
| 		(this as any).api('drive').then(info => { |  | ||||||
| 			this.capacity = info.capacity; |  | ||||||
| 			this.usage = info.usage; |  | ||||||
| 			this.fetching = false; |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .root |  | ||||||
| 	> p |  | ||||||
| 		> b |  | ||||||
| 			margin 0 8px |  | ||||||
| </style> |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div> |  | ||||||
| 	<div class="none ui info" v-if="!fetching && users.length == 0"> |  | ||||||
| 		<p>%fa:info-circle%%i18n:@no-users%</p> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="users" v-if="users.length != 0"> |  | ||||||
| 		<div v-for="user in users" :key="user.id"> |  | ||||||
| 			<p><b>{{ user | userName }}</b> @{{ user | acct }}</p> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	data() { |  | ||||||
| 		return { |  | ||||||
| 			fetching: true, |  | ||||||
| 			users: [] |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
| 	mounted() { |  | ||||||
| 		(this as any).api('mute/list').then(x => { |  | ||||||
| 			this.users = x.users; |  | ||||||
| 			this.fetching = false; |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
| @@ -5,9 +5,9 @@ | |||||||
| 		<p :class="{ active: page == 'theme' }" @mousedown="page = 'theme'">%fa:palette .fw%%i18n:@theme%</p> | 		<p :class="{ active: page == 'theme' }" @mousedown="page = 'theme'">%fa:palette .fw%%i18n:@theme%</p> | ||||||
| 		<p :class="{ active: page == 'web' }" @mousedown="page = 'web'">%fa:desktop .fw%Web</p> | 		<p :class="{ active: page == 'web' }" @mousedown="page = 'web'">%fa:desktop .fw%Web</p> | ||||||
| 		<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%%i18n:@notification%</p> | 		<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%%i18n:@notification%</p> | ||||||
| 		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:@drive%</p> | 		<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:common.drive%</p> | ||||||
| 		<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'">%fa:hashtag .fw%%i18n:@tags%</p> | 		<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'">%fa:hashtag .fw%%i18n:@tags%</p> | ||||||
| 		<p :class="{ active: page == 'mute' }" @mousedown="page = 'mute'">%fa:ban .fw%%i18n:@mute%</p> | 		<p :class="{ active: page == 'muteAndBlock' }" @mousedown="page = 'muteAndBlock'">%fa:ban .fw%%i18n:@mute-and-block%</p> | ||||||
| 		<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%%i18n:@apps%</p> | 		<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%%i18n:@apps%</p> | ||||||
| 		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p> | 		<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p> | ||||||
| 		<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p> | 		<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p> | ||||||
| @@ -189,12 +189,9 @@ | |||||||
| 			</section> | 			</section> | ||||||
| 		</ui-card> | 		</ui-card> | ||||||
|  |  | ||||||
| 		<ui-card class="drive" v-show="page == 'drive'"> | 		<div class="drive" v-if="page == 'drive'"> | ||||||
| 			<div slot="title">%fa:cloud% %i18n:@drive%</div> | 			<mk-drive-settings/> | ||||||
| 			<section> | 		</div> | ||||||
| 				<x-drive/> |  | ||||||
| 			</section> |  | ||||||
| 		</ui-card> |  | ||||||
|  |  | ||||||
| 		<ui-card class="hashtags" v-show="page == 'hashtags'"> | 		<ui-card class="hashtags" v-show="page == 'hashtags'"> | ||||||
| 			<div slot="title">%fa:hashtag% %i18n:@tags%</div> | 			<div slot="title">%fa:hashtag% %i18n:@tags%</div> | ||||||
| @@ -203,12 +200,9 @@ | |||||||
| 			</section> | 			</section> | ||||||
| 		</ui-card> | 		</ui-card> | ||||||
|  |  | ||||||
| 		<ui-card class="mute" v-show="page == 'mute'"> | 		<div class="muteAndBlock" v-show="page == 'muteAndBlock'"> | ||||||
| 			<div slot="title">%fa:ban% %i18n:@mute%</div> | 			<mk-mute-and-block/> | ||||||
| 			<section> | 		</div> | ||||||
| 				<x-mute/> |  | ||||||
| 			</section> |  | ||||||
| 		</ui-card> |  | ||||||
|  |  | ||||||
| 		<ui-card class="apps" v-show="page == 'apps'"> | 		<ui-card class="apps" v-show="page == 'apps'"> | ||||||
| 			<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div> | 			<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div> | ||||||
| @@ -238,12 +232,9 @@ | |||||||
| 			</section> | 			</section> | ||||||
| 		</ui-card> | 		</ui-card> | ||||||
|  |  | ||||||
| 		<ui-card class="api" v-show="page == 'api'"> | 		<div class="api" v-show="page == 'api'"> | ||||||
| 			<div slot="title">%fa:key% API</div> | 			<mk-api-settings/> | ||||||
| 			<section class="fit-top"> | 		</div> | ||||||
| 				<x-api/> |  | ||||||
| 			</section> |  | ||||||
| 		</ui-card> |  | ||||||
|  |  | ||||||
| 		<ui-card class="other" v-show="page == 'other'"> | 		<ui-card class="other" v-show="page == 'other'"> | ||||||
| 			<div slot="title">%fa:info-circle% %i18n:@about%</div> | 			<div slot="title">%fa:info-circle% %i18n:@about%</div> | ||||||
| @@ -295,26 +286,20 @@ | |||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import XMute from './settings.mute.vue'; |  | ||||||
| import XPassword from './settings.password.vue'; | import XPassword from './settings.password.vue'; | ||||||
| import X2fa from './settings.2fa.vue'; | import X2fa from './settings.2fa.vue'; | ||||||
| import XApi from './settings.api.vue'; |  | ||||||
| import XApps from './settings.apps.vue'; | import XApps from './settings.apps.vue'; | ||||||
| import XSignins from './settings.signins.vue'; | import XSignins from './settings.signins.vue'; | ||||||
| import XDrive from './settings.drive.vue'; |  | ||||||
| import XTags from './settings.tags.vue'; | import XTags from './settings.tags.vue'; | ||||||
| import { url, langs, version } from '../../../config'; | import { url, langs, version } from '../../../config'; | ||||||
| import checkForUpdate from '../../../common/scripts/check-for-update'; | import checkForUpdate from '../../../common/scripts/check-for-update'; | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| 	components: { | 	components: { | ||||||
| 		XMute, |  | ||||||
| 		XPassword, | 		XPassword, | ||||||
| 		X2fa, | 		X2fa, | ||||||
| 		XApi, |  | ||||||
| 		XApps, | 		XApps, | ||||||
| 		XSignins, | 		XSignins, | ||||||
| 		XDrive, |  | ||||||
| 		XTags | 		XTags | ||||||
| 	}, | 	}, | ||||||
| 	props: { | 	props: { | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ | |||||||
| 					<router-link :to="`/@${ $store.state.i.username }`">%fa:user%<span>%i18n:@profile%</span>%fa:angle-right%</router-link> | 					<router-link :to="`/@${ $store.state.i.username }`">%fa:user%<span>%i18n:@profile%</span>%fa:angle-right%</router-link> | ||||||
| 				</li> | 				</li> | ||||||
| 				<li @click="drive"> | 				<li @click="drive"> | ||||||
| 					<p>%fa:cloud%<span>%i18n:@drive%</span>%fa:angle-right%</p> | 					<p>%fa:cloud%<span>%i18n:common.drive%</span>%fa:angle-right%</p> | ||||||
| 				</li> | 				</li> | ||||||
| 				<li> | 				<li> | ||||||
| 					<router-link to="/i/favorites">%fa:star%<span>%i18n:@favorites%</span>%fa:angle-right%</router-link> | 					<router-link to="/i/favorites">%fa:star%<span>%i18n:@favorites%</span>%fa:angle-right%</router-link> | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
| 			<li v-if="this.$store.state.i && this.$store.state.i.isAdmin" | 			<li v-if="this.$store.state.i && this.$store.state.i.isAdmin" | ||||||
| 				@click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li> | 				@click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li> | ||||||
|  |  | ||||||
| 			<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:@drive%</li> --> | 			<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:common.drive%</li> --> | ||||||
| 			<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> --> | 			<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> --> | ||||||
| 		</ul> | 		</ul> | ||||||
| 	</nav> | 	</nav> | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
| <div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready }" | <div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready }" | ||||||
| 		@dragover.prevent.stop="onDragover" | 		@dragenter.prevent.stop="onDragenter" | ||||||
| 		@dragleave="onDragleave" | 		@dragleave="onDragleave" | ||||||
| 		@drop.prevent.stop="onDrop" | 		@drop.prevent.stop="onDrop" | ||||||
| 		v-hotkey="keymap"> | 		v-hotkey="keymap"> | ||||||
| @@ -269,7 +269,7 @@ export default Vue.extend({ | |||||||
| 			this.dragging = false; | 			this.dragging = false; | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
| 		onDragover(e) { | 		onDragenter(e) { | ||||||
| 			// テンポラリカラムにはドロップさせない | 			// テンポラリカラムにはドロップさせない | ||||||
| 			if (this.isTemporaryColumn) { | 			if (this.isTemporaryColumn) { | ||||||
| 				e.dataTransfer.dropEffect = 'none'; | 				e.dataTransfer.dropEffect = 'none'; | ||||||
| @@ -287,7 +287,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| 			e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none'; | 			e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none'; | ||||||
|  |  | ||||||
| 			if (!this.dragging) this.draghover = true; | 			if (!this.dragging && isDeckColumn) this.draghover = true; | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
| 		onDragleave() { | 		onDragleave() { | ||||||
|   | |||||||
| @@ -8,10 +8,7 @@ | |||||||
| 		</template> | 		</template> | ||||||
| 	</div> | 	</div> | ||||||
|  |  | ||||||
| 	<div v-if="!fetching && requestInitPromise != null" class="error"> | 	<mk-error v-if="!fetching && requestInitPromise != null" @retry="resolveInitPromise"/> | ||||||
| 		<p>%fa:exclamation-triangle% %i18n:common.error.title%</p> |  | ||||||
| 		<ui-button @click="resolveInitPromise">%i18n:common.error.retry%</ui-button> |  | ||||||
| 	</div> |  | ||||||
|  |  | ||||||
| 	<!-- トランジションを有効にするとなぜかメモリリークする --> | 	<!-- トランジションを有効にするとなぜかメモリリークする --> | ||||||
| 	<!--<transition-group name="mk-notes" class="transition" ref="notes">--> | 	<!--<transition-group name="mk-notes" class="transition" ref="notes">--> | ||||||
| @@ -159,8 +156,8 @@ export default Vue.extend({ | |||||||
| 			} | 			} | ||||||
| 			//#endregion | 			//#endregion | ||||||
|  |  | ||||||
| 			// タブが非表示またはスクロール位置が最上部ではないならタイトルで通知 | 			// タブが非表示ならタイトルで通知 | ||||||
| 			if (document.hidden || !this.isScrollTop()) { | 			if (document.hidden) { | ||||||
| 				this.$store.commit('pushBehindNote', note); | 				this.$store.commit('pushBehindNote', note); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @@ -221,13 +218,6 @@ export default Vue.extend({ | |||||||
| 		> * | 		> * | ||||||
| 			transition transform .3s ease, opacity .3s ease | 			transition transform .3s ease, opacity .3s ease | ||||||
|  |  | ||||||
| 	> .error |  | ||||||
| 		max-width 300px |  | ||||||
| 		margin 0 auto |  | ||||||
| 		padding 16px |  | ||||||
| 		text-align center |  | ||||||
| 		color var(--text) |  | ||||||
|  |  | ||||||
| 	> .placeholder | 	> .placeholder | ||||||
| 		padding 16px | 		padding 16px | ||||||
| 		opacity 0.3 | 		opacity 0.3 | ||||||
|   | |||||||
| @@ -178,9 +178,9 @@ export default Vue.extend({ | |||||||
| 		> .date | 		> .date | ||||||
| 			display block | 			display block | ||||||
| 			margin 0 | 			margin 0 | ||||||
| 			line-height 32px | 			line-height 28px | ||||||
| 			text-align center | 			text-align center | ||||||
| 			font-size 0.8em | 			font-size 12px | ||||||
| 			color var(--dateDividerFg) | 			color var(--dateDividerFg) | ||||||
| 			background var(--dateDividerBg) | 			background var(--dateDividerBg) | ||||||
| 			border-bottom solid 1px var(--faceDivider) | 			border-bottom solid 1px var(--faceDivider) | ||||||
|   | |||||||
| @@ -24,14 +24,34 @@ | |||||||
| 			<div class="description"> | 			<div class="description"> | ||||||
| 				<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/> | 				<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/> | ||||||
| 			</div> | 			</div> | ||||||
|  | 			<div class="counts"> | ||||||
|  | 				<div> | ||||||
|  | 					<b>{{ user.notesCount | number }}</b> | ||||||
|  | 					<span>%i18n:@posts%</span> | ||||||
|  | 				</div> | ||||||
|  | 				<div> | ||||||
|  | 					<b>{{ user.followingCount | number }}</b> | ||||||
|  | 					<span>%i18n:@following%</span> | ||||||
|  | 				</div> | ||||||
|  | 				<div> | ||||||
|  | 					<b>{{ user.followersCount | number }}</b> | ||||||
|  | 					<span>%i18n:@followers%</span> | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 		<div class="pinned" v-if="user.pinnedNotes && user.pinnedNotes.length > 0"> | 		<div class="pinned" v-if="user.pinnedNotes && user.pinnedNotes.length > 0"> | ||||||
| 			<p>%fa:thumbtack% %i18n:@pinned-notes%</p> | 			<p class="caption" @click="toggleShowPinned">%fa:thumbtack% %i18n:@pinned-notes%</p> | ||||||
| 			<div class="notes"> | 			<span class="angle" v-if="showPinned">%fa:angle-up%</span> | ||||||
|  | 			<span class="angle" v-else>%fa:angle-down%</span> | ||||||
|  | 			<div class="notes" v-show="showPinned"> | ||||||
| 				<x-note v-for="n in user.pinnedNotes" :key="n.id" :note="n" :mini="true"/> | 				<x-note v-for="n in user.pinnedNotes" :key="n.id" :note="n" :mini="true"/> | ||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 		<div class="images" v-if="images.length > 0"> | 		<div class="images" v-if="images.length > 0"> | ||||||
|  | 			<p class="caption" @click="toggleShowImages">%fa:images R% %i18n:@images%</p> | ||||||
|  | 			<span class="angle" v-if="showImages">%fa:angle-up%</span> | ||||||
|  | 			<span class="angle" v-else>%fa:angle-down%</span> | ||||||
|  | 			<div v-show="showImages"> | ||||||
| 				<router-link v-for="image in images" | 				<router-link v-for="image in images" | ||||||
| 					:style="`background-image: url(${image.thumbnailUrl})`" | 					:style="`background-image: url(${image.thumbnailUrl})`" | ||||||
| 					:key="`${image.id}:${image._note.id}`" | 					:key="`${image.id}:${image._note.id}`" | ||||||
| @@ -39,13 +59,22 @@ | |||||||
| 					:title="`${image.name}\n${(new Date(image.createdAt)).toLocaleString()}`" | 					:title="`${image.name}\n${(new Date(image.createdAt)).toLocaleString()}`" | ||||||
| 				></router-link> | 				></router-link> | ||||||
| 			</div> | 			</div> | ||||||
|  | 		</div> | ||||||
| 		<div class="activity"> | 		<div class="activity"> | ||||||
|  | 			<p class="caption" @click="toggleShowActivity">%fa:chart-bar R% %i18n:@activity%</p> | ||||||
|  | 			<span class="angle" v-if="showActivity">%fa:angle-up%</span> | ||||||
|  | 			<span class="angle" v-else>%fa:angle-down%</span> | ||||||
|  | 			<div v-show="showActivity"> | ||||||
| 				<div ref="chart"></div> | 				<div ref="chart"></div> | ||||||
| 			</div> | 			</div> | ||||||
|  | 		</div> | ||||||
| 		<div class="tl"> | 		<div class="tl"> | ||||||
|  | 			<p class="caption">%fa:comment-alt R% %i18n:@timeline%</p> | ||||||
|  | 			<div> | ||||||
| 				<x-notes ref="timeline" :more="existMore ? fetchMoreNotes : null"/> | 				<x-notes ref="timeline" :more="existMore ? fetchMoreNotes : null"/> | ||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
|  | 	</div> | ||||||
| </x-column> | </x-column> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| @@ -84,7 +113,10 @@ export default Vue.extend({ | |||||||
| 			existMore: false, | 			existMore: false, | ||||||
| 			moreFetching: false, | 			moreFetching: false, | ||||||
| 			withFiles: false, | 			withFiles: false, | ||||||
| 			images: [] | 			images: [], | ||||||
|  | 			showPinned: true, | ||||||
|  | 			showImages: true, | ||||||
|  | 			showActivity: true | ||||||
| 		}; | 		}; | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| @@ -282,6 +314,18 @@ export default Vue.extend({ | |||||||
| 				compact: false, | 				compact: false, | ||||||
| 				items: menu | 				items: menu | ||||||
| 			}); | 			}); | ||||||
|  | 		}, | ||||||
|  |  | ||||||
|  | 		toggleShowPinned() { | ||||||
|  | 			this.showPinned = !this.showPinned; | ||||||
|  | 		}, | ||||||
|  |  | ||||||
|  | 		toggleShowImages() { | ||||||
|  | 			this.showImages = !this.showImages; | ||||||
|  | 		}, | ||||||
|  |  | ||||||
|  | 		toggleShowActivity() { | ||||||
|  | 			this.showActivity = !this.showActivity; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| @@ -349,7 +393,6 @@ export default Vue.extend({ | |||||||
| 		color var(--text) | 		color var(--text) | ||||||
| 		text-align center | 		text-align center | ||||||
| 		background var(--face) | 		background var(--face) | ||||||
| 		border-bottom solid 1px var(--faceDivider) |  | ||||||
|  |  | ||||||
| 		&:before | 		&:before | ||||||
| 			content "" | 			content "" | ||||||
| @@ -365,25 +408,50 @@ export default Vue.extend({ | |||||||
| 			border-right solid 16px transparent | 			border-right solid 16px transparent | ||||||
| 			border-bottom solid 16px var(--face) | 			border-bottom solid 16px var(--face) | ||||||
|  |  | ||||||
| 	> .pinned | 		> .counts | ||||||
| 		padding-bottom 16px | 			display grid | ||||||
| 		background var(--deckColumnBg) | 			grid-template-columns 1fr 1fr 1fr | ||||||
|  | 			margin-top 8px | ||||||
|  | 			border-top solid 1px var(--faceDivider) | ||||||
|  |  | ||||||
| 		> p | 			> div | ||||||
|  | 				padding 8px 8px 0 8px | ||||||
|  | 				text-align center | ||||||
|  |  | ||||||
|  | 				> b | ||||||
|  | 					display block | ||||||
|  | 					font-size 110% | ||||||
|  |  | ||||||
|  | 				> span | ||||||
|  | 					display block | ||||||
|  | 					font-size 80% | ||||||
|  | 					opacity 0.7 | ||||||
|  |  | ||||||
|  | 	> * | ||||||
|  | 		> p.caption | ||||||
| 			margin 0 | 			margin 0 | ||||||
| 			padding 8px 16px | 			padding 8px 16px | ||||||
| 			font-size 12px | 			font-size 12px | ||||||
| 			color var(--text) | 			color var(--text) | ||||||
|  |  | ||||||
|  | 			& + .angle | ||||||
|  | 				position absolute | ||||||
|  | 				top 0 | ||||||
|  | 				right 8px | ||||||
|  | 				padding 6px | ||||||
|  | 				font-size 14px | ||||||
|  | 				color var(--text) | ||||||
|  |  | ||||||
|  | 	> .pinned | ||||||
| 		> .notes | 		> .notes | ||||||
| 			background var(--face) | 			background var(--face) | ||||||
|  |  | ||||||
| 	> .images | 	> .images | ||||||
|  | 		> div | ||||||
| 			display grid | 			display grid | ||||||
| 			grid-template-columns 1fr 1fr 1fr | 			grid-template-columns 1fr 1fr 1fr | ||||||
| 			gap 8px | 			gap 8px | ||||||
| 			padding 16px | 			padding 16px | ||||||
| 		margin-bottom 16px |  | ||||||
| 			background var(--face) | 			background var(--face) | ||||||
|  |  | ||||||
| 			> * | 			> * | ||||||
| @@ -394,10 +462,11 @@ export default Vue.extend({ | |||||||
| 				border-radius 4px | 				border-radius 4px | ||||||
|  |  | ||||||
| 	> .activity | 	> .activity | ||||||
| 		margin-bottom 16px | 		> div | ||||||
| 			background var(--face) | 			background var(--face) | ||||||
|  |  | ||||||
| 	> .tl | 	> .tl | ||||||
|  | 		> div | ||||||
| 			background var(--face) | 			background var(--face) | ||||||
|  |  | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -11,7 +11,11 @@ | |||||||
| 	<div class="action-form"> | 	<div class="action-form"> | ||||||
| 		<ui-button @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id"> | 		<ui-button @click="user.isMuted ? unmute() : mute()" v-if="$store.state.i.id != user.id"> | ||||||
| 			<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span> | 			<span v-if="user.isMuted">%fa:eye% %i18n:@unmute%</span> | ||||||
| 			<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span> | 			<span v-else>%fa:eye-slash% %i18n:@mute%</span> | ||||||
|  | 		</ui-button> | ||||||
|  | 		<ui-button @click="user.isBlocking ? unblock() : block()" v-if="$store.state.i.id != user.id"> | ||||||
|  | 			<span v-if="user.isBlocking">%fa:user% %i18n:@unblock%</span> | ||||||
|  | 			<span v-else>%fa:user-slash% %i18n:@block%</span> | ||||||
| 		</ui-button> | 		</ui-button> | ||||||
| 		<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button> | 		<ui-button @click="list">%fa:list% %i18n:@push-to-a-list%</ui-button> | ||||||
| 	</div> | 	</div> | ||||||
| @@ -66,6 +70,27 @@ export default Vue.extend({ | |||||||
| 			}); | 			}); | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
|  | 		block() { | ||||||
|  | 			if (!window.confirm('%i18n:@block-confirm%')) return; | ||||||
|  | 			(this as any).api('blocking/create', { | ||||||
|  | 				userId: this.user.id | ||||||
|  | 			}).then(() => { | ||||||
|  | 				this.user.isBlocking = true; | ||||||
|  | 			}, () => { | ||||||
|  | 				alert('error'); | ||||||
|  | 			}); | ||||||
|  | 		}, | ||||||
|  |  | ||||||
|  | 		unblock() { | ||||||
|  | 			(this as any).api('blocking/delete', { | ||||||
|  | 				userId: this.user.id | ||||||
|  | 			}).then(() => { | ||||||
|  | 				this.user.isBlocking = false; | ||||||
|  | 			}, () => { | ||||||
|  | 				alert('error'); | ||||||
|  | 			}); | ||||||
|  | 		}, | ||||||
|  |  | ||||||
| 		list() { | 		list() { | ||||||
| 			const w = (this as any).os.new(MkUserListsWindow); | 			const w = (this as any).os.new(MkUserListsWindow); | ||||||
| 			w.$once('choosen', async list => { | 			w.$once('choosen', async list => { | ||||||
| @@ -114,7 +139,6 @@ export default Vue.extend({ | |||||||
| 	> .action-form | 	> .action-form | ||||||
| 		padding 16px | 		padding 16px | ||||||
| 		text-align center | 		text-align center | ||||||
| 		border-bottom solid 1px var(--faceDivider) |  | ||||||
|  |  | ||||||
| 		> * | 		> * | ||||||
| 			width 100% | 			width 100% | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ | |||||||
| 			:src="file.url" | 			:src="file.url" | ||||||
| 			:alt="file.name" | 			:alt="file.name" | ||||||
| 			:title="file.name" | 			:title="file.name" | ||||||
| 			@load="onImageLoaded" |  | ||||||
| 			:style="style"> | 			:style="style"> | ||||||
| 		<template v-if="kind != 'image'">%fa:file%</template> | 		<template v-if="kind != 'image'">%fa:file%</template> | ||||||
| 		<footer v-if="kind == 'image' && file.properties && file.properties.width && file.properties.height"> | 		<footer v-if="kind == 'image' && file.properties && file.properties.width && file.properties.height"> | ||||||
| @@ -46,14 +45,6 @@ | |||||||
| 			<ui-button @click="del">%fa:trash-alt R% %i18n:@delete%</ui-button> | 			<ui-button @click="del">%fa:trash-alt R% %i18n:@delete%</ui-button> | ||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
| 	<div class="exif" v-show="exif"> |  | ||||||
| 		<div> |  | ||||||
| 			<p> |  | ||||||
| 				%fa:camera%%i18n:@exif% |  | ||||||
| 			</p> |  | ||||||
| 			<pre ref="exif" class="json">{{ exif ? JSON.stringify(exif, null, 2) : '' }}</pre> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="hash"> | 	<div class="hash"> | ||||||
| 		<div> | 		<div> | ||||||
| 			<p> | 			<p> | ||||||
| @@ -67,8 +58,6 @@ | |||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import * as EXIF from 'exif-js'; |  | ||||||
| import * as hljs from 'highlight.js'; |  | ||||||
| import { gcd } from '../../../../../prelude/math'; | import { gcd } from '../../../../../prelude/math'; | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| @@ -139,15 +128,6 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| 		showCreatedAt() { | 		showCreatedAt() { | ||||||
| 			alert(new Date(this.file.createdAt).toLocaleString()); | 			alert(new Date(this.file.createdAt).toLocaleString()); | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		onImageLoaded() { |  | ||||||
| 			const self = this; |  | ||||||
| 			EXIF.getData(this.$refs.img, function(this: any) { |  | ||||||
| 				const allMetaData = EXIF.getAllTags(this); |  | ||||||
| 				self.exif = allMetaData; |  | ||||||
| 				hljs.highlightBlock(self.$refs.exif); |  | ||||||
| 			}); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| @@ -256,34 +236,4 @@ export default Vue.extend({ | |||||||
| 				border-radius 2px | 				border-radius 2px | ||||||
| 				background #f5f5f5 | 				background #f5f5f5 | ||||||
|  |  | ||||||
| 	> .exif |  | ||||||
| 		padding 14px |  | ||||||
| 		border-top solid 1px var(--faceDivider) |  | ||||||
|  |  | ||||||
| 		> div |  | ||||||
| 			max-width 500px |  | ||||||
| 			margin 0 auto |  | ||||||
|  |  | ||||||
| 			> p |  | ||||||
| 				display block |  | ||||||
| 				margin 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				color var(--text) |  | ||||||
| 				font-size 0.9em |  | ||||||
|  |  | ||||||
| 				> [data-fa] |  | ||||||
| 					margin-right 4px |  | ||||||
|  |  | ||||||
| 			> pre |  | ||||||
| 				display block |  | ||||||
| 				width 100% |  | ||||||
| 				margin 6px 0 0 0 |  | ||||||
| 				padding 8px |  | ||||||
| 				height 128px |  | ||||||
| 				overflow auto |  | ||||||
| 				font-size 0.9em |  | ||||||
| 				border solid 1px #dfdfdf |  | ||||||
| 				border-radius 2px |  | ||||||
| 				background #f5f5f5 |  | ||||||
|  |  | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
| <div class="kmmwchoexgckptowjmjgfsygeltxfeqs"> | <div class="kmmwchoexgckptowjmjgfsygeltxfeqs"> | ||||||
| 	<nav ref="nav"> | 	<nav ref="nav"> | ||||||
| 		<a @click.prevent="goRoot()" href="/i/drive">%fa:cloud%%i18n:@drive%</a> | 		<a @click.prevent="goRoot()" href="/i/drive">%fa:cloud%%i18n:common.drive%</a> | ||||||
| 		<template v-for="folder in hierarchyFolders"> | 		<template v-for="folder in hierarchyFolders"> | ||||||
| 			<span :key="folder.id + '>'">%fa:angle-right%</span> | 			<span :key="folder.id + '>'">%fa:angle-right%</span> | ||||||
| 			<a :key="folder.id" @click.prevent="cd(folder)" :href="`/i/drive/folder/${folder.id}`">{{ folder.name }}</a> | 			<a :key="folder.id" @click.prevent="cd(folder)" :href="`/i/drive/folder/${folder.id}`">{{ folder.name }}</a> | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ | |||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| 	props: { | 	props: { | ||||||
| 		user: { | 		user: { | ||||||
| @@ -24,6 +25,7 @@ export default Vue.extend({ | |||||||
| 			required: true | 			required: true | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	data() { | 	data() { | ||||||
| 		return { | 		return { | ||||||
| 			u: this.user, | 			u: this.user, | ||||||
| @@ -31,28 +33,24 @@ export default Vue.extend({ | |||||||
| 			connection: null | 			connection: null | ||||||
| 		}; | 		}; | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	mounted() { | 	mounted() { | ||||||
| 		this.connection = (this as any).os.stream.useSharedConnection('main'); | 		this.connection = (this as any).os.stream.useSharedConnection('main'); | ||||||
|  |  | ||||||
| 		this.connection.on('follow', this.onFollow); | 		this.connection.on('follow', this.onFollowChange); | ||||||
| 		this.connection.on('unfollow', this.onUnfollow); | 		this.connection.on('unfollow', this.onFollowChange); | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	beforeDestroy() { | 	beforeDestroy() { | ||||||
| 		this.connection.dispose(); | 		this.connection.dispose(); | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	methods: { | 	methods: { | ||||||
|  | 		onFollowChange(user) { | ||||||
| 		onFollow(user) { |  | ||||||
| 			if (user.id == this.u.id) { |  | ||||||
| 				this.u.isFollowing = user.isFollowing; |  | ||||||
| 				this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou; |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		onUnfollow(user) { |  | ||||||
| 			if (user.id == this.u.id) { | 			if (user.id == this.u.id) { | ||||||
| 				this.u.isFollowing = user.isFollowing; | 				this.u.isFollowing = user.isFollowing; | ||||||
| 				this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou; | 				this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou; | ||||||
|  | 				this.$forceUpdate(); | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
| @@ -90,8 +88,6 @@ export default Vue.extend({ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> | <style lang="stylus" scoped> | ||||||
|  |  | ||||||
|  |  | ||||||
| .mk-follow-button | .mk-follow-button | ||||||
| 	display block | 	display block | ||||||
| 	user-select none | 	user-select none | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ import noteCard from './note-card.vue'; | |||||||
| import userCard from './user-card.vue'; | import userCard from './user-card.vue'; | ||||||
| import noteDetail from './note-detail.vue'; | import noteDetail from './note-detail.vue'; | ||||||
| import followButton from './follow-button.vue'; | import followButton from './follow-button.vue'; | ||||||
| import muteButton from './mute-button.vue'; |  | ||||||
| import friendsMaker from './friends-maker.vue'; | import friendsMaker from './friends-maker.vue'; | ||||||
| import notification from './notification.vue'; | import notification from './notification.vue'; | ||||||
| import notifications from './notifications.vue'; | import notifications from './notifications.vue'; | ||||||
| @@ -37,7 +36,6 @@ Vue.component('mk-note-card', noteCard); | |||||||
| Vue.component('mk-user-card', userCard); | Vue.component('mk-user-card', userCard); | ||||||
| Vue.component('mk-note-detail', noteDetail); | Vue.component('mk-note-detail', noteDetail); | ||||||
| Vue.component('mk-follow-button', followButton); | Vue.component('mk-follow-button', followButton); | ||||||
| Vue.component('mk-mute-button', muteButton); |  | ||||||
| Vue.component('mk-friends-maker', friendsMaker); | Vue.component('mk-friends-maker', friendsMaker); | ||||||
| Vue.component('mk-notification', notification); | Vue.component('mk-notification', notification); | ||||||
| Vue.component('mk-notifications', notifications); | Vue.component('mk-notifications', notifications); | ||||||
|   | |||||||
| @@ -1,79 +0,0 @@ | |||||||
| <template> |  | ||||||
| <button |  | ||||||
|   class="mk-mute-button" |  | ||||||
|   :class="{ active: user.isMuted }" |  | ||||||
|   @click="onClick"> |  | ||||||
|   <span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span> |  | ||||||
|   <span v-else>%fa:eye% %i18n:@unmute%</span> |  | ||||||
| </button> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue' |  | ||||||
| export default Vue.extend({ |  | ||||||
|   props: { |  | ||||||
|     user: { |  | ||||||
|       type: Object, |  | ||||||
|       required: true |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     onClick() { |  | ||||||
|       if (!this.user.isMuted) { |  | ||||||
|         this.mute(); |  | ||||||
|       } else { |  | ||||||
|         this.unmute(); |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     mute() { |  | ||||||
|       (this as any).api('mute/create', { userId: this.user.id}) |  | ||||||
|         .then(() => { this.user.isMuted = true }) |  | ||||||
|         .catch(() => { alert('error')}) |  | ||||||
|     }, |  | ||||||
|     unmute() { |  | ||||||
|       (this as any).api('mute/delete', { userId: this.user.id }) |  | ||||||
|         .then(() => { this.user.isMuted = false }) |  | ||||||
|         .catch(() => { alert('error') }) |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
| }) |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| .mk-mute-button |  | ||||||
|   display block |  | ||||||
|   user-select none |  | ||||||
|   cursor pointer |  | ||||||
|   padding 0 16px |  | ||||||
|   margin 0 |  | ||||||
|   min-width 100px |  | ||||||
|   line-height 36px |  | ||||||
|   font-size 14px |  | ||||||
|   font-weight bold |  | ||||||
|   color var(--primary) |  | ||||||
|   background transparent |  | ||||||
|   outline none |  | ||||||
|   border solid 1px var(--primary) |  | ||||||
|   border-radius 36px |  | ||||||
|  |  | ||||||
|   &:hover |  | ||||||
|     background var(--primaryAlpha01) |  | ||||||
|  |  | ||||||
|   &:active |  | ||||||
|     background var(--primaryAlpha02) |  | ||||||
|  |  | ||||||
|   &.active |  | ||||||
|     color var(--primaryForeground) |  | ||||||
|     background var(--primary) |  | ||||||
|  |  | ||||||
|     &:hover |  | ||||||
|       background var(--primaryLighten10) |  | ||||||
|       border-color var(--primaryLighten10) |  | ||||||
|     &:active |  | ||||||
|       background var(--primaryDarken10) |  | ||||||
|       border-color var(--primaryDarken10) |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -4,7 +4,7 @@ | |||||||
| 		<header> | 		<header> | ||||||
| 			<button class="cancel" @click="cancel">%fa:times%</button> | 			<button class="cancel" @click="cancel">%fa:times%</button> | ||||||
| 			<div> | 			<div> | ||||||
| 				<span class="text-count" :class="{ over: trimmedLength(text) > 1000 }">{{ 1000 - trimmedLength(text) }}</span> | 				<span class="text-count" :class="{ over: trimmedLength(text) > this.maxNoteTextLength }">{{ this.maxNoteTextLength - trimmedLength(text) }}</span> | ||||||
| 				<span class="geo" v-if="geo">%fa:map-marker-alt%</span> | 				<span class="geo" v-if="geo">%fa:map-marker-alt%</span> | ||||||
| 				<button class="submit" :disabled="!canPost" @click="post">{{ submitText }}</button> | 				<button class="submit" :disabled="!canPost" @click="post">{{ submitText }}</button> | ||||||
| 			</div> | 			</div> | ||||||
| @@ -102,10 +102,17 @@ export default Vue.extend({ | |||||||
| 			visibleUsers: [], | 			visibleUsers: [], | ||||||
| 			useCw: false, | 			useCw: false, | ||||||
| 			cw: null, | 			cw: null, | ||||||
| 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]') | 			recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'), | ||||||
|  | 			maxNoteTextLength: 1000 | ||||||
| 		}; | 		}; | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
|  | 	created() { | ||||||
|  | 		(this as any).os.getMeta().then(meta => { | ||||||
|  | 			this.maxNoteTextLength = meta.maxNoteTextLength; | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  |  | ||||||
| 	computed: { | 	computed: { | ||||||
| 		draftId(): string { | 		draftId(): string { | ||||||
| 			return this.renote | 			return this.renote | ||||||
| @@ -144,7 +151,7 @@ export default Vue.extend({ | |||||||
| 		canPost(): boolean { | 		canPost(): boolean { | ||||||
| 			return !this.posting && | 			return !this.posting && | ||||||
| 				(1 <= this.text.length || 1 <= this.files.length || this.poll || this.renote) && | 				(1 <= this.text.length || 1 <= this.files.length || this.poll || this.renote) && | ||||||
| 				(this.text.trim().length <= 1000); | 				(this.text.trim().length <= this.maxNoteTextLength); | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ | |||||||
| 					<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'">%fa:R calendar-alt%%i18n:@widgets%%fa:angle-right%</router-link></li> | 					<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'">%fa:R calendar-alt%%i18n:@widgets%%fa:angle-right%</router-link></li> | ||||||
| 					<li><router-link to="/i/favorites" :data-active="$route.name == 'favorites'">%fa:star%%i18n:@favorites%%fa:angle-right%</router-link></li> | 					<li><router-link to="/i/favorites" :data-active="$route.name == 'favorites'">%fa:star%%i18n:@favorites%%fa:angle-right%</router-link></li> | ||||||
| 					<li><router-link to="/i/lists" :data-active="$route.name == 'user-lists'">%fa:list%%i18n:@user-lists%%fa:angle-right%</router-link></li> | 					<li><router-link to="/i/lists" :data-active="$route.name == 'user-lists'">%fa:list%%i18n:@user-lists%%fa:angle-right%</router-link></li> | ||||||
| 					<li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:@drive%%fa:angle-right%</router-link></li> | 					<li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:common.drive%%fa:angle-right%</router-link></li> | ||||||
| 				</ul> | 				</ul> | ||||||
| 				<ul> | 				<ul> | ||||||
| 					<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li> | 					<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li> | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
| 	<span slot="header"> | 	<span slot="header"> | ||||||
| 		<template v-if="folder"><span style="margin-right:4px;">%fa:R folder-open%</span>{{ folder.name }}</template> | 		<template v-if="folder"><span style="margin-right:4px;">%fa:R folder-open%</span>{{ folder.name }}</template> | ||||||
| 		<template v-if="file"><mk-file-type-icon data-icon :type="file.type" style="margin-right:4px;"/>{{ file.name }}</template> | 		<template v-if="file"><mk-file-type-icon data-icon :type="file.type" style="margin-right:4px;"/>{{ file.name }}</template> | ||||||
| 		<template v-if="!folder && !file"><span style="margin-right:4px;">%fa:cloud%</span>%i18n:@drive%</template> | 		<template v-if="!folder && !file"><span style="margin-right:4px;">%fa:cloud%</span>%i18n:common.drive%</template> | ||||||
| 	</span> | 	</span> | ||||||
| 	<template slot="func"><button @click="fn">%fa:ellipsis-h%</button></template> | 	<template slot="func"><button @click="fn">%fa:ellipsis-h%</button></template> | ||||||
| 	<mk-drive | 	<mk-drive | ||||||
|   | |||||||
| @@ -26,6 +26,9 @@ | |||||||
| 					<ui-switch v-model="iLikeSushi">%i18n:common.i-like-sushi%</ui-switch> | 					<ui-switch v-model="iLikeSushi">%i18n:common.i-like-sushi%</ui-switch> | ||||||
| 					<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch> | 					<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch> | ||||||
| 					<ui-switch v-model="alwaysShowNsfw">%i18n:common.always-show-nsfw% (%i18n:common.this-setting-is-this-device-only%)</ui-switch> | 					<ui-switch v-model="alwaysShowNsfw">%i18n:common.always-show-nsfw% (%i18n:common.this-setting-is-this-device-only%)</ui-switch> | ||||||
|  | 				</section> | ||||||
|  |  | ||||||
|  | 				<section> | ||||||
| 					<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch> | 					<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch> | ||||||
| 					<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch> | 					<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch> | ||||||
| 				</section> | 				</section> | ||||||
| @@ -80,6 +83,10 @@ | |||||||
| 				</section> | 				</section> | ||||||
| 			</ui-card> | 			</ui-card> | ||||||
|  |  | ||||||
|  | 			<mk-drive-settings/> | ||||||
|  |  | ||||||
|  | 			<mk-mute-and-block/> | ||||||
|  |  | ||||||
| 			<ui-card> | 			<ui-card> | ||||||
| 				<div slot="title">%fa:volume-up% %i18n:@sound%</div> | 				<div slot="title">%fa:volume-up% %i18n:@sound%</div> | ||||||
|  |  | ||||||
| @@ -118,6 +125,8 @@ | |||||||
| 				</section> | 				</section> | ||||||
| 			</ui-card> | 			</ui-card> | ||||||
|  |  | ||||||
|  | 			<mk-api-settings /> | ||||||
|  |  | ||||||
| 			<ui-card> | 			<ui-card> | ||||||
| 				<div slot="title">%fa:sync-alt% %i18n:@update%</div> | 				<div slot="title">%fa:sync-alt% %i18n:@update%</div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ | |||||||
| 					<a class="avatar"> | 					<a class="avatar"> | ||||||
| 						<img :src="user.avatarUrl" alt="avatar"/> | 						<img :src="user.avatarUrl" alt="avatar"/> | ||||||
| 					</a> | 					</a> | ||||||
| 					<mk-mute-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> | 					<button class="menu" ref="menu" @click="menu">%fa: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"/> | ||||||
| 				</div> | 				</div> | ||||||
| 				<div class="title"> | 				<div class="title"> | ||||||
| @@ -67,6 +67,7 @@ import Vue from 'vue'; | |||||||
| import * as age from 's-age'; | import * as age from 's-age'; | ||||||
| import parseAcct from '../../../../../misc/acct/parse'; | import parseAcct from '../../../../../misc/acct/parse'; | ||||||
| import Progress from '../../../common/scripts/loading'; | import Progress from '../../../common/scripts/loading'; | ||||||
|  | import Menu from '../../../common/views/components/menu.vue'; | ||||||
| import XHome from './user/home.vue'; | import XHome from './user/home.vue'; | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| @@ -109,8 +110,62 @@ export default Vue.extend({ | |||||||
| 				Progress.done(); | 				Progress.done(); | ||||||
| 				document.title = `${Vue.filter('userName')(this.user)} | ${(this as any).os.instanceName}`; | 				document.title = `${Vue.filter('userName')(this.user)} | ${(this as any).os.instanceName}`; | ||||||
| 			}); | 			}); | ||||||
|  | 		}, | ||||||
|  |  | ||||||
|  | 		menu() { | ||||||
|  | 			let menu = [{ | ||||||
|  | 				icon: this.user.isMuted ? '%fa:eye%' : '%fa:eye-slash%', | ||||||
|  | 				text: this.user.isMuted ? '%i18n:@unmute%' : '%i18n:@mute%', | ||||||
|  | 				action: () => { | ||||||
|  | 					if (this.user.isMuted) { | ||||||
|  | 						(this as any).api('mute/delete', { | ||||||
|  | 							userId: this.user.id | ||||||
|  | 						}).then(() => { | ||||||
|  | 							this.user.isMuted = false; | ||||||
|  | 						}, () => { | ||||||
|  | 							alert('error'); | ||||||
|  | 						}); | ||||||
|  | 					} else { | ||||||
|  | 						(this as any).api('mute/create', { | ||||||
|  | 							userId: this.user.id | ||||||
|  | 						}).then(() => { | ||||||
|  | 							this.user.isMuted = true; | ||||||
|  | 						}, () => { | ||||||
|  | 							alert('error'); | ||||||
|  | 						}); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 			}, { | ||||||
|  | 				icon: this.user.isBlocking ? '%fa:user%' : '%fa:user-slash%', | ||||||
|  | 				text: this.user.isBlocking ? '%i18n:@unblock%' : '%i18n:@block%', | ||||||
|  | 				action: () => { | ||||||
|  | 					if (this.user.isBlocking) { | ||||||
|  | 						(this as any).api('blocking/delete', { | ||||||
|  | 							userId: this.user.id | ||||||
|  | 						}).then(() => { | ||||||
|  | 							this.user.isBlocking = false; | ||||||
|  | 						}, () => { | ||||||
|  | 							alert('error'); | ||||||
|  | 						}); | ||||||
|  | 					} else { | ||||||
|  | 						(this as any).api('blocking/create', { | ||||||
|  | 							userId: this.user.id | ||||||
|  | 						}).then(() => { | ||||||
|  | 							this.user.isBlocking = true; | ||||||
|  | 						}, () => { | ||||||
|  | 							alert('error'); | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}]; | ||||||
|  |  | ||||||
|  | 			this.os.new(Menu, { | ||||||
|  | 				source: this.$refs.menu, | ||||||
|  | 				compact: true, | ||||||
|  | 				items: menu | ||||||
|  | 			}); | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| @@ -156,14 +211,10 @@ main | |||||||
| 			max-width 600px | 			max-width 600px | ||||||
|  |  | ||||||
| 			> .top | 			> .top | ||||||
| 				&:after | 				display flex | ||||||
| 					content '' |  | ||||||
| 					display block |  | ||||||
| 					clear both |  | ||||||
|  |  | ||||||
| 				> .avatar | 				> .avatar | ||||||
| 					display block | 					display block | ||||||
| 					float left |  | ||||||
| 					width 25% | 					width 25% | ||||||
| 					height 40px | 					height 40px | ||||||
|  |  | ||||||
| @@ -183,11 +234,15 @@ main | |||||||
| 							border 4px solid $bg | 							border 4px solid $bg | ||||||
| 							border-radius 12px | 							border-radius 12px | ||||||
|  |  | ||||||
| 				> .mk-mute-button | 				> .menu | ||||||
| 					float right | 					margin 0 0 0 auto | ||||||
|  | 					padding 8px | ||||||
|  | 					margin-right 8px | ||||||
|  | 					font-size 18px | ||||||
|  | 					color var(--text) | ||||||
|  |  | ||||||
| 				> .mk-follow-button | 				> .mk-follow-button | ||||||
| 					float right | 					margin 0 | ||||||
|  |  | ||||||
| 			> .title | 			> .title | ||||||
| 				margin 8px 0 | 				margin 8px 0 | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ | |||||||
| 		faceClearButtonHover: 'rgba(0, 0, 0, 0.1)', | 		faceClearButtonHover: 'rgba(0, 0, 0, 0.1)', | ||||||
| 		faceClearButtonActive: 'rgba(0, 0, 0, 0.2)', | 		faceClearButtonActive: 'rgba(0, 0, 0, 0.2)', | ||||||
| 		popupBg: ':lighten<5<$secondary', | 		popupBg: ':lighten<5<$secondary', | ||||||
| 		popupFg: '#d6dce2', | 		popupFg: '$text', | ||||||
|  |  | ||||||
| 		subNoteBg: 'rgba(0, 0, 0, 0.18)', | 		subNoteBg: 'rgba(0, 0, 0, 0.18)', | ||||||
| 		subNoteText: ':alpha<0.7<$text', | 		subNoteText: ':alpha<0.7<$text', | ||||||
| @@ -131,6 +131,11 @@ | |||||||
| 		remoteInfoBg: '#42321c', | 		remoteInfoBg: '#42321c', | ||||||
| 		remoteInfoFg: '#ffbd3e', | 		remoteInfoFg: '#ffbd3e', | ||||||
|  |  | ||||||
|  | 		infoBg: '#253142', | ||||||
|  | 		infoFg: '#fff', | ||||||
|  | 		infoWarnBg: '#42321c', | ||||||
|  | 		infoWarnFg: '#ffbd3e', | ||||||
|  |  | ||||||
| 		messagingRoomBg: '@bg', | 		messagingRoomBg: '@bg', | ||||||
| 		messagingRoomInfo: '#fff', | 		messagingRoomInfo: '#fff', | ||||||
| 		messagingRoomDateDividerLine: 'rgba(255, 255, 255, 0.1)', | 		messagingRoomDateDividerLine: 'rgba(255, 255, 255, 0.1)', | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ | |||||||
| 		faceClearButtonHover: 'rgba(0, 0, 0, 0.025)', | 		faceClearButtonHover: 'rgba(0, 0, 0, 0.025)', | ||||||
| 		faceClearButtonActive: 'rgba(0, 0, 0, 0.05)', | 		faceClearButtonActive: 'rgba(0, 0, 0, 0.05)', | ||||||
| 		popupBg: ':lighten<5<$secondary', | 		popupBg: ':lighten<5<$secondary', | ||||||
| 		popupFg: '#586069', | 		popupFg: '$text', | ||||||
|  |  | ||||||
| 		subNoteBg: 'rgba(0, 0, 0, 0.01)', | 		subNoteBg: 'rgba(0, 0, 0, 0.01)', | ||||||
| 		subNoteText: ':alpha<0.7<$text', | 		subNoteText: ':alpha<0.7<$text', | ||||||
| @@ -131,6 +131,11 @@ | |||||||
| 		remoteInfoBg: '#fff0db', | 		remoteInfoBg: '#fff0db', | ||||||
| 		remoteInfoFg: '#573c08', | 		remoteInfoFg: '#573c08', | ||||||
|  |  | ||||||
|  | 		infoBg: '#e5f5ff', | ||||||
|  | 		infoFg: '#72818a', | ||||||
|  | 		infoWarnBg: '#fff0db', | ||||||
|  | 		infoWarnFg: '#573c08', | ||||||
|  |  | ||||||
| 		messagingRoomBg: '#fff', | 		messagingRoomBg: '#fff', | ||||||
| 		messagingRoomInfo: '#000', | 		messagingRoomInfo: '#000', | ||||||
| 		messagingRoomDateDividerLine: 'rgba(0, 0, 0, 0.1)', | 		messagingRoomDateDividerLine: 'rgba(0, 0, 0, 0.1)', | ||||||
|   | |||||||
| @@ -49,6 +49,8 @@ export default function load() { | |||||||
| 	if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256; | 	if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256; | ||||||
| 	if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8; | 	if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8; | ||||||
|  |  | ||||||
|  | 	if (config.maxNoteTextLength == null) config.maxNoteTextLength = 1000; | ||||||
|  |  | ||||||
| 	if (config.name == null) config.name = 'Misskey'; | 	if (config.name == null) config.name = 'Misskey'; | ||||||
|  |  | ||||||
| 	return Object.assign(config, mixin); | 	return Object.assign(config, mixin); | ||||||
|   | |||||||
| @@ -14,11 +14,13 @@ export type Source = { | |||||||
| 		 * メンテナの連絡先(URLかmailto形式のURL) | 		 * メンテナの連絡先(URLかmailto形式のURL) | ||||||
| 		 */ | 		 */ | ||||||
| 		url: string; | 		url: string; | ||||||
|  | 		email?: string; | ||||||
| 		repository_url?: string; | 		repository_url?: string; | ||||||
| 		feedback_url?: string; | 		feedback_url?: string; | ||||||
| 	}; | 	}; | ||||||
| 	name?: string; | 	name?: string; | ||||||
| 	description?: string; | 	description?: string; | ||||||
|  | 	languages?: string[]; | ||||||
| 	welcome_bg_url?: string; | 	welcome_bg_url?: string; | ||||||
| 	url: string; | 	url: string; | ||||||
| 	port: number; | 	port: number; | ||||||
| @@ -103,6 +105,8 @@ export type Source = { | |||||||
| 		engine: string; | 		engine: string; | ||||||
| 		timeout: number; | 		timeout: number; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	maxNoteTextLength?: number; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ | |||||||
|  |  | ||||||
| 以下のURLに、`i`というパラメータ名で認証情報を含めて、websocket接続してください。例: | 以下のURLに、`i`というパラメータ名で認証情報を含めて、websocket接続してください。例: | ||||||
| ``` | ``` | ||||||
| %URL%/streaming?i=xxxxxxxxxxxxxxx | %WS_URL%/streaming?i=xxxxxxxxxxxxxxx | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。 | 認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。 | ||||||
| @@ -22,7 +22,7 @@ | |||||||
| 認証情報は省略することもできますが、その場合非ログインでの利用ということになり、受信できる情報や可能な操作は限られます。例: | 認証情報は省略することもできますが、その場合非ログインでの利用ということになり、受信できる情報や可能な操作は限られます。例: | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
| %URL%/streaming | %WS_URL%/streaming | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
|   | |||||||
| @@ -9,9 +9,9 @@ export type TextElementHashtag = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| export default function(text: string, i: number) { | export default function(text: string, i: number) { | ||||||
| 	if (!(/^\s#[^\s\.,!\?]+/.test(text) || (i == 0 && /^#[^\s\.,!\?]+/.test(text)))) return null; | 	if (!(/^\s#[^\s\.,!\?#]+/.test(text) || (i == 0 && /^#[^\s\.,!\?#]+/.test(text)))) return null; | ||||||
| 	const isHead = text.startsWith('#'); | 	const isHead = text.startsWith('#'); | ||||||
| 	const hashtag = text.match(/^\s?#[^\s\.,!\?]+/)[0]; | 	const hashtag = text.match(/^\s?#[^\s\.,!\?#]+/)[0]; | ||||||
| 	const res: any[] = !isHead ? [{ | 	const res: any[] = !isHead ? [{ | ||||||
| 		type: 'text', | 		type: 'text', | ||||||
| 		content: text[0] | 		content: text[0] | ||||||
|   | |||||||
| @@ -17,7 +17,8 @@ export default function(text: string, index: number) { | |||||||
| 	const quote = match[1] | 	const quote = match[1] | ||||||
| 		.split('\n') | 		.split('\n') | ||||||
| 		.map(line => line.replace(/^>+/g, '').trim()) | 		.map(line => line.replace(/^>+/g, '').trim()) | ||||||
| 		.join('\n'); | 		.join('\n') | ||||||
|  | 		.trim(); | ||||||
|  |  | ||||||
| 	return { | 	return { | ||||||
| 		type: 'quote', | 		type: 'quote', | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								src/misc/get-drive-file-url.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/misc/get-drive-file-url.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | import { IDriveFile } from '../models/drive-file'; | ||||||
|  | import config from '../config'; | ||||||
|  |  | ||||||
|  | export default function(file: IDriveFile, thumbnail = false): string { | ||||||
|  | 	if (file == null) return null; | ||||||
|  |  | ||||||
|  | 	if (file.metadata.withoutChunks) { | ||||||
|  | 		if (thumbnail) { | ||||||
|  | 			return file.metadata.thumbnailUrl || file.metadata.url; | ||||||
|  | 		} else { | ||||||
|  | 			return file.metadata.url; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if (thumbnail) { | ||||||
|  | 			return `${config.drive_url}/${file._id}?thumbnail`; | ||||||
|  | 		} else { | ||||||
|  | 			return `${config.drive_url}/${file._id}`; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; |  | ||||||
|  |  | ||||||
| const AccessToken = db.get<IAccessToken>('accessTokens'); | const AccessToken = db.get<IAccessToken>('accessTokens'); | ||||||
| AccessToken.createIndex('token'); | AccessToken.createIndex('token'); | ||||||
| @@ -15,30 +14,3 @@ export type IAccessToken = { | |||||||
| 	token: string; | 	token: string; | ||||||
| 	hash: string; | 	hash: string; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * AccessTokenを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteAccessToken(accessToken: string | mongo.ObjectID | IAccessToken) { |  | ||||||
| 	let a: IAccessToken; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(accessToken)) { |  | ||||||
| 		a = await AccessToken.findOne({ |  | ||||||
| 			_id: accessToken |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof accessToken === 'string') { |  | ||||||
| 		a = await AccessToken.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(accessToken) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		a = accessToken as IAccessToken; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (a == null) return; |  | ||||||
|  |  | ||||||
| 	// このAccessTokenを削除 |  | ||||||
| 	await AccessToken.remove({ |  | ||||||
| 		_id: a._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -22,27 +22,28 @@ export type IApp = { | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Pack an app for API response |  * Pack an app for API response | ||||||
|  * |  | ||||||
|  * @param {any} app |  | ||||||
|  * @param {any} me? |  | ||||||
|  * @param {any} options? |  | ||||||
|  * @return {Promise<any>} |  | ||||||
|  */ |  */ | ||||||
| export const pack = ( | export const pack = ( | ||||||
| 	app: any, | 	app: any, | ||||||
| 	me?: any, | 	me?: any, | ||||||
| 	options?: { | 	options?: { | ||||||
|  | 		detail?: boolean, | ||||||
| 		includeSecret?: boolean, | 		includeSecret?: boolean, | ||||||
| 		includeProfileImageIds?: boolean | 		includeProfileImageIds?: boolean | ||||||
| 	} | 	} | ||||||
| ) => new Promise<any>(async (resolve, reject) => { | ) => new Promise<any>(async (resolve, reject) => { | ||||||
| 	const opts = options || { | 	const opts = Object.assign({ | ||||||
|  | 		detail: false, | ||||||
| 		includeSecret: false, | 		includeSecret: false, | ||||||
| 		includeProfileImageIds: false | 		includeProfileImageIds: false | ||||||
| 	}; | 	}, options); | ||||||
|  |  | ||||||
| 	let _app: any; | 	let _app: any; | ||||||
|  |  | ||||||
|  | 	const fields = opts.detail ? {} : { | ||||||
|  | 		name: true | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	// Populate the app if 'app' is ID | 	// Populate the app if 'app' is ID | ||||||
| 	if (isObjectId(app)) { | 	if (isObjectId(app)) { | ||||||
| 		_app = await App.findOne({ | 		_app = await App.findOne({ | ||||||
| @@ -51,7 +52,7 @@ export const pack = ( | |||||||
| 	} else if (typeof app === 'string') { | 	} else if (typeof app === 'string') { | ||||||
| 		_app = await App.findOne({ | 		_app = await App.findOne({ | ||||||
| 			_id: new mongo.ObjectID(app) | 			_id: new mongo.ObjectID(app) | ||||||
| 		}); | 		}, { fields }); | ||||||
| 	} else { | 	} else { | ||||||
| 		_app = deepcopy(app); | 		_app = deepcopy(app); | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								src/models/blocking.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/models/blocking.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | import * as mongo from 'mongodb'; | ||||||
|  | import db from '../db/mongodb'; | ||||||
|  | import isObjectId from '../misc/is-objectid'; | ||||||
|  | const deepcopy = require('deepcopy'); | ||||||
|  | import { pack as packUser, IUser } from './user'; | ||||||
|  |  | ||||||
|  | const Blocking = db.get<IBlocking>('blocking'); | ||||||
|  | Blocking.createIndex('blockerId'); | ||||||
|  | Blocking.createIndex('blockeeId'); | ||||||
|  | Blocking.createIndex(['blockerId', 'blockeeId'], { unique: true }); | ||||||
|  | export default Blocking; | ||||||
|  |  | ||||||
|  | export type IBlocking = { | ||||||
|  | 	_id: mongo.ObjectID; | ||||||
|  | 	createdAt: Date; | ||||||
|  | 	blockeeId: mongo.ObjectID; | ||||||
|  | 	blockerId: mongo.ObjectID; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const packMany = ( | ||||||
|  | 	blockings: (string | mongo.ObjectID | IBlocking)[], | ||||||
|  | 	me?: string | mongo.ObjectID | IUser | ||||||
|  | ) => { | ||||||
|  | 	return Promise.all(blockings.map(x => pack(x, me))); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const pack = ( | ||||||
|  | 	blocking: any, | ||||||
|  | 	me?: any | ||||||
|  | ) => new Promise<any>(async (resolve, reject) => { | ||||||
|  | 	let _blocking: any; | ||||||
|  |  | ||||||
|  | 	// Populate the blocking if 'blocking' is ID | ||||||
|  | 	if (isObjectId(blocking)) { | ||||||
|  | 		_blocking = await Blocking.findOne({ | ||||||
|  | 			_id: blocking | ||||||
|  | 		}); | ||||||
|  | 	} else if (typeof blocking === 'string') { | ||||||
|  | 		_blocking = await Blocking.findOne({ | ||||||
|  | 			_id: new mongo.ObjectID(blocking) | ||||||
|  | 		}); | ||||||
|  | 	} else { | ||||||
|  | 		_blocking = deepcopy(blocking); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Rename _id to id | ||||||
|  | 	_blocking.id = _blocking._id; | ||||||
|  | 	delete _blocking._id; | ||||||
|  |  | ||||||
|  | 	// Populate blockee | ||||||
|  | 	_blocking.blockee = await packUser(_blocking.blockeeId, me, { | ||||||
|  | 		detail: true | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	resolve(_blocking); | ||||||
|  | }); | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| import monkDb, { nativeDbConn } from '../db/mongodb'; | import monkDb, { nativeDbConn } from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; |  | ||||||
|  |  | ||||||
| const DriveFileThumbnail = monkDb.get<IDriveFileThumbnail>('driveFileThumbnails.files'); | const DriveFileThumbnail = monkDb.get<IDriveFileThumbnail>('driveFileThumbnails.files'); | ||||||
| DriveFileThumbnail.createIndex('metadata.originalId', { sparse: true, unique: true }); | DriveFileThumbnail.createIndex('metadata.originalId', { sparse: true, unique: true }); | ||||||
| @@ -28,35 +27,3 @@ export type IDriveFileThumbnail = { | |||||||
| 	contentType: string; | 	contentType: string; | ||||||
| 	metadata: IMetadata; | 	metadata: IMetadata; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * DriveFileThumbnailを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteDriveFileThumbnail(driveFile: string | mongo.ObjectID | IDriveFileThumbnail) { |  | ||||||
| 	let d: IDriveFileThumbnail; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(driveFile)) { |  | ||||||
| 		d = await DriveFileThumbnail.findOne({ |  | ||||||
| 			_id: driveFile |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof driveFile === 'string') { |  | ||||||
| 		d = await DriveFileThumbnail.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(driveFile) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		d = driveFile as IDriveFileThumbnail; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (d == null) return; |  | ||||||
|  |  | ||||||
| 	// このDriveFileThumbnailのチャンクをすべて削除 |  | ||||||
| 	await DriveFileThumbnailChunk.remove({ |  | ||||||
| 		files_id: d._id |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	// このDriveFileThumbnailを削除 |  | ||||||
| 	await DriveFileThumbnail.remove({ |  | ||||||
| 		_id: d._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,13 +1,9 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| const deepcopy = require('deepcopy'); | const deepcopy = require('deepcopy'); | ||||||
| import { pack as packFolder } from './drive-folder'; | import { pack as packFolder } from './drive-folder'; | ||||||
| import config from '../config'; |  | ||||||
| import monkDb, { nativeDbConn } from '../db/mongodb'; | import monkDb, { nativeDbConn } from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; | import isObjectId from '../misc/is-objectid'; | ||||||
| import Note, { deleteNote } from './note'; | import getDriveFileUrl from '../misc/get-drive-file-url'; | ||||||
| import MessagingMessage, { deleteMessagingMessage } from './messaging-message'; |  | ||||||
| import User from './user'; |  | ||||||
| import DriveFileThumbnail, { deleteDriveFileThumbnail } from './drive-file-thumbnail'; |  | ||||||
|  |  | ||||||
| const DriveFile = monkDb.get<IDriveFile>('driveFiles.files'); | const DriveFile = monkDb.get<IDriveFile>('driveFiles.files'); | ||||||
| DriveFile.createIndex('md5'); | DriveFile.createIndex('md5'); | ||||||
| @@ -37,7 +33,14 @@ export type IMetadata = { | |||||||
| 	thumbnailUrl?: string; | 	thumbnailUrl?: string; | ||||||
| 	src?: string; | 	src?: string; | ||||||
| 	deletedAt?: Date; | 	deletedAt?: Date; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * このファイルの中身データがMongoDB内に保存されているのか否か | ||||||
|  | 	 * オブジェクトストレージを利用している or リモートサーバーへの直リンクである | ||||||
|  | 	 * な場合は false になります | ||||||
|  | 	 */ | ||||||
| 	withoutChunks?: boolean; | 	withoutChunks?: boolean; | ||||||
|  |  | ||||||
| 	storage?: string; | 	storage?: string; | ||||||
| 	storageProps?: any; | 	storageProps?: any; | ||||||
| 	isSensitive?: boolean; | 	isSensitive?: boolean; | ||||||
| @@ -77,71 +80,13 @@ export function validateFileName(name: string): boolean { | |||||||
| 	); | 	); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | export const packMany = ( | ||||||
|  * DriveFileを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteDriveFile(driveFile: string | mongo.ObjectID | IDriveFile) { |  | ||||||
| 	let d: IDriveFile; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(driveFile)) { |  | ||||||
| 		d = await DriveFile.findOne({ |  | ||||||
| 			_id: driveFile |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof driveFile === 'string') { |  | ||||||
| 		d = await DriveFile.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(driveFile) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		d = driveFile as IDriveFile; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (d == null) return; |  | ||||||
|  |  | ||||||
| 	// このDriveFileを添付しているNoteをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await Note.find({ fileIds: d._id }) |  | ||||||
| 	).map(x => deleteNote(x))); |  | ||||||
|  |  | ||||||
| 	// このDriveFileを添付しているMessagingMessageをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await MessagingMessage.find({ fileId: d._id }) |  | ||||||
| 	).map(x => deleteMessagingMessage(x))); |  | ||||||
|  |  | ||||||
| 	// このDriveFileがアバターやバナーに使われていたらそれらのプロパティをnullにする |  | ||||||
| 	const u = await User.findOne({ _id: d.metadata.userId }); |  | ||||||
| 	if (u) { |  | ||||||
| 		if (u.avatarId && u.avatarId.equals(d._id)) { |  | ||||||
| 			await User.update({ _id: u._id }, { $set: { avatarId: null } }); |  | ||||||
| 		} |  | ||||||
| 		if (u.bannerId && u.bannerId.equals(d._id)) { |  | ||||||
| 			await User.update({ _id: u._id }, { $set: { bannerId: null } }); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// このDriveFileのDriveFileThumbnailをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await DriveFileThumbnail.find({ 'metadata.originalId': d._id }) |  | ||||||
| 	).map(x => deleteDriveFileThumbnail(x))); |  | ||||||
|  |  | ||||||
| 	// このDriveFileのチャンクをすべて削除 |  | ||||||
| 	await DriveFileChunk.remove({ |  | ||||||
| 		files_id: d._id |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	// このDriveFileを削除 |  | ||||||
| 	await DriveFile.remove({ |  | ||||||
| 		_id: d._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const packMany = async ( |  | ||||||
| 	files: any[], | 	files: any[], | ||||||
| 	options?: { | 	options?: { | ||||||
| 		detail: boolean | 		detail: boolean | ||||||
| 	} | 	} | ||||||
| ) => { | ) => { | ||||||
| 	return (await Promise.all(files.map(f => pack(f, options)))).filter(x => x != null); | 	return Promise.all(files.map(f => pack(f, options))); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -190,8 +135,8 @@ export const pack = ( | |||||||
|  |  | ||||||
| 	_target = Object.assign(_target, _file.metadata); | 	_target = Object.assign(_target, _file.metadata); | ||||||
|  |  | ||||||
| 	_target.url = _file.metadata.url ? _file.metadata.url : `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`; | 	_target.url = getDriveFileUrl(_file); | ||||||
| 	_target.thumbnailUrl = _file.metadata.thumbnailUrl ? _file.metadata.thumbnailUrl : _file.metadata.url ? _file.metadata.url : `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}?thumbnail`; | 	_target.thumbnailUrl = getDriveFileUrl(_file, true); | ||||||
| 	_target.isRemote = _file.metadata.isRemote; | 	_target.isRemote = _file.metadata.isRemote; | ||||||
|  |  | ||||||
| 	if (_target.properties == null) _target.properties = {}; | 	if (_target.properties == null) _target.properties = {}; | ||||||
| @@ -218,6 +163,7 @@ export const pack = ( | |||||||
| 	delete _target.storage; | 	delete _target.storage; | ||||||
| 	delete _target.storageProps; | 	delete _target.storageProps; | ||||||
| 	delete _target.isRemote; | 	delete _target.isRemote; | ||||||
|  | 	delete _target._user; | ||||||
|  |  | ||||||
| 	resolve(_target); | 	resolve(_target); | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -23,51 +23,6 @@ export function isValidFolderName(name: string): boolean { | |||||||
| 	); | 	); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * DriveFolderを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteDriveFolder(driveFolder: string | mongo.ObjectID | IDriveFolder) { |  | ||||||
| 	let d: IDriveFolder; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(driveFolder)) { |  | ||||||
| 		d = await DriveFolder.findOne({ |  | ||||||
| 			_id: driveFolder |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof driveFolder === 'string') { |  | ||||||
| 		d = await DriveFolder.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(driveFolder) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		d = driveFolder as IDriveFolder; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (d == null) return; |  | ||||||
|  |  | ||||||
| 	// このDriveFolderに格納されているDriveFileがあればすべてルートに移動 |  | ||||||
| 	await DriveFile.update({ |  | ||||||
| 		'metadata.folderId': d._id |  | ||||||
| 	}, { |  | ||||||
| 		$set: { |  | ||||||
| 			'metadata.folderId': null |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	// このDriveFolderに格納されているDriveFolderがあればすべてルートに移動 |  | ||||||
| 	await DriveFolder.update({ |  | ||||||
| 		parentId: d._id |  | ||||||
| 	}, { |  | ||||||
| 		$set: { |  | ||||||
| 			parentId: null |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	// このDriveFolderを削除 |  | ||||||
| 	await DriveFolder.remove({ |  | ||||||
| 		_id: d._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Pack a drive folder for API response |  * Pack a drive folder for API response | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import isObjectId from '../misc/is-objectid'; | |||||||
| import { pack as packNote } from './note'; | import { pack as packNote } from './note'; | ||||||
|  |  | ||||||
| const Favorite = db.get<IFavorite>('favorites'); | const Favorite = db.get<IFavorite>('favorites'); | ||||||
|  | Favorite.createIndex('userId'); | ||||||
| Favorite.createIndex(['userId', 'noteId'], { unique: true }); | Favorite.createIndex(['userId', 'noteId'], { unique: true }); | ||||||
| export default Favorite; | export default Favorite; | ||||||
|  |  | ||||||
| @@ -15,38 +16,11 @@ export type IFavorite = { | |||||||
| 	noteId: mongo.ObjectID; | 	noteId: mongo.ObjectID; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | export const packMany = ( | ||||||
|  * Favoriteを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteFavorite(favorite: string | mongo.ObjectID | IFavorite) { |  | ||||||
| 	let f: IFavorite; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(favorite)) { |  | ||||||
| 		f = await Favorite.findOne({ |  | ||||||
| 			_id: favorite |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof favorite === 'string') { |  | ||||||
| 		f = await Favorite.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(favorite) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		f = favorite as IFavorite; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (f == null) return; |  | ||||||
|  |  | ||||||
| 	// このFavoriteを削除 |  | ||||||
| 	await Favorite.remove({ |  | ||||||
| 		_id: f._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const packMany = async ( |  | ||||||
| 	favorites: any[], | 	favorites: any[], | ||||||
| 	me: any | 	me: any | ||||||
| ) => { | ) => { | ||||||
| 	return (await Promise.all(favorites.map(f => pack(f, me)))).filter(x => x != null); | 	return Promise.all(favorites.map(f => pack(f, me))); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -5,6 +5,8 @@ import isObjectId from '../misc/is-objectid'; | |||||||
| import { pack as packUser } from './user'; | import { pack as packUser } from './user'; | ||||||
|  |  | ||||||
| const FollowRequest = db.get<IFollowRequest>('followRequests'); | const FollowRequest = db.get<IFollowRequest>('followRequests'); | ||||||
|  | FollowRequest.createIndex('followerId'); | ||||||
|  | FollowRequest.createIndex('followeeId'); | ||||||
| FollowRequest.createIndex(['followerId', 'followeeId'], { unique: true }); | FollowRequest.createIndex(['followerId', 'followeeId'], { unique: true }); | ||||||
| export default FollowRequest; | export default FollowRequest; | ||||||
|  |  | ||||||
| @@ -28,33 +30,6 @@ export type IFollowRequest = { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * FollowRequestを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteFollowRequest(followRequest: string | mongo.ObjectID | IFollowRequest) { |  | ||||||
| 	let f: IFollowRequest; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(followRequest)) { |  | ||||||
| 		f = await FollowRequest.findOne({ |  | ||||||
| 			_id: followRequest |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof followRequest === 'string') { |  | ||||||
| 		f = await FollowRequest.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(followRequest) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		f = followRequest as IFollowRequest; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (f == null) return; |  | ||||||
|  |  | ||||||
| 	// このFollowingを削除 |  | ||||||
| 	await FollowRequest.remove({ |  | ||||||
| 		_id: f._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Pack a request for API response |  * Pack a request for API response | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; |  | ||||||
|  |  | ||||||
| const Following = db.get<IFollowing>('following'); | const Following = db.get<IFollowing>('following'); | ||||||
|  | Following.createIndex('followerId'); | ||||||
|  | Following.createIndex('followeeId'); | ||||||
| Following.createIndex(['followerId', 'followeeId'], { unique: true }); | Following.createIndex(['followerId', 'followeeId'], { unique: true }); | ||||||
| export default Following; | export default Following; | ||||||
|  |  | ||||||
| @@ -25,30 +26,3 @@ export type IFollowing = { | |||||||
| 		sharedInbox?: string; | 		sharedInbox?: string; | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Followingを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteFollowing(following: string | mongo.ObjectID | IFollowing) { |  | ||||||
| 	let f: IFollowing; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(following)) { |  | ||||||
| 		f = await Following.findOne({ |  | ||||||
| 			_id: following |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof following === 'string') { |  | ||||||
| 		f = await Following.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(following) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		f = following as IFollowing; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (f == null) return; |  | ||||||
|  |  | ||||||
| 	// このFollowingを削除 |  | ||||||
| 	await Following.remove({ |  | ||||||
| 		_id: f._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								src/models/instance.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/models/instance.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | import * as mongo from 'mongodb'; | ||||||
|  | import db from '../db/mongodb'; | ||||||
|  |  | ||||||
|  | const Instance = db.get<IInstance>('instances'); | ||||||
|  | Instance.createIndex('host', { unique: true }); | ||||||
|  | export default Instance; | ||||||
|  |  | ||||||
|  | export interface IInstance { | ||||||
|  | 	_id: mongo.ObjectID; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * ホスト | ||||||
|  | 	 */ | ||||||
|  | 	host: string; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * このインスタンスを捕捉した日時 | ||||||
|  | 	 */ | ||||||
|  | 	caughtAt: Date; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * このインスタンスのシステム (MastodonとかMisskeyとかPleromaとか) | ||||||
|  | 	 */ | ||||||
|  | 	system: string; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * このインスタンスのユーザー数 | ||||||
|  | 	 */ | ||||||
|  | 	usersCount: number; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * このインスタンスから受け取った投稿数 | ||||||
|  | 	 */ | ||||||
|  | 	notesCount: number; | ||||||
|  | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; |  | ||||||
|  |  | ||||||
| const MessagingHistory = db.get<IMessagingHistory>('messagingHistories'); | const MessagingHistory = db.get<IMessagingHistory>('messagingHistories'); | ||||||
| export default MessagingHistory; | export default MessagingHistory; | ||||||
| @@ -12,30 +11,3 @@ export type IMessagingHistory = { | |||||||
| 	partnerId: mongo.ObjectID; | 	partnerId: mongo.ObjectID; | ||||||
| 	messageId: mongo.ObjectID; | 	messageId: mongo.ObjectID; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * MessagingHistoryを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteMessagingHistory(messagingHistory: string | mongo.ObjectID | IMessagingHistory) { |  | ||||||
| 	let m: IMessagingHistory; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(messagingHistory)) { |  | ||||||
| 		m = await MessagingHistory.findOne({ |  | ||||||
| 			_id: messagingHistory |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof messagingHistory === 'string') { |  | ||||||
| 		m = await MessagingHistory.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(messagingHistory) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		m = messagingHistory as IMessagingHistory; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (m == null) return; |  | ||||||
|  |  | ||||||
| 	// このMessagingHistoryを削除 |  | ||||||
| 	await MessagingHistory.remove({ |  | ||||||
| 		_id: m._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ import { pack as packUser } from './user'; | |||||||
| import { pack as packFile } from './drive-file'; | import { pack as packFile } from './drive-file'; | ||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; | import isObjectId from '../misc/is-objectid'; | ||||||
| import MessagingHistory, { deleteMessagingHistory } from './messaging-history'; |  | ||||||
| import { length } from 'stringz'; | import { length } from 'stringz'; | ||||||
|  |  | ||||||
| const MessagingMessage = db.get<IMessagingMessage>('messagingMessages'); | const MessagingMessage = db.get<IMessagingMessage>('messagingMessages'); | ||||||
| @@ -24,38 +23,6 @@ export function isValidText(text: string): boolean { | |||||||
| 	return length(text.trim()) <= 1000 && text.trim() != ''; | 	return length(text.trim()) <= 1000 && text.trim() != ''; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * MessagingMessageを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteMessagingMessage(messagingMessage: string | mongo.ObjectID | IMessagingMessage) { |  | ||||||
| 	let m: IMessagingMessage; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(messagingMessage)) { |  | ||||||
| 		m = await MessagingMessage.findOne({ |  | ||||||
| 			_id: messagingMessage |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof messagingMessage === 'string') { |  | ||||||
| 		m = await MessagingMessage.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(messagingMessage) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		m = messagingMessage as IMessagingMessage; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (m == null) return; |  | ||||||
|  |  | ||||||
| 	// このMessagingMessageを指すMessagingHistoryをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await MessagingHistory.find({ messageId: m._id }) |  | ||||||
| 	).map(x => deleteMessagingHistory(x))); |  | ||||||
|  |  | ||||||
| 	// このMessagingMessageを削除 |  | ||||||
| 	await MessagingMessage.remove({ |  | ||||||
| 		_id: m._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Pack a messaging message for API response |  * Pack a messaging message for API response | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -1,8 +1,12 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; | import isObjectId from '../misc/is-objectid'; | ||||||
|  | const deepcopy = require('deepcopy'); | ||||||
|  | import { pack as packUser, IUser } from './user'; | ||||||
|  |  | ||||||
| const Mute = db.get<IMute>('mute'); | const Mute = db.get<IMute>('mute'); | ||||||
|  | Mute.createIndex('muterId'); | ||||||
|  | Mute.createIndex('muteeId'); | ||||||
| Mute.createIndex(['muterId', 'muteeId'], { unique: true }); | Mute.createIndex(['muterId', 'muteeId'], { unique: true }); | ||||||
| export default Mute; | export default Mute; | ||||||
|  |  | ||||||
| @@ -13,29 +17,40 @@ export interface IMute { | |||||||
| 	muteeId: mongo.ObjectID; | 	muteeId: mongo.ObjectID; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | export const packMany = ( | ||||||
|  * Muteを物理削除します | 	mutes: (string | mongo.ObjectID | IMute)[], | ||||||
|  */ | 	me?: string | mongo.ObjectID | IUser | ||||||
| export async function deleteMute(mute: string | mongo.ObjectID | IMute) { | ) => { | ||||||
| 	let m: IMute; | 	return Promise.all(mutes.map(x => pack(x, me))); | ||||||
|  | }; | ||||||
|  |  | ||||||
| 	// Populate | export const pack = ( | ||||||
|  | 	mute: any, | ||||||
|  | 	me?: any | ||||||
|  | ) => new Promise<any>(async (resolve, reject) => { | ||||||
|  | 	let _mute: any; | ||||||
|  |  | ||||||
|  | 	// Populate the mute if 'mute' is ID | ||||||
| 	if (isObjectId(mute)) { | 	if (isObjectId(mute)) { | ||||||
| 		m = await Mute.findOne({ | 		_mute = await Mute.findOne({ | ||||||
| 			_id: mute | 			_id: mute | ||||||
| 		}); | 		}); | ||||||
| 	} else if (typeof mute === 'string') { | 	} else if (typeof mute === 'string') { | ||||||
| 		m = await Mute.findOne({ | 		_mute = await Mute.findOne({ | ||||||
| 			_id: new mongo.ObjectID(mute) | 			_id: new mongo.ObjectID(mute) | ||||||
| 		}); | 		}); | ||||||
| 	} else { | 	} else { | ||||||
| 		m = mute as IMute; | 		_mute = deepcopy(mute); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (m == null) return; | 	// Rename _id to id | ||||||
|  | 	_mute.id = _mute._id; | ||||||
|  | 	delete _mute._id; | ||||||
|  |  | ||||||
| 	// このMuteを削除 | 	// Populate mutee | ||||||
| 	await Mute.remove({ | 	_mute.mutee = await packUser(_mute.muteeId, me, { | ||||||
| 		_id: m._id | 		detail: true | ||||||
| 	}); | 	}); | ||||||
| } |  | ||||||
|  | 	resolve(_mute); | ||||||
|  | }); | ||||||
|   | |||||||
| @@ -7,6 +7,8 @@ import Reaction from './note-reaction'; | |||||||
| import { pack as packUser } from './user'; | import { pack as packUser } from './user'; | ||||||
|  |  | ||||||
| const NoteReaction = db.get<INoteReaction>('noteReactions'); | const NoteReaction = db.get<INoteReaction>('noteReactions'); | ||||||
|  | NoteReaction.createIndex('noteId'); | ||||||
|  | NoteReaction.createIndex('userId'); | ||||||
| NoteReaction.createIndex(['userId', 'noteId'], { unique: true }); | NoteReaction.createIndex(['userId', 'noteId'], { unique: true }); | ||||||
| export default NoteReaction; | export default NoteReaction; | ||||||
|  |  | ||||||
| @@ -31,33 +33,6 @@ export const validateReaction = $.str.or([ | |||||||
| 	'pudding' | 	'pudding' | ||||||
| ]); | ]); | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * NoteReactionを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteNoteReaction(noteReaction: string | mongo.ObjectID | INoteReaction) { |  | ||||||
| 	let n: INoteReaction; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(noteReaction)) { |  | ||||||
| 		n = await NoteReaction.findOne({ |  | ||||||
| 			_id: noteReaction |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof noteReaction === 'string') { |  | ||||||
| 		n = await NoteReaction.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(noteReaction) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		n = noteReaction as INoteReaction; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (n == null) return; |  | ||||||
|  |  | ||||||
| 	// このNoteReactionを削除 |  | ||||||
| 	await NoteReaction.remove({ |  | ||||||
| 		_id: n._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Pack a reaction for API response |  * Pack a reaction for API response | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ import * as mongo from 'mongodb'; | |||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
|  |  | ||||||
| const NoteUnread = db.get<INoteUnread>('noteUnreads'); | const NoteUnread = db.get<INoteUnread>('noteUnreads'); | ||||||
|  | NoteUnread.createIndex('userId'); | ||||||
|  | NoteUnread.createIndex('noteId'); | ||||||
| NoteUnread.createIndex(['userId', 'noteId'], { unique: true }); | NoteUnread.createIndex(['userId', 'noteId'], { unique: true }); | ||||||
| export default NoteUnread; | export default NoteUnread; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; |  | ||||||
|  |  | ||||||
| const NoteWatching = db.get<INoteWatching>('noteWatching'); | const NoteWatching = db.get<INoteWatching>('noteWatching'); | ||||||
|  | NoteWatching.createIndex('userId'); | ||||||
|  | NoteWatching.createIndex('noteId'); | ||||||
| NoteWatching.createIndex(['userId', 'noteId'], { unique: true }); | NoteWatching.createIndex(['userId', 'noteId'], { unique: true }); | ||||||
| export default NoteWatching; | export default NoteWatching; | ||||||
|  |  | ||||||
| @@ -12,30 +13,3 @@ export interface INoteWatching { | |||||||
| 	userId: mongo.ObjectID; | 	userId: mongo.ObjectID; | ||||||
| 	noteId: mongo.ObjectID; | 	noteId: mongo.ObjectID; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * NoteWatchingを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteNoteWatching(noteWatching: string | mongo.ObjectID | INoteWatching) { |  | ||||||
| 	let n: INoteWatching; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(noteWatching)) { |  | ||||||
| 		n = await NoteWatching.findOne({ |  | ||||||
| 			_id: noteWatching |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof noteWatching === 'string') { |  | ||||||
| 		n = await NoteWatching.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(noteWatching) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		n = noteWatching as INoteWatching; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (n == null) return; |  | ||||||
|  |  | ||||||
| 	// このNoteWatchingを削除 |  | ||||||
| 	await NoteWatching.remove({ |  | ||||||
| 		_id: n._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -6,14 +6,12 @@ import isObjectId from '../misc/is-objectid'; | |||||||
| import { length } from 'stringz'; | import { length } from 'stringz'; | ||||||
| import { IUser, pack as packUser } from './user'; | import { IUser, pack as packUser } from './user'; | ||||||
| import { pack as packApp } from './app'; | import { pack as packApp } from './app'; | ||||||
| import PollVote, { deletePollVote } from './poll-vote'; | import PollVote from './poll-vote'; | ||||||
| import Reaction, { deleteNoteReaction } 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 NoteWatching, { deleteNoteWatching } from './note-watching'; | import Favorite from './favorite'; | ||||||
| import NoteReaction from './note-reaction'; |  | ||||||
| import Favorite, { deleteFavorite } from './favorite'; |  | ||||||
| import Notification, { deleteNotification } from './notification'; |  | ||||||
| import Following from './following'; | import Following from './following'; | ||||||
|  | import config from '../config'; | ||||||
|  |  | ||||||
| const Note = db.get<INote>('notes'); | const Note = db.get<INote>('notes'); | ||||||
| Note.createIndex('uri', { sparse: true, unique: true }); | Note.createIndex('uri', { sparse: true, unique: true }); | ||||||
| @@ -21,15 +19,15 @@ Note.createIndex('userId'); | |||||||
| Note.createIndex('mentions'); | Note.createIndex('mentions'); | ||||||
| Note.createIndex('visibleUserIds'); | Note.createIndex('visibleUserIds'); | ||||||
| Note.createIndex('tagsLower'); | Note.createIndex('tagsLower'); | ||||||
|  | Note.createIndex('_user.host'); | ||||||
| Note.createIndex('_files._id'); | Note.createIndex('_files._id'); | ||||||
| Note.createIndex('_files.contentType'); | Note.createIndex('_files.contentType'); | ||||||
| Note.createIndex({ | Note.createIndex({ createdAt: -1 }); | ||||||
| 	createdAt: -1 | Note.createIndex({ score: -1 }, { sparse: true }); | ||||||
| }); |  | ||||||
| export default Note; | export default Note; | ||||||
|  |  | ||||||
| export function isValidText(text: string): boolean { | export function isValidText(text: string): boolean { | ||||||
| 	return length(text.trim()) <= 1000 && text.trim() != ''; | 	return length(text.trim()) <= config.maxNoteTextLength && text.trim() != ''; | ||||||
| } | } | ||||||
|  |  | ||||||
| export function isValidCw(text: string): boolean { | export function isValidCw(text: string): boolean { | ||||||
| @@ -84,8 +82,14 @@ export type INote = { | |||||||
| 		heading: number; | 		heading: number; | ||||||
| 		speed: number; | 		speed: number; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	uri: string; | 	uri: string; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * 人気の投稿度合いを表すスコア | ||||||
|  | 	 */ | ||||||
|  | 	score: number; | ||||||
|  |  | ||||||
| 	// 非正規化 | 	// 非正規化 | ||||||
| 	_reply?: { | 	_reply?: { | ||||||
| 		userId: mongo.ObjectID; | 		userId: mongo.ObjectID; | ||||||
| @@ -101,72 +105,6 @@ export type INote = { | |||||||
| 	_files?: IDriveFile[]; | 	_files?: IDriveFile[]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Noteを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteNote(note: string | mongo.ObjectID | INote) { |  | ||||||
| 	let n: INote; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(note)) { |  | ||||||
| 		n = await Note.findOne({ |  | ||||||
| 			_id: note |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof note === 'string') { |  | ||||||
| 		n = await Note.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(note) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		n = note as INote; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	console.log(n == null ? `Note: delete skipped ${note}` : `Note: deleting ${n._id}`); |  | ||||||
|  |  | ||||||
| 	if (n == null) return; |  | ||||||
|  |  | ||||||
| 	// このNoteへの返信をすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await Note.find({ replyId: n._id }) |  | ||||||
| 	).map(x => deleteNote(x))); |  | ||||||
|  |  | ||||||
| 	// このNoteのRenoteをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await Note.find({ renoteId: n._id }) |  | ||||||
| 	).map(x => deleteNote(x))); |  | ||||||
|  |  | ||||||
| 	// この投稿に対するNoteWatchingをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await NoteWatching.find({ noteId: n._id }) |  | ||||||
| 	).map(x => deleteNoteWatching(x))); |  | ||||||
|  |  | ||||||
| 	// この投稿に対するNoteReactionをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await NoteReaction.find({ noteId: n._id }) |  | ||||||
| 	).map(x => deleteNoteReaction(x))); |  | ||||||
|  |  | ||||||
| 	// この投稿に対するPollVoteをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await PollVote.find({ noteId: n._id }) |  | ||||||
| 	).map(x => deletePollVote(x))); |  | ||||||
|  |  | ||||||
| 	// この投稿に対するFavoriteをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await Favorite.find({ noteId: n._id }) |  | ||||||
| 	).map(x => deleteFavorite(x))); |  | ||||||
|  |  | ||||||
| 	// この投稿に対するNotificationをすべて削除 |  | ||||||
| 	await Promise.all(( |  | ||||||
| 		await Notification.find({ noteId: n._id }) |  | ||||||
| 	).map(x => deleteNotification(x))); |  | ||||||
|  |  | ||||||
| 	// このNoteを削除 |  | ||||||
| 	await Note.remove({ |  | ||||||
| 		_id: n._id |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	console.log(`Note: deleted ${n._id}`); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const hideNote = async (packedNote: any, meId: mongo.ObjectID) => { | export const hideNote = async (packedNote: any, meId: mongo.ObjectID) => { | ||||||
| 	let hide = false; | 	let hide = false; | ||||||
|  |  | ||||||
| @@ -226,7 +164,7 @@ export const hideNote = async (packedNote: any, meId: mongo.ObjectID) => { | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export const packMany = async ( | export const packMany = ( | ||||||
| 	notes: (string | mongo.ObjectID | INote)[], | 	notes: (string | mongo.ObjectID | INote)[], | ||||||
| 	me?: string | mongo.ObjectID | IUser, | 	me?: string | mongo.ObjectID | IUser, | ||||||
| 	options?: { | 	options?: { | ||||||
| @@ -234,7 +172,7 @@ export const packMany = async ( | |||||||
| 		skipHide?: boolean; | 		skipHide?: boolean; | ||||||
| 	} | 	} | ||||||
| ) => { | ) => { | ||||||
| 	return (await Promise.all(notes.map(n => pack(n, me, options)))).filter(x => x != null); | 	return Promise.all(notes.map(n => pack(n, me, options))); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -297,6 +235,7 @@ export const pack = async ( | |||||||
| 	delete _note.prev; | 	delete _note.prev; | ||||||
| 	delete _note.next; | 	delete _note.next; | ||||||
| 	delete _note.tagsLower; | 	delete _note.tagsLower; | ||||||
|  | 	delete _note.score; | ||||||
| 	delete _note._user; | 	delete _note._user; | ||||||
| 	delete _note._reply; | 	delete _note._reply; | ||||||
| 	delete _note._renote; | 	delete _note._renote; | ||||||
| @@ -320,11 +259,6 @@ export const pack = async ( | |||||||
|  |  | ||||||
| 	// When requested a detailed note data | 	// When requested a detailed note data | ||||||
| 	if (opts.detail) { | 	if (opts.detail) { | ||||||
| 		//#region 重いので廃止 |  | ||||||
| 		_note.prev = null; |  | ||||||
| 		_note.next = null; |  | ||||||
| 		//#endregion |  | ||||||
|  |  | ||||||
| 		if (_note.replyId) { | 		if (_note.replyId) { | ||||||
| 			// Populate reply to note | 			// Populate reply to note | ||||||
| 			_note.reply = pack(_note.replyId, meId, { | 			_note.reply = pack(_note.replyId, meId, { | ||||||
|   | |||||||
| @@ -51,37 +51,10 @@ export interface INotification { | |||||||
| 	isRead: Boolean; | 	isRead: Boolean; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | export const packMany = ( | ||||||
|  * Notificationを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deleteNotification(notification: string | mongo.ObjectID | INotification) { |  | ||||||
| 	let n: INotification; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(notification)) { |  | ||||||
| 		n = await Notification.findOne({ |  | ||||||
| 			_id: notification |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof notification === 'string') { |  | ||||||
| 		n = await Notification.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(notification) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		n = notification as INotification; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (n == null) return; |  | ||||||
|  |  | ||||||
| 	// このNotificationを削除 |  | ||||||
| 	await Notification.remove({ |  | ||||||
| 		_id: n._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const packMany = async ( |  | ||||||
| 	notifications: any[] | 	notifications: any[] | ||||||
| ) => { | ) => { | ||||||
| 	return (await Promise.all(notifications.map(n => pack(n)))).filter(x => x != null); | 	return Promise.all(notifications.map(n => pack(n))); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| import * as mongo from 'mongodb'; | import * as mongo from 'mongodb'; | ||||||
| import db from '../db/mongodb'; | import db from '../db/mongodb'; | ||||||
| import isObjectId from '../misc/is-objectid'; |  | ||||||
|  |  | ||||||
| const PollVote = db.get<IPollVote>('pollVotes'); | const PollVote = db.get<IPollVote>('pollVotes'); | ||||||
| export default PollVote; | export default PollVote; | ||||||
| @@ -12,30 +11,3 @@ export interface IPollVote { | |||||||
| 	noteId: mongo.ObjectID; | 	noteId: mongo.ObjectID; | ||||||
| 	choice: number; | 	choice: number; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * PollVoteを物理削除します |  | ||||||
|  */ |  | ||||||
| export async function deletePollVote(pollVote: string | mongo.ObjectID | IPollVote) { |  | ||||||
| 	let p: IPollVote; |  | ||||||
|  |  | ||||||
| 	// Populate |  | ||||||
| 	if (isObjectId(pollVote)) { |  | ||||||
| 		p = await PollVote.findOne({ |  | ||||||
| 			_id: pollVote |  | ||||||
| 		}); |  | ||||||
| 	} else if (typeof pollVote === 'string') { |  | ||||||
| 		p = await PollVote.findOne({ |  | ||||||
| 			_id: new mongo.ObjectID(pollVote) |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		p = pollVote as IPollVote; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (p == null) return; |  | ||||||
|  |  | ||||||
| 	// このPollVoteを削除 |  | ||||||
| 	await PollVote.remove({ |  | ||||||
| 		_id: p._id |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user