Windowsに入っている古くて使いづらいPowerShellをアップグレードするところから始める。
- Powershell 7.xを入れる
- PowerShellを管理者権限で起動
Set-ExecutionPolicy RemoteSignedを流す- hoge.ps1などの名前で適当にファイルを作り、
C:\Program Files\PowerShell\7\pwsh.exeに関連付けする
ミキサーが使えない場合に自分のマイク入力とPCからのスピーカー出力を両方取りたいときに使える方法。
確認環境
Windows 11環境下。
| Env | Ver |
|---|---|
| ffmpeg | 7.1.1-essentials_build-www.gyan.dev |
| Screen Capture Recorder | 0.13.3 |
事前セットアップ
Chocolateyはあるものとする。
- ffmpegのインストール
choco install ffmpeg - Screen Capture Recorderのインストール
GitHubのリリース一覧からインストーラーを拾ってきてインストールする
手順
- 録音するマイクを調べる
ffmpeg -list_devices true -f dshow -i dummy - 録音するマイクを指定して録音する(以下はマイク名が「マイク (Sound BlasterX G1)」であるケース)
ffmpeg -f dshow -i audio="マイク (Sound BlasterX G1)" -f dshow -i audio=virtual-audio-capturer -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map "[a]" output.mp3 - Qキーを押して終了する(Ctrl+Cだと保存されない)
おまけ
ps1ファイルをダブルクリックで実行できる環境を作っておき、以下の内容でrec.ps1みたいなものを作っておくと、ワンクリックで呼び出せる。
Write-Host "録音を開始する場合は何かキーを押してください…" -NoNewLine
[Console]::ReadKey($true) > $null
$input="マイク (Sound BlasterX G1)"
$filename=Get-Date -Format "yyyy-MM-dd_HH_mm_ss"
ffmpeg -f dshow -i audio=$input -f dshow -i audio=virtual-audio-capturer -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map "[a]" "$filename.mp3"
自動生成されたHTMLから社員情報を引っこ抜くスクリプトを作った時に考えたことを書き出してみる。ブラウザのDevToolsを使った簡易ツールを書いていて、頭に浮かんだことだ。データやコードは架空の内容なので実在しない。
ベースのHTML
大まかに最初に目に入ってきたのはこんな内容だった。機械生成されているせいかフォーマットがガタガタ気味だ。
<span class="Content">
<span id="undefined">SHAIN.XLS page1</span>
</span>
<span class="Content">
<br>
<span id="undefined">社員リスト</span>
<span id="undefined"></span>
</span>
<span class="Content">
<br>
<span id="hoge1">00001</span>
<span id="fuga1">:山菱喜一</span>
</span>
<span class="Content">
<br>
<span id="hoge2">00002</span>
<span id="fuga2">:鈴木与一</span>
</span>
<span class="Content">
<br>
<span id="hoge3">00011</span>
<span id="fuga3">:茨城妙子</span>
</span>
<span class="Content">
<span id="undefined">SHAIN.XLS</span>
<span id="undefined"> page2</span>
</span>
<span class="Content">
<br>
<span id="hoge4">00012</span>
<span id="fuga4">:奈良楓</span>
</span>
...
まずは関数ベースで考える
ひとまず普段は関数ベースで実装しているので関数ベースで実装する。書いていてgetEmployee(name, list)の仮引数にあるlistは冗長ではないかということに気づく。
const emp_list = document.getElementsByClassName('Content');
[...emp_list].reduce((acc, cur) => {
if (cur.id === 'undefined' || cur.children.length !== 3) {
return acc;
} else {
const id = cur.children[1].innerText;
const name = cur.children[2].innerText.replace(/^:/, '');
if (/^\d+$/.test(id)) {
acc.push({ id, name });
}
return acc;
}
}, []);
const getEmployee = (name, list) => {
const re = new RegExp(`.*${name}.*`);
const result = list.filter((emp) => re.test(emp));
console.log(result);
};
クラスにしてみる
そしてクラスにしたほうが素直にならないかと考え、クラスにしてみた。getEmployee(name, list)はsearch(name)となり、冗長性が減ったほか、抽象的な表現で分かりやすくなった気がする。
class EmployeeSearch {
constructor() {
const emp_list = document.getElementsByClassName('Content');
this.list = [...emp_list].reduce((acc, cur) => {
if (cur.id === 'undefined' || cur.children.length !== 3) {
return acc;
} else {
const id = cur.children[1].innerText;
const name = cur.children[2].innerText.replace(/^:/, '');
if (/^\d+$/.test(id)) {
acc.push({ id, name });
}
return acc;
}
}, []);
}
search(name) {
const re = new RegExp(`.*${name}.*`);
const result = this.list.filter((emp) => re.test(emp.name));
console.log(result);
}
}
追加仕様に合わせ関数を新設し、クラスを改良する
動作確認をしていく中で表示と名前が分かれたパターンを発見したので、これに合わせて直してゆく。
<span class="Content">
<br>
<span id="hoge2">00002</span>
<span id="fuga2">:飯田</span>
<span id="piyo2">太郎</span>
</span>
この対応をしようとすると分岐が必要だと考えたが、愚直にやってしまうとコンストラクタの中がごちゃつく上、テストもしづらいと考え、DOMをパースする処理を外部関数に切り出し、それを呼ぶことにした。
const getEmployeeFromList = (domList) => {
const id = domList[1].innerText;
const name1 = domList[2].innerText.replace(/^:/, '');
if (domList.length === 3) {
return {
id,
name: name1
}
} else {
const name2 = domList[3].innerText;
return {
id,
name: `${name1}${name2}`
}
}
};
class EmployeeSearch {
constructor() {
const emp_list = document.getElementsByClassName('Content');
this.list = [...emp_list].reduce((acc, cur) => {
if (cur.id === 'undefined' || cur.children.length < 3) {
return acc;
} else {
const { id, name } = getEmployeeFromList(cur.children);
if (/^\d+$/.test(id)) {
acc.push({ id, name });
}
return acc;
}
}, []);
}
search(name) {
const re = new RegExp(`.*${name}.*`);
const result = this.list.filter((emp) => re.test(emp.name));
console.log(result);
}
}
更により良くするには?
ブラウザのDevToolsにあるConsoleで書いたコードなので、現実問題テストコードも書かないし、そこまで凝る必要もないのが、よりよい設計にするにはコンストラクタでパースせず、事前にパース処理した結果をコンストラクタを通じて注入して処理するようにするとよいだろう。そうすると責務が分離され、テストがしやすく、コードもきれいになると考える。
クラスにするか、関数にするか
これはまだ正直答えが見えていないが、インスタンスを引き回す場合はクラスのほうが都合がいい可能性がある気がしてきている。
関数でもできるにはできるが、毎回引数にインスタンス相当のものを渡すのは冗長である可能性がある。疎結合という文脈では関数のほうがより良い可能性もあるが、人間の認知負荷や、保守性との兼ね合いだと思う。
明確な損益分岐点はまだ見えていないし、今回のケースだと割とどっちでもいい部分もあるとは思う。
キッチンペーパーホルダーと皿立てを買った。
まずここ数年、箱や袋型のキッチンペーパーを使っていたのだが、中身が減ってくると取り出しづらかったし、場所をとるので割と邪魔だった。そこでロール式に買い替えたのだが、そのままでは取り出しづらい問題があった。横置きにしていれば転がるし、縦置きにしていれば自転しないし、場所をとる問題も大きく改善しない。
というわけでダイソーでキッチンペーパーホルダーを買ってきた。これは戸棚や鴨居に引っ掛けられるフックを上下左右90度方向にはめ込むことが出来、いろんな方向に設置できる優れものだ。
分解しないと交換できない製品もある中、抜き差しだけで交換できる部分もよい。
配置の微妙さは否めないが、しばらく使ってみたい。
他には皿立ても買った。これもダイソー。
元々は重ね置きをしていたのだが、これだと取り出しづらく埃が溜まりやすい問題があったので、その辺りを改善できないかと買ってみた。皿を引っ張り出すときに皿置きがずれ落ちて皿が全滅する可能性を若干心配するが、奥に置いているのと、自重による摩擦抵抗がそこそこあるので大丈夫だと信じたい。
ただ深皿の配置が微妙なのと、汁椀を置いたところさらに微妙になったので、これは微妙かもしれない…。





