@playpilot/tpi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.github/workflows/tests.yml +22 -0
  2. package/.prettierignore +4 -0
  3. package/.prettierrc +16 -0
  4. package/README.md +38 -0
  5. package/dist/link-injections.js +7 -0
  6. package/eslint.config.js +33 -0
  7. package/index.html +11 -0
  8. package/jsconfig.json +19 -0
  9. package/package.json +35 -0
  10. package/src/app.d.ts +13 -0
  11. package/src/app.html +12 -0
  12. package/src/demo.spec.js +7 -0
  13. package/src/lib/api.js +160 -0
  14. package/src/lib/array.js +15 -0
  15. package/src/lib/auth.js +84 -0
  16. package/src/lib/constants.js +2 -0
  17. package/src/lib/enums/TrackingEvent.js +15 -0
  18. package/src/lib/fakeData.js +140 -0
  19. package/src/lib/genres.json +420 -0
  20. package/src/lib/global.css +37 -0
  21. package/src/lib/hash.js +15 -0
  22. package/src/lib/html.js +21 -0
  23. package/src/lib/index.js +1 -0
  24. package/src/lib/linkInjection.js +275 -0
  25. package/src/lib/search.js +24 -0
  26. package/src/lib/text.js +61 -0
  27. package/src/lib/tracking.js +32 -0
  28. package/src/lib/variables.css +16 -0
  29. package/src/main.js +45 -0
  30. package/src/routes/+layout.svelte +54 -0
  31. package/src/routes/+page.svelte +96 -0
  32. package/src/routes/components/AfterArticlePlaylinks.svelte +90 -0
  33. package/src/routes/components/ContextMenu.svelte +67 -0
  34. package/src/routes/components/Description.svelte +47 -0
  35. package/src/routes/components/Editorial/Alert.svelte +18 -0
  36. package/src/routes/components/Editorial/DragHandle.svelte +134 -0
  37. package/src/routes/components/Editorial/Editor.svelte +277 -0
  38. package/src/routes/components/Editorial/EditorItem.svelte +260 -0
  39. package/src/routes/components/Editorial/ManualInjection.svelte +192 -0
  40. package/src/routes/components/Editorial/PlaylinkTypeSelect.svelte +132 -0
  41. package/src/routes/components/Editorial/Search/TitleSearch.svelte +176 -0
  42. package/src/routes/components/Editorial/Switch.svelte +76 -0
  43. package/src/routes/components/Editorial/TextInput.svelte +29 -0
  44. package/src/routes/components/Genres.svelte +41 -0
  45. package/src/routes/components/Icons/IconAlign.svelte +12 -0
  46. package/src/routes/components/Icons/IconBack.svelte +3 -0
  47. package/src/routes/components/Icons/IconBookmark.svelte +3 -0
  48. package/src/routes/components/Icons/IconChevron.svelte +18 -0
  49. package/src/routes/components/Icons/IconClose.svelte +3 -0
  50. package/src/routes/components/Icons/IconContinue.svelte +3 -0
  51. package/src/routes/components/Icons/IconDots.svelte +5 -0
  52. package/src/routes/components/Icons/IconEnlarge.svelte +12 -0
  53. package/src/routes/components/Icons/IconIMDb.svelte +3 -0
  54. package/src/routes/components/Icons/IconNewTab.svelte +3 -0
  55. package/src/routes/components/Modal.svelte +106 -0
  56. package/src/routes/components/Participants.svelte +44 -0
  57. package/src/routes/components/Playlinks.svelte +155 -0
  58. package/src/routes/components/Popover.svelte +95 -0
  59. package/src/routes/components/RoundButton.svelte +38 -0
  60. package/src/routes/components/SkeletonText.svelte +33 -0
  61. package/src/routes/components/Title.svelte +180 -0
  62. package/src/routes/components/TitleModal.svelte +24 -0
  63. package/src/routes/components/TitlePopover.svelte +17 -0
  64. package/src/tests/helpers.js +18 -0
  65. package/src/tests/lib/api.test.js +162 -0
  66. package/src/tests/lib/array.test.js +14 -0
  67. package/src/tests/lib/auth.test.js +115 -0
  68. package/src/tests/lib/hash.test.js +28 -0
  69. package/src/tests/lib/html.test.js +16 -0
  70. package/src/tests/lib/linkInjection.test.js +754 -0
  71. package/src/tests/lib/search.test.js +42 -0
  72. package/src/tests/lib/text.test.js +94 -0
  73. package/src/tests/lib/tracking.test.js +71 -0
  74. package/src/tests/routes/+page.test.js +109 -0
  75. package/src/tests/routes/components/AfterArticlePlaylinks.test.js +115 -0
  76. package/src/tests/routes/components/ContextMenu.test.js +37 -0
  77. package/src/tests/routes/components/Description.test.js +58 -0
  78. package/src/tests/routes/components/Editorial/Alert.test.js +17 -0
  79. package/src/tests/routes/components/Editorial/DragHandle.test.js +55 -0
  80. package/src/tests/routes/components/Editorial/Editor.test.js +64 -0
  81. package/src/tests/routes/components/Editorial/EditorItem.test.js +142 -0
  82. package/src/tests/routes/components/Editorial/ManualInjection.test.js +114 -0
  83. package/src/tests/routes/components/Editorial/PlaylinkTypeSelect.test.js +63 -0
  84. package/src/tests/routes/components/Editorial/Search/TitleSearch.test.js +58 -0
  85. package/src/tests/routes/components/Editorial/Switch.test.js +60 -0
  86. package/src/tests/routes/components/Editorial/TextInput.test.js +30 -0
  87. package/src/tests/routes/components/Genres.test.js +37 -0
  88. package/src/tests/routes/components/Modal.test.js +84 -0
  89. package/src/tests/routes/components/Participants.test.js +33 -0
  90. package/src/tests/routes/components/Playlinks.test.js +101 -0
  91. package/src/tests/routes/components/Popover.test.js +66 -0
  92. package/src/tests/routes/components/RoundButton.test.js +35 -0
  93. package/src/tests/routes/components/SkeletonText.test.js +12 -0
  94. package/src/tests/routes/components/Title.test.js +82 -0
  95. package/src/tests/routes/components/TitleModal.test.js +33 -0
  96. package/src/tests/routes/components/TitlePopover.test.js +23 -0
  97. package/src/tests/setup.js +53 -0
  98. package/src/typedefs.js +72 -0
  99. package/static/favicon.png +0 -0
  100. package/svelte.config.js +13 -0
  101. package/vite.config.js +61 -0
@@ -0,0 +1,15 @@
1
+
2
+ /**
3
+ * Returns the largest number in an array of numbers. Returns 0 if the array has no entries.
4
+ * @param {number[]} array
5
+ * @return {number}
6
+ */
7
+ export function getLargestValueInArray(array) {
8
+ let largest = 0
9
+
10
+ for (let i = 0; i < array.length; i++) {
11
+ if (array[i] > largest) largest = array[i]
12
+ }
13
+
14
+ return largest
15
+ }
@@ -0,0 +1,84 @@
1
+ import { getApiToken } from './api'
2
+ import { apiBaseUrl } from './constants'
3
+
4
+ const cookieName = 'EncryptedToken'
5
+ const urlParam = 'articleReplacementEditToken'
6
+
7
+ /**
8
+ * Authorize the user
9
+ * @param {string} href The current window.location.href
10
+ * @returns {Promise<boolean>} Whether the user is authorized or not
11
+ */
12
+ export async function authorize(href = window.location.href) {
13
+ const headers = new Headers({ 'Content-Type': 'application/json' })
14
+
15
+ try {
16
+ const apiToken = getApiToken()
17
+ if (!apiToken) throw new Error('No token was provided')
18
+
19
+ const authToken = getAuthToken(href)
20
+ if (!authToken) throw new Error('Could not be authenticated')
21
+
22
+ const response = await fetch(apiBaseUrl + `/external-pages/edit-authorization?api-token=${apiToken}`, {
23
+ headers,
24
+ method: 'POST',
25
+ body: JSON.stringify(({
26
+ private_token: authToken,
27
+ })),
28
+ })
29
+
30
+ if (!response.ok) throw response
31
+
32
+ setAuthCookie(authToken)
33
+
34
+ return true
35
+ } catch(error) {
36
+ console.error(error)
37
+ }
38
+
39
+ return false
40
+ }
41
+
42
+ /**
43
+ * Get the auth token from the URL, a stored cookie, or from the window object
44
+ * @param {string} [href] URL that the param is extracted from
45
+ * @returns {string} Auth token
46
+ */
47
+ export function getAuthToken(href = '') {
48
+ // @ts-ignore
49
+ const configToken = window?.PlayPilotLinkInjections?.editorial_token
50
+ if (configToken) return configToken
51
+
52
+ if (href) {
53
+ const urlToken = new URL(href).searchParams.get(urlParam)
54
+ if (urlToken) return decodeURI(urlToken)
55
+ }
56
+
57
+ const cookieToken = ('; '+document.cookie).split(`; ${cookieName}=`).pop()?.split(';')[0]
58
+ return cookieToken || ''
59
+ }
60
+
61
+ /**
62
+ * Set auth cookie equal to given value
63
+ * @param {string} value The auth token value
64
+ */
65
+ function setAuthCookie(value) {
66
+ const time = new Date()
67
+ const days = 30
68
+
69
+ time.setTime(time.getTime() + (days * 24 * 60 * 60 * 1000))
70
+ const expires = 'expires='+ time.toUTCString()
71
+
72
+ document.cookie = cookieName + '=' + value + ';' + expires + ';path=/'
73
+ }
74
+
75
+ /**
76
+ * Returns whether or not the user has requested editorial mode to be enabled.
77
+ * This won't enable editorial mode by itself, as that also requires authentication.
78
+ * @returns {boolean}
79
+ */
80
+ export function isEditorialModeEnabled() {
81
+ // @ts-ignore
82
+ const windowToken = window?.PlayPilotLinkInjections?.editorial_token
83
+ return new URLSearchParams(window.location.search).get('playpilot-editorial-mode') === 'true' || !!windowToken
84
+ }
@@ -0,0 +1,2 @@
1
+ export const playPilotBaseUrl = 'https://www.playpilot.com'
2
+ export const apiBaseUrl = 'https://partner-api.playpilot.tech/1.0.0'
@@ -0,0 +1,15 @@
1
+ export const TrackingEvent = Object.freeze({
2
+ ArticlePageView: 'ali_article_page_view',
3
+
4
+ TitleModalView: 'ali_title_modal_view',
5
+ TitleModalScroll: 'ali_title_modal_scroll',
6
+ TitleModalPlaylinkClick: 'ali_title_modal_playlink_click',
7
+ TitleModalSaveClick: 'ali_title_modal_save_click',
8
+
9
+ TitlePopoverView: 'ali_title_popover_view',
10
+ TitlePopoverSaveClick: 'ali_title_popover_save_click',
11
+ TitlePopoverPlaylinkClick: 'ali_title_popover_playlink_click',
12
+
13
+ AfterArticlePlaylinkClick: 'ali_after_article_playlink_click',
14
+ AfterArticleModalButtonClick: 'ali_after_article_modal_button_click',
15
+ })
@@ -0,0 +1,140 @@
1
+ /** @type {Participant[]} */
2
+ export const participants = [
3
+ {
4
+ sid: 'pr5C5W',
5
+ name: 'James Franco',
6
+ birth_date: '1978-04-19',
7
+ death_date: null,
8
+ jobs: ['actor'],
9
+ image: null,
10
+ image_uuid: '08ed2fac357011eb87470aff12c0f5c9',
11
+ gender: 'Male',
12
+ character: 'Will Rodman (archive footage) (uncredited)',
13
+ },
14
+ {
15
+ sid: 'pr8bZm',
16
+ name: 'Thomas Rosales Jr.',
17
+ birth_date: '1948-02-03',
18
+ death_date: null,
19
+ jobs: ['actor'],
20
+ image: null,
21
+ image_uuid: '61cc1a66358411eba39d029d7cbf5ab1',
22
+ gender: 'Male',
23
+ character: 'Old Man',
24
+ },
25
+ {
26
+ sid: 'pr45Dp',
27
+ name: 'Barack Obama',
28
+ birth_date: '1961-08-04',
29
+ death_date: null,
30
+ jobs: ['actor'],
31
+ image: null,
32
+ image_uuid: 'bfb13c18358b11eb9244064c1c9dcb21',
33
+ gender: 'Male',
34
+ character: 'Self (archive footage) (uncredited)',
35
+ },
36
+ {
37
+ sid: 'pr6DnN',
38
+ name: 'Gary Oldman',
39
+ birth_date: '1958-03-21',
40
+ death_date: null,
41
+ jobs: ['actor'],
42
+ image: null,
43
+ image_uuid: '4f59082e356d11eb87470aff12c0f5c9',
44
+ gender: 'Male',
45
+ character: 'Dreyfus',
46
+ },
47
+ {
48
+ sid: 'pr7GK8',
49
+ name: 'Michael Papajohn',
50
+ birth_date: '1964-11-07',
51
+ death_date: null,
52
+ jobs: ['actor'],
53
+ image: null,
54
+ image_uuid: '0b316760357011eb87470aff12c0f5c9',
55
+ gender: 'Male',
56
+ character: 'Cannon-Gunner',
57
+ },
58
+ {
59
+ sid: 'pr88KG',
60
+ name: 'Judy Greer',
61
+ birth_date: '1975-07-20',
62
+ death_date: null,
63
+ jobs: ['actor'],
64
+ image: null,
65
+ image_uuid: '5433b2c6357811eb87470aff12c0f5c9',
66
+ gender: 'Female',
67
+ character: 'Cornelia',
68
+ },
69
+ ]
70
+
71
+ /** @type {TitleData} */
72
+ export const title = {
73
+ sid: 'tig9r9F',
74
+ slug: 'dune-prophecy-2024-series',
75
+ poster_uuid: '61feb4b0a58f11efb0b50a58a9feac02',
76
+ standing_poster_uuid: '6239ee86a58f11efb0b50a58a9feac02',
77
+ genres: ['101', '109', '123', '107'],
78
+ year: 2024,
79
+ imdb_score: 7.5,
80
+ type: 'series',
81
+ providers: [
82
+ {
83
+ sid: 'plxWzpL',
84
+ name: 'Max',
85
+ url: 'https://out.playpilot.com/playlink/gAAAAABnReWk_jqQh4e6vBNNqD0rl4fafWJGUBj939o2z4EZB7yWUJ2jq5RpLSPYvD1kRdsj2CXkst0obPR-UYwuBx7_ofbR1aTCOEc8gV40OGChzuRbPmXl4U-OXhrkRMR5KJi0A8vJ2UGQcPBieRTiHovwTDnPO1rRs1jGwwwLcqkDFw24ILoDyGjLZzG-sy_b3C7I9bTxGeDTyqk1-hakg_S9_rzIorkHrMD4wJpXaeSsAbMUMb-z8VNvzdNKCOtRHZ_8pM-FaLt8Fp5rLa9XwHZ4z_37eyjF3e5BVIB_2kvaiRGcQ0I=',
86
+ logo_url: 'https://picsum.photos/64/64',
87
+ extra_info: {
88
+ category: 'SVOD',
89
+ },
90
+ },
91
+ {
92
+ sid: 'plxWzpK',
93
+ name: 'Netflix',
94
+ url: 'https://out.playpilot.com/playlink/gAAAAABnReWk_jqQh4e6vBNNqD0rl4fafWJGUBj939o2z4EZB7yWUJ2jq5RpLSPYvD1kRdsj2CXkst0obPR-UYwuBx7_ofbR1aTCOEc8gV40OGChzuRbPmXl4U-OXhrkRMR5KJi0A8vJ2UGQcPBieRTiHovwTDnPO1rRs1jGwwwLcqkDFw24ILoDyGjLZzG-sy_b3C7I9bTxGeDTyqk1-hakg_S9_rzIorkHrMD4wJpXaeSsAbMUMb-z8VNvzdNKCOtRHZ_8pM-FaLt8Fp5rLa9XwHZ4z_37eyjF3e5BVIB_2kvaiRGcQ0I=',
95
+ logo_url: 'https://picsum.photos/seed/2/64/64',
96
+ extra_info: {
97
+ category: 'RENT',
98
+ },
99
+ },
100
+ ],
101
+ description: 'Ten thousand years before the ascension of Paul Atreides, sisters Valya and Tula Harkonnen establish the fabled sect and female order that would become known as the Bene Gesserit to control the future of humankind.',
102
+ small_poster: 'https://img.playpilot.tech/61feb4b0a58f11efb0b50a58a9feac02/src/img?optimizer=image&class=16by9x14',
103
+ medium_poster: 'https://img.playpilot.tech/61feb4b0a58f11efb0b50a58a9feac02/src/img?optimizer=image&class=16by9x40',
104
+ standing_poster: 'https://img.playpilot.tech/6239ee86a58f11efb0b50a58a9feac02/src/img?optimizer=image&class=2by3x18',
105
+ title: 'Dune: Prophecy',
106
+ original_title: 'Dune: Prophecy',
107
+ participants,
108
+ }
109
+
110
+ /** @type {LinkInjection[]} */
111
+ export const linkInjections = [{
112
+ sid: '1',
113
+ title: 'Quan',
114
+ sentence: 'In an interview with Epire Magazine, Quan reveals he quested starring in Love Hurts',
115
+ playpilot_url: 'https://playpilot.com/movie/example/',
116
+ key: 'some-key-1',
117
+ title_details: title,
118
+ }, {
119
+ sid: '2',
120
+ title: 'The Long Kiss Goodnight',
121
+ sentence: 'The movie is in a similar vein to successful films such as The Long Kiss Goodnight and Nobody',
122
+ playpilot_url: 'https://playpilot.com/movie/example-2/',
123
+ key: 'some-key-2',
124
+ after_article: true,
125
+ title_details: title,
126
+ }, {
127
+ sid: '3',
128
+ title: 'Nobody',
129
+ sentence: 'The movie is in a similar vein to successful films such as The Long Kiss Goodnight and Nobody',
130
+ playpilot_url: 'https://playpilot.com/movie/example-3/',
131
+ key: 'some-key-3',
132
+ after_article: true,
133
+ title_details: title,
134
+ }, {
135
+ sid: '4',
136
+ title: 'The Wheel of Time',
137
+ sentence: '(The more I think about the Bene Gesserit the more I see how much they influenced not just the Jedi in Star Wars but also the Aes Sedai in The Wheel of Time and even the sorceresses in The Witcher books, though Herbert\'s order is the most ominous and terrifying of them all)',
138
+ playpilot_url: 'https://playpilot.com/movie/example-4/',
139
+ key: 'some-key-4',
140
+ }]
@@ -0,0 +1,420 @@
1
+ [
2
+ {
3
+ "slug": "100",
4
+ "name": "All",
5
+ "categories": {
6
+ "movie": 100,
7
+ "series": 100,
8
+ "documentary": 100,
9
+ "kids": 100,
10
+ "cinema": 100,
11
+ "podcasts": 100
12
+ }
13
+ },
14
+ {
15
+ "slug": "999",
16
+ "name": "Unscripted",
17
+ "categories": {},
18
+ "media_format": "video"
19
+ },
20
+ {
21
+ "slug": "900",
22
+ "name": "Independent",
23
+ "categories": {},
24
+ "media_format": "video"
25
+ },
26
+ {
27
+ "slug": "113",
28
+ "name": "Game Show",
29
+ "categories": {
30
+ "series": 36,
31
+ "kids": 28
32
+ },
33
+ "media_format": "video"
34
+ },
35
+ {
36
+ "slug": "112",
37
+ "name": "Film Noir",
38
+ "categories": {
39
+ "movie": 37
40
+ },
41
+ "media_format": "video"
42
+ },
43
+ {
44
+ "slug": "212",
45
+ "name": "Entertainment",
46
+ "categories": {
47
+ "kids": 80,
48
+ "series": 42,
49
+ "movie": 42
50
+ },
51
+ "media_format": "video"
52
+ },
53
+ {
54
+ "slug": "120",
55
+ "name": "News",
56
+ "categories": {
57
+ "series": 26,
58
+ "documentary": 36,
59
+ "kids": 38
60
+ },
61
+ "media_format": "video"
62
+ },
63
+ {
64
+ "slug": "208",
65
+ "name": "Short",
66
+ "categories": {
67
+ "movie": 21,
68
+ "documentary": 30,
69
+ "kids": 36
70
+ },
71
+ "media_format": "video"
72
+ },
73
+ {
74
+ "slug": "902",
75
+ "name": "Bollywood",
76
+ "categories": {},
77
+ "media_format": "video"
78
+ },
79
+ {
80
+ "slug": "240",
81
+ "name": "Concert",
82
+ "categories": {
83
+ "movie": 45
84
+ },
85
+ "media_format": "video"
86
+ },
87
+ {
88
+ "slug": "901",
89
+ "name": "Arthouse",
90
+ "categories": {},
91
+ "media_format": "video"
92
+ },
93
+ {
94
+ "slug": "903",
95
+ "name": "Alternate Version",
96
+ "categories": {},
97
+ "media_format": "video"
98
+ },
99
+ {
100
+ "slug": "121",
101
+ "name": "Reality TV",
102
+ "categories": {
103
+ "series": 24
104
+ },
105
+ "media_format": "video"
106
+ },
107
+ {
108
+ "slug": "202",
109
+ "name": "Culture",
110
+ "categories": {
111
+ "kids": 40,
112
+ "documentary": 84,
113
+ "series": 44
114
+ },
115
+ "media_format": "video"
116
+ },
117
+ {
118
+ "slug": "107",
119
+ "name": "Drama",
120
+ "categories": {
121
+ "series": 82,
122
+ "movie": 82,
123
+ "cinema": 88,
124
+ "documentary": 44
125
+ },
126
+ "media_format": "video"
127
+ },
128
+ {
129
+ "slug": "105",
130
+ "name": "Crime",
131
+ "categories": {
132
+ "series": 84,
133
+ "documentary": 86,
134
+ "cinema": 64,
135
+ "movie": 84
136
+ },
137
+ "media_format": "video"
138
+ },
139
+ {
140
+ "slug": "128",
141
+ "name": "Western",
142
+ "categories": {
143
+ "movie": 12,
144
+ "series": 12,
145
+ "documentary": 24
146
+ },
147
+ "media_format": "video"
148
+ },
149
+ {
150
+ "slug": "127",
151
+ "name": "Thriller",
152
+ "categories": {
153
+ "series": 70,
154
+ "documentary": 28,
155
+ "cinema": 80,
156
+ "movie": 70
157
+ },
158
+ "media_format": "video"
159
+ },
160
+ {
161
+ "slug": "102",
162
+ "name": "Animation",
163
+ "categories": {
164
+ "series": 50,
165
+ "cinema": 50,
166
+ "kids": 90,
167
+ "documentary": 48,
168
+ "movie": 50
169
+ },
170
+ "media_format": "video"
171
+ },
172
+ {
173
+ "slug": "119",
174
+ "name": "Mystery",
175
+ "categories": {
176
+ "movie": 76,
177
+ "cinema": 70,
178
+ "kids": 26,
179
+ "documentary": 38,
180
+ "series": 76
181
+ },
182
+ "media_format": "video"
183
+ },
184
+ {
185
+ "slug": "227",
186
+ "name": "Science",
187
+ "categories": {
188
+ "series": 22,
189
+ "kids": 46,
190
+ "documentary": 74
191
+ },
192
+ "media_format": "video"
193
+ },
194
+ {
195
+ "slug": "108",
196
+ "name": "Nature",
197
+ "categories": {
198
+ "kids": 48,
199
+ "documentary": 76,
200
+ "series": 28
201
+ },
202
+ "media_format": "video"
203
+ },
204
+ {
205
+ "slug": "116",
206
+ "name": "War",
207
+ "categories": {
208
+ "movie": 14,
209
+ "documentary": 68,
210
+ "series": 14,
211
+ "cinema": 66
212
+ },
213
+ "media_format": "video"
214
+ },
215
+ {
216
+ "slug": "123",
217
+ "name": "Sci-Fi",
218
+ "categories": {
219
+ "series": 72,
220
+ "movie": 72,
221
+ "cinema": 68,
222
+ "kids": 70,
223
+ "documentary": 32
224
+ },
225
+ "media_format": "video"
226
+ },
227
+ {
228
+ "slug": "106",
229
+ "name": "Documentary",
230
+ "categories": {
231
+ "kids": 50
232
+ },
233
+ "media_format": "video"
234
+ },
235
+ {
236
+ "slug": "232",
237
+ "name": "Stand-up",
238
+ "categories": {
239
+ "movie": 18,
240
+ "series": 18
241
+ },
242
+ "media_format": "video"
243
+ },
244
+ {
245
+ "slug": "126",
246
+ "name": "Talk Show",
247
+ "categories": {
248
+ "kids": 34,
249
+ "series": 16
250
+ },
251
+ "media_format": "video"
252
+ },
253
+ {
254
+ "slug": "111",
255
+ "name": "Fantasy",
256
+ "categories": {
257
+ "kids": 78,
258
+ "cinema": 74,
259
+ "documentary": 42,
260
+ "movie": 38,
261
+ "series": 38
262
+ },
263
+ "media_format": "video"
264
+ },
265
+ {
266
+ "slug": "114",
267
+ "name": "History",
268
+ "categories": {
269
+ "movie": 35,
270
+ "kids": 44,
271
+ "cinema": 10,
272
+ "series": 80,
273
+ "documentary": 90
274
+ },
275
+ "media_format": "video"
276
+ },
277
+ {
278
+ "slug": "109",
279
+ "name": "Adventure",
280
+ "categories": {
281
+ "kids": 88,
282
+ "cinema": 86,
283
+ "documentary": 82,
284
+ "series": 88,
285
+ "movie": 88
286
+ },
287
+ "media_format": "video"
288
+ },
289
+ {
290
+ "slug": "101",
291
+ "name": "Action",
292
+ "categories": {
293
+ "documentary": 50,
294
+ "kids": 86,
295
+ "series": 90,
296
+ "cinema": 90,
297
+ "movie": 90
298
+ },
299
+ "media_format": "video"
300
+ },
301
+ {
302
+ "slug": "124",
303
+ "name": "Horror",
304
+ "categories": {
305
+ "cinema": 76,
306
+ "documentary": 40,
307
+ "series": 78,
308
+ "movie": 80
309
+ },
310
+ "media_format": "video"
311
+ },
312
+ {
313
+ "slug": "115",
314
+ "name": "Comedy",
315
+ "categories": {
316
+ "cinema": 84,
317
+ "documentary": 46,
318
+ "series": 86,
319
+ "kids": 82,
320
+ "movie": 86
321
+ },
322
+ "media_format": "video"
323
+ },
324
+ {
325
+ "slug": "104",
326
+ "name": "Biography",
327
+ "categories": {
328
+ "series": 46,
329
+ "documentary": 88,
330
+ "cinema": 10,
331
+ "movie": 46
332
+ },
333
+ "media_format": "video"
334
+ },
335
+ {
336
+ "slug": "118",
337
+ "name": "Music",
338
+ "categories": {
339
+ "kids": 72,
340
+ "cinema": 9,
341
+ "documentary": 78,
342
+ "movie": 32,
343
+ "series": 32
344
+ },
345
+ "media_format": "video"
346
+ },
347
+ {
348
+ "slug": "125",
349
+ "name": "Sport",
350
+ "categories": {
351
+ "cinema": 7,
352
+ "kids": 68,
353
+ "series": 20,
354
+ "documentary": 70,
355
+ "movie": 20
356
+ },
357
+ "media_format": "video"
358
+ },
359
+ {
360
+ "slug": "122",
361
+ "name": "Romance",
362
+ "categories": {
363
+ "documentary": 34,
364
+ "cinema": 78,
365
+ "movie": 74,
366
+ "series": 74
367
+ },
368
+ "media_format": "video"
369
+ },
370
+ {
371
+ "slug": "103",
372
+ "name": "Kids",
373
+ "categories": {
374
+ "kids": 76
375
+ },
376
+ "media_format": "video"
377
+ },
378
+ {
379
+ "slug": "222",
380
+ "name": "Lifestyle",
381
+ "categories": {
382
+ "documentary": 80,
383
+ "kids": 74,
384
+ "series": 34
385
+ },
386
+ "media_format": "video"
387
+ },
388
+ {
389
+ "slug": "117",
390
+ "name": "Musical",
391
+ "categories": {
392
+ "kids": 30,
393
+ "movie": 78,
394
+ "cinema": 8,
395
+ "series": 30
396
+ },
397
+ "media_format": "video"
398
+ },
399
+ {
400
+ "slug": "129",
401
+ "name": "Anime",
402
+ "categories": {
403
+ "cinema": 5,
404
+ "movie": 48,
405
+ "kids": 84,
406
+ "series": 48
407
+ },
408
+ "media_format": "video"
409
+ },
410
+ {
411
+ "slug": "110",
412
+ "name": "Family",
413
+ "categories": {
414
+ "series": 40,
415
+ "cinema": 40,
416
+ "movie": 40
417
+ },
418
+ "media_format": "video"
419
+ }
420
+ ]