const clientId = "CLIENT-ID";
const clientSecret = "CLIENT-SECRET";
async function fetchPosts() {
const response = await fetch(
"https://www.reddit.com/r/memes/hot.json?limit=10"
);
const data = await response.json();
// Exclude stickied posts
const nonStickiedPosts = data.data.children.filter(post => !post.data.stickied);
return nonStickiedPosts;
}
function filterValidPosts(posts) {
return posts.filter(
(post) =>
post.data.title &&
post.data.url &&
post.data.url.startsWith("http") &&
post.data.url.includes(".gif") &&
post.data.url.includes("v.redd.it") &&
post.data.self && // Exclude self-posts
!post.data.removed // Exclude deleted posts
);
}
function convertToDirectLink(redditMediaLink) {
const url = new URL(redditMediaLink);
// Check if it's a Reddit preview link
if (url.hostname === "preview.redd.it") {
const [mediaId, format] = url.pathname.split("/").pop().split(".");
if (mediaId && format) {
// Build the direct link
return `https://i.redd.it/${mediaId}.${format}`;
}
}
// If it's not a Reddit preview link, return the original link
return redditMediaLink;
}
// ...
// Function to render posts as cards on the webpage
async function renderPosts(posts) {
const container = document.getElementById("postsContainer");
container.innerHTML = "";
for (let i = 0; i < posts.length; i += 3) {
const row = document.createElement("div");
row.classList.add("row");
for (let j = i; j < i + 3 && j < posts.length; j++) {
const post = posts[j];
const card = document.createElement("div");
card.classList.add("card");
const cardContent = document.createElement("div");
cardContent.classList.add("card-content");
if (post.data.is_gallery) {
// Handle Reddit galleries
if (post.data.media_metadata) {
// Iterate over media_metadata to get direct links
for (const mediaId in post.data.media_metadata) {
const galleryImage = post.data.media_metadata[mediaId];
const directLink = convertToDirectLink(galleryImage.s.u); // Use the s.u field for direct link
const image = document.createElement("img");
image.src = directLink;
image.alt = post.data.title;
cardContent.appendChild(image);
}
}
} else if (post.data.url) {
// Handle posts with a single image or external links
const image = document.createElement("img");
image.src = await convertToDirectLink(post.data.url);
image.alt = post.data.title;
cardContent.appendChild(image);
}
cardContent.innerHTML += `<h3>${post.data.title}</h3>`;
card.appendChild(cardContent);
row.appendChild(card);
}
container.appendChild(row);
}
}
async function fetchAndRenderNewPosts() {
try {
const posts = await fetchPosts();
const validPosts = filterValidPosts(posts);
if (validPosts.length > 0) {
renderPosts(validPosts);
} else {
console.warn("No valid posts fetched. Trying again with new posts.");
const newPosts = await fetchPosts();
renderPosts(newPosts);
}
} catch (error) {
console.error("Error fetching or rendering posts:", error);
}
}
window.onload = function () {
fetchAndRenderNewPosts();
setInterval(fetchAndRenderNewPosts, 300000); // Fetch new posts every 5 minutes (adjust as needed)
};
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: flex-start;
max-height: 100vh; /* Set a maximum height for the container */
overflow-y: auto; /* Add vertical scroll if needed */
}
.row {
display: flex;
justify-content: space-around;
margin-bottom: 20px; /* Adjust as needed for spacing between rows */
}
.card {
margin: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
transition: box-shadow 0.3s ease-in-out;
overflow: hidden;
width: calc(33% - 20px); /* Adjust as needed for spacing between cards */
max-width: 300px; /* Limit the maximum width of each card */
}
.card:hover {
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.card-content {
position: relative;
}
.card img {
width: 100%;
height: 100%;
object-fit: cover; /* Ensure the image covers the entire container */
}
<div class="container" id="postsContainer"></div>
I made a Reddit post fetching web site and I'm able to get the galleries (posts with multiple images) in a card where all the images are put and also the single images posts as cards along with their title. Now for the gallery type posts, I want to make a swiper so that I can just swipe instead of seeing multiple images in a row in one card box, but I don't know how to do that.
function convertToDirectLink(redditMediaLink) {
const url = new URL(redditMediaLink);
// Check if it's a Reddit preview link
if (url.hostname === "preview.redd.it") {
const [mediaId, format] = url.pathname.split("/").pop().split(".");
if (mediaId && format) {
// Build the direct link
return `https://i.redd.it/${mediaId}.${format}`;
}
}
// If it's not a Reddit preview link, return the original link
return redditMediaLink;
}
// ...
// Function to render posts as cards on the webpage
async function renderPosts(posts) {
const container = document.getElementById("postsContainer");
container.innerHTML = "";
for (let i = 0; i < posts.length; i += 3) {
const row = document.createElement("div");
row.classList.add("row");
for (let j = i; j < i + 3 && j < posts.length; j++) {
const post = posts[j];
const card = document.createElement("div");
card.classList.add("card");
const cardContent = document.createElement("div");
cardContent.classList.add("card-content");
if (post.data.is_gallery) {
// Handle Reddit galleries
if (post.data.media_metadata) {
// Iterate over media_metadata to get direct links
for (const mediaId in post.data.media_metadata) {
const galleryImage = post.data.media_metadata[mediaId];
const directLink = convertToDirectLink(galleryImage.s.u); // Use the s.u field for direct link
const image = document.createElement("img");
image.src = directLink;
image.alt = post.data.title;
cardContent.appendChild(image);
}
}
} else if (post.data.url) {
// Handle posts with a single image or external links
const image = document.createElement("img");
image.src = await convertToDirectLink(post.data.url);
image.alt = post.data.title;
cardContent.appendChild(image);
}
cardContent.innerHTML += `<h3>${post.data.title}</h3>`;
card.appendChild(cardContent);
row.appendChild(card);
}
container.appendChild(row);
}
}
// ...
async function fetchAndRenderNewPosts() {
try {
const posts = await fetchPosts();
const validPosts = filterValidPosts(posts);
if (validPosts.length > 0) {
renderPosts(validPosts);
} else {
console.warn("No valid posts fetched. Trying again with new posts.");
const newPosts = await fetchPosts();
renderPosts(newPosts);
}
} catch (error) {
console.error("Error fetching or rendering posts:", error);
}
}
window.onload = function () {
fetchAndRenderNewPosts();
setInterval(fetchAndRenderNewPosts, 300000); // Fetch new posts every 5 minutes (adjust as needed)
};
Code summary: this is everything I've done so far. The link converter converts the preview.redd.it link to i.redd.it for easier and high resolution displaying. The render part just renders the image in a card with 3 cards in each row.
This could be one way of doing it.
Changes made to your original code, for simplicity's sake
You'll notice that I've removed your initial fetching logic. This was done for testing purposes - a greatly reduced JSON was used to mimic the response from your original URL.
Also, since they were not used in the available code, I've taken the liberty of removing the
clientIdand theclientSecretfrom the code. You will, of course, use them, if there's a need for it.The
setIntervalhas also been removed, as the code I'm providing is just for testing purposes - you will, of course, include it in your original code.There were minor changes in the CSS, as well, to accommodate for the styling of the swiper (
min-widthwas set for your.rowclass - remove it, and you'll see why it was added).Changes made to your original code, to include swiper.js
The function
renderPostshas been adapted to contain the logic for creating the swiper's container, which will hold the images retrieved from reddit. In doing this, I've relied on the official documentation. Please note that this is just one way of doing it - feel free to experiment, if you find that the solution I've offered is not suitable for what you need.Adding a custom class to the cards containing galleries is done so that we'll know whether there's a need to initialize the swiper, or not.
Finally, at the very end of your
renderPostsfunction, I've included a new function -initSwiper. The function is straightforward, and adapted from what is in the official documentation (no scrollbar, horizontal swiping, the swiper is initialized if there are gallery posts, etc).