Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions eco_project/backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,32 @@ def handle_connect():
def handle_disconnect():
print('Client disconnected')

from werkzeug.utils import secure_filename

UPLOAD_FOLDER = os.path.join(app.root_path, 'uploads')
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

@app.route('/api/upload', methods=['POST'])
def upload_file():
if 'media' not in request.files:
return jsonify({"error": "No file part"}), 400
file = request.files['media']
if file.filename == '':
return jsonify({"error": "No selected file"}), 400
if file:
filename = secure_filename(file.filename)
file.save(os.path.join(UPLOAD_FOLDER, filename))
return jsonify({"message": "File uploaded successfully"}), 201

@app.route('/api/gallery')
def gallery():
files = os.listdir(UPLOAD_FOLDER)
return jsonify(files)

@app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(UPLOAD_FOLDER, filename)

@socketio.on('chat_message')
def handle_chat_message(message):
emit('chat_message', message, broadcast=True)
Expand Down
53 changes: 53 additions & 0 deletions eco_project/backend/static/camera.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* General styles for the camera page */
#camera-container {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 2rem;
}

#camera-stream {
width: 100%;
max-width: 600px;
border: 2px solid #ccc;
border-radius: 5px;
}

#camera-controls {
margin-top: 1rem;
}

#camera-controls button {
margin: 0 0.5rem;
padding: 0.8rem 1.2rem;
font-size: 1rem;
cursor: pointer;
border-radius: 5px;
border: none;
background-color: #007bff;
color: white;
}

#camera-controls button:disabled {
background-color: #ccc;
cursor: not-allowed;
}

/* Gallery styles */
#gallery {
padding: 1rem;
}

#gallery-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}

.gallery-item img,
.gallery-item video {
width: 100%;
height: auto;
border-radius: 5px;
border: 1px solid #ddd;
}
38 changes: 38 additions & 0 deletions eco_project/backend/static/camera.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Camera Access - Environment Protection</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="camera.css">
</head>
<body>
<header>
<h1>Camera Access</h1>
<nav>
<a href="index.html">Home</a>
</nav>
</header>
<main>
<section id="camera-container">
<video id="camera-stream" autoplay playsinline></video>
<div id="camera-controls">
<button id="capture-photo">Capture Photo</button>
<button id="start-video">Start Recording</button>
<button id="stop-video" disabled>Stop Recording</button>
</div>
</section>
<section id="gallery">
<h2>Gallery</h2>
<div id="gallery-container">
<!-- Captured photos and videos will be displayed here -->
</div>
</section>
</main>
<footer>
<p>&copy; 2025 Environment Protection Initiative</p>
</footer>
<script src="camera.js"></script>
</body>
</html>
109 changes: 109 additions & 0 deletions eco_project/backend/static/camera.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
document.addEventListener('DOMContentLoaded', () => {
const cameraStream = document.getElementById('camera-stream');
const capturePhotoButton = document.getElementById('capture-photo');
const startVideoButton = document.getElementById('start-video');
const stopVideoButton = document.getElementById('stop-video');
const galleryContainer = document.getElementById('gallery-container');

let mediaRecorder;
let recordedChunks = [];

// Access camera
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
cameraStream.srcObject = stream;
})
.catch(err => {
console.error("Error accessing camera: ", err);
galleryContainer.innerHTML = '<p>Could not access the camera. Please check permissions.</p>';
});

// Capture photo
capturePhotoButton.addEventListener('click', () => {
const canvas = document.createElement('canvas');
canvas.width = cameraStream.videoWidth;
canvas.height = cameraStream.videoHeight;
canvas.getContext('2d').drawImage(cameraStream, 0, 0);
canvas.toBlob(blob => {
const timestamp = new Date().toISOString();
uploadFile(blob, `photo_${timestamp}.png`);
}, 'image/png');
});

// Start recording
startVideoButton.addEventListener('click', () => {
recordedChunks = [];
const stream = cameraStream.srcObject;
mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=vp9' });

mediaRecorder.ondataavailable = event => {
if (event.data.size > 0) {
recordedChunks.push(event.data);
}
};

mediaRecorder.onstop = () => {
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const timestamp = new Date().toISOString();
uploadFile(blob, `video_${timestamp}.webm`);
};

mediaRecorder.start();
startVideoButton.disabled = true;
stopVideoButton.disabled = false;
});

// Stop recording
stopVideoButton.addEventListener('click', () => {
mediaRecorder.stop();
startVideoButton.disabled = false;
stopVideoButton.disabled = true;
});

// Upload file
function uploadFile(blob, filename) {
const formData = new FormData();
formData.append('media', blob, filename);

fetch('/api/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
console.log(data.message);
fetchGallery();
})
.catch(error => {
console.error('Error uploading file:', error);
});
}

// Fetch and display gallery
function fetchGallery() {
fetch('/api/gallery')
.then(response => response.json())
.then(files => {
displayMedia(files);
})
.catch(error => console.error('Error fetching gallery:', error));
}

function displayMedia(files) {
galleryContainer.innerHTML = '';
if (files.length === 0) {
galleryContainer.innerHTML = '<p>No media in the gallery yet.</p>';
return;
}
files.forEach(file => {
const mediaElement = file.endsWith('.png') || file.endsWith('.jpg') ?
`<img src="/uploads/${file}" alt="${file}">` :
`<video src="/uploads/${file}" controls></video>`;

galleryContainer.innerHTML += `<div class="gallery-item">${mediaElement}</div>`;
});
}

// Initial load
fetchGallery();
});
1 change: 1 addition & 0 deletions eco_project/backend/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ <h2>Community</h2>
<p>Share your ideas and connect with others.</p>
<ul>
<li><a href="videos.html">Watch Videos</a></li>
<li><a href="camera.html">Publish Videos/Photos</a></li>
<li><a href="forest_seeds.html">Forest Seeds Promotion</a></li>
<li><a href="chat.html">Join the Chat</a></li>
</ul>
Expand Down
Loading