トップ 追記

Masa's blog

検索キーワード:

2026年03月01日 yt-dlpでダウンロードした字幕ファイルをChatGPTの助けを借りたpythonスクリプトで日本語に翻訳 [長年日記]

_ とある外国映画のフルサイズ動画をyt-dlpで取得。日本語字幕に対応していなかったのでChatGPTに相談したら、「あなたにはpythonスクリプトを使った方法をおすすめ...」とアドバイスされた。

_ youtubeからyt-dlpを使って動画と字幕ファイルをダウンロード

字幕でサポートされる言語を確認。

$ yt-dlp --list-subs 'https://www.youtube.com/... snip ...'

動画と字幕ファイルをダウンロード

$ yt-dlp --write-subs --sub-langs "en.*" --convert-subs srt 'https://www.youtube.com/... snip ...'

字幕ファイルが、動画ファイルと共に拡張子「srt」でダウンロードされる。

_ pythonからgoogle翻訳を呼び出して字幕ファイルを日本語に翻訳

作業ディレクトリを用意

$ mkdir srt_translate
$ cd srt_translate

pythonの仮想環境を準備

$ python3 -m venv venv

pythonの仮想環境を有効化

$ source venv/bin/activate

必要なモジュールをインストール

$ pip install pysrt deep-translator

インストールされたモジュールを確認

$ pip list
Package            Version
------------------ -----------
beautifulsoup4     4.14.3
certifi            2026.2.25
chardet            6.0.0.post1
charset-normalizer 3.4.4
deep-translator    1.11.4
idna               3.11
pip                26.0.1
pysrt              1.1.2
requests           2.32.5
soupsieve          2.8.3
typing_extensions  4.15.0
urllib3            2.6.3

翻訳pythonスクリプトを準備。ChatGPTいわく「netflixレベル」とのこと...

$ vi translate_netflix.py
# --- 必要なライブラリの読み込み ---

import pysrt                 # SRT字幕ファイルの読み込み・編集・保存用
import json                  # 翻訳結果をキャッシュとして保存するため
import os                    # ファイルの存在確認などのOS操作
import time                  # API連続アクセスを避けるための待機処理
from deep_translator import GoogleTranslator  # Google翻訳を利用するライブラリ


# --- 入出力ファイル設定 ---

INPUT_FILE = "input.srt"                # 英語字幕ファイル
OUTPUT_FILE = "output_netflix_ja.srt"   # 日本語字幕の出力先
CACHE_FILE = "cache.json"               # 翻訳結果を保存するキャッシュファイル


# --- 動作パラメータ(調整可能) ---

BATCH_SIZE = 40      # まとめて翻訳する字幕行数(大きいほど高速)
SLEEP_TIME = 1       # バッチごとに待機する秒数(API制限回避)

MAX_CHARS_PER_LINE = 15   # 1行あたり最大文字数(放送基準)
MAX_LINES = 2              # 字幕は最大2行まで
CHARS_PER_SECOND = 4       # 1秒あたり読める文字数(放送字幕の目安)


# --- 翻訳エンジン初期化(英語→日本語) ---

translator = GoogleTranslator(source='en', target='ja')


# --- キャッシュ読み込み ---
# 既に翻訳した文章は再翻訳しない(高速化+API負荷軽減)

if os.path.exists(CACHE_FILE):
    with open(CACHE_FILE, "r", encoding="utf-8") as f:
        cache = json.load(f)
else:
    cache = {}  # キャッシュが無ければ空辞書


# --- キャッシュ保存関数 ---
# 翻訳途中で止まっても再開できるよう、随時保存

def save_cache():
    with open(CACHE_FILE, "w", encoding="utf-8") as f:
        json.dump(cache, f, ensure_ascii=False)


# --- 字幕表示時間(秒)を計算する関数 ---
# SRTの開始時刻と終了時刻から表示秒数を求める

def duration_seconds(sub):
    return (sub.end.ordinal - sub.start.ordinal) / 1000.0


# --- 放送・配信レベルの字幕整形関数 ---
# ・口語化
# ・文字数制限
# ・最大2行
# ・読みやすい改行

def format_subtitle(text, max_chars):

    # --- 簡易口語化(字幕向けに簡潔に) ---
    text = text.replace("私は", "")
    text = text.replace("です。", "。")
    text = text.replace("ます。", "。")

    # --- 改行候補を作成(句読点ごと) ---
    parts = text.replace("、", "、\n").replace("。", "。\n").split("\n")

    lines = []

    # --- 各パートを最大文字数以内に分割 ---
    for part in parts:
        while len(part) > max_chars:
            lines.append(part[:max_chars])
            part = part[max_chars:]
        if part:
            lines.append(part)

    # --- 行数が多すぎる場合は2行にまとめる ---
    if len(lines) > MAX_LINES:
        half = len(lines) // 2
        lines = [
            "".join(lines[:half]),
            "".join(lines[half:])
        ]

    # 最大2行まで返す
    return "\n".join(lines[:MAX_LINES])


# --- SRTファイル読み込み ---

print("Loading...")
subs = pysrt.open(INPUT_FILE, encoding='utf-8')
total = len(subs)
print("Total:", total)


# --- バッチ処理用の一時領域 ---
batch = []          # 翻訳待ちテキスト
batch_index = []    # 元の字幕番号


# --- メイン処理ループ ---
for i, sub in enumerate(subs):

    # 改行をスペースに変換(翻訳エンジン対策)
    text = sub.text.replace("\n", " ")

    # --- 表示時間に応じた最大文字数を計算 ---
    duration = duration_seconds(sub)

    # 字幕全体で表示できる最大文字数
    max_chars_total = int(duration * CHARS_PER_SECOND)

    # 下限10文字、上限30文字(15×2行)
    max_chars_total = max(10, min(max_chars_total, MAX_CHARS_PER_LINE * MAX_LINES))

    # 1行あたりの文字数
    max_chars_per_line = max_chars_total // MAX_LINES


    # --- キャッシュにあれば翻訳せず使用 ---
    if text in cache:
        subs[i].text = format_subtitle(cache[text], max_chars_per_line)
        continue


    # --- バッチに追加 ---
    batch.append((text, max_chars_per_line))
    batch_index.append(i)


    # --- 一定数たまったらまとめて翻訳 ---
    if len(batch) >= BATCH_SIZE:

        # テキストを改行区切りで結合
        joined = "\n".join([b[0] for b in batch])

        try:
            # 一括翻訳(高速化)
            translated = translator.translate(joined)

            # 結果を行ごとに分割
            results = translated.split("\n")

            # 元の字幕に戻す
            for (src, maxc), idx, dst in zip(batch, batch_index, results):
                cache[src] = dst
                subs[idx].text = format_subtitle(dst, maxc)

            # キャッシュ保存
            save_cache()

            print(f"{i+1}/{total}")

        except Exception as e:
            print("Error:", e)

        # バッチをリセット
        batch = []
        batch_index = []

        # API負荷軽減
        time.sleep(SLEEP_TIME)


# --- 残りのバッチ処理 ---
if batch:
    joined = "\n".join([b[0] for b in batch])
    translated = translator.translate(joined)
    results = translated.split("\n")

    for (src, maxc), idx, dst in zip(batch, batch_index, results):
        cache[src] = dst
        subs[idx].text = format_subtitle(dst, maxc)

    save_cache()


# --- 日本語字幕として保存 ---
print("Saving...")
subs.save(OUTPUT_FILE, encoding='utf-8')
print("Done")

翻訳前の字幕ファイルを準備

$ cp ~/... snip .../ダウンロードした字幕ファイル.srt input.srt

翻訳スクリプトを実行

$ python translate_netflix.py

変換結果が「output_netflix_ja.srt」に出力される。

変換が途中で停止しても

  • cache.json に保存
  • 再実行すると未翻訳分だけ処理

とのこと。

python仮想環境の無効化

$ deactivate

_ ffmpegを使って動画に字幕ファイルを合成

$ ffmpeg -i ダウンロードした動画ファイル.mp4 -vf subtitles=output_netflix_ja.srt  字幕ファイル合成後の動画ファイル.mp4

翻訳された結果が直訳されたっぽい違和感のあるものだったので、さらにChatGPTに相談したところ、ローカルAI環境を構築する方法を提案してきた...こちらの話はまた後ほど。


2026年02月24日 PowershellでのCSVとXMLの扱い方 [長年日記]

_ PowershellでのCSVの扱い方

ヘッダーありCSVを表示

> Get-Content .\test_header.csv
name,email,tel,age
伊藤 太郎,taro@foo.org,090-1111-1111,23
伊藤 次郎,jiro@foo.org,090-2222-2222,22
伊藤 三郎,saburo@foo.org,090-3333-3333,22
伊藤 四郎,siro@foo.org,090-4444-4444,22
伊藤 五郎,goro@foo.org,090-5555-5555,20
伊藤 花子,hanako@foo.org,,9

ヘッダーありCSVをCSVオブジェクトとして取込み

> $csv = (Get-Content test_header.csv | ConvertFrom-Csv)
> $csv

name       email          tel           age
----       -----          ---           ---
伊藤 太郎 taro@foo.org   090-1111-1111 23
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 花子 hanako@foo.org               9

CSVオブジェクトから項目「name」「tel」を取り出し

> $csv | select-object name,tel

name       tel
----       ---
伊藤 太郎 090-1111-1111
伊藤 次郎 090-2222-2222
伊藤 三郎 090-3333-3333
伊藤 四郎 090-4444-4444
伊藤 五郎 090-5555-5555
伊藤 花子

CSVオブジェクトから先頭2行を取り出し

> $csv | select-object name,tel -first 2

name       tel
----       ---
伊藤 太郎 090-1111-1111
伊藤 次郎 090-2222-2222

CSVオブジェクトから最終2行を取り出し

> $csv | select-object name,email -last 2

name       email
----       -----
伊藤 五郎 goro@foo.org
伊藤 花子 hanako@foo.org

CSVオブジェクトから先頭2行をスキップして、そこから先頭1行取り出し

> $csv | select-object name,email -skip 2 -first 1

name       email
----       -----
伊藤 三郎 saburo@foo.org

CSVオブジェクトから「name」の末尾が「次郎」と「email」の先頭が「taro」の行を抽出

> $csv | where-object{$_.name -match "次郎$" -or $_.email -match "^taro"}

name       email        tel           age
----       -----        ---           ---
伊藤 太郎 taro@foo.org 090-1111-1111 23
伊藤 次郎 jiro@foo.org 090-2222-2222 22

CSVオブジェクトを「age」の昇順、「tel」の降順にソート⇒「age」の昇順にならない!?

> $csv | sort-object -property @{expression={$_.age}},@{expression={$_.tel};desc=$true}

name       email          tel           age
----       -----          ---           ---
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 太郎 taro@foo.org   090-1111-1111 23
伊藤 花子 hanako@foo.org               9

CSVオブジェクトを「age」の昇順、「tel」の降順にソート⇒今度はOK!

> $csv | sort-object -property @{expression={[decimal]$_.age}},@{expression={$_.tel};desc=$true}

name       email          tel           age
----       -----          ---           ---
伊藤 花子 hanako@foo.org               9
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 太郎 taro@foo.org   090-1111-1111 23

CSVオブジェクトをCSVに変換

> $csv | convertto-csv
!!TYPE System.Management.Automation.PSCustomObject
"name","email","tel","age"
"伊藤 太郎","taro@foo.org","090-1111-1111","23"
"伊藤 次郎","jiro@foo.org","090-2222-2222","22"
"伊藤 三郎","saburo@foo.org","090-3333-3333","22"
"伊藤 四郎","siro@foo.org","090-4444-4444","22"
"伊藤 五郎","goro@foo.org","090-5555-5555","20"
"伊藤 花子","hanako@foo.org","","9"

CSVオブジェクトをCSVに変換(「#TYPE System.Management.Automation.PSCustomObject」の行は省略)

> $csv | convertto-csv -NoTypeInformation
"name","email","tel","age"
"伊藤 太郎","taro@foo.org","090-1111-1111","23"
"伊藤 次郎","jiro@foo.org","090-2222-2222","22"
"伊藤 三郎","saburo@foo.org","090-3333-3333","22"
"伊藤 四郎","siro@foo.org","090-4444-4444","22"
"伊藤 五郎","goro@foo.org","090-5555-5555","20"
"伊藤 花子","hanako@foo.org","","9"

ヘッダーなしCSVを表示

> Get-Content .\test_noheader.csv
伊藤 太郎,taro@foo.org,090-1111-1111,23
伊藤 次郎,jiro@foo.org,090-2222-2222,22
伊藤 三郎,saburo@foo.org,090-3333-3333,22
伊藤 四郎,siro@foo.org,090-4444-4444,22
伊藤 五郎,goro@foo.org,090-5555-5555,20
伊藤 花子,hanako@foo.org,,9

ヘッダーなしCSVをCSVオブジェクトとして取込み⇒1行目がヘッダーとして認識されている!?

> $csv = (Get-Content test_noheader.csv | ConvertFrom-Csv)
> $csv

伊藤 太郎 taro@foo.org   090-1111-1111 23
---------- ------------   ------------- --
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 花子 hanako@foo.org               9

ヘッダーなしCSVをヘッダーを指定してCSVオブジェクトとして取込み⇒ヘッダーが正しく認識されている!

> $csv = (Get-Content test_noheader.csv | ConvertFrom-Csv -header @("name","email","tel","age"))
> $csv

name       email          tel           age
----       -----          ---           ---
伊藤 太郎 taro@foo.org   090-1111-1111 23
伊藤 次郎 jiro@foo.org   090-2222-2222 22
伊藤 三郎 saburo@foo.org 090-3333-3333 22
伊藤 四郎 siro@foo.org   090-4444-4444 22
伊藤 五郎 goro@foo.org   090-5555-5555 20
伊藤 花子 hanako@foo.org               9

_ PowershellでのXMLの扱い方

サンプルXML(test.xml)の表示

> Get-Content .\test.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <record id="1">
    <name version="1">伊藤 太郎</name>
    <email>ito-taro@foo.org</email>
    <tel>090-1234-1111</tel>
     <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>]]></detail>
  </record>
  <record id="2">
    <name version="1">伊藤 次郎</name>
    <email>ito-jiro@foo.org</email>
    <tel>090-1234-2222</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/02/02</birthday></root>]]></detail>
  </record>
  <record id="3">
    <name version="1">伊藤 三郎</name>
    <email>ito-saburo@foo.org</email>
    <tel>090-1234-3333</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>]]></detail>
  </record>
</root>

サンプルXML(test.xml)をXMLオブジェクト($xml1)に取込み

> [xml]$xml1 = Get-Content .\test.xml

XMLオブジェクトを表示

> $xml1

xml                            root
---                            ----
version="1.0" encoding="UTF-8" root

XMLオブジェクトのノード(xml)を表示

> $xml1.xml
version="1.0" encoding="UTF-8"

XMLオブジェクトのノード(root)を表示

> $xml1.root

record
------
{name, name, name}

XMLオブジェクトのノード(record)を表示

> $xml1.root.record

id     : 1
name   : name
email  : ito-taro@foo.org
tel    : 090-1234-1111
detail : detail

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

id     : 3
name   : name
email  : ito-saburo@foo.org
tel    : 090-1234-3333
detail : detail

XMLオブジェクトのノード(record)の2番目を表示

> $xml1.root.record[1]

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

XMLオブジェクトのノード(name)を表示

> $xml1.root.record.name

version #text
------- -----
1       伊藤 太郎
1       伊藤 次郎
1       伊藤 三郎

XMLオブジェクトのノード(name)の値を表示

> $xml1.root.record.name.'#text'
伊藤 太郎
伊藤 次郎
伊藤 三郎

XMLオブジェクトのノード(detail)を表示

> $xml1.root.record.detail

#cdata-section
--------------
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/02/02</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>

XMLオブジェクトのノード(detail)の値を表示

> $xml1.root.record.detail.'#cdata-section'
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/02/02</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>

XMLオブジェクトのノード(record)の属性(id)を表示

> $xml1.root.record.id
1
2
3

XMLオブジェクトのノード(record)を検索して表示

> $xml1.root.record | where-object{$_.name.'#text' -eq "伊藤 次郎"}

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

XMLオブジェクトのノード(record)から「伊藤 次郎」を検索して、「伊藤 花子」に変更

> $record1 = $xml1.root.record | where-object{$_.name.'#text' -eq "伊藤 次郎"}
> $record1.name.'#text' = "伊藤 花子"
> $xml1.root.record.name

version #text
------- -----
1       伊藤 太郎
1       伊藤 花子
1       伊藤 三郎

XMLオブジェクトのノード(record)から「伊藤 花子」を検索して、入れ子のXMLオブジェクト内のbirthdayを変更

> $record2 = $xml1.root.record | where-object{$_.name.'#text' -eq "伊藤 花子"}
> [xml]$xml2 = $record2.detail.'#cdata-section'
> $xml2.root.birthday = "2002/01/23"
> $record2.detail.'#cdata-section' = $xml2.outerXML
> $xml1.root.record.detail

#cdata-section
--------------
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2002/01/23</birthday></root>
<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>

「id」が「2」のnode(レコード)を指定して削除する

> $recordToRemove = $xml1.root.record | where-object{$_.id -eq "2"}
> $xml1.root.RemoveChild($recordToRemove)

id     : 2
name   : name
email  : ito-jiro@foo.org
tel    : 090-1234-2222
detail : detail

上記の削除結果を確認する

> $xml1.root.record

id     : 1
name   : name
email  : ito-taro@foo.org
tel    : 090-1234-1111
detail : detail

id     : 3
name   : name
email  : ito-saburo@foo.org
tel    : 090-1234-3333
detail : detail

ノード(record)を作成し、属性(id)に「4」をセットする

> $record = $xml1.CreateElement("record")
> $record.SetAttribute("id","4")
> $record

id
--
4

ノード(name)を作成し、属性(version)に「1」をセットし、値に「伊藤 四郎」をセットする

> $name = $xml1.CreateElement("name")
> $name.SetAttribute("version","1")
> $name.innerXML = "伊藤 四郎"
> $name

version #text
------- -----
1       伊藤 四郎

ノード(email)を作成し、値に「ito-siro@foo.org」をセットする

> $email = $xml1.CreateElement("email")
> $email.innerXML = "ito-siro@foo.org"
> $email

#text
-----
ito-siro@foo.org

ノード(tel)を作成し、値に「090-1234-4444」をセットする

> $tel = $xml1.CreateElement("tel")
> $tel.innerXML = "090-1234-4444"
> $tel

#text
-----
090-1234-4444

ノード(record)にノード(name)を追加する

> $record.AppendChild($name)

version #text
1       伊藤 四郎

ノード(record)にノード(email)を追加する

> $record.AppendChild($email)

#text
ito-siro@foo.org

ノード(record)にノード(tel)を追加する

> $record.AppendChild($tel)

#text
090-1234-4444

ノード(record)の内容を確認する

> $record

id name email                  tel
-- ---- -----                  ---
4  name ito-siro@foo.org 090-1234-4444

ノード(root)にノード(record)を追加する

> $xml1.root.AppendChild($record)

id name email                  tel
-- ---- -----                  ---
4  name ito-siro@foo.org 090-1234-4444

ノード(root)にノード(record)が追加されたことを確認する

> $xml1.root.record

id     : 1
name   : name
email  : ito-taro@foo.org
tel    : 090-1234-1111
detail : detail

id     : 3
name   : name
email  : ito-saburo@foo.org
tel    : 090-1234-3333
detail : detail

id    : 4
name  : name
email : ito-siro@foo.org
tel   : 090-1234-4444

いろいろ更新したXMLオブジェクトを「test2.xml」にセーブ

> $xml1.Save("$pwd/test2.xml")

更新したXML(test2.xml)を表示

> Get-Content .\test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <record id="1">
    <name version="1">伊藤 太郎</name>
    <email>ito-taro@foo.org</email>
    <tel>090-1234-1111</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2001/01/01</birthday></root>]]></detail>
  </record>
  <record id="3">
    <name version="1">伊藤 三郎</name>
    <email>ito-saburo@foo.org</email>
    <tel>090-1234-3333</tel>
    <detail><![CDATA[<?xml version="1.0" encoding="UTF-8"?><root><birthday>2003/03/03</birthday></root>]]></detail>
  </record>
  <record id="4">
    <name version="1">伊藤 四郎</name>
    <email>ito-siro@foo.org</email>
    <tel>090-1234-4444</tel>
  </record>
</root>

2025年06月22日 Slackware64-currentでsendmail-8.18.1のビルド失敗 [長年日記]

_ Slackware64-currentで

slackpkg -batch=on -default_answer=y upgrade-all

したところ、icu4c-76からicu4c-77にバージョンアップしたためsendmailが一部のライブラリを動的リンク出来なくなり起動しなくなった。

sendmailはextraパッケージから自分でビルドする必要があるので、いつも通りに行ってみると以下のエラーが出た。

vfscanf.c:249:30: error: assignment to ‘ULONGLONG_T (*)(const char *, char **, int)’ {aka ‘long long unsigned int (*)(const char *, char **, int)’} from incompatible pointer type ‘ULONGLONG_T (*)(void)’ {aka ‘long long unsigned int (*)(void)’} [-Wincompatible-pointer-types]
  249 |                         ccfn = (ULONGLONG_T (*)())sm_strtoll;
      |                              ^
vfscanf.c:327:30: error: assignment to ‘ULONGLONG_T (*)(const char *, char **, int)’ {aka ‘long long unsigned int (*)(const char *, char **, int)’} from incompatible pointer type ‘ULONGLONG_T (*)(void)’ {aka ‘long long unsigned int (*)(void)’} [-Wincompatible-pointer-types]
  327 |                         ccfn = (ULONGLONG_T (*)()) sm_strtoll;
      |                              ^

この手のエラーはコンパイラのバージョンが新しすぎてエラーチェックが厳しくなっているため、古めのソースだとよく出るやつ...

こんな時はLinuxQuestions.orgで尋ねるに限る。

あっという間(4時間程度)でレスが付き、パッチを3種類提供していただけました。

もちろんパチッを適用後はビルドがサックリ完了。ありがたや :)


2025年04月14日 Windows 11 Insider Preview 10.0.26120.3863 (ge_release_upr) インストールエラー 0xc1900209 [長年日記]

_ エラーコード 0xc1900209 は、Windows 11 Insider Preview のインストール中に互換性の問題が検出されたことを示しているらしい。これは通常、インストールを妨げているアプリケーションやドライバが原因とのこと。

インストールログを調べるには、以下のパスにあるログファイルを確認。

C:\$WINDOWS.~BT\Sources\Panther\CompatDataXXXX.xml

ログの抜粋。

<CompatibilityInfo BlockingType="Hard" Message="お使いの PC は、このバージョンの Windows ではまだサポートされていません。
Windows Updateは、問題が解決されると、このバージョンの Windows を自動的に提供します。
" Title="この PC をこのバージョンの Windows にアップグレードすることはできません。"/>
<DriverPackage Inf="oem58.inf" BlockMigration="True" HasSignedBinaries="False"/>
<DriverPackage Inf="oem57.inf" BlockMigration="True" HasSignedBinaries="False"/>

BlockMigration="True" かつ HasSignedBinaries="False" となっており、署名されていない or 不適切なドライバが移行をブロックしているもよう。

ドライバの情報を検索してみる。

pnputil /enum-drivers

一部を抜粋。

公開名:     oem57.inf
元の名前:      prnms009.inf
プロバイダー名:      Microsoft
クラス名:         Printer
クラス GUID:         {4d36e979-e325-11ce-bfc1-08002be10318}
クラス バージョン:      4.0
ドライバー バージョン:     06/21/2006 10.0.22621.1
署名者名:        Microsoft Windows

古いプリンタドライバ(?)らしい...

とりあえず削除してみる。

pnputil /delete-driver oem57.inf /uninstall /force
pnputil /delete-driver oem58.inf /uninstall /force

下記のエラーメッセージが出て削除できず。

ドライバー パッケージがアンインストールされました。
ドライバー パッケージを削除できませんでした: ひとつ以上のデバイスが現在、指定された INF を使用してインストールされています。

regeditで「oem57.inf」「oem58.inf」を検索し、全て削除。

以上の対応で、Windows 11 Insider Previewのインストールエラーが解消 d(^^)。


2025年04月13日 vmware上の仮想Windows11ProでMACアドレスの取得が不正になる場合の対応 [長年日記]

_ ホストOSがLinuxで、仮想OSがWindows11 Pro(192.168.0.10)で運用しているが、何故かWindows11 Proがゲートウェイ(192.168.0.100)のMACを動的に誤った値で取得してしまう。以下のコマンドで静的に登録することで対応。

PS C:\Windows\System32> arp -d 192.168.0.100; netsh interface ipv4 delete neighbors "Ethernet0" 192.168.0.100; netsh -c "interface ipv4" add neighbors "Ethernet0" 192.168.0.100 xx-yy-zz-47-e3-ec
OK

google検索だけでは埒があかなかったが、ChatGPTと会話を重ねることで解決!


2025年03月22日 xfce4-terminal内のメールアドレス文字列をCTLR+左クリックした時に起動するメーラの設定 [長年日記]

_ xfce4-terminal内のメールアドレスっぽい文字列をCTRL+左クリックするとemacsのデフォルトメーラが起動する。これをmewに変更したい。

_ メーラとして設定するスクリプト

$ cat ~/etc/mailer.sh
#! /bin/sh
#
# (mew-user-agent-compose "address1,address2," "subject")
#
xfce4-terminal -e "emacs -nw --eval \"(mew-user-agent-compose \\\"$1\\\" nil)\""

_ 設定コマンド

$ xfce4-mime-settings

上記のコマンドでGUIの設定ツールが起動する。

_ 設定ファイル

設定内容は以下のファイルに記録される。

$ cat ~/.local/share/xfce4/helpers/custom-MailReader.desktop
[Desktop Entry]
NoDisplay=true
Version=1.0
Encoding=UTF-8
Type=X-XFCE-Helper
X-XFCE-Category=MailReader
X-XFCE-CommandsWithParameter=mailer.sh "%s"
Icon=mailer.sh
Name=mailer.sh
X-XFCE-Commands=mailer.sh

以上


2025年02月24日 USB Sound Blaster Digital Music SX with Slackware [長年日記]

_ USB Sound Blaster Digital Music SX

USB Sound Blaster Digital Music SXという古いオーディオインターフェースを入手したのだが、ヘッドフォンから再生される音も、マイク端子からの音もバリバリとノイズまじりになる。pulseaudioのデフォルトサンプリングレートが44100Hzに対し、SXの方は48000Hzしか対応していないらしい。

そこで~/.config/pulse/daemon.confに以下を記述し、

default-sample-rate = 48000

pulseaudioを再起動すると改善される。

$ pulseaudio -k
$ pulseaudio --start --log-target=syslog

2025年02月20日 spf record for no-ip [長年日記]

_ spf record for no-ip

v=spf1 a:myh.no-ip.org include:hcn.zaq.ne.jp ~all

2025年02月11日 pulseaudioによる合成マイク作成 [長年日記]

_ pulseaudio環境でヘッドフォンから再生されている音声とマイク入力を合成して録音するために、仮想の合成マイクを作ってみた。

_ 仮想の出力デバイス(VOUT)を作成し、そこへの出力を取り込むためのデバイス(VOUT.monitor)に名称(MONITOR.VOUT)を設定する

$ pacmd load-module module-null-sink sink_name=VOUT
$ pacmd update-sink-proplist VOUT device.description=VOUT
$ pacmd update-source-proplist VOUT.monitor device.description=MONITOR.VOUT

_ VOUTに出力するためのソースを確認する

$ pacmd list-sources|egrep name:
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__HDMI3__sink.monitor>
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__HDMI2__sink.monitor>
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__HDMI1__sink.monitor>
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Headphones__sink.monitor>
name: <alsa_input.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Mic2__source>
name: <alsa_input.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Mic1__source>

_ VOUTにマイクの入力を接続する

$ pacmd load-module module-loopback source=alsa_input.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Mic1__source sink=VOUT

_ VOUTにヘッドフォンの再生音声を接続する

$ pacmd load-module module-loopback source=alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Headphones__sink.monitor sink=VOUT

_ 仮想のソース(VOUT.monitor)を確認する

$ pacmd list-sources|egrep name:
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__HDMI3__sink.monitor>
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__HDMI2__sink.monitor>
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__HDMI1__sink.monitor>
name: <alsa_output.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Headphones__sink.monitor>
name: <alsa_input.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Mic2__source>
name: <alsa_input.pci-0000_00_1f.3-platform-skl_hda_dsp_generic.HiFi__Mic1__source>
name: <VOUT.monitor>

_ ffmpegを使って録音してみる

$ ffmpeg -f pulse -i VOUT.monitor output.mp3

_ 仮想合成マイクを削除する

$ pacmd unload-module module-loopback
$ pacmd unload-module module-null-sink

2025年01月19日 Audacityの自分用メモ... [長年日記]

_ ホワイトノイズ除去

  • 無音部分を選択
  • エフェクト->ノイズ除去と修復->ノイズを低減->ノイズプロファイルを取得
  • 全選択
  • エフェクト->ノイズ除去と修復->ノイズを低減->[OK]
  • ファイル->オーディオをエクスポート

_ 音量のノーマライズ

  • 全選択
  • エフェクト->音量と音圧->ノーマライズ->適用

_ 表示拡大縮小

  • Ctrl-1 表示拡大
  • Ctrl-2 表示リセット
  • Ctrl-3 表示縮小

_ カーソル移動

  • 位置付:左右カーソルキーまたはクリック
  • トラックの先頭:J
  • トラックの末尾:K

_ 選択

  • 選択:Shift+左右カーソルキー
  • 全選択:Ctrl+A 又は 波形上をダブルクリック
  • 解除:Alt+S N

_ 選択範囲を再生範囲に設定&解除

  • 設定:Shift+L
  • 解除:Shift+Alt+L

_ ループ再生設定&解除

  • 設定&解除(トグル):L

_ 再生&停止

  • スペース(トグル)

_ 録音&停止

  • 選択トラックに追加:R
  • 新規トラック:Shift+R
  • 停止:スペース

_ 再生録音一時停止

  • P

_ 新規トラック追加

  • ステレオ:Alt+T N S
  • モノラル:Alt+T N M

_ 繰り返し

  • 選択
  • エフェクト->特殊->繰り返し->繰り返し回数の追加->適用