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`
|
||||
2. `npm install`
|
||||
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",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "2.5.0",
|
||||
"clientVersion": "1.0.5241",
|
||||
"version": "2.6.2",
|
||||
"clientVersion": "1.0.5260",
|
||||
"codename": "nighthike",
|
||||
"main": "./built/index.js",
|
||||
"private": true,
|
||||
|
@ -45,7 +45,7 @@ export default Vue.extend({
|
||||
} else if (url.hostname == 'youtu.be') {
|
||||
this.youtubeId = url.pathname;
|
||||
} else {
|
||||
fetch('/url?url=' + this.url).then(res => {
|
||||
fetch('/url?url=' + encodeURIComponent(this.url)).then(res => {
|
||||
res.json().then(info => {
|
||||
this.title = info.title;
|
||||
this.description = info.description;
|
||||
|
@ -62,7 +62,7 @@ export default Vue.extend({
|
||||
more() {
|
||||
this.moreFetching = true;
|
||||
|
||||
(this as any).api('notes/list-timeline', {
|
||||
(this as any).api('notes/user-list-timeline', {
|
||||
listId: this.list.id,
|
||||
limit: fetchLimit + 1,
|
||||
untilId: (this.$refs.timeline as any).tail().id,
|
||||
|
@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<mk-ui>
|
||||
<main v-if="!fetching">
|
||||
<a v-if="note.next" :href="note.next">%fa:angle-up%%i18n:@next%</a>
|
||||
<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>
|
||||
</mk-ui>
|
||||
</template>
|
||||
@ -48,17 +50,12 @@ main
|
||||
padding 16px
|
||||
text-align center
|
||||
|
||||
> a
|
||||
display inline-block
|
||||
> footer
|
||||
margin-top 16px
|
||||
|
||||
&:first-child
|
||||
margin-bottom 4px
|
||||
|
||||
&:last-child
|
||||
margin-top 4px
|
||||
|
||||
> [data-fa]
|
||||
margin-right 4px
|
||||
> a
|
||||
display inline-block
|
||||
margin 0 16px
|
||||
|
||||
> .mk-note-detail
|
||||
margin 0 auto
|
||||
|
@ -62,7 +62,7 @@ export default Vue.extend({
|
||||
more() {
|
||||
this.moreFetching = true;
|
||||
|
||||
(this as any).api('notes/list-timeline', {
|
||||
(this as any).api('notes/user-list-timeline', {
|
||||
listId: this.list.id,
|
||||
limit: fetchLimit + 1,
|
||||
untilId: (this.$refs.timeline as any).tail().id,
|
||||
|
@ -6,8 +6,8 @@
|
||||
<mk-note-detail :note="note"/>
|
||||
</div>
|
||||
<footer>
|
||||
<a v-if="note.prev" :href="note.prev">%fa:angle-left% %i18n:@prev%</a>
|
||||
<a v-if="note.next" :href="note.next">%i18n:@next% %fa:angle-right%</a>
|
||||
<router-link v-if="note.prev" :to="note.prev">%fa:angle-left% %i18n:@prev%</router-link>
|
||||
<router-link v-if="note.next" :to="note.next">%i18n:@next% %fa:angle-right%</router-link>
|
||||
</footer>
|
||||
</main>
|
||||
</mk-ui>
|
||||
|
@ -9,6 +9,7 @@ import User from './user';
|
||||
import DriveFileThumbnail, { deleteDriveFileThumbnail } from './drive-file-thumbnail';
|
||||
|
||||
const DriveFile = monkDb.get<IDriveFile>('driveFiles.files');
|
||||
DriveFile.createIndex('md5');
|
||||
DriveFile.createIndex('metadata.uri', { sparse: true, unique: true });
|
||||
export default DriveFile;
|
||||
|
||||
|
@ -15,9 +15,8 @@ import Notification, { deleteNotification } from './notification';
|
||||
import Following from './following';
|
||||
|
||||
const Note = db.get<INote>('notes');
|
||||
|
||||
Note.createIndex('uri', { sparse: true, unique: true });
|
||||
|
||||
Note.createIndex('userId');
|
||||
export default Note;
|
||||
|
||||
export function isValidText(text: string): boolean {
|
||||
@ -271,41 +270,10 @@ export const pack = async (
|
||||
|
||||
// When requested a detailed note data
|
||||
if (opts.detail) {
|
||||
// Get previous note info
|
||||
_note.prev = (async () => {
|
||||
const prev = await Note.findOne({
|
||||
userId: _note.userId,
|
||||
_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;
|
||||
})();
|
||||
//#region 重いので廃止
|
||||
_note.prev = null;
|
||||
_note.next = null;
|
||||
//#endregion
|
||||
|
||||
if (_note.replyId) {
|
||||
// Populate reply to note
|
||||
|
@ -14,7 +14,7 @@ export default async (job: kue.Job, done): Promise<void> => {
|
||||
done();
|
||||
} else {
|
||||
console.warn(`deliver failed: ${res.statusMessage}`);
|
||||
done(new Error(res.statusMessage));
|
||||
done(res);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -43,27 +43,21 @@ function parse(html: string): string {
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
const cls = node.attrs
|
||||
? (node.attrs.find(x => x.name == 'class') || { value: '' }).value.split(' ')
|
||||
: [];
|
||||
const txt = getText(node);
|
||||
|
||||
// for Mastodon
|
||||
if (cls.includes('mention')) {
|
||||
const mention = getText(node);
|
||||
|
||||
const part = mention.split('@');
|
||||
// メンション
|
||||
if (txt.startsWith('@')) {
|
||||
const part = txt.split('@');
|
||||
|
||||
if (part.length == 2) {
|
||||
//#region ホスト名部分が省略されているので復元する
|
||||
|
||||
const href = new URL(node.attrs.find(x => x.name == 'href').value);
|
||||
const acct = mention + '@' + href.hostname;
|
||||
const acct = txt + '@' + href.hostname;
|
||||
text += acct;
|
||||
break;
|
||||
|
||||
//#endregion
|
||||
} else if (part.length == 3) {
|
||||
text += mention;
|
||||
text += txt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,8 @@ export default (
|
||||
.count({
|
||||
recipientId: userId,
|
||||
isRead: false
|
||||
}, {
|
||||
limit: 1
|
||||
});
|
||||
|
||||
if (count == 0) {
|
||||
|
@ -43,6 +43,8 @@ export default (
|
||||
.count({
|
||||
notifieeId: userId,
|
||||
isRead: false
|
||||
}, {
|
||||
limit: 1
|
||||
});
|
||||
|
||||
if (count == 0) {
|
||||
|
@ -38,12 +38,9 @@ module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||
if (pollErr) return rej('invalid poll param');
|
||||
|
||||
const query = {
|
||||
createdAt: {
|
||||
$gte: new Date(Date.now() - ms('1days'))
|
||||
},
|
||||
renoteCount: {
|
||||
$gt: 0
|
||||
}
|
||||
_id: { $gte: new Date(Date.now() - ms('1days')) },
|
||||
renoteCount: { $gt: 0 },
|
||||
'_user.host': null
|
||||
} as any;
|
||||
|
||||
if (reply != undefined) {
|
||||
|
@ -1,48 +1,26 @@
|
||||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
import Note from '../../../models/note';
|
||||
import User from '../../../models/user';
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /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>}
|
||||
* Get the misskey's statistics
|
||||
*/
|
||||
module.exports = params => new Promise(async (res, rej) => {
|
||||
const notesCount = await Note
|
||||
.count();
|
||||
const notesCount = await Note.count();
|
||||
|
||||
const usersCount = await User
|
||||
.count();
|
||||
const usersCount = await User.count();
|
||||
|
||||
const originalNotesCount = await Note.count({
|
||||
'_user.host': null
|
||||
});
|
||||
|
||||
const originalUsersCount = await User.count({
|
||||
host: null
|
||||
});
|
||||
|
||||
res({
|
||||
notesCount: notesCount,
|
||||
usersCount: usersCount
|
||||
notesCount,
|
||||
usersCount,
|
||||
originalNotesCount,
|
||||
originalUsersCount
|
||||
});
|
||||
});
|
||||
|
@ -87,7 +87,7 @@ router.get('/url', require('./url-preview'));
|
||||
|
||||
//#region for crawlers
|
||||
// User
|
||||
router.get('/@:user', async ctx => {
|
||||
router.get('/@:user', async (ctx, next) => {
|
||||
const { username, host } = parseAcct(ctx.params.user);
|
||||
const user = await User.findOne({
|
||||
usernameLower: username.toLowerCase(),
|
||||
@ -97,7 +97,8 @@ router.get('/@:user', async ctx => {
|
||||
if (user != null) {
|
||||
await ctx.render('user', { user });
|
||||
} else {
|
||||
ctx.status = 404;
|
||||
// リモートユーザーなので
|
||||
await next();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -14,8 +14,8 @@ module.exports = async (ctx: Koa.Context) => {
|
||||
|
||||
function wrap(url: string): string {
|
||||
return url != null
|
||||
? url.startsWith('https://')
|
||||
? url.startsWith('https://') || url.startsWith('data:')
|
||||
? url
|
||||
: `https://images.weserv.nl/?url=${url.replace(/^http:\/\//, '')}`
|
||||
: `https://images.weserv.nl/?url=${encodeURIComponent(url.replace(/^http:\/\//, ''))}`
|
||||
: null;
|
||||
}
|
||||
|
@ -118,7 +118,8 @@ const addFile = async (
|
||||
// Check if there is a file with the same hash
|
||||
const much = await DriveFile.findOne({
|
||||
md5: hash,
|
||||
'metadata.userId': user._id
|
||||
'metadata.userId': user._id,
|
||||
'metadata.deletedAt': { $exists: false }
|
||||
});
|
||||
|
||||
if (much !== null) {
|
||||
|
@ -392,14 +392,17 @@ export default async (user: IUser, data: {
|
||||
}
|
||||
}
|
||||
|
||||
//#region TODO: これ重い
|
||||
// 今までで同じ投稿をRenoteしているか
|
||||
const existRenote = await Note.findOne({
|
||||
userId: user._id,
|
||||
renoteId: data.renote._id,
|
||||
_id: {
|
||||
$ne: note._id
|
||||
}
|
||||
});
|
||||
//const existRenote = await Note.findOne({
|
||||
// userId: user._id,
|
||||
// renoteId: data.renote._id,
|
||||
// _id: {
|
||||
// $ne: note._id
|
||||
// }
|
||||
//});
|
||||
const existRenote = null;
|
||||
//#endregion
|
||||
|
||||
if (!existRenote) {
|
||||
// Update renoteee status
|
||||
|
Reference in New Issue
Block a user