Tvheadend / DVBLink Integration

The DVBLink Server has a great Remote API [1] and can easily be integrated into third party products. I actually managed to use the existing Plex DVR (Beta) with my DVBLink server using a simple setup with a web server in between to translate the API.

My setup uses an Apache web server listening on ports 80 and 5004. On port 80 I deliver the configuration files (discover.json, lineup_status.json and lineup.json). While these could be built dynamically using the DVBLink Remote API, I am using static versions that I manually created for now. With the channel IDs Plex then builds up the EPG.

For the recordings I use a simple set of pass-through RewriteRules running on port 5004 to map the channels.

RewriteRule    "^/auto/v60.*$"  "http://<DVBLinkServer>:8101/dvblink/direct?channel=10670000"  [P]

Unfortunately, there is still a drawback as I cannot specify any duration for the stream in DVBLink. As such, Plex DVR will just continue and I have to manually stop the recordings.

It would be great if DVBLink Server could be integrated into a future version of Plex DVR, especially as it supports lots of different tuners. However, I do unterstand that during the Beta period you are going to focus on the HDHomeRun product.

[1] http://dvblogic.com/wiki/index.php?title=How_to_write_my_own_DVBLink_client

Hi,

Could you send me your discover.json, lineup_status.json and lineup.json files? I want to work on having these generated automagically, but I can’t find documentation on how they should be structured.

Hi,

Would you be willing to post your setup and the pages to translate?

Cheers
Alex

Hi there,

Unfortunately I didn’t have much time to continue with the setup and writing the translation layer between the two components. I’m still struggling with finding a solution how to stop the recording.

Instead of using the Rewrite approach from above, using Apache, I tried to come up with a small proxy written in Python that could then also do the translation. However, if I just close the stream after the recording duration, the recording fails and is lost. It would be much appreciated if anyone knew how the end of the recording should be signaled to Plex.

Anyway, I have attached the static json files. You probably need to adapt them with additional channels and your URLs. I anonymized the DeviceID and DeviceAuth token, so I hope it is still working.

In the current static setup I use an Apache running a virtualhost on port 80 that distributes the static json files and another virtualhost running on port 5004 with the Rewrite rules from the first post.

1 Like

Many thanks! I will play with it a bit. Why does the tuner stop the recording? …

That sounds strange to me :wink:

I had assumed that Plex asks for the stream,. creates the recording and stops receiving the stream when the program is over. Lets see if I can tweak your code to call the TVH HTSP api, otherwise I will docker-install DVBLink and see tonight how far I come.

Cheers
Alex

@iPhonedation said:
Many thanks! I will play with it a bit. Why does the tuner stop the recording? …

That sounds strange to me :wink:

I had assumed that Plex asks for the stream,. creates the recording and stops receiving the stream when the program is over. Lets see if I can tweak your code to call the TVH HTSP api, otherwise I will docker-install DVBLink and see tonight how far I come.

Cheers
Alex

Please keep us/me updated on this, I’m willing to help out if needed :slight_smile:

Hi,

so I get to the point that I can receive the stream via Chrome from TVH by replicating the ReWriteRule from above… But it does not seem that Plex really saves it.

I will spend some more time on this tomorrow. The EPG looks very promising actually.

What wonders me is the time/duration in the URL call. Does HDHR stop the stream by itself after that time? That would explain the comment from bcyrill.

I will post more when I know more.

Cheers
Alex

I’ve actully started an python proxy implementation, I’ve got it covered as far as discover.json, lineup_status.json and lineup.json goes

I however can’t find an example output of “http://–ip–/lineup.post?scan=start&source=Cable” (change source to whatever is currently in use) to mimic.

Anyone mind shareing?

Do you need the scan? I hacked the tvh-playlist file into a .json in the format (just 3 channels as a test) and it works like a charme to select the region and getting the EPG.

When running the the “DVR setup guide” you get to scan for channels, thats when PMS is requesting that URL

Yes … But you could provide a lineup.json file instead of scanning.

I got it to work. So I just recorded Tagesthemen for a few minutes and it worked flawlessly. The ReWrite to my TVH server just needed to have the user:password@ in front of the URL.

I will program a movie tonight and see how this worked.

@iPhonedation Keep in mind that it will probably just keep recording and not stop, so make sure you have enough disk space.

@iPhonedation said:
Yes … But you could provide a lineup.json file instead of scanning.

I got it to work. So I just recorded Tagesthemen for a few minutes and it worked flawlessly. The ReWrite to my TVH server just needed to have the user:password@ in front of the URL.

I will program a movie tonight and see how this worked.

Yeah, just an typo in my JSON generation. So my proxy properly proxy’s requests TVH<>Plex (channel propergation works), however I can’t seem to get past this screen, hitting continue does nothing.

Will investigate further

EDIT: duh. seems to be an Chrome issue, Edge works

Wow! I hope you will share this little baby with us :slight_smile:

@iPhonedation said:
Wow! I hope you will share this little baby with us :slight_smile:

Sure, will have to work out how to solve delivering the stream properly to Plex (Plex expects the stream to be cut of by the other end, eg. HDHR - http://localhost:5004/auto/v6?duration=4005&transcode=heavy)

Actually, I just recorded a series and it stopped just by itself, no issue at all here on my setup. so i am not sure if this is really required.

Both, with pass or htsp seems to work.

Sep 25, 2016 23:48:54.556 [0x7f7e2e3ba700] DEBUG - Activity: updated activity b1d9f014-a37a-49a9-8bfc-10511ca0badf - completed 99% - Recording Sep 25, 2016 23:50:00.559 [0x7f7e1bffe700] DEBUG - Activity: updated activity b1d9f014-a37a-49a9-8bfc-10511ca0badf - completed 100% - Recording Sep 25, 2016 23:50:09.408 [0x7f7e1bffe700] DEBUG - EPG[onconnect]: Purging 1 airings which completed in the past.

@iPhonedation said:
Actually, I just recorded a series and it stopped just by itself, no issue at all here on my setup. so i am not sure if this is really required.

Both, with pass or htsp seems to work.

Sep 25, 2016 23:48:54.556 [0x7f7e2e3ba700] DEBUG - Activity: updated activity b1d9f014-a37a-49a9-8bfc-10511ca0badf - completed 99% - Recording Sep 25, 2016 23:50:00.559 [0x7f7e1bffe700] DEBUG - Activity: updated activity b1d9f014-a37a-49a9-8bfc-10511ca0badf - completed 100% - Recording Sep 25, 2016 23:50:09.408 [0x7f7e1bffe700] DEBUG - EPG[onconnect]: Purging 1 airings which completed in the past.

Thats good to know. Could you post an full example url of this? "^/auto/v60.$", I’m mostly interested in what comes after v60.

sure:

RewriteEngine on RewriteRule "^/auto/v001.*$" "http://plex:plex@iphnasvdr:9981/stream/channelid/1571866797?ticket=43892B897FAF6465BB31B187B4995EBE931BF622&profile=htsp" RewriteRule "^/auto/v002.*$" "http://plex:plex@iphnasvdr:9981/stream/channelid/1488363555?ticket=291F1CC01F6A395F646B9BD22779780120945882&profile=pass"

while iphnasvdr is the dns name of my qnap where the tvh runs on.

Both work. I took these out of http://tvheadend:9981/playlist which generates a .m3u file. And then manually put them in a apache.conf file that is my vhost.conf for port 5004.

Interesting. It always kept recording here. Will try again tomorrow to see if I can get it to work as well.

I was also playing around with a replacement for the Apache redirect approach with a python proxy that I found on github: https://github.com/abhinavsingh/proxy.py/blob/develop/proxy.py

I had to make the two following changes to modify the request on the fly (It’s a single hardcoded channel for now):

class HttpParser(object):
...
def process_line(self, data):
        line = data.split(SP)
        if self.type == HTTP_REQUEST_PARSER:
            self.method = line[0].upper()
            # for now always record the following hard coded channel
            line[1] = '/dvblink/direct?channel=10670000'

...

class Proxy(multiprocessing.Process):
...
    def _process_request(self, data):
...
            if self.request.method == b"CONNECT":
                host, port = self.request.url.path.split(COLON)
            elif self.request.url:
                # hardcoded host and port
                host, port = '<IP of DVBLink Server>', 8101

Also I just noted that when I was trying to implement the stream to stop, that I forgot to send an empty chunk in the end which apparently in “chunked transfer encoding” signals the end (https://en.wikipedia.org/wiki/Chunked_transfer_encoding).

@jkaberg The full request looks something like this:
[Full request URI: http://192.168.1.211:5004/auto/v2?duration=2990&transcode=heavy]