diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 21dfb44b9..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "rules": { - "no-case-declarations": "off", - "indent": [ - "error", - 2, - { "SwitchCase": 1 } - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "never" - ] - } -} diff --git a/.github/ISSUE_TEMPLATE/----streams_edit.yml b/.github/ISSUE_TEMPLATE/----streams_edit.yml index 66d85ca4a..de3afb11a 100644 --- a/.github/ISSUE_TEMPLATE/----streams_edit.yml +++ b/.github/ISSUE_TEMPLATE/----streams_edit.yml @@ -15,7 +15,7 @@ body: - type: markdown attributes: value: | - What exactly needs to be changed? + What exactly needs to be changed? To delete an existing value without replacement use the `~` symbol. - type: input attributes: @@ -35,6 +35,7 @@ body: - 576p - 480p - 360p + - '~' - type: dropdown attributes: @@ -43,6 +44,7 @@ body: options: - 'Not 24/7' - 'Geo-blocked' + - '~' - type: input attributes: diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..f22174332 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,46 @@ +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import globals from "globals"; +import tsParser from "@typescript-eslint/parser"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all +}); + +export default [ + ...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended"), + { + plugins: { + "@typescript-eslint": typescriptEslint, + }, + + languageOptions: { + globals: { + ...globals.browser, + }, + + parser: tsParser, + ecmaVersion: "latest", + sourceType: "module", + }, + + rules: { + "no-case-declarations": "off", + + indent: ["error", 2, { + SwitchCase: 1, + }], + + "linebreak-style": ["error", "unix"], + quotes: ["error", "single"], + semi: ["error", "never"], + }, + }, +]; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 130835051..d34ae1d21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "^9.21.0", "@freearhey/core": "^0.2.1", "@octokit/core": "^4.2.1", "@octokit/plugin-paginate-rest": "^7.1.2", @@ -24,6 +26,7 @@ "cli-progress": "^3.12.0", "commander": "^8.3.0", "eslint": "^9.17.0", + "globals": "^16.0.0", "iptv-playlist-parser": "^0.13.0", "jest-expect-message": "^1.1.3", "lodash": "^4.17.21", @@ -917,9 +920,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -938,10 +941,21 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", - "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz", + "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -2982,6 +2996,14 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/eslint/node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3522,9 +3544,9 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", "engines": { "node": ">=18" }, @@ -6745,9 +6767,9 @@ } }, "@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -6758,12 +6780,19 @@ "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==" + } } }, "@eslint/js": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", - "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==" + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz", + "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==" }, "@eslint/object-schema": { "version": "2.1.5", @@ -8281,6 +8310,11 @@ "optionator": "^0.9.3" }, "dependencies": { + "@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -8685,9 +8719,9 @@ } }, "globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==" + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==" }, "graceful-fs": { "version": "4.2.9", diff --git a/package.json b/package.json index cd033bce7..0574d252c 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,8 @@ "private": true, "license": "MIT", "dependencies": { + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "^9.21.0", "@freearhey/core": "^0.2.1", "@octokit/core": "^4.2.1", "@octokit/plugin-paginate-rest": "^7.1.2", @@ -52,6 +54,7 @@ "cli-progress": "^3.12.0", "commander": "^8.3.0", "eslint": "^9.17.0", + "globals": "^16.0.0", "iptv-playlist-parser": "^0.13.0", "jest-expect-message": "^1.1.3", "lodash": "^4.17.21", diff --git a/scripts/commands/playlist/update.ts b/scripts/commands/playlist/update.ts index 7dc54bc2f..a1ed93d83 100644 --- a/scripts/commands/playlist/update.ts +++ b/scripts/commands/playlist/update.ts @@ -56,7 +56,7 @@ async function removeStreams(loader: IssueLoader) { const data = issue.data if (data.missing('broken_links')) return - const brokenLinks = data.get('broken_links').split(/\r?\n/).filter(Boolean) + const brokenLinks = data.getString('broken_links').split(/\r?\n/).filter(Boolean) let changed = false brokenLinks.forEach(link => { @@ -79,27 +79,27 @@ async function editStreams(loader: IssueLoader) { if (data.missing('stream_url')) return let stream = streams.first( - (_stream: Stream) => _stream.url === data.get('stream_url') + (_stream: Stream) => _stream.url === data.getString('stream_url') ) as Stream if (!stream) return if (data.has('channel_id')) { - const channel = groupedChannels.get(data.get('channel_id')) + const channel = groupedChannels.get(data.getString('channel_id')) if (!channel) return - stream.channel = data.get('channel_id') + stream.channel = data.getString('channel_id') stream.filepath = `${channel.country.toLowerCase()}.m3u` stream.line = -1 stream.name = channel.name } - if (data.has('label')) stream.label = data.get('label') - if (data.has('quality')) stream.quality = data.get('quality') - if (data.has('timeshift')) stream.timeshift = data.get('timeshift') - if (data.has('user_agent')) stream.userAgent = data.get('user_agent') - if (data.has('http_referrer')) stream.httpReferrer = data.get('http_referrer') + if (data.has('label')) stream.label = data.getString('label') + if (data.has('quality')) stream.quality = data.getString('quality') + if (data.has('timeshift')) stream.timeshift = data.getString('timeshift') + if (data.has('user_agent')) stream.userAgent = data.getString('user_agent') + if (data.has('http_referrer')) stream.httpReferrer = data.getString('http_referrer') processedIssues.add(issue.number) }) @@ -110,24 +110,24 @@ async function addStreams(loader: IssueLoader) { issues.forEach((issue: Issue) => { const data = issue.data if (data.missing('channel_id') || data.missing('stream_url')) return - if (streams.includes((_stream: Stream) => _stream.url === data.get('stream_url'))) return - if (!validUrl.isUri(data.get('stream_url'))) return + if (streams.includes((_stream: Stream) => _stream.url === data.getString('stream_url'))) return + if (!validUrl.isUri(data.getString('stream_url'))) return - const channel = groupedChannels.get(data.get('channel_id')) + const channel = groupedChannels.get(data.getString('channel_id')) if (!channel) return const stream = new Stream({ - channel: data.get('channel_id'), - url: data.get('stream_url'), - label: data.get('label'), - quality: data.get('quality'), - timeshift: data.get('timeshift'), - userAgent: data.get('user_agent'), - httpReferrer: data.get('http_referrer'), + channel: data.getString('channel_id'), + url: data.getString('stream_url'), + label: data.getString('label'), + quality: data.getString('quality'), + timeshift: data.getString('timeshift'), + userAgent: data.getString('user_agent'), + httpReferrer: data.getString('http_referrer'), filepath: `${channel.country.toLowerCase()}.m3u`, line: -1, - name: data.get('channel_name') || channel.name + name: data.getString('channel_name') || channel.name }) streams.add(stream) diff --git a/scripts/commands/report/create.ts b/scripts/commands/report/create.ts index 74b73f610..4b361e5f9 100644 --- a/scripts/commands/report/create.ts +++ b/scripts/commands/report/create.ts @@ -35,8 +35,8 @@ async function main() { const addRequests = await loader.load({ labels: ['streams:add'] }) const buffer = new Dictionary() addRequests.forEach((issue: Issue) => { - const channelId = issue.data.get('channel_id') || undefined - const streamUrl = issue.data.get('stream_url') || undefined + const channelId = issue.data.getString('channel_id') || undefined + const streamUrl = issue.data.getString('stream_url') const result = new Dictionary({ issueNumber: issue.number, @@ -61,8 +61,8 @@ async function main() { logger.info('checking streams:edit requests...') const editRequests = await loader.load({ labels: ['streams:edit'] }) editRequests.forEach((issue: Issue) => { - const channelId = issue.data.get('channel_id') || undefined - const streamUrl = issue.data.get('stream_url') || undefined + const channelId = issue.data.getString('channel_id') || undefined + const streamUrl = issue.data.getString('stream_url') || undefined const result = new Dictionary({ issueNumber: issue.number, @@ -82,7 +82,7 @@ async function main() { logger.info('checking broken streams reports...') const brokenStreamReports = await loader.load({ labels: ['broken stream'] }) brokenStreamReports.forEach((issue: Issue) => { - const brokenLinks = issue.data.get('broken_links') || undefined + const brokenLinks = issue.data.getString('broken_links') || undefined const result = new Dictionary({ issueNumber: issue.number, diff --git a/scripts/core/index.ts b/scripts/core/index.ts index 7fd792daf..69656cc5f 100644 --- a/scripts/core/index.ts +++ b/scripts/core/index.ts @@ -6,3 +6,4 @@ export * from './issueLoader' export * from './issueParser' export * from './htmlTable' export * from './apiClient' +export * from './issueData' diff --git a/scripts/core/issueData.ts b/scripts/core/issueData.ts new file mode 100644 index 000000000..879a64b8b --- /dev/null +++ b/scripts/core/issueData.ts @@ -0,0 +1,32 @@ +import { Dictionary } from '@freearhey/core' + +export class IssueData { + _data: Dictionary + constructor(data: Dictionary) { + this._data = data + } + + has(key: string): boolean { + return this._data.has(key) + } + + missing(key: string): boolean { + return this._data.missing(key) || this._data.get(key) === undefined + } + + getBoolean(key: string): boolean { + return Boolean(this._data.get(key)) + } + + getString(key: string): string { + const deleteSymbol = '~' + + return this._data.get(key) === deleteSymbol ? '' : this._data.get(key) + } + + getArray(key: string): string[] { + const deleteSymbol = '~' + + return this._data.get(key) === deleteSymbol ? [] : this._data.get(key).split(';') + } +} diff --git a/scripts/core/issueLoader.ts b/scripts/core/issueLoader.ts index 34c7cb2b0..4656fa8c9 100644 --- a/scripts/core/issueLoader.ts +++ b/scripts/core/issueLoader.ts @@ -15,22 +15,25 @@ export class IssueLoader { if (TESTING) { switch (labels) { case 'streams:add': - issues = require('../../tests/__data__/input/issues/streams_add.js') + issues = (await import('../../tests/__data__/input/issues/streams_add.js')).default break case 'streams:edit': - issues = require('../../tests/__data__/input/issues/streams_edit.js') + issues = (await import('../../tests/__data__/input/issues/streams_edit.js')).default break case 'broken stream': - issues = require('../../tests/__data__/input/issues/broken_stream.js') + issues = (await import('../../tests/__data__/input/issues/broken_stream.js')).default break case 'streams:add,approved': - issues = require('../../tests/__data__/input/issues/streams_add_approved.js') + issues = (await import('../../tests/__data__/input/issues/streams_add_approved.js')) + .default break case 'streams:edit,approved': - issues = require('../../tests/__data__/input/issues/streams_edit_approved.js') + issues = (await import('../../tests/__data__/input/issues/streams_edit_approved.js')) + .default break case 'streams:remove,approved': - issues = require('../../tests/__data__/input/issues/streams_remove_approved.js') + issues = (await import('../../tests/__data__/input/issues/streams_remove_approved.js')) + .default break } } else { diff --git a/scripts/core/issueParser.ts b/scripts/core/issueParser.ts index 6d4658985..921e645f6 100644 --- a/scripts/core/issueParser.ts +++ b/scripts/core/issueParser.ts @@ -1,5 +1,6 @@ import { Dictionary } from '@freearhey/core' import { Issue } from '../models' +import { IssueData } from './issueData' const FIELDS = new Dictionary({ 'Channel ID': 'channel_id', @@ -28,7 +29,7 @@ export class IssueParser { const data = new Dictionary() fields.forEach((field: string) => { - let parsed = field.split(/\r?\n/).filter(Boolean) + const parsed = field.split(/\r?\n/).filter(Boolean) let _label = parsed.shift() _label = _label ? _label.trim() : '' let _value = parsed.join('\r\n') @@ -46,6 +47,6 @@ export class IssueParser { const labels = issue.labels.map(label => label.name) - return new Issue({ number: issue.number, labels, data }) + return new Issue({ number: issue.number, labels, data: new IssueData(data) }) } } diff --git a/scripts/models/issue.ts b/scripts/models/issue.ts index fecb1fde1..74602e745 100644 --- a/scripts/models/issue.ts +++ b/scripts/models/issue.ts @@ -1,15 +1,15 @@ -import { Dictionary } from '@freearhey/core' +import { IssueData } from '../core' type IssueProps = { number: number labels: string[] - data: Dictionary + data: IssueData } export class Issue { number: number labels: string[] - data: Dictionary + data: IssueData constructor({ number, labels, data }: IssueProps) { this.number = number diff --git a/tests/__data__/expected/streams_update/us.m3u b/tests/__data__/expected/streams_update/us.m3u index 5730c94c3..cf05ee504 100644 --- a/tests/__data__/expected/streams_update/us.m3u +++ b/tests/__data__/expected/streams_update/us.m3u @@ -1,5 +1,4 @@ #EXTM3U -#EXTINF:-1 tvg-id="BBCAmericaEast.us" tvg-shift="-4" user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edge/12.246",BBC America East (720p) [Geo-blocked] -#EXTVLCOPT:http-referrer=https://example2.com/ +#EXTINF:-1 tvg-id="BBCAmericaEast.us" tvg-shift="-4" user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edge/12.246",BBC America East (720p) #EXTVLCOPT:http-user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edge/12.246 https://servilive.com:3126/live/tele2000live.m3u8 diff --git a/tests/__data__/input/issues/streams_edit_approved.js b/tests/__data__/input/issues/streams_edit_approved.js index 7dc37a7bb..d04e9769a 100644 --- a/tests/__data__/input/issues/streams_edit_approved.js +++ b/tests/__data__/input/issues/streams_edit_approved.js @@ -61,7 +61,7 @@ module.exports = [ closed_at: null, author_association: 'COLLABORATOR', active_lock_reason: null, - body: '### Stream URL\n\nhttps://servilive.com:3126/live/tele2000live.m3u8\n\n### Channel ID\n\nBBCAmericaEast.us\n\n### Channel Name\n\nBBC America\n\n### Quality\n\n720p\n\n### Label\n\nGeo-blocked\n\n### Timeshift\n\n-4\n\n### HTTP User-Agent\n\nMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edge/12.246\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)', + body: '### Stream URL\n\nhttps://servilive.com:3126/live/tele2000live.m3u8\n\n### Channel ID\n\nBBCAmericaEast.us\n\n### Channel Name\n\nBBC America\n\n### Quality\n\n720p\n\n### Label\n\n~\n\n### Timeshift\n\n-4\n\n### HTTP User-Agent\n\nMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edge/12.246\n\n### HTTP Referrer\n\n~\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/14110/reactions', total_count: 0, @@ -77,5 +77,84 @@ module.exports = [ timeline_url: 'https://api.github.com/repos/iptv-org/iptv/issues/14110/timeline', performed_via_github_app: null, state_reason: null + }, + { + url: 'https://api.github.com/repos/iptv-org/iptv/issues/14120', + 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', + id: 1884922249, + node_id: 'I_kwDOCWUK8M5wWaGJ', + number: 14120, + title: 'Edit: Tele2000', + 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:add', + 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://ythls.onrender.com/channel/UC40TUSUx490U5uR1lZt3Ajg.m3u8\n\n### Channel 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', + 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/14120/timeline', + performed_via_github_app: null, + state_reason: null } ] diff --git a/tests/__data__/input/streams_update/br.m3u b/tests/__data__/input/streams_update/br.m3u index 3c01333e4..6dcdaee15 100644 --- a/tests/__data__/input/streams_update/br.m3u +++ b/tests/__data__/input/streams_update/br.m3u @@ -1,6 +1,6 @@ #EXTM3U #EXTINF:-1 tvg-id="",VTV [Not 24/7] https://ythls.onrender.com/channel/UC40TUSUx490U5uR1lZt3Ajg.m3u8 -#EXTINF:-1 tvg-id="",Tele2000 +#EXTINF:-1 tvg-id="",Tele2000 [Not 24/7] #EXTVLCOPT:http-referrer=https://example2.com/ https://servilive.com:3126/live/tele2000live.m3u8 diff --git a/tests/commands/playlist/update.test.ts b/tests/commands/playlist/update.test.ts index 14bd8a119..10f73b156 100644 --- a/tests/commands/playlist/update.test.ts +++ b/tests/commands/playlist/update.test.ts @@ -25,7 +25,9 @@ it('can format playlists', () => { ) }) - expect(stdout).toBe('OUTPUT=closes #14151, closes #14140, closes #14110, closes #14178\n') + expect(stdout).toBe( + 'OUTPUT=closes #14151, closes #14140, closes #14110, closes #14120, closes #14178\n' + ) }) function content(filepath: string) { diff --git a/yarn.lock b/yarn.lock index 2b8af6028..b80af0346 100644 --- a/yarn.lock +++ b/yarn.lock @@ -306,10 +306,10 @@ dependencies: "@types/json-schema" "^7.0.15" -"@eslint/eslintrc@^3.2.0": - version "3.2.0" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz" - integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== +"@eslint/eslintrc@^3.2.0", "@eslint/eslintrc@^3.3.0": + version "3.3.0" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz" + integrity sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -321,6 +321,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@^9.21.0": + version "9.21.0" + resolved "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz" + integrity sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw== + "@eslint/js@9.17.0": version "9.17.0" resolved "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz" @@ -1895,6 +1900,11 @@ globals@^14.0.0: resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz" integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== +globals@^16.0.0: + version "16.0.0" + resolved "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz" + integrity sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A== + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.9" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"