diff --git a/sites/telecablesat.fr/telecablesat.fr.config.js b/sites/telecablesat.fr/telecablesat.fr.config.js new file mode 100644 index 00000000..1157c08b --- /dev/null +++ b/sites/telecablesat.fr/telecablesat.fr.config.js @@ -0,0 +1,120 @@ +const cheerio = require('cheerio') +const axios = require('axios') +const dayjs = require('dayjs') + +const utc = require('dayjs/plugin/utc') +const timezone = require('dayjs/plugin/timezone') +const customParseFormat = require('dayjs/plugin/customParseFormat') + +dayjs.extend(utc) +dayjs.extend(timezone) +dayjs.extend(customParseFormat) + +const API_ENDPOINT = 'https://tv-programme.telecablesat.fr/chaine' + +module.exports = { + site: 'telecablesat.fr', + url: function ({ channel, date }) { + return `${API_ENDPOINT}/${channel.site_id}/index.html?date=${date.format('YYYY-MM-DD')}` + }, + async parser({ content, date, channel }) { + let programs = [] + let items = parseItems(content) + if (!items.length) return programs + const url = `${API_ENDPOINT}/${channel.site_id}/index.html` + const promises = [ + axios.get(`${url}?date=${date.format('YYYY-MM-DD')}&period=noon`), + axios.get(`${url}?date=${date.format('YYYY-MM-DD')}&period=afternoon`) + ] + await Promise.allSettled(promises).then(results => { + results.forEach(r => { + if (r.status === 'fulfilled') { + items = items.concat(parseItems(r.value.data)) + } + }) + }) + for (let item of items) { + const prev = programs[programs.length - 1] + const $item = cheerio.load(item) + let start = parseStart($item, date) + if (prev) { + if (start.isBefore(prev.start)) { + start = start.add(1, 'd') + date = date.add(1, 'd') + } + prev.stop = start + } + const stop = start.add(1, 'h') + programs.push({ + title: parseTitle($item), + description: parseDescription($item), + icon: parseIcon($item), + start, + stop + }) + } + + return programs + }, + async channels() { + const data = await axios + .get(`https://tv-programme.telecablesat.fr/`) + .then(r => r.data) + .catch(console.log) + + const $ = cheerio.load(data) + const items = $( + '#ptgv_left > section.main > div > div > div:nth-child(1) > div > div > div.linker.with_search > div.inside > div.scroller > a' + ).toArray() + + return items.map(item => { + const $item = cheerio.load(item) + const link = $item('*').attr('href') + const [_, site_id] = link.match(/\/chaine\/(\d+)\//) || [null, null] + const name = $item('*').text().trim() + return { + lang: 'fr', + site_id, + name + } + }) + } +} + +function parseStart($item, date) { + const timeString = $item('.schedule-hour').text() + if (!timeString) return null + + return dayjs.tz(`${date.format('YYYY-MM-DD')} ${timeString}`, 'YYYY-MM-DD HH:mm', 'Europe/Paris') +} + +function parseIcon($item) { + const imgSrc = $item('img').attr('src') + + return imgSrc ? `https:${imgSrc}` : null +} + +function parseTitle($item) { + return $item('div.item-content > div.title-left').text().trim() +} + +function parseDescription($item) { + return $item('div.item-content > p').text() +} + +async function loadProgramDetails(item) { + if (!item.onClick || !item.onClick.URLPage) return {} + + return await axios + .get(item.onClick.URLPage) + .then(r => r.data) + .catch(console.error) +} + +function parseItems(content) { + const $ = cheerio.load(content) + + return $( + '#ptgv_left > div.container > div.row.no-gutter > div.col-md-8 > div > div > div > div > div > div > div.news' + ).toArray() +} diff --git a/sites/telecablesat.fr/telecablesat.fr.test.js b/sites/telecablesat.fr/telecablesat.fr.test.js new file mode 100644 index 00000000..b933005c --- /dev/null +++ b/sites/telecablesat.fr/telecablesat.fr.test.js @@ -0,0 +1,106 @@ +// npm run channels:parse -- --config=./sites/telecablesat.fr/telecablesat.fr.config.js --output=./sites/telecablesat.fr/telecablesat.fr_fr.channels.xml +// npx epg-grabber --config=sites/telecablesat.fr/telecablesat.fr.config.js --channels=sites/telecablesat.fr/telecablesat.fr_fr.channels.xml --output=guide.xml --days=2 + +const { parser, url } = require('./telecablesat.fr.config.js') +const axios = require('axios') +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('2022-03-11', 'YYYY-MM-DD').startOf('d') +const channel = { + site_id: '2', + xmltv_id: '13emeRue.us' +} + +jest.mock('axios') + +it('can generate valid url', () => { + expect(url({ channel, date })).toBe( + 'https://tv-programme.telecablesat.fr/chaine/2/index.html?date=2022-03-11' + ) +}) + +it('can parse response', done => { + const content = `
06:25

Des randonneurs font une macabre découverte en installant leur tente dans la nature : une jeune fille de Lusagne a en effet été sauvagement assassinée et son corps a été dissimulé sommairement dans les buissons. Rapidement, des lettres anonymes...

08:05

Alors que les fêtes de fin d'année battent leur plein, le commissaire Rousseau se voit confronté à une délicate affaire. En peu de temps, une troisième jeune fille vient d'être retrouvée assassinée. Le vieux limier ne croit pas à l'hypothèse...

` + + axios.get.mockImplementation(url => { + if ( + url === 'https://tv-programme.telecablesat.fr/chaine/2/index.html?date=2022-03-11&period=noon' + ) { + return Promise.resolve({ + data: '
12:35

Brett, Foster et Kidd font une virée dans l\'Indiana. Sur la route, ils sont les témoins d\'un accident. Un bus qui transporte une équipe de hockey percute une voiture en panne. Sans réseau téléphonique, ils ne peuvent prévenir leurs collègues. En...

' + }) + } else if ( + url === + 'https://tv-programme.telecablesat.fr/chaine/2/index.html?date=2022-03-11&period=afternoon' + ) { + return Promise.resolve({ + data: '
01:45

Lors d\'une urgence, la vie du lieutenant Casey est soudainement mise en danger : un homme le menace avec une arme. Grissom prévient la caserne qu\'ils devront se préparer à une évaluation de leur performance. Otis apprend qu\'il a remporté un prix...

' + }) + } else { + return Promise.resolve({ data: '' }) + } + }) + + parser({ content, date, channel }) + .then(result => { + result.map(p => { + p.start = p.start.toJSON() + p.stop = p.stop.toJSON() + return p + }) + + expect(result).toMatchObject([ + { + start: '2022-03-11T05:25:00.000Z', + stop: '2022-03-11T07:05:00.000Z', + title: 'Alex Hugo', + description: + 'Des randonneurs font une macabre découverte en installant leur tente dans la nature : une jeune fille de Lusagne a en effet été sauvagement assassinée et son corps a été dissimulé sommairement dans les buissons. Rapidement, des lettres anonymes...', + icon: 'https://tv.cdnartwhere.eu/cache/i2/Dc5BDsIgEADAv3C2pQvC0r6FCyxLq6aUFEyMxr_rvGA-IobGYhFb77UtXnq516FuRz_aQKmM4f08mdPKY-HuJR2lh1vh02RHABRSnukK0-wYMwBERBei1rOXUwBjOc2oCSgbIqUQ0KrILqNh5VwEl9iO97qKi9hDe_wf1uJLOyO-Pw.jpg' + }, + { + start: '2022-03-11T07:05:00.000Z', + stop: '2022-03-11T11:35:00.000Z', + title: 'Les saisons meurtrières : hiver rouge', + description: + "Alors que les fêtes de fin d'année battent leur plein, le commissaire Rousseau se voit confronté à une délicate affaire. En peu de temps, une troisième jeune fille vient d'être retrouvée assassinée. Le vieux limier ne croit pas à l'hypothèse...", + icon: 'https://tv.cdnartwhere.eu/cache/i2/Dc5BDoMgEEDRu7Cu4AgIeBY2DAzaNiIRmjRteve6_Mlb_C_D0IgtbOu9tsULL_Y61O3oRxtiKjx8XidRWokX6l7Eo_RwL3TqbCNADCm7qGB0lkwGADTGBpTSeXEBbeyk1EguAybptJbyapyQAmogG9VMwB91ZTe2h_a8PubZvKXV7PcH.jpg' + }, + { + start: '2022-03-11T11:35:00.000Z', + stop: '2022-03-12T00:45:00.000Z', + title: 'Chicago Fire', + description: + "Brett, Foster et Kidd font une virée dans l'Indiana. Sur la route, ils sont les témoins d'un accident. Un bus qui transporte une équipe de hockey percute une voiture en panne. Sans réseau téléphonique, ils ne peuvent prévenir leurs collègues. En...", + icon: 'https://tv.cdnartwhere.eu/cache/i2/Dc5BDsIgEADAv3DWwpayQN_CZaFLq6aUFEyMxr_rvGA-IlJjMYut99rmIIPc67VuRz_aNS1loPfzZF5WHgr3INNROt0Knya7BJBoyT5NoLxjmwEgWusoau2DtCqBc1OOiCZNI2vvVLSAigzl0WSvAVFHPdzrKi5ip_b4PxDtSzsjvj8.jpg' + }, + { + start: '2022-03-12T00:45:00.000Z', + stop: '2022-03-12T01:45:00.000Z', + title: 'Chicago Fire', + description: + "Lors d'une urgence, la vie du lieutenant Casey est soudainement mise en danger : un homme le menace avec une arme. Grissom prévient la caserne qu'ils devront se préparer à une évaluation de leur performance. Otis apprend qu'il a remporté un prix...", + icon: 'https://tv.cdnartwhere.eu/cache/i2/Dc5BDsIgEADAv3C2hZVSoG_hsixLq6aUFEyMxr_rvGA-ImJjsYit99qWIIPc61C3ox9toFRGfD9P5rTyWLgHSUfpeCt8muwIgDBlTxMo79hmAIjWOoxa-yCT9loxMqIBjhMb7eFqk8qTy6CJZ01GUTTjva7iInZsj_9jnu1LOyO-Pw.jpg' + } + ]) + done() + }) + .catch(done) +}) + +it('can handle empty guide', done => { + parser({ + content: ` `, + date, + channel + }) + .then(result => { + expect(result).toMatchObject([]) + done() + }) + .catch(done) +}) diff --git a/sites/telecablesat.fr/telecablesat.fr_fr.channels.xml b/sites/telecablesat.fr/telecablesat.fr_fr.channels.xml new file mode 100644 index 00000000..a34e3d5e --- /dev/null +++ b/sites/telecablesat.fr/telecablesat.fr_fr.channels.xml @@ -0,0 +1,285 @@ + + + + 13eme RUE + 2M Monde + 3SAT + 6ter + AB 1 + AB 3 + ABXPLORE + Action + ACTV + Al Jazeera English + Alsace 20 + Altice Studio + Animaux + Antenne Réunion + A+ International France + Arte + Automoto + BBC Entertainment + BBC 1 + BBC 2 + BBC World News + BE 1 + Be Ciné + beIN SPORTS 1 + beIN SPORTS 2 + beIN SPORTS 3 + beIN SPORTS MAX 10 + beIN SPORTS MAX 4 + beIN SPORTS MAX 5 + beIN SPORTS MAX 6 + beIN SPORTS MAX 7 + beIN SPORTS MAX 8 + beIN SPORTS MAX 9 + Be Séries + BET + BFM Business + BFM Grand Lille + BFM Lyon Métropole + BFM Marseille + BFMTV + Boing + Boomerang + Canal C + BX1 + C8 + Canal J + Canal+ Antilles + Canal+ Cinéma + Canal+ Décalé + Canal+ Family + Canal+ + Canal+ Séries + Canal+ Sport + Canal Z + Canal Zoom + Canvas + Cartoon Network + CGTN + Chasse et pêche + Chérie 25 + Ciné+ Classic + Ciné+ Classic Belgique + Ciné+ Club + Ciné+ Emotion + Ciné+ Famiz + Ciné+ Frisson + Ciné+ Frisson Belgique + Ciné+ Premier + Ciné+ Premier Belgique + Clique TV + Club RTL + CNEWS + CNN + Comédie+ + Comedy Central + Crime District + CSTAR + Das Erste + Demain TV + Discovery Channel + Discovery Family + Discovery Science + Disney Channel Wallonia + Disney Channel + Disney Junior + Dorcel TV + DW (English) + één + E ! + Eleven Sports 1 + Eleven Sports 2 + Eleven Sports 3 + Equidia + Eurochannel + Euronews + Eurosport 1 + Eurosport 2 + France 2 + France 24 + France 3 + France 3 Alpes + France 3 Alsace + France 3 Aquitaine + France 3 Auvergne + France 3 Bourgogne + France 3 Bretagne + France 3 Centre-Val de Loire + France 3 Champagne-Ardennes + France 3 Corse Via Stella + France 3 Côte d'Azur + France 3 Franche-Comté + France 3 Languedoc-Roussillon + France 3 Limousin + France 3 Lorraine + France 3 Midi-Pyrénées + France 3 Nord Pas-de-Calais + France 3 Normandie - Caen + France 3 Normandie - Rouen + France 3 Paris Ile-de-France + France 3 Pays de la Loire + France 3 Picardie + France 3 Poitou-Charentes + France 3 Provence-Alpes + France 3 Rhône-Alpes + France 4 + France 5 + Franceinfo + Game One + Golf Channel + Golf+ + Guadeloupe la 1ère + Gulli + Guyane la 1ère + Histoire TV + Hustler TV + I24news + Infosport+ + Discovery Investigation + J-One + Ketnet + KTO + TVE 1 + TVE 2 + La Trois + La Une + LCI - La Chaîne Info + La Chaîne parlementaire + L'Equipe + LM TV Sarthe + M6 + Mangas + Man-X + Martinique la 1ère + MAtélé + Mayotte la 1ère + MCM + Melody + Melody d'Afrique + Men's UP TV + Mezzo + Mezzo Live HD + MTV + Museum TV + MyZen.tv + National Geographic + National Geographic Wild + Nautical Channel + Nickelodéon + Nickelodeon Junior + Nickelodéon Wallonia + Nollywood TV + Non Stop People HD + NoTélé + Nouvelle-Calédonie la 1ère + Novelas TV + NRJ 12 + OCS Choc + OCS City + OCS Géants + OCS Max + OLTV + Olympia TV + Paramount Channel + Paris Première + Pink TV + Piwi+ + Planète+ + Planète+ Aventure & Expérience + Planète+ Crime Investigation + Plug RTL + Polar+ + Pro7 + Proximus 11 + Rai Uno + Rai Due + Rai Tre + Réunion la 1ère + RMC Découverte + RMC Sport 1 + RMC Sport 2 + RMC Sport Access 1 + RMC Sport Access 2 + RMC Sport Live 10 + RMC Sport Live 11 + RMC Sport Live 12 + RMC Sport Live 13 + RMC Sport Live 14 + RMC Sport Live 5 + RMC Sport Live 6 + RMC Sport Live 7 + RMC Sport Live 8 + RMC Sport Live 9 + RMC Sport 1 UHD + RMC Story + Rouge TV + RSI LA 1 + RSI LA 2 + RTC Télé Liège + RTL 9 + RTL TVI + RTPI + RTS 1 + RTS 2 + Saint-Pierre et Miquelon la 1ère + Science & Vie TV + Seasons + serieclub + Stingray Brava + Stingray Djazz + Stingray Festival 4K + Stingray i-Concerts + Syfy + TCM Cinéma + Télé Grenoble Isère + Télé MB + Télénantes + Télé Sambre + TéléToon+ + Téva + TF1 + TF1 Séries Films + TFX + TIJI + Tipik + TMC + Toonami + Toute l'histoire + TRACE Sport Stars + Trek + TV5MONDE Europe + TV5MONDE + TV7 Bordeaux + 8 Mont-Blanc + TvBreizh + TV COM + TVE + TV Lux + TVR Rennes 35 Bretagne + TVSUD Marseille + TV Tours + Ushuaïa TV + VEDIA + ATV Martinique + ATV Guadeloupe + ATV Guyane + ViàMoselleTV + Vià Occitanie Montpellier + Vià Occitanie Pays Gardois + ViàVosges + Vice TV + VOOsport World 1 + VOOsport World 2 + VOOsport World 3 + VTM + W9 + Wallis et Futuna la 1ère + Warner TV + Wéo + XXL + ZDF + +