DeepLinks: ESPN+

@KineticMan On a related subject, I'd like to see if I can get this working with ADBTuner -- which would require something of a hybrid approach between your two projects.

One workflow that comes to mind would require that the unique ID (deeplink) for each event be the same across both projects. Is that the case? If so, for a given virtual channel (lane), is is possible to curl the unique ID for the event on that lane?

i believe on ESPN4CC4C, i grabbed ANY event that ESPN showed having a live URL (so it included ESPN,ESPN2,etc) and on DeepLinks I filtered it to only ESPN+ events (i think I was less interested in the talk show stuff). I don't even recall exactly WHY i did that, but it's a simple filter on DeepLinks if we wanted all events

and on ESPN4CC4C, it may look a little different because I made that mini-guide and honestly with only 40 lanes preset, it will probably miss some events (esp in the evening with college bball having 52342097 games now).

end of day, I can make any change relatively easy. just figured at some point, it was overkill to have all events. filtering might help if we go down that path.

i think thats possible... wondering if just making a new hybrid probably would be easier than trying to rewrite both of them.

so, in summary - you want a "mini-guide" like ESPN4CC4C with x "lanes".. what would you like the URL for each event/m3u to call?

I don't think it'll be necessary to rewrite anything. The idea would be to setup those 40 lanes (or whatever number someone chooses) in ADBTuner, then when the actual tuning happens use curl (via an ADBTuner custom tuning config) to get the UUID for the current event showing in the guide for that lane.

E.G., someone tunes to the event in lane 1, and when tuning the needed deeplink UUID is grabbed for that event from your DB. This assumes that UUID present in the http:// construct is the same as the UUID present in the sportscenter:// construct -- which is why I was asking.

The typical ADBTuner M3U would be used with the XML you generate for cc4c use.

EDIT: I just confirmed they are the same, so that's great. Now it's just a question of grabbing that ID for the event that's active in a given lane.

got it... the data already exists in the DB so just a matter of finding a way to grab it easy for new hybrid approach. on the case.

Is the idea that ADBTuner would get the actual deep link URL by querying another URL?

Does anybody know how to combine ESPN with another service (ie. DTV Stream)? I have been moving around lately but I would love to have this combined with DTV Stream. I don't record much so I have 2 HDMI devices on hand. I don't want to limit espn-ah4c or ah4c to 1 device each...

check this test out.. is this what you'd like to see? this was relatively easy to grab. i just had to edit the vc_resolver script. any other format u want, i can provide. ill push to git under ESPN4CC4C.

curl -sS "http://127.0.0.1:8094/whatson/9?format=txt"
8fca688b-e27b-4352-a188-4a5438c21eac

example for your script

LANE=9
PLAYID=$(curl -sS "http://<resolver-host>:8094/whatson/$LANE?format=txt")
if [ -n "$PLAYID" ]; then
  adb -s 192.168.86.37:5555 shell am start     -n com.espn.gtv/com.espn.startup.presentation.StartupActivity     -d "sportscenter://x-callback-url/showWatchStream?playID=$PLAYID"
else
  echo "No active event on lane $LANE"
fi

Yes.

The deeplink IDs ESPN+ uses for live events are always changing, as are the events. @KineticMan has already established a structure (for use with cc4c), that sets up a fixed number of channels, and then slots those events into those channels.

So my thinking is, in ADBTuner, we set each one of the virtual channels up in ADBTuner and then when someone wants to watch that event, we know that whatever is currently showing in the guide on channel x is what they want -- and we can get the deeplink using a curl command in an ADBTuner Custom Config to get the correct deeplink UUID.

Seems easy enough (as @KineticMan demo'd just above) -- unless you have another idea?

Perfect-o. Nice work.

Stay tuned. I think we'll have something along these lines very soon, using ADBTuner.

1 Like

Sounds pretty straightforward. I was thinking I could help out by adding support for dynamic URLs such as this so it wouldn't necessarily require a custom configuration.

Merged into main. Put some documentation too. Let me know if you need anything else.

I don't know that it would be necessary because @bnhf is working on something with ADBTuner configurations, but if you could include the full deeplink url in the response I could have ADBTuner parse it natively.

{
  "ok": true,
  "lane": 6,
  "event_uid": "3355a8ae-9719-472c-9017-1f0be2b774ce:dbc4b7c1b7d56ea7f2c4e10118cb8126",
  "at": "2025-11-06T22:26:20+00:00",
  "deeplink_url": "sportscenter://x-callback-url/showWatchStream?playID=3355a8ae-9719-472c-9017-1f0be2b774ce:dbc4b7c1b7d56ea7f2c4e10118cb8126"
}

With this perhaps we could have an ADBTuner URL configured like this?
http://x.x.x.x:8094/whatson/6?dynamic=1&param=deeplink_url

sure - just so we're clear - i'm applying this to ESPN4CC4C. DeepLinks doesnt do any "lane/channel planning"

  • /whatson/{lane} and /whatson_all now include a deeplink_url in JSON.
  • You can also grab just the deeplink as plain text for easier parsing.
  • Add dynamic=1 if you want it resolved live (what’s playable right now).

Quick examples

JSON (includes deeplink_url):

http://<host>:8094/whatson/6?dynamic=1

Sample response:

{
  "ok": true,
  "lane": 6,
  "event_uid": "3355a8ae-...8126",
  "at": "2025-11-06T22:26:20+00:00",
  "deeplink_url": "sportscenter://x-callback-url/showWatchStream?playID=3355a8ae-...8126"
}

Plain text (short form; good for ADBTuner “open URL”):

http://<host>:8094/whatson/6?dynamic=1&fmt=txt&param=deeplink_url

Returns:

sportscenter://x-callback-url/showWatchStream?playID=3355a8ae-...8126

Plain text (explicit “full” form; same URL today, but locked for future):

http://<host>:8094/whatson/6?dynamic=1&fmt=txt&param=deeplink_url_full

Empty when nothing playable (TXT comes back blank; JSON has deeplink_url: null):

http://<host>:8094/whatson/6?dynamic=1&fmt=txt&param=deeplink_url

Returns:

<empty>

I'm really sorry, I probably should have explained better. That's my fault.

The url query string args "dynamic" and "param" were for ADBTuner's use. You did far more work than I was asking for.

All I was looking for was to have the "deeplink_url" added to the response from http://<host>:8094/whatson/6. However, if you would prefer that we request that by including a specific parameter I can understand that.

For reference, I was thinking that ADBTuner would just do something like the following. If "dynamic" and "param" are included in the query string then ADBTuner would strip those parameters from the URL and then query the ESPN4CC4C endpoint. ADBTuner would use the value of the "param" argument to find the value in the returned JSON.

ESPN4CC would only see http://<host>:8094/whatson/6 in the request.

if {"dynamic", "param"} <= set(query_params):
    clean_url = url_query_cleaner(tuning_url, ["dynamic", "param"], remove=True)
    url_data = httpx.get(clean_url, timeout=5).json()
    if url_data:
        dynamic_url = url_data.get(query_params["param"][0], None)
        if dynamic_url:
            tuning_url = dynamic_url

Edit: This is just one parameter ("dynamic_url_json_key") in ADBTuner now.

If you want, I could submit a pull request, I had just figured it was a one-liner so I didn't bother. Thanks again.

ahhhhh... i wondered why you wanted that dynamic param..

you want it in json output, or plain text? way easier lol....

JSON is fine. If your existing response just included that field that would be awesome.

{
  "ok": true,
  "lane": 1,
  "event_uid": "7be1c665-b635-4e6e-95ad-8a6ba6b13018:59018f34f0de2248cc92d1c0909924b3",
  "at": "2025-11-07T19:43:51+00:00",
  "deeplink_url": "sportscenter://x-callback-url/showWatchStream?playID=7be1c665-b635-4e6e-95ad-8a6ba6b13018:59018f34f0de2248cc92d1c0909924b3"
}

For testing purposes I had just added it to vc_resolver.py in the whatson() function. I didn't take a deep dive or anything so it's very possible I'm over simplifying it.

if kind == "event" and eid:
    ...
  
    deeplink_url = f"sportscenter://x-callback-url/showWatchStream?playID={eid}"
    return JSONResponse(
        {
            "ok": True,
            "lane": normalized_lane,
            "event_uid": eid,
            "at": when_iso,
            "deeplink_url": deeplink_url,
        },
        status_code=200,
    )

this work?

# Plain-text deeplink (short)
curl -sS "http://192.168.86.72:8094/deeplink/6"

sportscenter://x-callback-url/showWatchStream?playID=7be1c665-b635-4e6e-95ad-8a6ba6b13018
# JSON with short deeplink included
curl -sS "http://192.168.86.72:8094/whatson/6" | jq .


```json
{
  "ok": true,
  "lane": 6,
  "event_uid": "7be1c665-b635-4e6e-95ad-8a6ba6b13018:59018f34f0de2248cc92d1c0909924b3",
  "at": "2025-11-07T19:43:51+00:00",
  "deeplink_url": "sportscenter://x-callback-url/showWatchStream?playID=7be1c665-b635-4e6e-95ad-8a6ba6b13018"
}

This would work. Thanks!

1 Like