{"id":34239,"date":"2025-08-28T12:10:18","date_gmt":"2025-08-28T10:10:18","guid":{"rendered":"https:\/\/labs.ubn.one\/signage\/?page_id=34239"},"modified":"2025-12-12T21:30:10","modified_gmt":"2025-12-12T20:30:10","slug":"noordkop247","status":"publish","type":"page","link":"https:\/\/labs.ubn.one\/signage\/index.php\/noordkop247\/","title":{"rendered":"Noordkop247"},"content":{"rendered":"\n<!-- NKC LOGO AND BASIC CSS -->\n<style>\n\t.site-identity:after {\n\t\tcontent: '';\n\t\tdisplay: block;\n\t\tbackground-image: none;\n\t\tbackground-repeat: no-repeat;\n\t\tbackground-position: center;\n\t\tbackground-size: contain;\n\t\twidth: 480px;\n\t\t\/* height: 304px; *\/\n\t\theight: 380px;\n\t\tmargin-top: -345px;\n\t\tz-index: 9999;\n\t}\n\tbody {\n\t\tbackground-color: white;\n\t\tfont-family: 'Montserrat','helvetica',Arial !important;\n                font-weight: 600;\n\t\tbackground-image: url(\"https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2024\/07\/nkc_bg.png\");\n\t\tbackground-repeat: no-repeat;\n\t\tbackground-position: right;\n\t}\n\n\/* NEWS SCRAPER *\/\n\t.entry-content img {\n\t  max-width: 79% !important;\n\t}\n\t.slide-entry-wrap {\n\t\tpadding-left: 73px !important;\n\t}\n\t.slide-content {\n\t\ttext-align: center;\n\t}\n\t.slide-entry-title {\n\t\tfont-size: 30px;\n\t\tcolor: #ca9215;\n\t\t\/* color: #dde007; *\/\n\t\tfont-family: 'Montserrat','helvetica',Arial;\n \t\tfont-weight: 600;\n\t\tline-height: 1.2;\n\t\tmargin-top: 5px;\n\t}\n\t.entry-content {\n\t\t\/* background-color: black; *\/\n\t}\n\thr {\n\t\tdisplay: none;\n\t}\n<\/style>\n\n\n\n<!-- LOGO DIV STYLE -->\n<style>\n.logo-div-logo {\n    display: block;\n    position: absolute;\n    background-image: url(\"https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2025\/08\/Noordkop247-logo-transparant.png\");\n    background-repeat: no-repeat;\n    background-position: center;\n    background-size: contain;\n    width: 480px;\n    height: 380px;\n    margin-left: -624px;\n    margin-top: 177px;\n    z-index: 9999;\n}\n.logo-div-red {\n    left: 144px;\n    top: 0px;\n    width: 135px;\n    height: 350px;\n    background-color: #a61735;\n    border: none;\n    position: absolute;\n}\n.logo-div-green {\n    left: 489px;\n    top: 470px;\n    width: 135px;\n    height: 220px;\n    background-color: #76b729;\n    border: none;\n    position: absolute;\n}\n<\/style>\n<div class=\"logo-div-logo\"><\/div>\n<div class=\"logo-div-red\"><\/div>\n<div class=\"logo-div-green\"><\/div>\n\n\n\n<!-- HEADLINES TITLE -->\n<style>\n    .headlines_title {\n        width: 800px;\n        float: left;\n        margin-top: 50px;\n        margin-bottom: 30px;\n        margin-left: 73px;\n        font-family: 'Montserrat','helvetica',Arial;\n        font-weight: 600;\n        font-size: 30px;\n        color: white;\n    }\n    .headlines_sub {\n        font-size: 20px;\n\tcolor: #e6e6e6;\n        background-color: #1E1D1B;\n        padding: 5px 5px 5px 20px;\n        width: 460px;\n        border-radius: 0px;\n        position: absolute;\n        top: 568px;\n        left: 841px;\n    }\n    .headlines_sub i {\n\tcolor: #a61735;       \n    }\n<\/style>\n\n<div class=\"headlines_title\">Headlines uit de Noordkop:<\/div>\n<div class=\"headlines_sub\"><i class=\"fa-solid fa-arrow-pointer\"><\/i> Bekijk meer Nieuws op Noordkop247.nl<\/div>\n\n\n\n<style>\n\/* --- Zorg dat de plugin container geen absolute position krijgt --- *\/\n.wprss_ajax {\n    display: block !important;\n    width: auto !important;\n    position: absolute;\n    top: 109px;\n    left: 841px;\n}\n\n\/* Hoofdcontainer: vaste ruimtes zoals gevraagd *\/\n.wp_rss_retriever {\n    position: relative !important;\n    width: 965px !important;   \/* was 865 *\/\n    height: auto !important;   \/* 400px limiet verwijderd *\/\n    overflow: visible !important;\n}\n\n\/* UL reset *\/\n.wp_rss_retriever_list {\n    list-style: none !important;\n    padding: 0 !important;\n    margin: 0 !important;\n}\n\n\/* Verberg metadata en beschrijving (zoals gewenst) *\/\n.wp_rss_retriever_container,\n.wp_rss_retriever_metadata,\n.wp_rss_retriever_date {\n    display: none !important;\n}\n\n\/* Items positie (links groot, rechts twee klein) *\/\n.wp_rss_retriever_item {\n    position: absolute !important;\n    overflow: hidden !important;\n    border-radius: 0px !important; \/* square images *\/\n}\n\n\/* Groot links *\/\n.wp_rss_retriever_item:nth-child(1) {\n    left: 0;\n    top: 0;\n    width: 660px !important;   \/* vergroot zodat rechts mooi uitkomt *\/\n    height: 440px !important;  \/* verhouding foto behouden *\/\n}\n\n\/* Rechts boven *\/\n.wp_rss_retriever_item:nth-child(2) {\n    right: 0;\n    top: 0;\n    width: 290px !important;\n    height: 215px !important;\n\n    \/* ruimte tussen boven & onder *\/\n    margin-bottom: 10px !important;\n}\n\n\/* Rechts onder *\/\n.wp_rss_retriever_item:nth-child(3) {\n    right: 0;\n    top: 225px !important;  \/* ruimte cre\u00ebren onder blok 2 *\/\n    width: 290px !important;\n    height: 215px !important;\n}\n\n\/* Afbeeldingen - forceer zichtbaarheid en cover *\/\n.wp_rss_retriever_image,\n.wp_rss_retriever_image img {\n    display: block !important;\n    width: 100% !important;\n    height: 100% !important;\n    object-fit: cover !important;\n    border-radius: 0px !important; \/* vierkant *\/\n}\n\n\/* Soms voegt plugin inline width\/height toe op de <a> wrapper. Override *\/\n.wp_rss_retriever_item .wp_rss_retriever_image[style] {\n    width: 100% !important;\n    height: 100% !important;\n}\n\n\/* Titels *\/\n.wp_rss_retriever_title {\n    position: absolute !important;\n    left: 0 !important;\n    right: 0 !important;\n    bottom: 0 !important;\n    padding: 12px !important;\n    color: #ffffff !important;\n    font-family: 'Montserrat', Arial, sans-serif !important;\n    font-weight: 700 !important;\n    font-size: 20px !important;\n    text-decoration: none !important;\n    background: linear-gradient(transparent, rgba(0,0,0,0.65)) !important;\n    display: block !important;\n    box-sizing: border-box !important;\n    line-height: 1.15 !important;\n    overflow: hidden !important;\n    white-space: nowrap !important; \/* we will truncate with JS *\/\n    text-overflow: ellipsis;\n}\n\n\/* Optionele debug-outline (uitzetten door 'display: none' hieronder) *\/\n.rss-debug-outline { display: none; outline: 2px dashed rgba(255,0,0,0.25); }\n\n\/* OVERRULE inline width\/height van WP RSS retriever *\/\n.wp_rss_retriever_image,\n.wp_rss_retriever_image img {\n    width: 100% !important;\n    height: 100% !important;\n    object-fit: cover !important;\n}\n\n\/* De wrapper forceer je ook naar 100% hoogte *\/\n.wp_rss_retriever_item .wp_rss_retriever_image[style] {\n    width: 100% !important;\n    height: 100% !important;\n}\n\n.wp_rss_retriever_item_wrapper {\n    position: relative !important;\n    width: 100% !important;\n    height: 100% !important;\n    overflow: hidden !important;\n    border-radius: 0px !important;\n}\n\n.wp_rss_retriever_image {\n    position: absolute !important;\n    top: 0; left: 0;\n    width: 100% !important;\n    height: 100% !important;\n    z-index: 1 !important;   \/* afbeelding bovenaan *\/\n}\n\n.wp_rss_retriever_image img {\n    width: 100% !important;\n    height: 100% !important;\n    object-fit: cover !important;\n}\n\n.wp_rss_retriever_title {\n    position: absolute !important;\n    left: 0 !important;\n    right: 0 !important;\n    bottom: -10px !important;\n    padding: 14px !important;\n    font-size: 20px !important;\n    font-weight: 700 !important;\n    color: #fff !important;\n\n    \/* Zorg dat de gradient exact tot de onderrand loopt *\/\n    background: linear-gradient(\n        rgba(0,0,0,0) 0%,\n        rgba(0,0,0,0.75) 100%\n    ) !important;\n\n    z-index: 5 !important;\n    border-radius: 0px !important;\n    white-space: nowrap !important;\n    text-overflow: ellipsis;\n    overflow: hidden !important;\n}\n<\/style>\n\n\n\n<!-- RSS TITLE LIMIT -->\n<script>\n(function () {\n    \/\/ ---- Config ----\n    const MAX_TITLE_CHARS = 45; \/\/ <-- pas hier aan\n    const TITLE_SELECTOR = \".wp_rss_retriever_title\";\n    const FEED_WRAPPER_SELECTOR = \".wprss_ajax\"; \/\/ plugin wrapper waar AJAX in plaatst\n\n    \/\/ ---- Functie: Verkort teksten en voeg ellipsis toe (veilig, behoudt link) ----\n    function shortenTitles() {\n        document.querySelectorAll(TITLE_SELECTOR).forEach(function (titleEl) {\n            \/\/ bewaar originele volledige titel in data attribuut (indien nog niet gedaan)\n            if (!titleEl.dataset.fullTitle) {\n                titleEl.dataset.fullTitle = titleEl.textContent.trim();\n            }\n            const full = titleEl.dataset.fullTitle;\n            if (!full) return;\n            if (full.length > MAX_TITLE_CHARS) {\n                \/\/ gebruik substring op woordgrens als mogelijk (niet mid-word afbreken)\n                let cut = full.substring(0, MAX_TITLE_CHARS);\n                \/\/ probeer laatste spatie zoeken voor nettere afkapping\n                const lastSpace = cut.lastIndexOf(' ');\n                if (lastSpace > Math.floor(MAX_TITLE_CHARS * 0.6)) {\n                    cut = cut.substring(0, lastSpace);\n                }\n                titleEl.textContent = cut + \"\u2026\";\n                titleEl.setAttribute('title', full); \/\/ tooltip met volledige titel\n            } else {\n                titleEl.textContent = full;\n            }\n        });\n    }\n\n    \/\/ ---- Functie: Forceer afbeeldingen zichtbaar (somige plugins togglen classes) ----\n    function ensureImagesVisible() {\n        document.querySelectorAll(\".wp_rss_retriever_image, .wp_rss_retriever_image img\").forEach(function (el) {\n            el.style.display = \"block\";\n            el.style.visibility = \"visible\";\n            el.style.opacity = \"1\";\n        });\n    }\n\n    \/\/ ---- Run once at start ----\n    document.addEventListener(\"DOMContentLoaded\", function () {\n        shortenTitles();\n        ensureImagesVisible();\n    });\n\n    \/\/ ---- Luister naar plugin custom event(s) (primaire) ----\n    \/\/ RSS Feed Retriever triggert custom events na fetch; luister daarop\n    document.addEventListener(\"wprss_fetch_done\", function () {\n        shortenTitles();\n        ensureImagesVisible();\n    });\n    \/\/ fallback alternatieve event name\n    document.addEventListener(\"wprss_loaded\", function () {\n        shortenTitles();\n        ensureImagesVisible();\n    });\n\n    \/\/ ---- jQuery AJAX complete fallback (indien jQuery beschikbaar) ----\n    if (window.jQuery) {\n        jQuery(document).ajaxComplete(function (event, xhr, settings) {\n            \/\/ kleine vertraging zodat DOM geschilderd is\n            setTimeout(function () {\n                shortenTitles();\n                ensureImagesVisible();\n            }, 50);\n        });\n    }\n\n    \/\/ ---- MutationObserver fallback: observe veranderingen in de feed wrapper ----\n    const feedWrapper = document.querySelector(FEED_WRAPPER_SELECTOR);\n    if (feedWrapper) {\n        const mo = new MutationObserver(function (mutations) {\n            \/\/ als childList verandert, run de routines\n            let changed = false;\n            for (const m of mutations) {\n                if (m.addedNodes && m.addedNodes.length) { changed = true; break; }\n                if (m.removedNodes && m.removedNodes.length) { changed = true; break; }\n            }\n            if (changed) {\n                \/\/ korte vertraging zodat images DOM attributes zijn gezet\n                setTimeout(function () {\n                    shortenTitles();\n                    ensureImagesVisible();\n                }, 60);\n            }\n        });\n        mo.observe(feedWrapper, { childList: true, subtree: true });\n    } else {\n        \/\/ als wrapper niet beschikbaar: observe document body als backup\n        const mo2 = new MutationObserver(function (mutations) {\n            let changed = false;\n            for (const m of mutations) {\n                if (m.addedNodes && m.addedNodes.length) { changed = true; break; }\n            }\n            if (changed) {\n                setTimeout(function () {\n                    shortenTitles();\n                    ensureImagesVisible();\n                }, 80);\n            }\n        });\n        mo2.observe(document.body, { childList: true, subtree: true });\n    }\n\n    \/\/ ---- Debug functie: toon outlines tijdelijk (zet 'display: block' in CSS hierboven) ----\n    window.rssDebugOutline = function () {\n        document.querySelectorAll('.wp_rss_retriever_item').forEach(i => i.classList.add('rss-debug-outline'));\n        document.querySelectorAll('.wp_rss_retriever_image').forEach(i => i.classList.add('rss-debug-outline'));\n    };\n\n})();\n<\/script>\n\n\n<div class=\"wprss_ajax\" data-id=\"rss2fe6d66b7c\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/labs.ubn.one\/signage\/wp-content\/plugins\/wp-rss-retriever\/inc\/imgs\/ajax-loader.gif\" alt=\"Loading RSS Feed\" width=\"16\" height=\"16\"><\/div>\n\n\n\n<!-- RADIO BAR -->\n<style>\n   .Radio_Bar {\n    width: 1806px;\n    height: 250px;\n    border: none;\n    position: absolute;\n    left: 0px;\n    top: 650px;\n    \/* Background gradient: transparent areas on top and bottom, solid color in middle *\/\n    background: linear-gradient(\n        to bottom,\n        transparent 0px,             \/* Start of div: fully transparent *\/\n        transparent 30px,            \/* Top transparent area height (change 40px to adjust top) *\/\n        #0f4a6a 30px,                \/* Start of solid color *\/\n        #0f4a6a calc(100% - 20px),  \/* End of solid color, 20px from bottom (change 20px to adjust bottom) *\/\n        transparent calc(100% - 20px), \/* Bottom transparent area starts *\/\n        transparent 100%             \/* End of div: fully transparent *\/\n    );\n   }\n   .radioPlayer_content {\n        width: 1200px;\n        margin-left: 116px;\n        float: left;\n        text-align: left;\n    }\n   .radioPlayer_text {\n        margin-top: 10px;\n    }\n   .radioPlayer_text h3 {\n        color: white;\n        font-family: 'Montserrat','helvetica',Arial;\n \tfont-weight: 600;\n        margin-top: 0px;\n        font-size: 30px;\n    }\n   #radioPlayer {\n        cursor: pointer;\n        width: 210px;\n        height: 210px;\n        border-radius: 0px !important;\n        float: left;\n        margin-right: 20px;\n    }\n<\/style>\n  <div class=\"Radio_Bar\">\n    <div class=\"radioPlayer_content\">\n      <img decoding=\"async\" id=\"radioPlayer\" src=\"https:\/\/placehold.co\/300\/EEE\/31343C?font=raleway&#038;text=Laden\" alt=\"Radio Player\">\n      <div class=\"radioPlayer_text\">\n         <br><span style=\"font-size: 20px; color: black;\">NU OP DE RADIO:<\/span>\n         <h3 id=\"stream-stats\">Loading&#8230;<\/h3>\n      <\/div>\n    <\/div>\n  <\/div>\n\n<script>\nlet lastTrack = null;\n\nasync function fetchStreamStats() {\n  const blacklist = [\n    \"De beste mix van nieuws en hits op Noordkop 247\",\n    \"ANWB Verkeer\",\n    \"Nieuws uit de regio\",\n    \"Welkom Bij Een Nieuw Uur Noordkop247!\"\n  ];\n  const specialCase = \"Het wereldnieuws\";\n  const specialImage = \"https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2024\/07\/nos.png\";\n  const apiKey = \"acbf892e36234d5b1636e034acd2e8c2\";\n\n  try {\n    const response = await fetch(\"https:\/\/radiostreams.noordkop247.nl:9443\/status.xsl\");\n    const htmlText = await response.text();\n    const parser = new DOMParser();\n    const doc = parser.parseFromString(htmlText, \"text\/html\");\n\n    \/\/ ---- NEW PARSER FOR UPDATED ICECAST PAGE ----\n    const streams = doc.querySelectorAll(\".roundcont\");\n\n    let targetBlock = null;\n\n    \/\/ 1. Try to find mount point \/noordkop\n    streams.forEach(block => {\n      const h3 = block.querySelector(\"h3\");\n      if (h3 && h3.textContent.includes(\"\/noordkop\")) {\n        targetBlock = block;\n      }\n    });\n\n    \/\/ 2. If not found, find first Stream Title = \"Noordkop Centraal\"\n    if (!targetBlock) {\n      streams.forEach(block => {\n        const titleRow = Array.from(block.querySelectorAll(\"tr\"))\n          .find(row => row.children[0]?.textContent.trim() === \"Stream Title:\");\n        const titleValue = titleRow?.children[1]?.textContent.trim();\n        if (titleValue === \"Noordkop Centraal\" && !targetBlock) {\n          targetBlock = block;\n        }\n      });\n    }\n\n    if (!targetBlock) {\n      document.getElementById(\"stream-stats\").textContent =\n        \"Het Laatste Nieuws & de Beste Muziek! (Noordkop stream not found)\";\n      return;\n    }\n\n    \/\/ Extract Current Song\n    const rows = targetBlock.querySelectorAll(\"tr\");\n    let currentlyPlayingValue = \"Not found\";\n\n    rows.forEach(row => {\n      const cells = row.querySelectorAll(\"td\");\n      if (cells.length === 2 && cells[0].textContent.trim() === \"Current Song:\") {\n        currentlyPlayingValue = cells[1].textContent.trim();\n      }\n    });\n\n    \/\/ ------ YOUR EXISTING LOGIC BELOW (unchanged except name change) ------\n\n    if (blacklist.includes(currentlyPlayingValue)) {\n      currentlyPlayingValue = \"Het Laatste Nieuws & de Beste Muziek!\";\n      document.getElementById(\"stream-stats\").textContent = currentlyPlayingValue;\n      document.getElementById(\"radioPlayer\").src =\n        \"https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2024\/07\/nkc_album_default.png\";\n    } else if (currentlyPlayingValue === specialCase) {\n      document.getElementById(\"stream-stats\").textContent = currentlyPlayingValue;\n      document.getElementById(\"radioPlayer\").src = specialImage;\n    } else {\n      currentlyPlayingValue = currentlyPlayingValue\n        .split(\" \")\n        .map(word =>\n          word.match(\/^\\(.*\\)$\/)\n            ? word\n            : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()\n        )\n        .join(\" \");\n\n      const ytRegex = \/\\(yt\\)|\\(YT\\)\/gi;\n      const cleanForDisplay = currentlyPlayingValue.replace(ytRegex, \"\").trim();\n\n      if (currentlyPlayingValue !== lastTrack) {\n        document.getElementById(\"stream-stats\").textContent = cleanForDisplay;\n\n        const cleanForAlbum = currentlyPlayingValue.replace(\/\\(.*?\\)\/g, \"\").trim();\n        const [artist, track] = cleanForAlbum.split(\" - \").map(str => str.trim());\n\n        if (artist && track) {\n          const albumArtUrl = await fetchAlbumArt(artist, track, apiKey);\n          document.getElementById(\"radioPlayer\").src =\n            albumArtUrl ||\n            \"https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2024\/07\/nkc_album_default.png\";\n        } else {\n          document.getElementById(\"radioPlayer\").src =\n            \"https:\/\/placehold.co\/300\/EEE\/31343C?font=raleway&text=Geen+Afbeelding\";\n        }\n\n        lastTrack = currentlyPlayingValue;\n      }\n    }\n  } catch (error) {\n    document.getElementById(\"stream-stats\").textContent =\n      \"Het Laatste Nieuws & de Beste Muziek! (Error: \" + error + \")\";\n  }\n}\n\nasync function fetchAlbumArt(artist, track, apiKey) {\n  try {\n    const response = await fetch(\n      `https:\/\/ws.audioscrobbler.com\/2.0\/?method=track.getInfo&api_key=${apiKey}&artist=${encodeURIComponent(\n        artist\n      )}&track=${encodeURIComponent(track)}&format=json`\n    );\n    const data = await response.json();\n    return (\n      data.track?.album?.image?.find(img => img.size === \"large\")?.[\"#text\"] || null\n    );\n  } catch (error) {\n    console.error(\"Error fetching album art:\", error);\n    return null;\n  }\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n  let isMuted = true;\n  let audio = null;\n  const image = document.getElementById(\"radioPlayer\");\n\n  image.addEventListener(\"click\", function () {\n    if (isMuted) {\n      if (!audio) {\n        audio = new Audio(\"https:\/\/radiostreams.noordkop247.nl:9443\/noordkop\");\n        audio.volume = 1;\n        audio.play();\n      } else {\n        audio.volume = 1;\n      }\n      image.src = \"https:\/\/placehold.co\/300\/EEE\/31343C?font=raleway&text=Radio+Playing\";\n      isMuted = false;\n    } else {\n      if (audio) {\n        audio.volume = 0;\n      }\n      image.src = \"https:\/\/placehold.co\/300\/EEE\/31343C?font=raleway&text=Mute+Radio\";\n      isMuted = true;\n    }\n  });\n\n  setInterval(fetchStreamStats, 30000);\n  fetchStreamStats();\n});\n<\/script>\n\n\n\n<!-- RADIO BAR - PROGRAM IMAGE -->\n<img decoding=\"async\" id=\"programimgrefresh\" class=\"programImage\" src=\"https:\/\/cdr.ubn.one\/nk247\/pm\/api\/export.php?naam=signagepm.png\">\n<style>\n    .programImage {\nwidth: 230px;\n  height: 230px;\n  border: 0px;\n  border-radius: 0% !important;\n  position: absolute;\n  top: 650px;\n  left: 1576px;\n    }\n<\/style>\n\n<script>\nwindow.addEventListener('load', () => {\n    const img = document.getElementById('programimgrefresh');\n\n    \/\/ Hour-based cache-buster (changes once per hour)\n    const ts = Math.floor(Date.now() \/ 3600000);\n\n    \/\/ Add cache buster, preserving existing query parameters\n    img.src = `https:\/\/cdr.ubn.one\/nk247\/pm\/api\/export.php?naam=signagepm.png&cache=${ts}`;\n});\n<\/script>\n\n\n\n<!-- TICKER BAR -->\n<style>\n.div_iframe {\n    width: 1690px;\n    height: 58px;\n    border: none;\n    position: absolute;\n    left: 116px;\n    top: 920px;\n    margin: 0;\n    overflow: hidden;\n    z-index: 1;\n    background: #1E1D1B;\n    color: #fff;\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    font-family: 'Montserrat','helvetica',Arial;\n    font-weight: 600;\n    font-size: 20px;\n    padding: 0 10px;\n    box-sizing: border-box;\n}\n\n#rss-title {\n    opacity: 0;\n    transition: opacity 1s;\n    display: flex;\n    align-items: center;\n}\n\n#rss-title.show {\n    opacity: 1;\n}\n\n#rss-title img {\n    width: 24px;       \/* Image size *\/\n    height: 24px;\n    margin-right: 8px; \/* Space between image and title *\/\n    border-radius: 0px;\n}\n\n#date-time {\n    font-size: 20px;\n    font-family: 'Montserrat','helvetica',Arial;\n    font-weight: 600;\n}\n\n.blink-colon {\n    display: inline-block;\n    transition: color 0.0s;\n}\n<\/style>\n\n<div class=\"div_iframe\">\n    <div id=\"rss-title\">Loading&#8230;<\/div>\n    <div id=\"date-time\"><\/div>\n<\/div>\n\n<script>\n\/\/ ========== CONFIGURATION ==========\nconst RSS_URL = 'https:\/\/noordkop247.nl\/?feed=TV';   \/\/ Updated RSS feed URL\nconst RSS_STARTTXT = \"\";\nconst RSS_ENDTXT = 'Bekijk meer Nieuws op: Noordkop247.nl';\nconst DISPLAY_DURATION = 7000;\nconst USE_CORS_PROXY = true;\nconst CORS_PROXY = 'https:\/\/corsproxy.io\/?';\n\n\/\/ ===== IMAGE CONFIG =====\nconst USE_IMAGES = true;\nconst IMAGE_URLS = [\n    'https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2025\/09\/2.png',\n    'https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2025\/09\/4.png',\n    'https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2025\/09\/7.png'\n];\nconst EXTRA_IMAGE = 'https:\/\/labs.ubn.one\/signage\/wp-content\/uploads\/2025\/09\/extra.png';\n\n\/\/ ===== EXTRA TXT FILE =====\nconst EXTRA_TXT_URL = 'https:\/\/cdr.ubn.one\/nk247\/pm\/api\/signagepml.txt'; \n\/\/ ====================================\n\nlet titles = [];\nlet extraTitles = [];\nlet currentIndex = 0;\nlet showingExtra = false;\n\n\/\/ Fetch RSS feed\nasync function fetchRSS() {\n    try {\n        const url = USE_CORS_PROXY ? (CORS_PROXY + encodeURIComponent(RSS_URL)) : RSS_URL;\n        const response = await fetch(url);\n        const data = await response.text();\n\n        const parser = new DOMParser();\n        const xml = parser.parseFromString(data, \"text\/xml\");\n\n        const items = xml.getElementsByTagName('item');\n\n        titles = Array.from(items)\n            .map(i => {\n                const t = i.getElementsByTagName('title')[0];\n                return t ? t.textContent.trim() : '';\n            })\n            .filter(Boolean);\n\n        \/\/ ---------- INSERTED LOGIC (ONLY CHANGE REQUESTED) ----------\n        \/\/ Add RSS_STARTTXT at the beginning if not empty\n        if (RSS_STARTTXT.trim() !== \"\") {\n            titles.unshift(RSS_STARTTXT.trim());\n        }\n\n        \/\/ Add RSS_ENDTXT at the end if not empty\n        if (RSS_ENDTXT.trim() !== \"\") {\n            titles.push(RSS_ENDTXT.trim());\n        }\n        \/\/ -----------------------------------------------------------------\n\n        if (!titles.length) {\n            document.getElementById('rss-title').textContent =\n                \"No RSS items found.\";\n            return;\n        }\n\n        if (EXTRA_TXT_URL) await fetchExtraTitles();\n        startTicker();\n\n    } catch (err) {\n        console.error(\"Failed to fetch RSS:\", err);\n        document.getElementById('rss-title').textContent = \"Failed to load RSS.\";\n    }\n}\n\n\/\/ Fetch external TXT titles\nasync function fetchExtraTitles() {\n    try {\n        const resp = await fetch(EXTRA_TXT_URL);\n        const text = await resp.text();\n        extraTitles = text.split('\\n').map(l => l.trim()).filter(Boolean);\n    } catch (err) {\n        console.warn(\"No extra TXT titles found:\", err);\n    }\n}\n\n\/\/ Ticker logic (unchanged)\nfunction startTicker() {\n    const titleDiv = document.getElementById('rss-title');\n\n    function showNextTitle() {\n        titleDiv.classList.remove('show');\n        setTimeout(() => {\n            let imageHtml = '';\n            let text = '';\n\n            if (!showingExtra) {\n                if (USE_IMAGES && IMAGE_URLS.length > 0) {\n                    const imageIndex = currentIndex % IMAGE_URLS.length;\n                    imageHtml = `<img decoding=\"async\" src=\"${IMAGE_URLS[imageIndex]}\" alt=\"icon\">`;\n                }\n                text = titles[currentIndex];\n                currentIndex++;\n                if (currentIndex >= titles.length) {\n                    currentIndex = 0;\n                    if (extraTitles.length) showingExtra = true;\n                }\n            } else {\n                imageHtml = `<img decoding=\"async\" src=\"${EXTRA_IMAGE}\" alt=\"extra\">`;\n                text = extraTitles[currentIndex];\n                currentIndex++;\n                if (currentIndex >= extraTitles.length) {\n                    currentIndex = 0;\n                    showingExtra = false;\n                }\n            }\n\n            titleDiv.innerHTML = imageHtml + text;\n            titleDiv.classList.add('show');\n        }, 500);\n    }\n\n    \/\/ First item\n    let firstHtml = '';\n    if (USE_IMAGES && IMAGE_URLS.length > 0) {\n        firstHtml = `<img decoding=\"async\" src=\"${IMAGE_URLS[0]}\" alt=\"icon\">`;\n    }\n    titleDiv.innerHTML = firstHtml + titles[0];\n    titleDiv.classList.add('show');\n    currentIndex = 1;\n\n    setInterval(showNextTitle, DISPLAY_DURATION);\n}\n\n\/\/ Live date\/time (unchanged)\nfunction updateDateTime() {\n    const dtDiv = document.getElementById('date-time');\n\n    function createTimeElements() {\n        dtDiv.innerHTML = `\n            <span id=\"date-part\"><\/span><span id=\"colon\" class=\"blink-colon\">:<\/span><span id=\"minute-part\"><\/span>\n        `;\n    }\n\n    createTimeElements();\n    const datePart = document.getElementById('date-part');\n    const colon = document.getElementById('colon');\n    const minutePart = document.getElementById('minute-part');\n\n    let showColon = true;\n\n    function refreshTime() {\n        const now = new Date();\n        const dd = String(now.getDate()).padStart(2, '0');\n        const mm = String(now.getMonth() + 1).padStart(2, '0');\n        const yyyy = now.getFullYear();\n        const hh = String(now.getHours()).padStart(2, '0');\n        const min = String(now.getMinutes()).padStart(2, '0');\n\n        datePart.textContent = `${dd}-${mm}-${yyyy} ${hh}`;\n        minutePart.textContent = min;\n        colon.style.color = showColon ? \"#fff\" : \"#1E1D1B\";\n        showColon = !showColon;\n    }\n\n    refreshTime();\n    setInterval(refreshTime, 1000);\n}\n\n\/\/ Initialize\nfetchRSS();\nupdateDateTime();\n<\/script>\n\n\n\n<!-- BOTTOM INFO BAR -->\n<style>\n   .Info_Bar {\n        width: 1920px;\n        border: none;\n        position: absolute;\n        background-repeat: no-repeat;\n        color: white;\n        font-family: 'Montserrat','helvetica',Arial;\n \tfont-weight: 600;\n        font-size: 20px;\n        text-align: center;\n        left: 0px;\n        top: 990px;\n   }\n<\/style>\n\n<div class=\"Info_Bar\">\n<i class=\"fa-brands fa-whatsapp\"><\/i> 088 5247 247 &nbsp; <i class=\"fa-brands fa-square-facebook\"><\/i>\/Noordkop247 &nbsp; <i class=\"fa-brands fa-square-threads\"><\/i> <i class=\"fa-brands fa-instagram\"><\/i>\/nk247 &nbsp; <i class=\"fa-brands fa-bluesky\"><\/i>\/noordkop247.bsky.social &nbsp; <i class=\"fa-solid fa-radio\"><\/i> 105.6 &#038; 107.7 MHz &#8211; Digitaal &#8211; Noordkop247.nl\/live\n<\/div>\n\n\n\n<!-- PAGE RELOAD EVERY 1 HOURS -->\n<script>\n\/\/ Function to refresh the page\nfunction refreshPage() {\n    window.location.reload(true); \/\/ Reloads the current page from the server\n}\n\n\/\/ Function to calculate the time until the next 1 minute past the hour\nfunction getTimeUntilNextMinutePastHour() {\n    var now = new Date();\n    var nextMinutePastHour = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours() + 1, 1, 0, 0);\n    return nextMinutePastHour - now;\n}\n\n\/\/ Initial setup to refresh the page at the next 1 minute past the hour\nfunction setupInitialRefresh() {\n    var timeUntilNextMinutePastHour = getTimeUntilNextMinutePastHour();\n    setTimeout(function() {\n        refreshPage();\n        \/\/ After the initial refresh, set up a regular interval for future refreshes\n        setInterval(refreshPage, 3600000); \/\/ 3600000 ms = 1 hour\n    }, timeUntilNextMinutePastHour);\n}\n\n\/\/ Set up the initial refresh\nsetupInitialRefresh();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Headlines uit de Noordkop: Bekijk meer Nieuws op Noordkop247.nl NU OP DE RADIO: Loading&#8230; Loading&#8230; 088 5247 247 &nbsp; \/Noordkop247 &nbsp; \/nk247 &nbsp; \/noordkop247.bsky.social &nbsp;&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-34239","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/pages\/34239","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/comments?post=34239"}],"version-history":[{"count":206,"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/pages\/34239\/revisions"}],"predecessor-version":[{"id":36308,"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/pages\/34239\/revisions\/36308"}],"wp:attachment":[{"href":"https:\/\/labs.ubn.one\/signage\/index.php\/wp-json\/wp\/v2\/media?parent=34239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}