Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
12c624fa58 | |||
97c4758de2 | |||
f20c08f0f7 | |||
1641d6bce2 | |||
f5d2cb5c61 | |||
26941f62c6 | |||
06461bb9ee | |||
9f4624283d | |||
d4b696d03a | |||
219fdecc50 | |||
7af9ad9869 | |||
a858dd4453 | |||
f47377d181 | |||
bc197bc958 | |||
1836dd7312 | |||
b844a8e9d5 | |||
a4ed163b62 | |||
f40e1ff0cc | |||
d261fdbbc0 | |||
6b0a42af27 | |||
107d9fd2c8 | |||
4116b9eaf2 | |||
ecd71ef5ff | |||
058602352c | |||
59c39fab13 |
@ -67,3 +67,15 @@ web-push generate-vapid-keys
|
|||||||
1. `git reset --hard && git pull origin master`
|
1. `git reset --hard && git pull origin master`
|
||||||
2. `npm install`
|
2. `npm install`
|
||||||
3. `npm run build`
|
3. `npm run build`
|
||||||
|
|
||||||
|
## メモリが足りなくてビルドできない場合
|
||||||
|
Misskeyの(クライアントの)ビルドには、目安として8GBくらいのメモリを必要とします。
|
||||||
|
VPSなどでビルドする時は、もしかしたらメモリが足りなくなる可能性があります。
|
||||||
|
そうなった場合、もしVPSではなくあなたのPCが十分なメモリを搭載しているなら、あなたのPC上でビルドし、生成されたファイルをVPSにFTPでアップロードする方法を採ることができます。
|
||||||
|
|
||||||
|
1. あなたのPC上にMisskeyをインストールする
|
||||||
|
2. 設定ファイルを用意する。設定ファイルは、サーバーに合わせた設定にします。
|
||||||
|
3. npm run webpack
|
||||||
|
4. built/client をサーバーにアップロードする
|
||||||
|
5. サーバー上で、npm run gulp
|
||||||
|
6. 完了
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "2.5.0",
|
"version": "2.6.2",
|
||||||
"clientVersion": "1.0.5241",
|
"clientVersion": "1.0.5260",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -45,7 +45,7 @@ export default Vue.extend({
|
|||||||
} else if (url.hostname == 'youtu.be') {
|
} else if (url.hostname == 'youtu.be') {
|
||||||
this.youtubeId = url.pathname;
|
this.youtubeId = url.pathname;
|
||||||
} else {
|
} else {
|
||||||
fetch('/url?url=' + this.url).then(res => {
|
fetch('/url?url=' + encodeURIComponent(this.url)).then(res => {
|
||||||
res.json().then(info => {
|
res.json().then(info => {
|
||||||
this.title = info.title;
|
this.title = info.title;
|
||||||
this.description = info.description;
|
this.description = info.description;
|
||||||
|
@ -62,7 +62,7 @@ export default Vue.extend({
|
|||||||
more() {
|
more() {
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
(this as any).api('notes/list-timeline', {
|
(this as any).api('notes/user-list-timeline', {
|
||||||
listId: this.list.id,
|
listId: this.list.id,
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilId: (this.$refs.timeline as any).tail().id,
|
untilId: (this.$refs.timeline as any).tail().id,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<mk-ui>
|
<mk-ui>
|
||||||
<main v-if="!fetching">
|
<main v-if="!fetching">
|
||||||
<a v-if="note.next" :href="note.next">%fa:angle-up%%i18n:@next%</a>
|
|
||||||
<mk-note-detail :note="note"/>
|
<mk-note-detail :note="note"/>
|
||||||
<a v-if="note.prev" :href="note.prev">%fa:angle-down%%i18n:@prev%</a>
|
<footer>
|
||||||
|
<router-link v-if="note.next" :to="note.next">%fa:angle-left% %i18n:@next%</router-link>
|
||||||
|
<router-link v-if="note.prev" :to="note.prev">%i18n:@prev% %fa:angle-right%</router-link>
|
||||||
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
</template>
|
</template>
|
||||||
@ -48,17 +50,12 @@ main
|
|||||||
padding 16px
|
padding 16px
|
||||||
text-align center
|
text-align center
|
||||||
|
|
||||||
> a
|
> footer
|
||||||
display inline-block
|
margin-top 16px
|
||||||
|
|
||||||
&:first-child
|
> a
|
||||||
margin-bottom 4px
|
display inline-block
|
||||||
|
margin 0 16px
|
||||||
&:last-child
|
|
||||||
margin-top 4px
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
> .mk-note-detail
|
> .mk-note-detail
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
@ -62,7 +62,7 @@ export default Vue.extend({
|
|||||||
more() {
|
more() {
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
(this as any).api('notes/list-timeline', {
|
(this as any).api('notes/user-list-timeline', {
|
||||||
listId: this.list.id,
|
listId: this.list.id,
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilId: (this.$refs.timeline as any).tail().id,
|
untilId: (this.$refs.timeline as any).tail().id,
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<mk-note-detail :note="note"/>
|
<mk-note-detail :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<a v-if="note.prev" :href="note.prev">%fa:angle-left% %i18n:@prev%</a>
|
<router-link v-if="note.prev" :to="note.prev">%fa:angle-left% %i18n:@prev%</router-link>
|
||||||
<a v-if="note.next" :href="note.next">%i18n:@next% %fa:angle-right%</a>
|
<router-link v-if="note.next" :to="note.next">%i18n:@next% %fa:angle-right%</router-link>
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
|
@ -9,6 +9,7 @@ import User from './user';
|
|||||||
import DriveFileThumbnail, { deleteDriveFileThumbnail } from './drive-file-thumbnail';
|
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('metadata.uri', { sparse: true, unique: true });
|
DriveFile.createIndex('metadata.uri', { sparse: true, unique: true });
|
||||||
export default DriveFile;
|
export default DriveFile;
|
||||||
|
|
||||||
|
@ -15,9 +15,8 @@ import Notification, { deleteNotification } from './notification';
|
|||||||
import Following from './following';
|
import Following from './following';
|
||||||
|
|
||||||
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 });
|
||||||
|
Note.createIndex('userId');
|
||||||
export default Note;
|
export default Note;
|
||||||
|
|
||||||
export function isValidText(text: string): boolean {
|
export function isValidText(text: string): boolean {
|
||||||
@ -271,41 +270,10 @@ export const pack = async (
|
|||||||
|
|
||||||
// When requested a detailed note data
|
// When requested a detailed note data
|
||||||
if (opts.detail) {
|
if (opts.detail) {
|
||||||
// Get previous note info
|
//#region 重いので廃止
|
||||||
_note.prev = (async () => {
|
_note.prev = null;
|
||||||
const prev = await Note.findOne({
|
_note.next = null;
|
||||||
userId: _note.userId,
|
//#endregion
|
||||||
_id: {
|
|
||||||
$lt: id
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
fields: {
|
|
||||||
_id: true
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
_id: -1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return prev ? prev._id.toHexString() : null;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Get next note info
|
|
||||||
_note.next = (async () => {
|
|
||||||
const next = await Note.findOne({
|
|
||||||
userId: _note.userId,
|
|
||||||
_id: {
|
|
||||||
$gt: id
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
fields: {
|
|
||||||
_id: true
|
|
||||||
},
|
|
||||||
sort: {
|
|
||||||
_id: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return next ? next._id.toHexString() : null;
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (_note.replyId) {
|
if (_note.replyId) {
|
||||||
// Populate reply to note
|
// Populate reply to note
|
||||||
|
@ -14,7 +14,7 @@ export default async (job: kue.Job, done): Promise<void> => {
|
|||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
console.warn(`deliver failed: ${res.statusMessage}`);
|
console.warn(`deliver failed: ${res.statusMessage}`);
|
||||||
done(new Error(res.statusMessage));
|
done(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -43,27 +43,21 @@ function parse(html: string): string {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
const cls = node.attrs
|
const txt = getText(node);
|
||||||
? (node.attrs.find(x => x.name == 'class') || { value: '' }).value.split(' ')
|
|
||||||
: [];
|
|
||||||
|
|
||||||
// for Mastodon
|
// メンション
|
||||||
if (cls.includes('mention')) {
|
if (txt.startsWith('@')) {
|
||||||
const mention = getText(node);
|
const part = txt.split('@');
|
||||||
|
|
||||||
const part = mention.split('@');
|
|
||||||
|
|
||||||
if (part.length == 2) {
|
if (part.length == 2) {
|
||||||
//#region ホスト名部分が省略されているので復元する
|
//#region ホスト名部分が省略されているので復元する
|
||||||
|
|
||||||
const href = new URL(node.attrs.find(x => x.name == 'href').value);
|
const href = new URL(node.attrs.find(x => x.name == 'href').value);
|
||||||
const acct = mention + '@' + href.hostname;
|
const acct = txt + '@' + href.hostname;
|
||||||
text += acct;
|
text += acct;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
} else if (part.length == 3) {
|
} else if (part.length == 3) {
|
||||||
text += mention;
|
text += txt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ export default (
|
|||||||
.count({
|
.count({
|
||||||
recipientId: userId,
|
recipientId: userId,
|
||||||
isRead: false
|
isRead: false
|
||||||
|
}, {
|
||||||
|
limit: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
|
@ -43,6 +43,8 @@ export default (
|
|||||||
.count({
|
.count({
|
||||||
notifieeId: userId,
|
notifieeId: userId,
|
||||||
isRead: false
|
isRead: false
|
||||||
|
}, {
|
||||||
|
limit: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
|
@ -38,12 +38,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
|||||||
if (pollErr) return rej('invalid poll param');
|
if (pollErr) return rej('invalid poll param');
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
createdAt: {
|
_id: { $gte: new Date(Date.now() - ms('1days')) },
|
||||||
$gte: new Date(Date.now() - ms('1days'))
|
renoteCount: { $gt: 0 },
|
||||||
},
|
'_user.host': null
|
||||||
renoteCount: {
|
|
||||||
$gt: 0
|
|
||||||
}
|
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
if (reply != undefined) {
|
if (reply != undefined) {
|
||||||
|
@ -1,48 +1,26 @@
|
|||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
import Note from '../../../models/note';
|
import Note from '../../../models/note';
|
||||||
import User from '../../../models/user';
|
import User from '../../../models/user';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* Get the misskey's statistics
|
||||||
* /stats:
|
|
||||||
* note:
|
|
||||||
* summary: Show the misskey's statistics
|
|
||||||
* responses:
|
|
||||||
* 200:
|
|
||||||
* description: Success
|
|
||||||
* schema:
|
|
||||||
* type: object
|
|
||||||
* properties:
|
|
||||||
* notesCount:
|
|
||||||
* description: count of all notes of misskey
|
|
||||||
* type: number
|
|
||||||
* usersCount:
|
|
||||||
* description: count of all users of misskey
|
|
||||||
* type: number
|
|
||||||
*
|
|
||||||
* default:
|
|
||||||
* description: Failed
|
|
||||||
* schema:
|
|
||||||
* $ref: "#/definitions/Error"
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the misskey's statistics
|
|
||||||
*
|
|
||||||
* @param {any} params
|
|
||||||
* @return {Promise<any>}
|
|
||||||
*/
|
*/
|
||||||
module.exports = params => new Promise(async (res, rej) => {
|
module.exports = params => new Promise(async (res, rej) => {
|
||||||
const notesCount = await Note
|
const notesCount = await Note.count();
|
||||||
.count();
|
|
||||||
|
|
||||||
const usersCount = await User
|
const usersCount = await User.count();
|
||||||
.count();
|
|
||||||
|
const originalNotesCount = await Note.count({
|
||||||
|
'_user.host': null
|
||||||
|
});
|
||||||
|
|
||||||
|
const originalUsersCount = await User.count({
|
||||||
|
host: null
|
||||||
|
});
|
||||||
|
|
||||||
res({
|
res({
|
||||||
notesCount: notesCount,
|
notesCount,
|
||||||
usersCount: usersCount
|
usersCount,
|
||||||
|
originalNotesCount,
|
||||||
|
originalUsersCount
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -87,7 +87,7 @@ router.get('/url', require('./url-preview'));
|
|||||||
|
|
||||||
//#region for crawlers
|
//#region for crawlers
|
||||||
// User
|
// User
|
||||||
router.get('/@:user', async ctx => {
|
router.get('/@:user', async (ctx, next) => {
|
||||||
const { username, host } = parseAcct(ctx.params.user);
|
const { username, host } = parseAcct(ctx.params.user);
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
usernameLower: username.toLowerCase(),
|
usernameLower: username.toLowerCase(),
|
||||||
@ -97,7 +97,8 @@ router.get('/@:user', async ctx => {
|
|||||||
if (user != null) {
|
if (user != null) {
|
||||||
await ctx.render('user', { user });
|
await ctx.render('user', { user });
|
||||||
} else {
|
} else {
|
||||||
ctx.status = 404;
|
// リモートユーザーなので
|
||||||
|
await next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ module.exports = async (ctx: Koa.Context) => {
|
|||||||
|
|
||||||
function wrap(url: string): string {
|
function wrap(url: string): string {
|
||||||
return url != null
|
return url != null
|
||||||
? url.startsWith('https://')
|
? url.startsWith('https://') || url.startsWith('data:')
|
||||||
? url
|
? url
|
||||||
: `https://images.weserv.nl/?url=${url.replace(/^http:\/\//, '')}`
|
: `https://images.weserv.nl/?url=${encodeURIComponent(url.replace(/^http:\/\//, ''))}`
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,8 @@ const addFile = async (
|
|||||||
// Check if there is a file with the same hash
|
// Check if there is a file with the same hash
|
||||||
const much = await DriveFile.findOne({
|
const much = await DriveFile.findOne({
|
||||||
md5: hash,
|
md5: hash,
|
||||||
'metadata.userId': user._id
|
'metadata.userId': user._id,
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (much !== null) {
|
if (much !== null) {
|
||||||
|
@ -392,14 +392,17 @@ export default async (user: IUser, data: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region TODO: これ重い
|
||||||
// 今までで同じ投稿をRenoteしているか
|
// 今までで同じ投稿をRenoteしているか
|
||||||
const existRenote = await Note.findOne({
|
//const existRenote = await Note.findOne({
|
||||||
userId: user._id,
|
// userId: user._id,
|
||||||
renoteId: data.renote._id,
|
// renoteId: data.renote._id,
|
||||||
_id: {
|
// _id: {
|
||||||
$ne: note._id
|
// $ne: note._id
|
||||||
}
|
// }
|
||||||
});
|
//});
|
||||||
|
const existRenote = null;
|
||||||
|
//#endregion
|
||||||
|
|
||||||
if (!existRenote) {
|
if (!existRenote) {
|
||||||
// Update renoteee status
|
// Update renoteee status
|
||||||
|
Reference in New Issue
Block a user