Skip to content

Commit 794557f

Browse files
feat: Integrate YouTube API for video gallery
Adds a new page to display YouTube videos related to environmental protection. Implements a backend endpoint (`/api/youtube_videos`) to fetch videos from the YouTube API using a server-side API key. Creates the corresponding frontend HTML, CSS, and JavaScript (`youtube.html`, `youtube.css`, `youtube.js`) to display the videos. Adds a link to the new page on the homepage. Includes a `.env.example` to document the required `YOUTUBE_API_KEY`.
1 parent 1103750 commit 794557f

7 files changed

Lines changed: 124 additions & 0 deletions

File tree

eco_project/backend/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
YOUTUBE_API_KEY=

eco_project/backend/app.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,38 @@ def uploaded_file(filename):
657657
def handle_chat_message(message):
658658
emit('chat_message', message, broadcast=True)
659659

660+
661+
from googleapiclient.discovery import build
662+
663+
@app.route('/api/youtube_videos')
664+
def youtube_videos():
665+
youtube_api_key = os.environ.get('YOUTUBE_API_KEY')
666+
if not youtube_api_key:
667+
return jsonify({"error": "YouTube API key is not configured."}), 500
668+
669+
try:
670+
youtube = build('youtube', 'v3', developerKey=youtube_api_key)
671+
672+
search_response = youtube.search().list(
673+
q="environmental protection",
674+
part="snippet",
675+
maxResults=10,
676+
type="video"
677+
).execute()
678+
679+
videos = []
680+
for search_result in search_response.get("items", []):
681+
videos.append({
682+
"title": search_result["snippet"]["title"],
683+
"video_id": search_result["id"]["videoId"]
684+
})
685+
686+
return jsonify(videos)
687+
688+
except Exception as e:
689+
return jsonify({"error": str(e)}), 500
690+
691+
660692
if __name__ == '__main__':
661693
port = int(os.environ.get("PORT", 8080))
662694
socketio.run(app, host='0.0.0.0', port=port, debug=False, allow_unsafe_werkzeug=True)

eco_project/backend/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ requests
33
gunicorn
44
google-cloud-logging
55
Flask-SocketIO
6+
google-api-python-client

eco_project/backend/static/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ <h2>Community</h2>
5252
<p>Share your ideas and connect with others.</p>
5353
<ul>
5454
<li><a href="videos.html">Watch Videos</a></li>
55+
<li><a href="youtube.html">Watch YouTube Videos</a></li>
5556
<li><a href="camera.html">Publish Videos/Photos</a></li>
5657
<li><a href="forest_seeds.html">Forest Seeds Promotion</a></li>
5758
<li><a href="chat.html">Join the Chat</a></li>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
.video-container {
2+
display: flex;
3+
flex-wrap: wrap;
4+
justify-content: space-around;
5+
padding: 20px;
6+
}
7+
8+
.video-item {
9+
width: 300px;
10+
margin: 15px;
11+
border: 1px solid #ccc;
12+
box-shadow: 0 0 5px rgba(0,0,0,0.1);
13+
}
14+
15+
.video-item iframe {
16+
width: 100%;
17+
height: 170px;
18+
}
19+
20+
.video-item-title {
21+
padding: 10px;
22+
font-weight: bold;
23+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>YouTube Videos - Environment Protection</title>
7+
<link rel="stylesheet" href="style.css">
8+
<link rel="stylesheet" href="youtube.css">
9+
</head>
10+
<body>
11+
<header>
12+
<h1>YouTube Video Gallery</h1>
13+
<nav>
14+
<a href="index.html">Home</a>
15+
</nav>
16+
</header>
17+
<main>
18+
<section id="videos">
19+
<h2>Featured Videos</h2>
20+
<div class="video-container">
21+
<!-- Video embeds will go here -->
22+
</div>
23+
</section>
24+
</main>
25+
<footer>
26+
<p>&copy; 2025 Environment Protection Initiative</p>
27+
</footer>
28+
<script src="youtube.js"></script>
29+
</body>
30+
</html>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
document.addEventListener('DOMContentLoaded', () => {
2+
const videoContainer = document.querySelector('.video-container');
3+
4+
async function fetchVideos() {
5+
try {
6+
const response = await fetch('/api/youtube_videos');
7+
if (!response.ok) {
8+
throw new Error(`HTTP error! status: ${response.status}`);
9+
}
10+
const videos = await response.json();
11+
displayVideos(videos);
12+
} catch (error) {
13+
videoContainer.innerHTML = `<p>Error fetching videos: ${error.message}</p>`;
14+
}
15+
}
16+
17+
function displayVideos(videos) {
18+
if (videos.length === 0) {
19+
videoContainer.innerHTML = '<p>No videos to display.</p>';
20+
return;
21+
}
22+
let html = '';
23+
videos.forEach(video => {
24+
const embedUrl = `https://www.youtube.com/embed/${video.video_id}`;
25+
html += `
26+
<div class="video-item">
27+
<iframe src="${embedUrl}" frameborder="0" allowfullscreen></iframe>
28+
<div class="video-item-title">${video.title}</div>
29+
</div>
30+
`;
31+
});
32+
videoContainer.innerHTML = html;
33+
}
34+
35+
fetchVideos();
36+
});

0 commit comments

Comments
 (0)