
Le package de support, de formation et le service continu qui nous a été offert a très bien fonctionné pour nous sur la première ligne que nous avons achetée, il était donc évident de choisir Europlacer pour aller de l’avant car leur offre était si différente de celle de la concurrence.
.youtube-playlist-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin: 20px 0;
}
.youtube-video-card {
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
overflow: hidden;
transition: all 0.3s ease;
cursor: pointer;
}
.youtube-video-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
}
.youtube-thumbnail-container {
position: relative;
width: 100%;
padding-bottom: 56.25%; /* 16:9 aspect ratio */
overflow: hidden;
}
.youtube-thumbnail {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.youtube-play-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(255,0,0,0.9);
border-radius: 50%;
width: 60px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 14px;
opacity: 0;
transition: opacity 0.3s ease;
}
.youtube-video-card:hover .youtube-play-overlay {
opacity: 1;
}
.youtube-video-info {
padding: 16px;
}
.youtube-video-title {
font-size: 15px;
font-weight: 400;
margin: 0 0 8px 0;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
color: #333;
}
.youtube-video-date {
font-size: 11px;
color: #666;
margin: 0;
}
.youtube-loading {
text-align: center;
padding: 40px;
font-size: 18px;
color: #666;
}
.youtube-error {
text-align: center;
padding: 40px;
color: #d32f2f;
background: #ffebee;
border-radius: 8px;
margin: 20px 0;
}
const YOUTUBE_API_KEY = 'AIzaSyBqDDWnweT4aX2OazwRnKKL4rT3HF4Tn74';
const PLAYLIST_ID = 'PL10f3SNoljkra3TPCSYRk24pHTqlJytpO';
async function loadYouTubePlaylist() {
const container = document.getElementById('youtube-playlist-container');
try {
// Fetch playlist items
const response = await fetch(
`https://www.googleapis.com/youtube/v3/playlistItems?` +
`part=snippet&maxResults=100&playlistId=${PLAYLIST_ID}&` +
`order=date&key=${YOUTUBE_API_KEY}`
);
if (!response.ok) {
throw new Error(`YouTube API error: ${response.status}`);
}
const data = await response.json();
if (!data.items || data.items.length === 0) {
container.innerHTML = '
Loading YouTube videos...
No videos found in playlist.
';
return;
}
// Filter out deleted/private videos
const validVideos = data.items.filter(video => {
// Check if video is accessible
const videoId = video.snippet.resourceId?.videoId;
const title = video.snippet.title;
// Filter out deleted/private videos
// They typically have titles like "Deleted video" or "Private video"
// or missing essential data
return videoId &&
title &&
title !== 'Deleted video' &&
title !== 'Private video' &&
!title.startsWith('[Deleted video]') &&
!title.startsWith('[Private video]');
});
// Check if any videos remain after filtering
if (validVideos.length === 0) {
container.innerHTML = 'No available videos found in playlist.
';
return;
}
// Sort by published date (most recent first)
const sortedVideos = validVideos.sort((a, b) =>
new Date(b.snippet.publishedAt) - new Date(a.snippet.publishedAt)
);
// Create grid HTML
const gridHTML = `
${sortedVideos.map(video => {
const videoId = video.snippet.resourceId.videoId;
const title = video.snippet.title;
// Use different thumbnail sources - try multiple options
const thumbnail = video.snippet.thumbnails.maxres?.url ||
video.snippet.thumbnails.standard?.url ||
video.snippet.thumbnails.high?.url ||
video.snippet.thumbnails.medium?.url ||
video.snippet.thumbnails.default?.url ||
`https://img.youtube.com/vi/${videoId}/mqdefault.jpg`;
const publishedDate = new Date(video.snippet.publishedAt)
.toLocaleDateString();
return `
`;
}).join('')}
`;
container.innerHTML = gridHTML;
} catch (error) {
console.error('Error loading YouTube playlist:', error);
container.innerHTML = `
${title}
Error loading videos: ${error.message}
Check your API key and playlist ID
`;
}
}
function openYouTubeVideo(videoId) {
// Open video in new tab
window.open(`https://www.youtube.com/watch?v=${videoId}`, '_blank');
// Alternative: Embed video in modal (uncomment if preferred)
// showVideoModal(videoId);
}
// Optional: Modal functionality for embedded player
function showVideoModal(videoId) {
const modal = document.createElement('div');
modal.style.cssText = `
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.8); z-index: 10000; display: flex;
align-items: center; justify-content: center; cursor: pointer;
`;
const iframe = document.createElement('iframe');
iframe.style.cssText = `
width: 90%; max-width: 800px; height: 450px; border: none;
border-radius: 8px; cursor: default;
`;
iframe.src = `https://www.youtube.com/embed/${videoId}?autoplay=1`;
iframe.onclick = (e) => e.stopPropagation();
modal.appendChild(iframe);
modal.onclick = () => modal.remove();
document.body.appendChild(modal);
}
// Load the playlist when page loads
document.addEventListener('DOMContentLoaded', loadYouTubePlaylist);
Check your API key and playlist ID




