Android Live Channels integration for Live TV and DVR Scheduling



I am starting to work on an Android TV TIF (TV Input Framework) Plex frontend add-on for Android Live Channels for watching Live TV and Scheduling recordings through the plex api to the Plex Media Server backend.

I need a bit of help on how to query the PMS for a list of channels and xmltv epg either in xml format or sql format for the TIF to add channels and sync epg data into Live Channels.

I have been working with SQLite data from another Live Channels plugin and also examining "plexapp-rest-library" for querying such data and working with account syncing ( for getting the Plex Token for account sync.

Could someone in the dev community here point me in the correct direction for querying such data as live tv channels and xmltv data? I can see some channel data in the tv.plex.providers.epg.onconnect-hash.db database so I should be able to query this information for ChannelSync data in the Android TV Input Framework.

Any pointers are greatly appreciated :smile:


Your best friend is Chrome browser in debug mode!

I did pull the avail channels for a tuner here:


YOU ARE THE MAN! Great place to start THANK YOU!


What would the api call with Plex Token to generate a channel list?



I’ll work on debugging and catching logs, looks like lots of segmented transport stream parts via /livetv/sessions still trying to catch a log on an actual json channel list and xmltv.db data with matching channel tvg-id’s. All the code is out there to implement this add-on I just need a bit of help from some more experienced android/java plex API developers:

Example for syncing plex epg xmltv.xml data and channel data in json format all we need is plex_link_channel_url and plex_link_epg_url.

        XmlTvParser.TvListing listings = PlexUtil.getTvListings(context,
                context.getString(R.string.plex_link_epg_url), PlexUtil.FORMAT_XMLTV);

        XmlTvParser.TvListing channelListings = PlexUtil.getTvListings(context,
                context.getString(R.string.plex_link_channel_url), PlexUtil.FORMAT_JSON);

        // channel entry
        ContentValues values = new ContentValues();
        values.put(TvContract.Channels.COLUMN_INPUT_ID, inputId);

        values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, Integer.toString(entry.getNumber()));
        values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, entry.getName());
        values.put(TvContract.Channels.COLUMN_SERVICE_ID, 0);
        values.put(TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID, 0);
        values.put(TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, entry.getUid());
        values.put(TvContract.Channels.COLUMN_SERVICE_TYPE, entry.isRadio() ? TvContract.Channels.SERVICE_TYPE_AUDIO : TvContract.Channels.SERVICE_TYPE_AUDIO_VIDEO);
        values.put(TvContract.Channels.COLUMN_TYPE, TvContract.Channels.TYPE_DVB_S2);
        values.put(TvContract.Channels.COLUMN_SEARCHABLE, 1);
        values.put(TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA, Integer.toString(entry.getUid()));

        // channel link needs Android M
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            values.put(TvContract.Channels.COLUMN_APP_LINK_POSTER_ART_URI, getUriToResource(context, R.drawable.banner_timers).toString());
            values.put(TvContract.Channels.COLUMN_APP_LINK_INTENT_URI, link);
            values.put(TvContract.Channels.COLUMN_APP_LINK_TEXT, context.getString(R.string.timer_title));
            values.put(TvContract.Channels.COLUMN_APP_LINK_COLOR, Utils.getColor(context, R.color.primary_color));
            values.put(TvContract.Channels.COLUMN_APP_LINK_ICON_URI, "");

        Uri channelUri = existingChannels.get(entry.getNumber());


@dane22 said:
Your best friend is Chrome browser in debug mode!

I did pull the avail channels for a tuner here:

How are you getting the list of channels via:

	# Start by getting enabled channels
	url = ''

I have been trying with my Plex Auth token and I must be missing some header or .json response file needed


curl -X "GET" "'" \
     -H "X-Plex-Version: 1.0.0" \
     -H "X-Plex-Product: Plex Media Server" \
     -H "X-Plex-Client-Identifier: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
     -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" \
     --data-urlencode "user[password]=pw" \
     --data-urlencode "user[login]=username"





And you get the device key from the first call


@dane22 said:


Perfect thanks a million dane22. Exactly what I needed :slight_smile:


So perfect that lead me to find the header for stream info now to pipe that into a channelsync with transportstream data and then lineup the xmltv epg data (need to figure out this next)


<MediaContainer size="1">
<Video type="clip" title="Live Session " summary="" index="1" ratingCount="0" genuineMediaAnalysis="1" key="/livetv/sessions/77225251-e993-4bc0-97fb-94764cc6c98d" live="1">
<Media videoResolution="720" width="1280" height="720" aspectRatio="1.78" audioChannels="2" audioCodec="ac3" videoCodec="mpeg2video" container="mpegts" origin="livetv" protocol="hls" uuid="77225251-e993-4bc0-97fb-94764cc6c98d">
<Part size="0" container="mpegts" protocol="hls">
<Stream streamType="1" codec="mpeg2video" index="0" closedCaptions="1" frameRate="59.940" height="720" level="4" pixelAspectRatio="1:1" profile="main" width="1280"/>
<Stream streamType="2" selected="1" codec="ac3" index="1" channels="2" bitrate="192" language="English" languageCode="eng" audioChannelLayout="stereo" samplingRate="48000"/>
<TranscodeSession key="/transcode/sessions/77225251-e993-4bc0-97fb-94764cc6c98d" throttled="0" complete="0" progress="-1" speed="0.89999997615814209" duration="7200000" context="static" sourceVideoCodec="" sourceAudioCodec="" videoDecision="copy" audioDecision="copy" protocol="hls" container="mpegts" videoCodec="*" audioCodec="*" audioChannels="2" transcodeHwRequested="1" transcodeHwFullPipeline="0" timeStamp="1524004887.2486539" maxOffsetAvailable="110.663267" minOffsetAvailable="1"/>


And some more media info in the chrome console :smile:

[Player] Timeline, {
  "ratingKey": "com.gracenote.onconnect://episode/EP000014578224",
  "key": "/livetv/sessions/77225251-e993-4bc0-97fb-94764cc6c98d",
  "playQueueItemID": "2",
  "state": "playing",
  "hasMDE": 1,
  "time": 518000,
  "duration": 4294967296000


This gets the segmented transport streams in m3u8 which will play in vlc for testing but as stated it is segmented .ts parts so its not smooth or buffered. Good start for app dev just need the function calls now and im thinking i could learn something from Plexapp REST Library


just need to find the plex api call for gracenote xmltv output with matching plex channel ids and session info…

This definitely helps

"ratingKey": "com.gracenote.onconnect://episode/EP000014578224",


So basically makes sense that the m3u8 is segmented due to time-shift support so this should help when creating a large buffer at stream startup.


On android the link looks like this for livetv playback:



Well this is interesting. In this FFMPEG streaming guide it segments all ts files into an m3u8 just as plex does:

ffmpeg -i source.mp4 -map 0 
-codec:v libx264 -codec:a libfaac 
-f ssegment -segment_list playlist.m3u8 
-segment_list_flags +live -segment_time 10 


Here is plex ffmpeg segmenter command

'/usr/lib/plexmediaserver/Plex Transcoder' '-noaccurate_seek' '-ignore_unknown' '-scan_all_pmts' '-1' '-rw_timeout' '30000000' '-fflags' '+discardcorruptts+fillwallclockdts' '-i' '' '-map' '0:V?' '-codec:V' 'copy' '-map' '0:a?' '-codec:a' 'copy' '-copypriorss:a' '0' '-map' '0:s?' '-codec:s' 'copy' '-segment_format' 'mpegts' '-f' 'ssegment' '-individual_header_trailer' '0' '-segment_time' '1' '-segment_start_number' '0' '-segment_time_delta' '0.0625' '-segment_list' '' '-segment_list_type' 'csv' '-segment_list_size' '2147483647' '-segment_list_separate_stream_times' '1' '-max_delay' '5000000' '-map_metadata' '-1' '-map_chapters' '-1' 'media-%05d.ts' '-y' '-nostats' '-loglevel' 'quiet' '-loglevel_plex' 'error' '-progressurl' ''


And this would be the live progress url :smile:

-progressurl’ ‘


I really need to find a way to GET actual channel id’s ie

Just as tvheadend does for the frontend app to work in Android Live Channels…


Hmmm grepping logs I do get a unique channel id:

POST /livetv/dvrs/23/channels/600/tune


That doesnt seem to work but im getting close and im basically using this topic for notes so I can come back and see progress. Here are a few more GET commands for livetv info:

GET >> enc.xml
GET >> livetv.xml
GET >> channels.xml
GET >> dvrs.xml