You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.9 KiB
152 lines
4.9 KiB
// index.js |
|
|
|
const puppeteer = require('puppeteer'); |
|
const { PuppeteerScreenRecorder } = require('puppeteer-screen-recorder'); |
|
const ffmpeg = require('fluent-ffmpeg'); |
|
const getVideoDurationInSeconds = require('get-video-duration').getVideoDurationInSeconds; |
|
|
|
async function rotateVideo(inputPath, outputPath) { |
|
// Get original duration |
|
const originalDuration = await getVideoDurationInSeconds(inputPath); |
|
const targetDuration = 30; |
|
const speedFactor = originalDuration / targetDuration; |
|
|
|
return new Promise((resolve, reject) => { |
|
ffmpeg(inputPath) |
|
.videoFilters([ |
|
{ filter: 'crop', options: '1920:1080:0:0' }, |
|
{ filter: 'transpose', options: '2' }, |
|
{ filter: 'setpts', options: `PTS/${speedFactor}` } |
|
]) |
|
// Optional: speed up audio as well (max 2x per atempo, so chain if needed) |
|
.audioFilters( |
|
speedFactor <= 2 |
|
? { filter: 'atempo', options: speedFactor } |
|
: [ |
|
{ filter: 'atempo', options: 2 }, |
|
{ filter: 'atempo', options: speedFactor / 2 } |
|
] |
|
) |
|
.save(outputPath) |
|
.on('end', () => { |
|
console.log('Crop, rotation, and speed-up complete!'); |
|
resolve(); |
|
}) |
|
.on('error', err => reject(err)); |
|
}); |
|
} |
|
|
|
function addMusicToVideo(videoPath, musicPath, outputPath, musicVolume = 0.1) { |
|
return new Promise((resolve, reject) => { |
|
ffmpeg() |
|
.addInput(videoPath) |
|
.addInput(musicPath) |
|
.complexFilter([ |
|
// If your video has NO audio, just set the music volume and map |
|
'[1:a]volume=' + musicVolume + '[aud]' |
|
]) |
|
.outputOptions([ |
|
'-map 0:v', // video from first input |
|
'-map [aud]', // audio from [aud] |
|
'-shortest', // end when shortest ends |
|
'-c:v copy' // copy video, do not re-encode |
|
]) |
|
.save(outputPath) |
|
.on('end', () => { |
|
console.log('Music added and volume set!'); |
|
resolve(); |
|
}) |
|
.on('error', reject); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
(async () => { |
|
const browser = await puppeteer.launch({ headless: false }); |
|
const page = await browser.newPage(); |
|
|
|
// Set to vertical/portrait mode |
|
await page.setViewport({ |
|
width: 1920, |
|
height: 1080, |
|
deviceScaleFactor: 1, |
|
}); |
|
|
|
await page.goto('https://tacticfront.io/join/aQoyBBX7'); |
|
|
|
// Click "Pause game" on load |
|
await page.waitForSelector('button[title="Pause game"]'); |
|
await page.click('button[title="Pause game"]'); |
|
console.log('Game paused. Waiting for unpause (second click)...'); |
|
|
|
// Set up a promise in Node |
|
const clickedPromise = new Promise(resolve => { |
|
page.exposeFunction('notifyPauseButtonClicked', resolve); |
|
}); |
|
|
|
// Attach a page-wide click handler in the browser context |
|
await page.evaluate(() => { |
|
// Remove any existing listener for safety |
|
window._pauseButtonHandler && document.removeEventListener('click', window._pauseButtonHandler); |
|
|
|
window._pauseButtonHandler = function (e) { |
|
if ( |
|
e.target && |
|
e.target.tagName === 'BUTTON' && |
|
e.target.title === 'Pause game' |
|
) { |
|
window.notifyPauseButtonClicked(); |
|
document.removeEventListener('click', window._pauseButtonHandler); // Only once |
|
} |
|
}; |
|
|
|
document.addEventListener('click', window._pauseButtonHandler); |
|
}); |
|
|
|
console.log('Game paused. Waiting for unpause (manual click)...'); |
|
await clickedPromise; |
|
|
|
|
|
// Start recording |
|
console.log("Recorder Start") |
|
const recorder = new PuppeteerScreenRecorder(page); |
|
await recorder.start('./replay.mp4'); |
|
|
|
// Stop recording on game end |
|
let recordingStopped = false; |
|
async function finishRecording() { |
|
if (!recordingStopped) { |
|
recordingStopped = true; |
|
await recorder.stop(); |
|
await browser.close(); |
|
// Now rotate the video |
|
await rotateVideo('replay.mp4', 'output_vertical.mp4'); |
|
await addMusicToVideo('output_vertical.mp4', './music/a-hero-of-the-80s-126684.mp3', 'final_output.mp4', 0.05); |
|
|
|
} |
|
} |
|
page.on('console', async msg => { |
|
if (msg.text().includes('local server ending game')) { |
|
console.log('Detected "local server ending game" in console. Stopping recording...'); |
|
await finishRecording(); |
|
} |
|
}); |
|
|
|
setTimeout(async () => { |
|
if (!recordingStopped) { |
|
console.log('Timeout reached. Stopping recording...'); |
|
await finishRecording(); |
|
} |
|
}, 10 * 60 * 1000); // 5 minutes |
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
// Spina has won the game |
|
//local server ending game
|
|
|