Merge branch 'master' into Carlinhos027-patch-2

This commit is contained in:
Aleksandr Statciuk 2025-04-16 03:16:44 +03:00 committed by GitHub
commit c99694aa7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
225 changed files with 4063 additions and 3092 deletions

View file

@ -6,9 +6,9 @@ labels: ['streams:add']
body:
- type: input
attributes:
label: Channel ID (required)
description: Unique channel ID from [iptv-org.github.io](https://iptv-org.github.io/). If you can't find the channel you want in the list, please let us know through this [form](https://github.com/iptv-org/database/issues/new?assignees=&labels=channels%3Aadd&projects=&template=channels_add.yml&title=Add%3A+) before posting your request.
placeholder: 'BBCAmericaEast.us'
label: Stream ID (required)
description: "ID of the stream consisting of `<channel_id>` or `<channel_id>@<feed_id>`. Full list of supported channels with corresponding ID could be found on [iptv-org.github.io](https://iptv-org.github.io/). If you can't find the channel you want in the list, please let us know through this [form](https://github.com/iptv-org/database/issues/new?assignees=&labels=channels%3Aadd&projects=&template=channels_add.yml&title=Add%3A+) before posting your request."
placeholder: 'BBCAmerica.us@East'
validations:
required: true
@ -28,9 +28,12 @@ body:
- 2160p
- 1280p
- 1080p
- 1080i
- 720p
- 576p
- 576i
- 480p
- 480i
- 360p
- type: dropdown

View file

@ -19,9 +19,9 @@ body:
- type: input
attributes:
label: Channel ID
description: Channel ID from [iptv-org.github.io](https://iptv-org.github.io/).
placeholder: 'BBCAmericaEast.us'
label: Stream ID
description: "ID of the stream consisting of `<channel_id>` or `<channel_id>@<feed_id>`. Full list of supported channels with corresponding ID could be found on [iptv-org.github.io](https://iptv-org.github.io/). If you can't find the channel you want in the list, please let us know through this [form](https://github.com/iptv-org/database/issues/new?assignees=&labels=channels%3Aadd&projects=&template=channels_add.yml&title=Add%3A+) before posting your request."
placeholder: 'BBCAmerica.us@East'
- type: dropdown
attributes:
@ -31,9 +31,12 @@ body:
- 2160p
- 1280p
- 1080p
- 1080i
- 720p
- 576p
- 576i
- 480p
- 480i
- 360p
- '~'

View file

@ -1,7 +1,7 @@
name: 🚧 Report broken stream
description: Report a broken or unstable stream
title: 'Broken: '
labels: ['broken stream']
labels: ['broken stream', 'streams:remove']
body:
- type: markdown

View file

@ -22,7 +22,7 @@
| News | Programming is mostly news |
| Outdoor | Programming related to outdoor activities like fishing, hunting, etc. |
| Relax | Programming is calm sounding and beautiful views |
| Religious | Religious Programming |
| Religious | Religious programming |
| Science | Science and Technology |
| Series | Channels that only show series |
| Shop | Programming is for shopping |

View file

@ -1,30 +0,0 @@
## Supported Regions
| Code | Description |
| ------------------------------------------------------------------------ | -------------------------------------- |
| [AFR](https://en.wikipedia.org/wiki/Africa) | Africa |
| [AMER](https://en.wikipedia.org/wiki/Americas) | Americas |
| [APAC](https://en.wikipedia.org/wiki/Asia-Pacific) | Asia-Pacific |
| [ARAB](https://en.wikipedia.org/wiki/Arab_world) | Arab world |
| [ASEAN](https://en.wikipedia.org/wiki/ASEAN) | Association of Southeast Asian Nations |
| [ASIA](https://en.wikipedia.org/wiki/Asia) | Asia |
| [CARIB](https://en.wikipedia.org/wiki/Caribbean) | Caribbean |
| [CAS](https://en.wikipedia.org/wiki/Central_Asia) | Central Asia |
| [CENAMER](https://en.wikipedia.org/wiki/Central_America) | Central America |
| [CIS](https://en.wikipedia.org/wiki/Commonwealth_of_Independent_States) | Commonwealth of Independent States |
| [EMEA](https://en.wikipedia.org/wiki/Europe,_the_Middle_East_and_Africa) | Europe, the Middle East and Africa |
| [EUR](https://en.wikipedia.org/wiki/Europe) | Europe |
| [HISPAM](https://en.wikipedia.org/wiki/Hispanic_America) | Hispanic America |
| [LAC](https://en.wikipedia.org/wiki/Latin_America_and_the_Caribbean) | Latin America and the Caribbean |
| [LATAM](https://en.wikipedia.org/wiki/Latin_America) | Latin America |
| [MAGHREB](https://en.wikipedia.org/wiki/Maghreb) | Maghreb |
| [MENA](https://en.wikipedia.org/wiki/MENA) | Middle East and North Africa |
| [MIDEAST](https://en.wikipedia.org/wiki/Middle_East) | Middle East |
| [NAM](https://en.wikipedia.org/wiki/Northern_America) | Northern America |
| [NORAM](https://en.wikipedia.org/wiki/North_America) | North America |
| [NORD](https://en.wikipedia.org/wiki/Nordic_countries) | Nordics |
| [OCE](https://en.wikipedia.org/wiki/Oceania) | Oceania |
| [SAS](https://en.wikipedia.org/wiki/South_Asia) | South Asia |
| [SSA](https://en.wikipedia.org/wiki/Sub-Saharan_Africa) | Sub-Saharan Africa |
| [WAFR](https://en.wikipedia.org/wiki/West_Africa) | West Africa |
| [INT](https://en.wikipedia.org/wiki/West_Africa) | Worldwide |

View file

@ -36,12 +36,12 @@ https://iptv-org.github.io/iptv/index.m3u
### Grouped by category
Playlists in which channels are grouped by category. A list of all supported categories with descriptions can be found [here](.readme/supported-categories.md).
<details>
<summary>Expand</summary>
<br>
Playlist in which each channel has its _category_ as a group title:
```
https://iptv-org.github.io/iptv/index.category.m3u
```
@ -55,12 +55,12 @@ Same thing, but split up into separate files:
### Grouped by language
Playlists in which channels are grouped by the language in which they are broadcast.
<details>
<summary>Expand</summary>
<br>
Playlist in which each channel has its _language_ as a group title:
```
https://iptv-org.github.io/iptv/index.language.m3u
```
@ -74,12 +74,12 @@ Same thing, but split up into separate files:
### Grouped by country
Playlists in which channels are grouped by country for which they are broadcasted.
<details>
<summary>Expand</summary>
<br>
Playlist in which each channel has its _country_ as a group title:
```
https://iptv-org.github.io/iptv/index.country.m3u
```
@ -97,7 +97,7 @@ Same thing, but split up into separate files:
<summary>Expand</summary>
<br>
Playlist in which each channel has its _region_ as a group title:
Playlists in which channels are grouped by the region for which they are broadcasted.
```
https://iptv-org.github.io/iptv/index.region.m3u

View file

@ -20,15 +20,23 @@ Regardless of which option you choose, before posting your request please do the
- Make sure the link you want to add works stably. To check this, open it in one of the players (for example, [VLC player](https://www.videolan.org/vlc/index.html)) and watch the broadcast for at least a minute (some test streams are interrupted after 15-30 seconds).
- Make sure the link is not already in the playlist. This can be done by [searching](https://github.com/search?q=repo%3Aiptv-org%2Fiptv+http%3A%2F%2Fexample.com&type=code) the repository.
- Find the ID of the channel you want to add in our [database](https://iptv-org.github.io/). If this particular channel is not in the database, then leave a request to add it [here](https://github.com/iptv-org/database/issues/new/choose) and wait until it is approved before continuing.
- Make sure the channel is not blocklisted. This can be done by checking the [blocklist.csv](https://github.com/iptv-org/database/blob/master/data/blocklist.csv) file.
- Find the ID of the channel you want on [iptv-org.github.io](https://iptv-org.github.io/). If your desired channel is not on the list you can leave a request to add it [here](https://github.com/iptv-org/database/issues/new/choose).
- Make sure the channel is not blocklisted. It can also be done through [iptv-org.github.io](https://iptv-org.github.io/).
- The link does not lead to the Xtream Codes server. [Why don't you accept links to Xtream Codes server?](FAQ.md#why-dont-you-accept-links-to-xtream-codes-server)
- If you know that the broadcast only works in certain countries or it is periodically interrupted, do not forget to indicate this in the request.
A requests without a valid channel ID or working link to the stream will be closed immediately.
A requests without a valid stream ID or working link to the stream will be closed immediately.
Note all links in playlists are sorted automatically by scripts so there is no need to sort them manually. For more info, see [Scripts](#scripts).
### How to fix the stream description?
Most of the stream description (channel name, categories, languages, broadcast area, logo) we load from the [iptv-org/database](https://github.com/iptv-org/database) using the stream ID.
So first of all, make sure that the desired stream has the correct ID. A full list of all supported channels and their corresponding IDs can be found on [iptv-org.github.io](https://iptv-org.github.io/). To change the stream ID of any link in the playlist, just fill out this [form](https://github.com/iptv-org/iptv/issues/new?assignees=&labels=streams%3Aedit&projects=&template=2_streams_edit.yml&title=Edit%3A+).
If, however, you have found an error in the database itself, this is the place to go: [How to edit channel description?](https://github.com/iptv-org/database/blob/master/CONTRIBUTING.md#how-to-edit-channel-description)
### How to distinguish a link to an Xtream Codes server from a regular one?
Most of them have this form:
@ -52,6 +60,37 @@ The only thing before publishing your report is to make sure that:
An issue without a valid link will be closed immediately.
### How to find a broken stream?
For starters, you can just try to open the playlist in [VLC player](https://www.videolan.org/vlc/). The player outputs all errors to the log (Tools -> Messages) so you'll be able to determine pretty accurately why a link isn't working.
Another way to test links is to use the NPM script. To do this, first make sure you have [Node.js](https://nodejs.org/en) installed on your system. Then go to the `iptv` folder using [Console](https://en.wikipedia.org/wiki/Windows_Console) (or [Terminal](<https://en.wikipedia.org/wiki/Terminal_(macOS)>) if you have macOS) and run the command:
```sh
npm run playlist:test path/to/playlist.m3u
```
This command will run an automatic check of all links in the playlist and display their status:
```sh
npm run playlist:test streams/fr.m3u
streams/fr.m3u
┌─────┬───────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────────┐
│ │ tvg-id │ url │ status │
├─────┼───────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────┤
│ 0 │ 6ter.fr │ https://origin-caf900c010ea8046.live.6cloud.fr/out/v1/29c7a579af3348b48230f76cd75699a5/dash_short... │ LOADING... │
│ 1 │ 20MinutesTV.fr │ https://lives.digiteka.com/stream/86d3e867-a272-496b-8412-f59aa0104771/index.m3u8 │ FFMPEG_STREAMS_NOT_FOUND │
│ 2 │ │ https://video1.getstreamhosting.com:1936/8420/8420/playlist.m3u8 │ OK │
│ 3 │ ADNTVPlus.fr │ https://samsunguk-adn-samsung-fre-qfrlc.amagi.tv/playlist/samsunguk-adn-samsung-fre/playlist.m3u8 │ HTTP_FORBIDDEN │
│ 4 │ Africa24.fr │ https://edge12.vedge.infomaniak.com/livecast/ik:africa24/manifest.m3u8 │ OK │
│ 5 │ Africa24English.fr │ https://edge17.vedge.infomaniak.com/livecast/ik:africa24sport/manifest.m3u8 │ OK │
│ 6 │ AfricanewsEnglish.fr │ https://37c774660687468c821a51190046facf.mediatailor.us-east-1.amazonaws.com/v1/master/04fd913bb2... │ HTTP_GATEWAY_TIMEOUT │
│ 7 │ AlpedHuezTV.fr │ https://edge.vedge.infomaniak.com/livecast/ik:adhtv/chunklist.m3u8 │ HTTP_NOT_FOUND │
```
After that, all you have to do is report any broken streams you find.
### How do I remove my channel from playlist?
To request removal of a link to a channel from the repository, you need to fill out this [form](https://github.com/iptv-org/iptv/issues/new?assignees=&labels=removal+request&projects=&template=-removal-request.yml&title=Remove%3A+) and wait for the request to be reviewed (this usually takes no more than 1 business day). And if the request is approved, links to the channel will be immediately removed from the repository.
@ -65,22 +104,22 @@ Please note that we only accept removal requests from channel owners and their o
For a stream to be approved, its description must follow this template:
```
#EXTINF:-1 tvg-id="CHANNEL_ID",CHANNEL_NAME (RESOLUTION) [LABEL]
#EXTINF:-1 tvg-id="STREAM_ID",CHANNEL_NAME (QUALITY) [LABEL]
STREAM_URL
```
| Attribute | Description | Required | Valid values |
| -------------- | ------------------------------------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| `CHANNEL_ID` | Channel ID. | Optional | Full list of supported channels with corresponding ID could be found on [iptv-org.github.io](https://iptv-org.github.io/). |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------- |
| `STREAM_ID` | ID of the stream. Full list of supported channels with corresponding ID could be found on [iptv-org.github.io](https://iptv-org.github.io/). | Optional | `<channel_id>` or `<channel_id>@<feed_id>` |
| `CHANNEL_NAME` | Full name of the channel. May contain any characters except: `,`, `[`, `]`. | Required | - |
| `RESOLUTION` | Maximum stream resolution. | Optional | `2160p`, `1080p`, `720p`, `480p`, `360p` etc |
| `QUALITY` | Maximum stream quality. | Optional | `2160p`, `1080p`, `720p`, `480p`, `360p` etc |
| `LABEL` | Specified in cases where the broadcast for some reason may not be available to some users. | Optional | `Geo-blocked` or `Not 24/7` |
| `STREAM_URL` | Stream URL. | Required | - |
Example:
```xml
#EXTINF:-1 tvg-id="ExampleTV.ua",Example TV (720p) [Not 24/7]
#EXTINF:-1 tvg-id="ExampleTV.ua@HD",Example TV (720p) [Not 24/7]
https://example.com/playlist.m3u8
```
@ -110,7 +149,6 @@ http://example.com/stream.m3u8
- `config.json`: config for the `markdown-include` package, which is used to compile everything into one `README.md` file.
- `preview.png`: image displayed in the `README.md`.
- `supported-categories.md`: list of supported categories.
- `supported-regions.md`: list of supported regions.
- `template.md`: template for `README.md`.
- `scripts/`: contains all scripts used in the repository.
- `streams/`: contains all streams broken down by the country from which they are broadcast.

696
README.md

File diff suppressed because it is too large Load diff

30
package-lock.json generated
View file

@ -10,7 +10,7 @@
"dependencies": {
"@eslint/eslintrc": "^3.3.0",
"@eslint/js": "^9.21.0",
"@freearhey/core": "^0.2.1",
"@freearhey/core": "^0.7.0",
"@octokit/core": "^6.1.4",
"@octokit/plugin-paginate-rest": "^11.4.3",
"@octokit/plugin-rest-endpoint-methods": "^7.1.3",
@ -1063,9 +1063,9 @@
}
},
"node_modules/@freearhey/core": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.2.1.tgz",
"integrity": "sha512-kEdIxZClykKhGpgyCSlkwuVuSCCAWr3J5YvOUMJQDPgVAYvT5VbD8MYKPm+OwNi9T4HFmF6qqY90qwKJPoOXCA==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.7.0.tgz",
"integrity": "sha512-HXkKPYGY7ife7JAc1q/Qxzy0WUdSnyt3rHThCShZHgnH3rz0tpkjHFW7LNegB3he0IKn/Zc95/YSOQ97Fq8ctA==",
"dependencies": {
"@types/fs-extra": "^11.0.2",
"@types/lodash": "^4.14.198",
@ -1078,6 +1078,7 @@
"node-gzip": "^1.1.2",
"normalize-url": "^6.1.0",
"object-treeify": "^2.1.1",
"run-script-os": "^1.1.6",
"signale": "^1.4.0"
}
},
@ -6059,6 +6060,15 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/run-script-os": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz",
"integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==",
"bin": {
"run-os": "index.js",
"run-script-os": "index.js"
}
},
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
@ -7455,9 +7465,9 @@
}
},
"@freearhey/core": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.2.1.tgz",
"integrity": "sha512-kEdIxZClykKhGpgyCSlkwuVuSCCAWr3J5YvOUMJQDPgVAYvT5VbD8MYKPm+OwNi9T4HFmF6qqY90qwKJPoOXCA==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.7.0.tgz",
"integrity": "sha512-HXkKPYGY7ife7JAc1q/Qxzy0WUdSnyt3rHThCShZHgnH3rz0tpkjHFW7LNegB3he0IKn/Zc95/YSOQ97Fq8ctA==",
"requires": {
"@types/fs-extra": "^11.0.2",
"@types/lodash": "^4.14.198",
@ -7470,6 +7480,7 @@
"node-gzip": "^1.1.2",
"normalize-url": "^6.1.0",
"object-treeify": "^2.1.1",
"run-script-os": "^1.1.6",
"signale": "^1.4.0"
},
"dependencies": {
@ -11122,6 +11133,11 @@
"queue-microtask": "^1.2.2"
}
},
"run-script-os": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz",
"integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw=="
},
"semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",

View file

@ -39,7 +39,7 @@
"dependencies": {
"@eslint/eslintrc": "^3.3.0",
"@eslint/js": "^9.21.0",
"@freearhey/core": "^0.2.1",
"@freearhey/core": "^0.7.0",
"@octokit/core": "^6.1.4",
"@octokit/plugin-paginate-rest": "^11.4.3",
"@octokit/plugin-rest-endpoint-methods": "^7.1.3",

View file

@ -1,21 +1,37 @@
import { Logger, Storage } from '@freearhey/core'
import { API_DIR, STREAMS_DIR } from '../../constants'
import { Logger, Storage, Collection } from '@freearhey/core'
import { API_DIR, STREAMS_DIR, DATA_DIR } from '../../constants'
import { PlaylistParser } from '../../core'
import { Stream } from '../../models'
import { Stream, Channel, Feed } from '../../models'
import { uniqueId } from 'lodash'
async function main() {
const logger = new Logger()
logger.info('loading api data...')
const dataStorage = new Storage(DATA_DIR)
const channelsData = await dataStorage.json('channels.json')
const channels = new Collection(channelsData).map(data => new Channel(data))
const channelsGroupedById = channels.keyBy((channel: Channel) => channel.id)
const feedsData = await dataStorage.json('feeds.json')
const feeds = new Collection(feedsData).map(data =>
new Feed(data).withChannel(channelsGroupedById)
)
const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) =>
feed.channel ? feed.channel.id : uniqueId()
)
logger.info('loading streams...')
const streamsStorage = new Storage(STREAMS_DIR)
const parser = new PlaylistParser({ storage: streamsStorage })
const parser = new PlaylistParser({
storage: streamsStorage,
channelsGroupedById,
feedsGroupedByChannelId
})
const files = await streamsStorage.list('**/*.m3u')
let streams = await parser.parse(files)
streams = streams
.map(data => new Stream(data))
.orderBy([(stream: Stream) => stream.channel])
.orderBy((stream: Stream) => stream.getId())
.map((stream: Stream) => stream.toJSON())
logger.info(`found ${streams.count()} streams`)
logger.info('saving to .api/streams.json...')

View file

@ -12,7 +12,9 @@ async function main() {
client.download('countries.json'),
client.download('languages.json'),
client.download('regions.json'),
client.download('subdivisions.json')
client.download('subdivisions.json'),
client.download('feeds.json'),
client.download('timezones.json')
]
await Promise.all(requests)

View file

@ -1,25 +1,36 @@
import { Logger, Storage, Collection } from '@freearhey/core'
import { STREAMS_DIR, DATA_DIR } from '../../constants'
import { PlaylistParser } from '../../core'
import { Stream, Playlist, Channel } from '../../models'
import { Stream, Playlist, Channel, Feed } from '../../models'
import { program } from 'commander'
import { uniqueId } from 'lodash'
program.argument('[filepath]', 'Path to file to validate').parse(process.argv)
async function main() {
const storage = new Storage(STREAMS_DIR)
const streamsStorage = new Storage(STREAMS_DIR)
const logger = new Logger()
logger.info('loading channels from api...')
logger.info('loading data from api...')
const dataStorage = new Storage(DATA_DIR)
const channelsContent = await dataStorage.json('channels.json')
const groupedChannels = new Collection(channelsContent)
.map(data => new Channel(data))
.keyBy((channel: Channel) => channel.id)
const channelsData = await dataStorage.json('channels.json')
const channels = new Collection(channelsData).map(data => new Channel(data))
const channelsGroupedById = channels.keyBy((channel: Channel) => channel.id)
const feedsData = await dataStorage.json('feeds.json')
const feeds = new Collection(feedsData).map(data =>
new Feed(data).withChannel(channelsGroupedById)
)
const feedsGroupedByChannelId = feeds.groupBy(feed =>
feed.channel ? feed.channel.id : uniqueId()
)
logger.info('loading streams...')
const parser = new PlaylistParser({ storage })
const files = program.args.length ? program.args : await storage.list('**/*.m3u')
const parser = new PlaylistParser({
storage: streamsStorage,
channelsGroupedById,
feedsGroupedByChannelId
})
const files = program.args.length ? program.args : await streamsStorage.list('**/*.m3u')
let streams = await parser.parse(files)
logger.info(`found ${streams.count()} streams`)
@ -35,8 +46,8 @@ async function main() {
logger.info('removing wrong id...')
streams = streams.map((stream: Stream) => {
if (groupedChannels.missing(stream.channel)) {
stream.channel = ''
if (!stream.channel || channelsGroupedById.missing(stream.channel.id)) {
stream.id = ''
}
return stream
@ -46,22 +57,22 @@ async function main() {
streams = streams.orderBy(
[
(stream: Stream) => stream.name,
(stream: Stream) => parseInt(stream.quality.replace('p', '')),
(stream: Stream) => stream.label,
(stream: Stream) => stream.getVerticalResolution(),
(stream: Stream) => stream.getLabel(),
(stream: Stream) => stream.url
],
['asc', 'desc', 'asc', 'asc']
)
logger.info('saving...')
const groupedStreams = streams.groupBy((stream: Stream) => stream.filepath)
const groupedStreams = streams.groupBy((stream: Stream) => stream.getFilepath())
for (let filepath of groupedStreams.keys()) {
const streams = groupedStreams.get(filepath) || []
if (!streams.length) return
const playlist = new Playlist(streams, { public: false })
await storage.save(filepath, playlist.toString())
await streamsStorage.save(filepath, playlist.toString())
}
}

View file

@ -1,14 +1,23 @@
import { Logger, Storage, Collection, File } from '@freearhey/core'
import { Logger, Storage, Collection } from '@freearhey/core'
import { PlaylistParser } from '../../core'
import { Stream, Category, Channel, Language, Country, Region, Subdivision } from '../../models'
import _ from 'lodash'
import {
Stream,
Category,
Channel,
Language,
Country,
Region,
Subdivision,
Feed,
Timezone
} from '../../models'
import { uniqueId } from 'lodash'
import {
CategoriesGenerator,
CountriesGenerator,
LanguagesGenerator,
RegionsGenerator,
IndexGenerator,
IndexNsfwGenerator,
IndexCategoryGenerator,
IndexCountryGenerator,
IndexLanguageGenerator,
@ -19,123 +28,136 @@ import { DATA_DIR, LOGS_DIR, STREAMS_DIR } from '../../constants'
async function main() {
const logger = new Logger()
const dataStorage = new Storage(DATA_DIR)
logger.info('loading data from api...')
const channelsContent = await dataStorage.json('channels.json')
const channels = new Collection(channelsContent).map(data => new Channel(data))
const categoriesContent = await dataStorage.json('categories.json')
const categories = new Collection(categoriesContent).map(data => new Category(data))
const countriesContent = await dataStorage.json('countries.json')
const countries = new Collection(countriesContent).map(data => new Country(data))
const languagesContent = await dataStorage.json('languages.json')
const languages = new Collection(languagesContent).map(data => new Language(data))
const regionsContent = await dataStorage.json('regions.json')
const regions = new Collection(regionsContent).map(data => new Region(data))
const subdivisionsContent = await dataStorage.json('subdivisions.json')
const subdivisions = new Collection(subdivisionsContent).map(data => new Subdivision(data))
logger.info('loading streams...')
let streams = await loadStreams({ channels, categories, languages })
let totalStreams = streams.count()
streams = streams.uniqBy((stream: Stream) => (stream.channel || _.uniqueId()) + stream.timeshift)
logger.info(`found ${totalStreams} streams (including ${streams.count()} unique)`)
const generatorsLogger = new Logger({
stream: await new Storage(LOGS_DIR).createStream(`generators.log`)
})
logger.info('loading data from api...')
const categoriesData = await dataStorage.json('categories.json')
const countriesData = await dataStorage.json('countries.json')
const languagesData = await dataStorage.json('languages.json')
const regionsData = await dataStorage.json('regions.json')
const subdivisionsData = await dataStorage.json('subdivisions.json')
const timezonesData = await dataStorage.json('timezones.json')
const channelsData = await dataStorage.json('channels.json')
const feedsData = await dataStorage.json('feeds.json')
logger.info('preparing data...')
const subdivisions = new Collection(subdivisionsData).map(data => new Subdivision(data))
const subdivisionsGroupedByCode = subdivisions.keyBy(
(subdivision: Subdivision) => subdivision.code
)
const subdivisionsGroupedByCountryCode = subdivisions.groupBy(
(subdivision: Subdivision) => subdivision.countryCode
)
let regions = new Collection(regionsData).map(data =>
new Region(data).withSubdivisions(subdivisions)
)
const regionsGroupedByCode = regions.keyBy((region: Region) => region.code)
const categories = new Collection(categoriesData).map(data => new Category(data))
const categoriesGroupedById = categories.keyBy((category: Category) => category.id)
const languages = new Collection(languagesData).map(data => new Language(data))
const languagesGroupedByCode = languages.keyBy((language: Language) => language.code)
const countries = new Collection(countriesData).map(data =>
new Country(data)
.withRegions(regions)
.withLanguage(languagesGroupedByCode)
.withSubdivisions(subdivisionsGroupedByCountryCode)
)
const countriesGroupedByCode = countries.keyBy((country: Country) => country.code)
regions = regions.map((region: Region) => region.withCountries(countriesGroupedByCode))
const timezones = new Collection(timezonesData).map(data =>
new Timezone(data).withCountries(countriesGroupedByCode)
)
const timezonesGroupedById = timezones.keyBy((timezone: Timezone) => timezone.id)
const channels = new Collection(channelsData).map(data =>
new Channel(data)
.withCategories(categoriesGroupedById)
.withCountry(countriesGroupedByCode)
.withSubdivision(subdivisionsGroupedByCode)
)
const channelsGroupedById = channels.keyBy((channel: Channel) => channel.id)
const feeds = new Collection(feedsData).map(data =>
new Feed(data)
.withChannel(channelsGroupedById)
.withLanguages(languagesGroupedByCode)
.withTimezones(timezonesGroupedById)
.withBroadcastCountries(
countriesGroupedByCode,
regionsGroupedByCode,
subdivisionsGroupedByCode
)
.withBroadcastRegions(regions)
.withBroadcastSubdivisions(subdivisionsGroupedByCode)
)
const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) =>
feed.channel ? feed.channel.id : uniqueId()
)
logger.info('loading streams...')
const storage = new Storage(STREAMS_DIR)
const parser = new PlaylistParser({
storage,
channelsGroupedById,
feedsGroupedByChannelId
})
const files = await storage.list('**/*.m3u')
let streams = await parser.parse(files)
const totalStreams = streams.count()
streams = streams.uniqBy((stream: Stream) =>
stream.hasId() ? stream.getChannelId() + stream.getFeedId() : uniqueId()
)
logger.info(`found ${totalStreams} streams (including ${streams.count()} unique)`)
logger.info('sorting streams...')
streams = streams.orderBy(
[
(stream: Stream) => stream.getId(),
(stream: Stream) => stream.getVerticalResolution(),
(stream: Stream) => stream.getLabel()
],
['asc', 'asc', 'desc']
)
logger.info('generating categories/...')
await new CategoriesGenerator({ categories, streams, logger: generatorsLogger }).generate()
logger.info('generating countries/...')
await new CountriesGenerator({
countries,
streams,
regions,
subdivisions,
logger: generatorsLogger
}).generate()
logger.info('generating languages/...')
await new LanguagesGenerator({ streams, logger: generatorsLogger }).generate()
logger.info('generating regions/...')
await new RegionsGenerator({
streams,
regions,
subdivisions,
logger: generatorsLogger
}).generate()
logger.info('generating index.m3u...')
await new IndexGenerator({ streams, logger: generatorsLogger }).generate()
logger.info('generating index.category.m3u...')
await new IndexCategoryGenerator({ streams, logger: generatorsLogger }).generate()
logger.info('generating index.country.m3u...')
await new IndexCountryGenerator({
streams,
countries,
regions,
subdivisions,
logger: generatorsLogger
}).generate()
logger.info('generating index.language.m3u...')
await new IndexLanguageGenerator({ streams, logger: generatorsLogger }).generate()
logger.info('generating index.region.m3u...')
await new IndexRegionGenerator({ streams, regions, logger: generatorsLogger }).generate()
}
main()
async function loadStreams({
channels,
categories,
languages
}: {
channels: Collection
categories: Collection
languages: Collection
}) {
const groupedChannels = channels.keyBy(channel => channel.id)
const groupedCategories = categories.keyBy(category => category.id)
const groupedLanguages = languages.keyBy(language => language.code)
const storage = new Storage(STREAMS_DIR)
const parser = new PlaylistParser({ storage })
const files = await storage.list('**/*.m3u')
let streams = await parser.parse(files)
streams = streams
.orderBy(
[
(stream: Stream) => stream.channel,
(stream: Stream) => parseInt(stream.quality.replace('p', '')),
(stream: Stream) => stream.label
],
['asc', 'asc', 'desc', 'asc']
)
.map((stream: Stream) => {
const channel: Channel | undefined = groupedChannels.get(stream.channel)
if (channel) {
const channelCategories = channel.categories
.map((id: string) => groupedCategories.get(id))
.filter(Boolean)
const channelLanguages = channel.languages
.map((id: string) => groupedLanguages.get(id))
.filter(Boolean)
stream.categories = channelCategories
stream.languages = channelLanguages
stream.broadcastArea = channel.broadcastArea
stream.isNSFW = channel.isNSFW
if (channel.logo) stream.logo = channel.logo
} else {
const file = new File(stream.filepath)
const [_, countryCode] = file.name().match(/^([a-z]{2})(_|$)/) || [null, null]
const defaultBroadcastArea = countryCode ? [`c/${countryCode.toUpperCase()}`] : []
stream.broadcastArea = new Collection(defaultBroadcastArea)
}
return stream
})
return streams
}

View file

@ -1,7 +1,7 @@
import { Logger, Storage, Collection } from '@freearhey/core'
import { ROOT_DIR, STREAMS_DIR } from '../../constants'
import { ROOT_DIR, STREAMS_DIR, DATA_DIR } from '../../constants'
import { PlaylistParser, StreamTester, CliTable } from '../../core'
import { Stream } from '../../models'
import { Stream, Feed, Channel } from '../../models'
import { program } from 'commander'
import { eachLimit } from 'async-es'
import commandExists from 'command-exists'
@ -38,8 +38,6 @@ const logger = new Logger()
const tester = new StreamTester()
async function main() {
const storage = new Storage(ROOT_DIR)
if (await isOffline()) {
logger.error(chalk.red('Internet connection is required for the script to work'))
@ -56,9 +54,25 @@ async function main() {
return
}
logger.info('loading channels from api...')
const dataStorage = new Storage(DATA_DIR)
const channelsData = await dataStorage.json('channels.json')
const channels = new Collection(channelsData).map(data => new Channel(data))
const channelsGroupedById = channels.keyBy((channel: Channel) => channel.id)
const feedsData = await dataStorage.json('feeds.json')
const feeds = new Collection(feedsData).map(data =>
new Feed(data).withChannel(channelsGroupedById)
)
const feedsGroupedByChannelId = feeds.groupBy(feed => feed.channel)
logger.info('loading streams...')
const parser = new PlaylistParser({ storage })
const files = program.args.length ? program.args : await storage.list(`${STREAMS_DIR}/*.m3u`)
const rootStorage = new Storage(ROOT_DIR)
const parser = new PlaylistParser({
storage: rootStorage,
channelsGroupedById,
feedsGroupedByChannelId
})
const files = program.args.length ? program.args : await rootStorage.list(`${STREAMS_DIR}/*.m3u`)
streams = await parser.parse(files)
logger.info(`found ${streams.count()} streams`)
@ -89,7 +103,7 @@ async function main() {
main()
async function runTest(stream: Stream) {
const key = stream.filepath + stream.channel + stream.url
const key = stream.filepath + stream.getId() + stream.url
results[key] = chalk.white('LOADING...')
const result = await tester.test(stream)
@ -125,11 +139,11 @@ function drawTable() {
]
})
streams.forEach((stream: Stream, index: number) => {
const status = results[stream.filepath + stream.channel + stream.url] || chalk.gray('PENDING')
const status = results[stream.filepath + stream.getId() + stream.url] || chalk.gray('PENDING')
const row = {
'': index,
'tvg-id': stream.channel.length > 25 ? stream.channel.slice(0, 22) + '...' : stream.channel,
'tvg-id': stream.getId().length > 25 ? stream.getId().slice(0, 22) + '...' : stream.getId(),
url: stream.url.length > 100 ? stream.url.slice(0, 97) + '...' : stream.url,
status
}

View file

@ -1,45 +1,63 @@
import { Logger, Storage, Collection, Dictionary } from '@freearhey/core'
import { DATA_DIR, STREAMS_DIR } from '../../constants'
import { IssueLoader, PlaylistParser } from '../../core'
import { Stream, Playlist, Channel, Issue } from '../../models'
import { Stream, Playlist, Channel, Feed, Issue } from '../../models'
import validUrl from 'valid-url'
import { uniqueId } from 'lodash'
let processedIssues = new Collection()
let streams: Collection
let groupedChannels: Dictionary
let issues: Collection
async function main() {
const logger = new Logger({ disabled: true })
const loader = new IssueLoader()
logger.info('loading issues...')
issues = await loader.load()
const issues = await loader.load()
logger.info('loading channels from api...')
const dataStorage = new Storage(DATA_DIR)
const channelsContent = await dataStorage.json('channels.json')
groupedChannels = new Collection(channelsContent)
.map(data => new Channel(data))
.keyBy((channel: Channel) => channel.id)
const channelsData = await dataStorage.json('channels.json')
const channels = new Collection(channelsData).map(data => new Channel(data))
const channelsGroupedById = channels.keyBy((channel: Channel) => channel.id)
const feedsData = await dataStorage.json('feeds.json')
const feeds = new Collection(feedsData).map(data =>
new Feed(data).withChannel(channelsGroupedById)
)
const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) =>
feed.channel ? feed.channel.id : uniqueId()
)
logger.info('loading streams...')
const streamsStorage = new Storage(STREAMS_DIR)
const parser = new PlaylistParser({ storage: streamsStorage })
const parser = new PlaylistParser({
storage: streamsStorage,
feedsGroupedByChannelId,
channelsGroupedById
})
const files = await streamsStorage.list('**/*.m3u')
streams = await parser.parse(files)
const streams = await parser.parse(files)
logger.info('removing broken streams...')
await removeStreams(loader)
await removeStreams({ streams, issues })
logger.info('edit stream description...')
await editStreams(loader)
await editStreams({
streams,
issues,
channelsGroupedById,
feedsGroupedByChannelId
})
logger.info('add new streams...')
await addStreams(loader)
await addStreams({
streams,
issues,
channelsGroupedById,
feedsGroupedByChannelId
})
logger.info('saving...')
const groupedStreams = streams.groupBy((stream: Stream) => stream.filepath)
const groupedStreams = streams.groupBy((stream: Stream) => stream.getFilepath())
for (let filepath of groupedStreams.keys()) {
let streams = groupedStreams.get(filepath) || []
streams = streams.filter((stream: Stream) => stream.removed === false)
@ -54,7 +72,7 @@ async function main() {
main()
async function removeStreams(loader: IssueLoader) {
async function removeStreams({ streams, issues }: { streams: Collection; issues: Collection }) {
const requests = issues.filter(
issue => issue.labels.includes('streams:remove') && issue.labels.includes('approved')
)
@ -62,10 +80,13 @@ async function removeStreams(loader: IssueLoader) {
const data = issue.data
if (data.missing('brokenLinks')) return
const brokenLinks = data.getString('brokenLinks').split(/\r?\n/).filter(Boolean)
const brokenLinks = data.getString('brokenLinks') || ''
let changed = false
brokenLinks.forEach(link => {
brokenLinks
.split(/\r?\n/)
.filter(Boolean)
.forEach(link => {
const found: Stream = streams.first((_stream: Stream) => _stream.url === link.trim())
if (found) {
found.removed = true
@ -77,7 +98,17 @@ async function removeStreams(loader: IssueLoader) {
})
}
async function editStreams(loader: IssueLoader) {
async function editStreams({
streams,
issues,
channelsGroupedById,
feedsGroupedByChannelId
}: {
streams: Collection
issues: Collection
channelsGroupedById: Dictionary
feedsGroupedByChannelId: Dictionary
}) {
const requests = issues.filter(
issue => issue.labels.includes('streams:edit') && issue.labels.includes('approved')
)
@ -86,59 +117,110 @@ async function editStreams(loader: IssueLoader) {
if (data.missing('streamUrl')) return
let stream = streams.first(
let stream: Stream = streams.first(
(_stream: Stream) => _stream.url === data.getString('streamUrl')
) as Stream
)
if (!stream) return
if (data.has('channelId')) {
const channel = groupedChannels.get(data.getString('channelId'))
const streamId = data.getString('streamId') || ''
const [channelId, feedId] = streamId.split('@')
if (!channel) return
stream.channel = data.getString('channelId')
stream.filepath = `${channel.country.toLowerCase()}.m3u`
stream.line = -1
stream.name = channel.name
if (channelId) {
stream
.setChannelId(channelId)
.setFeedId(feedId)
.withChannel(channelsGroupedById)
.withFeed(feedsGroupedByChannelId)
.updateId()
.updateName()
.updateFilepath()
}
if (data.has('label')) stream.label = data.getString('label')
if (data.has('quality')) stream.quality = data.getString('quality')
if (data.has('httpUserAgent')) stream.httpUserAgent = data.getString('httpUserAgent')
if (data.has('httpReferrer')) stream.httpReferrer = data.getString('httpReferrer')
const label = data.getString('label') || ''
const quality = data.getString('quality') || ''
const httpUserAgent = data.getString('httpUserAgent') || ''
const httpReferrer = data.getString('httpReferrer') || ''
if (data.has('label')) stream.setLabel(label)
if (data.has('quality')) stream.setQuality(quality)
if (data.has('httpUserAgent')) stream.setHttpUserAgent(httpUserAgent)
if (data.has('httpReferrer')) stream.setHttpReferrer(httpReferrer)
processedIssues.add(issue.number)
})
}
async function addStreams(loader: IssueLoader) {
async function addStreams({
streams,
issues,
channelsGroupedById,
feedsGroupedByChannelId
}: {
streams: Collection
issues: Collection
channelsGroupedById: Dictionary
feedsGroupedByChannelId: Dictionary
}) {
const requests = issues.filter(
issue => issue.labels.includes('streams:add') && issue.labels.includes('approved')
)
requests.forEach((issue: Issue) => {
const data = issue.data
if (data.missing('channelId') || data.missing('streamUrl')) return
if (data.missing('streamId') || data.missing('streamUrl')) return
if (streams.includes((_stream: Stream) => _stream.url === data.getString('streamUrl'))) return
if (!validUrl.isUri(data.getString('streamUrl'))) return
const stringUrl = data.getString('streamUrl') || ''
if (!isUri(stringUrl)) return
const channel = groupedChannels.get(data.getString('channelId'))
const streamId = data.getString('streamId') || ''
const [channelId] = streamId.split('@')
const channel: Channel = channelsGroupedById.get(channelId)
if (!channel) return
const label = data.getString('label') || ''
const quality = data.getString('quality') || ''
const httpUserAgent = data.getString('httpUserAgent') || ''
const httpReferrer = data.getString('httpReferrer') || ''
const stream = new Stream({
channel: data.getString('channelId'),
url: data.getString('streamUrl'),
label: data.getString('label'),
quality: data.getString('quality'),
httpUserAgent: data.getString('httpUserAgent'),
httpReferrer: data.getString('httpReferrer'),
filepath: `${channel.country.toLowerCase()}.m3u`,
tvg: {
id: streamId,
name: '',
url: '',
logo: '',
rec: '',
shift: ''
},
name: data.getString('channelName') || channel.name,
url: stringUrl,
group: {
title: ''
},
http: {
'user-agent': httpUserAgent,
referrer: httpReferrer
},
line: -1,
name: data.getString('channelName') || channel.name
raw: '',
timeshift: '',
catchup: {
type: '',
source: '',
days: ''
}
})
.withChannel(channelsGroupedById)
.withFeed(feedsGroupedByChannelId)
.setLabel(label)
.setQuality(quality)
.updateName()
.updateFilepath()
streams.add(stream)
processedIssues.add(issue.number)
})
}
function isUri(string: string) {
return validUrl.isUri(encodeURI(string))
}

View file

@ -1,9 +1,9 @@
import { Logger, Storage, Collection, Dictionary } from '@freearhey/core'
import { PlaylistParser } from '../../core'
import { Channel, Stream, Blocked } from '../../models'
import { Channel, Stream, Blocked, Feed } from '../../models'
import { program } from 'commander'
import chalk from 'chalk'
import _ from 'lodash'
import { uniqueId } from 'lodash'
import { DATA_DIR, STREAMS_DIR } from '../../constants'
program.argument('[filepath]', 'Path to file to validate').parse(process.argv)
@ -17,42 +17,53 @@ type LogItem = {
async function main() {
const logger = new Logger()
logger.info(`loading blocklist...`)
logger.info('loading data from api...')
const dataStorage = new Storage(DATA_DIR)
const channelsContent = await dataStorage.json('channels.json')
const channels = new Collection(channelsContent).map(data => new Channel(data))
const channelsData = await dataStorage.json('channels.json')
const channels = new Collection(channelsData).map(data => new Channel(data))
const channelsGroupedById = channels.keyBy((channel: Channel) => channel.id)
const feedsData = await dataStorage.json('feeds.json')
const feeds = new Collection(feedsData).map(data =>
new Feed(data).withChannel(channelsGroupedById)
)
const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) =>
feed.channel ? feed.channel.id : uniqueId()
)
const blocklistContent = await dataStorage.json('blocklist.json')
const blocklist = new Collection(blocklistContent).map(data => new Blocked(data))
logger.info(`found ${blocklist.count()} records`)
const blocklistGroupedByChannelId = blocklist.keyBy((blocked: Blocked) => blocked.channelId)
logger.info('loading streams...')
const streamsStorage = new Storage(STREAMS_DIR)
const parser = new PlaylistParser({ storage: streamsStorage })
const parser = new PlaylistParser({
storage: streamsStorage,
channelsGroupedById,
feedsGroupedByChannelId
})
const files = program.args.length ? program.args : await streamsStorage.list('**/*.m3u')
const streams = await parser.parse(files)
logger.info(`found ${streams.count()} streams`)
let errors = new Collection()
let warnings = new Collection()
let groupedStreams = streams.groupBy((stream: Stream) => stream.filepath)
for (const filepath of groupedStreams.keys()) {
const streams = groupedStreams.get(filepath)
let streamsGroupedByFilepath = streams.groupBy((stream: Stream) => stream.getFilepath())
for (const filepath of streamsGroupedByFilepath.keys()) {
const streams = streamsGroupedByFilepath.get(filepath)
if (!streams) continue
const log = new Collection()
const buffer = new Dictionary()
streams.forEach((stream: Stream) => {
const invalidId =
stream.channel && !channels.first((channel: Channel) => channel.id === stream.channel)
if (invalidId) {
if (stream.channelId) {
const channel = channelsGroupedById.get(stream.channelId)
if (!channel) {
log.add({
type: 'warning',
line: stream.line,
message: `"${stream.channel}" is not in the database`
message: `"${stream.id}" is not in the database`
})
}
}
const duplicate = stream.url && buffer.has(stream.url)
if (duplicate) {
@ -65,19 +76,19 @@ async function main() {
buffer.set(stream.url, true)
}
const blocked = blocklist.first(blocked => stream.channel === blocked.channel)
const blocked = stream.channel ? blocklistGroupedByChannelId.get(stream.channel.id) : false
if (blocked) {
if (blocked.reason === 'dmca') {
log.add({
type: 'error',
line: stream.line,
message: `"${stream.channel}" is on the blocklist due to claims of copyright holders (${blocked.ref})`
message: `"${blocked.channelId}" is on the blocklist due to claims of copyright holders (${blocked.ref})`
})
} else if (blocked.reason === 'nsfw') {
log.add({
type: 'error',
line: stream.line,
message: `"${stream.channel}" is on the blocklist due to NSFW content (${blocked.ref})`
message: `"${blocked.channelId}" is on the blocklist due to NSFW content (${blocked.ref})`
})
}
}

View file

@ -1,154 +1,164 @@
import { Logger, Storage, Collection, Dictionary } from '@freearhey/core'
import { DATA_DIR, STREAMS_DIR } from '../../constants'
import { IssueLoader, PlaylistParser } from '../../core'
import { Blocked, Channel, Issue, Stream } from '../../models'
import { Blocked, Channel, Issue, Stream, Feed } from '../../models'
import { uniqueId } from 'lodash'
async function main() {
const logger = new Logger()
const loader = new IssueLoader()
const storage = new Storage(DATA_DIR)
let report = new Collection()
logger.info('loading issues...')
const issues = await loader.load()
logger.info('loading data from api...')
const dataStorage = new Storage(DATA_DIR)
const channelsData = await dataStorage.json('channels.json')
const channels = new Collection(channelsData).map(data => new Channel(data))
const channelsGroupedById = channels.keyBy((channel: Channel) => channel.id)
const feedsData = await dataStorage.json('feeds.json')
const feeds = new Collection(feedsData).map(data =>
new Feed(data).withChannel(channelsGroupedById)
)
const feedsGroupedByChannelId = feeds.groupBy((feed: Feed) =>
feed.channel ? feed.channel.id : uniqueId()
)
const blocklistContent = await dataStorage.json('blocklist.json')
const blocklist = new Collection(blocklistContent).map(data => new Blocked(data))
const blocklistGroupedByChannelId = blocklist.keyBy((blocked: Blocked) => blocked.channelId)
logger.info('loading streams...')
const streamsStorage = new Storage(STREAMS_DIR)
const parser = new PlaylistParser({ storage: streamsStorage })
const parser = new PlaylistParser({
storage: streamsStorage,
channelsGroupedById,
feedsGroupedByChannelId
})
const files = await streamsStorage.list('**/*.m3u')
const streams = await parser.parse(files)
const streamsGroupedByUrl = streams.groupBy((stream: Stream) => stream.url)
const streamsGroupedByChannel = streams.groupBy((stream: Stream) => stream.channel)
logger.info('loading channels from api...')
const channelsContent = await storage.json('channels.json')
const channelsGroupedById = new Collection(channelsContent)
.map(data => new Channel(data))
.groupBy((channel: Channel) => channel.id)
logger.info('loading blocklist from api...')
const blocklistContent = await storage.json('blocklist.json')
const blocklistGroupedByChannel = new Collection(blocklistContent)
.map(data => new Blocked(data))
.groupBy((blocked: Blocked) => blocked.channel)
let report = new Collection()
logger.info('checking streams:add requests...')
const addRequests = issues.filter(issue => issue.labels.includes('streams:add'))
const addRequestsBuffer = new Dictionary()
addRequests.forEach((issue: Issue) => {
const channelId = issue.data.getString('channelId') || undefined
const streamUrl = issue.data.getString('streamUrl')
const result = new Dictionary({
issueNumber: issue.number,
type: 'streams:add',
channelId,
streamUrl,
status: 'pending'
})
if (!channelId) result.set('status', 'missing_id')
else if (!streamUrl) result.set('status', 'missing_link')
else if (blocklistGroupedByChannel.has(channelId)) result.set('status', 'blocked')
else if (channelsGroupedById.missing(channelId)) result.set('status', 'wrong_id')
else if (streamsGroupedByUrl.has(streamUrl)) result.set('status', 'on_playlist')
else if (addRequestsBuffer.has(streamUrl)) result.set('status', 'duplicate')
else result.set('status', 'pending')
addRequestsBuffer.set(streamUrl, true)
report.add(result.data())
})
logger.info('checking streams:edit requests...')
const editRequests = issues.filter(issue => issue.labels.find(label => label === 'streams:edit'))
editRequests.forEach((issue: Issue) => {
const channelId = issue.data.getString('channelId') || undefined
const streamUrl = issue.data.getString('streamUrl') || undefined
const result = new Dictionary({
issueNumber: issue.number,
type: 'streams:edit',
channelId,
streamUrl,
status: 'pending'
})
if (!streamUrl) result.set('status', 'missing_link')
else if (streamsGroupedByUrl.missing(streamUrl)) result.set('status', 'invalid_link')
else if (channelId && channelsGroupedById.missing(channelId)) result.set('status', 'invalid_id')
report.add(result.data())
})
const streamsGroupedByChannelId = streams.groupBy((stream: Stream) => stream.channelId)
logger.info('checking broken streams reports...')
const brokenStreamReports = issues.filter(issue =>
issue.labels.find(label => label === 'broken stream')
issue.labels.find((label: string) => label === 'broken stream')
)
brokenStreamReports.forEach((issue: Issue) => {
const brokenLinks = issue.data.getArray('brokenLinks') || []
if (!brokenLinks.length) {
const result = new Dictionary({
const result = {
issueNumber: issue.number,
type: 'broken stream',
channelId: undefined,
streamId: undefined,
streamUrl: undefined,
status: 'missing_link'
})
}
report.add(result.data())
report.add(result)
} else {
for (const streamUrl of brokenLinks) {
const result = new Dictionary({
const result = {
issueNumber: issue.number,
type: 'broken stream',
channelId: undefined,
streamUrl: undefined,
streamId: undefined,
streamUrl: truncate(streamUrl),
status: 'pending'
})
}
if (streamsGroupedByUrl.missing(streamUrl)) {
result.set('streamUrl', streamUrl)
result.set('status', 'wrong_link')
result.status = 'wrong_link'
}
report.add(result.data())
report.add(result)
}
}
})
logger.info('checking streams:add requests...')
const addRequests = issues.filter(issue => issue.labels.includes('streams:add'))
const addRequestsBuffer = new Dictionary()
addRequests.forEach((issue: Issue) => {
const streamId = issue.data.getString('streamId') || ''
const streamUrl = issue.data.getString('streamUrl') || ''
const [channelId] = streamId.split('@')
const result = {
issueNumber: issue.number,
type: 'streams:add',
streamId: streamId || undefined,
streamUrl: truncate(streamUrl),
status: 'pending'
}
if (!channelId) result.status = 'missing_id'
else if (!streamUrl) result.status = 'missing_link'
else if (blocklistGroupedByChannelId.has(channelId)) result.status = 'blocked'
else if (channelsGroupedById.missing(channelId)) result.status = 'wrong_id'
else if (streamsGroupedByUrl.has(streamUrl)) result.status = 'on_playlist'
else if (addRequestsBuffer.has(streamUrl)) result.status = 'duplicate'
else result.status = 'pending'
addRequestsBuffer.set(streamUrl, true)
report.add(result)
})
logger.info('checking streams:edit requests...')
const editRequests = issues.filter(issue =>
issue.labels.find((label: string) => label === 'streams:edit')
)
editRequests.forEach((issue: Issue) => {
const streamId = issue.data.getString('streamId') || ''
const streamUrl = issue.data.getString('streamUrl') || ''
const [channelId] = streamId.split('@')
const result = {
issueNumber: issue.number,
type: 'streams:edit',
streamId: streamId || undefined,
streamUrl: truncate(streamUrl),
status: 'pending'
}
if (!streamUrl) result.status = 'missing_link'
else if (streamsGroupedByUrl.missing(streamUrl)) result.status = 'invalid_link'
else if (channelId && channelsGroupedById.missing(channelId)) result.status = 'invalid_id'
report.add(result)
})
logger.info('checking channel search requests...')
const channelSearchRequests = issues.filter(issue =>
issue.labels.find(label => label === 'channel search')
issue.labels.find((label: string) => label === 'channel search')
)
const channelSearchRequestsBuffer = new Dictionary()
channelSearchRequests.forEach((issue: Issue) => {
const channelId = issue.data.getString('channelId')
const streamId = issue.data.getString('channelId') || ''
const [channelId] = streamId.split('@')
const result = new Dictionary({
const result = {
issueNumber: issue.number,
type: 'channel search',
channelId,
streamId: streamId || undefined,
streamUrl: undefined,
status: 'pending'
})
}
if (!channelId) result.set('status', 'missing_id')
else if (channelsGroupedById.missing(channelId)) result.set('status', 'invalid_id')
else if (channelSearchRequestsBuffer.has(channelId)) result.set('status', 'duplicate')
else if (blocklistGroupedByChannel.has(channelId)) result.set('status', 'blocked')
else if (streamsGroupedByChannel.has(channelId)) result.set('status', 'fulfilled')
if (!channelId) result.status = 'missing_id'
else if (channelsGroupedById.missing(channelId)) result.status = 'invalid_id'
else if (channelSearchRequestsBuffer.has(channelId)) result.status = 'duplicate'
else if (blocklistGroupedByChannelId.has(channelId)) result.status = 'blocked'
else if (streamsGroupedByChannelId.has(channelId)) result.status = 'fulfilled'
else {
const channelData = channelsGroupedById.get(channelId)
if (channelData.length && channelData[0].closed) result.set('status', 'closed')
if (channelData.length && channelData[0].closed) result.status = 'closed'
}
channelSearchRequestsBuffer.set(channelId, true)
report.add(result.data())
report.add(result)
})
report = report.orderBy(item => item.issueNumber).filter(item => item.status !== 'pending')
@ -157,3 +167,10 @@ async function main() {
}
main()
function truncate(string: string, limit: number = 100) {
if (!string) return string
if (string.length < limit) return string
return string.slice(0, limit) + '...'
}

View file

@ -41,7 +41,7 @@ export class ApiClient {
}
async download(filename: string) {
const stream = await this.storage.createStream(`/temp/data/${filename}`)
const stream = await this.storage.createStream(`temp/data/${filename}`)
const bar = this.progressBar.create(0, 0, { filename })

View file

@ -1,9 +1,10 @@
import { Table } from 'console-table-printer'
import { ComplexOptions } from 'console-table-printer/dist/src/models/external-table'
export class CliTable {
table: Table
constructor(options?) {
constructor(options?: ComplexOptions | string[]) {
this.table = new Table(options)
}

View file

@ -18,7 +18,7 @@ export class IssueData {
return Boolean(this._data.get(key))
}
getString(key: string): string {
getString(key: string): string | undefined {
const deleteSymbol = '~'
return this._data.get(key) === deleteSymbol ? '' : this._data.get(key)

View file

@ -16,7 +16,7 @@ export class IssueLoader {
}
let issues: object[] = []
if (TESTING) {
issues = (await import('../../tests/__data__/input/issues/all.js')).default
issues = (await import('../../tests/__data__/input/playlist_update/issues.js')).default
} else {
issues = await octokit.paginate(octokit.rest.issues.listForRepo, {
owner: OWNER,

View file

@ -3,11 +3,10 @@ import { Issue } from '../models'
import { IssueData } from './issueData'
const FIELDS = new Dictionary({
'Stream ID': 'streamId',
'Channel ID': 'channelId',
'Channel ID (required)': 'channelId',
'Feed ID': 'feedId',
'Stream URL': 'streamUrl',
'Stream URL (optional)': 'streamUrl',
'Stream URL (required)': 'streamUrl',
'Broken Link': 'brokenLinks',
'Broken Links': 'brokenLinks',
Label: 'label',
@ -18,8 +17,7 @@ const FIELDS = new Dictionary({
'HTTP Referrer': 'httpReferrer',
'What happened to the stream?': 'reason',
Reason: 'reason',
Notes: 'notes',
'Notes (optional)': 'notes'
Notes: 'notes'
})
export class IssueParser {
@ -30,7 +28,7 @@ export class IssueParser {
fields.forEach((field: string) => {
const parsed = typeof field === 'string' ? field.split(/\r?\n/).filter(Boolean) : []
let _label = parsed.shift()
_label = _label ? _label.trim() : ''
_label = _label ? _label.replace(/ \(optional\)| \(required\)/, '').trim() : ''
let _value = parsed.join('\r\n')
_value = _value ? _value.trim() : ''

View file

@ -1,4 +1,5 @@
export type LogItem = {
type: string
filepath: string
count: number
}

View file

@ -1,12 +1,22 @@
import { Collection, Storage } from '@freearhey/core'
import { Collection, Storage, Dictionary } from '@freearhey/core'
import parser from 'iptv-playlist-parser'
import { Stream } from '../models'
type PlaylistPareserProps = {
storage: Storage
feedsGroupedByChannelId: Dictionary
channelsGroupedById: Dictionary
}
export class PlaylistParser {
storage: Storage
feedsGroupedByChannelId: Dictionary
channelsGroupedById: Dictionary
constructor({ storage }: { storage: Storage }) {
constructor({ storage, feedsGroupedByChannelId, channelsGroupedById }: PlaylistPareserProps) {
this.storage = storage
this.feedsGroupedByChannelId = feedsGroupedByChannelId
this.channelsGroupedById = channelsGroupedById
}
async parse(files: string[]): Promise<Collection> {
@ -21,41 +31,18 @@ export class PlaylistParser {
}
async parseFile(filepath: string): Promise<Collection> {
const streams = new Collection()
const content = await this.storage.load(filepath)
const parsed: parser.Playlist = parser.parse(content)
parsed.items.forEach((item: parser.PlaylistItem) => {
const { name, label, quality } = parseTitle(item.name)
const stream = new Stream({
channel: item.tvg.id,
name,
label,
quality,
filepath,
line: item.line,
url: item.url,
httpReferrer: item.http.referrer,
httpUserAgent: item.http['user-agent']
})
const streams = new Collection(parsed.items).map((data: parser.PlaylistItem) => {
const stream = new Stream(data)
.withFeed(this.feedsGroupedByChannelId)
.withChannel(this.channelsGroupedById)
.setFilepath(filepath)
streams.add(stream)
return stream
})
return streams
}
}
function parseTitle(title: string): { name: string; label: string; quality: string } {
const [, label] = title.match(/ \[(.*)\]$/) || [null, '']
title = title.replace(new RegExp(` \\[${escapeRegExp(label)}\\]$`), '')
const [, quality] = title.match(/ \(([0-9]+p)\)$/) || [null, '']
title = title.replace(new RegExp(` \\(${quality}\\)$`), '')
return { name: title, label, quality }
}
function escapeRegExp(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
}

View file

@ -11,15 +11,15 @@ export class StreamTester {
async test(stream: Stream) {
if (TESTING) {
const results = (await import('../../tests/__data__/input/test_results/all.js')).default
const results = (await import('../../tests/__data__/input/playlist_test/results.js')).default
return results[stream.url]
} else {
return this.checker.checkStream({
url: stream.url,
http: {
referrer: stream.httpReferrer,
'user-agent': stream.httpUserAgent
referrer: stream.getHttpReferrer(),
'user-agent': stream.getHttpUserAgent()
}
})
}

View file

@ -29,11 +29,7 @@ export class CategoriesGenerator implements Generator {
const categoryStreams = streams
.filter((stream: Stream) => stream.hasCategory(category))
.map((stream: Stream) => {
const streamCategories = stream.categories
.map((category: Category) => category.name)
.sort()
const groupTitle = stream.categories ? streamCategories.join(';') : ''
stream.groupTitle = groupTitle
stream.groupTitle = stream.getCategoryNames().join(';')
return stream
})
@ -41,13 +37,17 @@ export class CategoriesGenerator implements Generator {
const playlist = new Playlist(categoryStreams, { public: true })
const filepath = `categories/${category.id}.m3u`
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(
JSON.stringify({ type: 'category', filepath, count: playlist.streams.count() })
)
})
const undefinedStreams = streams.filter((stream: Stream) => stream.noCategories())
const undefinedStreams = streams.filter((stream: Stream) => !stream.hasCategories())
const playlist = new Playlist(undefinedStreams, { public: true })
const filepath = 'categories/undefined.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(
JSON.stringify({ type: 'category', filepath, count: playlist.streams.count() })
)
}
}

View file

@ -1,12 +1,10 @@
import { Generator } from './generator'
import { Collection, Storage, Logger } from '@freearhey/core'
import { Country, Region, Subdivision, Stream, Playlist } from '../models'
import { Country, Subdivision, Stream, Playlist } from '../models'
import { PUBLIC_DIR } from '../constants'
type CountriesGeneratorProps = {
streams: Collection
regions: Collection
subdivisions: Collection
countries: Collection
logger: Logger
}
@ -14,55 +12,37 @@ type CountriesGeneratorProps = {
export class CountriesGenerator implements Generator {
streams: Collection
countries: Collection
regions: Collection
subdivisions: Collection
storage: Storage
logger: Logger
constructor({ streams, countries, regions, subdivisions, logger }: CountriesGeneratorProps) {
constructor({ streams, countries, logger }: CountriesGeneratorProps) {
this.streams = streams
this.countries = countries
this.regions = regions
this.subdivisions = subdivisions
this.storage = new Storage(PUBLIC_DIR)
this.logger = logger
}
async generate(): Promise<void> {
const streams = this.streams
.orderBy([stream => stream.getTitle()])
.orderBy((stream: Stream) => stream.getTitle())
.filter((stream: Stream) => stream.isSFW())
const regions = this.regions.filter((region: Region) => region.code !== 'INT')
this.countries.forEach(async (country: Country) => {
const countrySubdivisions = this.subdivisions.filter(
(subdivision: Subdivision) => subdivision.country === country.code
const countryStreams = streams.filter((stream: Stream) =>
stream.isBroadcastInCountry(country)
)
const countrySubdivisionsCodes = countrySubdivisions.map(
(subdivision: Subdivision) => `s/${subdivision.code}`
)
const countryAreaCodes = regions
.filter((region: Region) => region.countries.includes(country.code))
.map((region: Region) => `r/${region.code}`)
.concat(countrySubdivisionsCodes)
.add(`c/${country.code}`)
const countryStreams = streams.filter(stream =>
stream.broadcastArea.intersects(countryAreaCodes)
)
if (countryStreams.isEmpty()) return
const playlist = new Playlist(countryStreams, { public: true })
const filepath = `countries/${country.code.toLowerCase()}.m3u`
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(
JSON.stringify({ type: 'country', filepath, count: playlist.streams.count() })
)
countrySubdivisions.forEach(async (subdivision: Subdivision) => {
const subdivisionStreams = streams.filter(stream =>
stream.broadcastArea.includes(`s/${subdivision.code}`)
country.getSubdivisions().forEach(async (subdivision: Subdivision) => {
const subdivisionStreams = streams.filter((stream: Stream) =>
stream.isBroadcastInSubdivision(subdivision)
)
if (subdivisionStreams.isEmpty()) return
@ -70,16 +50,22 @@ export class CountriesGenerator implements Generator {
const playlist = new Playlist(subdivisionStreams, { public: true })
const filepath = `subdivisions/${subdivision.code.toLowerCase()}.m3u`
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(
JSON.stringify({ type: 'subdivision', filepath, count: playlist.streams.count() })
)
})
})
const internationalStreams = streams.filter(stream => stream.isInternational())
if (internationalStreams.notEmpty()) {
const playlist = new Playlist(internationalStreams, { public: true })
const filepath = 'countries/int.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
}
const undefinedStreams = streams.filter((stream: Stream) => !stream.hasBroadcastArea())
const undefinedPlaylist = new Playlist(undefinedStreams, { public: true })
const undefinedFilepath = 'countries/undefined.m3u'
await this.storage.save(undefinedFilepath, undefinedPlaylist.toString())
this.logger.info(
JSON.stringify({
type: 'country',
filepath: undefinedFilepath,
count: undefinedPlaylist.streams.count()
})
)
}
}

View file

@ -26,14 +26,14 @@ export class IndexCategoryGenerator implements Generator {
let groupedStreams = new Collection()
streams.forEach((stream: Stream) => {
if (stream.noCategories()) {
if (!stream.hasCategories()) {
const streamClone = stream.clone()
streamClone.groupTitle = 'Undefined'
groupedStreams.add(streamClone)
return
}
stream.categories.forEach((category: Category) => {
stream.getCategories().forEach((category: Category) => {
const streamClone = stream.clone()
streamClone.groupTitle = category.name
groupedStreams.push(streamClone)
@ -48,6 +48,6 @@ export class IndexCategoryGenerator implements Generator {
const playlist = new Playlist(groupedStreams, { public: true })
const filepath = 'index.category.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(JSON.stringify({ type: 'index', filepath, count: playlist.streams.count() }))
}
}

View file

@ -1,29 +1,20 @@
import { Generator } from './generator'
import { Collection, Storage, Logger } from '@freearhey/core'
import { Stream, Playlist, Country, Subdivision, Region } from '../models'
import { Stream, Playlist, Country } from '../models'
import { PUBLIC_DIR } from '../constants'
type IndexCountryGeneratorProps = {
streams: Collection
regions: Collection
countries: Collection
subdivisions: Collection
logger: Logger
}
export class IndexCountryGenerator implements Generator {
streams: Collection
countries: Collection
regions: Collection
subdivisions: Collection
storage: Storage
logger: Logger
constructor({ streams, regions, countries, subdivisions, logger }: IndexCountryGeneratorProps) {
constructor({ streams, logger }: IndexCountryGeneratorProps) {
this.streams = streams
this.countries = countries
this.regions = regions
this.subdivisions = subdivisions
this.storage = new Storage(PUBLIC_DIR)
this.logger = logger
}
@ -32,10 +23,10 @@ export class IndexCountryGenerator implements Generator {
let groupedStreams = new Collection()
this.streams
.orderBy(stream => stream.getTitle())
.filter(stream => stream.isSFW())
.forEach(stream => {
if (stream.noBroadcastArea()) {
.orderBy((stream: Stream) => stream.getTitle())
.filter((stream: Stream) => stream.isSFW())
.forEach((stream: Stream) => {
if (!stream.hasBroadcastArea()) {
const streamClone = stream.clone()
streamClone.groupTitle = 'Undefined'
groupedStreams.add(streamClone)
@ -48,7 +39,7 @@ export class IndexCountryGenerator implements Generator {
groupedStreams.add(streamClone)
}
this.getStreamBroadcastCountries(stream).forEach((country: Country) => {
stream.getBroadcastCountries().forEach((country: Country) => {
const streamClone = stream.clone()
streamClone.groupTitle = country.name
groupedStreams.add(streamClone)
@ -65,40 +56,6 @@ export class IndexCountryGenerator implements Generator {
const playlist = new Playlist(groupedStreams, { public: true })
const filepath = 'index.country.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
}
getStreamBroadcastCountries(stream: Stream) {
const groupedRegions = this.regions.keyBy((region: Region) => region.code)
const groupedCountries = this.countries.keyBy((country: Country) => country.code)
const groupedSubdivisions = this.subdivisions.keyBy(
(subdivision: Subdivision) => subdivision.code
)
let broadcastCountries = new Collection()
stream.broadcastArea.forEach(broadcastAreaCode => {
const [type, code] = broadcastAreaCode.split('/')
switch (type) {
case 'c':
broadcastCountries.add(code)
break
case 'r':
if (code !== 'INT' && groupedRegions.has(code)) {
broadcastCountries = broadcastCountries.concat(groupedRegions.get(code).countries)
}
break
case 's':
if (groupedSubdivisions.has(code)) {
broadcastCountries.add(groupedSubdivisions.get(code).country)
}
break
}
})
return broadcastCountries
.uniq()
.map(code => groupedCountries.get(code))
.filter(Boolean)
this.logger.info(JSON.stringify({ type: 'index', filepath, count: playlist.streams.count() }))
}
}

View file

@ -27,6 +27,6 @@ export class IndexGenerator implements Generator {
const playlist = new Playlist(sfwStreams, { public: true })
const filepath = 'index.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(JSON.stringify({ type: 'index', filepath, count: playlist.streams.count() }))
}
}

View file

@ -22,17 +22,17 @@ export class IndexLanguageGenerator implements Generator {
async generate(): Promise<void> {
let groupedStreams = new Collection()
this.streams
.orderBy(stream => stream.getTitle())
.filter(stream => stream.isSFW())
.forEach(stream => {
if (stream.noLanguages()) {
.orderBy((stream: Stream) => stream.getTitle())
.filter((stream: Stream) => stream.isSFW())
.forEach((stream: Stream) => {
if (!stream.hasLanguages()) {
const streamClone = stream.clone()
streamClone.groupTitle = 'Undefined'
groupedStreams.add(streamClone)
return
}
stream.languages.forEach((language: Language) => {
stream.getLanguages().forEach((language: Language) => {
const streamClone = stream.clone()
streamClone.groupTitle = language.name
groupedStreams.add(streamClone)
@ -47,6 +47,6 @@ export class IndexLanguageGenerator implements Generator {
const playlist = new Playlist(groupedStreams, { public: true })
const filepath = 'index.language.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(JSON.stringify({ type: 'index', filepath, count: playlist.streams.count() }))
}
}

View file

@ -25,6 +25,6 @@ export class IndexNsfwGenerator implements Generator {
const playlist = new Playlist(allStreams, { public: true })
const filepath = 'index.nsfw.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(JSON.stringify({ type: 'index', filepath, count: playlist.streams.count() }))
}
}

View file

@ -28,14 +28,21 @@ export class IndexRegionGenerator implements Generator {
.orderBy((stream: Stream) => stream.getTitle())
.filter((stream: Stream) => stream.isSFW())
.forEach((stream: Stream) => {
if (stream.noBroadcastArea()) {
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
}
this.getStreamRegions(stream).forEach((region: Region) => {
stream.getBroadcastRegions().forEach((region: Region) => {
const streamClone = stream.clone()
streamClone.groupTitle = region.name
groupedStreams.push(streamClone)
@ -43,41 +50,14 @@ export class IndexRegionGenerator implements Generator {
})
groupedStreams = groupedStreams.orderBy((stream: Stream) => {
if (stream.groupTitle === 'Undefined') return 'ZZ'
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.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
}
getStreamRegions(stream: Stream) {
let streamRegions = new Collection()
stream.broadcastArea.forEach(broadcastAreaCode => {
const [type, code] = broadcastAreaCode.split('/')
switch (type) {
case 'r':
const groupedRegions = this.regions.keyBy((region: Region) => region.code)
streamRegions.add(groupedRegions.get(code))
break
case 's':
const [countryCode] = code.split('-')
const subdivisionRegions = this.regions.filter((region: Region) =>
region.countries.includes(countryCode)
)
streamRegions = streamRegions.concat(subdivisionRegions)
break
case 'c':
const countryRegions = this.regions.filter((region: Region) =>
region.countries.includes(code)
)
streamRegions = streamRegions.concat(countryRegions)
break
}
})
return streamRegions
this.logger.info(JSON.stringify({ type: 'index', filepath, count: playlist.streams.count() }))
}
}

View file

@ -18,35 +18,40 @@ export class LanguagesGenerator implements Generator {
async generate(): Promise<void> {
const streams = this.streams
.orderBy(stream => stream.getTitle())
.filter(stream => stream.isSFW())
.orderBy((stream: Stream) => stream.getTitle())
.filter((stream: Stream) => stream.isSFW())
let languages = new Collection()
streams.forEach((stream: Stream) => {
languages = languages.concat(stream.languages)
languages = languages.concat(stream.getLanguages())
})
languages
.filter(Boolean)
.uniqBy((language: Language) => language.code)
.orderBy((language: Language) => language.name)
.forEach(async (language: Language) => {
const languageStreams = streams.filter(stream => stream.hasLanguage(language))
const languageStreams = streams.filter((stream: Stream) => stream.hasLanguage(language))
if (languageStreams.isEmpty()) return
const playlist = new Playlist(languageStreams, { public: true })
const filepath = `languages/${language.code}.m3u`
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(
JSON.stringify({ type: 'language', filepath, count: playlist.streams.count() })
)
})
const undefinedStreams = streams.filter(stream => stream.noLanguages())
const undefinedStreams = streams.filter((stream: Stream) => !stream.hasLanguages())
if (undefinedStreams.isEmpty()) return
const playlist = new Playlist(undefinedStreams, { public: true })
const filepath = 'languages/undefined.m3u'
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(
JSON.stringify({ type: 'language', filepath, count: playlist.streams.count() })
)
}
}

View file

@ -1,53 +1,61 @@
import { Generator } from './generator'
import { Collection, Storage, Logger } from '@freearhey/core'
import { Playlist, Subdivision, Region } from '../models'
import { Playlist, Region, Stream } from '../models'
import { PUBLIC_DIR } from '../constants'
type RegionsGeneratorProps = {
streams: Collection
regions: Collection
subdivisions: Collection
logger: Logger
}
export class RegionsGenerator implements Generator {
streams: Collection
regions: Collection
subdivisions: Collection
storage: Storage
logger: Logger
constructor({ streams, regions, subdivisions, logger }: RegionsGeneratorProps) {
constructor({ streams, regions, logger }: RegionsGeneratorProps) {
this.streams = streams
this.regions = regions
this.subdivisions = subdivisions
this.storage = new Storage(PUBLIC_DIR)
this.logger = logger
}
async generate(): Promise<void> {
const streams = this.streams
.orderBy(stream => stream.getTitle())
.filter(stream => stream.isSFW())
.orderBy((stream: Stream) => stream.getTitle())
.filter((stream: Stream) => stream.isSFW())
this.regions.forEach(async (region: Region) => {
if (region.code === 'INT') return
if (region.isWorldwide()) return
const regionSubdivisionsCodes = this.subdivisions
.filter((subdivision: Subdivision) => region.countries.indexOf(subdivision.country) > -1)
.map((subdivision: Subdivision) => `s/${subdivision.code}`)
const regionCodes = region.countries
.map((code: string) => `c/${code}`)
.concat(regionSubdivisionsCodes)
.add(`r/${region.code}`)
const regionStreams = streams.filter(stream => stream.broadcastArea.intersects(regionCodes))
const regionStreams = streams.filter((stream: Stream) => stream.isBroadcastInRegion(region))
const playlist = new Playlist(regionStreams, { public: true })
const filepath = `regions/${region.code.toLowerCase()}.m3u`
await this.storage.save(filepath, playlist.toString())
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
this.logger.info(
JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() })
)
})
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.logger.info(
JSON.stringify({
type: 'region',
filepath: internationalFilepath,
count: internationalPlaylist.streams.count()
})
)
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.logger.info(JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() }))
}
}

View file

@ -5,13 +5,13 @@ type BlockedProps = {
}
export class Blocked {
channel: string
channelId: string
reason: string
ref: string
constructor({ ref, reason, channel }: BlockedProps) {
this.channel = channel
this.reason = reason
this.ref = ref
constructor(data: BlockedProps) {
this.channelId = data.channel
this.reason = data.reason
this.ref = data.ref
}
}

View file

@ -0,0 +1,11 @@
type BroadcastAreaProps = {
code: string
}
export class BroadcastArea {
code: string
constructor(data: BroadcastAreaProps) {
this.code = data.code
}
}

View file

@ -1,4 +1,4 @@
type CategoryProps = {
type CategoryData = {
id: string
name: string
}
@ -7,8 +7,8 @@ export class Category {
id: string
name: string
constructor({ id, name }: CategoryProps) {
this.id = id
this.name = name
constructor(data: CategoryData) {
this.id = data.id
this.name = data.name
}
}

View file

@ -1,17 +1,16 @@
import { Collection } from '@freearhey/core'
import { Collection, Dictionary } from '@freearhey/core'
import { Category, Country, Subdivision } from './index'
type ChannelProps = {
type ChannelData = {
id: string
name: string
alt_names: string[]
network: string
owners: string[]
owners: Collection
country: string
subdivision: string
city: string
broadcast_area: string[]
languages: string[]
categories: string[]
categories: Collection
is_nsfw: boolean
launched: string
closed: string
@ -24,56 +23,86 @@ export class Channel {
id: string
name: string
altNames: Collection
network: string
network?: string
owners: Collection
country: string
subdivision: string
city: string
broadcastArea: Collection
languages: Collection
categories: Collection
countryCode: string
country?: Country
subdivisionCode?: string
subdivision?: Subdivision
cityName?: string
categoryIds: Collection
categories?: Collection
isNSFW: boolean
launched: string
closed: string
replacedBy: string
website: string
launched?: string
closed?: string
replacedBy?: string
website?: string
logo: string
constructor({
id,
name,
alt_names,
network,
owners,
country,
subdivision,
city,
broadcast_area,
languages,
categories,
is_nsfw,
launched,
closed,
replaced_by,
website,
logo
}: ChannelProps) {
this.id = id
this.name = name
this.altNames = new Collection(alt_names)
this.network = network
this.owners = new Collection(owners)
this.country = country
this.subdivision = subdivision
this.city = city
this.broadcastArea = new Collection(broadcast_area)
this.languages = new Collection(languages)
this.categories = new Collection(categories)
this.isNSFW = is_nsfw
this.launched = launched
this.closed = closed
this.replacedBy = replaced_by
this.website = website
this.logo = logo
constructor(data: ChannelData) {
this.id = data.id
this.name = data.name
this.altNames = new Collection(data.alt_names)
this.network = data.network || undefined
this.owners = new Collection(data.owners)
this.countryCode = data.country
this.subdivisionCode = data.subdivision || undefined
this.cityName = data.city || undefined
this.categoryIds = new Collection(data.categories)
this.isNSFW = data.is_nsfw
this.launched = data.launched || undefined
this.closed = data.closed || undefined
this.replacedBy = data.replaced_by || undefined
this.website = data.website || undefined
this.logo = data.logo
}
withSubdivision(subdivisionsGroupedByCode: Dictionary): this {
if (!this.subdivisionCode) return this
this.subdivision = subdivisionsGroupedByCode.get(this.subdivisionCode)
return this
}
withCountry(countriesGroupedByCode: Dictionary): this {
this.country = countriesGroupedByCode.get(this.countryCode)
return this
}
withCategories(groupedCategories: Dictionary): this {
this.categories = this.categoryIds
.map((id: string) => groupedCategories.get(id))
.filter(Boolean)
return this
}
getCountry(): Country | undefined {
return this.country
}
getSubdivision(): Subdivision | undefined {
return this.subdivision
}
getCategories(): Collection {
return this.categories || new Collection()
}
hasCategories(): boolean {
return !!this.categories && this.categories.notEmpty()
}
hasCategory(category: Category): boolean {
return (
!!this.categories &&
this.categories.includes((_category: Category) => _category.id === category.id)
)
}
isSFW(): boolean {
return this.isNSFW === false
}
}

View file

@ -1,20 +1,58 @@
type CountryProps = {
import { Collection, Dictionary } from '@freearhey/core'
import { Region, Language } from '.'
type CountryData = {
code: string
name: string
languages: string[]
lang: string
flag: string
}
export class Country {
code: string
name: string
languages: string[]
flag: string
languageCode: string
language?: Language
subdivisions?: Collection
regions?: Collection
constructor({ code, name, languages, flag }: CountryProps) {
this.code = code
this.name = name
this.languages = languages
this.flag = flag
constructor(data: CountryData) {
this.code = data.code
this.name = data.name
this.flag = data.flag
this.languageCode = data.lang
}
withSubdivisions(subdivisionsGroupedByCountryCode: Dictionary): this {
this.subdivisions = subdivisionsGroupedByCountryCode.get(this.code) || new Collection()
return this
}
withRegions(regions: Collection): this {
this.regions = regions.filter(
(region: Region) => region.code !== 'INT' && region.includesCountryCode(this.code)
)
return this
}
withLanguage(languagesGroupedByCode: Dictionary): this {
this.language = languagesGroupedByCode.get(this.languageCode)
return this
}
getLanguage(): Language | undefined {
return this.language
}
getRegions(): Collection {
return this.regions || new Collection()
}
getSubdivisions(): Collection {
return this.subdivisions || new Collection()
}
}

200
scripts/models/feed.ts Normal file
View file

@ -0,0 +1,200 @@
import { Collection, Dictionary } from '@freearhey/core'
import { Country, Language, Region, Channel, Subdivision } from './index'
type FeedData = {
channel: string
id: string
name: string
is_main: boolean
broadcast_area: Collection
languages: Collection
timezones: Collection
video_format: string
}
export class Feed {
channelId: string
channel?: Channel
id: string
name: string
isMain: boolean
broadcastAreaCodes: Collection
broadcastCountryCodes: Collection
broadcastCountries?: Collection
broadcastRegionCodes: Collection
broadcastRegions?: Collection
broadcastSubdivisionCodes: Collection
broadcastSubdivisions?: Collection
languageCodes: Collection
languages?: Collection
timezoneIds: Collection
timezones?: Collection
videoFormat: string
constructor(data: FeedData) {
this.channelId = data.channel
this.id = data.id
this.name = data.name
this.isMain = data.is_main
this.broadcastAreaCodes = new Collection(data.broadcast_area)
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(channelsGroupedById: Dictionary): this {
this.channel = channelsGroupedById.get(this.channelId)
return this
}
withLanguages(languagesGroupedByCode: Dictionary): this {
this.languages = this.languageCodes
.map((code: string) => languagesGroupedByCode.get(code))
.filter(Boolean)
return this
}
withTimezones(timezonesGroupedById: Dictionary): this {
this.timezones = this.timezoneIds
.map((id: string) => timezonesGroupedById.get(id))
.filter(Boolean)
return this
}
withBroadcastSubdivisions(subdivisionsGroupedByCode: Dictionary): this {
this.broadcastSubdivisions = this.broadcastSubdivisionCodes.map((code: string) =>
subdivisionsGroupedByCode.get(code)
)
return this
}
withBroadcastCountries(
countriesGroupedByCode: Dictionary,
regionsGroupedByCode: Dictionary,
subdivisionsGroupedByCode: Dictionary
): this {
let broadcastCountries = new Collection()
if (this.isInternational()) {
this.broadcastCountries = broadcastCountries
return this
}
this.broadcastCountryCodes.forEach((code: string) => {
broadcastCountries.add(countriesGroupedByCode.get(code))
})
this.broadcastRegionCodes.forEach((code: string) => {
const region: Region = regionsGroupedByCode.get(code)
if (region) {
region.countryCodes.forEach((countryCode: string) => {
broadcastCountries.add(countriesGroupedByCode.get(countryCode))
})
}
})
this.broadcastSubdivisionCodes.forEach((code: string) => {
const subdivision: Subdivision = subdivisionsGroupedByCode.get(code)
if (subdivision) {
broadcastCountries.add(countriesGroupedByCode.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
return region.countryCodes.intersects(countriesCodes)
})
return this
}
hasBroadcastArea(): boolean {
return (
this.isInternational() || (!!this.broadcastCountries && this.broadcastCountries.notEmpty())
)
}
getBroadcastCountries(): Collection {
return this.broadcastCountries || new Collection()
}
getBroadcastRegions(): Collection {
return this.broadcastRegions || new Collection()
}
getTimezones(): Collection {
return this.timezones || new Collection()
}
getLanguages(): Collection {
return this.languages || new Collection()
}
hasLanguages(): boolean {
return !!this.languages && this.languages.notEmpty()
}
hasLanguage(language: Language): boolean {
return (
!!this.languages &&
this.languages.includes((_language: Language) => _language.code === language.code)
)
}
isInternational(): boolean {
return this.broadcastAreaCodes.includes('r/INT')
}
isBroadcastInSubdivision(subdivision: Subdivision): boolean {
if (this.isInternational()) return false
return this.broadcastSubdivisionCodes.includes(subdivision.code)
}
isBroadcastInCountry(country: Country): boolean {
if (this.isInternational()) return false
return this.getBroadcastCountries().includes(
(_country: Country) => _country.code === country.code
)
}
isBroadcastInRegion(region: Region): boolean {
if (this.isInternational()) return false
return this.getBroadcastRegions().includes((_region: Region) => _region.code === region.code)
}
}

View file

@ -8,3 +8,6 @@ export * from './language'
export * from './country'
export * from './region'
export * from './subdivision'
export * from './feed'
export * from './broadcastArea'
export * from './timezone'

View file

@ -1,4 +1,4 @@
type LanguageProps = {
type LanguageData = {
code: string
name: string
}
@ -7,8 +7,8 @@ export class Language {
code: string
name: string
constructor({ code, name }: LanguageProps) {
this.code = code
this.name = name
constructor(data: LanguageData) {
this.code = data.code
this.name = data.name
}
}

View file

@ -1,6 +1,7 @@
import { Collection } from '@freearhey/core'
import { Collection, Dictionary } from '@freearhey/core'
import { Subdivision } from '.'
type RegionProps = {
type RegionData = {
code: string
name: string
countries: string[]
@ -9,11 +10,43 @@ type RegionProps = {
export class Region {
code: string
name: string
countries: Collection
countryCodes: Collection
countries?: Collection
subdivisions?: Collection
constructor({ code, name, countries }: RegionProps) {
this.code = code
this.name = name
this.countries = new Collection(countries)
constructor(data: RegionData) {
this.code = data.code
this.name = data.name
this.countryCodes = new Collection(data.countries)
}
withCountries(countriesGroupedByCode: Dictionary): this {
this.countries = this.countryCodes.map((code: string) => countriesGroupedByCode.get(code))
return this
}
withSubdivisions(subdivisions: Collection): this {
this.subdivisions = subdivisions.filter(
(subdivision: Subdivision) => this.countryCodes.indexOf(subdivision.countryCode) > -1
)
return this
}
getSubdivisions(): Collection {
return this.subdivisions || new Collection()
}
getCountries(): Collection {
return this.countries || new Collection()
}
includesCountryCode(code: string): boolean {
return this.countryCodes.includes((countryCode: string) => countryCode === code)
}
isWorldwide(): boolean {
return this.code === 'INT'
}
}

View file

@ -1,64 +1,193 @@
import { URL, Collection } from '@freearhey/core'
import { Category, Language } from './index'
type StreamProps = {
name: string
url: string
filepath: string
line: number
channel?: string
httpReferrer?: string
httpUserAgent?: string
label?: string
quality?: string
}
import { URL, Collection, Dictionary } from '@freearhey/core'
import { Feed, Channel, Category, Region, Subdivision, Country, Language } from './index'
import parser from 'iptv-playlist-parser'
export class Stream {
channel: string
filepath: string
line: number
httpReferrer: string
label: string
name: string
quality: string
url: string
httpUserAgent: string
logo: string
broadcastArea: Collection
categories: Collection
languages: Collection
isNSFW: boolean
id?: string
groupTitle: string
channelId?: string
channel?: Channel
feedId?: string
feed?: Feed
filepath?: string
line: number
label?: string
verticalResolution?: number
isInterlaced?: boolean
httpReferrer?: string
httpUserAgent?: string
removed: boolean = false
constructor({
channel,
filepath,
line,
httpReferrer,
label,
name,
quality,
url,
httpUserAgent
}: StreamProps) {
this.channel = channel || ''
this.filepath = filepath
this.line = line
this.httpReferrer = httpReferrer || ''
this.label = label || ''
constructor(data: parser.PlaylistItem) {
if (!data.name) throw new Error('"name" property is required')
if (!data.url) throw new Error('"url" property is required')
const [channelId, feedId] = data.tvg.id.split('@')
const { name, label, quality } = parseTitle(data.name)
const { verticalResolution, isInterlaced } = parseQuality(quality)
this.id = data.tvg.id || undefined
this.feedId = feedId || undefined
this.channelId = channelId || undefined
this.line = data.line
this.label = label || undefined
this.name = name
this.quality = quality || ''
this.url = url
this.httpUserAgent = httpUserAgent || ''
this.logo = ''
this.broadcastArea = new Collection()
this.categories = new Collection()
this.languages = new Collection()
this.isNSFW = false
this.verticalResolution = verticalResolution || undefined
this.isInterlaced = isInterlaced || undefined
this.url = data.url
this.httpReferrer = data.http.referrer || undefined
this.httpUserAgent = data.http['user-agent'] || undefined
this.groupTitle = 'Undefined'
}
withChannel(channelsGroupedById: Dictionary): this {
if (!this.channelId) return this
this.channel = channelsGroupedById.get(this.channelId)
return this
}
withFeed(feedsGroupedByChannelId: Dictionary): this {
if (!this.channelId) return this
const channelFeeds = feedsGroupedByChannelId.get(this.channelId) || []
if (this.feedId) this.feed = channelFeeds.find((feed: Feed) => feed.id === this.feedId)
if (!this.feedId && !this.feed) this.feed = channelFeeds.find((feed: Feed) => feed.isMain)
return this
}
setId(id: string): this {
this.id = id
return this
}
setChannelId(channelId: string): this {
this.channelId = channelId
return this
}
setFeedId(feedId: string | undefined): this {
this.feedId = feedId
return this
}
setLabel(label: string): this {
this.label = label
return this
}
setQuality(quality: string): this {
const { verticalResolution, isInterlaced } = parseQuality(quality)
this.verticalResolution = verticalResolution || undefined
this.isInterlaced = isInterlaced || undefined
return this
}
setHttpUserAgent(httpUserAgent: string): this {
this.httpUserAgent = httpUserAgent
return this
}
setHttpReferrer(httpReferrer: string): this {
this.httpReferrer = httpReferrer
return this
}
setFilepath(filepath: string): this {
this.filepath = filepath
return this
}
updateFilepath(): this {
if (!this.channel) return this
this.filepath = `${this.channel.countryCode.toLowerCase()}.m3u`
return this
}
getChannelId(): string {
return this.channelId || ''
}
getFeedId(): string {
if (this.feedId) return this.feedId
if (this.feed) return this.feed.id
return ''
}
getFilepath(): string {
return this.filepath || ''
}
getHttpReferrer(): string {
return this.httpReferrer || ''
}
getHttpUserAgent(): string {
return this.httpUserAgent || ''
}
getQuality(): string {
if (!this.verticalResolution) return ''
let quality = this.verticalResolution.toString()
if (this.isInterlaced) quality += 'i'
else quality += 'p'
return quality
}
hasId(): boolean {
return !!this.id
}
hasQuality(): boolean {
return !!this.verticalResolution
}
getVerticalResolution(): number {
if (!this.hasQuality()) return 0
return parseInt(this.getQuality().replace(/p|i/, ''))
}
updateName(): this {
if (!this.channel) return this
this.name = this.channel.name
if (this.feed && !this.feed.isMain) {
this.name += ` ${this.feed.name}`
}
return this
}
updateId(): this {
if (!this.channel) return this
if (this.feed) {
this.id = `${this.channel.id}@${this.feed.id}`
} else {
this.id = this.channel.id
}
return this
}
normalizeURL() {
const url = new URL(this.url)
@ -81,43 +210,82 @@ export class Stream {
return !!this.channel
}
hasCategories(): boolean {
return this.categories.notEmpty()
getBroadcastRegions(): Collection {
return this.feed ? this.feed.getBroadcastRegions() : new Collection()
}
noCategories(): boolean {
return this.categories.isEmpty()
getBroadcastCountries(): Collection {
return this.feed ? this.feed.getBroadcastCountries() : new Collection()
}
hasCategory(category: Category): boolean {
return this.categories.includes((_category: Category) => _category.id === category.id)
}
noLanguages(): boolean {
return this.languages.isEmpty()
}
hasLanguage(language: Language): boolean {
return this.languages.includes((_language: Language) => _language.code === language.code)
}
noBroadcastArea(): boolean {
return this.broadcastArea.isEmpty()
}
isInternational(): boolean {
return this.broadcastArea.includes('r/INT')
hasBroadcastArea(): boolean {
return this.feed ? this.feed.hasBroadcastArea() : false
}
isSFW(): boolean {
return this.isNSFW === false
return this.channel ? this.channel.isSFW() : true
}
hasCategories(): boolean {
return this.channel ? this.channel.hasCategories() : false
}
hasCategory(category: Category): boolean {
return this.channel ? this.channel.hasCategory(category) : false
}
getCategoryNames(): string[] {
return this.getCategories()
.map((category: Category) => category.name)
.sort()
.all()
}
getCategories(): Collection {
return this.channel ? this.channel.getCategories() : new Collection()
}
getLanguages(): Collection {
return this.feed ? this.feed.getLanguages() : new Collection()
}
hasLanguages() {
return this.feed ? this.feed.hasLanguages() : false
}
hasLanguage(language: Language) {
return this.feed ? this.feed.hasLanguage(language) : false
}
getBroadcastAreaCodes(): Collection {
return this.feed ? this.feed.broadcastAreaCodes : new Collection()
}
isBroadcastInSubdivision(subdivision: Subdivision): boolean {
return this.feed ? this.feed.isBroadcastInSubdivision(subdivision) : false
}
isBroadcastInCountry(country: Country): boolean {
return this.feed ? this.feed.isBroadcastInCountry(country) : false
}
isBroadcastInRegion(region: Region): boolean {
return this.feed ? this.feed.isBroadcastInRegion(region) : false
}
isInternational(): boolean {
return this.feed ? this.feed.isInternational() : false
}
getLogo(): string {
return this?.channel?.logo || ''
}
getTitle(): string {
let title = `${this.name}`
if (this.quality) {
title += ` (${this.quality})`
if (this.getQuality()) {
title += ` (${this.getQuality()})`
}
if (this.label) {
@ -127,15 +295,26 @@ export class Stream {
return title
}
getLabel(): string {
return this.label || ''
}
getId(): string {
return this.id || ''
}
data() {
return {
id: this.id,
channel: this.channel,
feed: this.feed,
filepath: this.filepath,
httpReferrer: this.httpReferrer,
label: this.label,
name: this.name,
quality: this.quality,
verticalResolution: this.verticalResolution,
isInterlaced: this.isInterlaced,
url: this.url,
httpReferrer: this.httpReferrer,
httpUserAgent: this.httpUserAgent,
line: this.line
}
@ -143,18 +322,20 @@ export class Stream {
toJSON() {
return {
channel: this.channel || null,
channel: this.channelId || null,
feed: this.feedId || null,
url: this.url,
referrer: this.httpReferrer || null,
user_agent: this.httpUserAgent || null
user_agent: this.httpUserAgent || null,
quality: this.getQuality() || null
}
}
toString(options: { public: boolean }) {
let output = `#EXTINF:-1 tvg-id="${this.channel}"`
let output = `#EXTINF:-1 tvg-id="${this.getId()}"`
if (options.public) {
output += ` tvg-logo="${this.logo}" group-title="${this.groupTitle}"`
output += ` tvg-logo="${this.getLogo()}" group-title="${this.groupTitle}"`
}
if (this.httpReferrer) {
@ -180,3 +361,29 @@ export class Stream {
return output
}
}
function parseTitle(title: string): {
name: string
label: string
quality: string
} {
const [, label] = title.match(/ \[(.*)\]$/) || [null, '']
title = title.replace(new RegExp(` \\[${escapeRegExp(label)}\\]$`), '')
const [, quality] = title.match(/ \(([0-9]+p)\)$/) || [null, '']
title = title.replace(new RegExp(` \\(${quality}\\)$`), '')
return { name: title, label, quality }
}
function escapeRegExp(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
}
function parseQuality(quality: string): { verticalResolution: number; isInterlaced: boolean } {
let [, verticalResolutionString] = quality.match(/^(\d+)/) || [null, undefined]
const isInterlaced = /i$/i.test(quality)
let verticalResolution = 0
if (verticalResolutionString) verticalResolution = parseInt(verticalResolutionString)
return { verticalResolution, isInterlaced }
}

View file

@ -1,4 +1,7 @@
type SubdivisionProps = {
import { Dictionary } from '@freearhey/core'
import { Country } from '.'
type SubdivisionData = {
code: string
name: string
country: string
@ -7,11 +10,18 @@ type SubdivisionProps = {
export class Subdivision {
code: string
name: string
country: string
countryCode: string
country?: Country
constructor({ code, name, country }: SubdivisionProps) {
this.code = code
this.name = name
this.country = country
constructor(data: SubdivisionData) {
this.code = data.code
this.name = data.name
this.countryCode = data.country
}
withCountry(countriesGroupedByCode: Dictionary): this {
this.country = countriesGroupedByCode.get(this.countryCode)
return this
}
}

View file

@ -0,0 +1,30 @@
import { Collection, Dictionary } from '@freearhey/core'
type TimezoneData = {
id: string
utc_offset: string
countries: string[]
}
export class Timezone {
id: string
utcOffset: string
countryCodes: Collection
countries?: Collection
constructor(data: TimezoneData) {
this.id = data.id
this.utcOffset = data.utc_offset
this.countryCodes = new Collection(data.countries)
}
withCountries(countriesGroupedByCode: Dictionary): this {
this.countries = this.countryCodes.map((code: string) => countriesGroupedByCode.get(code))
return this
}
getCountries(): Collection {
return this.countries || new Collection()
}
}

View file

@ -11,6 +11,7 @@ export class CategoryTable implements Table {
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)
@ -19,13 +20,12 @@ export class CategoryTable implements Table {
let data = new Collection()
parser
.parse(generatorsLog)
.filter((logItem: LogItem) => logItem.filepath.includes('categories/'))
.filter((logItem: LogItem) => logItem.type === 'category')
.forEach((logItem: LogItem) => {
const file = new File(logItem.filepath)
const categoryId = file.name()
const category: Category = categories.first(
(category: Category) => category.id === categoryId
)
const category: Category = categoriesGroupedById.get(categoryId)
data.add([
category ? category.name : 'ZZ',
category ? category.name : 'Undefined',

View file

@ -12,34 +12,31 @@ export class CountryTable implements Table {
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)
let data = new Collection()
parser
.parse(generatorsLog)
.filter(
(logItem: LogItem) =>
logItem.filepath.includes('countries/') || logItem.filepath.includes('subdivisions/')
)
parsed
.filter((logItem: LogItem) => logItem.type === 'subdivision')
.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 (subdivisionCode) {
const subdivision = subdivisions.first(
(subdivision: Subdivision) => subdivision.code === code
)
if (country && subdivisionCode) {
const subdivision = subdivisionsGroupedByCode.get(code)
if (subdivision) {
const country = countries.first(
(country: Country) => country.code === subdivision.country
)
data.add([
`${country.name}/${subdivision.name}`,
`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${subdivision.name}`,
@ -47,18 +44,28 @@ export class CountryTable implements Table {
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
])
}
} else if (countryCode === 'INT') {
}
})
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([
'ZZ',
'🌍 International',
country.name,
`${country.flag} ${country.name}`,
logItem.count,
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
])
} else {
const country = countries.first((country: Country) => country.code === countryCode)
data.add([
country.name,
`${country.flag} ${country.name}`,
'ZZ',
'Undefined',
logItem.count,
`<code>https://iptv-org.github.io/iptv/${logItem.filepath}</code>`
])

View file

@ -11,6 +11,7 @@ export class LanguageTable implements Table {
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)
@ -19,13 +20,11 @@ export class LanguageTable implements Table {
let data = new Collection()
parser
.parse(generatorsLog)
.filter((logItem: LogItem) => logItem.filepath.includes('languages/'))
.filter((logItem: LogItem) => logItem.type === 'language')
.forEach((logItem: LogItem) => {
const file = new File(logItem.filepath)
const languageCode = file.name()
const language: Language = languages.first(
(language: Language) => language.code === languageCode
)
const language: Language = languagesGroupedByCode.get(languageCode)
data.add([
language ? language.name : 'ZZ',

View file

@ -11,6 +11,7 @@ export class RegionTable implements Table {
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)
@ -19,22 +20,35 @@ export class RegionTable implements Table {
let data = new Collection()
parser
.parse(generatorsLog)
.filter((logItem: LogItem) => logItem.filepath.includes('regions/'))
.filter((logItem: LogItem) => logItem.type === 'region')
.forEach((logItem: LogItem) => {
const file = new File(logItem.filepath)
const regionCode = file.name().toUpperCase()
const region: Region = regions.first((region: Region) => region.code === regionCode)
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])
data = data
.orderBy(item => item[0])
.map(item => {
item.shift()
return item
})
const table = new HTMLTable(data.all(), [
{ name: 'Region', align: 'left' },

View file

@ -1,3 +1,5 @@
#EXTM3U
#EXTINF:-1 tvg-id="AndorraTV.ad",ATV (720p)
https://videos.rtva.ad/live/rtva/playlist.m3u8
#EXTINF:-1 tvg-id="AndorraTV.ad@Web",Andorra TV (1080p)
https://live-edge-eu-1.cdn.enetres.net/56495F77FD124FECA75590A906965F2C022/live-3000/index.m3u8

View file

@ -3,9 +3,9 @@
https://vo-live.cdb.cdn.orange.com/Content/Channel/AbuDhabiChannel/HLS/index.m3u8
#EXTINF:-1 tvg-id="AbuDhabiEmirates.ae",Abu Dhabi Emirates (1080p)
https://vo-live.cdb.cdn.orange.com/Content/Channel/EmiratesChannel/HLS/index.m3u8
#EXTINF:-1 tvg-id="AbuDhabiSports1.ae",Abu Dhabi Sports 1
#EXTINF:-1 tvg-id="AbuDhabiSports1.ae",Abu Dhabi Sports 1 (1080p)
https://vo-live-media.cdb.cdn.orange.com/Content/Channel/AbuDhabiSportsChannel1/HLS/index.m3u8
#EXTINF:-1 tvg-id="AbuDhabiSports2.ae",Abu Dhabi Sports 2
#EXTINF:-1 tvg-id="AbuDhabiSports2.ae",Abu Dhabi Sports 2 (1080p)
https://tr-live-route.adm.tcon.hlit.hvds.tv/Content/Channel/AbuDhabiSportsChannel2/DASH/master.mpd
#EXTINF:-1 tvg-id="AbuDhabiSports2.ae",Abu Dhabi Sports 2 (1080p)
https://vo-live.cdb.cdn.orange.com/Content/Channel/AbuDhabiSportsChannel2/HLS/index.m3u8
@ -19,6 +19,8 @@ https://mbc1-enc.edgenextcdn.net/out/v1/f5f319206ed740f9a831f2097c2ead23/index.m
https://live.alarabiya.net/alarabiapublish/aswaaq.smil/playlist.m3u8
#EXTINF:-1 tvg-id="AlArabiyaPrograms.ae",Al Arabiya Programs (1080p)
https://d1j4r34gq3qw9y.cloudfront.net/out/v1/96804f3a14864641a21c25e8ca9afb74/index.m3u8
#EXTINF:-1 tvg-id="AlDafrahTV.ae",Al Dafrah TV (720p)
https://rtmp-live-ingest-eu-west-3-universe-dacast-com.akamaized.net/transmuxv1/streams/dbb8ac05-a020-784c-3a95-6ed027941532.m3u8
#EXTINF:-1 tvg-id="AlMashhad.ae",Al Mashhad (1080p)
https://bcovlive-a.akamaihd.net/20c3ca22be3c4f03b30afbf3c92cfd14/ap-south-1/6313884884001/playlist.m3u8
#EXTINF:-1 tvg-id="AlQamarTV.ae",Al Qamar TV (1080p)
@ -31,8 +33,6 @@ https://svs.itworkscdn.net/kablatvlive/kabtv1.smil/playlist.m3u8
https://svs.itworkscdn.net/alwoustalive/alwoustatv.smil/playlist.m3u8
#EXTINF:-1 tvg-id="AlYaumTV.ae",Al Yaum TV (1080p)
https://iko-live.akamaized.net/AlyuamTV/master.m3u8
#EXTINF:-1 tvg-id="AlYaumTV.ae",Al Yaum TV (720p)
https://alyaum-tv.akamaized.net/hls/alyaum-tv.m3u8
#EXTINF:-1 tvg-id="Alarabiya.ae",Alarabiya (1080p)
https://d35j504z0x2vu2.cloudfront.net/v1/master/0bc8e8376bd8417a1b6761138aa41c26c7309312/al-arabiya/playlist.m3u8
#EXTINF:-1 tvg-id="Alarabiya.ae",Alarabiya (1080p)
@ -63,7 +63,7 @@ https://dmieigthvllta.cdn.mgmlcdn.com/dubaitvht/smil:dubaitv.stream.smil/chunkli
https://dmiffthftl.cdn.mangomolo.com/dubaizaman/smil:dubaizaman.stream.smil/chunklist.m3u8
#EXTINF:-1 tvg-id="FujairahTV.ae",Fujairah TV (720p)
https://live.kwikmotion.com/fujairahlive/fujairah.smil/playlist.m3u8
#EXTINF:-1 tvg-id="JustVogueTV.ae",Just Vogue TV
#EXTINF:-1 tvg-id="JustVogueTV.ae",Just Vogue TV (1080p)
https://ip100.radyotelekomtv.com:3873/stream/play.m3u8
#EXTINF:-1 tvg-id="Majid.ae",Majid TV (1080p)
https://vo-live.cdb.cdn.orange.com/Content/Channel/MajidChildrenChannel/HLS/index.m3u8
@ -151,9 +151,9 @@ https://weyyak-live.akamaized.net/weyyak_mix/index.m3u8
https://weyyak-live.akamaized.net/weyyak_nawaem/index.m3u8
#EXTINF:-1 tvg-id="YasTV.ae",Yas TV (1080p)
https://vo-live.cdb.cdn.orange.com/Content/Channel/YASSportsChannel/HLS/index.m3u8
#EXTINF:-1 tvg-id="AlDafrahTV.ae",Al Dafrah TV (720p)
https://rtmp-live-ingest-eu-west-3-universe-dacast-com.akamaized.net/transmuxv1/streams/dbb8ac05-a020-784c-3a95-6ed027941532.m3u8
#EXTINF:-1 tvg-id="ZeeAlwan.ae",Zee Alwan (720p) [Geo-blocked]
https://weyyak-live.akamaized.net/weyyak_zee_alwan/index.m3u8
#EXTINF:-1 tvg-id="ZeeAflam.ae",Zee Aflam (720p) [Geo-blocked]
https://weyyak-live.akamaized.net/weyyak_zee_aflam/index.m3u8
#EXTINF:-1 tvg-id="ZeeAlwan.ae",Zee Alwan (720p) [Geo-blocked]
https://weyyak-live.akamaized.net/weyyak_zee_alwan/index.m3u8
#EXTINF:-1 tvg-id="SpacetoonArabic.ae",Spacetoon Arabic (1080p)
https://shd-gcp-live.edgenextcdn.net/live/bitmovin-spacetoon/d8382fb9ab4b2307058f12c7ea90db54/index.m3u8

View file

@ -19,6 +19,8 @@ https://live1.mediadesk.al/oranews.m3u8
http://198.244.188.94/panorama/livestream/playlist.m3u8
#EXTINF:-1 tvg-id="ReportTV.al",Report TV (720p)
https://deb10stream.duckdns.org/hls/stream.m3u8
#EXTINF:-1 tvg-id="Syri.al",Syri (720p) [Not 24/7]
https://stream.syritv.al/SyriTV/index.m3u8
#EXTINF:-1 tvg-id="TopChannel.al",Top News (720p)
https://trueodin.serv00.net/?t=topnewsal
#EXTINF:-1 tvg-id="TropojaTelevizion.al",Tropoja TV (1080p)
@ -27,5 +29,3 @@ https://live.prostream.al/al/smil:tropojatv.smil/playlist.m3u8
https://fe.tring.al/delta/105/out/u/rdghfhsfhfshs.m3u8
#EXTINF:-1 tvg-id="ZjarrTV.al",Zjarr TV (720p) [Not 24/7]
https://cdn.jwplayer.com/live/events/r2qgHu7W.m3u8
#EXTINF:-1 tvg-id="Syri.al",Syri (720p) [Not 24/7]
https://stream.syritv.al/SyriTV/index.m3u8

View file

@ -5,32 +5,8 @@ http://stream01.vnet.am/AmediaPremium/mono.m3u8
http://stream02.vnet.am/Kinoman/mono.m3u8
#EXTINF:-1 tvg-id="FightBox.nl",FightBox
http://stream01.vnet.am/Fightbox/mono.m3u8
#EXTINF:-1 tvg-id="Fox.ru",Fox
https://stream01.vnet.am/Fox/mono.m3u8
#EXTINF:-1 tvg-id="Hollywood.ru",Hollywood
http://stream01.vnet.am/ParamountChannel/mono.m3u8
#EXTINF:-1 tvg-id="NationalGeographicWild.ru",National Geographic Wild
http://stream02.vnet.am/NatGeoWild/mono.m3u8
#EXTINF:-1 tvg-id="NicktoonsCIS.ru",Nicktoons
https://stream01.vnet.am/Boomerang/mono.m3u8
#EXTINF:-1 tvg-id="BoksTV.ru",Бокс ТВ
http://stream01.vnet.am/BoksTv/mono.m3u8
#EXTINF:-1 tvg-id="Detskimir.ru",Детский мир
http://stream01.vnet.am/CartoonNetwork/mono.m3u8
#EXTINF:-1 tvg-id="Domkino.ru",Дом Кино
https://stream01.vnet.am/DomKino/mono.m3u8
#EXTINF:-1 tvg-id="India.ru",Индия
https://stream01.vnet.am/ZeeTV/mono.m3u8
#EXTINF:-1 tvg-id="CarouselInternational.ru",Карусель Int
http://stream02.vnet.am/Karusel/mono.m3u8
#EXTINF:-1 tvg-id="KinopremyeraHD.ru",Кинопремьера HD
http://stream02.vnet.am/Kinopremera/mono.m3u8
#EXTINF:-1 tvg-id="KukhnyaTV.ru",Кухня ТВ HD
http://stream01.vnet.am/KukhnyaTv/mono.m3u8
#EXTINF:-1 tvg-id="MuzTV.ru",Муз ТВ
http://stream01.vnet.am/MuzTv/mono.m3u8
#EXTINF:-1 tvg-id="Mult.ru",Мульт
http://stream01.vnet.am/Mult/mono.m3u8
#EXTINF:-1 tvg-id="Nauka.ru",Наука 2.0
http://stream01.vnet.am/Nauka/mono.m3u8
#EXTINF:-1 tvg-id="NTVMir.ru",НТВ Мир
@ -41,7 +17,5 @@ http://stream01.vnet.am/Evrika/mono.m3u8
http://stream01.vnet.am/Perec/mono.m3u8
#EXTINF:-1 tvg-id="FridayInternational.ru",Пятница International
https://stream01.vnet.am/Pyatnica/mono.m3u8
#EXTINF:-1 tvg-id="STSkids.ru",СТС Kids
http://stream02.vnet.am/DisneyChannel/mono.m3u8
#EXTINF:-1 tvg-id="Telecafe.ru",Телекафе
http://stream01.vnet.am/Telekafe/mono.m3u8

View file

@ -16,9 +16,9 @@ https://panel.dattalive.com/6605140/smil:6605140.smil/playlist.m3u8
#EXTVLCOPT:http-user-agent=iPhone
https://g1.vxral-hor.transport.edge-access.net/a15/ngrp:a24-100056_all/a24-100056.m3u8
#EXTINF:-1 tvg-id="AiredeSantaFe.ar",Aire de Santa Fe (1080p)
https://unlimited1-us.dps.live/airedesantafetv/airedesantafetv.smil/playlist.m3u8
#EXTINF:-1 tvg-id="AlternaTV.ar",Alterna TV (720p)
https://alternatv.ar/stream/hls/live.m3u8
https://unlimited1-us.dps.live/airedesantafetv/airedesantafetv.smil/playlist.m3u8
#EXTINF:-1 tvg-id="Am1020.ar",Am1020 (360p) [Geo-blocked]
http://51.79.83.93:9998/live/am1020/playlist.m3u8
#EXTINF:-1 tvg-id="AmericaTV.ar",America TV (480p)

View file

@ -27,6 +27,8 @@ https://bitcdn-kronehit.bitmovin.com/v2/hls/playlist.m3u8
https://streaming13.huberwebmedia.at/LiveApp/streams/985585225397790082777809.m3u8
#EXTINF:-1 tvg-id="Okto.at",Okto TV (1080p)
https://cdn3.wowza.com/1/MHFtazJReW5rOFhP/N2NWNDZ2/hls/live/playlist.m3u8
#EXTINF:-1 tvg-id="ORF1HD.at",ORF 1 HD
https://s6.hopslan.com/orfx11/index.m3u8
#EXTINF:-1 tvg-id="ORF1HD.at" http-referrer="https://livestreamde.com/",ORF 1 HD
#EXTVLCOPT:http-referrer=https://livestreamde.com/
https://strm.hdtvizlecanli.com/live/orf1.m3u8
@ -48,6 +50,8 @@ http://iptv.rtv-ooe.at/stream.m3u8
https://m317.video-stream-hosting.de/gzSoftware-live/_definst_/smil:livestream.smil/playlist.m3u8
#EXTINF:-1 tvg-id="ServusTV.at",ServusTV (1080p) [Geo-blocked]
https://stv-live.akamaized.net/hls/live/2031011/lingeoSTVATwebPri/master.m3u8
#EXTINF:-1 tvg-id="SteiermarkTV.at",Steiermark TV (1080p)
https://h056.video-stream-hosting.de/easycast8-live/_definst_/mp4:livestreamhd4/playlist.m3u8?ref=
#EXTINF:-1 tvg-id="SwamijiTVAmerican.at",Swamiji TV American (1080p) [Not 24/7]
https://stream.swamiji.tv/YogaIPTV/smil:YogaStreamUS.smil/playlist.m3u8
#EXTINF:-1 tvg-id="SwamijiTVAustralian.at",Swamiji TV Australian (1080p) [Not 24/7]
@ -64,9 +68,3 @@ http://89.187.168.245:8080/live/sUPPERchannel2/index.m3u8
https://live1.markenfunk.com/t1/ngrp:live_all/playlist.m3u8
#EXTINF:-1 tvg-id="W24.at",W24 (720p) [Not 24/7]
https://ms01.w24.at/W24/smil:liveevent.smil/playlist.m3u8
#EXTINF:-1 tvg-id="ORF1HD.at",ORF 1 HD
https://s6.hopslan.com/orfx1/index.m3u8
#EXTINF:-1 tvg-id="ORF1HD.at",ORF 1 HD
https://s6.hopslan.com/orfx11/index.m3u8
#EXTINF:-1 tvg-id="SteiermarkTV.at",Steiermark TV (1080p)
https://h056.video-stream-hosting.de/easycast8-live/_definst_/mp4:livestreamhd4/playlist.m3u8?ref=

View file

@ -3,8 +3,6 @@
https://2gblive.akamaized.net/hls/live/2033805/2GB/index.m3u8
#EXTINF:-1 tvg-id="3AW.au",3AW Melbourne (1080p)
https://3awlive.akamaized.net/hls/live/2032295/3AW/index.m3u8
#EXTINF:-1 tvg-id="3TamilTV.au",3 Tamil TV (720p) [Not 24/7]
https://6n3yogbnd9ok-hls-live.5centscdn.com/threetamil/d0dbe915091d400bd8ee7f27f0791303.sdp/index.m3u8
#EXTINF:-1 tvg-id="6PR.au",6PR Perth (1080p)
https://6prlive.akamaized.net/hls/live/2033806/6PR/index.m3u8
#EXTINF:-1 tvg-id="9GemSydney.au",9Gem (720p) [Geo-blocked]
@ -13,12 +11,8 @@ https://9now-livestreams.akamaized.net/hls/live/2008311/gem-syd/master.m3u8
https://9now-livestreams.akamaized.net/hls/live/2008312/go-syd/master.m3u8
#EXTINF:-1 tvg-id="9LifeSydney.au",9Life (720p) [Geo-blocked]
https://9now-livestreams.akamaized.net/hls/live/2008313/life-syd/master.m3u8
#EXTINF:-1 tvg-id="10BoldSydney.au",10 Bold (720p) [Geo-blocked]
https://i.mjh.nz/10bold-nsw.m3u8
#EXTINF:-1 tvg-id="10BoldAdelaide.au",10 Bold Adelaide (1080p)
https://dce3793146fef017.mediapackage.us-west-2.amazonaws.com/out/v1/55cdf73af7894775ba6de8f57482b66a/CMAF_HLS/index.m3u8
#EXTINF:-1 tvg-id="10PeachSydney.au",10 Peach (720p) [Geo-blocked]
https://i.mjh.nz/10peach-nsw.m3u8
#EXTINF:-1 tvg-id="ABCAustralia.au",ABC Australia
https://abc-news-dmd-streams-1.akamaized.net/out/v1/701126012d044971b3fa89406a440133/index.m3u8
#EXTINF:-1 tvg-id="ABCMESydney.au",ABC Me (720p)
@ -41,8 +35,6 @@ https://c.mjh.nz/abc-wa.m3u8
https://c.mjh.nz/abc-tv-plus.m3u8
#EXTINF:-1 tvg-id="ABCTVNSW.au",ABC TV Sydney (720p)
https://c.mjh.nz/abc-nsw.m3u8
#EXTINF:-1 tvg-id="AUSTamilTV.au",AUS Tamil TV (720p) [Not 24/7]
https://bk7l2pn7dx53-hls-live.5centscdn.com/austamil/fe01ce2a7fbac8fafaed7c982a04e229.sdp/playlist.m3u8
#EXTINF:-1 tvg-id="AusbizTV.au",ausbiz TV (720p) [Not 24/7]
https://d9quh89lh7dtw.cloudfront.net/public-output/index.m3u8
#EXTINF:-1 tvg-id="BloombergTVAustralia.au",Bloomberg TV Australia (270p)
@ -61,8 +53,6 @@ https://9now-livestreams-fhd-t.akamaized.net/u/prod/simulcast/mel/ch9/hls/r1/ind
https://9now-livestreams-fhd-t.akamaized.net/u/prod/simulcast/per/ch9/hls/r1/index.m3u8
#EXTINF:-1 tvg-id="Channel9Sydney.au",Channel 9 Sydney (720p) [Geo-blocked]
https://9now-livestreams-fhd-t.akamaized.net/u/prod/simulcast/syd/ch9/hls/r1/index.m3u8
#EXTINF:-1 tvg-id="10Sydney.au",Channel 10 (720p) [Geo-blocked]
https://i.mjh.nz/10-nsw.m3u8
#EXTINF:-1 tvg-id="Channel44.au",Channel 44 (480p)
https://d1k6kax80wecy5.cloudfront.net/WFqZJc/index.m3u8
#EXTINF:-1 tvg-id="CTBPerth.au",CTB Perth (720p)
@ -73,16 +63,10 @@ https://movies.ctbperth.net.au/hls/stream.m3u8
https://news.ctbperth.net.au/hls/stream.m3u8
#EXTINF:-1 tvg-id="ExpoChannel.au",Expo Channel (360p)
https://tvsnhlslivetest.akamaized.net/hls/live/2034711/EXPO-MSL4/master.m3u8
#EXTINF:-1 tvg-id="GOOD.au",GOOD.
https://i.mjh.nz/.r/good-dot.m3u8
#EXTINF:-1 tvg-id="HopeChannelAustralia.au",Hope Channel Australia (1080p)
https://videodelivery.net/9fb3596948ddf463fde0ec4b85625b24/manifest/video.m3u8
#EXTINF:-1 tvg-id="IndoOzTV.au",Indo Oz TV (720p)
https://stream.e2is.in/hls/indoztv.m3u8
#EXTINF:-1 tvg-id="JonmoBhumiTV.au",JonmoBhumi TV (720p) [Not 24/7]
https://us170.jagobd.com:447/c3VydmVyX8RpbEU9Mi8xNy8yMDE0GIDU6RgzQ6NTAgdEoaeFzbF92YWxIZTO0U0ezN1IzMyfvcGVMZEJCTEFWeVN3PTOmdFsaWRtaW51aiPhnPTI/jonmobhumitv.stream/playlist.m3u8
#EXTINF:-1 tvg-id="M4TVMalayalam.au",M4TV Malayalam (1080p) [Not 24/7]
https://app.m4stream.live/mfourmalayalamhls/live.m3u8
#EXTINF:-1 tvg-id="",Race Central TV (720p) [Not 24/7]
https://nrpus.bozztv.com/36bay2/gusa-racecentral/index.m3u8
#EXTINF:-1 tvg-id="Racingcom.au",Racing.com (720p)
@ -99,15 +83,11 @@ https://skylivetab-new.akamaized.net/hls/live/2038780/sky1/index.m3u8
https://skylivetab-new.akamaized.net/hls/live/2038781/sky2/index.m3u8
#EXTINF:-1 tvg-id="SkyThoroughbredCentral.au",Sky Thoroughbred Central (720p) [Geo-blocked]
https://skylivetab-new.akamaized.net/hls/live/2038782/stcsd/index.m3u8
#EXTINF:-1 tvg-id="tickerNews.au",Ticker News (1080p)
https://cdn-uw2-prod.tsv2.amagi.tv/linear/amg01486-tickernews-tickernewsweb-ono/playlist.m3u8
#EXTINF:-1 tvg-id="",Travel & Food TV (720p)
https://nrpus.bozztv.com/36bay2/gusa-moviemagictv/index.m3u8
#EXTINF:-1 tvg-id="TVSN.au",TVSN (1080p)
https://tvsnhlslivetest.akamaized.net/hls/live/2034711/TVSN-MSL4/master.m3u8
#EXTINF:-1 tvg-id="TVSNBeauty.au",TVSN Beauty (1080p)
https://live-tvsn.simplestreamcdn.com/live12/tvsnbeauty/bitrate1.isml/.m3u8
#EXTINF:-1 tvg-id="",TVSN Catchup TV (1080p)
https://tvsnshowsvod.akamaized.net/CatchUpTV/TVSN-AU/2411171630/TVSN_2411171630.m3u8
#EXTINF:-1 tvg-id="TVSNJewellery.au",TVSN Jewellery (1080p)
https://live-tvsn.simplestreamcdn.com/live13/tvsnjewellery/bitrate1.isml/.m3u8

View file

@ -1,6 +1,4 @@
#EXTM3U
#EXTINF:-1 tvg-id="EuronewsEnglish.fr",Euronews English (720p)
https://euronews-euronews-world-1-au.samsung.wurl.tv/manifest/playlist.m3u8
#EXTINF:-1 tvg-id="HorseCountryTV.uk",Horse and Country (720p)
https://hncfree-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="InsightTV.nl",Insight TV (720p)
@ -11,18 +9,12 @@ https://introuble-samsungau.amagi.tv/playlist.m3u8
https://inwild-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="InWonder.nl",InWonder (720p)
https://inwonder-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="RealFamilies.au",Real Families (Australia) (720p)
https://lds-realfamilies-samsunguau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="RealStories.uk",Real Stories (720p)
https://lds-realstories-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="Rialto.nz",Rialto (1080p)
https://rialto-rialto-samsungaustralia.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="RyanandFriends.us",Ryan and Friends (1080p)
https://ryanandfriends-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="Tastemade.au",Tastemade Australia (1080p)
https://tmint-aus-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="Timeline.us",Time Line Australia (720p)
https://lds-timeline-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="TraceSportStars.fr",Trace Sport Stars (Australia) (1080p)
https://lightning-tracesport-samsungau.amagi.tv/playlist.m3u8
#EXTINF:-1 tvg-id="TraceUrban.fr",Trace Urban (Australia) (1080p)

View file

@ -3,14 +3,10 @@
https://cdn01.setar.aw/Canal49/canal49/playlist.m3u8
#EXTINF:-1 tvg-id="ArubaTVPlus.aw",ArubaTV + (1080p)
https://livertmptwo.com:19360/atvplusrelay/atvplusrelay.m3u8
#EXTINF:-1 tvg-id="BalchiTV.aw",Balchi TV (720p)
https://livertmptwo.com:19360/balchirelaytv/balchirelaytv.m3u8
#EXTINF:-1 tvg-id="CoolFM989.aw",Cool FM 98.9 (720p)
https://live2.tensila.com/cool-v-1.arubara/hls/master.m3u8
#EXTINF:-1 tvg-id="",Dushi TV (720p)
https://livertmptwo.com:19360/dushitvrelay/dushitvrelay.m3u8
#EXTINF:-1 tvg-id="HeartRadioAruba.aw",Heart Radio Aruba (720p) [Not 24/7]
https://live2.tensila.com/heart-v-1.heartar/hls/live/mystream.m3u8
#EXTINF:-1 tvg-id="Hit94FM.aw",Hit 94 FM (720p)
https://565280.gvideo.io/cmaf/565280_2069313/master.m3u8
#EXTINF:-1 tvg-id="NosIslaTV.aw" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36",Nos Isla TV (1080p) [Not 24/7]
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
https://backend-server-dot-telearuba-app.appspot.com/media/livestream23/playlist.m3u8
@ -25,3 +21,6 @@ https://backend-server-dot-telearuba-app.appspot.com/media/livestream13/playlist
https://cdn01.setar.aw/Telearuba/telearuba/playlist.m3u8
#EXTINF:-1 tvg-id="VIPTV.aw",VIP TV (720p)
https://ed5ov1.live.opencaster.com/bkyqeDgfaukC/index.m3u8
#EXTINF:-1 tvg-id="X1027FM.aw" http-referrer="https://player.castr.com/live_21e811c0d60d11eeaa1a471c2c967e4a",X 102.7 FM (720p) [Not 24/7]
#EXTVLCOPT:http-referrer=https://player.castr.com/live_21e811c0d60d11eeaa1a471c2c967e4a
https://stream.castr.com/65dee3aad6beacddbd6cd1af/live_21e811c0d60d11eeaa1a471c2c967e4a/index.m3u8

View file

@ -35,8 +35,6 @@ https://raw.githubusercontent.com/UzunMuhalefet/streams/refs/heads/main/myvideo-
https://str.yodacdn.net/medeniyyet/index.m3u8
#EXTINF:-1 tvg-id="",MTV TV
https://raw.githubusercontent.com/UzunMuhalefet/streams/refs/heads/main/myvideo-az/mtv-azerbaycan.m3u8
#EXTINF:-1 tvg-id="ShowPlusTV.az",Show Plus TV (720p)
https://glb.bozztv.com/glb/ssh101/showplus/index.m3u8
#EXTINF:-1 tvg-id="SpaceTV.az",Space TV
https://raw.githubusercontent.com/UzunMuhalefet/streams/main/myvideo-az/space-tv.m3u8
#EXTINF:-1 tvg-id="",TMB TV

View file

@ -1,8 +1,6 @@
#EXTM3U
#EXTINF:-1 tvg-id="AlJazeeraBalkans.ba",Al Jazeera Balkans (1080p)
https://live-hls-apps-ajb-v3-fa.getaj.net/AJB/index.m3u8
#EXTINF:-1 tvg-id="B1TV.ba",B1 TV (1080p) [Not 24/7]
http://wowza.bihnet.net:88/hls/b1-live.m3u8
#EXTINF:-1 tvg-id="BHRT.ba",BHRT (720p) [Geo-blocked]
https://bhrtstream.bhtelecom.ba/bhrtportal.m3u8
#EXTINF:-1 tvg-id="BHRT.ba",BHRT (270p) [Geo-blocked]
@ -25,8 +23,6 @@ http://glasdrine.cutuk.net:8081/433ssdsw/GlasDrineSD/playlist.m3u8
https://prd-hometv-live-open.spectar.tv/ERO_1_083/playlist.m3u8
#EXTINF:-1 tvg-id="RTVZenica.ba",RTV Zenica (720p)
https://stream.rtvze.ba/live/123/123.m3u8
#EXTINF:-1 tvg-id="SevdahTV.ba",Sevdah TV (288p)
https://restreamer2.tnt.ba/hls/stream.m3u8
#EXTINF:-1 tvg-id="SuperTV.ba",Super TV Media (720p)
https://mirtv.club/live/mirtv/index.m3u8
#EXTINF:-1 tvg-id="Televizija5.ba",Televizija 5 (576p)
@ -37,3 +33,5 @@ https://live.tv-m.net/hls/stream.m3u8
https://restreamer1.tnt.ba/hls/tntkids.m3u8
#EXTINF:-1 tvg-id="TVSlonExtra.ba",TV Slon Extra (1080p) [Not 24/7]
http://31.47.0.130:8082
#EXTINF:-1 tvg-id="NTVICKakanj.ba",NTV IC Kakanj (720p)
https://lon.rtsp.me/dEqnY-myGj84bKrieCIPfA/1743271667/hls/3dH3YAD6.m3u8

View file

@ -11,14 +11,10 @@ https://www.btvlive.gov.bd/streams/ef8b8bbc-98b7-4ba7-a49d-a0adaf259d35/ES/d96eb
https://amigofx.com:1936/channelsreporter/channelsreporter/playlist.m3u8
#EXTINF:-1 tvg-id="DeshiTV.ca",Deshi TV (720p)
https://deshitv.deshitv24.net/live/myStream/playlist.m3u8
#EXTINF:-1 tvg-id="ETenTV.bd",E Ten TV (1080p) [Not 24/7]
https://iptvbd.live/test/1080.m3u8
#EXTINF:-1 tvg-id="EkusheyTV.bd",Ekushey TV (480p)
https://ekusheyserver.com/etvlivesn.m3u8
#EXTINF:-1 tvg-id="JamunaTV.bd",Jamuna TV (720p) [Geo-blocked]
http://113.212.111.246:8080/hls/col12.m3u8
#EXTINF:-1 tvg-id="",JaTV (720p)
https://cloud2.smartsolbd.com/live/jatvbd/index.m3u8
#EXTINF:-1 tvg-id="ProbashiTVNews.ca",Probashi TV News (720p)
http://probashi.alvegroups.com:8081/probashitv/probashi/playlist.m3u8
#EXTINF:-1 tvg-id="SangsadTV.bd",Sangsad TV (1080p)

View file

@ -7,32 +7,24 @@ https://live.zendzend.com/streams/29375_107244/playlist.m3u8
https://bel-live-hls.akamaized.net/hls/live/2038650/BEL-Live-HLS/master.m3u8
#EXTINF:-1 tvg-id="BAMTV.be",Bel'Afrika Media TV (1080p)
https://goccn.cloud/hls/belafrikatv/index.m3u8
#EXTINF:-1 tvg-id="BelgianFederalParliament.be",Belgian Federal Parliament (720p) [Not 24/7]
http://livestream.parolis.be:1935/live/PLN_NL/playlist.m3u8
#EXTINF:-1 tvg-id="Bouke.be",Bouke [Geo-blocked]
https://tvlocales-live.freecaster.com/live/95d2f70d-9229-478b-9aed-bc4fa220316d/95d2f70d-9229-478b-9aed-bc4fa220316d.isml/master.m3u8
#EXTINF:-1 tvg-id="BX1.be",BX1 (720p) [Not 24/7]
https://59959724487e3.streamlock.net/stream/live/playlist.m3u8
#EXTINF:-1 tvg-id="CanalZoom.be",Canal Zoom [Geo-blocked]
https://tvlocales-live.freecaster.com/live/95d2e3af-5ab8-45a9-9dc9-f544d006b5d5/95d2e3af-5ab8-45a9-9dc9-f544d006b5d5.isml/master.m3u8
#EXTINF:-1 tvg-id="CityMusicTV.be",City Music TV (720p)
https://5592f056abba8.streamlock.net/citytv/citytv/playlist.m3u8
#EXTINF:-1 tvg-id="EbS.be",EbS (1080p)
https://streams.prd.commavservices.eu/live/ebs/index.m3u8
#EXTINF:-1 tvg-id="EbSPlus.be",EbS+ (1080p)
https://streams.prd.commavservices.eu/live/ebsplus/index.m3u8
#EXTINF:-1 tvg-id="FunVision.be",Fun Radio Vision (720p) [Not 24/7]
https://raw.githubusercontent.com/Sphinxroot/HSL/main/DM/be/FunRadio.m3u8
#EXTINF:-1 tvg-id="HLNLive.be",HLN Live (720p)
https://dpg-eventstreams.akamaized.net/hlnlivesrt-xmr/streamx/hlnlivesrt_720p.m3u8
#EXTINF:-1 tvg-id="JapanimTV.be",Japanim TV (1080p)
https://foxkidstv.be:3369/stream/play.m3u8
#EXTINF:-1 tvg-id="JoeFM.be",Joe FM (720p) [Not 24/7]
https://dpp-streamlive-plain.medialaancdn.be/joe_kijklive/plain/hls_hd.m3u8
#EXTINF:-1 tvg-id="KetnetJunior.be",Ketnet Junior (720p)
https://content.uplynk.com/channel/e11a05356cc44198977436418ad71832.m3u8
#EXTINF:-1 tvg-id="KetnetJunior.be",Ketnet Junior (720p)
https://content.uplynk.com/channel/e11a05356cc44198977436418ad71832.mpd
#EXTINF:-1 tvg-id="LaUne.be",La Une (1080p)
http://41.205.93.154/LA-UNE/mpegts
#EXTINF:-1 tvg-id="LN24.be",LN24
https://live-ln24.digiteka.com/1911668011/index.m3u8
#EXTINF:-1 tvg-id="Matele.be",MaTele (1080p) [Not 24/7]
@ -47,10 +39,6 @@ https://streaming01.divercom.be/notele_live/direct.stream/playlist.m3u8
https://live-video.dpgmedia.net/f1d26a28c95485cc/out/v1/5f60a245c110454fba652900ecf30ea2/index.m3u8
#EXTINF:-1 tvg-id="RadioContact.be",Radio Contact (1080p)
https://contact-live-hls.akamaized.net/hls/live/2038650/CONTACT-Live-HLS/master.m3u8
#EXTINF:-1 tvg-id="RadioPROS.be",Radio PROS (720p) [Not 24/7]
http://highvolume04.streampartner.nl/radiopros/livestream/playlist.m3u8
#EXTINF:-1 tvg-id="RadioPROS.be",Radio PROS (720p) [Not 24/7]
https://558bd16067b67.streamlock.net/radiopros/livestream/playlist.m3u8
#EXTINF:-1 tvg-id="",RTC Télé Liège [Geo-blocked]
https://tvlocales-live.freecaster.com/live/95d2f6eb-6f01-4d1d-8543-d14966de7b04/95d2f6eb-6f01-4d1d-8543-d14966de7b04.isml/master.m3u8
#EXTINF:-1 tvg-id="RTLTVI.be",RTL-TVI (1080p) [Not 24/7]
@ -77,5 +65,3 @@ https://live-radio-cf-vrt.akamaized.net/groupb/live/0f394a26-c87d-475e-8590-e9c6
https://dpp-live-events.medialaancdn.be/events/hls/aes/webstream1.m3u8
#EXTINF:-1 tvg-id="VTM2.be",VTM 2 (720p)
https://dpp-live-events.medialaancdn.be/events/hls/aes/webstream3.m3u8
#EXTINF:-1 tvg-id="LaUne.be",La Une (1080p)
http://41.205.93.154/LA-UNE/mpegts

View file

@ -1,13 +1,5 @@
#EXTM3U
#EXTINF:-1 tvg-id="AfricanewsFrench.fr",AfricaNews Français (720p)
https://rakuten-africanews-2-be.samsung.wurl.tv/manifest/playlist.m3u8
#EXTINF:-1 tvg-id="AFVFamily.us",AFV Family
https://futuretoday-afv-family-2-be.samsung.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="BloombergQuicktake.us",Bloomberg Quicktake
https://bloomberg-quicktake-1-be.samsung.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="BloombergTV.us",Bloomberg TV
https://bloomberg-bloomberg-1-be.samsung.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="EuronewsFrench.fr",Euronews
https://rakuten-euronews-10-be.samsung.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="RakutenTVFamilyMovies.fr",Rakuten Family
https://rakuten-family-16-be.samsung.wurl.tv/playlist.m3u8

View file

@ -5,20 +5,12 @@ https://ms4.sedemosmi.tv/live/M3E5ajhtdjJkaXBscmZubmUxMmh1cjN1bjZrbm5wZW8/index.
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="b1bbox.bg",B1B Box (720p)
https://e105-ts.cdn.bg/b1b/fls/b1btv.stream/playlist.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="CodeFashionTV.bg",Code Fashion TV (1080p)
https://cdn3.invivo.bg/Codefashion_5500/index.m3u8
#EXTINF:-1 tvg-id="CodeHealthTV.bg",Code Health TV (1080p)
https://cdn3.invivo.bg/codehealth_test/index.m3u8
#EXTINF:-1 tvg-id="DSTV.bg",DSTV (614p) [Not 24/7]
http://46.249.95.140:8081/hls/data.m3u8
#EXTINF:-1 tvg-id="EuroFolkTV.bg",EuroFolk TV (720p)
https://eurofolk.cdn.netbadgers.com/bg040/bg041/bg041.m3u8
#EXTINF:-1 tvg-id="Eurocom.bg",Evrokom (360p)
https://live.ecomservice.bg/hls/stream.m3u8
#EXTINF:-1 tvg-id="HopeChannelBulgaria.bg",Hope Channel Bulgaria
@ -48,11 +40,7 @@ https://streamer103.neterra.tv/tiankov-orient/live.m3u8
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="TVDarts.bg",TV Darts (576p)
https://streamer103.neterra.tv/darts/live.m3u8
#EXTINF:-1 tvg-id="TVZagora.bg",TV Zagora (576p)
http://zagoratv.ddns.net:8080/tvzagora.m3u8
#EXTINF:-1 tvg-id="TVart.bg",TVart (1080p)
https://stream.osc.bg/tvart/Stream3/playlist.m3u8
#EXTINF:-1 tvg-id="TVNBulgaria.bg",TVN-Bulgaria (1080p)
https://obs.friendshipchurch.eu/tvn/mystream.m3u8

View file

@ -153,3 +153,9 @@ https://fl1004.bozztv.com/ssh101/zoytvsports4/index.m3u8
https://fl1004.bozztv.com/ssh101/zoytvsports5/index.m3u8
#EXTINF:-1 tvg-id="ZoyTVTurcas.bo",Zoy TV Turcas
https://fl1004.bozztv.com/ssh101/zoytvturcas/index.m3u8
#EXTINF:-1 tvg-id="BoliviaTV.bo",Bolivia TV (720p)
https://5fe2654d6127d.streamlock.net:443/boliviatv/videoboliviatv/playlist.m3u8
#EXTINF:-1 tvg-id="ZoyTVSports1.bo",Zoy TV Sports 1 (1080p)
https://ssh101stream.ssh101.com/akamaissh101/ssh101/zoytvsports/playlist.m3u8
#EXTINF:-1 tvg-id="ZoyTVTurcas.bo",Zoy TV Turcas (720p)
https://ssh101stream.ssh101.com/akamaissh101/ssh101/zoytvturcas/playlist.m3u8

View file

@ -9,3 +9,5 @@ https://sincerecloud.stream/loadbalancer/public/actMdyoE.m3u8
https://media.streambrothers.com:1936/8014/8014/playlist.m3u8
#EXTINF:-1 tvg-id="NosTVBonaire.bq",Nos TV Bonaire (1080p)
http://streaming.flamingotv.net/nostv/live.m3u8
#EXTINF:-1 tvg-id="VozDiBonaireTV.bq",Voz Di Bonaire TV (720p)
https://tv.westream.cloud/VozdiBonaireTV/VozdiBonaireTV.m3u8

View file

@ -599,3 +599,11 @@ https://video01.kshost.com.br/seap8272/seap8272/playlist.m3u8
http://painelvj.com.br/tvaguaboa2/tvaguaboa2.sdp/playlist.m3u8
#EXTINF:-1 tvg-id="WTVBrasil.br",WTV Brasil (720p)
https://stmv1.srvstm.com/wtvbrasil/wtvbrasil/playlist.m3u8
#EXTINF:-1 tvg-id="TVCancaoNova.br",TV Cancao Nova (720p)
https://5c65286fc6ace.streamlock.net/cancaonova/CancaoNova.stream_720p/playlist.m3u8
#EXTINF:-1 tvg-id="TVMAX.br",TV MAX (720p)
https://5cf4a2c2512a2.streamlock.net/tvmax/tvmax/playlist.m3u8
#EXTINF:-1 tvg-id="TVBrasil.br",TV Brasil (720p)
https://tvbrasil-stream.ebc.com.br/index.m3u8
#EXTINF:-1 tvg-id="RedeTV.br",Rede TV! (720p)
https://cdn.jmvstream.com/w/AVJ-15235/playlist/playlist.m3u8

View file

@ -1 +1,7 @@
#EXTM3U
#EXTINF:-1 tvg-id="GuardianTalkRadio.bs",Guardian Talk Radio (1080p)
https://cdn-edge1.streamcomedia.com/abr_tngr969fm/abr-tngr969fm_streams/playlist.m3u8
#EXTINF:-1 tvg-id="IslandLuckTV.bs",Island Luck TV (1080p) [Geo-blocked]
https://islandluck-edge1.streamcomedia.com/abr_islandluck-ott/abr-islandluck-ott_streams/playlist.m3u8
#EXTINF:-1 tvg-id="TheParliamentaryChannel.bs",The Parliamentary Channel (720p) [Not 24/7]
https://zns-edge1.streamcomedia.cloud/abr_parliamentarychannel/abr-parliament_streams/playlist.m3u8

View file

@ -3,6 +3,8 @@
https://edge13.vedge.infomaniak.com/livecast/ik:alpen-wellelivestream/manifest.m3u8
#EXTINF:-1 tvg-id="AlpenlandTV.ch",Alpenland TV (720p)
https://edge14.vedge.infomaniak.com/livecast/ik:alpen-wellelivestream/playlist.m3u8
#EXTINF:-1 tvg-id="BlueSport2.ch",Blue Sport 2 (720p)
http://62.210.211.188:2095/play/a00f
#EXTINF:-1 tvg-id="Canal9.ch",Canal 9 en Français (1080p)
https://livehd.vedge.infomaniak.com/livecast/livehd/master.m3u8
#EXTINF:-1 tvg-id="CanalAlphaJura.ch",Canal Alpha Jura (1080p)
@ -77,5 +79,3 @@ https://livevideo.infomaniak.com/streaming/livecast/tvm3/playlist.m3u8
https://cdnapisec.kaltura.com/p/1719221/sp/171922100/playManifest/entryId/1_t5h46v64/format/applehttp/protocol/https/a.m3u8
#EXTINF:-1 tvg-id="WedoBigStories.ch",Wedo Big Stories (1080p)
https://weyyak-live.akamaized.net/wedo_big_stories/index.m3u8
#EXTINF:-1 tvg-id="BlueSport2.ch",Blue Sport 2 (720p)
http://62.210.211.188:2095/play/a00f

View file

@ -443,7 +443,7 @@ https://mdstrm.com/live-stream-playlist/6046495ddf98b007fa2fe807.m3u8
https://mediacpstreamchile.com:1936/8028/8028/playlist.m3u8
#EXTINF:-1 tvg-id="ZappingMusic.cl",Zapping Music (720p)
https://zmlive.zappingtv.com/zm-free/zm.smil/playlist.m3u8
#EXTINF:-1 tvg-id="ZonaPlayTV.cl",Zona Play TV (720p)
https://paneltv.online:1936/8100/8100/playlist.m3u8
#EXTINF:-1 tvg-id="ZonaLatina.cl",Zona Latina (480p)
http://190.2.212.209:8050/play/a0oj
#EXTINF:-1 tvg-id="ZonaPlayTV.cl",Zona Play TV (720p)
https://paneltv.online:1936/8100/8100/playlist.m3u8

View file

@ -1,4 +1,6 @@
#EXTM3U
#EXTINF:-1 tvg-id="AndoTV.cn",Ando TV
http://stream.qhbtv.com/adws/sd/live.m3u8
#EXTINF:-1 tvg-id="AndoTV.cn",Ando TV (576p)
http://119.1.122.186:4022/rtp/238.255.2.189:5999
#EXTINF:-1 tvg-id="AnimationShowChannel.cn",Animation Show Channel
@ -23,46 +25,10 @@ http://49.113.179.174:4022/udp/238.125.3.121:5140
http://gslbservzqhsw.itv.cmvideo.cn/index.m3u8?Contentid=reallive-hdcctv1&channel-id=ystenlive&livemode=1&stbId=3
#EXTINF:-1 tvg-id="CCTV1.cn",CCTV1 (576p)
http://117.161.133.51:81/gitv_live/G_CCTV-1/G_CCTV-1.m3u8
#EXTINF:-1 tvg-id="CCTV2.cn",CCTV2 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.102:10250
#EXTINF:-1 tvg-id="CCTV2.cn",CCTV2 (576p)
http://117.161.133.51:81/gitv_live/G_CCTV-2/G_CCTV-2.m3u8
#EXTINF:-1 tvg-id="CCTV3.cn",CCTV3 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.122:10370
#EXTINF:-1 tvg-id="",CCTV4 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.138:10466
#EXTINF:-1 tvg-id="CCTV5.cn",CCTV5 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.123:10376
#EXTINF:-1 tvg-id="CCTV5Plus.cn",CCTV5+ (1080p)
http://bl.dchwtq.asia:10000/rtp/239.254.96.234:9484
#EXTINF:-1 tvg-id="CCTV6.cn",CCTV6 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.124:10382
#EXTINF:-1 tvg-id="CCTV7.cn",CCTV7 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.103:10256
#EXTINF:-1 tvg-id="CCTV8.cn",CCTV8 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.125:10388
#EXTINF:-1 tvg-id="CCTV9.cn",CCTV9 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.104:10262
#EXTINF:-1 tvg-id="CCTV10.cn",CCTV10 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.105:10268
#EXTINF:-1 tvg-id="CCTV11.cn",CCTV11 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.154:10560
#EXTINF:-1 tvg-id="CCTV12.cn",CCTV12 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.106:10274
#EXTINF:-1 tvg-id="CCTV13.cn",CCTV13 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.254.96.161:9040
#EXTINF:-1 tvg-id="CCTV14.cn",CCTV14 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.107:10280
#EXTINF:-1 tvg-id="CCTV15.cn",CCTV15 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.155:10566
#EXTINF:-1 tvg-id="CCTV15.cn",CCTV15音乐
http://hwrr.jx.chinamobile.com:8080/PLTV/88888888/224/3221225641/index.m3u8
#EXTINF:-1 tvg-id="CCTV16.cn",CCTV16 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.247:11124
#EXTINF:-1 tvg-id="",CCTV16-4K (2160p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.249:11136
#EXTINF:-1 tvg-id="CCTV17.cn",CCTV17 (1080p)
http://bl.dchwtq.asia:10000/rtp/239.69.1.152:10548
#EXTINF:-1 tvg-id="",CCTV TV Guide (576p)
http://117.161.133.51:81/gitv_live/G_DIANSHIZN-CQ/G_DIANSHIZN-CQ.m3u8?p=GITV
#EXTINF:-1 tvg-id="CCTVWorldGeography.cn",CCTV 世界地理
@ -157,6 +123,8 @@ http://118.122.2.29:9999/hls/47/index.m3u8
http://1.183.141.194:8001/hls/55/index.m3u8
#EXTINF:-1 tvg-id="NeiMonggolTV.cn",Nei Monggol TV
http://49.113.179.174:4022/udp/238.125.7.93:5140
#EXTINF:-1 tvg-id="NeiMonggolTV.cn",Nei Monggol TV
http://110.19.156.172:9901/tsfile/live/1003_1.m3u8
#EXTINF:-1 tvg-id="NeiMonggolTV2MongolianCultureChannel.cn",Nei Monggol TV 2 Mongolian Culture Channel
http://1.183.141.194:8001/hls/54/index.m3u8
#EXTINF:-1 tvg-id="QTV1.cn",QTV-1
@ -227,6 +195,8 @@ http://49.113.179.174:4022/udp/238.125.7.153:5140
http://106.124.91.222:85/tsfile/live/21220_1.m3u8?authid=0&key=txiptv&playlive=1
#EXTINF:-1 tvg-id="XinjiangTV12.cn",Xinjiang TV 12
http://49.113.179.174:4022/udp/238.125.3.185:5140
#EXTINF:-1 tvg-id="XizangTVChinese.cn",Xizang TV Chinese
http://php.jdshipin.com/xztv.php?id=ws
#EXTINF:-1 tvg-id="XizangTVTibetan.cn",Xizang TV Tibetan
http://49.113.179.174:4022/udp/238.125.3.94:5140
#EXTINF:-1 tvg-id="XizangTVTibetan.cn",Xizang TV Tibetan
@ -1565,7 +1535,3 @@ http://yslk.chinashadt.com:1635/live/stream:di1.stream/playlist.m3u8
http://yslk.chinashadt.com:1635/live/stream:di2.stream/playlist.m3u8
#EXTINF:-1 tvg-id="",龙岩综合 (540p)
http://stream.lytv.net.cn/2/sd/live.m3u8
#EXTINF:-1 tvg-id="AndoTV.cn",Ando TV
http://stream.qhbtv.com/adws/sd/live.m3u8
#EXTINF:-1 tvg-id="XizangTVChinese.cn",Xizang TV Chinese
http://php.jdshipin.com/xztv.php?id=ws

View file

@ -65,6 +65,8 @@ https://canaldos.internetinalambrico.com.co:1936/live/canal2.stream/playlist.m3u
https://glb.bozztv.com/glb/ssh101/infotv01/playlist.m3u8
#EXTINF:-1 tvg-id="CanalInstitucional.co",Canal Institucional (720p) [Not 24/7]
https://streaming.rtvc.gov.co/TV_CanalInstitucional_live/smil:live.smil/playlist.m3u8
#EXTINF:-1 tvg-id="CanalInstitucional.co",Canal Institucional (480p)
http://190.2.212.209:8050/play/a0lw
#EXTINF:-1 tvg-id="CanalMasTelevision.co",Canal Más Televisión (720p)
https://movil.ejeserver.com/live/teledoradahd.m3u8
#EXTINF:-1 tvg-id="CanalMasTelevision.co",Canal Más Televisión (720p)
@ -81,6 +83,8 @@ https://video.ejeserver.com/live/nets.m3u8
https://canal.mediaserver.com.co/live/oracionconson.m3u8
#EXTINF:-1 tvg-id="CanalPyC.co",Canal PyC (480p) [Not 24/7]
https://glb.bozztv.com/glb/ssh101/pyctelevision/index.m3u8
#EXTINF:-1 tvg-id="CanalRCN.co",Canal RCN (480p)
http://190.2.212.209:8050/play/a0lt
#EXTINF:-1 tvg-id="CanalRegionalFTV.co",Canal Regional FTV (720p) [Not 24/7]
https://tvlatina.live:1936/8024/8024/playlist.m3u8
#EXTINF:-1 tvg-id="CanalSantaMartaTV.co",Canal Santa Marta TV (720p) [Not 24/7]
@ -92,6 +96,8 @@ https://play.amelbasoluciones.co:3976/live/telepalmartvlive.m3u8
#EXTINF:-1 tvg-id="CanalTRO.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Canal TRO (1080p)
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/canaltro2live/smil:live.smil/playlist.m3u8
#EXTINF:-1 tvg-id="CanalTRO.co",Canal TRO (480p)
http://190.2.212.209:8050/play/a0m5
#EXTINF:-1 tvg-id="CanalTROPlus.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Canal TRO Plus (1080p) [Geo-blocked]
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/canaltro2live/smil:troplus.smil/playlist.m3u8
@ -196,6 +202,8 @@ https://xhateaec.com/livestreams/19.crKOSL8FRzpid0MA.m3u8
https://stmv4.voxtvhd.com.br/psctv/psctv/playlist.m3u8
#EXTINF:-1 tvg-id="",PyC Televisión (720p) [Not 24/7]
https://ssh101-fl.bozztv.com/ssh101/pyctelevision/playlist.m3u8
#EXTINF:-1 tvg-id="RCNNovelas.co",RCN Novelas (480p)
http://190.2.212.209:8050/play/a0ox
#EXTINF:-1 tvg-id="RCNXtra.co",RCN Xtra (1080p)
https://latv-rcn-xtra-1-mx.tcl.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="RDMTelevision.co",RDM Televisión (720p) [Not 24/7]
@ -212,6 +220,8 @@ https://tvlatina.live:1936/8004/8004/playlist.m3u8
https://server.asilivehd.com:3802/live/canal4live.m3u8
#EXTINF:-1 tvg-id="SenalColombia.co",Señal Colombia (1080p)
https://streaming.rtvc.gov.co/TV_Senal_Colombia_live/smil:live.smil/playlist.m3u8
#EXTINF:-1 tvg-id="SinLimites.co",Sin Limites (480p)
http://190.2.212.209:8050/play/a0pa
#EXTINF:-1 tvg-id="SuramTV.co",Suram TV (1080p)
https://livetv.305streamhd.com:3111/live/suramtvlive.m3u8
#EXTINF:-1 tvg-id="TamesisTeVe.co",Támesis TeVe (614p) [Not 24/7]
@ -228,18 +238,24 @@ https://video.ejeserver.com/live/telesanjacinto.m3u8
#EXTINF:-1 tvg-id="TeleVid.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Tele Vid (1080p)
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/televidtvlive/smil:dvrlive.smil/playlist.m3u8?DVR=
#EXTINF:-1 tvg-id="Teleantioquia.co",Teleantioquia (480p)
http://190.2.212.209:8050/play/a0n1
#EXTINF:-1 tvg-id="Teleantioquia.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Teleantioquia (360p) [Not 24/7]
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/teleantioquialive/smil:dvrlive.smil/playlist.m3u8
#EXTINF:-1 tvg-id="Teleantioquia2.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Teleantioquia 2 (720p)
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/teleantioquialive/smil:live.smil/playlist.m3u8?DVR=
#EXTINF:-1 tvg-id="Telecafe.co",Telecafe (480p)
http://190.2.212.209:8050/play/a0ne
#EXTINF:-1 tvg-id="Telecafe.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Telecafé (720p)
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/telecafelive/smil:dvrlive.smil/playlist.m3u8
#EXTINF:-1 tvg-id="Telecaribe.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Telecaribe (720p)
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/telecaribetvlive/smil:rtmp01.smil/playlist.m3u8
#EXTINF:-1 tvg-id="Telecaribe.co",Telecaribe (480p)
http://190.2.212.209:8050/play/a0nc
#EXTINF:-1 tvg-id="TelecaribePlus.co" http-user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160",Telecaribe Plus (720p)
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36 CrKey/1.44.191160
https://liveingesta118.cdnmedia.tv/telecaribetvlive/smil:rtmp02.smil/playlist.m3u8
@ -247,10 +263,14 @@ https://liveingesta118.cdnmedia.tv/telecaribetvlive/smil:rtmp02.smil/playlist.m3
https://cp.panelchs.com:1936/8094/8094/playlist.m3u8
#EXTINF:-1 tvg-id="Teleislas.co",Teleislas (486p) [Not 24/7]
https://5ab772334c39c.streamlock.net/live-teleislas/teleislas/playlist.m3u8
#EXTINF:-1 tvg-id="Teleislas.co",Teleislas (480p)
http://190.2.212.209:8050/play/a0m6
#EXTINF:-1 tvg-id="TelemusicaTV.co",Telemúsica TV (540p) [Geo-blocked]
https://canal.mediaserver.com.co/live/telemusica.m3u8
#EXTINF:-1 tvg-id="TelenetTelevision.co",Telenet Televisión (478p)
https://cp.panelchs.com:1936/8058/8058/playlist.m3u8
#EXTINF:-1 tvg-id="Telepacifico.co",Telepacifico (480p)
http://190.2.212.209:8050/play/a0n3
#EXTINF:-1 tvg-id="Telepacifico.co",Telepacífico (1080p) [Not 24/7]
https://stream.logicideas.media/telepacifico-live/smil:live.smil/playlist.m3u8
#EXTINF:-1 tvg-id="Telepasto.co",Telepasto (360p) [Geo-blocked]
@ -263,6 +283,8 @@ https://cp.panelchs.com:1936/8060/8060/playlist.m3u8
https://stream.logicideas.media/canaltrece-live/smil:live.smil/playlist.m3u8
#EXTINF:-1 tvg-id="TrecePlus.co",Trece + (720p)
https://stream.logicideas.media/canaltreceplus-live/smil:live1plus.smil/playlist.m3u8
#EXTINF:-1 tvg-id="TrecePlus.co",Trece+ (480p)
http://190.2.212.209:8050/play/a0nf
#EXTINF:-1 tvg-id="TropicalTV.co",Tropical TV (480p) [Not 24/7]
https://rpn3.bozztv.com/ssh101/ssh101/estvco/playlist.m3u8
#EXTINF:-1 tvg-id="TuKanal.co",Tu Kanal (1080p)
@ -293,30 +315,8 @@ https://video.ejeserver.com/live/veotv.m3u8
https://eu1.servers10.com:8081/vidanuevatv/index.m3u8
#EXTINF:-1 tvg-id="ViveTV.co",Vive TV Colombia (1080p)
http://192.144.113.132:1935/live/ViveTV/playlist.m3u8
#EXTINF:-1 tvg-id="WinSports.co",Win Sports (480p)
http://190.2.212.209:8050/play/a0n2
#EXTINF:-1 tvg-id="Zoom.co" http-referrer="https://canalzoom.org/senal-en-vivo",Zoom (1080p)
#EXTVLCOPT:http-referrer=https://canalzoom.org/senal-en-vivo
https://canalzoom.smoothcloud.co:3027/live/canalzoombr1live.m3u8
#EXTINF:-1 tvg-id="CanalRCN.co",Canal RCN (480p)
http://190.2.212.209:8050/play/a0lt
#EXTINF:-1 tvg-id="WinSports.co",Win Sports (480p)
http://190.2.212.209:8050/play/a0n2
#EXTINF:-1 tvg-id="CanalInstitucional.co",Canal Institucional (480p)
http://190.2.212.209:8050/play/a0lw
#EXTINF:-1 tvg-id="RCNNovelas.co",RCN Novelas (480p)
http://190.2.212.209:8050/play/a0ox
#EXTINF:-1 tvg-id="SinLimites.co",Sin Limites (480p)
http://190.2.212.209:8050/play/a0pa
#EXTINF:-1 tvg-id="CanalTRO.co",Canal TRO (480p)
http://190.2.212.209:8050/play/a0m5
#EXTINF:-1 tvg-id="Teleantioquia.co",Teleantioquia (480p)
http://190.2.212.209:8050/play/a0n1
#EXTINF:-1 tvg-id="Telecafe.co",Telecafe (480p)
http://190.2.212.209:8050/play/a0ne
#EXTINF:-1 tvg-id="Telecaribe.co",Telecaribe (480p)
http://190.2.212.209:8050/play/a0nc
#EXTINF:-1 tvg-id="Teleislas.co",Teleislas (480p)
http://190.2.212.209:8050/play/a0m6
#EXTINF:-1 tvg-id="Telepacifico.co",Telepacifico (480p)
http://190.2.212.209:8050/play/a0n3
#EXTINF:-1 tvg-id="TrecePlus.co",Trece+ (480p)
http://190.2.212.209:8050/play/a0nf

View file

@ -36,6 +36,10 @@ https://sc-kuzeykibrissmarttv.ercdn.net/kanalt/bantp1/playlist.m3u8
https://sc-kuzeykibrissmarttv.ercdn.net/kibristv/bant1/playlist.m3u8
#EXTINF:-1 tvg-id="OmegaChannel.cy",Omega Channel (1080p)
http://l1.cloudskep.com/tst/omcy/playlist.m3u8
#EXTINF:-1 tvg-id="OMONOIATV.cy",OMONOIA TV (684p)
http://62.233.57.226:8001/play/a00b00
#EXTINF:-1 tvg-id="OneChannelCyprus.cy",One Channel Cyprus (576p)
http://62.210.211.188:2095/play/a00e
#EXTINF:-1 tvg-id="RIK1.cy",RIK 1
http://l6.cloudskep.com/tvb6/rik1-1/mpeg.2ts
#EXTINF:-1 tvg-id="RIK2.cy",RIK 2
@ -60,7 +64,3 @@ https://sc-kuzeykibrissmarttv.ercdn.net/tv2020/bantp1/playlist.m3u8
https://dev.aftermind.xyz/edge-hls/unitrust/voulitv/index.m3u8?token=8TXWzhY3h6jrzqEqx
#EXTINF:-1 tvg-id="VouliTV.cy",Vouli TV (1080p) [Not 24/7]
https://dev.aftermind.xyz/hls/unitrust/voulitv/index.m3u8?token=8TXWzhY3h6jrzqEqx
#EXTINF:-1 tvg-id="OMONOIATV.cy",OMONOIA TV (684p)
http://62.233.57.226:8001/play/a00b00
#EXTINF:-1 tvg-id="OneChannelCyprus.cy",One Channel Cyprus (576p)
http://62.210.211.188:2095/play/a00e

View file

@ -3,8 +3,6 @@
https://123tv-mx1.flex-cdn.net/index.m3u8
#EXTINF:-1 tvg-id="3sat.de",3sat (720p) [Geo-blocked]
https://zdf-hls-18.akamaized.net/hls/live/2016501/dach/high/master.m3u8
#EXTINF:-1 tvg-id="AlexBerlin.de",Alex Berlin (1080p) [Not 24/7]
https://alex-stream.rosebud-media.de/live/alexlivetv40.smil/playlist.m3u8
#EXTINF:-1 tvg-id="AllgauTV.de",Allgäu TV (1080p)
https://stream01.welocal.stream/stream/fhd-allgaeutv_25679/ngrp:stream_all/playlist.m3u8
#EXTINF:-1 tvg-id="AltenburgTV.de",Altenburg TV (1080p)
@ -197,6 +195,8 @@ https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_nds/master.m3u8
https://mcdn.ndr.de/ndr/hls/ndr_fs/ndr_sh/master.m3u8
#EXTINF:-1 tvg-id="Nickelodeon.de",Nick Germany (1080p) [Geo-blocked]
https://0d26a00dfbb1.airspace-cdn.cbsivideo.com/nick1999/master/nick1999.m3u8
#EXTINF:-1 tvg-id="Nickelodeon.de",Nickelodeon
https://ma.anixa.tv/clips/stream/nickelodeon/playlist.php
#EXTINF:-1 tvg-id="Nickelodeon.de",Nickelodeon Deutschland [Geo-blocked]
https://unilivemtveu-lh.akamaihd.net/i/nickde_1@448749/master.m3u8
#EXTINF:-1 tvg-id="NiederbayernTV.de",Niederbayern TV (720p)
@ -214,13 +214,7 @@ https://hls1.wtnet.de/noa4hh/apple/wifi6500.m3u8
#EXTINF:-1 tvg-id="noa4Norderstedt.de",Noa 4 Norderstedt (1080p)
https://hls1.wtnet.de/noa4/apple/wifi6500.m3u8
#EXTINF:-1 tvg-id="NRWision.de",NRWision (1080p)
https://fms.nrwision.de/live/livestreamHD.stream/playlist.m3u8
#EXTINF:-1 tvg-id="NRWision.de",NRWISION (1080p)
https://fms.nrwision.de/live/livestreamHD.stream_source/playlist.m3u8
#EXTINF:-1 tvg-id="NRWision.de",NRWision (720p)
https://fms.nrwision.de/live/livestreamHD.stream_1080p/playlist.m3u8
#EXTINF:-1 tvg-id="NRWision.de",NRWision (360p)
https://fms.nrwision.de/live/livestreamHD.stream_360p/playlist.m3u8
https://fms.nrwision.de/live/ngrp:livestreamHD.stream/playlist.m3u8
#EXTINF:-1 tvg-id="OberpfalzTV.de",Oberpfalz TV (1080p)
https://oberpfalztv.iptv-playoutcenter.de/oberpfalztv/oberpfalztv.stream_1/playlist.m3u8
#EXTINF:-1 tvg-id="Oeins.de",oeins (Oldenburg) (1080p) [Not 24/7]
@ -371,17 +365,12 @@ https://live.creacast.com/rockland-radio/smil:rockland-radio.smil/playlist.m3u8
https://rt-ger.rttv.com/dvr/rtdeutsch/playlist.m3u8
#EXTINF:-1 tvg-id="RTDE.de",RT DE (1080p) [Not 24/7]
https://rt-ger.rttv.com/live/rtdeutsch/playlist.m3u8
#EXTINF:-1 tvg-id="RTL.de",RTL (576p)
https://s6.hopslan.com/rtlc1/tracks-v1a1/mono.m3u8
#EXTINF:-1 tvg-id="RTL.de",RTL (Germany) (576p)
http://178.219.128.68:64888/RTL
#EXTINF:-1 tvg-id="RTLSuper.de",RTL Super (576p)
http://178.219.128.68:64888/SUPERTL
#EXTINF:-1 tvg-id="RTLZwei.de",RTL Zwei (1080p)
http://178.219.128.68:64888/RTL2
#EXTINF:-1 tvg-id="RTLZwei.de" http-referrer="https://www.2ix2.com/rtl2-live/",RTL Zwei (576p)
#EXTVLCOPT:http-referrer=https://www.2ix2.com/rtl2-live/
https://s6.hopslan.com/rtl2x1/index.m3u8
#EXTINF:-1 tvg-id="SaarlandFernsehen1.de",Saarland Fernsehen 1 (1080p)
https://saarland1.iptv-playoutcenter.de/saarland1/saarland1.stream_1/playlist.m3u8
#EXTINF:-1 tvg-id="SaarlandFernsehen2.de",Saarland Fernsehen 2 (720p) [Not 24/7]
@ -492,6 +481,8 @@ https://wdrlokalzeit.akamaized.net/hls/live/2018025-b/wdrlz_muensterland/master.
https://wdrlokalzeit.akamaized.net/hls/live/2018020-b/wdrlz_siegen/master.m3u8
#EXTINF:-1 tvg-id="WDRFernsehenWuppertal.de",WDR Fernsehen Wuppertal (720p) [Geo-blocked]
https://wdrlokalzeit.akamaized.net/hls/live/2018028-b/wdrlz_wuppertal/master.m3u8
#EXTINF:-1 tvg-id="WELT.de",WELT
https://s6.hopslan.com/n24X/index.m3u8
#EXTINF:-1 tvg-id="WeltderWunderTV.de",Welt der Wunder TV (576p)
https://wdw.iptv-playoutcenter.de/wdw/wdw1/playlist.m3u8
#EXTINF:-1 tvg-id="Wir24TV.de",Wir24 TV (1080p) [Geo-blocked]
@ -510,7 +501,9 @@ https://zdf-hls-16.akamaized.net/hls/live/2016499/de/high/master.m3u8
https://ef56ef401101403a8b06f1dec29ef1eb.mediatailor.us-east-1.amazonaws.com/v1/master/44f73ba4d03e9607dcd9bebdcb8494d86964f1d8/Samsung-de_ZeeOne/playlist.m3u8
#EXTINF:-1 tvg-id="ZweiMusicTelevision.de",ZWEI2 Music (1080p)
https://cdne.folxplay.tv/folx-trz/streams/ch-2/master.m3u8
#EXTINF:-1 tvg-id="WELT.de",WELT
https://s6.hopslan.com/n24X/index.m3u8
#EXTINF:-1 tvg-id="Nickelodeon.de",Nickelodeon
https://ma.anixa.tv/clips/stream/nickelodeon/playlist.php
#EXTINF:-1 tvg-id="MCTV.de",MC TV (720p)
https://rrr.sz.xlcdn.com/?account=mceutv&file=mc2&type=live&service=wowza&protocol=https&output=playlist.m3u8
#EXTINF:-1 tvg-id="RFH.de",RFH (1080p)
https://h056.video-stream-hosting.de/medienasa-live/_definst_/mp4:RFH_high/index.m3u8
#EXTINF:-1 tvg-id="AlexBerlin.de",Alex Berlin (1080p)
https://alex-stream.rosebud-media.de/bounce/alexlivetv50.smil/index.m3u8

View file

@ -185,6 +185,8 @@ https://ss3.domint.net:3136/gtv_str/globalhd/playlist.m3u8
https://imagenuniversaltv.net:3820/live/guacaratvlive.m3u8
#EXTINF:-1 tvg-id="",Guaymate [Not 24/7]
https://5790d294af2dc.streamlock.net/8100/8100/playlist.m3u8
#EXTINF:-1 tvg-id="GuaymateTV.do",Guaymate TV (720p)
https://ssh101stream.ssh101.com/akamaissh101/ssh101/guaymatetv/playlist.m3u8
#EXTINF:-1 tvg-id="HainaVision.do",Haina Vision (720p)
https://cdn.streamingcpanel.com:3447/live/hainavisionlive.m3u8
#EXTINF:-1 tvg-id="HermanasMirabalTV.do",Hermanas Mirabal TV (720p) [Not 24/7]
@ -517,5 +519,3 @@ https://ss3.domint.net:3108/zol_str/vzol/playlist.m3u8
https://5790d294af2dc.streamlock.net/Zonavisiontv/Zonavisiontv/playlist.m3u8
#EXTINF:-1 tvg-id="ZTV.do",ZTV (720p) [Not 24/7]
https://lb00zdigital.streamprolive.com/mnt/hls/live.m3u8
#EXTINF:-1 tvg-id="GuaymateTV.do",Guaymate TV (720p)
https://ssh101stream.ssh101.com/akamaissh101/ssh101/guaymatetv/playlist.m3u8

View file

@ -130,8 +130,6 @@ https://ssh101-fl.bozztv.com/ssh101/scandalotv/index.m3u8
https://eu1.servers10.com:8081/8108/index.m3u8
#EXTINF:-1 tvg-id="SonoOndaTV.ec",Sono Onda TV (720p)
https://live.obslivestream.com/sonoondatv/index.m3u8
#EXTINF:-1 tvg-id="Teleamazonas.ec",Teleamazonas (1080p) [Geo-blocked]
https://teleamazonas-live.cdn.vustreams.com/live/0fc97608-6057-4db8-9af7-102c21ac18af/live.isml/0fc97608-6057-4db8-9af7-102c21ac18af.m3u8
#EXTINF:-1 tvg-id="Teledigital.ec",Teledigital (240p) [Not 24/7]
https://tv.portalexpress.es:3182/hybrid/play.m3u8
#EXTINF:-1 tvg-id="Telerama.ec",Telerama (240p) [Not 24/7]
@ -154,3 +152,5 @@ https://cloud37.ecuatel.com/vostv/live/manifest.m3u8
https://video2.makrodigital.com/wuanplus/wuanplus/playlist.m3u8
#EXTINF:-1 tvg-id="ZaracayTV.ec",Zaracay TV (1080p) [Not 24/7]
https://video2.makrodigital.com/zaracay/zaracay/playlist.m3u8
#EXTINF:-1 tvg-id="Teleamazonas.ec",Teleamazonas (1080p)
https://teleamazonas-live.cdn.vustreams.com/live/fd4ab346-b4e3-4628-abf0-b5a1bc192428/live.isml/playlist.m3u8

View file

@ -45,9 +45,13 @@ https://shls-masr2-ak.akamaized.net/out/v1/f683685242b549f48ea8a5171e3e993a/inde
https://nogoumtv.nrpstream.com/hls/stream.m3u8
#EXTINF:-1 tvg-id="PNCDrama.eg",PNC Drama (1080p)
https://d35j504z0x2vu2.cloudfront.net/v1/master/0bc8e8376bd8417a1b6761138aa41c26c7309312/pnc-drama/playlist.m3u8
#EXTINF:-1 tvg-id="TeN.eg",TeN (720p) [Geo-blocked]
https://weyyak-live.akamaized.net/weyyak_ten_tv/index.m3u8
#EXTINF:-1 tvg-id="TheKingdomSat.eg",The Kingdom Sat (720p)
https://bcovlive-a.akamaihd.net/0e524e1838ed411dad0a674d18e07914/eu-central-1/6415808954001/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="WatanTV.eg",Watan TV (1080p)
https://rp.tactivemedia.com/watantv_source/live/playlist.m3u8
#EXTINF:-1 tvg-id="TeN.eg",TeN (720p) [Geo-blocked]
https://weyyak-live.akamaized.net/weyyak_ten_tv/index.m3u8
#EXTINF:-1 tvg-id="RotanaCinemaEgypt.eg",Rotana Cinema Egypt (1080p)
https://rotana.hibridcdn.net/rotana/cinemamasr_net-7Y83PP5adWixDF93/playlist.m3u8
#EXTINF:-1 tvg-id="OnE.eg",On E (1080p)
https://bcovlive-a.akamaihd.net/3dc60bab470f4c9fbf00408ecb7c3d7a/eu-west-1/6057955906001/playlist_dvr.m3u8

View file

@ -52,10 +52,20 @@ https://cls.alcarria.tv/alcarriatv/livestream/playlist.m3u8
http://vegafibratv.com:8085/AMC/index.m3u8
#EXTINF:-1 tvg-id="Antena3.es",Antena 3 (720p)
http://185.189.225.150:85/Antena3HD/index.m3u8
#EXTINF:-1 tvg-id="AquiNoHayQuienViva.es",Aqui No Hay Quien Viva (720p)
https://fast-channels.atresmedia.com/648ef3951756b0e425af83cc/648ef3951756b0e425af83cc.m3u8
#EXTINF:-1 tvg-id="ArabiTV.es",Arabí TV (1080p)
https://streamtv2.elitecomunicacion.cloud:3956/live/arabitvlive.m3u8
#EXTINF:-1 tvg-id="AragonTV.es",Aragón TV (720p) [Not 24/7]
https://cartv.streaming.aranova.es/hls/live/aragontv_canal1.m3u8
#EXTINF:-1 tvg-id="AtresplayerClasicos.es",Atresplayer Clasicos (1080p)
https://fast-channels.atresmedia.com/648ef12c2bfab0e4507e0d61/648ef12c2bfab0e4507e0d61.m3u8
#EXTINF:-1 tvg-id="AtresplayerComedia.es",Atresplayer Comedia (1080p)
https://fast-channels.atresmedia.com/648ef23d2bfab0e4557e0d61/648ef23d2bfab0e4557e0d61.m3u8
#EXTINF:-1 tvg-id="AtresplayerInquietos.es",Atresplayer Inquietos (1080p)
https://fast-channels.atresmedia.com/648ef3162bfab0e4587e0d61/648ef3162bfab0e4587e0d61.m3u8
#EXTINF:-1 tvg-id="AtresplayerMulticine.es",Atresplayer Multicine (1080p)
https://fast-channels.atresmedia.com/648ef18c1756b0e41daf83cc/648ef18c1756b0e41daf83cc.m3u8
#EXTINF:-1 tvg-id="BabyTV.es",BabyTV (Spain) (1080p)
http://185.189.225.150:85/BabyTV/index.m3u8
#EXTINF:-1 tvg-id="BailenTV.es",Bailén TV (720p) [Not 24/7]
@ -69,6 +79,8 @@ https://cdnapisec.kaltura.com/p/2346171/sp/234617100/playManifest/entryId/1_n644
https://cdnapisec.kaltura.com/p/2346171/sp/234617100/playManifest/entryId/1_n6442jz0/format/applehttp/protocol/https/uiConfId/42816492/a.m3u8?referrer=aHR0cHM6Ly9iZXRldmUuY2F0
#EXTINF:-1 tvg-id="BiosferaTV.es",Biosfera TV (720p) [Not 24/7]
https://tvdatta.com:3021/live/biosferatvlive.m3u8
#EXTINF:-1 tvg-id="Boing.es",Boing
http://185.189.225.150:85/boing/index.m3u8
#EXTINF:-1 tvg-id="BomCine.es",Bom Cine (576p)
http://185.189.225.150:85/BOM/index.m3u8
#EXTINF:-1 tvg-id="BonDiaTV.es",Bon Dia TV (1080p)
@ -223,8 +235,12 @@ https://liveingesta318.cdnmedia.tv/9tvlive/smil:live.smil/playlist.m3u8?DVR=
https://directes-tv-cat.3catdirectes.cat/live-origin/c33-super3-hls/master.m3u8
#EXTINF:-1 tvg-id="El33SX3.es",El 33 SX3 (1080p) [Geo-blocked]
https://directes-tv-es.3catdirectes.cat/live-origin/c33-super3-hls/master.m3u8
#EXTINF:-1 tvg-id="ElClubdelaComedia.es",El Club de la Comedia (1080p)
https://fast-channels.atresmedia.com/648f47f7a2ffb0e40aeff3ad/648f47f7a2ffb0e40aeff3ad.m3u8
#EXTINF:-1 tvg-id="ElConfidencialTV.es",El Confidencial TV (1080p)
https://daqnsnf5phf17.cloudfront.net/v1/master/3722c60a815c199d9c0ef36c5b73da68a62b09d1/cc-sde7fypd1420w-prod/fast-channel-elconfidencial/fast-channel-elconfidencial.m3u8
#EXTINF:-1 tvg-id="ElHormiguero.es",El Hormiguero (1080p)
https://fast-channels.atresmedia.com/648ef5882bfab0e4627e0d61/648ef5882bfab0e4627e0d61.m3u8
#EXTINF:-1 tvg-id="ElPaisTV.es",EL PAÍS TV (1080p)
https://d2xqbi89ghm9hh.cloudfront.net/v1/master/3722c60a815c199d9c0ef36c5b73da68a62b09d1/cc-79fx3huimw4xc-ssai-prd/fast-channel-el-pais.m3u8
#EXTINF:-1 tvg-id="ElToroTV.es",El Toro TV (720p)
@ -233,6 +249,8 @@ https://streaming-1.eltorotv.com/lb0/eltorotv-streaming-web/index.m3u8
https://elche7tv.gestec-video.com/hls/canal2.m3u8
#EXTINF:-1 tvg-id="EmpordaTV.es",Empordà TV (1080p)
https://video3.lhdserver.es/empordatv2/live.m3u8
#EXTINF:-1 tvg-id="EquipodeInvestigacion.es",Equipo de Investigacion (1080p)
https://fast-channels.atresmedia.com/648ef5551756b0e429af83cc/648ef5551756b0e429af83cc.m3u8
#EXTINF:-1 tvg-id="ErloTelebista.es",Erlo Telebista (720p)
https://5940924978228.streamlock.net/8159/8159/master.m3u8
#EXTINF:-1 tvg-id="Esport3.es",Esport3 (1080p) [Geo-blocked]
@ -261,8 +279,12 @@ https://media2.streambrothers.com:1936/8150/8150/playlist.m3u8
http://185.189.225.150:85/fdf/index.m3u8
#EXTINF:-1 tvg-id="Fibwi.es",Fibwi (1080p) [Not 24/7]
https://hostcdn3.fibwi.com/fibwi_diario/index.fmp4.m3u8
#EXTINF:-1 tvg-id="FisicaoQuimica.es",Fisica o Quimica (1080p)
https://fast-channels.atresmedia.com/648ef50a2bfab0e4607e0d61/648ef50a2bfab0e4607e0d61.m3u8
#EXTINF:-1 tvg-id="FitelTV.es",Fitel TV (1080p)
https://tv.mywifisocial.es/live.m3u8
#EXTINF:-1 tvg-id="Flooxer.es",Flooxer (1080p)
https://fast-channels.atresmedia.com/5c1285e47ed1a861f8125285/5c1285e47ed1a861f8125285.m3u8
#EXTINF:-1 tvg-id="FuengirolaTV.es",Fuengirola TV (360p) [Not 24/7]
https://secure.todostreaming.es/live/nerja-livestream.m3u8
#EXTINF:-1 tvg-id="FuerteventuraTV.es",Fuerteventura TV (1080p)
@ -442,6 +464,8 @@ https://tv.portalexpress.es:3731/stream/play.m3u8
https://tvmelilla-hls-rm-lw.flumotion.com/playlist.m3u8
#EXTINF:-1 tvg-id="RadioTelevisionMogan.es",Radio Televisión Mogán (1080p)
https://cloudvideo.servers10.com:8081/8028/index.m3u8
#EXTINF:-1 tvg-id="RakutenViki.es",Rakuten Viki (1080p)
https://newidco-rakutenviki-2-eu.xiaomi.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="RakutenViki.es",Rakuten Viki (720p)
https://fd18f1cadd404894a31a3362c5f319bd.mediatailor.us-east-1.amazonaws.com/v1/manifest/04fd913bb278d8775298c26fdca9d9841f37601f/RakutenTV-eu_RakutenViki-1/048a962c-e84b-4a0e-aeb3-98376f4b9953/2.m3u8
#EXTINF:-1 tvg-id="RealMadridTV.es",Real Madrid TV (404p)
@ -655,27 +679,13 @@ https://janus.xpbroadcasting.com:8443/hls/xptvUS.m3u8
#EXTINF:-1 tvg-id="ZafraTV.es" http-referrer="https://player.streamingconnect.com/",Zafra TV (1080p)
#EXTVLCOPT:http-referrer=https://player.streamingconnect.com/
https://cloud.fastchannel.es/mic/manifiest/hls/radiotvzafra/radiotvzafra.m3u8
#EXTINF:-1 tvg-id="RakutenViki.es",Rakuten Viki (1080p)
https://newidco-rakutenviki-2-eu.xiaomi.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="AtresplayerInquietos.es",Atresplayer Inquietos (1080p)
https://fast-channels.atresmedia.com/648ef3162bfab0e4587e0d61/648ef3162bfab0e4587e0d61.m3u8
#EXTINF:-1 tvg-id="AtresplayerMulticine.es",Atresplayer Multicine (1080p)
https://fast-channels.atresmedia.com/648ef18c1756b0e41daf83cc/648ef18c1756b0e41daf83cc.m3u8
#EXTINF:-1 tvg-id="AtresplayerComedia.es",Atresplayer Comedia (1080p)
https://fast-channels.atresmedia.com/648ef23d2bfab0e4557e0d61/648ef23d2bfab0e4557e0d61.m3u8
#EXTINF:-1 tvg-id="AtresplayerClasicos.es",Atresplayer Clasicos (1080p)
https://fast-channels.atresmedia.com/648ef12c2bfab0e4507e0d61/648ef12c2bfab0e4507e0d61.m3u8
#EXTINF:-1 tvg-id="Flooxer.es",Flooxer (1080p)
https://fast-channels.atresmedia.com/5c1285e47ed1a861f8125285/5c1285e47ed1a861f8125285.m3u8
#EXTINF:-1 tvg-id="FisicaoQuimica.es",Fisica o Quimica (1080p)
https://fast-channels.atresmedia.com/648ef50a2bfab0e4607e0d61/648ef50a2bfab0e4607e0d61.m3u8
#EXTINF:-1 tvg-id="EquipodeInvestigacion.es",Equipo de Investigacion (1080p)
https://fast-channels.atresmedia.com/648ef5551756b0e429af83cc/648ef5551756b0e429af83cc.m3u8
#EXTINF:-1 tvg-id="ElHormiguero.es",El Hormiguero (1080p)
https://fast-channels.atresmedia.com/648ef5882bfab0e4627e0d61/648ef5882bfab0e4627e0d61.m3u8
#EXTINF:-1 tvg-id="ElClubdelaComedia.es",El Club de la Comedia (1080p)
https://fast-channels.atresmedia.com/648f47f7a2ffb0e40aeff3ad/648f47f7a2ffb0e40aeff3ad.m3u8
#EXTINF:-1 tvg-id="AquiNoHayQuienViva.es",Aqui No Hay Quien Viva (720p)
https://fast-channels.atresmedia.com/648ef3951756b0e425af83cc/648ef3951756b0e425af83cc.m3u8
#EXTINF:-1 tvg-id="Boing.es",Boing
http://185.189.225.150:85/boing/index.m3u8
#EXTINF:-1 tvg-id="Atreseries.es",Atreseries (480p)
http://181.78.109.48:8000/play/a00l/index.m3u8
#EXTINF:-1 tvg-id="Antena3.es",Antena 3 (480p)
http://181.78.109.48:8000/play/a00f/index.m3u8
#EXTINF:-1 tvg-id="AXN.es",AXN (1080p)
http://181.78.109.48:8000/play/a05u/index.m3u8
#EXTINF:-1 tvg-id="AXN.es",AXN (480p)
http://181.78.109.48:8000/play/a023/index.m3u8
#EXTINF:-1 tvg-id="Nickelodeon.es",Nickelodeon (480p)
http://181.78.109.48:8000/play/a05a/index.m3u8

View file

@ -3,8 +3,6 @@
https://dhx-caillou-1-es.samsung.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="EuronewsSpanish.fr",Euronews en Español (720p)
https://rakuten-euronews-4-es.samsung.wurl.tv/manifest/playlist.m3u8
#EXTINF:-1 tvg-id="FashionTVEurope.fr",Fashion TV (Spain) (1080p)
https://fashiontv-fashiontv-2-es.samsung.wurl.tv/manifest/playlist.m3u8
#EXTINF:-1 tvg-id="",iHola Play
https://rakuten-hola-2-es.samsung.wurl.tv/playlist.m3u8
#EXTINF:-1 tvg-id="PeopleAreAwesome.us",People are Awesome

View file

@ -1,4 +1,6 @@
#EXTM3U
#EXTINF:-1 tvg-id="6ter.fr",6ter
https://origin-caf900c010ea8046.live.6cloud.fr/out/v1/29c7a579af3348b48230f76cd75699a5/dash_short_cenc10_6ter_hd_index.mpd
#EXTINF:-1 tvg-id="20MinutesTV.fr",20 Minutes TV (1080p)
https://lives.digiteka.com/stream/86d3e867-a272-496b-8412-f59aa0104771/index.m3u8
#EXTINF:-1 tvg-id="",A12 TV (720p)
@ -59,6 +61,8 @@ https://raw.githubusercontent.com/Paradise-91/ParaTV/main/streams/equidia/live2.
https://raw.githubusercontent.com/Paradise-91/ParaTV/main/streams/equidia/racingmag.m3u8
#EXTINF:-1 tvg-id="EreTV.fr",Ère TV (1080p)
https://mn-nl.mncdn.com/awraastv/awraastv_hd.smil/playlist.m3u8
#EXTINF:-1 tvg-id="EuronewsEnglishHD.fr",Euronews English HD (1080p)
http://stream01.vnet.am/Channel_119/mono.m3u8
#EXTINF:-1 tvg-id="FashionTVCzechSlovak.fr",FashionTV Czech&Slovak (450p) [Not 24/7]
http://lb.streaming.sk/fashiontv/stream/playlist.m3u8
#EXTINF:-1 tvg-id="France2.fr",France 2 (1080p)
@ -185,6 +189,8 @@ http://178.170.47.109/MTVHITS/index.m3u8
http://190.2.155.162:8080/mtvhit/mpegts
#EXTINF:-1 tvg-id="MuseumTVFrench.fr",Museum TV (1080p)
https://live2.creacast.com/museum-france/smil:museum-france.smil/master.m3u8
#EXTINF:-1 tvg-id="MuseumTVEnglish.fr",Museum TV English (1080p)
https://cdn-ue1-prod.tsv2.amagi.tv/linear/amg01492-secomsasmediart-museumtven-xiaomi/playlist.m3u8
#EXTINF:-1 tvg-id="MyZenTV.fr",MyZen TV (1080p)
https://cdn-ue1-prod.tsv2.amagi.tv/linear/amg01255-secomcofites-my-myzen-en-plex/playlist.m3u8
#EXTINF:-1 tvg-id="NancyWebTV.fr",Nancy Web TV (394p) [Not 24/7]
@ -223,6 +229,10 @@ https://raw.githubusercontent.com/Paradise-91/ParaTV/main/streams/tf1plus/tf1.m3
https://raw.githubusercontent.com/Paradise-91/ParaTV/main/streams/tf1plus/tf1sf.m3u8
#EXTINF:-1 tvg-id="TFX.fr",TFX (720p) [Geo-blocked]
https://raw.githubusercontent.com/Paradise-91/ParaTV/main/streams/tf1plus/tfx.m3u8
#EXTINF:-1 tvg-id="TiVi5Monde.fr",TiVi5 Monde [Geo-blocked]
https://ott.tv5monde.com/Content/HLS/Live/channel(tivi5)/variant.m3u8
#EXTINF:-1 tvg-id="TiVi5Monde.fr",TiVi5Monde (1080p)
http://154.197.91.168:7001/play/a0dz/index.m3u8
#EXTINF:-1 tvg-id="TMC.fr",TMC (720p) [Geo-blocked]
https://raw.githubusercontent.com/Paradise-91/ParaTV/main/streams/tf1plus/tmc.m3u8
#EXTINF:-1 tvg-id="TraceLatina.fr",Trace Latina
@ -231,8 +241,6 @@ http://185.234.217.27:8002/play/a02f/index.m3u8
https://amg01131-tracetv-amg01131c1-rakuten-us-1081.playouts.now.amagi.tv/playlist/amg01131-tracetvfast-traceurban-rakutenus/playlist.m3u8
#EXTINF:-1 tvg-id="TV3V.fr",TV3V (720p)
https://tv3v.hdr-tv.com/live/tv3v/livestream/master.m3u8
#EXTINF:-1 tvg-id="TiVi5Monde.fr",TiVi5Monde (1080p)
http://154.197.91.168:7001/play/a0dz/index.m3u8
#EXTINF:-1 tvg-id="TV5MondeAsia.fr",TV5 Monde Asia (Asie) (1080p) [Geo-blocked]
https://ott.tv5monde.com/Content/HLS/Live/channel(seasie)/variant.m3u8
#EXTINF:-1 tvg-id="TV5MondeEurope.fr",TV5Monde Europe (1080p) [Geo-blocked]
@ -275,11 +283,3 @@ https://vosgestv.live-kd.com/live/vosgestv/vosgestv/playlist.m3u8
https://live.digiteka.com/1/WGQ1NnhEN0lzM0NU/dk1EOHhw/hls/live/playlist.m3u8
#EXTINF:-1 tvg-id="Weo.fr",Wéo (Picardie) (480p) [Not 24/7]
https://live.digiteka.com/1/Zks2L0VsM2V0T242/QTBqcFly/hls/live/playlist.m3u8
#EXTINF:-1 tvg-id="6ter.fr",6ter
https://origin-caf900c010ea8046.live.6cloud.fr/out/v1/29c7a579af3348b48230f76cd75699a5/dash_short_cenc10_6ter_hd_index.mpd
#EXTINF:-1 tvg-id="EuronewsEnglishHD.fr",Euronews English HD (1080p)
http://stream01.vnet.am/Channel_119/mono.m3u8
#EXTINF:-1 tvg-id="MuseumTVEnglish.fr",Museum TV English (1080p)
https://cdn-ue1-prod.tsv2.amagi.tv/linear/amg01492-secomsasmediart-museumtven-xiaomi/playlist.m3u8
#EXTINF:-1 tvg-id="TiVi5Monde.fr",TiVi5 Monde [Geo-blocked]
https://ott.tv5monde.com/Content/HLS/Live/channel(tivi5)/variant.m3u8

View file

@ -1,6 +1,6 @@
#EXTM3U
#EXTINF:-1 tvg-id="ETV.gp",ETV (1080p)
https://edge.vedge.infomaniak.com/livecast/ik:etvgp/manifest.m3u8
https://edge12.vedge.infomaniak.com/livecast/ik:etvgp/manifest.m3u8
#EXTINF:-1 tvg-id="MadrasFMTV.gp",Madras FM TV (1080p)
https://edge12.vedge.infomaniak.com/livecast/ik:madrasfmtv/manifest.m3u8
#EXTINF:-1 tvg-id="RadioTVBasseTerre.gp",Radio TV Basse-Terre (720p)

View file

@ -23,6 +23,10 @@ https://www.hellasnet.tv/rest2.live.hn/w2r.alf/playlist.m3u8
http://alphatvlive.siliconweb.com/1/Y2Rsd1lUcUVoajcv/UVdCN25h/hls/live/playlist.m3u8
#EXTINF:-1 tvg-id="ANT1.gr",ANT1 (1080p) [Geo-blocked]
http://d1nfykbwa3n98t.cloudfront.net/out/v1/6e5667da5a6843899a337dea72adb61b/antenna.m3u8
#EXTINF:-1 tvg-id="ANT1.gr" http-referrer="http://watch.antennaplus.gr" http-user-agent="Chrome",ANT1 (1080p) [Geo-blocked]
#EXTVLCOPT:http-referrer=http://watch.antennaplus.gr
#EXTVLCOPT:http-user-agent=Chrome
https://mcdn.antennaplus.gr/live/media0/Ant1/HLS/Ant1.m3u8
#EXTINF:-1 tvg-id="ART.gr",APT (1080p)
https://hugh.cdn.rumble.cloud/live/k5e12sb4/slot-82/fdd0-tbln/chunklist_DVR.m3u8
#EXTINF:-1 tvg-id="ARTTV.gr",ART TV (720p)
@ -63,8 +67,6 @@ http://live.streams.ovh:1935/tvcreta/tvcreta/playlist.m3u8
http://81.171.10.42:554/liveD/DStream.sdp/playlist.m3u8
#EXTINF:-1 tvg-id="DiavataTV.gr",Diavata TV (720p)
https://ssh101.bozztv.com/ssh101/diavatatvweb/playlist.m3u8
#EXTINF:-1 tvg-id="DiavataTV.gr",Diavata TV (720p)
https://video.streams.ovh:1936/DiavataTV/DiavataTV/playlist.m3u8
#EXTINF:-1 tvg-id="DiktyoTV.gr",Diktyo TV (576p)
https://5d00db0e0fcd5.streamlock.net/7322/7322/playlist.m3u8
#EXTINF:-1 tvg-id="DipsoTV.gr",Dipso TV (720p) [Not 24/7]
@ -156,6 +158,8 @@ https://til.pp.ua:3872/live/mesogeiostvlive.m3u8
https://vod.streams.ovh:3876/stream/play.m3u8
#EXTINF:-1 tvg-id="NaftemporikiTV.gr",Naftemporiki TV (1080p)
https://naftemporiki-live.cdn.vustreams.com/live/a4b4a88a-681c-4a2d-8e74-33daa5f2cb61/live.isml/.m3u8
#EXTINF:-1 tvg-id="NationalGeographic.gr",National Geographic (1080p)
http://62.210.211.188:2095/play/a00d
#EXTINF:-1 tvg-id="NeaTV.gr",Nea TV (720p)
https://live.neatv.gr:8888/hls/neatv.m3u8
#EXTINF:-1 tvg-id="NeaTV.gr",Nea TV (720p)
@ -277,9 +281,3 @@ http://live.cretetv.gr:1935/cretetv/myStream/f1tv.m3u8
https://vod.streams.ovh:3037/stream/play.m3u8
#EXTINF:-1 tvg-id="RIKSat.cy",ΡΙΚ Sat (720p) [Not 24/7]
http://l3.cloudskep.com/cybcsat/abr/playlist.m3u8
#EXTINF:-1 tvg-id="NationalGeographic.gr",National Geographic (1080p)
http://62.210.211.188:2095/play/a00d
#EXTINF:-1 tvg-id="ANT1.gr" http-referrer="http://watch.antennaplus.gr" http-user-agent="Chrome",ANT1 (1080p) [Geo-blocked]
#EXTVLCOPT:http-referrer=http://watch.antennaplus.gr
#EXTVLCOPT:http-user-agent=Chrome
https://mcdn.antennaplus.gr/live/media0/Ant1/HLS/Ant1.m3u8

View file

@ -199,12 +199,6 @@ http://194.76.186.33:8000/play/a05h/index.m3u8
http://194.76.186.33:8000/play/a02a/index.m3u8
#EXTINF:-1 tvg-id="RTLHarom.hu",RTL Harom (576p)
http://194.76.186.33:8000/play/a05d/index.m3u8
#EXTINF:-1 tvg-id="RTL.hu",RTL Hungary (1080p)
http://194.76.186.33:8000/play/a041/index.m3u8
#EXTINF:-1 tvg-id="RTL.hu",RTL Hungary (576p)
http://194.76.186.33:8000/play/a01e/index.m3u8
#EXTINF:-1 tvg-id="RTL.hu",RTL Hungary (576p)
http://194.76.186.33:8000/play/a04g/index.m3u8
#EXTINF:-1 tvg-id="RTLKetto.hu",RTL Ketto (1080p)
http://194.76.186.33:8000/play/a01z/index.m3u8
#EXTINF:-1 tvg-id="RTLKetto.hu",RTL Ketto (576p)

View file

@ -1,12 +1,12 @@
#EXTM3U
#EXTINF:-1 tvg-id="7SMusic.in",7S Music (576p) [Not 24/7]
http://103.199.161.254/Content/7smusic/Live/Channel(7smusic)/index.m3u8
#EXTINF:-1 tvg-id="9XJalwa.in",9X Jalwa
https://amg01281-9xmediapvtltd-9xjalwa-samsungin-goszf.amagi.tv/playlist/amg01281-9xmediapvtltd-9xjalwa-samsungin/playlist.m3u8
#EXTINF:-1 tvg-id="9XJhakaas.in",9x Jhakaas
https://amg01281-9xmediapvtltd-9xjhakaas-samsungin-ci2cs.amagi.tv/playlist/amg01281-9xmediapvtltd-9xjhakaas-samsungin/playlist.m3u8
#EXTINF:-1 tvg-id="9XTashan.in",9X Tashan
https://amg01281-9xmediapvtltd-9xtashan-samsungin-xz1sd.amagi.tv/playlist/amg01281-9xmediapvtltd-9xtashan-samsungin/playlist.m3u8
#EXTINF:-1 tvg-id="9XM.in",9XM (576p)
https://d35j504z0x2vu2.cloudfront.net/v1/manifest/0bc8e8376bd8417a1b6761138aa41c26c7309312/9xm/23886666-8fc5-470f-aab1-bd637ed607b1/3.m3u8
#EXTINF:-1 tvg-id="A1TVRajasthan.in",A1 TV Rajasthan (720p)
https://5b48d7e1b4bce.streamlock.net/myapp/a1live/playlist.m3u8
#EXTINF:-1 tvg-id="AajTak.in",Aaj Tak
@ -646,6 +646,8 @@ https://yoganadam.cinesoftcdn.com/yoganadam/live/index.m3u8
https://zainabia.livebox.co.in/ZainabiaChannelhls/channel.m3u8
#EXTINF:-1 tvg-id="Zee24Kalak.in",Zee 24 Kalak (720p)
https://livetv-channels.b-cdn.net/8077/playlist.m3u8
#EXTINF:-1 tvg-id="",Zee Alwan (576p) [Not 24/7]
https://tgn.bozztv.com/gin-dvrfl05/ga-zeealwan/index.m3u8
#EXTINF:-1 tvg-id="ZeeBiharJharkhand.in",Zee Bihar Jharkhand (720p)
https://d3dxf2v5wg5rcy.cloudfront.net/out/v1/349f643193e347609b16671d8e0bfb4a/index.m3u8
#EXTINF:-1 tvg-id="ZeeBiharJharkhand.in",Zee Bihar Jharkhand (720p)
@ -674,7 +676,13 @@ https://livetv-channels.b-cdn.net/8076/playlist.m3u8
http://183.89.246.119:8881/play/a09a/index.m3u8
#EXTINF:-1 tvg-id="Zoom.in",Zoom (1080p)
http://103.81.104.118/hls/stream8.m3u8
#EXTINF:-1 tvg-id="ZeeAlwan.in",Zee Alwan (576p) [Not 24/7]
https://tgn.bozztv.com/gin-dvrfl05/ga-zeealwan/index.m3u8
#EXTINF:-1 tvg-id="9XM.in",9XM (576p)
https://d35j504z0x2vu2.cloudfront.net/v1/manifest/0bc8e8376bd8417a1b6761138aa41c26c7309312/9xm/23886666-8fc5-470f-aab1-bd637ed607b1/3.m3u8
#EXTINF:-1 tvg-id="ShowBox.in",ShowBox
https://epiconvh.akamaized.net/live/showbox/master.m3u8
#EXTINF:-1 tvg-id="RajTV.in",Raj TV
https://d3qs3d2rkhfqrt.cloudfront.net/out/v1/2839e3d1e0f84a2e821c1708d5fdfdf0/index.m3u8
#EXTINF:-1 tvg-id="DDSahyadri.in",DD Sahyadri
https://d3qs3d2rkhfqrt.cloudfront.net/out/v1/66dcc3ebe182447ba42837e746cf0c7c/index.m3u8
#EXTINF:-1 tvg-id="DDSaptagiri.in",DD Saptagiri
https://d2lk5u59tns74c.cloudfront.net/out/v1/26e915d6d12b4a06822c5e33c088ed56/index.m3u8
#EXTINF:-1 tvg-id="DDHaryana.in",DD Haryana
https://d2lk5u59tns74c.cloudfront.net/out/v1/950fc69666474351bde0a32b9600c804/index.m3u8

View file

@ -3,6 +3,8 @@
https://mediaserver.abnvideos.com/streams/abnsat.m3u8
#EXTINF:-1 tvg-id="AfaqTV.iq",Afaq TV
http://63b03f7689049.streamlock.net:1935/live/1/playlist.m3u8
#EXTINF:-1 tvg-id="AfarinBaxcha.iq",Afarin Baxcha (1080p)
https://5dcabf026b188.streamlock.net/afarinTV/livestream/playlist.m3u8
#EXTINF:-1 tvg-id="AfarinTV.iq",Afarin TV (720p) [Not 24/7]
https://65f16f0fdfc51.streamlock.net/afarinTV/livestream/playlist.m3u8
#EXTINF:-1 tvg-id="AlahadTV.iq",Al Ahad TV
@ -32,7 +34,7 @@ https://arrafidain.tvplayer.online/arrafidaintv/source2/playlist.m3u8
https://arrafidain.tvplayer.online/arrafidaintv/source/playlist.m3u8
#EXTINF:-1 tvg-id="AlRasheedTV.iq",Al Rasheed TV (1080p) [Not 24/7]
https://media1.livaat.com/static/AL-RASHEED-HD/playlist.m3u8
#EXTINF:-1 tvg-id="AlShabab.iq",Al Shabab TV (1080p)
#EXTINF:-1 tvg-id="",Al Shabab TV (1080p)
http://149.100.11.244:8001/play/a07n/index.m3u8
#EXTINF:-1 tvg-id="AlAimmaTV.iq" http-referrer="https://alaimma.tv",Al-Aimma TV (1080p)
#EXTVLCOPT:http-referrer=https://alaimma.tv
@ -138,6 +140,8 @@ http://stream.nubar.tv:1935/private/NUBARtv/playlist.m3u8
https://media2.streambrothers.com:1936/8218/8218/playlist.m3u8
#EXTINF:-1 tvg-id="RudawTV.iq",Rudaw TV (1080p)
https://svs.itworkscdn.net/rudawlive/rudawlive.smil/playlist.m3u8
#EXTINF:-1 tvg-id="ShamsTV.iq",Shams TV (1080p)
https://stream.shams.tv/hls/stream.m3u8
#EXTINF:-1 tvg-id="UTV.iq",UTV (1080p)
https://mn-nl.mncdn.com/utviraqi2/64c80359/index.m3u8
#EXTINF:-1 tvg-id="WaarTV.iq",Waar TV
@ -146,7 +150,3 @@ https://ca-rt.onetv.app/Waar/index-0.m3u8
https://5a3ed7a72ed4b.streamlock.net/zagrostv/SMIL:myStream.smil/playlist.m3u8
#EXTINF:-1 tvg-id="",Zarok TV Sorani (720p)
https://zindisorani.zaroktv.com.tr/hls/stream.m3u8
#EXTINF:-1 tvg-id="AfarinBaxcha.iq",Afarin Baxcha (1080p)
https://5dcabf026b188.streamlock.net/afarinTV/livestream/playlist.m3u8
#EXTINF:-1 tvg-id="ShamsTV.iq",Shams TV (1080p)
https://stream.shams.tv/hls/stream.m3u8

View file

@ -71,3 +71,5 @@ https://hls.nejat.live/hls/stream.m3u8
https://hls.vox1.live/hls/stream.m3u8
#EXTINF:-1 tvg-id="YourTimeTV.ir",YourTime TV (720p) [Not 24/7]
https://hls.yourtime.live/hls/stream.m3u8
#EXTINF:-1 tvg-id="VarzeshTV.ir",Varzesh TV (480p)
https://stream.sainaertebat.com/hls2/varzeshtest.m3u8

View file

@ -37,6 +37,8 @@ https://59d7d6f47d7fc.streamlock.net/auroraarte/auroraarte/playlist.m3u8
https://ed05.top-ix.org/avtvlive/azzurra/streaming/playlist.m3u8
#EXTINF:-1 tvg-id="BikeChannel.it",Bike (720p)
http://backup.superstreaming.inaria.me/BikeSmartMobilityDTT/playlist.m3u8
#EXTINF:-1 tvg-id="Boing.it",Boing (720p)
https://liveturner.akamaized.net/75a4d1a90e744fa5b9901a1853d2c47f/eu-central-1/6284318116001/playlist.m3u8
#EXTINF:-1 tvg-id="Boing.it",Boing Italy [Geo-blocked]
https://live2.msf.cdn.mediaset.net/content/hls_h0_clr_vos/live/channel(kb)/index.m3u8
#EXTINF:-1 tvg-id="BomChannel.it",Bom Channel
@ -314,6 +316,9 @@ https://mediapolisevent.rai.it/relinker/relinkerServlet.htm?cont=2606803
https://mediapolis.rai.it/relinker/relinkerServlet.htm?cont=308718
#EXTINF:-1 tvg-id="Rai2.it",Rai 2 (302p) [Geo-blocked]
http://stream.tvtap.net:8081/live/it-rai2.stream/playlist.m3u8
#EXTINF:-1 tvg-id="Rai2HD.it" http-referrer="https://babaktv.com/",Rai 2 HD
#EXTVLCOPT:http-referrer=https://babaktv.com/
https://m3u.iranvids.com/rai02/output.m3u8
#EXTINF:-1 tvg-id="Rai3.it",Rai 3 (720p)
https://dash2.antik.sk/live/test_rai_tre_tizen/playlist.m3u8
#EXTINF:-1 tvg-id="Rai3.it",Rai 3 (720p) [Not 24/7]
@ -662,8 +667,11 @@ https://stream.cp.ets-sistemi.it:1936/profservtv/profservtv/playlist.m3u8
https://5f22d76e220e1.streamlock.net/canale5/canale5/playlist.m3u8
#EXTINF:-1 tvg-id="ZerounoTVNews.it",Zerouno TV News (720p)
https://5db313b643fd8.streamlock.net/ZerounoTVEventi/ZerounoTVEventi/playlist.m3u8
#EXTINF:-1 tvg-id="Boing.it",Boing (720p)
https://liveturner.akamaized.net/75a4d1a90e744fa5b9901a1853d2c47f/eu-central-1/6284318116001/playlist.m3u8
#EXTINF:-1 tvg-id="Rai2HD.it" http-referrer="https://babaktv.com/",Rai 2 HD
#EXTVLCOPT:http-referrer=https://babaktv.com/
https://m3u.iranvids.com/rai02/output.m3u8
#EXTINF:-1 tvg-id="Telenova.it",Telenova (720p)
https://64b16f23efbee.streamlock.net/telenova/telenova/playlist.m3u8
#EXTINF:-1 tvg-id="TeleQuattro.it",Tele Quattro (720p)
https://59d7d6f47d7fc.streamlock.net/telequattro/telequattro/playlist.m3u8
#EXTINF:-1 tvg-id="7RadioVisione.it",7 RadioVisione (720p)
https://stream10.xdevel.com/video1s976543-1932/stream/playlist.m3u8
#EXTINF:-1 tvg-id="RTV38.it",RTV38 (576p)
https://streamcdne1-845d8509d2cb4f249dd0b2ae5755b6c2.msvdn.net/rtv38/rtv38_live_main/mainabr/rtv38_live_main/main_576/chunks_dvr.m3u8

View file

@ -32,10 +32,6 @@ https://cdn.skygo.mn/live/disk1/NHK_World_Premium/HLSv3-FTA/NHK_World_Premium.m3
https://master.nhkworld.jp/nhkworld-tv/playlist/live.m3u8
#EXTINF:-1 tvg-id="JOAXDTV.jp",Nippon TV (540p) [Not 24/7]
https://ntv4.mov3.co/hls/ntv.m3u8
#EXTINF:-1 tvg-id="NTVNEWS24.jp",NTV News24 (480p)
https://n24-cdn-live.ntv.co.jp/ch01/index.m3u8
#EXTINF:-1 tvg-id="NTVNEWS24.jp",NTV News24 (480p)
https://n24-cdn-live.ntv.co.jp/ch02/index.m3u8
#EXTINF:-1 tvg-id="QVC.jp",QVC Japan (720p)
https://cdn-live1.qvc.jp/iPhone/1501/1501.m3u8
#EXTINF:-1 tvg-id="ShopChannel.jp",Shop Channel (1080p) [Not 24/7]

View file

@ -17,8 +17,6 @@ http://cdns.jp-primehome.com:8000/zhongying/live/playlist.m3u8?cid=bs04&isp=4
http://cdns.jp-primehome.com:8000/zhongying/live/playlist.m3u8?cid=bs05&isp=4
#EXTINF:-1 tvg-id="ChannelGinga.jp",Channel Ginga (1080p)
http://cdns.jp-primehome.com:8000/zhongying/live/playlist.m3u8?cid=cs29&isp=4
#EXTINF:-1 tvg-id="CNNj.jp",CNNj (544p)
http://cdns.jp-primehome.com:8000/zhongying/live/playlist.m3u8?cid=cs16&isp=4
#EXTINF:-1 tvg-id="DisneyChannel.jp",Disney Channel Japan (544p)
http://cdns.jp-primehome.com:8000/zhongying/live/playlist.m3u8?cid=bs24&isp=4
#EXTINF:-1 tvg-id="EiseiGekijo.jp",Eisei Gekijo (544p)

View file

@ -17,6 +17,8 @@ https://streaming.freshnewsasia.com/live/ngrp:myStream_all/playlist.m3u8
http://clive.malisresidences.com:1935/hm_hdtv/_definst_/smil:HMHDTV.smil/playlist.m3u8
#EXTINF:-1 tvg-id="iTVHD.kh",iTV HD
http://43.252.18.195:5080/live/streams/itv.khmeretv.m3u8
#EXTINF:-1 tvg-id="KomsanTV.kh",Komsan TV [Not 24/7]
http://tv.cootel.com.kh:8077/streams/d/Komsan/playlist.m3u8
#EXTINF:-1 tvg-id="MSJTV.kh" http-referrer="https://www.iptvservice.site/",MSJ TV (1080p)
#EXTVLCOPT:http-referrer=https://www.iptvservice.site/
https://live-ali7.tv360.metfone.com.kh/live/myStream/playlist.m3u8
@ -38,10 +40,14 @@ https://fmseatv.netlinkbroadcaster.com/hls/test.m3u8
https://live-evg13.tv360.metfone.com.kh/live/towntv.m3u8
#EXTINF:-1 tvg-id="TownTV.kh",Town TV (720p)
https://live.kh.malimarcdn.com/live/towntv.stream/playlist.m3u8
#EXTINF:-1 tvg-id="TV3.kh",TV 3
http://206.189.93.160:1935/live/myStream_720p/playlist.m3u8
#EXTINF:-1 tvg-id="TV3.kh",TV 3 (720p)
https://edge6a.v2h-cdn.com/tv3cam/tv3cam.stream/playlist.m3u8
#EXTINF:-1 tvg-id="TV5Cambodia.kh",TV5 Cambodia
http://live.happywatch99.com/livehd14/77bbe9df6a93cf229cd40f1400af00fa.sdp/playlist.m3u8
#EXTINF:-1 tvg-id="TV5Cambodia.kh",TV5 Cambodia (1080p)
https://es1-p1-netcdn.metfone.com.kh/netcdn-live-36/36/output/playlist.m3u8
#EXTINF:-1 tvg-id="TV5Cambodia.kh",TV5 Cambodia (720p)
https://live-evg3.tv360.metfone.com.kh/live/tv5.m3u8
#EXTINF:-1 tvg-id="TVK.kh",TVK (720p)
@ -50,9 +56,7 @@ https://live.kh.malimarcdn.com/live/tvk.stream/playlist.m3u8
https://live.kh.malimarcdn.com/live/tvk2.stream/playlist.m3u8
#EXTINF:-1 tvg-id="WikiTV.kh",WIKI TV (720p)
https://stream.wikitv.asia/live/ngrp:myStream_all/playlist.m3u8
#EXTINF:-1 tvg-id="TV5Cambodia.kh",TV5 Cambodia (1080p)
https://es1-p1-netcdn.metfone.com.kh/netcdn-live-36/36/output/playlist.m3u8
#EXTINF:-1 tvg-id="KomsanTV.kh",Komsan TV [Not 24/7]
http://tv.cootel.com.kh:8077/streams/d/Komsan/playlist.m3u8
#EXTINF:-1 tvg-id="TV3.kh",TV 3
http://206.189.93.160:1935/live/myStream_720p/playlist.m3u8
#EXTINF:-1 tvg-id="MyTV.kh",My TV
http://43.252.18.195:5080/live/streams/mytv.m3u8
#EXTINF:-1 tvg-id="CTN.kh",CTN (480p)
http://43.252.18.195:5080/live/streams/ctntv.m3u8

View file

@ -35,6 +35,8 @@ https://btn.nowcdn.co.kr/btn/btnlive2m/playlist.m3u8
https://du35ivadp6cxj.cloudfront.net/out/v1/81781d23cbbf490990b2aa9181d4ce19/CGNWebLiveKR.m3u8
#EXTINF:-1 tvg-id="ChannelA.kr",Channel A [Geo-blocked]
http://channelalive.ktcdn.co.kr/chalivepc/_definst_/atv2/playlist.m3u8
#EXTINF:-1 tvg-id="ChannelA.kr",Channel A (360p)
http://www.hwado.net/webtv/catv/52_440DDPPJ.php
#EXTINF:-1 tvg-id="CJOnStyle.kr",CJ OnStyle (540p)
https://live-ch1.cjonstyle.net/cjmalllive/stream2/playlist.m3u8
#EXTINF:-1 tvg-id="CJOnStylePlus.kr",CJ OnStyle Plus (540p)
@ -86,8 +88,6 @@ https://live.jobplustv.or.kr/live/wowtvlive1.sdp/playlist.m3u8
#EXTINF:-1 tvg-id="KBS1TV.kr",KBS 1TV [Not 24/7]
http://mytv.dothome.co.kr/ch/public/1.php
#EXTINF:-1 tvg-id="KBS1TV.kr",KBS 1 UHD (720p)
http://202.60.106.14:8080/200/playlist.m3u8
#EXTINF:-1 tvg-id="KBS1TV.kr",KBS 1 UHD (720p)
http://202.60.106.14:21585/200/playlist.m3u8
#EXTINF:-1 tvg-id="KBS2TV.kr",KBS 2TV [Not 24/7]
http://mytv.dothome.co.kr/ch/public/3.php
@ -105,8 +105,6 @@ http://kbs-dokdo.gscdn.com/dokdo_300/dokdo_300.stream/playlist.m3u8
http://mytv.dothome.co.kr/ch/catv/4.php
#EXTINF:-1 tvg-id="KBSWorld.kr",KBS World
http://mytv.dothome.co.kr/ch/catv/7.php
#EXTINF:-1 tvg-id="KBSWorld.kr",KBS World (Vietnamese Subtitles) (720p)
https://livecdn.fptplay.net/sdb/kbs_hls.smil/playlist.m3u8
#EXTINF:-1 tvg-id="KCTV.kr",KCTV 광주 CH05 (720p) [Not 24/7]
http://119.77.96.184:1935/chn05/chn05/playlist.m3u8
#EXTINF:-1 tvg-id="KTV.kr",Korea TV (1080p)
@ -147,6 +145,8 @@ https://5ee9633b25727.streamlock.net/jmbc_tv/_definst_/jmbc_tv.stream/playlist.m
http://vod.mpmbc.co.kr:1935/live/encoder-tv/playlist.m3u8
#EXTINF:-1 tvg-id="MBCNet.kr",MBC Net (480p) [Geo-blocked]
http://mytv.dothome.co.kr/ch/catv/28.php
#EXTINF:-1 tvg-id="MBCTV.kr",MBC TV (720p)
http://www.hwado.net/webtv/catv/503_CFEA7803.php
#EXTINF:-1 tvg-id="HLATDTV.kr",MBC Yeosu (여수 MBC) (1080p) [Not 24/7]
https://5c3639aa99149.streamlock.net/live_TV/tv/playlist.m3u8
#EXTINF:-1 tvg-id="MTN.kr",MTN (720p)
@ -173,6 +173,8 @@ https://live.knou.ac.kr/knou1/live1/playlist.m3u8
https://rtv-stream2.a04f922e9e85c8d25ebfeae3dfd22a67.com/rtv/rtv.m3u8
#EXTINF:-1 tvg-id="RUTCTV.kr",RUTC TV (720p)
http://d26sxnc75smwvh.cloudfront.net/livehttporigin/rutclive_720p2.stream/playlist.m3u8
#EXTINF:-1 tvg-id="SBS.kr",SBS (480p)
http://www.hwado.net/webtv/catv/502_76142D8F.php
#EXTINF:-1 tvg-id="HLDRDTV.kr",SBS CJB (540p) [Not 24/7]
http://1.222.207.80:1935/live/cjbtv/playlist.m3u8
#EXTINF:-1 tvg-id="HLCGDTV.kr",SBS G1 (360p) [Not 24/7]
@ -221,9 +223,3 @@ http://157.245.196.186/live/livestream.m3u8
http://202.60.106.14:8080/214/playlist.m3u8
#EXTINF:-1 tvg-id="YTN.kr",YTN (720p)
http://202.60.106.14:21585/214/playlist.m3u8
#EXTINF:-1 tvg-id="SBS.kr",SBS (480p)
http://www.hwado.net/webtv/catv/502_76142D8F.php
#EXTINF:-1 tvg-id="ChannelA.kr",Channel A (360p)
http://www.hwado.net/webtv/catv/52_440DDPPJ.php
#EXTINF:-1 tvg-id="MBCTV.kr",MBC TV (720p)
http://www.hwado.net/webtv/catv/503_CFEA7803.php

View file

@ -31,8 +31,6 @@ https://stream.kaztrk.kz/regional/kokshetautv/index.m3u8
http://212.42.111.152:8080/hls/manas.m3u8
#EXTINF:-1 tvg-id="Mangystay.kz",Mańǵystaý (540p) [Not 24/7]
https://stream.kaztrk.kz/regional/mangystautv/index.m3u8
#EXTINF:-1 tvg-id="MuzzOne.kz",MuzzOne (1080p)
https://muzzone-stream.daitsuna.net/muzzondvr/muzzone/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="Ontustik.kz",Ontústik (360p)
https://stream.kaztrk.kz/regional/shymkenttv/index.m3u8
#EXTINF:-1 tvg-id="Qazaqstan.kz",Qazaqstan TV (720p) [Not 24/7]
@ -63,3 +61,5 @@ https://tvcdn01.oktv.kz/tv/mtrk/playlist.m3u8
http://serv25.vintera.tv:8081/novoetv/nov_tv/playlist.m3u8
#EXTINF:-1 tvg-id="ChannelOneEurasia.kz",Первый канал Евразия (720p)
https://1tvkz-stream.daitsuna.net/1tvkz/1tvkz/playlist.m3u8
#EXTINF:-1 tvg-id="MuzzOne.kz",MuzzOne (1080p)
https://streams.qazcdn.net/muzzone/muzzone/playlist_dvr.m3u8

View file

@ -3,8 +3,6 @@
https://tv.hiruhost.com:1936/8012/8012/playlist.m3u8
#EXTINF:-1 tvg-id="ImaiTV.lk",Imai TV (720p)
https://rpn3.bozztv.com/ssh101/ssh101/imaitv/playlist.m3u8
#EXTINF:-1 tvg-id="ITN.lk",ITN (720p) [Not 24/7]
https://j78dp2pnlq5r-hls-live.comcities.net/ITNDigital/cf467ddf13ba30dd3c71435cafa6fd6e.sdp/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="MonaraTV.lk",Monara TV (720p) [Not 24/7]
https://jk3lz8xklw79-hls-live.5centscdn.com/lpl/d0dbe915091d400bd8ee7f27f0791303.sdp/playlist.m3u8
#EXTINF:-1 tvg-id="Rupavahini.lk",Rupavahini (480p)
@ -19,3 +17,7 @@ https://jk3lz8xklw79-hls-live.5centscdn.com/live/6226f7cbe59e99a90b5cef6f94f966f
https://j78dp2pnlq5r-hls-live.comcities.net/ITNDigital/20a317b0496a4930b375290505e5d628.sdp/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="VerbumTV.lk",Verbum TV (414p) [Not 24/7]
https://verbumtv.livebox.co.in/verbumtvhls/live.m3u8
#EXTINF:-1 tvg-id="VasanthamTV.lk",Vasantham TV (720p)
https://222103-hls.akamaized.net/668828a00bf80aa436254876/live_2cdb4ef03c1311efadcf7986aa245789/rewind-3600.m3u8
#EXTINF:-1 tvg-id="ITN.lk",ITN (1080p)
https://222103-hls.akamaized.net/668828a00bf80aa436254876/live_aabd3d003af211efadcf7986aa245789/rewind-3600.m3u8

View file

@ -3,36 +3,26 @@
#EXTVLCOPT:http-referrer=https://2m.ma
#EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0
https://cdn-globecast.akamaized.net/live/eds/2m_monde/hls_video_ts_tuhawxpiemz257adfc/2m_monde.m3u8
#EXTINF:-1 tvg-id="2MNational.ma",2M National (1080p)
http://154.197.91.168:7001/play/a0fn/index.m3u8
#EXTINF:-1 tvg-id="AlAoulaInter.ma",Al Aoula International (1080p)
http://154.197.91.168:7001/play/a0f5/index.m3u8
#EXTINF:-1 tvg-id="AlAoulaInter.ma",Al Aoula International (480p)
https://cdn.live.easybroadcast.io/abr_corp/73_aloula_w1dqfwm/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="AlAoula.ma",Al Aoula Laâyoune (1080p)
http://154.197.91.168:7001/play/a0f6/index.m3u8
#EXTINF:-1 tvg-id="AlAoula.ma",Al Aoula Laâyoune (480p)
#EXTINF:-1 tvg-id="LaayouneTV.ma",Al Aoula Laâyoune (480p)
https://cdn.live.easybroadcast.io/abr_corp/73_laayoune_pgagr52/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="AlMaghribia.ma",Al Maghribia (1080p)
http://154.197.91.168:7001/play/a0f9/index.m3u8
#EXTINF:-1 tvg-id="AlMaghribia.ma",Al Maghribia (480p)
https://cdn.live.easybroadcast.io/abr_corp/73_almaghribia_83tz85q/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="",Al Rahman (480p)
http://149.100.11.244:8001/play/a06j/index.m3u8
#EXTINF:-1 tvg-id="Arryadia.ma",Arryadia (1080p)
http://154.197.91.168:7001/play/a0f7/index.m3u8
#EXTINF:-1 tvg-id="Arryadia.ma",Arryadia (480p)
https://cdn.live.easybroadcast.io/abr_corp/73_arryadia_k2tgcj0/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="Arryadia.ma",Arryadia (1080p)
http://154.197.91.168:7001/play/a0fa/index.m3u8
#EXTINF:-1 tvg-id="Assadissa.ma",Assadissa (480p)
https://cdn.live.easybroadcast.io/abr_corp/73_assadissa_7b7u5n1/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="Athaqafia.ma",Athaqafia (1080p)
http://154.197.91.168:7001/play/a0f8/index.m3u8
#EXTINF:-1 tvg-id="Athaqafia.ma",Athaqafia (480p)
https://cdn.live.easybroadcast.io/abr_corp/73_arrabia_hthcj4p/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="ChadaTV.ma",Chada TV (720p)
https://chadatv.vedge.infomaniak.com/livecast/chadatv/playlist.m3u8
#EXTINF:-1 tvg-id="ChadaTV.ma",Chada TV (720p)
https://edge19.vedge.infomaniak.com/livecast/ik:chadatv/playlist.m3u8
#EXTINF:-1 tvg-id="M24TV.ma",M24 TV (1080p)
https://67aac8c668349.streamlock.net/live/ngrp:Live2.stream_all/playlist.m3u8
#EXTINF:-1 tvg-id="Medi1TVAfrique.ma",Medi 1 TV Afrique (1080p) [Not 24/7]
https://streaming1.medi1tv.com/live/smil:medi1fr.smil/playlist.m3u8
#EXTINF:-1 tvg-id="Medi1TVAfrique.ma",Medi 1 TV Afrique (1080p) [Not 24/7]
@ -45,7 +35,9 @@ https://streaming2.medi1tv.com/live/smil:medi1ar.smil/playlist.m3u8
https://streaming1.medi1tv.com/live/smil:medi1tv.smil/playlist.m3u8
#EXTINF:-1 tvg-id="Medi1TVMaghreb.ma",Medi 1 TV Maghreb (1080p) [Not 24/7]
https://streaming2.medi1tv.com/live/smil:medi1tv.smil/playlist.m3u8
#EXTINF:-1 tvg-id="TamazightTV.ma",Tamazight (1080p)
http://154.197.91.168:7001/play/a0fb/index.m3u8
#EXTINF:-1 tvg-id="TamazightTV.ma",Tamazight (480p)
https://cdn.live.easybroadcast.io/abr_corp/73_tamazight_tccybxt/playlist_dvr.m3u8
#EXTINF:-1 tvg-id="2MMonde.ma",2M Monde (720p)
https://d3g87jnubafe6a.cloudfront.net/out/v1/1fa0fb3c8dec402994a6f7a7f6492b82/index.m3u8
#EXTINF:-1 tvg-id="TeleMaroc.ma",Tele Maroc (720p)
https://raw.githubusercontent.com/ipstreet312/freeiptv/master/ressources/kuw/telmar.m3u8

View file

@ -1,7 +1,7 @@
#EXTM3U
#EXTINF:-1 tvg-id="MonacoInfo.mc",Monaco Info (720p) [Not 24/7]
https://webtvmonacoinfo.mc/live/prod_720/index.m3u8
#EXTINF:-1 tvg-id="SuperyachtTV.mc",Superyacht TV (1080p)
https://sy.wns.live/hls/stream.m3u8
#EXTINF:-1 tvg-id="TVMonaco.mc",TV Monaco (1080p)
https://production-fast-mcrtv.content.okast.tv/channels/2116dc08-1959-465d-857f-3619daefb66b/b702b2b9-aebd-436c-be69-2118f56f3d86/2024/media.m3u8
#EXTINF:-1 tvg-id="MonacoInfo.mc",Monaco Info (1080p)
https://webtv.monacoinfo.com/live/prod/index.m3u8

View file

@ -3,29 +3,61 @@
http://hls.protv.md/acasatv/acasatv.m3u8
#EXTINF:-1 tvg-id="BaltiTV.md",Bălţi TV (1080p) [Geo-blocked]
http://77.89.199.174:8000/play/1024/index.m3u8
#EXTINF:-1 tvg-id="BusuiocTV.md",Busuioc TV (1080p)
http://62.233.57.226:8001/play/a005
#EXTINF:-1 tvg-id="BusuiocTV.md",Busuioc TV (540p) [Not 24/7]
https://busuioctv.iforward.eu/hls/busuioc.m3u8
#EXTINF:-1 tvg-id="Cinema1.md",Cinema 1 (1080p)
http://62.233.57.226:8001/play/a00l00
#EXTINF:-1 tvg-id="DrochiaTV.md",Drochia TV (1080p) [Not 24/7]
https://hls.drochia.tv/tv/web.m3u8
#EXTINF:-1 tvg-id="DuniaSinema.my",Dunia Sinema (1080p)
https://unifi-live05.secureswiftcontent.com/UnifiHD/live27-1080FHD.m3u8
#EXTINF:-1 tvg-id="ExclusivTV.md",Exclusiv TV (1080p)
http://62.233.57.226:8001/play/a00f
#EXTINF:-1 tvg-id="GRT.md",GRT (1080p)
http://62.233.57.226:8001/play/a00f00
#EXTINF:-1 tvg-id="JurnalTV.md",Jurnal TV (1080p)
http://62.233.57.226:8001/play/a00i
#EXTINF:-1 tvg-id="Moldova1.md",Moldova 1 (1080p)
https://v0.trm.md/static/streaming-playlists/hls/9b79338b-1870-4cd7-91d4-0f6ce5cac7ca/master.m3u8
#EXTINF:-1 tvg-id="Moldova2.md",Moldova 2 (1080p)
https://v0.trm.md/static/streaming-playlists/hls/d5fafab0-9c37-4746-9e7a-b2d6c0427015/master.m3u8
#EXTINF:-1 tvg-id="Moldova2.md",Moldova 2 (1080p)
http://62.233.57.226:8001/play/a00a
#EXTINF:-1 tvg-id="MoldovaTV.md",Moldova TV (576p) [Not 24/7]
http://89.38.8.130:39435
#EXTINF:-1 tvg-id="N4.md",N4 (1080p)
http://62.233.57.226:8001/play/a007
#EXTINF:-1 tvg-id="N4.md",N4 (360p) [Not 24/7]
https://web.sats.gstv.tech/cpl11/da8df281-1165-440a-8c86-959f71b695b6/N4web.m3u8
#EXTINF:-1 tvg-id="NextTV.md",Next TV (1080p)
http://62.233.57.226:8001/play/a00h
#EXTINF:-1 tvg-id="NorocTV.md",Noroc TV (1080p)
http://62.233.57.226:8001/play/a00i00
#EXTINF:-1 tvg-id="NorocTV.md",Noroc TV (576p) [Not 24/7]
https://live.noroc.tv/noroc/noroc.m3u8
#EXTINF:-1 tvg-id="NTSTV.md",NTS TV (1080p)
http://62.233.57.226:8001/play/a00d
#EXTINF:-1 tvg-id="PremieraTV.md",Premiera TV (1080p)
http://62.233.57.226:8001/play/a009
#EXTINF:-1 tvg-id="PrivescEuTV.md",Privesc.Eu TV (2160p)
https://cachestar.privesc.eu/liniar/moldova/playlist.m3u8
#EXTINF:-1 tvg-id="PROTVChisinau.md",PRO TV Chisinau (1080p)
http://62.233.57.226:8001/play/a00g
#EXTINF:-1 tvg-id="PublikaTV.md",Publika TV (720p)
https://livebeta.publika.press/LIVE/P/6810.m3u8
#EXTINF:-1 tvg-id="RealitateaTV.md",Rlive TV (406p)
https://realitatealive.md/tv/rlive.m3u8
#EXTINF:-1 tvg-id="SorTV.md",Sor TV (720p)
http://188.237.212.16:8888/live/cameraFeed.m3u8
#EXTINF:-1 tvg-id="StarTV.md",Star TV (1080p)
http://62.233.57.226:8001/play/a008
#EXTINF:-1 tvg-id="TeleM.md",TeleM (576p)
https://tv.streambox.ro/hls/telem/index.m3u8
#EXTINF:-1 tvg-id="TezaurTV.md",Tezaur TV (1080p)
http://62.233.57.226:8001/play/a00j
#EXTINF:-1 tvg-id="TezaurTV.md",Tezaur TV (1080p)
https://tezaurtv.md/wp-content/uploads/live/index.m3u8
#EXTINF:-1 tvg-id="TVNord.md",TV-Nord (1080p)
https://6065d3147e895.streamlock.net:4444/npcl/live/playlist.m3u8
@ -33,33 +65,5 @@ https://6065d3147e895.streamlock.net:4444/npcl/live/playlist.m3u8
https://tvr-tvrmoldova.cdn.zitec.com/live/tvrmoldova/main.m3u8
#EXTINF:-1 tvg-id="VoceaBasarabieiTV.md",Vocea Basarabiei TV (720p) [Not 24/7]
https://storage.voceabasarabiei.md/vocea/vocea.m3u8
#EXTINF:-1 tvg-id="ExclusivTV.md",Exclusiv TV (1080p)
http://62.233.57.226:8001/play/a00f
#EXTINF:-1 tvg-id="TezaurTV.md",Tezaur TV (1080p)
http://62.233.57.226:8001/play/a00j
#EXTINF:-1 tvg-id="StarTV.md",Star TV (1080p)
http://62.233.57.226:8001/play/a008
#EXTINF:-1 tvg-id="ZonaM.md",Zona M (576p)
http://62.233.57.226:8001/play/a00e
#EXTINF:-1 tvg-id="PROTVChisinau.md",PRO TV Chisinau (1080p)
http://62.233.57.226:8001/play/a00g
#EXTINF:-1 tvg-id="PremieraTV.md",Premiera TV (1080p)
http://62.233.57.226:8001/play/a009
#EXTINF:-1 tvg-id="NTSTV.md",NTS TV (1080p)
http://62.233.57.226:8001/play/a00d
#EXTINF:-1 tvg-id="NorocTV.md",Noroc TV (1080p)
http://62.233.57.226:8001/play/a00i00
#EXTINF:-1 tvg-id="NextTV.md",Next TV (1080p)
http://62.233.57.226:8001/play/a00h
#EXTINF:-1 tvg-id="N4.md",N4 (1080p)
http://62.233.57.226:8001/play/a007
#EXTINF:-1 tvg-id="Moldova2.md",Moldova 2 (1080p)
http://62.233.57.226:8001/play/a00a
#EXTINF:-1 tvg-id="JurnalTV.md",Jurnal TV (1080p)
http://62.233.57.226:8001/play/a00i
#EXTINF:-1 tvg-id="GRT.md",GRT (1080p)
http://62.233.57.226:8001/play/a00f00
#EXTINF:-1 tvg-id="Cinema1.md",Cinema 1 (1080p)
http://62.233.57.226:8001/play/a00l00
#EXTINF:-1 tvg-id="BusuiocTV.md",Busuioc TV (1080p)
http://62.233.57.226:8001/play/a005

View file

@ -14,18 +14,20 @@ http://210.210.155.35/dr9445/h/h04/index.m3u8
http://210.210.155.37/uq2663/h/h22/index.m3u8
#EXTINF:-1 tvg-id="MaahTV.my",Maah TV (720p) [Not 24/7]
https://hls.maahtv.live/hls/stream.m3u8
#EXTINF:-1 tvg-id="Okey.my" http-referrer="https://rtm-player.glueapi.io/",Okey RTM [Geo-blocked]
#EXTINF:-1 tvg-id="Okey.my" http-referrer="https://rtm-player.glueapi.io/",Okey [Geo-blocked]
#EXTVLCOPT:http-referrer=https://rtm-player.glueapi.io/
https://d25tgymtnqzu8s.cloudfront.net/smil:okey/playlist.m3u8?id=3
#EXTINF:-1 tvg-id="ParlimenMalaysia.my" http-referrer="https://rtm-player.glueapi.io/",RTM Parlimen (Dewan Negara) [Geo-blocked]
#EXTINF:-1 tvg-id="RTMASEAN.my",RTM ASEAN
https://d25tgymtnqzu8s.cloudfront.net/event/smil:event1/chunklist_b2596000_slENG.m3u8
#EXTINF:-1 tvg-id="RTMParlimenDewanNegara.my" http-referrer="https://rtm-player.glueapi.io/",RTM Parlimen (Dewan Negara) [Geo-blocked]
#EXTVLCOPT:http-referrer=https://rtm-player.glueapi.io/
https://d25tgymtnqzu8s.cloudfront.net/smil:negara/playlist.m3u8?id=8
#EXTINF:-1 tvg-id="ParlimenMalaysia.my" http-referrer="https://rtm-player.glueapi.io/",RTM Parlimen (Dewan Rakyat) [Geo-blocked]
#EXTINF:-1 tvg-id="RTMParlimenDewanRakyat.my" http-referrer="https://rtm-player.glueapi.io/",RTM Parlimen (Dewan Rakyat) [Geo-blocked]
#EXTVLCOPT:http-referrer=https://rtm-player.glueapi.io/
https://d25tgymtnqzu8s.cloudfront.net/smil:rakyat/playlist.m3u8?id=7
#EXTINF:-1 tvg-id="TV1.my",RTM TV 1 [Geo-blocked]
#EXTINF:-1 tvg-id="TV1.my",TV1 [Geo-blocked]
https://d25tgymtnqzu8s.cloudfront.net/smil:tv1/manifest.mpd
#EXTINF:-1 tvg-id="TV2.my",RTM TV 2 [Geo-blocked]
#EXTINF:-1 tvg-id="TV2.my",TV2 [Geo-blocked]
https://d25tgymtnqzu8s.cloudfront.net/smil:tv2/manifest.mpd
#EXTINF:-1 tvg-id="SukanRTM.my",Sukan RTM [Geo-blocked]
https://d25tgymtnqzu8s.cloudfront.net/smil:sukan/manifest.mpd
@ -42,7 +44,9 @@ https://tonton-live-switch-ssar.akamaized.net/stream-tv3/master.m3u8?bpkio_servi
https://d25tgymtnqzu8s.cloudfront.net/smil:tv6/playlist.m3u8?id=6
#EXTINF:-1 tvg-id="TV9.my",TV9
https://tonton-live-switch-ssar.akamaized.net/stream-tv9/master.m3u8?bpkio_serviceid=6c0958d82a830a02ca0936d9cfab8311
#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="NTV7.my",NTV7
https://tonton-live-switch-ssar.akamaized.net/stream-ntv7/master.m3u8?bpkio_serviceid=6c0958d82a830a02ca0936d9cfab8311
#EXTINF:-1 tvg-id="TVIKIM.my",TVIKIM
https://edge-sg1.vediostream.com/abr/tvikim/playlist.m3u8
#EXTINF:-1 tvg-id="RTMASEAN.my",RTM ASEAN
https://d25tgymtnqzu8s.cloudfront.net/event/smil:event1/chunklist_b2596000_slENG.m3u8

Some files were not shown because too many files have changed in this diff Show more