ESPN+ & FOX Sports with Custom Channels via EPlusTV

Source URL: http://[your-ip-here]:8000/channels.m3u
Guide data field: http://[your-ip-here]:8000/xmltv.xml

It's been a while since I used Docker desktop but I believe it has a built-in terminal. If you have what looks like a play button next to the container, I think that should start it.

thanks that was helpful. I found a "terminal" button in Docker Desktop. I entered the code, and got this response:

eplustv@4.8.0 start
ts-node -r tsconfig-paths/register index.tsx

=== E+TV v4.8.0 starting ===
Server started on port 8000
=== Getting events ===
=== Done getting events ===
=== Building the schedule ===
=== Done building the schedule ===

That seems good, now it seems that I'm supposed to run the following from my webbrowser(?). I'm guessing that is the ip for EplusTV? How do I find out what the eplusTV ip is?
http://:8000

Use the ip of the machine docker is running on. If you are using the same machine as your dvr server you can find the ip on the settings, status, net section. Just add :8000 to the end. It will be something like 192.168.1.150:8000

Thanks - GetChannels DVR says: 2 interfaces: 192.168.1.154, 172.31.0.1. I entered both in my web browser with :8000 at the end e.g. http://192.168.1.154:8000
And it says: " This site can’t be reached. 192.168.1.154 refused to connect.

Update: Does Docker "go to sleep" or something. As I had previously successfully run "docker run -p 8000:8000 -v config_dir:/app/config m0ngr31/eplustv" but the http://192.168.1.154:8000 didn't work (as noted above). I decided to rerun that in docker and now it works! I'm entering my subscription info ! THX

1 Like

It shouldn’t but I don’t really know much about docker running on windows. I would also suggest you install a docker container called “Portainer” it helps to visualize your docker environment and will help with other channels tools like Olivetin and OliveTin’s project one click.

@m0ngr31 is there a way to get SNY as a linear channel after adding to the MLB app? My previous setup is broken now that SNY isn't streaming on its own website anymore.

AFAIK, MLB just does the streaming for games, not their linear feed. If they have an app somewhere that does the linear stream I can look at adding that if you let me borrow your creds

Do you know what zone you're in for MSG? Maybe I missed a mapping there or something

Hello @m0ngr31 , first off thank you for building and running this project. I could use some help when you have a moment. I got as far as being able to get the ESPN+ streams working. But no matter what settings I change, my feed will cut out after 1-5 minutes. I spent all weekend trying to troubleshoot and am at a loss.

Additionally, I have paramount+ and thought I authenticated properly on the eplustv admin/setup screen but I didn't see any feeds for NCAA games this past weekend. Is that for NFL only perhaps?

Thanks in advance for any guidance.

Can you be very specific when you say "cut out"? What device are you using?

It happens on all my devices. On my pc where I host my server/docker. Same thing happens on my firestick or laptop. I get a feed for 1-5 minutes and then it dies. I get a transcoding error. I have to press play to get it going again. Happens on every channel. I have my server set up to feed original quality, direct. Hardware encoding.

1 Like

Ok, reason I ask is I am having a similar but apparently different issue except mine is about "Device Disk Full"

I don't have access either, but presumably this is the SNY feed:
https://www.mlb.com/tv/sny
From
image

I fixed my issue in case this comes up for anyone else.

I have an ESPN+ subscription, but technically not ESPN (no cable subscription). But with xfinity being my internet provider, I was able to authenticate the ESPN channels even without a cable subscription. I started to suspect that was the issue. So I removed and did a fresh install of eplus via portainer in docker, didn't authenticate ESPN (only ESPN+), and it appears that's fixed the problem. My current stream has been going for 30 minutes strong. Until this point, the longest I could get a stream before it would break was 5-6 minutes tops.

Pigs get fat, hogs get slaughtered.

That would make sense. The ESPN site will give you a free view for a few minutes before it cuts off.

Hey all, I'm having an issue getting NESN to authenticate, and hoping I could get some assistance.

When I check the NESN checkbox in the E+TV Configuration, nothing appears to happen, but I do see the following in the container logs:

> eplustv@4.8.1 start
> ts-node -r tsconfig-paths/register index.tsx
=== E+TV v4.8.1 starting ===
Server started on port 9000
=== Getting events ===
=== Done getting events ===
=== Building the schedule ===
=== Done building the schedule ===
AxiosError: Request failed with status code 403
    at settle (/app/node_modules/axios/lib/core/settle.js:19:12)
    at IncomingMessage.handleStreamEnd (/app/node_modules/axios/lib/adapters/http.js:512:11)
    at IncomingMessage.emit (node:events:529:35)
    at IncomingMessage.emit (node:domain:489:12)
    at endReadableNT (node:internal/streams/readable:1400:12)
    at processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ERR_BAD_REQUEST',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [ 'xhr', 'http' ],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 60000,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function [FormData]], Blob: [class Blob] },
    validateStatus: [Function: validateStatus],
    headers: AxiosHeaders {
Could not start the authentication process for Fox Sports!
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      'User-Agent': 'okhttp/4.11.0',
      authorization: 'sk_Np1qvyUgFaGj5Y4c',
      'Content-Length': '133',
      'Accept-Encoding': 'gzip, compress, deflate, br'
    },
    method: 'post',
    url: 'https://api.short.io/links',
    data: '{"domain":"tv.nesn.com","expiredURL":"https://support.nesn.com","originalURL":"https://nesn.com/watch/authenticate/Q2B3OUB/5a75d2da"}'
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      finish: [Function: requestOnFinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    maxRequestsOnConnectionReached: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    strictContentLength: false,
    _contentLength: '133',
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    _closed: false,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'api.short.io',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'api.short.io',
      _closeAfterHandlingError: false,
      _readableState: [ReadableState],
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular *1],
      timeout: 60000,
      [Symbol(alpncallback)]: null,
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(async_id_symbol)]: 1494,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: Timeout {
        _idleTimeout: 60000,
        _idlePrev: [TimersList],
        _idleNext: [Timeout],
        _idleStart: 35537,
        _onTimeout: [Function: bound ],
        _timerArgs: undefined,
        _repeat: null,
        _destroyed: false,
        [Symbol(refed)]: false,
        [Symbol(kHasPrimitive)]: false,
        [Symbol(asyncId)]: 1502,
        [Symbol(triggerId)]: 1497
      },
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kSetNoDelay)]: false,
      [Symbol(kSetKeepAlive)]: true,
      [Symbol(kSetKeepAliveInitialDelay)]: 60,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    _header: 'POST /links HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/json\r\n' +
      'User-Agent: okhttp/4.11.0\r\n' +
      'authorization: sk_Np1qvyUgFaGj5Y4c\r\n' +
      'Content-Length: 133\r\n' +
      'Accept-Encoding: gzip, compress, deflate, br\r\n' +
      'Host: api.short.io\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: nop],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object: null prototype],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype],
      freeSockets: [Object: null prototype] {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    joinDuplicateHeaders: undefined,
    path: '/links',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      socket: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      rawHeaders: [Array],
      rawTrailers: [],
      joinDuplicateHeaders: undefined,
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 403,
      statusMessage: 'Forbidden',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'https://api.short.io/links',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(kHeaders)]: [Object],
      [Symbol(kHeadersCount)]: 40,
      [Symbol(kTrailers)]: null,
      [Symbol(kTrailersCount)]: 0
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'api.short.io',
    protocol: 'https:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 133,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'https://api.short.io/links',
      _timeout: null,
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'content-type': [Array],
      'user-agent': [Array],
      authorization: [Array],
      'content-length': [Array],
      'accept-encoding': [Array],
      host: [Array]
    },
    [Symbol(errored)]: null,
    [Symbol(kHighWaterMark)]: 16384,
    [Symbol(kRejectNonStandardBodyWrites)]: false,
    [Symbol(kUniqueHeaders)]: null
  },
  response: {
    status: 403,
    statusText: 'Forbidden',
    headers: AxiosHeaders {
      date: 'Tue, 25 Mar 2025 02:52:35 GMT',
      'content-type': 'application/json; charset=utf-8',
      'content-length': '70',
      connection: 'close',
      'content-security-policy': "default-src 'none'",
      'cross-origin-opener-policy': 'same-origin',
      'cross-origin-resource-policy': 'same-origin',
      'origin-agent-cluster': '?1',
      'referrer-policy': 'no-referrer',
      'strict-transport-security': 'max-age=63072000; includeSubDomains',
      'x-content-type-options': 'nosniff',
      'x-dns-prefetch-control': 'off',
      'x-download-options': 'noopen',
      'x-frame-options': 'DENY',
      'x-permitted-cross-domain-policies': 'none',
      'x-xss-protection': '0',
      vary: 'Origin',
      'x-ratelimit-limit': '50',
      'x-ratelimit-remaining': '49',
      'x-ratelimit-reset': '1'
    },
    config: {
      transitional: [Object],
      adapter: [Array],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 60000,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      env: [Object],
      validateStatus: [Function: validateStatus],
      headers: [AxiosHeaders],
      method: 'post',
      url: 'https://api.short.io/links',
      data: '{"domain":"tv.nesn.com","expiredURL":"https://support.nesn.com","originalURL":"https://nesn.com/watch/authenticate/Q2B3OUB/5a75d2da"}'
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      strictContentLength: false,
      _contentLength: '133',
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: [TLSSocket],
      _header: 'POST /links HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Content-Type: application/json\r\n' +
        'User-Agent: okhttp/4.11.0\r\n' +
        'authorization: sk_Np1qvyUgFaGj5Y4c\r\n' +
        'Content-Length: 133\r\n' +
        'Accept-Encoding: gzip, compress, deflate, br\r\n' +
        'Host: api.short.io\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      joinDuplicateHeaders: undefined,
      path: '/links',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'api.short.io',
      protocol: 'https:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(errored)]: null,
      [Symbol(kHighWaterMark)]: 16384,
      [Symbol(kRejectNonStandardBodyWrites)]: false,
      [Symbol(kUniqueHeaders)]: null
    },
    data: {
      message: 'Access to domain denied',
      success: false,
      statusCode: 403
    }
  }
}
TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
    at /app/services/providers/nesn/views/Login.tsx:17:41
    at Generator.next (<anonymous>)
    at fulfilled (/app/services/providers/nesn/views/Login.tsx:5:58)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)

Any thoughts?

Just FYI that T-Mobile MLB Tuesday deal is active starting today....just activated mine again for this season.

2 Likes

Now that MLB and Peacock both offer ways to view SF Giants game in market (through a monthly fee). Is this possible to add to this container?

Peacock has DRM, so that can't be added here.

But if Giants.TV streams through an MLB.com account, that should already work.