From ca6adc35bab4f08ea3f0bd75f3170dfd54eb4d45 Mon Sep 17 00:00:00 2001 From: octospacc Date: Tue, 27 May 2025 15:51:46 +0200 Subject: [PATCH] Initial GitHub+Gists support; Handle Pinterest pin.it links; First functional testing cases --- Proxatore.php | 47 +++++++++++----------- Tests.php | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 Tests.php diff --git a/Proxatore.php b/Proxatore.php index 18ea64b..def7128 100644 --- a/Proxatore.php +++ b/Proxatore.php @@ -50,7 +50,7 @@ define('USER_AGENT', "Proxatore/2025/1 ({$_SERVER['SERVER_NAME']})"); /*************************************/ //define('SCRIPT_NAME', $_SERVER['SCRIPT_NAME'] /* '/' */); -define('SCRIPT_NAME', ($_SERVER['SCRIPT_NAME'] === '/' ? $_SERVER['SCRIPT_NAME'] : "{$_SERVER['SCRIPT_NAME']}/")); +define('SCRIPT_NAME', ($_SERVER['SCRIPT_NAME'] === '/' ? '/' : "{$_SERVER['SCRIPT_NAME']}/")); define('HISTORY_FILE', './Proxatore.history.jsonl'); // const OPTIONS_OVERRIDES = [ @@ -61,6 +61,8 @@ define('HISTORY_FILE', './Proxatore.history.jsonl'); const PLATFORMS = [ 'spaccbbs' => ['bbs.spacc.eu.org'], + 'github' => ['github.com'], + 'github-gist' => ['gist.github.com'], 'bilibili' => ['bilibili.com'], 'bluesky' => ['bsky.app'], 'facebook' => ['facebook.com', 'm.facebook.com'], @@ -105,11 +107,15 @@ const PLATFORMS_PROXIES = [ ]; const PLATFORMS_REDIRECTS = [ + 'pin.it' => 'pinterest', 'vm.tiktok.com' => 'tiktok', 'youtu.be' => 'youtube', ]; const PLATFORMS_API = [ + 'github-gist' => [ + 'tag' => 'article', + ], 'spotify' => [ 'id' => '__NEXT_DATA__', 'data' => [ @@ -150,6 +156,13 @@ const EMBEDS = [ 'reddit' => ['embed.reddit.com'], ]; +const EMBEDS_COMPLEX = [ + 'github-gist' => [ + 'prefix' => 'data:text/html;charset=utf-8,', + ], +]; + const EMBEDS_API = [ 'soundcloud' => [ 'meta' => 'twitter:player', @@ -309,6 +322,8 @@ function makeEmbedUrl(string $platform, string $relativeUrl, array $meta=null): $url = EMBEDS_PREFIXES_FULL[$platform] . urlencode($relativeUrl); } else if ($api = (EMBEDS_API[$platform] ?? null)) { return $meta[$api['meta']]; + //} else if ($api = EMBEDS_COMPLEX[$platform] ?? null) { + //return $api['prefix'] . $relativeUrl . $api['suffix']; } else { $url = (EMBEDS[$platform][0] ?? PLATFORMS[$platform][0] ?? PLATFORMS_PROXIES[$platform][0] ?? $platform) . '/' . trim($relativeUrl, '/') . (EMBEDS_SUFFIXES[$platform] ?? ''); } @@ -566,11 +581,16 @@ function fetchPageMedia(array &$item): void { $relativeUrl = $item['result']['relativeurl']; if ($api = platformMapGet($platform, PLATFORMS_API)) { $json = null; - if (isset($api['url'])) { - $json = fetchContent($api['url'] . urlLast($relativeUrl))['body']; - } else if (isset($api['id'])) { + if ($apiUrl = $api['url'] ?? null) { + $json = fetchContent($apiUrl . urlLast($relativeUrl))['body']; + } else { $doc = htmldom(fetchContent(makeEmbedUrl($platform, $relativeUrl, $item['meta']))['body']); - $json = $doc->getElementById($api['id'])->textContent; + if ($id = $api['id'] ?? null) { + $json = $doc->getElementById($id)->textContent; + } else if ($tag = $api['tag'] ?? null) { + $item['result']['description'] = $doc->getElementsByTagName($tag)[0]->textContent; + return; + } } $data = json_decode($json, true); $values = []; @@ -1071,23 +1091,6 @@ ul.platforms a { and to view them with a clean and streamlined interface, that works well on both modern systems and old browsers or slow connections.
Additionally, it allows you to share links between social media platforms, ensuring link previews, which are often blocked by competitors, always display correctly.

-

How to self-host?

- This software is free and open-source, and you can host it on your own server, for either private or public use. -

-

Base requirements

-
A web server with PHP
-
(Currently only tested on nginx with PHP 8.2 and IIS with PHP 8.3, as of May 2025.)
-
curl and mbstring PHP extensions
-
The program requires these PHP extensions to be installed and enabled on the server to work.
-
-

Optional requirements

-
A dedicated domain name
-
To host the program properly, instead of in a subpath.
-
yt-dlp on your server
-
To stream videos from various platforms in MP4 format.
-
A cobalt API server
-
To have a fallback for access to media files for the most popular platforms.
-
'; echo '

Made with πŸ•ΈοΈ and 🧨 by OctoSpacc. diff --git a/Tests.php b/Tests.php new file mode 100644 index 0000000..1d421cc --- /dev/null +++ b/Tests.php @@ -0,0 +1,107 @@ +Search results:'; + +$tests = [ + [ + 'name' => 'Search with "test" query', + 'path' => '?proxatore-search=test', + 'expectedContains' => [SEARCH_HEADING], + ], + [ + 'name' => 'Search with inexistent term', + 'path' => '?proxatore-search=ThisStringSaying'.uniqid('', true).'DoesNeverExist', + 'expectedContains' => [SEARCH_HEADING, '

Nothing was found.

'], + ], + // [ + // 'name' => 'Invalid platform', + // 'path' => 'unknown/path', + // 'expectedContains' => ['No immediate results or search query provided.'], + // ], +]; + +$linkTests = [ + [ + 'name' => 'YouTube 1', + 'title' => 'Rick Astley - Never Gonna Give You Up (Official Music Video)', + 'path' => 'youtube.com/watch?v=dQw4w9WgXcQ', + ], + [ + 'name' => 'YouTube 2', + 'title' => 'Me at the zoo', + 'path' => 'youtube.com/watch?v=jNQXAC9IVRw', + ], + [ + 'name' => 'Pinterest 1', + 'path' => 'pinterest.com/pin/305118943524103084', + ], + [ + 'name' => 'Telegram Image 1', + 'title' => 'Pavel Durov', + 'path' => 'telegram.me/durov/6', + ], + [ + 'name' => 'Telegram Image+Text 1', + 'path' => 'telegram.me/SpaccInc/7', + 'expectedContains' => ['Simple spacc from yesterday, my USB wall charger is definitely close to breaking completely.'], + ], +]; + +foreach ($linkTests as $test) { + $path = explode('/', ltrim($test['path'], '/')); + $platform = implode('.', array_slice(explode('.', reset($path)), 0, -1)); + $realPath = "{$platform}/" . implode('/', array_slice($path, 1)); + $tests[] = [ ...$test, 'path' => "http://{$test['path']}", 'expectedRedirect' => $realPath ]; + $tests[] = [ ...$test, 'path' => "https://{$test['path']}", 'expectedRedirect' => $realPath ]; + $tests[] = [ ...$test, 'expectedRedirect' => $realPath ]; + $tests[] = [ ...$test, 'path' => $realPath ]; +} + +$allPassed = true; + +foreach ($tests as $test) { + if (!isset($test['expectedCode'])) { + $test['expectedCode'] = (isset($test['expectedRedirect']) ? 302 : 200); + } + + $url = rtrim(PROXATORE_URL, '/') . '/' . $test['path']; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $body = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $error = curl_error($ch); + curl_close($ch); + + $passed = true; + $messages = []; + + if ($code !== $test['expectedCode']) { + $passed = false; + $messages[] = "Expected HTTP code {$test['expectedCode']}, got $code."; + } + if ($code !== 0 && $test['expectedCode'] !== 302) { + foreach ($test['expectedContains'] ?? (($test['title'] ?? null) ? [$test['title']] : []) as $substr) { + if (strpos($body, $substr) === false) { + $passed = false; + $messages[] = "Response body did not contain '$substr'."; + } + } + } else { + $messages[] = $error; + } + + $status = $passed ? 'βœ… PASS' : '❌ FAIL'; + $name = $test['name'] . (($test['title'] ?? null) ? ": {$test['title']}" : null); + echo "[{$status}] {$name} <{$test['path']}>\n"; + if (!$passed) { + foreach ($messages as $msg) { + echo " - $msg\n"; + } + $allPassed = false; + } +} + +exit($allPassed ? 0 : 1);