diff --git a/SITES.md b/SITES.md
index 8178ba28e..c3a569249 100644
--- a/SITES.md
+++ b/SITES.md
@@ -22,11 +22,11 @@
| beinsports.com | 130 | 81 | 🟢 | |
| berrymedia.co.kr | 5 | 5 | 🟢 | |
| cableplus.com.uy | 171 | 44 | 🟢 | |
- | canalplus.com | 13118 | 179 | 🟢 | |
+ | canalplus.com | 13118 | 179 | 🟢 | https://github.com/iptv-org/epg/issues/3002 |
| cgates.lt | 47 | 29 | 🟢 | |
| chada.ma | 1 | 1 | 🟢 | |
| chaines-tv.orange.fr | 373 | 328 | 🟢 | |
- | claro.com.br | 273 | 0 | 🟢 | |
+ | claro.com.br | 273 | 0 | 🟢 | https://github.com/iptv-org/epg/issues/2988 |
| clarotvmais.com.br | 158 | 0 | 🟢 | |
| clickthecity.com | 32 | 30 | 🟢 | |
| content.astro.com.my | 149 | 93 | 🟢 | |
@@ -38,7 +38,7 @@
| derana.lk | 1 | 1 | 🟢 | |
| digea.gr | 88 | 0 | 🟢 | |
| digiturk.com.tr | 112 | 91 | 🟢 | |
- | directv.com | 1043 | 640 | 🔴 | https://github.com/iptv-org/epg/issues/2284 |
+ | directv.com | 1043 | 640 | 🔴 | https://github.com/iptv-org/epg/issues/3001, https://github.com/iptv-org/epg/issues/2284 |
| directv.com.ar | 371 | 0 | 🔴 | https://github.com/iptv-org/epg/issues/2339 |
| directv.com.uy | 374 | 59 | 🟢 | |
| dishtv.in | 434 | 326 | 🟢 | |
@@ -146,7 +146,7 @@
| ruv.is | 2 | 2 | 🟢 | |
| s.mxtv.jp | 2 | 2 | 🟢 | |
| sat.tv | 30308 | 249 | 🟢 | |
- | shahid.mbc.net | 206 | 167 | 🟢 | |
+ | shahid.mbc.net | 207 | 168 | 🟢 | |
| siba.com.co | 98 | 95 | 🟢 | |
| singtel.com | 155 | 113 | 🟢 | |
| sjonvarp.is | 13 | 13 | 🟢 | |
@@ -212,10 +212,11 @@
| tvmusor.hu | 99 | 66 | 🟢 | |
| tvmustra.hu | 189 | 0 | 🟢 | |
| tvpassport.com | 19287 | 2496 | 🟢 | |
- | tvplus.com.tr | 150 | 144 | 🟢 | |
+ | tvplus.com.tr | 150 | 144 | 🟢 | https://github.com/iptv-org/epg/issues/2983 |
| tvprofil.com | 9091 | 408 | 🟢 | |
| tvtv.us | 2299 | 2230 | 🟢 | |
| v3.myafn.dodmedia.osd.mil | 8 | 8 | 🟢 | |
+ | vantagetv.ee | 3 | 1 | 🟢 | |
| vidio.com | 57 | 52 | 🟢 | |
| virginmediatelevision.ie | 5 | 5 | 🟢 | |
| virgintvgo.virginmedia.com | 238 | 181 | 🟢 | |
@@ -229,7 +230,7 @@
| wavve.com | 77 | 76 | 🟢 | |
| web.magentatv.de | 348 | 226 | 🟢 | https://github.com/iptv-org/epg/issues/2966 |
| webtv.delta.nl | 247 | 204 | 🟢 | |
- | winplay.co | 2 | 2 | 🟢 | |
+ | winplay.co | 2 | 2 | 🟢 | https://github.com/iptv-org/epg/issues/3003 |
| worldfishingnetwork.com | 1 | 1 | 🟢 | |
| www3.nhk.or.jp | 1 | 1 | 🟢 | |
| xem.kplus.vn | 77 | 0 | 🟢 | |
@@ -237,7 +238,7 @@
| yes.co.il | 174 | 0 | 🟢 | |
| zap.co.ao | 114 | 63 | 🟢 | |
| zap2it.com | 595 | 0 | 🟢 | |
- | ziggogo.tv | 156 | 150 | 🟢 | |
+ | ziggogo.tv | 156 | 150 | 🟢 | https://github.com/iptv-org/epg/issues/2977, https://github.com/iptv-org/epg/issues/2976 |
| znbc.co.zm | 4 | 4 | 🟢 | |
| zuragt.mn | 34 | 27 | 🟢 | |
diff --git a/sites/movistarplus.es/movistarplus.es.config.js b/sites/movistarplus.es/movistarplus.es.config.js
index c58b51901..00930b959 100644
--- a/sites/movistarplus.es/movistarplus.es.config.js
+++ b/sites/movistarplus.es/movistarplus.es.config.js
@@ -1,6 +1,11 @@
const axios = require('axios')
const cheerio = require('cheerio')
const dayjs = require('dayjs')
+const utc = require('dayjs/plugin/utc')
+const timezone = require('dayjs/plugin/timezone')
+
+dayjs.extend(utc)
+dayjs.extend(timezone)
module.exports = {
site: 'movistarplus.es',
@@ -8,35 +13,87 @@ module.exports = {
url({ channel, date }) {
return `https://www.movistarplus.es/programacion-tv/${channel.site_id}/${date.format('YYYY-MM-DD')}`
},
- async parser({ content }) {
+ request: {
+ headers: {
+ 'User-Agent':
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
+ 'Accept-Language': 'es-ES,es;q=0.9,en;q=0.8',
+ Referer: 'https://www.movistarplus.es/programacion-tv'
+ },
+ maxRedirects: 5
+ },
+ async parser({ content, date }) {
let programs = []
- let items = parseItems(content)
- if (!items.length) return programs
-
const $ = cheerio.load(content)
- const programElements = $('div[id^="ele-"]').get()
- for (let i = 0; i < items.length; i++) {
- const el = items[i]
- let description = null
+ const programDivs = $('div[id^="ele-"]').toArray()
- if (programElements[i]) {
- const programDiv = $(programElements[i])
- const programLink = programDiv.find('a').attr('href')
-
- if (programLink) {
- const idMatch = programLink.match(/id=(\d+)/)
- if (idMatch && idMatch[1]) {
- description = await getProgramDescription(programLink).catch(() => null)
+ for (let i = 0; i < programDivs.length; i++) {
+ const el = $(programDivs[i])
+
+ const title = el.find('li.title').text().trim()
+ if (!title) continue
+
+ const timeText = el.find('li.time').text().trim()
+ if (!timeText) continue
+
+ const [hours, minutes] = timeText.split(':').map(h => parseInt(h, 10))
+
+ // Parse time in Spain timezone (Europe/Madrid)
+ let startDate = dayjs.tz(
+ `${date.format('YYYY-MM-DD')} ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`,
+ 'YYYY-MM-DD HH:mm',
+ 'Europe/Madrid'
+ )
+
+ // If the time is in early morning (before 5 AM), it's the next day
+ if (hours < 5) {
+ startDate = startDate.add(1, 'day')
+ }
+
+ // Calculate end time from next program's start time
+ let endDate
+ if (i < programDivs.length - 1) {
+ const nextEl = $(programDivs[i + 1])
+ const nextTimeText = nextEl.find('li.time').text().trim()
+ if (nextTimeText) {
+ const [nextHours, nextMinutes] = nextTimeText.split(':').map(h => parseInt(h, 10))
+ endDate = dayjs.tz(
+ `${date.format('YYYY-MM-DD')} ${nextHours.toString().padStart(2, '0')}:${nextMinutes.toString().padStart(2, '0')}`,
+ 'YYYY-MM-DD HH:mm',
+ 'Europe/Madrid'
+ )
+
+ // If the next time is in early morning (before 5 AM), it's the next day
+ if (nextHours < 5) {
+ endDate = endDate.add(1, 'day')
+ }
+
+ // If end time is still before or same as start time, add another day
+ if (endDate.isBefore(startDate) || endDate.isSame(startDate)) {
+ endDate = endDate.add(1, 'day')
}
}
}
+ // If no end time, use start of next day
+ if (!endDate) {
+ endDate = startDate.add(1, 'day').startOf('day')
+ }
+
+ const programLink = el.find('a').attr('href')
+ let description = null
+
+ if (programLink) {
+ description = await getProgramDescription(programLink).catch(() => null)
+ }
+
programs.push({
- title: el.item.name,
- description: description,
- start: dayjs(el.item.startDate),
- stop: dayjs(el.item.endDate)
+ title,
+ description,
+ start: startDate,
+ stop: endDate
})
}
@@ -44,7 +101,13 @@ module.exports = {
},
async channels() {
const html = await axios
- .get('https://www.movistarplus.es/programacion-tv')
+ .get('https://www.movistarplus.es/programacion-tv', {
+ headers: {
+ 'User-Agent':
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
+ }
+ })
.then(r => r.data)
.catch(console.log)
@@ -65,33 +128,17 @@ module.exports = {
}
}
-function parseItems(content) {
- try {
- const $ = cheerio.load(content)
- let scheme = $('script:contains("@type": "ItemList")').html()
- scheme = JSON.parse(scheme)
- if (!scheme || !Array.isArray(scheme.itemListElement)) return []
-
- return scheme.itemListElement
- } catch {
- return []
- }
-}
-
async function getProgramDescription(programUrl) {
- try {
- const response = await axios.get(programUrl, {
- headers: {
- 'Referer': 'https://www.movistarplus.es/programacion-tv/'
- }
- })
+ const response = await axios.get(programUrl, {
+ headers: {
+ 'User-Agent':
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ Referer: 'https://www.movistarplus.es/programacion-tv/'
+ }
+ })
- const $ = cheerio.load(response.data)
- const description = $('.show-content .text p').first().text().trim() || null
+ const $ = cheerio.load(response.data)
+ const description = $('.show-content .text p').first().text().trim() || null
- return description
- } catch (error) {
- console.error(`Error fetching description from ${programUrl}:`, error.message)
- return null
- }
+ return description
}
diff --git a/sites/vantagetv.ee/__data__/content.xml b/sites/vantagetv.ee/__data__/content.xml
new file mode 100644
index 000000000..b819412df
--- /dev/null
+++ b/sites/vantagetv.ee/__data__/content.xml
@@ -0,0 +1,1069 @@
+
+
+
+ Vantage Music
+
+
+ Vantage Dance
+
+
+ Vantage Rock
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ brand:new
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Urbanzone
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Old Skool Hip-Hop Show
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Rockzone
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Clubzone
+
+
+ Partyzone
+
+
+ Chillout Zone
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ The European Top 20
+
+
+ Video Mix
+
+
+ Urbanzone
+
+
+ Old Skool Hip-Hop Show
+
+
+ Rockzone
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ The UK Dance Top 20
+
+
+ Old Skool Hip-Hop Show
+
+
+ Rockzone
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Chillout Zone
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ brand:new
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+ Get ready for your day with Vantage Music
+
+
+ It's The 80's
+ The start of the music video era, with 80's classics not to be forgotten as well as some you probably have forgotten (for good reason!).
+
+
+ The 90's
+ Britpop, Jamming basslines, Catchy pop, forgotten boy bands with a bit of hip hop. It's the 90's baby.
+
+
+ Ultimate 2000's
+ A mix of the hits of 2000's along with some more lesser known artists.
+
+
+ Video Mix
+ Driving basslines, catchy pop, cool boy bands, and top-notch hip hop! You'll find all this and more at WILD 90S. Flashback vibes guaranteed! (Station info)
+
+
+ It's The 80's
+ The start of the music video era, with 80's classics not to be forgotten as well as some you probably have forgotten (for good reason!).
+
+
+ The 90's
+ Britpop, Jamming basslines, Catchy pop, forgotten boy bands with a bit of hip hop. It's the 90's baby.
+
+
+ Ultimate 2000's
+ A mix of the hits of 2000's along with some more lesser known artists.
+
+
+ Urbanzone
+ A playlist of songs to come out from the modern rap scene, along with some upcoming underground rap artists.
+
+
+ Night Videos
+ Whether you can't sleep, doing the night shift, or even if you just want to keep yourself awake, Vantage has non-stop commercial free music all night long.
+
+
+ Breakfast with Vantage Music
+ Get ready for your day with Vantage Music
+
+
+ It's The 80's
+ The start of the music video era, with 80's classics not to be forgotten as well as some you probably have forgotten (for good reason!).
+
+
+ The 90's
+ Britpop, Jamming basslines, Catchy pop, forgotten boy bands with a bit of hip hop. It's the 90's baby.
+
+
+ Ultimate 2000's
+ A mix of the hits of 2000's along with some more lesser known artists.
+
+
+ Video Mix
+ Driving basslines, catchy pop, cool boy bands, and top-notch hip hop! You'll find all this and more at WILD 90S. Flashback vibes guaranteed! (Station info)
+
+
+ It's The 80's
+ The start of the music video era, with 80's classics not to be forgotten as well as some you probably have forgotten (for good reason!).
+
+
+ The 90's
+ Britpop, Jamming basslines, Catchy pop, forgotten boy bands with a bit of hip hop. It's the 90's baby.
+
+
+ Ultimate 2000's
+ A mix of the hits of 2000's along with some more lesser known artists.
+
+
+ Old Skool Hip-Hop Show
+
+
+ Night Videos
+ Whether you can't sleep, doing the night shift, or even if you just want to keep yourself awake, Vantage has non-stop commercial free music all night long.
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Rockzone
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Clubzone
+
+
+ Partyzone
+
+
+ Night Videos
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ The European Top 20
+
+
+ Video Mix
+
+
+ Urbanzone
+
+
+ Old Skool Hip-Hop Show
+
+
+ Rockzone
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Breakfast with Vantage Music
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Video Mix
+
+
+ The UK Dance Top 20
+
+
+ Old Skool Hip-Hop Show
+
+
+ Rockzone
+
+
+ It's The 80's
+
+
+ The 90's
+
+
+ Ultimate 2000's
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Chillout Zone
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Dance
+
+
+ Don't Stop The Dance
+
+
+ The UK Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ The German Official Dance Chart
+
+
+ Don't Stop The Dance
+
+
+ Clubzone Reloaded
+
+
+ Partyzone Reloaded
+
+
+ Dance All Night
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
+ Breakfast with Vantage Rock
+ Get ready for your day with Vantage Rock
+
+
+ Can't Stop The Rock
+ Commercial free rock music, all day long
+
+
+ Rock All Night
+ It might be late, but that's no reason to stop!
+
+
\ No newline at end of file
diff --git a/sites/vantagetv.ee/readme.md b/sites/vantagetv.ee/readme.md
new file mode 100644
index 000000000..b7c4b118a
--- /dev/null
+++ b/sites/vantagetv.ee/readme.md
@@ -0,0 +1,15 @@
+# vantagetv.ee
+
+https://vantagetv.ee/epg.xml
+
+### Download the guide
+
+```sh
+npm run grab --- --site=vantagetv.ee
+```
+
+### Test
+
+```sh
+npm test --- vantagetv.ee
+```
diff --git a/sites/vantagetv.ee/vantagetv.ee.channels.xml b/sites/vantagetv.ee/vantagetv.ee.channels.xml
new file mode 100644
index 000000000..609cc8ca2
--- /dev/null
+++ b/sites/vantagetv.ee/vantagetv.ee.channels.xml
@@ -0,0 +1,6 @@
+
+
+ Vantage Music
+ Vantage Dance
+ Vantage Rock
+
\ No newline at end of file
diff --git a/sites/vantagetv.ee/vantagetv.ee.config.js b/sites/vantagetv.ee/vantagetv.ee.config.js
new file mode 100644
index 000000000..9cd489f43
--- /dev/null
+++ b/sites/vantagetv.ee/vantagetv.ee.config.js
@@ -0,0 +1,27 @@
+const parser = require('epg-parser')
+
+module.exports = {
+ site: 'vantagetv.ee',
+ days: 2,
+ url: 'http://vantagetv.ee/epg.xml',
+ parser: function ({ content, channel, date }) {
+ let programs = []
+ const items = parseItems(content, channel, date)
+ items.forEach(item => {
+ programs.push({
+ title: item.title?.[0]?.value,
+ description: item.desc?.[0]?.value,
+ start: item.start,
+ stop: item.stop
+ })
+ })
+
+ return programs
+ }
+}
+
+function parseItems(content, channel, date) {
+ const { programs } = parser.parse(content)
+
+ return programs.filter(p => p.channel === channel.site_id && date.isSame(p.start, 'day'))
+}
diff --git a/sites/vantagetv.ee/vantagetv.ee.test.js b/sites/vantagetv.ee/vantagetv.ee.test.js
new file mode 100644
index 000000000..5db1dd3a9
--- /dev/null
+++ b/sites/vantagetv.ee/vantagetv.ee.test.js
@@ -0,0 +1,41 @@
+const { parser, url } = require('./vantagetv.ee.config.js')
+const fs = require('fs')
+const path = require('path')
+const dayjs = require('dayjs')
+const utc = require('dayjs/plugin/utc')
+const customParseFormat = require('dayjs/plugin/customParseFormat')
+dayjs.extend(customParseFormat)
+dayjs.extend(utc)
+
+const date = dayjs.utc('2026-02-05', 'YYYY-MM-DD').startOf('d')
+const channel = { site_id: 'vrock' }
+
+it('can generate valid url', () => {
+ expect(url).toBe('http://vantagetv.ee/epg.xml')
+})
+
+it('can parse response', () => {
+ const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.xml'))
+
+ const results = parser({ content, channel, date })
+
+ expect(results.length).toBe(3)
+ expect(results[0]).toMatchObject({
+ title: 'Breakfast with Vantage Rock',
+ description: 'Get ready for your day with Vantage Rock',
+ start: '2026-02-05T04:00:00.000Z',
+ stop: '2026-02-05T08:00:00.000Z'
+ })
+ expect(results[2]).toMatchObject({
+ title: 'Rock All Night',
+ description: 'It might be late, but that's no reason to stop!',
+ start: '2026-02-05T22:00:00.000Z',
+ stop: '2026-02-06T04:00:00.000Z'
+ })
+})
+
+it('can handle empty guide', () => {
+ const results = parser({ content: '' })
+
+ expect(results).toMatchObject([])
+})