instance = $instance; } public function login(string $username, string $password): ?string { // Try HTTPS first; on failure, optionally retry with HTTP to support dev instances $schemesToTry = []; if (preg_match('/^https?:\/\//i', $this->instance)) { // Preserve user-provided scheme as first try $schemesToTry[] = strtolower(str_starts_with($this->instance, 'http://') ? 'http' : 'https'); } else { // Default order: https then http $schemesToTry = ['https', 'http']; } foreach ($schemesToTry as $idx => $scheme) { try { $request = new LemmyRequest($this->instance); // ensure scheme used matches current attempt $request = $request->withScheme($scheme); $response = $request->post('user/login', [ 'username_or_email' => $username, 'password' => $password, ]); if (!$response->successful()) { $responseBody = $response->body(); logger()->error('Lemmy login failed', [ 'status' => $response->status(), 'body' => $responseBody, 'scheme' => $scheme, ]); // Check if it's a rate limit error if (str_contains($responseBody, 'rate_limit_error')) { throw new Exception('Rate limited by Lemmy instance. Please wait a moment and try again.'); } // If first attempt failed and there is another scheme to try, continue loop if ($idx === 0 && count($schemesToTry) > 1) { continue; } return null; } $data = $response->json(); return $data['jwt'] ?? null; } catch (Exception $e) { logger()->error('Lemmy login exception', ['error' => $e->getMessage(), 'scheme' => $scheme]); // If this was the first attempt and HTTPS, try HTTP next if ($idx === 0 && in_array('http', $schemesToTry, true)) { continue; } return null; } } return null; } public function getCommunityId(string $communityName, string $token): int { try { $request = new LemmyRequest($this->instance, $token); $response = $request->get('community', ['name' => $communityName]); if (!$response->successful()) { throw new Exception('Failed to fetch community: ' . $response->status()); } $data = $response->json(); return $data['community_view']['community']['id'] ?? throw new Exception('Community not found'); } catch (Exception $e) { logger()->error('Community lookup failed', ['error' => $e->getMessage()]); throw $e; } } public function syncChannelPosts(string $token, int $platformChannelId, string $communityName): void { try { $request = new LemmyRequest($this->instance, $token); $response = $request->get('post/list', [ 'community_id' => $platformChannelId, 'limit' => 50, 'sort' => 'New' ]); if (!$response->successful()) { logger()->warning('Failed to sync channel posts', [ 'status' => $response->status(), 'platform_channel_id' => $platformChannelId ]); return; } $data = $response->json(); $posts = $data['posts'] ?? []; foreach ($posts as $postData) { $post = $postData['post']; PlatformChannelPost::storePost( PlatformEnum::LEMMY, (string) $platformChannelId, $communityName, (string) $post['id'], $post['url'] ?? null, $post['name'] ?? null, isset($post['published']) ? new \DateTime($post['published']) : null ); } logger()->info('Synced channel posts', [ 'platform_channel_id' => $platformChannelId, 'posts_count' => count($posts) ]); } catch (Exception $e) { logger()->error('Exception while syncing channel posts', [ 'error' => $e->getMessage(), 'platform_channel_id' => $platformChannelId ]); } } /** * @return array */ public function createPost(string $token, string $title, string $body, int $platformChannelId, ?string $url = null, ?string $thumbnail = null, ?int $languageId = null): array { try { $request = new LemmyRequest($this->instance, $token); $postData = [ 'name' => $title, 'body' => $body, 'community_id' => $platformChannelId, ]; if ($url) { $postData['url'] = $url; } if ($thumbnail) { $postData['custom_thumbnail'] = $thumbnail; } if ($languageId) { $postData['language_id'] = $languageId; } $response = $request->post('post', $postData); if (!$response->successful()) { throw new Exception('Failed to create post: ' . $response->status() . ' - ' . $response->body()); } return $response->json(); } catch (Exception $e) { logger()->error('Post creation failed', ['error' => $e->getMessage()]); throw $e; } } /** * @return array */ public function getLanguages(): array { try { $request = new LemmyRequest($this->instance); $response = $request->get('site'); if (!$response->successful()) { logger()->warning('Failed to fetch site languages', [ 'status' => $response->status() ]); return []; } $data = $response->json(); return $data['all_languages'] ?? []; } catch (Exception $e) { logger()->error('Exception while fetching languages', [ 'error' => $e->getMessage() ]); return []; } } }