Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
6b2888383c | |||
3c38a867b4 | |||
7f5a69f4d8 | |||
bb9ab31d5e | |||
9def80af8a | |||
9256bcdbe4 | |||
9b775022bc | |||
32371ed2bd | |||
8b98c08a81 | |||
7cf72f7447 | |||
913385b10d | |||
7306468d08 | |||
11e5667778 | |||
38cc02e261 | |||
d52cf46cc1 | |||
c6110dd996 | |||
51d8de2c38 | |||
4455a1aa9d | |||
040d395ddb | |||
8296cac636 | |||
3eafe8b87d | |||
c01512e261 | |||
e5cf3aecd5 | |||
a8f90b41b7 | |||
b79169b975 | |||
437d52e2ed | |||
1329721440 | |||
6affb4fe97 | |||
15395686aa | |||
5cf1956135 | |||
fff307d4bb | |||
2b7782ba03 | |||
96d961ee80 | |||
9f064d76d9 | |||
2e39106c4b | |||
04650464f3 | |||
3bc7e1e35c | |||
7019ddbfc7 |
@ -159,3 +159,10 @@ drive:
|
|||||||
|
|
||||||
# Summaly proxy
|
# Summaly proxy
|
||||||
# summalyProxy: "http://example.com"
|
# summalyProxy: "http://example.com"
|
||||||
|
|
||||||
|
# User recommendation
|
||||||
|
user_recommendation:
|
||||||
|
external: true
|
||||||
|
engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
|
||||||
|
timeout: 300000
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ 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/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>
|
||||||
@ -80,6 +81,7 @@ Please see [Contribution guide](./CONTRIBUTING.md).
|
|||||||
<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>
|
<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=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>
|
||||||
|
10
package.json
10
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "10.0.0",
|
"version": "10.2.1",
|
||||||
"clientVersion": "1.0.10328",
|
"clientVersion": "1.0.10366",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
@ -96,7 +96,7 @@
|
|||||||
"crc-32": "1.2.0",
|
"crc-32": "1.2.0",
|
||||||
"css-loader": "1.0.0",
|
"css-loader": "1.0.0",
|
||||||
"dateformat": "3.0.3",
|
"dateformat": "3.0.3",
|
||||||
"debug": "4.0.1",
|
"debug": "4.1.0",
|
||||||
"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",
|
||||||
@ -191,7 +191,7 @@
|
|||||||
"single-line-log": "1.1.2",
|
"single-line-log": "1.1.2",
|
||||||
"speakeasy": "2.0.0",
|
"speakeasy": "2.0.0",
|
||||||
"stringz": "1.0.0",
|
"stringz": "1.0.0",
|
||||||
"style-loader": "0.23.0",
|
"style-loader": "0.23.1",
|
||||||
"stylus": "0.54.5",
|
"stylus": "0.54.5",
|
||||||
"stylus-loader": "3.0.2",
|
"stylus-loader": "3.0.2",
|
||||||
"summaly": "2.2.0",
|
"summaly": "2.2.0",
|
||||||
@ -204,7 +204,7 @@
|
|||||||
"ts-node": "7.0.1",
|
"ts-node": "7.0.1",
|
||||||
"tslint": "5.10.0",
|
"tslint": "5.10.0",
|
||||||
"typescript": "2.9.2",
|
"typescript": "2.9.2",
|
||||||
"typescript-eslint-parser": "19.0.2",
|
"typescript-eslint-parser": "20.0.0",
|
||||||
"uglify-es": "3.3.9",
|
"uglify-es": "3.3.9",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
|
@ -13,14 +13,14 @@ export default prop => ({
|
|||||||
},
|
},
|
||||||
|
|
||||||
$_ns_isRenote(): boolean {
|
$_ns_isRenote(): boolean {
|
||||||
return (this.$_ns_note_.renote &&
|
return (this.$_ns_note_.renote != null &&
|
||||||
this.$_ns_note_.text == null &&
|
this.$_ns_note_.text == null &&
|
||||||
this.$_ns_note_.fileIds.length == 0 &&
|
this.$_ns_note_.fileIds.length == 0 &&
|
||||||
this.$_ns_note_.poll == null);
|
this.$_ns_note_.poll == null);
|
||||||
},
|
},
|
||||||
|
|
||||||
$_ns_target(): any {
|
$_ns_target(): any {
|
||||||
return this._ns_isRenote ? this.$_ns_note_.renote : this.$_ns_note_;
|
return this.$_ns_isRenote ? this.$_ns_note_.renote : this.$_ns_note_;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -86,8 +86,20 @@ export default prop => ({
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case 'reacted': {
|
case 'reacted': {
|
||||||
const reaction = body.reaction;
|
const reaction = body.reaction;
|
||||||
if (this.$_ns_target.reactionCounts == null) Vue.set(this.$_ns_target, 'reactionCounts', {});
|
|
||||||
this.$_ns_target.reactionCounts[reaction] = (this.$_ns_target.reactionCounts[reaction] || 0) + 1;
|
if (this.$_ns_target.reactionCounts == null) {
|
||||||
|
Vue.set(this.$_ns_target, 'reactionCounts', {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$_ns_target.reactionCounts[reaction] == null) {
|
||||||
|
Vue.set(this.$_ns_target.reactionCounts, reaction, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$_ns_target.reactionCounts[reaction]++;
|
||||||
|
|
||||||
|
if (body.userId == this.$store.state.i.id) {
|
||||||
|
Vue.set(this.$_ns_target, 'myReaction', reaction);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,14 +253,13 @@ abstract class Connection extends EventEmitter {
|
|||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
public send(typeOrPayload, payload?) {
|
public send(typeOrPayload, payload?) {
|
||||||
const data = payload === undefined ? typeOrPayload : {
|
const type = payload === undefined ? typeOrPayload.type : typeOrPayload;
|
||||||
type: typeOrPayload,
|
const body = payload === undefined ? typeOrPayload.body : payload;
|
||||||
body: payload
|
|
||||||
};
|
|
||||||
|
|
||||||
this.stream.send('channel', {
|
this.stream.send('channel', {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
body: data
|
type: type,
|
||||||
|
body: body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,9 +186,8 @@ export default Vue.extend({
|
|||||||
if (this.game.isStarted && !this.game.isEnded) {
|
if (this.game.isStarted && !this.game.isEnded) {
|
||||||
this.pollingClock = setInterval(() => {
|
this.pollingClock = setInterval(() => {
|
||||||
const crc32 = CRC32.str(this.logs.map(x => x.pos.toString()).join(''));
|
const crc32 = CRC32.str(this.logs.map(x => x.pos.toString()).join(''));
|
||||||
this.connection.send({
|
this.connection.send('check', {
|
||||||
type: 'check',
|
crc32: crc32
|
||||||
crc32
|
|
||||||
});
|
});
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
@ -224,9 +223,8 @@ export default Vue.extend({
|
|||||||
sound.play();
|
sound.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.connection.send({
|
this.connection.send('set', {
|
||||||
type: 'set',
|
pos: pos
|
||||||
pos
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.checkEnd();
|
this.checkEnd();
|
||||||
|
@ -149,9 +149,9 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.connection.on('change-accepts', this.onChangeAccepts);
|
this.connection.on('changeAccepts', this.onChangeAccepts);
|
||||||
this.connection.on('update-settings', this.onUpdateSettings);
|
this.connection.on('updateSettings', this.onUpdateSettings);
|
||||||
this.connection.on('init-form', this.onInitForm);
|
this.connection.on('initForm', this.onInitForm);
|
||||||
this.connection.on('message', this.onMessage);
|
this.connection.on('message', this.onMessage);
|
||||||
|
|
||||||
if (this.game.user1Id != this.$store.state.i.id && this.game.settings.form1) this.form = this.game.settings.form1;
|
if (this.game.user1Id != this.$store.state.i.id && this.game.settings.form1) this.form = this.game.settings.form1;
|
||||||
@ -159,9 +159,9 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.off('change-accepts', this.onChangeAccepts);
|
this.connection.off('changeAccepts', this.onChangeAccepts);
|
||||||
this.connection.off('update-settings', this.onUpdateSettings);
|
this.connection.off('updateSettings', this.onUpdateSettings);
|
||||||
this.connection.off('init-form', this.onInitForm);
|
this.connection.off('initForm', this.onInitForm);
|
||||||
this.connection.off('message', this.onMessage);
|
this.connection.off('message', this.onMessage);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -171,15 +171,11 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
accept() {
|
accept() {
|
||||||
this.connection.send({
|
this.connection.send('accept', {});
|
||||||
type: 'accept'
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.connection.send({
|
this.connection.send('cancelAccept', {});
|
||||||
type: 'cancel-accept'
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onChangeAccepts(accepts) {
|
onChangeAccepts(accepts) {
|
||||||
@ -189,8 +185,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateSettings() {
|
updateSettings() {
|
||||||
this.connection.send({
|
this.connection.send('updateSettings', {
|
||||||
type: 'update-settings',
|
|
||||||
settings: this.game.settings
|
settings: this.game.settings
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -216,8 +211,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onChangeForm(item) {
|
onChangeForm(item) {
|
||||||
this.connection.send({
|
this.connection.send('updateForm', {
|
||||||
type: 'update-form',
|
|
||||||
id: item.id,
|
id: item.id,
|
||||||
value: item.value
|
value: item.value
|
||||||
});
|
});
|
||||||
@ -238,9 +232,9 @@ export default Vue.extend({
|
|||||||
const y = Math.floor(pos / this.game.settings.map[0].length);
|
const y = Math.floor(pos / this.game.settings.map[0].length);
|
||||||
const newPixel =
|
const newPixel =
|
||||||
pixel == ' ' ? '-' :
|
pixel == ' ' ? '-' :
|
||||||
pixel == '-' ? 'b' :
|
pixel == '-' ? 'b' :
|
||||||
pixel == 'b' ? 'w' :
|
pixel == 'b' ? 'w' :
|
||||||
' ';
|
' ';
|
||||||
const line = this.game.settings.map[y].split('');
|
const line = this.game.settings.map[y].split('');
|
||||||
line[x] = newPixel;
|
line[x] = newPixel;
|
||||||
this.$set(this.game.settings.map, y, line.join(''));
|
this.$set(this.game.settings.map, y, line.join(''));
|
||||||
|
@ -174,8 +174,7 @@ export default Vue.extend({
|
|||||||
|
|
||||||
this.messages.push(message);
|
this.messages.push(message);
|
||||||
if (message.userId != this.$store.state.i.id && !document.hidden) {
|
if (message.userId != this.$store.state.i.id && !document.hidden) {
|
||||||
this.connection.send({
|
this.connection.send('read', {
|
||||||
type: 'read',
|
|
||||||
id: message.id
|
id: message.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -247,8 +246,7 @@ export default Vue.extend({
|
|||||||
if (document.hidden) return;
|
if (document.hidden) return;
|
||||||
this.messages.forEach(message => {
|
this.messages.forEach(message => {
|
||||||
if (message.userId !== this.$store.state.i.id && !message.isRead) {
|
if (message.userId !== this.$store.state.i.id && !message.isRead) {
|
||||||
this.connection.send({
|
this.connection.send('read', {
|
||||||
type: 'read',
|
|
||||||
id: message.id
|
id: message.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-reactions-viewer">
|
<div class="mk-reactions-viewer">
|
||||||
<template v-if="reactions">
|
<template v-if="reactions">
|
||||||
<span :class="{notReacted}" @click="react('like')" v-if="reactions.like"><mk-reaction-icon reaction="like"/><span>{{ reactions.like }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'like' }" @click="react('like')" v-if="reactions.like"><mk-reaction-icon reaction="like"/><span>{{ reactions.like }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('love')" v-if="reactions.love"><mk-reaction-icon reaction="love"/><span>{{ reactions.love }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'love' }" @click="react('love')" v-if="reactions.love"><mk-reaction-icon reaction="love"/><span>{{ reactions.love }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('laugh')" v-if="reactions.laugh"><mk-reaction-icon reaction="laugh"/><span>{{ reactions.laugh }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'laugh' }" @click="react('laugh')" v-if="reactions.laugh"><mk-reaction-icon reaction="laugh"/><span>{{ reactions.laugh }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('hmm')" v-if="reactions.hmm"><mk-reaction-icon reaction="hmm"/><span>{{ reactions.hmm }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'hmm' }" @click="react('hmm')" v-if="reactions.hmm"><mk-reaction-icon reaction="hmm"/><span>{{ reactions.hmm }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('surprise')" v-if="reactions.surprise"><mk-reaction-icon reaction="surprise"/><span>{{ reactions.surprise }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'surprise' }" @click="react('surprise')" v-if="reactions.surprise"><mk-reaction-icon reaction="surprise"/><span>{{ reactions.surprise }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('congrats')" v-if="reactions.congrats"><mk-reaction-icon reaction="congrats"/><span>{{ reactions.congrats }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'congrats' }" @click="react('congrats')" v-if="reactions.congrats"><mk-reaction-icon reaction="congrats"/><span>{{ reactions.congrats }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('angry')" v-if="reactions.angry"><mk-reaction-icon reaction="angry"/><span>{{ reactions.angry }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'angry' }" @click="react('angry')" v-if="reactions.angry"><mk-reaction-icon reaction="angry"/><span>{{ reactions.angry }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('confused')" v-if="reactions.confused"><mk-reaction-icon reaction="confused"/><span>{{ reactions.confused }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'confused' }" @click="react('confused')" v-if="reactions.confused"><mk-reaction-icon reaction="confused"/><span>{{ reactions.confused }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('rip')" v-if="reactions.rip"><mk-reaction-icon reaction="rip"/><span>{{ reactions.rip }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'rip' }" @click="react('rip')" v-if="reactions.rip"><mk-reaction-icon reaction="rip"/><span>{{ reactions.rip }}</span></span>
|
||||||
<span :class="{notReacted}" @click="react('pudding')" v-if="reactions.pudding"><mk-reaction-icon reaction="pudding"/><span>{{ reactions.pudding }}</span></span>
|
<span :class="{ reacted: note.myReaction == 'pudding' }" @click="react('pudding')" v-if="reactions.pudding"><mk-reaction-icon reaction="pudding"/><span>{{ reactions.pudding }}</span></span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -22,9 +22,6 @@ export default Vue.extend({
|
|||||||
computed: {
|
computed: {
|
||||||
reactions(): number {
|
reactions(): number {
|
||||||
return this.note.reactionCounts;
|
return this.note.reactionCounts;
|
||||||
},
|
|
||||||
notReacted(): boolean {
|
|
||||||
return this.note.myReaction == null;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -40,25 +37,42 @@ export default Vue.extend({
|
|||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.mk-reactions-viewer
|
.mk-reactions-viewer
|
||||||
border-top dashed 1px var(--reactionViewerBorder)
|
margin 6px 0
|
||||||
border-bottom dashed 1px var(--reactionViewerBorder)
|
|
||||||
margin 4px 0
|
|
||||||
|
|
||||||
&:empty
|
&:empty
|
||||||
display none
|
display none
|
||||||
|
|
||||||
> span
|
> span
|
||||||
margin-right 8px
|
display inline-block
|
||||||
|
height 32px
|
||||||
|
margin-right 6px
|
||||||
|
padding 0 6px
|
||||||
|
border-radius 4px
|
||||||
|
|
||||||
&.notReacted
|
*
|
||||||
|
user-select none
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
|
&.reacted
|
||||||
|
background var(--primary)
|
||||||
|
|
||||||
|
> span
|
||||||
|
color var(--primaryForeground)
|
||||||
|
|
||||||
|
&:not(.reacted)
|
||||||
cursor pointer
|
cursor pointer
|
||||||
|
background var(--reactionViewerButtonBg)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background var(--reactionViewerButtonHoverBg)
|
||||||
|
|
||||||
> .mk-reaction-icon
|
> .mk-reaction-icon
|
||||||
font-size 1.4em
|
font-size 1.4em
|
||||||
|
|
||||||
> span
|
> span
|
||||||
margin-left 4px
|
font-size 1.1em
|
||||||
font-size 1.2em
|
line-height 32px
|
||||||
|
vertical-align middle
|
||||||
color var(--text)
|
color var(--text)
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
<router-link class="name" :to="user | userPage" v-user-preview="user.id">{{ user | userName }}</router-link>
|
<router-link class="name" :to="user | userPage" v-user-preview="user.id">{{ user | userName }}</router-link>
|
||||||
<p class="username">@{{ user | acct }}</p>
|
<p class="username">@{{ user | acct }}</p>
|
||||||
</div>
|
</div>
|
||||||
<mk-follow-button :user="user"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p>
|
<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p>
|
||||||
|
@ -26,12 +26,14 @@ export default Vue.extend({
|
|||||||
this.init();
|
this.init();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.close();
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
init() {
|
init() {
|
||||||
if (this.connection) this.connection.close();
|
if (this.connection) this.connection.dispose();
|
||||||
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
|
this.connection = (this as any).os.stream.connectToChannel('userList', {
|
||||||
|
listId: this.list.id
|
||||||
|
});
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', this.onNote);
|
||||||
this.connection.on('userAdded', this.onUserAdded);
|
this.connection.on('userAdded', this.onUserAdded);
|
||||||
this.connection.on('userRemoved', this.onUserRemoved);
|
this.connection.on('userRemoved', this.onUserRemoved);
|
||||||
|
@ -46,8 +46,10 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.connection) this.connection.close();
|
if (this.connection) this.connection.dispose();
|
||||||
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
|
this.connection = (this as any).os.stream.connectToChannel('userList', {
|
||||||
|
listId: this.list.id
|
||||||
|
});
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', this.onNote);
|
||||||
this.connection.on('userAdded', this.onUserAdded);
|
this.connection.on('userAdded', this.onUserAdded);
|
||||||
this.connection.on('userRemoved', this.onUserRemoved);
|
this.connection.on('userRemoved', this.onUserRemoved);
|
||||||
@ -56,7 +58,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.close();
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
<router-link class="name" :to="_user | userPage" v-user-preview="_user.id">{{ _user | userName }}</router-link>
|
<router-link class="name" :to="_user | userPage" v-user-preview="_user.id">{{ _user | userName }}</router-link>
|
||||||
<p class="username">@{{ _user | acct }}</p>
|
<p class="username">@{{ _user | acct }}</p>
|
||||||
</div>
|
</div>
|
||||||
<mk-follow-button :user="_user"/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<p class="empty" v-else>%i18n:@no-one%</p>
|
<p class="empty" v-else>%i18n:@no-one%</p>
|
||||||
|
@ -36,13 +36,15 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.connection.close();
|
this.connection.dispose();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
init() {
|
init() {
|
||||||
if (this.connection) this.connection.close();
|
if (this.connection) this.connection.dispose();
|
||||||
this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
|
this.connection = (this as any).os.stream.connectToChannel('userList', {
|
||||||
|
listId: this.list.id
|
||||||
|
});
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', this.onNote);
|
||||||
this.connection.on('userAdded', this.onUserAdded);
|
this.connection.on('userAdded', this.onUserAdded);
|
||||||
this.connection.on('userRemoved', this.onUserRemoved);
|
this.connection.on('userRemoved', this.onUserRemoved);
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
face: '$secondary',
|
face: '$secondary',
|
||||||
faceText: '#fff',
|
faceText: '#fff',
|
||||||
faceHeader: ':lighten<5<$secondary',
|
faceHeader: ':lighten<5<$secondary',
|
||||||
faceHeaderText: '#e3e5e8',
|
faceHeaderText: '$text',
|
||||||
faceDivider: 'rgba(0, 0, 0, 0.3)',
|
faceDivider: 'rgba(0, 0, 0, 0.3)',
|
||||||
faceTextButton: '$text',
|
faceTextButton: '$text',
|
||||||
faceTextButtonHover: ':lighten<10<$text',
|
faceTextButtonHover: ':lighten<10<$text',
|
||||||
@ -84,7 +84,8 @@
|
|||||||
|
|
||||||
reactionPickerButtonHoverBg: 'rgba(255, 255, 255, 0.18)',
|
reactionPickerButtonHoverBg: 'rgba(255, 255, 255, 0.18)',
|
||||||
|
|
||||||
reactionViewerBorder: 'rgba(255, 255, 255, 0.1)',
|
reactionViewerButtonBg: 'rgba(255, 255, 255, 0.1)',
|
||||||
|
reactionViewerButtonHoverBg: 'rgba(255, 255, 255, 0.2)',
|
||||||
|
|
||||||
pollEditorInputBg: 'rgba(0, 0, 0, 0.25)',
|
pollEditorInputBg: 'rgba(0, 0, 0, 0.25)',
|
||||||
|
|
||||||
|
@ -84,7 +84,8 @@
|
|||||||
|
|
||||||
reactionPickerButtonHoverBg: '#eee',
|
reactionPickerButtonHoverBg: '#eee',
|
||||||
|
|
||||||
reactionViewerBorder: 'rgba(0, 0, 0, 0.1)',
|
reactionViewerButtonBg: 'rgba(0, 0, 0, 0.05)',
|
||||||
|
reactionViewerButtonHoverBg: 'rgba(0, 0, 0, 0.1)',
|
||||||
|
|
||||||
pollEditorInputBg: '#fff',
|
pollEditorInputBg: '#fff',
|
||||||
|
|
||||||
|
@ -96,6 +96,12 @@ export type Source = {
|
|||||||
google_maps_api_key: string;
|
google_maps_api_key: string;
|
||||||
|
|
||||||
clusterLimit?: number;
|
clusterLimit?: number;
|
||||||
|
|
||||||
|
user_recommendation: {
|
||||||
|
external: boolean;
|
||||||
|
engine: string;
|
||||||
|
timeout: number;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,7 +17,7 @@ const summarize = (note: any): string => {
|
|||||||
summary += note.text ? note.text : '';
|
summary += note.text ? note.text : '';
|
||||||
|
|
||||||
// ファイルが添付されているとき
|
// ファイルが添付されているとき
|
||||||
if (note.files.length != 0) {
|
if ((note.files || []).length != 0) {
|
||||||
summary += ` (${note.files.length}つのファイル)`;
|
summary += ` (${note.files.length}つのファイル)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,15 +24,15 @@ export const meta = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (params: any) => new Promise(async (res, rej) => {
|
export default async (params: any) => {
|
||||||
const [ps, psErr] = getParams(meta, params);
|
const [ps, psErr] = getParams(meta, params);
|
||||||
if (psErr) return rej(psErr);
|
if (psErr) throw psErr;
|
||||||
|
|
||||||
const object = await fetchAny(ps.uri);
|
const object = await fetchAny(ps.uri);
|
||||||
if (object !== null) return res(object);
|
if (object !== null) return object;
|
||||||
|
|
||||||
return rej('object not found');
|
throw new Error('object not found');
|
||||||
});
|
};
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* URIからUserかNoteを解決する
|
* URIからUserかNoteを解決する
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
/**
|
|
||||||
* Module dependencies
|
|
||||||
*/
|
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import config from '../../../config';
|
import config from '../../../config';
|
||||||
import Meta from '../../../models/meta';
|
import Meta from '../../../models/meta';
|
||||||
@ -9,9 +6,17 @@ import { ILocalUser } from '../../../models/user';
|
|||||||
const pkg = require('../../../../package.json');
|
const pkg = require('../../../../package.json');
|
||||||
const client = require('../../../../built/client/meta.json');
|
const client = require('../../../../built/client/meta.json');
|
||||||
|
|
||||||
/**
|
export const meta = {
|
||||||
* Show core info
|
desc: {
|
||||||
*/
|
'ja-JP': 'インスタンス情報を取得します。',
|
||||||
|
'en-US': 'Get the information of this instance.'
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: false,
|
||||||
|
|
||||||
|
params: {},
|
||||||
|
};
|
||||||
|
|
||||||
export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
|
export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
|
||||||
const meta: any = (await Meta.findOne()) || {};
|
const meta: any = (await Meta.findOne()) || {};
|
||||||
|
|
||||||
@ -28,10 +33,12 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
|
|||||||
machine: os.hostname(),
|
machine: os.hostname(),
|
||||||
os: os.platform(),
|
os: os.platform(),
|
||||||
node: process.version,
|
node: process.version,
|
||||||
|
|
||||||
cpu: {
|
cpu: {
|
||||||
model: os.cpus()[0].model,
|
model: os.cpus()[0].model,
|
||||||
cores: os.cpus().length
|
cores: os.cpus().length
|
||||||
},
|
},
|
||||||
|
|
||||||
broadcasts: meta.broadcasts || [],
|
broadcasts: meta.broadcasts || [],
|
||||||
disableRegistration: meta.disableRegistration,
|
disableRegistration: meta.disableRegistration,
|
||||||
disableLocalTimeline: meta.disableLocalTimeline,
|
disableLocalTimeline: meta.disableLocalTimeline,
|
||||||
@ -40,6 +47,7 @@ export default (params: any, me: ILocalUser) => new Promise(async (res, rej) =>
|
|||||||
swPublickey: config.sw ? config.sw.public_key : null,
|
swPublickey: config.sw ? config.sw.public_key : null,
|
||||||
hidedTags: (me && me.isAdmin) ? meta.hidedTags : undefined,
|
hidedTags: (me && me.isAdmin) ? meta.hidedTags : undefined,
|
||||||
bannerUrl: meta.bannerUrl,
|
bannerUrl: meta.bannerUrl,
|
||||||
|
|
||||||
features: {
|
features: {
|
||||||
registration: !meta.disableRegistration,
|
registration: !meta.disableRegistration,
|
||||||
localTimeLine: !meta.disableLocalTimeline,
|
localTimeLine: !meta.disableLocalTimeline,
|
||||||
|
@ -3,6 +3,8 @@ import $ from 'cafy';
|
|||||||
import User, { pack, ILocalUser } from '../../../../models/user';
|
import User, { pack, ILocalUser } from '../../../../models/user';
|
||||||
import { getFriendIds } from '../../common/get-friends';
|
import { getFriendIds } from '../../common/get-friends';
|
||||||
import Mute from '../../../../models/mute';
|
import Mute from '../../../../models/mute';
|
||||||
|
import * as request from 'request'
|
||||||
|
import config from '../../../../config'
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
@ -15,44 +17,74 @@ export const meta = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
|
export default (params: any, me: ILocalUser) => new Promise(async (res, rej) => {
|
||||||
// Get 'limit' parameter
|
if (config.user_recommendation && config.user_recommendation.external) {
|
||||||
const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit);
|
const userName = me.username
|
||||||
if (limitErr) return rej('invalid limit param');
|
const hostName = config.hostname
|
||||||
|
const limit = params.limit
|
||||||
// Get 'offset' parameter
|
const offset = params.offset
|
||||||
const [offset = 0, offsetErr] = $.num.optional.min(0).get(params.offset);
|
const timeout = config.user_recommendation.timeout
|
||||||
if (offsetErr) return rej('invalid offset param');
|
const engine = config.user_recommendation.engine
|
||||||
|
const url = engine
|
||||||
// ID list of the user itself and other users who the user follows
|
.replace('{{host}}', hostName)
|
||||||
const followingIds = await getFriendIds(me._id);
|
.replace('{{user}}', userName)
|
||||||
|
.replace('{{limit}}', limit)
|
||||||
// ミュートしているユーザーを取得
|
.replace('{{offset}}', offset)
|
||||||
const mutedUserIds = (await Mute.find({
|
request(
|
||||||
muterId: me._id
|
{
|
||||||
})).map(m => m.muteeId);
|
url: url,
|
||||||
|
timeout: timeout,
|
||||||
const users = await User
|
json: true,
|
||||||
.find({
|
followRedirect: true,
|
||||||
_id: {
|
followAllRedirects: true
|
||||||
$nin: followingIds.concat(mutedUserIds)
|
|
||||||
},
|
},
|
||||||
isLocked: false,
|
(error: any, response: any, body: any) => {
|
||||||
$or: [{
|
if (!error && response.statusCode == 200) {
|
||||||
lastUsedAt: {
|
res(body)
|
||||||
$gte: new Date(Date.now() - ms('7days'))
|
} else {
|
||||||
|
res([])
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
host: null
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
limit: limit,
|
|
||||||
skip: offset,
|
|
||||||
sort: {
|
|
||||||
followersCount: -1
|
|
||||||
}
|
}
|
||||||
});
|
)
|
||||||
|
} else {
|
||||||
|
// Get 'limit' parameter
|
||||||
|
const [limit = 10, limitErr] = $.num.optional.range(1, 100).get(params.limit);
|
||||||
|
if (limitErr) return rej('invalid limit param');
|
||||||
|
|
||||||
// Serialize
|
// Get 'offset' parameter
|
||||||
res(await Promise.all(users.map(async user =>
|
const [offset = 0, offsetErr] = $.num.optional.min(0).get(params.offset);
|
||||||
await pack(user, me, { detail: true }))));
|
if (offsetErr) return rej('invalid offset param');
|
||||||
|
|
||||||
|
// ID list of the user itself and other users who the user follows
|
||||||
|
const followingIds = await getFriendIds(me._id);
|
||||||
|
|
||||||
|
// ミュートしているユーザーを取得
|
||||||
|
const mutedUserIds = (await Mute.find({
|
||||||
|
muterId: me._id
|
||||||
|
})).map(m => m.muteeId);
|
||||||
|
|
||||||
|
const users = await User
|
||||||
|
.find({
|
||||||
|
_id: {
|
||||||
|
$nin: followingIds.concat(mutedUserIds)
|
||||||
|
},
|
||||||
|
isLocked: false,
|
||||||
|
$or: [{
|
||||||
|
lastUsedAt: {
|
||||||
|
$gte: new Date(Date.now() - ms('7days'))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
host: null
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
limit: limit,
|
||||||
|
skip: offset,
|
||||||
|
sort: {
|
||||||
|
followersCount: -1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Serialize
|
||||||
|
res(await Promise.all(users.map(async user =>
|
||||||
|
await pack(user, me, { detail: true }))));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -23,10 +23,10 @@ export default class extends Channel {
|
|||||||
public onMessage(type: string, body: any) {
|
public onMessage(type: string, body: any) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'accept': this.accept(true); break;
|
case 'accept': this.accept(true); break;
|
||||||
case 'cancel-accept': this.accept(false); break;
|
case 'cancelAccept': this.accept(false); break;
|
||||||
case 'update-settings': this.updateSettings(body.settings); break;
|
case 'updateSettings': this.updateSettings(body.settings); break;
|
||||||
case 'init-form': this.initForm(body); break;
|
case 'initForm': this.initForm(body); break;
|
||||||
case 'update-form': this.updateForm(body.id, body.value); break;
|
case 'updateForm': this.updateForm(body.id, body.value); break;
|
||||||
case 'message': this.message(body); break;
|
case 'message': this.message(body); break;
|
||||||
case 'set': this.set(body.pos); break;
|
case 'set': this.set(body.pos); break;
|
||||||
case 'check': this.check(body.crc32); break;
|
case 'check': this.check(body.crc32); break;
|
||||||
|
@ -44,6 +44,10 @@ module.exports = (server: http.Server) => {
|
|||||||
request.resourceURL.pathname === '/local-timeline' ? channels.localTimeline :
|
request.resourceURL.pathname === '/local-timeline' ? channels.localTimeline :
|
||||||
request.resourceURL.pathname === '/hybrid-timeline' ? channels.hybridTimeline :
|
request.resourceURL.pathname === '/hybrid-timeline' ? channels.hybridTimeline :
|
||||||
request.resourceURL.pathname === '/global-timeline' ? channels.globalTimeline : null);
|
request.resourceURL.pathname === '/global-timeline' ? channels.globalTimeline : null);
|
||||||
|
|
||||||
|
if (request.resourceURL.pathname === '/') {
|
||||||
|
main.connectChannel(Math.random().toString(), null, channels.main);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.once('close', () => {
|
connection.once('close', () => {
|
||||||
|
@ -44,7 +44,8 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise
|
|||||||
});
|
});
|
||||||
|
|
||||||
publishNoteStream(note._id, 'reacted', {
|
publishNoteStream(note._id, 'reacted', {
|
||||||
reaction: reaction
|
reaction: reaction,
|
||||||
|
userId: user._id
|
||||||
});
|
});
|
||||||
|
|
||||||
// リアクションされたユーザーがローカルユーザーなら通知を作成
|
// リアクションされたユーザーがローカルユーザーなら通知を作成
|
||||||
|
64
src/tools/move-drive-files.ts
Normal file
64
src/tools/move-drive-files.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import * as Minio from 'minio';
|
||||||
|
import * as uuid from 'uuid';
|
||||||
|
import DriveFile, { DriveFileChunk, getDriveFileBucket } from '../models/drive-file';
|
||||||
|
import DriveFileThumbnail, { DriveFileThumbnailChunk } from '../models/drive-file-thumbnail';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
|
DriveFile.find({
|
||||||
|
$or: [{
|
||||||
|
withoutChunks: { $exists: false }
|
||||||
|
}, {
|
||||||
|
withoutChunks: false
|
||||||
|
}]
|
||||||
|
}).then(async files => {
|
||||||
|
files.forEach(async file => {
|
||||||
|
const minio = new Minio.Client(config.drive.config);
|
||||||
|
|
||||||
|
const keyDir = `${config.drive.prefix}/${uuid.v4()}`;
|
||||||
|
const key = `${keyDir}/${name}`;
|
||||||
|
const thumbnailKeyDir = `${config.drive.prefix}/${uuid.v4()}`;
|
||||||
|
const thumbnailKey = `${thumbnailKeyDir}/${name}.thumbnail.jpg`;
|
||||||
|
|
||||||
|
const baseUrl = config.drive.baseUrl
|
||||||
|
|| `${ config.drive.config.useSSL ? 'https' : 'http' }://${ config.drive.config.endPoint }${ config.drive.config.port ? `:${config.drive.config.port}` : '' }/${ config.drive.bucket }`;
|
||||||
|
|
||||||
|
const bucket = await getDriveFileBucket();
|
||||||
|
const readable = bucket.openDownloadStream(file._id);
|
||||||
|
|
||||||
|
await minio.putObject(config.drive.bucket, key, readable, file.length, {
|
||||||
|
'Content-Type': file.contentType,
|
||||||
|
'Cache-Control': 'max-age=31536000, immutable'
|
||||||
|
});
|
||||||
|
|
||||||
|
await DriveFile.findOneAndUpdate({ _id: file._id }, {
|
||||||
|
$set: {
|
||||||
|
'metadata.withoutChunks': true,
|
||||||
|
'metadata.storage': 'minio',
|
||||||
|
'metadata.storageProps': {
|
||||||
|
key: key,
|
||||||
|
thumbnailKey: thumbnailKey
|
||||||
|
},
|
||||||
|
'metadata.url': `${ baseUrl }/${ keyDir }/${ encodeURIComponent(name) }`,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// チャンクをすべて削除
|
||||||
|
await DriveFileChunk.remove({
|
||||||
|
files_id: file._id
|
||||||
|
});
|
||||||
|
|
||||||
|
//#region サムネイルもあれば削除
|
||||||
|
const thumbnail = await DriveFileThumbnail.findOne({
|
||||||
|
'metadata.originalId': file._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (thumbnail) {
|
||||||
|
await DriveFileThumbnailChunk.remove({
|
||||||
|
files_id: thumbnail._id
|
||||||
|
});
|
||||||
|
|
||||||
|
await DriveFileThumbnail.remove({ _id: thumbnail._id });
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user