diff --git a/v2/app/src-tauri/Cargo.lock b/v2/app/src-tauri/Cargo.lock index f1f14c8..3841e0c 100644 --- a/v2/app/src-tauri/Cargo.lock +++ b/v2/app/src-tauri/Cargo.lock @@ -8,6 +8,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -32,6 +43,23 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android_log-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" + +[[package]] +name = "android_logger" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" +dependencies = [ + "android_log-sys", + "env_filter", + "log", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -51,15 +79,26 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" name = "app" version = "0.1.0" dependencies = [ + "dotenv", + "log", + "rosc", "serde", "serde_json", "tauri", "tauri-build", "tauri-plugin-fs", "tauri-plugin-http", + "tauri-plugin-log", "tauri-plugin-opener", + "tokio", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-broadcast" version = "0.7.2" @@ -253,6 +292,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -293,6 +344,29 @@ dependencies = [ "piper", ] +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "brotli" version = "8.0.2" @@ -320,6 +394,40 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "byte-unit" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" +dependencies = [ + "rust_decimal", + "schemars 1.1.0", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bytemuck" version = "1.24.0" @@ -807,6 +915,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "dpi" version = "0.1.2" @@ -899,6 +1013,16 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -962,6 +1086,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "fern" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29" +dependencies = [ + "log", +] + [[package]] name = "field-offset" version = "0.3.6" @@ -1030,6 +1163,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futf" version = "0.1.5" @@ -1453,6 +1592,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] [[package]] name = "hashbrown" @@ -2003,6 +2145,9 @@ name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +dependencies = [ + "value-bag", +] [[package]] name = "lru-slab" @@ -2068,6 +2213,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2165,6 +2316,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2202,6 +2363,15 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "objc-sys" version = "0.3.5" @@ -2873,6 +3043,26 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "publicsuffix" version = "2.3.0" @@ -2962,6 +3152,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.7.3" @@ -3147,6 +3343,15 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + [[package]] name = "reqwest" version = "0.12.25" @@ -3207,6 +3412,62 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rosc" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd37602e1513794e952274082d074e8d31aa7f64d047e3acb746c91db40600a5" +dependencies = [ + "byteorder", + "nom", + "time", +] + +[[package]] +name = "rust_decimal" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-hash" version = "2.1.1" @@ -3348,6 +3609,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "selectors" version = "0.24.0" @@ -3578,6 +3845,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "siphasher" version = "0.3.11" @@ -3847,6 +4120,12 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" version = "0.12.16" @@ -4030,6 +4309,28 @@ dependencies = [ "urlpattern", ] +[[package]] +name = "tauri-plugin-log" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5709c792b8630290b5d9811a1f8fe983dd925fc87c7fc7f4923616458cd00b6" +dependencies = [ + "android_logger", + "byte-unit", + "fern", + "log", + "objc2 0.6.3", + "objc2-foundation 0.3.2", + "serde", + "serde_json", + "serde_repr", + "swift-rs", + "tauri", + "tauri-plugin", + "thiserror 2.0.17", + "time", +] + [[package]] name = "tauri-plugin-opener" version = "2.5.2" @@ -4225,7 +4526,9 @@ checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -4634,6 +4937,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -4652,6 +4961,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "value-bag" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" + [[package]] name = "version-compare" version = "0.2.1" @@ -5434,6 +5749,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x11" version = "2.21.0" diff --git a/v2/app/src-tauri/Cargo.toml b/v2/app/src-tauri/Cargo.toml index c99e4b9..685f564 100644 --- a/v2/app/src-tauri/Cargo.toml +++ b/v2/app/src-tauri/Cargo.toml @@ -25,3 +25,8 @@ serde_json = "1" tauri-plugin-http = "2" tauri-plugin-fs = "2" +rosc = "0.11.4" +tokio = { version = "1.45.1", features = ["net"] } +dotenv = "0.15.0" +tauri-plugin-log = "2" +log = "0.4.27" \ No newline at end of file diff --git a/v2/app/src-tauri/src/lib.rs b/v2/app/src-tauri/src/lib.rs index f5ee1e3..b4cfdac 100644 --- a/v2/app/src-tauri/src/lib.rs +++ b/v2/app/src-tauri/src/lib.rs @@ -1,4 +1,17 @@ +use rosc::{encoder, OscMessage, OscPacket, OscType}; +use serde::Serialize; +use std::{net::SocketAddrV4, str::FromStr}; +use tauri::{AppHandle, Emitter, Manager}; +use tokio::net::UdpSocket; + +#[derive(Serialize, Clone)] +struct OscEvent { + addr: String, + args: Vec, +} + // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ + #[tauri::command] fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) @@ -10,7 +23,32 @@ pub fn run() { .plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![greet]) + .invoke_handler(tauri::generate_handler![send_osc_message]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } + + +#[tauri::command] +async fn send_osc_message( + key: &str, + message: &str, + host: &str, + target: &str, +) -> Result<(), String> { + // print + println!("Sending OSC message:{} {} {}", target, key,message); + + let sock = UdpSocket::bind(host).await.unwrap(); + let remote = SocketAddrV4::from_str(target).unwrap(); + + let msg_buf = encoder::encode(&OscPacket::Message(OscMessage { + addr: key.to_string(), + args: vec![OscType::String(message.parse().unwrap())], + })) + .unwrap(); + + sock.send_to(&msg_buf, remote).await.unwrap(); + + Ok(()) +} \ No newline at end of file diff --git a/v2/app/src/App.jsx b/v2/app/src/App.jsx index 26829f4..d1f8db8 100644 --- a/v2/app/src/App.jsx +++ b/v2/app/src/App.jsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import "./App.css"; import { searchByText, searchByTheme, processTheme } from "./utils/parsing"; import Graph from "./components/graph"; +import { invoke } from "@tauri-apps/api/core"; const files=['大家想到未來不會很絕望嗎','日常生活','有人懂嗎','看到學貸還款通知書寄來','租屋網站']; const ContentTags=['Summary','Keywords','Order','User','Content']; @@ -30,7 +31,16 @@ function App() { processRawFiles('resources/raw/1222', 'resources/collect/1222'); } + + useEffect(()=>{ + if(!results || results.length===0) return; + + + },[results]); + useEffect(()=>{ + + sendOsc('/status', 'App Loaded'); fetch('themes.json').then(response=>response.json()).then(async (json)=>{ console.log(json); diff --git a/v2/app/src/components/graph.jsx b/v2/app/src/components/graph.jsx index 49e72c9..b214287 100644 --- a/v2/app/src/components/graph.jsx +++ b/v2/app/src/components/graph.jsx @@ -5,6 +5,7 @@ import { generateLinesFromPoints, get3dCoordinates } from '../utils/draw'; import { OrbitControls, PerspectiveCamera, Bounds, useBounds, Line } from '@react-three/drei' import Point, {PointContentType} from './point.jsx'; import { useControls, button } from "leva"; +import { sendOsc } from '../utils/osc.js'; export default function Graph({results}){ @@ -36,6 +37,20 @@ export default function Graph({results}){ useEffect(()=>{ zoomToFit(); + + if(!points || points.length===0) return; + + points.forEach((point, index)=>{ + console.log(`send osc Point ${index}: (${point[0].toFixed(2)}, ${point[1].toFixed(2)}, ${point[2].toFixed(2)})`); + sendOsc('/point',JSON.stringify({ + index: index, + x: point[0], + y: point[1], + z: point[2], + content: results?.[index]?.payload.teaser + })); + }); + }, [points]); useEffect(()=>{ diff --git a/v2/app/src/utils/osc.js b/v2/app/src/utils/osc.js new file mode 100644 index 0000000..e5e4bd6 --- /dev/null +++ b/v2/app/src/utils/osc.js @@ -0,0 +1,8 @@ +import { invoke } from "@tauri-apps/api/core"; + +const TD_OSC_PORT=7000; + +export function sendOsc(key, message){ + console.log("Sending OSC:", key, message); + invoke('send_osc_message', {key: `${key}`, message: message, host:'0.0.0.0:0', target:`127.0.0.1:${TD_OSC_PORT}`}) +} \ No newline at end of file diff --git a/v2/scrapper/main.js b/v2/scrapper/main.js index eda0d5a..1298319 100644 --- a/v2/scrapper/main.js +++ b/v2/scrapper/main.js @@ -38,16 +38,21 @@ const Keywords=[ "歸屬感 飄","租來的 人生","網路 社群 溫暖","家鄉 不屬於","靈魂 避難所" ] -const Version="v2"; -const DEBUG_MODE=false; + +const Version="v2-1"; +const DEBUG_MODE=true; async function step1(){ - const chooseKeywords=['人生 妥協','邊界 被侵犯','卡住 職涯','尷尬 年齡','厭世 創作']; + // const chooseKeywords=['人生 妥協','邊界 被侵犯','卡住 職涯','尷尬 年齡','厭世 創作']; + const chooseThemse=['職涯','00後整頓職場','生活方式','長大後才懂的事','privilege']; + const chooseKeywords=['成年 限制 學貸 獨立','學貸 房租 焦慮','職場 權利 privilege','職涯 嚮往','門禁 自由 限制','人生 妥協 期待','人生 自主']; + // const keyword="工作 生活 平衡"; for(const keyword of chooseKeywords){ - const searchResults = await searchThreads(keyword, 20, cookies); + // const searchResults = await searchThreads(keyword, 50, cookies, 'TAG'); + const searchResults = await searchThreads(keyword, 50, cookies, 'KEYWORD'); console.log(JSON.stringify(searchResults)); for(const url of searchResults.urls){ @@ -159,9 +164,9 @@ async function step3(){ async function main(){ - // await step1(); + await step1(); // await step2(); - await step3(); + // await step3(); } diff --git a/v2/scrapper/search.js b/v2/scrapper/search.js index 1951794..48dbe53 100644 --- a/v2/scrapper/search.js +++ b/v2/scrapper/search.js @@ -7,12 +7,17 @@ import puppeteer from 'puppeteer'; * @param {number} limit - Maximum number of URLs to return. * @param {Array} cookies - Optional: Array of Puppeteer-formatted cookies to handle login. */ -export async function searchThreads(keyword, limit = 20, cookies = []) { +export async function searchThreads(keyword, limit = 20, cookies = [], searchMode='KEYWORD') { if (!keyword) { throw new Error("Please provide a keyword for the search."); } - const searchUrl = `https://www.threads.net/search?q=${encodeURIComponent(keyword)}&serp_type=default`; + const searchUrl = `https://www.threads.net/search?` + +`q=${encodeURIComponent(keyword)}` + +`&search_type=TOP` + +`&limit=${limit}` + +`&search_mode=${searchMode}` + +`&media_type=TEXT`; console.log(`[Search Start] Keyword: "${keyword}" | URL: ${searchUrl}`); const browser = await puppeteer.launch({