Kodi Community Forum

Full Version: Hellowlol HTPC-Manager fork support thread
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Hi Hellowlol,

I upgraded the Python on my NAS but I'm now getting cherrypy errors on start. Any suggestion what might be causing it?

pyopenssl is deffo installed as sab, headphones, couch are all using the same instance of python.

Code:
2016-04-15 21:06:09 :: root :: INFO :: Welcome to Hellowlol's HTPC Manager fork
2016-04-15 21:06:09 :: root :: INFO :: Loglevel set to debug
2016-04-15 21:06:09 :: htpc.updater :: DEBUG :: Selecting Update engine.
2016-04-15 21:06:09 :: htpc.updater :: DEBUG :: Checking if git is installed
2016-04-15 21:06:09 :: htpc.updater :: DEBUG :: Running git version
2016-04-15 21:06:09 :: htpc.updater :: DEBUG :: Found git path git
2016-04-15 21:06:09 :: htpc.settings :: DEBUG :: Saving settings git_path to the database.
2016-04-15 21:06:09 :: htpc.updater :: INFO :: Using GitUpdater engine
2016-04-15 21:06:09 :: htpc.updater :: DEBUG :: Getting current version.
2016-04-15 21:06:10 :: htpc.updater :: DEBUG :: Running git rev-parse HEAD
2016-04-15 21:06:10 :: htpc.updater :: DEBUG :: Current version: c9db507c6dfab949ff52659180b289dc72d4650c
2016-04-15 21:06:10 :: htpc.updater :: DEBUG :: Running git rev-parse --abbrev-ref HEAD
2016-04-15 21:06:10 :: apscheduler.scheduler :: INFO :: Added job "Updater.update_needed" to job store "default"
2016-04-15 21:06:10 :: modules.kodi :: ERROR :: Invalid server. Selecting first Available.
2016-04-15 21:06:10 :: htpc.settings :: DEBUG :: Saving settings newznab_current_indexer to the database.
2016-04-15 21:06:10 :: apscheduler.scheduler :: DEBUG :: Looking for jobs to run
2016-04-15 21:06:10 :: apscheduler.scheduler :: DEBUG :: Next wakeup is due at 2016-04-16 03:06:10.011449+01:00 (in 21599.974173 seconds)
2016-04-15 21:06:10 :: modules.stats :: ERROR :: Required package 'smartmontools' is not installed, or 'smartctl'
component is not on the system path. Please install and try again.
2016-04-15 21:06:10 :: htpc.server :: DEBUG :: Setting up to start cherrypy
2016-04-15 21:06:10 :: htpc.server :: DEBUG :: Updating cherrypy config, activating sessions and auth
2016-04-15 21:06:10 :: htpc.server :: DEBUG :: There isnt any certificate or key, trying to make them
2016-04-15 21:06:10 :: htpc.helpers :: ERROR :: No module named _openssl
2016-04-15 21:06:10 :: htpc.helpers :: ERROR :: You need pyopenssl and OpenSSL to make a cert
2016-04-15 21:06:10 :: htpc.server :: DEBUG :: SSL is enabled
2016-04-15 21:06:10 :: htpc.server :: INFO :: Starting up webserver
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Listening for SIGHUP.
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Listening for SIGTERM.
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Listening for SIGUSR1.
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Bus STARTING
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE PID 17711 written to '/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/HTPC-Manager.pid'.
2016-04-15 21:06:10 :: cherrypy.error :: ERROR :: [15/Apr/2016:21:06:10] ENGINE Error in 'start' listener <bound method Server.start of <cherrypy._cpserver.Server object at 0xf68eb1ec>>
Traceback (most recent call last):
  File "/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/libs/cherrypy/process/wspbus.py", line 205, in publish
    output.append(listener(*args, **kwargs))
  File "/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/libs/cherrypy/_cpserver.py", line 167, in start
    self.httpserver, self.bind_addr = self.httpserver_from_self()
  File "/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/libs/cherrypy/_cpserver.py", line 158, in httpserver_from_self
    httpserver = _cpwsgi_server.CPWSGIServer(self)
  File "/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/libs/cherrypy/_cpwsgi_server.py", line 64, in __init__
    self.server_adapter.ssl_certificate_chain)
  File "/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/libs/cherrypy/wsgiserver/ssl_pyopenssl.py", line 169, in __init__
    raise ImportError("You must install pyOpenSSL to use HTTPS.")
ImportError: You must install pyOpenSSL to use HTTPS.

2016-04-15 21:06:10 :: cherrypy.error :: ERROR :: [15/Apr/2016:21:06:10] ENGINE Shutting down due to error in start listener:
Traceback (most recent call last):
  File "/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/libs/cherrypy/process/wspbus.py", line 243, in start
    self.publish('start')
  File "/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/libs/cherrypy/process/wspbus.py", line 223, in publish
    raise exc
ChannelFailures: ImportError('You must install pyOpenSSL to use HTTPS.',)

2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Bus STOPPING
2016-04-15 21:06:10 :: apscheduler.scheduler :: INFO :: Scheduler has been shut down
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE HTTP Server None already shut down
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Bus STOPPED
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Bus EXITING
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE PID file removed: '/share/CACHEDEV1_DATA/.qpkg/HTPC-Manager/HTPC-Manager.pid'.
2016-04-15 21:06:10 :: cherrypy.error :: INFO :: [15/Apr/2016:21:06:10] ENGINE Bus EXITED
No really, except from cherrypy failing to import cherrypy. Can you read the issue guidelines on github and open a new issue and I'll look into it.
Hellow should it still display fanart in the background on the now playing window in Kodi?

I'm now using the QNAP package http://forum.qnap.com/viewtopic.php?f=320&t=117760 with PIL embedded so would have thought this would work but I just get the grey background. Was just asking in case this feature was removed?
It seems I have disabled it. I can't remember why, I hust remember that. I added additional options regarding the background image.

I can enable it again
I thought it was a nice touch, would be good to have the option to enable / disable it.

Where are the additional options? I don't seem to be able to spot them anywhere.

Is this also the case for Movie info? I'm sure that had fanart as well.
Sorry, it wasn't that kind of options. It was related to the image how to manipulate it etc. it wasn't intended for public use so it only exist in the image function.

It will be for anything that has fanart
Ah ok, well it's up to you if you chose to enable it again. Would be nice to see it back.
Hi
How to add Jackett (https://github.com/Jackett/Jackett)

Newznab (enable)

API URL:http://ip:port/torznab/indexer-name not working Sad
(2016-04-26, 17:58)krystyan Wrote: [ -> ]Hi
How to add Jackett (https://github.com/Jackett/Jackett)

Newznab (enable)

API URL:http://ip:port/torznab/indexer-name not working Sad

Hi!

It will not work. Jackett are for torrents. The newznab module is for nzbs. If you want to use torrents use the torrent module. I have only included trackers that has a api, the best public trackers and the best movie tracker and TV tracker is included but you need access to them.
Ok. thx
I added now in "Other apps" temporarily.
Hi,

I have managed to get the tvheadend module working again with HTS Tvheadend 4.1-361~gd9cf931.
Still needs a bit of tidying up but at least you can now connect, list recordings, set timers, delete recordings. Need to tidy up the channel list.

Tried Private messaging hellow but wouldn't let me. Code is below (2 file changes). You will also have to uncomment of adding module in main code (Htpc.py).

Hope this helps someone.

Kevin

tvheadend.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cherrypy
import htpc
import logging
import urllib2
import urllib
import base64
import json
from cherrypy.lib.auth2 import require


class TVHeadend(object):
def __init__(self):
self.logger = logging.getLogger('modules.tvheadend')
htpc.MODULES.append({
'name': 'TVHeadend',
'id': 'tvheadend',
'test': htpc.WEBDIR + 'TVHeadend/ping',
'fields': [
{'type': 'bool', 'label': 'Enable', 'name': 'tvheadend_enable'},
{'type': 'text', 'label': 'Menu name', 'name': 'tvheadend_name'},
{'type': 'text', 'label': 'IP / Host *', 'name': 'tvheadend_host'},
{'type': 'text', 'label': 'Port *', 'name': 'tvheadend_port'},
{'type': 'text', 'label': 'Username', 'name': 'tvheadend_username'},
{'type': 'password', 'label': 'Password', 'name': 'tvheadend_password'},
{'type': 'text', 'label': 'Reverse proxy link', 'placeholder': '', 'desc': 'Reverse proxy link, e.g. https://domain.com/tvh', 'name': 'tvheadend_reverse_proxy_link'},

]
})

@cherrypy.expose()
@require()
def index(self):
return htpc.LOOKUP.get_template("tvheadend.html").render(scriptname="tvheadend", webinterface=self.webinterface())

def webinterface(self):
ip = htpc.settings.get('tvheadend_host')
port = htpc.settings.get('tvheadend_port')
url = 'http://%s:%s/' % (ip, port)

if htpc.settings.get('tvheadend_reverse_proxy_link'):
url = htpc.settings.get('tvheadend_reverse_proxy_link')

return url

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def GetEPG(self, strLimit="300", strChannel=""):
return self.fetch("api/epg/events/grid", {'limit': strLimit, 'start': "0", 'channel': strChannel })

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def GetChannels(self):
return self.fetch("api/channel/grid", { 'dir': 'ASC', 'sort': 'tags', 'limit': 1000})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def GetChannelTags(self):
return self.fetch("api/channeltag/list", {'op': 'listTags'})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def DVRAdd(self, strEventID=""):
return self.fetch("api/dvr/entry/create_by_event", {'event_id': strEventID, 'config_uuid': ''})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def DVRDel(self, strEntryID=""):
return self.fetch("api/idnode/delete", {'uuid': strEntryID})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def DVRList(self, strType=""):
return self.fetch("api/dvr/entry/grid_" + strType, None)
#return self.fetch("dvrlist_" + strType, None)

def fetch(self, strQuery, rgpData):
rgpHeaders = {}
username = htpc.settings.get("tvheadend_username", "")
password = htpc.settings.get("tvheadend_password", "")

if username and password:
rgpHeaders['Authorization'] = 'Basic %s' % base64.encodestring('%s:%s' % (username, password)).strip('\n')

# Lame debug to get as much info as possible
self.logger.debug('strQuery: %s' % strQuery)
self.logger.debug('rgpData: %s' % rgpData)

strResponse = None
strData = None

if rgpData is not None:
strData = urllib.urlencode(rgpData)

url = "http://%s:%s/%s" % (htpc.settings.get("tvheadend_host", ""), htpc.settings.get("tvheadend_port", ""), strQuery)
self.logger.debug('url: %s' % url)
self.logger.debug('encoded: %s' % strData)
try:

pRequest = urllib2.Request("http://%s:%s/%s" % (htpc.settings.get("tvheadend_host", ""), htpc.settings.get("tvheadend_port", ""), strQuery), data = strData, headers = rgpHeaders)
strResponse = urllib2.urlopen(pRequest).read()
return json.loads(strResponse)
except Exception as e:
self.logger.error('%s %s failed error: %s' % strQuery, rgpData, e)






tvheadend.js:

function parseJSON(strQuery, pCallback) {
$(".spinner").show();

$.getJSON(WEBDIR + "tvheadend/" + strQuery, function (pResult) {
if (pCallback == null) {
$(".spinner").hide();
return;
}

pCallback(pResult);
$(".spinner").hide();
});
}

function convertTimestamp(nTimestamp) {
var strDate = new Date(nTimestamp * 1000).toString();
return strDate.substring(0, strDate.indexOf(' GMT')); // Strip GMT crap
}

function showEPG(pChannel) {
parseJSON("GetEPG/300/" + pChannel.uuid, function(pResult) {
var strTable = $("<table>").addClass("table table-striped table-hover").append(
$("<tr>").append("<th>Name</th>")
.append("<th>Start</th>")
.append("<th>End</th>")
.append("<th>Actions</th>")
);

$.each(pResult.entries, function(nIndex, pEntry) {
strTable.append($("<tr>")
.append($("<td>").text(pEntry.title))
.append($("<td>").text(convertTimestamp(pEntry.start)))
.append($("<td>").text(convertTimestamp(pEntry.stop)))
.append($("<td>")
.append($("<a>").text("REC").click(function(pEvent) {
pEvent.preventDefault();
parseJSON("DVRAdd/" + pEntry.eventId, null);
}))
));
});

showModal(pChannel.name, strTable,
{
/*'Watch' : function() {
strTable.html("<video controls autoplay>"
+ "<source src=\"http://192.168.1.11:9981/stream/channel/" + pChannel.uuid + "\"></source>"
+ "</video>");
}*/
}
);
});
}

function getChannelTags() {
parseJSON("GetChannelTags", function(pResult) {
$.each(pResult.entries, function(nIndex, pEntry) {
// Add nav tabs
$(".nav.nav-tabs").append($("<li>")
.append($("<a>")
.attr("href", "#tag-" + pEntry.key)
.attr("data-toggle", "tab")
.text(pEntry.val)));

// Add tab pane
var strTabPane = $("<div>").attr("id", "tag-" + pEntry.key)
.attr("class", "tab-pane");

$(".tab-content").append(strTabPane.append($("<ul>").attr("id", "tag-" + pEntry.key + "-grid").attr("class", "thumbnails")));
});
getChannels();
});

$(window).trigger("hashchange");
}

function getChannels() {
parseJSON("GetChannels", function(pResult) {
$.each(pResult.entries, function(nIndex, pEntry) {
var strHTML = $("<div>").attr("class", "channel");
var pHTMLEntry = null;

if (pEntry.icon != undefined) {
pHTMLEntry = $("<img>").attr("src", pEntry.icon);
}
else {
pHTMLEntry = $("<a>").text(pEntry.name);
}

pHTMLEntry.click(function (pEvent) {
showEPG(pEntry);
});

strHTML.append(pHTMLEntry);

$.each(pEntry.tags, function(nIndex, nTag) {
$("#tag-" + nTag + "-grid").append($("<li>").append(strHTML));
});
});
});
}

function parseRecordings(strType) {
var strTable = $("<table>").attr("id", "recordings_" + strType)
.attr("class", "recordingtable")
.append($("<tr>")
.append("<th>Channel</th>")
.append("<th>Title</th>")
.append("<th>Start</th>")
.append("<th>End</th>")
.append("<th>Status</th>")
.append("<th>Actions</th>")
);

parseJSON("DVRList/" + strType, function(pResult) {
$.each(pResult.entries, function(nIndex, pEntry) {
strTable.append($("<tr>").attr("id", "recording-" + pEntry.uuid)
.append($("<td>").text(pEntry.channelname))
.append($("<td>").text(pEntry.disp_title))
.append($("<td>").text(convertTimestamp(pEntry.start)))
.append($("<td>").text(convertTimestamp(pEntry.stop)))
.append($("<td>").text(pEntry.status))
.append($("<td>").append($("<a>").text("DEL").click(function(pEvent) {
pEvent.preventDefault();

parseJSON("DVRDel/" + pEntry.uuid, function(pResult) {
if (pResult.success == 1) {
$("#recording-" + pEntry.uuid).fadeOut();
}
});
})))
);
});
});

$("#recordings").append("<h2>" + strType.charAt(0).toUpperCase() + strType.slice(1) + " recordings</h2>")
.append(strTable);
}

function getRecordings() {
parseRecordings("upcoming");
parseRecordings("finished");
}

$(document).ready(function () {
getChannelTags();
getChannels();
getRecordings();
});
Thats awesome. Can you send a pr on github? What tvheadend version is this tested against?

(2016-05-04, 10:11)kevcompton Wrote: [ -> ]Hi,

I have managed to get the tvheadend module working again with HTS Tvheadend 4.1-361~gd9cf931.
Still needs a bit of tidying up but at least you can now connect, list recordings, set timers, delete recordings. Need to tidy up the channel list.

Tried Private messaging hellow but wouldn't let me. Code is below (2 file changes). You will also have to uncomment of adding module in main code (Htpc.py).

Hope this helps someone.

Kevin

tvheadend.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cherrypy
import htpc
import logging
import urllib2
import urllib
import base64
import json
from cherrypy.lib.auth2 import require


class TVHeadend(object):
def __init__(self):
self.logger = logging.getLogger('modules.tvheadend')
htpc.MODULES.append({
'name': 'TVHeadend',
'id': 'tvheadend',
'test': htpc.WEBDIR + 'TVHeadend/ping',
'fields': [
{'type': 'bool', 'label': 'Enable', 'name': 'tvheadend_enable'},
{'type': 'text', 'label': 'Menu name', 'name': 'tvheadend_name'},
{'type': 'text', 'label': 'IP / Host *', 'name': 'tvheadend_host'},
{'type': 'text', 'label': 'Port *', 'name': 'tvheadend_port'},
{'type': 'text', 'label': 'Username', 'name': 'tvheadend_username'},
{'type': 'password', 'label': 'Password', 'name': 'tvheadend_password'},
{'type': 'text', 'label': 'Reverse proxy link', 'placeholder': '', 'desc': 'Reverse proxy link, e.g. https://domain.com/tvh', 'name': 'tvheadend_reverse_proxy_link'},

]
})

@cherrypy.expose()
@require()
def index(self):
return htpc.LOOKUP.get_template("tvheadend.html").render(scriptname="tvheadend", webinterface=self.webinterface())

def webinterface(self):
ip = htpc.settings.get('tvheadend_host')
port = htpc.settings.get('tvheadend_port')
url = 'http://%s:%s/' % (ip, port)

if htpc.settings.get('tvheadend_reverse_proxy_link'):
url = htpc.settings.get('tvheadend_reverse_proxy_link')

return url

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def GetEPG(self, strLimit="300", strChannel=""):
return self.fetch("api/epg/events/grid", {'limit': strLimit, 'start': "0", 'channel': strChannel })

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def GetChannels(self):
return self.fetch("api/channel/grid", { 'dir': 'ASC', 'sort': 'tags', 'limit': 1000})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def GetChannelTags(self):
return self.fetch("api/channeltag/list", {'op': 'listTags'})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def DVRAdd(self, strEventID=""):
return self.fetch("api/dvr/entry/create_by_event", {'event_id': strEventID, 'config_uuid': ''})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def DVRDel(self, strEntryID=""):
return self.fetch("api/idnode/delete", {'uuid': strEntryID})

@cherrypy.expose()
@require()
@cherrypy.tools.json_out()
def DVRList(self, strType=""):
return self.fetch("api/dvr/entry/grid_" + strType, None)
#return self.fetch("dvrlist_" + strType, None)

def fetch(self, strQuery, rgpData):
rgpHeaders = {}
username = htpc.settings.get("tvheadend_username", "")
password = htpc.settings.get("tvheadend_password", "")

if username and password:
rgpHeaders['Authorization'] = 'Basic %s' % base64.encodestring('%s:%s' % (username, password)).strip('\n')

# Lame debug to get as much info as possible
self.logger.debug('strQuery: %s' % strQuery)
self.logger.debug('rgpData: %s' % rgpData)

strResponse = None
strData = None

if rgpData is not None:
strData = urllib.urlencode(rgpData)

url = "http://%s:%s/%s" % (htpc.settings.get("tvheadend_host", ""), htpc.settings.get("tvheadend_port", ""), strQuery)
self.logger.debug('url: %s' % url)
self.logger.debug('encoded: %s' % strData)
try:

pRequest = urllib2.Request("http://%s:%s/%s" % (htpc.settings.get("tvheadend_host", ""), htpc.settings.get("tvheadend_port", ""), strQuery), data = strData, headers = rgpHeaders)
strResponse = urllib2.urlopen(pRequest).read()
return json.loads(strResponse)
except Exception as e:
self.logger.error('%s %s failed error: %s' % strQuery, rgpData, e)






tvheadend.js:

function parseJSON(strQuery, pCallback) {
$(".spinner").show();

$.getJSON(WEBDIR + "tvheadend/" + strQuery, function (pResult) {
if (pCallback == null) {
$(".spinner").hide();
return;
}

pCallback(pResult);
$(".spinner").hide();
});
}

function convertTimestamp(nTimestamp) {
var strDate = new Date(nTimestamp * 1000).toString();
return strDate.substring(0, strDate.indexOf(' GMT')); // Strip GMT crap
}

function showEPG(pChannel) {
parseJSON("GetEPG/300/" + pChannel.uuid, function(pResult) {
var strTable = $("<table>").addClass("table table-striped table-hover").append(
$("<tr>").append("<th>Name</th>")
.append("<th>Start</th>")
.append("<th>End</th>")
.append("<th>Actions</th>")
);

$.each(pResult.entries, function(nIndex, pEntry) {
strTable.append($("<tr>")
.append($("<td>").text(pEntry.title))
.append($("<td>").text(convertTimestamp(pEntry.start)))
.append($("<td>").text(convertTimestamp(pEntry.stop)))
.append($("<td>")
.append($("<a>").text("REC").click(function(pEvent) {
pEvent.preventDefault();
parseJSON("DVRAdd/" + pEntry.eventId, null);
}))
));
});

showModal(pChannel.name, strTable,
{
/*'Watch' : function() {
strTable.html("<video controls autoplay>"
+ "<source src=\"http://192.168.1.11:9981/stream/channel/" + pChannel.uuid + "\"></source>"
+ "</video>");
}*/
}
);
});
}

function getChannelTags() {
parseJSON("GetChannelTags", function(pResult) {
$.each(pResult.entries, function(nIndex, pEntry) {
// Add nav tabs
$(".nav.nav-tabs").append($("<li>")
.append($("<a>")
.attr("href", "#tag-" + pEntry.key)
.attr("data-toggle", "tab")
.text(pEntry.val)));

// Add tab pane
var strTabPane = $("<div>").attr("id", "tag-" + pEntry.key)
.attr("class", "tab-pane");

$(".tab-content").append(strTabPane.append($("<ul>").attr("id", "tag-" + pEntry.key + "-grid").attr("class", "thumbnails")));
});
getChannels();
});

$(window).trigger("hashchange");
}

function getChannels() {
parseJSON("GetChannels", function(pResult) {
$.each(pResult.entries, function(nIndex, pEntry) {
var strHTML = $("<div>").attr("class", "channel");
var pHTMLEntry = null;

if (pEntry.icon != undefined) {
pHTMLEntry = $("<img>").attr("src", pEntry.icon);
}
else {
pHTMLEntry = $("<a>").text(pEntry.name);
}

pHTMLEntry.click(function (pEvent) {
showEPG(pEntry);
});

strHTML.append(pHTMLEntry);

$.each(pEntry.tags, function(nIndex, nTag) {
$("#tag-" + nTag + "-grid").append($("<li>").append(strHTML));
});
});
});
}

function parseRecordings(strType) {
var strTable = $("<table>").attr("id", "recordings_" + strType)
.attr("class", "recordingtable")
.append($("<tr>")
.append("<th>Channel</th>")
.append("<th>Title</th>")
.append("<th>Start</th>")
.append("<th>End</th>")
.append("<th>Status</th>")
.append("<th>Actions</th>")
);

parseJSON("DVRList/" + strType, function(pResult) {
$.each(pResult.entries, function(nIndex, pEntry) {
strTable.append($("<tr>").attr("id", "recording-" + pEntry.uuid)
.append($("<td>").text(pEntry.channelname))
.append($("<td>").text(pEntry.disp_title))
.append($("<td>").text(convertTimestamp(pEntry.start)))
.append($("<td>").text(convertTimestamp(pEntry.stop)))
.append($("<td>").text(pEntry.status))
.append($("<td>").append($("<a>").text("DEL").click(function(pEvent) {
pEvent.preventDefault();

parseJSON("DVRDel/" + pEntry.uuid, function(pResult) {
if (pResult.success == 1) {
$("#recording-" + pEntry.uuid).fadeOut();
}
});
})))
);
});
});

$("#recordings").append("<h2>" + strType.charAt(0).toUpperCase() + strType.slice(1) + " recordings</h2>")
.append(strTable);
}

function getRecordings() {
parseRecordings("upcoming");
parseRecordings("finished");
}

$(document).ready(function () {
getChannelTags();
getChannels();
getRecordings();
});
Thanks.

Will do, haven't used GitHub much before but will do my best. Done some more testing since posting above, just need to figure out why channels are being duplicated.

I'm running it on a ReadyNas box and the version of tvheadend is 4.1
They are are being duplicated since you don't remove the old content but add new stuff. Try using $(selector).empty()
(2016-05-04, 17:45)hellow Wrote: [ -> ]They are are being duplicated since you don't remove the old content but add new stuff. Try using $(selector).empty()

I've added the latest version to GitHub. Where would you put this code?
The issue is for channels that appear in 2 groups eg both TV Channels and HDTV, so the channel gets processed twice (once per group) but should only appear once in each group.
But this list is being repeat so you get channel 1, channel 2, channel 3, channel 1, channel 2, channel 3.

The code that looks to be wrong is this:

function getChannels() {
parseJSON("GetChannels", function(pResult) {

$.each(pResult.entries, function(nIndex, pEntry) {

$.each(pEntry.tags, function(nIndex, nTag) {

var strHTML = null;

var strHTML = $("<div>").attr("class", "channel");
var pHTMLEntry = null;

if (pEntry.icon != undefined) {
pHTMLEntry = $("<img>").attr("src", pEntry.icon);
}
else {
pHTMLEntry = $("<a>").text(pEntry.name);
}

pHTMLEntry.click(function (pEvent) {
showEPG(pEntry);
});

strHTML.append(pHTMLEntry);

$("#tag-" + nTag + "-grid").append($("<li>").append(strHTML));
});
});
});
}
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19