diff --git a/.gitignore b/.gitignore index 7bb4750..75327c4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ output/qr-codes # Served icons output/icons +# Served listings +listings/lp-output + # Server-side cache cache diff --git a/.phpenv b/.phpenv index ea4ce88..a6eb760 100644 --- a/.phpenv +++ b/.phpenv @@ -11,23 +11,13 @@ $ROOM_ICONS="$DOCUMENT_ROOT/icons"; $ROOM_ICONS_RELATIVE="icons"; - $REPOSITORY_CANONICAL_URL="https://codeberg.org/gravel/sessioncommunities.online"; - - include_once "$PROJECT_ROOT/php/utils/logging.php"; - - // Read the -v|--verbose option increasing logging verbosity to debug. - $options = getopt("vn", ["verbose", "fast", "no-color", "dry-run"]); - if (isset($options["v"]) or isset($options["verbose"])) { - $LOGGING_VERBOSITY = LoggingVerbosity::Debug; - } + $LISTING_PROVIDER_ROOT="$PROJECT_ROOT/listings"; + $LISTINGS_INI="$LISTING_PROVIDER_ROOT/listings.ini"; + $LISTING_PROVIDER_OUTPUT="$LISTING_PROVIDER_ROOT/lp-output"; + $LISTING_PROVIDER_LISTING_SUMMARY="$LISTING_PROVIDER_OUTPUT/listings"; + $LISTING_PROVIDER_LISTINGS="$LISTING_PROVIDER_OUTPUT/listing"; - $FAST_FETCH_MODE = (isset($options["fast"])); - - $DO_DRY_RUN = (isset($options["n"]) || isset($options["dry-run"])); - - if (isset($options["no-color"])) { - LoggingVerbosity::$showColor = false; - } + $REPOSITORY_CANONICAL_URL="https://codeberg.org/gravel/sessioncommunities.online"; // set timeout for file_get_contents() ini_set('default_socket_timeout', 6); // in seconds, default is 60 diff --git a/Makefile b/Makefile index 891a518..79933bd 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,10 @@ list: ## Using make dependencies is duplicating behaviour but reads better. # /bin/php php/update-listing.php # Refresh listing and generate HTML. -all: fetch html +sco: fetch html + +# Refresh listing, generate HTML and update listing provider. +all: fetch html listing # Fetch room listing. fetch: @@ -26,6 +29,10 @@ fetch-dry: html: /bin/php php/generate-html.php $(FLAGS) +# Generate listing provider endpoints from data. +listing: + /bin/php php/generate-listings.php $(FLAGS) + # Serve a local copy which responds to file changes. dev: FLAGS = --verbose dev: open diff --git a/listings/listings.ini b/listings/listings.ini new file mode 100644 index 0000000..1a0c8d6 --- /dev/null +++ b/listings/listings.ini @@ -0,0 +1,106 @@ + +[regional] +name=Regional Communities +rating=safe +rooms[]=brasil+118d +rooms[]=deutsch+118d +rooms[]=espanol+118d +rooms[]=francais+118d +rooms[]=iom+118d +rooms[]=italiano+118d +rooms[]=nl+118d +rooms[]=persian+118d +rooms[]=portugues+118d +rooms[]=uk+118d +rooms[]=russian+118d +rooms[]=bangladesh+13f6 +rooms[]=czsk+13f6 +rooms[]=india+13f6 +rooms[]=indonesia+13f6 +rooms[]=korea+13f6 +rooms[]=poland+13f6 +rooms[]=scandinavia+2812 +rooms[]=fi+2812 +rooms[]=br+2b92 +rooms[]=germanpoliticssocietyphilosophy+8183 +sogs[]=fe93941471c07f294255391dba92ae3cf356efc4fdd287d8ba1ffef096dbaf56 + +[tech] +name=Tech Communities +rating=safe +rooms[]=android+118d +rooms[]=ai+118d +rooms[]=gaming+118d +rooms[]=im+118d +rooms[]=linux+118d +rooms[]=webdev+118d +rooms[]=programming+13f6 +rooms[]=tech+2054 +rooms[]=ev-en+2812 +rooms[]=pv-en+2812 +rooms[]=gee+2b92 +rooms[]=mathnodes-dvpn-oxen-dero+8585 +rooms[]=plex+c01b + +[china] +name=Chinese-language Communities +rating=unknown +sogs[]=45674f4135e2dd929279a72e1e73957eed741c7bec00c87b1797ad52c235ea36 +sogs[]=7f55510a392324988041e7a97191f618a32dc05f2f6343de917fcfe1cb424e51 + +[powerusers] +name=Communities for Powerusers +rating=safe +rooms[]=snops+118d +rooms[]=sogops+118d +rooms[]=indexloki+2cbd +rooms[]=SNappsDevs+2cbd +rooms[]=sessiondev+e56f + +[misc] +name=Miscellanous +rating=unknown +rooms[]=health+118d +rooms[]=music+118d +rooms[]=modernsurvival+118d +rooms[]=philosophy+118d +rooms[]=pol+2054 +rooms[]=biz+2b92 +rooms[]=guns+2b92 +rooms[]=hall+7242 +rooms[]=camping+c01b +rooms[]=offtopic+e56f +rooms[]=AISFW+fc30 + +[oxen] +name=Official Communities +rating=safe +sogs[]=a03c383cf63c3c4efe67acc52112a6dd734b3a946b9545f488aaa93da7991238 + +[cryptocurrency] +name=Cryptocurrency +rooms[]=bitcoinaustralia+4bec +rooms[]=moneroaustralia+4bec +rooms[]=crypto+a03c + +[privsec] +name=Privacy & Security +rating=safe +rooms[]=im+118d +rooms[]=privacy+118d +rooms[]=security+118d +rooms[]=degoogle+48e9 +rooms[]=privacyaustralia+4bec + +[casual] +name=Casual Communities +rating=safe +rooms[]=general-chat+8c12 +rooms[]=midnight-madness+9be4 + +[nsfw] +name=18+ Communities +rating=nsfw +rooms[]=womanbodybeauty+13f6 +rooms[]=piao+2cd5 +rooms[]=AINSFW+fc30 \ No newline at end of file diff --git a/php/fetch-servers.php b/php/fetch-servers.php index fcd4c33..e36e265 100644 --- a/php/fetch-servers.php +++ b/php/fetch-servers.php @@ -2,6 +2,7 @@ // requires php-curl require_once 'getenv.php'; + require_once 'utils/getopt.php'; require_once 'utils/utils.php'; require_once 'servers/known-servers.php'; require_once 'utils/servers-rooms.php'; diff --git a/php/generate-html.php b/php/generate-html.php index 9034ccc..6cd874c 100644 --- a/php/generate-html.php +++ b/php/generate-html.php @@ -2,6 +2,7 @@ // Perform static site generation. require_once "getenv.php"; + require_once "utils/getopt.php"; // https://stackoverflow.com/a/17161106 function rglob($pattern, $flags = 0) { diff --git a/php/generate-listings.php b/php/generate-listings.php new file mode 100644 index 0000000..1e962d6 --- /dev/null +++ b/php/generate-listings.php @@ -0,0 +1,116 @@ +name = $name; + $this->rating = $rating ?? "unknown"; + $this->rooms = $rooms; + } + + public function jsonSerialize(): mixed { + // TODO: Careful serialization + $details = get_object_vars($this); + $details['rooms'] = array_map(function(\CommunityRoom $room){ + return $room->to_listing_data(); + }, $this->rooms); + return $details; + } + + public function to_summary(): array { + return array( + 'name' => $this->name, + 'rating' => $this->rating, + 'rooms' => count($this->rooms) + ); + } + } + + /** + * @return \CommunityListing[] + */ + function resolve_listings_config(): array { + global $LISTINGS_INI, $ROOMS_FILE; + $listings_raw = parse_ini_file($LISTINGS_INI, process_sections: true); + $servers_raw = file_get_contents($ROOMS_FILE); + $server_data = json_decode($servers_raw, true); + $servers = CommunityServer::from_details_array($server_data); + $rooms_by_id = []; + foreach (CommunityServer::enumerate_rooms($servers) as $room) { + $rooms_by_id[$room->get_room_identifier()] = $room; + } + $sogs_by_pubkey = []; + foreach ($servers as $server) { + $sogs_by_pubkey[$server->get_pubkey()] = $server; + } + $listings = []; + foreach ($listings_raw as $id => $listing_props) { + $rooms = []; + if (isset($listing_props['rooms'])) { + foreach ($listing_props['rooms'] as $room_id) { + if (isset($rooms_by_id[$room_id])) { + $rooms[] = $rooms_by_id[$room_id]; + } else { + log_warning("Could not find room $room_id from listing $id."); + } + } + } + if (isset($listing_props['sogs'])) { + foreach ($listing_props['sogs'] as $public_key) { + if (isset($sogs_by_pubkey[$public_key])) { + /** @var \CommunityServer $sogs */ + $sogs = $sogs_by_pubkey[$public_key]; + array_push($rooms, ...$sogs->rooms); + } else { + log_warning("Could not find sogs $public_key from listing $id."); + } + } + } + $listings[$id] = new CommunityListing( + $listing_props['name'], + $listing_props['rating'], + $rooms + ); + } + + return $listings; + } + + function generate_listings() { + global $LISTING_PROVIDER_LISTING_SUMMARY, $LISTING_PROVIDER_LISTINGS; + log_info("Generating listings..."); + + $listings_resolved = resolve_listings_config(); + log_value($listings_resolved); + $summaries = array_map(function(\CommunityListing $listing) { + return $listing->to_summary(); + }, $listings_resolved); + file_put_contents($LISTING_PROVIDER_LISTING_SUMMARY, json_encode($summaries)); + foreach ($listings_resolved as $id => $listing) { + file_put_contents( + "$LISTING_PROVIDER_LISTINGS/$id", + json_encode($listing) + ); + } + $listings_count = count($listings_resolved); + log_info("Generated $listings_count listings."); + } + + file_exists($LISTING_PROVIDER_LISTINGS) or mkdir($LISTING_PROVIDER_LISTINGS, 0755, true); + + $options = getopt("v", ["verbose"]); + if (isset($options["v"]) or isset($options["verbose"])) { + $LOGGING_VERBOSITY = LoggingVerbosity::Debug; + } + + generate_listings(); +?> \ No newline at end of file diff --git a/php/update-listing.php b/php/update-listing.php index 9cf40cd..7db661b 100644 --- a/php/update-listing.php +++ b/php/update-listing.php @@ -1,4 +1,5 @@ \ No newline at end of file diff --git a/php/utils/getopt.php b/php/utils/getopt.php new file mode 100644 index 0000000..bb6bd95 --- /dev/null +++ b/php/utils/getopt.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/php/utils/servers-rooms.php b/php/utils/servers-rooms.php index 108ed2f..3294457 100644 --- a/php/utils/servers-rooms.php +++ b/php/utils/servers-rooms.php @@ -116,6 +116,25 @@ return $details; } + /** + * Return information for JSON serialization in listing. + */ + function to_listing_data(): array { + $details = get_object_vars($this); + unset($details['server']); + $details['join_url'] = $this->get_join_url(); + unset($details['tags']); + unset($details['language_flag']); + return array( + "api" => $details, + "extras" => array( + "join_url" => $this->get_join_url(), + "language_flag" => $this->language_flag, + "tags" => $this->get_raw_tags() + ) + ); + } + /** * Create a CommunityRoom instance from loaded data. * @param CommunityServer $server @@ -307,6 +326,15 @@ return count($this->get_staff()) < $minimal_staff_count; } + /** + * @return string[] + */ + function get_raw_tags(): array { + return array_map(function(\CommunityTag $tag) { + return $tag->text; + }, $this->tags); + } + /** * Return the tags associated with this room. * @return \CommunityTag[] Tags as string array.