chromeで開いたページをTouchdesignerでリアルタイムレンダリングする
動機
大学の課題でTouchdesignerを用いた作品を制作する授業があった。そこで、読み込んだウェブサイトがリアルタイムにTouchdesigner上でレンダーされ、サイトの滞在時間によってウィンドウのサイズを変える仕組みを使うことで何か面白い可視化を行えるのではないかと考えた。
先日、講評が終わりひとまず課題は終了となったがまだシステムを設計したに過ぎない段階で作品として、可視化として意義のあるものとして成立させるにはまだまだ道は長い状況である。
しかし、いったんの区切りとして現在の状況をまとめ改めて振り返り、そして備忘録として残しておきたいと思う。また、作品が進展するたびに更新していけたらと思う。
※Touchdesignerのことも、プログラミングのこともそんなに詳しくないため正確でない表現や間違いがあるであろうことは先に言っておく。
(2024.07.15)
実装概要
- chromeの拡張機能を作成し訪れたサイトのurlとタイトルとタイムスタンプを取得する。
- chromeの拡張機能で取得した情報を、flask(正直flaskが何なのかはよくわかっていない、、、参考サイト)を用いてデータベースに保存する。
- データベースに保存されたデータをcsvに変換する
- Touchdesignerでcsvを読み込み、web render topで表示、rectangle sopに適用させるconstant matでweb render topを読み込み3D空間上で取得したwebサイトのキャプチャを表示する。
実装詳細プログラムファイル
-
chromeの拡張機能を作成する。
chromeの拡張機能の作成方法の詳細については他の方が解説されている記事(Chrome拡張機能の実装(入門から公開まで))を参考にする。ファイル構造は以下の通り
browsing_history_tracker/ ├── background.js └── manifest.json
background.jsの中身
// background.js chrome.history.onVisited.addListener(function(result) { const url = result.url; const title = result.title || "No Title"; const time = new Date(result.lastVisitTime).toISOString(); console.log(`Visited URL: ${url}`); console.log(`Page Title: ${title}`); console.log(`Visit Time: ${time}`); fetch('http://localhost:5000/save_history', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: url, title: title, time: time }) }).then(response => { if (!response.ok) { console.error('Failed to send data to server'); } }).catch(error => { console.error('Error:', error); }); });
manifest.jsonの中身
{ "manifest_version": 3, "name": "Browsing History Tracker", "description": "A Chrome extension to track browsing history.", "version": "1.0", "permissions": ["history", "tabs"], "background": { "service_worker": "background.js" } }
ファイルはこのリンク先(github)に保存している。
-
取得した情報の処理を行う
この工程については、あまりよくわかっていない。そろそろ夏休みで時間があるからコードをしっかり読んでいきたいけど取り合え得ず今はよくわからないまま進んでいくことにする。フォルダ構造は以下の通り
browsing_history_server/ ├── fetch_all_history.py ├── formatting.py ├── init_db.py └── server.py
fetch_all_history.pyの中身
import sqlite3 def fetch_all_history(): conn = sqlite3.connect('browsing_history.db') c = conn.cursor() c.execute("SELECT * FROM history") rows = c.fetchall() for row in rows: print(f"URL: {row[1]}\nTitle: {row[2]}\nTime: {row[3]}\n") conn.close() if __name__ == '__main__': fetch_all_history()
formatting.pyの中身
ここでは、csvの形を指定している、はず、、import sqlite3 import csv def update_csv(): conn = sqlite3.connect('browsing_history.db') c = conn.cursor() c.execute("SELECT url, title, time FROM history") rows = c.fetchall() conn.close() # 3行n列のCSV形式で保存 with open('browsing_history.csv', 'w', newline='', encoding='utf-8') as csvfile: csvwriter = csv.writer(csvfile) # 各エントリを3行で保存 for row in rows: csvwriter.writerow(['url', row[0]]) csvwriter.writerow(['title', row[1]]) csvwriter.writerow(['timestamp', row[2]]) csvwriter.writerow([]) # 空行を追加してエントリ間を区切る if __name__ == '__main__': update_csv()
init_db.pyの中身
import sqlite3 def init_db(): conn = sqlite3.connect('browsing_history.db') c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS history (url TEXT, title TEXT, time TIMESTAMP)''') conn.commit() conn.close() if __name__ == '__main__': init_db()
server.pyの中身
from flask import Flask, request, jsonify from flask_cors import CORS import sqlite3 from datetime import datetime, timedelta import csv from init_db import init_db app = Flask(__name__) CORS(app) # CORSを有効にしてクロスオリジンリクエストを許可 # アプリケーション起動時にデータベースを初期化 with app.app_context(): init_db() @app.route('/') def index(): return 'Browsing History Tracker Server is running.' @app.route('/save_history', methods=['POST']) def save_history(): data = request.json conn = sqlite3.connect('browsing_history.db') c = conn.cursor() # ISO 8601形式のタイムスタンプをパースしてdatetimeオブジェクトに変換 visit_time = datetime.fromisoformat(data['time'].replace('Z', '+00:00')) # データを改行付きで保存 c.execute("INSERT INTO history (url, title, time) VALUES (?, ?, ?)", (data['url'], data['title'], visit_time)) conn.commit() conn.close() # CSVファイルを更新 update_csv() return jsonify({"status": "success"}), 200 def update_csv(): conn = sqlite3.connect('browsing_history.db') c = conn.cursor() c.execute("SELECT url, title, time FROM history") rows = c.fetchall() conn.close() with open('browsing_history.csv', 'w', newline='', encoding='utf-8') as csvfile: csvwriter = csv.writer(csvfile) # ヘッダー行を書く csvwriter.writerow(['url', 'title', 'timestamp', 'subtraction']) previous_time = None for row in rows: current_time = datetime.fromisoformat(row[2]) if previous_time: subtraction = (current_time - previous_time).total_seconds() else: subtraction = timedelta(0) csvwriter.writerow([row[0], row[1], row[2], str(subtraction)]) previous_time = current_time if __name__ == '__main__': app.run(debug=True)
ファイルはこのリンク先(github)に保存している。
※csvとデータベース(.dbファイル)についてはプログラムの実行後に自動で作成されるようになっているので用意する必要はない。
-
server.pyを実行する
コマンドプロンプト(macの場合はターミナル)を用いてプログラムを実行する。上記のように、C:\Users\Ikeda>cd C:\Users\Ikeda\OneDrive\デスクトップ\touchdesigner_最終講評\browsing_history_server C:\Users\Ikeda\OneDrive\デスクトップ\touchdesigner_最終講評\browsing_history_server>
cd パス名
と書き、実行したいファイル(ここではserver.py)のある場所まで移動する。たぶんmacでも同じだった、はず。上記のように、C:\Users\Ikeda\OneDrive\デスクトップ\touchdesigner_最終講評\browsing_history_server>python server.py * Serving Flask app 'server' * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:5000 Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 684-011-203
python server.py
とコマンドをうつことでプログラムが実行される。このことで.dbファイルとcsvが作成され記録されていく。
※上手く実行されずこれをインストールしろとかいわれたらとりあえずしたがって、またpython server.py
を実行する。
※macの場合いろいろ違う感じだった。(普段macを使ってないからあまり詳しくはわからないけどmacで実行したときにはまったとこを記録しておく)
1.実行したコードを停止するときCTRL+C
を打つけどctrlとcommandを混同しないように注意する。
2.いろいろインストールさせられていよいよ実行ってときに毎回、前にインストールしたパッケージをインストールさせられた。これはプログラムを実行するときに前に作成した仮想環境を有効化していないことが原因だった。そのため、cd パス名
でファイルがある場所に移動した後に仮想環境を有効化するために. [環境名]/bin/activate
コマンドを打つ必要がある。ただし、.
もあとは半角スペースが必要。参考サイト
3.windowsではpython server.py
で実行できたのにmacではできないことがあった。これの原因ははっきとはよくわかっていないが、macで実行する場合はpython3 server.py
のようにpythonの後ろに3と表記することで動作するようになったので注意。
-
Touchdesignerでレンダリングする
現時点では、Touchdesignerでの実装は非常にシンプルでweb render topを用いて3D空間上でレンダリングしているだけ。
toeファイル
(以上)