forked from Simnation/Main
467 lines
18 KiB
JavaScript
467 lines
18 KiB
JavaScript
import { GameView } from './gameview.js';
|
|
const gameview = new GameView();
|
|
let isRecording = false;
|
|
let isDashcamRecording = false;
|
|
let recordingTimeout;
|
|
let dashcamRecordingTimeout;
|
|
let dashcamTimer;
|
|
|
|
$(document).ready(function () {
|
|
$('.overlayCont').hide();
|
|
$('.currWatchCont').hide();
|
|
$('.RecordInfo').hide();
|
|
$('.recCont').hide();
|
|
$('.askMain').hide();
|
|
$('.vidplaycont').hide();
|
|
$('#dashcam-recording-ui').hide();
|
|
const beepSound = document.getElementById('beep-sound');
|
|
const offSound = document.getElementById('off-sound');
|
|
|
|
function updateTime() {
|
|
const date = new Date();
|
|
date.setUTCHours(date.getUTCHours() - 5);
|
|
|
|
const month = ("0" + (date.getMonth() + 1)).slice(-2);
|
|
const day = ("0" + date.getDate()).slice(-2);
|
|
const hours = ("0" + date.getHours()).slice(-2);
|
|
const minutes = ("0" + date.getMinutes()).slice(-2);
|
|
const seconds = ("0" + date.getSeconds()).slice(-2);
|
|
|
|
const gameTime = `${month}-${day} ${hours}:${minutes}:${seconds}-0500`;
|
|
|
|
$('.bodyDate').html('<i class="fa-solid fa-circle fa-fade bodyIcon"></i>' + gameTime);
|
|
}
|
|
|
|
let interval;
|
|
|
|
window.addEventListener('message', function (event) {
|
|
const data = event.data;
|
|
if (data.action === 'open') {
|
|
updateTime();
|
|
interval = setInterval(updateTime, 1000);
|
|
$('.bodyNum').text(data.bodyname);
|
|
$('.bodyCallsign').text(data.callsign);
|
|
$('.overlayCont').removeClass('popOut').addClass('popIn').show();
|
|
beepSound.play();
|
|
} else if (data.action === 'close') {
|
|
clearInterval(interval);
|
|
$('.overlayCont').removeClass('popIn').addClass('popOut').one('animationend', function () {
|
|
$(this).hide();
|
|
$(this).removeClass('popOut');
|
|
});
|
|
offSound.play();
|
|
}
|
|
if (data.action === 'openWatch') {
|
|
let typeCam;
|
|
let plateText;
|
|
let carText;
|
|
|
|
if (data.debug) {
|
|
var controlsHtml = `
|
|
<span class="watchInText typeCam">Controls</span>
|
|
<br>
|
|
<span class="watchInText typeCam">W -> Up</span>
|
|
<br>
|
|
<span class="watchInText typeCam">S -> Down</span>
|
|
<br>
|
|
<span class="watchInText typeCam">A -> Left</span>
|
|
<br>
|
|
<span class="watchInText typeCam">D -> Right</span>
|
|
<br>
|
|
<span class="watchInText typeCam">Q -> Forward</span>
|
|
<br>
|
|
<span class="watchInText typeCam">E -> Backward</span>
|
|
`;
|
|
document.querySelector('.userLaber').innerHTML = controlsHtml;
|
|
} else {
|
|
if (data.isbodycam) {
|
|
typeCam = "BODYCAM";
|
|
plateText = "CamID: " + data.bodyId;
|
|
carText = "Name: " + data.name;
|
|
} else {
|
|
typeCam = "DASHCAM";
|
|
plateText = "Plate: " + data.bodyId;
|
|
carText = "Car: " + data.name;
|
|
}
|
|
document.querySelector('.typeCam').textContent = typeCam;
|
|
document.querySelector('.plateText').textContent = plateText;
|
|
document.querySelector('.carText').textContent = carText;
|
|
}
|
|
$('.backInText').text(data.exitKey);
|
|
$('.currWatchCont').fadeIn();
|
|
} else if (data.action === 'closeWatch') {
|
|
$('.currWatchCont').fadeOut();
|
|
}
|
|
if (data.action === 'toggle_record') {
|
|
clearTimeout(recordingTimeout);
|
|
if (!isRecording) {
|
|
// Start recording
|
|
isRecording = true;
|
|
$('.HeadText').html('<i class="fa-solid fa-circle fa-fade bodyIcon" style="color: rgb(173, 8, 8);"></i>' + 'Recording Started');
|
|
$('.RecordInfo').fadeIn();
|
|
startRecording(data.hook, data.service);
|
|
recordingTimeout = setTimeout(() => {
|
|
if (isRecording) {
|
|
// Stop recording automatically after configured time
|
|
isRecording = false;
|
|
$('.HeadText').html('<i class="fa-solid fa-circle bodyIcon" style="color: white;"></i>' + 'Recording Stopped');
|
|
setTimeout(() => {
|
|
$('.RecordInfo').fadeOut();
|
|
}, 2000);
|
|
stopRecording();
|
|
}
|
|
}, data.recTiming * 1000);
|
|
} else {
|
|
// Stop recording
|
|
isRecording = false;
|
|
$('.HeadText').html('<i class="fa-solid fa-circle bodyIcon" style="color: white;"></i>' + 'Recording Stopped');
|
|
clearTimeout(recordingTimeout);
|
|
setTimeout(() => {
|
|
$('.RecordInfo').fadeOut();
|
|
}, 2000);
|
|
stopRecording();
|
|
}
|
|
}
|
|
if (data.action === 'toggle_dashcam_record') {
|
|
clearTimeout(dashcamRecordingTimeout);
|
|
if (!isDashcamRecording) {
|
|
// Start dashcam recording
|
|
isDashcamRecording = true;
|
|
$('#dashcam-recording-ui').show();
|
|
$('#dashcam-vehicle-info').text(`${data.vehicleName} - ${data.vehiclePlate}`);
|
|
|
|
// Start a timer for the dashcam recording
|
|
let seconds = 0;
|
|
dashcamTimer = setInterval(() => {
|
|
seconds++;
|
|
const mins = Math.floor(seconds / 60);
|
|
const secs = seconds % 60;
|
|
$('#dashcam-timer').text(`${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`);
|
|
}, 1000);
|
|
|
|
// Start recording using the existing function
|
|
startRecording(data.hook, data.service, data.recTiming, true);
|
|
|
|
// Auto-stop after the configured time
|
|
dashcamRecordingTimeout = setTimeout(() => {
|
|
if (isDashcamRecording) {
|
|
isDashcamRecording = false;
|
|
$('#dashcam-recording-ui').hide();
|
|
clearInterval(dashcamTimer);
|
|
stopRecording(true);
|
|
}
|
|
}, data.recTiming * 1000);
|
|
} else {
|
|
// Stop dashcam recording
|
|
isDashcamRecording = false;
|
|
$('#dashcam-recording-ui').hide();
|
|
clearTimeout(dashcamRecordingTimeout);
|
|
clearInterval(dashcamTimer);
|
|
stopRecording(true);
|
|
}
|
|
}
|
|
if (data.action === 'stop_dashcam_recording') {
|
|
if (isDashcamRecording) {
|
|
isDashcamRecording = false;
|
|
$('#dashcam-recording-ui').hide();
|
|
clearTimeout(dashcamRecordingTimeout);
|
|
clearInterval(dashcamTimer);
|
|
stopRecording(true);
|
|
}
|
|
}
|
|
if (data.action === 'cancel_rec_force') {
|
|
if (isRecording) {
|
|
// Force stop recording
|
|
isRecording = false;
|
|
$('.HeadText').html('<i class="fa-solid fa-circle bodyIcon" style="color: white;"></i>' + 'Recording Stopped');
|
|
clearTimeout(recordingTimeout);
|
|
setTimeout(() => {
|
|
$('.RecordInfo').fadeOut();
|
|
}, 1000);
|
|
stopRecording();
|
|
}
|
|
if (isDashcamRecording) {
|
|
isDashcamRecording = false;
|
|
$('#dashcam-recording-ui').hide();
|
|
clearTimeout(dashcamRecordingTimeout);
|
|
clearInterval(dashcamTimer);
|
|
stopRecording(true);
|
|
}
|
|
}
|
|
|
|
// RECORDS SHOWING
|
|
if (data.action === 'show_records') {
|
|
$('.recInnerScroll').empty();
|
|
$('.recDesc').text(`${data.jobTitle} Database`);
|
|
|
|
if (Array.isArray(data.recordData) && data.recordData.length > 0) {
|
|
$.each(data.recordData, function (index, record) {
|
|
var recordType = record.recordtype || 'bodycam';
|
|
var recordIcon = recordType === 'dashcam' ? 'fa-car' : 'fa-video';
|
|
var camBox = $(
|
|
`
|
|
<div class="camBox">
|
|
<div class="camInfo">
|
|
<div class="camTitle">${record.playername}<span class="camStreet"> [${record.street}]</span></div>
|
|
<div class="camDesc">${recordType.toUpperCase()} | Date: ${record.date}</div>
|
|
</div>
|
|
<div class="camIcons">
|
|
<div class="camShow" data-stored="${record.videolink}"><i class="fa-solid fa-eye"></i></div>
|
|
${data.isBoss ? `<div class="camDelete" data-url="${record.videolink}"><i class="fa-solid fa-trash"></i></div>` : ''}
|
|
</div>
|
|
</div>
|
|
`
|
|
);
|
|
$('.recInnerScroll').append(camBox);
|
|
});
|
|
$('.recCont').show();
|
|
} else {
|
|
$('.recInnerScroll').html('<h1 class="noRecAv">No records available</h1>');
|
|
$('.recCont').show();
|
|
}
|
|
}
|
|
|
|
// Refresh Records
|
|
if (data.action === 'refreshrec') {
|
|
$('.recInnerScroll').empty();
|
|
if (Array.isArray(data.recordData) && data.recordData.length > 0) {
|
|
$.each(data.recordData, function (index, record) {
|
|
var recordType = record.recordtype || 'bodycam';
|
|
var recordIcon = recordType === 'dashcam' ? 'fa-car' : 'fa-video';
|
|
var camBox = $(
|
|
`
|
|
<div class="camBox">
|
|
<div class="camInfo">
|
|
<div class="camTitle">${record.playername}<span class="camStreet"> [${record.street}]</span></div>
|
|
<div class="camDesc">${recordType.toUpperCase()} | Date: ${record.date}</div>
|
|
</div>
|
|
<div class="camIcons">
|
|
<div class="camShow" data-stored="${record.videolink}"><i class="fa-solid fa-eye"></i></div>
|
|
${data.isBoss ? `<div class="camDelete" data-url="${record.videolink}"><i class="fa-solid fa-trash"></i></div>` : ''}
|
|
</div>
|
|
</div>
|
|
`
|
|
);
|
|
$('.recInnerScroll').append(camBox);
|
|
});
|
|
$('.recCont').show();
|
|
} else {
|
|
$('.recInnerScroll').html('<h1 class="noRecAv">No records available</h1>');
|
|
$('.recCont').show();
|
|
}
|
|
}
|
|
});
|
|
|
|
let deleteUrl = '';
|
|
|
|
// SEARCH AND DATE FILTERS :)
|
|
function updateVisibility(searchText) {
|
|
$('.camBox').each(function () {
|
|
var camTitleText = $(this).find('.camTitle').text().toLowerCase();
|
|
var camDescDate = $(this).find('.camDesc').text().trim().replace(/.*Date: /, '');
|
|
if ((searchText === '' || camTitleText.includes(searchText)) &&
|
|
($(this).css('display') !== 'none' || camDescDate === $('.selectedDate').val())
|
|
) {
|
|
$(this).show();
|
|
}
|
|
else if ((searchText === '' || camTitleText.includes(searchText)) &&
|
|
($('.selectedDate').val() === '')
|
|
) {
|
|
$(this).show();
|
|
} else {
|
|
$(this).hide();
|
|
}
|
|
});
|
|
}
|
|
|
|
$('.searchInput').on('input', function () {
|
|
var searchText = $(this).val().toLowerCase();
|
|
updateVisibility(searchText);
|
|
});
|
|
|
|
$('.selectedDate').on('change', function () {
|
|
var selectedDate = $(this).val();
|
|
$('.camBox').each(function () {
|
|
var camDescDate = $(this).find('.camDesc').text().trim().replace(/.*Date: /, '');
|
|
if (selectedDate === '') {
|
|
$(this).show();
|
|
} else if (selectedDate === camDescDate) {
|
|
$(this).show();
|
|
} else {
|
|
$(this).hide();
|
|
}
|
|
});
|
|
var searchText = $('.searchInput').val().toLowerCase();
|
|
updateVisibility(searchText);
|
|
});
|
|
|
|
$(document).on('click', '.camDelete', function () {
|
|
const camBox = $(this).closest('.camBox');
|
|
deleteUrl = $(this).data('url');
|
|
$('.askMain').fadeIn();
|
|
});
|
|
|
|
$(document).on('click', '.askBtn:nth-child(1)', function () {
|
|
$('.askMain').fadeOut();
|
|
if (deleteUrl) {
|
|
$.post(`https://${GetParentResourceName()}/deleteVideo`, JSON.stringify({
|
|
vidurl: deleteUrl
|
|
}));
|
|
}
|
|
});
|
|
|
|
$(document).on('click', '.askBtn:nth-child(2)', function () {
|
|
$('.askMain').fadeOut();
|
|
});
|
|
|
|
$(document).on('click', '.camShow', function () {
|
|
var videoUrl = $(this).data('stored');
|
|
$('.vidPlayer').attr('src', videoUrl);
|
|
$('.vidplaycont').show();
|
|
});
|
|
|
|
$(document).on('click', '.vidPlayerIcon', function () {
|
|
$('.vidplaycont').hide();
|
|
$('.vidPlayer').attr('src', '');
|
|
});
|
|
|
|
$(document).on('click', function (event) {
|
|
if ($(event.target).is('.vidplaycont')) {
|
|
$('.vidplaycont').hide();
|
|
$('.vidPlayer').attr('src', '');
|
|
}
|
|
});
|
|
|
|
$(document).on('keydown', function (e) {
|
|
if (e.which === 27) {
|
|
$('.askMain').hide();
|
|
$('.searchInput').val('');
|
|
$('.selectedDate').val('');
|
|
$('.recCont').hide();
|
|
$('.vidplaycont').hide();
|
|
$('.vidPlayer').attr('src', '');
|
|
$.post(`https://${GetParentResourceName()}/closeRecUI`, '{}');
|
|
}
|
|
});
|
|
});
|
|
|
|
let mediaRecorder;
|
|
let audioStream;
|
|
const canvasElement = document.querySelector('canvas');
|
|
|
|
async function uploadBlob(videoBlob, hook, service, isDashcam = false) {
|
|
$.post(`https://${GetParentResourceName()}/exitBodyCam`, '{}');
|
|
const formData = new FormData();
|
|
try {
|
|
let response, responseData;
|
|
if (service === 'fivemanage') {
|
|
formData.append('video', videoBlob);
|
|
response = await fetch('https://api.fivemanage.com/api/video', {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: hook,
|
|
},
|
|
body: formData,
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to upload video to FiveManage: ${response.status}`);
|
|
}
|
|
responseData = await response.json();
|
|
$.post(`https://${GetParentResourceName()}/videoLog`, JSON.stringify({
|
|
vidurl: responseData.url,
|
|
isDashcam: isDashcam
|
|
}));
|
|
} else if (service === 'fivemerr') {
|
|
formData.append('file', videoBlob, 'video.webm');
|
|
response = await fetch('https://api.fivemerr.com/v1/media/videos', {
|
|
method: 'POST',
|
|
headers: {
|
|
Authorization: hook,
|
|
},
|
|
body: formData,
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to upload video to Fivemerr: ${response.status}`);
|
|
}
|
|
responseData = await response.json();
|
|
$.post(`https://${GetParentResourceName()}/videoLog`, JSON.stringify({
|
|
vidurl: responseData.url,
|
|
isDashcam: isDashcam
|
|
}));
|
|
} else if (service === 'discord') {
|
|
formData.append('file', videoBlob, 'video.webm');
|
|
response = await fetch(hook, {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to upload video to Discord: ${response.status}`);
|
|
}
|
|
responseData = await response.json();
|
|
$.post(`https://${GetParentResourceName()}/videoLog`, JSON.stringify({
|
|
vidurl: responseData.attachments[0].url,
|
|
isDashcam: isDashcam
|
|
}));
|
|
}
|
|
} catch (error) {
|
|
console.error('^1[ERROR]:^3', error.message);
|
|
}
|
|
}
|
|
|
|
async function startMicrophoneCapture() {
|
|
try {
|
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
return stream;
|
|
} catch (error) {
|
|
console.error('Microphone capture failed. Recording video only.');
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function startRecording(hook, service, recordTime, isDashcam = false) {
|
|
audioStream = await startMicrophoneCapture();
|
|
if (!isRecording && !isDashcamRecording) {
|
|
if (audioStream) {
|
|
audioStream.getAudioTracks().forEach(track => track.stop());
|
|
}
|
|
return;
|
|
}
|
|
|
|
console.log(isDashcam ? 'Dashcam Recording Started' : 'Bodycam Recording Started');
|
|
const gameView = gameview.createGameView(canvasElement);
|
|
const canvasStream = canvasElement.captureStream(30);
|
|
|
|
// Combine audio and video streams
|
|
const combinedStream = new MediaStream([
|
|
...canvasStream.getVideoTracks(),
|
|
...(audioStream ? audioStream.getAudioTracks() : [])
|
|
]);
|
|
|
|
const videoChunks = [];
|
|
window.gameView = gameView;
|
|
mediaRecorder = new MediaRecorder(combinedStream, { mimeType: 'video/webm;codecs=vp9' });
|
|
mediaRecorder.start();
|
|
mediaRecorder.ondataavailable = (e) => e.data.size > 0 && videoChunks.push(e.data);
|
|
mediaRecorder.onstop = async () => {
|
|
const videoBlob = new Blob(videoChunks, { type: 'video/webm' });
|
|
if (videoBlob.size > 0) {
|
|
uploadBlob(videoBlob, hook, service, isDashcam);
|
|
}
|
|
if (audioStream) {
|
|
audioStream.getAudioTracks().forEach(track => track.stop());
|
|
}
|
|
};
|
|
}
|
|
|
|
function stopRecording(isDashcam = false) {
|
|
if (mediaRecorder && mediaRecorder.state === 'recording') {
|
|
mediaRecorder.stop();
|
|
}
|
|
|
|
if (isDashcam) {
|
|
isDashcamRecording = false;
|
|
$('#dashcam-recording-ui').hide();
|
|
} else {
|
|
isRecording = false;
|
|
}
|
|
}
|