diff --git a/scripts/commands/issue/validate.ts b/scripts/commands/issue/validate.ts index a5bd0e2f95..bd7acecd51 100644 --- a/scripts/commands/issue/validate.ts +++ b/scripts/commands/issue/validate.ts @@ -60,8 +60,6 @@ async function main() { .split(/\r?\n/) .filter(Boolean) .forEach((link: string) => { - errors = errors.concat(validateStreamUrl(link)) - const found: Stream = streams.first((_stream: Stream) => _stream.url === link.trim()) if (!found) { errors.push(`The stream with the URL "${link}" is missing from the playlists`) @@ -80,9 +78,11 @@ async function main() { } } - const streamId = data.getString('stream_id') - if (streamId) { - errors = errors.concat(validateStreamId(streamId)) + if (!data.isDeleted('stream_id')) { + const streamId = data.getString('stream_id') + if (streamId) { + errors = errors.concat(validateStreamId(streamId)) + } } } diff --git a/scripts/commands/playlist/test.ts b/scripts/commands/playlist/test.ts index 0f5629ec6a..447455b7fb 100644 --- a/scripts/commands/playlist/test.ts +++ b/scripts/commands/playlist/test.ts @@ -5,8 +5,8 @@ import { Logger, Collection } from '@freearhey/core' import { program, OptionValues } from 'commander' import { Storage } from '@freearhey/storage-js' import { Playlist, Stream } from '../../models' +import { loadData, data } from '../../api' import { truncate } from '../../utils' -import { loadData } from '../../api' import { eachLimit } from 'async' import dns from 'node:dns' import chalk from 'chalk' @@ -70,6 +70,10 @@ async function main() { }) const files = program.args.length ? program.args : await rootStorage.list(`${STREAMS_DIR}/*.m3u`) streams = await parser.parse(files) + streams = streams.map((stream: Stream) => { + stream.setGuides(data.guidesGroupedByStreamId.get(stream.getId())) + return stream + }) logger.info(`found ${streams.count()} streams`) if (streams.count() > LIVE_UPDATE_MAX_STREAMS) isLiveUpdateEnabled = false diff --git a/scripts/commands/playlist/validate.ts b/scripts/commands/playlist/validate.ts index 8f420b8577..30bb066b90 100644 --- a/scripts/commands/playlist/validate.ts +++ b/scripts/commands/playlist/validate.ts @@ -53,7 +53,13 @@ async function main() { const log = new Collection() streams.forEach((stream: Stream) => { - if (stream.channel) { + if (!stream.channel) { + log.add({ + type: 'warning', + line: stream.getLine(), + message: `"${stream.url}" is missing a channel ID` + }) + } else { const channel = data.channelsKeyById.get(stream.channel) if (!channel) { log.add({ @@ -62,6 +68,23 @@ async function main() { message: `"${stream.tvgId}" is not in the database` }) } + + if (!stream.feed) { + log.add({ + type: 'warning', + line: stream.getLine(), + message: `"${stream.url}" is missing a feed ID` + }) + } else { + const feed = data.feedsKeyByStreamId.get(stream.getId()) + if (!feed) { + log.add({ + type: 'warning', + line: stream.getLine(), + message: `There is no feed with the ID "${stream.feed}" in the database for the "${stream.channel}" channel` + }) + } + } } const isDuplicate = stream.url && buffer.has(stream.url) diff --git a/scripts/commands/report/create.ts b/scripts/commands/report/create.ts index d6e94aef1a..2fafc6a15f 100644 --- a/scripts/commands/report/create.ts +++ b/scripts/commands/report/create.ts @@ -140,35 +140,57 @@ async function main() { const channelSearchRequests = discussions.filter( (discussion: Discussion) => discussion.category === 'Channel Search' ) - const channelSearchRequestsBuffer = new Dictionary() + + const requestsWithFeed = new Set() + channelSearchRequests.forEach((discussion: Discussion) => { const streamId = discussion.data.getString('stream_id') || discussion.data.getString('channel_id') || '' const [channelId, feedId] = streamId.split('@') - const result = { + if (channelId && feedId) { + requestsWithFeed.add(channelId) + } + }) + + const seenStreamIds = new Set() + + channelSearchRequests.forEach((discussion: Discussion) => { + const streamId = + discussion.data.getString('stream_id') || discussion.data.getString('channel_id') || '' + const [channelId, feedId] = streamId.split('@') + const channelData = channelId ? data.channelsKeyById.get(channelId) : null + + const isExactDuplicate = streamId && seenStreamIds.has(streamId) + const overlappedByFeeds = !feedId && channelId && requestsWithFeed.has(channelId) + + const rules = [ + { status: status.MISSING_CHANNEL_ID, when: !channelId }, + { status: status.INVALID_CHANNEL_ID, when: data.channelsKeyById.missing(channelId) }, + { status: status.DUPLICATE_REQUEST, when: isExactDuplicate || overlappedByFeeds }, + { + status: status.CHANNEL_BLOCKED, + when: data.blocklistRecordsGroupedByChannel.has(channelId) + }, + { status: status.FULFILLED, when: streamsGroupedById.has(streamId) }, + { status: status.FULFILLED, when: !feedId && streamsGroupedByChannel.has(channelId) }, + { status: status.CHANNEL_CLOSED, when: channelData && channelData.isClosed() } + ] + + const matchedRule = rules.find(rule => rule.when) + const finalStatus = matchedRule ? matchedRule.status : status.PENDING + + if (streamId) { + seenStreamIds.add(streamId) + } + + report.add({ issueNumber: discussion.number, type: 'channel search', streamId: streamId || undefined, streamUrl: undefined, - status: status.PENDING - } - - if (!channelId) result.status = status.MISSING_CHANNEL_ID - else if (data.channelsKeyById.missing(channelId)) result.status = status.INVALID_CHANNEL_ID - else if (channelSearchRequestsBuffer.has(streamId)) result.status = status.DUPLICATE_REQUEST - else if (data.blocklistRecordsGroupedByChannel.has(channelId)) - result.status = status.CHANNEL_BLOCKED - else if (streamsGroupedById.has(streamId)) result.status = status.FULFILLED - else if (!feedId && streamsGroupedByChannel.has(channelId)) result.status = status.FULFILLED - else { - const channelData = data.channelsKeyById.get(channelId) - if (channelData && channelData.isClosed()) result.status = status.CHANNEL_CLOSED - } - - channelSearchRequestsBuffer.set(streamId, true) - - report.add(result) + status: finalStatus + }) }) report = report.sortBy(item => item.issueNumber).filter(item => item.status !== status.PENDING) diff --git a/scripts/core/dataSet.ts b/scripts/core/dataSet.ts index 14dd1771f4..9e41de55ac 100644 --- a/scripts/core/dataSet.ts +++ b/scripts/core/dataSet.ts @@ -14,23 +14,25 @@ export class DataSet { return this._data.missing(key) || this._data.get(key) === undefined } + isDeleted(key: string): boolean { + const deleteSymbol = '~' + + return this._data.get(key) === deleteSymbol + } + getBoolean(key: string): boolean { return Boolean(this._data.get(key)) } getString(key: string): string | undefined { - const deleteSymbol = '~' - - return this._data.get(key) === deleteSymbol ? '' : this._data.get(key) + return this._data.get(key) } getArray(key: string): string[] | undefined { - const deleteSymbol = '~' - if (this._data.missing(key)) return undefined const value = this._data.get(key) - return !value || value === deleteSymbol ? [] : value.split('\r\n') + return !value || this.isDeleted(key) ? [] : value.split('\r\n') } } diff --git a/scripts/models/stream.ts b/scripts/models/stream.ts index 173f4554f5..9bc3fbff4a 100644 --- a/scripts/models/stream.ts +++ b/scripts/models/stream.ts @@ -33,20 +33,28 @@ export class Stream extends sdk.Models.Stream { } updateWithIssue(dataSet: DataSet): this { - const streamId = dataSet.getString('stream_id') || '' - const [channelId, feedId] = streamId.split('@') - - if (channelId) { - this.channel = channelId - this.feed = feedId + if (dataSet.isDeleted('stream_id')) { + this.channel = '' + this.feed = '' this.updateTvgId().updateTitle().updateFilepath() + } else if (dataSet.has('stream_id')) { + const streamId = dataSet.getString('stream_id') || '' + const [channelId, feedId] = streamId.split('@') + + if (channelId) { + this.channel = channelId + this.feed = feedId + this.updateTvgId().updateTitle().updateFilepath() + } } const data = { - label: dataSet.getString('label'), - quality: dataSet.getString('quality'), - httpUserAgent: dataSet.getString('http_user_agent'), - httpReferrer: dataSet.getString('http_referrer') + label: dataSet.isDeleted('label') ? '' : dataSet.getString('label'), + quality: dataSet.isDeleted('quality') ? '' : dataSet.getString('quality'), + httpUserAgent: dataSet.isDeleted('http_user_agent') + ? '' + : dataSet.getString('http_user_agent'), + httpReferrer: dataSet.isDeleted('http_referrer') ? '' : dataSet.getString('http_referrer') } if (data.label !== undefined) this.label = data.label @@ -318,8 +326,9 @@ export class Stream extends sdk.Models.Stream { } updateTvgId(): this { - if (!this.channel) return this - if (this.feed) { + if (!this.channel) { + this.tvgId = '' + } else if (this.feed) { this.tvgId = `${this.channel}@${this.feed}` } else { this.tvgId = this.channel diff --git a/scripts/utils.ts b/scripts/utils.ts index 2b354e6657..6e31eafc9b 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -244,9 +244,9 @@ export async function loadDiscussions() { }) const query = ` - query ($owner: String!, $repo: String!, $cursor: String) { + query ($owner: String!, $repo: String!, $cursor: String, $orderBy: DiscussionOrder) { repository(owner: $owner, name: $repo) { - discussions(first: 100, after: $cursor, states: OPEN) { + discussions(first: 100, after: $cursor, states: OPEN, orderBy: $orderBy) { nodes { number body @@ -265,7 +265,11 @@ export async function loadDiscussions() { const result = await octokit.graphql.paginate(query, { owner: 'iptv-org', - repo: 'iptv' + repo: 'iptv', + orderBy: { + field: 'CREATED_AT', + direction: 'ASC' + } }) discussions = result.repository.discussions.nodes diff --git a/tests/__data__/expected/issue_validate/logs/streams_edit.txt b/tests/__data__/expected/issue_validate/logs/streams_edit.txt index 7a2f28bdab..f2f262d908 100644 --- a/tests/__data__/expected/issue_validate/logs/streams_edit.txt +++ b/tests/__data__/expected/issue_validate/logs/streams_edit.txt @@ -1,3 +1,2 @@ The request contains error(s): -- The stream with the URL "https://livestream.telvue.com/templeuni1/f7b44cfafd5c52223d5498196c8a2e7b.sdp/playlist.m3u8" is missing from the playlists -- There is no channel with the ID "boo.us" in the database \ No newline at end of file +- The stream with the URL "https://jmp2.uk/plu-5a74b8e1e22a61737979c6bf.m3u8" is missing from the playlists \ No newline at end of file diff --git a/tests/__data__/expected/playlist_test/ag.m3u b/tests/__data__/expected/playlist_test/ag.m3u index 16dc963ff6..8be0f82183 100644 --- a/tests/__data__/expected/playlist_test/ag.m3u +++ b/tests/__data__/expected/playlist_test/ag.m3u @@ -1,3 +1,3 @@ -#EXTM3U -#EXTINF:-1 tvg-id="ABSTV.ag",ABS TV +#EXTM3U x-tvg-url="https://example.com/guide.xml.gz" +#EXTINF:-1 tvg-id="ABSTV.ag@SD",ABS TV https://tego-cdn2a.sibercdn.com/Live_TV-ABSTV-10/tracks-v3a1/rewind-7200.m3u8?token=e5f61e7be8363eb781b4bdfe591bf917dd529c1a-SjY3NzRTbDZQNnFQVkZaNkZja2RxV3JKc1VBa05zQkdMNStJakRGV0VTTzNrOEVGVUlIQmxta1NLV0o3bzdVdQ-1736094545-1736008145 diff --git a/tests/__data__/expected/playlist_update/playlist_update.log b/tests/__data__/expected/playlist_update/playlist_update.log index e715c918c2..41f10574db 100644 --- a/tests/__data__/expected/playlist_update/playlist_update.log +++ b/tests/__data__/expected/playlist_update/playlist_update.log @@ -1 +1 @@ -closes #14175, closes #14105, closes #14104, closes #14057, closes #14034, closes #13964, closes #13893, closes #13881, closes #13793, closes #13751, closes #13715, closes #14110, closes #14120, closes #14151, closes #14150 \ No newline at end of file +closes #14175, closes #14105, closes #14104, closes #14057, closes #14034, closes #13964, closes #13893, closes #13881, closes #13793, closes #13751, closes #13715, closes #14110, closes #14121, closes #14151, closes #14150, closes #39097 \ No newline at end of file diff --git a/tests/__data__/expected/playlist_update/streams/uk.m3u b/tests/__data__/expected/playlist_update/streams/uk.m3u index 9caa57c157..8ab98201bf 100644 --- a/tests/__data__/expected/playlist_update/streams/uk.m3u +++ b/tests/__data__/expected/playlist_update/streams/uk.m3u @@ -3,5 +3,7 @@ http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 #EXTINF:-1 tvg-id="BBCNews.uk",BBC News HD (480p) [Geo-blocked] http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8 +#EXTINF:-1 tvg-id="",Fox Sports (720p) +https://jmp2.uk/plu-5a74b8e1e22a61737979c6bf.m3u8 #EXTINF:-1 tvg-id="BeanoTV.uk@SD",Beano TV (1080p) https://a5b4bacecd47433dad06d3189fc7422e.mediatailor.us-east-1.amazonaws.com/v1/manifest/04fd913bb278d8775298c26fdca9d9841f37601f/RakutenTV-eu_BeanoTV/b1f233d5-847c-437d-aa4f-f73e67a85323/2.m3u8|Referer="https://referer.xyz/"|User-Agent="Mozilla/5.0 (iPhone; CPU iPhone OS 17_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1"|Origin="https://origin.xyz" diff --git a/tests/__data__/input/data/feeds.json b/tests/__data__/input/data/feeds.json index ba10a5e7f6..b385f6da9e 100644 --- a/tests/__data__/input/data/feeds.json +++ b/tests/__data__/input/data/feeds.json @@ -873,5 +873,21 @@ "America/Port_of_Spain" ], "video_format": "576i" + }, + { + "channel": "Channel7.bz", + "id": "SD", + "name": "SD", + "is_main": true, + "broadcast_area": [ + "c/BZ" + ], + "languages": [ + "eng" + ], + "timezones": [ + "America/New_York" + ], + "video_format": "576i" } ] \ No newline at end of file diff --git a/tests/__data__/input/data/guides.json b/tests/__data__/input/data/guides.json index 14c2cdce98..4381177832 100644 --- a/tests/__data__/input/data/guides.json +++ b/tests/__data__/input/data/guides.json @@ -113,5 +113,25 @@ "format": "XML" } ] + }, + { + "channel": "ABSTV.ag", + "feed": "SD", + "site": "example.com", + "site_id": "#", + "site_name": "ABS TV", + "lang": "es", + "sources": [ + { + "host": "example2.com", + "url": "https://example2.com/guide.xml", + "format": "XML" + }, + { + "host": "example.com", + "url": "https://example.com/guide.xml.gz", + "format": "GZIP" + } + ] } ] \ No newline at end of file diff --git a/tests/__data__/input/issues.js b/tests/__data__/input/issues.js index c51bc99da3..ad74fce337 100644 --- a/tests/__data__/input/issues.js +++ b/tests/__data__/input/issues.js @@ -1779,15 +1779,15 @@ module.exports = [ state_reason: null }, { - url: 'https://api.github.com/repos/iptv-org/iptv/issues/14120', + url: 'https://api.github.com/repos/iptv-org/iptv/issues/14121', repository_url: 'https://api.github.com/repos/iptv-org/iptv', - labels_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14120/labels{/name}', - comments_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14120/comments', - events_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14120/events', - html_url: 'https://github.com/iptv-org/iptv/issues/14120', + labels_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14121/labels{/name}', + comments_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14121/comments', + events_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14121/events', + html_url: 'https://github.com/iptv-org/iptv/issues/14121', id: 1884922249, node_id: 'I_kwDOCWUK8M5wWaGJ', - number: 14120, + number: 14121, title: 'Edit: Tele2000', user: { login: 'freearhey', @@ -1842,7 +1842,7 @@ module.exports = [ active_lock_reason: null, body: '### Stream URL\n\nhttps://ythls.onrender.com/channel/UC40TUSUx490U5uR1lZt3Ajg.m3u8\n\n### Stream ID\n\n_No response_\n\n### Quality\n\nNone\n\n### Label\n\nNone\n\n### HTTP User-Agent\n\n_No response_\n\n### HTTP Referrer\n\n_No response_\n\n### Notes\n\n_No response_\n\n### Contributing Guide\n\n- [X] I have read [Contributing Guide](https://github.com/iptv-org/iptv/blob/master/CONTRIBUTING.md)', reactions: { - url: 'https://api.github.com/repos/iptv-org/iptv/issues/14120/reactions', + url: 'https://api.github.com/repos/iptv-org/iptv/issues/14121/reactions', total_count: 0, '+1': 0, '-1': 0, @@ -1853,7 +1853,7 @@ module.exports = [ rocket: 0, eyes: 0 }, - timeline_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14120/timeline', + timeline_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14121/timeline', performed_via_github_app: null, state_reason: null }, @@ -2472,5 +2472,84 @@ module.exports = [ timeline_url: 'https://api.github.com/repos/iptv-org/iptv/issues/15175/timeline', performed_via_github_app: null, state_reason: null + }, + { + url: 'https://api.github.com/repos/iptv-org/iptv/issues/39097', + repository_url: 'https://api.github.com/repos/iptv-org/iptv', + labels_url: 'https://api.github.com/repos/iptv-org/iptv/issues/39097/labels{/name}', + comments_url: 'https://api.github.com/repos/iptv-org/iptv/issues/39097/comments', + events_url: 'https://api.github.com/repos/iptv-org/iptv/issues/39097/events', + html_url: 'https://github.com/iptv-org/iptv/issues/39097', + id: 1884922249, + node_id: 'I_kwDOCWUK8M5wWaGJ', + number: 39097, + title: 'Edit: Fox Sports', + user: { + login: 'freearhey', + id: 7253922, + node_id: 'MDQ6VXNlcjcyNTM5MjI=', + avatar_url: 'https://avatars.githubusercontent.com/u/7253922?v=4', + gravatar_id: '', + url: 'https://api.github.com/users/freearhey', + html_url: 'https://github.com/freearhey', + followers_url: 'https://api.github.com/users/freearhey/followers', + following_url: 'https://api.github.com/users/freearhey/following{/other_user}', + gists_url: 'https://api.github.com/users/freearhey/gists{/gist_id}', + starred_url: 'https://api.github.com/users/freearhey/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/freearhey/subscriptions', + organizations_url: 'https://api.github.com/users/freearhey/orgs', + repos_url: 'https://api.github.com/users/freearhey/repos', + events_url: 'https://api.github.com/users/freearhey/events{/privacy}', + received_events_url: 'https://api.github.com/users/freearhey/received_events', + type: 'User', + site_admin: false + }, + labels: [ + { + id: 5923498886, + node_id: 'LA_kwDOCWUK8M8AAAABYRFrhg', + url: 'https://api.github.com/repos/iptv-org/iptv/labels/approved', + name: 'approved', + color: '85ddde', + default: false, + description: '' + }, + { + id: 5923508587, + node_id: 'LA_kwDOCWUK8M8AAAABYRGRaw', + url: 'https://api.github.com/repos/iptv-org/iptv/labels/streams:edit', + name: 'streams:edit', + color: '017ff9', + default: false, + description: 'Request to add a new link to a playlist' + } + ], + state: 'open', + locked: false, + assignee: null, + assignees: [], + milestone: null, + comments: 1, + created_at: '2023-09-07T00:30:51Z', + updated_at: '2023-09-07T00:48:23Z', + closed_at: null, + author_association: 'COLLABORATOR', + active_lock_reason: null, + body: '### Stream URL\n\nhttps://jmp2.uk/plu-5a74b8e1e22a61737979c6bf.m3u8\n\n### Stream ID\n\n~\n\n### Quality\n\n720p\n\n### Label\n\nNone\n\n### HTTP User-Agent\n\nNone\n\n### HTTP Referrer\n\n_No response_\n\n### Notes\n\n_No response_\n\n### Contributing Guide\n\n- [X] I have read [Contributing Guide](https://github.com/iptv-org/iptv/blob/master/CONTRIBUTING.md)', + reactions: { + url: 'https://api.github.com/repos/iptv-org/iptv/issues/39097/reactions', + total_count: 0, + '+1': 0, + '-1': 0, + laugh: 0, + hooray: 0, + confused: 0, + heart: 0, + rocket: 0, + eyes: 0 + }, + timeline_url: 'https://api.github.com/repos/iptv-org/iptv/issues/39097/timeline', + performed_via_github_app: null, + state_reason: null } ] diff --git a/tests/__data__/input/playlist_test/streams/ag.m3u b/tests/__data__/input/playlist_test/streams/ag.m3u index 0ec3908d50..9fd1a8bdb2 100644 --- a/tests/__data__/input/playlist_test/streams/ag.m3u +++ b/tests/__data__/input/playlist_test/streams/ag.m3u @@ -1,5 +1,5 @@ -#EXTM3U -#EXTINF:-1 tvg-id="ABSTV.ag",ABS TV +#EXTM3U x-tvg-url="https://example.com/guide.xml.gz" +#EXTINF:-1 tvg-id="ABSTV.ag@SD",ABS TV https://tego-cdn2a.sibercdn.com/Live_TV-ABSTV-10/tracks-v3a1/rewind-7200.m3u8?token=e5f61e7be8363eb781b4bdfe591bf917dd529c1a-SjY3NzRTbDZQNnFQVkZaNkZja2RxV3JKc1VBa05zQkdMNStJakRGV0VTTzNrOEVGVUlIQmxta1NLV0o3bzdVdQ-1736094545-1736008145 #EXTINF:-1 tvg-id="ABSTV.ag@HD",ABS TV (1080p) https://query-streamlink.herokuapp.com/iptv-query?streaming-ip=https://www.twitch.tv/absliveantigua3 diff --git a/tests/__data__/input/playlist_update/streams/uk.m3u b/tests/__data__/input/playlist_update/streams/uk.m3u index 033f5a36b5..cdc3234c37 100644 --- a/tests/__data__/input/playlist_update/streams/uk.m3u +++ b/tests/__data__/input/playlist_update/streams/uk.m3u @@ -3,3 +3,5 @@ http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/index.m3u8 #EXTINF:-1 tvg-id="BBCNews.uk",BBC News HD (480p) [Geo-blocked] http://1111296894.rsc.cdn77.org/LS-ATL-54548-6/playlist.m3u8 +#EXTINF:-1 tvg-id="FoxSports.uk",Fox Sports +https://jmp2.uk/plu-5a74b8e1e22a61737979c6bf.m3u8 diff --git a/tests/__data__/input/playlist_validate/missing_channel_id.m3u b/tests/__data__/input/playlist_validate/missing_channel_id.m3u new file mode 100644 index 0000000000..51c64a6acd --- /dev/null +++ b/tests/__data__/input/playlist_validate/missing_channel_id.m3u @@ -0,0 +1,3 @@ +#EXTM3U +#EXTINF:-1 tvg-id="",Channel 7 +https://example.com/playlist2.m3u8 diff --git a/tests/__data__/input/playlist_validate/missing_feed_id.m3u b/tests/__data__/input/playlist_validate/missing_feed_id.m3u new file mode 100644 index 0000000000..d6330d145c --- /dev/null +++ b/tests/__data__/input/playlist_validate/missing_feed_id.m3u @@ -0,0 +1,3 @@ +#EXTM3U +#EXTINF:-1 tvg-id="Channel7.bz",Channel 7 +https://example.com/playlist2.m3u8 diff --git a/tests/__data__/input/playlist_validate/us_blocked.m3u b/tests/__data__/input/playlist_validate/us_blocked.m3u index 3a5e4bd531..10cd9324fc 100644 --- a/tests/__data__/input/playlist_validate/us_blocked.m3u +++ b/tests/__data__/input/playlist_validate/us_blocked.m3u @@ -1,7 +1,7 @@ #EXTM3U #EXTINF:-1 tvg-id="FoxSports2.us@Asia",Fox Sports 2 Asia (Thai) (720p) https://example.com/playlist.m3u8 -#EXTINF:-1 tvg-id="TVN.pl",TVN +#EXTINF:-1 tvg-id="TVN.pl@SD",TVN https://example.com/playlist2.m3u8 -#EXTINF:-1 tvg-id="EverydayHeroes.us",Everyday Heroes (720p) +#EXTINF:-1 tvg-id="EverydayHeroes.us@SD",Everyday Heroes (720p) https://a.jsrdn.com/broadcast/7b1451fa52/+0000/c.m3u8 diff --git a/tests/__data__/input/playlist_validate/wrong_id.m3u b/tests/__data__/input/playlist_validate/wrong_channel_id.m3u similarity index 93% rename from tests/__data__/input/playlist_validate/wrong_id.m3u rename to tests/__data__/input/playlist_validate/wrong_channel_id.m3u index 94d9cc2bc8..46b4d07619 100644 --- a/tests/__data__/input/playlist_validate/wrong_id.m3u +++ b/tests/__data__/input/playlist_validate/wrong_channel_id.m3u @@ -1,5 +1,5 @@ #EXTM3U -#EXTINF:-1 tvg-id="qib22lAq1L.us",ABC (720p) +#EXTINF:-1 tvg-id="qib22lAq1L.us@SD",ABC (720p) #EXTVLCOPT:http-referrer=http://imn.iq #EXTVLCOPT:http-user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 #KODIPROP:inputstream=inputstream.adaptive diff --git a/tests/__data__/input/playlist_validate/wrong_feed_id.m3u b/tests/__data__/input/playlist_validate/wrong_feed_id.m3u new file mode 100644 index 0000000000..7c729db6a7 --- /dev/null +++ b/tests/__data__/input/playlist_validate/wrong_feed_id.m3u @@ -0,0 +1,3 @@ +#EXTM3U +#EXTINF:-1 tvg-id="Channel7.bz@HD",Channel 7 +https://example.com/playlist2.m3u8 diff --git a/tests/commands/issue/validate.test.ts b/tests/commands/issue/validate.test.ts index 061fb65dc7..fca2145e95 100644 --- a/tests/commands/issue/validate.test.ts +++ b/tests/commands/issue/validate.test.ts @@ -43,7 +43,7 @@ describe('issue:validate', () => { }) it('can handle streams:edit request', () => { - const body = issues.find(issue => issue.number === 14120)?.body + const body = issues.find(issue => issue.number === 39097)?.body const cmd = `${ENV_VAR} npm run issue:validate --- --body="${body}" --labels="approved,streams:edit"` try { diff --git a/tests/commands/playlist/validate.test.ts b/tests/commands/playlist/validate.test.ts index e87ce1843b..86692fba87 100644 --- a/tests/commands/playlist/validate.test.ts +++ b/tests/commands/playlist/validate.test.ts @@ -12,7 +12,9 @@ describe('playlist:validate', () => { it('show an error if channel id in the blocklist', () => { const cmd = `${ENV_VAR} npm run playlist:validate -- us_blocked.m3u` try { - execSync(cmd, { encoding: 'utf8' }) + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(cmd, stdout) + process.exit(0) } catch (error) { if (process.env.DEBUG === 'true') console.log(cmd, error) expect((error as ExecError).stdout).toContain('us_blocked.m3u') @@ -26,22 +28,64 @@ describe('playlist:validate', () => { } }) - it('show a warning if channel has wrong id', () => { - const cmd = `${ENV_VAR} npm run playlist:validate -- wrong_id.m3u` + it('show a warning if stream is missing a channel id', () => { + const cmd = `${ENV_VAR} npm run playlist:validate -- missing_channel_id.m3u` try { - execSync(cmd, { encoding: 'utf8' }) + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(cmd, stdout) + expect(stdout).toContain( + 'missing_channel_id.m3u\n 2 warning "https://example.com/playlist2.m3u8" is missing a channel ID\n\n1 problems (0 errors, 1 warnings)\n' + ) } catch (error) { if (process.env.DEBUG === 'true') console.log(cmd, error) - expect((error as ExecError).stdout).toContain( - 'wrong_id.m3u\n 2 warning "qib22lAq1L.us" is not in the database\n\n1 problems (0 errors, 1 warnings)\n' + } + }) + + it('show a warning if stream has wrong channel id', () => { + const cmd = `${ENV_VAR} npm run playlist:validate -- wrong_channel_id.m3u` + try { + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(cmd, stdout) + expect(stdout).toContain( + 'wrong_channel_id.m3u\n 2 warning "qib22lAq1L.us" is not in the database\n\n1 problems (0 errors, 1 warnings)\n' ) + } catch (error) { + if (process.env.DEBUG === 'true') console.log(cmd, error) + } + }) + + it('show a warning if stream is missing a feed id', () => { + const cmd = `${ENV_VAR} npm run playlist:validate -- missing_feed_id.m3u` + try { + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(cmd, stdout) + expect(stdout).toContain( + 'missing_feed_id.m3u\n 2 warning "https://example.com/playlist2.m3u8" is missing a feed ID\n\n1 problems (0 errors, 1 warnings)\n' + ) + } catch (error) { + if (process.env.DEBUG === 'true') console.log(cmd, error) + } + }) + + it('show a warning if stream has a wrong feed id', () => { + const cmd = `${ENV_VAR} npm run playlist:validate -- wrong_feed_id.m3u` + try { + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(cmd, stdout) + expect(stdout).toContain( + 'wrong_feed_id.m3u\n 2 warning There is no feed with the ID "HD" in the database for the "Channel7.bz" channel\n\n1 problems (0 errors, 1 warnings)\n' + ) + } catch (error) { + if (process.env.DEBUG === 'true') console.log(cmd, error) } }) it('show a error if stream has an invalid url', () => { const cmd = `${ENV_VAR} npm run playlist:validate -- invalid_url.m3u` try { - execSync(cmd, { encoding: 'utf8' }) + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(cmd, stdout) + process.exit(0) } catch (error) { if (process.env.DEBUG === 'true') console.log(cmd, error) expect((error as ExecError).stdout).toContain('invalid_url.m3u') @@ -54,6 +98,7 @@ describe('playlist:validate', () => { it('skip the file if it does not exist', () => { const cmd = `${ENV_VAR} npm run playlist:validate -- missing.m3u` - execSync(cmd, { encoding: 'utf8' }) + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(cmd, stdout) }) }) diff --git a/tests/commands/report/create.test.ts b/tests/commands/report/create.test.ts index 7dd3db603a..3c71b0ca41 100644 --- a/tests/commands/report/create.test.ts +++ b/tests/commands/report/create.test.ts @@ -25,6 +25,7 @@ describe('report:create', () => { │ 8 │ 19957 │ 'channel search' │ '13thStreet.au' │ undefined │ 'channel_closed' │ │ 9 │ 20956 │ 'channel search' │ 'IONTV.us' │ undefined │ 'fulfilled' │ │ 10 │ 25157 │ 'streams:add' │ 'OnTimeSports.eg@SD' │ 'OnTime Sports SD.mu38' │ 'invalid_stream_url' │ +│ 11 │ 39097 │ 'streams:edit' │ '~' │ 'https://jmp2.uk/plu-5a74b8e1e22a61737979c6bf.m3u8' │ 'nonexistent_link' │ └─────────┴─────────────┴──────────────────┴─────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────┘`) ).toBe(true) })