This commit is contained in:
flash 2022-02-05 03:35:42 +00:00
parent 66679ae1df
commit ab2ffae8fd
27 changed files with 2252 additions and 2782 deletions

View file

@ -11,7 +11,7 @@ $baseUrl = empty($external) ? '' : '//' . $_SERVER['HTTP_HOST'];
window.fm = { onload: <?=json_encode($onload);?> };
</script>
<?php endif; ?>
<script src="<?=$baseUrl;?>/assets/2020v2.js" charset="utf-8" type="text/javascript"></script>
<script src="<?=$baseUrl;?>/assets/2021.js" charset="utf-8" type="text/javascript"></script>
<?php if(isset($scripts) && is_array($scripts)) foreach($scripts as $script): ?>
<script src="<?=$script;?>" charset="utf-8" type="text/javascript"></script>
<?php endforeach;?>

View file

@ -10,7 +10,7 @@ $showNowPlaying = !empty($is_index) || !empty($do_fullscreen_header);
<meta charset="utf-8"/>
<title><?=($title ?? 'flash.moe');?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="<?=$baseUrl;?>/assets/2020v2.css" type="text/css" rel="stylesheet"/>
<link href="<?=$baseUrl;?>/css/2021.css" type="text/css" rel="stylesheet"/>
<link href="<?=$baseUrl;?>/assets/sprite.css" type="text/css" rel="stylesheet"/>
<link href="<?=$baseUrl;?>/css/electrolize/style.css" type="text/css" rel="stylesheet"/>
<?php if(isset($styles) && is_array($styles)) foreach($styles as $style): ?>

@ -1 +1 @@
Subproject commit 74c0e6f17c21af3669345e38598ada1d37675ad4
Subproject commit 960cabb0567153db037f93d356895a13340aedd4

View file

@ -2,6 +2,9 @@
namespace Makai;
use Index\Autoloader;
use Index\Data\ConnectionFailedException;
use Index\Data\MariaDB\MariaDBBackend;
use Index\Data\MariaDB\MariaDBConnectionInfo;
define('MKI_STARTUP', microtime(true));
define('MKI_ROOT', __DIR__);
@ -9,6 +12,7 @@ define('MKI_DEBUG', is_file(MKI_ROOT . '/.debug'));
define('MKI_DIR_SRC', MKI_ROOT . '/src');
define('MKI_DIR_LIB', MKI_ROOT . '/lib');
define('MKI_DIR_PUB', MKI_ROOT . '/public');
define('MKI_DIR_PAGES', MKI_ROOT . '/pages');
if(MKI_DEBUG) {
ini_set('display_errors', 'on');
@ -21,3 +25,17 @@ if(MKI_DEBUG) {
require_once MKI_DIR_LIB . '/index/index.php';
Autoloader::addNamespace(__NAMESPACE__, MKI_DIR_SRC);
try {
$db = (new MariaDBBackend)->createConnection(MariaDBConnectionInfo::create(
'unix:/var/run/mysqld/mysqld.sock',
'website',
'A3NjVvHRkHAxiYgk8MM4ZrCwrLVyPIYX',
'website',
'utf8mb4',
'SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\'',
));
} catch(ConnectionFailedException $ex) {
echo '<h3>Unable to connect to database</h3>';
die($ex->getMessage());
}

View file

@ -1,23 +1,94 @@
<?php
namespace Makai;
if(preg_match('#^/blog/([0-9]+)$#', $reqPath, $matches) || $reqPath === '/blog.php' || $reqPath === '/blog-post.php') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Location: //flash.moe/2020/blog.php?blog=1&p=' . ($matches[1] ?? filter_input(INPUT_GET, 'p', FILTER_SANITIZE_NUMBER_INT) ?? ''));
return FM_HIT | 302;
}
$router->get('/blog.php', function() {
header('Location: /old-blog/' . (int)filter_input(INPUT_GET, 'p', FILTER_SANITIZE_NUMBER_INT));
return 302;
});
if($reqPath === '/blog-assets.json') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
$router->get('/blog-post.php', function() {
header('Location: /old-blog/' . (int)filter_input(INPUT_GET, 'p', FILTER_SANITIZE_NUMBER_INT));
return 302;
});
header('Content-Type: application/json; charset=utf-8');
$router->get('/blog/:id', function(string $id) {
header('Location: /old-blog/' . intval($id));
return 302;
});
echo json_encode([
'header_backgrounds' => FM_BGS,
'footer_quotes' => FM_FEET,
$router->get('/old-blog', function() {
$blogInfo = json_decode(file_get_contents(MKI_DIR_PUB . '/old_blog_posts.json'));
$body = fm_component('header', [
'title' => 'flash.moe / old blog posts',
]);
return FM_HIT;
}
$body .= <<<HTML
<div style="max-width: 1000px; margin: 0 auto; font-size: 20px; line-height: 1.7em;">
<div style="margin: 5px; background-color: #222; border-radius: 5px; padding: 2px 5px; text-align: center;">List of old blog posts to enjoy while I Eventually make the new script.</div>
</div>
HTML;
$body .= '<div class="ob-wrapper"><div class="ob-blogs">';
foreach($blogInfo as $postInfo) {
$preview = trim(explode("\n", $postInfo->post_text)[0]);
$dateCustom = date('Y-m-d @ H:i:s T', $postInfo->post_published);
$dateISO = date('c', $postInfo->post_published);
$body .= <<<HTML
<div class="ob-blog ob-preview">
<h1><a href="/old-blog/{$postInfo->post_id}">{$postInfo->post_title}</a></h1>
<time datetime="{$dateISO}">{$dateCustom}</time>
<p>{$preview}</p>
<a class="ob-continue" href="/old-blog/{$postInfo->post_id}">Continue reading</a>
</div>\r\n
HTML;
}
$body .= '</div></div>';
$body .= fm_component('footer');
return $body;
});
$router->get('/old-blog/:id', function(string $id) {
if(!is_numeric($id))
return 404;
$postId = intval($id);
$blogInfo = json_decode(file_get_contents(MKI_DIR_PUB . '/old_blog_posts.json'));
foreach($blogInfo as $postInfo) {
if($postInfo->post_id !== $postId)
continue;
$dateCustom = date('Y-m-d @ H:i:s T', $postInfo->post_published);
$dateISO = date('c', $postInfo->post_published);
$preview = trim(explode("\n", $postInfo->post_text)[0]);
$body = fm_component('header', [
'title' => 'flash.moe / ' . $postInfo->post_title,
]);
$body .= '<div class="ob-wrapper"><div class="ob-blog"><div class="ob-blog">';
if(!empty($postInfo->post_new_url))
$body .= "<a href=\"{$postInfo->post_new_url}\" style=\"display: block; text-align: center; color: #fff; text-decoration: none; font-size: 2em; line-height: 1.5em; padding: 20px 10px; margin: 10px 0; font-weight: bold; background-color: #222; border-radius: 5px\">This post has a new url, please go here instead!</a>";
$body .= "<h1>{$postInfo->post_title}</h1>";
$body .= "<time datetime=\"{$dateISO}\">{$dateCustom}</time>";
$splitLines = explode("\n", $postInfo->post_text);
foreach ($splitLines as $paragraph)
if(!empty($paragraph))
$body .= '<p>' . trim($paragraph) . '</p>';
$body .= '</div></div></div>';
$body .= fm_component('footer');
return $body;
}
return 404;
});

View file

@ -1,56 +1,13 @@
<?php
namespace Makai;
if($reqPath === '/contact.php' || $reqPath === '/contact.html') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Location: /contact');
return FM_HIT | 302;
}
$router->get('/contact.php', mkiRedirect('/contact'));
$router->get('/contact.html', mkiRedirect('/contact'));
if($reqPath === '/nintendo' || $reqPath === '/nintendo.php') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Location: /contact#gaming');
return FM_HIT | 302;
}
if($reqPath === '/now-listening.json') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Content-Type: application/json; charset=utf-8');
if($reqHead)
return FM_HIT;
$lfmInfo = cache_output('lastfm', 10, function() {
return json_decode(file_get_contents('https://now.flash.moe/get.php?u=flashwave_'));
});
if(empty($lfmInfo[0]->name))
echo '[]';
else {
$lfmInfo = $lfmInfo[0];
echo json_encode([
'name' => strval($lfmInfo->name),
'now_playing' => !empty($lfmInfo->nowplaying),
'url' => strval($lfmInfo->url),
'cover' => !empty($lfmInfo->images->large) ? strval($lfmInfo->images->large) : '',
'artist' => [
'name' => !empty($lfmInfo->artist->name) ? strval($lfmInfo->artist->name) : '',
'url' => explode('/_/', strval($lfmInfo->url))[0],
],
]);
}
return FM_HIT;
}
if($reqPath === '/contact') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
if($reqHead)
return FM_HIT;
$router->get('/nintendo', mkiRedirect('/contact#gaming'));
$router->get('/nintendo.php', mkiRedirect('/contact#gaming'));
$router->get('/contact', function() {
$contact = [
[
'id' => 'contact',
@ -189,38 +146,45 @@ if($reqPath === '/contact') {
],
];
fm_component('header', [
$body = fm_component('header', [
'title' => 'flash.moe / contact',
]);
foreach($contact as $section) {
?>
<div class="section" id="section-<?=$section['id'];?>">
$body .= <<<HTML
<div class="section" id="section-{$section['id']}">
<div class="section-content">
<div class="section-background"></div>
<h1><?=$section['title'];?></h1>
<h1>{$section['title']}</h1>
</div>
</div>
<div class="socials">
<?php foreach($section['items'] as $social): ?>
<div class="social social-<?=$social['id'];?>">
<?php if(isset($social['link'])): ?>
<a href="<?=$social['link'];?>" class="social-background" target="_blank" rel="noopener"></a>
<?php else: ?>
<div class="social-background" onclick="fm.selectTextInElement(this.parentNode.querySelector('.social-handle')); fm.copySelectedText();"></div>
<?php endif; ?>
<div class="social-icon <?=$social['icon'];?>"></div>
HTML;
foreach($section['items'] as $social) {
$body .= '<div class="social social-' . $social['id'] . '">';
if(isset($social['link'])) {
$body .= '<a href="' . $social['link'] . '" class="social-background" target="_blank" rel="noopener"></a>';
} else {
$body .= '<div class="social-background" onclick="fm.selectTextInElement(this.parentNode.querySelector(\'.social-handle\')); fm.copySelectedText();"></div>';
}
$body .= <<<HTML
<div class="social-icon {$social['icon']}"></div>
<div class="social-content">
<div class="social-name"><?=$social['name'];?></div>
<div class="social-handle"><?=$social['display'];?></div>
<div class="social-name">{$social['name']}</div>
<div class="social-handle">{$social['display']}</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php
HTML;
}
$body .= '</div>';
}
fm_component('footer');
$body .= fm_component('footer');
return FM_HIT;
}
return $body;
});

View file

@ -1,20 +1,16 @@
<?php
namespace Makai;
if($reqPath === '/etc.php' || $reqPath === 'etc.html'
|| $reqPath === '/etcetera' || $reqPath === '/etcetera.html' || $reqPath === '/etcetera.php'
|| $reqPath === '/misc' || $reqPath === '/misc.html' || $reqPath === '/misc.php') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Location: /etc');
return FM_HIT | 302;
}
$router->get('/etc.php', mkiRedirect('/etc'));
$router->get('/etc.html', mkiRedirect('/etc'));
$router->get('/etcetera', mkiRedirect('/etc'));
$router->get('/etcetera.html', mkiRedirect('/etc'));
$router->get('/etcetera.php', mkiRedirect('/etc'));
$router->get('/misc', mkiRedirect('/etc'));
$router->get('/misc.html', mkiRedirect('/etc'));
$router->get('/misc.php', mkiRedirect('/etc'));
if($reqPath === '/etc') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
if($reqHead)
return FM_HIT;
$router->get('/etc', function() {
$links = [
[
'title' => 'ASCII Table',
@ -48,28 +44,32 @@ if($reqPath === '/etc') {
],
];
fm_component('header', [
$body = fm_component('header', [
'title' => 'flash.moe / etcetera',
]);
?>
<div class="section">
<div class="section-content">
<div class="section-background"></div>
<h1>Etcetera</h1>
</div>
</div>
<?php foreach($links as $link): ?>
<div class="etcetera-item">
<div class="etcetera-item-content">
<a href="<?=$link['link'];?>" class="etcetera-item-link" rel="noopener" target="_blank"></a>
<h2><?=$link['title'];?></h2>
<p><?=$link['desc'];?></p>
</div>
</div>
<?php
endforeach;
fm_component('footer');
$body .= <<<HTML
<div class="section">
<div class="section-content">
<div class="section-background"></div>
<h1>Etcetera</h1>
</div>
</div>
HTML;
return FM_HIT;
}
foreach($links as $link) {
$body .= <<<HTML
<div class="etcetera-item">
<div class="etcetera-item-content">
<a href="{$link['link']}" class="etcetera-item-link" rel="noopener" target="_blank"></a>
<h2>{$link['title']}</h2>
<p>{$link['desc']}</p>
</div>
</div>
HTML;
}
$body .= fm_component('footer');
return $body;
});

View file

@ -1,61 +1,69 @@
<?php
namespace Makai;
if($reqPath === '/about' || $reqPath === '/about.html' || $reqPath === '/about.php'
|| $reqPath === '/index.php' || $reqPath === '/index.html') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Location: /');
return FM_HIT | 302;
}
$router->get('/about', mkiRedirect('/'));
$router->get('/about.html', mkiRedirect('/'));
$router->get('/about.php', mkiRedirect('/'));
$router->get('/index.php', mkiRedirect('/'));
$router->get('/index.html', mkiRedirect('/'));
if($reqPath === '/header-bgs.json') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
$router->get('/365', mkiRedirect('/?fw365'));
header('Content-Type: application/json; charset=utf-8');
if($reqHead)
return FM_HIT;
echo json_encode(FM_BGS);
$router->get('/donate', mkiRedirect('https://paypal.me/flashwave'));
return FM_HIT;
}
if($reqPath === '/now-listening') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
if($reqHead)
return FM_HIT;
$router->get('/header-bgs.json', function() {
return json_encode(FM_BGS);
});
$router->get('/now-listening', function() {
$offset = (int)filter_input(INPUT_GET, 'offset', FILTER_SANITIZE_NUMBER_INT);
fm_component('header', [
$body = fm_component('header', [
'title' => 'flash.moe / now listening',
'do_fullscreen_header' => true,
'is_now_playing' => true,
'offset' => $offset,
]);
fm_component('footer', [
$body .= fm_component('footer', [
'hide' => true,
'onload' => [
['fm.initIndex', 10],
],
]);
return FM_HIT;
}
return $body;
});
if($reqPath === '/home') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
if($reqHead)
return FM_HIT;
$router->get('/now-listening.json', function() {
$lfmInfo = cache_output('lastfm', 10, function() {
return json_decode(file_get_contents('https://now.flash.moe/get.php?u=flashwave_'));
});
fm_component('header', [
if(empty($lfmInfo[0]->name))
return [];
$lfmInfo = $lfmInfo[0];
return [
'name' => strval($lfmInfo->name),
'now_playing' => !empty($lfmInfo->nowplaying),
'url' => strval($lfmInfo->url),
'cover' => !empty($lfmInfo->images->large) ? strval($lfmInfo->images->large) : '',
'artist' => [
'name' => !empty($lfmInfo->artist->name) ? strval($lfmInfo->artist->name) : '',
'url' => explode('/_/', strval($lfmInfo->url))[0],
],
];
});
$router->get('/home', function() {
$body = fm_component('header', [
'title' => 'flash.moe / homepage',
'do_fullscreen_header' => true,
]);
?>
$body .= <<<HTML
<div class="php">
<div class="php-time">
<div class="php-time-analog">
@ -91,8 +99,9 @@ if($reqPath === '/home') {
</div>
</form>
</div>
<?php
fm_component('footer', [
HTML;
$body .= fm_component('footer', [
'hide' => true,
'skip_analytics' => true,
'onload' => [
@ -101,22 +110,10 @@ if($reqPath === '/home') {
],
]);
return FM_HIT;
}
if($reqPath === '/donate') {
header('Location: https://paypal.me/flashwave');
return FM_HIT | 302;
}
if($reqPath === '/' || $reqPath === '/365') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
if($reqHead)
return FM_HIT;
$is365 = $reqPath === '/365';
return $body;
});
$router->get('/', function() use ($db) {
$legacyPage = (string)filter_input(INPUT_GET, 'p');
if(!empty($legacyPage)) {
$legacyPages = [
@ -127,20 +124,19 @@ if($reqPath === '/' || $reqPath === '/365') {
'hosted' => '/etc',
'friends' => '/related',
];
if(isset($legacyPages[$legacyPage])) {
header('Location: ' . $legacyPages[$legacyPage]);
return FM_HIT | 302;
return 302;
}
}
$blogInfo = cache_output('blog', 600, function() {
return json_decode(file_get_contents('https://flash.moe/2020/?blog_dump'));
});
$projInfo = cache_output('projects-featured', 300, function() {
return json_decode(file_get_contents('https://flash.moe/2020/projects.php?dump_that_shit&rf'));
});
$is365 = isset($_GET['fw365']);
shuffle($projInfo);
$blogInfo = json_decode(file_get_contents(MKI_DIR_PUB . '/old_blog_posts.json'));
$projects = (new Projects($db))->getFeatured();
$languages = new Languages($db);
$contact = [
[
@ -173,108 +169,145 @@ if($reqPath === '/' || $reqPath === '/365') {
],
];
fm_component('header', [
$body = fm_component('header', [
'title' => 'flash.moe',
'is_index' => true,
'is_365' => $is365,
]);
?>
<div class="index-menu">
<?php for($i = 1; $i < count(FM_NAV); ++$i): ?>
<a href="<?=(FM_NAV[$i]['link']);?>"<?php if(FM_NAV[$i]['link'][0] === '/' && substr(FM_NAV[$i]['link'], 0, 2) !== '//') { echo ' data-fm-dynload=""'; } ?>><?=(FM_NAV[$i]['title']);?></a>
<?php endfor; ?>
</div>
<div class="index-featured">
<div class="index-feature">
<div class="index-feature-header">
<a href="//blog.flash.moe" class="index-feature-header-link"></a>
<div class="index-feature-header-title">Blog</div>
<div class="index-feature-header-more">More</div>
</div>
<div class="index-blog">
<?php $blogCount = 0; foreach($blogInfo as $blogPost): if($blogCount++ >= 5) break; ?>
<div class="index-blog-post">
<a href="//flash.moe/blog/<?=$blogPost->post_id;?>" class="index-blog-post-link"></a>
<div class="index-blog-post-header">
<div class="index-blog-post-title"><?=$blogPost->post_title;?></div>
<div class="index-blog-post-published"><time datetime="<?=date('c', $blogPost->post_published);?>" title="<?=date('r', $blogPost->post_published);?>"><?=time_elapsed($blogPost->post_published);?></time></div>
</div>
<div class="index-blog-post-content">
<?=first_paragraph($blogPost->post_text);?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="index-feature">
<div class="index-feature-header">
<a href="/projects" class="index-feature-header-link" data-fm-dynload=""></a>
<div class="index-feature-header-title">Projects</div>
<div class="index-feature-header-more">More</div>
</div>
<?php
$projCount = 0;
foreach($projInfo as $proj):
if($projCount++ >= 3)
break;
$links = [];
if(isset($proj->homepage))
$links[] = ['class' => 'homepage', 'text' => 'Homepage', 'url' => $proj->homepage];
if(isset($proj->repository))
$links[] = ['class' => 'repository', 'text' => 'Source', 'url' => $proj->repository];
if(isset($proj->forum))
$links[] = ['class' => 'forum', 'text' => 'Discussion', 'url' => $proj->forum];
?>
<div class="index-project" style="background-color: #<?=str_pad(dechex($proj->colour), 6, '0', STR_PAD_LEFT);?>;">
<a href="/projects#<?=$proj->name_clean;?>" class="index-project-anchor" data-fm-dynload=""></a>
<div class="index-project-content">
<div class="index-project-name"><?=$proj->name;?></div>
<div class="index-project-summary"><?=$proj->summary;?></div>
</div>
<?php if(!empty($links)): ?>
<div class="index-project-links">
<?php foreach($links as $link): ?>
<a class="index-project-link index-project-link-<?=$link['class'];?>" href="<?=$link['url'];?>" rel="noopener" target="_blank">
<?=$link['text'];?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<div class="index-feature">
<div class="index-feature-header">
<a href="/contact" class="index-feature-header-link" data-fm-dynload=""></a>
<div class="index-feature-header-title">Contact</div>
<div class="index-feature-header-more">More</div>
</div>
<div class="index-contact">
<?php foreach($contact as $social): ?>
<div class="social social-<?=$social['id'];?>">
<?php if(isset($social['link'])): ?>
<a href="<?=$social['link'];?>" class="social-background" target="_blank" rel="noopener"></a>
<?php else: ?>
<div class="social-background" onclick="fm.selectTextInElement(this.parentNode.querySelector('.social-handle')); fm.copySelectedText();"></div>
<?php endif; ?>
<div class="social-icon <?=$social['icon'];?>"></div>
<div class="social-content">
<div class="social-name"><?=$social['name'];?></div>
<div class="social-handle"><?=$social['display'];?></div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
$body .= '<div class="index-menu">';
for($i = 1; $i < count(FM_NAV); ++$i) {
$link = FM_NAV[$i];
$body .= "<a href=\"{$link['link']}\"";
if($link['link'][0] === '/' && substr($link['link'], 0, 2) !== '//')
$body .= ' data-fm-dynload=""';
$body .= ">{$link['title']}</a>";
}
$body .= <<<HTML
</div>
<div class="index-featured">
<div class="index-feature">
<div class="index-feature-header">
<a href="//blog.flash.moe" class="index-feature-header-link"></a>
<div class="index-feature-header-title">Blog</div>
<div class="index-feature-header-more">More</div>
</div>
<?php
fm_component('footer', [
<div class="index-blog">
HTML;
$blogCount = 0;
foreach($blogInfo as $blogPost) {
if($blogCount++ >= 5)
break;
$dateTimeC = date('c', $blogPost->post_published);
$dateTimeR = date('r', $blogPost->post_published);
$timeElapsed = time_elapsed($blogPost->post_published);
$paragraph = first_paragraph($blogPost->post_text);
$body .= <<<HTML
<div class="index-blog-post">
<a href="//flash.moe/blog/{$blogPost->post_id}" class="index-blog-post-link"></a>
<div class="index-blog-post-header">
<div class="index-blog-post-title">{$blogPost->post_title}</div>
<div class="index-blog-post-published"><time datetime="{$dateTimeC}" title="<{$dateTimeR}">{$timeElapsed}</time></div>
</div>
<div class="index-blog-post-content">
{$paragraph}
</div>
</div>
HTML;
}
$body .= <<<HTML
</div>
</div>
<div class="index-feature">
<div class="index-feature-header">
<a href="/projects" class="index-feature-header-link" data-fm-dynload=""></a>
<div class="index-feature-header-title">Projects</div>
<div class="index-feature-header-more">More</div>
</div>
HTML;
foreach($projects as $project) {
$links = [];
if($project->hasHomePageUrl())
$links[] = ['class' => 'homepage', 'text' => 'Homepage', 'url' => $project->getHomePageUrl()];
if($project->hasSourceUrl())
$links[] = ['class' => 'repository', 'text' => 'Source', 'url' => $project->getSourceUrl()];
if($project->hasDiscussionUrl())
$links[] = ['class' => 'forum', 'text' => 'Discussion', 'url' => $project->getDiscussionUrl()];
$colour = $project->hasColour() ? $project->getColour() : $languages->getProjectColour($project);
$colour = str_pad(dechex($colour), 6, '0', STR_PAD_LEFT);
$body .= <<<HTML
<div class="index-project" style="background-color: #{$colour};">
<a href="/projects#{$project->getCleanName()}" class="index-project-anchor" data-fm-dynload=""></a>
<div class="index-project-content">
<div class="index-project-name">{$project->getName()}</div>
HTML;
if($project->hasSummary())
$body .= "<div class=\"index-project-summary\">{$project->getSummary()}</div>";
$body .= '</div>';
if(!empty($links)) {
$body .= '<div class="index-project-links">';
foreach($links as $link)
$body .= "<a class=\"index-project-link index-project-link-{$link['class']}\" href=\"{$link['url']}\" rel=\"noopener\" target=\"_blank\">{$link['text']}</a>";
$body .= '</div>';
}
$body .= '</div>';
}
$body .= <<<HTML
</div>
<div class="index-feature">
<div class="index-feature-header">
<a href="/contact" class="index-feature-header-link" data-fm-dynload=""></a>
<div class="index-feature-header-title">Contact</div>
<div class="index-feature-header-more">More</div>
</div>
<div class="index-contact">
HTML;
foreach($contact as $social) {
$body .= "<div class=\"social social-{$social['id']}\">";
if(isset($social['link'])) {
$body .= "<a href=\"{$social['link']}\" class=\"social-background\" target=\"_blank\" rel=\"noopener\"></a>";
} else {
$body .= "<div class=\"social-background\" onclick=\"fm.selectTextInElement(this.parentNode.querySelector('.social-handle')); fm.copySelectedText();\"></div>";
}
$body .= <<<HTML
<div class="social-icon {$social['icon']}"></div>
<div class="social-content">
<div class="social-name">{$social['name']}</div>
<div class="social-handle">{$social['display']}</div>
</div>
</div>
HTML;
}
$body .= '</div></div></div>';
$body .= fm_component('footer', [
'is_index' => true,
'onload' => [
['fm.initIndex'],
],
]);
return FM_HIT;
}
return $body;
});

View file

@ -1,96 +1,126 @@
<?php
namespace Makai;
if($reqPath === '/projects.php' || $reqPath === '/projects.html'
|| $reqPath === '/utilities' || $reqPath === '/utilities.php' || $reqPath === '/utilities.html') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Location: /projects');
return FM_HIT | 302;
}
$router->get('/projects.php', mkiRedirect('/projects'));
$router->get('/projects.html', mkiRedirect('/projects'));
$router->get('/utilities', mkiRedirect('/projects'));
$router->get('/utilities.php', mkiRedirect('/projects'));
$router->get('/utilities.html', mkiRedirect('/projects'));
if($reqPath === '/projects') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
if($reqHead)
return FM_HIT;
$router->get('/projects', function() use ($db) {
$projects = (new Projects($db))->getAll();
$languages = new Languages($db);
$projInfo = cache_output('projects', 300, function() {
return json_decode(file_get_contents('https://flash.moe/2020/projects.php?dump_that_shit'));
});
fm_component('header', [
'title' => 'flash.moe / projects',
]);
$sectionInfos = [
'project' => [
$sections = [
'projects' => [
'title' => 'Active Projects',
'desc' => 'Projects that I work on on a fairly regular basis.',
'items' => [],
],
'tool' => [
'tools' => [
'title' => 'Tools',
'desc' => 'Personal quality of life tools that I update when I need something new from them.',
'items' => [],
],
'archive' => [
'archives' => [
'title' => 'Archived Projects',
'desc' => 'Past projects that I no longer work on.',
'items' => [],
],
];
foreach($projInfo as $section => $projects):
$sectionInfo = $sectionInfos[$section];
?>
<div class="section" id="section-<?=$section;?>">
<div class="section-content">
<div class="section-background"></div>
<h1><?=$sectionInfo['title'];?></h1>
<p><?=$sectionInfo['desc'];?></p>
</div>
</div>
<?php
foreach($projects as $proj):
$links = [];
if(isset($proj->homepage))
$links[] = ['class' => 'homepage', 'text' => 'Homepage', 'url' => $proj->homepage];
if(isset($proj->repository))
$links[] = ['class' => 'repository', 'text' => 'Source', 'url' => $proj->repository];
if(isset($proj->forum))
$links[] = ['class' => 'forum', 'text' => 'Discussion', 'url' => $proj->forum];
foreach($projects as $project) {
if($project->isArchived())
$sections['archives']['items'][] = $project;
else {
if($project->isTool())
$sections['tools']['items'][] = $project;
else
$sections['projects']['items'][] = $project;
}
}
$descLines = explode("\n", trim($proj->description ?? ''));
?>
<div class="project project-type-<?=$section;?>" id="<?=$proj->name_clean;?>" style="--project-colour: #<?=str_pad(dechex($proj->colour), 6, '0', STR_PAD_LEFT);?>;">
$body = fm_component('header', [
'title' => 'flash.moe / projects',
]);
foreach($sections as $sectionId => $section) {
$body .= <<<HTML
<div class="section" id="section-{$sectionId}">
<div class="section-content">
<div class="section-background"></div>
<h1>{$section['title']}</h1>
<p>{$section['desc']}</p>
</div>
</div>
HTML;
foreach($section['items'] as $project) {
$links = [];
if($project->hasHomePageUrl())
$links[] = ['class' => 'homepage', 'text' => 'Homepage', 'url' => $project->getHomePageUrl()];
if($project->hasSourceUrl())
$links[] = ['class' => 'repository', 'text' => 'Source', 'url' => $project->getSourceUrl()];
if($project->hasDiscussionUrl())
$links[] = ['class' => 'forum', 'text' => 'Discussion', 'url' => $project->getDiscussionUrl()];
$descLines = $project->hasDescription() ? $project->getDescription()->trim()->split("\n") : [];
$langs = $languages->getByProject($project);
if($project->hasColour())
$colour = $project->getColour();
else
foreach($langs as $lang)
if($lang->hasColour()) {
$colour = $lang->getColour();
break;
}
$colour = str_pad(dechex($colour), 6, '0', STR_PAD_LEFT);
$body .= <<<HTML
<div class="project project-type-{$sectionId}" id="{$project->getCleanName()}" style="--project-colour: #{$colour};">
<div class="project-content">
<div class="project-details">
<h2><?=$proj->name;?><div class="project-languages">
<?php foreach($proj->languages as $lang): ?>
<div class="project-language" style="--language-colour: #<?=str_pad(dechex($lang->colour), 6, '0', STR_PAD_LEFT);?>;">
<?=$lang->name;?>
</div>
<?php endforeach; ?>
</div></h2>
<p class="project-details-summary"><?=$proj->summary;?></p>
<?php foreach($descLines as $line): if(empty($line)) continue; ?>
<p><?=trim($line);?></p>
<?php endforeach; ?>
</div>
<?php if(!empty($links)): ?>
<div class="project-links">
<?php foreach($links as $link): ?>
<a class="project-link project-link-<?=$link['class'];?>" href="<?=$link['url'];?>" rel="noopener" target="_blank">
<?=$link['text'];?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php
endforeach;
endforeach;
<h2>{$project->getName()}<div class="project-languages">
HTML;
fm_component('footer');
foreach($langs as $lang) {
$langColour = str_pad(dechex($lang->getColour() ?? 0), 6, '0', STR_PAD_LEFT);
$body .= "<div class=\"project-language\" style=\"--language-colour: #{$langColour};\">{$lang->getName()}</div>";
}
return FM_HIT;
}
$body .= '</div></h2>';
if($project->hasSummary())
$body .= "<p class=\"project-details-summary\">{$project->getSummary()}</p>";
foreach($descLines as $line) {
$line = $line->trim();
if($line->isEmpty())
continue;
$body .= "<p>{$line}</p>";
}
$body .= '</div>';
if(!empty($links)) {
$body .= '<div class="project-links">';
foreach($links as $link)
$body .= "<a class=\"project-link project-link-{$link['class']}\" href=\"{$link['url']}\" rel=\"noopener\" target=\"_blank\">{$link['text']}</a>";
$body .= '</div>';
}
$body .= '</div></div>';
}
}
$body .= fm_component('footer');
return $body;
});

View file

@ -1,20 +1,13 @@
<?php
namespace Makai;
if($reqPath === '/related.php' || $reqPath === '/related.html'
|| $reqPath === '/friends' || $reqPath === '/friends.html' || $reqPath === '/friends.php') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
header('Location: /related');
return FM_HIT | 302;
}
if($reqPath === '/related') {
if($reqMethod !== 'GET')
return FM_ERR | 405;
if($reqHead)
return FM_HIT;
$router->get('/related.php', mkiRedirect('/related'));
$router->get('/related.html', mkiRedirect('/related'));
$router->get('/friends', mkiRedirect('/related'));
$router->get('/friends.php', mkiRedirect('/related'));
$router->get('/friends.html', mkiRedirect('/related'));
$router->get('/related', function() {
$related = [
[
'id' => 'own',
@ -102,31 +95,36 @@ if($reqPath === '/related') {
],
];
fm_component('header', [
$body = fm_component('header', [
'title' => 'flash.moe / related',
]);
foreach($related as $section):
?>
<div class="section" id="<?=$section['id'];?>">
foreach($related as $section) {
$body .= <<<HTML
<div class="section" id="{$section['id']}">
<div class="section-content">
<div class="section-background"></div>
<h1><?=$section['name'];?></h1>
<h1>{$section['name']}</h1>
</div>
</div>
<?php foreach($section['sites'] as $site): ?>
HTML;
foreach($section['sites'] as $site) {
$body .= <<<HTML
<div class="related-site">
<div class="related-site-content">
<a href="<?=$site['url'];?>" class="related-site-link" rel="noopener" target="_blank"></a>
<h2><?=$site['name'];?></h2>
<?php if(isset($site['desc'])): ?>
<p><?=$site['desc'];?></p>
<?php endif; ?>
</div>
</div>
<?php endforeach; endforeach;
<a href="{$site['url']}" class="related-site-link" rel="noopener" target="_blank"></a>
<h2>{$site['name']}</h2>
HTML;
fm_component('footer');
if(isset($site['desc']))
$body .= "<p>{$site['desc']}</p>";
return FM_HIT;
}
$body .= '</div></div>';
}
}
$body .= fm_component('footer');
return $body;
});

View file

@ -1,29 +0,0 @@
<?php
http_response_code(404);
require_once __DIR__ . '/../_v4/includes.php';
define('FWH_STYLE', FWH_2020);
echo html_doctype();
?>
<html lang="en">
<head>
<?=html_charset();?>
<title>404 Not Found</title>
<?=html_stylesheet('2020.css');?>
<?=html_meta();?>
</head>
<body>
<div class="wrapper">
<?=html_sidebar();?>
<div class="notfound">
<h1>404 - Page not found!</h1>
<p>You either went to an invalid URL or this content has been deleted.</p>
</div>
</div>
<?php if(html_old_ie()) { ?>
<?=html_script('/assets/fixpng.js');?>
<?php } ?>
</body>
</html>

View file

@ -1,84 +0,0 @@
<?php
require_once __DIR__ . '/../_v4/includes.php';
define('FWH_STYLE', FWH_2020);
$blogMode = !empty($_GET['blog']);
$postId = !empty($_GET['p']) && is_string($_GET['p']) && ctype_digit($_GET['p']) ? (int)($_GET['p']) : 0;
if($postId < 1) {
header('Location: /2020');
exit;
}
$getPost = $pdo->prepare('
SELECT `post_id`, `post_title`, `post_text`, UNIX_TIMESTAMP(`post_published`) AS `post_published`, `post_safe`, `post_new_url`
FROM `fm_blog_posts`
WHERE `post_id` = :id
AND `post_published` IS NOT NULL
AND `post_published` < CURRENT_TIMESTAMP
AND `post_deleted` IS NULL
');
$getPost->bindValue('id', $postId);
$post = $getPost->execute() ? $getPost->fetch(PDO::FETCH_OBJ) : false;
if(html_default_mode() === FWH_JVDG && empty($post->post_safe))
unset($post);
if(!empty($post)) {
$dateCustom = date('Y-m-d @ H:i:s T', $post->post_published);
$dateISO = date('c', $post->post_published);
$preview = trim(explode("\n", $post->post_text)[0]);
$title = $post->post_title;
} else http_response_code(404);
if($blogMode) {
fm_component('header', [
'title' => $title,
'styles' => [
'/css/2020.css'
],
]);
} else {
echo html_doctype();
?>
<html lang="en">
<head>
<?=html_charset();?>
<title><?=$title ?? 'flash.moe';?></title>
<?=html_stylesheet('2020.css');?>
<?=html_meta();?>
</head>
<body>
<?php } ?>
<div class="wrapper">
<?php if(!$blogMode) echo html_sidebar(); ?>
<?php if(empty($post)) { ?>
<div class="notfound">
<h1>Post not found!</h1>
<p>You either went to an invalid URL or this post has been deleted.</p>
</div>
<?php } else { ?>
<div class="blog">
<?php if(!empty($post->post_new_url)): ?>
<a href="<?=$post->post_new_url;?>" style="display: block; text-align: center; color: #fff; text-decoration: none; font-size: 2em; line-height: 1.5em; padding: 20px 10px; margin: 10px 0; font-weight: bold">This post has a new url, please go here instead!</a>
<?php endif; ?>
<h1><?=$post->post_title;?></h1>
<time datetime="<?=$dateISO;?>"><?=$dateCustom;?></time>
<?php
$splitLines = explode("\n", $post->post_text);
foreach ($splitLines as $paragraph)
if(!empty($paragraph))
echo '<p>' . trim($paragraph) . '</p>';
?>
</div>
<?php } ?>
</div>
<?php if($blogMode): fm_component('footer'); else: ?>
<?php if(html_old_ie()) { ?>
<?=html_script('/assets/fixpng.js');?>
<?php } ?>
</body>
</html>
<?php endif; ?>

View file

@ -1,106 +0,0 @@
<?php
require_once __DIR__ . '/../_v4/includes.php';
define('FWH_STYLE', FWH_2020);
$blogMode = !empty($_GET['blog']);
$requireSafe = html_default_mode() === FWH_JVDG;
if(!$requireSafe) {
$getPosts = $pdo->prepare("
SELECT `post_id`, `post_title`, `post_text`, UNIX_TIMESTAMP(`post_published`) AS `post_published`
FROM `fm_blog_posts` AS bp
WHERE `post_published` IS NOT NULL
AND `post_published` < CURRENT_TIMESTAMP
AND `post_deleted` IS NULL
ORDER BY `post_published` DESC
");
$posts = $getPosts->execute() ? $getPosts->fetchAll(PDO::FETCH_OBJ) : false;
$posts = $posts ? $posts : [];
}
if(isset($_GET['blog_dump'])) {
header('Content-Type: application/json; charset=utf-8');
echo json_encode($posts ?? []);
return;
}
if($blogMode) {
fm_component('header', [
'title' => 'flash.moe blog',
'styles' => [
'/css/2020.css'
],
]);
} else {
echo html_doctype();
?>
<html lang="en">
<head>
<?=html_charset();?>
<title><?=$_SERVER['HTTP_HOST'];?></title>
<?=html_stylesheet('2020.css');?>
<?=html_meta();?>
<?php if($requireSafe): ?>
<style type="text/css">
.wrapper { justify-content: center; }
</style>
<?php endif; ?>
</head>
<body>
<?php } ?>
<?php /*if($blogMode): ?>
<div style="max-width: 1000px; margin: 0 auto; font-size: 20px; line-height: 1.7em;">
<div style="margin: 5px; background-color: #222; border-radius: 5px; padding: 2px 5px;">New blog script is still work in progress, enjoy the old version!</div>
</div>
<?php endif;*/ ?>
<div class="wrapper">
<?php if(!$blogMode) echo html_sidebar(); ?>
<?php if(!empty($posts)): ?>
<div class="blogs">
<?php
/*if(!$requireSafe) {
?>
<div class="banner">
<img src="/assets/misaka-2.png" alt=""/>
<h1>Blog</h1>
</div>
<?php
}*/
$urlSuffix = $blogMode ? '?blog=1' : '';
foreach($posts as $post) {
$preview = trim(explode("\n", $post->post_text)[0]);
$dateCustom = date('Y-m-d @ H:i:s T', $post->post_published);
$dateISO = date('c', $post->post_published);
echo <<<HTML
<div class="blog preview">
<h1><a href="/blog/{$post->post_id}">{$post->post_title}</a></h1>
<time datetime="{$dateISO}">{$dateCustom}</time>
<p>{$preview}</p>
<a class="continue" href="/blog/{$post->post_id}{$urlSuffix}">Continue reading</a>
</div>\r\n
HTML;
}
?>
</div>
<?php endif; ?>
<?php if($blogMode): fm_component('footer'); else: ?>
</div>
<?=html_script('/assets/lastfm2020.js');?>
<?php
if(!$requireSafe) {
if(html_old_ie()) {
?>
<?=html_script('/assets/fixpng.js');?>
<bgsound src="/assets/SMS-JBIOS-Demo.mid" loop="infinite"/>
<?php } elseif(html_netscape()) { ?>
<embed src="/assets/SMS-JBIOS-Demo.mid" autostart="true" hidden="true" loop="true"></embed>
<?php
}
}
?>
</body>
</html>
<?php endif; ?>

View file

@ -1,67 +0,0 @@
<?php
require_once __DIR__ . '/../_v4/includes.php';
define('FWH_STYLE', FWH_2020);
echo html_doctype();
?>
<html lang="en">
<head>
<?=html_charset();?>
<title>Nintendo Friend Codes</title>
<?=html_stylesheet('2020.css');?>
<?=html_meta();?>
</head>
<body>
<div class="wrapper">
<?=html_sidebar();?>
<div class="nintendo">
<div class="nintendo-notice">
<p>List of my Nintendo friend codes so I don't have to dig them up every time. Please use these codes only if we know each other.</p>
<p>If you're adding me on 3DS you'll have to send me your friend code as well, use the contact links in the sidebar to do so.</p>
</div>
<div class="nintendo-fc nintendo-fc-switch" id="switch">
<div class="nintendo-fc-title">
<h2>Nintendo Switch</h2>
</div>
<div class="nintendo-fc-code">
<code>SW-7446-8163-4902</code>
</div>
</div>
<div class="nintendo-fc nintendo-fc-3ds" id="n3ds">
<div class="nintendo-fc-title">
<h2>Nintendo 3DS</h2>
</div>
<div class="nintendo-fc-code">
<code>4013-0352-0648</code>
</div>
</div>
<div class="nintendo-fc nintendo-fc-wiiu" id="wiiu">
<div class="nintendo-fc-title">
<h2>Nintendo Wii U</h2>
</div>
<div class="nintendo-fc-code">
<code>flashwave0</code>
</div>
</div>
<div class="nintendo-notice">
<p>Below are friend codes for Nintendo WFC revival services, these will only be useful with modified consoles.</p>
</div>
<div class="nintendo-fc nintendo-fc-wii" id="mkwii">
<div class="nintendo-fc-title">
<h2>Mario Kart Wii (Wiimmfi)</h2>
</div>
<div class="nintendo-fc-code">
<code>5202-9182-8404</code>
</div>
</div>
</div>
</div>
<?=html_script('/assets/lastfm2020.js');?>
</body>
</html>

View file

@ -1,177 +0,0 @@
<?php
require_once __DIR__ . '/../_v4/includes.php';
define('FWH_STYLE', FWH_2020);
$randomFeatured = isset($_GET['rf']);
$getProjects = $pdo->prepare('
SELECT `project_id`, `project_name`, COALESCE(`project_name_clean`, REPLACE(LOWER(`project_name`), \' \', \'-\')) AS `project_name_clean`, `project_summary`, `project_description`, `project_featured`, `project_order`, `project_homepage`, `project_repository`, `project_forum`, UNIX_TIMESTAMP(`project_archived`) AS `project_archived`, `project_type`, UNIX_TIMESTAMP(`project_created`) AS `project_created`, `project_colour`
FROM `fm_projects`
WHERE `project_deleted` IS NULL
'. ($randomFeatured ? ' AND `project_featured` <> 0 ORDER BY RAND()' : 'ORDER BY `project_order` DESC')
);
$getProjects->execute();
$projects = $getProjects->fetchAll(PDO::FETCH_OBJ);
$activeProjects = [];
$toolProjects = [];
$archivedProjects = [];
foreach($projects as $project) {
if(!empty($project->project_archived))
$archivedProjects[] = $project;
elseif($project->project_type === 'Tool')
$toolProjects[] = $project;
else
$activeProjects[] = $project;
}
$getLanguages = $pdo->prepare('
SELECT pl.`language_id`, pl.`language_name`, pl.`language_colour`
FROM `fm_proglangs` AS pl
LEFT JOIN `fm_projects_proglangs` AS ppl
ON ppl.`language_id` = pl.`language_id`
WHERE ppl.`project_id` = :project_id
ORDER BY ppl.`priority`
');
function fm_project_box(stdClass $project, array $languages): string {
$colour = html_colour(isset($languages[0]->language_colour) ? $languages[0]->language_colour : 0x212121);
$html = <<<HTML
<div class="project" style="box-shadow: 0 1px 2px {$colour}; background-color: {$colour};">
<div class="project-name">
<h2>{$project->project_name}</h2>
</div>
<div class="project-inner">
<p>{$project->project_summary}</p>
<div class="project-languages">\r\n
HTML;
$indent = ' ';
foreach($languages as $lang) {
$colour = html_colour($lang->language_colour);
$html .= "{$indent} <div class=\"project-language\" style=\"box-shadow: 0 1px 2px {$colour}; background-color: {$colour};\"><div>{$lang->language_name}</div></div>\r\n";
}
$html .= "{$indent}</div>\r\n";
$links = '';
if(!empty($project->project_homepage))
$links .= " <a href=\"{$project->project_homepage}\"><img src=\"". html_baseurl() ."/assets/icons/s-home.png\" alt=\"\" width=\"17\" height=\"17\" /> Homepage</a>\r\n";
if(!empty($project->project_repository))
$links .= " <a href=\"{$project->project_repository}\"><img src=\"". html_baseurl() ."/assets/icons/s-code.png\" alt=\"\" width=\"17\" height=\"17\" /> Source</a>\r\n";
if(!empty($project->project_forum))
$links .= " <a href=\"{$project->project_forum}\"><img src=\"". html_baseurl() ."/assets/icons/s-forum.png\" alt=\"\" width=\"17\" height=\"17\" /> Discussion</a>\r\n";
if(!empty($links)) {
$html .= "{$indent}<div class=\"project-links\">\r\n";
$html .= "{$indent}{$links}";
$html .= "{$indent}</div>\r\n";
}
$html .= <<<HTML
</div>
</div>\r\n
HTML;
return $html;
}
if(isset($_GET['dump_that_shit'])) {
$doConvert = !isset($_GET['noconvert']);
$meow = [];
$projects = array_merge($activeProjects, $toolProjects, $archivedProjects);
foreach($projects as $project) {
if($doConvert) {
$projKeys = array_keys((array)$project);
foreach($projKeys as $key) {
$project->{substr($key, 8)} = $project->{$key};
unset($project->{$key});
}
}
$getLanguages->bindValue('project_id', $project->id ?? $project->project_id);
$getLanguages->execute();
$project->languages = $getLanguages->fetchAll(PDO::FETCH_OBJ);
if($doConvert) {
$langKeys = array_keys((array)$project->languages[0]);
for($i = 0; $i < count($project->languages); ++$i)
foreach($langKeys as $key) {
if(!isset($project->colour))
$project->colour = $project->languages[$i]->language_colour;
$project->languages[$i]->{substr($key, 9)} = $project->languages[$i]->{$key};
unset($project->languages[$i]->{$key});
}
}
if($randomFeatured || !$doConvert)
$meow[] = $project;
else {
$key = $project->archived ? 'archive' : strtolower($project->type);
$meow[$key][] = $project;
}
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($meow);
return;
}
echo html_doctype();
?>
<html lang="en">
<head>
<?=html_charset();?>
<title>Projects</title>
<?=html_stylesheet('2020.css');?>
<?=html_meta();?>
</head>
<body>
<div class="wrapper">
<?=html_sidebar();?>
<div class="projects">
<h1 id="projects">Active Projects</h1>
<div class="projects-list active">
<?php
foreach ($activeProjects as $project) {
$getLanguages->bindValue('project_id', $project->project_id);
$getLanguages->execute();
$languages = $getLanguages->fetchAll(PDO::FETCH_OBJ);
echo fm_project_box($project, $languages);
}
?>
</div>
<h1 id="tools">Tools</h1>
<div class="projects-list tools">
<?php
foreach ($toolProjects as $project) {
$getLanguages->bindValue('project_id', $project->project_id);
$getLanguages->execute();
$languages = $getLanguages->fetchAll(PDO::FETCH_OBJ);
echo fm_project_box($project, $languages);
}
?>
</div>
<h1 id="archived">Archived Projects</h1>
<div class="projects-list archived">
<?php
foreach ($archivedProjects as $project) {
$getLanguages->bindValue('project_id', $project->project_id);
$getLanguages->execute();
$languages = $getLanguages->fetchAll(PDO::FETCH_OBJ);
echo fm_project_box($project, $languages);
}
?>
</div>
</div>
</div>
<?php if(html_old_ie()) { ?>
<?=html_script('/assets/fixpng.js');?>
<?php } ?>
</body>
</html>

View file

@ -1,2 +0,0 @@
<?php
require_once __DIR__ . '/2020/404.php';

View file

@ -1,49 +0,0 @@
<?php
define('FM_NAV', [
['title' => 'Home', 'link' => '/'],
//['title' => 'Blog', 'link' => '//blog.flash.moe'],
['title' => 'Blog', 'link' => '//flash.moe/2020/?blog=1'],
['title' => 'Projects', 'link' => '/projects'],
['title' => 'Contact', 'link' => '/contact'],
['title' => 'Related', 'link' => '/related'],
['title' => 'Etcetera', 'link' => '/etc'],
['title' => 'Forum', 'link' => '//forum.flash.moe'],
]);
define('FM_BGS', [
'/assets/headers/krk-000.jpg', '/assets/headers/krk-001.jpg', '/assets/headers/krk-002.jpg',
'/assets/headers/krk-003.jpg', '/assets/headers/krk-004.jpg', '/assets/headers/krk-005.jpg',
'/assets/headers/krk-006.jpg', '/assets/headers/krk-007.jpg', '/assets/headers/krk-008.jpg',
'/assets/headers/mkt-000.jpg', '/assets/headers/mkt-001.jpg', '/assets/headers/mkt-002.jpg',
'/assets/headers/mkt-003.jpg', '/assets/headers/mkt-004.jpg', '/assets/headers/mkt-005.jpg',
'/assets/headers/mkt-006.jpg', '/assets/headers/mkt-007.jpg', '/assets/headers/mkt-008.jpg',
'/assets/headers/mkt-009.jpg', '/assets/headers/mkt-010.jpg', '/assets/headers/mkt-011.jpg',
'/assets/headers/mkt-012.jpg', '/assets/headers/mkt-013.jpg', '/assets/headers/mkt-014.jpg',
'/assets/headers/mkt-015.jpg', '/assets/headers/mkt-016.jpg', '/assets/headers/mkt-017.jpg',
'/assets/headers/mkt-018.jpg', '/assets/headers/mkt-019.jpg', '/assets/headers/mkt-020.jpg',
'/assets/headers/mkt-021.jpg', '/assets/headers/mkt-022.jpg', '/assets/headers/mkt-023.jpg',
'/assets/headers/mkt-024.jpg', '/assets/headers/mkt-025.jpg', '/assets/headers/mkt-026.jpg',
'/assets/headers/mkt-027.jpg', '/assets/headers/mkt-028.jpg', '/assets/headers/mkt-029.jpg',
'/assets/headers/mkt-030.jpg', '/assets/headers/mkt-031.jpg', '/assets/headers/mkt-032.jpg',
'/assets/headers/mkt-033.jpg', '/assets/headers/mkt-034.jpg', '/assets/headers/mkt-035.jpg',
'/assets/headers/mkt-036.jpg', '/assets/headers/mkt-037.jpg', '/assets/headers/mkt-038.jpg',
'/assets/headers/mkt-039.jpg', '/assets/headers/mkt-040.jpg', '/assets/headers/mkt-041.jpg',
'/assets/headers/mkt-042.jpg', '/assets/headers/mkt-043.jpg', '/assets/headers/mkt-044.jpg',
'/assets/headers/mkt-045.jpg', '/assets/headers/mkt-046.jpg', '/assets/headers/mkt-047.jpg',
'/assets/headers/mkt-048.jpg', '/assets/headers/mkt-049.jpg', '/assets/headers/mkt-050.jpg',
'/assets/headers/mkt-051.jpg', '/assets/headers/mkt-052.jpg', '/assets/headers/mkt-053.jpg',
'/assets/headers/mkt-054.jpg', '/assets/headers/mkt-055.jpg', '/assets/headers/mkt-056.jpg',
'/assets/headers/mkt-057.jpg', '/assets/headers/mkt-058.jpg', '/assets/headers/mkt-059.jpg',
'/assets/headers/mkt-060.jpg', '/assets/headers/mkt-061.jpg', '/assets/headers/mkt-062.jpg',
'/assets/headers/mkt-063.jpg',
]);
define('FM_FEET', [
'if it ain\'t broke, i\'ll break it',
]);
function fm_component(string $_component_name, array $vars = []) {
extract($vars);
require __DIR__ . '/../../components/' . $_component_name . '.php';
}

View file

@ -1,501 +0,0 @@
<?php
define('FWH_2016', 2016);
define('FWH_2019', 2019);
define('FWH_2020', 2020);
define('FWH_FMOE', 1);
define('FWH_JVDG', 2);
define('HTML_MODERN', 1);
define('HTML_NETSCAPE', 2);
define('HTML_OLDIE', 3);
define('HTML_PRESTO', 4);
define('HTML_INORI', 5);
define('HTML_GECKSCAPE', 5);
define('HTML_N3DS', 6);
if(isset($_GET['jvdg']))
define('FWH_MODE', FWH_JVDG);
function html_browser(): int {
static $browser = null;
if($browser)
return $browser;
$simulate = !empty($_GET['_sim']) && is_string($_GET['_sim']) ? (int)$_GET['_sim'] : null;
if(!empty($simulate))
return $browser = $simulate;
if(preg_match('#Nintendo 3DS#i', $_SERVER['HTTP_USER_AGENT'] ?? ''))
return $browser = HTML_N3DS;
if(preg_match('#Presto#i', $_SERVER['HTTP_USER_AGENT'] ?? ''))
return $browser = HTML_PRESTO;
if(preg_match('#Trident#i', $_SERVER['HTTP_USER_AGENT'] ?? ''))
return $browser = HTML_INORI;
if(preg_match('#MSIE#i', $_SERVER['HTTP_USER_AGENT'] ?? ''))
return $browser = HTML_OLDIE;
if(preg_match('#Netscape6#i', $_SERVER['HTTP_USER_AGENT'] ?? '') || preg_match('#Navigator#i', $_SERVER['HTTP_USER_AGENT'] ?? ''))
return $browser = HTML_GECKSCAPE;
if(preg_match('#Mozilla/4#i', $_SERVER['HTTP_USER_AGENT'] ?? ''))
return $browser = HTML_NETSCAPE;
return $browser = HTML_MODERN;
}
function html_old_browser(): bool {
return in_array(html_browser(), [HTML_NETSCAPE, HTML_OLDIE], true);
}
function html_modern(): bool {
return html_browser() === HTML_MODERN;
}
function html_netscape(): bool {
return html_browser() === HTML_NETSCAPE;
}
function html_old_ie(): bool {
return html_browser() === HTML_OLDIE;
}
function html_presto(): bool {
return html_browser() === HTML_PRESTO || html_browser() === HTML_GECKSCAPE;
}
function html_inori(): bool {
return html_browser() === HTML_INORI;
}
function html_n3ds(): bool {
return html_browser() === HTML_N3DS;
}
function html_default_ver(): int {
return defined('FWH_STYLE') ? FWH_STYLE : 0;
}
function html_default_mode(): int {
return defined('FWH_MODE') ? FWH_MODE : FWH_FMOE;
}
function html_baseurl(): string {
if($_SERVER['HTTP_HOST'] !== 'flash.moe')
return '//flash.moe';
return '';
}
function html_local_url(string $url): string {
if($url[0] === '/' && substr($url, 0, 2) !== '//') {
$url = '/' . trim($url, '/');
$originalUrl = $url;
$cleanPath = '/' . trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
if(substr($cleanPath, 0, 3) === '/20'
&& (md5_file(__DIR__ . '/../index.php') !== '20c2c2b0b4a9fa31e10922b913a5ac07'
|| substr($cleanPath, 0, 14) !== '/2020/blog.php')) {
$url = substr($cleanPath, 0, 5) . $url;
if(in_array($originalUrl, ['/projects', '/404', '/blog', '/nintendo']))
$url .= '.php';
}
}
return $url;
}
function html_colour(?int $raw): string {
if (is_null($raw))
return 'inherit';
return '#' . str_pad(dechex($raw), 6, '0', STR_PAD_LEFT);
}
function html_doctype(?int $version = null): string {
return html_old_browser()
? "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\r\n"
: "<!doctype html>\r\n";
}
function html_charset(string $charset = 'utf-8', ?int $version = null): string {
return html_old_browser()
? "<meta http-equiv=\"content-type\" content=\"text/html; charset={$charset}\"/>\r\n"
: "<meta charset=\"{$charset}\"/>\r\n";
}
function html_stylesheet(string $name, array $params = [], ?int $version = null): string {
if(html_modern())
$cssFormat = '/css/%s';
else {
$cssFormat = '/css.php?path=%s';
if(empty($params['accent']))
$params['accent'] = html_default_mode() === FWH_JVDG ? '#2d9940' : '#4a3650';
if(!empty($params)) {
foreach($params as $key => $val)
$cssFormat .= '&' . rawurlencode($key) . '=' . str_replace('%', '%%', rawurlencode($val));
}
}
return "<link href=\"". html_baseurl() . sprintf($cssFormat, $name) ."\" type=\"text/css\" rel=\"stylesheet\"/>\r\n";
}
function html_script(string $path, string $charset = 'utf-8', string $language = 'javascript', ?int $version = null): string {
if($path[0] === '/' && $path[1] !== '/')
$path = html_baseurl() . $path;
$html = "<script src=\"{$path}\" type=\"text/{$language}\"";
if(html_old_browser())
$html .= "language=\"{$language}\" ";
return $html . " charset=\"{$charset}\"></script>\r\n";
}
function html_meta(?int $version = null): string {
$meta = "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\"/>\r\n";
if(html_default_mode() === FWH_JVDG)
$meta .= " <style>:root { --accent-colour: #2d9940; }</style>\r\n";
return $meta;
}
function html_open(?int $version = null): string {
return html_doctype($version) . (($version ?? html_default_ver()) < FWH_2020 ? "<html>" : '');
}
function html_close(?int $version = null): string {
return ($version ?? html_default_ver()) < FWH_2020 ? "</html>" : '';
}
function html_head(string $title, array $vars = [], ?int $version = null): string {
$version = $version ?? html_default_ver();
$accentColour = $vars['accent_colour'] ?? '#555';
$html = html_charset();
$html .= "<title>{$title}</title>";
switch ($version) {
case FWH_2016:
return $html . html_stylesheet('2016.css', ['accent' => $accentColour], $version) . html_meta($version);
case FWH_2019:
$html .= html_stylesheet('2019.css', ['accent' => $accentColour], $version);
if (!empty($vars['transitional']))
$html .= html_stylesheet('2016-lite.css', ['accent' => $accentColour], $version);
$html .= html_meta($version);
if(html_modern()) {
$html .= <<<HTML
<style>
:root {
--accent-colour: {$accentColour};
}
</style>
HTML;
}
return $html;
}
return '';
}
function html_navigation(array $navigation, array $vars = [], ?int $version = null): string {
$home = html_local_url($navigation[0]['link'] ?? $vars['link'] ?? '/');
if(html_old_browser()) {
$title = !empty($vars['title1']) ? ($vars['title1'] . ($vars['title2'] ?? '')) : $vars['title'] ?? 'flashwave';
$html = '<table border="1" width="100%"><tr><td align="center" colspan="' . count($navigation) . '"><h1>' . $title . '</h1></td></tr><tr>';
foreach ($navigation as $item) {
$item['link'] = html_local_url($item['link']);
$html .= "<td align=\"center\"><a href=\"{$item['link']}\">{$item['title']}</a></td>";
}
return $html . '</tr></table>';
}
switch ($version ?? html_default_ver()) {
case FWH_2016:
$title = $vars['title'] ?? 'flash.moe';
$html = <<<HTML
<nav class="header">
<div class="header__inner">
<a href="{$home}" class="header__logo">
{$title}
</a>
<div class="header__menu">
HTML;
foreach ($navigation as $item) {
$item['link'] = html_local_url($item['link']);
$html .= sprintf('
<a class="nav-item" href="%s">
<span class="nav-item__icon mdi %s"></span>
<span class="nav-item__name">%s</span>
</a>
', $item['link'], $item['mdi-icon'] ?? 'mdi-link-variant', $item['title']);
}
$html .= <<<HTML
</div>
</div>
</nav>
HTML;
return $html;
case FWH_2019:
$title1 = $vars['title1'] ?? 'flash';
$title2 = $vars['title2'] ?? 'wave';
$html = <<<HTML
<nav class="header">
<div class="header__background"></div>
<div class="header__wrapper">
<a class="header__logo" href="{$home}">{$title1}<span class="header__logo__highlight">{$title2}</span></a>
<div class="header__items">
HTML;
foreach ($navigation as $item) {
$item['link'] = html_local_url($item['link']);
$html .= "<a href=\"{$item['link']}\" class=\"header__item\">{$item['title']}</a>";
}
$html .= '</div>';
$html .= <<<HTML
</div>
</nav>
HTML;
return $html;
}
return '';
}
function html_footer(?int $version = null): string {
$currentYear = date('Y');
if(html_old_browser()) {
return <<<HTML
<div align="center"><small>
&copy; <a href="http://flash.moe">Flashwave</a> 2010-{$currentYear}
</small></div>
HTML;
}
switch ($version ?? html_default_ver()) {
case FWH_2016:
return <<<HTML
<footer class="footer">
&copy; <a href="https://flash.moe" class="footer__link">Flashwave</a> 2010-{$currentYear}
</footer>
HTML;
case FWH_2019:
return <<<HTML
<footer class="footer">
<div class="footer__background"></div>
<div class="footer__wrapper">
&copy; <a href="https://flash.moe" class="footer__link">Flashwave</a> 2010-{$currentYear}
</div>
</footer>
HTML;
}
return '';
}
function html_sidebar(?int $version = null, ?array $links = null, ?array $accounts = null): string {
$version = $version ?? html_default_ver();
if($version < FWH_2020)
return '';
$isJvdg = html_default_mode() === FWH_JVDG;
$links = $links ?? [
[
'title' => 'Home',
'desc' => 'Index with latest blog posts',
'dest' => html_local_url('/'),
'hide' => $isJvdg,
],
[
'title' => 'Projects',
'desc' => 'List of things I\'ve made or am making',
'dest' => html_local_url('/projects'),
'hide' => $isJvdg,
],
[
'title' => 'Forum',
'desc' => 'Feature requests and bug reports for some projects',
'dest' => '//forum.flash.moe',
'hide' => $isJvdg,
],
[
'title' => 'Flashii',
'desc' => 'Community site I run and develop',
'dest' => '//flashii.net',
'hide' => $isJvdg,
],
[
'title' => 'Railgun',
'desc' => 'Chat server and chat protocols I work on',
'dest' => '//railgun.sh',
'hide' => $isJvdg,
],
];
$accounts = $accounts ?? [
[
'title' => 'E-mail',
'url' => 'mailto:me+contact@flash.moe',
'image' => html_baseurl() . '/assets/icons/email.png',
],
[
'title' => 'Flashii',
'url' => '//flashii.net/profile.php?u=1',
'image' => html_baseurl() . '/assets/icons/flashii.png',
'hide' => $isJvdg,
],
[
'title' => 'Github',
'url' => '//github.com/flashwave',
'image' => html_baseurl() . '/assets/icons/github.png',
],
[
'title' => 'YouTube',
'url' => '//youtube.com/c/flashwave',
'image' => html_baseurl() . '/assets/icons/youtube.png',
'hide' => $isJvdg,
],
[
'title' => 'Twitch',
'url' => '//twitch.tv/flashwave0',
'image' => html_baseurl() . '/assets/icons/twitch.png',
'hide' => $isJvdg,
],
[
'title' => 'Steam',
'url' => '//steamcommunity.com/id/flashwave_',
'image' => html_baseurl() . '/assets/icons/steam.png',
'hide' => $isJvdg,
],
[
'title' => 'Twitter',
'url' => 'javascript:confirm(\'Proceed with caution.\') ? location.assign(\'//twitter.com/smugwave\') : void(0);',
'image' => html_baseurl() . '/assets/icons/twitter.png',
'hide' => $isJvdg,
],
[
'title' => 'last.fm',
'url' => '//www.last.fm/user/flashwave_',
'image' => html_baseurl() . '/assets/icons/lastfm.png',
'hide' => $isJvdg,
],
[
'title' => 'Nintendo',
'url' => '/nintendo',
'image' => html_baseurl() . '/assets/icons/ninswitch.png',
'hide' => $isJvdg,
],
[
'title' => 'Donate',
'url' => '//paypal.me/flashwave',
'image' => html_baseurl() . '/assets/icons/paypal.png',
'hide' => $isJvdg,
],
];
$title1 = $isJvdg ? 'julian' : 'flash';
$title2 = $isJvdg ? 'vdg' : 'wave';
$avatar = $isJvdg ? '//julianvdg.nl/avatar.php' : '//flashii.net/user-assets.php?m=avatar&amp;u=1&amp;r=120';
$avatarHTML = $isJvdg ? '' : '<img src="'. $avatar .'" width="60" height="60" alt="" class="header-avatar"/>';
$html = <<<HTML
<div class="sidebar">
<div class="sidebar-inner">
<div class="header">
<div class="header-text">
<div class="header-title">{$title1}<span class="header-title-hilight">{$title2}</span></div>
<div class="header-slogan">if it ain't broke, i'll break it</div>
</div>
{$avatarHTML}
</div>\r\n
HTML;
$html .= " <div class=\"links\">\r\n";
foreach($links as $link) {
if(!empty($link['hide']))
continue;
$html .= <<<HTML
<a href="{$link['dest']}" class="link">
<div class="link-title">{$link['title']}</div>
<div class="link-desc">{$link['desc']}</div>
</a>\r\n
HTML;
}
$html .= " </div>\r\n";
$html .= " <div class=\"accounts\">\r\n";
foreach($accounts as $account) {
if(!empty($account['hide']))
continue;
$html .= <<<HTML
<a href="{$account['url']}" class="account" rel="noreferrer noopener">
<img src="{$account['image']}" alt="" width="25" height="25" class="account-icon"/>
<div class="account-name">{$account['title']}</div>
</a>\r\n
HTML;
}
$html .= " </div>\r\n";
$html .= <<<HTML
<div class="music hidden" id="music">
<div class="music-header" id="music-header">
Listening to
</div>
<div class="music-wrap">
<div class="music-meta">
<div class="music-title">
<a href="#" class="music-title-link" id="music-title">Title</a>
</div>
<div class="music-artist">
<a href="#" class="music-artist-link" id="music-artist">Artist</a>
</div>
</div>
<img src="//now.flash.moe/resources/no-cover.png" width="50" height="50" alt="" class="music-cover" id="music-cover"/>
</div>
</div>\r\n
HTML;
$name = $isJvdg ? 'Julian van de Groep' : 'Flashwave';
$year = date('Y');
if(!$isJvdg)
$html .= <<<HTML
</div>
<div class="copyright">
&copy; <a href="//{$_SERVER['HTTP_HOST']}">{$name}</a> 2010-{$year}
</div>
</div>\r\n
HTML;
else $html .= '</div></div>';
return $html;
}

View file

@ -1,20 +1,13 @@
<?php
define('FM_DEBUG',
is_file(__DIR__ . '/.debug')
|| $_SERVER['REMOTE_ADDR'] === '83.87.130.248'
|| substr($_SERVER['REMOTE_ADDR'], 0, 19) === '2001:1c02:20f:3200:'
);
define('FM_DEBUG', false);
error_reporting(FM_DEBUG ? -1 : 0);
ini_set('display_errors', FM_DEBUG ? 'On' : 'Off');
error_reporting(0);
ini_set('display_errors', 'off');
date_default_timezone_set('UTC');
mb_internal_encoding('UTF-8');
set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__);
require_once 'compat.php';
require_once 'html.php';
try {
$pdo = new PDO('mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=website;charset=utf8mb4', 'website', 'A3NjVvHRkHAxiYgk8MM4ZrCwrLVyPIYX', [
PDO::ATTR_CASE => PDO::CASE_NATURAL,
@ -33,28 +26,3 @@ try {
echo '<h3>Unable to connect to database</h3>';
die($ex->getMessage());
}
define('HEAD_FLASHWAVE', [
'accent_colour' => '#4a3650',
]);
define('HEAD_ERROR', [
'accent_colour' => '#960018',
]);
define('HEAD_BLOG', [
'accent_colour' => '#4a3650',
'transitional' => true,
]);
define('HEAD_WHOIS', [
'accent_colour' => '#555',
'transitional' => true,
]);
define('NAV_FLASHWAVE', [
['title' => 'Home', 'link' => '/'],
['title' => 'Projects', 'link' => '/projects.php'],
]);
define('NAV_ERROR', [
['title' => 'Retry', 'link' => $_SERVER['REQUEST_URI']],
['title' => 'Home', 'link' => '/'],
]);
define('NAV_WHOIS', NAV_FLASHWAVE);

View file

@ -1,351 +1,351 @@
Date.prototype.getWeek = function() {
var date = new Date(this.getTime());
date.setHours(0, 0, 0, 0);
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
var week1 = new Date(date.getFullYear(), 0, 4);
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
}
Date.prototype.getWeekYear = function() {
var date = new Date(this.getTime());
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
return date.getFullYear();
}
window.fm = (function() {
var fm = this;
this.container = document.querySelector('.container');
this.headerBackground = null;
this.originalHeaderBackground = null;
this.defaultCoverImage = 'https://lastfm.freetls.fastly.net/i/u/174s/2a96cbd8b46e442fc41c2b86b821562f.png';
this.indexIsPlaying = false;
this.indexPlayingDefaultCover = false;
this.indexPlayingContainer = null;
this.indexPlayingCover = null;
this.indexPlayingTitle = null;
this.indexPlayingArtist = null;
this.indexLastNp = null;
this.indexPlayingInterval = null;
this.homeInterval = null;
this.callByName = function(name, args) {
var ref = window,
parent = null,
parts = name.split('.');
for(var i = 0; i < parts.length; ++i) {
parent = ref;
if(typeof ref[parts[i]] !== 'undefined')
ref = ref[parts[i]];
else return;
}
if(typeof ref !== 'function')
return;
return ref.apply(parent, args);
};
this.runFuncs = function(funcs) {
for(var i = 0; i < funcs.length; ++i)
fm.callByName(funcs[i][0], funcs[i].slice(1));
};
if(this.onload && Array.isArray(this.onload))
window.addEventListener('load', function() { fm.runFuncs(fm.onload); });
if(sessionStorage.getItem('header-bgs') === null
|| sessionStorage.getItem('header-bgs-loaded') < Date.now() - 86400000) {
var hXhr = new XMLHttpRequest;
hXhr.onload = function() {
sessionStorage.setItem('header-bgs', hXhr.responseText);
sessionStorage.setItem('header-bgs-loaded', Date.now());
};
hXhr.open('GET', '/header-bgs.json');
hXhr.send();
}
this.dynloadCurrent = function() {
return {
components: {
header: {
title: document.title,
is_index: document.body.classList.contains('index'),
do_fullscreen_header: document.body.classList.contains('fullscreen-header'),
is_now_playing: document.body.classList.contains('now-playing'),
},
footer: {
onload: this.onload || [],
}
},
raw_html: fm.container.innerHTML,
};
};
this.dynloadApply = function(state) {
if((state.components || {}).header) {
document.title = state.components.header.title || '';
document.body.classList[state.components.header.is_index ? 'add' : 'remove']('index');
document.body.classList[state.components.header.do_fullscreen_header ? 'add' : 'remove']('fullscreen-header');
document.body.classList[state.components.header.is_now_playing ? 'add' : 'remove']('now-playing');
}
if(typeof state.raw_html !== 'undefined')
this.container.innerHTML = state.raw_html;
if((state.components || {}).footer) {
this.runFuncs(state.components.footer.onload || []);
}
fm.dynloadInit();
fm.setRandomHeaderBackgroundIfNotPlaying();
};
this.dynloadInit = function(initial) {
if(initial) {
history.replaceState(this.dynloadCurrent(), document.title, location.toString());
window.addEventListener('popstate', function(ev) {
fm.dynloadApply(ev.state || {});
});
}
var dynload = document.querySelectorAll('[data-fm-dynload]');
for(var i = 0; i < dynload.length; ++i)
(function(dc){
var url = new URL(dc.href),
hash = url.hash.substring(1);
url.hash = '';
dc.removeAttribute('data-fm-dynload');
dc.addEventListener('click', function(ev) {
ev.stopPropagation();
ev.preventDefault();
var xhr = new XMLHttpRequest;
xhr.onload = function() {
try {
var obj = JSON.parse(xhr.responseText);
} catch(ex) {}
if(!obj) {
location.assign(dc.href);
return;
}
var title = ((obj.components || {}).header || {}).title || '';
history.pushState(obj, title, dc.href);
fm.dynloadApply(obj);
if(hash) {
var targetEl = document.getElementById(hash);
if(targetEl) {
setTimeout(function() {
window.scrollTo({
top: targetEl.getBoundingClientRect().top,
behavior: 'smooth'
});
}, 500);
}
}
};
xhr.onerror = function(ev) {
location.assign(dc.href);
};
xhr.open('GET', url);
xhr.setRequestHeader('Accept', 'application/x-fdynload+json');
xhr.send();
}, true);
})(dynload[i]);
};
this.dynloadInit(true);
this.selectTextInElement = function(elem) {
// MSIE
if(document.body.createTextRange) {
var range = document.body.createTextRange();
range.moveToElementText(elem);
range.select();
return;
}
// Mozilla
if(window.getSelection) {
var select = window.getSelection(),
range = document.createRange();
range.selectNodeContents(elem);
select.removeAllRanges();
select.addRange(range);
return;
}
console.warn('Unable to select text.');
};
this.copySelectedText = function() {
if(document.execCommand) {
document.execCommand('copy');
return;
}
console.warn('Unable to copy text.');
};
this.getNowListening = function(callback) {
if(!callback)
return;
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function() {
if(xhr.readyState !== 4 || xhr.status !== 200)
return;
callback.call(this, JSON.parse(xhr.responseText));
}.bind(this);
xhr.open('GET', '/now-listening.json');
xhr.send();
};
this.updateIndexNowListening = function() {
window.fm.getNowListening(function(info) {
if(this.indexLastNp === null
|| this.indexLastNp.url != info.url
|| this.indexLastNp.now_playing != info.now_playing) {
if(this.indexLastNp !== null)
this.originalHeaderBackground = this.getRandomHeaderBackground();
this.indexLastNp = info;
} else return;
this.indexIsPlaying = info.now_playing;
this.indexPlayingDefaultCover = !info.cover || info.cover === this.defaultCoverImage;
this.indexPlayingContainer.classList[info.now_playing ? 'remove' : 'add']('header-now-playing-hidden');
this.indexPlayingCover.alt = this.indexPlayingCover.src = (info.cover !== this.defaultCoverImage ? info.cover : '//now.flash.moe/resources/no-cover.png');
this.indexPlayingTitle.textContent = this.indexPlayingTitle.title = info.name;
this.indexPlayingTitle.href = info.url;
this.indexPlayingArtist.textContent = this.indexPlayingArtist.title = (info.artist || {}).name || '';
this.indexPlayingArtist.href = (info.artist || {}).url || '';
this.switchHeaderBackground(
info.now_playing && !this.indexPlayingDefaultCover
? this.indexPlayingCover.src
: this.originalHeaderBackground
);
});
};
this.getRandomHeaderBackground = function() {
var set = JSON.parse(sessionStorage.getItem('header-bgs'));
if(!set)
return '/assets/errors/404.jpg';
return set[parseInt(Math.random() * set.length) - 1];
};
this.setRandomHeaderBackground = function() {
this.switchHeaderBackground(this.getRandomHeaderBackground());
};
this.setRandomHeaderBackgroundIfNotPlaying = function() {
if(!this.indexIsPlaying || this.indexPlayingDefaultCover)
this.setRandomHeaderBackground();
};
this.getCurrentHeaderBackground = function() {
return this.headerBackground.querySelector('img').src;
};
this.headerBackgroundIsChanging = false;
this.switchHeaderBackground = function(url) {
if(this.headerBackgroundIsChanging || this.getCurrentHeaderBackground() === url)
return;
this.headerBackgroundIsChanging = true;
var newImg = document.createElement('img'),
oldImg = this.headerBackground.querySelector('img');
newImg.alt = newImg.src = url;
newImg.style.opacity = '0';
oldImg.style.zIndex = '-1';
newImg.style.zIndex = '0';
this.headerBackground.appendChild(newImg);
newImg.onload = function() {
setTimeout(function() {
newImg.style.opacity = null;
setTimeout(function() {
newImg.style.zIndex = null;
this.headerBackground.removeChild(oldImg);
this.headerBackgroundIsChanging = false;
}.bind(this), 500);
}.bind(this), 50);
}.bind(this);
newImg.onerror = function() {
this.headerBackgroundIsChanging = false;
this.switchHeaderBackground(this.originalHeaderBackground);
}.bind(this);
};
this.headerBackground = document.querySelector('.header-background');
this.originalHeaderBackground = this.headerBackground.querySelector('img').src;
this.initIndex = function(npInterval) {
if(!this.indexPlayingContainer) {
this.indexPlayingContainer = document.querySelector('.header-now-playing');
this.indexPlayingCover = window.fm.indexPlayingContainer.querySelector('.header-now-playing-cover img');
this.indexPlayingCover.onerror = function() {
this.indexPlayingCover.src = '//now.flash.moe/resources/no-cover.png';
}.bind(this);
this.indexPlayingTitle = window.fm.indexPlayingContainer.querySelector('.header-now-playing-title a');
this.indexPlayingArtist = window.fm.indexPlayingContainer.querySelector('.header-now-playing-artist a');
}
if(this.indexPlayingInterval) {
clearInterval(this.indexPlayingInterval);
this.indexPlayingInterval = null;
}
this.updateIndexNowListening();
this.indexPlayingInterval = setInterval(this.updateIndexNowListening, (npInterval || 30) * 1000);
};
this.initClock = function() {
if(this.homeInterval)
return;
var digitalClock = document.querySelector('.php-time-digital'),
analogClock = document.querySelector('.php-time-analog'),
dateZone = document.querySelector('.php-time-date'),
digHours = digitalClock.querySelector('.php-time-digital-hours'),
digSeparator = digitalClock.querySelector('.php-time-digital-separator'),
digMinutes = digitalClock.querySelector('.php-time-digital-minutes'),
angHours = analogClock.querySelector('.clock-hand-hours'),
angMinutes = analogClock.querySelector('.clock-hand-minutes'),
angSeconds = analogClock.querySelector('.clock-hand-seconds')
dateWeek = dateZone.querySelector('.php-date-week'),
dateDay = dateZone.querySelector('.php-date-day'),
dateMonth = dateZone.querySelector('.php-date-month'),
dateYear = dateZone.querySelector('.php-date-year');
this.homeInterval = setInterval(function() {
if(!document.body.contains(digitalClock)) {
clearInterval(this.homeInterval);
this.homeInterval = null;
return;
}
var time = new Date;
var dHour = time.getHours(),
dMin = time.getMinutes();
if(dHour < 10)
dHour = '0' + dHour;
if(dMin < 10)
dMin = '0' + dMin;
dateWeek.textContent = time.getWeek();
dateDay.textContent = time.getDate();
dateMonth.textContent = time.getMonth() + 1;
dateYear.textContent = time.getFullYear();
digHours.textContent = dHour;
digMinutes.textContent = dMin;
digSeparator.classList[time.getSeconds() % 2 ? 'add' : 'remove']('php-time-digital-separator-hidden');
var rSec = time.getSeconds() / 60,
rMin = (time.getMinutes() + Math.min(.99, rSec)) / 60,
rHour = (time.getHours() + Math.min(.99, rMin)) / 12;
angHours.style.setProperty('--hand-rotation', (rHour * 360).toString() + 'deg');
angMinutes.style.setProperty('--hand-rotation', (rMin * 360).toString() + 'deg');
angSeconds.style.setProperty('--hand-rotation', (rSec * 360).toString() + 'deg');
}.bind(this), 200);
};
return this;
}).call(window.fm || {});
Date.prototype.getWeek = function() {
var date = new Date(this.getTime());
date.setHours(0, 0, 0, 0);
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
var week1 = new Date(date.getFullYear(), 0, 4);
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
}
Date.prototype.getWeekYear = function() {
var date = new Date(this.getTime());
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
return date.getFullYear();
}
window.fm = (function() {
var fm = this;
this.container = document.querySelector('.container');
this.headerBackground = null;
this.originalHeaderBackground = null;
this.defaultCoverImage = 'https://lastfm.freetls.fastly.net/i/u/174s/2a96cbd8b46e442fc41c2b86b821562f.png';
this.indexIsPlaying = false;
this.indexPlayingDefaultCover = false;
this.indexPlayingContainer = null;
this.indexPlayingCover = null;
this.indexPlayingTitle = null;
this.indexPlayingArtist = null;
this.indexLastNp = null;
this.indexPlayingInterval = null;
this.homeInterval = null;
this.callByName = function(name, args) {
var ref = window,
parent = null,
parts = name.split('.');
for(var i = 0; i < parts.length; ++i) {
parent = ref;
if(typeof ref[parts[i]] !== 'undefined')
ref = ref[parts[i]];
else return;
}
if(typeof ref !== 'function')
return;
return ref.apply(parent, args);
};
this.runFuncs = function(funcs) {
for(var i = 0; i < funcs.length; ++i)
fm.callByName(funcs[i][0], funcs[i].slice(1));
};
if(this.onload && Array.isArray(this.onload))
window.addEventListener('load', function() { fm.runFuncs(fm.onload); });
if(sessionStorage.getItem('header-bgs') === null
|| sessionStorage.getItem('header-bgs-loaded') < Date.now() - 86400000) {
var hXhr = new XMLHttpRequest;
hXhr.onload = function() {
sessionStorage.setItem('header-bgs', hXhr.responseText);
sessionStorage.setItem('header-bgs-loaded', Date.now());
};
hXhr.open('GET', '/header-bgs.json');
hXhr.send();
}
this.dynloadCurrent = function() {
return {
components: {
header: {
title: document.title,
is_index: document.body.classList.contains('index'),
do_fullscreen_header: document.body.classList.contains('fullscreen-header'),
is_now_playing: document.body.classList.contains('now-playing'),
},
footer: {
onload: this.onload || [],
}
},
raw_html: fm.container.innerHTML,
};
};
this.dynloadApply = function(state) {
if((state.components || {}).header) {
document.title = state.components.header.title || '';
document.body.classList[state.components.header.is_index ? 'add' : 'remove']('index');
document.body.classList[state.components.header.do_fullscreen_header ? 'add' : 'remove']('fullscreen-header');
document.body.classList[state.components.header.is_now_playing ? 'add' : 'remove']('now-playing');
}
if(typeof state.raw_html !== 'undefined')
this.container.innerHTML = state.raw_html;
if((state.components || {}).footer) {
this.runFuncs(state.components.footer.onload || []);
}
fm.dynloadInit();
fm.setRandomHeaderBackgroundIfNotPlaying();
};
this.dynloadInit = function(initial) {
if(initial) {
history.replaceState(this.dynloadCurrent(), document.title, location.toString());
window.addEventListener('popstate', function(ev) {
fm.dynloadApply(ev.state || {});
});
}
var dynload = document.querySelectorAll('[data-fm-dynload]');
for(var i = 0; i < dynload.length; ++i)
(function(dc){
var url = new URL(dc.href),
hash = url.hash.substring(1);
url.hash = '';
dc.removeAttribute('data-fm-dynload');
dc.addEventListener('click', function(ev) {
ev.stopPropagation();
ev.preventDefault();
var xhr = new XMLHttpRequest;
xhr.onload = function() {
try {
var obj = JSON.parse(xhr.responseText);
} catch(ex) {}
if(!obj) {
location.assign(dc.href);
return;
}
var title = ((obj.components || {}).header || {}).title || '';
history.pushState(obj, title, dc.href);
fm.dynloadApply(obj);
if(hash) {
var targetEl = document.getElementById(hash);
if(targetEl) {
setTimeout(function() {
window.scrollTo({
top: targetEl.getBoundingClientRect().top,
behavior: 'smooth'
});
}, 500);
}
}
};
xhr.onerror = function(ev) {
location.assign(dc.href);
};
xhr.open('GET', url);
xhr.setRequestHeader('Accept', 'application/x-fdynload+json');
xhr.send();
}, true);
})(dynload[i]);
};
this.dynloadInit(true);
this.selectTextInElement = function(elem) {
// MSIE
if(document.body.createTextRange) {
var range = document.body.createTextRange();
range.moveToElementText(elem);
range.select();
return;
}
// Mozilla
if(window.getSelection) {
var select = window.getSelection(),
range = document.createRange();
range.selectNodeContents(elem);
select.removeAllRanges();
select.addRange(range);
return;
}
console.warn('Unable to select text.');
};
this.copySelectedText = function() {
if(document.execCommand) {
document.execCommand('copy');
return;
}
console.warn('Unable to copy text.');
};
this.getNowListening = function(callback) {
if(!callback)
return;
var xhr = new XMLHttpRequest;
xhr.onreadystatechange = function() {
if(xhr.readyState !== 4 || xhr.status !== 200)
return;
callback.call(this, JSON.parse(xhr.responseText));
}.bind(this);
xhr.open('GET', '/now-listening.json');
xhr.send();
};
this.updateIndexNowListening = function() {
window.fm.getNowListening(function(info) {
if(this.indexLastNp === null
|| this.indexLastNp.url != info.url
|| this.indexLastNp.now_playing != info.now_playing) {
if(this.indexLastNp !== null)
this.originalHeaderBackground = this.getRandomHeaderBackground();
this.indexLastNp = info;
} else return;
this.indexIsPlaying = info.now_playing;
this.indexPlayingDefaultCover = !info.cover || info.cover === this.defaultCoverImage;
this.indexPlayingContainer.classList[info.now_playing ? 'remove' : 'add']('header-now-playing-hidden');
this.indexPlayingCover.alt = this.indexPlayingCover.src = (info.cover !== this.defaultCoverImage ? info.cover : '//now.flash.moe/resources/no-cover.png');
this.indexPlayingTitle.textContent = this.indexPlayingTitle.title = info.name;
this.indexPlayingTitle.href = info.url;
this.indexPlayingArtist.textContent = this.indexPlayingArtist.title = (info.artist || {}).name || '';
this.indexPlayingArtist.href = (info.artist || {}).url || '';
this.switchHeaderBackground(
info.now_playing && !this.indexPlayingDefaultCover
? this.indexPlayingCover.src
: this.originalHeaderBackground
);
});
};
this.getRandomHeaderBackground = function() {
var set = JSON.parse(sessionStorage.getItem('header-bgs'));
if(!set)
return '/assets/errors/404.jpg';
return set[parseInt(Math.random() * set.length) - 1];
};
this.setRandomHeaderBackground = function() {
this.switchHeaderBackground(this.getRandomHeaderBackground());
};
this.setRandomHeaderBackgroundIfNotPlaying = function() {
if(!this.indexIsPlaying || this.indexPlayingDefaultCover)
this.setRandomHeaderBackground();
};
this.getCurrentHeaderBackground = function() {
return this.headerBackground.querySelector('img').src;
};
this.headerBackgroundIsChanging = false;
this.switchHeaderBackground = function(url) {
if(this.headerBackgroundIsChanging || this.getCurrentHeaderBackground() === url)
return;
this.headerBackgroundIsChanging = true;
var newImg = document.createElement('img'),
oldImg = this.headerBackground.querySelector('img');
newImg.alt = newImg.src = url;
newImg.style.opacity = '0';
oldImg.style.zIndex = '-1';
newImg.style.zIndex = '0';
this.headerBackground.appendChild(newImg);
newImg.onload = function() {
setTimeout(function() {
newImg.style.opacity = null;
setTimeout(function() {
newImg.style.zIndex = null;
this.headerBackground.removeChild(oldImg);
this.headerBackgroundIsChanging = false;
}.bind(this), 500);
}.bind(this), 50);
}.bind(this);
newImg.onerror = function() {
this.headerBackgroundIsChanging = false;
this.switchHeaderBackground(this.originalHeaderBackground);
}.bind(this);
};
this.headerBackground = document.querySelector('.header-background');
this.originalHeaderBackground = this.headerBackground.querySelector('img').src;
this.initIndex = function(npInterval) {
if(!this.indexPlayingContainer) {
this.indexPlayingContainer = document.querySelector('.header-now-playing');
this.indexPlayingCover = window.fm.indexPlayingContainer.querySelector('.header-now-playing-cover img');
this.indexPlayingCover.onerror = function() {
this.indexPlayingCover.src = '//now.flash.moe/resources/no-cover.png';
}.bind(this);
this.indexPlayingTitle = window.fm.indexPlayingContainer.querySelector('.header-now-playing-title a');
this.indexPlayingArtist = window.fm.indexPlayingContainer.querySelector('.header-now-playing-artist a');
}
if(this.indexPlayingInterval) {
clearInterval(this.indexPlayingInterval);
this.indexPlayingInterval = null;
}
this.updateIndexNowListening();
this.indexPlayingInterval = setInterval(this.updateIndexNowListening, (npInterval || 30) * 1000);
};
this.initClock = function() {
if(this.homeInterval)
return;
var digitalClock = document.querySelector('.php-time-digital'),
analogClock = document.querySelector('.php-time-analog'),
dateZone = document.querySelector('.php-time-date'),
digHours = digitalClock.querySelector('.php-time-digital-hours'),
digSeparator = digitalClock.querySelector('.php-time-digital-separator'),
digMinutes = digitalClock.querySelector('.php-time-digital-minutes'),
angHours = analogClock.querySelector('.clock-hand-hours'),
angMinutes = analogClock.querySelector('.clock-hand-minutes'),
angSeconds = analogClock.querySelector('.clock-hand-seconds')
dateWeek = dateZone.querySelector('.php-date-week'),
dateDay = dateZone.querySelector('.php-date-day'),
dateMonth = dateZone.querySelector('.php-date-month'),
dateYear = dateZone.querySelector('.php-date-year');
this.homeInterval = setInterval(function() {
if(!document.body.contains(digitalClock)) {
clearInterval(this.homeInterval);
this.homeInterval = null;
return;
}
var time = new Date;
var dHour = time.getHours(),
dMin = time.getMinutes();
if(dHour < 10)
dHour = '0' + dHour;
if(dMin < 10)
dMin = '0' + dMin;
dateWeek.textContent = time.getWeek();
dateDay.textContent = time.getDate();
dateMonth.textContent = time.getMonth() + 1;
dateYear.textContent = time.getFullYear();
digHours.textContent = dHour;
digMinutes.textContent = dMin;
digSeparator.classList[time.getSeconds() % 2 ? 'add' : 'remove']('php-time-digital-separator-hidden');
var rSec = time.getSeconds() / 60,
rMin = (time.getMinutes() + Math.min(.99, rSec)) / 60,
rHour = (time.getHours() + Math.min(.99, rMin)) / 12;
angHours.style.setProperty('--hand-rotation', (rHour * 360).toString() + 'deg');
angMinutes.style.setProperty('--hand-rotation', (rMin * 360).toString() + 'deg');
angSeconds.style.setProperty('--hand-rotation', (rSec * 360).toString() + 'deg');
}.bind(this), 200);
};
return this;
}).call(window.fm || {});

File diff suppressed because it is too large Load diff

View file

@ -2,16 +2,16 @@
namespace Makai;
use Index\DateTime;
use Index\Routing\Router;
use Index\Routing\RoutePathNotFoundException;
use Index\Routing\RouteMethodNotSupportedException;
require_once __DIR__ . '/../makai.php';
define('FM_HIT', 0x01000000);
define('FM_ERR', 0x02000000);
define('FM_NAV', [
['title' => 'Home', 'link' => '/'],
//['title' => 'Blog', 'link' => '//blog.flash.moe'],
['title' => 'Blog', 'link' => '//flash.moe/2020/?blog=1'],
['title' => 'Blog', 'link' => '/old-blog'],
['title' => 'Projects', 'link' => '/projects'],
['title' => 'Contact', 'link' => '/contact'],
['title' => 'Related', 'link' => '/related'],
@ -75,17 +75,23 @@ define('FM_ERRS' , [
define('FM_DYNLOAD', filter_input(INPUT_SERVER, 'HTTP_ACCEPT') === 'application/x-fdynload+json');
function fm_component(string $_component_name, array $vars = []) {
function fm_component(string $_component_name, array $vars = []): string {
if(FM_DYNLOAD) {
global $fmComponentVars;
if(!isset($fmComponentVars))
$fmComponentVars = [];
$fmComponentVars[$_component_name] = $vars;
return;
return '';
}
extract($vars);
ob_start();
require __DIR__ . '/../components/' . $_component_name . '.php';
$meow = ob_get_contents();
ob_clean();
return $meow;
}
function first_paragraph(string $text, string $delimiter = "\n"): string {
@ -130,8 +136,6 @@ function cache_output(string $name, int $lifetime, callable $callable) {
return unserialize(file_get_contents($path));
}
ob_start();
$reqMethod = (string)filter_input(INPUT_SERVER, 'REQUEST_METHOD');
$reqPath = '/' . trim(parse_url((string)filter_input(INPUT_SERVER, 'REQUEST_URI'), PHP_URL_PATH), '/');
$reqHead = false;
@ -141,55 +145,86 @@ if($reqMethod == 'HEAD') {
$reqHead = true;
}
if(FM_DYNLOAD)
ob_start();
$router = new Router;
if(substr($reqPath, 0, 7) === '/error/') {
$statusCode = intval(substr($reqPath, 7, 3));
} else {
foreach(glob(__DIR__ . '/../pages/*.php') as $page) {
$result = include_once $page;
$statusCode = $result & 0xFFF;
if(($result & FM_HIT) === FM_HIT) {
if($statusCode >= 100 && $statusCode <= 999)
http_response_code($statusCode);
else
$statusCode = 200;
break;
}
if(($result & FM_ERR) === FM_ERR)
break;
}
// Make sure we have a valid error code
if($statusCode < 100)
$statusCode = 404;
}
if($statusCode >= 400 && $statusCode <= 599 && ob_get_length() < 1) {
$errorInfo = FM_ERRS[$statusCode ?? 404] ?? FM_ERRS[404];
$router->get('/error/:code', function(string $code) use ($reqHead) {
$errorInfo = FM_ERRS[$code ?? 404] ?? FM_ERRS[404];
http_response_code($errorInfo['code']);
if(!$reqHead) {
fm_component('header', ['title' => $errorInfo['title']]);
?>
$body = fm_component('header', ['title' => $errorInfo['title']]);
$body .= <<<HTML
<div class="http-error">
<h2 class="http-error-head"><?=$errorInfo['title'];?></h2>
<img src="<?=$errorInfo['image'];?>" alt="<?=$errorInfo['image'];?>" class="http-error-image"/>
<div class="http-error-desc"><?=$errorInfo['desc'];?></div>
<h2 class="http-error-head">{$errorInfo['title']}</h2>
<img src="{$errorInfo['image']}" alt="{$errorInfo['image']}" class="http-error-image"/>
<div class="http-error-desc">{$errorInfo['desc']}</div>
</div>
<?php
fm_component('footer');
HTML;
$body .= fm_component('footer');
return $body;
}
});
function mkiRedirect(string $to): callable {
return function() use ($to) {
header('Location: ' . $to);
return 302;
};
}
require_once MKI_DIR_PAGES . '/blog.php';
require_once MKI_DIR_PAGES . '/contact.php';
require_once MKI_DIR_PAGES . '/etcetera.php';
require_once MKI_DIR_PAGES . '/index.php';
require_once MKI_DIR_PAGES . '/projects.php';
require_once MKI_DIR_PAGES . '/related.php';
header('X-Powered-By: Makai');
try {
$handlers = $router->resolve($reqMethod, $reqPath);
} catch(RoutePathNotFoundException $ex) {
$handlers = $router->resolve('GET', '/error/404');
} catch(RouteMethodNotSupportedException $ex) {
$handlers = $router->resolve('GET', '/error/405');
}
$result = $handlers->run();
if(is_int($result))
$result = $router->resolve('GET', "/error/{$result}")->run();
if($result !== null && !is_bool($result)) {
if(is_int($result)) {
http_response_code($result);
header('Content-Type: text/plain; charset=us-ascii');
echo $result;
} elseif(is_array($result)
|| $result instanceof \stdClass
|| $result instanceof \JsonSerializable) {
http_response_code(200);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($result);
} else {
$result = (string)$result;
if(strtolower(substr($result, 0, 14)) === '<!doctype html') {
header('Content-Type: text/html; charset=utf-8');
echo $result;
} else {
if(FM_DYNLOAD) {
header('Content-Type: application/x-fdynload+json');
echo json_encode([
'components' => $fmComponentVars ?? [],
'raw_html' => $result,
]);
} else {
header('Content-Type: text/plain; charset=us-ascii');
echo $result;
}
}
}
}
if(FM_DYNLOAD) {
$contents = ob_get_contents();
ob_end_clean();
header('Content-Type: application/x-fdynload+json');
echo json_encode([
'components' => $fmComponentVars ?? [],
'raw_html' => $contents,
]);
}

File diff suppressed because one or more lines are too long

37
src/LanguageInfo.php Normal file
View file

@ -0,0 +1,37 @@
<?php
namespace Makai;
use Index\AString;
use Index\WString;
class LanguageInfo {
private AString $id;
private WString $name;
private ?int $colour;
public function __construct(
AString $id,
WString $name,
?int $colour
) {
$this->id = $id;
$this->name = $name;
$this->colour = $colour;
}
public function getId(): AString {
return $this->id;
}
public function getName(): WString {
return $this->name;
}
public function hasColour(): bool {
return $this->colour !== null;
}
public function getColour(): ?int {
return $this->colour;
}
}

53
src/Languages.php Normal file
View file

@ -0,0 +1,53 @@
<?php
namespace Makai;
use Index\Data\DbType;
use Index\Data\IDatabaseConnection;
use Index\Data\IDatabaseResult;
class Languages {
private const QUERY = 'SELECT pl.`language_id`, pl.`language_name`, pl.`language_colour` FROM `fm_proglangs` AS pl';
private const QUERY_PROJECT = self::QUERY . ' LEFT JOIN `fm_projects_proglangs` AS ppl ON ppl.`language_id` = pl.`language_id` WHERE ppl.`project_id` = ? ORDER BY ppl.`priority`';
private const QUERY_PROJECT_COLOUR = 'SELECT pl.`language_colour` FROM `fm_proglangs` AS pl LEFT JOIN `fm_projects_proglangs` AS ppl ON ppl.`language_id` = pl.`language_id` WHERE pl.`language_colour` IS NOT NULL AND ppl.`project_id` = ? ORDER BY ppl.`priority` LIMIT 1';
private IDatabaseConnection $conn;
public function __construct(IDatabaseConnection $conn) {
$this->conn = $conn;
}
public function getByProject(ProjectInfo $project): array {
$stmt = $this->conn->prepare(self::QUERY_PROJECT);
$stmt->addParameter(1, $project->getId(), DbType::STRING);
$stmt->execute();
$result = $stmt->getResult();
$objs = [];
while($result->next())
$objs[] = self::createObject($result);
return $objs;
}
public function getProjectColour(ProjectInfo $project): ?int {
$stmt = $this->conn->prepare(self::QUERY_PROJECT_COLOUR);
$stmt->addParameter(1, $project->getId(), DbType::STRING);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
return null;
return $result->getInteger(0);
}
private static function createObject(IDatabaseResult $result): LanguageInfo {
return new LanguageInfo(
$result->getAString(0), // id
$result->getWString(1, 'utf-8'), // name
$result->isNull(2) ? null : $result->getInteger(2) // colour
);
}
}

144
src/ProjectInfo.php Normal file
View file

@ -0,0 +1,144 @@
<?php
namespace Makai;
use Index\AString;
use Index\WString;
use Index\DateTime;
class ProjectInfo {
private string $id;
private WString $name;
private AString $nameClean;
private ?WString $summary;
private ?WString $description;
private bool $featured;
private int $order;
private ?int $colour;
private string $type;
private ?AString $homepage;
private ?AString $source;
private ?AString $discussion;
private DateTime $createdAt;
private ?DateTime $archivedAt;
private ?DateTime $deletedAt;
public function __construct(
string $id, WString $name, AString $nameClean,
?WString $summary, ?WString $description,
bool $featured, int $order, ?int $colour, string $type,
?AString $homepage, ?AString $source, ?AString $discussion,
int $createdAt, ?int $archivedAt, ?int $deletedAt
) {
$this->id = $id;
$this->name = $name;
$this->nameClean = $nameClean;
$this->summary = $summary;
$this->description = $description;
$this->featured = $featured;
$this->order = $order;
$this->colour = $colour;
$this->type = $type;
$this->homepage = $homepage;
$this->source = $source;
$this->discussion = $discussion;
$this->createdAt = DateTime::fromUnixTimeSeconds($createdAt);
$this->archivedAt = $archivedAt === null ? null : DateTime::fromUnixTimeSeconds($archivedAt);
$this->deletedAt = $deletedAt === null ? null : DateTime::fromUnixTimeSeconds($deletedAt);
}
public function getId(): string {
return $this->id;
}
public function getName(): WString {
return $this->name;
}
public function getCleanName(): AString {
return $this->nameClean;
}
public function hasSummary(): bool {
return $this->summary !== null;
}
public function getSummary(): ?WString {
return $this->summary;
}
public function hasDescription(): bool {
return $this->description !== null;
}
public function getDescription(): ?WString {
return $this->description;
}
public function isFeatured(): bool {
return $this->featured;
}
public function getOrder(): int {
return $this->order;
}
public function hasColour(): bool {
return $this->colour !== null;
}
public function getColour(): ?int {
return $this->colour;
}
public function getProjectType(): string {
return $this->type;
}
public function isTool(): bool {
return $this->getProjectType() === 'Tool';
}
public function hasHomePageUrl(): bool {
return $this->homepage !== null;
}
public function getHomePageUrl(): ?AString {
return $this->homepage;
}
public function hasSourceUrl(): bool {
return $this->source !== null;
}
public function getSourceUrl(): ?AString {
return $this->source;
}
public function hasDiscussionUrl(): bool {
return $this->discussion !== null;
}
public function getDiscussionUrl(): ?AString {
return $this->discussion;
}
public function getCreatedAt(): DateTime {
return $this->createdAt;
}
public function getArchivedAt(): ?DateTime {
return $this->archivedAt;
}
public function isArchived(): bool {
return $this->archivedAt !== null;
}
public function getDeletedAt(): ?DateTime {
return $this->deletedAt;
}
public function isDeleted(): bool {
return $this->deletedAt !== null;
}
}

62
src/Projects.php Normal file
View file

@ -0,0 +1,62 @@
<?php
namespace Makai;
use Index\Data\IDatabaseConnection;
use Index\Data\IDatabaseResult;
class Projects {
private const QUERY = 'SELECT `project_id`, `project_name`, COALESCE(`project_name_clean`, REPLACE(LOWER(`project_name`), \' \', \'-\')) AS `project_name_clean`, `project_summary`, `project_description`, `project_featured`, `project_order`, `project_homepage`, `project_repository`, `project_forum`, UNIX_TIMESTAMP(`project_archived`) AS `project_archived`, `project_type`, UNIX_TIMESTAMP(`project_created`) AS `project_created`, `project_colour` FROM `fm_projects` WHERE `project_deleted` IS NULL';
private const QUERY_ALL = self::QUERY . ' ORDER BY `project_order` DESC';
private const QUERY_FEATURED = self::QUERY . ' AND `project_featured` <> 0 ORDER BY RAND() LIMIT 3';
private IDatabaseConnection $conn;
public function __construct(IDatabaseConnection $conn) {
$this->conn = $conn;
}
public function getAll(): array {
$stmt = $this->conn->prepare(self::QUERY_ALL);
$stmt->execute();
$result = $stmt->getResult();
$objs = [];
while($result->next())
$objs[] = self::createObject($result);
return $objs;
}
public function getFeatured(): array {
$stmt = $this->conn->prepare(self::QUERY_FEATURED);
$stmt->execute();
$result = $stmt->getResult();
$objs = [];
while($result->next())
$objs[] = self::createObject($result);
return $objs;
}
private static function createObject(IDatabaseResult $result): ProjectInfo {
return new ProjectInfo(
$result->getString(0), // id
$result->getWString(1, 'utf-8'), // name
$result->getAString(2), // clean name
$result->isNull(3) ? null : $result->getWString(3, 'utf-8'), // summary
$result->isNull(4) ? null : $result->getWString(4, 'utf-8'), // description
$result->getInteger(5) !== 0, // featured
$result->getInteger(6), // order
$result->isNull(13) ? null : $result->getInteger(13), // colour
$result->getString(11), // type
$result->isNull(7) ? null : $result->getAString(7), // homepage
$result->isNull(8) ? null : $result->getAString(8), // repository
$result->isNull(9) ? null : $result->getAString(9), // forum
$result->getInteger(12), // created
$result->isNull(10) ? null : $result->getInteger(10), // archived
null // deleted
);
}
}