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