Merge branch 'master' into master
This commit is contained in:
3
.readme/.gitignore
vendored
3
.readme/.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
_categories.md
|
||||
_countries.md
|
||||
_languages.md
|
||||
_regions.md
|
||||
_subdivisions.md
|
||||
_regions.md
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"build" : "PLAYLISTS.md",
|
||||
"files" : ["./.readme/template.md"]
|
||||
}
|
||||
@@ -40,13 +40,14 @@ Same thing, but split up into separate files:
|
||||
|
||||
</details>
|
||||
|
||||
### Grouped by country
|
||||
### Grouped by broadcast area
|
||||
|
||||
Playlists in which channels are grouped by country for which they are broadcasted.
|
||||
Playlists in which channels are grouped by broadcast area.
|
||||
|
||||
<details>
|
||||
<summary>Expand</summary>
|
||||
<br>
|
||||
|
||||
#### Countries
|
||||
|
||||
```
|
||||
https://iptv-org.github.io/iptv/index.country.m3u
|
||||
@@ -57,34 +58,7 @@ Same thing, but split up into separate files:
|
||||
<!-- prettier-ignore -->
|
||||
#include "./.readme/_countries.md"
|
||||
|
||||
</details>
|
||||
|
||||
### Grouped by subdivision
|
||||
|
||||
Playlists in which channels are grouped by subdivision for which they are broadcasted.
|
||||
|
||||
<details>
|
||||
<summary>Expand</summary>
|
||||
<br>
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
#include "./.readme/_subdivisions.md"
|
||||
|
||||
</details>
|
||||
|
||||
### Grouped by region
|
||||
|
||||
Playlists in which channels are grouped by the region for which they are broadcasted.
|
||||
|
||||
<details>
|
||||
<summary>Expand</summary>
|
||||
<br>
|
||||
|
||||
```
|
||||
https://iptv-org.github.io/iptv/index.region.m3u
|
||||
```
|
||||
|
||||
Same thing, but split up into separate files:
|
||||
#### Regions
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
#include "./.readme/_regions.md"
|
||||
|
||||
8157
PLAYLISTS.md
8157
PLAYLISTS.md
File diff suppressed because it is too large
Load Diff
91
package-lock.json
generated
91
package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alex_neo/jest-expect-message": "^1.0.5",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@freearhey/core": "^0.10.2",
|
||||
@@ -45,6 +46,11 @@
|
||||
"tsx": "^4.20.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@alex_neo/jest-expect-message": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@alex_neo/jest-expect-message/-/jest-expect-message-1.0.5.tgz",
|
||||
"integrity": "sha512-1eBykZCd0pPGl5qKtV6Z5ARA6yuhXzHsVN2h5GH5/H6svYa37Jr7vMio5OFpiw1LBHtscrZs7amSkZkcwm0cvQ=="
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
@@ -1254,14 +1260,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/editor": {
|
||||
"version": "4.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.15.tgz",
|
||||
"integrity": "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ==",
|
||||
"license": "MIT",
|
||||
"version": "4.2.17",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.17.tgz",
|
||||
"integrity": "sha512-r6bQLsyPSzbWrZZ9ufoWL+CztkSatnJ6uSxqd6N+o41EZC51sQeWOzI6s5jLb+xxTWxl7PlUppqm8/sow241gg==",
|
||||
"dependencies": {
|
||||
"@inquirer/core": "^10.1.15",
|
||||
"@inquirer/type": "^3.0.8",
|
||||
"external-editor": "^3.1.0"
|
||||
"@inquirer/external-editor": "^1.0.1",
|
||||
"@inquirer/type": "^3.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -1297,6 +1302,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/external-editor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz",
|
||||
"integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==",
|
||||
"dependencies": {
|
||||
"chardet": "^2.1.0",
|
||||
"iconv-lite": "^0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@inquirer/figures": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz",
|
||||
@@ -3853,10 +3878,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chardet": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"license": "MIT"
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz",
|
||||
"integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA=="
|
||||
},
|
||||
"node_modules/ci-info": {
|
||||
"version": "4.3.0",
|
||||
@@ -4547,20 +4571,6 @@
|
||||
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/external-editor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chardet": "^0.7.0",
|
||||
"iconv-lite": "^0.4.24",
|
||||
"tmp": "^0.0.33"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz",
|
||||
@@ -5033,12 +5043,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"license": "MIT",
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -6848,15 +6857,6 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/outvariant": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz",
|
||||
@@ -7280,8 +7280,7 @@
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.2",
|
||||
@@ -7667,18 +7666,6 @@
|
||||
"resolved": "https://registry.npmjs.org/timer-node/-/timer-node-5.0.9.tgz",
|
||||
"integrity": "sha512-zXxCE/5/YDi0hY9pygqgRqjRbrFRzigYxOudG0I3syaqAAmX9/w9sxex1bNFCN6c1S66RwPtEIJv65dN+1psew=="
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tmpl": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alex_neo/jest-expect-message": "^1.0.5",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@freearhey/core": "^0.10.2",
|
||||
|
||||
@@ -18,7 +18,8 @@ async function main() {
|
||||
loader.download('logos.json'),
|
||||
loader.download('timezones.json'),
|
||||
loader.download('guides.json'),
|
||||
loader.download('streams.json')
|
||||
loader.download('streams.json'),
|
||||
loader.download('cities.json')
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ import {
|
||||
IndexLanguageGenerator,
|
||||
IndexCountryGenerator,
|
||||
SubdivisionsGenerator,
|
||||
IndexRegionGenerator,
|
||||
CategoriesGenerator,
|
||||
CountriesGenerator,
|
||||
LanguagesGenerator,
|
||||
RegionsGenerator,
|
||||
SourcesGenerator,
|
||||
CitiesGenerator,
|
||||
IndexGenerator,
|
||||
RawGenerator
|
||||
} from '../../generators'
|
||||
@@ -36,7 +36,8 @@ async function main() {
|
||||
subdivisions,
|
||||
categories,
|
||||
countries,
|
||||
regions
|
||||
regions,
|
||||
cities
|
||||
}: DataProcessorData = processor.process(data)
|
||||
|
||||
logger.info('loading streams...')
|
||||
@@ -90,6 +91,13 @@ async function main() {
|
||||
logFile
|
||||
}).generate()
|
||||
|
||||
logger.info('generating cities/...')
|
||||
await new CitiesGenerator({
|
||||
cities,
|
||||
streams,
|
||||
logFile
|
||||
}).generate()
|
||||
|
||||
logger.info('generating regions/...')
|
||||
await new RegionsGenerator({
|
||||
streams,
|
||||
@@ -115,9 +123,6 @@ async function main() {
|
||||
logger.info('generating index.language.m3u...')
|
||||
await new IndexLanguageGenerator({ streams, logFile }).generate()
|
||||
|
||||
logger.info('generating index.region.m3u...')
|
||||
await new IndexRegionGenerator({ streams, regions, logFile }).generate()
|
||||
|
||||
logger.info('saving generators.log...')
|
||||
const logStorage = new Storage(LOGS_DIR)
|
||||
logStorage.saveFile(logFile)
|
||||
|
||||
@@ -1,32 +1,47 @@
|
||||
import { Logger } from '@freearhey/core'
|
||||
import {
|
||||
CategoryTable,
|
||||
CountryTable,
|
||||
LanguageTable,
|
||||
RegionTable,
|
||||
SubdivisionTable
|
||||
} from '../../tables'
|
||||
import { Markdown } from '../../core'
|
||||
import { README_DIR } from '../../constants'
|
||||
import path from 'path'
|
||||
import { CategoriesTable, CountriesTable, LanguagesTable, RegionsTable } from '../../tables'
|
||||
import { DataLoader, DataProcessor, Markdown } from '../../core'
|
||||
import { DataProcessorData } from '../../types/dataProcessor'
|
||||
import { DataLoaderData } from '../../types/dataLoader'
|
||||
import { README_DIR, DATA_DIR, ROOT_DIR } from '../../constants'
|
||||
import { Logger, Storage } from '@freearhey/core'
|
||||
|
||||
async function main() {
|
||||
const logger = new Logger()
|
||||
const dataStorage = new Storage(DATA_DIR)
|
||||
const processor = new DataProcessor()
|
||||
const loader = new DataLoader({ storage: dataStorage })
|
||||
const data: DataLoaderData = await loader.load()
|
||||
const {
|
||||
subdivisionsKeyByCode,
|
||||
languagesKeyByCode,
|
||||
countriesKeyByCode,
|
||||
categoriesKeyById,
|
||||
subdivisions,
|
||||
countries,
|
||||
regions,
|
||||
cities
|
||||
}: DataProcessorData = processor.process(data)
|
||||
|
||||
logger.info('creating category table...')
|
||||
await new CategoryTable().make()
|
||||
await new CategoriesTable({ categoriesKeyById }).make()
|
||||
logger.info('creating language table...')
|
||||
await new LanguageTable().make()
|
||||
logger.info('creating country table...')
|
||||
await new CountryTable().make()
|
||||
logger.info('creating subdivision table...')
|
||||
await new SubdivisionTable().make()
|
||||
await new LanguagesTable({ languagesKeyByCode }).make()
|
||||
logger.info('creating countires table...')
|
||||
await new CountriesTable({
|
||||
countriesKeyByCode,
|
||||
subdivisionsKeyByCode,
|
||||
subdivisions,
|
||||
countries,
|
||||
cities
|
||||
}).make()
|
||||
logger.info('creating region table...')
|
||||
await new RegionTable().make()
|
||||
await new RegionsTable({ regions }).make()
|
||||
|
||||
logger.info('updating playlists.md...')
|
||||
const configPath = path.join(README_DIR, 'config.json')
|
||||
const playlists = new Markdown(configPath)
|
||||
const playlists = new Markdown({
|
||||
build: `${ROOT_DIR}/PLAYLISTS.md`,
|
||||
template: `${README_DIR}/template.md`
|
||||
})
|
||||
playlists.compile()
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ export class DataLoader {
|
||||
logos,
|
||||
timezones,
|
||||
guides,
|
||||
streams
|
||||
streams,
|
||||
cities
|
||||
] = await Promise.all([
|
||||
this.storage.json('countries.json'),
|
||||
this.storage.json('regions.json'),
|
||||
@@ -70,7 +71,8 @@ export class DataLoader {
|
||||
this.storage.json('logos.json'),
|
||||
this.storage.json('timezones.json'),
|
||||
this.storage.json('guides.json'),
|
||||
this.storage.json('streams.json')
|
||||
this.storage.json('streams.json'),
|
||||
this.storage.json('cities.json')
|
||||
])
|
||||
|
||||
return {
|
||||
@@ -85,7 +87,8 @@ export class DataLoader {
|
||||
logos,
|
||||
timezones,
|
||||
guides,
|
||||
streams
|
||||
streams,
|
||||
cities
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { DataProcessorData } from '../types/dataProcessor'
|
||||
import { DataLoaderData } from '../types/dataLoader'
|
||||
import { Collection } from '@freearhey/core'
|
||||
import {
|
||||
@@ -11,14 +12,16 @@ import {
|
||||
Region,
|
||||
Stream,
|
||||
Guide,
|
||||
City,
|
||||
Feed,
|
||||
Logo
|
||||
} from '../models'
|
||||
|
||||
export class DataProcessor {
|
||||
constructor() {}
|
||||
process(data: DataLoaderData): DataProcessorData {
|
||||
let regions = new Collection(data.regions).map(data => new Region(data))
|
||||
let regionsKeyByCode = regions.keyBy((region: Region) => region.code)
|
||||
|
||||
process(data: DataLoaderData) {
|
||||
const categories = new Collection(data.categories).map(data => new Category(data))
|
||||
const categoriesKeyById = categories.keyBy((category: Category) => category.id)
|
||||
|
||||
@@ -26,25 +29,23 @@ export class DataProcessor {
|
||||
const languagesKeyByCode = languages.keyBy((language: Language) => language.code)
|
||||
|
||||
let subdivisions = new Collection(data.subdivisions).map(data => new Subdivision(data))
|
||||
const subdivisionsKeyByCode = subdivisions.keyBy((subdivision: Subdivision) => subdivision.code)
|
||||
const subdivisionsGroupedByCountryCode = subdivisions.groupBy(
|
||||
let subdivisionsKeyByCode = subdivisions.keyBy((subdivision: Subdivision) => subdivision.code)
|
||||
let subdivisionsGroupedByCountryCode = subdivisions.groupBy(
|
||||
(subdivision: Subdivision) => subdivision.countryCode
|
||||
)
|
||||
|
||||
let regions = new Collection(data.regions).map(data => new Region(data))
|
||||
const regionsKeyByCode = regions.keyBy((region: Region) => region.code)
|
||||
let countries = new Collection(data.countries).map(data => new Country(data))
|
||||
let countriesKeyByCode = countries.keyBy((country: Country) => country.code)
|
||||
|
||||
const countries = new Collection(data.countries).map(data =>
|
||||
new Country(data)
|
||||
const cities = new Collection(data.cities).map(data =>
|
||||
new City(data)
|
||||
.withRegions(regions)
|
||||
.withLanguage(languagesKeyByCode)
|
||||
.withSubdivisions(subdivisionsGroupedByCountryCode)
|
||||
)
|
||||
const countriesKeyByCode = countries.keyBy((country: Country) => country.code)
|
||||
|
||||
subdivisions = subdivisions.map((subdivision: Subdivision) =>
|
||||
subdivision.withCountry(countriesKeyByCode)
|
||||
.withCountry(countriesKeyByCode)
|
||||
.withSubdivision(subdivisionsKeyByCode)
|
||||
)
|
||||
const citiesKeyByCode = cities.keyBy((city: City) => city.code)
|
||||
const citiesGroupedByCountryCode = cities.groupBy((city: City) => city.countryCode)
|
||||
const citiesGroupedBySubdivisionCode = cities.groupBy((city: City) => city.subdivisionCode)
|
||||
|
||||
const timezones = new Collection(data.timezones).map(data =>
|
||||
new Timezone(data).withCountries(countriesKeyByCode)
|
||||
@@ -56,27 +57,12 @@ export class DataProcessor {
|
||||
(blocklistRecord: BlocklistRecord) => blocklistRecord.channelId
|
||||
)
|
||||
|
||||
let channels = new Collection(data.channels).map(data =>
|
||||
new Channel(data)
|
||||
.withCategories(categoriesKeyById)
|
||||
.withCountry(countriesKeyByCode)
|
||||
.withSubdivision(subdivisionsKeyByCode)
|
||||
.withCategories(categoriesKeyById)
|
||||
)
|
||||
let channels = new Collection(data.channels).map(data => new Channel(data))
|
||||
let channelsKeyById = channels.keyBy((channel: Channel) => channel.id)
|
||||
|
||||
const channelsKeyById = channels.keyBy((channel: Channel) => channel.id)
|
||||
|
||||
const feeds = new Collection(data.feeds).map(data =>
|
||||
new Feed(data)
|
||||
.withChannel(channelsKeyById)
|
||||
.withLanguages(languagesKeyByCode)
|
||||
.withTimezones(timezonesKeyById)
|
||||
.withBroadcastCountries(countriesKeyByCode, regionsKeyByCode, subdivisionsKeyByCode)
|
||||
.withBroadcastRegions(regions)
|
||||
.withBroadcastSubdivisions(subdivisionsKeyByCode)
|
||||
)
|
||||
const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) => feed.channelId)
|
||||
const feedsGroupedById = feeds.groupBy((feed: Feed) => feed.id)
|
||||
let feeds = new Collection(data.feeds).map(data => new Feed(data))
|
||||
let feedsGroupedByChannelId = feeds.groupBy((feed: Feed) => feed.channelId)
|
||||
let feedsGroupedById = feeds.groupBy((feed: Feed) => feed.id)
|
||||
|
||||
const logos = new Collection(data.logos).map(data => new Logo(data).withFeed(feedsGroupedById))
|
||||
const logosGroupedByChannelId = logos.groupBy((logo: Logo) => logo.channelId)
|
||||
@@ -90,11 +76,60 @@ export class DataProcessor {
|
||||
const guides = new Collection(data.guides).map(data => new Guide(data))
|
||||
const guidesGroupedByStreamId = guides.groupBy((guide: Guide) => guide.getStreamId())
|
||||
|
||||
regions = regions.map((region: Region) => region.withCountries(countriesKeyByCode))
|
||||
regions = regions.map((region: Region) =>
|
||||
region
|
||||
.withCountries(countriesKeyByCode)
|
||||
.withRegions(regions)
|
||||
.withSubdivisions(subdivisions)
|
||||
.withCities(cities)
|
||||
)
|
||||
regionsKeyByCode = regions.keyBy((region: Region) => region.code)
|
||||
|
||||
countries = countries.map((country: Country) =>
|
||||
country
|
||||
.withCities(citiesGroupedByCountryCode)
|
||||
.withSubdivisions(subdivisionsGroupedByCountryCode)
|
||||
.withRegions(regions)
|
||||
.withLanguage(languagesKeyByCode)
|
||||
)
|
||||
countriesKeyByCode = countries.keyBy((country: Country) => country.code)
|
||||
|
||||
subdivisions = subdivisions.map((subdivision: Subdivision) =>
|
||||
subdivision
|
||||
.withCities(citiesGroupedBySubdivisionCode)
|
||||
.withCountry(countriesKeyByCode)
|
||||
.withRegions(regions)
|
||||
)
|
||||
subdivisionsKeyByCode = subdivisions.keyBy((subdivision: Subdivision) => subdivision.code)
|
||||
subdivisionsGroupedByCountryCode = subdivisions.groupBy(
|
||||
(subdivision: Subdivision) => subdivision.countryCode
|
||||
)
|
||||
|
||||
channels = channels.map((channel: Channel) =>
|
||||
channel.withFeeds(feedsGroupedByChannelId).withLogos(logosGroupedByChannelId)
|
||||
channel
|
||||
.withFeeds(feedsGroupedByChannelId)
|
||||
.withLogos(logosGroupedByChannelId)
|
||||
.withCategories(categoriesKeyById)
|
||||
.withCountry(countriesKeyByCode)
|
||||
.withSubdivision(subdivisionsKeyByCode)
|
||||
.withCategories(categoriesKeyById)
|
||||
)
|
||||
channelsKeyById = channels.keyBy((channel: Channel) => channel.id)
|
||||
|
||||
feeds = feeds.map((feed: Feed) =>
|
||||
feed
|
||||
.withChannel(channelsKeyById)
|
||||
.withLanguages(languagesKeyByCode)
|
||||
.withTimezones(timezonesKeyById)
|
||||
.withBroadcastArea(
|
||||
citiesKeyByCode,
|
||||
subdivisionsKeyByCode,
|
||||
countriesKeyByCode,
|
||||
regionsKeyByCode
|
||||
)
|
||||
)
|
||||
feedsGroupedByChannelId = feeds.groupBy((feed: Feed) => feed.channelId)
|
||||
feedsGroupedById = feeds.groupBy((feed: Feed) => feed.id)
|
||||
|
||||
return {
|
||||
blocklistRecordsGroupedByChannelId,
|
||||
@@ -111,6 +146,7 @@ export class DataProcessor {
|
||||
regionsKeyByCode,
|
||||
blocklistRecords,
|
||||
channelsKeyById,
|
||||
citiesKeyByCode,
|
||||
subdivisions,
|
||||
categories,
|
||||
countries,
|
||||
@@ -119,6 +155,7 @@ export class DataProcessor {
|
||||
channels,
|
||||
regions,
|
||||
streams,
|
||||
cities,
|
||||
guides,
|
||||
feeds,
|
||||
logos
|
||||
|
||||
@@ -1,33 +1,37 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
export class Markdown {
|
||||
filepath: string
|
||||
type MarkdownConfig = {
|
||||
build: string
|
||||
template: string
|
||||
}
|
||||
|
||||
constructor(filepath: string) {
|
||||
this.filepath = filepath
|
||||
export class Markdown {
|
||||
build: string
|
||||
template: string
|
||||
|
||||
constructor(config: MarkdownConfig) {
|
||||
this.build = config.build
|
||||
this.template = config.template
|
||||
}
|
||||
|
||||
compile() {
|
||||
const config = JSON.parse(fs.readFileSync(this.filepath, 'utf8'))
|
||||
const workingDir = process.cwd()
|
||||
|
||||
config.files.forEach((templateFile: string) => {
|
||||
const templatePath = path.resolve(workingDir, templateFile)
|
||||
const content = fs.readFileSync(templatePath, 'utf8')
|
||||
const processedContent = this.processIncludes(content, workingDir)
|
||||
|
||||
if (config.build) {
|
||||
const outputPath = path.resolve(workingDir, config.build)
|
||||
fs.writeFileSync(outputPath, processedContent, 'utf8')
|
||||
}
|
||||
})
|
||||
const workingDir = process.cwd()
|
||||
|
||||
const templatePath = path.resolve(workingDir, this.template)
|
||||
const template = fs.readFileSync(templatePath, 'utf8')
|
||||
const processedContent = this.processIncludes(template, workingDir)
|
||||
|
||||
if (this.build) {
|
||||
const outputPath = path.resolve(workingDir, this.build)
|
||||
fs.writeFileSync(outputPath, processedContent, 'utf8')
|
||||
}
|
||||
}
|
||||
|
||||
private processIncludes(content: string, baseDir: string): string {
|
||||
private processIncludes(template: string, baseDir: string): string {
|
||||
const includeRegex = /#include\s+"([^"]+)"/g
|
||||
|
||||
return content.replace(includeRegex, (match, includePath) => {
|
||||
|
||||
return template.replace(includeRegex, (match, includePath) => {
|
||||
try {
|
||||
const fullPath = path.resolve(baseDir, includePath)
|
||||
const includeContent = fs.readFileSync(fullPath, 'utf8')
|
||||
|
||||
43
scripts/generators/citiesGenerator.ts
Normal file
43
scripts/generators/citiesGenerator.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { City, Stream, Playlist } from '../models'
|
||||
import { Collection, Storage, File } from '@freearhey/core'
|
||||
import { PUBLIC_DIR, EOL } from '../constants'
|
||||
import { Generator } from './generator'
|
||||
|
||||
type CitiesGeneratorProps = {
|
||||
streams: Collection
|
||||
cities: Collection
|
||||
logFile: File
|
||||
}
|
||||
|
||||
export class CitiesGenerator implements Generator {
|
||||
streams: Collection
|
||||
cities: Collection
|
||||
storage: Storage
|
||||
logFile: File
|
||||
|
||||
constructor({ streams, cities, logFile }: CitiesGeneratorProps) {
|
||||
this.streams = streams.clone()
|
||||
this.cities = cities
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logFile = logFile
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
const streams = this.streams
|
||||
.orderBy((stream: Stream) => stream.getTitle())
|
||||
.filter((stream: Stream) => stream.isSFW())
|
||||
|
||||
this.cities.forEach(async (city: City) => {
|
||||
const cityStreams = streams.filter((stream: Stream) => stream.isBroadcastInCity(city))
|
||||
|
||||
if (cityStreams.isEmpty()) return
|
||||
|
||||
const playlist = new Playlist(cityStreams, { public: true })
|
||||
const filepath = `cities/${city.code.toLowerCase()}.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logFile.append(
|
||||
JSON.stringify({ type: 'city', filepath, count: playlist.streams.count() }) + EOL
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,18 @@ export class CountriesGenerator implements Generator {
|
||||
)
|
||||
})
|
||||
|
||||
const internationalStreams = streams.filter((stream: Stream) => stream.isInternational())
|
||||
const internationalPlaylist = new Playlist(internationalStreams, { public: true })
|
||||
const internationalFilepath = 'countries/int.m3u'
|
||||
await this.storage.save(internationalFilepath, internationalPlaylist.toString())
|
||||
this.logFile.append(
|
||||
JSON.stringify({
|
||||
type: 'country',
|
||||
filepath: internationalFilepath,
|
||||
count: internationalPlaylist.streams.count()
|
||||
}) + EOL
|
||||
)
|
||||
|
||||
const undefinedStreams = streams.filter((stream: Stream) => !stream.hasBroadcastArea())
|
||||
const undefinedPlaylist = new Playlist(undefinedStreams, { public: true })
|
||||
const undefinedFilepath = 'countries/undefined.m3u'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export * from './categoriesGenerator'
|
||||
export * from './citiesGenerator'
|
||||
export * from './countriesGenerator'
|
||||
export * from './indexCategoryGenerator'
|
||||
export * from './indexCountryGenerator'
|
||||
export * from './indexGenerator'
|
||||
export * from './indexLanguageGenerator'
|
||||
export * from './indexNsfwGenerator'
|
||||
export * from './indexRegionGenerator'
|
||||
export * from './languagesGenerator'
|
||||
export * from './rawGenerator'
|
||||
export * from './regionsGenerator'
|
||||
|
||||
@@ -33,17 +33,17 @@ export class IndexCountryGenerator implements Generator {
|
||||
return
|
||||
}
|
||||
|
||||
if (stream.isInternational()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'International'
|
||||
groupedStreams.add(streamClone)
|
||||
}
|
||||
|
||||
stream.getBroadcastCountries().forEach((country: Country) => {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = country.name
|
||||
groupedStreams.add(streamClone)
|
||||
})
|
||||
|
||||
if (stream.isInternational()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'International'
|
||||
groupedStreams.add(streamClone)
|
||||
}
|
||||
})
|
||||
|
||||
groupedStreams = groupedStreams.orderBy((stream: Stream) => {
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
import { Collection, Storage, File } from '@freearhey/core'
|
||||
import { Stream, Playlist, Region } from '../models'
|
||||
import { PUBLIC_DIR, EOL } from '../constants'
|
||||
import { Generator } from './generator'
|
||||
|
||||
type IndexRegionGeneratorProps = {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
logFile: File
|
||||
}
|
||||
|
||||
export class IndexRegionGenerator implements Generator {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
storage: Storage
|
||||
logFile: File
|
||||
|
||||
constructor({ streams, regions, logFile }: IndexRegionGeneratorProps) {
|
||||
this.streams = streams.clone()
|
||||
this.regions = regions
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logFile = logFile
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
let groupedStreams = new Collection()
|
||||
this.streams
|
||||
.orderBy((stream: Stream) => stream.getTitle())
|
||||
.filter((stream: Stream) => stream.isSFW())
|
||||
.forEach((stream: Stream) => {
|
||||
if (stream.isInternational()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'International'
|
||||
groupedStreams.push(streamClone)
|
||||
return
|
||||
}
|
||||
|
||||
if (!stream.hasBroadcastArea()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'Undefined'
|
||||
groupedStreams.push(streamClone)
|
||||
return
|
||||
}
|
||||
|
||||
stream.getBroadcastRegions().forEach((region: Region) => {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = region.name
|
||||
groupedStreams.push(streamClone)
|
||||
})
|
||||
})
|
||||
|
||||
groupedStreams = groupedStreams.orderBy((stream: Stream) => {
|
||||
if (stream.groupTitle === 'International') return 'ZZ'
|
||||
if (stream.groupTitle === 'Undefined') return 'ZZZ'
|
||||
return stream.groupTitle
|
||||
})
|
||||
|
||||
const playlist = new Playlist(groupedStreams, { public: true })
|
||||
const filepath = 'index.region.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logFile.append(
|
||||
JSON.stringify({ type: 'index', filepath, count: playlist.streams.count() }) + EOL
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,6 @@ export class RegionsGenerator implements Generator {
|
||||
.filter((stream: Stream) => stream.isSFW())
|
||||
|
||||
this.regions.forEach(async (region: Region) => {
|
||||
if (region.isWorldwide()) return
|
||||
|
||||
const regionStreams = streams.filter((stream: Stream) => stream.isBroadcastInRegion(region))
|
||||
|
||||
const playlist = new Playlist(regionStreams, { public: true })
|
||||
@@ -39,25 +37,5 @@ export class RegionsGenerator implements Generator {
|
||||
JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() }) + EOL
|
||||
)
|
||||
})
|
||||
|
||||
const internationalStreams = streams.filter((stream: Stream) => stream.isInternational())
|
||||
const internationalPlaylist = new Playlist(internationalStreams, { public: true })
|
||||
const internationalFilepath = 'regions/int.m3u'
|
||||
await this.storage.save(internationalFilepath, internationalPlaylist.toString())
|
||||
this.logFile.append(
|
||||
JSON.stringify({
|
||||
type: 'region',
|
||||
filepath: internationalFilepath,
|
||||
count: internationalPlaylist.streams.count()
|
||||
}) + EOL
|
||||
)
|
||||
|
||||
const undefinedStreams = streams.filter((stream: Stream) => !stream.hasBroadcastArea())
|
||||
const playlist = new Playlist(undefinedStreams, { public: true })
|
||||
const filepath = 'regions/undefined.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logFile.append(
|
||||
JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() }) + EOL
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,103 @@
|
||||
type BroadcastAreaProps = {
|
||||
code: string
|
||||
}
|
||||
import { Collection, Dictionary } from '@freearhey/core'
|
||||
import { City, Subdivision, Region, Country } from './'
|
||||
|
||||
export class BroadcastArea {
|
||||
code: string
|
||||
codes: Collection
|
||||
citiesIncluded: Collection
|
||||
subdivisionsIncluded: Collection
|
||||
countriesIncluded: Collection
|
||||
regionsIncluded: Collection
|
||||
|
||||
constructor(data: BroadcastAreaProps) {
|
||||
this.code = data.code
|
||||
constructor(codes: Collection) {
|
||||
this.codes = codes
|
||||
}
|
||||
|
||||
withLocations(
|
||||
citiesKeyByCode: Dictionary,
|
||||
subdivisionsKeyByCode: Dictionary,
|
||||
countriesKeyByCode: Dictionary,
|
||||
regionsKeyByCode: Dictionary
|
||||
): this {
|
||||
let citiesIncluded = new Collection()
|
||||
let subdivisionsIncluded = new Collection()
|
||||
let countriesIncluded = new Collection()
|
||||
let regionsIncluded = new Collection()
|
||||
|
||||
this.codes.forEach((value: string) => {
|
||||
const [type, code] = value.split('/')
|
||||
|
||||
switch (type) {
|
||||
case 'ct': {
|
||||
const city: City = citiesKeyByCode.get(code)
|
||||
if (!city) return
|
||||
citiesIncluded.add(city)
|
||||
regionsIncluded = regionsIncluded.concat(city.getRegions())
|
||||
break
|
||||
}
|
||||
case 's': {
|
||||
const subdivision: Subdivision = subdivisionsKeyByCode.get(code)
|
||||
if (!subdivision) return
|
||||
subdivisionsIncluded.add(subdivision)
|
||||
regionsIncluded = regionsIncluded.concat(subdivision.getRegions())
|
||||
break
|
||||
}
|
||||
case 'c': {
|
||||
const country: Country = countriesKeyByCode.get(code)
|
||||
if (!country) return
|
||||
countriesIncluded.add(country)
|
||||
regionsIncluded = regionsIncluded.concat(country.getRegions())
|
||||
break
|
||||
}
|
||||
case 'r': {
|
||||
const region: Region = regionsKeyByCode.get(code)
|
||||
if (!region) return
|
||||
regionsIncluded = regionsIncluded.concat(region.getRegions())
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.citiesIncluded = citiesIncluded.uniqBy((city: City) => city.code)
|
||||
this.subdivisionsIncluded = subdivisionsIncluded.uniqBy(
|
||||
(subdivision: Subdivision) => subdivision.code
|
||||
)
|
||||
this.countriesIncluded = countriesIncluded.uniqBy((country: Country) => country.code)
|
||||
this.regionsIncluded = regionsIncluded.uniqBy((region: Region) => region.code)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
getCountries(): Collection {
|
||||
return this.countriesIncluded || new Collection()
|
||||
}
|
||||
|
||||
getSubdivisions(): Collection {
|
||||
return this.subdivisionsIncluded || new Collection()
|
||||
}
|
||||
|
||||
getCities(): Collection {
|
||||
return this.citiesIncluded || new Collection()
|
||||
}
|
||||
|
||||
getRegions(): Collection {
|
||||
return this.regionsIncluded || new Collection()
|
||||
}
|
||||
|
||||
includesCountry(country: Country): boolean {
|
||||
return this.getCountries().includes((_country: Country) => _country.code === country.code)
|
||||
}
|
||||
|
||||
includesSubdivision(subdivision: Subdivision): boolean {
|
||||
return this.getSubdivisions().includes(
|
||||
(_subdivision: Subdivision) => _subdivision.code === subdivision.code
|
||||
)
|
||||
}
|
||||
|
||||
includesRegion(region: Region): boolean {
|
||||
return this.getRegions().includes((_region: Region) => _region.code === region.code)
|
||||
}
|
||||
|
||||
includesCity(city: City): boolean {
|
||||
return this.getCities().includes((_city: City) => _city.code === city.code)
|
||||
}
|
||||
}
|
||||
|
||||
78
scripts/models/city.ts
Normal file
78
scripts/models/city.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Collection, Dictionary } from '@freearhey/core'
|
||||
import { Country, Region, Subdivision } from '.'
|
||||
import type { CityData, CitySerializedData } from '../types/city'
|
||||
|
||||
export class City {
|
||||
code: string
|
||||
name: string
|
||||
countryCode: string
|
||||
country?: Country
|
||||
subdivisionCode?: string
|
||||
subdivision?: Subdivision
|
||||
wikidataId: string
|
||||
regions?: Collection
|
||||
|
||||
constructor(data?: CityData) {
|
||||
if (!data) return
|
||||
|
||||
this.code = data.code
|
||||
this.name = data.name
|
||||
this.countryCode = data.country
|
||||
this.subdivisionCode = data.subdivision || undefined
|
||||
this.wikidataId = data.wikidata_id
|
||||
}
|
||||
|
||||
withCountry(countriesKeyByCode: Dictionary): this {
|
||||
this.country = countriesKeyByCode.get(this.countryCode)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withSubdivision(subdivisionsKeyByCode: Dictionary): this {
|
||||
if (!this.subdivisionCode) return this
|
||||
|
||||
this.subdivision = subdivisionsKeyByCode.get(this.subdivisionCode)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withRegions(regions: Collection): this {
|
||||
this.regions = regions.filter((region: Region) =>
|
||||
region.countryCodes.includes(this.countryCode)
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
getRegions(): Collection {
|
||||
if (!this.regions) return new Collection()
|
||||
|
||||
return this.regions
|
||||
}
|
||||
|
||||
serialize(): CitySerializedData {
|
||||
return {
|
||||
code: this.code,
|
||||
name: this.name,
|
||||
countryCode: this.countryCode,
|
||||
country: this.country ? this.country.serialize() : undefined,
|
||||
subdivisionCode: this.subdivisionCode || null,
|
||||
subdivision: this.subdivision ? this.subdivision.serialize() : undefined,
|
||||
wikidataId: this.wikidataId
|
||||
}
|
||||
}
|
||||
|
||||
deserialize(data: CitySerializedData): this {
|
||||
this.code = data.code
|
||||
this.name = data.name
|
||||
this.countryCode = data.countryCode
|
||||
this.country = data.country ? new Country().deserialize(data.country) : undefined
|
||||
this.subdivisionCode = data.subdivisionCode || undefined
|
||||
this.subdivision = data.subdivision
|
||||
? new Subdivision().deserialize(data.subdivision)
|
||||
: undefined
|
||||
this.wikidataId = data.wikidataId
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ export class Country {
|
||||
language?: Language
|
||||
subdivisions?: Collection
|
||||
regions?: Collection
|
||||
cities?: Collection
|
||||
|
||||
constructor(data?: CountryData) {
|
||||
if (!data) return
|
||||
@@ -23,15 +24,19 @@ export class Country {
|
||||
}
|
||||
|
||||
withSubdivisions(subdivisionsGroupedByCountryCode: Dictionary): this {
|
||||
this.subdivisions = subdivisionsGroupedByCountryCode.get(this.code) || new Collection()
|
||||
this.subdivisions = new Collection(subdivisionsGroupedByCountryCode.get(this.code))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withRegions(regions: Collection): this {
|
||||
this.regions = regions.filter(
|
||||
(region: Region) => region.code !== 'INT' && region.includesCountryCode(this.code)
|
||||
)
|
||||
this.regions = regions.filter((region: Region) => region.includesCountryCode(this.code))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withCities(citiesGroupedByCountryCode: Dictionary): this {
|
||||
this.cities = new Collection(citiesGroupedByCountryCode.get(this.code))
|
||||
|
||||
return this
|
||||
}
|
||||
@@ -54,6 +59,10 @@ export class Country {
|
||||
return this.subdivisions || new Collection()
|
||||
}
|
||||
|
||||
getCities(): Collection {
|
||||
return this.cities || new Collection()
|
||||
}
|
||||
|
||||
serialize(): CountrySerializedData {
|
||||
return {
|
||||
code: this.code,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Country, Language, Region, Channel, Subdivision } from './index'
|
||||
import { Country, Language, Region, Channel, Subdivision, BroadcastArea, City } from './index'
|
||||
import { Collection, Dictionary } from '@freearhey/core'
|
||||
import type { FeedData } from '../types/feed'
|
||||
|
||||
@@ -9,12 +9,7 @@ export class Feed {
|
||||
name: string
|
||||
isMain: boolean
|
||||
broadcastAreaCodes: Collection
|
||||
broadcastCountryCodes: Collection
|
||||
broadcastCountries?: Collection
|
||||
broadcastRegionCodes: Collection
|
||||
broadcastRegions?: Collection
|
||||
broadcastSubdivisionCodes: Collection
|
||||
broadcastSubdivisions?: Collection
|
||||
broadcastArea?: BroadcastArea
|
||||
languageCodes: Collection
|
||||
languages?: Collection
|
||||
timezoneIds: Collection
|
||||
@@ -32,25 +27,6 @@ export class Feed {
|
||||
this.languageCodes = new Collection(data.languages)
|
||||
this.timezoneIds = new Collection(data.timezones)
|
||||
this.videoFormat = data.video_format
|
||||
this.broadcastCountryCodes = new Collection()
|
||||
this.broadcastRegionCodes = new Collection()
|
||||
this.broadcastSubdivisionCodes = new Collection()
|
||||
|
||||
this.broadcastAreaCodes.forEach((areaCode: string) => {
|
||||
const [type, code] = areaCode.split('/')
|
||||
|
||||
switch (type) {
|
||||
case 'c':
|
||||
this.broadcastCountryCodes.add(code)
|
||||
break
|
||||
case 'r':
|
||||
this.broadcastRegionCodes.add(code)
|
||||
break
|
||||
case 's':
|
||||
this.broadcastSubdivisionCodes.add(code)
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
withChannel(channelsKeyById: Dictionary): this {
|
||||
@@ -93,76 +69,36 @@ export class Feed {
|
||||
return this
|
||||
}
|
||||
|
||||
withBroadcastSubdivisions(subdivisionsKeyByCode: Dictionary): this {
|
||||
this.broadcastSubdivisions = this.broadcastSubdivisionCodes.map((code: string) =>
|
||||
subdivisionsKeyByCode.get(code)
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withBroadcastCountries(
|
||||
withBroadcastArea(
|
||||
citiesKeyByCode: Dictionary,
|
||||
subdivisionsKeyByCode: Dictionary,
|
||||
countriesKeyByCode: Dictionary,
|
||||
regionsKeyByCode: Dictionary,
|
||||
subdivisionsKeyByCode: Dictionary
|
||||
regionsKeyByCode: Dictionary
|
||||
): this {
|
||||
const broadcastCountries = new Collection()
|
||||
|
||||
if (this.isInternational()) {
|
||||
this.broadcastCountries = broadcastCountries
|
||||
return this
|
||||
}
|
||||
|
||||
this.broadcastCountryCodes.forEach((code: string) => {
|
||||
broadcastCountries.add(countriesKeyByCode.get(code))
|
||||
})
|
||||
|
||||
this.broadcastRegionCodes.forEach((code: string) => {
|
||||
const region: Region = regionsKeyByCode.get(code)
|
||||
if (region) {
|
||||
region.countryCodes.forEach((countryCode: string) => {
|
||||
broadcastCountries.add(countriesKeyByCode.get(countryCode))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.broadcastSubdivisionCodes.forEach((code: string) => {
|
||||
const subdivision: Subdivision = subdivisionsKeyByCode.get(code)
|
||||
if (subdivision) {
|
||||
broadcastCountries.add(countriesKeyByCode.get(subdivision.countryCode))
|
||||
}
|
||||
})
|
||||
|
||||
this.broadcastCountries = broadcastCountries.uniq().filter(Boolean)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withBroadcastRegions(regions: Collection): this {
|
||||
if (!this.broadcastCountries) return this
|
||||
const countriesCodes = this.broadcastCountries.map((country: Country) => country.code)
|
||||
|
||||
this.broadcastRegions = regions.filter((region: Region) => {
|
||||
if (region.code === 'INT') return false
|
||||
const intersected = region.countryCodes.intersects(countriesCodes)
|
||||
return intersected.notEmpty()
|
||||
})
|
||||
this.broadcastArea = new BroadcastArea(this.broadcastAreaCodes).withLocations(
|
||||
citiesKeyByCode,
|
||||
subdivisionsKeyByCode,
|
||||
countriesKeyByCode,
|
||||
regionsKeyByCode
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
hasBroadcastArea(): boolean {
|
||||
return (
|
||||
this.isInternational() || (!!this.broadcastCountries && this.broadcastCountries.notEmpty())
|
||||
)
|
||||
return !!this.broadcastArea
|
||||
}
|
||||
|
||||
getBroadcastCountries(): Collection {
|
||||
return this.broadcastCountries || new Collection()
|
||||
if (!this.broadcastArea) return new Collection()
|
||||
|
||||
return this.broadcastArea.getCountries()
|
||||
}
|
||||
|
||||
getBroadcastRegions(): Collection {
|
||||
return this.broadcastRegions || new Collection()
|
||||
if (!this.broadcastArea) return new Collection()
|
||||
|
||||
return this.broadcastArea.getRegions()
|
||||
}
|
||||
|
||||
getTimezones(): Collection {
|
||||
@@ -184,35 +120,34 @@ export class Feed {
|
||||
)
|
||||
}
|
||||
|
||||
isInternational(): boolean {
|
||||
return this.broadcastAreaCodes.includes('r/INT')
|
||||
isBroadcastInCity(city: City): boolean {
|
||||
if (!this.broadcastArea) return false
|
||||
|
||||
return this.broadcastArea.includesCity(city)
|
||||
}
|
||||
|
||||
isBroadcastInSubdivision(subdivision: Subdivision): boolean {
|
||||
if (this.isInternational()) return false
|
||||
if (this.broadcastSubdivisionCodes.includes(subdivision.code)) return true
|
||||
if (
|
||||
this.broadcastSubdivisionCodes.isEmpty() &&
|
||||
subdivision.country &&
|
||||
this.isBroadcastInCountry(subdivision.country)
|
||||
)
|
||||
return true
|
||||
if (!this.broadcastArea) return false
|
||||
|
||||
return false
|
||||
return this.broadcastArea.includesSubdivision(subdivision)
|
||||
}
|
||||
|
||||
isBroadcastInCountry(country: Country): boolean {
|
||||
if (this.isInternational()) return false
|
||||
if (!this.broadcastArea) return false
|
||||
|
||||
return this.getBroadcastCountries().includes(
|
||||
(_country: Country) => _country.code === country.code
|
||||
)
|
||||
return this.broadcastArea.includesCountry(country)
|
||||
}
|
||||
|
||||
isBroadcastInRegion(region: Region): boolean {
|
||||
if (this.isInternational()) return false
|
||||
if (!this.broadcastArea) return false
|
||||
|
||||
return this.getBroadcastRegions().includes((_region: Region) => _region.code === region.code)
|
||||
return this.broadcastArea.includesRegion(region)
|
||||
}
|
||||
|
||||
isInternational(): boolean {
|
||||
if (!this.broadcastArea) return false
|
||||
|
||||
return this.broadcastArea.codes.join(',').includes('r/')
|
||||
}
|
||||
|
||||
getGuides(): Collection {
|
||||
|
||||
@@ -2,6 +2,7 @@ export * from './blocklistRecord'
|
||||
export * from './broadcastArea'
|
||||
export * from './category'
|
||||
export * from './channel'
|
||||
export * from './city'
|
||||
export * from './country'
|
||||
export * from './feed'
|
||||
export * from './guide'
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { Collection, Dictionary } from '@freearhey/core'
|
||||
import { Country, Subdivision } from '.'
|
||||
import { City, Country, Subdivision } from '.'
|
||||
import type { RegionData, RegionSerializedData } from '../types/region'
|
||||
import { CountrySerializedData } from '../types/country'
|
||||
import { SubdivisionSerializedData } from '../types/subdivision'
|
||||
import { CitySerializedData } from '../types/city'
|
||||
|
||||
export class Region {
|
||||
code: string
|
||||
name: string
|
||||
countryCodes: Collection
|
||||
countries: Collection = new Collection()
|
||||
subdivisions: Collection = new Collection()
|
||||
countries?: Collection
|
||||
subdivisions?: Collection
|
||||
cities?: Collection
|
||||
regions?: Collection
|
||||
|
||||
constructor(data?: RegionData) {
|
||||
if (!data) return
|
||||
@@ -33,20 +36,50 @@ export class Region {
|
||||
return this
|
||||
}
|
||||
|
||||
withCities(cities: Collection): this {
|
||||
this.cities = cities.filter((city: City) => this.countryCodes.indexOf(city.countryCode) > -1)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withRegions(regions: Collection): this {
|
||||
this.regions = regions.filter(
|
||||
(region: Region) => !region.countryCodes.intersects(this.countryCodes).isEmpty()
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
getSubdivisions(): Collection {
|
||||
if (!this.subdivisions) return new Collection()
|
||||
|
||||
return this.subdivisions
|
||||
}
|
||||
|
||||
getCountries(): Collection {
|
||||
if (!this.countries) return new Collection()
|
||||
|
||||
return this.countries
|
||||
}
|
||||
|
||||
getCities(): Collection {
|
||||
if (!this.cities) return new Collection()
|
||||
|
||||
return this.cities
|
||||
}
|
||||
|
||||
getRegions(): Collection {
|
||||
if (!this.regions) return new Collection()
|
||||
|
||||
return this.regions
|
||||
}
|
||||
|
||||
includesCountryCode(code: string): boolean {
|
||||
return this.countryCodes.includes((countryCode: string) => countryCode === code)
|
||||
}
|
||||
|
||||
isWorldwide(): boolean {
|
||||
return this.code === 'INT'
|
||||
return ['INT', 'WW'].includes(this.code)
|
||||
}
|
||||
|
||||
serialize(): RegionSerializedData {
|
||||
@@ -54,9 +87,14 @@ export class Region {
|
||||
code: this.code,
|
||||
name: this.name,
|
||||
countryCodes: this.countryCodes.all(),
|
||||
countries: this.countries.map((country: Country) => country.serialize()).all(),
|
||||
subdivisions: this.subdivisions
|
||||
countries: this.getCountries()
|
||||
.map((country: Country) => country.serialize())
|
||||
.all(),
|
||||
subdivisions: this.getSubdivisions()
|
||||
.map((subdivision: Subdivision) => subdivision.serialize())
|
||||
.all(),
|
||||
cities: this.getCities()
|
||||
.map((city: City) => city.serialize())
|
||||
.all()
|
||||
}
|
||||
}
|
||||
@@ -71,6 +109,9 @@ export class Region {
|
||||
this.subdivisions = new Collection(data.subdivisions).map((data: SubdivisionSerializedData) =>
|
||||
new Subdivision().deserialize(data)
|
||||
)
|
||||
this.cities = new Collection(data.cities).map((data: CitySerializedData) =>
|
||||
new City().deserialize(data)
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
import { Feed, Channel, Category, Region, Subdivision, Country, Language, Logo } from './index'
|
||||
import {
|
||||
Feed,
|
||||
Channel,
|
||||
Category,
|
||||
Region,
|
||||
Subdivision,
|
||||
Country,
|
||||
Language,
|
||||
Logo,
|
||||
City
|
||||
} from './index'
|
||||
import { URL, Collection, Dictionary } from '@freearhey/core'
|
||||
import type { StreamData } from '../types/stream'
|
||||
import parser from 'iptv-playlist-parser'
|
||||
@@ -330,6 +340,10 @@ export class Stream {
|
||||
return this.feed ? this.feed.broadcastAreaCodes : new Collection()
|
||||
}
|
||||
|
||||
isBroadcastInCity(city: City): boolean {
|
||||
return this.feed ? this.feed.isBroadcastInCity(city) : false
|
||||
}
|
||||
|
||||
isBroadcastInSubdivision(subdivision: Subdivision): boolean {
|
||||
return this.feed ? this.feed.isBroadcastInSubdivision(subdivision) : false
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { SubdivisionData, SubdivisionSerializedData } from '../types/subdivision'
|
||||
import { Dictionary } from '@freearhey/core'
|
||||
import { Country } from '.'
|
||||
import { Dictionary, Collection } from '@freearhey/core'
|
||||
import { Country, Region } from '.'
|
||||
|
||||
export class Subdivision {
|
||||
code: string
|
||||
name: string
|
||||
countryCode: string
|
||||
country?: Country
|
||||
parentCode?: string
|
||||
regions?: Collection
|
||||
cities?: Collection
|
||||
|
||||
constructor(data?: SubdivisionData) {
|
||||
if (!data) return
|
||||
@@ -14,6 +17,7 @@ export class Subdivision {
|
||||
this.code = data.code
|
||||
this.name = data.name
|
||||
this.countryCode = data.country
|
||||
this.parentCode = data.parent || undefined
|
||||
}
|
||||
|
||||
withCountry(countriesKeyByCode: Dictionary): this {
|
||||
@@ -22,12 +26,39 @@ export class Subdivision {
|
||||
return this
|
||||
}
|
||||
|
||||
withRegions(regions: Collection): this {
|
||||
this.regions = regions.filter((region: Region) =>
|
||||
region.countryCodes.includes(this.countryCode)
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withCities(citiesGroupedBySubdivisionCode: Dictionary): this {
|
||||
this.cities = new Collection(citiesGroupedBySubdivisionCode.get(this.code))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
getRegions(): Collection {
|
||||
if (!this.regions) return new Collection()
|
||||
|
||||
return this.regions
|
||||
}
|
||||
|
||||
getCities(): Collection {
|
||||
if (!this.cities) return new Collection()
|
||||
|
||||
return this.cities
|
||||
}
|
||||
|
||||
serialize(): SubdivisionSerializedData {
|
||||
return {
|
||||
code: this.code,
|
||||
name: this.name,
|
||||
countryCode: this.code,
|
||||
country: this.country ? this.country.serialize() : undefined
|
||||
countryCode: this.countryCode,
|
||||
country: this.country ? this.country.serialize() : undefined,
|
||||
parentCode: this.parentCode || null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +67,7 @@ export class Subdivision {
|
||||
this.name = data.name
|
||||
this.countryCode = data.countryCode
|
||||
this.country = data.country ? new Country().deserialize(data.country) : undefined
|
||||
this.parentCode = data.parentCode || undefined
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
import { Storage, Collection, File } from '@freearhey/core'
|
||||
import { Storage, Collection, File, Dictionary } from '@freearhey/core'
|
||||
import { HTMLTable, LogParser, LogItem } from '../core'
|
||||
import { LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Category } from '../models'
|
||||
import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Table } from './table'
|
||||
|
||||
export class CategoryTable implements Table {
|
||||
constructor() {}
|
||||
type CategoriesTableProps = {
|
||||
categoriesKeyById: Dictionary
|
||||
}
|
||||
|
||||
export class CategoriesTable implements Table {
|
||||
categoriesKeyById: Dictionary
|
||||
|
||||
constructor({ categoriesKeyById }: CategoriesTableProps) {
|
||||
this.categoriesKeyById = categoriesKeyById
|
||||
}
|
||||
|
||||
async make() {
|
||||
const dataStorage = new Storage(DATA_DIR)
|
||||
const categoriesContent = await dataStorage.json('categories.json')
|
||||
const categories = new Collection(categoriesContent).map(data => new Category(data))
|
||||
const categoriesGroupedById = categories.keyBy((category: Category) => category.id)
|
||||
|
||||
const parser = new LogParser()
|
||||
const logsStorage = new Storage(LOGS_DIR)
|
||||
const generatorsLog = await logsStorage.load('generators.log')
|
||||
|
||||
let data = new Collection()
|
||||
let items = new Collection()
|
||||
parser
|
||||
.parse(generatorsLog)
|
||||
.filter((logItem: LogItem) => logItem.type === 'category')
|
||||
.forEach((logItem: LogItem) => {
|
||||
const file = new File(logItem.filepath)
|
||||
const categoryId = file.name()
|
||||
const category: Category = categoriesGroupedById.get(categoryId)
|
||||
const category: Category = this.categoriesKeyById.get(categoryId)
|
||||
|
||||
data.add([
|
||||
items.add([
|
||||
category ? category.name : 'ZZ',
|
||||
category ? category.name : 'Undefined',
|
||||
logItem.count,
|
||||
@@ -34,14 +37,14 @@ export class CategoryTable implements Table {
|
||||
])
|
||||
})
|
||||
|
||||
data = data
|
||||
items = items
|
||||
.orderBy(item => item[0])
|
||||
.map(item => {
|
||||
item.shift()
|
||||
return item
|
||||
})
|
||||
|
||||
const table = new HTMLTable(data.all(), [
|
||||
const table = new HTMLTable(items.all(), [
|
||||
{ name: 'Category' },
|
||||
{ name: 'Channels', align: 'right' },
|
||||
{ name: 'Playlist', nowrap: true }
|
||||
189
scripts/tables/countriesTable.ts
Normal file
189
scripts/tables/countriesTable.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import { Storage, Collection, Dictionary } from '@freearhey/core'
|
||||
import { City, Country, Subdivision } from '../models'
|
||||
import { LOGS_DIR, README_DIR } from '../constants'
|
||||
import { LogParser, LogItem } from '../core'
|
||||
import { Table } from './table'
|
||||
|
||||
type CountriesTableProps = {
|
||||
countriesKeyByCode: Dictionary
|
||||
subdivisionsKeyByCode: Dictionary
|
||||
countries: Collection
|
||||
subdivisions: Collection
|
||||
cities: Collection
|
||||
}
|
||||
|
||||
export class CountriesTable implements Table {
|
||||
countriesKeyByCode: Dictionary
|
||||
subdivisionsKeyByCode: Dictionary
|
||||
countries: Collection
|
||||
subdivisions: Collection
|
||||
cities: Collection
|
||||
|
||||
constructor({
|
||||
countriesKeyByCode,
|
||||
subdivisionsKeyByCode,
|
||||
countries,
|
||||
subdivisions,
|
||||
cities
|
||||
}: CountriesTableProps) {
|
||||
this.countriesKeyByCode = countriesKeyByCode
|
||||
this.subdivisionsKeyByCode = subdivisionsKeyByCode
|
||||
this.countries = countries
|
||||
this.subdivisions = subdivisions
|
||||
this.cities = cities
|
||||
}
|
||||
|
||||
async make() {
|
||||
const parser = new LogParser()
|
||||
const logsStorage = new Storage(LOGS_DIR)
|
||||
const generatorsLog = await logsStorage.load('generators.log')
|
||||
const parsed = parser.parse(generatorsLog)
|
||||
const logCountries = parsed.filter((logItem: LogItem) => logItem.type === 'country')
|
||||
const logSubdivisions = parsed.filter((logItem: LogItem) => logItem.type === 'subdivision')
|
||||
const logCities = parsed.filter((logItem: LogItem) => logItem.type === 'city')
|
||||
|
||||
let items = new Collection()
|
||||
this.countries.forEach((country: Country) => {
|
||||
const countriesLogItem = logCountries.find(
|
||||
(logItem: LogItem) => logItem.filepath === `countries/${country.code.toLowerCase()}.m3u`
|
||||
)
|
||||
|
||||
let countryItem = {
|
||||
index: country.name,
|
||||
count: 0,
|
||||
link: `https://iptv-org.github.io/iptv/countries/${country.code.toLowerCase()}.m3u`,
|
||||
name: `${country.flag} ${country.name}`,
|
||||
children: new Collection()
|
||||
}
|
||||
|
||||
if (countriesLogItem) {
|
||||
countryItem.count = countriesLogItem.count
|
||||
}
|
||||
|
||||
const countrySubdivisions = this.subdivisions.filter(
|
||||
(subdivision: Subdivision) => subdivision.countryCode === country.code
|
||||
)
|
||||
const countryCities = this.cities.filter((city: City) => city.countryCode === country.code)
|
||||
if (countrySubdivisions.notEmpty()) {
|
||||
this.subdivisions.forEach((subdivision: Subdivision) => {
|
||||
if (subdivision.countryCode !== country.code) return
|
||||
const subdivisionCities = countryCities.filter(
|
||||
(city: City) =>
|
||||
(city.subdivisionCode && city.subdivisionCode === subdivision.code) ||
|
||||
city.countryCode === subdivision.countryCode
|
||||
)
|
||||
const subdivisionsLogItem = logSubdivisions.find(
|
||||
(logItem: LogItem) =>
|
||||
logItem.filepath === `subdivisions/${subdivision.code.toLowerCase()}.m3u`
|
||||
)
|
||||
|
||||
let subdivisionItem = {
|
||||
index: subdivision.name,
|
||||
name: subdivision.name,
|
||||
count: 0,
|
||||
link: `https://iptv-org.github.io/iptv/subdivisions/${subdivision.code.toLowerCase()}.m3u`,
|
||||
children: new Collection()
|
||||
}
|
||||
|
||||
if (subdivisionsLogItem) {
|
||||
subdivisionItem.count = subdivisionsLogItem.count
|
||||
}
|
||||
|
||||
subdivisionCities.forEach((city: City) => {
|
||||
if (city.countryCode !== country.code || city.subdivisionCode !== subdivision.code)
|
||||
return
|
||||
const citiesLogItem = logCities.find(
|
||||
(logItem: LogItem) => logItem.filepath === `cities/${city.code.toLowerCase()}.m3u`
|
||||
)
|
||||
|
||||
if (!citiesLogItem) return
|
||||
|
||||
subdivisionItem.children.add({
|
||||
index: city.name,
|
||||
name: city.name,
|
||||
count: citiesLogItem.count,
|
||||
link: `https://iptv-org.github.io/iptv/${citiesLogItem.filepath}`
|
||||
})
|
||||
})
|
||||
|
||||
if (subdivisionItem.count > 0 || subdivisionItem.children.notEmpty()) {
|
||||
countryItem.children.add(subdivisionItem)
|
||||
}
|
||||
})
|
||||
} else if (countryCities.notEmpty()) {
|
||||
countryCities.forEach((city: City) => {
|
||||
const citiesLogItem = logCities.find(
|
||||
(logItem: LogItem) => logItem.filepath === `cities/${city.code.toLowerCase()}.m3u`
|
||||
)
|
||||
|
||||
if (!citiesLogItem) return
|
||||
|
||||
countryItem.children.add({
|
||||
index: city.name,
|
||||
name: city.name,
|
||||
count: citiesLogItem.count,
|
||||
link: `https://iptv-org.github.io/iptv/${citiesLogItem.filepath}`,
|
||||
children: new Collection()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (countryItem.count > 0 || countryItem.children.notEmpty()) {
|
||||
items.add(countryItem)
|
||||
}
|
||||
})
|
||||
|
||||
const internationalLogItem = logCountries.find(
|
||||
(logItem: LogItem) => logItem.filepath === 'countries/int.m3u'
|
||||
)
|
||||
|
||||
if (internationalLogItem) {
|
||||
items.push({
|
||||
index: 'ZZ',
|
||||
name: '🌐 International',
|
||||
count: internationalLogItem.count,
|
||||
link: `https://iptv-org.github.io/iptv/${internationalLogItem.filepath}`,
|
||||
children: new Collection()
|
||||
})
|
||||
}
|
||||
|
||||
const undefinedLogItem = logCountries.find(
|
||||
(logItem: LogItem) => logItem.filepath === `countries/undefined.m3u`
|
||||
)
|
||||
|
||||
if (undefinedLogItem) {
|
||||
items.push({
|
||||
index: 'ZZZ',
|
||||
name: 'Undefined',
|
||||
count: undefinedLogItem.count,
|
||||
link: `https://iptv-org.github.io/iptv/${undefinedLogItem.filepath}`,
|
||||
children: new Collection()
|
||||
})
|
||||
}
|
||||
|
||||
items = items.orderBy(item => item.index)
|
||||
|
||||
const output = items
|
||||
.map(item => {
|
||||
let row = `- ${item.name} <code>${item.link}</code>`
|
||||
|
||||
item.children
|
||||
.orderBy(item => item.index)
|
||||
.forEach(item => {
|
||||
row += `\r\n\ - ${item.name} <code>${item.link}</code>`
|
||||
|
||||
item.children
|
||||
.orderBy(item => item.index)
|
||||
.forEach(item => {
|
||||
row += `\r\n\ - ${item.name} <code>${item.link}</code>`
|
||||
})
|
||||
})
|
||||
|
||||
return row
|
||||
})
|
||||
.join('\r\n')
|
||||
|
||||
const readmeStorage = new Storage(README_DIR)
|
||||
await readmeStorage.save('_countries.md', output)
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import { Storage, Collection, File } from '@freearhey/core'
|
||||
import { HTMLTable, LogParser, LogItem } from '../core'
|
||||
import { Country } from '../models'
|
||||
import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Table } from './table'
|
||||
|
||||
export class CountryTable implements Table {
|
||||
constructor() {}
|
||||
|
||||
async make() {
|
||||
const dataStorage = new Storage(DATA_DIR)
|
||||
|
||||
const countriesContent = await dataStorage.json('countries.json')
|
||||
const countries = new Collection(countriesContent).map(data => new Country(data))
|
||||
const countriesGroupedByCode = countries.keyBy((country: Country) => country.code)
|
||||
|
||||
const parser = new LogParser()
|
||||
const logsStorage = new Storage(LOGS_DIR)
|
||||
const generatorsLog = await logsStorage.load('generators.log')
|
||||
const parsed = parser.parse(generatorsLog)
|
||||
|
||||
let data = new Collection()
|
||||
|
||||
parsed
|
||||
.filter((logItem: LogItem) => logItem.type === 'country')
|
||||
.forEach((logItem: LogItem) => {
|
||||
const file = new File(logItem.filepath)
|
||||
const code = file.name().toUpperCase()
|
||||
const [countryCode] = code.split('-') || ['', '']
|
||||
const country = countriesGroupedByCode.get(countryCode)
|
||||
|
||||
if (country) {
|
||||
data.add([
|
||||
country.name,
|
||||
`${country.flag} ${country.name}`,
|
||||
logItem.count,
|
||||
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
|
||||
])
|
||||
} else {
|
||||
data.add([
|
||||
'ZZ',
|
||||
'Undefined',
|
||||
logItem.count,
|
||||
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
data = data
|
||||
.orderBy(item => item[0])
|
||||
.map(item => {
|
||||
item.shift()
|
||||
return item
|
||||
})
|
||||
|
||||
const table = new HTMLTable(data.all(), [
|
||||
{ name: 'Country' },
|
||||
{ name: 'Channels', align: 'right' },
|
||||
{ name: 'Playlist', nowrap: true }
|
||||
])
|
||||
|
||||
const readmeStorage = new Storage(README_DIR)
|
||||
await readmeStorage.save('_countries.md', table.toString())
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from './categoryTable'
|
||||
export * from './countryTable'
|
||||
export * from './languageTable'
|
||||
export * from './regionTable'
|
||||
export * from './subdivisionTable'
|
||||
export * from './categoriesTable'
|
||||
export * from './countriesTable'
|
||||
export * from './languagesTable'
|
||||
export * from './regionsTable'
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import { Storage, Collection, File } from '@freearhey/core'
|
||||
import { Storage, Collection, File, Dictionary } from '@freearhey/core'
|
||||
import { HTMLTable, LogParser, LogItem } from '../core'
|
||||
import { LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Language } from '../models'
|
||||
import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Table } from './table'
|
||||
|
||||
export class LanguageTable implements Table {
|
||||
constructor() {}
|
||||
type LanguagesTableProps = {
|
||||
languagesKeyByCode: Dictionary
|
||||
}
|
||||
|
||||
export class LanguagesTable implements Table {
|
||||
languagesKeyByCode: Dictionary
|
||||
|
||||
constructor({ languagesKeyByCode }: LanguagesTableProps) {
|
||||
this.languagesKeyByCode = languagesKeyByCode
|
||||
}
|
||||
|
||||
async make() {
|
||||
const dataStorage = new Storage(DATA_DIR)
|
||||
const languagesContent = await dataStorage.json('languages.json')
|
||||
const languages = new Collection(languagesContent).map(data => new Language(data))
|
||||
const languagesGroupedByCode = languages.keyBy((language: Language) => language.code)
|
||||
|
||||
const parser = new LogParser()
|
||||
const logsStorage = new Storage(LOGS_DIR)
|
||||
const generatorsLog = await logsStorage.load('generators.log')
|
||||
@@ -24,7 +27,7 @@ export class LanguageTable implements Table {
|
||||
.forEach((logItem: LogItem) => {
|
||||
const file = new File(logItem.filepath)
|
||||
const languageCode = file.name()
|
||||
const language: Language = languagesGroupedByCode.get(languageCode)
|
||||
const language: Language = this.languagesKeyByCode.get(languageCode)
|
||||
|
||||
data.add([
|
||||
language ? language.name : 'ZZ',
|
||||
@@ -1,62 +0,0 @@
|
||||
import { Storage, Collection, File } from '@freearhey/core'
|
||||
import { HTMLTable, LogParser, LogItem } from '../core'
|
||||
import { Region } from '../models'
|
||||
import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Table } from './table'
|
||||
|
||||
export class RegionTable implements Table {
|
||||
constructor() {}
|
||||
|
||||
async make() {
|
||||
const dataStorage = new Storage(DATA_DIR)
|
||||
const regionsContent = await dataStorage.json('regions.json')
|
||||
const regions = new Collection(regionsContent).map(data => new Region(data))
|
||||
const regionsGroupedByCode = regions.keyBy((region: Region) => region.code)
|
||||
|
||||
const parser = new LogParser()
|
||||
const logsStorage = new Storage(LOGS_DIR)
|
||||
const generatorsLog = await logsStorage.load('generators.log')
|
||||
|
||||
let data = new Collection()
|
||||
parser
|
||||
.parse(generatorsLog)
|
||||
.filter((logItem: LogItem) => logItem.type === 'region')
|
||||
.forEach((logItem: LogItem) => {
|
||||
const file = new File(logItem.filepath)
|
||||
const regionCode = file.name().toUpperCase()
|
||||
const region: Region = regionsGroupedByCode.get(regionCode)
|
||||
|
||||
if (region) {
|
||||
data.add([
|
||||
region.name,
|
||||
region.name,
|
||||
logItem.count,
|
||||
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
|
||||
])
|
||||
} else {
|
||||
data.add([
|
||||
'ZZZ',
|
||||
'Undefined',
|
||||
logItem.count,
|
||||
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
data = data
|
||||
.orderBy(item => item[0])
|
||||
.map(item => {
|
||||
item.shift()
|
||||
return item
|
||||
})
|
||||
|
||||
const table = new HTMLTable(data.all(), [
|
||||
{ name: 'Region', align: 'left' },
|
||||
{ name: 'Channels', align: 'right' },
|
||||
{ name: 'Playlist', align: 'left', nowrap: true }
|
||||
])
|
||||
|
||||
const readmeStorage = new Storage(README_DIR)
|
||||
await readmeStorage.save('_regions.md', table.toString())
|
||||
}
|
||||
}
|
||||
52
scripts/tables/regionsTable.ts
Normal file
52
scripts/tables/regionsTable.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Storage, Collection, File } from '@freearhey/core'
|
||||
import { HTMLTable, LogParser, LogItem } from '../core'
|
||||
import { LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Region } from '../models'
|
||||
import { Table } from './table'
|
||||
|
||||
type RegionsTableProps = {
|
||||
regions: Collection
|
||||
}
|
||||
|
||||
export class RegionsTable implements Table {
|
||||
regions: Collection
|
||||
|
||||
constructor({ regions }: RegionsTableProps) {
|
||||
this.regions = regions
|
||||
}
|
||||
|
||||
async make() {
|
||||
const parser = new LogParser()
|
||||
const logsStorage = new Storage(LOGS_DIR)
|
||||
const generatorsLog = await logsStorage.load('generators.log')
|
||||
const parsed = parser.parse(generatorsLog)
|
||||
const logRegions = parsed.filter((logItem: LogItem) => logItem.type === 'region')
|
||||
|
||||
let items = new Collection()
|
||||
this.regions.forEach((region: Region) => {
|
||||
const logItem = logRegions.find(
|
||||
(logItem: LogItem) => logItem.filepath === `regions/${region.code.toLowerCase()}.m3u`
|
||||
)
|
||||
|
||||
if (!logItem) return
|
||||
|
||||
items.add({
|
||||
index: region.name,
|
||||
name: region.name,
|
||||
count: logItem.count,
|
||||
link: `https://iptv-org.github.io/iptv/${logItem.filepath}`
|
||||
})
|
||||
})
|
||||
|
||||
items = items.orderBy(item => item.index)
|
||||
|
||||
const output = items
|
||||
.map(item => {
|
||||
return `- ${item.name} <code>${item.link}</code>`
|
||||
})
|
||||
.join('\r\n')
|
||||
|
||||
const readmeStorage = new Storage(README_DIR)
|
||||
await readmeStorage.save('_regions.md', output)
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import { Storage, Collection, File } from '@freearhey/core'
|
||||
import { HTMLTable, LogParser, LogItem } from '../core'
|
||||
import { Country, Subdivision } from '../models'
|
||||
import { DATA_DIR, LOGS_DIR, README_DIR } from '../constants'
|
||||
import { Table } from './table'
|
||||
|
||||
export class SubdivisionTable implements Table {
|
||||
constructor() {}
|
||||
|
||||
async make() {
|
||||
const dataStorage = new Storage(DATA_DIR)
|
||||
|
||||
const countriesContent = await dataStorage.json('countries.json')
|
||||
const countries = new Collection(countriesContent).map(data => new Country(data))
|
||||
const countriesGroupedByCode = countries.keyBy((country: Country) => country.code)
|
||||
const subdivisionsContent = await dataStorage.json('subdivisions.json')
|
||||
const subdivisions = new Collection(subdivisionsContent).map(data => new Subdivision(data))
|
||||
const subdivisionsGroupedByCode = subdivisions.keyBy(
|
||||
(subdivision: Subdivision) => subdivision.code
|
||||
)
|
||||
|
||||
const parser = new LogParser()
|
||||
const logsStorage = new Storage(LOGS_DIR)
|
||||
const generatorsLog = await logsStorage.load('generators.log')
|
||||
const parsed = parser.parse(generatorsLog)
|
||||
const parsedSubdivisions = parsed.filter((logItem: LogItem) => logItem.type === 'subdivision')
|
||||
|
||||
let output = ''
|
||||
countries.forEach((country: Country) => {
|
||||
const parsedCountrySubdivisions = parsedSubdivisions.filter((logItem: LogItem) =>
|
||||
logItem.filepath.includes(`subdivisions/${country.code.toLowerCase()}`)
|
||||
)
|
||||
|
||||
if (!parsedCountrySubdivisions.length) return
|
||||
|
||||
output += `\r\n<details>\r\n<summary>${country.name}</summary>\r\n`
|
||||
|
||||
const data = new Collection()
|
||||
|
||||
parsedCountrySubdivisions.forEach((logItem: LogItem) => {
|
||||
const file = new File(logItem.filepath)
|
||||
const code = file.name().toUpperCase()
|
||||
const [countryCode, subdivisionCode] = code.split('-') || ['', '']
|
||||
const country = countriesGroupedByCode.get(countryCode)
|
||||
|
||||
if (country && subdivisionCode) {
|
||||
const subdivision = subdivisionsGroupedByCode.get(code)
|
||||
if (subdivision) {
|
||||
data.add([
|
||||
subdivision.name,
|
||||
logItem.count,
|
||||
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
|
||||
])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const table = new HTMLTable(data.all(), [
|
||||
{ name: 'Subdivision' },
|
||||
{ name: 'Channels', align: 'right' },
|
||||
{ name: 'Playlist', nowrap: true }
|
||||
])
|
||||
|
||||
output += table.toString()
|
||||
|
||||
output += '\r\n</details>'
|
||||
})
|
||||
|
||||
const readmeStorage = new Storage(README_DIR)
|
||||
await readmeStorage.save('_subdivisions.md', output.trim())
|
||||
}
|
||||
}
|
||||
20
scripts/types/city.d.ts
vendored
Normal file
20
scripts/types/city.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { CountrySerializedData } from './country'
|
||||
import { SubdivisionSerializedData } from './subdivision'
|
||||
|
||||
export type CitySerializedData = {
|
||||
code: string
|
||||
name: string
|
||||
countryCode: string
|
||||
country?: CountrySerializedData
|
||||
subdivisionCode: string | null
|
||||
subdivision?: SubdivisionSerializedData
|
||||
wikidataId: string
|
||||
}
|
||||
|
||||
export type CityData = {
|
||||
code: string
|
||||
name: string
|
||||
country: string
|
||||
subdivision: string | null
|
||||
wikidata_id: string
|
||||
}
|
||||
1
scripts/types/dataLoader.d.ts
vendored
1
scripts/types/dataLoader.d.ts
vendored
@@ -17,4 +17,5 @@ export type DataLoaderData = {
|
||||
timezones: object | object[]
|
||||
guides: object | object[]
|
||||
streams: object | object[]
|
||||
cities: object | object[]
|
||||
}
|
||||
|
||||
3
scripts/types/dataProcessor.d.ts
vendored
3
scripts/types/dataProcessor.d.ts
vendored
@@ -15,6 +15,7 @@ export type DataProcessorData = {
|
||||
regionsKeyByCode: Dictionary
|
||||
blocklistRecords: Collection
|
||||
channelsKeyById: Dictionary
|
||||
citiesKeyByCode: Dictionary
|
||||
subdivisions: Collection
|
||||
categories: Collection
|
||||
countries: Collection
|
||||
@@ -23,6 +24,8 @@ export type DataProcessorData = {
|
||||
channels: Collection
|
||||
regions: Collection
|
||||
streams: Collection
|
||||
cities: Collection
|
||||
guides: Collection
|
||||
feeds: Collection
|
||||
logos: Collection
|
||||
}
|
||||
|
||||
8
scripts/types/feed.d.ts
vendored
8
scripts/types/feed.d.ts
vendored
@@ -1,12 +1,10 @@
|
||||
import { Collection } from '@freearhey/core'
|
||||
|
||||
export type FeedData = {
|
||||
channel: string
|
||||
id: string
|
||||
name: string
|
||||
is_main: boolean
|
||||
broadcast_area: Collection
|
||||
languages: Collection
|
||||
timezones: Collection
|
||||
broadcast_area: string[]
|
||||
languages: string[]
|
||||
timezones: string[]
|
||||
video_format: string
|
||||
}
|
||||
|
||||
5
scripts/types/region.d.ts
vendored
5
scripts/types/region.d.ts
vendored
@@ -1,9 +1,14 @@
|
||||
import { CitySerializedData } from './city'
|
||||
import { CountrySerializedData } from './country'
|
||||
import { SubdivisionSerializedData } from './subdivision'
|
||||
|
||||
export type RegionSerializedData = {
|
||||
code: string
|
||||
name: string
|
||||
countryCodes: string[]
|
||||
countries?: CountrySerializedData[]
|
||||
subdivisions?: SubdivisionSerializedData[]
|
||||
cities?: CitySerializedData[]
|
||||
}
|
||||
|
||||
export type RegionData = {
|
||||
|
||||
4
scripts/types/subdivision.d.ts
vendored
4
scripts/types/subdivision.d.ts
vendored
@@ -1,12 +1,16 @@
|
||||
import { CountrySerializedData } from './country'
|
||||
|
||||
export type SubdivisionSerializedData = {
|
||||
code: string
|
||||
name: string
|
||||
countryCode: string
|
||||
country?: CountrySerializedData
|
||||
parentCode: string | null
|
||||
}
|
||||
|
||||
export type SubdivisionData = {
|
||||
code: string
|
||||
name: string
|
||||
country: string
|
||||
parent: string | null
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ https://mbc1-enc.edgenextcdn.net/out/v1/0965e4d7deae49179172426cbfb3bc5e/index.m
|
||||
https://shd-gcp-live.edgenextcdn.net/live/bitmovin-mbc-1-na/eec141533c90dd34722c503a296dd0d8/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MBC1.ae",MBC 1 (1080p)
|
||||
https://shls-live-enc.edgenextcdn.net/out/v1/0965e4d7deae49179172426cbfb3bc5e/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MBC2.ae",MBC 2 (480p)
|
||||
https://edge66.magictvbox.com/liveApple/MBC_2/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MBC2.ae",MBC 2 (576p)
|
||||
http://213.57.91.138:8000/play/a05k
|
||||
#EXTINF:-1 tvg-id="MBC4.ae@SD",MBC 4 (1080p)
|
||||
https://shd-gcp-live.edgenextcdn.net/live/bitmovin-mbc-4/24f134f1cd63db9346439e96b86ca6ed/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MBC5.ae@SD",MBC 5 (1080p)
|
||||
@@ -139,3 +139,5 @@ http://213.57.91.138:8000/play/a05a
|
||||
https://viamotionhsi.netplus.ch/live/eds/alarabiya/browser-HLS8/alarabiya.m3u8
|
||||
#EXTINF:-1 tvg-id="Alarabiya.ae@SD",Alarabiya
|
||||
https://viamotionhsi.netplus.ch/live/eds/alarabiya/browser-dash/alarabiya.mpd
|
||||
#EXTINF:-1 tvg-id="MBCAction.ae@SD",MBC Action (576p)
|
||||
http://213.57.91.138:8000/play/a05l
|
||||
|
||||
@@ -77,3 +77,5 @@ https://live-radio-cf-vrt.akamaized.net/groupb/live/0f394a26-c87d-475e-8590-e9c6
|
||||
https://live-radio-cf-vrt.akamaized.net/groupb/live/0f394a26-c87d-475e-8590-e9c6e79b28d9/live.isml/.mpd
|
||||
#EXTINF:-1 tvg-id="VTM.be",VTM (720p)
|
||||
https://dpp-live-events.medialaancdn.be/events/hls/aes/webstream1.m3u8
|
||||
#EXTINF:-1 tvg-id="AB3.be@HD",AB3 HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/ab3/browser-HLS8/ab3.m3u8
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="78TV.bg",7/8 TV (1080p)
|
||||
https://ms4.sedemosmi.tv/live/M3E5ajhtdjJkaXBscmZubmUxMmh1cjN1bjZrbm5wZW8/index.m3u8
|
||||
#EXTINF:-1 tvg-id="100AutoMotoTV.bg",100% Auto Moto TV (406p) [Not 24/7]
|
||||
http://100automoto.tv:1935/bgtv1/autotv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AgroTV.bg",Agro TV (480p)
|
||||
https://restr2.bgtv.bg/agro/hls/agro.m3u8
|
||||
#EXTINF:-1 tvg-id="BalkanikaTV.bg",Balkanika TV (270p)
|
||||
rtsp://stream.teracomm.bg/balkanika
|
||||
#EXTINF:-1 tvg-id="CityTV.bg",City TV (576p) [Not 24/7]
|
||||
https://tv.city.bg/play/tshls/citytv/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DSTV.bg",DSTV (614p) [Not 24/7]
|
||||
@@ -22,8 +18,6 @@ https://old2.rn-tv.com/k0/stream.m3u8
|
||||
https://streamer1.streamhost.org/salive/GMIlcbgM/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MagicTV.bg",Magic TV (720p)
|
||||
https://bss1.neterra.tv/magictv/magictv.m3u8
|
||||
#EXTINF:-1 tvg-id="PIKTV.bg",PIK TV (720p)
|
||||
https://s.piktv.bg/l/live/index.m3u8
|
||||
#EXTINF:-1 tvg-id="PlovdivOrthodoxTV.bg",Plovdivska Pravoslavna TV (1080p)
|
||||
http://78.130.149.196:1935/live/pptv.stream/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="RMTV.bg",RMTV (288p)
|
||||
@@ -38,9 +32,9 @@ https://streamer103.neterra.tv/tiankov-folk/live.m3u8
|
||||
https://streamer103.neterra.tv/tiankov-orient/live.m3u8
|
||||
#EXTINF:-1 tvg-id="TravelTV.bg",Travel TV (576p)
|
||||
https://streamer103.neterra.tv/travel/live.m3u8
|
||||
#EXTINF:-1 tvg-id="TV1.bg",TV 1 (720p)
|
||||
https://tv1.cloudcdn.bg:8081/stream.m3u8
|
||||
#EXTINF:-1 tvg-id="TVZagora.bg",TV Zagora (576p)
|
||||
http://zagoratv.ddns.net:8080/tvzagora.m3u8
|
||||
#EXTINF:-1 tvg-id="TVNBulgaria.bg",TVN-Bulgaria (1080p)
|
||||
https://obs.friendshipchurch.eu/tvn/mystream.m3u8
|
||||
#EXTINF:-1 tvg-id="BNT4.bg@SD",BNT 4
|
||||
https://viamotionhsi.netplus.ch/live/eds/bntworld/browser-HLS8/bntworld.m3u8
|
||||
|
||||
@@ -19,7 +19,7 @@ https://alba-bo-bolivision-bolivision.stream.mediatiquestream.com/index.m3u8
|
||||
https://5fe2654d6127d.streamlock.net/cadenaa/videocadenaa/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Canal29TVA.bo@SD",Canal 29 TVA
|
||||
https://play.agenciastreaming.com:19360/8160/8160.m3u8
|
||||
#EXTINF:-1 tvg-id="Ceacom.bo",Ceacom [Not 24/7]
|
||||
#EXTINF:-1 tvg-id="CEACOMTV.bo@SD",CEACOM TV [Not 24/7]
|
||||
https://eu1.servers10.com:8081/ceacom/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CoralTV.bo",Coral TV (480p)
|
||||
https://tv.mediacp.eu:8081/coraltv/index.m3u8
|
||||
|
||||
@@ -137,3 +137,7 @@ https://viamotionhsi.netplus.ch/live/eds/onetv/browser-dash/onetv.mpd
|
||||
https://viamotionhsi.netplus.ch/live/eds/rougetv/browser-dash/rougetv.mpd
|
||||
#EXTINF:-1 tvg-id="Carac5.ch@SD",Carac 5 SD
|
||||
https://viamotionhsi.netplus.ch/live/eds/teleswizz/browser-dash/teleswizz.mpd
|
||||
#EXTINF:-1 tvg-id="NRTV.ch@SD",NRTV
|
||||
https://viamotionhsi.netplus.ch/live/eds/nrtv/browser-HLS8/nrtv.m3u8
|
||||
#EXTINF:-1 tvg-id="StarTV.ch@SD",Star TV
|
||||
https://viamotionhsi.netplus.ch/live/eds/startv/browser-HLS8/startv.m3u8
|
||||
|
||||
@@ -143,6 +143,8 @@ http://49.113.179.174:4022/udp/238.125.7.93:5140
|
||||
http://110.19.156.172:9901/tsfile/live/1003_1.m3u8
|
||||
#EXTINF:-1 tvg-id="NeiMonggolTV.cn",Nei Monggol TV
|
||||
http://play1-qk.nmtv.cn/live/1686560387346365.m3u8
|
||||
#EXTINF:-1 tvg-id="NeiMonggolTV.cn",Nei Monggol TV
|
||||
https://cdn4.skygo.mn/live/disk1/NeigMGL/HLSv3-FTA/NeigMGL.m3u8
|
||||
#EXTINF:-1 tvg-id="NeiMonggolTV2MongolianCultureChannel.cn",Nei Monggol TV 2 Mongolian Culture Channel
|
||||
http://1.24.190.98:10080/hls/40/index.m3u8
|
||||
#EXTINF:-1 tvg-id="NeiMonggolTV2MongolianCultureChannel.cn",Nei Monggol TV 2 Mongolian Culture Channel
|
||||
|
||||
@@ -123,7 +123,7 @@ https://mist01.homestream.fun/hls/tlmas904/0_1/index.m3u8
|
||||
https://k20.usastreams.com:8081/telered/index.m3u8
|
||||
#EXTINF:-1 tvg-id="TeleSURCostaRica.cr",TeleSUR Costa Rica (720p) [Not 24/7]
|
||||
https://s1.tvdatta.com:3582/live/telesurlive.m3u8
|
||||
#EXTINF:-1 tvg-id="Teletica7.cr" http-referrer="https://bradmax.com/client/embed-player/c7c83ebb46fa89529a7383d933e2038729f8e4c9_13428?id=tv7&mediaUrl=https://cdn01.teletica.com/TeleticaLiveStream/Stream/playlist_dvr.m3u8&mediaUrl2=https://6zklxk9bdw9b-hls-live.5centscdn.com/TeleticaLiveStream/d072c3a8dde8622c607ecd258fd628e8.sdp/playlist_dvr.m3u8",Teletica 7 (720p) [Geo-blocked]
|
||||
#EXTINF:-1 tvg-id="Teletica7.cr@SD" http-referrer="https://bradmax.com/client/embed-player/c7c83ebb46fa89529a7383d933e2038729f8e4c9_13428?id=tv7&mediaUrl=https://cdn01.teletica.com/TeleticaLiveStream/Stream/playlist_dvr.m3u8&mediaUrl2=https://6zklxk9bdw9b-hls-live.5centscdn.com/TeleticaLiveStream/d072c3a8dde8622c607ecd258fd628e8.sdp/playlist_dvr.m3u8",Teletica 7 (720p) [Geo-blocked]
|
||||
#EXTVLCOPT:http-referrer=https://bradmax.com/client/embed-player/c7c83ebb46fa89529a7383d933e2038729f8e4c9_13428?id=tv7&mediaUrl=https://cdn01.teletica.com/TeleticaLiveStream/Stream/playlist_dvr.m3u8&mediaUrl2=https://6zklxk9bdw9b-hls-live.5centscdn.com/TeleticaLiveStream/d072c3a8dde8622c607ecd258fd628e8.sdp/playlist_dvr.m3u8
|
||||
https://cdn01.teletica.com/TeleticaLiveStream/Stream/playlist_dvr.m3u8
|
||||
#EXTINF:-1 tvg-id="TicaVision.cr@SD",TicaVision
|
||||
|
||||
@@ -510,3 +510,11 @@ https://viamotionhsi.netplus.ch/live/eds/deluxemusic/browser-HLS8/deluxemusic.m3
|
||||
https://viamotionhsi.netplus.ch/live/eds/swrbw/browser-HLS8/swrbw.m3u8
|
||||
#EXTINF:-1 tvg-id="KiKA.de@HD",KiKA HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/kikahd/browser-HLS8/kikahd.m3u8
|
||||
#EXTINF:-1 tvg-id="RTL.de@SD",RTL
|
||||
https://viamotionhsi.netplus.ch/live/eds/rtl/browser-HLS8/rtl.m3u8
|
||||
#EXTINF:-1 tvg-id="NDRFernsehen.de@Hamburg",NDR Fernsehen
|
||||
https://viamotionhsi.netplus.ch/live/eds/ndr/browser-HLS8/ndr.m3u8
|
||||
#EXTINF:-1 tvg-id="MDRFernsehen.de@Thuringen",MDR Fernsehen Thuringen
|
||||
https://viamotionhsi.netplus.ch/live/eds/mdr/browser-HLS8/mdr.m3u8
|
||||
#EXTINF:-1 tvg-id="ARDalpha.de@HD",ARD-alpha HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/bralpha/browser-HLS8/bralpha.m3u8
|
||||
|
||||
@@ -56,3 +56,5 @@ https://d35j504z0x2vu2.cloudfront.net/v1/master/0bc8e8376bd8417a1b6761138aa41c26
|
||||
https://rotana.hibridcdn.net/rotananet/cinemamasr_net-7Y83PP5adWixDF93/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="WatanTV.eg",Watan TV (1080p)
|
||||
https://rp.tactivemedia.com/watantv_source/live/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AlMasriyah.eg@SD",Al Masriyah
|
||||
https://viamotionhsi.netplus.ch/live/eds/almasriyah/browser-HLS8/almasriyah.m3u8
|
||||
|
||||
@@ -48,7 +48,7 @@ https://d1ujfw1zyymzyd.cloudfront.net/v1/master/3722c60a815c199d9c0ef36c5b73da68
|
||||
https://d82pyvmcw2kdc.cloudfront.net/v1/master/3722c60a815c199d9c0ef36c5b73da68a62b09d1/cc-swfivzrzwamaq/live/fast-channel-animevisionclassics-efc8dc6d/fast-channel-animevisionclassics-efc8dc6d.m3u8
|
||||
#EXTINF:-1 tvg-id="ArabiTV.es",Arabí TV (1080p)
|
||||
https://streamtv2.elitecomunicacion.cloud:3628/live/arabitv2025live.m3u8
|
||||
#EXTINF:-1 tvg-id="AragonTV.es",Aragón TV (720p) [Not 24/7]
|
||||
#EXTINF:-1 tvg-id="AragonTVInternacional.es@SD",Aragon TV Internacional (720p) [Not 24/7]
|
||||
https://cartv.streaming.aranova.es/hls/live/aragontv_canal1.m3u8
|
||||
#EXTINF:-1 tvg-id="BabyTV.uk@Spain",BabyTV (Spain) (1080p)
|
||||
http://185.189.225.150:85/BabyTV/index.m3u8
|
||||
@@ -396,8 +396,8 @@ https://open.http.mp.streamamg.com/p/3001314/sp/300131400/playManifest/entryId/0
|
||||
https://d2glyu450vvghm.cloudfront.net/v1/master/3722c60a815c199d9c0ef36c5b73da68a62b09d1/cc-21u4g5cjglv02/sm.m3u8
|
||||
#EXTINF:-1 tvg-id="SolidariaTV.es",Solidaria TV (720p)
|
||||
https://canadaremar2.todostreaming.es/live/solidariatv-webhd.m3u8
|
||||
#EXTINF:-1 tvg-id="SpektraTV.es",SpektraTV (720p)
|
||||
https://cloudvideo.servers10.com:8081/8136/index.m3u8
|
||||
#EXTINF:-1 tvg-id="SpektraTV.es@SD",SpektraTV (720p)
|
||||
https://cloudvideo.servers10.com:8081/8026/tracks-v1a1/index.m3u8
|
||||
#EXTINF:-1 tvg-id="STZTelebista.es",STZ Telebista (1080p)
|
||||
https://cloudvideo.servers10.com:8081/stztelebista/index.m3u8
|
||||
#EXTINF:-1 tvg-id="SX3.es",SX3 (1080p) [Geo-blocked]
|
||||
@@ -517,12 +517,12 @@ https://janus.xpbroadcasting.com:8443/hls/xptv2.m3u8
|
||||
#EXTINF:-1 tvg-id="XPTVUS.es",XPTV US (720p)
|
||||
https://janus.xpbroadcasting.com:8443/hls/xptvUS.m3u8
|
||||
#EXTINF:-1 tvg-id="AtreseriesInternacional.es@SD",Atreseries Internacional (480p)
|
||||
http://181.78.208.254:8080/play/a0d5/index.m3u8
|
||||
http://38.180.133.31:8000/play/a0ko/index.m3u8
|
||||
#EXTINF:-1 tvg-id="BCNGospelTV.es",BCN Gospel TV (1080p)
|
||||
https://live1.ovalcast.com:3641/live/bcngospeltvlive.m3u8
|
||||
#EXTINF:-1 tvg-id="Antena3Internacional.es@SD",Antena 3 Internacional (480p)
|
||||
http://38.180.133.31:8000/play/a0ki/index.m3u8
|
||||
#EXTINF:-1 tvg-id="AragonTVInternacional.es@SD",Aragon TV Internacional
|
||||
#EXTINF:-1 tvg-id="AragonTV.es@SD",Aragon TV (720p)
|
||||
https://viamotionhsi.netplus.ch/live/eds/aragontv/browser-HLS8/aragontv.m3u8
|
||||
#EXTINF:-1 tvg-id="24HorasInternacional.es@SD",24 Horas Internacional
|
||||
https://viamotionhsi.netplus.ch/live/eds/canal24horas/browser-HLS8/canal24horas.m3u8
|
||||
|
||||
@@ -287,3 +287,7 @@ https://cdn.gunadarma.ac.id/streams/ugtv/ingestugtv.m3u8
|
||||
https://ams.juraganstreaming.com:5443/LiveApp/streams/wesaltv.m3u8
|
||||
#EXTINF:-1 tvg-id="ZeeBioskop.id",Zee Bioskop (360p) [Geo-blocked]
|
||||
http://vod.linknetott.swiftcontent.com/Content/HLS/Live/Channel(ch161)/index.m3u8
|
||||
#EXTINF:-1 tvg-id="SurabayaTV.id@SD",Surabaya TV (1080p)
|
||||
https://e.siar.us/live/surabayatv.m3u8
|
||||
#EXTINF:-1 tvg-id="BanjarTV.id@SD",Banjar TV (720p) [Not 24/7]
|
||||
https://banjartv.siar.us/banjartv/live/playlist.m3u8
|
||||
|
||||
@@ -166,8 +166,8 @@ https://cdn-apse1-prod.tsv2.amagi.tv/linear/amg01448-samsungin-dabanggin-samsung
|
||||
https://live-dangal.akamaized.net/liveabr/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="DarshanaTV.in@SD",Darshana TV (720p)
|
||||
https://cdn-2.pishow.tv/live/1453/master.m3u8
|
||||
#EXTINF:-1 tvg-id="DDArunPrabha.in",DD Arun Prabha
|
||||
https://d2lk5u59tns74c.cloudfront.net/out/v1/308556d9fd1246adb479ef012a39bbfe/index_3.m3u8
|
||||
#EXTINF:-1 tvg-id="DDArunPrabha.in@SD",DD Arun Prabha (360p)
|
||||
https://d2lk5u59tns74c.cloudfront.net/out/v1/308556d9fd1246adb479ef012a39bbfe/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DDAssam.in",DD Assam
|
||||
https://d2lk5u59tns74c.cloudfront.net/out/v1/d380bf5c167b4319a46cdd8204bc26b2/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DDAssam.in",DD Assam
|
||||
@@ -196,14 +196,14 @@ https://cdn-6.pishow.tv/live/9/master.m3u8
|
||||
https://cdn-1.pishow.tv/live/31/master.m3u8
|
||||
#EXTINF:-1 tvg-id="DDMalayalam.in",DD Malayalam
|
||||
https://d3eyhgoylams0m.cloudfront.net/v1/manifest/93ce20f0f52760bf38be911ff4c91ed02aa2fd92/ed7bd2c7-8d10-4051-b397-2f6b90f99acb/562ee8f9-9950-48a0-ba1d-effa00cf0478/2.m3u8
|
||||
#EXTINF:-1 tvg-id="DDManipur.in",DD Manipur
|
||||
https://ddmanipur.org/hls/stream1.m3u8
|
||||
#EXTINF:-1 tvg-id="DDMeghalaya.in",DD Meghalaya
|
||||
https://d3eyhgoylams0m.cloudfront.net/v1/manifest/93ce20f0f52760bf38be911ff4c91ed02aa2fd92/ed7bd2c7-8d10-4051-b397-2f6b90f99acb/dafc23f6-c3d9-44d7-8d31-27aa80efe0b7/2.m3u8
|
||||
#EXTINF:-1 tvg-id="DDManipur.in@SD",DD Manipur (504p)
|
||||
https://d2lk5u59tns74c.cloudfront.net/out/v1/8b75afc6576f450e8f554b6c877681d2/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DDMeghalaya.in@SD",DD Meghalaya (504p)
|
||||
https://d3qs3d2rkhfqrt.cloudfront.net/out/v1/4f81bc8d13dd49b484da35988abb8729/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DDMizoram.in",DD Mizoram
|
||||
https://d3eyhgoylams0m.cloudfront.net/v1/manifest/93ce20f0f52760bf38be911ff4c91ed02aa2fd92/ed7bd2c7-8d10-4051-b397-2f6b90f99acb/5f0e3651-3393-41d2-a137-a4513be8f3d5/2.m3u8
|
||||
#EXTINF:-1 tvg-id="DDNagaland.in",DD Nagaland
|
||||
https://d3eyhgoylams0m.cloudfront.net/v1/manifest/93ce20f0f52760bf38be911ff4c91ed02aa2fd92/ed7bd2c7-8d10-4051-b397-2f6b90f99acb/4437588d-6c41-4a61-91ca-33a6900617a6/2.m3u8
|
||||
#EXTINF:-1 tvg-id="DDNagaland.in@SD",DD Nagaland (504p)
|
||||
https://d2lk5u59tns74c.cloudfront.net/out/v1/29c92e0bef954a6d9b0908d1be29c1f0/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DDNational.in@HD",DD National HD (1080p)
|
||||
https://d3qs3d2rkhfqrt.cloudfront.net/out/v1/40492a64c1db4a1385ba1a397d357d3a/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DDNews.in@SD",DD News (1080p)
|
||||
@@ -308,8 +308,8 @@ http://akalmultimedia.net:1935/gdnslive/gdns-live/chunklist.m3u8
|
||||
https://server.livelegitpro.in/globalpunjab/globalpunjab/index.m3u8
|
||||
#EXTINF:-1 tvg-id="GlobalPunjab.in",Global Punjab (720p) [Not 24/7]
|
||||
https://media.streambrothers.com:1936/8522/8522/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Goa365.in",Goa365 (720p)
|
||||
https://asia.mslivestream.net/mslive/f9fe659e19d111baf97526ad526b55b4.sdp/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Goa365.in@SD",Goa365 (1080p)
|
||||
https://ktismaservers.in:3086/live/goa365live.m3u8
|
||||
#EXTINF:-1 tvg-id="GoodNewsToday.in@SD",Good News Today (720p)
|
||||
https://aajtaklive.vgcdn.net/v1/master/611d79b11b77e2f571934fd80ca1413453772ac7/3196cced-ce29-4219-9809-f07ccdaa02b9/vglive-sk-848805/master.m3u8
|
||||
#EXTINF:-1 tvg-id="GoodShepherdTV.in",Good Shepherd TV (720p)
|
||||
@@ -511,12 +511,12 @@ https://cdn-3.pishow.tv/live/1481/master.m3u8
|
||||
https://5dd3981940faa.streamlock.net/mercytv/mercytv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MetroTV.in",Metro TV (576p)
|
||||
https://2nbyjxw5l53k-hls-live.qezycdn.com/metrotv/live.stream/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Mh1Music.in",MH One Music (1080p)
|
||||
https://mhlive.paramountinfosystem.com/mhonemusictest/d0dbe915091d400bd8ee7f27f0791303.sdp/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Mh1News.in",MH One News (1080p)
|
||||
https://mhlive.paramountinfosystem.com/mhonetest/d0dbe915091d400bd8ee7f27f0791303.sdp/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MHOneShraddha.in",MH One Shraddha (1080p)
|
||||
https://mhlive.paramountinfosystem.com/mhoneshraddhatest/d0dbe915091d400bd8ee7f27f0791303.sdp/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Mh1Music.in@SD",Mh 1 Music (720p)
|
||||
https://mhonemusic.com/hls/1/stream.m3u8
|
||||
#EXTINF:-1 tvg-id="Mh1News.in@SD",Mh 1 News (1080p)
|
||||
https://mhonenews.in/hls/stream.m3u8
|
||||
#EXTINF:-1 tvg-id="MHOneShraddha.in@SD",MH One Shraddha (720p)
|
||||
https://mhoneshaddha.com/hls/1/stream.m3u8
|
||||
#EXTINF:-1 tvg-id="MirrorNow.in",Mirror Now (720p)
|
||||
https://pubads.g.doubleclick.net/ssai/event/DXkHhH2QSnma-HnE3QJqlA/master.m3u8
|
||||
#EXTINF:-1 tvg-id="MKSix.in@SD",MK Six (720p) [Not 24/7]
|
||||
@@ -803,8 +803,8 @@ https://cdn-1.pishow.tv/live/276/master.m3u8
|
||||
https://yuppftalive.akamaized.net/080823/subhartitv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="SubhavaarthaTV.in",Subhavaartha TV (720p)
|
||||
https://2mk9qae4rwyb-hls-live.wmncdn.net/shubhavartha/live.stream/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="SudarshanNews.in",Sudarshan News (720p)
|
||||
https://ott.livelegitpro.in/pusa/sudarshantv/index.m3u8
|
||||
#EXTINF:-1 tvg-id="SudarshanNews.in@SD",Sudarshan News (1080p)
|
||||
https://ott.livelegitpro.in/sudarshannews/sudarshannews/tracks-v1/index.fmp4.m3u8
|
||||
#EXTINF:-1 tvg-id="SVBC2.in@SD",SVBC 2 (576p)
|
||||
https://yuppftalive.akamaized.net/080823/svbc2tamil/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="SVBC3.in",SVBC 3 (720p)
|
||||
@@ -976,8 +976,8 @@ https://vg-zeefta.akamaized.net/ptnr-yupptv/title-zeepunjabharyanahima/v1/master
|
||||
https://vg-zeefta.akamaized.net/ptnr-yupptv/title-zeerajashthannews/v1/master/611d79b11b77e2f571934fd80ca1413453772ac7/8e864b9a-1681-41a0-99a6-387490bc5b24/main.m3u8
|
||||
#EXTINF:-1 tvg-id="ZeeSalaam.in",Zee Salaam (720p)
|
||||
https://d3i8oqsdv88b3m.cloudfront.net/out/v1/08f6360f9104421f90319460c0e03f11/index.m3u8
|
||||
#EXTINF:-1 tvg-id="ZeeUttarPradeshUttarakhand.in",Zee Uttar Pradesh/Uttarakhand (720p)
|
||||
https://livetv-channels.b-cdn.net/8076/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="ZeeUttarPradeshUttarakhand.in@SD",Zee Uttar Pradesh/Uttarakhand (720p)
|
||||
https://duw35ict5q7th.cloudfront.net/index_3.m3u8
|
||||
#EXTINF:-1 tvg-id="ZillarBartaNews.in",ZillarBarta News (720p)
|
||||
https://live-stream.utkalbongo.com/utkalbongo/stream18/hls/zillarbartalive.m3u8
|
||||
#EXTINF:-1 tvg-id="ZillarBartaNews.in",ZillarBarta News
|
||||
@@ -996,3 +996,19 @@ https://d35j504z0x2vu2.cloudfront.net/v1/master/0bc8e8376bd8417a1b6761138aa41c26
|
||||
http://217.20.112.199/asianet/index.m3u8
|
||||
#EXTINF:-1 tvg-id="ChumbakTV.in@SD",Chumbak TV (720p)
|
||||
https://cdn-1.pishow.tv/live/1451/master.m3u8
|
||||
#EXTINF:-1 tvg-id="DDHimachalPradesh.in@SD",DD Himachal Pradesh (504p)
|
||||
https://d3qs3d2rkhfqrt.cloudfront.net/out/v1/afd2e335b0ba40eb9bdf1096118c6ede/index.m3u8
|
||||
#EXTINF:-1 tvg-id="RajPariwar.in@SD",Raj Pariwar (1080p) [Not 24/7]
|
||||
https://livestream.rajtvnet.in/hlslive/Admin/px08241089/live/Raj_Pariwar/master_1.m3u8
|
||||
#EXTINF:-1 tvg-id="RajNewsTelugu.in@SD",Raj News Telugu (1080p) [Not 24/7]
|
||||
https://livestream.rajtvnet.in/hlslive/Admin/px08241089/live/Raj_News_Telugu/master_1.m3u8
|
||||
#EXTINF:-1 tvg-id="DDTamil.in@SD",DD Tamil (1080p)
|
||||
https://d2lk5u59tns74c.cloudfront.net/out/v1/abf46b14847e45499f4a47f3a9afe93d/index.m3u8
|
||||
#EXTINF:-1 tvg-id="KolkataTV.in@SD",Kolkata TV (1080p)
|
||||
https://d35j504z0x2vu2.cloudfront.net/v1/master/0bc8e8376bd8417a1b6761138aa41c26c7309312/kolkata-tv/index.m3u8
|
||||
#EXTINF:-1 tvg-id="HNN24x7.in@SD",HNN 24x7 (576p)
|
||||
https://ott.livelegitpro.in:9899/hnnnews/hnnnews/tracks-v1/index.fmp4.m3u8
|
||||
#EXTINF:-1 tvg-id="BharatExpress.in@SD",Bharat Express (480p)
|
||||
https://stream1.livebox.co.in/VCAREhls/live.m3u8
|
||||
#EXTINF:-1 tvg-id="MunsifTV.in@SD",Munsif TV (720p)
|
||||
https://d35j504z0x2vu2.cloudfront.net/v1/manifest/0bc8e8376bd8417a1b6761138aa41c26c7309312/munsif-tv/e5ae862b-c65c-4b17-b9a8-038853525c64/0.m3u8
|
||||
|
||||
@@ -21,8 +21,6 @@ https://familyhls.avatv.live/hls/stream.m3u8
|
||||
https://live20.bozztv.com/dvrfl05/gin-ayeneh/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CaltexTV.ir",Caltex Music (720p)
|
||||
https://video.caltexmusic.com/hls/caltextv.m3u8
|
||||
#EXTINF:-1 tvg-id="",Digi Movie [Not 24/7]
|
||||
https://fastdehost.com/live/digimovie.m3u8
|
||||
#EXTINF:-1 tvg-id="HispanTV.ir",Hispan TV
|
||||
https://cdnlive.presstv.ir/live/smil:live.smil/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="HodHodFarsiTV.ir@SD",HodHod Farsi TV
|
||||
@@ -59,8 +57,6 @@ https://ca-rt.onetv.app:8443/ITN/index-0.m3u8
|
||||
https://ca1.buximedia.com/itv/life/tracks-v1a1/mono.m3u8
|
||||
#EXTINF:-1 tvg-id="ITVPersianMusic.ir",ITV Persian Music (1080p)
|
||||
https://ca1.buximedia.com/itv/persian/tracks-v1a1/mono.m3u8
|
||||
#EXTINF:-1 tvg-id="",King Movie [Not 24/7]
|
||||
https://fastdehost.com/live/kingmovie.m3u8
|
||||
#EXTINF:-1 tvg-id="MihanTV.ir",Mihan TV (720p)
|
||||
https://iptv.mihantv.com/mihantv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MohabatTV.ir",Mohabat TV (540p)
|
||||
@@ -96,16 +92,6 @@ https://live20.bozztv.com/gin-36bay3/gin-saharafgh/tracks-v1a1/mono.m3u8
|
||||
https://live20.bozztv.com/dvrfl05/gin-saharurdu/index.m3u8
|
||||
#EXTINF:-1 tvg-id="SalamatTV.ir@SD",Salamat TV
|
||||
https://live20.bozztv.com/dvrfl05/gin-iribsalamat/index.m3u8
|
||||
#EXTINF:-1 tvg-id="",Serial Baran1 [Not 24/7]
|
||||
https://fastdehost.com/live/serialbaran1.m3u8
|
||||
#EXTINF:-1 tvg-id="",Serial Baran2 [Not 24/7]
|
||||
https://server3.fastdehost.com/live/serialbaran2.m3u8
|
||||
#EXTINF:-1 tvg-id="",Serial Baran3 [Not 24/7]
|
||||
https://server3.fastdehost.com/live/serialbaran3.m3u8
|
||||
#EXTINF:-1 tvg-id="",Serial Baran4 [Not 24/7]
|
||||
https://server3.fastdehost.com/live/serialbaran4.m3u8
|
||||
#EXTINF:-1 tvg-id="",Serial Baran5 [Not 24/7]
|
||||
https://server4.fastdehost.com/live/serialbaran5.m3u8
|
||||
#EXTINF:-1 tvg-id="SNNTV.ir",SNN TV (720p) [Not 24/7]
|
||||
https://live2.snn.ir/hls/snn2_hd720/index.m3u8
|
||||
#EXTINF:-1 tvg-id="TBNNejatTV.ir",TBN Nejat TV (720p)
|
||||
|
||||
@@ -751,3 +751,7 @@ https://5db313b643fd8.streamlock.net/ZerounoTVEventi/ZerounoTVEventi/playlist.m3
|
||||
https://5f22d76e220e1.streamlock.net/iuniortv/iuniortv/chunklist_w774879328.m3u8
|
||||
#EXTINF:-1 tvg-id="BergamoTV.it@SD",Bergamo TV (1080p)
|
||||
https://db142859fd5541b09de25d6507f1f2d3.msvdn.net/live/S17501676/oIxAsgEEA46M/playlist_dvr.m3u8
|
||||
#EXTINF:-1 tvg-id="AntennaSudExtra.it@SD",Antenna Sud Extra (720p)
|
||||
https://live.antennasudwebtv.it:9443/hls/vod92.m3u8
|
||||
#EXTINF:-1 tvg-id="AntennaSud.it@SD",Antenna Sud (720p)
|
||||
https://live.antennasudwebtv.it:9443/hls/vod.m3u8
|
||||
|
||||
@@ -54,3 +54,7 @@ http://171.244.62.178/jptv2/get.php?id=4SlJSS46Vw5igmOdvfKMww==
|
||||
http://171.244.62.178/jptv2/get.php?id=hnsnBqHDt2EXQupW2soBjw==
|
||||
#EXTINF:-1 tvg-id="JOAKDTV.jp",JOAK-DTV
|
||||
http://171.244.62.178/jptv2/get.php?id=mCOs5Hrdk31FTwR6IJj_hA==
|
||||
#EXTINF:-1 tvg-id="JOIXDTV.jp@HD",JOIX-DTV (720p)
|
||||
https://mt01.utako.moe/ytv/index.m3u8
|
||||
#EXTINF:-1 tvg-id="NHKWorldJapan.jp@HD",NHK World-Japan HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/nhk/browser-HLS8/nhk.m3u8
|
||||
|
||||
@@ -111,3 +111,9 @@ https://cdn4.skygo.mn/live/disk1/UlziiTV/HLSv3-FTA/UlziiTV.m3u8
|
||||
https://cdn4.skygo.mn/live/disk1/SoyonGegeeruulegch/HLSv3-FTA/SoyonGegeeruulegch.m3u8
|
||||
#EXTINF:-1 tvg-id="",Хөгжим (720p)
|
||||
https://cdn4.skygo.mn/live/disk1/Khugjim/HLSv3-FTA/Khugjim.m3u8
|
||||
#EXTINF:-1 tvg-id="SevenChannel.mn@SD",Seven Channel (480p)
|
||||
https://cdn4.skygo.mn/live/disk1/TV7/HLS-FTA/TV7.m3u8
|
||||
#EXTINF:-1 tvg-id="Cinema.mn@SD",Cinema
|
||||
https://cdn4.skygo.mn/live/disk1/CinemaTV/HLSv3-FTA/CinemaTV.m3u8
|
||||
#EXTINF:-1 tvg-id="GlobalTV.mn@SD",Global TV
|
||||
https://cdn4.skygo.mn/live/disk1/GlobalTV/HLSv3-FTA/GlobalTV.m3u8
|
||||
|
||||
@@ -402,3 +402,7 @@ https://stream.oursnetworktv.com/latin/encoder73/playlist.m3u8
|
||||
https://stream8.mexiserver.com:1936/xtinetwork/xtinetwork/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="ZAZ.mx",ZAZ
|
||||
https://cloud.fastchannel.es/mic/manifiest/hls/zaztv/zaztv.m3u8
|
||||
#EXTINF:-1 tvg-id="FoxSportsPremium.mx",Fox Sports Premium (1080p)
|
||||
https://live20.bozztv.com/akamaissh101/ssh101/foxsports/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Canal5.mx",Canal 5 (720p)
|
||||
http://104.238.205.28:8989/278329_.m3u8
|
||||
|
||||
@@ -3,16 +3,6 @@
|
||||
https://cdn6.163189.xyz/live/8tv/stream.m3u8
|
||||
#EXTINF:-1 tvg-id="8TV.my",8TV
|
||||
https://tonton-live-switch-ssar.akamaized.net/stream-8tv/master.m3u8?bpkio_serviceid=6c0958d82a830a02ca0936d9cfab8311
|
||||
#EXTINF:-1 tvg-id="AstroAwani.my",Astro Awani (720p)
|
||||
https://d2idp3hzkhjpih.cloudfront.net/out/v1/4b85d9c2bf97413eb0c9fd875599b837/index.m3u8
|
||||
#EXTINF:-1 tvg-id="AstroBoxOfficeThangathirai.my",Astro Box Office Thangathirai (720p)
|
||||
https://live20.bozztv.com/akamaissh101/ssh101/sungo546/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AstroVaanavil.my@SD",Astro Vaanavil
|
||||
https://live20.bozztv.com/akamaissh101/ssh101/sungo543/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AstroVaanavil.my@SD",Astro Vaanavil
|
||||
https://live20.bozztv.com/akamaissh101/ssh101/sungo545/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AstroVinmeen.my@SD",Astro Vinmeen
|
||||
https://live20.bozztv.com/akamaissh101/ssh101/sungo544/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AwesomeTV.my",Awesome TV [Geo-blocked]
|
||||
https://488b9e074624.ap-south-1.playback.live-video.net/api/video/v1/ap-south-1.533267421985.channel.B7bB1wHJRCnw.m3u8
|
||||
#EXTINF:-1 tvg-id="BeritaRTM.my" http-referrer="https://rtm-player.glueapi.io/",Berita RTM [Geo-blocked]
|
||||
|
||||
@@ -19,20 +19,6 @@ https://primetv-prod.akamaized.net/v1/prime-freeview-aes128.m3u8
|
||||
https://tv.wyatts-server.com/stream/channelid/1977627680?auth=Lo47lPuhjUwYZIPv+NymH3qAyhMe1svINVM4Kac2fvA=&profile=pass
|
||||
#EXTINF:-1 tvg-id="SkyOpen.nz@Plus1",Sky open +1 (576p) [Geo-blocked]
|
||||
https://linear-p.media.skyone.co.nz/primeplus1.clear.m3u8
|
||||
#EXTINF:-1 tvg-id="SkySport1.nz",Sky Sport 1 (1080p)
|
||||
http://primestreams.tv:826/live/SF11/vulwBvtfo9/118585.ts
|
||||
#EXTINF:-1 tvg-id="SkySport2.nz",Sky Sport 2 (1080p)
|
||||
http://primestreams.tv:826/live/SF11/vulwBvtfo9/118586.ts
|
||||
#EXTINF:-1 tvg-id="SkySport3.nz",Sky Sport 3 (1080p)
|
||||
https://hls.sheepland.xyz/play/0/15?proxy=0
|
||||
#EXTINF:-1 tvg-id="SkySport4.nz",Sky Sport 4 (1080p)
|
||||
https://hls.sheepland.xyz/play/0/36?proxy=0
|
||||
#EXTINF:-1 tvg-id="SkySport5.nz",Sky Sport 5 (1080p)
|
||||
http://primestreams.tv:826/live/SF11/vulwBvtfo9/118589.ts
|
||||
#EXTINF:-1 tvg-id="SkySport6.nz",Sky Sport 6 (1080p)
|
||||
https://hls.sheepland.xyz/play/0/70?proxy=0
|
||||
#EXTINF:-1 tvg-id="SkySport7.nz",Sky Sport 7 (1080p)
|
||||
https://hls.sheepland.xyz/play/0/66?proxy=0
|
||||
#EXTINF:-1 tvg-id="TeReo.nz",Te Reo
|
||||
https://i.mjh.nz/.r/te-reo.m3u8
|
||||
#EXTINF:-1 tvg-id="TVNZ1.nz@SD",TVNZ 1
|
||||
|
||||
@@ -37,3 +37,5 @@ https://rds3gen.desdeparaguay.net/trecetv/trecetv_alta/playlist.m3u8
|
||||
https://tigocloud.desdeparaguay.net/800tv/800tv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="VenusMedia.py",Venus Media (720p)
|
||||
https://rds3gen.desdeparaguay.net/venusmedia/venusmedia/.m3u8
|
||||
#EXTINF:-1 tvg-id="SucesoTV.py",Suceso TV [Not 24/7]
|
||||
https://live.enhdtv.com:8081/8060/index.m3u8
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="AlArabyTV.qa",Al Araby TV (1080p)
|
||||
https://alarabyta.cdn.octivid.com/alaraby/smil:alaraby.stream.smil/chunklist.m3u8
|
||||
#EXTINF:-1 tvg-id="AlArabyTV.qa@SD",Al Araby TV (1080p)
|
||||
https://live.kwikmotion.com/alaraby1live/alaraby_abr/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AlArabyTV.qa",Al Araby TV (1080p)
|
||||
https://stream.ads.ottera.tv/playlist.m3u8?network_id=5616
|
||||
#EXTINF:-1 tvg-id="AlArabyTV2.qa",Al Araby TV 2 (1080p)
|
||||
https://alarabyta.cdn.octivid.com/alaraby2n/smil:alaraby2n.stream.smil/chunklist.m3u8
|
||||
#EXTINF:-1 tvg-id="AlArabyTV2.qa@SD",Al Araby TV 2 (1080p)
|
||||
https://live.kwikmotion.com/alaraby2live/alaraby2.smil/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AlArabyTV2.qa",Al Araby TV 2 (1080p)
|
||||
https://stream.ads.ottera.tv/playlist.m3u8?network_id=5617
|
||||
#EXTINF:-1 tvg-id="AlJazeera.qa",Al Jazeera (1080p)
|
||||
@@ -111,3 +111,5 @@ https://qatartv.akamaized.net/hls/live/2026574/qtv2/master.m3u8
|
||||
https://streamer1.qna.org.qa/148133344_live/148133344_63.sdp/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AlJazeera.qa@English",Al Jazeera English
|
||||
https://viamotionhsi.netplus.ch/live/eds/aljazeera/browser-HLS8/aljazeera.m3u8
|
||||
#EXTINF:-1 tvg-id="AlJazeeraDocumentary.qa@HD",Al Jazeera Documentary (1080p)
|
||||
http://213.57.91.138:8000/play/a06h
|
||||
|
||||
@@ -199,3 +199,5 @@ http://89.38.8.130:39443
|
||||
https://viamotionhsi.netplus.ch/live/eds/tvrinternational/browser-HLS8/tvrinternational.m3u8
|
||||
#EXTINF:-1 tvg-id="TVRInternational.ro@SD",TVR International
|
||||
https://viamotionhsi.netplus.ch/live/eds/tvrinternational/browser-dash/tvrinternational.mpd
|
||||
#EXTINF:-1 tvg-id="JimJam.ro" http-user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0",JimJam
|
||||
https://saruman1.tharen.cfd/jimy/usergenq3n0lz7kr.m3u8
|
||||
|
||||
@@ -307,3 +307,5 @@ http://hls.shansontv.cdnvideo.ru/shansontv/shansontv.sdp/playlist.m3u8
|
||||
http://stream0.tv41.ru/live.m3u8
|
||||
#EXTINF:-1 tvg-id="Yuvelirochka.ru",Ювелирочка ТВ (576p)
|
||||
https://live-uvelirochka.cdnvideo.ru/uvelirochka/uvelirochka_720p3/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Home4K.ru",Home 4K (2160p)
|
||||
http://178.217.72.66:8080/HOME_4K/index.m3u8
|
||||
|
||||
@@ -32,12 +32,46 @@ https://kino-1.catcast.tv/content/37742/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MuzykaKino.ru@International",Музыка Кино International [Not 24/7]
|
||||
https://kino-1.catcast.tv/content/37739/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoKlassika.ru",Сити Эдем КиноКлассика [Not 24/7]
|
||||
https://v2.catcast.tv/content/34185/index.m3u8
|
||||
https://cityeden.catcast.tv/content/34185/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoMistika.ru",Сити Эдем КиноМистика [Not 24/7]
|
||||
https://v2.catcast.tv/content/40783/index.m3u8
|
||||
https://cityeden.catcast.tv/content/40783/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoAction.ru",Сити Эдем КиноЭкшен [Not 24/7]
|
||||
https://v2.catcast.tv/content/41333/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenTV.ru",Сити Эдем ТВ [Not 24/7]
|
||||
https://v2.catcast.tv/content/34246/index.m3u8
|
||||
https://cityeden.catcast.tv/content/41333/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenTV.ru",Сити Эдем ТВ Христианский [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/34246/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenTeleNovella.ru",Сити Эдем ТелеНовелла [Not 24/7]
|
||||
https://v2.catcast.tv/content/46209/index.m3u8
|
||||
https://cityeden.catcast.tv/content/46209/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenMedZdrav.ru",Сити Эдем МедЗдрав [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/47519/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenReceptyGurmana.ru",Сити Эдем Рецепты Гурмана [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/47516/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenAutoGid.ru",Сити Эдем АвтоГид [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/47515/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenMeditationMusic.ru",Сити Эдем Meditation Music [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/47410/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenClassicMusic.ru",Сити Эдем Классическая Музыка [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/47400/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenSirtakiTV.ru",Сити Эдем Сиртаки ТВ [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/46421/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoDrama.ru",Сити Эдем КиноДрама [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/45269/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoFantastika.ru",Сити Эдем КиноФантастика [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/45268/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoKomediya.ru",Сити Эдем КиноКомедия [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/41331/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoDetektiv.ru",Сити Эдем КиноДетектив [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/41327/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoArt.ru",Сити Эдем КиноАрт [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/38398/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoDok.ru",Сити Эдем КиноДок [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/38354/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoSemya.ru",Сити Эдем КиноСемья [Not 24/7]
|
||||
https://v2.catcast.tv/content/38128/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenKinoAsia.ru",Сити Эдем КиноАзия [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/34393/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenBirmaPlay.ru",Сити Эдем Бирма Play [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/34364/index.m3u8
|
||||
#EXTINF:-1 tvg-id="CityEdenPlay.ru",Сити Эдем Play Христианский Музыкальный [Not 24/7]
|
||||
https://cityeden.catcast.tv/content/34100/index.m3u8
|
||||
#EXTINF:-1 tvg-id="VHSTV.ru",VHS TV [Not 24/7]
|
||||
https://v2.catcast.tv/content/47609/index.m3u8
|
||||
|
||||
@@ -5,13 +5,5 @@ https://livetv.mylifeisgood.net.ru/channels/strwc.m3u8
|
||||
https://livetv.mylifeisgood.net.ru/channels/strvf.m3u8
|
||||
#EXTINF:-1 tvg-id="TERRA.ru",TERRA
|
||||
https://livetv.mylifeisgood.net.ru/channels/terra.m3u8
|
||||
#EXTINF:-1 tvg-id="MuzTV.ru",Муз-ТВ
|
||||
https://livetv.mylifeisgood.net.ru/channels/muztvhd.m3u8
|
||||
#EXTINF:-1 tvg-id="Friday.ru",Пятница!
|
||||
https://livetv.mylifeisgood.net.ru/channels/fridayhd.m3u8
|
||||
#EXTINF:-1 tvg-id="TV3.ru",ТВ-3
|
||||
https://livetv.mylifeisgood.net.ru/channels/tv3hd.m3u8
|
||||
#EXTINF:-1 tvg-id="TNT.ru",ТНТ
|
||||
https://livetv.mylifeisgood.net.ru/channels/tnthd.m3u8
|
||||
#EXTINF:-1 tvg-id="U.ru",Ю
|
||||
https://livetv.mylifeisgood.net.ru/channels/u_ott_tv_hq.m3u8
|
||||
|
||||
@@ -134,8 +134,6 @@ https://thaqafeyyah-ak.akamaized.net/out/v1/f6851f68ada94f82ae6b64a441eb5ab1/ind
|
||||
https://live.kwikmotion.com/sbrksasaudiaradiolive/srpksasaudiaradio/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="SBC.sa",SBC (1080p)
|
||||
https://shd-gcp-live.edgenextcdn.net/live/bitmovin-sbc/90e09c0c28db26435799b4a14892a167/index.m3u8
|
||||
#EXTINF:-1 tvg-id="SSCActionWaleed.sa",SSC Action Waleed (1080p) [Not 24/7]
|
||||
https://shls-live-event2-prod-dub.shahid.net/out/v1/0456ede1a39145d98b3d8c8062ddc998/index.m3u8
|
||||
#EXTINF:-1 tvg-id="Tarab.sa",Tarab (1080p)
|
||||
https://shls-live-enc.edgenextcdn.net/out/v1/90143f040feb40589d18c57863d9e829/index.m3u8
|
||||
#EXTINF:-1 tvg-id="Tarab.sa",Tarab (1080p)
|
||||
|
||||
@@ -1,27 +1,19 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="GMM25.th",GMM 25 (720p)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffbf/gmm25/gmm25.m3u8
|
||||
#EXTINF:-1 tvg-id="HappyTV65.th",Happy TV 65 (576p)
|
||||
https://n-edge-1-th.v2h-cdn.com/happy/happy/playlist.m3u8
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffbf/ugvhgvh/ugvhgvh.m3u8
|
||||
#EXTINF:-1 tvg-id="JKN18.th",JKN 18 (1080p)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffda/jkn18/jkn18.m3u8
|
||||
#EXTINF:-1 tvg-id="LidoChannel.th",Lido Channel (720p)
|
||||
https://n-edge-1-th.v2h-cdn.com/lido/lido/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="DramaChannel.th",MV Mall ดี๊ดี (1080p)
|
||||
https://n-edge-1-th.v2h-cdn.com/rama_m/rama/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="DramaChannel.th",MV Mall DD (1080p)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/fdee/mvmalldd/mvmalldd.m3u8
|
||||
#EXTINF:-1 tvg-id="One31.th",ONE HD 31 (720p)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffba/one/one.m3u8
|
||||
#EXTINF:-1 tvg-id="SakalaChannel.th",Sakala Channel (1080p)
|
||||
https://n-edge-1-th.v2h-cdn.com/scala/scala/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="SiamChannel.th",Siam Channel (1080p)
|
||||
https://n-edge-1-th.v2h-cdn.com/siam/siam/playlist.m3u8
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffba/yogvfi/yogvfi.m3u8
|
||||
#EXTINF:-1 tvg-id="TSports7.th",T Sports 7 (720p)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffef/tsport/tsport.m3u8
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffef/mulxvnghf/mulxvnghf.m3u8
|
||||
#EXTINF:-1 tvg-id="Thaiban83.th",Thaiban 83 (576p)
|
||||
https://n-edge-1-th.v2h-cdn.com/thaiban/thaiban/playlist.m3u8
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffcd/thaibaan/thaibaan.m3u8
|
||||
#EXTINF:-1 tvg-id="TNN16.th",TNN 16 (720p)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffdc/tnn/tnn.m3u8
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffdc/mugvhogvho/mugvhogvho.m3u8
|
||||
#EXTINF:-1 tvg-id="True4U.th",True 4U (720)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffca/true24/true24.m3u8
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/ffca/mifainp/mifainp.m3u8
|
||||
#EXTINF:-1 tvg-id="Channel5.th",TV5 HD (720p)
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/fffb/5hd/5hd.m3u8
|
||||
https://lb1-live-mv.v2h-cdn.com/hls/fffb/muushk/muushk.m3u8
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="FIFAPlus.uk@English",FIFA+ (720p)
|
||||
https://a62dad94.wurl.com/master/f36d25e7e52f1ba8d7e56eb859c636563214f541/UmFrdXRlblRWLWV1X0ZJRkFQbHVzRW5nbGlzaF9ITFM/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="AfghanistanInternational.uk",Afghanistan International (720p)
|
||||
https://hls.afintl.com/hls/stream.m3u8
|
||||
#EXTINF:-1 tvg-id="AfrobeatTVEntertainment.uk",Afrobeats (1080p)
|
||||
@@ -310,3 +312,27 @@ https://viamotionhsi.netplus.ch/live/eds/cnbc/browser-HLS8/cnbc.m3u8
|
||||
https://tv.ddns.vn/tv/bbcearth/index.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCLifestyle.uk@Asia",BBC Lifestyle Asia (1080p)
|
||||
https://tv.ddns.vn/tv/bbclifestyle/index.m3u8
|
||||
#EXTINF:-1 tvg-id="Manoto.uk",Manoto TV
|
||||
https://m3u.iranvids.com/manoto/output.m3u8
|
||||
#EXTINF:-1 tvg-id="More4.uk@HD",More4 HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/more4/browser-dash/more4.mpd
|
||||
#EXTINF:-1 tvg-id="Film4.uk@HD",Film4 HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/film4/browser-dash/film4.mpd
|
||||
#EXTINF:-1 tvg-id="BBCFourCBeebies.uk@HD",BBC Four/CBeebies
|
||||
https://viamotionhsi.netplus.ch/live/eds/bbc4cbeebies/browser-dash/bbc4cbeebies.mpd
|
||||
#EXTINF:-1 tvg-id="BBCThreeCBBC.uk@HD",BBC Three/CBBC
|
||||
https://viamotionhsi.netplus.ch/live/eds/bbc3cbbc/browser-dash/bbc3cbbc.mpd
|
||||
#EXTINF:-1 tvg-id="BBCTwo.uk@HD",BBC Two HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/bbc2/browser-dash/bbc2.mpd
|
||||
#EXTINF:-1 tvg-id="ITV4.uk@SD",ITV4
|
||||
https://viamotionhsi.netplus.ch/live/eds/itv4/browser-dash/itv4.mpd
|
||||
#EXTINF:-1 tvg-id="ITV3.uk@SD",ITV3
|
||||
https://viamotionhsi.netplus.ch/live/eds/itv3/browser-dash/itv3.mpd
|
||||
#EXTINF:-1 tvg-id="ITV2.uk@SD",ITV2
|
||||
https://viamotionhsi.netplus.ch/live/eds/itv2/browser-dash/itv2.mpd
|
||||
#EXTINF:-1 tvg-id="Channel4.uk@UKHD",Channel 4 UK HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/channel4/browser-dash/channel4.mpd
|
||||
#EXTINF:-1 tvg-id="Channel5.uk@HD",Channel 5 HD
|
||||
https://viamotionhsi.netplus.ch/live/eds/channel5/browser-dash/channel5.mpd
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk@Europe",BBC News Europe
|
||||
https://viamotionhsi.netplus.ch/live/eds/bbcworld/browser-HLS8/bbcworld.m3u8
|
||||
|
||||
@@ -11,5 +11,3 @@ https://pac12-sportstribal.amagi.tv/playlist.m3u8
|
||||
https://d2xeo83q8fcni6.cloudfront.net/v1/master/9d062541f2ff39b5c0f48b743c6411d25f62fc25/SkiTV-SportsTribal/193.m3u8
|
||||
#EXTINF:-1 tvg-id="SportsGrid.us",SportsGrid (1080p)
|
||||
https://sportsgrid-tribal.amagi.tv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="WorldPokerTour.us",World Poker Tour (1080p) [Not 24/7]
|
||||
https://d3w4n3hhseniak.cloudfront.net/v1/master/9d062541f2ff39b5c0f48b743c6411d25f62fc25/WPT-SportsTribal/120.m3u8
|
||||
|
||||
@@ -125,8 +125,8 @@ https://2nbyjjx7y53k-hls-live.5centscdn.com/cls040318/b0d2763968fd0bdd2dc0d44ba2
|
||||
https://streams2.sofast.tv/v1/master/611d79b11b77e2f571934fd80ca1413453772ac7/be6f9eac-280e-4748-b866-2eb2463c1844/manifest.m3u8
|
||||
#EXTINF:-1 tvg-id="BanningCityTV.us",Banning CityTV (Banning CA) (1080p)
|
||||
https://vbfast-c.viebit.com/072e341f-100d-4da1-9c18-65370ebf35c6/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCAmerica.us",BBC America
|
||||
https://dvrfl04.tulix.tv/teleup-bbca/index.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCAmerica.us@East",BBC America
|
||||
https://bcovlive-a.akamaihd.net/7f5ec16d102f4b5d92e8e27bc95ff424/us-east-1/6240731308001/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BeachTVCSULB.us",Beach TV CSULB (160p) [Not 24/7]
|
||||
http://stream04.amp.csulb.edu:1935/Beach_TV/smil:BeachTV.smil/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BeachTVFloridaAlabama.us",Beach TV Florida & Alabama (720p)
|
||||
@@ -1042,3 +1042,7 @@ https://livechannel.mdc.akamaized.net/stitch/livechannel/1341/master1400000.m3u8
|
||||
https://cineverse.g-mana.live/media/ac7cff3c-5bc3-4745-ac4d-56aadb586d00/profile/1/profileManifest.m3u8
|
||||
#EXTINF:-1 tvg-id="BloombergTV.us@Europe",Bloomberg TV Europe
|
||||
https://viamotionhsi.netplus.ch/live/eds/bloomberg/browser-HLS8/bloomberg.m3u8
|
||||
#EXTINF:-1 tvg-id="P3TV.us",P3TV [Not 24/7]
|
||||
https://5790d294af2dc.streamlock.net/8042/8042/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="FilmRiseClassicTV.us@SD",FilmRise Classic TV (720p)
|
||||
https://d2tv4k5moji5m7.cloudfront.net/v1/master/3722c60a815c199d9c0ef36c5b73da68a62b09d1/cc-lu4pzh9l4b57p/master.m3u8
|
||||
|
||||
@@ -79,8 +79,6 @@ https://tvpass.org/live/HallmarkMoviesMysteriesEast/sd
|
||||
https://tvpass.org/live/IFCEast/hd
|
||||
#EXTINF:-1 tvg-id="IFC.us@East",IFC East (360p)
|
||||
https://tvpass.org/live/IFCEast/sd
|
||||
#EXTINF:-1 tvg-id="KABCDT1.us",KABC-DT1 (720p)
|
||||
https://tvpass.org/live/abc-kabc-los-angeles-ca/hd
|
||||
#EXTINF:-1 tvg-id="KABCDT1.us",KABC-DT1 (360p)
|
||||
https://tvpass.org/live/abc-kabc-los-angeles-ca/sd
|
||||
#EXTINF:-1 tvg-id="KCBSDT1.us",KCBS-DT1 (1080p)
|
||||
|
||||
@@ -137,3 +137,9 @@ https://vod2live.univtec.com/manifest/4c41c0d8-e2e4-43cc-bd43-79afe715e1b3.m3u8
|
||||
https://cloud.fastchannel.es/manifiest/hls/prog9/vepacotv.m3u8
|
||||
#EXTINF:-1 tvg-id="VPItv.ve",VPItv (1080p)
|
||||
https://ott3.streann.com/loadbalancer/services/public/channels/5d23d5882cdce61dae029fd8/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="FortunaTV.ve",Fortuna TV (1080p)
|
||||
https://streamtv.intervenhosting.net:3355/live/fortunatvlive.m3u8
|
||||
#EXTINF:-1 tvg-id="LaraenRedes.ve",Lara en Redes TV (1080p)
|
||||
https://streamtv.intervenhosting.net:3763/hybrid/play.m3u8
|
||||
#EXTINF:-1 tvg-id="LGDTelevision.ve@SD",LGD Television (720p)
|
||||
https://streamtv.intervenhosting.net:3403/hybrid/play.m3u8
|
||||
|
||||
@@ -43,8 +43,6 @@ https://sabctretalh.cdn.mangomolo.com/lehae/smil:lehae.stream.smil/master.m3u8
|
||||
https://sabconetanw.cdn.mangomolo.com/news/smil:news.stream.smil/master.m3u8
|
||||
#EXTINF:-1 tvg-id="SeraphimTV.za",Seraphim TV [Not 24/7]
|
||||
https://restream.churchtv247.co.za/Apostle/Hggc@24/1.m3u8
|
||||
#EXTINF:-1 tvg-id="SuperSportRugby.za@SD",SuperSport Rugby
|
||||
https://live20.bozztv.com/trn03/gin-ssrugby/index.m3u8
|
||||
#EXTINF:-1 tvg-id="TBNAfrica.za",TBN Africa (1080p)
|
||||
https://tbn-jw.cdn.vustreams.com/live/tbn-africa/live.isml/master.m3u8
|
||||
#EXTINF:-1 tvg-id="ZeeBollymovies.za@SD",Zee Bollymovies (1080p)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
@@ -1,26 +1,16 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Andorra",ATV
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Canada",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Canada",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Kazakhstan",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Kyrgyzstan",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Russia",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Tajikistan",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Turkmenistan",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Uzbekistan",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="International",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="International",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="International",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="International",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined" http-referrer="http://imn.iq" http-user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",Andorra TV (720p) [Not 24/7]
|
||||
#EXTVLCOPT:http-referrer=http://imn.iq
|
||||
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Americas",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Americas",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Asia",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Asia",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Central Asia",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Commonwealth of Independent States",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Commonwealth of Independent States",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Europe",ATV
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Europe",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Europe",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Europe, the Middle East and Africa",ATV
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="Europe, the Middle East and Africa",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="Europe, the Middle East and Africa",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="North America",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="North America",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Northern America",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Northern America",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="International",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="International",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined" http-referrer="http://imn.iq" http-user-agent="Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",Andorra TV (720p) [Not 24/7]
|
||||
#EXTVLCOPT:http-referrer=http://imn.iq
|
||||
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148
|
||||
#KODIPROP:inputstream=inputstream.adaptive
|
||||
#KODIPROP:inputstream.adaptive.manifest_type=mpd
|
||||
#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha
|
||||
#KODIPROP:inputstream.adaptive.license_key=https://drm.ors.at/acquire-license/widevine?BrandGuid=13f2e056-53fe-4469-ba6d-999970dbe549&userToken=v9ZVSksv4S7rT55o10dmYNRa4asye3z05eWCFxD%2FFYIlTJEpuf6tF8asPcyQOFq0h5opS%2B6WoMxnshWkihpHq5qrdrBEZ69piE94J9Feh385snGOqK3PYO7tLLjxmsCAe%2B9%2BNnurSSO5RCAIRsL125nSj1eOR%2F1GSKOgGH80HK2FDLiePxPkeaAxuWzacNBB%2FqnIGGxfe3GlmN65cU9F8WEpKFDlaxW%2Fv3ZSLAp3%2BZEq1aZXJ6Oz%2Fi0diD0EybH7|Content-Type=application/octet-stream|R{SSM}|
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index2.m3u8|Referer="https://referer.xyz/"|User-Agent="Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1"|Origin="https://origin.xyz"
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad@HD" tvg-logo="https://i.imgur.com/CnhTn8i.png" group-title="Undefined",ATV HD
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv_hd
|
||||
#EXTINF:-1 tvg-id="" tvg-logo="" group-title="Undefined",Daawah TV
|
||||
http://51.15.246.58:8081/daawahtv/daawahtv2/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="Zoo.ad@HD" tvg-logo="https://i.imgur.com/ciTJrnl.png" group-title="Undefined",Zoo (720p)
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/zoo
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",ЭлТР (480p) [Not 24/7]
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",ЭлТР (480p) [Not 24/7]
|
||||
http://gohoski.fvds.ru:3000/mediabay/162/index.m3u8
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
@@ -1,4 +1,8 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",ЭлТР (480p) [Not 24/7]
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Undefined",ATV
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",ЭлТР (480p) [Not 24/7]
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="AndorraTV.ad@SD" tvg-logo="https://i.imgur.com/BnhTn8i.png" group-title="Undefined",ATV
|
||||
https://iptv-all.lanesh4d0w.repl.co/andorra/atv
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
#EXTINF:-1 tvg-id="ElTR.kg" tvg-logo="https://i.ibb.co/r6czQwQ/365049798-774721644658455-5702658175909463406-n-2.png" group-title="General",ЭлТР (480p) [Not 24/7]
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="5AABTV.ca" tvg-logo="" group-title="Undefined",5AAB TV
|
||||
http://158.69.124.9:1935/5aabtv/5aabtv/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
#EXTINF:-1 tvg-id="MeteoMedia.ca" tvg-logo="https://s1.twnmm.com/images/en_ca/mobile/logos/twn-mobile-logo.png" group-title="Weather",Meteomedia
|
||||
http://encodercdn1.frontline.ca/encoder181/output/Meteo_Media_720p/playlist.m3u8
|
||||
#EXTINF:-1 tvg-id="LDPRTV.ru" tvg-logo="https://iptvx.one/icn/ldpr-tv.png" group-title="General",ЛДПР ТВ (1080p)
|
||||
http://46.46.143.222:1935/live/mp4:ldpr.stream/blocked.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
#EXTM3U
|
||||
#EXTINF:-1 tvg-id="BBCNews.uk" tvg-logo="https://raw.githubusercontent.com/Tapiosinn/tv-logos/master/countries/united-kingdom/bbc-news-uk.png" group-title="General;News",BBC News HD
|
||||
http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8
|
||||
#EXTINF:-1 tvg-id="DunaWorld.hu" tvg-logo="https://i.imgur.com/uOBQJZS.png" group-title="Undefined",Duna World (576i)
|
||||
http://146.59.85.40:89/dunaworld/index.m3u8
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user