friendship ended with social-app. php is my new best friend
1<?php 2error_reporting(E_ALL); 3ini_set('display_errors', 'On'); 4ini_set('log_errors_max_len', '0'); 5 6require_once('vendor/autoload.php'); 7require_once('config.php'); 8require_once('lib/bskyToucher.php'); 9 10use League\CommonMark\CommonMarkConverter; 11use React\Promise\Deferred; 12use React\EventLoop\Loop; 13use React\Promise\Promise; 14use Tracy\Debugger; 15use Tracy\OutputDebugger; 16use Matrix\Async; 17 18$bskyToucher = new BskyToucher(); 19 20$favoriteFeeds = array_map(function ($feed) use ($bskyToucher) { 21 return $bskyToucher->getFeedInfo($feed); 22}, FAVORITE_FEEDS); 23 24function getPostOgImage(object $post): ?string { 25 if (!property_exists($post, 'embedType') || !$post->embedType) return null; 26 27 if ($post->embedType === 'app.bsky.embed.images') { 28 return $post->embeds[0]->imgUrl; 29 } else if ($post->embedType === 'app.bsky.embed.external' || $post->embedType === 'app.bsky.embed.video') { 30 return $post->embeds[0]->thumb; 31 } else if ($post->embedType === 'app.bsky.embed.record') { 32 return getPostOgImage($post->embeds[0]->post); 33 } 34 return null; 35} 36 37/*Debugger::enable(); 38// This where errors and exceptions will be logged. Make sure this directory exists and is writable. 39Debugger::$logDirectory = __DIR__ . '/../log/'; 40//Debugger::$strictMode = true; // display all errors 41// Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // all errors except deprecated notices 42if (Debugger::$showBar) { 43 // This is specific to the Tracy Extension for Flight if you've included that 44 // otherwise comment this out. 45 //new TracyExtensionLoader($app); 46}*/ 47 48Flight::set('frontpageFeed', FRONTPAGE_FEED); 49Flight::set('slingshotInstance', SLINGSHOT_INSTANCE); 50Flight::set('constellationInstance', CONSTELLATION_INSTANCE); 51Flight::set('plcDirectory', PLC_DIRECTORY); 52Flight::set('defaultPds', DEFAULT_PDS); 53Flight::set('publicApi', PUBLIC_API); 54Flight::set('frontpageFeed', FRONTPAGE_FEED); 55Flight::set('defaultRelay', DEFAULT_RELAY); 56Flight::set('userAuth', null); 57Flight::set('flight.log_errors', false); 58Flight::set('flight.handle_errors', false); 59Flight::set('flight.content_length', false); 60 61Flight::set('standardParams', [ 62 'siteTitle' => SITE_TITLE, 63 'themes' => THEMES, 64 'fonts' => FONTS, 65 'setTheme' => array_key_exists('sbs_theme', $_COOKIE) ? $_COOKIE['sbs_theme'] : DEFAULT_THEME, 66 'setFont' => array_key_exists('sbs_font', $_COOKIE) ? $_COOKIE['sbs_font'] : DEFAULT_FONT, 67 'userAuth' => Flight::get('userAuth'), 68 'favFeeds' => $favoriteFeeds, 69 'pages' => PAGES, 70 'links' => LINKS, 71 'ogdomain' => SITE_DOMAIN 72]); 73 74Flight::route('/', function () { 75 $bskyToucher = new BskyToucher(); 76 $posts = $bskyToucher->getFeed(Flight::get('frontpageFeed')); 77 $feedInfo = $bskyToucher->getFeedInfo(Flight::get('frontpageFeed')); 78 $latte = new Latte\Engine; 79 $latte->render('./templates/home.latte', array_merge(Flight::get('standardParams'), [ 80 'mainClass' => 'home feed', 81 'feedInfo' => $feedInfo, 82 'posts' => $posts->feed, 83 'cursor' => $posts->cursor, 84 'feedAtUri' => FRONTPAGE_FEED, 85 'ogtitle' => SITE_TITLE, 86 'ogdesc' => SITE_DESC, 87 'ogimage' => '', 88 'ogurl' => SITE_DOMAIN.'/' 89 ])); 90}); 91 92Flight::route('/u/@handle:[a-z0-9\.]+/@rkey:[a-z0-9]+', function (string $handle, string $rkey): void { 93 $bskyToucher = new BskyToucher(); 94 $post = $bskyToucher->getPost($handle, $rkey, Flight::get('userAuth') === null); 95 $atUri = 'at://'.$post->author->did.'/app.bsky.feed.post/'.$rkey; 96 $latte = new Latte\Engine; 97 $latte->render('./templates/single.latte', array_merge(Flight::get('standardParams'), [ 98 'mainClass' => 'post', 99 'post' => $post, 100 'ogtitle' => SITE_TITLE." | ".$post->author->displayName." (@".$post->author->handle.")", 101 'ogdesc' => $post->content, 102 'ogimage' => getPostOgImage($post), 103 'ogurl' => SITE_DOMAIN.'/u/'.$handle.'/'.$rkey 104 ])); 105}); 106 107Flight::route('/u/@handle:[a-z0-9\.]+(/@tab:[a-z]+)', function (string $handle, ?string $tab): void { 108 $bskyToucher = new BskyToucher(); 109 $user = $bskyToucher->getUserInfo($handle, 'handle'); 110 $posts = $bskyToucher->getUserPosts($user->did); 111 $latte = new Latte\Engine; 112 $latte->render('./templates/profile.latte', array_merge(Flight::get('standardParams'), [ 113 'mainClass' => 'profile', 114 'handle' => $handle, 115 'posts' => $posts, 116 'user' => $user, 117 'ogtitle' => SITE_TITLE." | ".$user->displayName." (@".$user->handle.")", 118 'ogdesc' => $user->description, 119 'ogimage' => $user->avatar, 120 'ogurl' => SITE_DOMAIN.'/u/'.$user->handle.'/' 121 ])); 122}); 123 124Flight::route('/f/@did:did:plc:[0-9a-z]+/@name:[a-z0-9\-\_]+', function (string $did, string $name): void { 125 $bskyToucher = new BskyToucher(); 126 $feedUrl = "at://".$did."/app.bsky.feed.generator/".$name; 127 $feedInfo = $bskyToucher->getFeedInfo($feedUrl); 128 $creatorInfo = $bskyToucher->getUserInfo($feedInfo->creatorDid, 'did'); 129 $posts = $bskyToucher->getFeed($feedUrl); 130 $latte = new Latte\Engine; 131 $latte->render('./templates/feed.latte', array_merge(Flight::get('standardParams'), [ 132 'mainClass' => 'feed', 133 'posts' => $posts->feed, 134 'cursor' => $posts->cursor, 135 'feedName' => $feedInfo->title, 136 'feedAvatar' => $feedInfo->avatar, 137 'feedDescription' => $feedInfo->description, 138 'feedAtUri' => $feedUrl, 139 'feedAuthorName' => $creatorInfo->displayName, 140 'feedAuthorHandle' => $creatorInfo->handle, 141 'feedAuthorDid' => $creatorInfo->did, 142 'feedAuthorPds' => $creatorInfo->pds, 143 'ogtitle' => SITE_TITLE." | ".$feedInfo->title, 144 'ogdesc' => $feedInfo->description, 145 'ogimage' => $feedInfo->avatar, 146 'ogurl' => SITE_DOMAIN.'/f/'.$did.'/'.$name 147 ])); 148}); 149 150Flight::route('/s', function (): void { 151 $latte = new Latte\Engine; 152 $latte->render('./templates/search.latte', array_merge(Flight::get('standardParams'), [ 153 'mainClass' => 'search', 154 'params' => $_GET, 155 'ogtitle' => SITE_TITLE." | search".(array_key_exists('s', $_GET) ? ': '.$_GET['s'] : ''), 156 'ogdesc' => SITE_DESC, 157 'ogimage' => '', 158 'ogurl' => SITE_DOMAIN.'/u/'.$handle.'/'.$rkey 159 ])); 160}); 161 162Flight::route('GET /login', function(): void { 163 $latte = new Latte\Engine; 164 $latte->render('./templates/login.latte', array_merge(Flight::get('standardParams'), [ 165 'mainClass' => 'form', 166 'ogtitle' => SITE_TITLE." | login", 167 'ogdesc' => SITE_DESC, 168 'ogimage' => '', 169 'ogurl' => SITE_DOMAIN.'/login' 170 ])); 171}); 172 173Flight::route('POST /login', function(): void { 174 // whatever stupid token exchange dance needs to happen to direct them to oauth 175}); 176 177Flight::route('/createaccount', function(): void { 178 $latte = new Latte\Engine; 179 $latte->render('./templates/create.latte', array_merge(Flight::get('standardParams'), [ 180 'mainClass' => 'form', 181 'ogtitle' => SITE_TITLE." | create account", 182 'ogdesc' => SITE_DESC, 183 'ogimage' => '', 184 'ogurl' => SITE_DOMAIN.'/createaccount' 185 ])); 186}); 187 188Flight::route('/api/@endpoint', function (string $endpoint): void { 189 $bskyToucher = new BskyToucher(); 190 $latte = new Latte\Engine; 191 if ($endpoint === 'userPosts') { 192 if (!array_key_exists('user', $_GET)) Flight::json(["error" => "missing user in query"]); 193 if (!preg_match('/^did:plc:([a-z0-9]+)$/', $_GET['user'], $_out)) Flight::json(["error" => "malformed user DID"]); 194 $user = $_GET['user']; 195 $auth = false; // TODO: set up so that it's like. actually dynamic later 196 $cursor = array_key_exists('cursor', $_GET) ? $_GET['cursor'] : 0; 197 $posts = $bskyToucher->getUserPosts($user, $cursor, $auth); 198 $latte->render('./templates/_partials/feedPosts.latte', array_merge(Flight::get('standardParams'), [ 199 'posts' => $posts 200 ])); 201 return; 202 } else if ($endpoint === 'feedPosts') { 203 if (!array_key_exists('feed', $_GET)) Flight::json(["error" => "missing feed uri in query"]); 204 if (!preg_match('/^at:\/\/(did:plc:[a-z0-9]+)\/app.bsky.feed.generator\/([a-z0-9]+)$/', $_GET['feed'], $_out)) Flight::json(["error" => "malformed at-uri representing feed", "feed" => $_GET['feed']]); 205 $cursor = array_key_exists('cursor', $_GET) ? $_GET['cursor'] : 0; 206 $auth = false; // TODO: again. once i figure out auth 207 $posts = $bskyToucher->getFeed($_GET['feed'], $cursor, $auth); 208 if ($posts) { 209 $html = $latte->renderToString('./templates/_partials/feedPosts.latte', array_merge(Flight::get('standardParams'), [ 210 'posts' => $posts->feed 211 ])); 212 Flight::json(['posts' => $html, 'cursor' => $posts->cursor]); 213 } 214 } else if ($endpoint === 'notifs') { 215 216 } 217}); 218 219Flight::route('/@page', function (string $page): void { 220 $latte = new Latte\Engine; 221 $converter = new CommonMarkConverter(); 222 $md = $converter->convert(file_get_contents('./pages/'.$page.'.md')); 223 $latte->render('./templates/page.latte', array_merge(Flight::get('standardParams'), [ 224 'mainClass' => 'page', 225 'content' => $md, 226 'ogtitle' => SITE_TITLE." | ".$page, 227 'ogdesc' => SITE_DESC, 228 'ogimage' => '', 229 'ogurl' => SITE_DOMAIN.'/'.$page 230 ])); 231}); 232 233Flight::start(); 234 235?>