require 'Res/FastVoltMarkdown.php'; use FastVolt\Helper\Markdown; $markdown = Markdown::new(); $instance = 'https://memos.octt.eu.org'; $footer = ""; $id = $_GET['id']; $uid = $_GET['uid']; function uidfromdata ( $data ) { return explode( '%', explode( '%12%16', urlencode($data) )[1] )[0]; } if ( !$id && !$uid ) { // when no memo is specified, show links to the latest ones // the JSON API won't list memos without auth, so we (mis)use the GRPC one $memos = array_slice( explode( "\n\tmemos/", file_get_contents( "{$instance}/memos.api.v1.MemoService/ListMemos", false, stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => 'Content-Type: application/grpc-web+proto', 'content' => urldecode('%00%00%00%008%08%10%1A4row_status%20%3D%3D%20%22NORMAL%22%20%26%26%20visibilities%20%3D%3D%20%5B\'PUBLIC\'%5D'), ]]) ) ), 1 ); $titletitle = 'Latest public memos'; if ( $_GET['rss'] ) { header('Content-Type: application/rss+xml; charset=utf-8'); echo ''; echo "{$titletitle}{$instance}"; foreach ( $memos as $memo ) { if ( ($uid = uidfromdata($memo)) ) { echo "{$uid}{$instance}/m/{$uid}"; } } echo ''; } else { echo "{$titletitle}

Latest public memos from {$instance}:

{$footer}"; } return; } // pre-v0.22.4 //if ( !$id ) { // // as of writing this, there is no JSON API to get a memo by its uid // // so, we first get the numeric id by sloppily parsing the GRPC API // $id = explode( '%', urlencode(explode( 'memos/', file_get_contents( "{$instance}/memos.api.v1.MemoService/SearchMemos", false, stream_context_create([ 'http' => [ // 'method' => 'POST', // 'header' => 'Content-Type: application/grpc-web+proto', // 'content' => urldecode('%00%00%00%00!%0A%1Fuid%20%3D%3D%20%22' . $uid . '%22'), // ]]) ) )[1]))[0]; //} $base = file_get_contents($instance); $warning = ''; if ( $_GET['structure'] === 'original' ) { $warning = ''; } // pre-v0.22.4 //if ( !$id ) { // http_response_code(400); // echo $base; // return; //} // pre-v0.22.4: we always use the numeric id to get memo data via the JSON API //$memo = json_decode(file_get_contents("{$instance}/api/v1/memos/{$id}")); $idoruidendpoint = ($uid ? "memos:by-uid/{$uid}" : "memos/{$id}"); $memo = json_decode(file_get_contents("{$instance}/api/v1/{$idoruidendpoint}")); // post-v0.22.4 $user = json_decode(file_get_contents("{$instance}/api/v1/{$memo->creator}")); // patch Markdown before parsing it, so output is quasi-consistent with Memos $content = ''; $inblock = false; $lines = explode( "\n", $memo->content ); foreach ( $lines as $line ) { if ( str_starts_with( $line, '```' ) ) { $inblock = !$inblock; } else if ( !$inblock && str_starts_with( $line, '#' ) ) { // prevent hashtags from being interpreted as headings $firstword = explode( ' ', str_replace( "\t", ' ', $line ) )[0]; if ( $firstword !== '#' ) { $content .= " {$firstword}"; $line = substr( $line, strlen($firstword) ); } } $content .= $line . "\n"; if ( !$inblock ) { // the parser won't support Markdown natural-linebreak mode, so add \n's $content .= "\n"; } } $markdown->setContent($content); $content = $markdown->toHtml(); $htmlparts = explode( '
', $content );
$content = array_shift($htmlparts);
foreach ( $htmlparts as $part ) {
	[$inside, $after] = explode( '
', $part ); //$content .= '
' . $inside . '
' . $after; $content .= '' . $after; } $nickname = htmlspecialchars($user->nickname); $pagetitle = "Memo by {$nickname}"; $pagedescription = htmlspecialchars($memo->content); $htmlimage = implode( '', array_slice( explode( '"', implode( '', array_slice( explode( '"; } $meta = " {$pagetitle} {$htmlimage} "; $body = "
{$nickname} on {$memo->displayTime} [JSON] {$warning}
{$content}
{$footer}
"; $base = str_replace( 'Memos', '', $base ); $base = str_replace( "", "{$meta}", $base ); $base = str_replace( "
", "
{$body}
", $base ); echo $base;