friendship ended with social-app. php is my new best friend

rejigger autoload; delete some unneeded files; readme updates

+14 -3
README.md
···
## tdl
* [X] Move profile rendering to bskyRenderer lib file (and also fix the rendering)
+
* [X] Unmove profile rendering and then move it to template files
* [X] Implement feeds page (still dependent on bsky)
* [X] Implement search (still dependent on bsky)
* [ ] Make settings page???
···
* [X] Hashtag feed page (still dependent on bsky)
* [ ] Move interaction stuff to the renderer
* [X] Apply facets to text
-
* [ ] Templating engine??
+
* [X] Templating engine??
* [ ] Make login page actually work
* [ ] Figure out how to do threading
* [ ] User authentication (:C)
···
## thanks to
+
* [pdsls.dev](https://pdsls.dev) for helping me figure out what API endpoints to call from the network tab
* [constellation](https://constellation.microcosm.blue) and [slingshot](https://slingshot.microcosm.blue) for a lot of data fetching to reduce load on PDS + dependence on bsky.app
* [plc.directory](https://plc.directory) and [plc.parakeet.at](https://plc.parakeet.at) for plc lookups
-
* [pdsls.dev](https://pdsls.dev) for helping me figure out what API endpoints to call from the network tab
* [red dwarf](https://reddwarf.whey.party) for being inspirational (and *also* helping me figure out what API endpoints to call)
+
* [bailey townsend]() because i stared at your rust oauth code for several hours trying to divine how to make PHP work. thank you
+
+
## dependencies
+
+
* guzzle (for http requests)
+
* monolog (for logging; mostly just a dev thing)
+
* flight (for routing)
+
* latte (for templating)
+
* opengraph (for what you'd expect)
+
* php-oauth (also for what you'd expect)
## suppose i am someone who wanted to install this
ok wowee!! just so you know this isn't fully cooked yet so there's a lot of features missing. there's a lot of stuff that goes into one of these things as it turns out. but if you really want to:
-
- edit the values in config.php. if you don't have a pds you're willing to let people sign up with (or don't know what that is) just leave it set as-is. if you have a particular feed you want to show on the front page, set that there; otherwise it defaults to bird pictures
+
- edit the values in config.php. if you don't have a pds you're willing to let people sign up with or don't have a favorite (or don't know what that is) just leave it set as-is. you'll need to graph the atURIs of feeds to use for your frontpage/favorite feeds area; you can look those up using [pdsls.dev](https://pdsls.dev).
- copy .env.example to .env and add your secret values to it.
- copy the files in the data folder and remove the .example suffix. these are for globally banning/suspending people at the client level (e.g. if you just don't want anyone to be able to see j*sse s*ngal on your client).
- get [composer](https://getcomposer.org) if you don't have it and then do `composer install` in the folder
+5 -4
index.php
···
]));
});
-
Flight::route('/u/\@@handle/@rkey', function (string $handle, string $rkey): void {
+
Flight::route('/u/@handle:[a-z0-9\.]+/@rkey:[a-z0-9]+', function (string $handle, string $rkey): void {
$bskyToucher = new BskyToucher();
$post = $bskyToucher->getPost($handle, $rkey, Flight::get('userAuth') === null);
$atUri = 'at://'.$post->did.'/app.bsky.feed.post/'.$rkey;
···
]));
});
-
Flight::route('/u/\@@handle(/@tab)', function (string $handle, ?string $tab): void {
+
Flight::route('/u/@handle:[a-z0-9\.]+(/@tab:[a-z]+)', function (string $handle, ?string $tab): void {
$latte = new Latte\Engine;
$latte->render('./templates/profile.latte', array_merge(Flight::get('standardParams'), [
'handle' => $handle,
···
]));
});
-
Flight::route('/f/@did/@name', function (string $did, string $name): void {
+
Flight::route('/f/@did:did:plc:[0-9a-z]+/@name:[a-z0-9\-\_]+', function (string $did, string $name): void {
$bskyToucher = new BskyToucher();
$feedUrl = "at://".$did."/app.bsky.feed.generator/".$name;
$feedInfo = $bskyToucher->getFeedInfo("at://".$did."/app.bsky.feed.generator/".$name);
···
Flight::route('/s', function (): void {
$latte = new Latte\Engine;
$latte->render('./templates/search.latte', array_merge(Flight::get('standardParams'), [
-
'mainClass' => 'search'
+
'mainClass' => 'search',
+
'params' => $_GET
]));
});
-3
oauth/callback.php
···
-
<?php
-
-
?>
-36
oauth/router.php
···
-
<?php
-
require_once('config.php');
-
require_once('lib/bskyOperations.php');
-
require_once('lib/bskyProvider.php');
-
require_once('vendor/autoload.php');
-
-
use chillerlan\OAuth\Core\{OAuthInterface, OAuth2Provider};
-
use chillerlan\OAuth\OAuthOptions;
-
use chillerlan\OAuth\Storage\SessionStorage;
-
use GuzzleHttp\Client;
-
use GuzzleHttp\Psr7\HttpFactory;
-
-
use Smallnest\BskyOps\BskyToucher;
-
use Smallnest\BskyProvider\Bsky;
-
-
$bskyToucher = new BskyToucher();
-
-
if (array_key_exists('username', $_GET)) {
-
$user = htmlspecialchars($_GET['username']);
-
[$_, $pds] = $bskyToucher->getUserDidAndProvider($user);
-
-
if ($pds) {
-
$httpOptions = [
-
'verify' => '/path/to/cacert.pem',
-
'headers' => [
-
'User-Agent' => OAuthInterface::USER_AGENT,
-
],
-
];
-
$http = new \GuzzleHttp\Client($httpOptions);
-
$provider = new Bsky($options, $http, new HttpFactory, new HttpFactory, new HttpFactory, $storage);
-
$provider->setPds($pds);
-
header('Location: '.$provider->getAuthorizationUrl([], []));
-
}
-
}
-
die(1);
-
?>
+8 -1
pages/about.md
···
the ethos of smallbird social is to be as low-tech as possible. as few dependencies as possible, as little javascript as possible. we are mostly on the internet of 2003 here. this also means there are no apps. nothing is going in an app store although i intend for this to be as mobile-friendly as possible but i do not want to deal with 1) building an app and 2) dealing with the app store review process, which would mean this whole process would be subject to censorship.
**I'm in Mississippi and I can't see your website?**
-
Sorry, I am one woman and can't deal with potentially incurring a fuckton in fines if someone decides i look legit enough.
+
Sorry, I am one woman and can't deal with potentially incurring a fuckton in fines if someone decides i look legit enough.
+
+
### server information
+
+
**Public API Subscription:** api.public.bsky.app, until another appview exists
+
**Constellation Subscription:** constellation.snek.cc
+
**Slingshot Subscription:** slingshot.microcosm.blue
+
**PLC Directory:** plc.directory
+10 -1
public/config.php
···
# some options are
# - myatproto.social (run by blacksky)
# - cryptoanarchy.net (run by blacksky)
+
# - sprk.so
define('DEFAULT_RELAY', "https://relay.fire.hose.cam");
# some relay options:
+
# - bsky.network (you know who runs this)
+
# - relay1.us-east.bsky.network (bsky US east)
+
# - relay1.us-west.bsky.network (bsky US west)
# - relay3.fr.hose.cam (france)
# - relay.fire.hose.cam (montreal)
# - relay-ovh.demo.bsky.dev
-
# - wherever the core rsky one is
+
# - atproto.africa (blacksky)
+
# - relay.upcloud.world (upcloud)
+
# - relay.hayescmd.net (edavis.dev)
+
# - relay.xero.systems (dane.is.extraordinarily.cool)
+
# - relay.feeds.blue (mackuba.eu; self-hosted only)
define('PLC_DIRECTORY', "https://plc.directory");
# other plc directory options:
# - https://plc.parakeet.at/
···
define('PRETTY_URLS', false);
define('DEFAULT_THEME', "catppuccin");
define('DEFAULT_FONT', "recursive");
+
define('THREAD_POST_COUNT', 5);
?>
-1
templates/layout.latte
···
<h1><a href="/">{include '_partials/logo.latte'}{$siteTitle}</a></h1>
</header>
{include '_partials/nav.latte'}
-
hi
<main class={$mainClass}>
{block content}{/block}
</main>
+5 -2
templates/search.latte
···
<form class="searchForm" method="POST">
<div class="form-input">
<label>Query</label>
-
<p class="help">Search is limited to this instance's local flock of PDSes!</p>
+
<p class="help">Search is limited to this instance's flock of PDSes!</p>
<input type="text" name="search" id="search" />
</div>
<div class="form-input btn-row">
<button type="submit" class="btn btn-primary">Search</button>
</div>
-
</form>
+
</form>
+
<div id="results">
+
+
</div>
+6 -1
templates/settings.latte
···
-
{layout 'layout.latte'}
+
{layout 'layout.latte'}
+
+
{block content}
+
<h2>Settings</h2>
+
At some point settings will go here!
+
{/block}
+23 -23
templates/single.latte
···
{layout 'layout.latte'}
{include '_partials/post.latte', post: $post}
-
<div id="interactions">
-
<button type="button" popovertarget="likes" class="btn-invis">See Likes</button> <button type="button" popovertarget="reposts" class="btn-invis">See Reposts</button> <button type="button" popovertarget="quotes" class="btn-invis">See Quotes</button>
-
</div>
-
<div id="likes" popover>
-
{foreach $post->likes as $like}
-
{include 'profile_mini.latte', user: $like}
-
{/foreach}
-
</div>
-
<div id="reposts" popover>
-
{foreach $post->reposts as $repost}
-
{include 'profile_mini.latte', user: $repost}
-
{/foreach}
-
</div>
-
<div id="quotes" popover>
-
{foreach $post->quotes as $quote}
-
{include 'post.latte', post: $quote}
-
{/foreach}
-
</div>
-
<div id="replies">
-
{foreach $post->replies as $reply}
-
{include 'post.latte', post: $reply}
-
{/foreach}
-
</div>
+
<div id="interactions">
+
<button type="button" popovertarget="likes" class="btn-invis">See Likes</button> <button type="button" popovertarget="reposts" class="btn-invis">See Reposts</button> <button type="button" popovertarget="quotes" class="btn-invis">See Quotes</button>
+
</div>
+
<div id="likes" popover>
+
{foreach $post->likes as $like}
+
{include 'profile_mini.latte', user: $like}
+
{/foreach}
+
</div>
+
<div id="reposts" popover>
+
{foreach $post->reposts as $repost}
+
{include 'profile_mini.latte', user: $repost}
+
{/foreach}
+
</div>
+
<div id="quotes" popover>
+
{foreach $post->quotes as $quote}
+
{include 'post.latte', post: $quote}
+
{/foreach}
+
</div>
+
<div id="replies">
+
{foreach $post->replies as $reply}
+
{include 'post.latte', post: $reply}
+
{/foreach}
+
</div>
+1 -1
vendor/autoload.php
···
require_once __DIR__ . '/composer/autoload_real.php';
-
return ComposerAutoloaderInitd5149d77d4e37381fd8c08eb5617487a::getLoader();
+
return ComposerAutoloaderInit084207acd9d27dbf5822b930886b2c3d::getLoader();
+5 -5
vendor/composer/autoload_real.php
···
// autoload_real.php @generated by Composer
-
class ComposerAutoloaderInitd5149d77d4e37381fd8c08eb5617487a
+
class ComposerAutoloaderInit084207acd9d27dbf5822b930886b2c3d
{
private static $loader;
···
require __DIR__ . '/platform_check.php';
-
spl_autoload_register(array('ComposerAutoloaderInitd5149d77d4e37381fd8c08eb5617487a', 'loadClassLoader'), true, true);
+
spl_autoload_register(array('ComposerAutoloaderInit084207acd9d27dbf5822b930886b2c3d', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
-
spl_autoload_unregister(array('ComposerAutoloaderInitd5149d77d4e37381fd8c08eb5617487a', 'loadClassLoader'));
+
spl_autoload_unregister(array('ComposerAutoloaderInit084207acd9d27dbf5822b930886b2c3d', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
-
call_user_func(\Composer\Autoload\ComposerStaticInitd5149d77d4e37381fd8c08eb5617487a::getInitializer($loader));
+
call_user_func(\Composer\Autoload\ComposerStaticInit084207acd9d27dbf5822b930886b2c3d::getInitializer($loader));
$loader->register(true);
-
$filesToLoad = \Composer\Autoload\ComposerStaticInitd5149d77d4e37381fd8c08eb5617487a::$files;
+
$filesToLoad = \Composer\Autoload\ComposerStaticInit084207acd9d27dbf5822b930886b2c3d::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+5 -5
vendor/composer/autoload_static.php
···
namespace Composer\Autoload;
-
class ComposerStaticInitd5149d77d4e37381fd8c08eb5617487a
+
class ComposerStaticInit084207acd9d27dbf5822b930886b2c3d
{
public static $files = array (
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
···
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
-
$loader->prefixLengthsPsr4 = ComposerStaticInitd5149d77d4e37381fd8c08eb5617487a::$prefixLengthsPsr4;
-
$loader->prefixDirsPsr4 = ComposerStaticInitd5149d77d4e37381fd8c08eb5617487a::$prefixDirsPsr4;
-
$loader->prefixesPsr0 = ComposerStaticInitd5149d77d4e37381fd8c08eb5617487a::$prefixesPsr0;
-
$loader->classMap = ComposerStaticInitd5149d77d4e37381fd8c08eb5617487a::$classMap;
+
$loader->prefixLengthsPsr4 = ComposerStaticInit084207acd9d27dbf5822b930886b2c3d::$prefixLengthsPsr4;
+
$loader->prefixDirsPsr4 = ComposerStaticInit084207acd9d27dbf5822b930886b2c3d::$prefixDirsPsr4;
+
$loader->prefixesPsr0 = ComposerStaticInit084207acd9d27dbf5822b930886b2c3d::$prefixesPsr0;
+
$loader->classMap = ComposerStaticInit084207acd9d27dbf5822b930886b2c3d::$classMap;
}, null, ClassLoader::class);
}
+2 -2
vendor/composer/installed.php
···
'name' => '__root__',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
-
'reference' => '1449c15d703431251e83d08dde0e9b6ac4875dbf',
+
'reference' => '17a2b5d2e68ab0da5b500ef4ae0fc450b64a0b69',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
···
'__root__' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
-
'reference' => '1449c15d703431251e83d08dde0e9b6ac4875dbf',
+
'reference' => '17a2b5d2e68ab0da5b500ef4ae0fc450b64a0b69',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),