[C++] 234 FLTK : vector不具合の回避

[M1 Mac, Big Sur 11.7.2, clang 13.0.0, FLTK 3.8.1, NO IDE]

ビデオ編集アプリがvector<string>の要素取得で不具合を起こしました。アプリの実行ファイルでは問題なく動作し、appファイルでおかしくなります。

以前よりこのアプリに限らずvectorがらみの不具合が頻発しており、仕方ないのでvectorを作成せず各要素を直接変数に代入しました。

今回はswitch文を使いましたが、array<string, 5>への代入&取得でも上手くいくと思います。

MacOSのレポートによるとlibc++.1.dylibあたりに問題があるようです。深追いはやめておきます。

このアプリで音声なし動画の分割、結合、複数箇所モザイク作成ができます。Final Cut Proは持っていますが、サクッと編集できるツールとして作りました。サイズは1.6MBでffmpegやffprobeファイルは含みません。

FFmpegのライセンスはLGPLですから、動的リンクであればソースコード非開示で頒布可能のようです。

FLTKではGUIの野暮ったさが拭えないので、頒布するならwxWidgetsで作り直しでしょうか。

いずれにせよこのアプリのGUIはまだまだ手入れが必要です。

string width_str, height_str, fps_str, time_str, frames_str;

void showData(string file){
    std::ifstream ifFile;
    string buffer;

    ifFile.open(file, std::ios::in);
    std::getline(ifFile, buffer);
    cout << "buffer: " << buffer << endl;

    // bufferを先頭からカンマで分割していく
    int first = 0;
    int last = buffer.find_first_of(",");

    int count = 0;
    while (first < buffer.size()) {
        string subStr(buffer, first, last - first);
        
        switch (count){
            case 0:
                width_str = subStr;
                break;
            case 1:
                height_str = subStr;
                break;
            case 2:
                fps_str = subStr;
                break;
            case 3:
                time_str = subStr;
                break;
            case 4:
                frames_str = subStr;
                break;
            default:
                break;
        }
        first = last + 1;
        last = buffer.find_first_of(",", first);
 
        if (last == string::npos) {
            last = buffer.size();
        }
        count += 1;
    }

<以下略>
MacOSレポート

[C++] 233 FLTK : ビデオ編集アプリの改良

[M1 Mac, Big Sur 11.7.2, clang 13.0.0, FLTK 3.8.1, NO IDE]

昨年2022年9月に作成したビデオツール統合アプリから、ビデオ編集機能(音声なし)を取り出して改良を試みます。

コードの内容を大分忘れていて思い出すのに少々時間がかかりました。

分離したアプリをMakefileで作成できるようになったので、これから改良に着手します。

[PHP] 13 ブラウザ起動と同時にDeveloper Toolsを開く Chrome, Firefox

[M1 Mac, Big Sur 11.7.2, PHP 8.2.1, MySQL 8.0.31, noFramework]

ブラウザ起動と同時にDeveloper Toolsを開くようにしました。

Firefoxは下側に開きます。後から右側に変えられるものの私には非常に使いにくいのでChromeに戻ってきました。

<?php
require_once ('../../composer/vendor/autoload.php');
use Facebook\WebDriver\Chrome\ChromeDriver;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\WebDriverExpectedCondition;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Remote\DesiredCapabilities;

# MySQLサーバ起動判定
exec('mysqladmin ping', $out, $ret);
$out_str = $out[0];
$out_str2 = sprintf("out_str: %s", $out_str);
echo $out_str2;

if(strpos($out[0],'alive') === false){
    exec('mysql.server start');
}else{
    print 'MySQLは起動しています';
    echo "\n";
}

# Webサーバ起動
exec('php -S localhost:8890 -t "/code/PHP/projects/02_mysql_searcher39" > /dev/null &');

# chromedriverのパス設定
$driverPath = realpath("/opt/homebrew/Caskroom/chromedriver/109.0.5414.74/chromedriver");
putenv("webdriver.chrome.driver=" . $driverPath);

# オプション指定
$options = new ChromeOptions();
$options->addArguments(['--width=400','--height=400','--auto-open-devtools-for-tabs']);

$caps = DesiredCapabilities::chrome();
$caps->setCapability(ChromeOptions::CAPABILITY, $options);

# Chromeを起動しphpスクリプトを実行
$driver = ChromeDriver::start($caps);
$driver->get('http://localhost:8890/input.php');

<以下略>
<?php
require_once ('../../composer/vendor/autoload.php');
use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxOptions;
use Facebook\WebDriver\WebDriverExpectedCondition;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Remote\DesiredCapabilities;

# MySQLサーバ起動判定
exec('mysqladmin ping', $out, $ret);
$out_str = $out[0];
$out_str2 = sprintf("out_str: %s", $out_str);
echo $out_str2;

if(strpos($out[0],'alive') === false){
    exec('mysql.server start');
}else{
    print 'MySQLは起動しています';
    echo "\n";
}

# Webサーバ起動
exec('php -S localhost:8890 -t "/code/PHP/projects/02_mysql_searcher38" > /dev/null &');

# geckodriverのパス設定
putenv('webdriver.gecko.driver=/usr/local/bin/geckodriver');

# オプション設定
$desiredCapabilities = DesiredCapabilities::firefox();
$firefoxOptions = new FirefoxOptions();
$firefoxOptions->addArguments([ '--width=600','--height=400','-devtools']);
$desiredCapabilities->setCapability(FirefoxOptions::CAPABILITY, $firefoxOptions);

# Firefoxを起動しphpスクリプトを実行
$driver = FirefoxDriver::start($desiredCapabilities);
$driver->get('http://localhost:8890/input.php');

<以下略>

[PHP] 12 Firefoxで自動操作

[M1 Mac, Big Sur 11.7.2, PHP 8.2.1, MySQL 8.0.31, noFW]

Webアプリ自動操作のブラウザをFirefoxに変えてみました。

Developer Toolsは最初から日本語対応です。警告の内容が細かく、Chromeに比較して開発者にやさしい仕様に見えました。

しばらくFirefoxを試してみます。

<?php
require_once ('../../composer/vendor/autoload.php');
use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxDriverService;
use Facebook\WebDriver\Firefox\FirefoxOptions;
use Facebook\WebDriver\WebDriverExpectedCondition;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Remote\DesiredCapabilities;

# MySQLサーバ起動判定
exec('mysqladmin ping', $out, $ret);
$out_str = $out[0];
$out_str2 = sprintf("out_str: %s", $out_str);
echo $out_str2;

if(strpos($out[0],'alive') === false){
    exec('mysql.server start');
}else{
    print 'MySQLは起動しています';
    echo "\n";
}

# Webサーバ起動
exec('php -S localhost:8890 -t "/code/PHP/projects/02_mysql_searcher37" > /dev/null &');

# geckodriverのパス設定
putenv('webdriver.gecko.driver=/usr/local/bin/geckodriver');

# オプション設定
$desiredCapabilities = DesiredCapabilities::firefox();
$firefoxOptions = new FirefoxOptions();
$firefoxOptions->addArguments([ '--width=600','--height=400']);
$desiredCapabilities->setCapability(FirefoxOptions::CAPABILITY, $firefoxOptions);

# Firefoxを起動しphpスクリプトを実行
$driver = FirefoxDriver::start($desiredCapabilities);
$driver->get('http://localhost:8890/input.php');

# Firefox表示待機
$driver->wait(10)->until(
    WebDriverExpectedCondition::visibilityOfElementLocated(WebDriverBy::id("form_submit"))
);

sleep(1);
# 自動入力
$driver->findElement(WebDriverBy::id("input1"))->sendKeys("lpw");
sleep(1);
$driver->findElement(WebDriverBy::id("input2"))->sendKeys("Email");
sleep(1);
$driver->findElement(WebDriverBy::id("input3"))->sendKeys("@yahoo.co.jp");
sleep(1);
# 確定ボタン押下
$driver->findElement(WebDriverBy::id("button"))->click();

# search.phpへの遷移待機
$driver->wait(10)->until(
    WebDriverExpectedCondition::visibilityOfElementLocated(WebDriverBy::id("clockTime"))
);

sleep(1);
# 検索ボタン押下
$driver->findElement(WebDriverBy::id("button2"))->click();

?>

参考サイト

[PHP] 11 日付取得とglob関数

[M1 Mac, Big Sur 11.7.2, PHP 8.2.1, MySQL 8.0.31, noFW]

MySQL検索結果のCSVファイル名に日付と通し番号を付けました。

タイポしてしまったスクリプトが停止せずに動いたことには驚きました。PHPは変数宣言が不要なので、式の右辺に突然未宣言の変数を書いてもエラーになりません。

PythonやVBAよりも文法がゆるい言語があるとは知りませんでした。

# 正しいスクリプト
$csv_counts = $csv_counts + 1;

# タイポしたスクリプト(エラーにならない)
$csv_counts = $csv_unts + 1;
# 今日の日付取得
$objDateTime = new DateTime();
$date = $objDateTime->format('ymd');
// echo nl2br($date."\n");

# 今日作成csvファイルをカウント
$num_file;
foreach (glob("/projects/_csv/*.csv") as $filename) {
    // echo nl2br($filename."\n");
    if (strpos($filename,$date) == true){
        $num_file +=1;
    }
}
// echo nl2br($num_file."\n");
$new_num = $num_file + 1;

# csvファイルパス作成
$prefix_csv = '/projects/_csv/';
$file_csv = $prefix_csv.$date."_mysql_".$new_num.".csv";
// echo nl2br($file_csv."\n");

# csvファイル作成
$fp_csv = fopen($file_csv, 'a');

# MySQL検索
$tbls_num = 1;
$counts = 0;
$csv_counts = 0;
foreach ($tbls as $tbl) {
    $query = sprintf("SELECT * FROM `%s` WHERE `%s` LIKE '%%%s%%'", implode($tbl), $field2, $key2);
    $result = $conn->query($query);
    $rows = $result->fetch_all(MYSQLI_ASSOC);

    # 件数カウント
    $count = count($rows);
    $counts = $counts + $count;

    # csv化(1000件以下)
    for($i = 0, $size = count($rows); $i < $size; ++$i){
        if ($csv_counts < 1000){
            $row_str = $rows[$i];
            fputcsv($fp_csv, $row_str);

            $csv_counts = $csv_counts + 1;
        } 
    }
    $tbls_num = $tbls_num + 1;
}
fclose($fp_csv);

$conn->close();
exec('mysql.server stop');

[PHP] 10 homeディレクトリの取得

[M1 Mac, Big Sur 11.7.2, PHP 8.2.1, MySQL 8.0.31, noFW]

プログラムからクライアント側のローカルファイルを読み込むことは当然厳禁ですが、ファイル出力は可能です。

MySQLの検索結果CSVファイルをhomeディレクトリに出力させてみました。UTF-8であればPythonに比べてCSVファイルの作成は簡単です。

今更ですがPHPでは文字列をピリオドで結合するんですね。当たり前のようにプラスでつないで気付くまでエラーに見舞われていました。この結合方式はPerl由来なのでしょうか。

$db2 = $_COOKIE["db"];
$field2 = $_COOKIE["field"];
$key2 = $_COOKIE["key"];

# MySQLにログイン
$conn = new mysqli('localhost', 'root', 'root');
if (!$conn){
    die("MySQL接続に失敗しました");
} else {
    // print 'MySQL接続に成功しました';
}

# データベース選択
$select_db = sprintf("use %s", $db2);
$select = $conn->query($select_db);

# 全テーブル取得
$tbls_query = $conn->query('show tables;');
$tbls = $tbls_query->fetch_all(MYSQLI_ASSOC);

$tbls_count = count($tbls);

# homeディレクトリ取得
ob_start();
echo posix_getpwuid(posix_geteuid())['dir'];
$home_dir = ob_get_clean();
$home_dir = strtolower($home_dir);

# csvファイルパス作成
$suffix_csv = '/MySQL/test.csv';
$file_csv = $home_dir.$suffix_csv;

# csvファイル作成
$fp_csv = fopen($file_csv, 'a');

$tbls_num = 1;
$counts = 0;
foreach ($tbls as $tbl) {
    $query = sprintf("SELECT * FROM `%s` WHERE `%s` LIKE '%%%s%%'", implode($tbl), $field2, $key2);
    $result = $conn->query($query);
    $rows = $result->fetch_all(MYSQLI_ASSOC);

    # 件数カウント
    $count = count($rows);
    $counts = $counts + $count;

    # csv化(1000件以下)
    if ($counts <= 1000){
        for($i = 0, $size = count($rows); $i < $size; ++$i){
            $row_str = $rows[$i];
            fputcsv($fp_csv, $row_str);
        }
    }
    
    $tbls_num = $tbls_num + 1;
}
fclose($fp_csv);

$conn->close();
exec('mysql.server stop');

[PHP] 09 POSTリクエストでsubmitしたformの内容を取得する cookie

[M1 Mac, Big Sur 11.7.2, PHP 8.2.1, MySQL 8.0.31]

submitしたformの内容を次ページに表示させても数秒で消えてしまいます。

そこでfilter_inputメソッドで取得した変数をcookieに一旦格納してから、使用時にこれを取り出しました。ただcookieに入れてしまうとfilter_inputメソッドで取得した際の変数名($dbなど)も問題なく使えるようになります。

なぜこのようなことになるのかよく分かりません。ガベージコレクション絡みでしょうか。

$db = filter_input(INPUT_POST, 'db');
$field = filter_input(INPUT_POST, 'field');
$key = filter_input(INPUT_POST, 'key');

setcookie('db', $db);
setcookie('field', $field);
setcookie('key', $key);

if(isset($_POST['button2'])){
    $db2 = $_COOKIE["db"];
    $field2 = $_COOKIE["field"];
    $key2 = $_COOKIE["key"];

    # MySQLにログイン
    $conn = new mysqli('localhost', 'root', 'root');
    if (!$conn){
        die("MySQL接続に失敗しました");
    } else {
        // print 'MySQL接続に成功しました';
    }

    <変数はクエリで使用>

<中略>

<table id="search_table" border="2">
        <tr>
            <td>データベース</td>
            <td id="input1-2" width="180" name="db2"><?php echo $db; ?></td>
        </tr>
        <tr>
            <td>フィールド</td>
            <td id="input2-2" width="180" name="field2"><?php echo $field; ?></td>
        </tr>
        <tr>
            <td>検索語</td>
            <td id="input3.2" width="180" name="key2"><?php echo $key; ?></td>
        </tr>
</table>

[JavaScript] 12 submitボタンに動作を追加する

[M1 Mac, Big Sur 11.7.2]

検索ボタンを押すとMySQLへログインして検索するよう設定していますが、同時にストップウォッチが動作するようにしました。

<form method="post" name="formSearch">
    <input id="button2" type="submit" name="button2" value="検索"
    style="color:blue; width:80px; height:40px; font-size:18px; background-color:RGB(211,203,198);
    border:solid; border-color:RGB(30,144,255);">
</form>
<br>

<script language="javascript" type="text/javascript">
    const button2 = document.getElementById('button2');

    button2.addEventListener('click',(e) => {
        startWatch();
        document.cookie="watch=1;";
    });
</script>

<中略>

<span id="elapsedTime"></span>
<br>

<script language="javascript" type="text/javascript">
    function getCookieValue(key) {
        const cookies = document.cookie.split(';');
        for (let cookie of cookies) {
            var cookiesArray = cookie.split('='); 
            if (cookiesArray[0].trim() == key.trim()) { 
                return cookiesArray[1];
            }
        }
        return '';
    }

    function showElapsedTime(time) {
        var now = new Date();
        const eTime = Math.floor((now - time)/1000);
        document.cookie="time=" + eTime + ";";

        var eTimeShow = "検索時間(秒) " + eTime;
        document.getElementById("elapsedTime").innerHTML = eTimeShow;

        return eTimeShow;
    }

    function startWatch(){
        var startTime = new Date();

        setInterval(
            function()
            {showElapsedTime(startTime);}
            ,1000 ) ;
    }

    var watchBool = getCookieValue("watch");
    if (watchBool == 1){
        let time = getCookieValue("time");
        var eTimeShow = "検索時間(秒) " + time;
        console.log(eTimeShow);
        document.getElementById("elapsedTime").innerHTML = eTimeShow;
    }
</script>

[JavaScript] 11 プログレスバー Fetch API

[M1 Mac, Big Sur 11.7.2]

懸案のプログレスバー表示ですが、PHPの簡易webサーバ側(PHPファイルと同じディレクトリ)にMySQL検索の進捗率を格納したテキストファイルを置いて定期的に読み込もうとしたもののデータを更新できず上手くいきませんでした。記録として残しておきます。

以前JavaScriptの学習を断念した原因であるHTTP通信に取り組まざるを得なくなりました。

様々な検証を通して、根本的にMySQL検索中は最新テキストファイルへのアクセスができないことが判明しました。

仕様なのかマシンスペックなのか何が原因なのかは良く分かりません。少なくとも今の環境ではどう手立てを施してもできないのかもしれません。

ここ数日かなりのめり込み愛着もわいてきましたのでJavaScriptと今後決別することはありませんが、この程度の動作も簡単には出来ないとなると使用頻度は低いままに終わりそうです。MySQL検索はターミナルでのPython実行で事足りますから。

直前試行の残データを読み込んだまま更新されない
<progress class="progress" value="0" id="pb">
</progress>
<div id="rate"></div>

<script type="text/javascript">
    async function showRate() {
        let response = await fetch("./files/rate.txt");
        var rateID = document.getElementById('rate')

        if (response.ok) {
            var rate = await response.text();
            rateID.textContent = rate;
            console.log("rate: %s", rate);
        }
        else {
            alert("HTTP-Error: " + response.status);
        }

        document.getElementById("pb").value = rate;
        
    };

    // Fetch APIの使用可否確認
    if(window.fetch ) {
	    console.log("fetch使用可能");
    } else {
	    console.log("fetch使用不可");
    }

    setInterval('showRate()', 1000);
</script>

[JavaScript] 10 cookieの使用 検索時間の記録

[M1 Mac, Big Sur 11.7.2]

MySQLアプリの検索時間をcookieに都度記録し、検索が完了してリロードされた時に最終記録を表示するようにしました。意味がないのですがプログレスバーはいきなり最後だけ100%で表示されます。

PHPもJavaScriptも初心者なので、HTMLを加えた3者が混在するPHPファイルを書くのは骨が折れます。どちらもそれなりに書けるようになるとスクリプト言語はPythonを合わせた3言語を学んだことになります。

Rubyも学んでみたいですが、それにしかできないことでもないと着手しそうにないですね。

MySQL検索終了時
<input id="checkBox" type="checkbox" name="checkBox" value="開始" onClick="startTimer()"/>

<span id="elapsedTime"></span>

<script language="javascript" type="text/javascript">

    function getCookieValue(key) {
        const cookies = document.cookie.split(';');
        for (let cookie of cookies) {
            var cookiesArray = cookie.split('='); 
            if (cookiesArray[0].trim() == key.trim()) { 
                return cookiesArray[1];
            }
        }
        return '';
    }

    function showElapsedTime(time) {
        var now = new Date();
        const eTime = Math.floor((now - time)/1000);
        document.cookie="time=" + eTime + ";";
        console.log(eTime);

        var eTimeShow = "検索時間(秒) " + eTime;
        console.log(eTimeShow);
        document.getElementById("elapsedTime").innerHTML = eTimeShow;

        return eTimeShow;
    }

    function startTimer(){
        var startTime = new Date();

        setInterval(
            function()
            {showElapsedTime(startTime);}
            ,1000 ) ;
    }

    try {
        let checkBox = document.getElementById('checkBox');
        console.log("checkBox: %b", checkBox.checked);

        if (checkBox.checked == false){
            var time = getCookieValue("time");
            var eTimeShow = "検索時間(秒) " + time;
            console.log(eTimeShow);
            document.getElementById("elapsedTime").innerHTML = eTimeShow;
        }
    }
    catch(e){
    }
</script>