Add files via upload
This commit is contained in:
parent
08676d5dea
commit
d5151a9dec
7
blog.txt
7
blog.txt
|
@ -1 +1,6 @@
|
||||||
2020-10-01T08:05:33Z (#MWZkYw) Welcome to picoblog. For updates and such, visit [https://0xff.nu/picoblog](https://0xff.nu/picoblog).
|
# nick = lucas
|
||||||
|
# url = https://picoblog.lu700.repl.co/blog.txt
|
||||||
|
# avatar = https://avatars.githubusercontent.com/u/83518257
|
||||||
|
# description = aaaa
|
||||||
|
2021-08-27T20:08:55Z (#tad8XR4) geektweet
|
||||||
|
2021-08-27T20:09:10Z (#DcV8475) lol @<thing https://feed-url>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slimdown - A very basic regex-based Markdown parser.
|
||||||
|
* Author: Johnny Broadway <johnny@johnnybroadway.com>
|
||||||
|
* Website: https://gist.github.com/jbroadway/2836900
|
||||||
|
* License: MIT
|
||||||
|
*/
|
||||||
|
class Slimdown {
|
||||||
|
public static $rules = array (
|
||||||
|
'/(?<!!)\[([^\[]+)\]\(([^\)]+)\)/' => '<a href=\'\2\'>\1</a>', // links
|
||||||
|
'/(\*\*|__)(.*?)\1/' => '<strong>\2</strong>', // bold
|
||||||
|
'/(\*|_)(.*?)\1/' => '<em>\2</em>', // emphasis
|
||||||
|
'/\~\~(.*?)\~\~/' => '<del>\1</del>', // del
|
||||||
|
'/\:\"(.*?)\"\:/' => '<q>\1</q>', // quote
|
||||||
|
'/`(.*?)`/' => '<code>\1</code>', // inline code
|
||||||
|
'/(?:!\[([^\[]+)\]\(([^\)]+)\))/' => '<img src=\'\2\' alt=\'\1\' loading=\'lazy\'>',
|
||||||
|
'/==(.*?)==/' => '<mark>\1</mark>',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a rule.
|
||||||
|
*/
|
||||||
|
public static function add_rule ($regex, $replacement) {
|
||||||
|
self::$rules[$regex] = $replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render some Markdown into HTML.
|
||||||
|
*/
|
||||||
|
public static function render ($text) {
|
||||||
|
$text = "\n" . $text . "\n";
|
||||||
|
foreach (self::$rules as $regex => $replacement) {
|
||||||
|
if (is_callable ( $replacement)) {
|
||||||
|
$text = preg_replace_callback ($regex, $replacement, $text);
|
||||||
|
} else {
|
||||||
|
$text = preg_replace ($regex, $replacement, $text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trim ($text);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* picoblog
|
||||||
|
*
|
||||||
|
* made by hxii (https://0xff.nu/picoblog)
|
||||||
|
*
|
||||||
|
* Picoblog is a very simple front-end for a twtxt (https://github.com/prologic/twtxt) format microblog with support for:
|
||||||
|
* - Limited Markdown (strong, em, marked, deleted, links, images, inline code).
|
||||||
|
* - Tags (#tags are automatically converted to links).
|
||||||
|
* - Unique IDs (I use them, but they are optional).
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace hxii;
|
||||||
|
|
||||||
|
class PicoBlog
|
||||||
|
{
|
||||||
|
|
||||||
|
private $sourcefile, $format;
|
||||||
|
public $rawentries, $blog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param string $sourcefile Source file in twtxt format (or PicoBlog format).
|
||||||
|
*/
|
||||||
|
//twtxt
|
||||||
|
public function __construct(string $sourcefile, string $format = 'picoblog')
|
||||||
|
{
|
||||||
|
$this->sourcefile = $sourcefile;
|
||||||
|
$this->format = $format;
|
||||||
|
$this->readSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for and parse query string from $_SERVER['QUERY_STRING']).
|
||||||
|
* Used to get entries by ID or tag.
|
||||||
|
*
|
||||||
|
* @return array|boolean
|
||||||
|
*/
|
||||||
|
public function parseQuery()
|
||||||
|
{
|
||||||
|
if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
|
||||||
|
parse_str($_SERVER['QUERY_STRING'], $return);
|
||||||
|
return $return;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read source file/URL
|
||||||
|
*
|
||||||
|
* @return boolean true if successful, false if not
|
||||||
|
*/
|
||||||
|
private function readSource()
|
||||||
|
{
|
||||||
|
if (is_file($this->sourcefile) && is_readable($this->sourcefile)) {
|
||||||
|
$this->rawentries = explode(PHP_EOL, file_get_contents($this->sourcefile));
|
||||||
|
if (!empty($this->rawentries)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} elseif ($url = filter_var($this->sourcefile, FILTER_VALIDATE_URL)) {
|
||||||
|
$this->rawentries = preg_split('/\x0A/', file_get_contents($url));
|
||||||
|
if (!empty($this->rawentries)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \Exception("{$this->sourcefile} is empty! Aborting.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse entries from source file and replace tags with links
|
||||||
|
*
|
||||||
|
* @param array $entries array of raw entries
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function parseEntries(array $entries, bool $parseTags = true)
|
||||||
|
{
|
||||||
|
switch ($this->format) {
|
||||||
|
case 'twtxt':
|
||||||
|
$pattern = '/^(?<date>[^\t]+)\t(?<entry>.+)/';
|
||||||
|
break;
|
||||||
|
case 'picoblog':
|
||||||
|
$pattern = '/^(?<date>[^\t]+)\t\(#(?<id>[a-zA-Z0-9]{1,7})\)\t(?<entry>.+)/';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foreach ($entries as $i => $entry) {
|
||||||
|
preg_match($pattern, $entry, $matches);
|
||||||
|
if (!$matches) continue;
|
||||||
|
$id = (!empty($matches['id'])) ? $matches['id'] : $i;
|
||||||
|
$matches['entry'] = $this->parseUsers($matches['entry']);
|
||||||
|
$matches['entry'] = $this->parseHashlinks($matches['entry']);
|
||||||
|
$parsedEntries[$id] = [
|
||||||
|
'date' => $matches['date'],
|
||||||
|
'entry' => ($parseTags) ? preg_replace('/#(\w+)?/', '<a href="?tag=$1" class="tag">#${1}</a>', $matches['entry']) : $matches['entry'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $parsedEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse user's nick
|
||||||
|
*
|
||||||
|
* @param string $entry
|
||||||
|
* @return string string with parsed users
|
||||||
|
*/
|
||||||
|
/*private function parseNick(array $entries)
|
||||||
|
{
|
||||||
|
$pattern = '/^(?<date>[^\t]+)\t(?<nick>.+)/';
|
||||||
|
preg_match('# nick\t=\t]+)\t(?<nick>.+)/', $nick, $matchn);
|
||||||
|
//if (!$matches) continue;
|
||||||
|
//$id = (!empty($matches['id'])) ? $matches['id'] : $i;
|
||||||
|
//$matches['entry'] = $this->parseUsers($matches['entry']);
|
||||||
|
//$matches['entry'] = $this->parseHashlinks($matches['entry']);
|
||||||
|
$parsedNick = [
|
||||||
|
'nick' => $matchn['nick']
|
||||||
|
];
|
||||||
|
return $parsedNick;
|
||||||
|
}
|
||||||
|
private function parseNick(string $entry) {
|
||||||
|
$pattern = "# nick = (.+)";
|
||||||
|
$aaa=preg_match_all($pattern, $this->rawentries, $matches);
|
||||||
|
print_r($aaa);
|
||||||
|
return print_r($aaa);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse any mentioned users in twtxt format: @<username https://feed-url>
|
||||||
|
*
|
||||||
|
* @param string $entry
|
||||||
|
* @return string string with parsed users
|
||||||
|
*/
|
||||||
|
private function parseUsers(string $entry) {
|
||||||
|
$pattern = '/\@<([a-zA-Z0-9\.]+)\W+(https?:\/\/[^>]+)>/';
|
||||||
|
return preg_replace($pattern,'<a href="$2">@$1</a>',$entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse any hashtags in twtxt.net hashlink format: #<tag https://feed-url>
|
||||||
|
*
|
||||||
|
* @param string $entry
|
||||||
|
* @return string string with parsed hashtags
|
||||||
|
*/
|
||||||
|
private function parseHashlinks(string $entry) {
|
||||||
|
$pattern = '/#<(\w+)\W+(https?:\/\/[^>]+)>/';
|
||||||
|
return preg_replace($pattern, '<a href="$2">#$1</a>', $entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a filtered list of raw entries
|
||||||
|
*
|
||||||
|
* @param string|array $search entry filter. can be 'all', 'newest', 'oldest', 'random' or an ID/Tag.
|
||||||
|
* @param bool $reverse return array in reverse order
|
||||||
|
* For ID, we're looking for ['id'=>'IDHERE']. For tag, we're looking for ['tag'=>'tagname']
|
||||||
|
* @return boolean|array
|
||||||
|
*/
|
||||||
|
public function getEntries($search, bool $reverse = true)
|
||||||
|
{
|
||||||
|
switch ($search) {
|
||||||
|
case '':
|
||||||
|
return false;
|
||||||
|
case 'all':
|
||||||
|
return ($reverse) ? array_reverse($this->rawentries) : $this->rawentries;
|
||||||
|
case 'newest':
|
||||||
|
return [reset($this->rawentries)];
|
||||||
|
case 'oldest':
|
||||||
|
return [end($this->rawentries)];
|
||||||
|
case 'random':
|
||||||
|
return [$this->rawentries[array_rand($this->rawentries, 1)]];
|
||||||
|
default:
|
||||||
|
if (isset($search['id'])) {
|
||||||
|
$filter = array_filter($this->rawentries, function ($entry) use ($search) {
|
||||||
|
preg_match("/\b$search[id]\b/i", $entry, $match);
|
||||||
|
return $match;
|
||||||
|
});
|
||||||
|
return $filter;
|
||||||
|
} elseif (isset($search['tag'])) {
|
||||||
|
$filter = array_filter($this->rawentries, function ($entry) use ($search) {
|
||||||
|
preg_match("/#\b$search[tag]\b/i", $entry, $match);
|
||||||
|
return $match;
|
||||||
|
});
|
||||||
|
return $filter;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Render Markdown in given entries and output as HTML
|
||||||
|
*
|
||||||
|
* @param array $entries array of parsed entries to render
|
||||||
|
* @param string $entryWrap tne entry wrapper, e.g. <li>{entry}</li>
|
||||||
|
* @param bool $parseTags should #tags be parsed to links?
|
||||||
|
* @return string entries in HTML
|
||||||
|
*/
|
||||||
|
public function renderEntries(array $entries, $show, string $entryWrap = '<li>{entry}</li>', bool $parseTags = false)
|
||||||
|
{
|
||||||
|
if (!$entries) return false;
|
||||||
|
$entries = $this->parseEntries($entries, $parseTags);
|
||||||
|
//$nick = $this->parseNick($nick);
|
||||||
|
require_once('includes/Slimdown.php');
|
||||||
|
$html = '';
|
||||||
|
foreach ($entries as $id => $entry) {
|
||||||
|
include "settings.php";
|
||||||
|
$text = \Slimdown::render($entry['entry']);
|
||||||
|
$date = $entry['date'];
|
||||||
|
$date_p = date("d-m-Y", strtotime($entry['date']));
|
||||||
|
if($show!=true){
|
||||||
|
$text = "<a href='?id={$id}'><div class='e'><span class='text'>" . $text . "</span><span class='date' title='{$date}'>{$date_p}</span></div></a>";
|
||||||
|
} else {
|
||||||
|
$text = "<div class='e show'><a href='{$url}'><h3><img class='pp' src='{$avatar}'> {$nick}</h3></a><h1 class='text'>" . $text . "</h1><p><span>#{$id}</span><span class='date' title='{$date}'>{$date_p}</span></p></div>";
|
||||||
|
}
|
||||||
|
$html .= str_replace('{entry}', $text, $entryWrap);
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
// Inlcude the files
|
||||||
|
include_once 'settings.php';
|
||||||
|
include_once 'includes/picoblog.php';
|
||||||
|
|
||||||
|
// Instantiate the class with the source file
|
||||||
|
$mb = new \hxii\PicoBlog($url);
|
||||||
|
|
||||||
|
// Parse query string and get blog entries
|
||||||
|
$query = $mb->parseQuery();
|
||||||
|
$entries = ($query) ? $mb->getEntries($query) : $mb->getEntries('all');
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?php echo $nick ?>@<?= $_SERVER['HTTP_HOST'] ?></title>
|
||||||
|
<link rel="icon" href="<?php echo $avatar ?>">
|
||||||
|
<link rel="stylesheet" type="text/css" href="styles.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>picoblog</h1>
|
||||||
|
<?php
|
||||||
|
// Display message and link to main list if viewing a filtered entry list
|
||||||
|
if ($query!=false) {
|
||||||
|
echo '<div>Currently viewing ' . implode('', $query) . '. Back to <a href="' . $_SERVER['PHP_SELF'] . '">list?</a></div>';
|
||||||
|
echo($mb->renderEntries($entries, true, '{entry}'));
|
||||||
|
} else {
|
||||||
|
echo($mb->renderEntries($entries, false, '{entry}'));
|
||||||
|
} ?>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php // Settings (most of them will be eliminated soon)
|
||||||
|
$url="https://picoblog.lu700.repl.co/blog.txt";
|
||||||
|
$nick = "lucas";
|
||||||
|
$avatar = "https://avatars.githubusercontent.com/u/83518257";
|
||||||
|
$description = "aaaa"; ?>
|
|
@ -0,0 +1,23 @@
|
||||||
|
@import url("https://lucas.koyu.space/styles.css");
|
||||||
|
.e{
|
||||||
|
margin:1px 10px;
|
||||||
|
padding:10px;
|
||||||
|
background:repeat-y center fixed url("bkg.png");
|
||||||
|
background-size:cover;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.e a{
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
/*.text{
|
||||||
|
float:left;
|
||||||
|
}*/
|
||||||
|
.date{
|
||||||
|
float:right;
|
||||||
|
}
|
||||||
|
.pp{
|
||||||
|
background:url("https://avatars.githubusercontent.com/u/83518257");
|
||||||
|
border-radius:100%;
|
||||||
|
width:20px;
|
||||||
|
height:20px;
|
||||||
|
}
|
Loading…
Reference in New Issue