mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 07:24:13 +00:00 
			
		
		
		
	リモートユーザーのHTMLで表現されたプロフィールをMFMに変換するように
This commit is contained in:
		
							parent
							
								
									3633d7ada1
								
							
						
					
					
						commit
						79d1bf30a4
					
				
					 29 changed files with 90 additions and 92 deletions
				
			
		| 
						 | 
				
			
			@ -32,7 +32,7 @@
 | 
			
		|||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import Vue from 'vue';
 | 
			
		||||
import * as emojilib from 'emojilib';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
import getAcct from '../../../../../acct/render';
 | 
			
		||||
import { url } from '../../../config';
 | 
			
		||||
import MkUrl from './url.vue';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,7 +83,7 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import dateStringify from '../../../common/scripts/date-stringify';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
 | 
			
		||||
import MkPostFormWindow from './post-form-window.vue';
 | 
			
		||||
import MkRenoteFormWindow from './renote-form-window.vue';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,7 @@
 | 
			
		|||
import Vue from 'vue';
 | 
			
		||||
import dateStringify from '../../../common/scripts/date-stringify';
 | 
			
		||||
import canHideText from '../../../common/scripts/can-hide-text';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
 | 
			
		||||
import MkPostFormWindow from './post-form-window.vue';
 | 
			
		||||
import MkRenoteFormWindow from './renote-form-window.vue';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ import Vue from 'vue';
 | 
			
		|||
import * as XDraggable from 'vuedraggable';
 | 
			
		||||
import getKao from '../../../common/scripts/get-kao';
 | 
			
		||||
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
import { host } from '../../../config';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,7 +67,7 @@
 | 
			
		|||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import parse from '../../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../../mfm/parse';
 | 
			
		||||
import canHideText from '../../../../common/scripts/can-hide-text';
 | 
			
		||||
 | 
			
		||||
import MkNoteMenu from '../../../../common/views/components/note-menu.vue';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,7 +83,7 @@
 | 
			
		|||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
 | 
			
		||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
 | 
			
		||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,7 +68,7 @@
 | 
			
		|||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
import canHideText from '../../../common/scripts/can-hide-text';
 | 
			
		||||
 | 
			
		||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ import Vue from 'vue';
 | 
			
		|||
import * as XDraggable from 'vuedraggable';
 | 
			
		||||
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
 | 
			
		||||
import getKao from '../../../common/scripts/get-kao';
 | 
			
		||||
import parse from '../../../../../text/parse';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
import { host } from '../../../config';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										71
									
								
								src/mfm/html-to-mfm.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/mfm/html-to-mfm.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
const parse5 = require('parse5');
 | 
			
		||||
 | 
			
		||||
export default function(html: string): string {
 | 
			
		||||
	const dom = parse5.parseFragment(html);
 | 
			
		||||
 | 
			
		||||
	let text = '';
 | 
			
		||||
 | 
			
		||||
	dom.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
 | 
			
		||||
	return text.trim();
 | 
			
		||||
 | 
			
		||||
	function getText(node: any) {
 | 
			
		||||
		if (node.nodeName == '#text') return node.value;
 | 
			
		||||
 | 
			
		||||
		if (node.childNodes) {
 | 
			
		||||
			return node.childNodes.map((n: any) => getText(n)).join('');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return '';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function analyze(node: any) {
 | 
			
		||||
		switch (node.nodeName) {
 | 
			
		||||
			case '#text':
 | 
			
		||||
				text += node.value;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'br':
 | 
			
		||||
				text += '\n';
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'a':
 | 
			
		||||
				const txt = getText(node);
 | 
			
		||||
 | 
			
		||||
				// メンション
 | 
			
		||||
				if (txt.startsWith('@')) {
 | 
			
		||||
					const part = txt.split('@');
 | 
			
		||||
 | 
			
		||||
					if (part.length == 2) {
 | 
			
		||||
						//#region ホスト名部分が省略されているので復元する
 | 
			
		||||
						const href = new URL(node.attrs.find((x: any) => x.name == 'href').value);
 | 
			
		||||
						const acct = txt + '@' + href.hostname;
 | 
			
		||||
						text += acct;
 | 
			
		||||
						break;
 | 
			
		||||
						//#endregion
 | 
			
		||||
					} else if (part.length == 3) {
 | 
			
		||||
						text += txt;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (node.childNodes) {
 | 
			
		||||
					node.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'p':
 | 
			
		||||
				text += '\n\n';
 | 
			
		||||
				if (node.childNodes) {
 | 
			
		||||
					node.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				if (node.childNodes) {
 | 
			
		||||
					node.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import { INote } from '../../../models/note';
 | 
			
		||||
import toHtml from '../../../text/html';
 | 
			
		||||
import parse from '../../../text/parse';
 | 
			
		||||
import toHtml from '../../../mfm/html';
 | 
			
		||||
import parse from '../../../mfm/parse';
 | 
			
		||||
import config from '../../../config';
 | 
			
		||||
 | 
			
		||||
export default function(note: INote) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
import * as mongo from 'mongodb';
 | 
			
		||||
const parse5 = require('parse5');
 | 
			
		||||
import * as debug from 'debug';
 | 
			
		||||
 | 
			
		||||
import config from '../../../config';
 | 
			
		||||
| 
						 | 
				
			
			@ -10,79 +9,10 @@ import { INote as INoteActivityStreamsObject, IObject } from '../type';
 | 
			
		|||
import { resolvePerson, updatePerson } from './person';
 | 
			
		||||
import { resolveImage } from './image';
 | 
			
		||||
import { IRemoteUser, IUser } from '../../../models/user';
 | 
			
		||||
import htmlToMFM from '../../../mfm/html-to-mfm';
 | 
			
		||||
 | 
			
		||||
const log = debug('misskey:activitypub');
 | 
			
		||||
 | 
			
		||||
function parse(html: string): string {
 | 
			
		||||
	const dom = parse5.parseFragment(html);
 | 
			
		||||
 | 
			
		||||
	let text = '';
 | 
			
		||||
 | 
			
		||||
	dom.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
 | 
			
		||||
	return text.trim();
 | 
			
		||||
 | 
			
		||||
	function getText(node: any) {
 | 
			
		||||
		if (node.nodeName == '#text') return node.value;
 | 
			
		||||
 | 
			
		||||
		if (node.childNodes) {
 | 
			
		||||
			return node.childNodes.map((n: any) => getText(n)).join('');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return '';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function analyze(node: any) {
 | 
			
		||||
		switch (node.nodeName) {
 | 
			
		||||
			case '#text':
 | 
			
		||||
				text += node.value;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'br':
 | 
			
		||||
				text += '\n';
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'a':
 | 
			
		||||
				const txt = getText(node);
 | 
			
		||||
 | 
			
		||||
				// メンション
 | 
			
		||||
				if (txt.startsWith('@')) {
 | 
			
		||||
					const part = txt.split('@');
 | 
			
		||||
 | 
			
		||||
					if (part.length == 2) {
 | 
			
		||||
						//#region ホスト名部分が省略されているので復元する
 | 
			
		||||
						const href = new URL(node.attrs.find((x: any) => x.name == 'href').value);
 | 
			
		||||
						const acct = txt + '@' + href.hostname;
 | 
			
		||||
						text += acct;
 | 
			
		||||
						break;
 | 
			
		||||
						//#endregion
 | 
			
		||||
					} else if (part.length == 3) {
 | 
			
		||||
						text += txt;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (node.childNodes) {
 | 
			
		||||
					node.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 'p':
 | 
			
		||||
				text += '\n\n';
 | 
			
		||||
				if (node.childNodes) {
 | 
			
		||||
					node.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				if (node.childNodes) {
 | 
			
		||||
					node.childNodes.forEach((n: any) => analyze(n));
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Noteをフェッチします。
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +88,7 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 | 
			
		|||
	const reply = note.inReplyTo ? await resolveNote(note.inReplyTo, resolver) : null;
 | 
			
		||||
 | 
			
		||||
	// テキストのパース
 | 
			
		||||
	const text = parse(note.content);
 | 
			
		||||
	const text = htmlToMFM(note.content);
 | 
			
		||||
 | 
			
		||||
	// ユーザーの情報が古かったらついでに更新しておく
 | 
			
		||||
	if (actor.updatedAt == null || Date.now() - actor.updatedAt.getTime() > 1000 * 60 * 60 * 24) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
import * as mongo from 'mongodb';
 | 
			
		||||
import { JSDOM } from 'jsdom';
 | 
			
		||||
import { toUnicode } from 'punycode';
 | 
			
		||||
import * as debug from 'debug';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +10,7 @@ import { resolveImage } from './image';
 | 
			
		|||
import { isCollectionOrOrderedCollection, IObject, IPerson } from '../type';
 | 
			
		||||
import { IDriveFile } from '../../../models/drive-file';
 | 
			
		||||
import Meta from '../../../models/meta';
 | 
			
		||||
import htmlToMFM from '../../../mfm/html-to-mfm';
 | 
			
		||||
 | 
			
		||||
const log = debug('misskey:activitypub');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +80,6 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
 | 
			
		|||
	]);
 | 
			
		||||
 | 
			
		||||
	const host = toUnicode(finger.subject.replace(/^.*?@/, '')).toLowerCase();
 | 
			
		||||
	const summaryDOM = JSDOM.fragment(person.summary);
 | 
			
		||||
 | 
			
		||||
	// Create user
 | 
			
		||||
	let user: IRemoteUser;
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +88,7 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
 | 
			
		|||
			avatarId: null,
 | 
			
		||||
			bannerId: null,
 | 
			
		||||
			createdAt: Date.parse(person.published) || null,
 | 
			
		||||
			description: summaryDOM.textContent,
 | 
			
		||||
			description: htmlToMFM(person.summary),
 | 
			
		||||
			followersCount,
 | 
			
		||||
			followingCount,
 | 
			
		||||
			notesCount,
 | 
			
		||||
| 
						 | 
				
			
			@ -211,8 +210,6 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver)
 | 
			
		|||
		)
 | 
			
		||||
	]);
 | 
			
		||||
 | 
			
		||||
	const summaryDOM = JSDOM.fragment(person.summary);
 | 
			
		||||
 | 
			
		||||
	// アイコンとヘッダー画像をフェッチ
 | 
			
		||||
	const [avatar, banner] = (await Promise.all<IDriveFile>([
 | 
			
		||||
		person.icon,
 | 
			
		||||
| 
						 | 
				
			
			@ -231,7 +228,7 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver)
 | 
			
		|||
			bannerId: banner ? banner._id : null,
 | 
			
		||||
			avatarUrl: avatar && avatar.metadata.isMetaOnly ? avatar.metadata.url : null,
 | 
			
		||||
			bannerUrl: banner && banner.metadata.isMetaOnly ? banner.metadata.url : null,
 | 
			
		||||
			description: summaryDOM.textContent,
 | 
			
		||||
			description: htmlToMFM(person.summary),
 | 
			
		||||
			followersCount,
 | 
			
		||||
			followingCount,
 | 
			
		||||
			notesCount,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ import watch from './watch';
 | 
			
		|||
import Mute from '../../models/mute';
 | 
			
		||||
import pushSw from '../../publishers/push-sw';
 | 
			
		||||
import event from '../../publishers/stream';
 | 
			
		||||
import parse from '../../text/parse';
 | 
			
		||||
import parse from '../../mfm/parse';
 | 
			
		||||
import { IApp } from '../../models/app';
 | 
			
		||||
import UserList from '../../models/user-list';
 | 
			
		||||
import resolveUser from '../../remote/resolve-user';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import * as assert from 'assert';
 | 
			
		||||
 | 
			
		||||
import analyze from '../src/text/parse';
 | 
			
		||||
import syntaxhighlighter from '../src/text/parse/core/syntax-highlighter';
 | 
			
		||||
import analyze from '../src/mfm/parse';
 | 
			
		||||
import syntaxhighlighter from '../src/mfm/parse/core/syntax-highlighter';
 | 
			
		||||
 | 
			
		||||
describe('Text', () => {
 | 
			
		||||
	it('can be analyzed', () => {
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue