diff --git a/index.php b/index.php index 3267e39..b1cff4e 100644 --- a/index.php +++ b/index.php @@ -35,10 +35,11 @@ $routes = [ '/login' => 'login.php', '/logout' => 'logout.php', '/profile' => 'profile.php', - '/profile' => 'profile.php', + '/gallery' => 'gallery.php', //'/profile/([a-zA-Z0-9_-]+)' => 'profile.php', '/conv/([a-zA-Z0-9]{7})' => 'conv.php', // matches only twtHash of exactly 7 alphanumeric characters '/post/([a-zA-Z0-9]{7})' => 'post.php', // matches only twtHash of exactly 7 alphanumeric characters + //'/thumb' => 'thumb.php', '/webmention' => 'webmention_endpoint.php', ]; diff --git a/libs/Cropper.php b/libs/Cropper.php new file mode 100644 index 0000000..59ed6e0 --- /dev/null +++ b/libs/Cropper.php @@ -0,0 +1,297 @@ + + * @package CoffeeCode\Cropper + */ +class Cropper +{ + /** @var string */ + private string $cachePath; + + /** @var string */ + private string $imagePath; + + /** @var string */ + private string $imageName; + + /** @var string */ + private string $imageMime; + + /** @var int */ + private int $quality; + + /** @var int */ + private int $compressor; + + /**@var bool */ + private bool $webP; + + /** + * Allow jpg and png to thumb and cache generate + * @var array allowed media types + */ + private static array $allowedExt = ['image/jpeg', "image/png"]; + + /** @var ConversionFailedException */ + public ConversionFailedException $exception; + + /** + * Cropper constructor. + * compressor must be 1-9 + * quality must be 1-100 + * + * @param string $cachePath + * @param int $quality + * @param int $compressor + * @param bool $webP + * @throws Exception + */ + public function __construct(string $cachePath, int $quality = 75, int $compressor = 5, bool $webP = false) + { + $this->cachePath = $cachePath; + $this->quality = $quality; + $this->compressor = $compressor; + $this->webP = $webP; + + if (!file_exists($this->cachePath) || !is_dir($this->cachePath)) { + if (!mkdir($this->cachePath, 0755, true)) { + throw new Exception("Could not create cache folder"); + } + } + } + + /** + * Make an thumb image + * + * @param string $imagePath + * @param int $width + * @param int|null $height + * @return null|string + */ + public function make(string $imagePath, int $width, int $height = null): ?string + { + if (!file_exists($imagePath)) { + return "Image not found"; + } + + $this->imagePath = $imagePath; + $this->imageName = $this->name($this->imagePath, $width, $height); + $this->imageMime = mime_content_type($this->imagePath); + + if (!in_array($this->imageMime, self::$allowedExt)) { + return "Not a valid JPG or PNG image"; + } + + return $this->image($width, $height); + } + + /** + * @param int $width + * @param int|null $height + * @return string|null + */ + private function image(int $width, int $height = null): ?string + { + $imageWebP = "{$this->cachePath}/{$this->imageName}.webp"; + $imageExt = "{$this->cachePath}/{$this->imageName}." . pathinfo($this->imagePath)['extension']; + + if ($this->webP && file_exists($imageWebP) && is_file($imageWebP)) { + return $imageWebP; + } + + if (file_exists($imageExt) && is_file($imageExt)) { + return $imageExt; + } + + return $this->imageCache($width, $height); + } + + /** + * @param string $name + * @param int|null $width + * @param int|null $height + * @return string + */ + protected function name(string $name, int $width = null, int $height = null): string + { + $filterName = mb_convert_encoding(htmlspecialchars(mb_strtolower(pathinfo($name)["filename"])), 'ISO-8859-1', + 'UTF-8'); + $formats = mb_convert_encoding('ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜüÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûýýþÿRr"!@#$%&*()_-+={[}]/?;:.,\\\'<>°ºª', + 'ISO-8859-1', 'UTF-8'); + $replace = 'aaaaaaaceeeeiiiidnoooooouuuuuybsaaaaaaaceeeeiiiidnoooooouuuyybyrr '; + $trimName = trim(strtr($filterName, $formats, $replace)); + $name = str_replace(["-----", "----", "---", "--"], "-", str_replace(" ", "-", $trimName)); + + $hash = $this->hash($this->imagePath); + $widthName = ($width ? "-{$width}" : ""); + $heightName = ($height ? "x{$height}" : ""); + + return "{$name}{$widthName}{$heightName}-{$hash}"; + } + + /** + * @param string $path + * @return string + */ + protected function hash(string $path): string + { + return hash("crc32", pathinfo($path)['basename']); + } + + /** + * Clear cache + * + * @param string|null $imagePath + * @example $t->flush("images/image.jpg"); clear image name and variations size + * @example $t->flush(); clear all image cache folder + */ + public function flush(string $imagePath = null): void + { + foreach (scandir($this->cachePath) as $file) { + $file = "{$this->cachePath}/{$file}"; + if ($imagePath && strpos($file, $this->hash($imagePath))) { + $this->imageDestroy($file); + } elseif (!$imagePath) { + $this->imageDestroy($file); + } + } + } + + /** + * @param int $width + * @param int|null $height + * @return null|string + */ + private function imageCache(int $width, int $height = null): ?string + { + list($src_w, $src_h) = getimagesize($this->imagePath); + $height = ($height ?? ($width * $src_h) / $src_w); + + $src_x = 0; + $src_y = 0; + + $cmp_x = $src_w / $width; + $cmp_y = $src_h / $height; + + if ($cmp_x > $cmp_y) { + $src_x = round(($src_w - ($src_w / $cmp_x * $cmp_y)) / 2); + $src_w = round($src_w / $cmp_x * $cmp_y); + } elseif ($cmp_y > $cmp_x) { + $src_y = round(($src_h - ($src_h / $cmp_y * $cmp_x)) / 2); + $src_h = round($src_h / $cmp_y * $cmp_x); + } + + $height = (int)$height; + $src_x = (int)$src_x; + $src_y = (int)$src_y; + $src_w = (int)$src_w; + $src_h = (int)$src_h; + + if ($this->imageMime == "image/jpeg") { + return $this->fromJpg($width, $height, $src_x, $src_y, $src_w, $src_h); + } + + if ($this->imageMime == "image/png") { + return $this->fromPng($width, $height, $src_x, $src_y, $src_w, $src_h); + } + + return null; + } + + /** + * @param string $imagePatch + */ + private function imageDestroy(string $imagePatch): void + { + if (file_exists($imagePatch) && is_file($imagePatch)) { + unlink($imagePatch); + } + } + + /** + * @param int $width + * @param int $height + * @param int $src_x + * @param int $src_y + * @param int $src_w + * @param int $src_h + * @return string + */ + private function fromJpg(int $width, int $height, int $src_x, int $src_y, int $src_w, int $src_h): string + { + $thumb = imagecreatetruecolor($width, $height); + $source = imagecreatefromjpeg($this->imagePath); + + imagecopyresampled($thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h); + imagejpeg($thumb, "{$this->cachePath}/{$this->imageName}.jpg", $this->quality); + + imagedestroy($thumb); + imagedestroy($source); + + if ($this->webP) { + return $this->toWebP("{$this->cachePath}/{$this->imageName}.jpg"); + } + + return "{$this->cachePath}/{$this->imageName}.jpg"; + } + + /** + * @param int $width + * @param int $height + * @param int $src_x + * @param int $src_y + * @param int $src_w + * @param int $src_h + * @return string + */ + private function fromPng(int $width, int $height, int $src_x, int $src_y, int $src_w, int $src_h): string + { + $thumb = imagecreatetruecolor($width, $height); + $source = imagecreatefrompng($this->imagePath); + + imagealphablending($thumb, false); + imagesavealpha($thumb, true); + imagecopyresampled($thumb, $source, 0, 0, $src_x, $src_y, $width, $height, $src_w, $src_h); + imagepng($thumb, "{$this->cachePath}/{$this->imageName}.png", $this->compressor); + + imagedestroy($thumb); + imagedestroy($source); + + if ($this->webP) { + return $this->toWebP("{$this->cachePath}/{$this->imageName}.png"); + } + + return "{$this->cachePath}/{$this->imageName}.png"; + } + + /** + * @param string $image + * @param bool $unlinkImage + * @return string + */ + public function toWebP(string $image, $unlinkImage = true): string + { + try { + $webPConverted = pathinfo($image)["dirname"] . "/" . pathinfo($image)["filename"] . ".webp"; + WebPConvert::convert($image, $webPConverted, ["default-quality" => $this->quality]); + + if ($unlinkImage) { + unlink($image); + } + + return $webPConverted; + } catch (ConversionFailedException $exception) { + $this->exception = $exception; + return $image; + } + } +} diff --git a/libs/Slimdown.php b/libs/Slimdown.php index 6e2c8d2..60b2080 100644 --- a/libs/Slimdown.php +++ b/libs/Slimdown.php @@ -115,6 +115,7 @@ class Slimdown { // Substitute _ and * in links so they don't break the URLs $link = str_replace (['_', '*'], ['{^^^}', '{~~~}'], $link); return sprintf ('\'%s\'', $link, $text); + //return sprintf ('\'%s\'', $link, $text); // added support for thumbnail generation on the fly } private static function fix_link ($regs) { diff --git a/libs/timeline.css b/libs/timeline.css index e985cb1..f078f8b 100644 --- a/libs/timeline.css +++ b/libs/timeline.css @@ -1,19 +1,41 @@ /* === SimpleCSS overwrites === */ +:root, ::backdrop { + + /* Default (light) theme */ + --sans-font: -apple-system,BlinkMacSystemFont,"Avenir Next",Avenir,"Nimbus Sans L",Roboto,"Noto Sans","Segoe UI",Arial,Helvetica,"Helvetica Neue",sans-serif; + --mono-font: Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace; + --standard-border-radius: 0.5rem; + --bg: #fff; + --accent-bg: #f5f7ff; + --text: #212121; + --text-light: #585858; + --border: #d8dae1; /*#898EA4;*/ + --accent: #0d47a1; + --code: #d81b60; + --preformatted: #444; + --marked: #ffdd33; + --disabled: #efefef; +} -::backdrop, :root { - --sans-font: -apple-system,BlinkMacSystemFont,"Avenir Next",Avenir,"Nimbus Sans L",Roboto,"Noto Sans","Segoe UI",Arial,Helvetica,"Helvetica Neue",sans-serif; - --mono-font: Consolas,Menlo,Monaco,"Andale Mono","Ubuntu Mono",monospace; - --standard-border-radius: 0.5rem; - --bg: #fff; - --accent-bg: #f5f7ff; - --text: #212121; - --text-light: #585858; - --border: #d8dae1; /*#898EA4;*/ - --accent: #0d47a1; - --code: #d81b60; - --preformatted: #444; - --marked: #ffdd33; - --disabled: #efefef; +/* Dark theme */ +@media (prefers-color-scheme: dark) { + :root, + ::backdrop { + color-scheme: dark; + --bg: #212121; + --accent-bg: #2b2b2b; + --text: #dcdcdc; + --text-light: #ababab; + --accent: #ffb300; + --code: #f06292; + --preformatted: #ccc; + --disabled: #111; + } + /* Add a bit of transparency so light media isn't so glaring in dark mode */ + img, + video { + opacity: 0.8; + } } body > header { @@ -117,6 +139,7 @@ img { max-width: 100%; height: auto; border-radius: 0.25rem; + border: thin solid var(--border); } img.avatar { @@ -183,10 +206,6 @@ article .twt-msg { padding: 0.5rem 0; } -article .twt-msg a { - text-decoration: underline; -} - article .twt-msg > blockquote { margin: 0; border-left: thick solid grey; @@ -217,9 +236,6 @@ article small a:visited { } -article small a:hover { - color: var(--accent); -} /* === New Post Form === */ @@ -238,11 +254,14 @@ nav.pagnation { padding: 0.5rem 0; } - /* === REFRESH === */ #refreshInfo { display: block; +} + +#refreshInfo { + display: block; text-align: center: } @@ -253,8 +272,31 @@ nav.pagnation { float: right; } +/* == Gallery ===================== */ + +.gallery { + max-width: 1200px; + margin: 0 auto ; + display: grid; + grid-gap: 0.75rem; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + /*grid-auto-rows: 225px;*/ + /*grid-auto-flow: dense;*/ +} + +.gallery a img { + /* https://web.dev/aspect-ratio/ */ + aspect-ratio: 1 / 1; + width: 100%; + /*height: 100%;*/ + object-fit: cover; + /*background-color: var(--border-color);*/ + border-radius: 0.25rem; +} + /* === FOOTER === */ + footer { border-top: thin solid grey; margin-top: 1rem; diff --git a/libs/twtxt.php b/libs/twtxt.php index dea66b5..a1f0af3 100644 --- a/libs/twtxt.php +++ b/libs/twtxt.php @@ -1,875 +1,452 @@ [ - 'peer_name' => 'generic-server', - 'verify_peer' => FALSE, - 'verify_peer_name' => FALSE, - 'allow_self_signed' => TRUE - ] - ] - ); - curl_setopt($curl, CURLOPT_SSLVERSION, 4); - */ - - /** - * The function searches for a key-value pair in a string and returns the value if found. - * - * @param keyToFind The key we want to find in the string. - * @param string The string in which to search for the key-value pair. - * - * @return the value of the key that matches the given keyToFind in the given string. If a match is - * found, the function returns the value of the key as a string after trimming any whitespace. If no - * match is found, the function returns null. - */ - function getSingleParameter($keyToFind, $string) { - if (!str_contains($string, $keyToFind)) { - return null; - } - - $pattern = '/\s*' . $keyToFind . '\s*=\s*([^#\n]+)/'; - //$pattern = '/\s*' . $keyToFind . '\s*=\s*([^\s#]+)/'; // Only matches the first word - preg_match($pattern, $string, $matches); - - if (isset($matches[1])) { - return trim($matches[1]); - } - - return null; - } - - function getDoubleParameter($keywordToFind, $string) { - // Returns string or null - $pattern = '/#\s*' . preg_quote($keywordToFind, '/') . '\s*=\s*(\S+)\s*(\S+)/'; - // Matches "# = " - preg_match($pattern, $string, $matches); - - if (isset($matches[1]) && isset($matches[2])) { - $result = array($matches[1], $matches[2]); - return $result; - } - - return null; - } - - function getReplyHashFromTwt(string $twtString): string { - // Extract the text between parentheses using regular expressions - $pattern = '/\(#([^\)]+)\)/'; // Matches "(#)" - preg_match($pattern, $twtString, $matches); - - if (isset($matches[1])) { - $textBetweenParentheses = $matches[1]; - return $textBetweenParentheses; - } - - return ''; - } - - -function getMentionsFromTwt(string $twtString) { - - $pattern = '/@<([^>]+)\s([^>]+)>/'; // Matches "@" - +function getImagesFromTwt(string $twtString) { + $pattern = '/(]+>)/i'; preg_match_all($pattern, $twtString, $matches, PREG_SET_ORDER); - - $result = array(); - - foreach ($matches as $match) { - - $nick = $match[1]; - - $url = $match[2]; - - $result[] = array("nick" => $nick, "url" => $url); - + $result[] = array($match[0]); } - - return $result; - } +function getMentionsFromTwt(string $twtString) { + $pattern = '/@<([^>]+)\s([^>]+)>/'; // Matches "@" + preg_match_all($pattern, $twtString, $matches, PREG_SET_ORDER); + $result = array(); + + foreach ($matches as $match) { + $nick = $match[1]; + $url = $match[2]; + $result[] = array("nick" => $nick, "url" => $url); + } + + return $result; +} function replaceMentionsFromTwt(string $twtString): string { - // Example input: 'Hello @, how are you? @'; - // Example output: Hello @eapl.mx@eapl.mx/twtxt.txt, how are you? @nick@server.com/something/twtxt.txt - - $pattern = '/@<([^ ]+)\s([^>]+)>/'; - //$replacement = '@$1'; - $replacement = '@$1'; $replacement .= ''; // Adds a hidden link direcly to the twtxt.txt of the mentioned target - #$twtString = '@'; - #$pattern = '/@<([^ ]+) ([^>]+)>/'; - #$replacement = '@$1'; - $result = preg_replace($pattern, $replacement, $twtString); - return $result; - - // from https://github.com/hxii/picoblog/blob/master/picoblog.php - //$pattern = '/\@<([a-zA-Z0-9\.]+)\W+(https?:\/\/[^>]+)>/'; - //return preg_replace($pattern,'@$1',$twtString); - } - - function replaceLinksFromTwt(string $twtString) { - - // TODO: Make this NOT match with `inline code` to avoid links in code-snippets - // 1. Look into how yarnd handles this - - // Regular expression pattern to match URLs - $pattern = '/(?$1'; - $result = preg_replace($pattern, $replacement, $twtString); - - return $result; - } - - function replaceMarkdownLinksFromTwt(string $twtString) { - $pattern = '/\[([^\]]+)\]\(([^)]+)\)/'; - - $replacement = '$1'; - $result = preg_replace($pattern, $replacement, $twtString); - - return $result; - } - - function replaceImagesFromTwt(string $twtString) { - $pattern = '/!\[(.*?)\]\((.*?)\)/'; - //$replacement = '$1'; - $replacement = '$1'; - $result = preg_replace($pattern, $replacement, $twtString); - - return $result; - } - - function replaceTagsFromTwt(string $twtString) { - $pattern = '/#(\w+)?/'; - $replacement = '#\1'; // Dummy link - //$replacement = '#${1}'; - $result = preg_replace($pattern, $replacement, $twtString); - - return $result; - } - - - function getTimeElapsedString($timestamp, $full = false) { - $now = new DateTime; - $ago = new DateTime; - $ago->setTimestamp($timestamp); - - $agoText = 'ago'; - if ($now < $ago) { - $agoText = 'in the future'; - } - - $diff = $now->diff($ago); - - //$diff->w = floor($diff->d / 7); - $w = floor($diff->d / 7); - $d = $diff->d - ($w * 7); - //$diff->d -= $diff->w * 7; - - $string = array( - 'y' => 'year', - 'm' => 'month', - 'w' => 'week', - 'd' => 'day', - 'h' => 'hour', - 'i' => 'minute', - 's' => 'second', - ); - foreach ($string as $k => &$v) { // k is key, and v is value... Obviously - if ($k === 'w') { - if ($w) { - $v = $w . ' ' . $v . ($w > 1 ? 's' : ''); - } else { - unset($string[$k]); - } - } else { - if ($diff->$k) { - $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); - } else { - unset($string[$k]); - } - } - } - - if (!$full) $string = array_slice($string, 0, 1); - return $string ? implode(', ', $string) . " $agoText" : 'just now'; - } - - function getCachedFileContentsOrUpdate($fileURL, $cacheDurationSecs = 15) { - # TODO: Process the Warning - # Warning: file_get_contents(https://eapl.mx/twtxt.net): - # failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in - - $cacheFilePath = getCachedFileName($fileURL); - - // Check if cache file exists and it's not expired - if (file_exists($cacheFilePath) && (time() - filemtime($cacheFilePath)) < $cacheDurationSecs) { - return file_get_contents($cacheFilePath); - } - - // File doesn't exist in cache or has expired, so fetch and cache it - $contents = file_get_contents($fileURL); - file_put_contents($cacheFilePath, $contents); - - return $contents; - } - - function getCachedFileContents($filePath) { - $cacheFile = getCachedFileName($filePath); - - // Check if cache file exists and it's not expired - if (file_exists($cacheFile)) { - return file_get_contents($cacheFile); - } - - return null; - } - - function updateCachedFile($filePath, $cacheDurationSecs = 15) { - $cacheFilePath = getCachedFileName($filePath); - - // File doesn't exist in cache or has expired, so fetch and cache it - // TODO: Seems it's not working right! - $fileDoesntExist = !file_exists($cacheFilePath); - $fileIsOld = false; - if (!$fileDoesntExist) { - $fileIsOld = !((time() - filemtime($cacheFilePath)) < $cacheDurationSecs); - } - - if ($fileDoesntExist || $fileIsOld) { - #echo "Loading Cached file $cacheFilePath
\n"; - $contents = @file_get_contents($filePath); - - if ($contents === false) { - // File loaded with errors, skip saving it - return; - } - - file_put_contents($cacheFilePath, $contents); - } - } - - function getTwtsFromTwtxtString($url) { - $fileContent = getCachedFileContents($url); - - if (is_null($fileContent)) { - return null; - } - $fileContent = mb_convert_encoding($fileContent, 'UTF-8'); - - $fileLines = explode("\n", $fileContent); - - $twtxtData = new TwtxtFile(); - - foreach ($fileLines as $currentLine) { - // Remove empty lines - if (empty($currentLine)) { - continue; - } - - if (str_starts_with($currentLine, '#')) { - // Check if comments (starting with #) have some metadata - if (!is_null(getSingleParameter('url', $currentLine))) { - $currentURL = getSingleParameter('url', $currentLine); - - if (empty($twtxtData->URLs)) { - $twtxtData->mainURL = $currentURL; - } - $twtxtData->URLs[] = $currentURL; - } - if (!is_null(getSingleParameter('nick', $currentLine))) { - $twtxtData->nick = getSingleParameter('nick', $currentLine); - } - if (!is_null(getSingleParameter('avatar', $currentLine))) { - $twtxtData->avatar = getSingleParameter('avatar', $currentLine); - } - if (!is_null(getSingleParameter('emoji', $currentLine))) { - $twtxtData->emoji = getSingleParameter('emoji', $currentLine); - } - if (!is_null(getSingleParameter('lang', $currentLine))) { - $twtxtData->lang = getSingleParameter('lang', $currentLine); - } - if (!is_null(getSingleParameter('description', $currentLine))) { - $twtxtData->description = getSingleParameter('description', $currentLine); - // TODO - FIX BUG: only takes first word! - } - if (!is_null(getSingleParameter('follow', $currentLine))) { - $twtxtData->following[] = getSingleParameter('follow', $currentLine); - } - } - - if (!str_starts_with($currentLine, '#')) { - $explodedLine = explode("\t", $currentLine); - if (count($explodedLine) >= 2) { - $dateStr = $explodedLine[0]; - $twtContent = $explodedLine[1]; - - $twtContent = replaceMentionsFromTwt($twtContent); - - // Convert HTML problematic characters - //$twtContent = htmlentities($twtContent); // TODO: Messing up rendering of @mentions #BUG - - // Replace the Line separator character (U+2028) - // \u2028 is \xE2 \x80 \xA8 in UTF-8 - // Check here: https://www.mclean.net.nz/ucf/ - //$twtContent = str_replace("\xE2\x80\xA8", "
\n", $twtContent); - - // For some reason I was having trouble finding this nomenclature - // that's why I leave the UTF-8 representation for future reference - $twtContent = str_replace("\u{2028}", "\n
\n", $twtContent); - - //$twtContent = replaceMarkdownLinksFromTwt($twtContent); - //$twtContent = replaceImagesFromTwt($twtContent); - $twtContent = Slimdown::render($twtContent); - $twtContent = replaceLinksFromTwt($twtContent); // TODO: - - - // Get and remote the hash - + // Get and remove the hash $hash = getReplyHashFromTwt($twtContent); - if ($hash) { - $twtContent = str_replace("(#$hash)", '', $twtContent); - } - - // TODO: Make ?tag= filtering feature - //$twtContent = replaceTagsFromTwt($twtContent); - - // TODO: Get mentions - $mentions = getMentionsFromTwt($twtContent); - - // Get Lang metadata - - if (($timestamp = strtotime($dateStr)) === false) { - //echo "The string ($dateStr) is incorrect"; - // Incorrect date string, skip this twt - continue; - } else { - $displayDate = getTimeElapsedString($timestamp); - } - - // TODO: Only 1 twt by second is allowed here - $twt = new Twt(); - - $twt->originalTwtStr = $currentLine; - $twt->hash = getHashFromTwt($currentLine, $twtxtData->mainURL); - $twt->fullDate = date('j F Y h:i:s A', $timestamp) . ' (UTC)'; - $twt->displayDate = $displayDate; - $twt->content = $twtContent; - $twt->replyToHash = $hash; - $twt->mentions = $mentions; - $twt->avatar = $twtxtData->avatar; - $twt->emoji = $twtxtData->emoji; - $twt->nick = $twtxtData->nick; - $twt->mainURL = $twtxtData->mainURL; - - $twtxtData->twts[$timestamp] = $twt; - // TODO: Interpret the content as markdown -- @DONE using Slimdown.php above - } - } - } - - return $twtxtData; - } - - function insertFollowingURL($urlString) { - // Check if it's a valid URL - // Retrieve the nickname, if didn't find a nick, ask for one - - $originalCode = ' - Lorem ipsum dolor sit amet, - #~~~# - consectetur adipiscing elit.'; - - $text = '#~~~#'; - $newText = '123' . PHP_EOL . $text; - $result = str_replace('#~~~#', $newText, $originalCode); - - echo $result; - } - - function getCachedFileName($filePath) { - return __DIR__ . '/../private/cache/' . hash('sha256', $filePath); // TODO: make better path - } - - if (!function_exists('str_starts_with')) { - function str_starts_with($haystack, $needle) { - return (string)$needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0; - } - } - if (!function_exists('str_ends_with')) { - function str_ends_with($haystack, $needle) { - return $needle !== '' && substr($haystack, -strlen($needle)) === (string)$needle; - } - } - if (!function_exists('str_contains')) { - function str_contains($haystack, $needle) { - return $needle !== '' && mb_strpos($haystack, $needle) !== false; - } - } - diff --git a/partials/__img_posts.php b/partials/__img_posts.php new file mode 100644 index 0000000..2bc37d2 --- /dev/null +++ b/partials/__img_posts.php @@ -0,0 +1,51 @@ +'; + +foreach ($twts as $twt) { + $img_array = getImagesFromTwt($twt->content); + + foreach ($img_array as $img) { + //echo ''.$img[0].''; + // Workaround until cache issue is resolved + echo ''.$img[0].''; + } +} + +echo ''; + + +/* + +// old way from Pixelblog, for refernece/inspiration + +// Loop through each post and extract date and entry text: + +foreach ($img_posts as $post) { + + $date = preg_filter('/^(?[^\t]+)\t(?.+)/', '\1', $post); + $entry = preg_filter('/^(?[^\t]+)\t(?.+)/', '\2', $post); + $text_only = preg_filter('/!\[(.*?)\]\((.*?)\)/', '\1', $entry); // this gives the post without the markdown img links (not sure why, but it works) + $text_only = trim($text_only); + $text_only = strip_tags($text_only); + + preg_match_all('/!\[(?.*?)\]\((?.*?)\)/', $entry, $img_array); + //echo '
'; print_r($img_array);    echo '
'; // FOR DEBUGING + + foreach ($img_array['url'] as $img => $val) { + $url = $img_array['url'][$img]; + //$alt = $img_array['alt'][$img]; + echo ''.$text_only.''; + //echo '' . $text_only . ''; + + } +} + +*/ + +?> diff --git a/partials/base.php b/partials/base.php index 485f98b..f41ca8a 100644 --- a/partials/base.php +++ b/partials/base.php @@ -1,6 +1,6 @@ mainURL] = $parsedTwtxtFile; - } + $parsedTwtxtFile = getTwtsFromTwtxtString($twtsURL); + if (!is_null($parsedTwtxtFile)) { + $parsedTwtxtFiles[$parsedTwtxtFile->mainURL] = $parsedTwtxtFile; + } } else { // Show timeline for the URL - $parsedTwtxtFiles = []; - foreach ($fileLines as $currentLine) { - if (str_starts_with($currentLine, '#')) { - if (!is_null(getDoubleParameter('follow', $currentLine))) { - $follow = getDoubleParameter('follow', $currentLine); - $twtFollowingList[] = $follow; + $parsedTwtxtFiles = []; + foreach ($fileLines as $currentLine) { + if (str_starts_with($currentLine, '#')) { + if (!is_null(getDoubleParameter('follow', $currentLine))) { + $follow = getDoubleParameter('follow', $currentLine); + $twtFollowingList[] = $follow; - // Read the parsed files if in Cache - $followURL = $follow[1]; - $parsedTwtxtFile = getTwtsFromTwtxtString($followURL); - if (!is_null($parsedTwtxtFile)) { - $parsedTwtxtFiles[$parsedTwtxtFile->mainURL] = $parsedTwtxtFile; - } - } - } - } + // Read the parsed files if in Cache + $followURL = $follow[1]; + $parsedTwtxtFile = getTwtsFromTwtxtString($followURL); + if (!is_null($parsedTwtxtFile)) { + $parsedTwtxtFiles[$parsedTwtxtFile->mainURL] = $parsedTwtxtFile; + } + } + } + } } $twts = []; # Combine all the followers twts foreach ($parsedTwtxtFiles as $currentTwtFile) { - if (!is_null($currentTwtFile)) { - $twts += $currentTwtFile->twts; - } + if (!is_null($currentTwtFile)) { + $twts += $currentTwtFile->twts; + } } if (!empty($_GET['hash'])) { - $hash = $_GET['hash']; - $twts = array_filter($twts, function($twt) use ($hash) { - return $twt->hash === $hash || $twt->replyToHash === $hash; - }); + $hash = $_GET['hash']; + $twts = array_filter($twts, function ($twt) use ($hash) { + return $twt->hash === $hash || $twt->replyToHash === $hash; + }); } - krsort($twts, SORT_NUMERIC); if (!empty($_GET['hash'])) { - $twts = array_reverse($twts, true); + $twts = array_reverse($twts, true); } $page = 1; if (!empty($_GET['page'])) { - $page = intval($_GET['page']); + $page = intval($_GET['page']); } -$startingTwt = (($page - 1) * TWTS_PER_PAGE); -$twts = array_slice($twts, $startingTwt, TWTS_PER_PAGE); +// If we should paginate our twts list +if (!empty($paginateTwts)) { + $startingTwt = (($page - 1) * TWTS_PER_PAGE); + $twts = array_slice($twts, $startingTwt, TWTS_PER_PAGE); +} $baseURL = str_replace("/index.php", "", $_SERVER['SCRIPT_NAME']); diff --git a/partials/header.php b/partials/header.php index fae81ab..1f2f479 100644 --- a/partials/header.php +++ b/partials/header.php @@ -19,9 +19,13 @@ $profile = getTwtsFromTwtxtString($config['public_txt_url']);

- + - nick ?>@mainURL, PHP_URL_HOST); ?> + mainURL, PHP_URL_HOST); ?> + +