forked from FoundKeyGang/FoundKey
activitypub: hashtags no longer displaying as links
Some hashtags sent from Mastodon were erroneously displayed as links. This is because Mastodon seems to mangle hashtags containing non-ASCII codepoints (such as e.g. umlauts). This lead to the previous code which depended on the list of hashtags to not recognize a hashtag. Instead, the `rel="tag"` microformat is recognized instead. This makes the `htmlToMfm` wrapper function unnecessary so it was removed. Changelog: Fixed
This commit is contained in:
parent
b4080d788d
commit
194fff3603
4 changed files with 6 additions and 16 deletions
|
@ -7,7 +7,7 @@ const treeAdapter = parse5.defaultTreeAdapter;
|
||||||
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
||||||
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
|
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
|
||||||
|
|
||||||
export function fromHtml(html: string, hashtagNames?: string[], quoteUri?: string | null): string {
|
export function fromHtml(html: string, quoteUri?: string | null): string {
|
||||||
const dom = parse5.parseFragment(
|
const dom = parse5.parseFragment(
|
||||||
// some AP servers like Pixelfed use br tags as well as newlines
|
// some AP servers like Pixelfed use br tags as well as newlines
|
||||||
html.replace(/<br\s?\/?>\r?\n/gi, '\n'),
|
html.replace(/<br\s?\/?>\r?\n/gi, '\n'),
|
||||||
|
@ -63,7 +63,7 @@ export function fromHtml(html: string, hashtagNames?: string[], quoteUri?: strin
|
||||||
const href = node.attrs.find(x => x.name === 'href');
|
const href = node.attrs.find(x => x.name === 'href');
|
||||||
|
|
||||||
// hashtags
|
// hashtags
|
||||||
if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) {
|
if (txt.startsWith('#') && href && /\btag\b/.test(rel?.value)) {
|
||||||
text += txt;
|
text += txt;
|
||||||
// mentions
|
// mentions
|
||||||
} else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) {
|
} else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) {
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { IObject } from '../type.js';
|
|
||||||
import { extractApHashtagObjects } from '../models/tag.js';
|
|
||||||
import { fromHtml } from '@/mfm/from-html.js';
|
|
||||||
|
|
||||||
export function htmlToMfm(html: string, tag?: IObject | IObject[], quoteUri?: string | null) {
|
|
||||||
const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null);
|
|
||||||
|
|
||||||
return fromHtml(html, hashtagNames, quoteUri);
|
|
||||||
}
|
|
|
@ -16,11 +16,11 @@ import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||||
import { getApLock } from '@/misc/app-lock.js';
|
import { getApLock } from '@/misc/app-lock.js';
|
||||||
import { createMessage } from '@/services/messages/create.js';
|
import { createMessage } from '@/services/messages/create.js';
|
||||||
import { StatusError } from '@/misc/fetch.js';
|
import { StatusError } from '@/misc/fetch.js';
|
||||||
|
import { fromHtml } from '@/mfm/from-html.js';
|
||||||
import { parseAudience } from '../audience.js';
|
import { parseAudience } from '../audience.js';
|
||||||
import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type.js';
|
import { IObject, getOneApId, getApId, getOneApHrefNullable, validPost, IPost, isEmoji, getApType } from '../type.js';
|
||||||
import DbResolver from '../db-resolver.js';
|
import DbResolver from '../db-resolver.js';
|
||||||
import Resolver from '../resolver.js';
|
import Resolver from '../resolver.js';
|
||||||
import { htmlToMfm } from '../misc/html-to-mfm.js';
|
|
||||||
import { apLogger } from '../logger.js';
|
import { apLogger } from '../logger.js';
|
||||||
import { resolvePerson } from './person.js';
|
import { resolvePerson } from './person.js';
|
||||||
import { resolveImage } from './image.js';
|
import { resolveImage } from './image.js';
|
||||||
|
@ -199,7 +199,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver =
|
||||||
} else if (typeof note._misskey_content !== 'undefined') {
|
} else if (typeof note._misskey_content !== 'undefined') {
|
||||||
text = note._misskey_content;
|
text = note._misskey_content;
|
||||||
} else if (typeof note.content === 'string') {
|
} else if (typeof note.content === 'string') {
|
||||||
text = htmlToMfm(note.content, note.tag, quote?.uri);
|
text = fromHtml(note.content, quote?.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// vote
|
// vote
|
||||||
|
|
|
@ -24,7 +24,6 @@ import { uriPersonCache } from '@/services/user-cache.js';
|
||||||
import { publishInternalEvent } from '@/services/stream.js';
|
import { publishInternalEvent } from '@/services/stream.js';
|
||||||
import { db } from '@/db/postgre.js';
|
import { db } from '@/db/postgre.js';
|
||||||
import { apLogger } from '../logger.js';
|
import { apLogger } from '../logger.js';
|
||||||
import { htmlToMfm } from '../misc/html-to-mfm.js';
|
|
||||||
import { fromHtml } from '@/mfm/from-html.js';
|
import { fromHtml } from '@/mfm/from-html.js';
|
||||||
import { isCollectionOrOrderedCollection, isCollection, IActor, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue, getApType, isActor } from '../type.js';
|
import { isCollectionOrOrderedCollection, isCollection, IActor, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue, getApType, isActor } from '../type.js';
|
||||||
import Resolver from '../resolver.js';
|
import Resolver from '../resolver.js';
|
||||||
|
@ -185,7 +184,7 @@ export async function createPerson(uri: string, resolver?: Resolver = new Resolv
|
||||||
|
|
||||||
await transactionalEntityManager.save(new UserProfile({
|
await transactionalEntityManager.save(new UserProfile({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
description: person.summary ? htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null,
|
description: person.summary ? fromHtml(truncate(person.summary, summaryLength)) : null,
|
||||||
url: getOneApHrefNullable(person.url),
|
url: getOneApHrefNullable(person.url),
|
||||||
fields,
|
fields,
|
||||||
birthday: bday ? bday[0] : null,
|
birthday: bday ? bday[0] : null,
|
||||||
|
@ -361,7 +360,7 @@ export async function updatePerson(uri: string, resolver?: Resolver = new Resolv
|
||||||
await UserProfiles.update({ userId: exist.id }, {
|
await UserProfiles.update({ userId: exist.id }, {
|
||||||
url: getOneApHrefNullable(person.url),
|
url: getOneApHrefNullable(person.url),
|
||||||
fields,
|
fields,
|
||||||
description: person.summary ? htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null,
|
description: person.summary ? fromHtml(truncate(person.summary, summaryLength)) : null,
|
||||||
birthday: bday ? bday[0] : null,
|
birthday: bday ? bday[0] : null,
|
||||||
location: person['vcard:Address'] || null,
|
location: person['vcard:Address'] || null,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue