Project

General

Profile

[SOLVED] Importing VDR recordings

Added by Joerg Knitter about 5 years ago

I just switched from VDR to Tvheadend. I wanted to import my former recordings and therefore did not delete my VDR´s recording partition during the setup. As no code for the automatic import of VDR recordings existed (yet; at least, I was not aware of any), I wrote the following Python script.
It is partially based on the great work of "ullix tv" at https://tvheadend.org/boards/5/topics/28252?r=29113#message-29113.
It parses all subdirectories, searches for the "info" file of each VDR recording and extracts the needed information for registration in Tvheadend. No VDR file is being moved or altered, the original recording files are just "linked":

#!/usr/bin/python
# -*- coding: UTF-8 -*-

""" 
usage: tvh_addfile_vdr.py

registers all found VDR recordings in tvheadend by sending a json formed conf info via http api:
http://user:pass@localhost:9981/api/dvr/entry/create?conf={"enabled": true, "start": 1000, <other json info>}
""" 

import json, urllib, subprocess, datetime, os

for dirPath, dirNames, fileList in os.walk("."):
    for fname in fileList:
        if (fname == 'info'):
            # print(os.path.join(os.path.abspath(dirPath),fname))
            video_storage = os.path.abspath(dirPath) + "/" 
            video_name = "00001.ts" 
            video_path = video_storage + video_name
            video_subtitle = "" 

            with open(video_storage + "info") as file:
                for line in file:
                    entry = line.strip().split(" ",1)
                    if entry[0].lower() == "t":
                        # print("Title: " + entry[1].strip())
                        video_title = entry[1].strip()
                    elif entry[0].lower() == "s":
                        # print("Subtitle: " + entry[1].strip())
                        video_subtitle = entry[1].strip()
                    elif entry[0].lower() == "d":
                        # print("Description: " + entry[1].strip())
                        video_description = entry[1].strip()
                    elif entry[0].lower() == "e":
                        # print("Timer start: " + str((entry[1].strip().split(" "))[1]))
                        # print("Timer length: " + str((entry[1].strip().split(" "))[2]))
                        video_startstmp = int((entry[1].strip().split(" "))[1])
                        video_stopstmp = video_startstmp + int((entry[1].strip().split(" "))[2])
                    elif entry[0].lower() == "c":
                        # print("Channel: " + str((entry[1].strip().split(" ",1))[1]))
                        video_channelname = str((entry[1].strip().split(" ",1))[1])

            print(video_title + " | " + video_subtitle + " (" + video_channelname + ", " + datetime.datetime.fromtimestamp(int(video_startstmp)).strftime('%Y-%m-%d %H:%M:%S') + ")")

            mask = """{
                "enabled": true,
                "start": 1000,
                "stop":  2000,
                "channelname": "local file",
                "title": {
                    "ger": "my title" 
                },
                "subtitle": {
                    "ger": "filename: my video" 
                },
                "description": {
                    "ger": "my description" 
                },
                "comment": "VDR recording",
                "files": [
                    {
                        "filename": "/full/path/to/videofile.ts" 
                    }
                ]
            }""" 
            mask = mask.replace("\n", "")                          # remove the line feeds

            new_mask                         = json.loads(mask)
            new_mask['files'][0]['filename'] = video_path
            new_mask['title']['ger']         = video_title
            new_mask['subtitle']['ger']      = video_subtitle
            new_mask['description']['ger']   = video_description
            new_mask['start']                = video_startstmp
            new_mask['stop']                 = video_stopstmp
            new_mask['channelname']          = video_channelname

            # print "New File Info: \n", json.dumps(new_mask, sort_keys = True, indent = 4)

            api_url     = 'http://tvh_addfile:addfile@localhost:9981/api/dvr/entry/create'
            post        = 'conf=' + json.dumps(new_mask)
            filehandle  = urllib.urlopen(api_url + "?" + post)
            print "Server Answer:", filehandle.read()

Usage:
Simply put this script in the root of your VDR directory (or any subdirectory if you don´t want to import every recording), adjust the username and password in the "api_url" variable and start it (as root) with "./tvh_addfile_vdr.py".
If you want to make a test run, you might change the "video_name" against anything else than "00001.ts" - because Tvheadend then does not find the recording files, the entries then will be listed in the "deleted recordings" tab. Alternatively, you can also add a "#" before the last two lines of the script to just get a list of all found recordings without adding them to Tvheadend.

Notes:
- Tested with Python 2, but might also work with Python 3
- Result tested in the Tvheadend web interface as well as with Kodi on Windows and Linux (LibreElec)
- The script just works with the "info" file used in VDR >1.7.x, not with "info.vdr" or "summary.vdr" of older VDR versions
- It is assumed that the recordings are in TS format and are NOT splitted.
- Be aware that Tvheadend does not delete the "index" and "marks" file when deleting a VDR recording - you will have to delete those files and the directory manually...
- Depending on the access rights on the VDR recordings, Tvheadend might no be able to delete the "00001.ts" recordings. You might have to use something like "sudo chown -R hts:video VDR" for assigning appropriate rights to all VDR files.

And finally;
- Use it at you own risk... ;)


Replies (1)

RE: [SOLVED] Importing VDR recordings - Added by Bernd Meyer over 1 year ago

according to https://sites.google.com/view/pvrlive/tvheadend:

Tvheadend 4.3 changed authentication type to Digest which is only supported from PVR Live 2.0.0 and later. If you are using a previous version make sure authentication type is set to Plain (or Both).

so, to make this python script work, don't forget to set the "Authentication type:" (configuration/general/base) to 'both' or 'plain'

    (1-1/1)