🏠️Top Page

🖊️おもしろき こともなき世をおもしろく 住みなすものは 心なりけり.

⏩️tMDbのAPIを使用して今まで観た映画をリスト化してみましたよ.

おはようございます.tMDbのAPIを使用して今まで観た映画をリスト化してみましたよ.sqliteの構造は下記になります.idはbigintと記載していますが、AUTO_INCREMENTの間違いです🐼.

Xにも呟きましたがAPIを使用して何かするのはこの頃飽きてきて触らなかったのですが、たまには触れてみようとコードを書いているうちに簡単に作れるようになってしまって少々物足りなさを感じています.

次回はAPIを使う側ではなくて作る側になろうと思っています.GW期間になると思いますが600円のレンタルサーバーのフリードメインを使ってツマラナイAPIみたいな失笑系を作ってみます.

なお、ソースコードの解説がなくてすみません、このソースコードを生成AIに投げてどのような処理か説明して言えば恐らく正解を教えてくれます.

明日へ続く

#真相をお話します.
少年と犬
Flow
curl -sS https://getcomposer.org/installer | php
composer require guzzlehttp/guzzle
composer require illuminate/database
<?php
require_once 'config.php';
require_once 'vendor/autoload.php';
use Illuminate\Database\Capsule\Manager as Capsule;
use Illuminate\Database\Capsule\Manager as DB;

class MovieList
{
    public $result = '';
    public $imgBasicUrl = 'https://image.tmdb.org/t/p/w500';
    public $filePath = FILEPATH_DIR_;
    public function __construct($filePath='')
    {
        $filePath = $filePath?$filePath:$this->filePath;
        if (!file_exists($filePath.'/movie-list.db')) {
            exit;
        }        
        $capsule = new Capsule();

        $capsule->addConnection([
            'driver'   => 'sqlite',
            'database' => $filePath.'/movie-list.db',
            'prefix'   => '',
        ]);

        $capsule->setAsGlobal();
        $capsule->bootEloquent();
    }

    public function getMovieList(string $q): void
    {
        $client = new \GuzzleHttp\Client();

        $response = $client->request('GET', 'https://api.themoviedb.org/3/search/multi?query=' . $q . '&include_adult=false&language=ja-JP&page=1', [
            'headers' => [
                'Authorization' => 'Bearer ' . API_KEY,
                'accept' => 'application/json',
            ],
        ]);
        $this->result = $response->getBody();
    }

    public function getResult(): void
    {
        $data = DB::table('list')->get();
        $lists = [];
        foreach ($data as $key => $value) {
           $result = unserialize($value->value);
            if(isset($result?->media_type) && $result->media_type == 'movie'){
                $lists[] = [
                    'id'=>$data[$key]->id,
                    'title'=>$result->title,
                    'img'=>$this->imgBasicUrl . $result->poster_path,
                ];
            }
        }
        print json_encode($lists);
    }

    public function saveCsvlist(): void
    {
        $fileData = explode("\n",file_get_contents('movie-list.csv'));
        $fileData = array_reverse($fileData);
        foreach($fileData as $line)
        {
            foreach(explode(',',$line) as $data){
                $q = urlencode($data);
                $movieList = new MovieList();
                $movieList->getMovieList($q);
                foreach((json_decode($movieList->result))?->results as $result){
                    DB::table('list')->insert([
                        'value' => serialize($result)
                    ]);
                }
            }
        }        
    }

    public function delete($id): void
    {
        
        DB::table('list')->where('id', '=', $id)->delete();
        print json_encode(['res'=>'true']);
    }

}
//(new MovieList())->saveCsvlist();
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    if(!isset($_POST['id'])){
        (new MovieList())->getResult();
    }else{
        //(new MovieList())->delete($_POST['id']);
    }   
}

⏩️映画、#真相をお話ししますを観ましたよ.感想なんかを書いていきます.

おはようございます.映画、#真相をお話ししますを観ましたよ.感想なんかを書いていきます.原作の小説が店頭に並んでいた頃からこの「#真相をお話しします」というタイトルには惹かれていた覚えがあります.とてもインパクトのある小説の映画化.

予告を観てB級かもしれないという思いもありましたが映画館に足を運んでみました.ちょっと違和感はあったものの、話が進んでいくに連れ映像も慣れて後半部分は違和感というものは払拭していました.

そして久しぶりにこんなにバッサリと画を切った終わらせ方を観たので、とても潔くて良かったです.なかなかこういう切り方を観なくなったのでとても清々しい気分になりました.

明日へ続く

⏩️こんなサイトを作りました.無償で制作します、続きがあるよ.

おはようございます.こんなサイトを作りました.無償で制作します、続きがあるよ.下記の画像を拡大してみてくれると分かるかと思いますが、無償でWEBサービス制作する代わりに運営権はこちらにあり、広告掲載を行って収益化を図るというもの.

https://x.o0o0.jp

収益化出来なかった場合はデジタル販売出来るところに置いて売る.設置等は分かる人に置いてもらうことになると思うけども、こちらとしては利益を得る可能性があるということでビジネス的には赤字になるけど依頼していたユーザーは買う可能性があるのでペイ出来れば良いかなと思っています.

なぜ、こういうサイトを作ったかというとこの頃アイディアが前よりあまり出てこなくなったので、ユーザーさんからアイディアを頂いて作るという仕組みを作ったのだけど、今のところ誰からも要望はないです.

これが有名なひとだったら依頼が来るだろうけど無名なので当分は来ないだろうなって思っています.

明日へ続く

⏩️映画、新幹線大爆破を観ました.結論から言うと大画面で見るとめちゃ良い.

おはようございます.ネトフリで映画、新幹線大爆破を観ました.結論から言うと大画面で見るとめちゃ良い.とても迫力とスリルがあってとても良かったです.それだけでは終わらなくて内容も濃い、ネタバレにならないレベルで言えば犯人が予想外だった、やばー!

海外ウケするかどうかは分からないけど、日本ウケは間違ないだろうなって思いました.まさにシン・ゴジラ的なところがあって良かったです.

この新幹線大爆破は映画館で上映しないのかな、結構お客さん入りそうな気がします.これスマホとかで観るより間違いなく大画面で観るように作られた映画.

これから映画、新幹線大爆破を観ようと思っている人は映画館並みの大きさの画面で観ることをオススメします.

明日へ続く

⏩️404画像をそのまま残しておくとSEOに影響があるのでどうするか?#php

おはようございます.404画像をそのまま残しておくとSEOに影響があるのでどうするか?php の場合、下記のコードで404ページに飛んでいるかどうかの確認は出来る.でも毎回、確認しているとページを表示している時に遅延が発生してとても良い処理とは言えないなのでDBに画像あるなしが確認できるテーブルを作ります.

<?php
class HttpCodeChecker
{

    public function getHttpStatusCode(string $url): int|false
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_NOBODY, true);
        curl_exec($ch);

        if (curl_errno($ch)) {
            curl_close($ch);
            return false; // エラーがあった場合
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        return $httpCode;
    }
}

画像のステータス確認できるコードで定期的にページをクロールしてステータスをテーブルに保存(更新)することにより404画像によってSEOに影響を与えない作りになります.

他にも方法はあるけど、レンタルサーバーではこの方法がベストプラクティスな解なのかもしれない.クロールするのが出来ない場合は一度、画像URLをJsonデータで出力してフロントエンド側で画像有無を判断し存在するものだけを表示するという案もあるのだけども、今のSEO的にはあまりオススメはしない.

明日へ続く

⏩️Reactでパスワード生成にバグがあって数値、記号が確実に入らなかったので.

おはようございます.Reactでパスワード生成にバグがあって数値、記号が確実に入らなかったのでその修正を先日行いました.そういやそうだなってソースコードを見返して思った次第です...

修正したコードはこちらになります.その話とは別にVScodeにもAI補助が付いてから自分も生成AIと言う物を個人開発するときに使用するようになっただけど...

import RingLoader from "react-spinners/RingLoader";
import { useState } from "react";
import "./App.css";

function PasswordTmp() {
  const [passwordLength, setPasswordLength] = useState(8);
  const [password, setPassword] = useState("");
  const [includeSymbols, setIncludeSymbols] = useState(false);
  const [includeNumbers, setIncludeNumbers] = useState(false);

  function makePassword(passwordLength, includeSymbols, includeNumbers) {
    const lowercase = "abcdefghijklmnopqrstuvwxyz";
    const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const numbers = "0123456789";
    const symbols = "!@#$%^&*()_+[]{}|;:,.<>?";
    let characters = lowercase + uppercase; // 文字のセットを初期化
    if (includeNumbers) {
      characters += numbers; // 数字を追加
    }
    if (includeSymbols) {
      characters += symbols; // 記号を追加
    }
    let result = remakePassword(characters,includeNumbers,includeSymbols);
    setPassword(result);
  }

  function remakePassword(characters,includeNumbers,includeSymbols){
    let passwords = "";
    let NumbersChecking = true;
    let SymbolsChecking = true;
    for (let i = 0; i < passwordLength; i++) {
      const randomIndex = Math.floor(Math.random() * characters.length);
      passwords += characters[randomIndex]; // ランダムな文字を選択
    }
    if (includeNumbers) {
      NumbersChecking = passwords.match(/[0-9]/g) ? true : false;
    }
    if (includeSymbols) {
      SymbolsChecking = passwords.match(/[\!@#\$%\^&\*\(\)_\+\[\]\{\}\|;:\,\.<>\?]/g) ? true :false;
    }
    return NumbersChecking && SymbolsChecking?passwords:remakePassword(characters,includeNumbers,includeSymbols);
  }


  return (
    <>
      <div>
        <h1>パスワード生成</h1>
        <p>
          <input
            type="number"
            value={passwordLength}
            placeholder="パスワードの長さ"
            max={99}
            min={3}
            onChange={(e) => setPasswordLength(e.target.value)}
          />
        </p>
        <p>
          <input id={'Symbols'}
            type="checkbox"
            value={1}
            checked={includeSymbols}
            onChange={(e) => setIncludeSymbols(e.target.checked)}
          />
          <label for={'Symbols'}>記号を含める</label>
        </p>
        <p>
          <input id={'Numbers'}
            type="checkbox"
            value={1}
            checked={includeNumbers}
            onChange={(e) => setIncludeNumbers(e.target.checked)}
          />
          <label for={'Numbers'}>数字を含める</label>
        </p>
        <button
          className="btn"
          onClick={() =>
            makePassword(passwordLength, includeSymbols, includeNumbers)
          }
        >
          パスワードを生成
        </button>
        <button
          className="btn"
          onClick={() => navigator.clipboard.writeText(password)}
        >
          パスワードをコピー
        </button>
        <p>生成されたパスワード: {password}</p>
        <p>パスワードの長さ: {passwordLength}</p>
        <p>記号を含める: {includeSymbols ? "はい" : "いいえ"}</p>
        <p>数字を含める: {includeNumbers ? "はい" : "いいえ"}</p>
      </div>
    </>
  );
}

export default PasswordTmp;

この頃、補完機能がとても「うざったく」思う時と「ありがとう」と思うときが存在していてなんとも言えない.特にウザって思うときは自分が望んでいないコードが出てきた時は正直困る.コードを直打ちしないといけないので今までの補完機能がやはり良いなと思います.

自分としては生成AIの補完機能をOFFに出来る機能がほしいところ、それがあればとてもコードを書くのは快適ですねー.あるのかなぁー🤔調べてみます.

明日へ続く

⏩️右にしようか左にしようか、はたまた上にしようか.GW一人小旅

おはようございます.右にしようか左にしようか、はたまた上にしようか悩んでいる話を書いていきます.ゴールデンウィークが近づいてきましたので小旅でもしようかなと考えています.

まず、このブログでは恒例となったTシャツアート展に行く案、とくに気を使う必要もないのとどんな所か分かっているので行くには問題ないものの刺激が少ない.

次に土佐久礼にカツオを食べに行くという案、どうもそこに行くと元専門学校の教師に会えるかもというなんとも言えないオプションが付いてくる土佐久礼の案.こちらはそれなりに刺激もありそうですが気を使いそうな予感があり、尚且つ客引きにメンタル使いそうなので疲れそうな気がしています.

最後に直島や男島などに行くという案、これは県外なのだけども一度、一人旅で行ったことがあるちょっとした旅.今からでもそんなに混みそうではないのだけども電車で行くとなるとまぁまぁ旅費がかかる案.

番外編として旅には行かずGWはボケーっと天を仰いで過ごすという案があります.

さて、今年のGWはどうしようか迷っている🤔

明日へ続く

⏩️Reactの簡単なものなら今でも作れるのだけども.#簡単止まり.

おはようございます.Reactの簡単なものなら今でも作れるのだけども簡単止まりなところを1UPしたいなと思っています.Xにもポストしたんだけどパスワード生成出来るものをReactで作ったのでソースコードを公開しますね.

Reactは基本そのままだとさくらレンタルサーバーなどでは動かないだけど、viteというモノを使用してビルドするとJavascriptに変換されたソースコードが出力されるので、それをレンタルサーバーにファイルアップロードする事によりレンタルサーバーでも動くようになります.

Reactにviteというモノを導入するに当たってDockerにUbuntuかcentOSなどを構築してその中にNodeJsとApache2を入れて自分はビルドしたモノを確認しています.

普通はNodeJsでサーバー立ててそちらで確認するのが普通なんだと思うのだけど、それだとレンタルサーバーで動いているかどうかが分からないので自分はビルド後のdistフォルダを中をApacheと紐づけて確認している形です.

トイウコトデ、ソースコードとサイトのリンクを貼っときます.

import RingLoader from "react-spinners/RingLoader";
import { useState } from "react";
import "./App.css";

function PasswordTmp() {
  const [passwordLength, setPasswordLength] = useState(8);
  const [password, setPassword] = useState("");
  const [includeSymbols, setIncludeSymbols] = useState(false);
  const [includeNumbers, setIncludeNumbers] = useState(false);

  function makePassword(passwordLength, includeSymbols, includeNumbers) {
    const lowercase = "abcdefghijklmnopqrstuvwxyz";
    const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const numbers = "0123456789";
    const symbols = "!@#$%^&*()_+[]{}|;:,.<>?";
    let characters = lowercase + uppercase; // 文字のセットを初期化
    if (includeNumbers) {
      characters += numbers; // 数字を追加
    }
    if (includeSymbols) {
      characters += symbols; // 記号を追加
    }
    let passwords = "";
    for (let i = 0; i < passwordLength; i++) {
      const randomIndex = Math.floor(Math.random() * characters.length);
      passwords += characters[randomIndex]; // ランダムな文字を選択
    }
    setPassword(passwords); // パスワードを更新
  }

  return (
    <>
      <div>
        <h1>パスワード生成</h1>
        <p>
          <input
            type="number"
            value={passwordLength}
            placeholder="パスワードの長さ"
            max={99}
            min={3}
            onChange={(e) => setPasswordLength(e.target.value)}
          />
        </p>
        <p>
          <input id={'Symbols'}
            type="checkbox"
            value={1}
            checked={includeSymbols}
            onChange={(e) => setIncludeSymbols(e.target.checked)}
          />
          <label for={'Symbols'}>記号を含める</label>
        </p>
        <p>
          <input id={'Numbers'}
            type="checkbox"
            value={1}
            checked={includeNumbers}
            onChange={(e) => setIncludeNumbers(e.target.checked)}
          />
          <label for={'Numbers'}>数字を含める</label>
        </p>
        <button
          className="btn"
          onClick={() =>
            makePassword(passwordLength, includeSymbols, includeNumbers)
          }
        >
          パスワードを生成
        </button>
        <button
          className="btn"
          onClick={() => navigator.clipboard.writeText(password)}
        >
          パスワードをコピー
        </button>
        <p>生成されたパスワード: {password}</p>
        <p>パスワードの長さ: {passwordLength}</p>
        <p>記号を含める: {includeSymbols ? "はい" : "いいえ"}</p>
        <p>数字を含める: {includeNumbers ? "はい" : "いいえ"}</p>
      </div>
    </>
  );
}

export default PasswordTmp;

https://zxz.sakura.ne.jp

明日へ続く

⏩️動画を見て時代だなって思った瞬間.自分、時代って言葉を使いすぎw.

おはようございます.以前、少し書いたのですが教育の場ではデジタル機器を使用してきていますよね.もうこんな田舎でもノートパソコンやタブレットを小学校から使用しています.そんな子供達が大人になったとき、社会はどう変わるのだろうかとこの頃おもうことがあります.

あと20年後といえば自分は仕事を退職して年金暮らしているような年代になるのかと思うですが、その想像が全くというほど想像できない.20年になるまえに恐らく南海トラフ巨大地震も起きていて大きく日本も変わった社会になっているのではないだろうかと思っています.

多分だけど自分はあと20年後も働いているような気がします.その頃にはプログラマーという職ではなくAIの書いたコードを手直しする職として働いている可能性が高いですね.

10年後は何となく今の延長線上にある気がするのだけど、20年後は今の延長線上では予測できない社会になっていそうです.

100年時代と言われている今日(こんにち)ですが、自分たちが老人と言われる時代は老化を止められる時代にもなってくるのだというのが自分の見解です.もしかするとブレイクスルーが起こり老化を止めるどころか、細胞を若返ることが出来るかも知れない.

そういう時代を目にすることが出来ると思うとワクワクしかないですね.

明日へ続く

⏩️感覚的に伸びると思うひとは伸びてきたので多分.感覚を大事にしよう.

おはようございます.人材発掘にもAIを使用する時代になってきたけど感覚的にこの人は伸びそうだというのは未だに人間のほうが勝っていそうだと思います.AIに感情が生まれればそういうのも分かるようになるかもですが、まだまだ先の話だと思っています.

まず先日ポストした171はもうすでに伸びているだけども、今の段階でメジャーで活躍出来そうなレベルだと思います.このままインディーでは勿体ないなって言う感覚もあるだろうしコアな推しファンはメジャーで活躍してほしいという気持ちを持っている人はいると思います.自分はたまたま聞いてこれは伸びそうだと思いました.

次にkatawareの春よはとても良いリズム感であるなって思います.こういうのは当にセンスなんだと思う、また歌詞(詩)も良いですね.

最後にカイシューマッハーさん、YOUTUBEのおすすめでポッチとクリックした瞬間、この人のピアノ演奏は素晴らしいと思いました.やっぱ一流は素晴らしいなって只々思った瞬間でした.こういうのはロボットやAIにはまだまだ到達出来ない領域だと思います.

素人でも凄い人はいるけれどもやっぱ一流と言われる人とは差があると思います.こういうのをYOUTUBEで見つけれて世界に触れられるというのは、とても良い時代だなって思います.

明日へ続く