/** * test_tts.js - TTS API テスト * node test_tts.js */ const https = require('https'); const fs = require('fs'); const path = require('path'); const envContent = fs.readFileSync(path.join(__dirname, '.env'), 'utf8'); const COOKIE_STR = envContent.match(/ALEXA_COOKIE=(.+)/)[1].trim(); function makeRequest(url, options = {}, extraCookies = '') { return new Promise((resolve, reject) => { const parsed = new URL(url); const allCookies = COOKIE_STR + (extraCookies ? '; ' + extraCookies : ''); const reqOpts = { hostname: parsed.hostname, path: parsed.pathname + parsed.search, method: options.method || 'GET', headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept': 'application/json, text/plain, */*', 'Accept-Language': 'ja-JP,ja;q=0.9', 'Cookie': allCookies, ...(options.headers || {}), }, }; const req = https.request(reqOpts, (res) => { let body = ''; res.on('data', d => body += d); res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body })); }); req.on('error', reject); if (options.body) req.write(options.body); req.end(); }); } async function main() { // 1. CSRFトークン取得 console.log('[1] CSRF token取得...'); const langRes = await makeRequest('https://alexa.amazon.co.jp/api/language'); const setCookies = langRes.headers['set-cookie'] || []; const csrfCookieStr = setCookies.find(c => c.startsWith('csrf=')); const csrfToken = csrfCookieStr ? csrfCookieStr.split('=')[1].split(';')[0] : null; console.log(' CSRF token:', csrfToken); console.log(' Status:', langRes.status); if (!csrfToken) { console.error('CSRF token not found!'); process.exit(1); } // 2. デバイス一覧取得 console.log('[2] デバイス一覧取得...'); const devRes = await makeRequest('https://alexa.amazon.co.jp/api/devices-v2/device?cached=false'); console.log(' Status:', devRes.status); const devices = JSON.parse(devRes.body).devices || []; console.log(' Device count:', devices.length); // デバイス一覧表示 devices.filter(d => d.deviceFamily !== 'TABLET').forEach(d => { console.log(` - ${d.accountName} (type=${d.deviceType}, serial=${d.serialNumber})`); }); // プレハブを探す const target = devices.find(d => d.serialNumber === 'G0922H08525302K5'); console.log('\nTarget device:', target ? `${target.accountName}` : 'NOT FOUND'); if (!target) { process.exit(1); } // 2.5. カスタマーIDを取得 const bootstrapRes = await makeRequest('https://alexa.amazon.co.jp/api/bootstrap'); const bootstrap = JSON.parse(bootstrapRes.body); const customerId = bootstrap.authentication?.customerId; console.log(' Customer ID:', customerId); // 3. TTSリクエスト const sequenceObj = { '@type': 'com.amazon.alexa.behaviors.model.Sequence', startNode: { '@type': 'com.amazon.alexa.behaviors.model.OpaquePayloadOperationNode', type: 'Alexa.Speak', operationPayload: { deviceType: target.deviceType, deviceSerialNumber: target.serialNumber, customerId: customerId, locale: 'ja-JP', textToSpeak: 'テストです。聞こえますか', }, }, }; const bodyObj = { behaviorId: 'PREVIEW', sequenceJson: JSON.stringify(sequenceObj), status: 'ENABLED', }; const body = JSON.stringify(bodyObj); console.log('\n[3] TTS送信...'); const ttsRes = await makeRequest('https://alexa.amazon.co.jp/api/behaviors/preview', { method: 'POST', headers: { 'Content-Type': 'application/json', 'csrf': csrfToken, 'Referer': 'https://alexa.amazon.co.jp/spa/index.html', 'Origin': 'https://alexa.amazon.co.jp', }, body, }, `csrf=${csrfToken}`); console.log('TTS status:', ttsRes.status); console.log('TTS response:', ttsRes.body.substring(0, 500)); if (ttsRes.status === 200 || ttsRes.status === 202) { console.log('\n成功!エコーがしゃべるはずです。'); } } main().catch(console.error);