mirror of
https://github.com/iptv-org/epg
synced 2026-09-10 13:56:51 -04:00
Properly generate TV schedule URL when redirected.
On www.tvpassport.com when schedule redirected to new URL, the requested date stripped from new URL so the fetched schedules only valid for current date. If URL was redirected, simply use the new URL with requested date appended. Signed-off-by: Toha <tohenk@yahoo.com>
This commit is contained in:
@@ -11,29 +11,24 @@ dayjs.extend(utc)
|
|||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
|
|
||||||
|
const headers = {}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
site: 'tvpassport.com',
|
site: 'tvpassport.com',
|
||||||
days: 3,
|
days: 3,
|
||||||
url({ channel, date }) {
|
async url({ channel, date }) {
|
||||||
return `https://www.tvpassport.com/tv-listings/stations/${channel.site_id}/${date.format(
|
return await getSiteUrl(channel, date.format('YYYY-MM-DD'))
|
||||||
'YYYY-MM-DD'
|
|
||||||
)}`
|
|
||||||
},
|
},
|
||||||
async request() {
|
request: {
|
||||||
return {
|
timeout: 30000,
|
||||||
timeout: 30000,
|
headers
|
||||||
headers: {
|
|
||||||
Cookie: await getCookie()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
parser: function ({ content }) {
|
parser({ content }) {
|
||||||
let programs = []
|
const programs = []
|
||||||
const currentTimezone = parseCurrentTimezone(content)
|
const [$, tz, items] = parseItems(content)
|
||||||
const items = parseItems(content)
|
for (const item of items) {
|
||||||
for (let item of items) {
|
const $item = $(item)
|
||||||
const $item = cheerio.load(item)
|
const start = parseStart($item, tz)
|
||||||
const start = parseStart($item, currentTimezone)
|
|
||||||
const duration = parseDuration($item)
|
const duration = parseDuration($item)
|
||||||
const stop = start.add(duration, 'm')
|
const stop = start.add(duration, 'm')
|
||||||
let title = parseTitle($item)
|
let title = parseTitle($item)
|
||||||
@@ -85,7 +80,7 @@ module.exports = {
|
|||||||
await doFetch(queue, async (url, res) => {
|
await doFetch(queue, async (url, res) => {
|
||||||
if (!res) return
|
if (!res) return
|
||||||
|
|
||||||
const [, site_id] = url.match(/\/tv-listings\/stations\/(.*)$/)
|
const site_id = getSiteId(url)
|
||||||
|
|
||||||
console.log(`[${i}/${total}]`, url)
|
console.log(`[${i}/${total}]`, url)
|
||||||
|
|
||||||
@@ -109,63 +104,88 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCookie() {
|
async function getSiteUrl(channel, date) {
|
||||||
const res = await axios.get('https://www.tvpassport.com/tv-listings')
|
const f = () =>
|
||||||
const setCookie = res.headers['set-cookie']
|
`https://www.tvpassport.com/tv-listings/stations/${channel.site_id}/${date}`
|
||||||
if (!setCookie || setCookie.length === 0) return ''
|
let url = f()
|
||||||
const cookies = setCookie.map(cookie => cookie.split(';')[0])
|
const res = await axios.head(url, { headers })
|
||||||
return cookies.join('; ')
|
.then(res => saveCookies(res))
|
||||||
|
.then(res => res?.request?.res?.responseUrl)
|
||||||
|
.catch(console.error)
|
||||||
|
if (res && res !== url) {
|
||||||
|
channel.site_id = getSiteId(res)
|
||||||
|
url = f()
|
||||||
|
}
|
||||||
|
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSiteId(url) {
|
||||||
|
const [, site_id] = url.match(/\/tv-listings\/stations\/(.*)$/)
|
||||||
|
|
||||||
|
return site_id
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveCookies(res) {
|
||||||
|
if (res.headers && Array.isArray(res.headers['set-cookie'])) {
|
||||||
|
const cookies = []
|
||||||
|
cookies.push(...res.headers['set-cookie']
|
||||||
|
.map(cookie => cookie.split(';')[0].trim()))
|
||||||
|
headers.Cookie = cookies.length ? cookies.join('; ') : null
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDescription($item) {
|
function parseDescription($item) {
|
||||||
return $item('*').data('description')
|
return $item.data('description')
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseImage($item) {
|
function parseImage($item) {
|
||||||
const showpicture = $item('*').data('showpicture')
|
const showpicture = $item.data('showpicture')
|
||||||
const url = new URL(showpicture, 'https://cdn.tvpassport.com/image/show/960x540/')
|
const url = new URL(showpicture, 'https://cdn.tvpassport.com/image/show/960x540/')
|
||||||
|
|
||||||
return url.href
|
return url.href
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTitle($item) {
|
function parseTitle($item) {
|
||||||
return $item('*').data('showname').toString()
|
return $item.data('showname').toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSubTitle($item) {
|
function parseSubTitle($item) {
|
||||||
return $item('*').data('episodetitle')?.toString() || null
|
return $item.data('episodetitle')?.toString() || null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseYear($item) {
|
function parseYear($item) {
|
||||||
return $item('*').data('year')?.toString() || null
|
return $item.data('year')?.toString() || null
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCategory($item) {
|
function parseCategory($item) {
|
||||||
const showtype = $item('*').data('showtype')
|
const showtype = $item.data('showtype')
|
||||||
|
|
||||||
return showtype ? showtype.split(', ') : []
|
return showtype ? showtype.split(', ') : []
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseActors($item) {
|
function parseActors($item) {
|
||||||
const cast = $item('*').data('cast')
|
const cast = $item.data('cast')
|
||||||
|
|
||||||
return cast ? cast.split(', ') : []
|
return cast ? cast.split(', ') : []
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDirector($item) {
|
function parseDirector($item) {
|
||||||
const director = $item('*').data('director')
|
const director = $item.data('director')
|
||||||
|
|
||||||
return director ? director.split(', ') : []
|
return director ? director.split(', ') : []
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseGuest($item) {
|
function parseGuest($item) {
|
||||||
const guest = $item('*').data('guest')
|
const guest = $item.data('guest')
|
||||||
|
|
||||||
return guest ? guest.split(', ') : []
|
return guest ? guest.split(', ') : []
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRating($item) {
|
function parseRating($item) {
|
||||||
const rating = $item('*').data('rating')
|
const rating = $item.data('rating')
|
||||||
|
|
||||||
return rating
|
return rating
|
||||||
? {
|
? {
|
||||||
@@ -176,28 +196,24 @@ function parseRating($item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parseStart($item, currentTimezone) {
|
function parseStart($item, currentTimezone) {
|
||||||
const time = $item('*').data('st')
|
const time = $item.data('st')
|
||||||
|
|
||||||
return dayjs.tz(time, 'YYYY-MM-DD HH:mm:ss', currentTimezone)
|
return dayjs.tz(time, 'YYYY-MM-DD HH:mm:ss', currentTimezone)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDuration($item) {
|
function parseDuration($item) {
|
||||||
const duration = $item('*').data('duration')
|
const duration = $item.data('duration')
|
||||||
|
|
||||||
return parseInt(duration)
|
return parseInt(duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseItems(content) {
|
function parseItems(content) {
|
||||||
if (!content) return []
|
if (!content) return [null, null, []]
|
||||||
const $ = cheerio.load(content)
|
const $ = cheerio.load(content)
|
||||||
|
|
||||||
return $('.station-listings .list-group-item').toArray()
|
return [
|
||||||
|
$,
|
||||||
|
$('#timezone_selector').val() || 'America/New_York',
|
||||||
|
$('.station-listings .list-group-item').toArray()
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseCurrentTimezone(content) {
|
|
||||||
if (!content) return 'America/New_York'
|
|
||||||
const $ = cheerio.load(content)
|
|
||||||
|
|
||||||
return $('#timezone_selector').val()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
const { parser, url } = require('./tvpassport.com.config.js')
|
const { parser, url } = require('./tvpassport.com.config.js')
|
||||||
|
const axios = require('axios')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
|
jest.mock('axios')
|
||||||
|
|
||||||
const date = dayjs.utc('2022-10-04', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2022-10-04', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = {
|
const channel = {
|
||||||
site_id: 'youtoo-america-network/5463',
|
site_id: 'youtoo-america-network/5463',
|
||||||
xmltv_id: 'YTATV.us'
|
xmltv_id: 'YTATV.us'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
axios.head.mockImplementation(() => {
|
||||||
expect(url({ channel, date })).toBe(
|
return Promise.resolve({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can generate valid url', async () => {
|
||||||
|
expect(await url({ channel, date })).toBe(
|
||||||
'https://www.tvpassport.com/tv-listings/stations/youtoo-america-network/5463/2022-10-04'
|
'https://www.tvpassport.com/tv-listings/stations/youtoo-america-network/5463/2022-10-04'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user