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

// 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