mirror of
https://github.com/iptv-org/epg
synced 2026-09-15 13:36:25 -04:00
Merge branch 'master' into pr/2823
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
# Enforce the usage of CRLF in GitHub Actions per ESLint configuration.
|
||||||
|
* text eol=crlf
|
||||||
@@ -6,10 +6,3 @@
|
|||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# If Yarn is used (yarn.lock)
|
|
||||||
/.yarn/*
|
|
||||||
.yarnrc
|
|
||||||
.yarnrc.yml
|
|
||||||
|
|
||||||
.idea
|
|
||||||
+5
-3
@@ -1,4 +1,5 @@
|
|||||||
import typescriptEslint from '@typescript-eslint/eslint-plugin'
|
import typescriptEslint from '@typescript-eslint/eslint-plugin'
|
||||||
|
import stylistic from '@stylistic/eslint-plugin'
|
||||||
import globals from 'globals'
|
import globals from 'globals'
|
||||||
import tsParser from '@typescript-eslint/parser'
|
import tsParser from '@typescript-eslint/parser'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
@@ -15,10 +16,11 @@ const compat = new FlatCompat({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
...compat.extends('eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'),
|
...compat.extends('eslint:recommended', 'plugin:@typescript-eslint/strict', 'plugin:@typescript-eslint/stylistic', 'prettier'),
|
||||||
{
|
{
|
||||||
plugins: {
|
plugins: {
|
||||||
'@typescript-eslint': typescriptEslint
|
'@typescript-eslint': typescriptEslint,
|
||||||
|
'@stylistic': stylistic
|
||||||
},
|
},
|
||||||
|
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
@@ -36,7 +38,7 @@ export default [
|
|||||||
'@typescript-eslint/no-require-imports': 'off',
|
'@typescript-eslint/no-require-imports': 'off',
|
||||||
'@typescript-eslint/no-var-requires': 'off',
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
'no-case-declarations': 'off',
|
'no-case-declarations': 'off',
|
||||||
'linebreak-style': ['error', 'windows'],
|
'@stylistic/linebreak-style': ['error', 'windows'],
|
||||||
|
|
||||||
quotes: [
|
quotes: [
|
||||||
'error',
|
'error',
|
||||||
|
|||||||
Generated
+2691
-1277
File diff suppressed because it is too large
Load Diff
+21
-13
@@ -38,7 +38,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alex_neo/jest-expect-message": "^1.0.5",
|
"@alex_neo/jest-expect-message": "^1.0.5",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "^9.30.0",
|
"@eslint/js": "^9.32.0",
|
||||||
"@freearhey/chronos": "^0.0.1",
|
"@freearhey/chronos": "^0.0.1",
|
||||||
"@freearhey/core": "^0.10.2",
|
"@freearhey/core": "^0.10.2",
|
||||||
"@freearhey/search-js": "^0.1.2",
|
"@freearhey/search-js": "^0.1.2",
|
||||||
@@ -46,33 +46,37 @@
|
|||||||
"@octokit/core": "^7.0.3",
|
"@octokit/core": "^7.0.3",
|
||||||
"@octokit/plugin-paginate-rest": "^13.1.1",
|
"@octokit/plugin-paginate-rest": "^13.1.1",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
|
"@octokit/plugin-rest-endpoint-methods": "^16.0.0",
|
||||||
"@swc/core": "^1.13.0",
|
"@stylistic/eslint-plugin": "^5.2.2",
|
||||||
|
"@swc/core": "^1.13.2",
|
||||||
"@swc/jest": "^0.2.39",
|
"@swc/jest": "^0.2.39",
|
||||||
"@types/cli-progress": "^3.11.6",
|
"@types/cli-progress": "^3.11.6",
|
||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/inquirer": "^9.0.8",
|
"@types/inquirer": "^9.0.8",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/langs": "^2.0.5",
|
"@types/langs": "^2.0.5",
|
||||||
"@types/lodash": "^4.17.19",
|
"@types/lodash.orderby": "^4.6.9",
|
||||||
"@types/node": "^24.0.14",
|
"@types/lodash.sortby": "^4.7.9",
|
||||||
|
"@types/lodash.startcase": "^4.4.9",
|
||||||
|
"@types/lodash.uniqby": "^4.7.9",
|
||||||
|
"@types/node": "^24.1.0",
|
||||||
"@types/node-cleanup": "^2.1.5",
|
"@types/node-cleanup": "^2.1.5",
|
||||||
"@types/numeral": "^2.0.5",
|
"@types/numeral": "^2.0.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.35.0",
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
||||||
"@typescript-eslint/parser": "^8.35.0",
|
"@typescript-eslint/parser": "^8.38.0",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.11.0",
|
||||||
"axios-cookiejar-support": "^6.0.4",
|
"axios-cookiejar-support": "^6.0.4",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
"cheerio": "^1.1.0",
|
"cheerio": "^1.1.2",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
"commander": "^14.0.0",
|
"commander": "^14.0.0",
|
||||||
"consola": "^3.4.2",
|
"consola": "^3.4.2",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^10.0.0",
|
||||||
"csv-parser": "^3.2.0",
|
"csv-parser": "^3.2.0",
|
||||||
"cwait": "^1.1.2",
|
"cwait": "^1.1.2",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"epg-grabber": "^0.41.0",
|
"epg-grabber": "^0.41.0",
|
||||||
"epg-parser": "^0.3.1",
|
"epg-parser": "^0.3.1",
|
||||||
"eslint": "^9.30.0",
|
"eslint": "^9.32.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"form-data": "^4.0.4",
|
"form-data": "^4.0.4",
|
||||||
"fs-extra": "^11.3.0",
|
"fs-extra": "^11.3.0",
|
||||||
@@ -80,12 +84,15 @@
|
|||||||
"globals": "^16.3.0",
|
"globals": "^16.3.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"inquirer": "^12.7.0",
|
"inquirer": "^12.8.2",
|
||||||
"jest": "^30.0.3",
|
"jest": "^30.0.5",
|
||||||
"jest-offline": "^1.0.1",
|
"jest-offline": "^1.0.1",
|
||||||
"langs": "^2.0.0",
|
"langs": "^2.0.0",
|
||||||
"libxml2-wasm": "^0.5.0",
|
"libxml2-wasm": "^0.5.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash.orderby": "^4.6.0",
|
||||||
|
"lodash.sortby": "^4.7.0",
|
||||||
|
"lodash.startcase": "^4.4.0",
|
||||||
|
"lodash.uniqby": "^4.7.0",
|
||||||
"luxon": "^3.7.1",
|
"luxon": "^3.7.1",
|
||||||
"mockdate": "^3.0.5",
|
"mockdate": "^3.0.5",
|
||||||
"nedb-promises": "^6.2.3",
|
"nedb-promises": "^6.2.3",
|
||||||
@@ -110,6 +117,7 @@
|
|||||||
"tsx": "^4.20.3",
|
"tsx": "^4.20.3",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"unzipit": "^1.4.3",
|
"unzipit": "^1.4.3",
|
||||||
|
"uuid": "^11.1.0",
|
||||||
"wildcard-match": "^5.1.4"
|
"wildcard-match": "^5.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import epgGrabber from 'epg-grabber'
|
|||||||
import { Command } from 'commander'
|
import { Command } from 'commander'
|
||||||
import readline from 'readline'
|
import readline from 'readline'
|
||||||
|
|
||||||
type ChoiceValue = { type: string; value?: Feed | Channel }
|
interface ChoiceValue { type: string; value?: Feed | Channel }
|
||||||
type Choice = { name: string; short?: string; value: ChoiceValue; default?: boolean }
|
interface Choice { name: string; short?: string; value: ChoiceValue; default?: boolean }
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
readline
|
readline
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ program
|
|||||||
.option('-o, --output <output>', 'Output file')
|
.option('-o, --output <output>', 'Output file')
|
||||||
.parse(process.argv)
|
.parse(process.argv)
|
||||||
|
|
||||||
type ParseOptions = {
|
interface ParseOptions {
|
||||||
config: string
|
config: string
|
||||||
set?: string
|
set?: string
|
||||||
output?: string
|
output?: string
|
||||||
@@ -43,9 +43,7 @@ async function main() {
|
|||||||
channelList = await parser.parse(outputFilepath)
|
channelList = await parser.parse(outputFilepath)
|
||||||
}
|
}
|
||||||
|
|
||||||
const args: {
|
const args: Record<string, string> = {}
|
||||||
[key: string]: string
|
|
||||||
} = {}
|
|
||||||
|
|
||||||
if (Array.isArray(options.set)) {
|
if (Array.isArray(options.set)) {
|
||||||
options.set.forEach((arg: string) => {
|
options.set.forEach((arg: string) => {
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import { program } from 'commander'
|
|||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import langs from 'langs'
|
import langs from 'langs'
|
||||||
|
|
||||||
program.argument('[filepath]', 'Path to *.channels.xml files to validate').parse(process.argv)
|
program.argument('[filepath...]', 'Path to *.channels.xml files to validate').parse(process.argv)
|
||||||
|
|
||||||
type ValidationError = {
|
interface ValidationError {
|
||||||
type: 'duplicate' | 'wrong_channel_id' | 'wrong_feed_id' | 'wrong_lang'
|
type: 'duplicate' | 'wrong_channel_id' | 'wrong_feed_id' | 'wrong_lang'
|
||||||
name: string
|
name: string
|
||||||
lang?: string
|
lang?: string
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ program
|
|||||||
.addOption(new Option('--curl', 'Display each request as CURL').default(false).env('CURL'))
|
.addOption(new Option('--curl', 'Display each request as CURL').default(false).env('CURL'))
|
||||||
.parse()
|
.parse()
|
||||||
|
|
||||||
export type GrabOptions = {
|
export interface GrabOptions {
|
||||||
site?: string
|
site?: string
|
||||||
channels?: string
|
channels?: string
|
||||||
output: string
|
output: string
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { parseChannels } from 'epg-grabber'
|
|||||||
import { Storage } from '@freearhey/core'
|
import { Storage } from '@freearhey/core'
|
||||||
import { ChannelList } from '../models'
|
import { ChannelList } from '../models'
|
||||||
|
|
||||||
type ChannelsParserProps = {
|
interface ChannelsParserProps {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { SiteConfig } from 'epg-grabber'
|
import { SiteConfig } from 'epg-grabber'
|
||||||
import _ from 'lodash'
|
|
||||||
import { pathToFileURL } from 'url'
|
import { pathToFileURL } from 'url'
|
||||||
|
|
||||||
export class ConfigLoader {
|
export class ConfigLoader {
|
||||||
@@ -28,6 +27,6 @@ export class ConfigLoader {
|
|||||||
channels: undefined
|
channels: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.merge(defaultConfig, config)
|
return { ...defaultConfig, ...config } as SiteConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { DataLoaderData } from '../types/dataLoader'
|
|||||||
import { Collection } from '@freearhey/core'
|
import { Collection } from '@freearhey/core'
|
||||||
|
|
||||||
export class DataProcessor {
|
export class DataProcessor {
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
process(data: DataLoaderData) {
|
process(data: DataLoaderData) {
|
||||||
let channels = new Collection(data.channels).map(data => new Channel(data))
|
let channels = new Collection(data.channels).map(data => new Channel(data))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { GrabOptions } from '../commands/epg/grab'
|
|||||||
import { TaskQueue, PromisyClass } from 'cwait'
|
import { TaskQueue, PromisyClass } from 'cwait'
|
||||||
import { SocksProxyAgent } from 'socks-proxy-agent'
|
import { SocksProxyAgent } from 'socks-proxy-agent'
|
||||||
|
|
||||||
type GrabberProps = {
|
interface GrabberProps {
|
||||||
logger: Logger
|
logger: Logger
|
||||||
queue: Queue
|
queue: Queue
|
||||||
options: GrabOptions
|
options: GrabOptions
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { DataLoaderData } from '../types/dataLoader'
|
|||||||
import { DataProcessorData } from '../types/dataProcessor'
|
import { DataProcessorData } from '../types/dataProcessor'
|
||||||
import { DATA_DIR } from '../constants'
|
import { DATA_DIR } from '../constants'
|
||||||
|
|
||||||
type GuideManagerProps = {
|
interface GuideManagerProps {
|
||||||
options: OptionValues
|
options: OptionValues
|
||||||
logger: Logger
|
logger: Logger
|
||||||
channels: Collection
|
channels: Collection
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
type Column = {
|
interface Column {
|
||||||
name: string
|
name: string
|
||||||
nowrap?: boolean
|
nowrap?: boolean
|
||||||
align?: string
|
align?: string
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ import { Logger } from '@freearhey/core'
|
|||||||
import { Queue, Grabber, GuideManager } from '.'
|
import { Queue, Grabber, GuideManager } from '.'
|
||||||
import { GrabOptions } from '../commands/epg/grab'
|
import { GrabOptions } from '../commands/epg/grab'
|
||||||
|
|
||||||
type JobProps = {
|
interface JobProps {
|
||||||
options: GrabOptions
|
options: GrabOptions
|
||||||
logger: Logger
|
logger: Logger
|
||||||
queue: Queue
|
queue: Queue
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { URL } from 'node:url'
|
import { URL } from 'node:url'
|
||||||
|
|
||||||
type ProxyParserResult = {
|
interface ProxyParserResult {
|
||||||
protocol: string | null
|
protocol: string | null
|
||||||
auth?: {
|
auth?: {
|
||||||
username?: string
|
username?: string
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Dictionary } from '@freearhey/core'
|
import { Dictionary } from '@freearhey/core'
|
||||||
import { SiteConfig, Channel } from 'epg-grabber'
|
import { SiteConfig, Channel } from 'epg-grabber'
|
||||||
|
|
||||||
export type QueueItem = {
|
export interface QueueItem {
|
||||||
channel: Channel
|
channel: Channel
|
||||||
date: string
|
date: string
|
||||||
config: SiteConfig
|
config: SiteConfig
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ConfigLoader, Queue } from './'
|
|||||||
import { SiteConfig } from 'epg-grabber'
|
import { SiteConfig } from 'epg-grabber'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
type QueueCreatorProps = {
|
interface QueueCreatorProps {
|
||||||
logger: Logger
|
logger: Logger
|
||||||
options: GrabOptions
|
options: GrabOptions
|
||||||
channels: Collection
|
channels: Collection
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class Channel {
|
|||||||
subdivisionCode?: string
|
subdivisionCode?: string
|
||||||
cityName?: string
|
cityName?: string
|
||||||
categoryIds?: Collection
|
categoryIds?: Collection
|
||||||
isNSFW: boolean = false
|
isNSFW = false
|
||||||
launched?: string
|
launched?: string
|
||||||
closed?: string
|
closed?: string
|
||||||
replacedBy?: string
|
replacedBy?: string
|
||||||
@@ -116,7 +116,7 @@ export class Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function format(logo: Logo): number {
|
function format(logo: Logo): number {
|
||||||
const levelByFormat: { [key: string]: number } = {
|
const levelByFormat: Record<string, number> = {
|
||||||
SVG: 0,
|
SVG: 0,
|
||||||
PNG: 3,
|
PNG: 3,
|
||||||
APNG: 1,
|
APNG: 1,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class ChannelList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
function escapeString(value: string, defaultValue: string = '') {
|
function escapeString(value: string, defaultValue = '') {
|
||||||
if (!value) return defaultValue
|
if (!value) return defaultValue
|
||||||
|
|
||||||
const regex = new RegExp(
|
const regex = new RegExp(
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class Feed {
|
|||||||
|
|
||||||
getLogos(): Collection {
|
getLogos(): Collection {
|
||||||
function format(logo: Logo): number {
|
function format(logo: Logo): number {
|
||||||
const levelByFormat: { [key: string]: number } = {
|
const levelByFormat: Record<string, number> = {
|
||||||
SVG: 0,
|
SVG: 0,
|
||||||
PNG: 3,
|
PNG: 3,
|
||||||
APNG: 1,
|
APNG: 1,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Collection, DateTime } from '@freearhey/core'
|
import { Collection, DateTime } from '@freearhey/core'
|
||||||
import { generateXMLTV } from 'epg-grabber'
|
import { generateXMLTV } from 'epg-grabber'
|
||||||
|
|
||||||
type GuideData = {
|
interface GuideData {
|
||||||
channels: Collection
|
channels: Collection
|
||||||
programs: Collection
|
programs: Collection
|
||||||
filepath: string
|
filepath: string
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Dictionary } from '@freearhey/core'
|
import { Dictionary } from '@freearhey/core'
|
||||||
import { OWNER, REPO } from '../constants'
|
import { OWNER, REPO } from '../constants'
|
||||||
|
|
||||||
type IssueProps = {
|
interface IssueProps {
|
||||||
number: number
|
number: number
|
||||||
labels: string[]
|
labels: string[]
|
||||||
data: Dictionary
|
data: Dictionary
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ export class Logo {
|
|||||||
feedId?: string
|
feedId?: string
|
||||||
feed?: Feed
|
feed?: Feed
|
||||||
tags: Collection = new Collection()
|
tags: Collection = new Collection()
|
||||||
width: number = 0
|
width = 0
|
||||||
height: number = 0
|
height = 0
|
||||||
format?: string
|
format?: string
|
||||||
url?: string
|
url?: string
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ enum StatusCode {
|
|||||||
OK = 'ok'
|
OK = 'ok'
|
||||||
}
|
}
|
||||||
|
|
||||||
type Status = {
|
interface Status {
|
||||||
code: StatusCode
|
code: StatusCode
|
||||||
emoji: string
|
emoji: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SiteProps = {
|
interface SiteProps {
|
||||||
domain: string
|
domain: string
|
||||||
totalChannels?: number
|
totalChannels?: number
|
||||||
markedChannels?: number
|
markedChannels?: number
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ export class Stream {
|
|||||||
isInterlaced?: boolean
|
isInterlaced?: boolean
|
||||||
referrer?: string
|
referrer?: string
|
||||||
userAgent?: string
|
userAgent?: string
|
||||||
groupTitle: string = 'Undefined'
|
groupTitle = 'Undefined'
|
||||||
removed: boolean = false
|
removed = false
|
||||||
|
|
||||||
constructor(data: StreamData) {
|
constructor(data: StreamData) {
|
||||||
const id = data.channel && data.feed ? [data.channel, data.feed].join('@') : data.channel
|
const id = data.channel && data.feed ? [data.channel, data.feed].join('@') : data.channel
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
import { Collection } from '@freearhey/core'
|
import { Collection } from '@freearhey/core'
|
||||||
|
|
||||||
export type ChannelData = {
|
export interface ChannelData {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
alt_names: string[]
|
alt_names: string[]
|
||||||
@@ -17,7 +17,7 @@ export type ChannelData = {
|
|||||||
website: string
|
website: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChannelSearchableData = {
|
export interface ChannelSearchableData {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
altNames: string[]
|
altNames: string[]
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
import { Storage } from '@freearhey/core'
|
import { Storage } from '@freearhey/core'
|
||||||
|
|
||||||
export type DataLoaderProps = {
|
export interface DataLoaderProps {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DataLoaderData = {
|
export interface DataLoaderData {
|
||||||
countries: object | object[]
|
countries: object | object[]
|
||||||
regions: object | object[]
|
regions: object | object[]
|
||||||
subdivisions: object | object[]
|
subdivisions: object | object[]
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { Collection, Dictionary } from '@freearhey/core'
|
import { Collection, Dictionary } from '@freearhey/core'
|
||||||
|
|
||||||
export type DataProcessorData = {
|
export interface DataProcessorData {
|
||||||
guideChannelsGroupedByStreamId: Dictionary
|
guideChannelsGroupedByStreamId: Dictionary
|
||||||
feedsGroupedByChannelId: Dictionary
|
feedsGroupedByChannelId: Dictionary
|
||||||
logosGroupedByChannelId: Dictionary
|
logosGroupedByChannelId: Dictionary
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { Collection } from '@freearhey/core'
|
import { Collection } from '@freearhey/core'
|
||||||
|
|
||||||
export type FeedData = {
|
export interface FeedData {
|
||||||
channel: string
|
channel: string
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
export type GuideData = {
|
export interface GuideData {
|
||||||
channel: string
|
channel: string
|
||||||
feed: string
|
feed: string
|
||||||
site: string
|
site: string
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
export type LogoData = {
|
export interface LogoData {
|
||||||
channel: string
|
channel: string
|
||||||
feed: string | null
|
feed: string | null
|
||||||
tags: string[]
|
tags: string[]
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
export type StreamData = {
|
export interface StreamData {
|
||||||
channel: string | null
|
channel: string | null
|
||||||
feed: string | null
|
feed: string | null
|
||||||
name?: string
|
name?: string
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./9tv.co.il.config.js')
|
const { parser, url } = require('./9tv.co.il.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -18,8 +20,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
'<li> <a href="#" class="guide_list_link w-inline-block"> <div class="guide_list_time">06:30</div><div class="guide_info_group"> <div class="guide_info_pict" style="background-image: url(/download/pictures/img_id=8484.jpg);"></div><div class="guide_txt_group"> <h3 class="guide_info_title">Слепая</h3> <div>Она не очень любит говорить о себе или о том, кто и зачем к ней обращается. Живет уединенно, в глуши. Но тех, кто приходит -принимает. Она видит судьбы. </div></div></div></a></li><li> <a href="#" class="guide_list_link even w-inline-block"> <div class="guide_list_time">09:10</div><div class="guide_info_group"> <div class="guide_info_pict" style="background-image: url(/download/pictures/img_id=23694.jpg);"></div><div class="guide_txt_group"> <h3 class="guide_info_title">Орел и решка. Морской сезон</h3> <div>Орел и решка. Морской сезон. Ведущие -Алина Астровская и Коля Серга.</div></div></div></a></li>'
|
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -49,7 +50,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '<!DOCTYPE html><html><head></head><body></body></html>'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<li> <a href="#" class="guide_list_link w-inline-block"> <div class="guide_list_time">06:30</div><div class="guide_info_group"> <div class="guide_info_pict" style="background-image: url(/download/pictures/img_id=8484.jpg);"></div><div class="guide_txt_group"> <h3 class="guide_info_title">Слепая</h3> <div>Она не очень любит говорить о себе или о том, кто и зачем к ней обращается. Живет уединенно, в глуши. Но тех, кто приходит -принимает. Она видит судьбы. </div></div></div></a></li><li> <a href="#" class="guide_list_link even w-inline-block"> <div class="guide_list_time">09:10</div><div class="guide_info_group"> <div class="guide_info_pict" style="background-image: url(/download/pictures/img_id=23694.jpg);"></div><div class="guide_txt_group"> <h3 class="guide_info_title">Орел и решка. Морской сезон</h3> <div>Орел и решка. Морской сезон. Ведущие -Алина Астровская и Коля Серга.</div></div></div></a></li>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html><head></head><body></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"date":"2001-11-17","categories":[],"channels":[]}
|
||||||
@@ -2,6 +2,8 @@ const { parser, url } = require('./allente.dk.config.js')
|
|||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
const { readFileSync } = require('fs')
|
||||||
|
const { resolve } = require('path')
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
|
|
||||||
@@ -16,8 +18,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = readFileSync(resolve(__dirname, '__data__/content.json'))
|
||||||
'{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}'
|
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"date":"2001-11-17","categories":[],"channels":[]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./allente.fi.config.js')
|
const { parser, url } = require('./allente.fi.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -16,8 +18,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}'
|
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -44,7 +45,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '{"date":"2001-11-17","categories":[],"channels":[]}'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"date":"2001-11-17","categories":[],"channels":[]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./allente.no.config.js')
|
const { parser, url } = require('./allente.no.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -16,8 +18,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}'
|
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -44,7 +45,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '{"date":"2001-11-17","categories":[],"channels":[]}'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"date":"2001-11-17","categories":[],"channels":[]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./allente.se.config.js')
|
const { parser, url } = require('./allente.se.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -16,8 +18,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'{"channels":[{"id":"0148","icon":"//images.ctfassets.net/989y85n5kcxs/5uT9g9pdQWRZeDPQXVI9g6/9cc44da567f591822ed645c99ecdcb64/SVT_1_black_new__2_.png","name":"SVT1 HD (T)","events":[{"id":"0086202208220710","live":false,"time":"2022-08-22T07:10:00Z","title":"Hemmagympa med Sofia","details":{"title":"Hemmagympa med Sofia","image":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/21/2022-08-22/se.cs.svt1.event.A_41214031600.jpg?size=2560x1440","description":"Svenskt träningsprogram från 2021. Styrka. Sofia Åhman leder SVT:s hemmagympapass. Denna gång fokuserar vi på styrka.","season":4,"episode":1,"categories":["other"],"duration":"20"}}]}]}'
|
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -44,7 +45,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '{"date":"2001-11-17","categories":[],"channels":[]}'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<channels>
|
|
||||||
<channel site="arianaafgtv.com" lang="en" xmltv_id="ArianaAfghanistanInternationalTV.us" site_id="#">Ariana Afghanistan Television</channel>
|
|
||||||
</channels>
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
const cheerio = require('cheerio')
|
|
||||||
const dayjs = require('dayjs')
|
|
||||||
const utc = require('dayjs/plugin/utc')
|
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
|
||||||
|
|
||||||
dayjs.extend(utc)
|
|
||||||
dayjs.extend(timezone)
|
|
||||||
dayjs.extend(customParseFormat)
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
site: 'arianaafgtv.com',
|
|
||||||
days: 2,
|
|
||||||
url: 'https://www.arianaafgtv.com/index.html',
|
|
||||||
parser({ content, date }) {
|
|
||||||
const programs = []
|
|
||||||
const items = parseItems(content, date)
|
|
||||||
items.forEach(item => {
|
|
||||||
const title = item.title
|
|
||||||
const start = parseStart(item, date)
|
|
||||||
const stop = parseStop(item, date)
|
|
||||||
programs.push({
|
|
||||||
title,
|
|
||||||
start,
|
|
||||||
stop
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
return programs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseStop(item, date) {
|
|
||||||
const time = `${date.format('MM/DD/YYYY')} ${item.end.toUpperCase()}`
|
|
||||||
|
|
||||||
return dayjs.tz(time, 'MM/DD/YYYY hh:mm A', 'Asia/Kabul')
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseStart(item, date) {
|
|
||||||
const time = `${date.format('MM/DD/YYYY')} ${item.start.toUpperCase()}`
|
|
||||||
|
|
||||||
return dayjs.tz(time, 'MM/DD/YYYY hh:mm A', 'Asia/Kabul')
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseItems(content, date) {
|
|
||||||
const $ = cheerio.load(content)
|
|
||||||
const dayOfWeek = date.format('dddd')
|
|
||||||
const column = $('.H4')
|
|
||||||
.filter((i, el) => {
|
|
||||||
return $(el).text() === dayOfWeek
|
|
||||||
})
|
|
||||||
.first()
|
|
||||||
.parent()
|
|
||||||
|
|
||||||
const rows = column
|
|
||||||
.find('.Paragraph')
|
|
||||||
.map((i, el) => {
|
|
||||||
return $(el).html()
|
|
||||||
})
|
|
||||||
.toArray()
|
|
||||||
.map(r => (r === ' ' ? '|' : r))
|
|
||||||
.join(' ')
|
|
||||||
.split('|')
|
|
||||||
|
|
||||||
const items = []
|
|
||||||
rows.forEach(row => {
|
|
||||||
row = row.trim()
|
|
||||||
if (row) {
|
|
||||||
const found = row.match(/(\d+(|:\d+)(a|p)m-\d+(|:\d+)(a|p)m)/gi)
|
|
||||||
if (!found) return
|
|
||||||
const time = found[0]
|
|
||||||
let start = time.match(/(\d+(|:\d+)(a|p)m)-/i)[1]
|
|
||||||
start = dayjs(start.toUpperCase(), ['hh:mmA', 'h:mmA', 'hA']).format('hh:mm A')
|
|
||||||
let end = time.match(/-(\d+(|:\d+)(a|p)m)/i)[1]
|
|
||||||
end = dayjs(end.toUpperCase(), ['hh:mmA', 'h:mmA', 'hA']).format('hh:mm A')
|
|
||||||
const title = row.replace(time, '').replace(' ', '').trim()
|
|
||||||
items.push({ start, end, title })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# arianaafgtv.com
|
|
||||||
|
|
||||||
https://arianaafgtv.com/#ariana-afghanistan-television-tv-guide
|
|
||||||
|
|
||||||
### Download the guide
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run grab --- --site=arianaafgtv.com
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm test --- arianaafgtv.com
|
|
||||||
```
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html><head></head><body><textarea data-jtrt-table-id="508" id="jtrt_table_settings_508" cols="30" rows="10">[[["Start","Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","",""],["7:00","City Report","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","",""],["7:30","ICC T20 Highlights","Sport ","Sport ","Sport ","Sport ","Sport ","Sport ","",""],["15:00","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","",""],["6:30","Quran and Hadis ","Falah","Falah","Falah","Falah","Falah","Falah","",""],["","\\n","","","","","","","",""]]]</textarea></body></html>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<!DOCTYPE html><html><head></head><body><textarea data-jtrt-table-id="508" id="jtrt_table_settings_508" cols="30" rows="10"></textarea></body></html>
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./arianatelevision.com.config.js')
|
const { parser, url } = require('./arianatelevision.com.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -16,8 +18,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
'<!DOCTYPE html><html><head></head><body><textarea data-jtrt-table-id="508" id="jtrt_table_settings_508" cols="30" rows="10">[[["Start","Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","",""],["7:00","City Report","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","ICC T20 Highlights","",""],["7:30","ICC T20 Highlights","Sport ","Sport ","Sport ","Sport ","Sport ","Sport ","",""],["15:00","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","ICC T20 World Cup","",""],["6:30","Quran and Hadis ","Falah","Falah","Falah","Falah","Falah","Falah","",""],["","\\n","","","","","","","",""]]]</textarea></body></html>'
|
|
||||||
const result = parser({ content, date }).map(p => {
|
const result = parser({ content, date }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -52,8 +53,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content:
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
'<!DOCTYPE html><html><head></head><body><textarea data-jtrt-table-id="508" id="jtrt_table_settings_508" cols="30" rows="10"></textarea></body></html>'
|
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
[{"id":158963,"eventid":null,"duration":"01:34:00","lang":"Arabic","title":"الراقصه و السياسي","description":"تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .","thumbnail":"/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg","image":"0","start_Time":"00:30","adddate":"3/4/2022 12:00:00 AM","repeat1":null,"iD_genre":0,"iD_Show_Type":0,"iD_Channel":77,"iD_country":0,"iD_rating":0,"end_time":"02:04","season_Number":0,"epoisode_Number":0,"hasCatchup":0,"cmsid":0,"containerID":0,"imagePath":"../../UploadImages/Channel/ARTAFLAM1/3/","youtube":"0","published_at":"0","directed_by":"0","composition":"0","cast":"0","timeShow":null,"short_description":"تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .","seOdescription":null,"tagseo":null,"channel_name":null,"pathimage":null,"pathThumbnail":null}]
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url, request } = require('./artonline.tv.config.js')
|
const { parser, url, request } = require('./artonline.tv.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -37,8 +39,7 @@ it('can generate valid request data for tomorrow', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'[{"id":158963,"eventid":null,"duration":"01:34:00","lang":"Arabic","title":"الراقصه و السياسي","description":"تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .","thumbnail":"/UploadImages/Channel/ARTAFLAM1/03/AlRaqesaWaAlSeyasi.jpg","image":"0","start_Time":"00:30","adddate":"3/4/2022 12:00:00 AM","repeat1":null,"iD_genre":0,"iD_Show_Type":0,"iD_Channel":77,"iD_country":0,"iD_rating":0,"end_time":"02:04","season_Number":0,"epoisode_Number":0,"hasCatchup":0,"cmsid":0,"containerID":0,"imagePath":"../../UploadImages/Channel/ARTAFLAM1/3/","youtube":"0","published_at":"0","directed_by":"0","composition":"0","cast":"0","timeShow":null,"short_description":"تقرر الراقصه سونيا انشاء دار حضانه للأطفال اليتامى و عندما تتقدم بمشورعها للمسئول يرفض فتتحداه ، تلجأ للوزير عبد الحميد رأفت تربطه بها علاقة قديمة ، يخشى على مركزه و يرفض مساعدتها فتقرر كتابة مذكراتها بمساعدة أحد الصحفيين ، يتخوف عبد الحميد و المسئولين ثم يفاجأ عبد الحميد بحصول سونيا على الموافقه للمشورع و البدء في تنفيذه و ذلك لعلاقتها بأحد كبار المسئولين .","seOdescription":null,"tagseo":null,"channel_name":null,"pathimage":null,"pathThumbnail":null}]'
|
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<div class="pm0 col-md-8" id="stopfix">
|
||||||
|
<h2 class="posts-date">Programmes d'Aujourd'hui</h2>
|
||||||
|
<div class="posts-area">
|
||||||
|
<h2> <i class="fas fa-circle"></i>00:00 - 09:00</h2>
|
||||||
|
<div class="relativeme">
|
||||||
|
<a href="https://chada.ma/fr/emissions/bloc-prime-clips/">
|
||||||
|
<img class="programthumb" src="https://chada.ma/wp-content/uploads/2023/11/Autres-slides-clips-la-couverture.jpg">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<h3>Bloc Prime + Clips</h3>
|
||||||
|
<div class="authorbox"></div>
|
||||||
|
<div class="ssprogramme row"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<div class="pm0 col-md-8" id="stopfix"><div class="posts-area"></div></div>
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./chada.ma.config.js')
|
const { parser, url } = require('./chada.ma.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
@@ -10,30 +12,12 @@ dayjs.extend(customParseFormat)
|
|||||||
|
|
||||||
jest.mock('axios')
|
jest.mock('axios')
|
||||||
|
|
||||||
const mockHtmlContent = `
|
|
||||||
<div class="pm0 col-md-8" id="stopfix">
|
|
||||||
<h2 class="posts-date">Programmes d'Aujourd'hui</h2>
|
|
||||||
<div class="posts-area">
|
|
||||||
<h2> <i class="fas fa-circle"></i>00:00 - 09:00</h2>
|
|
||||||
<div class="relativeme">
|
|
||||||
<a href="https://chada.ma/fr/emissions/bloc-prime-clips/">
|
|
||||||
<img class="programthumb" src="https://chada.ma/wp-content/uploads/2023/11/Autres-slides-clips-la-couverture.jpg">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<h3>Bloc Prime + Clips</h3>
|
|
||||||
<div class="authorbox"></div>
|
|
||||||
<div class="ssprogramme row"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
expect(url()).toBe('https://chada.ma/fr/chada-tv/grille-tv/')
|
expect(url()).toBe('https://chada.ma/fr/chada-tv/grille-tv/')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = mockHtmlContent
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.html'), 'utf8')
|
||||||
|
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = dayjs(p.start).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
p.start = dayjs(p.start).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
||||||
p.stop = dayjs(p.stop).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
p.stop = dayjs(p.stop).tz('Africa/Casablanca').format('YYYY-MM-DDTHH:mm:ssZ')
|
||||||
@@ -52,7 +36,7 @@ it('can parse response', () => {
|
|||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '<div class="pm0 col-md-8" id="stopfix"><div class="posts-area"></div></div>'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.html'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"192":[{"id":1635062528017,"programType":"EPISODE","title":"Tête de liste","channelId":"192","channelZappingNumber":11,"covers":[{"format":"RATIO_16_9","url":"https://proxymedia.woopic.com/340/p/169_EMI_9697669.jpg"},{"format":"RATIO_4_3","url":"https://proxymedia.woopic.com/340/p/43_EMI_9697669.jpg"}],"diffusionDate":1636328100,"duration":2700,"csa":2,"synopsis":"Un tueur en série prend un plaisir pervers à prévenir les autorités de Tallahassee avant chaque nouveau meurtre. Rossi apprend le décès d'un de ses vieux amis.","languageVersion":"VM","hearingImpaired":true,"audioDescription":false,"season":{"number":10,"episodesCount":23,"serie":{"title":"Esprits criminels"}},"episodeNumber":12,"definition":"SD","links":[{"rel":"SELF","href":"https://rp-live.orange.fr/live-webapp/v3/applications/STB4PC/programs/1635062528017"}],"dayPart":"OTHER","catchupId":null,"genre":"Série","genreDetailed":"Série Suspense"}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"code":60,"message":"Resource not found","param":{},"description":"L'URI demandé ou la ressource demandée n'existe pas.","stackTrace":null}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./chaines-tv.orange.fr.config.js')
|
const { parser, url } = require('./chaines-tv.orange.fr.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -10,8 +12,6 @@ const channel = {
|
|||||||
site_id: '192',
|
site_id: '192',
|
||||||
xmltv_id: 'TF1.fr'
|
xmltv_id: 'TF1.fr'
|
||||||
}
|
}
|
||||||
const content =
|
|
||||||
'{"192":[{"id":1635062528017,"programType":"EPISODE","title":"Tête de liste","channelId":"192","channelZappingNumber":11,"covers":[{"format":"RATIO_16_9","url":"https://proxymedia.woopic.com/340/p/169_EMI_9697669.jpg"},{"format":"RATIO_4_3","url":"https://proxymedia.woopic.com/340/p/43_EMI_9697669.jpg"}],"diffusionDate":1636328100,"duration":2700,"csa":2,"synopsis":"Un tueur en série prend un plaisir pervers à prévenir les autorités de Tallahassee avant chaque nouveau meurtre. Rossi apprend le décès d\'un de ses vieux amis.","languageVersion":"VM","hearingImpaired":true,"audioDescription":false,"season":{"number":10,"episodesCount":23,"serie":{"title":"Esprits criminels"}},"episodeNumber":12,"definition":"SD","links":[{"rel":"SELF","href":"https://rp-live.orange.fr/live-webapp/v3/applications/STB4PC/programs/1635062528017"}],"dayPart":"OTHER","catchupId":null,"genre":"Série","genreDetailed":"Série Suspense"}]}'
|
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const result = url({ channel, date })
|
const result = url({ channel, date })
|
||||||
@@ -21,6 +21,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
const result = parser({ date, channel, content })
|
const result = parser({ date, channel, content })
|
||||||
expect(result).toMatchObject([
|
expect(result).toMatchObject([
|
||||||
{
|
{
|
||||||
@@ -42,8 +43,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content:
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
'{"code":60,"message":"Resource not found","param":{},"description":"L\'URI demandé ou la ressource demandée n\'existe pas.","stackTrace":null}'
|
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"channels": [
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"startTime": "2024-12-26T23:00:00+00:00",
|
||||||
|
"endTime": "2024-12-27T00:00:00+00:00",
|
||||||
|
"title": "Τι Λέει ο Νόμος",
|
||||||
|
"description": "νημερωτική εκπομπή. Συζήτηση με τους εισηγητές των κομμάτων για το νομοθετικό έργο.",
|
||||||
|
"qoe": {
|
||||||
|
"genre": "Special"
|
||||||
|
},
|
||||||
|
"thumbnails": {
|
||||||
|
"standard": "https://gr-ermou-prod-cache05.static.cdn.cosmotetvott.gr/ote-prod/70/280/040029714812000800_1734415727199.jpg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"date":"2024-12-26","categories":[],"channels":[]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./cosmotetv.gr.config.js')
|
const { parser, url } = require('./cosmotetv.gr.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -13,29 +15,6 @@ jest.mock('axios')
|
|||||||
const date = dayjs.utc('2024-12-26', 'YYYY-MM-DD').startOf('d')
|
const date = dayjs.utc('2024-12-26', 'YYYY-MM-DD').startOf('d')
|
||||||
const channel = { site_id: 'vouli', xmltv_id: 'HellenicParliamentTV.gr' }
|
const channel = { site_id: 'vouli', xmltv_id: 'HellenicParliamentTV.gr' }
|
||||||
|
|
||||||
const mockEpgData = {
|
|
||||||
channels: [
|
|
||||||
{
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
startTime: '2024-12-26T23:00:00+00:00',
|
|
||||||
endTime: '2024-12-27T00:00:00+00:00',
|
|
||||||
title: 'Τι Λέει ο Νόμος',
|
|
||||||
description:
|
|
||||||
'νημερωτική εκπομπή. Συζήτηση με τους εισηγητές των κομμάτων για το νομοθετικό έργο.',
|
|
||||||
qoe: {
|
|
||||||
genre: 'Special'
|
|
||||||
},
|
|
||||||
thumbnails: {
|
|
||||||
standard:
|
|
||||||
'https://gr-ermou-prod-cache05.static.cdn.cosmotetvott.gr/ote-prod/70/280/040029714812000800_1734415727199.jpg'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
it('can generate valid url', () => {
|
it('can generate valid url', () => {
|
||||||
const startOfDay = dayjs(date).startOf('day').utc().unix()
|
const startOfDay = dayjs(date).startOf('day').utc().unix()
|
||||||
const endOfDay = dayjs(date).endOf('day').utc().unix()
|
const endOfDay = dayjs(date).endOf('day').utc().unix()
|
||||||
@@ -45,7 +24,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = JSON.stringify(mockEpgData)
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
||||||
const result = parser({ date, content }).map(p => {
|
const result = parser({ date, content }).map(p => {
|
||||||
p.start = dayjs(p.start).toISOString()
|
p.start = dayjs(p.start).toISOString()
|
||||||
p.stop = dayjs(p.stop).toISOString()
|
p.stop = dayjs(p.stop).toISOString()
|
||||||
@@ -70,7 +49,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '{"date":"2024-12-26","categories":[],"channels":[]}'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'), 'utf8')
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"result":[{"channel_id":"4028c68574537fcd0174be43042758d8","channel_name":"Trans TV","scehedule_title":"CNN Tech News","schedule_date":"2023-11-05 01:30:00","schedule_end_time":"02:00:00","schedule_json":{"availability":0,"channelId":"4028c68574537fcd0174be43042758d8","channelName":"Trans TV","duration":1800,"editable":true,"episodeName":"","imageUrl":"https://cdnjkt2.transvision.co.id:1001/catchup/schedule/thumbnail/4028c68574537fcd0174be43042758d8/4028c6858b8b3621018b9330e3701a7e/458x640","imageUrlWide":"https://cdnjkt2.transvision.co.id:1001/catchup/schedule/thumbnail/4028c68574537fcd0174be43042758d8/4028c6858b8b3621018b9330e3701a7e/320x180","name":"CNN Tech News","ottImageUrl":"","primarySynopsis":"CNN Indonesia Tech News adalah berita teknologi yang membawa pemirsa ke dunia teknologi yang penuh dengan informasi, pendidikan, hiburan sampai informasi kesehatan terkini.","scheduleId":"4028c6858b8b3621018b9330e3701a7e","scheduleTime":"18:30:00","secondarySynopsis":"CNN Indonesia Tech News is tech news brings viewers into the world of technology that provides information, education, entertainment to the latest health information.","startDt":"20231104183000","url":""},"schedule_start_time":"01:30:00"}]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { url, parser } = require('./cubmu.com.config.js')
|
const { url, parser } = require('./cubmu.com.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
@@ -14,9 +16,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
||||||
'{"result":[{"channel_id":"4028c68574537fcd0174be43042758d8","channel_name":"Trans TV","scehedule_title":"CNN Tech News","schedule_date":"2023-11-05 01:30:00","schedule_end_time":"02:00:00","schedule_json":{"availability":0,"channelId":"4028c68574537fcd0174be43042758d8","channelName":"Trans TV","duration":1800,"editable":true,"episodeName":"","imageUrl":"https://cdnjkt2.transvision.co.id:1001/catchup/schedule/thumbnail/4028c68574537fcd0174be43042758d8/4028c6858b8b3621018b9330e3701a7e/458x640","imageUrlWide":"https://cdnjkt2.transvision.co.id:1001/catchup/schedule/thumbnail/4028c68574537fcd0174be43042758d8/4028c6858b8b3621018b9330e3701a7e/320x180","name":"CNN Tech News","ottImageUrl":"","primarySynopsis":"CNN Indonesia Tech News adalah berita teknologi yang membawa pemirsa ke dunia teknologi yang penuh dengan informasi, pendidikan, hiburan sampai informasi kesehatan terkini.","scheduleId":"4028c6858b8b3621018b9330e3701a7e","scheduleTime":"18:30:00","secondarySynopsis":"CNN Indonesia Tech News is tech news brings viewers into the world of technology that provides information, education, entertainment to the latest health information.","startDt":"20231104183000","url":""},"schedule_start_time":"01:30:00"}]}'
|
|
||||||
|
|
||||||
const idResults = parser({ content, channel })
|
const idResults = parser({ content, channel })
|
||||||
expect(idResults).toMatchObject([
|
expect(idResults).toMatchObject([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const utc = require('dayjs/plugin/utc')
|
|||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
const parseDuration = require('parse-duration').default
|
const parseDuration = require('parse-duration').default
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const _ = require('lodash')
|
const sortBy = require('lodash.sortby')
|
||||||
|
|
||||||
dayjs.extend(customParseFormat)
|
dayjs.extend(customParseFormat)
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
@@ -28,7 +28,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return _.sortBy(programs, p => p.start)
|
return sortBy(programs, p => p.start.valueOf())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"d":[{"ChannelSection":"","ChannelFullName":"A&E HD","IsFavorite":false,"ChannelName":"A&EHD","ChannelNumber":207,"ProgramList":[{"_channelSection":"","eventId":"120289890767","titleId":"SH0110397700000001","title":"Chicas guapas","programId":null,"description":"Un espacio destinado a la belleza y los distintos estilos de vida, que muestra el trabajo inspiracional de la moda latinoamericana.","episodeTitle":null,"channelNumber":120,"channelName":"AME2","channelFullName":"América TV (ARG)","channelSection":"","contentChannelID":120,"startTime":"/Date(-62135578800000)/","endTime":"/Date(-62135578800000)/","GMTstartTime":"/Date(-62135578800000)/","GMTendTime":"/Date(-62135578800000)/","css":16,"language":null,"tmsId":"SH0110397700000001","rating":"NR","categoryId":"Tipos de Programas","categoryName":0,"subCategoryId":0,"subCategoryName":"Series","serviceExpiration":"/Date(-62135578800000)/","crId":null,"promoUrl1":null,"promoUrl2":null,"price":0,"isPurchasable":"N","videoUrl":"","imageUrl":"https://dnqt2wx2urq99.cloudfront.net/ondirectv/LOGOS/Canales/AR/120.png","titleSecond":"Chicas guapas","isHD":"N","DetailsURL":null,"BuyURL":null,"ProgramServiceId":null,"SearchDateTime":null,"startTimeString":"6/19/2022 12:00:00 AM","endTimeString":"6/19/2022 12:15:00 AM","DurationInMinutes":null,"castDetails":null,"scheduleDetails":null,"seriesDetails":null,"processedSeasonDetails":null}]}]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url, request } = require('./directv.com.ar.config.js')
|
const { parser, url, request } = require('./directv.com.ar.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -45,8 +47,7 @@ it('can generate valid request data', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'{"d":[{"ChannelSection":"","ChannelFullName":"A&E HD","IsFavorite":false,"ChannelName":"A&EHD","ChannelNumber":207,"ProgramList":[{"_channelSection":"","eventId":"120289890767","titleId":"SH0110397700000001","title":"Chicas guapas","programId":null,"description":"Un espacio destinado a la belleza y los distintos estilos de vida, que muestra el trabajo inspiracional de la moda latinoamericana.","episodeTitle":null,"channelNumber":120,"channelName":"AME2","channelFullName":"América TV (ARG)","channelSection":"","contentChannelID":120,"startTime":"/Date(-62135578800000)/","endTime":"/Date(-62135578800000)/","GMTstartTime":"/Date(-62135578800000)/","GMTendTime":"/Date(-62135578800000)/","css":16,"language":null,"tmsId":"SH0110397700000001","rating":"NR","categoryId":"Tipos de Programas","categoryName":0,"subCategoryId":0,"subCategoryName":"Series","serviceExpiration":"/Date(-62135578800000)/","crId":null,"promoUrl1":null,"promoUrl2":null,"price":0,"isPurchasable":"N","videoUrl":"","imageUrl":"https://dnqt2wx2urq99.cloudfront.net/ondirectv/LOGOS/Canales/AR/120.png","titleSecond":"Chicas guapas","isHD":"N","DetailsURL":null,"BuyURL":null,"ProgramServiceId":null,"SearchDateTime":null,"startTimeString":"6/19/2022 12:00:00 AM","endTimeString":"6/19/2022 12:15:00 AM","DurationInMinutes":null,"castDetails":null,"scheduleDetails":null,"seriesDetails":null,"processedSeasonDetails":null}]}]}'
|
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const dayjs = require('dayjs')
|
|||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
const uniqBy = require('lodash.uniqby')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
@@ -45,7 +46,6 @@ module.exports = {
|
|||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels({ country }) {
|
async channels({ country }) {
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
const countries = {
|
const countries = {
|
||||||
ao: 'ago',
|
ao: 'ago',
|
||||||
@@ -114,7 +114,7 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return _.uniqBy(channels, 'site_id')
|
return uniqBy(channels, 'site_id')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"data":{"entries":{"243":[{"createdAt":"2023-11-05T17:09:34.000Z","updatedAt":"2023-11-05T17:09:34.000Z","id":"009f3a34-8164-4ff9-b981-9dcab1a518fc","channelNo":"243","programmeId":null,"title":"News Live","episode":null,"slug":"news-live","date":"2023-11-08 17:00:00","startTime":"2023-11-08 20:00:00","endTime":"2023-11-08 20:30:00","length":1800,"description":"News Live","long_description":"Up to date news and analysis from around the world.","status":true,"channel":{"id":"7fd7a9a6-af32-c861-d2b0-4ddc7846fad2","key":"AljaInt","no":243,"name":"Al Jazeera International","slug":"al-jazeera-international","website":null,"description":"<p>An international 24-hour English-language It is the first English-language news channel brings you the latest global news stories, analysis from the Middle East & worldwide.</p>","shortDescription":null,"logo":"files/logos/channels/11-NEWS/AlJazeera Int SD-FirstMedia-Chl-243.jpg","externalId":"132","type":"radio","status":true,"chanel":"SD","locale":"id","relationId":"5a6ea4ae-a008-4889-9c68-7a6f1838e81d","onlyfm":null,"genress":[{"id":"1db3bb43-b00d-49af-b272-6c058a8c0b49","name":"International Free View"},{"id":"2e81a4bd-9719-4186-820a-7e035e07be13","name":"News"}]}}]}}}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { url, parser } = require('./firstmedia.com.config.js')
|
const { url, parser } = require('./firstmedia.com.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
@@ -13,8 +15,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'), 'utf8')
|
||||||
'{"data":{"entries":{"243":[{"createdAt":"2023-11-05T17:09:34.000Z","updatedAt":"2023-11-05T17:09:34.000Z","id":"009f3a34-8164-4ff9-b981-9dcab1a518fc","channelNo":"243","programmeId":null,"title":"News Live","episode":null,"slug":"news-live","date":"2023-11-08 17:00:00","startTime":"2023-11-08 20:00:00","endTime":"2023-11-08 20:30:00","length":1800,"description":"News Live","long_description":"Up to date news and analysis from around the world.","status":true,"channel":{"id":"7fd7a9a6-af32-c861-d2b0-4ddc7846fad2","key":"AljaInt","no":243,"name":"Al Jazeera International","slug":"al-jazeera-international","website":null,"description":"<p>An international 24-hour English-language It is the first English-language news channel brings you the latest global news stories, analysis from the Middle East & worldwide.</p>","shortDescription":null,"logo":"files/logos/channels/11-NEWS/AlJazeera Int SD-FirstMedia-Chl-243.jpg","externalId":"132","type":"radio","status":true,"chanel":"SD","locale":"id","relationId":"5a6ea4ae-a008-4889-9c68-7a6f1838e81d","onlyfm":null,"genress":[{"id":"1db3bb43-b00d-49af-b272-6c058a8c0b49","name":"International Free View"},{"id":"2e81a4bd-9719-4186-820a-7e035e07be13","name":"News"}]}}]}}}'
|
|
||||||
const results = parser({ content, channel, date })
|
const results = parser({ content, channel, date })
|
||||||
|
|
||||||
// All time in Asia/Jakarta
|
// All time in Asia/Jakarta
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"channel-programme":[
|
||||||
|
{
|
||||||
|
"id":"31cc8b4c-3711-49f0-bf22-2ec3993b0a07",
|
||||||
|
"programmeTitle":"NRL",
|
||||||
|
"title":"Eels v Titans",
|
||||||
|
"startTime":"2022-12-14T00:00:00+11:00",
|
||||||
|
"endTime":"2022-12-14T01:00:00+11:00",
|
||||||
|
"duration":60,
|
||||||
|
"live":false,
|
||||||
|
"genreId":"5c389cf4-8db7-4b52-9773-52355bd28559",
|
||||||
|
"channelId":2,
|
||||||
|
"channelName":"FOX League",
|
||||||
|
"channelAbbreviation":"LEAGUE",
|
||||||
|
"programmeUID":235220,
|
||||||
|
"round":"R1",
|
||||||
|
"statsMatchId":null,
|
||||||
|
"closedCaptioned":true,
|
||||||
|
"statsFixtureId":10207,
|
||||||
|
"genreTitle":"Rugby League",
|
||||||
|
"parentGenreId":"a953f929-2d12-41a4-b0e9-97f401afff11",
|
||||||
|
"parentGenreTitle":"Sport",
|
||||||
|
"pmgId":"PMG01306944",
|
||||||
|
"statsSport":"league",
|
||||||
|
"type":"GAME",
|
||||||
|
"hiDef":true,
|
||||||
|
"widescreen":true,
|
||||||
|
"classification":"",
|
||||||
|
"synopsis":"The Eels and Titans have plenty of motivation this season after heartbreaking Finals losses in 2021. Parramatta has won their past five against Gold Coast.",
|
||||||
|
"preGameStartTime":null,
|
||||||
|
"closeCaptioned":true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"channel-programme":[]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./foxsports.com.au.config.js')
|
const { parser, url } = require('./foxsports.com.au.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
@@ -15,9 +17,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'{"channel-programme":[{"id":"31cc8b4c-3711-49f0-bf22-2ec3993b0a07","programmeTitle":"NRL","title":"Eels v Titans","startTime":"2022-12-14T00:00:00+11:00","endTime":"2022-12-14T01:00:00+11:00","duration":60,"live":false,"genreId":"5c389cf4-8db7-4b52-9773-52355bd28559","channelId":2,"channelName":"FOX League","channelAbbreviation":"LEAGUE","programmeUID":235220,"round":"R1","statsMatchId":null,"closedCaptioned":true,"statsFixtureId":10207,"genreTitle":"Rugby League","parentGenreId":"a953f929-2d12-41a4-b0e9-97f401afff11","parentGenreTitle":"Sport","pmgId":"PMG01306944","statsSport":"league","type":"GAME","hiDef":true,"widescreen":true,"classification":"","synopsis":"The Eels and Titans have plenty of motivation this season after heartbreaking Finals losses in 2021. Parramatta has won their past five against Gold Coast.","preGameStartTime":null,"closeCaptioned":true}]}'
|
|
||||||
|
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -38,11 +38,6 @@ it('can parse response', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser(
|
const result = parser({content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))}, channel)
|
||||||
{
|
|
||||||
content: '{"channel-programme":[]}'
|
|
||||||
},
|
|
||||||
channel
|
|
||||||
)
|
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
[{"id":5856194,"publicUid":"f17b5a1d-3f2a-42a0-a11b-a08e5c9785fd","title":"בוש 4 - פרק 3","lead":"עונה 4 חדשה לדרמה הבלשית. 3. השטן בתוך הבית: הכוח המיוחד מנסה לחקור, ומגלה אליבי שקרי עם השלכות מרעישות. הבלש סנטיאגו רוברטסון צריך לשים את קשריו האישיים בצד למען החקירה. בוש זוכה לביקור פתע לילי.כ עב","description":"עונה 4 חדשה לדרמה הבלשית. 3. השטן בתוך הבית: הכוח המיוחד מנסה לחקור, ומגלה אליבי שקרי עם השלכות מרעישות. הבלש סנטיאגו רוברטסון צריך לשים את קשריו האישיים בצד למען החקירה. בוש זוכה לביקור פתע לילי.כ עב","rating":14,"ratingEmbedded":false,"type":"PROGRAMME","uhd":false,"since":"2025-03-27T21:26:00Z","till":"2025-03-27T22:17:00Z","images":{"16x9":[{"url":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1","templateUrl":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1&dsth={height:177}&dstw={width:315}"}]},"genres":[],"webUrl":"https://web.freetv.tv/news,1991/rw-11,3370462/2025-03-27/bw-4---prq-3,5856194","trailer":false,"live":{"type_":"LIVE","id":3370462},"available":true,"timeshiftAvailable":false,"startoverAvailable":false,"catchupTill":"2025-04-10T21:26:00Z","npvrTill":"2025-04-10T21:26:00Z","programRecordingId":7068534,"audio":false,"video":true,"showRecommendations":false,"recommended":false,"premiere":false,"liveBroadcast":false,"slug":"bw-4---prq-3"},{"id":5858584,"publicUid":"1dc296c9-0c28-4202-8b20-cbef56a763f5","title":"אבא משתדל - 5. חבר","lead":"סדרה קומית. יוסי מכיר אב לילד עם צרכים מיוחדים ובין השניים מתפתח קשר בסגנון חיזור גורלי שמערער את יוסי. כ עב.","description":"סדרה קומית. יוסי מכיר אב לילד עם צרכים מיוחדים ובין השניים מתפתח קשר בסגנון חיזור גורלי שמערער את יוסי. כ עב.","ratingEmbedded":false,"type":"PROGRAMME","uhd":false,"since":"2025-03-27T22:17:00Z","till":"2025-03-27T22:43:00Z","images":{"16x9":[{"url":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1","templateUrl":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1&dsth={height:177}&dstw={width:315}"}]},"genres":[],"webUrl":"https://web.freetv.tv/news,1991/rw-11,3370462/2025-03-27/b-mdl---5-br,5858584","trailer":false,"live":{"type_":"LIVE","id":3370462},"available":true,"timeshiftAvailable":false,"startoverAvailable":false,"catchupTill":"2025-04-10T22:17:00Z","npvrTill":"2025-04-10T22:17:00Z","programRecordingId":7071052,"audio":false,"video":true,"showRecommendations":false,"recommended":false,"premiere":false,"liveBroadcast":false,"slug":"b-mdl---5-br"}]
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./freetv.tv.config.js')
|
const { parser, url } = require('./freetv.tv.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -16,8 +18,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = '[{"id":5856194,"publicUid":"f17b5a1d-3f2a-42a0-a11b-a08e5c9785fd","title":"בוש 4 - פרק 3","lead":"עונה 4 חדשה לדרמה הבלשית. 3. השטן בתוך הבית: הכוח המיוחד מנסה לחקור, ומגלה אליבי שקרי עם השלכות מרעישות. הבלש סנטיאגו רוברטסון צריך לשים את קשריו האישיים בצד למען החקירה. בוש זוכה לביקור פתע לילי.כ עב","description":"עונה 4 חדשה לדרמה הבלשית. 3. השטן בתוך הבית: הכוח המיוחד מנסה לחקור, ומגלה אליבי שקרי עם השלכות מרעישות. הבלש סנטיאגו רוברטסון צריך לשים את קשריו האישיים בצד למען החקירה. בוש זוכה לביקור פתע לילי.כ עב","rating":14,"ratingEmbedded":false,"type":"PROGRAMME","uhd":false,"since":"2025-03-27T21:26:00Z","till":"2025-03-27T22:17:00Z","images":{"16x9":[{"url":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1","templateUrl":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1361162/COVER/images/1361162_1736767668746.jpg?srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1&dsth={height:177}&dstw={width:315}"}]},"genres":[],"webUrl":"https://web.freetv.tv/news,1991/rw-11,3370462/2025-03-27/bw-4---prq-3,5856194","trailer":false,"live":{"type_":"LIVE","id":3370462},"available":true,"timeshiftAvailable":false,"startoverAvailable":false,"catchupTill":"2025-04-10T21:26:00Z","npvrTill":"2025-04-10T21:26:00Z","programRecordingId":7068534,"audio":false,"video":true,"showRecommendations":false,"recommended":false,"premiere":false,"liveBroadcast":false,"slug":"bw-4---prq-3"},{"id":5858584,"publicUid":"1dc296c9-0c28-4202-8b20-cbef56a763f5","title":"אבא משתדל - 5. חבר","lead":"סדרה קומית. יוסי מכיר אב לילד עם צרכים מיוחדים ובין השניים מתפתח קשר בסגנון חיזור גורלי שמערער את יוסי. כ עב.","description":"סדרה קומית. יוסי מכיר אב לילד עם צרכים מיוחדים ובין השניים מתפתח קשר בסגנון חיזור גורלי שמערער את יוסי. כ עב.","ratingEmbedded":false,"type":"PROGRAMME","uhd":false,"since":"2025-03-27T22:17:00Z","till":"2025-03-27T22:43:00Z","images":{"16x9":[{"url":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?dsth=177&dstw=315&srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1","templateUrl":"//d1zqtf09wb8nt5.cloudfront.net/scale/oil/freetv/upload/programme/1070668/COVER/images/1070668_1742202219830.jpg?srcmode=0&srcx=0&srcy=0&quality=65&type=1&srcw=1/1&srch=1/1&dsth={height:177}&dstw={width:315}"}]},"genres":[],"webUrl":"https://web.freetv.tv/news,1991/rw-11,3370462/2025-03-27/b-mdl---5-br,5858584","trailer":false,"live":{"type_":"LIVE","id":3370462},"available":true,"timeshiftAvailable":false,"startoverAvailable":false,"catchupTill":"2025-04-10T22:17:00Z","npvrTill":"2025-04-10T22:17:00Z","programRecordingId":7071052,"audio":false,"video":true,"showRecommendations":false,"recommended":false,"premiere":false,"liveBroadcast":false,"slug":"b-mdl---5-br"}]'
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
|
|
||||||
const results = parser({ content }).map(p => {
|
const results = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"count":83,"next":null,"previous":null,"results":[{"id":135605,"video":{"id":626094,"name":"FSCONS 2017 - Keynote: TBA - Linda Sandvik","header":"Linda Sandvik's keynote at FSCONS 2017\r\n\r\nRecorded by NUUG for FSCONS.","description":null,"creator":"davidwnoble@gmail.com","organization":{"id":82,"name":"NUUG","homepage":"https://www.nuug.no/","description":"Forening NUUG er for alle som er interessert i fri programvare, åpne standarder og Unix-lignende operativsystemer.","postalAddress":"","streetAddress":"","editorId":2148,"editorName":"David Noble","editorEmail":"davidwnoble@gmail.com","editorMsisdn":"","fkmember":true},"duration":"00:57:55.640000","categories":["Samfunn"]},"schedulereason":5,"starttime":"2022-01-19T00:47:00+01:00","endtime":"2022-01-19T01:44:55.640000+01:00","duration":"00:57:55.640000"}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"count":0,"next":null,"previous":null,"results":[]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./frikanalen.no.config.js')
|
const { parser, url } = require('./frikanalen.no.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -18,8 +20,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'{"count":83,"next":null,"previous":null,"results":[{"id":135605,"video":{"id":626094,"name":"FSCONS 2017 - Keynote: TBA - Linda Sandvik","header":"Linda Sandvik\'s keynote at FSCONS 2017\\r\\n\\r\\nRecorded by NUUG for FSCONS.","description":null,"creator":"davidwnoble@gmail.com","organization":{"id":82,"name":"NUUG","homepage":"https://www.nuug.no/","description":"Forening NUUG er for alle som er interessert i fri programvare, åpne standarder og Unix-lignende operativsystemer.","postalAddress":"","streetAddress":"","editorId":2148,"editorName":"David Noble","editorEmail":"davidwnoble@gmail.com","editorMsisdn":"","fkmember":true},"duration":"00:57:55.640000","categories":["Samfunn"]},"schedulereason":5,"starttime":"2022-01-19T00:47:00+01:00","endtime":"2022-01-19T01:44:55.640000+01:00","duration":"00:57:55.640000"}]}'
|
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -41,7 +42,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '{"count":0,"next":null,"previous":null,"results":[]}'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"programs": [
|
||||||
|
{
|
||||||
|
"metaInfo": {
|
||||||
|
"title": "Гимн",
|
||||||
|
"description": "Государственный гимн Республики Казахстан"
|
||||||
|
},
|
||||||
|
"scheduleInfo": {
|
||||||
|
"start": 1736470800,
|
||||||
|
"end": 1736471100
|
||||||
|
},
|
||||||
|
"mediaInfo": {
|
||||||
|
"thumbnails": [
|
||||||
|
{
|
||||||
|
"url": "http://galam.server-img.lfstrm.tv:80/image/aHR0cDovL2dhbGFtLmltZy1vcmlnaW5hbHMubGZzdHJtLnR2OjgwL3R2aW1hZ2VzL3RodW1iL2YyNWFmYWY2ZDkzYjU5YjdkMjBiZDNiODhiZjg4NWI0X29yaWcuanBn"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"programs":[]}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./galamtv.kz.config.js')
|
const { parser, url } = require('./galamtv.kz.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -21,28 +23,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content = JSON.stringify({
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
programs: [
|
|
||||||
{
|
|
||||||
metaInfo: {
|
|
||||||
title: 'Гимн',
|
|
||||||
description: 'Государственный гимн Республики Казахстан'
|
|
||||||
},
|
|
||||||
scheduleInfo: {
|
|
||||||
start: 1736470800,
|
|
||||||
end: 1736471100
|
|
||||||
},
|
|
||||||
mediaInfo: {
|
|
||||||
thumbnails: [
|
|
||||||
{
|
|
||||||
url: 'http://galam.server-img.lfstrm.tv:80/image/aHR0cDovL2dhbGFtLmltZy1vcmlnaW5hbHMubGZzdHJtLnR2OjgwL3R2aW1hZ2VzL3RodW1iL2YyNWFmYWY2ZDkzYjU5YjdkMjBiZDNiODhiZjg4NWI0X29yaWcuanBn'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
const result = parser({ content, channel }).map(p => {
|
const result = parser({ content, channel }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -65,7 +46,7 @@ it('can handle empty guide', () => {
|
|||||||
const result = parser({
|
const result = parser({
|
||||||
date,
|
date,
|
||||||
channel,
|
channel,
|
||||||
content: '{"programs":[]}'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
const axios = require('axios')
|
||||||
const cheerio = require('cheerio')
|
const cheerio = require('cheerio')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const timezone = require('dayjs/plugin/timezone')
|
const timezone = require('dayjs/plugin/timezone')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
|
const uniqBy = require('lodash.uniqby')
|
||||||
|
|
||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
@@ -41,9 +43,6 @@ module.exports = {
|
|||||||
return programs
|
return programs
|
||||||
},
|
},
|
||||||
async channels() {
|
async channels() {
|
||||||
const axios = require('axios')
|
|
||||||
const _ = require('lodash')
|
|
||||||
|
|
||||||
const providers = ['-1', '-2', '-3']
|
const providers = ['-1', '-2', '-3']
|
||||||
|
|
||||||
const channels = []
|
const channels = []
|
||||||
@@ -77,7 +76,7 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.uniqBy(channels, 'site_id')
|
return uniqBy(channels, 'site_id')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"events": [ { "channel": { "id": 10458, "logo": "/logo/545820mediasethd_Light_Fit.png", "logoPadding": "/logo/545820mediasethd_Light_Padding.png", "logoDark": "/logo/545820mediasethd_Dark_Fit.png", "logoDarkPadding": "/logo/545820mediasethd_Dark_Padding.png", "logoLight": "/logo/545820mediasethd_Light_Padding.png", "name": "20Mediaset HD", "number": 151, "category": { "id": 3, "name": "Intrattenimento" } }, "content": { "uuid": "77c630aa-4744-44cb-a88e-3e871c6b73d9", "contentTitle": "Distretto di Polizia", "episodeNumber": 26, "seasonNumber": 6, "url": "/serie-tv/distretto-di-polizia/stagione-6/episodio-26/77c630aa-4744-44cb-a88e-3e871c6b73d9", "genre": { "id": 1, "name": "Intrattenimento" }, "subgenre": { "id": 9, "name": "Fiction" }, "imagesMap": [ { "key": "background", "img": { "url": "/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/background?md5ChecksumParam=88d3f48ce855316f4be25ab9bb846d32" } }, { "key": "cover", "img": { "url": "/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/cover?md5ChecksumParam=61135b999a63e3d3f4a933b9edeb0c1b" } }, { "key": "scene", "img": { "url": "/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/16-9?md5ChecksumParam=f41bfe414bec32505abdab19d00b8b43" } } ] }, "eventId": "139585132", "starttime": "2022-05-06T00:35:40Z", "endtime": "2022-05-06T01:15:40Z", "eventTitle": "Distretto di Polizia", "eventSynopsis": "S6 Ep26 La resa dei conti - Fino all'ultimo la sfida tra Ardenzi e Carrano, nemici di vecchia data, riserva clamorosi colpi di scena. E si scopre che non e' tutto come sembrava.", "epgEventTitle": "S6 Ep26 - Distretto di Polizia", "primeVision": false, "resolutions": [ { "resolutionType": "resolution4k", "value": false } ] }]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"events":[],"total":0}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
const { parser, url } = require('./guidatv.sky.it.config.js')
|
const { parser, url } = require('./guidatv.sky.it.config.js')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
const utc = require('dayjs/plugin/utc')
|
const utc = require('dayjs/plugin/utc')
|
||||||
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
const customParseFormat = require('dayjs/plugin/customParseFormat')
|
||||||
@@ -18,8 +20,7 @@ it('can generate valid url', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can parse response', () => {
|
it('can parse response', () => {
|
||||||
const content =
|
const content = fs.readFileSync(path.resolve(__dirname, '__data__/content.json'))
|
||||||
'{"events": [ { "channel": { "id": 10458, "logo": "/logo/545820mediasethd_Light_Fit.png", "logoPadding": "/logo/545820mediasethd_Light_Padding.png", "logoDark": "/logo/545820mediasethd_Dark_Fit.png", "logoDarkPadding": "/logo/545820mediasethd_Dark_Padding.png", "logoLight": "/logo/545820mediasethd_Light_Padding.png", "name": "20Mediaset HD", "number": 151, "category": { "id": 3, "name": "Intrattenimento" } }, "content": { "uuid": "77c630aa-4744-44cb-a88e-3e871c6b73d9", "contentTitle": "Distretto di Polizia", "episodeNumber": 26, "seasonNumber": 6, "url": "/serie-tv/distretto-di-polizia/stagione-6/episodio-26/77c630aa-4744-44cb-a88e-3e871c6b73d9", "genre": { "id": 1, "name": "Intrattenimento" }, "subgenre": { "id": 9, "name": "Fiction" }, "imagesMap": [ { "key": "background", "img": { "url": "/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/background?md5ChecksumParam=88d3f48ce855316f4be25ab9bb846d32" } }, { "key": "cover", "img": { "url": "/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/cover?md5ChecksumParam=61135b999a63e3d3f4a933b9edeb0c1b" } }, { "key": "scene", "img": { "url": "/uuid/77c630aa-4744-44cb-a88e-3e871c6b73d9/16-9?md5ChecksumParam=f41bfe414bec32505abdab19d00b8b43" } } ] }, "eventId": "139585132", "starttime": "2022-05-06T00:35:40Z", "endtime": "2022-05-06T01:15:40Z", "eventTitle": "Distretto di Polizia", "eventSynopsis": "S6 Ep26 La resa dei conti - Fino all\'ultimo la sfida tra Ardenzi e Carrano, nemici di vecchia data, riserva clamorosi colpi di scena. E si scopre che non e\' tutto come sembrava.", "epgEventTitle": "S6 Ep26 - Distretto di Polizia", "primeVision": false, "resolutions": [ { "resolutionType": "resolution4k", "value": false } ] }]}'
|
|
||||||
const result = parser({ content }).map(p => {
|
const result = parser({ content }).map(p => {
|
||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
@@ -45,7 +46,7 @@ it('can parse response', () => {
|
|||||||
|
|
||||||
it('can handle empty guide', () => {
|
it('can handle empty guide', () => {
|
||||||
const result = parser({
|
const result = parser({
|
||||||
content: '{"events":[],"total":0}'
|
content: fs.readFileSync(path.resolve(__dirname, '__data__/no_content.json'))
|
||||||
})
|
})
|
||||||
expect(result).toMatchObject([])
|
expect(result).toMatchObject([])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ module.exports = {
|
|||||||
let category = parseCategory($item)
|
let category = parseCategory($item)
|
||||||
let description = parseDescription($item)
|
let description = parseDescription($item)
|
||||||
const itemDetailsURL = parseDescriptionURL($item)
|
const itemDetailsURL = parseDescriptionURL($item)
|
||||||
if(itemDetailsURL) {
|
if (itemDetailsURL) {
|
||||||
const url = 'https://www.guidetnt.com' + itemDetailsURL
|
const url = 'https://www.guidetnt.com' + itemDetailsURL
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(url)
|
const response = await axios.get(url)
|
||||||
@@ -110,7 +110,9 @@ module.exports = {
|
|||||||
// Look inside each .tvlogo container
|
// Look inside each .tvlogo container
|
||||||
$('.tvlogo').each((i, el) => {
|
$('.tvlogo').each((i, el) => {
|
||||||
// Find all descendants that have an alt attribute
|
// Find all descendants that have an alt attribute
|
||||||
$(el).find('[alt]').each((j, subEl) => {
|
$(el)
|
||||||
|
.find('[alt]')
|
||||||
|
.each((j, subEl) => {
|
||||||
const alt = $(subEl).attr('alt')
|
const alt = $(subEl).attr('alt')
|
||||||
const href = $(subEl).attr('href')
|
const href = $(subEl).attr('href')
|
||||||
if (href && alt && alt.trim() !== '') {
|
if (href && alt && alt.trim() !== '') {
|
||||||
@@ -218,7 +220,10 @@ function parseItemDetails(itemDetails) {
|
|||||||
function parseCategoryText(text) {
|
function parseCategoryText(text) {
|
||||||
if (!text) return null
|
if (!text) return null
|
||||||
|
|
||||||
const parts = text.split(',').map(s => s.trim()).filter(Boolean)
|
const parts = text
|
||||||
|
.split(',')
|
||||||
|
.map(s => s.trim())
|
||||||
|
.filter(Boolean)
|
||||||
const len = parts.length
|
const len = parts.length
|
||||||
|
|
||||||
const category = parts[0] || null
|
const category = parts[0] || null
|
||||||
@@ -263,7 +268,7 @@ function parseCategoryText(text) {
|
|||||||
|
|
||||||
// Country: second to last
|
// Country: second to last
|
||||||
const countryIndex = len - 2
|
const countryIndex = len - 2
|
||||||
let country = (durationIndex === countryIndex) ? null : parts[countryIndex]
|
let country = durationIndex === countryIndex ? null : parts[countryIndex]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
category,
|
category,
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ it('can parse response', async () => {
|
|||||||
expect(results.length).toBe(29)
|
expect(results.length).toBe(29)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
category: 'Série',
|
category: 'Série',
|
||||||
description: 'Grande effervescence pour toute l\'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d\'optimiser les révisions d\'E...',
|
description:
|
||||||
|
"Grande effervescence pour toute l'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d'optimiser les révisions d'E...",
|
||||||
start: '2025-06-30T22:55:00.000Z',
|
start: '2025-06-30T22:55:00.000Z',
|
||||||
stop: '2025-06-30T23:45:00.000Z',
|
stop: '2025-06-30T23:45:00.000Z',
|
||||||
title: 'Camping Paradis'
|
title: 'Camping Paradis'
|
||||||
@@ -46,10 +47,11 @@ it('can parse response', async () => {
|
|||||||
})
|
})
|
||||||
expect(results[15]).toMatchObject({
|
expect(results[15]).toMatchObject({
|
||||||
category: 'Téléfilm',
|
category: 'Téléfilm',
|
||||||
description: 'La vie quasi parfaite de Riley bascule brutalement lorsqu\'un accident de voiture lui coûte la vie, laissant derrière elle sa famille. Alors que l\'enquête débute, l\'affaire prend une tournure étrange l...',
|
description:
|
||||||
|
"La vie quasi parfaite de Riley bascule brutalement lorsqu'un accident de voiture lui coûte la vie, laissant derrière elle sa famille. Alors que l'enquête débute, l'affaire prend une tournure étrange l...",
|
||||||
start: '2025-07-01T12:25:00.000Z',
|
start: '2025-07-01T12:25:00.000Z',
|
||||||
stop: '2025-07-01T14:00:00.000Z',
|
stop: '2025-07-01T14:00:00.000Z',
|
||||||
title: 'Trahie par l\'amour'
|
title: "Trahie par l'amour"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -60,13 +62,13 @@ it('can parse response for current day', async () => {
|
|||||||
p.start = p.start.toJSON()
|
p.start = p.start.toJSON()
|
||||||
p.stop = p.stop.toJSON()
|
p.stop = p.stop.toJSON()
|
||||||
return p
|
return p
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
expect(results.length).toBe(29)
|
expect(results.length).toBe(29)
|
||||||
expect(results[0]).toMatchObject({
|
expect(results[0]).toMatchObject({
|
||||||
category: 'Série',
|
category: 'Série',
|
||||||
description: 'Grande effervescence pour toute l\'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d\'optimiser les révisions d\'E...',
|
description:
|
||||||
|
"Grande effervescence pour toute l'équipe du Camping Paradis, qui prépare les Olympiades. Côté arrivants, Hélène et sa fille Eva viennent passer quelques jours dans le but d'optimiser les révisions d'E...",
|
||||||
start: '2025-06-30T22:55:00.000Z',
|
start: '2025-06-30T22:55:00.000Z',
|
||||||
stop: '2025-06-30T23:45:00.000Z',
|
stop: '2025-06-30T23:45:00.000Z',
|
||||||
title: 'Camping Paradis'
|
title: 'Camping Paradis'
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{"entryCount":184,"totalResults":184,"updated":1675790518889,"expires":1675791343825,"title":"EPG","periods":4,"periodStartTime":1675724400000,"periodEndTime":1675746000000,"entries":[{"o":"lgi-obolite-sk-prod-master:10024","l":[{"i":"crid:~~2F~~2Fport.cs~~2F122941980,imi:7ca159c917344e0dd3fbe1cd8db5ff8043d96a78","t":"Avengement","s":1675719300000,"e":1675724700000,"c":"lgi-obolite-sk-prod-master:genre-9","a":false,"r":true,"rm":true,"rs":0,"re":604800,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"entryCount":184,"totalResults":184,"updated":1675790518889,"expires":1675791376097,"title":"EPG","periods":4,"periodStartTime":1675746000000,"periodEndTime":1675767600000,"entries":[{"o":"lgi-obolite-sk-prod-master:10024","l":[{"i":"crid:~~2F~~2Fport.cs~~2F248281986,imi:e85129f9d1e211406a521df7a36f22237c22651b","t":"Zoom In","s":1675744500000,"e":1675746000000,"c":"lgi-obolite-sk-prod-master:genre-21","a":false,"r":true,"rm":true,"rs":0,"re":604800,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"entryCount":184,"totalResults":184,"updated":1675789948804,"expires":1675791024984,"title":"EPG","periods":4,"periodStartTime":1675767600000,"periodEndTime":1675789200000,"entries":[{"o":"lgi-obolite-sk-prod-master:10024","l":[{"i":"crid:~~2F~~2Fport.cs~~2F1379541,imi:5f806a2a0bc13e9745e14907a27116c60ea2c6ad","t":"Studentka","s":1675761000000,"e":1675767600000,"c":"lgi-obolite-sk-prod-master:genre-14","a":false,"r":true,"rm":true,"rs":0,"re":604800,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"entryCount":184,"totalResults":184,"updated":1675789948804,"expires":1675790973469,"title":"EPG","periods":4,"periodStartTime":1675789200000,"periodEndTime":1675810800000,"entries":[{"o":"lgi-obolite-sk-prod-master:10024","l":[{"i":"crid:~~2F~~2Fport.cs~~2F71927954,imi:f1b4b0285b72cf44cba74e1c62322a4c682385c7","t":"Zilionáři","s":1675785900000,"e":1675791900000,"c":"lgi-obolite-sk-prod-master:genre-9","a":false,"r":true,"rm":true,"rs":0,"re":604800,"rst":"cloud","ra":false,"ad":[],"sl":[]}]}]}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"id":"crid:~~2F~~2Fport.cs~~2F122941980,imi:7ca159c917344e0dd3fbe1cd8db5ff8043d96a78","startTime":1675719300000,"endTime":1675724700000,"actualStartTime":1675719300000,"actualEndTime":1675724700000,"expirationDate":1676324100000,"stationId":"lgi-obolite-sk-prod-master:10024","imi":"imi:7ca159c917344e0dd3fbe1cd8db5ff8043d96a78","scCridImi":"crid:~~2F~~2Fport.cs~~2F122941980,imi:7ca159c917344e0dd3fbe1cd8db5ff8043d96a78","mediaGroupId":"crid:~~2F~~2Fport.cs~~2F122941980","program":{"id":"crid:~~2F~~2Fport.cs~~2F122941980","title":"Avengement","description":"Během propustky z vězení za účelem návštěvy umírající matky v nemocnici zločinec Cain Burgess (Scott Adkins) unikne svým dozorcům a mizí v ulicích Londýna. Jde o epickou cestu krve a bolesti za...","longDescription":"Během propustky z vězení za účelem návštěvy umírající matky v nemocnici zločinec Cain Burgess (Scott Adkins) unikne svým dozorcům a mizí v ulicích Londýna. Jde o epickou cestu krve a bolesti za dosažením vytoužené pomsty na těch, kteří z něj udělali chladnokrevného vraha.","medium":"Movie","categories":[{"id":"lgi-obolite-sk-prod-master:genre-9","title":"Drama","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-obolite-sk-prod-master:genre-33","title":"Akcia","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"parentalRating":"18","cast":["Scott Adkins","Craig Fairbrass","Thomas Turgoose","Nick Moran","Kierston Wareing","Leo Gregory","Mark Strange","Luke LaFontaine","Beau Fowler","Dan Styles","Christopher Sciueref","Matt Routledge","Jane Thorne","Louis Mandylor","Terence Maynard","Greg Burridge","Michael Higgs","Damian Gallagher","Daniel Adegboyega","John Ioannou","Sofie Golding-Spittle","Joe Egan","Darren Swain","Lee Charles","Dominic Kinnaird","Ross O'Hennessy","Teresa Mahoney","Andrew Dunkelberger","Sam Hardy","Ivan Moy","Mark Sears","Phillip Ray Tommy"],"directors":["Jesse V. Johnson"],"images":[{"assetType":"HighResLandscape","assetTypes":["HighResLandscape"],"url":"http://62.179.125.152/SK/Images/hrl_3fa8387df870473fdacb1024635b52b2496b159c.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"http://62.179.125.152/SK/Images/hrp_19e3a660e637cd39e31046c284a66b3a95d698e4.jpg"},{"assetType":"boxCover","assetTypes":["boxCover"],"url":"http://62.179.125.152/SK/Images/bc_939160772e45a783fb3a19970696f5ebcb6e568b.jpg"},{"assetType":"boxart-small","assetTypes":["boxart-small"],"url":"http://62.179.125.152/SK/Images/bc_939160772e45a783fb3a19970696f5ebcb6e568b.jpg?w=75&h=108&mode=box"},{"assetType":"boxart-medium","assetTypes":["boxart-medium"],"url":"http://62.179.125.152/SK/Images/bc_939160772e45a783fb3a19970696f5ebcb6e568b.jpg?w=110&h=159&mode=box"},{"assetType":"boxart-xlarge","assetTypes":["boxart-xlarge"],"url":"http://62.179.125.152/SK/Images/bc_939160772e45a783fb3a19970696f5ebcb6e568b.jpg?w=210&h=303&mode=box"},{"assetType":"boxart-large","assetTypes":["boxart-large"],"url":"http://62.179.125.152/SK/Images/bc_939160772e45a783fb3a19970696f5ebcb6e568b.jpg?w=180&h=260&mode=box"}],"rootId":"crid:~~2F~~2Fport.cs~~2F122941980","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fport.cs~~2F122941980","shortDescription":"Během propustky z vězení za účelem návštěvy umírající matky v nemocnici zločinec Cain Burgess (Scott Adkins) unikne svým dozorcům a mizí v ulicích Londýna. Jde o epickou cestu krve a bolesti za...","mediaType":"FeatureFilm","year":"2019","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[]},"rootId":"crid:~~2F~~2Fport.cs~~2F122941980","replayTvAvailable":true,"audioTracks":[],"ratings":[],"offersLatestExpirationDate":1676247300000,"replayTvStartOffset":0,"replayTvEndOffset":604800,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"id":"crid:~~2F~~2Fport.cs~~2F248281986,imi:e85129f9d1e211406a521df7a36f22237c22651b","startTime":1675744500000,"endTime":1675746000000,"actualStartTime":1675744500000,"actualEndTime":1675746000000,"expirationDate":1676349300000,"stationId":"lgi-obolite-sk-prod-master:10024","imi":"imi:e85129f9d1e211406a521df7a36f22237c22651b","scCridImi":"crid:~~2F~~2Fport.cs~~2F248281986,imi:e85129f9d1e211406a521df7a36f22237c22651b","mediaGroupId":"crid:~~2F~~2Fport.cs~~2F41764266","program":{"id":"crid:~~2F~~2Fport.cs~~2F248281986","title":"Zoom In","description":"Film/Kino","longDescription":"Film/Kino","medium":"TV","categories":[{"id":"lgi-obolite-sk-prod-master:genre-21","title":"Hudba a umenie","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-obolite-sk-prod-master:genre-14","title":"Film","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"parentalRating":"9","cast":[],"directors":[],"images":[{"assetType":"HighResLandscape","assetTypes":["HighResLandscape"],"url":"http://62.179.125.152/SK/Images/hrl_cbed64b557e83227a2292604cbcae2d193877b1c.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"http://62.179.125.152/SK/Images/hrp_cfe405e669385365846b69196e1e94caa3e60de0.jpg"},{"assetType":"boxCover","assetTypes":["boxCover"],"url":"http://62.179.125.152/SK/Images/bc_cfe405e669385365846b69196e1e94caa3e60de0.jpg"},{"assetType":"boxart-small","assetTypes":["boxart-small"],"url":"http://62.179.125.152/SK/Images/bc_cfe405e669385365846b69196e1e94caa3e60de0.jpg?w=75&h=108&mode=box"},{"assetType":"boxart-medium","assetTypes":["boxart-medium"],"url":"http://62.179.125.152/SK/Images/bc_cfe405e669385365846b69196e1e94caa3e60de0.jpg?w=110&h=159&mode=box"},{"assetType":"boxart-xlarge","assetTypes":["boxart-xlarge"],"url":"http://62.179.125.152/SK/Images/bc_cfe405e669385365846b69196e1e94caa3e60de0.jpg?w=210&h=303&mode=box"},{"assetType":"boxart-large","assetTypes":["boxart-large"],"url":"http://62.179.125.152/SK/Images/bc_cfe405e669385365846b69196e1e94caa3e60de0.jpg?w=180&h=260&mode=box"}],"parentId":"crid:~~2F~~2Fport.cs~~2F41764266_series","rootId":"crid:~~2F~~2Fport.cs~~2F41764266","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fport.cs~~2F41764266","shortDescription":"Film/Kino","mediaType":"Episode","year":"2010","seriesEpisodeNumber":"1302070535","seriesNumber":"1302080520","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[]},"parentId":"crid:~~2F~~2Fport.cs~~2F41764266_series","rootId":"crid:~~2F~~2Fport.cs~~2F41764266","replayTvAvailable":true,"audioTracks":[],"ratings":[],"offersLatestExpirationDate":1675746000000,"replayTvStartOffset":0,"replayTvEndOffset":604800,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"id":"crid:~~2F~~2Fport.cs~~2F1379541,imi:5f806a2a0bc13e9745e14907a27116c60ea2c6ad","startTime":1675761000000,"endTime":1675767600000,"actualStartTime":1675761000000,"actualEndTime":1675767600000,"expirationDate":1676365800000,"stationId":"lgi-obolite-sk-prod-master:10024","imi":"imi:5f806a2a0bc13e9745e14907a27116c60ea2c6ad","scCridImi":"crid:~~2F~~2Fport.cs~~2F1379541,imi:5f806a2a0bc13e9745e14907a27116c60ea2c6ad","mediaGroupId":"crid:~~2F~~2Fport.cs~~2F1379541","program":{"id":"crid:~~2F~~2Fport.cs~~2F1379541","title":"Studentka","description":"Ambiciózní vysokoškolačka Valentina (Sophie Marceau) studuje literaturu na pařížské Sorbonně a právě se připravuje k závěrečným zkouškám. Žádný odpočinek, žádné volno, žádné večírky, téměř žádný...","longDescription":"Ambiciózní vysokoškolačka Valentina (Sophie Marceau) studuje literaturu na pařížské Sorbonně a právě se připravuje k závěrečným zkouškám. Žádný odpočinek, žádné volno, žádné večírky, téměř žádný spánek a především a hlavně ... žádná láska! Věří, že jedině tak obstojí před zkušební komisí. Jednoho dne se však odehraje něco, s čím nepočítala. Potká charismatického hudebníka Neda - a bláznivě se zamiluje. V tuto chvíli stojí před osudovým rozhodnutím: zahodí roky obrovského studijního nasazení, nebo odmítne lásku? Nebo se snad dá obojí skloubit dohromady?","medium":"Movie","categories":[{"id":"lgi-obolite-sk-prod-master:genre-14","title":"Film","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-obolite-sk-prod-master:genre-4","title":"Komédia","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"parentalRating":"9","cast":["Sophie Marceauová","Vincent Lindon","Elisabeth Vitali","Elena Pompei","Jean-Claude Leguay","Brigitte Chamarande","Christian Pereira","Gérard Dacier","Roberto Attias","Beppe Chierici","Nathalie Mann","Anne Macina","Janine Souchon","Virginie Demians","Hugues Leforestier","Jacqueline Noëlle","Marc-André Brunet","Isabelle Caubère","André Chazel","Med Salah Cheurfi","Guillaume Corea","Eric Denize","Gilles Gaston-Dreyfuss","Benoît Gourley","Marc Innocenti","Najim Laouriga","Laurent Ledermann","Philippe Maygal","Dominique Pifarely","Ysé Tran"],"directors":["Francis De Gueltz","Dominique Talmon","Claude Pinoteau"],"images":[{"assetType":"HighResLandscape","assetTypes":["HighResLandscape"],"url":"http://62.179.125.152/SK/Images/hrl_a8abceaa59bbb0aae8031dcdd5deba03aba8a100.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"http://62.179.125.152/SK/Images/hrp_72b11621270454812ac8474698fc75670db4a49d.jpg"},{"assetType":"boxCover","assetTypes":["boxCover"],"url":"http://62.179.125.152/SK/Images/bc_72b11621270454812ac8474698fc75670db4a49d.jpg"},{"assetType":"boxart-small","assetTypes":["boxart-small"],"url":"http://62.179.125.152/SK/Images/bc_72b11621270454812ac8474698fc75670db4a49d.jpg?w=75&h=108&mode=box"},{"assetType":"boxart-medium","assetTypes":["boxart-medium"],"url":"http://62.179.125.152/SK/Images/bc_72b11621270454812ac8474698fc75670db4a49d.jpg?w=110&h=159&mode=box"},{"assetType":"boxart-xlarge","assetTypes":["boxart-xlarge"],"url":"http://62.179.125.152/SK/Images/bc_72b11621270454812ac8474698fc75670db4a49d.jpg?w=210&h=303&mode=box"},{"assetType":"boxart-large","assetTypes":["boxart-large"],"url":"http://62.179.125.152/SK/Images/bc_72b11621270454812ac8474698fc75670db4a49d.jpg?w=180&h=260&mode=box"}],"rootId":"crid:~~2F~~2Fport.cs~~2F1379541","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fport.cs~~2F1379541","shortDescription":"Ambiciózní vysokoškolačka Valentina (Sophie Marceau) studuje literaturu na pařížské Sorbonně a právě se připravuje k závěrečným zkouškám. Žádný odpočinek, žádné volno, žádné večírky, téměř žádný...","mediaType":"FeatureFilm","year":"1988","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[]},"rootId":"crid:~~2F~~2Fport.cs~~2F1379541","replayTvAvailable":true,"audioTracks":[],"ratings":[],"offersLatestExpirationDate":1675767600000,"replayTvStartOffset":0,"replayTvEndOffset":604800,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"id":"crid:~~2F~~2Fport.cs~~2F71927954,imi:f1b4b0285b72cf44cba74e1c62322a4c682385c7","startTime":1675785900000,"endTime":1675791900000,"actualStartTime":1675785900000,"actualEndTime":1675791900000,"expirationDate":1676390700000,"stationId":"lgi-obolite-sk-prod-master:10024","imi":"imi:f1b4b0285b72cf44cba74e1c62322a4c682385c7","scCridImi":"crid:~~2F~~2Fport.cs~~2F71927954,imi:f1b4b0285b72cf44cba74e1c62322a4c682385c7","mediaGroupId":"crid:~~2F~~2Fport.cs~~2F71927954","program":{"id":"crid:~~2F~~2Fport.cs~~2F71927954","title":"Zilionáři","description":"David (Zach Galifianakis) je nekomplikovaný muž, který uvízl v monotónním životě. Den co den usedá za volant svého obrněného automobilu, aby odvážel obrovské sumy peněz jiných lidí. Jediným...","longDescription":"David (Zach Galifianakis) je nekomplikovaný muž, který uvízl v monotónním životě. Den co den usedá za volant svého obrněného automobilu, aby odvážel obrovské sumy peněz jiných lidí. Jediným vzrušujícím momentem v jeho životě je flirtování s kolegyní Kelly (Kristen Wiig), která ho však brzy zatáhne do těžko uvěřitelného dobrodružství. Skupinka nepříliš inteligentních loserů, pod vedením Steva (Owen Wilson), plánuje vyloupit banku a David jim v tom má samozřejmě pomoci. Navzdory absolutně amatérskému plánu se ale stane nemožné a oni mají najednou v kapse 17 miliónů dolarů. A protože tato partička je opravdu bláznivá, začne je hned ve velkém roztáčet. Peníze létají vzduchem za luxusní a kolikrát i zbytečné věci, ale nedochází jim, že pro policii tak zanechávají jasné stopy...","medium":"Movie","categories":[{"id":"lgi-obolite-sk-prod-master:genre-9","title":"Drama","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"},{"id":"lgi-obolite-sk-prod-master:genre-33","title":"Akcia","scheme":"urn:libertyglobal:metadata:cs:ContentCS:2014_1"}],"isAdult":false,"parentalRating":"15","cast":["Zach Galifianakis","Kristen Wiigová","Owen Wilson","Kate McKinnon","Leslie Jones","Jason Sudeikis","Ross Kimball","Devin Ratray","Mary Elizabeth Ellisová","Jon Daly","Ken Marino","Daniel Zacapa","Tom Werme","Njema Williams","Nils Cruz","Michael Fraguada","Christian Gonzalez","Candace Blanchard","Karsten Friske","Dallas Edwards","Barry Ratcliffe","Shelton Grant","Laura Palka","Reegus Flenory","Wynn Reichert","Jill Jane Clements","Joseph S. Wilson","Jee An","Rhoda Griffisová","Nicole Dupre Sobchack"],"directors":["Scott August","Richard L. Fox","Michelle Malley-Campos","Sebastian Mazzola","Steven Ritzi","Pete Waterman","Jared Hess"],"images":[{"assetType":"HighResLandscape","assetTypes":["HighResLandscape"],"url":"http://62.179.125.152/SK/Images/hrl_fd098116bac1429318aaf5fdae498ce76e258782.jpg"},{"assetType":"HighResPortrait","assetTypes":["HighResPortrait"],"url":"http://62.179.125.152/SK/Images/hrp_6f857ae9375b3bcceb6353a5b35775f52cd85302.jpg"},{"assetType":"boxCover","assetTypes":["boxCover"],"url":"http://62.179.125.152/SK/Images/bc_3f5a24412c7f4f434094fa1147a304aa6a5ebda6.jpg"},{"assetType":"boxart-small","assetTypes":["boxart-small"],"url":"http://62.179.125.152/SK/Images/bc_3f5a24412c7f4f434094fa1147a304aa6a5ebda6.jpg?w=75&h=108&mode=box"},{"assetType":"boxart-medium","assetTypes":["boxart-medium"],"url":"http://62.179.125.152/SK/Images/bc_3f5a24412c7f4f434094fa1147a304aa6a5ebda6.jpg?w=110&h=159&mode=box"},{"assetType":"boxart-xlarge","assetTypes":["boxart-xlarge"],"url":"http://62.179.125.152/SK/Images/bc_3f5a24412c7f4f434094fa1147a304aa6a5ebda6.jpg?w=210&h=303&mode=box"},{"assetType":"boxart-large","assetTypes":["boxart-large"],"url":"http://62.179.125.152/SK/Images/bc_3f5a24412c7f4f434094fa1147a304aa6a5ebda6.jpg?w=180&h=260&mode=box"}],"rootId":"crid:~~2F~~2Fport.cs~~2F71927954","parentalRatingDescription":[],"resolutions":[],"mediaGroupId":"crid:~~2F~~2Fport.cs~~2F71927954","shortDescription":"David (Zach Galifianakis) je nekomplikovaný muž, který uvízl v monotónním životě. Den co den usedá za volant svého obrněného automobilu, aby odvážel obrovské sumy peněz jiných lidí. Jediným...","mediaType":"FeatureFilm","year":"2016","videos":[],"videoStreams":[],"entitlements":["VIP","_OPEN_"],"currentProductIds":[],"currentTvodProductIds":[]},"rootId":"crid:~~2F~~2Fport.cs~~2F71927954","replayTvAvailable":true,"audioTracks":[],"ratings":[],"offersLatestExpirationDate":1676187900000,"replayTvStartOffset":0,"replayTvEndOffset":604800,"replayEnabledOnMobileClients":true,"replaySource":"cloud","isGoReplayableViaExternalApp":false}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[{"type":"PATH_PARAM","code":"period","reason":"INVALID"}]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user