@@ -0,0 +1,44 @@ | |||
export default class | |||
CommonModule | |||
{ | |||
static | |||
isWide (chr) | |||
{ | |||
return chr.match (/[^\x01-\x7f]/) !== null; | |||
} | |||
static | |||
lenByFull (str) | |||
{ | |||
return str.split ('').map (c => this.isWide (c) ? 1 : .5) | |||
.reduce ((a, c) => a + c); | |||
} | |||
static | |||
indexByFToC (str, index) | |||
{ | |||
let i = 0; | |||
let work = ''; | |||
for (let c of str) | |||
{ | |||
work += c; | |||
if (this.lenByFull (work) > index) | |||
break; | |||
i += 1; | |||
} | |||
return i; | |||
} | |||
static | |||
midByFull (str, start, length) | |||
{ | |||
const trimmedLeft = str.slice (this.indexByFToC (str, start)); | |||
return trimmedLeft.slice (0, this.indexByFToC (trimmedLeft, length)); | |||
} | |||
} | |||
@@ -22,12 +22,18 @@ | |||
</head> | |||
<body> | |||
<?php if (!($available)): ?> | |||
<div class="alert alert-danger" role="alert"> | |||
<strong>【警報】</strong>AIニジカが落ちてるぬ゛〜゛ん゛(泣) | |||
</div> | |||
<?php endif ?> | |||
<div class="container my-5"> | |||
<div class="accordion mb-5" id="accordion-filter"> | |||
<div class="accordion-item"> | |||
<h2 class="accordion-header"> | |||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-filter" aria-controls="collapse-filter"> | |||
絞り込みてすと | |||
絞り込み | |||
</button> | |||
</h2> | |||
@@ -124,9 +130,9 @@ | |||
$length, | |||
true) | |||
as $record): ?> | |||
<div class="mb-4"> | |||
<div class="mb-4 message-block"> | |||
<div> | |||
<?= $record['date_time'] ?> | |||
<span class="message-block-dt"><?= $record['date_time'] ?></span> | |||
</div> | |||
<div> | |||
@@ -135,11 +141,11 @@ | |||
</div> | |||
<div style="color: blue"> | |||
> <span style="font-style: italic"><?= $record['chat_message'] ?></span> | |||
> <span class="message-block-chat" style="font-style: italic"><?= $record['chat_message'] ?></span> | |||
</div> | |||
<div> | |||
<?= $record['answer'] ?> | |||
<span class="message-block-answer"><?= $record['answer'] ?></span> | |||
</div> | |||
</div> | |||
<?php endforeach ?> | |||
@@ -7,6 +7,11 @@ const LOG_PATH = './log.txt'; | |||
$log_data = []; | |||
exec ("(ps -Af | grep -e '^miteruzo' | grep 'python3 main.py') && (ps -Af | grep -e '^miteruzo' | grep 'obs')", | |||
$output, $exit_code); | |||
$available = $exit_code === 0; | |||
unset ($output, $exit_code); | |||
$page = (int) ($_GET['p'] ?? 1); | |||
$length = (int) ($_GET['max'] ?? 20); | |||
$asc = ($_GET['asc'] ?? 0) != 0; | |||
@@ -78,6 +78,15 @@ Script | |||
$.cookie ('expand-filter', '0'); | |||
}); | |||
$ ('.message-block').on ('click', function () | |||
{ | |||
const dt = $ (this).find ('.message-block-dt').text (); | |||
const chat = $ (this).find ('.message-block-chat').text (); | |||
const answer = $ (this).find ('.message-block-answer').text (); | |||
window.open (`./talk.php?dt=${dt}&chat=${chat}&answer=${answer}`); | |||
}); | |||
if ($.cookie ('expand-filter') === '0') | |||
{ | |||
$ ('#collapse-filter').removeClass ('show'); | |||
@@ -0,0 +1,32 @@ | |||
/* vim:set tabstop=2 softtabstop=2 expandtab :*/ | |||
@font-face | |||
{ | |||
font-family: 'Nikumaru'; | |||
src: url(./assets/nikumaru.otf); | |||
} | |||
html, body | |||
{ | |||
overflow: hidden; | |||
} | |||
body | |||
{ | |||
background-color: black; | |||
} | |||
#canvas | |||
{ | |||
width: 100%; | |||
height: 100%; | |||
padding: 0; | |||
margin: 0; | |||
overflow: unset; | |||
border: none | |||
!important; | |||
outline: none | |||
!important; | |||
display: block; | |||
} | |||
@@ -0,0 +1,23 @@ | |||
<!-- vim:set tabstop=4 softtabstop=4 expandtab :--> | |||
<!DOCTYPE html> | |||
<html lang="ja"> | |||
<head> | |||
<meta charset="UTF-8" /> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<script src="//code.jquery.com/jquery-3.3.1.min.js"></script> | |||
<link rel="stylesheet" href="./talk.css?<?= filemtime ('./talk.css') ?>" /> | |||
<link rel="preconnect" href="./assets/nikumaru.otf" /> | |||
<title>あほ</title> | |||
<input type="hidden" id="dt" value="<?= $dt ?>" /> | |||
<input type="hidden" id="chat" value="<?= $chat ?>" /> | |||
<input type="hidden" id="answer" value="<?= $answer ?>" /> | |||
</head> | |||
<body> | |||
<canvas id="canvas"></canvas> | |||
<script src="./talk.js?<?= filemtime ('./talk.js') ?>" type="module"></script> | |||
</body> | |||
</html> | |||
@@ -0,0 +1,136 @@ | |||
import CommonModule from './common_module.js'; | |||
class | |||
Talk | |||
{ | |||
static | |||
main () | |||
{ | |||
const canvas = new Canvas; | |||
window.onresize = () => canvas.resize (); | |||
} | |||
} | |||
class | |||
Canvas | |||
{ | |||
constructor () | |||
{ | |||
this.canvas = $ ('#canvas'); | |||
this.ctx = this.canvas[0].getContext ('2d'); | |||
(this.bg = new Image ()).src = './assets/bg.jpg'; | |||
this.bg.onload = () => this.resize (); | |||
(this.nizika = new Image ()).src = './assets/nizika.png'; | |||
this.nizika.onload = () => this.resize (); | |||
(this.talking = new Image ()).src = './assets/talking.png'; | |||
this.talking.onload = () => this.resize (); | |||
(new FontFace ('Nikumaru', 'url(./assets/nikumaru.otf)')).load ().then ( | |||
() => this.resize ()); | |||
} | |||
resize () | |||
{ | |||
this.canvas[0].width = $ (window).width (); | |||
this.canvas[0].height = $ (window).height (); | |||
this.redraw (); | |||
} | |||
redraw () | |||
{ | |||
this.putBG (); | |||
this.putText (0, 0, 15, $ ('#dt').val ()); | |||
this.putImage (this.nizika, 370, 260, 1.1); | |||
this.putImage (this.talking, 0, 0, 640 / 1024); | |||
this.putText (75, 43.75, 20, | |||
('> ' + ((CommonModule.lenByFull ($ ('#chat').val ()) <= 21) | |||
? $ ('#chat').val () | |||
: (CommonModule.midByFull ($ ('#chat').val (), 0, 19.5) | |||
+ '...'))), | |||
undefined, undefined, | |||
true); | |||
this.putText (62.5, 93.75, 31.25, | |||
((CommonModule.lenByFull ($ ('#answer').val ()) <= 16) | |||
? $ ('#answer').val () | |||
: CommonModule.midByFull ($ ('#answer').val (), 0, 16)), | |||
'Nikumaru', '#c00000'); | |||
if (CommonModule.lenByFull ($ ('#answer').val ()) > 16) | |||
{ | |||
this.putText (62.5, 125, 31.25, | |||
((CommonModule.lenByFull ($ ('#answer').val ()) <= 32) | |||
? CommonModule.midByFull ($ ('#answer').val (), 16, 16) | |||
: (CommonModule.midByFull ($ ('#answer').val (), 16, 14.5) | |||
+ '...')), | |||
'Nikumaru', '#c00000'); | |||
} | |||
} | |||
putBG () | |||
{ | |||
const [x, y, zoom] = this.convertPosition (0, 0); | |||
const width = this.bg.height * 4 / 3; | |||
const height = this.bg.height; | |||
this.ctx.drawImage (this.bg, | |||
(852 - 640) / 2, 0, width, height, | |||
x, y, width * zoom, height * zoom); | |||
} | |||
putImage (image, x, y, zoom = 1) | |||
{ | |||
let zoom2 | |||
[x, y, zoom2] = this.convertPosition (x, y); | |||
zoom *= zoom2 | |||
this.ctx.drawImage (image, | |||
0, 0, image.width, image.height, | |||
x, y, image.width * zoom, image.height * zoom); | |||
} | |||
putText (x, y, size, text, style = 'sans-serif', colour = 'black', | |||
italic = false) | |||
{ | |||
let zoom; | |||
[x, y, zoom] = this.convertPosition (x, y); | |||
size *= zoom; | |||
this.ctx.font = `${italic ? 'italic ' : ''}${Math.trunc (size)}px ${style}`; | |||
this.ctx.fillStyle = colour; | |||
this.ctx.textBaseline = 'top'; | |||
this.ctx.fillText (text, x, y); | |||
} | |||
convertPosition (x, y) | |||
{ | |||
const sizeX = this.canvas.width (); | |||
const sizeY = this.canvas.height (); | |||
const width = this.bg.height * 4 / 3; | |||
const height = this.bg.height; | |||
const vertical = sizeY / sizeX > height / width; | |||
const zoom = vertical ? (sizeX / width) : (sizeY / height); | |||
const baseX = vertical ? 0 : ((sizeX - width * zoom) / 2); | |||
const baseY = vertical ? ((sizeY - height * zoom) / 2) : 0; | |||
return [baseX + x * zoom, baseY + y * zoom, zoom]; | |||
} | |||
} | |||
$ (() => Talk.main ()); | |||
@@ -0,0 +1,11 @@ | |||
<?php | |||
if ($_SERVER['HTTP_HOST'] === 'nizika.monster') | |||
header ('location: //nizika.tv/talk.php'); | |||
$dt = htmlspecialchars ($_GET['dt']); | |||
$chat = htmlspecialchars ($_GET['chat']); | |||
$answer = htmlspecialchars ($_GET['answer']); | |||
require_once './talk.frm.php'; | |||