// The existingPosts array is used to track already displayed posts let existingPosts = []; // below times are in milliseconds // duration for slide animations let duration = 5000; // refresh rate let refresh = 30000; // getUrlParameter helps to fetch URL parameters function getUrlParameter(name) { name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); var results = regex.exec(location.search); console.log(results) return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); } // secondsAgo calculates how many seconds have passed since the provided date const secondsAgo = date => Math.floor((new Date() - date) / 1000); // timeAgo formats the time elapsed in a human readable format const timeAgo = function(seconds) { // An array of intervals for years, months, days, hours, and minutes. const intervals = [ { limit: 31536000, text: 'Jahren' }, { limit: 2592000, text: 'Monaten' }, { limit: 86400, text: 'Tagen' }, { limit: 3600, text: 'Stunden' }, { limit: 60, text: 'Minuten' } ]; // Loop through the intervals to find which one is the best fit. for (let interval of intervals) { if (seconds >= interval.limit) { return "Vor " + Math.floor(seconds / interval.limit) + ` ${interval.text}`; } } return "Vor " + Math.floor(seconds) + " Sekunden"; }; let includeReplies; // fetchConfig fetches the configuration from the config.json file const fetchConfig = async function() { try { const config = await $.getJSON('config.json'); $('#navbar-brand').text(config.navbarBrandText); $('.navbar').css('background-color', config.navbarColor); includeReplies = config.includeReplies; return config.defaultServerUrl; } catch (error) { console.log("Error loading config.json:", error); $('#navbar-brand').text("Netzbegrünung Mastowall"); $('.navbar').css('background-color', "#008939"); includeReplies = true; return "https://gruene.social"; } } // fetchPosts fetches posts from the server using the given hashtag const fetchPosts = async function(serverUrl, hashtag) { try { const posts = await $.get(`${serverUrl}/api/v1/timelines/tag/${hashtag}?limit=20`); return posts; } catch (error) { console.error(`Error loading posts for hashtag #${hashtag}:`, error); } }; // updateTimesOnPage updates the time information displayed for each post const updateTimesOnPage = function() { $('.card-text a').each(function() { const date = new Date($(this).attr('data-time')); const newTimeAgo = timeAgo(secondsAgo(date)); $(this).text(newTimeAgo); }); }; // displayPost creates and displays a post const displayPost = function(post) { if (existingPosts.includes(post.id) || (!includeReplies && post.in_reply_to_id !== null)) return 0; existingPosts.push(post.id); let cardHTML = `

${DOMPurify.sanitize(post.account.display_name)}

${post.media_attachments[0] ? `` : ''}

${DOMPurify.sanitize(post.content)}

${post.spoiler_text ? `

${DOMPurify.sanitize(post.spoiler_text)}

` : ''}

${timeAgo(secondsAgo(new Date(post.created_at)))}

`; let $card = $(cardHTML); $('#wall').prepend($card); $('.masonry-grid').masonry('prepended', $card); return 1; }; // updateWall displays all posts const updateWall = function(posts) { if (!posts || posts.length === 0) return; posts.sort((a, b) => new Date(a.created_at) - new Date(b.created_at)); let ret = 0 posts.forEach(post => ret += displayPost(post)); $('.masonry-grid').masonry('layout'); return ret; }; // updateCarousel const updateCarousel = function(slides, posts) { if (!posts || posts.length === 0) return; posts.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); // remove slides in carousel slides.innerHTML = ""; var newHTML = ` ` newHTML += `