1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-07-27 21:45:50 +02:00
parent eac8cbb0db
commit 75219990cf
6 changed files with 45 additions and 434 deletions

View file

@ -9,8 +9,6 @@ local PlyInCarCam = false
local bcamstate = false
local carCam = false
local onRec = false
local isRecording = false
local isDashcamRecording = false
-- for prop and ped
local propNetID = nil
@ -769,88 +767,22 @@ RegisterNetEvent('spy-bodycam:client:deleteDecoyPed',function(plyId)
end)
RegisterNetEvent('spy-bodycam:client:startRec',function(webhook,serviceUsed)
if isRecording then
SendNUIMessage({action = "cancel_rec_force"})
isRecording = false
NotifyPlayer('Recording stopped!', 'success', 2500)
if Config.ForceViewCam then
onRec = false
SetFollowPedCamViewMode(1)
SetTimecycleModifier('default')
SetTimecycleModifierStrength(1.0)
end
else
SendNUIMessage({
action = "toggle_record",
hook = webhook,
service = serviceUsed,
recTiming = Config.RecordTime,
})
isRecording = true
NotifyPlayer('Recording started!', 'success', 2500)
if Config.ForceViewCam then
SetTimecycleModifier(Config.CameraEffect.bodycam)
SetTimecycleModifierStrength(0.5)
CreateThread(function()
onRec = true
while onRec do
SetFollowPedCamViewMode(4)
Wait(0)
end
end)
end
end
end)
RegisterNetEvent('spy-bodycam:client:startDashcamRec', function(webhook, serviceUsed, netId)
if isDashcamRecording then
SendNUIMessage({action = "stop_dashcam_recording"})
isDashcamRecording = false
NotifyPlayer('Dashcam recording stopped!', 'success', 2500)
if Config.ForceViewCam then
onRec = false
SetFollowPedCamViewMode(1)
SetTimecycleModifier('default')
SetTimecycleModifierStrength(1.0)
end
else
local veh = NetworkGetEntityFromNetworkId(netId)
if not DoesEntityExist(veh) then
NotifyPlayer('Vehicle not found!', 'error', 2500)
return
end
-- Get vehicle info for recording overlay
local carPlate = GetVehicleNumberPlateText(veh)
local carName = GetVehDisplayName(GetEntityModel(veh))
-- Send message to NUI to start recording
SendNUIMessage({
action = "toggle_dashcam_record",
hook = webhook,
service = serviceUsed,
recTiming = Config.RecordTime,
vehicleId = netId,
vehiclePlate = carPlate,
vehicleName = carName
})
isDashcamRecording = true
NotifyPlayer('Dashcam recording started!', 'success', 2500)
if Config.ForceViewCam then
SetTimecycleModifier(Config.CameraEffect.dashcam)
SetTimecycleModifierStrength(0.5)
CreateThread(function()
onRec = true
while onRec do
SetFollowPedCamViewMode(4)
Wait(0)
end
end)
end
SendNUIMessage({
action = "toggle_record",
hook = webhook,
service = serviceUsed,
recTiming = Config.RecordTime,
})
if Config.ForceViewCam then
SetTimecycleModifier(Config.CameraEffect.bodycam)
SetTimecycleModifierStrength(0.5)
CreateThread(function()
onRec = true
while onRec do
SetFollowPedCamViewMode(4)
Wait(0)
end
end)
end
end)
@ -873,42 +805,6 @@ RegisterNetEvent('spy-bodycam:client:refreshRecords',function(records,isBoss)
})
end)
-- Register hotkeys for recording if enabled in config
Citizen.CreateThread(function()
if Config.EnableRecordingHotkeys then
-- Bodycam recording hotkey
RegisterKeyMapping('bodycamrecord', 'Start/Stop bodycam recording', 'keyboard', Config.RecordHotkey)
RegisterCommand('bodycamrecord', function()
if bcamstate then -- Only if bodycam is active
TriggerServerEvent('spy-bodycam:server:toggleRecording')
else
NotifyPlayer('Bodycam not activated!', 'error', 2500)
end
end, false)
-- Dashcam recording hotkey
RegisterKeyMapping('dashcamrecord', 'Start/Stop dashcam recording', 'keyboard', Config.DashcamHotkey)
RegisterCommand('dashcamrecord', function()
if IsPedInAnyVehicle(cache.ped, false) then
local veh = GetVehiclePedIsIn(cache.ped, false)
if isCarAuth(veh) then
local netId = NetworkGetNetworkIdFromEntity(veh)
if GlobalState.CarsOnBodycam[netId] then
TriggerServerEvent('spy-bodycam:server:toggleDashcamRecording', netId)
else
NotifyPlayer('Dashcam not activated in this vehicle!', 'error', 2500)
end
else
NotifyPlayer('Vehicle not authorized for dashcam!', 'error', 2500)
end
else
NotifyPlayer('You need to be in a vehicle to use dashcam!', 'error', 2500)
end
end, false)
end
end)
RegisterKeyMapping('bodycamexit', 'Exit bodycam spectate', 'keyboard', Config.ExitCamKey)
RegisterCommand('bodycamexit', function()
if PlyInCam or PlyInCarCam then
@ -931,7 +827,7 @@ RegisterNUICallback('videoLog', function(data, cb)
local videoUrl = data.vidurl
local pos = GetEntityCoords(cache.ped)
local s1, s2 = GetStreetNameAtCoord(pos.x, pos.y, pos.z)
TriggerServerEvent('spy-bodycam:server:logVideoDetails', videoUrl, GetStreetNameFromHashKey(s1), data.isDashcam)
TriggerServerEvent('spy-bodycam:server:logVideoDetails', videoUrl,GetStreetNameFromHashKey(s1))
end
end)
@ -1145,7 +1041,6 @@ function PlayWatchAnim(ped,isNet)
Citizen.Wait(10)
end
local prop = CreateObject(tabletprop, x, y, z + 0.2, isNet, true, false)
AttachEntityToEntity(prop, ped, GetPedBoneIndex(ped, 28422), -0.05, 0.0, 0.0, 0.0, 0.0, 0.0,
AttachEntityToEntity(prop, ped, GetPedBoneIndex(ped, 28422), -0.05, 0.0, 0.0, 0.0, 0.0, 0.0, true, true, false, true, 1, true)
local animDict = 'amb@code_human_in_bus_passenger_idles@female@tablet@idle_a'
RequestAnimDict(animDict)
@ -1325,37 +1220,4 @@ function HasItemsCheck(itemname)
return false
end
-- Register hotkeys for recording
if Config.EnableRecordingHotkeys then
RegisterCommand('+bodycamrecord', function()
if bcamstate then
TriggerServerEvent('spy-bodycam:server:toggleRecording')
else
NotifyPlayer('Bodycam not activated!', 'error', 2500)
end
end, false)
RegisterCommand('+dashcamrecord', function()
if IsPedInAnyVehicle(cache.ped, false) then
local veh = GetVehiclePedIsIn(cache.ped, false)
if isCarAuth(veh) then
local netId = NetworkGetNetworkIdFromEntity(veh)
if GlobalState.CarsOnBodycam[netId] then
TriggerServerEvent('spy-bodycam:server:toggleDashcamRecording', netId)
else
NotifyPlayer('Dashcam not activated in this vehicle!', 'error', 2500)
end
else
NotifyPlayer('Vehicle not authorized for dashcam!', 'error', 2500)
end
else
NotifyPlayer('You need to be in a vehicle to use dashcam!', 'error', 2500)
end
end, false)
RegisterKeyMapping('+bodycamrecord', 'Start/Stop bodycam recording', 'keyboard', Config.RecordHotkey)
RegisterKeyMapping('+dashcamrecord', 'Start/Stop dashcam recording', 'keyboard', Config.DashcamHotkey)
end

View file

@ -21,13 +21,10 @@ Config.Dependency = {
UseProgress = 'qb', -- qb | ox | esx
UseMenu = 'qb', -- qb | ox | esx
UseNotify = 'qb', -- qb | ox | esx
UseAppearance = 'illenium', -- qb | illenium | false
UseAppearance = 'illenium', -- qb | illenium | false
}
Config.ExitCamKey = 'BACK'
Config.RecordHotkey = 'F1' -- Hotkey for bodycam recording
Config.DashcamHotkey = 'F10' -- Hotkey for dashcam recording
Config.EnableRecordingHotkeys = true -- Enable/disable hotkey functionality
Config.CameraEffect = {
bodycam = 'Island_CCTV_ChannelFuzz',

View file

@ -161,71 +161,13 @@ Citizen.CreateThread(function()
end
end)
-- Handle bodycam recording toggle
RegisterNetEvent('spy-bodycam:server:toggleRecording', function()
local src = source
if PlayerOnBodycam[src] then
local defwebhook
if Upload.ServiceUsed == 'discord' then
local jobKey
if Config.Framework == 'qb' then
local Player = QBCore.Functions.GetPlayer(src)
jobKey = Player.PlayerData.job.name
else
local xPlayer = ESX.GetPlayerFromId(src)
jobKey = xPlayer.getJob().name
end
if Upload.JobUploads[jobKey] then
defwebhook = Upload.JobUploads[jobKey].webhook
else
defwebhook = Upload.DefaultUploads.webhook
end
elseif Upload.ServiceUsed == 'fivemanage' or Upload.ServiceUsed == 'fivemerr' then
defwebhook = Upload.Token
end
TriggerClientEvent('spy-bodycam:client:startRec', src, defwebhook, Upload.ServiceUsed)
else
NotifyPlayerSv('Bodycam not turned on!', 'error', 3000, src)
end
end)
-- Handle dashcam recording toggle
RegisterNetEvent('spy-bodycam:server:toggleDashcamRecording', function(netId)
local src = source
if CarsOnBodycam[netId] then
local defwebhook
if Upload.ServiceUsed == 'discord' then
local jobKey
if Config.Framework == 'qb' then
local Player = QBCore.Functions.GetPlayer(src)
jobKey = Player.PlayerData.job.name
else
local xPlayer = ESX.GetPlayerFromId(src)
jobKey = xPlayer.getJob().name
end
if Upload.JobUploads[jobKey] then
defwebhook = Upload.JobUploads[jobKey].webhook
else
defwebhook = Upload.DefaultUploads.webhook
end
elseif Upload.ServiceUsed == 'fivemanage' or Upload.ServiceUsed == 'fivemerr' then
defwebhook = Upload.Token
end
TriggerClientEvent('spy-bodycam:client:startDashcamRec', src, defwebhook, Upload.ServiceUsed, netId)
else
NotifyPlayerSv('Dashcam not turned on!', 'error', 3000, src)
end
end)
RegisterNetEvent('spy-bodycam:server:logVideoDetails', function(videoUrl, streetName, isDashcam)
RegisterNetEvent('spy-bodycam:server:logVideoDetails', function(videoUrl,streetName)
local src = source
local offName
local offJob
local offRank
local jobKey
local date = os.date('%Y-%m-%d')
local recordType = isDashcam and "dashcam" or "bodycam"
if Config.Framework == 'qb' then
local Player = QBCore.Functions.GetPlayer(src)
@ -242,13 +184,12 @@ RegisterNetEvent('spy-bodycam:server:logVideoDetails', function(videoUrl, street
end
---SQL UPLOAD
MySQL.Async.execute('INSERT INTO spy_bodycam (job, videolink, street, date, playername, recordtype) VALUES (@job, @videolink, @street, @date, @playername, @recordtype)', {
MySQL.Async.execute('INSERT INTO spy_bodycam (job, videolink, street, date, playername) VALUES (@job, @videolink, @street, @date, @playername)', {
['@job'] = jobKey,
['@videolink'] = videoUrl,
['@street'] = streetName,
['@date'] = date,
['@playername'] = offName,
['@recordtype'] = recordType
['@playername'] = offName
}, function(rowsChanged) end)
if Upload.DiscordLogs.Enabled then
@ -263,7 +204,7 @@ RegisterNetEvent('spy-bodycam:server:logVideoDetails', function(videoUrl, street
end
local embedData = {
{
title = Upload.DiscordLogs.Title .. (isDashcam and " (Dashcam)" or " (Bodycam)"),
title = Upload.DiscordLogs.Title,
color = 16761035,
fields = {
{ name = "Name:", value = offName, inline = false },
@ -271,7 +212,7 @@ RegisterNetEvent('spy-bodycam:server:logVideoDetails', function(videoUrl, street
{ name = "Job Rank:", value = offRank, inline = false },
},
footer = {
text = "Date: " .. os.date("!%Y-%m-%d %H:%M:%S", os.time()),
text = "Date: " .. os.date("!%Y-%m-%d %H:%M:%S", os.time()),
icon_url = "https://i.imgur.com/CuSyeZT.png",
},
author = author
@ -429,58 +370,4 @@ AddEventHandler('onResourceStart', function(resourceName)
checkForUpdates()
end
end)
-- Handle bodycam recording toggle
RegisterNetEvent('spy-bodycam:server:toggleRecording', function()
local src = source
if PlayerOnBodycam[src] then
local defwebhook
if Upload.ServiceUsed == 'discord' then
local jobKey
if Config.Framework == 'qb' then
local Player = QBCore.Functions.GetPlayer(src)
jobKey = Player.PlayerData.job.name
else
local xPlayer = ESX.GetPlayerFromId(src)
jobKey = xPlayer.getJob().name
end
if Upload.JobUploads[jobKey] then
defwebhook = Upload.JobUploads[jobKey].webhook
else
defwebhook = Upload.DefaultUploads.webhook
end
elseif Upload.ServiceUsed == 'fivemanage' or Upload.ServiceUsed == 'fivemerr' then
defwebhook = Upload.Token
end
TriggerClientEvent('spy-bodycam:client:startRec', src, defwebhook, Upload.ServiceUsed)
else
NotifyPlayerSv('Bodycam not turned on!', 'error', 3000, src)
end
end)
-- Handle dashcam recording toggle
RegisterNetEvent('spy-bodycam:server:toggleDashcamRecording', function(netId)
local src = source
if CarsOnBodycam[netId] then
local defwebhook
if Upload.ServiceUsed == 'discord' then
local jobKey
if Config.Framework == 'qb' then
local Player = QBCore.Functions.GetPlayer(src)
jobKey = Player.PlayerData.job.name
else
local xPlayer = ESX.GetPlayerFromId(src)
jobKey = xPlayer.getJob().name
end
if Upload.JobUploads[jobKey] then
defwebhook = Upload.JobUploads[jobKey].webhook
else
defwebhook = Upload.DefaultUploads.webhook
end
elseif Upload.ServiceUsed == 'fivemanage' or Upload.ServiceUsed == 'fivemerr' then
defwebhook = Upload.Token
end
TriggerClientEvent('spy-bodycam:client:startDashcamRec', src, defwebhook, Upload.ServiceUsed, netId)
else
NotifyPlayerSv('Dashcam not turned on!', 'error', 3000, src)
end
end)

View file

@ -79,15 +79,6 @@
</div>
</div>
</div>
<!-- Dashcam Recording UI -->
<div id="dashcam-recording-ui">
<div class="dashcam-header">
<div class="dashcam-recording-indicator"></div>
<span>DASHCAM RECORDING</span>
</div>
<div id="dashcam-vehicle-info">Police Cruiser - ABC123</div>
<div id="dashcam-timer">00:00</div>
</div>
<audio id="beep-sound" src="audio/on_sound.mp3"></audio>
<audio id="off-sound" src="audio/off_sound.mp3"></audio>
<script src="js/jquery-3.7.1.min.js"></script>

View file

@ -1,10 +1,7 @@
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();
@ -13,7 +10,6 @@ $(document).ready(function () {
$('.recCont').hide();
$('.askMain').hide();
$('.vidplaycont').hide();
$('#dashcam-recording-ui').hide();
const beepSound = document.getElementById('beep-sound');
const offSound = document.getElementById('off-sound');
@ -102,7 +98,7 @@ $(document).ready(function () {
startRecording(data.hook, data.service);
recordingTimeout = setTimeout(() => {
if (isRecording) {
// Stop recording automatically after configured time
// Stop recording automatically after 30 seconds
isRecording = false;
$('.HeadText').html('<i class="fa-solid fa-circle bodyIcon" style="color: white;"></i>' + 'Recording Stopped');
setTimeout(() => {
@ -122,53 +118,6 @@ $(document).ready(function () {
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
@ -180,13 +129,6 @@ $(document).ready(function () {
}, 1000);
stopRecording();
}
if (isDashcamRecording) {
isDashcamRecording = false;
$('#dashcam-recording-ui').hide();
clearTimeout(dashcamRecordingTimeout);
clearInterval(dashcamTimer);
stopRecording(true);
}
}
// RECORDS SHOWING
@ -196,18 +138,16 @@ $(document).ready(function () {
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 class="camDesc">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>` : ''}
${data.isBoss ? `<div class="camDelete"><i class="fa-solid fa-trash"></i></div>` : ''}
</div>
</div>
`
@ -226,18 +166,16 @@ $(document).ready(function () {
$('.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 class="camDesc">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>` : ''}
${data.isBoss ? `<div class="camDelete"><i class="fa-solid fa-trash"></i></div>` : ''}
</div>
</div>
`
@ -258,7 +196,7 @@ $(document).ready(function () {
function updateVisibility(searchText) {
$('.camBox').each(function () {
var camTitleText = $(this).find('.camTitle').text().toLowerCase();
var camDescDate = $(this).find('.camDesc').text().trim().replace(/.*Date: /, '');
var camDescDate = $(this).find('.camDesc').text().trim().replace('Date: ', '');
if ((searchText === '' || camTitleText.includes(searchText)) &&
($(this).css('display') !== 'none' || camDescDate === $('.selectedDate').val())
) {
@ -282,7 +220,7 @@ $(document).ready(function () {
$('.selectedDate').on('change', function () {
var selectedDate = $(this).val();
$('.camBox').each(function () {
var camDescDate = $(this).find('.camDesc').text().trim().replace(/.*Date: /, '');
var camDescDate = $(this).find('.camDesc').text().trim().replace('Date: ', '');
if (selectedDate === '') {
$(this).show();
} else if (selectedDate === camDescDate) {
@ -297,7 +235,7 @@ $(document).ready(function () {
$(document).on('click', '.camDelete', function () {
const camBox = $(this).closest('.camBox');
deleteUrl = $(this).data('url');
deleteUrl = camBox.find('.camShow').data('stored');
$('.askMain').fadeIn();
});
@ -349,7 +287,7 @@ let mediaRecorder;
let audioStream;
const canvasElement = document.querySelector('canvas');
async function uploadBlob(videoBlob, hook, service, isDashcam = false) {
async function uploadBlob(videoBlob, hook, service) {
$.post(`https://${GetParentResourceName()}/exitBodyCam`, '{}');
const formData = new FormData();
try {
@ -368,8 +306,7 @@ async function uploadBlob(videoBlob, hook, service, isDashcam = false) {
}
responseData = await response.json();
$.post(`https://${GetParentResourceName()}/videoLog`, JSON.stringify({
vidurl: responseData.url,
isDashcam: isDashcam
vidurl: responseData.url
}));
} else if (service === 'fivemerr') {
formData.append('file', videoBlob, 'video.webm');
@ -385,8 +322,7 @@ async function uploadBlob(videoBlob, hook, service, isDashcam = false) {
}
responseData = await response.json();
$.post(`https://${GetParentResourceName()}/videoLog`, JSON.stringify({
vidurl: responseData.url,
isDashcam: isDashcam
vidurl: responseData.url
}));
} else if (service === 'discord') {
formData.append('file', videoBlob, 'video.webm');
@ -399,8 +335,7 @@ async function uploadBlob(videoBlob, hook, service, isDashcam = false) {
}
responseData = await response.json();
$.post(`https://${GetParentResourceName()}/videoLog`, JSON.stringify({
vidurl: responseData.attachments[0].url,
isDashcam: isDashcam
vidurl: responseData.attachments[0].url
}));
}
} catch (error) {
@ -418,16 +353,15 @@ async function startMicrophoneCapture() {
}
}
async function startRecording(hook, service, recordTime, isDashcam = false) {
async function startRecording(hook, service) {
audioStream = await startMicrophoneCapture();
if (!isRecording && !isDashcamRecording) {
if (!isRecording){
if (audioStream) {
audioStream.getAudioTracks().forEach(track => track.stop());
}
return;
return
}
console.log(isDashcam ? 'Dashcam Recording Started' : 'Bodycam Recording Started');
console.log('Video Recording Started');
const gameView = gameview.createGameView(canvasElement);
const canvasStream = canvasElement.captureStream(30);
@ -445,7 +379,7 @@ async function startRecording(hook, service, recordTime, isDashcam = false) {
mediaRecorder.onstop = async () => {
const videoBlob = new Blob(videoChunks, { type: 'video/webm' });
if (videoBlob.size > 0) {
uploadBlob(videoBlob, hook, service, isDashcam);
uploadBlob(videoBlob, hook, service);
}
if (audioStream) {
audioStream.getAudioTracks().forEach(track => track.stop());
@ -453,15 +387,8 @@ async function startRecording(hook, service, recordTime, isDashcam = false) {
};
}
function stopRecording(isDashcam = false) {
function stopRecording() {
if (mediaRecorder && mediaRecorder.state === 'recording') {
mediaRecorder.stop();
}
if (isDashcam) {
isDashcamRecording = false;
$('#dashcam-recording-ui').hide();
} else {
isRecording = false;
}
}

View file

@ -449,56 +449,3 @@
font-size: 3rem;
font-family: "Fjalla One", sans-serif;
}
/* Dashcam Recording UI */
#dashcam-recording-ui {
position: absolute;
top: 20px;
left: 20px;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 15px;
border-radius: 5px;
font-family: "Play", sans-serif;
display: none;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 0, 0, 0.3);
min-width: 250px;
}
.dashcam-header {
display: flex;
align-items: center;
margin-bottom: 10px;
font-weight: bold;
font-size: 16px;
}
#dashcam-vehicle-info {
font-size: 14px;
margin-bottom: 5px;
color: #f0f0f0;
}
#dashcam-timer {
font-size: 20px;
font-weight: bold;
color: #ff3333;
text-align: center;
}
.dashcam-recording-indicator {
width: 12px;
height: 12px;
background-color: red;
border-radius: 50%;
display: inline-block;
margin-right: 10px;
animation: blink 1s infinite;
}
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
}