diff --git a/locales/es.yml b/locales/es.yml index 21a36c6a4f..eb039df696 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -39,7 +39,7 @@ common: weeks_ago: "Hace {} semana(s)" months_ago: "Hace {} mes(es)" years_ago: "Hace {} año(s)" - month-and-day: "{month}月 {day}日" + month-and-day: "{day} de {month}" trash: "Papelera" weekday-short: sunday: "domingo" @@ -235,13 +235,13 @@ common/views/components/messaging-room.vue: no-history: "El historial se ha acabado" resize-form: "Arrastra para redimensionar" new-message: "Nuevo mensaje" - only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです" + only-one-file-attached: "Un único archivo se puede conectar al mensaje" common/views/components/messaging-room.form.vue: input-message-here: "Escribe el mensaje aquí" send: "Enviar" attach-from-local: "Adjunta ficheros desde tu PC" attach-from-drive: "Adjunta ficheros desde tu disco" - only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです" + only-one-file-attached: "Un único archivo se puede conectar al mensaje" common/views/components/messaging-room.message.vue: is-read: "Leer" deleted: "El mensaje se ha borrado" @@ -378,56 +378,56 @@ common/views/widgets/tips.vue: tips-line10: "Usando el accesorio de Máquina del Tiempo puedes encontrar publicaciones antiguas" tips-line11: "Puedes resaltar publicaciones en la página de usuario haciendo click en \"...\"" tips-line13: "Todos los archivos añadidos a la publicación se han guardado en tu unidad." - tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます" - tips-line17: "「**」でテキストを囲むと**強調表示**されます" - tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができます" - tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています" - tips-line21: "APIを利用してbotの開発なども行えます" - tips-line23: "まゆかわいいよまゆ" - tips-line24: "Misskeyは2014年にサービスを開始しました" - tips-line25: "対応ブラウザではMisskeyを開いていなくても通知を受け取れます" + tips-line14: "Cuando personalizas el inicio puedas dar click derecho a un accesorio y cambiar el diseño." + tips-line17: "Al colocar ** delante y luego del texto, lo estarás destacando en negrillas" + tips-line19: "Algunas ventanas pueden ser separadas fuera del navegador" + tips-line20: "El porcentaje mostrando en el accesorio de calendario indica el porcentaje de tiempo transcurrido." + tips-line21: "También puedes usar la API para desarrollar tus propios bots." + tips-line23: "Mayu is tan bonito con sus cejas." + tips-line24: "Misskey inició en 2014." + tips-line25: "Puedes recibir notificaciones incluso si Misskey no está abierto en un navegador compatible." common/views/pages/follow.vue: - signed-in-as: "{}としてサインイン中" - following: "フォロー中" - follow: "フォロー" - request-pending: "フォロー許可待ち" - follow-request: "フォロー申請" + signed-in-as: "Autenticado como {}" + following: "Siguiendo" + follow: "Seguir" + request-pending: "Solicitud pendiente" + follow-request: "Solicitar suscripción" desktop: - banner-crop-title: "バナーとして表示する部分を選択" - banner: "バナー" - uploading-banner: "新しいバナーをアップロードしています" - banner-updated: "バナーを更新しました" - choose-banner: "バナーにする画像を選択" - avatar-crop-title: "アバターとして表示する部分を選択" - avatar: "アバター" - uploading-avatar: "新しいアバターをアップロードしています" - avatar-updated: "アバターを更新しました" - choose-avatar: "アバターにする画像を選択" + banner-crop-title: "Corta la parte que aparece como un banner" + banner: "Banner" + uploading-banner: "Cargando un nuevo banner" + banner-updated: "Banner actualizado" + choose-banner: "Escoge un banner" + avatar-crop-title: "Corta la parte que aparece como un avatar" + avatar: "Avatar" + uploading-avatar: "Cargando un nuevo avatar" + avatar-updated: "Avatar actualizado" + choose-avatar: "Escoge una imagen de avatar" desktop/views/components/activity.chart.vue: - total: "Black ... Total" - notes: "Blue ... Notes" - replies: "Red ... Replies" - renotes: "Green ... Renotes" + total: "Negro ... Total" + notes: "Azul ... Notas" + replies: "Rojo ... Respuestas" + renotes: "Verde ... Republicaciones" desktop/views/components/activity.vue: - title: "アクティビティ" - toggle: "表示を切り替え" + title: "Actividad" + toggle: "Alternar vistas" desktop/views/components/calendar.vue: - title: "{1}年 {2}月" - prev: "前の月" - next: "次の月" - go: "クリックして時間遡行" + title: "{1} / {2}" + prev: "Mes anterior" + next: "Próximo mes" + go: "Click para navegar" desktop/views/components/choose-file-from-drive-window.vue: - choose-file: "ファイル選択中" - upload: "PCからドライブにファイルをアップロード" - cancel: "キャンセル" - ok: "決定" - choose-prompt: "ファイルを選択" + choose-file: "Escoger archivos" + upload: "Cargar archivos de tu dispositivo" + cancel: "Cancelar" + ok: "OK" + choose-prompt: "Escoger archivos" desktop/views/components/choose-folder-from-drive-window.vue: - cancel: "キャンセル" - ok: "決定" + cancel: "Cancelar" + ok: "OK" choose-prompt: "Escoge una Carpeta" desktop/views/components/crop-window.vue: - skip: "クロップをスキップ" + skip: "Ignorar el cortado" cancel: "Cancelar" ok: "OK" desktop/views/components/drive-window.vue: @@ -438,8 +438,8 @@ desktop/views/components/drive.file.vue: banner: "Banner" contextmenu: rename: "Renombrar" - mark-as-sensitive: "閲覧注意に設定" - unmark-as-sensitive: "閲覧注意を解除" + mark-as-sensitive: "Marcar como 'sensible'" + unmark-as-sensitive: "Desmarcar como 'sensible'" copy-url: "Copia la URL" download: "Descargar" else-files: "Otros" @@ -484,8 +484,8 @@ desktop/views/components/drive.vue: upload: "Subir fichero" url-upload: "Subir desde una URL" desktop/views/components/media-image.vue: - sensitive: "閲覧注意" - click-to-show: "クリックして表示" + sensitive: "El contenido es NSFW (no seguro para ver en el trabajo, 'not safe for work')" + click-to-show: "Click para mostrar" desktop/views/components/media-video.vue: sensitive: "閲覧注意" click-to-show: "クリックして表示" @@ -652,26 +652,26 @@ desktop/views/components/settings.vue: version: "バージョン:" latest-version: "最新のバージョン:" update-checking: "アップデートを確認中" - do-update: "アップデートを確認" - update-settings: "詳細設定" - prevent-update: "アップデートを延期する(非推奨)" - prevent-update-desc: "この設定をオンにしてもアップデートが反映される場合があります。この設定はこのデバイスのみ有効です。" - no-updates: "利用可能な更新はありません" - no-updates-desc: "お使いのMisskeyは最新です。" - update-available: "新しいバージョンが利用可能です" - update-available-desc: "ページを再度読み込みすると更新が適用されます。" - advanced-settings: "高度な設定" - debug-mode: "デバッグモードを有効にする" - debug-mode-desc: "この設定はブラウザに記憶されます。" - experimental: "実験的機能を有効にする" - experimental-desc: "実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。" - tools: "ツール" - task-manager: "タスクマネージャ" - third-parties: "サードパーティ" + do-update: "Chequear por actualizaciones" + update-settings: "Configuración avanzada" + prevent-update: "Posponer actualizaciones (no recomendado)" + prevent-update-desc: "Incluso si activas esta configuración, algunas actualizaciones podrían aplicarse. Esta configuración está habilitada sólo para este dispositivo." + no-updates: "No hay actualizaciones disponibles" + no-updates-desc: "Tu Misskey está actualizado" + update-available: "Una nueva versión está disponible" + update-available-desc: "Las actualizaciones se aplicarán cuando actualices la página nuevamente." + advanced-settings: "Avanzado" + debug-mode: "Habilitar modo de depuración" + debug-mode-desc: "Esta configuración se ha guardado en el navegador." + experimental: "Habilitar herramientas experimentales" + experimental-desc: "Activar esto puede hacer que tu cliente de Misskey se vuelva inestable. La configuración se ha guardado en el navegador." + tools: "Herramientas" + task-manager: "Navegador de tareas" + third-parties: "Servicios externos" desktop/views/components/settings.2fa.vue: intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。" - detail: "詳細..." - url: "https://www.google.co.jp/intl/ja/landing/2step/" + detail: "Ver detalles..." + url: "https://www.google.com/landing/2step/" caution: "Si pierdes acceso al dispositivo, no podrás conectarte a Misskey." register: "Registrar un dispositivo" already-registered: "Un dispositivo ya fue registrado" @@ -704,19 +704,19 @@ desktop/views/components/settings.password.vue: reset: "Cambiar contraseña" enter-current-password: "Ingresar contraseña actual" enter-new-password: "Ingresar nueva contraseña" - enter-new-password-again: "もう一度新しいパスワードを入力してください" - not-match: "新しいパスワードが一致しません" - changed: "パスワードを変更しました" + enter-new-password-again: "Ingresar nueva contraseña de nuevo" + not-match: "Las nuevas contraseñas no se corresponden consigo mismas" + changed: "Contraseña actualizada" desktop/views/components/settings.profile.vue: - avatar: "アイコン" - choice-avatar: "画像を選択" - name: "名前" - location: "場所" - description: "自己紹介" - birthday: "誕生日" - save: "保存" - locked-account: "アカウントの保護" - is-locked: "投稿を非公開にする" + avatar: "Avatar" + choice-avatar: "Escoger una imagen" + name: "Nombre" + location: "Localización" + description: "Descripción" + birthday: "Fecha de nacimiento" + save: "Perfil actualizado" + locked-account: "Protege tu cuenta" + is-locked: "Crear una nota privada" other: "その他" is-bot: "このアカウントはBotです" is-cat: "このアカウントはCatです" diff --git a/package.json b/package.json index 5fdfe57c5e..f7cd4fed3b 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "misskey", "author": "syuilo ", - "version": "5.20.0", - "clientVersion": "1.0.8099", + "version": "5.21.0", + "clientVersion": "1.0.8117", "codename": "nighthike", "main": "./built/index.js", "private": true, @@ -59,7 +59,7 @@ "@types/mocha": "5.2.3", "@types/mongodb": "3.1.3", "@types/ms": "0.7.30", - "@types/node": "10.5.7", + "@types/node": "10.5.8", "@types/portscanner": "2.1.0", "@types/pug": "2.0.4", "@types/qrcode": "1.2.0", @@ -98,7 +98,7 @@ "diskusage": "0.2.4", "dompurify": "1.0.5", "elasticsearch": "15.1.1", - "element-ui": "2.4.5", + "element-ui": "2.4.6", "emojilib": "2.3.0", "escape-regexp": "0.0.1", "eslint": "5.0.1", @@ -106,7 +106,7 @@ "eventemitter3": "3.1.0", "exif-js": "2.3.0", "file-loader": "1.1.11", - "file-type": "8.1.0", + "file-type": "9.0.0", "fuckadblock": "3.2.1", "gulp": "3.9.1", "gulp-cssnano": "2.1.3", @@ -154,7 +154,7 @@ "monk": "6.0.6", "ms": "2.1.1", "nan": "2.10.0", - "node-sass": "4.9.2", + "node-sass": "4.9.3", "node-sass-json-importer": "3.3.1", "nprogress": "0.2.0", "object-assign-deep": "0.4.0", @@ -171,7 +171,7 @@ "recaptcha-promise": "0.1.3", "reconnecting-websocket": "3.2.2", "redis": "2.8.0", - "request": "2.87.0", + "request": "2.88.0", "request-promise-native": "1.0.5", "rimraf": "2.6.2", "rndstr": "1.0.0", @@ -187,7 +187,7 @@ "style-loader": "0.22.1", "stylus": "0.54.5", "stylus-loader": "3.0.2", - "summaly": "2.0.6", + "summaly": "2.1.2", "systeminformation": "3.42.9", "syuilo-password-strength": "0.0.1", "textarea-caret": "3.1.0", diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue index a924b62e64..6685296c16 100644 --- a/src/client/app/common/views/components/avatar.vue +++ b/src/client/app/common/views/components/avatar.vue @@ -1,6 +1,8 @@ diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue index 0cfa76fd80..8ad6a622d0 100644 --- a/src/client/app/common/views/components/url-preview.vue +++ b/src/client/app/common/views/components/url-preview.vue @@ -73,18 +73,19 @@ export default Vue.extend({ twttr.ready = loadTweet; (window as any).twttr = twttr; } - } else { - fetch('/url?url=' + encodeURIComponent(this.url)).then(res => { - res.json().then(info => { + return; + } + fetch('/url?url=' + encodeURIComponent(this.url)).then(res => { + res.json().then(info => { + if (info.url != null) { this.title = info.title; this.description = info.description; this.thumbnail = info.thumbnail; - this.player = info.player; this.icon = info.icon; this.sitename = info.sitename; this.fetching = false; - }); + } }); } } diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue index a01b44fc73..585a23de2d 100644 --- a/src/client/app/desktop/views/pages/welcome.vue +++ b/src/client/app/desktop/views/pages/welcome.vue @@ -18,7 +18,7 @@

{{ name }}

-

%i18n:@powered-by-misskey%

+

📦 %i18n:@signup%
diff --git a/src/client/app/desktop/views/widgets/profile.vue b/src/client/app/desktop/views/widgets/profile.vue index 9702aaa90a..a22607b612 100644 --- a/src/client/app/desktop/views/widgets/profile.vue +++ b/src/client/app/desktop/views/widgets/profile.vue @@ -6,10 +6,11 @@ {{ $store.state.i | userName }} diff --git a/src/docs/api/entities/drive-folder.yaml b/src/docs/api/entities/drive-folder.yaml new file mode 100644 index 0000000000..0fb8308dd4 --- /dev/null +++ b/src/docs/api/entities/drive-folder.yaml @@ -0,0 +1,41 @@ +name: "DriveFolder" + +desc: + ja: "ドライブのフォルダを表します。" + en: "A folder of Drive." + +props: + id: + type: "id" + optional: false + desc: + ja: "フォルダID" + en: "The ID of this folder" + + createdAt: + type: "date" + optional: false + desc: + ja: "作成日時" + en: "The created date of this folder" + + userId: + type: "id(User)" + optional: false + desc: + ja: "所有者ID" + en: "The ID of the owner of this folder" + + parentId: + type: "entity(DriveFolder)" + optional: false + desc: + ja: "親フォルダのID (ルートなら null)" + en: "The ID of parent folder" + + name: + type: "string" + optional: false + desc: + ja: "フォルダ名" + en: "The name of this folder" diff --git a/src/models/drive-file.ts b/src/models/drive-file.ts index 33c0451905..ad5496d7ca 100644 --- a/src/models/drive-file.ts +++ b/src/models/drive-file.ts @@ -10,7 +10,7 @@ import DriveFileThumbnail, { deleteDriveFileThumbnail } from './drive-file-thumb const DriveFile = monkDb.get('driveFiles.files'); DriveFile.createIndex('md5'); -DriveFile.createIndex('metadata.uri', { sparse: true, unique: true }); +DriveFile.createIndex(['metadata.uri', 'metadata.userId'], { sparse: true, unique: true }); export default DriveFile; export const DriveFileChunk = monkDb.get('driveFiles.chunks'); diff --git a/src/queue/processors/http/deliver.ts b/src/queue/processors/http/deliver.ts index 75e46559dd..e14a162105 100644 --- a/src/queue/processors/http/deliver.ts +++ b/src/queue/processors/http/deliver.ts @@ -7,7 +7,7 @@ export default async (job: bq.Job, done: any): Promise => { await request(job.data.user, job.data.to, job.data.content); done(); } catch (res) { - if (!res.hasOwnProperty('statusCode')) { + if (res == null || !res.hasOwnProperty('statusCode')) { console.warn(`deliver failed (unknown): ${res}`); return done(); } diff --git a/src/server/web/url-preview.ts b/src/server/web/url-preview.ts index 99ee2eaebd..e96eb309fe 100644 --- a/src/server/web/url-preview.ts +++ b/src/server/web/url-preview.ts @@ -14,7 +14,9 @@ module.exports = async (ctx: Koa.Context) => { ctx.body = summary; } catch (e) { - ctx.status = 500; + ctx.status = 200; + ctx.set('Cache-Control', 'max-age=86400, immutable'); + ctx.body = '{}'; } }; diff --git a/src/services/drive/add-file.ts b/src/services/drive/add-file.ts index a04bab9dbd..701d547776 100644 --- a/src/services/drive/add-file.ts +++ b/src/services/drive/add-file.ts @@ -294,16 +294,35 @@ export default async function( metadata.uri = uri; } - const driveFile = isLink - ? await DriveFile.insert({ - length: 0, - uploadDate: new Date(), - md5: hash, - filename: detectedName, - metadata: metadata, - contentType: mime - }) - : await (save(fs.createReadStream(path), detectedName, mime, hash, size, metadata)); + let driveFile: IDriveFile; + + if (isLink) { + try { + driveFile = await DriveFile.insert({ + length: 0, + uploadDate: new Date(), + md5: hash, + filename: detectedName, + metadata: metadata, + contentType: mime + }); + } catch (e) { + // duplicate key error (when already registered) + if (e.code === 11000) { + log(`already registered ${metadata.uri}`); + + driveFile = await DriveFile.findOne({ + 'metadata.uri': metadata.uri, + 'metadata.userId': user._id + }); + } else { + console.error(e); + throw e; + } + } + } else { + driveFile = await (save(fs.createReadStream(path), detectedName, mime, hash, size, metadata)); + } log(`drive file has been created ${driveFile._id}`);