diff --git a/sites/meo.pt/meo.pt.config.js b/sites/meo.pt/meo.pt.config.js index c8054d69..e5c9f2b0 100644 --- a/sites/meo.pt/meo.pt.config.js +++ b/sites/meo.pt/meo.pt.config.js @@ -20,21 +20,50 @@ module.exports = { } } }, - parser({ content }) { + async parser({ content }) { + const axios = require('axios') let programs = [] const items = parseItems(content) - items.forEach(item => { + if (!items.length) return programs + + // simple per-run in-memory cache + const detailsCache = new Map() + + for (const item of items) { const start = parseStart(item) let stop = parseStop(item) if (stop < start) { stop = stop.plus({ days: 1 }) } - programs.push({ - title: item.name, + + let description = '' + let image = '' + + const programID = item.uniqueId || null + if (programID) { + let details = detailsCache.get(programID) + if (!details) { + details = await fetchProgramDetails(programID, axios).catch(() => null) + if (details) detailsCache.set(programID, details) + } + if (details) { + description = details.description || description + image = details.image || image + } + } + + const prog = { + title: item.name || 'Sem título', start, stop - }) - }) + } + if (description) prog.description = description + if (image) { + prog.icon = { src: image } + prog.image = image + } + programs.push(prog) + } return programs }, @@ -43,12 +72,15 @@ module.exports = { const data = await axios .post('https://authservice.apps.meo.pt/Services/GridTv/GridTvMng.svc/getGridAnon', null, { headers: { - Origin: 'https://www.meo.pt' + Origin: 'https://www.meo.pt', + 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; en-US Trident/4.0)' } }) .then(r => r.data) .catch(console.log) + // channel logo at data.d.channels.logo + return data.d.channels .map(item => { return { @@ -80,3 +112,42 @@ function parseItems(content) { return Array.isArray(programs) ? programs : [] } + +async function fetchProgramDetails(programID, axiosInstance) { + try { + const response = await axiosInstance.post( + 'https://authservice.apps.meo.pt/Services/GridTv/GridTvMng.svc/getProgramDetails', + { + service: 'programdetail', + programID: String(programID), + accountID: '' + }, + { + headers: { + Origin: 'https://www.meo.pt', + 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; en-US Trident/4.0)' + }, + timeout: 10000 + } + ) + + const data = response.data + // Response structure has program data directly in data.d + const program = data?.d + if (!program || typeof program !== 'object') return null + + // Build image URL using MEO's image handler + let image = null + if (program.progName && program.channelSigla) { + const encodedTitle = encodeURIComponent(program.progName) + image = `https://proxycache.online.meo.pt/eemstb/ImageHandler.ashx?evTitle=${encodedTitle}&chCallLetter=${program.channelSigla}&profile=16_9&width=600` + } + + const description = program.description || null + + return { description, image } + } catch { + // Silent fail returning null so parser continues + return null + } +} diff --git a/sites/meo.pt/meo.pt.test.js b/sites/meo.pt/meo.pt.test.js index 7decee75..d86e9d2d 100644 --- a/sites/meo.pt/meo.pt.test.js +++ b/sites/meo.pt/meo.pt.test.js @@ -7,6 +7,10 @@ const customParseFormat = require('dayjs/plugin/customParseFormat') dayjs.extend(customParseFormat) dayjs.extend(utc) +const axios = require('axios') + +jest.mock('axios') + const date = dayjs.utc('2022-12-02', 'YYYY-MM-DD').startOf('d') const channel = { site_id: 'RTPM', @@ -39,9 +43,13 @@ it('can generate valid request method', () => { }) }) -it('can parse response', () => { +it('can parse response', async () => { const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json')) - let results = parser({ content }).map(p => { + + axios.post.mockResolvedValue({ data: {} }) + + let results = await parser({ content }) + results = results.map(p => { p.start = p.start.toJSON() p.stop = p.stop.toJSON() return p @@ -54,7 +62,7 @@ it('can parse response', () => { }) }) -it('can handle empty guide', () => { - const result = parser({ content: '', channel, date }) +it('can handle empty guide', async () => { + const result = await parser({ content: '', channel, date }) expect(result).toMatchObject([]) })