DaVinci Resolve 字幕をテキストファイルからスクリプトで追加する

前置き DaVinci Resolveで動画編集する際に、字幕の入力が面倒だった。字幕を1かたまり作成する時に以下の作業が必要になる。 Text+オブジェクトを配置 文字を設定 フォントを設定 サイズを設定 タイムライン上の位置、長さの設定 最後の項目は自動化が難しいが、他は自動化できないか調べたら、どうやらスクリプト機能で実現できるようだったので調べた。以下はその備忘録。 使用環境 Windows 11 DaVinci Resolve 20.2.1 Python 3.13.7 参考資料 C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting\README.txt が一次資料らしいのでそれを読んでいく。 LuaかPythonで書けるらしい。Luaであればインタプリタの導入は必要ないし、試しにLuaで書こうと思ったが、Luaの場合いまいちモジュール名がREADMEには書かれておらず不明瞭な点と、Pythonのほうが書き慣れているということでPythonを選択する。 またText+に関してはFusionの機能であり、Fusion関連であれば詳細なドキュメントがある。 Fusion8 Scripting Guide Pythonの導入 自分のWindows環境にはこの時点でPythonが入っていなかったため、Pythonを入れる。 https://www.python.org/ からインストーラをDLして来ればよい。 READMEには以下の変数を設定しろと書いてある。内容的にPythonのモジュールパス関連の設定のようだ。 1 2 3 RESOLVE_SCRIPT_API="%PROGRAMDATA%\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting" RESOLVE_SCRIPT_LIB="C:\Program Files\Blackmagic Design\DaVinci Resolve\fusionscript.dll" PYTHONPATH="%PYTHONPATH%;%RESOLVE_SCRIPT_API%\Modules\" GUIの場合はシステム環境変数の設定画面から環境変数を設定すればよいが、PowerShellの場合は以下のコマンドでシステム環境変数を追加できる(管理者権限で実行すること)。 1 2 3 4 5 6 7 $env:RESOLVE_SCRIPT_API="$env:PROGRAMDATA\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting" $env:RESOLVE_SCRIPT_LIB="C:\Program Files\Blackmagic Design\DaVinci Resolve\fusionscript.dll" $env:PYTHONPATH="$env:PYTHONPATH;$env:RESOLVE_SCRIPT_API\Modules\" [Environment]::SetEnvironmentVariable("RESOLVE_SCRIPT_API", "$env:RESOLVE_SCRIPT_API", 'Machine') [Environment]::SetEnvironmentVariable("RESOLVE_SCRIPT_LIB", "$env:RESOLVE_SCRIPT_LIB", 'Machine') [Environment]::SetEnvironmentVariable("PYTHONPATH", "$env:PYTHONPATH", 'Machine') これでDaVinci Resolveのコンソールから、関連モジュールがimportできるようになる。 下記redditによると、DaVinciのコンソールからならimport文は不要らしい。 https://www.reddit.com/r/davinciresolve/comments/1frb4lj/save_me_please_from_this_modulenotfound_error/?tl=ja コンソール画面を開く Workspace → Console を押す。 ...

2025-10-13 · (updated 2025-10-13) · 2 min · 257 words

FastAPIとOAuth2でユーザログイン機能(備忘録)

何をするか 以下の3つの機能を実装する。 ユーザを作成する。 ユーザを認証してトークンを生成し返す。 ユーザがログインしていないと401を返す:ここでは「ユーザ情報を返すAPI」を作成。 ユーザがログインしているかどうかで異なるレスポンスを返す:ここでは「ログインしているかどうかを真偽値で返すAPI」を作成。 方針 使う技術・フレームワーク、ライブラリなど PythonとMySQLはDocker Composeで動かす。 PythonのパッケージはPoetryで管理する。 APIサーバーはFastAPI + uvicornで動かす。 認可の方式としてOAuth2.0を用いる。認可グラントのタイプはシンプルなROPC。 なぜこれを選んだのかというと、単純にFastAPIのドキュメントに書かれていたのがこれだったため。いつかほかのタイプも実装してみたい。 DBのマイグレーションはalbemicを使用してみる。今回はユーザ情報しか作らないので、alembicの使用は間違いなくオーバーなのだが、勉強のため使ってみる。 プロジェクト構成 プロジェクトディレクトリは次のようにする。 DBに関するCRUDs処理はcrudsモジュールに書く。 DBと対応するモデルはmodelモジュールに書く。 APIのリクエストボディ、レスポンスボディの形式はschemas.pyに書く。 DBのセッションの作成はdb.pyに書く。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 . ├── api │ ├── cruds │ │ ├── __init__.py │ │ └── user.py │ ├── models │ │ ├── __init__.py │ │ └── user.py │ ├── routers │ │ ├── __init__.py │ │ └── auth.py │ ├── schemas │ │ ├── __init__.py │ │ └── user.py │ ├── db.py │ ├── main.py │ └── migrate_db.py ├── Dockerfile ├── docker-compose.yaml ├── poetry.lock └── pyproject.toml ちなみにこの図はtree -I __pycache__ --dirsfirsで生成。 ...

2023-06-29 · (updated 2023-06-30) · 7 min · 1388 words

Alembicを使ったDBマイグレーション(備忘録)

経緯 Alembicというライブラリを知ったので、試しに触ってみたメモ。 そもそもAlembicとは Alembicとは、DBマイグレーションライブラリの1つ。SQLAlchemyと一緒に用いる。 今回やってみること 今回行うマイグレーションは、以下の3つ。 空 User(email, password)を作成 User(email, password, name)に変更 使い方 Alembicの初期化 使うDBとの紐づけ エンティティ作成 マイグレーションファイルを作成 マイグレーション 想定する状況と準備 FastAPI上でWeb APIを提供し、その中でDBを操作することを想定する。ただし、メインテーマがマイグレーションのため、この記事でFastAPIの話は一切出ない。プロジェクト作成について、詳しくはFastAPI入門を参照するとよい。この記事では、ディレクトリ構成を大きく参考にしている。 パッケージ管理にはpoetryを使う。 DBにはMySQLを使う。 マイグレーションは同期処理で行うため、入れるのはPyMySQLだけでよい。しかしFastAPIでDBを処理するときに非同期での操作を行うことを見越し、aiomysqlを入れる。この時点でPyMySQLも入る。 1 poetry add sqlalchemy alembic aiomysql alembicの初期化 次のコマンドを実行する。 1 poetry run alembic init alembic プロジェクト配下にalembic/というディレクトリが生成される。 使うDBとの紐づけ alembic.iniを編集する。sqlalchemy.urlの記述を見つけたら以下のようにする。 1 sqlalchemy.url = mysql+pymysql://<url>/<name>?charset=utf8 <url>と<name>にはそれぞれ、mysqlのサーバーのURLとそのDBの名前を指定する。例えばmysqlがdbというDocker Composeのサービスとして稼働しており、3306ポートで受け付けており、そのDBの名前がappdbだった場合、次のようになる。 1 sqlalchemy.url = mysql+pymysql://root@db:3306/appdb?charset=utf8 api/db.pyにDBエンティティのベースを作っておく。 1 2 3 from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() alembic/env.pyのtarget_metadataを以下のようにする。 1 2 3 from api.db import Base target_metadata = Base.metadata 空のマイグレーション まだエンティティを作成していない状態でマイグレーションを行ってみる。 マイグレーション用のファイル作成 以下でマイグレーション用のファイルを作成する ...

2023-06-20 · (updated 2023-06-25) · 3 min · 588 words

Pythonを使った(静的)ページの画像のURL取得

Webページの画像だけを手っ取り早く取得したい場合にどうすれば良いのかを考えた。 これを行うプログラムをPythonで取得する。 この記事で作成したプログラムはGitHubのRepositoryに公開した。 前提 Pythonのバージョンは3.10を想定。 この記事では外部ライブラリとして Requests 2.26.0 Beautiful Soup 4.10.0 tqdm 4.62.3 w3lib 1.22.0 を使う。この記事のコードを動かす場合はpipコマンドなどでインストールしておく。 方針 やることは案外単純である。 WebページのHTMLデータを取ってくる。 img要素を探して、そのsrc属性を取ってくる。 scheme、netlocが無かったらそれを付加して、完全なURLにする。 1はRequests、2はBeautiful Soupを使えば良いだろう。 3は思ったより複雑である。src属性に入っているパスには、 URL: http://foo.org/bar/hoge.png スキームが省略されている: //foo.org/bar/hoge.png 絶対パス: /bar/hoge.png 相対パス: ../bar/hoge.png データURL: data:image/png;base64,... など色々ある。 これらのフォーマットを統一して完全なURLにするのは面倒であるが、幸運にもurllib.parse.urljoinという関数があったのでこれを使う (余談: 初め、urljoinの存在を知らずに自前でURLの変換機能を実装してしまった。学びにはなったが時間を費やした…)。 ついでの機能として、「特定の要素の中に含まれているimg要素のURLを取得する」ことも考える。 これはCSSセレクタとして指定できるようにする。 まとめると、画像のURLを取得する関数は以下のようなインターフェースとなる。 1 2 def get_img_urls(url: str, selector: Optional[str]=None) -> list[str]: pass # これから実装する URLとセレクタを引数にとり、img要素のURLのリストを返す関数である。 ついでに画像ダウンロードのためのCLIや、画像を閲覧するWebアプリなどが作れたら良い。 プロジェクトの構造 Pythonでモジュールを作ったことがないため、正しい作り方が分からないが、とりあえず以下のような構成にしてみる。 細かいディレクトリの構成は各節で述べる。 1 2 3 4 5 6 7 8 9 10 11 12 /project | +--+ getimg/ | +--+ commandline/ | +--+ viewer/ | +--+ tests/ +-- __init__.py +-- test_getimg.py +-- test_commandline.py CLI CLIの書式は以下のようにする。取得したい画像のあるページのURL、及び画像のダウンロード先を指定する。 ...

2021-12-09 · (updated 2021-12-16) · 8 min · 1516 words

PythonとFlask(+α)で作るToDoリストAPI

シンプルなToDoリストのWeb APIを作る。 今までWSGIの仕様のみ、Werkzeug の2通りで実装したが、今回はFlaskといくつかのライブラリを使う。使うのは以下の通り。 Flask: WSGIアプリフレームワーク。 peewee: ORMライブラリ。 marshmallow: データの変換やvalidationをするためのライブラリ。 Flaskとは WSGIのWebアプリを作るためのフレームワーク。 フレームワークであるため、Flaskが用意した作法に従ってコードを書くことで比較的手軽にWebアプリが作成できる。 前回との比較でいうならば、例えばルーティングの仕組みをプログラマが書く必要はない。これはFlaskに備わっている。 Djangoのようなフレームワークとは違って、持っている機能は少ない。必要に応じて外部ライブラリを組み合わせる。 例えば、Djangoではデフォルトでデータベースの仕組みが内蔵されているが、Flaskにはない。その代わりに、 データベースのライブラリとしてsqlite3やSQLAlchemy、peeweeなど、好きなものを用いれば良い。 ToDoリストAPIの仕様 今回ToDoのデータは以下キーと値を持つJSONデータとする。 key value id ID content ToDoの内容 created_at 作成日時 (ISO8601) updated_at 更新日時 (ISO8601) APIの仕様は以下の通り。 URL Method 説明 返却値 /todo/ GET 全てのToDoを取得。 ToDoのデータのリスト /todo/ POST ToDoを作成。 なし (LocationヘッダにそのToDoへのURLを乗せる) /todo/<todo_id> GET todo_idのidを持つToDoを取得。 ToDoのデータ /todo/<todo_id> PUT todo_idのidを持つToDoを変更。 なし /todo/<todo_id> DELETE todo_idのidを持つToDoを削除 なし データはSQLiteで管理する。 雛形 todo_listディレクトリを作成。todo_list/__init__.pyを以下のようにする。 1 2 3 4 5 6 7 8 9 10 11 from flask import Flask def create_app(): app = Flask(__name__) @app.route('/') def hello(): return 'Hello, World' return app exportコマンドで環境変数を設定する。 ...

2021-06-03 · (updated 2021-06-04) · 7 min · 1404 words

PythonとWerkzeugで作るToDoリストAPI

シンプルなToDoリストのWeb APIを作る。 前回はWSGIの仕様のみを参考にして作ったが、 今回はWerkzeugというライブラリを利用する。 Werkzeugとは Werkzeugのドキュメントの “Werkzeug is a comprehensive WSGI web application library.“という文面にもある通り、 これはWSGIのWebアプリを作るためのライブラリである。 あくまでフレームワークではなく、ライブラリであることに注意する。 Webアプリを作るうえで、便利なクラスや関数が用意された「道具箱」のようなイメージを持つとよいかもしれない (そもそも"werkzeug"という単語はドイツ語で「道具」という意味)。 あくまで道具があるだけなので、どういう設計を行うかなどを考える余地がある。 ToDoリストAPIの仕様 前回と同じだが、再掲する。 簡単のため、今回ToDoのデータはidと内容のみ持つデータとし、{ id: 0, "content": "やること" }というJSON形式とする。 APIの仕様は以下の通り。 URL Method 説明 返却値 /todo/ GET 全てのToDoを取得。 ToDoのデータのリスト /todo/ POST ToDoを作成。 なし (LocationヘッダにそのToDoへのURLを乗せる) /todo/<todo_id> GET todo_idのidを持つToDoを取得。 ToDoのデータ /todo/<todo_id> PUT todo_idのidを持つToDoを変更。 なし /todo/<todo_id> DELETE todo_idのidを持つToDoを削除 なし データは最終的にはSQLiteで管理する。 雛形 app.pyを以下のようにする。 1 2 3 4 5 6 7 8 9 10 11 from werkzeug.wrappers import Response def app(env, start_response): response = Response('Hello, World') return response(env, start_response) if __name__ == '__main__': from werkzeug.serving import run_simple run_simple('127.0.0.1', 5000, app, use_debugger=True, use_reloader=True) 以降、サーバーを起動する際はpython3 app.pyを実行する。 ...

2021-05-30 · (updated 2021-06-04) · 7 min · 1449 words

PythonとWSGIで作るToDoリストAPI

シンプルなToDoリストを作る。 今回は勉強のため、Webアプリケーションフレームワークは使わずに、 敢えてWSGIの仕様のみ参考にして書く. WSGIとは WSGIとは、WebサーバーとWebアプリとの間の標準的なインターフェース。 WSGIの仕様に沿ってWebアプリを作れば、 WSGI対応のどんなWebサーバーとも連携することができる。 WSGIの仕様はPEP3333に書かれている. ToDoリストAPIの仕様 簡単のため、今回ToDoのデータはidと内容のみ持つデータとし、{ id: 0, "content": "やること" }というJSON形式とする。 APIの仕様は以下の通り。 URL Method 説明 返却値 /todo/ GET 全てのToDoを取得。 ToDoのデータのリスト /todo/ POST ToDoを作成。 なし (LocationヘッダにそのToDoへのURLを乗せる) /todo/<todo_id> GET todo_idのidを持つToDoを取得。 ToDoのデータ /todo/<todo_id> PUT todo_idのidを持つToDoを変更。 なし /todo/<todo_id> DELETE todo_idのidを持つToDoを削除 なし データは最終的にはSQLiteで保存するが、最初は単純にlistで扱う。 雛形 まずはサーバーを作る。この時点ではルーティング処理を書いていない。 どのようなリクエストをしてもHello, Worldをレスポンスとして返す。 1 2 3 4 5 6 7 8 9 10 11 from wsgiref.simple_server import make_server def app(env, start_response): start_response('200 OK', [('Content-type', 'text/plain; charset=utf-8')]) return [b'Hello, World.'] if __name__ == '__main__': httpd = make_server('', 5000, app) httpd.serve_forever() 以降、サーバーを起動する際はpython3 app.pyを実行する。 ...

2021-05-29 · (updated 2021-06-04) · 8 min · 1499 words

Socket通信勉強(3) - 簡易HTTPサーバー作成

1年以上前に書いた記事 で、HTTPサーバーもどき(リクエストを読まず、ただ一方的にレスポンスを返すだけのサーバ)を書いた。 今回はもう少しだけこれを進化させる。 動機 非常にどうでもいいのだが動機を記しておく。 Land of Lispの13章でソケット通信が出てきた。 Land of Lispで扱っているCommon Lispの処理系がCLISPなのに対し、今自分が利用しているのはSBCLなので、 本文中のコードが動かない。そこで色々調べて、usocketを利用しようと思いつく。 その後なんとか書き上げる。ところがChromeやcurlでは動くのに、Safari(現バージョンは14.0.2)では動かない。ページを読み込んだ後、タイムアウトしたかのような挙動を起こす。 その理由を明らかにしたくて「そもそもLisp以外では動くのか。例えばPythonのソケット通信では動くのか」「PythonのWebアプリ、例えばFlaskの開発用サーバーで動くのはなぜか」 など色々調べた。cpythonのsocketserverやhttp.serverなどのソースコードも読んだ。 調べた結果、どうやらSafariがたまに「何も送らない通信(?)」を行うことが原因だった。 何も送ってくれないと、リクエストをrecvで受け取るときに、ブロッキングが働いてサーバー側が固まってしまう。 ただし普通のリクエストも送ってくるので、マルチスレッドなどの多重化を行なっておけば 問題なくSafariでもページが読み込まれる。なのでFlaskの開発用サーバーでは大した問題にならなかった。 Safariがなぜこんな通信をするのかはよく分からない。HTTPの仕様をちゃんと読んでいないので、何か見落としがあるのだろうか。もしくはバグか何かなのか。 何はともあれ、色々ソースコードを読んでいくうちに、リクエストヘッダの取得のやり方など参考になった。 せっかくなのて得た知見を元に再びHTTPサーバを作ってみようと思い立った。 作るもの 以下の条件を満たすHTTPサーバのようなものを作る(そもそも、どこまで実装できたらHTTPサーバと呼べるのだろうか)。 マルチスレッドにする。 HTTPリクエストのリクエストライン、ヘッダ情報をパースする。 リクエストボディは今回は考慮しない。 前回に比べてPythonについての知見が広がったため、 コードにおいてf-stringsやtype-annotation、dataclassなどの機能を使ってみている。 また処理を細かく関数に分ける。 listen用のソケットの作成 待ち受け用のソケットを作成し、それを返す関数を作成する。 bindやlistenは前回説明した通り。 動作確認を何度も行う都合上、TIME_WAIT状態のポートを待つのは面倒なので、setsockopt(...)の記述でそれを解決している。 (この辺りの詳細は"TIME_WAIT"とか"REUSEADDR"あたりのキーワードで検索すれば出てくる) 1 2 3 4 5 6 7 8 9 import socket def server_socket(port: int): soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) soc.bind(('', port)) soc.listen(5) return soc 動作確認 以下のようにrun_serverを作る。 1 2 3 4 5 6 7 8 9 10 def run_server(port: int): with server_socket(port) as soc: while True: conn, addr = soc.accept() print(f'Connected: {addr}') with conn: conn.shutdown(socket.SHUT_RDWR) if __name__ == '__main__': run_server(8080) 作ったサーバーを実行し、別の端末でcurl localhost:8080とすると、サーバー側で以下のようなメッセージが出力される。 60724の部分は実行の度に異なる。 ...

2021-03-06 · (updated 2021-03-06) · 7 min · 1285 words

PythonでPDFの順序並び替えと空白ページ挿入(2種類の方法)

平綴じ印刷ができるように、PDFの順序を入れ替えたり、空白ページを挿入するプログラムを書いた。 方法1はPython + いろんなコマンドで、方法2はPythonのPDFライブラリであるPyPDF4を利用した方法。 実装してみた結果、後者が圧倒的に簡単だった。 動機 平綴じがしたい場面が出てきたが、印刷機に専用の設定が見つからなかった。 なので平綴じになるようにPDFのページ順を1,2,3,4,5,6,7,8,…から4,1,2,3,8,5,6,7,..に変え、それをプリンタで両面刷り(短辺綴じ)・2ページ割付で印刷することを考えた。 平綴じの場合、紙に両面4ページずつ印刷されることになる。するとPDFのページ数は4の倍数でなくてはならない。よって、4の倍数でなかった場合はその分を空白ページで埋めなければならない。 PDFファイルの準備 テスト用にPDFファイルを作っておく。ここはなんでも良いのだが、とりあえず以下のLaTeXのコードから10ページのPDFファイルを作る。名前はinput.pdfとしておく。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 \documentclass{jsarticle} \begin{document} \centering \Huge 1 Page \newpage 2 Page \newpage 3 Page \newpage 4 Page \newpage 5 Page \newpage 6 Page \newpage 7 Page \newpage 8 Page \newpage 9 Page \newpage 10 Page \end{document} 方法1:Python + 諸々のコマンドの利用 方針 PDFのページ順を変えるためには、pdftkコマンドを利用すれば良い。pdftkは、Homebrewならbrew install pdftk-javaで使えるようになる)。例えば8ページのPDFファイルinput.pdfを並び替えるなら次のコマンドで可能。 ...

2021-01-07 · (updated 2021-01-07) · 3 min · 492 words

Eular法とRunge-Kutta法をPythonで実装する

備忘のために。数値解析関連の話はほとんど学んだことがないため、何か間違いがあるかも。 Eular法 以下、例に出そうとしている微分方程式が運動方程式なので、文字の使い方を力学っぽくしている(位置、速度、時間を $x, v, t$ みたいな気持ちで書いている)。 導出(1階) まず次の常微分方程式がある。 \[ \frac{dx}{dt} = f(t, x) \] 上の式を以下のように近似する。$h$を十分小さくすれば、微分の定義より上の式に近づく。 \[ \begin{aligned} \frac{x(t + h) - x(t)}{h} \simeq f(t, x) \\ \Rightarrow x(t + h) \simeq x(t) + f(t, x)h \end{aligned} \] これが、$x(t)$の更新式となっている。つまり、ある時刻$t_0$における値$x_0 = x(t_0)$を決めておけば、 \[ \begin{aligned} & t_k := t_{k-1} + h\\ \end{aligned} \] とおいて、 \[ \begin{aligned} & x(t_1) := x(t_0) + f(t_0, x_0)h \\ & x(t_2) := x(t_1) + f(t_1, x_1)h \\ & x(t_3) := x(t_2) + f(t_2, x_2)h \\ & … \end{aligned} \] ...

2020-05-28 · (updated 2021-03-31) · 8 min · 1520 words