ちんこ
守矢諏訪子 <suwako@076.moe>、2026-11-11 15:24
コミット a764d87e34735bcddafa95308744e259130f2218
・親 90fc153
・ファイルを見る
2個のファイル、+50 -1
| @@ -539,7 +539,7 @@ | ||
| 539 | 539 | 'original' => self::safeUrl(is_string($o['url'] ?? null) ? $o['url'] : $id), |
| 540 | 540 | 'author' => $this->who($authorUrl), |
| 541 | 541 | 'booster' => ($e['type'] ?? '') === 'boost' ? $this->who($e['actor']) : null, |
| 542 | - 'content' => Html::sanitize((string)($o['content'] ?? '')), | |
| 542 | + 'content' => $this->localMentionLinks(Html::sanitize((string)($o['content'] ?? '')), $o), | |
| 543 | 543 | 'summary' => (string)($o['summary'] ?? ''), |
| 544 | 544 | 'sensitive' => (bool)($o['sensitive'] ?? false) || ($o['summary'] ?? '') !== '', |
| 545 | 545 | 'attachments' => $attachments, |
| @@ -605,6 +605,38 @@ | ||
| 605 | 605 | ]; |
| 606 | 606 | } |
| 607 | 607 | |
| 608 | + /** | |
| 609 | + * 本文のメンションのリンクを、相手のサーバーではなくこのサイトのプロフィールのページ(/microblog/remote等)にする | |
| 610 | + * 投稿のtag(Mention)でアクターが分かるリンクだけ。ログインしていなければ他のサーバーに問い合わせないので、 | |
| 611 | + * キャッシュしているアクターだけ(それ以外は元のリンクのまま) | |
| 612 | + * | |
| 613 | + * @param string $html 安全にした本文 | |
| 614 | + * @param array $o 投稿(Note等) | |
| 615 | + * @return string | |
| 616 | + */ | |
| 617 | + private function localMentionLinks(string $html, array $o): string { | |
| 618 | + $actors = []; | |
| 619 | + foreach ((array)($o['tag'] ?? []) as $t) { | |
| 620 | + if (!is_array($t) || ($t['type'] ?? '') !== 'Mention' || !is_string($t['href'] ?? null)) continue; | |
| 621 | + $actors[$t['href']] = $t['href']; | |
| 622 | + // Mastodon・Misskey等はリンクにプロフィールのURL(https://host/@user)を使うので、サーバーとユーザー名でも探す | |
| 623 | + $name = strtolower(explode('@', ltrim((string)($t['name'] ?? ''), '@'))[0]); | |
| 624 | + if ($name !== '') $actors[Fedi::domainOf($t['href']).'/'.$name] ??= $t['href']; | |
| 625 | + } | |
| 626 | + if (empty($actors)) return $html; | |
| 627 | + | |
| 628 | + return preg_replace_callback('#<a href="([^"]*)" class="([^"]*)"#', function(array $m) use ($actors): string { | |
| 629 | + $classes = explode(' ', $m[2]); | |
| 630 | + if (!in_array('mention', $classes, true) || in_array('hashtag', $classes, true)) return $m[0]; | |
| 631 | + $href = html_entity_decode($m[1], ENT_QUOTES | ENT_HTML5, 'UTF-8'); | |
| 632 | + $user = strtolower(ltrim(basename((string)parse_url($href, PHP_URL_PATH)), '@')); | |
| 633 | + $actor = $actors[$href] ?? $actors[Fedi::domainOf($href).'/'.$user] ?? null; | |
| 634 | + if ($actor === null) return $m[0]; | |
| 635 | + if ($this->me === null && !Fedi::isLocal($actor) && Remote::cachedActor($actor) === null) return $m[0]; | |
| 636 | + return '<a href="'.Html::esc($this->actorPage($actor)).'" class="'.$m[2].'"'; | |
| 637 | + }, $html) ?? $html; | |
| 638 | + } | |
| 639 | + | |
| 608 | 640 | /** ログイン中のユーザーとアクターの関係 */ |
| 609 | 641 | private function relation(string $url): array { |
| 610 | 642 | if ($this->me === null) return ['self' => false, 'can' => false]; |
| @@ -689,6 +721,8 @@ | ||
| 689 | 721 | $tmpl->assign('pagetit', $title); |
| 690 | 722 | $tmpl->assign('curPage', 'microblog'); |
| 691 | 723 | $tmpl->assign('menu', $this->getMenu()); |
| 724 | + $tmpl->assign('support', $this->getSupport()); | |
| 725 | + $tmpl->assign('sns', $this->getSns()); | |
| 692 | 726 | $tmpl->assign('description', SITEINFO['description']); |
| 693 | 727 | $tmpl->assign('user', $this->user); |
| 694 | 728 | $tmpl->assign('me', $this->me); |
| @@ -106,4 +106,19 @@ | ||
| 106 | 106 | |
| 107 | 107 | return $menu; |
| 108 | 108 | } |
| 109 | + | |
| 110 | + /** | |
| 111 | + * フッターの支援のリンク(alt、class、img、href、show) | |
| 112 | + * LittleBeastのフッターでは使わないが、サイトのフッターで表示する時の為に全部のページで割り当てる | |
| 113 | + */ | |
| 114 | + public function getSupport(): array { | |
| 115 | + return []; | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * フッターのSNSのリンク(getSupport()と同じ形) | |
| 120 | + */ | |
| 121 | + public function getSns(): array { | |
| 122 | + return []; | |
| 123 | + } | |
| 109 | 124 | } |