mirror of
https://github.com/iptv-org/epg
synced 2026-09-14 21:16:26 -04:00
@@ -48,11 +48,11 @@ jobs:
|
|||||||
git config user.name "iptv-bot[bot]"
|
git config user.name "iptv-bot[bot]"
|
||||||
git config user.email "84861620+iptv-bot[bot]@users.noreply.github.com"
|
git config user.email "84861620+iptv-bot[bot]@users.noreply.github.com"
|
||||||
- name: Commit changed *.channels.xml files
|
- name: Commit changed *.channels.xml files
|
||||||
if: steps.files_after.outputs.channels_any_changed == 'true'
|
if: steps.files.outputs.channels_any_changed == 'true'
|
||||||
run: |
|
run: |
|
||||||
git add streams
|
git add streams
|
||||||
git status
|
git status
|
||||||
git commit -m "[Bot] Format *.channels.xml files" -m "Committed by [iptv-bot](https://github.com/apps/iptv-bot) via [format](https://github.com/iptv-org/epg/actions/runs/${{ github.run_id }}) workflow." --no-verify
|
git commit -m "[Bot] Format *.channels.xml files" -m "Committed by [iptv-bot](https://github.com/apps/iptv-bot) via [format](https://github.com/iptv-org/epg/actions/runs/${{ github.run_id }}) workflow." --no-verify
|
||||||
- name: Push all changes to the repository
|
- name: Push all changes to the repository
|
||||||
if: ${{ !env.ACT && github.ref == 'refs/heads/master' && steps.files_after.outputs.channels_any_changed == 'true' }}
|
if: ${{ !env.ACT && github.ref == 'refs/heads/master' && steps.files.outputs.channels_any_changed == 'true' }}
|
||||||
run: git push
|
run: git push
|
||||||
Generated
+7
-7
@@ -51,7 +51,7 @@
|
|||||||
"curl-generator": "^0.5.0",
|
"curl-generator": "^0.5.0",
|
||||||
"cwait": "^1.1.2",
|
"cwait": "^1.1.2",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"epg-grabber": "^0.45.0",
|
"epg-grabber": "^0.46.0",
|
||||||
"epg-parser": "^0.3.1",
|
"epg-parser": "^0.3.1",
|
||||||
"eslint": "^9.32.0",
|
"eslint": "^9.32.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
@@ -5477,9 +5477,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/epg-grabber": {
|
"node_modules/epg-grabber": {
|
||||||
"version": "0.45.0",
|
"version": "0.46.0",
|
||||||
"resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.45.0.tgz",
|
"resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.46.0.tgz",
|
||||||
"integrity": "sha512-GqjXRYOJcC3mX9OYdZHlpNEhwBbCF256uKGPXdUodUjkXTmraolIEXYRUeQJmPbL5/do766EewNwIBXqLzHkJA==",
|
"integrity": "sha512-35VJZWV1tJLro5SNP9bobcVB4fWK9rTUYmtRJ1/wIOA/tktxlCvZ+n/6LoKWS89YtKujqq3jid3cVf7JSImKzA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@freearhey/core": "^0.14.0",
|
"@freearhey/core": "^0.14.0",
|
||||||
"@types/bluebird": "^3.5.42",
|
"@types/bluebird": "^3.5.42",
|
||||||
@@ -14999,9 +14999,9 @@
|
|||||||
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
|
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
|
||||||
},
|
},
|
||||||
"epg-grabber": {
|
"epg-grabber": {
|
||||||
"version": "0.45.0",
|
"version": "0.46.0",
|
||||||
"resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.45.0.tgz",
|
"resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.46.0.tgz",
|
||||||
"integrity": "sha512-GqjXRYOJcC3mX9OYdZHlpNEhwBbCF256uKGPXdUodUjkXTmraolIEXYRUeQJmPbL5/do766EewNwIBXqLzHkJA==",
|
"integrity": "sha512-35VJZWV1tJLro5SNP9bobcVB4fWK9rTUYmtRJ1/wIOA/tktxlCvZ+n/6LoKWS89YtKujqq3jid3cVf7JSImKzA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@freearhey/core": "^0.14.0",
|
"@freearhey/core": "^0.14.0",
|
||||||
"@types/bluebird": "^3.5.42",
|
"@types/bluebird": "^3.5.42",
|
||||||
|
|||||||
+1
-1
@@ -81,7 +81,7 @@
|
|||||||
"curl-generator": "^0.5.0",
|
"curl-generator": "^0.5.0",
|
||||||
"cwait": "^1.1.2",
|
"cwait": "^1.1.2",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"epg-grabber": "^0.45.0",
|
"epg-grabber": "^0.46.0",
|
||||||
"epg-parser": "^0.3.1",
|
"epg-parser": "^0.3.1",
|
||||||
"eslint": "^9.32.0",
|
"eslint": "^9.32.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ program
|
|||||||
'Path to *.channels.xml file (required if the "--site" attribute is not specified)'
|
'Path to *.channels.xml file (required if the "--site" attribute is not specified)'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.addOption(new Option('-o, --output <path>', 'Path to output file').default('guide.xml'))
|
.addOption(new Option('-o, --output <path>', 'Path to output file'))
|
||||||
.addOption(new Option('-l, --lang <codes>', 'Filter channels by languages (ISO 639-1 codes)'))
|
.addOption(new Option('-l, --lang <codes>', 'Filter channels by languages (ISO 639-1 codes)'))
|
||||||
.addOption(
|
.addOption(
|
||||||
new Option('-t, --timeout <milliseconds>', 'Override the default timeout for each request')
|
new Option('-t, --timeout <milliseconds>', 'Override the default timeout for each request')
|
||||||
@@ -47,27 +47,22 @@ program
|
|||||||
)
|
)
|
||||||
.addOption(
|
.addOption(
|
||||||
new Option('--maxConnections <number>', 'Limit on the number of concurrent requests')
|
new Option('--maxConnections <number>', 'Limit on the number of concurrent requests')
|
||||||
.default(1)
|
|
||||||
.argParser(parseNumber)
|
.argParser(parseNumber)
|
||||||
.env('MAX_CONNECTIONS')
|
.env('MAX_CONNECTIONS')
|
||||||
)
|
)
|
||||||
.addOption(
|
.addOption(new Option('--gzip', 'Create a compressed version of the guide as well').env('GZIP'))
|
||||||
new Option('--gzip', 'Create a compressed version of the guide as well')
|
.addOption(new Option('--curl', 'Display each request as CURL').env('CURL'))
|
||||||
.default(false)
|
.addOption(new Option('--debug', 'Enable debug mode').env('DEBUG'))
|
||||||
.env('GZIP')
|
|
||||||
)
|
|
||||||
.addOption(new Option('--curl', 'Display each request as CURL').default(false).env('CURL'))
|
|
||||||
.addOption(new Option('--debug', 'Enable debug mode').default(false).env('DEBUG'))
|
|
||||||
.parse()
|
.parse()
|
||||||
|
|
||||||
interface GrabOptions {
|
interface GrabOptions {
|
||||||
site?: string
|
site?: string
|
||||||
channels?: string
|
channels?: string
|
||||||
output: string
|
output?: string
|
||||||
gzip: boolean
|
gzip?: boolean
|
||||||
curl: boolean
|
curl?: boolean
|
||||||
debug: boolean
|
debug?: boolean
|
||||||
maxConnections: number
|
maxConnections?: number
|
||||||
timeout?: number
|
timeout?: number
|
||||||
delay?: number
|
delay?: number
|
||||||
lang?: string
|
lang?: string
|
||||||
@@ -85,10 +80,10 @@ async function main() {
|
|||||||
const logger = new Logger({ level: options.debug ? LOG_LEVELS['debug'] : LOG_LEVELS['info'] })
|
const logger = new Logger({ level: options.debug ? LOG_LEVELS['debug'] : LOG_LEVELS['info'] })
|
||||||
|
|
||||||
logger.info('starting...')
|
logger.info('starting...')
|
||||||
let config: epgGrabber.Types.SiteConfig = defaultConfig
|
let globalConfig: epgGrabber.Types.SiteConfig = {}
|
||||||
|
|
||||||
if (typeof options.timeout === 'number')
|
if (typeof options.timeout === 'number')
|
||||||
config = merge(config, { request: { timeout: options.timeout } })
|
globalConfig = merge(globalConfig, { request: { timeout: options.timeout } })
|
||||||
if (options.proxy !== undefined) {
|
if (options.proxy !== undefined) {
|
||||||
const proxy = parseProxy(options.proxy)
|
const proxy = parseProxy(options.proxy)
|
||||||
if (
|
if (
|
||||||
@@ -96,31 +91,36 @@ async function main() {
|
|||||||
['socks', 'socks5', 'socks5h', 'socks4', 'socks4a'].includes(String(proxy.protocol))
|
['socks', 'socks5', 'socks5h', 'socks4', 'socks4a'].includes(String(proxy.protocol))
|
||||||
) {
|
) {
|
||||||
const socksProxyAgent = new SocksProxyAgent(options.proxy)
|
const socksProxyAgent = new SocksProxyAgent(options.proxy)
|
||||||
config = merge(config, {
|
globalConfig = merge(globalConfig, {
|
||||||
request: { httpAgent: socksProxyAgent, httpsAgent: socksProxyAgent }
|
request: { httpAgent: socksProxyAgent, httpsAgent: socksProxyAgent }
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
config = merge(config, { request: { proxy } })
|
globalConfig = merge(globalConfig, { request: { proxy } })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof options.output === 'string') config.output = options.output
|
if (typeof options.output === 'string') globalConfig.output = options.output
|
||||||
if (typeof options.days === 'number') config.days = options.days
|
if (typeof options.days === 'number') globalConfig.days = options.days
|
||||||
if (typeof options.delay === 'number') config.delay = options.delay
|
if (typeof options.delay === 'number') globalConfig.delay = options.delay
|
||||||
if (typeof options.maxConnections === 'number') config.maxConnections = options.maxConnections
|
if (typeof options.maxConnections === 'number')
|
||||||
if (typeof options.curl === 'boolean') config.curl = options.curl
|
globalConfig.maxConnections = options.maxConnections
|
||||||
if (typeof options.gzip === 'boolean') config.gzip = options.gzip
|
if (typeof options.curl === 'boolean') globalConfig.curl = options.curl
|
||||||
|
if (typeof options.gzip === 'boolean') globalConfig.gzip = options.gzip
|
||||||
const grabber =
|
if (typeof options.debug === 'boolean') globalConfig.debug = options.debug
|
||||||
process.env.NODE_ENV === 'test' ? new EPGGrabberMock(config) : new EPGGrabber(config)
|
|
||||||
|
|
||||||
const globalConfig = grabber.globalConfig
|
|
||||||
|
|
||||||
logger.debug(`config: ${JSON.stringify(globalConfig, null, 2)}`)
|
logger.debug(`config: ${JSON.stringify(globalConfig, null, 2)}`)
|
||||||
|
|
||||||
|
const grabber =
|
||||||
|
process.env.NODE_ENV === 'test'
|
||||||
|
? new EPGGrabberMock(globalConfig)
|
||||||
|
: new EPGGrabber(globalConfig)
|
||||||
|
|
||||||
grabber.client.instance.interceptors.request.use(
|
grabber.client.instance.interceptors.request.use(
|
||||||
request => {
|
request => {
|
||||||
if (globalConfig.curl) {
|
logger.debug(`request: ${JSON.stringify(request, null, 2)}`)
|
||||||
|
|
||||||
|
const curl = globalConfig.curl || defaultConfig.curl
|
||||||
|
if (curl) {
|
||||||
type AllowedMethods =
|
type AllowedMethods =
|
||||||
| 'GET'
|
| 'GET'
|
||||||
| 'get'
|
| 'get'
|
||||||
@@ -194,11 +194,12 @@ async function main() {
|
|||||||
channel.index = index++
|
channel.index = index++
|
||||||
if (!channel.site || !channel.site_id || !channel.name) continue
|
if (!channel.site || !channel.site_id || !channel.name) continue
|
||||||
|
|
||||||
const config = await loadJs(channel.getConfigPath())
|
let config = await loadJs(channel.getConfigPath())
|
||||||
const days: number = config.days || globalConfig.days
|
config = merge(defaultConfig, config)
|
||||||
|
|
||||||
if (!channel.xmltv_id) channel.xmltv_id = channel.site_id
|
if (!channel.xmltv_id) channel.xmltv_id = channel.site_id
|
||||||
|
|
||||||
|
const days = globalConfig.days || config.days
|
||||||
const currDate = dayjs.utc(process.env.CURR_DATE || new Date().toISOString())
|
const currDate = dayjs.utc(process.env.CURR_DATE || new Date().toISOString())
|
||||||
const dates = Array.from({ length: days }, (_, day) => currDate.add(day, 'd'))
|
const dates = Array.from({ length: days }, (_, day) => currDate.add(day, 'd'))
|
||||||
|
|
||||||
@@ -214,7 +215,9 @@ async function main() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const taskQueue = new TaskQueue(Promise as PromisyClass, options.maxConnections)
|
const maxConnections = globalConfig.maxConnections || defaultConfig.maxConnections
|
||||||
|
|
||||||
|
const taskQueue = new TaskQueue(Promise as PromisyClass, maxConnections)
|
||||||
|
|
||||||
const queueItems = queue.getItems()
|
const queueItems = queue.getItems()
|
||||||
|
|
||||||
@@ -271,9 +274,13 @@ async function main() {
|
|||||||
|
|
||||||
await Promise.all(requests.all())
|
await Promise.all(requests.all())
|
||||||
|
|
||||||
const pathTemplate = new Template(options.output)
|
const output = globalConfig.output || defaultConfig.output
|
||||||
|
|
||||||
const channelsGroupedByKey = channels.groupBy((channel: Channel) => {
|
const pathTemplate = new Template(output)
|
||||||
|
|
||||||
|
const channelsGroupedByKey = channels
|
||||||
|
.uniqBy((channel: Channel) => `${channel.xmltv_id}:${channel.site}:${channel.lang}`)
|
||||||
|
.groupBy((channel: Channel) => {
|
||||||
return pathTemplate.format({ lang: channel.lang || 'en', site: channel.site || '' })
|
return pathTemplate.format({ lang: channel.lang || 'en', site: channel.site || '' })
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -286,12 +293,14 @@ async function main() {
|
|||||||
return pathTemplate.format({ lang, site: program.site || '' })
|
return pathTemplate.format({ lang, site: program.site || '' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const gzip = globalConfig.gzip || defaultConfig.gzip
|
||||||
|
|
||||||
for (const groupKey of channelsGroupedByKey.keys()) {
|
for (const groupKey of channelsGroupedByKey.keys()) {
|
||||||
const groupChannels = new Collection(channelsGroupedByKey.get(groupKey))
|
const groupChannels = new Collection(channelsGroupedByKey.get(groupKey))
|
||||||
const groupPrograms = new Collection(programsGroupedByKey.get(groupKey))
|
const groupPrograms = new Collection(programsGroupedByKey.get(groupKey))
|
||||||
const guide = new Guide({
|
const guide = new Guide({
|
||||||
filepath: groupKey,
|
filepath: groupKey,
|
||||||
gzip: options.gzip,
|
gzip,
|
||||||
channels: groupChannels,
|
channels: groupChannels,
|
||||||
programs: groupPrograms
|
programs: groupPrograms
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
export default {
|
export default {
|
||||||
|
output: 'guide.xml',
|
||||||
days: 1,
|
days: 1,
|
||||||
delay: 0,
|
delay: 0,
|
||||||
|
maxConnections: 1,
|
||||||
|
curl: false,
|
||||||
|
gzip: false,
|
||||||
|
debug: false,
|
||||||
request: {
|
request: {
|
||||||
maxContentLength: 5242880,
|
maxContentLength: 5242880,
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?><tv date="20221020">
|
<?xml version="1.0" encoding="UTF-8" ?><tv date="20221020">
|
||||||
<channel id="Channel1.us"><display-name>Custom Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example.com</url></channel>
|
<channel id="Channel1.us"><display-name>Custom Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example.com</url></channel>
|
||||||
<channel id="Channel2.us"><display-name>Custom Channel 2</display-name><icon src="https://i.imgur.com/qmRnD0M.png"/><url>https://example.com</url></channel>
|
|
||||||
<channel id="Channel1.us"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example.com</url></channel>
|
|
||||||
<channel id="Channel3.us@Wrong"><display-name>Channel 3</display-name><icon src="https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"/><url>https://example2.com</url></channel>
|
|
||||||
<channel id="Channel4.us@HD"><display-name>Channel 4</display-name><icon src="https://i.imgur.com/BPzH88J.png"/><url>https://example2.com</url></channel>
|
|
||||||
<channel id="Channel1.us"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example2.com</url></channel>
|
<channel id="Channel1.us"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example2.com</url></channel>
|
||||||
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example.com)</title></programme>
|
<channel id="Channel4.us@HD"><display-name>Channel 4</display-name><icon src="https://i.imgur.com/BPzH88J.png"/><url>https://example2.com</url></channel>
|
||||||
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example.com)</title></programme>
|
<channel id="Channel3.us@Wrong"><display-name>Channel 3</display-name><icon src="https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"/><url>https://example2.com</url></channel>
|
||||||
|
<channel id="Channel1.us"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example.com</url></channel>
|
||||||
|
<channel id="Channel2.us"><display-name>Custom Channel 2</display-name><icon src="https://i.imgur.com/qmRnD0M.png"/><url>https://example.com</url></channel>
|
||||||
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021044000 +0000" stop="20221021071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
<programme start="20221021043000 +0000" stop="20221021071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example.com)</title></programme>
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel4.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example.com)</title></programme>
|
|
||||||
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel3.us@Wrong"><title lang="en">Program1 (example2.com)</title></programme>
|
|
||||||
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel4.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel4.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel3.us@Wrong"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel3.us@Wrong"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021044000 +0000" stop="20221021071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel2.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel2.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
</tv>
|
</tv>
|
||||||
@@ -1,18 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?><tv date="20221020">
|
<?xml version="1.0" encoding="UTF-8" ?><tv date="20221020">
|
||||||
<channel id="Channel1.us@HD"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example.com</url></channel>
|
<channel id="Channel1.us@HD"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example.com</url></channel>
|
||||||
<channel id="Channel2.us"><display-name>Channel 2</display-name><icon src="https://i.imgur.com/qmRnD0M.png"/><url>https://example.com</url><lcn>36</lcn></channel>
|
|
||||||
<channel id="140"><display-name>Channel 1</display-name><url>https://example.com</url></channel>
|
|
||||||
<channel id="Channel3.us"><display-name>Channel 3</display-name><icon src="https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"/><url>https://example.com</url></channel>
|
|
||||||
<channel id="Channel3.us"><display-name>Channel 3</display-name><icon src="https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"/><url>https://example2.com</url></channel>
|
|
||||||
<channel id="Channel4.us@HD"><display-name>Channel 4</display-name><icon src="https://i.imgur.com/BPzH88J.png"/><url>https://example2.com</url></channel>
|
|
||||||
<channel id="Channel1.us"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example2.com</url></channel>
|
<channel id="Channel1.us"><display-name>Channel 1</display-name><icon src="https://i.imgur.com/GPzH88J.png"/><url>https://example2.com</url></channel>
|
||||||
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="140"><title lang="fr">Programme1 (example.com)</title></programme>
|
<channel id="Channel4.us@HD"><display-name>Channel 4</display-name><icon src="https://i.imgur.com/BPzH88J.png"/><url>https://example2.com</url></channel>
|
||||||
<programme start="20221021043000 +0000" stop="20221021071000 +0000" channel="140"><title lang="fr">Programme1 (example.com)</title></programme>
|
<channel id="Channel3.us"><display-name>Channel 3</display-name><icon src="https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"/><url>https://example2.com</url></channel>
|
||||||
|
<channel id="Channel3.us"><display-name>Channel 3</display-name><icon src="https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"/><url>https://example.com</url></channel>
|
||||||
|
<channel id="140"><display-name>Channel 1</display-name><url>https://example.com</url></channel>
|
||||||
|
<channel id="Channel2.us"><display-name>Channel 2</display-name><icon src="https://i.imgur.com/qmRnD0M.png"/><url>https://example.com</url><lcn>36</lcn></channel>
|
||||||
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel1.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel1.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021044000 +0000" stop="20221021071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel1.us@HD"><title lang="en">Program1 (example.com)</title></programme>
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel4.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel1.us@HD"><title lang="en">Program1 (example.com)</title></programme>
|
|
||||||
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme>
|
|
||||||
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel3.us"><title lang="it">Program1 (example.com)</title></programme>
|
|
||||||
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel3.us"><title lang="it">Program1 (example.com)</title></programme>
|
|
||||||
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel4.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel4.us@HD"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel3.us"><title lang="it">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel3.us"><title lang="it">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021044000 +0000" stop="20221021071000 +0000" channel="140"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="140"><title lang="fr">Programme1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221021043100 +0000" stop="20221021071000 +0000" channel="Channel2.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
|
<programme start="20221020043100 +0000" stop="20221020071000 +0000" channel="Channel2.us"><title lang="en">Program1 (example2.com)</title></programme>
|
||||||
</tv>
|
</tv>
|
||||||
Reference in New Issue
Block a user