19日に更新してた

アフィリエイトはないよ

【python】旺文社 Target1900 のダウンロードコンテンツを分割してみた

旺文社 Target1900 のダウンロードコンテンツの音声は数単語ごとにまとまっているが、1単語ごとの音声ファイルが欲しい

Abceed で旺文社 Target1900 の単語単位の音声を復習が必要なものだけ聞けるようにしたかったが、機能がないのかどうもはかばかしくない*1。しかたがないので音声ダウンロードサービスを利用してみる。しかし、ダウンロードコンテンツの音声が数単語ごとにまとまっているので、全部をプレイリストに入れておいてわかるものから消していくという方法が使えない。

しかたがないので、分割しようと思います。

とりあえず、3.見出し語の意味→見出し語 を一括ダウンロードして win11 のデスクトップにおいてある設定です。

流行りに乗って AI を使ってみたいので Whisper を試してみる

最終的に ffmpeg を使うとして分割時間設定をどうするかと、「流行りに乗って AI や!」と Whisper を google colab で試してみる。
2言語混在しているとあまり精度が良くないとのことも、認識言語を日本語にするとそこそこ認識してくれるが、2単語分を一文扱いにしてくれたりする。認識言語を英語とかスペイン語とかにして試してみるも使えそうになかったので30分ぐらいいじって撤退。*2

Audacity で波形を見て、ffmpeg で全面的にやることに

www.audacityteam.org

波形見るのに Audacity を使ってダウンロードしたファイルを見てみると、単語ファイル間は1秒ほど空いている模様。ffmpeg で無音感知があると便利だなぁと検索してみると、silencedetect というオプションがありました。なので全面的にffmpeg 系でいくことに決定。

自動で全部やるのは自分の技術的に無理そうなので、ffplay で聞いて選り分ける

下に書いたコード以外にも silencedetect で stderr に出てきたのを正規表現で抜き出して、無音の最初と最後をリストにして zip 関数使って組み合わせて数数えてとかやっているのですが、大体下のに入っていたので割愛。

jupyter notebook 上で

import subprocess
import re
import os
from IPython.display import clear_output
import pickle

dirs=os.path.join(os.path.expanduser("~"),"Desktop","1900_3_all")
cwd=os.getcwd()
os.chdir(dirs)
s={}
dirlist=sorted([f for f in os.listdir(dirs) if f.endswith(".mp3")])

# cc=76

for n,f in enumerate(dirlist):
    
#     if n<cc:
#         continue
#     if n==cc:
#         s=pickle.load(open("./test.pkl","rb"))
    
    file=os.path.join(dirs,f)
    a=subprocess.run(f"ffmpeg -i {file} -af silencedetect=n=0.001:d=1:m=0 -vn -f null -", capture_output=True, text=True,encoding="utf-8")

    file_end=[float(f) for f in re.findall('silence_start: (\d+.\d+)\n',a.stderr)]
    file_start=[0]+[float(f) for f in re.findall('silence_end: (\d+.\d+)',a.stderr)]
    
    a,b,c=os.path.splitext(f)[0].rsplit("_",2)
        
    idealfiles = 1+int(c)-int(b)
    
    file_time=[(s,t) for s,t in zip(file_start,file_end)]
    if idealfiles==len(file_time):
        continue 
        
    checked=0

    for i,t in enumerate(file_time):
        print(f"{n} {i+1}/{checked}/{1+int(c)-int(b)}/{len(file_time)},{n}/{len(dirlist)}")
        if checked+(1+int(c)-int(b))==len(file_time):
            continue

        subprocess.run(f"ffplay -i {f} -ss {t[0]} -t {t[1]-t[0]+0.5}")
        aa=input("OKならEnter、問題ありなら文字入力後Enter")
        clear_output()
        if aa:
            s.setdefault(n,[]).append(i)
            checked+=1
    pickle.dump(s,open("./test.pkl","wb"))
    
    
os.chdir(cwd)
s

途中で休む対策に pickle 使って途中から始められるようにして*3、後から再度起動した場合に dirlist が pickle.dump 前と変わらないように内包表記使って endswith でなんとかしてます。
ファイルのはじめから音声部分まで1秒無音状態のファイルはなさそうなので file_start のリストの最初の0足して合わせてます。

表示をクリアしてわかりやすくしたり、ファイル名からそのファイル内の単語数を計算して、分割後のファイル数との差をチェックしたら後は飛ばすようにして、手間を惜しんでます。*4

そうして作った削除するファイルの Dictionary がこちら。

s={0: [0, 1, 2],
 2: [11],
 5: [2, 24],
 6: [0, 1],
 8: [12],
 11: [2, 24],
 12: [0, 1],
 14: [10],
 17: [2, 24],
 18: [0, 1],
 20: [10],
 23: [1, 22],
 24: [0, 1],
 26: [10],
 29: [2, 24],
 30: [0, 1],
 32: [11],
 34: [17],
 36: [0, 1],
 38: [11],
 41: [3, 25],
 42: [0, 1],
 44: [10],
 47: [0, 22],
 48: [0, 1, 2],
 50: [6],
 52: [10],
 53: [14],
 54: [0, 1],
 56: [7],
 58: [11],
 59: [15],
 60: [0, 1],
 62: [7],
 64: [11],
 65: [15],
 66: [0, 1],
 68: [8],
 70: [11],
 72: [0, 1],
 74: [9],
 76: [13],
 78: [0, 1],
 80: [9],
 82: [12],
 84: [0, 1],
 86: [8],
 88: [12],
 90: [0, 1, 2],
 92: [5],
 94: [5],
 95: [0, 1],
 97: [5],
 99: [5],
 100: [0, 1],
 102: [4],
 104: [5],
 105: [0, 1],
 107: [5],
 109: [5]}

なんで s なのかは今の僕にもわかりません。その場ののりです。
1989ファイルに分割されていたものを89減らすので数は合いました。

ここまでは前置きなので、次行きましょう。*5

外見だけは公式っぽく行きたいのでカバーアートとかタグとか

カバーアートは手持ちのファイルから抜いておきます。

#1900_3_allディレクトリ内で
ffmpeg -i TG1900_3_Sec01_0001_0014.mp3 cover.png

で、ffprobe も使ってこんなふうに。

s={0: [0, 1, 2],
 2: [11],
 5: [2, 24],
 6: [0, 1],
 8: [12],
 11: [2, 24],
 12: [0, 1],
 14: [10],
 17: [2, 24],
 18: [0, 1],
 20: [10],
 23: [1, 22],
 24: [0, 1],
 26: [10],
 29: [2, 24],
 30: [0, 1],
 32: [11],
 34: [17],
 36: [0, 1],
 38: [11],
 41: [3, 25],
 42: [0, 1],
 44: [10],
 47: [0, 22],
 48: [0, 1, 2],
 50: [6],
 52: [10],
 53: [14],
 54: [0, 1],
 56: [7],
 58: [11],
 59: [15],
 60: [0, 1],
 62: [7],
 64: [11],
 65: [15],
 66: [0, 1],
 68: [8],
 70: [11],
 72: [0, 1],
 74: [9],
 76: [13],
 78: [0, 1],
 80: [9],
 82: [12],
 84: [0, 1],
 86: [8],
 88: [12],
 90: [0, 1, 2],
 92: [5],
 94: [5],
 95: [0, 1],
 97: [5],
 99: [5],
 100: [0, 1],
 102: [4],
 104: [5],
 105: [0, 1],
 107: [5],
 109: [5]}

import subprocess
import re
import os
import time

dirs=os.path.join(os.path.expanduser("~"),"Desktop","1900_3_all")
pic=os.path.join(dirs,"cover.png")
out_dir_name="Target1900JE"
out_dir=os.path.join(dirs,out_dir_name)
cwd=os.getcwd()
os.chdir(dirs)
if not os.path.isdir(out_dir):
    os.mkdir(out_dir)
dirlist=sorted([f for f in os.listdir(dirs) if f.endswith(".mp3")])
j=1
for n,f in enumerate(dirlist):

    file=os.path.join(dirs,f)
    a=subprocess.run(f"ffmpeg -i {file} -af silencedetect=n=0.001:d=1:m=0 -vn -f null -", capture_output=True, text=True,encoding="utf-8")

    file_end=[float(f) for f in re.findall('silence_start: (\d+.\d+)\n',a.stderr)]
    file_start=[0]+[float(f) for f in re.findall('silence_end: (\d+.\d+)',a.stderr)]
    
    a,b,c=os.path.splitext(f)[0].rsplit("_",2)
        
    idealfiles = 1+int(c)-int(b)
    
    file_time=[(s,t) for s,t in zip(file_start,file_end)]
    
    gg=subprocess.run(f"ffprobe -i {file}", capture_output=True, text=True,encoding="utf-8")
    title0=re.findall("(Section \d+\D\d+\D+)", gg.stderr)[0]

    for i,t in enumerate(file_time):

        if n in s.keys():
            if i in s.get(n) :
                continue
        nums="_".join([a,str(j).zfill(4)])
        out_put_file=os.path.join(out_dir,nums+".mp3")
        
        title=title0+str(j)
        command=f'ffmpeg.exe -ss {t[0]} -t {t[1]-t[0]+0.5} -i {file} -i {pic} -map 0:a -map 1:v -c copy -disposition:1 attached_pic -id3v2_version 3 -map_metadata 0 -metadata title="{title}" -metadata track={j}  {out_put_file}'

        subprocess.run(command)
        j+=1
        time.sleep(0.1)
os.chdir(cwd)
print("終了")

後は勉強するだけ

おまけ

コチラで Target1900 の語彙リストを上げていただいています。

ukaru-eigo.com

ここの表をお借りしてきて、こんな感じで

import pandas as pd

url='https://ukaru-eigo.com/target-1900-word-list/'
df = pd.read_html(url)
words=df[0]["単語"].tolist()
jwords=[w.split(",")[0].split(";")[0].split("(⇔")[0].split("(≒")[0] for w in df[0]["意味"].tolist()]

tagtitle=[w0+" "+w1 for w0,w1 in zip(jwords,words)]
tagtitle

>>['を創り出す create',
>> '増加する increase',
>> 'を向上させる improve',
>> 以下略

ffmpeg の metadata の {title} を {tagtitle[j-1]} とでもしてやるとプレイヤータイトル表示が 'を創り出す create' などとなります。

copilot で作った"【python】旺文社ターゲット1900のダウンロードコンテンツを分割してみた。"の画像

*1:元々、本を買ったけれど覚えている、いないの管理が面倒なのでアプリを買おうと思い、セールに目を引かれてこちらを購入。公式だと1冊分だけだけれど買い切りで値段が安いみたい。そちらだとこの機能、あるのかも

*2:ここらへんは検索したら出てくるそのままなのでコードは省略。

*3:コメントアウトしている cc に再開したい n を入れる

*4:全部聞くつもりだったのですが、画面は流れる、数は多いで、途中で何やっているのかわからなくなって来たので追加した

*5: 上記の設定で調べるとダウンロードコンテンツの1,2,3は1989、4は1991で、全部聞いたわけではないのですが、減らす方のファイルは1,2,3ともこの Dictionary の中身で抽出できていたので、できているはず。

【golang】LINE Notify で1000文字を超えるものを分割送信するようにしてみた。

あまり長いものを送信していなかったので気にしていなかったのですが、どうも一送信の制限が1000文字らしいので対応してみました。*1

func line(message string) {
	accessToken := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
	message_limit := 1_000

	URL := "https://notify-api.line.me/api/notify"
	u, _ := url.ParseRequestURI(URL)
	c := &http.Client{}

	rune_message := []rune(message)
	repeat := len(rune_message)/message_limit + 1

	for i := 0; i < repeat; i++ {
		form := url.Values{}

		end := len(rune_message)
		if i+1 != repeat {
			end = message_limit * (i + 1)
		}
		rune_sliced_message := rune_message[message_limit*i : end]
		form.Add("message", string(rune_sliced_message))

		body := strings.NewReader(form.Encode())
		req, _ := http.NewRequest("POST", u.String(), body)
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Set("Authorization", "Bearer "+accessToken)

		c.Do(req)
	}

}
windows copilot で作った"【golang】LINE Notify で1000文字を超えるものを分割送信するようにしてみた。"の画像

*1:golang でアプリ化しているものに組み込んでいるので golang で。

今月のチラ裏

  • ELSA speak 起動画面が格好良くてアガる。
  • IT パスポートの合格証が送られてきた。合格証の日付が受験から約一ヶ月。経産大臣はどちらの署名だろうかと思っていたが、ギリギリ滑り込みみたいな西村大臣だった。
  • うま味調味料の使用の可否について度々燃えているの見て思うけれど、うま味調味料って単体だと使うの難しい。麺つゆとか、だし入りみそとか、味塩コショウとか、粉末だしだと楽に使えるので、うちではどうしてもそちらにしてしまう。単体で追加してうまく自然に使うにはなかなか量の加減がいるような気がするから、料理研究家が研究した内容を教えていただけるのはとてもありがたい。
  • utf-8 時代に外字はどうなっているのだろうかと思ったら、windows には外字エディタがまだあると検索で出てきたので起動してみた。作りたい字がある訳では無いけれど、なんかいいな。
  • abceed でターゲット1900を覚えているのですけれど、この単語帳ダウンロードコンテンツがあって英単語→日本語単語とか逆とかあるみたいなのですが、アプリではそういう機能がどこにあるかわからない。せっかく復習が必要なものがリストとして出てきているので、そのまま復習が必要なものだけを音声で聞いて覚えられたらいいのになと思うのでまた機能を探してみよう。
  • ターゲット1900の音声ファイルをダウンロードしてみたら、15単語くらいがくっついていて単語単位で使えなかったのでバラそうと画策。流行りに乗って AI 使おうと考え、whisper 使ったらタイムスタンプも付くらしいしいけるんじゃないかと思ったが、あんまりいい感じに出てこなかった。なかなか思い通りには行かないものです。また、何か考えてみよう。
  • ffmpeg の実行時の表示は stdout だと思っていたが、 stderr だった模様。
  • なろう小説じゃないけど英語アプリでトレーニングするとステータスの ENG が上がるという想定で、ELSA speak を毎日やって評価値の上下で一喜一憂している。夕食後のスマホポチポチの時間がいつの間にかそうなってた。
  • 「無職で引きこもってスマホゲーに課金しまくっているけれど、この先どうしよう」とか思っている方がもしここ読んでいるなら、スマホゲームのキャラのステータスじゃなくて、リアルの自分のステータス上げるために、自分の口使ってやる音ゲーノリで ELSA speak に限らず無料でお試しできる英語アプリいれて試しにやってみるのもいいのでは?ELSA speak だと単語や文法のコースもあるのだけれど、とりあえず置いておいても進められるし、発音とかイントネーションとかスコア化されるから音ゲーっぽい感じでできる。声出せる環境ならいつでもできるし同じ発音練習を延々とやっててもキレられる心配がないから試行錯誤も自由にできる。英語の発音記号別の開口量や舌の位置の色々な解説も動画やブログでも豊富にあって、ゲームのスコアだと白い目で見られるようなスコアでも英語のアプリだと違うと思うし、将来に繋げられる可能性が広がる。
  • パルワールドのネットワークエンジニアが一人でダウンなく150万人同時接続さばいているとのことで、何をどうやっているのか興味本位で知りたい所。
  • A4 ルーズリーフバインダー用に穴の空いた下敷きを探したけれど売ってなかったので、セリアで下敷きと一穴パンチを買ってきて穴を開けた。レーザー加工も考えたけれどレーザー加工機は持っていなし、レンタルも少し距離があるところにあるカインズで2500円かかることを考えると、ちょっと見た目が芳しくないけれど工具110円のほうがいいなと、失敗して工具だめにしても220円だし。できた代物は穴のあき方は不揃いではあるものの、とりあえず使用に耐える。手は痛いものの、30穴開けてもパンチも大丈夫そうだし、もう一枚くらい欲しいのでまた作ろう。
  • 適当にプログラム作って使って、「これ公開しようかな」と思って適当にコピペすると、それだけでは動かないコピペになっていたりするので申し訳ない。けどアクセスちょっと増えるのな。
  • copilot でも bard でも日本語の回文書いてと頼むとよくわからないのを返してくるけど、英語の回文を日本語訳していたらしい。訳しゃいいってものではないでしょ。
  • 草思社あたりが BellCurve*1の翻訳出さないかな。いまなら割と受け入れられそうに思うのだけれど。
  • abceed の教材に英語のハノンが出たけれど、やってみたい気持ちはあるものの手を出せるようになるのはまだまだ先だな。
  • アプリに機能がなさそうだったから、ターゲット1900 の音声ダウンロードファイルを分割したはいいけれど聞いていると眠くなって寝てしまう。寝たらあかんやん。
  • IPA chart の各国語版、日本語もあるでよ。本屋に行くと発音の本も色々出ていて、ELSA speak と使うなら発音記号からも調べられるものが欲しいけれどスマホアプリで発音練習する前提の IPA 的な発音本はないだろうから結局、この表を見ながら練習するのが一番ってなっちゃいそうだし、これ元に自分用の資料作るのがいいのかも。と言いつつ、良さそうな本をブックオフとかアマゾンマーケットプレイスで探していたり。
  • www.internationalphoneticassociation.org
  • 最近、あるサイトの ffmpeg 経由のダウンロードが上手く行かないなぁと思って検索してみたら、ffmpeg の -http_seekable 0 のオプションがないとエラーが出るという話が一昨年の5月くらいにあったみたい、知らなかった。バージョン上げてオプションつけたら大丈夫になった。人生あらゆるところでこんなもんなんやんなぁ。
  • 皇后陛下適応障害になったのは歯科矯正治療のせいだと言う説を聞いたことがあるが、最近、歯科矯正治療を受け始めた藤井八冠の成績でもって陰謀論かどうか判断する予定。
  • ダイソーの USB-C イヤホンを買ったのですが、ELSA speak と相性悪い。abceed とも相性悪いので英語アプリと相性悪いというか短い音声ファイルの頭の音が切れるので仕方がない。スマホ*2の性能のせいかもしれないけれど、bluetooth なら問題なかったので USB-C イヤホンの仕様のせいにしておこう、550円なので諦めがつくし他用途ならば問題ないし。
  • vison pro 52万円。最初の Macintosh が出た頃は100万超えだったらしいから、それに比べると安いのかな。
  • 7年くらい前の時点でマンションにサッシも入っていないような所が撮影現場。こんなのが今の中国中にいっぱいあるのだったら、かなりしんどいわな。最後の塔も送電線でも電波塔でもないっぽいから、負債が増すでしょうし。
  • www.youtube.com
  • ソースネクストで売っている Speak Premium 3年版が 34560円 → 25600円に、2月15日まで 25% off。インスタで本家の割引の広告が出ているタイミングなのだけれど、本家の割引の時はソースネクストでも安くなっているのだろうか。
  • ソースネクストの SpeakBuddy 1年版が 23800円→ 12800円に、2月17日まで 46% off。こちらは何に連動しているのだろうか。
  • go 1.22 で for 分の中での変数の扱いが変わって goroutine で即時関数とかに引数として入れなくても問題無くなったらしい。このエラー何回もやらかしたけれど、どこでもうるさく言われていることだったから重大問題引き起こしていたとは知らなかった。
  • 趣味的なものはうまく行かないときに惰性に近い感じになっても続けていると開けることがあるので、とりあえず続けておこうと思った。
  • Bard が Google Gemini に名前が変わってスマホアプリになったというのでインストールしに行ったら、"このアイテムはお住まいの国でご利用いただけません"だそうだ。 play.google.com
  • abceed で単語覚えるのは 100とか 200とかまとまった数の単語をクイズ形式で"もう一度"を使って、何回か繰り返して詰めていくのが一番効率良さそうな感じ。なので、バラした音声ファイル、あんまり使っていない。
  • しかし、abceed の target の熟語で、"A as well as B" みたいに A、Bが入っているのに、クイズ形式の選択肢にA、Bが入っているのは一つだけというのは、家人に勧めにくいのでなんとかして欲しいかと。
  • ELSA speak の発音練習の厳しさで慣れてしまったので、他のアプリの発音練習で「あ、ここ抜けた」というところが全く問題なく通っていくのが「ええのかこれ?」って感じになるけど、 ELSA speak で抜けた感があっても OK だと少し上達したのかな感が出てくる。
  • 自作ソフトの設定ファイルを適当にテキストで作ったけれど、toml あたりに変えようかと迷い中。自分用だからどうでもいいといえばいいのだけれど、きちんと考えておかないと後々面倒だよな、適当にいじくりまくって複雑になるし。Pkl 見て。
  • シーシャってなんやって調べたら水タバコか。イメージ的に大麻とか阿片窟っぽい。誘われたけど、頑張ってやめたタバコを吸いたくなるからあかんな。
copilotで作った中国中に誰も住んでないマンションがたくさんあって不況になってきているのはとてもしんどいだろうなと思っている日本人男性の画像

*1:Richard J. Herrnstein, Charles Murray

*2:イオンとかの wifi に繋いで Google 認証すると googleapis.com じゃなく googleapis.cn を経由する程度の中華 Android13

プロテインシェイカーボールの代わりに自作したステンレス針金のシェイカースプリング?

ホエイプロテインのお安いのを買って飲んでいると、ザバスプロテインシェイカーの蓋の縁に固まって溶けないことがよくある。

シェイカーボールを買おうかと思ったが、縁の部分にシェイカーボールは当たらなそうなので、縁に当たるように丸くに作ればいいかなと思い作ってみた。*1

どんな針金がいいか考えてみたが、歯医者で使うような針金なら害はないだろうとgoogle:歯科 針金 jisで検索して、sus304、sus316なら良さそうということでΦ1ミリ程度のステンレスの針金買ってきてΦ60㍉程度に丸めてみた。これくらいの太さでこれくらいの細工なら端の始末以外は素手でもなんとかなりました。*2
まず平面状の円にしてみたのですが、中で回転して縁に当たってくれなさそうだったのでらせん状、スプリング状2,3巻きで、長さも60~70㍉程度にしてみたら、とりあえず縁に当たるような感じになり、試用では縁に固まらなかったので使っていく予定。*3

windows copilot で作った"2,3巻のステンレス針金のシェイカースプリング"

*1:近所のドラッグストアでも手に入るのでザバスプロテインシェイカーは良い物だ

*2:端の始末をしっかりしないと洗うときに手を傷つけるのペンチとかは必要だと思います

*3:巻きを増やして、もっと長いほうが使い勝手がいいかもしれないし、100均でいいのが売っているのかもしれない。

令和5年12月下旬~令和6年1月中旬までの雑記

  • ここ数年、聞きもしないのに紅白と年末年始のNHKのニュースポッドキャストを録音保存しているのを今年もやらないとという意味不明な義務感が。
  • Bard についてなんかメールが来ていたのでまた試してみた。python 内包表記で fizzbuzz、一回間違えてたけど、指摘したらきちんと書いてきた。かなり賢くなってるし、bing より回答スピード速い気がする。以下回答のコード。
fizzbuzz_results = [
    "FizzBuzz" if n % 3 == 0 and n % 5 == 0 else "Fizz" if n % 3 == 0 else "Buzz" if n % 5 == 0 else n
    for n in range(1, 101)
]

print(fizzbuzz_results)

bard.google.com

  • Bing Chat も Bard もアナボリックステロイドについて聞くと答えられないと指示されているような回答なので、被害が出る可能性が高い内容については答えないようになっている模様。そのうち、そういうのが得意な裏モノが出てくるのだろう。
  • 数学の変換行列についてBing Chat と Bard に聞いてみたが、Bing Chat のほうが僕にはわかりやすく、目的に到達しやすかった。
  • ELSA speak 12月19日から31日まで premium 1年間が50%オフ。¥6990 だからオンライン英会話レッスンの一月分くらい。一日20円足らずなので、続けられるかどうかとサービスやめないかどうかが問題。
  • 星野ロミ氏の漫画村を作ろうが12月21日から開講。月額20500円。あれだけのもの作った方のオンラインプログラミング塾だから受けてみたい気もするが検討。

mmake.net

  • vividl で NHK の聞き逃しをダウンロードできるの知らなかった。自分の都道府県の radikoライブ配信もダウンロードできる。
  • ELSA speak 購入して始めてみているけれど、苦手な発音はとことん苦手。個別の発音だとなんとかなっても、単語として文章としてだと上手くいかない。スコアが上がったり下がったりしているので、右肩上がりの人はすごいなと感心する。
  • タワレコとか HMV とか寄る機会があったけれど、店によってはアイドル系以外はほとんど置いてない。
  • チンチンシタラナンダホラ

www.youtube.com

  • windows file recovery はじめて使ってみたけれど、検索キー次第なところがあるみたいで、初回は無理だったが何回かやったら復旧。どうなるかと思ったが良かった良かった。
  • kindleスマホの読み上げ機能で読んてくれるというのを試してみたら割といい。
  • ちょっとした機会があって聖書の創世記の触りだけ英語で読んでみたのだけれど、休息日って7日目だから曜日の enum で日曜始まりはダメなのでは?
  • abceed pro 1年 50% off、1月1日から14日まで。アプリの上に出てきた。英検とか toeic テストからだと、通常価格が出てくる。
  • 地震被害に合われた方にお見舞い申し上げます。亡くなられた方のご冥福をお祈りします。
  • bing ai で画像生成してみた。殺風景なブログだから、彩りにつけてみる。
bing ai で作った”スマートフォンで英語学習”画像
  • speak chatGPT を使った英会話アプリが初売り価格で最大70%オフだそうだけれど、今のところいっぱいいっぱいだし、こういう英会話アプリだと何をどういうふうに喋っていいかわからないからある程度型を手に入れてから。
  • windows copilot を windows の標準にするのはいいのだけれど、いつでも同じ程度に反応が返ってくるようにして欲しい。
  • のどかな世の中は豊かな物資と情報の伝達速度の遅さから成り立っていたのかも。
  • 能登半島の情勢とガソリン、電気の供給問題や交通手段を考えると、車はプラグインハイブリッドでガソリンでも電気でも動く方がいいのだろう。現状、トヨタ、三菱、マツダの三択か。全部お高めなのは仕方がない。
  • abceed で英単語、クイズ形式で4択はすごくいい。しかし、復習をどうやるのがいいのか。ノートに書き出してブツブツ覚える系だったのでスマホだけだと要領がよく分からなくて、5とか10ごとおぼえていく形を試してみることにした。
  • とりあえず、地震被害に合われた方になにかしたくても、僕にできることは募金くらいしかないので振り込む&小銭を募金箱に入れる。
  • マスコミの報道被害って虚偽広告を出されたわけだから、原状回復費用としては露出量の広告代金に比例するとかするととんでもない額になりそう。
  • golang を 1.21.6 にしてみる。

【golang】自機のグローバルIPが知りたかったので、5サイトほど巡るようにしてみた

自機のグローバル IP (IPv4)が知りたい状態がでてきていたので、qiita の記事を参考に引っ張っていました。参考にした記事はこちら。

qiita.com

しかし、こないだこの中のあるサイトから 503 と空の body が返ってきたのでちょっと数を回って来るようにいじってみました。golang で 部分だけ。

var body []byte
for _, url := range []string{"https://ipinfo.io/ip", "https://api.ipify.org/", "https://checkip.amazonaws.com/", "https://4.ident.me/", "http://ipaddr.show/"} {
	resp, err := http.Get(url)
	if err != nil || resp.StatusCode != 200 {
		resp.Body.Close()
		continue
	}
	defer resp.Body.Close()
	body, _ = io.ReadAll(resp.Body)
	break
}

// 5サイトともだめだった場合
if body == nil {
	body = []byte("IP didn't get")
}

とりあえず、エラー処理は適当ぶっこいてますがご勘弁を

bing ai "グローバルIPが知りたかったので、5サイトほど巡るようにしてみた、というブログタイトルに付ける画像を写実的にお願いします"で画像生成した画像

【Python】東証上場銘柄一覧を利用して効率的にYahoo!ファイナンスVIPクラブ CSVのダウンロードリストを作成する方法

python を使って Yahoo! ファイナンス VIP クラブの csv をダウンロードする方法を検索すると、それに関する記事がいくつかあるのですが、コード番号を range で総当りしているものが散見されます。存在しないコードを入力すると時間の無駄ですし、Yahoo! の方も無駄な資源を遣うことになります。

公表されているコードリストを入れてやれば無駄が少ないのではないか?ということで、日本取引所グループのサイトで東証上場銘柄一覧というものが毎月更新されています。それを、使ってコードのリストを作りましょう。

www.jpx.co.jp

ただ、東証上場銘柄一覧に出ているものが全て Yahoo! ファイナンスで情報公開されているかを python & jupyter-notebook で確認すると

import pandas as pd

data = pd.read_excel("https://www.jpx.co.jp/markets/statistics-equities/misc/tvdivq0000001vg2-att/data_j.xls")
data["市場・商品区分"].unique()

ででてくる

array(['プライム(内国株式)', 'ETF・ETN', 'スタンダード(内国株式)', 'グロース(内国株式)', 'PRO Market', 'プライム(外国株式)', 'REIT・ベンチャーファンド・カントリーファンド・インフラファンド', 'スタンダード(外国株式)', 'グロース(外国株式)', '出資証券'], dtype=object)

を一つづつエクセルでもダウンロードしておいた上記エクセルに検索をかけ、最初に当たった部分のコード番号を Yahoo!ファイナンスで検索すると、上のリストのうち 'PRO Market' だけは検索しても情報が出てきませんので、

import pandas as pd

data = pd.read_excel("https://www.jpx.co.jp/markets/statistics-equities/misc/tvdivq0000001vg2-att/data_j.xls")
code = data[data["市場・商品区分"]!='PRO Market']["コード"].tolist()

くらいでコードを選んで code を for 文で回してやると、エラー率がかなり下がり、ダウンロード時間も短縮できると思います。