From 2d7eef0b4893a6263fd2c890c368ca062f9b351d Mon Sep 17 00:00:00 2001
From: Your Name
Date: Sat, 5 Oct 2024 12:28:51 -0600
Subject: [PATCH] Added TVE, Peacock, and Prime support for NFL+ integration
---
README.md | 11 +-
package-lock.json | 4 +-
package.json | 2 +-
services/channels.ts | 361 +++++++++++++++++++------------------
services/generate-m3u.ts | 4 +-
services/generate-xmltv.ts | 4 +-
services/networks.ts | 25 ++-
services/nfl-handler.ts | 308 +++++++++++++++++++++++--------
8 files changed, 442 insertions(+), 277 deletions(-)
diff --git a/README.md b/README.md
index 2102794..93bb71b 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-Current version: **3.2.5**
+Current version: **3.2.6**
# About
This takes ESPN/ESPN+, FOX Sports, Paramount+, MSG+, NFL+, B1G+, NESN, Mountain West, FloSports, or MLB.tv programming and transforms it into a "live TV" experience with virtual linear channels. It will discover what is on, and generate a schedule of channels that will give you M3U and XMLTV files that you can import into something like [Jellyfin](https://jellyfin.org) or [Channels](https://getchannels.com).
@@ -70,14 +70,19 @@ Use if you would like to login with Paramount+
| GOLAZO* | Set if you would like the Golazo Network channel (only available with `LINEAR_CHANNELS`) | False | False |
#### NFL+
-Use if you would like to login with NFL+
+Use if you would like to login with NFL+.
+
+Please note that if you only have an NFL account, you can still get events from Amazon Prime, Peacock, or your TV Provider.
*** If you have access to NFL RedZone (NFL+ Premium), it will be scheduled. If `LINEAR_CHANNELS` is set, it will be on its own channel
| Environment Variable | Description | Required? | Default |
|---|---|---|---|
| NFLPLUS | Set if you would like NFL+ events | False | False |
-| NFLNETWORK* | Set if you would like the NFL Network channel (only available with `LINEAR_CHANNELS`) | False | False |
+| NFL_TVE | Set if you would like NFL games from your TV Provider (not needed with NFL+) | False | False |
+| NFL_PRIME | Set if you would like NFL games from Amazon Prime (not needed with NFL+) | False | False |
+| NFL_PEACOCK | Set if you would like NFL games from Peacock (not needed with NFL+) | False | False |
+| NFLNETWORK* | Set if you would like the NFL Network channel (only available with `LINEAR_CHANNELS`). Must have NFL+ or TV Provider. | False | False |
| NFLCHANNEL* | Set if you would like the NFL Channel (only available with `LINEAR_CHANNELS`) | False | False |
#### NESN
diff --git a/package-lock.json b/package-lock.json
index 0bef411..e22f05e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "eplustv",
- "version": "3.2.5",
+ "version": "3.2.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "eplustv",
- "version": "3.2.5",
+ "version": "3.2.6",
"license": "MIT",
"dependencies": {
"axios": "^1.2.2",
diff --git a/package.json b/package.json
index ea81319..7e8eadc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "eplustv",
- "version": "3.2.5",
+ "version": "3.2.6",
"description": "",
"scripts": {
"start": "ts-node index.ts",
diff --git a/services/channels.ts b/services/channels.ts
index 8b5065a..c1813d8 100644
--- a/services/channels.ts
+++ b/services/channels.ts
@@ -47,182 +47,187 @@ export const LINEAR_START_CHANNEL = nextStartChannel(startChannel + numOfChannel
export const useLinear = process.env.LINEAR_CHANNELS?.toLowerCase() === 'true' ? true : false;
/* eslint-disable sort-keys-custom-order-fix/sort-keys-custom-order-fix */
-export const CHANNEL_MAP = {
- 0: {
- canUse: useEspn1,
- id: 'espn1',
- logo: 'https://tmsimg.fancybits.co/assets/s32645_h3_aa.png?w=360&h=270',
- name: 'ESPN',
- stationId: '32645',
- tvgName: 'ESPNHD',
- },
- 1: {
- canUse: useEspn2,
- id: 'espn2',
- logo: 'https://tmsimg.fancybits.co/assets/s45507_ll_h15_aa.png?w=360&h=270',
- name: 'ESPN2',
- stationId: '45507',
- tvgName: 'ESPN2HD',
- },
- 2: {
- canUse: useEspnU,
- id: 'espnu',
- logo: 'https://tmsimg.fancybits.co/assets/s60696_ll_h15_aa.png?w=360&h=270',
- name: 'ESPNU',
- stationId: '60696',
- tvgName: 'ESPNUHD',
- },
- 3: {
- canUse: useSec,
- id: 'sec',
- logo: 'https://tmsimg.fancybits.co/assets/s89714_ll_h15_aa.png?w=360&h=270',
- name: 'SEC Network',
- stationId: '89714',
- tvgName: 'SECH',
- },
- 4: {
- canUse: useAccN,
- id: 'acc',
- logo: 'https://tmsimg.fancybits.co/assets/s111871_ll_h15_ac.png?w=360&h=270',
- name: 'ACC Network',
- stationId: '111871',
- tvgName: 'ACC',
- },
- 5: {
- canUse: useEspnews,
- id: 'espnews',
- logo: 'https://tmsimg.fancybits.co/assets/s59976_ll_h15_aa.png?w=360&h=270',
- name: 'ESPNews',
- stationId: '59976',
- tvgName: 'ESPNWHD',
- },
- 10: {
- canUse: useFoxSports,
- id: 'fs1',
- logo: 'https://tmsimg.fancybits.co/assets/s82547_ll_h15_aa.png?w=360&h=270',
- name: 'FS1',
- stationId: '82547',
- tvgName: 'FS1HD',
- },
- 11: {
- canUse: useFoxSports,
- id: 'fs2',
- logo: 'https://tmsimg.fancybits.co/assets/s59305_ll_h15_aa.png?w=360&h=270',
- name: 'FS2',
- stationId: '59305',
- tvgName: 'FS2HD',
- },
- 12: {
- canUse: useFoxSports,
- id: 'btn',
- logo: 'https://tmsimg.fancybits.co/assets/s58321_ll_h15_ac.png?w=360&h=270',
- name: 'B1G Network',
- stationId: '58321',
- tvgName: 'BIG10HD',
- },
- 13: {
- canUse: useFoxSports,
- id: 'fox-soccer-plus',
- logo: 'https://tmsimg.fancybits.co/assets/s66880_ll_h15_aa.png?w=360&h=270',
- name: 'FOX Soccer Plus',
- stationId: '66880',
- tvgName: 'FSCPLHD',
- },
- 20: {
- canUse: useParamount.cbsSportsHq,
- id: 'cbssportshq',
- logo: 'https://tmsimg.fancybits.co/assets/s108919_ll_h15_aa.png?w=360&h=270',
- name: 'CBS Sports HQ',
- stationId: '108919',
- tvgName: 'CBSSPHQ',
- },
- 21: {
- canUse: useParamount.golazo,
- id: 'golazo',
- logo: 'https://tmsimg.fancybits.co/assets/s133691_ll_h15_aa.png?w=360&h=270',
- name: 'GOLAZO Network',
- stationId: '133691',
- tvgName: 'GOLAZO',
- },
- 30: {
- canUse: useNfl.network,
- id: 'NFLNETWORK',
- logo: 'https://tmsimg.fancybits.co/assets/s45399_ll_h15_aa.png?w=360&h=270',
- name: 'NFL Network',
- stationId: '45399',
- tvgName: 'NFLHD',
- },
- 31: {
- canUse: useNfl.redZone,
- id: 'NFLNRZ',
- logo: 'https://tmsimg.fancybits.co/assets/s65025_ll_h9_aa.png?w=360&h=270',
- name: 'NFL RedZone',
- stationId: '65025',
- tvgName: 'NFLNRZD',
- },
- 32: {
- canUse: useNfl.channel,
- id: 'NFLDIGITAL1_OO_v3',
- logo: 'https://tmsimg.fancybits.co/assets/s121705_ll_h15_aa.png?w=360&h=270',
- name: 'NFL Channel',
- stationId: '121705',
- tvgName: 'NFLDC1',
- },
- 40: {
- canUse: useMLBtv,
- id: 'MLBTVBI',
- logo: 'https://tmsimg.fancybits.co/assets/s119153_ll_h15_aa.png?w=360&h=270',
- name: 'MLB Big Inning',
- stationId: '119153',
- tvgName: 'MLBTVBI',
- },
- 50: {
- canUse: useNesn,
- id: 'NESN',
- logo: 'https://tmsimg.fancybits.co/assets/s35038_ll_h15_ac.png?w=360&h=270',
- name: 'New England Sports Network HD',
- stationId: '35038',
- tvgName: 'NESNHD',
- },
- 51: {
- canUse: useNesn,
- id: 'NESN+',
- logo: 'https://tmsimg.fancybits.co/assets/s63198_ll_h15_ac.png?w=360&h=270',
- name: 'New England Sports Network Plus HD',
- stationId: '63516',
- tvgName: 'NESNPLD',
- },
- 60: {
- canUse: useMsgPlus,
- id: 'MSG',
- logo: 'https://tmsimg.fancybits.co/assets/s10979_ll_h15_ab.png?w=360&h=270',
- name: 'MSG',
- stationId: '10979',
- tvgName: 'MSG',
- },
- 61: {
- canUse: useMsgPlus,
- id: 'MSGSN',
- logo: 'https://tmsimg.fancybits.co/assets/s11105_ll_h15_ac.png?w=360&h=270',
- name: 'MSG Sportsnet HD',
- stationId: '15273',
- tvgName: 'MSGSNNP',
- },
- 62: {
- canUse: useMsgPlus,
- id: 'MSG2',
- logo: 'https://tmsimg.fancybits.co/assets/s70283_ll_h15_aa.png?w=360&h=270',
- name: 'MSG2 HD',
- stationId: '70283',
- tvgName: 'MSG2HD',
- },
- 63: {
- canUse: useMsgPlus,
- id: 'MSGSN2',
- logo: 'https://tmsimg.fancybits.co/assets/s70285_ll_h15_ab.png?w=360&h=270',
- name: 'MSG Sportsnet 2 HD',
- stationId: '70285',
- tvgName: 'MSG2SNH',
+export const CHANNELS = {
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+ get MAP() {
+ return {
+ 0: {
+ canUse: useEspn1,
+ id: 'espn1',
+ logo: 'https://tmsimg.fancybits.co/assets/s32645_h3_aa.png?w=360&h=270',
+ name: 'ESPN',
+ stationId: '32645',
+ tvgName: 'ESPNHD',
+ },
+ 1: {
+ canUse: useEspn2,
+ id: 'espn2',
+ logo: 'https://tmsimg.fancybits.co/assets/s45507_ll_h15_aa.png?w=360&h=270',
+ name: 'ESPN2',
+ stationId: '45507',
+ tvgName: 'ESPN2HD',
+ },
+ 2: {
+ canUse: useEspnU,
+ id: 'espnu',
+ logo: 'https://tmsimg.fancybits.co/assets/s60696_ll_h15_aa.png?w=360&h=270',
+ name: 'ESPNU',
+ stationId: '60696',
+ tvgName: 'ESPNUHD',
+ },
+ 3: {
+ canUse: useSec,
+ id: 'sec',
+ logo: 'https://tmsimg.fancybits.co/assets/s89714_ll_h15_aa.png?w=360&h=270',
+ name: 'SEC Network',
+ stationId: '89714',
+ tvgName: 'SECH',
+ },
+ 4: {
+ canUse: useAccN,
+ id: 'acc',
+ logo: 'https://tmsimg.fancybits.co/assets/s111871_ll_h15_ac.png?w=360&h=270',
+ name: 'ACC Network',
+ stationId: '111871',
+ tvgName: 'ACC',
+ },
+ 5: {
+ canUse: useEspnews,
+ id: 'espnews',
+ logo: 'https://tmsimg.fancybits.co/assets/s59976_ll_h15_aa.png?w=360&h=270',
+ name: 'ESPNews',
+ stationId: '59976',
+ tvgName: 'ESPNWHD',
+ },
+ 10: {
+ canUse: useFoxSports,
+ id: 'fs1',
+ logo: 'https://tmsimg.fancybits.co/assets/s82547_ll_h15_aa.png?w=360&h=270',
+ name: 'FS1',
+ stationId: '82547',
+ tvgName: 'FS1HD',
+ },
+ 11: {
+ canUse: useFoxSports,
+ id: 'fs2',
+ logo: 'https://tmsimg.fancybits.co/assets/s59305_ll_h15_aa.png?w=360&h=270',
+ name: 'FS2',
+ stationId: '59305',
+ tvgName: 'FS2HD',
+ },
+ 12: {
+ canUse: useFoxSports,
+ id: 'btn',
+ logo: 'https://tmsimg.fancybits.co/assets/s58321_ll_h15_ac.png?w=360&h=270',
+ name: 'B1G Network',
+ stationId: '58321',
+ tvgName: 'BIG10HD',
+ },
+ 13: {
+ canUse: useFoxSports,
+ id: 'fox-soccer-plus',
+ logo: 'https://tmsimg.fancybits.co/assets/s66880_ll_h15_aa.png?w=360&h=270',
+ name: 'FOX Soccer Plus',
+ stationId: '66880',
+ tvgName: 'FSCPLHD',
+ },
+ 20: {
+ canUse: useParamount.cbsSportsHq,
+ id: 'cbssportshq',
+ logo: 'https://tmsimg.fancybits.co/assets/s108919_ll_h15_aa.png?w=360&h=270',
+ name: 'CBS Sports HQ',
+ stationId: '108919',
+ tvgName: 'CBSSPHQ',
+ },
+ 21: {
+ canUse: useParamount.golazo,
+ id: 'golazo',
+ logo: 'https://tmsimg.fancybits.co/assets/s133691_ll_h15_aa.png?w=360&h=270',
+ name: 'GOLAZO Network',
+ stationId: '133691',
+ tvgName: 'GOLAZO',
+ },
+ 30: {
+ canUse: useNfl.network,
+ id: 'NFLNETWORK',
+ logo: 'https://tmsimg.fancybits.co/assets/s45399_ll_h15_aa.png?w=360&h=270',
+ name: 'NFL Network',
+ stationId: '45399',
+ tvgName: 'NFLHD',
+ },
+ 31: {
+ canUse: useNfl.redZone,
+ id: 'NFLNRZ',
+ logo: 'https://tmsimg.fancybits.co/assets/s65025_ll_h9_aa.png?w=360&h=270',
+ name: 'NFL RedZone',
+ stationId: '65025',
+ tvgName: 'NFLNRZD',
+ },
+ 32: {
+ canUse: useNfl.channel,
+ id: 'NFLDIGITAL1_OO_v3',
+ logo: 'https://tmsimg.fancybits.co/assets/s121705_ll_h15_aa.png?w=360&h=270',
+ name: 'NFL Channel',
+ stationId: '121705',
+ tvgName: 'NFLDC1',
+ },
+ 40: {
+ canUse: useMLBtv,
+ id: 'MLBTVBI',
+ logo: 'https://tmsimg.fancybits.co/assets/s119153_ll_h15_aa.png?w=360&h=270',
+ name: 'MLB Big Inning',
+ stationId: '119153',
+ tvgName: 'MLBTVBI',
+ },
+ 50: {
+ canUse: useNesn,
+ id: 'NESN',
+ logo: 'https://tmsimg.fancybits.co/assets/s35038_ll_h15_ac.png?w=360&h=270',
+ name: 'New England Sports Network HD',
+ stationId: '35038',
+ tvgName: 'NESNHD',
+ },
+ 51: {
+ canUse: useNesn,
+ id: 'NESN+',
+ logo: 'https://tmsimg.fancybits.co/assets/s63198_ll_h15_ac.png?w=360&h=270',
+ name: 'New England Sports Network Plus HD',
+ stationId: '63516',
+ tvgName: 'NESNPLD',
+ },
+ 60: {
+ canUse: useMsgPlus,
+ id: 'MSG',
+ logo: 'https://tmsimg.fancybits.co/assets/s10979_ll_h15_ab.png?w=360&h=270',
+ name: 'MSG',
+ stationId: '10979',
+ tvgName: 'MSG',
+ },
+ 61: {
+ canUse: useMsgPlus,
+ id: 'MSGSN',
+ logo: 'https://tmsimg.fancybits.co/assets/s11105_ll_h15_ac.png?w=360&h=270',
+ name: 'MSG Sportsnet HD',
+ stationId: '15273',
+ tvgName: 'MSGSNNP',
+ },
+ 62: {
+ canUse: useMsgPlus,
+ id: 'MSG2',
+ logo: 'https://tmsimg.fancybits.co/assets/s70283_ll_h15_aa.png?w=360&h=270',
+ name: 'MSG2 HD',
+ stationId: '70283',
+ tvgName: 'MSG2HD',
+ },
+ 63: {
+ canUse: useMsgPlus,
+ id: 'MSGSN2',
+ logo: 'https://tmsimg.fancybits.co/assets/s70285_ll_h15_ab.png?w=360&h=270',
+ name: 'MSG Sportsnet 2 HD',
+ stationId: '70285',
+ tvgName: 'MSG2SNH',
+ },
+ };
},
};
/* eslint-enable sort-keys-custom-order-fix/sort-keys-custom-order-fix */
@@ -234,7 +239,7 @@ export const calculateChannelNumber = (channelNum: string): number | string => {
return channelNum;
}
- const linearChannel = CHANNEL_MAP[chanNum - LINEAR_START_CHANNEL];
+ const linearChannel = CHANNELS.MAP[chanNum - LINEAR_START_CHANNEL];
if (linearChannel) {
return linearChannel.id;
@@ -252,7 +257,7 @@ export const calculateChannelFromName = (channelName: string): number => {
let channelNum = Number.MAX_SAFE_INTEGER;
- _.forOwn(CHANNEL_MAP, (val, key) => {
+ _.forOwn(CHANNELS.MAP, (val, key) => {
if (val.id === channelName) {
channelNum = parseInt(key, 10) + LINEAR_START_CHANNEL;
}
diff --git a/services/generate-m3u.ts b/services/generate-m3u.ts
index e1579a8..1a73a23 100644
--- a/services/generate-m3u.ts
+++ b/services/generate-m3u.ts
@@ -1,12 +1,12 @@
import _ from 'lodash';
-import {NUM_OF_CHANNELS, START_CHANNEL, CHANNEL_MAP, LINEAR_START_CHANNEL} from './channels';
+import {NUM_OF_CHANNELS, START_CHANNEL, CHANNELS, LINEAR_START_CHANNEL} from './channels';
export const generateM3u = (uri: string, linear = false): string => {
let m3uFile = '#EXTM3U';
if (linear) {
- _.forOwn(CHANNEL_MAP, (val, key) => {
+ _.forOwn(CHANNELS.MAP, (val, key) => {
if (!val.canUse) {
return;
}
diff --git a/services/generate-xmltv.ts b/services/generate-xmltv.ts
index ec92deb..1a05651 100644
--- a/services/generate-xmltv.ts
+++ b/services/generate-xmltv.ts
@@ -4,7 +4,7 @@ import moment from 'moment';
import {db} from './database';
import {usesMultiple} from './networks';
-import {calculateChannelFromName, CHANNEL_MAP, LINEAR_START_CHANNEL, NUM_OF_CHANNELS, START_CHANNEL} from './channels';
+import {calculateChannelFromName, CHANNELS, LINEAR_START_CHANNEL, NUM_OF_CHANNELS, START_CHANNEL} from './channels';
import {IEntry} from './shared-interfaces';
const baseCategories = ['HD', 'HDTV', 'Sports event', 'Sports'];
@@ -51,7 +51,7 @@ export const generateXml = async (linear = false): Promise => {
};
if (linear) {
- _.forOwn(CHANNEL_MAP, (val, key) => {
+ _.forOwn(CHANNELS.MAP, (val, key) => {
if (!val.canUse) {
return;
}
diff --git a/services/networks.ts b/services/networks.ts
index 684382f..b045652 100644
--- a/services/networks.ts
+++ b/services/networks.ts
@@ -38,28 +38,35 @@ export const useMsgPlus = process.env.MSGPLUS?.toLowerCase() === 'true' ? true :
export const useNfl = {
_channel: process.env.NFLCHANNEL?.toLowerCase() === 'true' ? true : false,
_network: process.env.NFLNETWORK?.toLowerCase() === 'true' ? true : false,
- // _paramount: process.env.NFL_PARAMOUNT?.toLowerCase() === 'true' ? true : false,
- _redZone: true,
- // _tve: process.env.NFL_TVE?.toLowerCase() === 'true' ? true : false,
+ _peacock: process.env.NFL_PEACOCK?.toLowerCase() === 'true' ? true : false,
+ _prime: process.env.NFL_PRIME?.toLowerCase() === 'true' ? true : false,
+ _redZone: false,
+ _tve: process.env.NFL_TVE?.toLowerCase() === 'true' ? true : false,
get channel(): boolean {
return this._channel && this.plus;
},
get network(): boolean {
return this._network && this.plus;
},
- // get paramount(): boolean {
- // return this._paramount && this.plus;
- // },
+ set network(value: boolean) {
+ this._network = value;
+ },
+ get peacock(): boolean {
+ return this._peacock && this.plus;
+ },
plus: process.env.NFLPLUS?.toLowerCase() === 'true' ? true : false,
+ get prime(): boolean {
+ return this._prime && this.plus;
+ },
get redZone(): boolean {
return this._redZone && this.plus;
},
set redZone(value: boolean) {
this._redZone = value;
},
- // get tve(): boolean {
- // return this._tve && this.plus;
- // },
+ get tve(): boolean {
+ return this._tve && this.plus;
+ },
};
export const useMountainWest = process.env.MTNWEST?.toLowerCase() === 'true' ? true : false;
diff --git a/services/nfl-handler.ts b/services/nfl-handler.ts
index e4b3594..9b35a56 100644
--- a/services/nfl-handler.ts
+++ b/services/nfl-handler.ts
@@ -24,6 +24,9 @@ interface INFLChannelRes {
}
interface INFLEvent {
+ authorizations: {
+ [key: string]: any;
+ };
title: string;
startTime: string;
endTime: string;
@@ -36,6 +39,7 @@ interface INFLEvent {
description: string;
callSign: string;
linear: boolean;
+ networks: string[];
}
const CLIENT_KEY = [
@@ -152,7 +156,13 @@ const TV_DEVICE_INFO = {
const DEFAULT_CATEGORIES = ['NFL', 'NFL+', 'Football'];
-type TOtherAuth = 'paramount' | 'tve';
+type TOtherAuth = 'prime' | 'tve' | 'peacock';
+
+interface INFLJwt {
+ dmaCode: string;
+ plans: {plan: string; status: string}[];
+ networks?: {[key: string]: string};
+}
const parseAirings = async (events: INFLEvent[]) => {
const now = moment();
@@ -191,6 +201,7 @@ const parseAirings = async (events: INFLEvent[]) => {
categories: [...new Set(categories)],
duration: end.diff(start, 'seconds'),
end: end.valueOf(),
+ feed: event.networks?.[0],
from: 'nfl+',
id: event.externalId,
image: event.preferredImage,
@@ -220,11 +231,13 @@ class NflHandler {
public tv_expires_at?: number;
// Supplemental Auth
- // public paramountPlusUserId?: string;
- // public paramountPlusUUID?: string;
- // public mvpdIdp?: string;
- // public mvpdUserId?: string;
- // public mvpdUUID?: string;
+ public mvpdIdp?: string;
+ public mvpdUserId?: string;
+ public mvpdUUID?: string;
+ public amazonPrimeUserId?: string;
+ public amazonPrimeUUID?: string;
+ public peacockUserId?: string;
+ public peacockUUID?: string;
public initialize = async () => {
if (!useNfl.plus) {
@@ -243,13 +256,17 @@ class NflHandler {
await this.startProviderAuthFlow();
}
- // if (useNfl.paramount && (!this.paramountPlusUserId || !this.paramountPlusUUID)) {
- // await this.startProviderAuthFlow('paramount');
- // }
+ if (useNfl.tve && (!this.mvpdIdp || !this.mvpdUserId || !this.mvpdUUID)) {
+ await this.startProviderAuthFlow('tve');
+ }
+
+ if (useNfl.peacock && (!this.peacockUserId || !this.peacockUUID)) {
+ await this.startProviderAuthFlow('peacock');
+ }
- // if (useNfl.tve && (!this.mvpdIdp || !this.mvpdUserId || !this.mvpdUUID)) {
- // await this.startProviderAuthFlow('tve');
- // }
+ if (useNfl.prime && (!this.amazonPrimeUserId || !this.amazonPrimeUUID)) {
+ await this.startProviderAuthFlow('prime');
+ }
};
public refreshTokens = async () => {
@@ -267,10 +284,11 @@ class NflHandler {
return;
}
- const {dmaCode}: {dmaCode: string; plans: {plan: string; status: string}[]} = jwt_decode(this.access_token);
+ const {dmaCode}: INFLJwt = jwt_decode(this.access_token);
const redZoneAccess = this.checkRedZoneAccess();
- const nflNetworkAccess = useLinear && useNfl.network;
+ const nflNetworkAccess = this.checkNetworkAccess();
+ const hasPlus = this.checkPlusAccess();
if (!dmaCode) {
console.log('DMA Code not found for NFL+. Not searching for events');
@@ -293,26 +311,38 @@ class NflHandler {
});
data.data.items.forEach(i => {
- if (
- i.contentType === 'GAME' &&
- moment(i.startTime).isBefore(endSchedule) &&
- i.dmaCodes.find(dc => dc === `${dmaCode}`) &&
- i.language.find(l => l === 'en')
- ) {
- events.push(i);
- } else if (
- i.callSign === 'NFLNRZ' &&
- i.title === 'NFL RedZone' &&
- moment(i.startTime).isBefore(endSchedule) &&
- redZoneAccess
- ) {
- events.push(i);
- } else if (i.callSign === 'NFLNETWORK' && moment(i.startTime).isBefore(endSchedule) && nflNetworkAccess) {
- events.push(i);
+ if (moment(i.startTime).isBefore(endSchedule)) {
+ if (
+ i.contentType === 'GAME' &&
+ i.dmaCodes.find(dc => dc === `${dmaCode}`) &&
+ i.language.find(l => l === 'en')
+ ) {
+ if (
+ // If you have NFL+, you get the game
+ hasPlus ||
+ // TVE
+ this.checkTVEEventAccess(i) ||
+ // Peacock
+ (i.authorizations.peacock && this.checkPeacockAccess()) ||
+ // Prime
+ (i.authorizations.amazon_prime && this.checkPrimeAccess())
+ ) {
+ events.push(i);
+ }
+ } else if (
+ i.callSign === 'NFLNRZ' &&
+ i.title === 'NFL RedZone' &&
+ // NFL+ Premium or TVE supports RedZone
+ redZoneAccess
+ ) {
+ events.push(i);
+ } else if (i.callSign === 'NFLNETWORK' && nflNetworkAccess) {
+ events.push(i);
+ }
}
});
- if (useNfl.channel) {
+ if (useNfl.channel && useLinear) {
const url = [
'https://',
'api.nfl.com',
@@ -352,7 +382,22 @@ class NflHandler {
const {data} = await axios.post(
url,
- {},
+ {
+ ...(this.checkTVEAccess() && {
+ idp: this.mvpdIdp,
+ mvpdUUID: this.mvpdUUID,
+ mvpdUserId: this.mvpdUserId,
+ networks: event.feed,
+ }),
+ ...(this.checkPrimeAccess() && {
+ amazonPrimeUUID: this.amazonPrimeUUID,
+ amazonPrimeUserId: this.amazonPrimeUserId,
+ }),
+ ...(this.checkPeacockAccess() && {
+ peacockUUID: this.amazonPrimeUUID,
+ peacockUserId: this.amazonPrimeUserId,
+ }),
+ },
{
headers: {
'Content-Type': 'application/json',
@@ -371,17 +416,69 @@ class NflHandler {
private checkRedZoneAccess = (): boolean => {
try {
- const {plans}: {dmaCode: string; plans: {plan: string; status: string}[]} = jwt_decode(this.access_token);
+ const {plans, networks}: INFLJwt = jwt_decode(this.access_token);
if (plans) {
useNfl.redZone =
- plans.findIndex(p => p.plan === 'NFL_PLUS_PREMIUM' && p.status === 'ACTIVE') > -1 ? true : false;
+ plans.findIndex(p => p.plan === 'NFL_PLUS_PREMIUM' && p.status === 'ACTIVE') > -1 || networks?.NFLRZ
+ ? true
+ : false;
}
} catch (e) {}
return useNfl.redZone;
};
+ private checkNetworkAccess = (): boolean => {
+ try {
+ const {plans, networks}: INFLJwt = jwt_decode(this.access_token);
+
+ if (plans) {
+ const hasPlus = (this.checkPlusAccess() || networks?.NFLN) && useLinear ? true : false;
+ useNfl.network = hasPlus;
+ }
+ } catch (e) {}
+
+ return useNfl.network;
+ };
+
+ private checkPlusAccess = (): boolean => {
+ let hasPlus = false;
+
+ try {
+ const {plans}: INFLJwt = jwt_decode(this.access_token);
+
+ if (plans) {
+ hasPlus =
+ plans.findIndex(p => (p.plan === 'NFL_PLUS' || p.plan === 'NFL_PLUS_PREMIUM') && p.status === 'ACTIVE') > -1
+ ? true
+ : false;
+ }
+ } catch (e) {}
+
+ return hasPlus;
+ };
+
+ private checkTVEAccess = (): boolean => (this.mvpdIdp && useNfl.tve ? true : false);
+ private checkPeacockAccess = (): boolean => (this.peacockUserId && useNfl.peacock ? true : false);
+ private checkPrimeAccess = (): boolean => (this.amazonPrimeUserId && useNfl.prime ? true : false);
+
+ private checkTVEEventAccess = (event: INFLEvent): boolean => {
+ let hasChannel = false;
+
+ try {
+ const {networks}: INFLJwt = jwt_decode(this.access_token);
+
+ event.networks.forEach(n => {
+ if (networks[n]) {
+ hasChannel = true;
+ }
+ });
+ } catch (e) {}
+
+ return hasChannel;
+ };
+
private extendTokens = async (): Promise => {
await this.extendToken();
await this.extendTvToken();
@@ -405,15 +502,19 @@ class NflHandler {
signatureTimestamp,
uidSignature,
}),
- // ...(this.mvpdIdp && {
- // mvpdIdp: this.mvpdIdp,
- // mvpdUUID: this.mvpdUUID,
- // mvpdUserId: this.mvpdUserId,
- // }),
- // ...(this.paramountPlusUserId && {
- // paramountPlusUUID: this.paramountPlusUUID,
- // paramountPlusUserId: this.paramountPlusUserId,
- // }),
+ ...(this.mvpdIdp && {
+ mvpdIdp: this.mvpdIdp,
+ mvpdUUID: this.mvpdUUID,
+ mvpdUserId: this.mvpdUserId,
+ }),
+ ...(this.amazonPrimeUserId && {
+ amazonPrimeUUID: this.amazonPrimeUUID,
+ amazonPrimeUserId: this.amazonPrimeUserId,
+ }),
+ ...(this.peacockUserId && {
+ peacockUUID: this.peacockUUID,
+ peacockUserId: this.peacockUserId,
+ }),
},
{
headers: {
@@ -425,9 +526,21 @@ class NflHandler {
this.access_token = data.accessToken;
this.refresh_token = data.refreshToken;
this.expires_at = data.expiresIn;
+
+ if (data.additionalInfo) {
+ data.additionalInfo.forEach(ai => {
+ if (ai.data) {
+ if (ai.data.idp === 'amazon') {
+ this.amazonPrimeUUID = ai.data.newUUID;
+ }
+ }
+ });
+ }
+
this.save();
this.checkRedZoneAccess();
+ this.checkNetworkAccess();
} catch (e) {
console.error(e);
console.log('Could not refresh token for NFL+');
@@ -452,15 +565,19 @@ class NflHandler {
signatureTimestamp,
uidSignature,
}),
- // ...(this.mvpdIdp && {
- // mvpdIdp: this.mvpdIdp,
- // mvpdUUID: this.mvpdUUID,
- // mvpdUserId: this.mvpdUserId,
- // }),
- // ...(this.paramountPlusUserId && {
- // paramountPlusUUID: this.paramountPlusUUID,
- // paramountPlusUserId: this.paramountPlusUserId,
- // }),
+ ...(this.mvpdIdp && {
+ mvpdIdp: this.mvpdIdp,
+ mvpdUUID: this.mvpdUUID,
+ mvpdUserId: this.mvpdUserId,
+ }),
+ ...(this.amazonPrimeUserId && {
+ amazonPrimeUUID: this.amazonPrimeUUID,
+ amazonPrimeUserId: this.amazonPrimeUserId,
+ }),
+ ...(this.peacockUserId && {
+ peacockUUID: this.peacockUUID,
+ peacockUserId: this.peacockUserId,
+ }),
},
{
headers: {
@@ -474,7 +591,18 @@ class NflHandler {
this.tv_expires_at = data.expiresIn;
this.save();
+ if (data.additionalInfo) {
+ data.additionalInfo.forEach(ai => {
+ if (ai.data) {
+ if (ai.data.idp === 'amazon') {
+ this.amazonPrimeUUID = ai.data.newUUID;
+ }
+ }
+ });
+ }
+
this.checkRedZoneAccess();
+ this.checkNetworkAccess();
} catch (e) {
console.error(e);
console.log('Could not refresh token for NFL+');
@@ -581,14 +709,18 @@ class NflHandler {
nflAccount: true,
nflToken: true,
}),
- // ...(otherAuth === 'paramount' && {
- // idp: 'PARAMOUNT_PLUS',
- // nflAccount: false,
- // }),
- // ...(otherAuth === 'tve' && {
- // idp: 'TV_PROVIDER',
- // nflAccount: false,
- // }),
+ ...(otherAuth === 'tve' && {
+ idp: 'TV_PROVIDER',
+ nflAccount: false,
+ }),
+ ...(otherAuth === 'prime' && {
+ idp: 'AMAZON',
+ nflAccount: false,
+ }),
+ ...(otherAuth === 'peacock' && {
+ idp: 'PEACOCK',
+ nflAccount: false,
+ }),
},
{
headers: {
@@ -599,8 +731,17 @@ class NflHandler {
},
);
- console.log('=== NFL+ Auth ===');
- console.log('Please open a browser window and go to: https://id.nfl.com/account/activate');
+ const otherAuthName =
+ otherAuth === 'tve'
+ ? '(TV Provider) '
+ : otherAuth === 'prime'
+ ? '(Amazon Prime) '
+ : otherAuth === 'peacock'
+ ? '(Peacock) '
+ : '';
+
+ console.log(`=== NFL+ Auth ${otherAuthName}===`);
+ console.log(`Please open a browser window and go to: https://id.nfl.com/account/activate?regCode=${code}`);
console.log('Enter code: ', code);
console.log('App will continue when login has completed...');
@@ -658,16 +799,19 @@ class NflHandler {
}
if (otherAuth === 'tve') {
- // this.mvpdIdp = data.idp;
- // this.mvpdUserId = data.userId;
- // this.mvpdUUID = data.uuid;
- // this.save();
- } else if (otherAuth === 'paramount') {
- // this.paramountPlusUserId = data.userId;
- // this.paramountPlusUUID = data.uuid;
- // this.save();
+ this.mvpdIdp = data.idp;
+ this.mvpdUserId = data.userId;
+ this.mvpdUUID = data.uuid;
+ } else if (otherAuth === 'prime') {
+ this.amazonPrimeUserId = data.userId;
+ this.amazonPrimeUUID = data.uuid;
+ } else if (otherAuth === 'peacock') {
+ this.peacockUserId = data.userId;
+ this.peacockUUID = data.uuid;
}
+ this.save();
+
await this.extendToken();
await this.extendTvToken();
} else {
@@ -702,11 +846,13 @@ class NflHandler {
tv_access_token,
tv_expires_at,
tv_refresh_token,
- // paramountPlusUserId,
- // paramountPlusUUID,
- // mvpdIdp,
- // mvpdUserId,
- // mvpdUUID,
+ mvpdIdp,
+ mvpdUserId,
+ mvpdUUID,
+ amazonPrimeUserId,
+ amazonPrimeUUID,
+ peacockUserId,
+ peacockUUID,
} = fsExtra.readJSONSync(path.join(configPath, 'nfl_tokens.json'));
this.device_id = device_id;
@@ -719,11 +865,13 @@ class NflHandler {
this.uid = uid;
// Supplemental Auth
- // this.paramountPlusUserId = paramountPlusUserId;
- // this.paramountPlusUUID = paramountPlusUUID;
- // this.mvpdIdp = mvpdIdp;
- // this.mvpdUserId = mvpdUserId;
- // this.mvpdUUID = mvpdUUID;
+ this.mvpdIdp = mvpdIdp;
+ this.mvpdUserId = mvpdUserId;
+ this.mvpdUUID = mvpdUUID;
+ this.amazonPrimeUUID = amazonPrimeUUID;
+ this.amazonPrimeUserId = amazonPrimeUserId;
+ this.peacockUserId = peacockUserId;
+ this.peacockUUID = peacockUUID;
}
};
}