From d4367e3fc20521235cdfc5e5eb03e7988840e32f Mon Sep 17 00:00:00 2001
From: Britney Fransen <brfransen@gmail.com>
Date: Sun, 17 Sep 2017 23:34:24 +0000
Subject: mythtv: add 29-fixes

---
 .../mythtv/stable-29/git_src/checkout_mythtv.sh    |   40 +
 .../mythtv/stable-29/git_src/checkout_mythweb.sh   |   38 +
 abs/core/mythtv/stable-29/git_src/git_hash         |    1 +
 abs/core/mythtv/stable-29/git_src/git_hash_web     |    1 +
 abs/core/mythtv/stable-29/mythplugins/PKGBUILD     |  121 ++
 .../mythtv/stable-29/mythplugins/cdparanoia.patch  |   52 +
 .../mythplugins/mythburn.py-aspectratio.patch      |  138 ++
 .../mythplugins/mythplugins-mythzoneminder.install |   11 +
 abs/core/mythtv/stable-29/mythtv/PKGBUILD          |  125 ++
 .../stable-29/mythtv/addDamagedToProgDetails.patch |   11 +
 .../mythtv/autoskip_reduce_commskip_jumpback.patch |   13 +
 .../mythtv/stable-29/mythtv/change_msg_types.patch |   20 +
 .../stable-29/mythtv/defaultThemeLinHES.patch      |   11 +
 .../disable_mythnotification_tuner_failure.patch   |   43 +
 .../stable-29/mythtv/menu-xml/HOST_SETTINGS.xml    |  114 ++
 .../stable-29/mythtv/menu-xml/dvd_backup.xml       |   39 +
 abs/core/mythtv/stable-29/mythtv/menu-xml/game.xml |   12 +
 .../mythtv/stable-29/mythtv/menu-xml/info_menu.xml |   76 +
 abs/core/mythtv/stable-29/mythtv/menu-xml/is.xml   |    3 +
 .../mythtv/menu-xml/lh_backend_control.xml         |   24 +
 .../stable-29/mythtv/menu-xml/library.xml.patch    |   25 +
 .../mythtv/stable-29/mythtv/menu-xml/linhes.xml    |   70 +
 .../stable-29/mythtv/menu-xml/linhes_tools.xml     |   31 +
 .../stable-29/mythtv/menu-xml/mainmenu.xml.patch   |   15 +
 .../stable-29/mythtv/menu-xml/mythbackup.xml       |   22 +
 .../stable-29/mythtv/menu-xml/mythrestore.xml      |   24 +
 .../mythtv/menu-xml/optical_menu.xml.patch         |   23 +
 .../mythtv/menu-xml/original/create_patch.sh       |    5 +
 .../stable-29/mythtv/menu-xml/siriusmenu.xml.del   |  419 +++++
 .../mythtv/stable-29/mythtv/menu-xml/update.xml    |   11 +
 .../mythtv/stable-29/mythtv/menu-xml/update2.xml   |   25 +
 .../stable-29/mythtv/menu-xml/xmmenu.xml.del       |  574 ++++++
 .../mythtv/stable-29/mythtv/myth_settings.patch    | 1960 ++++++++++++++++++++
 .../mythtv/mythfrontend_en_us.ts_Title_Case.patch  |  383 ++++
 abs/core/mythtv/stable-29/mythtv/mythtv.install    |   34 +
 abs/core/mythtv/stable-29/mythtv/recordings        |  145 ++
 .../mythtv/searchMetatdataSelectedGrabber.patch    |   18 +
 .../stable-29/mythtv/suggestedstarttime.patch.v1   |   32 +
 .../stable-29/mythtv/videoAlwaysUseBookmark.patch  |   22 +
 abs/core/mythtv/stable-29/mythweb/PKGBUILD         |   58 +
 abs/core/mythtv/stable-29/mythweb/mythweb.include  |    8 +
 abs/core/mythtv/stable-29/mythweb/mythweb.install  |   22 +
 .../stable-29/mythweb/mythweb_gen_light.conf       |    1 +
 43 files changed, 4820 insertions(+)
 create mode 100755 abs/core/mythtv/stable-29/git_src/checkout_mythtv.sh
 create mode 100755 abs/core/mythtv/stable-29/git_src/checkout_mythweb.sh
 create mode 100644 abs/core/mythtv/stable-29/git_src/git_hash
 create mode 100644 abs/core/mythtv/stable-29/git_src/git_hash_web
 create mode 100644 abs/core/mythtv/stable-29/mythplugins/PKGBUILD
 create mode 100644 abs/core/mythtv/stable-29/mythplugins/cdparanoia.patch
 create mode 100644 abs/core/mythtv/stable-29/mythplugins/mythburn.py-aspectratio.patch
 create mode 100644 abs/core/mythtv/stable-29/mythplugins/mythplugins-mythzoneminder.install
 create mode 100644 abs/core/mythtv/stable-29/mythtv/PKGBUILD
 create mode 100644 abs/core/mythtv/stable-29/mythtv/addDamagedToProgDetails.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/autoskip_reduce_commskip_jumpback.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/change_msg_types.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/defaultThemeLinHES.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/disable_mythnotification_tuner_failure.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/HOST_SETTINGS.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/dvd_backup.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/game.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/info_menu.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/is.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/lh_backend_control.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/library.xml.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/linhes.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/linhes_tools.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/mainmenu.xml.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/mythbackup.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/mythrestore.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/optical_menu.xml.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/original/create_patch.sh
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/siriusmenu.xml.del
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/update.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/update2.xml
 create mode 100644 abs/core/mythtv/stable-29/mythtv/menu-xml/xmmenu.xml.del
 create mode 100644 abs/core/mythtv/stable-29/mythtv/myth_settings.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/mythfrontend_en_us.ts_Title_Case.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/mythtv.install
 create mode 100644 abs/core/mythtv/stable-29/mythtv/recordings
 create mode 100644 abs/core/mythtv/stable-29/mythtv/searchMetatdataSelectedGrabber.patch
 create mode 100644 abs/core/mythtv/stable-29/mythtv/suggestedstarttime.patch.v1
 create mode 100644 abs/core/mythtv/stable-29/mythtv/videoAlwaysUseBookmark.patch
 create mode 100644 abs/core/mythtv/stable-29/mythweb/PKGBUILD
 create mode 100644 abs/core/mythtv/stable-29/mythweb/mythweb.include
 create mode 100644 abs/core/mythtv/stable-29/mythweb/mythweb.install
 create mode 100644 abs/core/mythtv/stable-29/mythweb/mythweb_gen_light.conf

diff --git a/abs/core/mythtv/stable-29/git_src/checkout_mythtv.sh b/abs/core/mythtv/stable-29/git_src/checkout_mythtv.sh
new file mode 100755
index 0000000..2ec818e
--- /dev/null
+++ b/abs/core/mythtv/stable-29/git_src/checkout_mythtv.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+#Quick script used to checkout the MythTV source
+#This source should be used build all mythplugins & main program
+
+_gitroot="https://github.com/MythTV/mythtv.git"
+_gitname="mythtv"
+_gitbranch="fixes/29"
+
+startdir=`pwd`
+
+#Set this to True, to update mythtv to the latest.
+#If not true then it will use the hash stored in git_hash
+_current="True"
+
+_checkoutHASH=`cat git_hash`
+
+if [ -d $_gitname ]
+then
+    cd $_gitname
+    git checkout $_gitbranch
+    git pull
+    echo "The local files are updated."
+    cd $startdir
+else
+    git clone -b $_gitbranch $_gitroot
+fi
+
+if [ -d $_gitname ]
+then
+    cd $_gitname
+    if [ $_current == True ]
+    then
+        git rev-parse HEAD > $startdir/git_hash
+    else
+        git checkout $_checkoutHASH
+    fi
+    cd mythtv
+    sh ./version.sh `pwd`
+fi
+echo "GIT checkout done or server timeout"
diff --git a/abs/core/mythtv/stable-29/git_src/checkout_mythweb.sh b/abs/core/mythtv/stable-29/git_src/checkout_mythweb.sh
new file mode 100755
index 0000000..1e8f5bf
--- /dev/null
+++ b/abs/core/mythtv/stable-29/git_src/checkout_mythweb.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+#Quick script used to checkout the Mythweb source
+#This source should be used build all mythplugins & main program
+
+_gitroot="https://github.com/MythTV/mythweb.git"
+_gitname="mythweb"
+_gitbranch="fixes/29"
+
+startdir=`pwd`
+
+#Set this to True, to update mythtv to the latest.
+#If not true then it will use the hash stored in git_hash
+_current="True"
+
+_checkoutHASH=`cat git_hash_web`
+
+if [ -d $_gitname ]
+then
+    cd $_gitname
+    git checkout $_gitbranch
+    git pull
+    echo "The local files are updated."
+    cd $startdir
+else
+    git clone -b $_gitbranch $_gitroot
+fi
+
+if [ -d $_gitname ]
+then
+    cd $_gitname
+    if [ $_current == True ]
+    then
+        git rev-parse HEAD > $startdir/git_hash_web
+    else
+        git checkout $_checkoutHASH
+    fi
+fi
+echo "GIT checkout done or server timeout"
diff --git a/abs/core/mythtv/stable-29/git_src/git_hash b/abs/core/mythtv/stable-29/git_src/git_hash
new file mode 100644
index 0000000..6bc47b4
--- /dev/null
+++ b/abs/core/mythtv/stable-29/git_src/git_hash
@@ -0,0 +1 @@
+5dce69fbb52c03739f9ca379fbb8e7885b45bd95
diff --git a/abs/core/mythtv/stable-29/git_src/git_hash_web b/abs/core/mythtv/stable-29/git_src/git_hash_web
new file mode 100644
index 0000000..96322d1
--- /dev/null
+++ b/abs/core/mythtv/stable-29/git_src/git_hash_web
@@ -0,0 +1 @@
+ece58ebc66872e5a9b6e748f36304bd474d8c902
diff --git a/abs/core/mythtv/stable-29/mythplugins/PKGBUILD b/abs/core/mythtv/stable-29/mythplugins/PKGBUILD
new file mode 100644
index 0000000..646acc0
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythplugins/PKGBUILD
@@ -0,0 +1,121 @@
+pkgbase=mythplugins
+pkgname=('mytharchive'
+         'mythbrowser'
+         'mythgallery'
+         'mythgame'
+         'mythmusic'
+         'mythnetvision'
+         'mythnews'
+         'mythweather'
+         'mythzoneminder')
+pkgver=29
+pkgrel=1
+arch=('i686' 'x86_64')
+url="http://www.mythtv.org"
+license=('GPL')
+makedepends=('cdrkit' 'dcraw' 'dvdauthor' 'dvd+rw-tools' 'ffmpeg' 'flac' 'libexif'
+             'libvorbis' 'mesa' 'libgl' 'mplayer' "mythtv>=${pkgver}"
+             'perl-datetime-format-iso8601' 'perl-date-manip' 'perl-image-size'
+             'perl-json' 'perl-libwww' 'perl-soap-lite' 'perl-xml-sax'
+             'perl-xml-simple' 'perl-xml-xpath' 'python-oauth' 'python2-pillow'
+             'python-pycurl' 'zlib')
+source=('mythburn.py-aspectratio.patch' 'cdparanoia.patch')
+
+build() {
+    if [ -e ${srcdir}/mythplugins ]
+    then
+        msg "Removing old mythplugins src"
+        rm -rf ${srcdir}/mythplugins
+    fi
+
+    cd ${startdir}
+    msg "Copying in mythplugins git_src"
+    cp -rp ../git_src/mythtv/mythplugins $srcdir
+    cd ${srcdir}/${pkgbase}
+
+    msg "Patching configure"
+    patch -Np1 -i "$srcdir/cdparanoia.patch"
+
+    msg "Configuring mythplugins"
+    ./configure --prefix=/usr \
+                --enable-all \
+                --python=/usr/bin/python2
+
+    msg "Compiling mythplugins"
+    qmake-qt5 mythplugins.pro || return 1
+    make || return 1
+}
+
+package_mytharchive() {
+    pkgdesc="Create DVDs or archive recorded shows in MythTV"
+    depends=('cdrkit' 'dvdauthor' 'dvd+rw-tools' 'ffmpeg' "mythtv>=${pkgver}"
+             'm2vrequantiser' 'mjpegtools' 'python2-pillow')
+    optdepends=('projectx: for subtitle support')
+    cd "${srcdir}/${_gitname}/${pkgbase}/mytharchive"
+    patch mythburn/scripts/mythburn.py < $srcdir/mythburn.py-aspectratio.patch || return 1
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythbrowser() {
+    pkgdesc="Mini web browser for MythTV"
+    depends=("mythtv>=${pkgver}")
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythbrowser"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythgallery() {
+    pkgdesc="Image gallery plugin for MythTV"
+    depends=('libexif' "mythtv>=${pkgver}" 'dcraw')
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythgallery"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythgame() {
+    pkgdesc="Game emulator plugin for MythTV"
+    depends=("mythtv>=${pkgver}" 'zlib')
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythgame"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythmusic() {
+    pkgdesc="Music playing plugin for MythTV"
+    depends=('cdparanoia' 'fftw' 'flac' 'libcdaudio' 'libcdio-paranoia' 
+             'libvisual-plugins' 'libvorbis' "mythtv>=${pkgver}" 'taglib')
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythmusic"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythnetvision() {
+    pkgdesc="MythNetvision plugin for MythTV"
+    depends=("mythtv>=${pkgver}" 'python-pycurl' 'python-oauth'
+             'python2-lxml' 'python2')
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythnetvision"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythnews() {
+    pkgdesc="News checking plugin for MythTV"
+    depends=("mythtv>=${pkgver}")
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythnews"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythweather() {
+    pkgdesc="Weather checking plugin for MythTV"
+    depends=("mythtv>=${pkgver}" 'perl-date-manip' 'perl-json' 'perl-soap-lite'
+             'perl-xml-sax' 'perl-xml-simple' 'perl-xml-xpath' 'perl-image-size'
+             'perl-datetime-format-iso8601')
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythweather"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+package_mythzoneminder() {
+    pkgdesc="View CCTV footage from zoneminder in MythTV"
+    depends=("mythtv>=${pkgver}")
+#    install=mythplugins-mythzoneminder.install
+    cd "${srcdir}/${_gitname}/${pkgbase}/mythzoneminder"
+    make INSTALL_ROOT="${pkgdir}" install || return 1
+}
+
+md5sums=('e98c2a09bcb051fdde959fb4bb2e5ab2'
+         '5de8dd79d0b8a2b006f3c3258938b6b7')
diff --git a/abs/core/mythtv/stable-29/mythplugins/cdparanoia.patch b/abs/core/mythtv/stable-29/mythplugins/cdparanoia.patch
new file mode 100644
index 0000000..b4d1449
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythplugins/cdparanoia.patch
@@ -0,0 +1,52 @@
+diff -Nru a/configure b/configure
+--- a/configure	2012-10-02 23:30:24.000000000 +1300
++++ b/configure	2013-01-09 14:54:40.448916370 +1300
+@@ -649,7 +649,7 @@
+         echo "MythMusic requires FLAC."
+     fi
+ 
+-    if ! check_lib cdio/cdio.h cdio_open -lcdio || ! check_lib cdio/cdda.h cdio_cddap_open -lcdio_cdda || ! check_lib cdio/paranoia.h cdio_paranoia_init -lcdio_paranoia ; then
++    if ! check_lib cdio/cdio.h cdio_open -lcdio || ! check_lib cdio/paranoia/cdda.h cdio_cddap_open -lcdio_cdda || ! check_lib cdio/paranoia/paranoia.h cdio_paranoia_init -lcdio_paranoia ; then
+         disable cdio
+     fi
+ 
+diff -Nru a/mythmusic/mythmusic/cddecoder.cpp b/mythmusic/mythmusic/cddecoder.cpp
+--- a/mythmusic/mythmusic/cddecoder.cpp	2012-10-02 23:30:24.000000000 +1300
++++ b/mythmusic/mythmusic/cddecoder.cpp	2013-01-09 14:53:37.031690618 +1300
+@@ -14,7 +14,7 @@
+ #include <QString>
+ 
+ // libcdio
+-#include <cdio/cdda.h>
++#include <cdio/paranoia/cdda.h>
+ #include <cdio/logging.h>
+ 
+ // MythTV
+diff -Nru a/mythmusic/mythmusic/cddecoder.h b/mythmusic/mythmusic/cddecoder.h
+--- a/mythmusic/mythmusic/cddecoder.h	2012-10-02 23:30:24.000000000 +1300
++++ b/mythmusic/mythmusic/cddecoder.h	2013-01-09 14:53:12.328140979 +1300
+@@ -11,8 +11,8 @@
+ #endif
+ 
+ #ifdef HAVE_CDIO
+-# include <cdio/cdda.h>
+-# include <cdio/paranoia.h>
++# include <cdio/paranoia/cdda.h>
++# include <cdio/paranoia/paranoia.h>
+ #endif
+ 
+ class Metadata;
+diff -Nru a/mythmusic/mythmusic/cdrip.cpp b/mythmusic/mythmusic/cdrip.cpp
+--- a/mythmusic/mythmusic/cdrip.cpp	2012-10-02 23:30:24.000000000 +1300
++++ b/mythmusic/mythmusic/cdrip.cpp	2013-01-09 14:54:11.815330268 +1300
+@@ -8,8 +8,8 @@
+ 
+ #include "config.h"
+ #ifdef HAVE_CDIO
+-# include <cdio/cdda.h>
+-# include <cdio/paranoia.h>
++# include <cdio/paranoia/cdda.h>
++# include <cdio/paranoia/paranoia.h>
+ #endif //def HAVE_CDIO
+ 
+ // C++ includes
diff --git a/abs/core/mythtv/stable-29/mythplugins/mythburn.py-aspectratio.patch b/abs/core/mythtv/stable-29/mythplugins/mythburn.py-aspectratio.patch
new file mode 100644
index 0000000..377de95
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythplugins/mythburn.py-aspectratio.patch
@@ -0,0 +1,138 @@
+--- mythburn.py.orig	2013-12-16 22:41:31.532703825 +0000
++++ mythburn.py	2013-12-16 22:40:52.191109409 +0000
+@@ -98,6 +98,7 @@
+ from fcntl import ioctl
+ import CDROM
+ from shutil import copy
++from subprocess import Popen, PIPE
+ 
+ import MythTV
+ from MythTV import datetime
+@@ -440,7 +441,7 @@
+                 os.remove(os.path.join(root, name))
+ 
+ #############################################################
+-# Romoves all the objects from a directory
++# Removes all the objects from a directory
+ 
+ def deleteEverythingInFolder(folder):
+     for root, dirs, files in os.walk(folder, topdown=False):
+@@ -666,14 +667,14 @@
+ # Gets the aspect ratio of a video file from its stream info file
+ 
+ def getAspectRatioOfVideo(index):
+-    """Returns the aspect ratio of the video file (1.333, 1.778, etc)"""
++    """Returns the aspect ratio of the original video file (1.333, 1.778, etc)"""
+ 
+     #open the XML containing information about this file
+-    infoDOM = xml.dom.minidom.parse(os.path.join(getItemTempPath(index), 'streaminfo.xml'))
++    infoDOM = xml.dom.minidom.parse(os.path.join(getItemTempPath(index), 'streaminfo_orig.xml'))
+ 
+     #error out if its the wrong XML
+     if infoDOM.documentElement.tagName != "file":
+-        fatalError("Stream info file doesn't look right (%s)" % os.path.join(getItemTempPath(index), 'streaminfo.xml'))
++        fatalError("Stream info file doesn't look right (%s)" % os.path.join(getItemTempPath(index), 'streaminfo_orig.xml'))
+     video = infoDOM.getElementsByTagName("file")[0].getElementsByTagName("streams")[0].getElementsByTagName("video")[0]
+     if video.attributes["aspectratio"].value != 'N/A':
+         aspect_ratio = float(video.attributes["aspectratio"].value)
+@@ -1695,6 +1696,37 @@
+         fatalError("Failed while running mytharchivehelper to get stream information.\n"
+                    "Result: %d, Command was %s" % (result, command))
+ 
++    #open the XML containing information about this file
++    infoDOM = xml.dom.minidom.parse(xmlFilename)
++    
++    #error out if its the wrong XML
++    if infoDOM.documentElement.tagName != "file":
++        fatalError("This info file doesn't look right (%s)." % xmlFilename)
++    
++    file = infoDOM.getElementsByTagName("file")[0]
++    video = infoDOM.getElementsByTagName("file")[0].getElementsByTagName("streams")[0].getElementsByTagName("video")[0]
++    
++    #use ffmpeg to get display aspect ratio (DAR) of video
++    cmd = "mythffmpeg -i " + quoteCmdArg(file.attributes["filename"].value) + " 2>&1"
++    aspect_ratio = Popen(cmd, shell=True, stdout=PIPE).stdout.read()
++    if "DAR" in aspect_ratio:
++        #clean DAR string
++        aspect_ratio = aspect_ratio.split("DAR ")[-1].split(",")[0]
++        aspect_ratio = ''.join([c for c in aspect_ratio if c in '1234567890:']).split(":")
++    else:
++        #calculate aspect from video size
++        aspect_ratio = getVideoSize(xmlFilename)
++
++    #convert to decimal+
++    aspect_ratio = float(aspect_ratio[0]) / float(aspect_ratio[1])
++
++    write("Video %s aspect ratio is: %s" % (filename, aspect_ratio))
++
++    #set aspect ratio
++    video.setAttribute("aspectratio",str(aspect_ratio))
++    
++    WriteXMLToFile (infoDOM,xmlFilename)
++
+     # print out the streaminfo.xml file to the log
+     infoDOM = xml.dom.minidom.parse(xmlFilename)
+     write(xmlFilename + ":-\n" + infoDOM.toprettyxml("    ", ""), False)
+@@ -2010,7 +2042,7 @@
+ #############################################################
+ # Re-encodes a file to mpeg2
+ 
+-def encodeVideoToMPEG2(source, destvideofile, video, audio1, audio2, aspectratio, profile):
++def encodeVideoToMPEG2(source, destvideofile, video, folder, audio1, audio2, aspectratio, profile):
+     """Encodes an unknown video source file eg. AVI to MPEG2 video and AC3 audio, use mythffmpeg"""
+ 
+     profileNode = findEncodingProfile(profile)
+@@ -2035,6 +2067,35 @@
+             value = quoteCmdArg(destvideofile)
+         if value == "%aspect":
+             value = aspectratio
++        if value == "720x480" or value == "720x576":
++            videores, fps, videoAR = getVideoParams(folder)
++            videoWidth = int(videores.split("x")[0])
++            videoHeight = int(videores.split("x")[1])
++            
++            #add padding to correct for aspects > than 1.9:1
++            if float(videoAR) >= 1.9:
++                #check which video type and set the correct height
++                if videomode == "ntsc":
++                    videoModeHeight = 480
++                else:
++                    videoModeHeight = 576
++ 
++                #calculate the video height based on the aspect ratio of the video
++                #multiply by 1.185 to compensate for dvds non-square pixels
++                calVideoHeight = int(round((720 / float(videoAR)) * 1.185))
++                if calVideoHeight % 2 == 1:
++                    calVideoHeight = calVideoHeight + 1
++                #write("calVideoHeight: %s" % calVideoHeight)
++                
++                #use original video height if the calculated video height is close
++                if (calVideoHeight + 20 < videoHeight) or (calVideoHeight - 20 > videoHeight):
++                     videoHeight = calVideoHeight
++
++                cropPixels = videoModeHeight - videoHeight
++
++                write("Crop Pixels Total: %s" % cropPixels)
++                name = "-vf"
++                value = "\"scale=720:%d, setsar=1:1, pad=720:%d:0:%d:black\"" % (videoModeHeight - cropPixels, videoModeHeight, cropPixels / 2)
+ 
+         # only re-encode the audio if it is not already in AC3 format
+         if audio1[AUDIO_CODEC] == "AC3":
+@@ -4608,7 +4669,7 @@
+ 
+             #do the re-encode 
+             encodeVideoToMPEG2(mediafile, os.path.join(folder, "newfile2.mpg"), video,
+-                            audio1, audio2, aspectratio, profile)
++                            folder, audio1, audio2, aspectratio, profile)
+             mediafile = os.path.join(folder, 'newfile2.mpg')
+ 
+             #remove the old mediafile that was run through mythtranscode
+@@ -4762,7 +4823,7 @@
+ 
+             #do the re-encode 
+             encodeVideoToMPEG2(mediafile, os.path.join(folder, "newfile2.mpg"), video,
+-                            audio1, audio2, aspectratio, profile)
++                            folder, audio1, audio2, aspectratio, profile)
+             mediafile = os.path.join(folder, 'newfile2.mpg')
+ 
+     #remove an intermediate file
diff --git a/abs/core/mythtv/stable-29/mythplugins/mythplugins-mythzoneminder.install b/abs/core/mythtv/stable-29/mythplugins/mythplugins-mythzoneminder.install
new file mode 100644
index 0000000..a4e0c0d
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythplugins/mythplugins-mythzoneminder.install
@@ -0,0 +1,11 @@
+post_install() {
+    . /etc/systemconfig
+    if [ $SystemType = Master_backend -o  $SystemType = Standalone ]
+    then
+        echo "This looks a zoneminder server install"
+        echo "Installing zoneminder"
+        #for reference the pacman statement below will not work because of a db lock.
+        pacman -S zoneminder
+    fi
+
+}
diff --git a/abs/core/mythtv/stable-29/mythtv/PKGBUILD b/abs/core/mythtv/stable-29/mythtv/PKGBUILD
new file mode 100644
index 0000000..feace83
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/PKGBUILD
@@ -0,0 +1,125 @@
+pkgname=mythtv
+pkgver=29
+pkgrel=2
+commit_hash=`cat ../git_src/git_hash`
+pkgdesc="A Homebrew PVR project $commit_hash"
+arch=('i686' 'x86_64')
+url="http://www.mythtv.org/"
+license=('GPL')
+depends=('avahi' 'exiv2' 'faad2' 'fftw' 'glew' 'lame' 'libass' 'libavc1394' 'libcdio'
+         'libcec' 'libgl' 'libcrystalhd-git' 'libiec61883' 'libva' 'libvdpau' 'libvpx'
+         'libx264' 'libxinerama' 'libxml2' 'libxrandr' 'LinHES-config>=8.1-6'
+         'LinHES-system>=8.4-4' 'lirc-utils' 'mysql-clients' 'mysql-python'
+         'openssl' 'perl-date-manip' 'perl-dbd-mysql'
+         'perl-io-socket-inet6' 'perl-libwww' 'perl-math-round'
+         'perl-net-upnp' 'perl-soap-lite' 'perl-xml-sax' 'python2-future'
+         'python2-pycurl' 'python2-requests' 'python2-requests-cache'
+         'python2-lxml' 'qt5-script' 'qt5-webkit' 'sdl' 'taglib' 'unzip' 'urlgrabber'
+         'wget' 'xmltv')
+makedepends=('mesa' 'mesa-libgl' 'yasm' 'x264' 'git' 'rsync' 'qt5-tools')
+replaces=()
+groups=('pvr')
+backup=()
+install='mythtv.install'
+
+patches=(
+         'myth_settings.patch'
+         'videoAlwaysUseBookmark.patch'
+         'autoskip_reduce_commskip_jumpback.patch'
+         'change_msg_types.patch'
+         'disable_mythnotification_tuner_failure.patch'
+         'searchMetatdataSelectedGrabber.patch'
+         'addDamagedToProgDetails.patch'
+         'defaultThemeLinHES.patch'
+         'mythfrontend_en_us.ts_Title_Case.patch'
+         )
+
+optdepends=()
+source=(`echo ${patches[@]:0}` 'recordings')
+
+build() {
+    if [ -e ${srcdir}/mythtv ]
+    then
+        msg "Removing old mythtv src"
+        rm -rf ${srcdir}/mythtv
+    fi
+
+    cd ${startdir}
+    msg "Copying in mythtv git_src"
+    cp -rp ../git_src/mythtv/mythtv $srcdir
+    cd ${srcdir}/$pkgname
+    echo "#!/bin/bash" > version.sh
+
+    msg "--------------------------applying patches------------------------------"
+    for i in `echo ${patches[@]:0}`
+    do
+        echo applying $i
+        patch -Np2  -i ${startdir}/src/$i  || return 1
+        echo "-----------------------------"
+    done
+    msg "--------------------------done applying patches-------------------------"
+
+    msg "Updating translations"
+    cd ${srcdir}/$pkgname/i18n
+    lrelease -removeidentical translate.pro
+    cd ${srcdir}/$pkgname
+
+    msg "Configuring mythtv"
+    ARCH=${CARCH/_/-}
+    #disable mythlogserver due to http://code.mythtv.org/trac/ticket/11230
+    ./configure --prefix=/usr \
+                --cpu=${ARCH} \
+                --disable-altivec \
+                --disable-audio-jack \
+                --disable-audio-pulseoutput \
+                --disable-distcc \
+                --disable-mythlogserver \
+                --dvb-path=/usr/include \
+                --enable-libmp3lame \
+                --enable-libvpx \
+                --enable-libxvid \
+                --enable-libx264 \
+                --enable-sdl \
+                --python=python2 \
+                --with-bindings=perl,python || return 1
+    msg "Compiling mythtv"
+    make all || return 1
+}
+
+package() {
+    cd "${srcdir}/${pkgname}"
+    # basic install
+    make INSTALL_ROOT="${pkgdir}" install
+    # install contrib files
+    rsync -arp --exclude .svn --delete-excluded contrib ${pkgdir}/usr/share/mythtv/ || return 1
+    # install database structure
+    rsync -arp --exclude .svn --delete-excluded database ${pkgdir}/usr/share/mythtv/ || return 1
+    # install docs
+    rsync -arp --exclude .svn --delete-excluded docs ${pkgdir}/usr/share/mythtv/ || return 1
+
+    # patch the xml LinHES style
+    cp -r ${startdir}/menu-xml/*.xml ${pkgdir}/usr/share/mythtv/themes/defaultmenu/
+    cd ${pkgdir}/usr/share/mythtv
+    patch -p0 < ${startdir}/menu-xml/mainmenu.xml.patch || return 1
+    patch -p0 < ${startdir}/menu-xml/optical_menu.xml.patch || return 1
+    patch -p0 < ${startdir}/menu-xml/library.xml.patch || return 1
+
+    # make mythtv log dir for old scripts that use it
+    mkdir -p ${pkgdir}/var/log/mythtv
+    chown 1000.1000 ${pkgdir}/var/log/mythtv
+
+    #install recordings (was pretty)
+    mkdir -p ${pkgdir}/etc/cron.hourly/
+    install -m0755 ${srcdir}/recordings ${pkgdir}/etc/cron.hourly/
+}
+
+md5sums=('fb5a87c52a31168a0c8fdde72f27cc45'
+         '41098e898361a5a3cde3eaae358482a8'
+         '2f983590a8a3cf81f386cc65b9628e13'
+         'f764758832f8e9068ffda1ac0c8aacba'
+         'ab2a31dc29ff325162a4b71b49f0adca'
+         '0f674b9cad031ba1e03aaf6b5ee1499f'
+         '6add9c16bbb988067e82029327e567b2'
+         'b0b238320fa78a4928dce2cea7c85071'
+         'decae343fa612feb6609c65d1fc2ad14'
+         '633cd853a89aeee5388daaad21ccec28')
diff --git a/abs/core/mythtv/stable-29/mythtv/addDamagedToProgDetails.patch b/abs/core/mythtv/stable-29/mythtv/addDamagedToProgDetails.patch
new file mode 100644
index 0000000..828ad1b
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/addDamagedToProgDetails.patch
@@ -0,0 +1,11 @@
+--- src/mythtv/programs/mythfrontend/progdetails.cpp.orig	2016-10-11 14:28:56.564443942 +0000
++++ src/mythtv/programs/mythfrontend/progdetails.cpp	2016-10-11 14:14:59.394161898 +0000
+@@ -323,6 +323,8 @@
+         attr += tr("720p Resolution") + ", ";
+     if  (videoprop & VID_1080)
+         attr += tr("1080i/p Resolution") + ", ";
++    if  (videoprop & VID_DAMAGED)
++        attr += tr("Damaged") + ", ";
+ 
+     if (subtype & SUB_HARDHEAR)
+         attr += tr("CC","Closed Captioned") + ", ";
diff --git a/abs/core/mythtv/stable-29/mythtv/autoskip_reduce_commskip_jumpback.patch b/abs/core/mythtv/stable-29/mythtv/autoskip_reduce_commskip_jumpback.patch
new file mode 100644
index 0000000..b6815ef
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/autoskip_reduce_commskip_jumpback.patch
@@ -0,0 +1,13 @@
+--- src/mythtv/libs/libmythtv/commbreakmap.cpp.orig	2017-03-15 20:34:21.722746111 +0000
++++ src/mythtv/libs/libmythtv/commbreakmap.cpp	2017-03-15 20:35:21.531732684 +0000
+@@ -271,8 +271,8 @@
+     {
+         comm_msg = tr("Skipping Back.");
+ 
+-        if (lastCommSkipStart > (2.0 * video_frame_rate))
+-            lastCommSkipStart -= (long long) (2.0 * video_frame_rate);
++        if (lastCommSkipStart > (video_frame_rate))
++            lastCommSkipStart -= (long) (video_frame_rate);
+         lastCommSkipDirection = 0;
+         lastCommSkipTime = time(NULL);
+         jumpToFrame = lastCommSkipStart;
diff --git a/abs/core/mythtv/stable-29/mythtv/change_msg_types.patch b/abs/core/mythtv/stable-29/mythtv/change_msg_types.patch
new file mode 100644
index 0000000..029dd9a
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/change_msg_types.patch
@@ -0,0 +1,20 @@
+--- src/mythtv/libs/libmythtv/tv_play.cpp.orig	2017-03-15 20:27:51.672833870 +0000
++++ src/mythtv/libs/libmythtv/tv_play.cpp	2017-03-15 20:29:10.646025774 +0000
+@@ -12714,7 +12714,7 @@
+     ctx->UnlockPlayingInfo(__FILE__, __LINE__);
+ 
+     if (!desc.isEmpty())
+-        UpdateOSDSeekMessage(ctx, desc, kOSDTimeout_Med);
++        SetOSDMessage(ctx, desc);
+ }
+ 
+ void TV::SetAutoCommercialSkip(const PlayerContext *ctx,
+@@ -12731,7 +12731,7 @@
+     ctx->UnlockDeletePlayer(__FILE__, __LINE__);
+ 
+     if (!desc.isEmpty())
+-        UpdateOSDSeekMessage(ctx, desc, kOSDTimeout_Med);
++        SetOSDMessage(ctx, desc);
+ }
+ 
+ void TV::SetManualZoom(const PlayerContext *ctx, bool zoomON, QString desc)
diff --git a/abs/core/mythtv/stable-29/mythtv/defaultThemeLinHES.patch b/abs/core/mythtv/stable-29/mythtv/defaultThemeLinHES.patch
new file mode 100644
index 0000000..947176e
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/defaultThemeLinHES.patch
@@ -0,0 +1,11 @@
+--- src/mythtv/libs/libmythui/mythuihelper.h.orig	2016-12-29 16:08:28.319634823 +0000
++++ src/mythtv/libs/libmythui/mythuihelper.h	2016-12-29 16:09:03.245104062 +0000
+@@ -9,7 +9,7 @@
+ #include "mythuiexp.h"
+ #include "themeinfo.h"
+ 
+-#define DEFAULT_UI_THEME "MythCenter"
++#define DEFAULT_UI_THEME "LinHES"
+ #define FALLBACK_UI_THEME "Terra"
+ 
+ class MythUIHelperPrivate;
diff --git a/abs/core/mythtv/stable-29/mythtv/disable_mythnotification_tuner_failure.patch b/abs/core/mythtv/stable-29/mythtv/disable_mythnotification_tuner_failure.patch
new file mode 100644
index 0000000..8e03f24
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/disable_mythnotification_tuner_failure.patch
@@ -0,0 +1,43 @@
+--- src/mythtv/libs/libmythtv/tv_rec.cpp.orig   2017-09-15 21:17:57.761339002 +0000
++++ src/mythtv/libs/libmythtv/tv_rec.cpp        2017-09-15 21:16:22.383499573 +0000
+@@ -3956,19 +3956,6 @@ MPEGStreamData *TVRec::TuningSignalCheck
+             newRecStatus = RecStatus::Failing;
+             curRecording->SaveVideoProperties(VID_DAMAGED, VID_DAMAGED);
+
+-            QString desc = tr("Good signal seen after %1 ms")
+-                           .arg(genOpt.channel_timeout +
+-                        startRecordingDeadline.msecsTo(current_time));
+-            QString title = curRecording->GetTitle();
+-            if (!curRecording->GetSubtitle().isEmpty())
+-                title += " - " + curRecording->GetSubtitle();
+-
+-            MythNotification mn(MythNotification::Check, desc,
+-                                "Recording", title,
+-                                tr("See 'Tuning timeout' in mythtv-setup "
+-                                   "for this input."));
+-            gCoreContext->SendEvent(MythEvent(mn));
+-
+             LOG(VB_GENERAL, LOG_WARNING, LOC +
+                 QString("It took longer than %1 ms to get a signal lock. "
+                         "Keeping status of '%2'")
+@@ -4016,19 +4003,6 @@ MPEGStreamData *TVRec::TuningSignalCheck
+
+         SendMythSystemRecEvent("REC_FAILING", curRecording);
+
+-        QString desc = tr("Taking more than %1 ms to get a lock.")
+-                       .arg(genOpt.channel_timeout);
+-        QString title = curRecording->GetTitle();
+-        if (!curRecording->GetSubtitle().isEmpty())
+-            title += " - " + curRecording->GetSubtitle();
+-
+-        MythNotification mn(MythNotification::Error, desc,
+-                            "Recording", title,
+-                            tr("See 'Tuning timeout' in mythtv-setup "
+-                               "for this input."));
+-        mn.SetDuration(30);
+-        gCoreContext->SendEvent(MythEvent(mn));
+-
+         LOG(VB_GENERAL, LOG_WARNING, LOC +
+             QString("TuningSignalCheck: taking more than %1 ms to get a lock. "
+                     "marking this recording as '%2'.")
+
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/HOST_SETTINGS.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/HOST_SETTINGS.xml
new file mode 100644
index 0000000..c9ec7fa
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/HOST_SETTINGS.xml
@@ -0,0 +1,114 @@
+<mythmenu name="HOST_SETTINGS">
+    <button>
+        <type>MV_ACCESS_SETUP_MENU</type>
+        <text>Access</text>
+        <description>Manage which LinHES Settings can be used</description>
+        <action>EXEC  mythinstall -s accesscontrol </action>
+    </button>
+
+    <button>
+        <type>MV_ADVANCED_SETUP_MENU</type>
+        <text>Advanced</text>
+        <description>Manage various Advanced Settings</description>
+        <action>EXEC  mythinstall -s advanced</action>
+    </button>
+
+    <button>
+        <type>MV_AUDIO_SETUP_MENU</type>
+        <text>Audio</text>
+        <description>Manage Audio drivers, cards &amp; devices</description>
+        <action>EXEC  mythinstall -s sound </action>
+    </button>
+
+    <button>
+        <type>MV_ADVANCED_X_SETUP_MENU</type>
+        <text>Display</text>
+        <description>Set the display resolution</description>
+        <action>EXEC  mythinstall -s advancedX</action>
+    </button>
+
+    <button>
+        <type>MV_NETWORK_SETUP_MENU</type>
+        <text>Dynamic DNS</text>
+        <description>Manage your dyndns.com account</description>
+        <action>EXEC  mythinstall -s ddns </action>
+    </button>
+
+   <button>
+        <type>MV_FILESHARES_MENU</type>
+        <text>File Sharing</text>
+        <description>Manage file sharing via NFS or SMB</description>
+        <action>EXEC  mythinstall -s fileshare</action>
+   </button>
+
+   <button>
+        <type>MV_SYSTEM_SETUP_MENU</type>
+        <text>Host</text>
+        <description>Manage LinHES system type, pointer size &amp; MythWelcome</description>
+        <action>EXEC  mythinstall -s hostype </action>
+   </button>
+
+   <button>
+        <type>MV_MISC_SETUP_MENU</type>
+        <text>Miscellaneous</text>
+        <description>Set timezone, shortcuts &amp; auto updates</description>
+        <action>EXEC  mythinstall -s misc </action>
+   </button>
+
+   <button>
+        <type>MV_NETWORK_SETUP_MENU</type>
+        <text>Network</text>
+        <description>Manage network devices &amp; hostname</description>
+        <action>EXEC  mythinstall -s network </action>
+   </button>
+
+    <button>
+        <type>MV_SOFTWARE_MENU</type>
+        <text>Programs</text>
+        <description>Manage programs for LinHES</description>
+        <action>EXEC  mythinstall -s  plugins,software </action>
+    </button>
+
+   <button>
+        <type>MV_IR_SETUP_MENU</type>
+        <text>Remotes</text>
+        <description>Manage remotes, receivers &amp; blasters</description>
+        <action>EXEC  mythinstall -s ir </action>
+   </button>
+
+   <button>
+        <type>MV_SCREENSAVER_SETUP_MENU</type>
+        <text>Screensaver</text>
+        <description>Manage the Screensaver</description>
+        <action>EXEC  mythinstall -s screensaver </action>
+   </button>
+
+   <button>
+        <type>MV_VNC_SETUP_MENU</type>
+        <text>Screen Sharing</text>
+        <description>Manage VNC and XVNC screen sharing</description>
+        <action>EXEC  mythinstall -s vnc </action>
+   </button>
+
+   <button>
+        <type>MV_SHUTDOWN_SETUP_MENU</type>
+        <text>Shutdown</text>
+        <description>Set when to turn off LinHES</description>
+        <action>EXEC  mythinstall -s sleep </action>
+   </button>
+<!-- disabled in the db so no need to show
+   <button>
+        <type>MV_USER_SETUP_MENU</type>
+        <text>User Accounts</text>
+        <description>Manage Users on LinHES</description>
+        <action>EXEC  mythinstall -s user </action>
+   </button>
+-->
+   <button>
+        <type>MV_WEBACCESS_SETUP_MENU</type>
+        <text>Web Security</text>
+        <description>Manage local website security</description>
+        <action>EXEC  mythinstall -s webuser </action>
+   </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/dvd_backup.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/dvd_backup.xml
new file mode 100644
index 0000000..2647d81
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/dvd_backup.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<mythmenu name="OPTICAL_DISK">
+
+    <button>
+        <type>DVD_RIP</type>
+        <text>Mirror DVD</text>
+        <description>Creates a mirror of your DVD</description>
+	<action>EXEC /usr/LH/bin/ripD_eject.sh m &amp;</action>
+    </button>
+
+    <button>
+        <type>DVD_RIP</type>
+        <text>ISO of DVD</text>
+        <description>Creates an ISO of your DVD</description>
+	<action>EXEC /usr/LH/bin/ripD_eject.sh i &amp;</action>
+    </button>
+
+    <button>
+        <type>DVD_RIP</type>
+        <text>High Quality</text>
+        <description>Creates a high quality MPEG4 of your DVD</description>
+	<action>EXEC /usr/LH/bin/ripD_eject.sh h &amp;</action>
+    </button>
+
+    <button>
+        <type>DVD_RIP</type>
+        <text>Normal Quality</text>
+        <description>Creates a normal quality MPEG4 of your DVD</description>
+	<action>EXEC /usr/LH/bin/ripD_eject.sh n &amp;</action>
+    </button>
+
+    <button>
+        <type>DVD_RIP</type>
+        <text>Low Quality</text>
+        <description>Creates a low quality MPEG4 of your DVD</description>
+	<action>EXEC /usr/LH/bin/ripD_eject.sh l &amp;</action>
+    </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/game.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/game.xml
new file mode 100644
index 0000000..293a9e6
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/game.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<mythmenu name="GAME">
+
+    <button>
+        <type>GAME</type>
+        <text>MythGame</text>
+        <description>Play video games</description>
+        <action>PLUGIN mythgame</action>
+        <depends>mythgame</depends>
+    </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/info_menu.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/info_menu.xml
new file mode 100644
index 0000000..017f90b
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/info_menu.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<mythmenu name="INFO">
+
+    <button>
+        <type>NEWS</type>
+        <text>News Feeds</text>
+        <description>Keep up with the news</description>
+        <action>PLUGIN mythnews</action>
+        <depends>mythnews</depends>
+    </button>
+
+    <button>
+        <type>MYTHTWITTER_TIMELINE</type>
+        <text>Twitter</text>
+        <description>Send and receive tweets</description>
+        <action>JUMP MythTwitter_Timeline</action>
+        <depends>mythtwitter</depends>
+    </button>
+
+    <button>
+        <type>WEATHER</type>
+        <text>Weather</text>
+        <action>PLUGIN mythweather</action>
+        <description>Local weather forecast</description>
+        <depends>mythweather</depends>
+    </button>
+
+    <button>
+       <type>WEATHER</type>
+        <text>Weather Station</text>
+        <action>PLUGIN mythwstation</action>
+        <depends>mythwstation</depends>
+    </button>
+
+    <button>
+        <type>WEBPAGE</type>
+        <text>Web</text>
+        <description>Browse the web</description>
+        <action>PLUGIN mythbrowser</action>
+        <depends>mythbrowser</depends>
+    </button>
+
+    <button>
+        <type>RECIPE</type>
+        <text>Recipes</text>
+        <description>Start cooking!</description>
+        <action>PLUGIN mythRecipe</action>
+        <depends>mythrecipe</depends>
+    </button>
+
+    <button>
+        <type>TV_STATUS</type>
+        <text>System Status</text>
+        <description>See what your system is doing</description>
+        <action>TV_STATUS</action>
+    </button>
+
+    <button>
+        <type>ZONEMINDER</type>
+        <text>ZoneMinder</text>
+        <description>Home surveillance</description>
+        <action>PLUGIN mythzoneminder</action>
+        <depends>mythzoneminder</depends>
+ </button>
+
+<!-- 
+ <button>
+        <type>SMOLT</type>
+        <text>Hardware profile</text>
+        <description>Tell us what hardware you have so we can support it</description>
+        <action>PLUGIN mythsmolt</action>
+        <depends>mythsmolt</depends>
+ </button>
+ -->
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/is.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/is.xml
new file mode 100644
index 0000000..19efc34
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/is.xml
@@ -0,0 +1,3 @@
+<mythmenu name="INTERNET_STREAMS">
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/lh_backend_control.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/lh_backend_control.xml
new file mode 100644
index 0000000..0b0cc17
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/lh_backend_control.xml
@@ -0,0 +1,24 @@
+<mythmenu name="LH_BACKEND">
+
+   <button>
+     <type></type>
+     <text>Start MythBackend</text>
+     <description>Start the Master MythBackend</description>
+     <action>EXEC lh_backend_control.sh start</action>
+   </button>
+
+   <button>
+     <type></type>
+     <text>Stop MythBackend</text>
+     <description>Stop the Master MythBackend</description>
+     <action>EXEC lh_backend_control.sh stop</action>
+   </button>
+
+   <button>
+     <type></type>
+     <text>Restart MythBackend</text>
+     <description>Restart the Master MythBackend</description>
+     <action>EXEC lh_backend_control.sh restart</action>
+   </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/library.xml.patch b/abs/core/mythtv/stable-29/mythtv/menu-xml/library.xml.patch
new file mode 100644
index 0000000..0c0177a
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/library.xml.patch
@@ -0,0 +1,25 @@
+--- themes/defaultmenu/library.xml.orig	2014-11-26 20:21:35.092552944 +0000
++++ themes/defaultmenu/library.xml	2014-11-26 20:22:43.103983263 +0000
+@@ -56,6 +56,13 @@
+     </button>
+ 
+     <button>
++        <type>STREAM</type>
++        <text>Online Content</text>
++        <description>Play content from online sources</description>
++        <action>MENU gen_is.xml</action>
++    </button>
++
++    <button>
+         <type>IMAGES</type>
+         <text>Image Gallery</text>
+         <description>Look at Pictures</description>
+@@ -67,7 +74,7 @@
+         <type>GAME</type>
+         <text>Play Games</text>
+         <description>Play video games</description>
+-        <action>PLUGIN mythgame</action>
++        <action>MENU game.xml</action>
+         <depends>mythgame</depends>
+     </button>
+ 
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/linhes.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/linhes.xml
new file mode 100644
index 0000000..fe7640d
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/linhes.xml
@@ -0,0 +1,70 @@
+<mythmenu name="LH_SERVICE_MENU">
+
+    <button>
+        <type>SETUP_GENERAL</type>
+        <text>MythTV Settings</text>
+        <text lang="IT">Impostazioni</text>
+        <text lang="ES">Configuración</text>
+        <text lang="DE">Zubehör / Konfiguration</text>
+        <text lang="DA">Tilbehør/Indstillinger</text>
+        <text lang="IS">Uppsetning</text>
+        <text lang="NL">Configuratie</text>
+        <text lang="PT">Utensílios</text>
+        <text lang="SV">Verktyg / Inställningar</text>
+        <text lang="JA">設�~Z</text>
+        <text lang="FI">Oheis/Asetukset</text>
+        <text lang="ZH_TW">工�~E�/設�~Z</text>
+        <text lang="SL">Nastavitve</text>
+        <text lang="ET">Utiliidid / sätted</text>
+        <text lang="RU">У�~Bили�~B�~K / �~]а�~A�~B�~@ойки</text>
+        <text lang="AR">تضب�~Jطات</text>
+        <text lang="PL">Narz�~Ydzia / ustawienia</text>
+        <text lang="HE">ע�~Vר�~Y�~] / �~T�~R�~Sר�~Uת</text>
+        <text lang="HU">Eszközök / Beállítások</text>
+        <alttext lang="DE">Verschiedenes</alttext>
+        <alttext lang="SV">Inställningar</alttext>
+        <alttext lang="ET">Sätted</alttext>
+        <alttext lang="RU">�~]а�~A�~B�~@ойки</alttext>
+        <alttext lang="AR">تضب�~Jطات</alttext>
+        <description>Configure MythTV and Plugins</description>
+        <description lang="DE">MythTV und Plugins konfigurieren</description>
+        <action>MENU util_menu.xml</action>
+    </button>
+
+   <button>
+     <type>LINHES_SETUP</type>
+     <text>LinHES Settings</text>
+     <description>Configure the LinHES System</description>
+     <action>MENU HOST_SETTINGS.xml</action>
+   </button>
+
+   <button>
+     <type>TOOLS</type>
+     <text>LinHES Tools</text>
+     <description>Utilities for LinHES System</description>
+     <action>MENU linhes_tools.xml</action>
+   </button>
+
+   <button>
+     <type>BACKUP</type>
+     <text>Backup LinHES</text>
+     <description>Backup the LinHES System</description>
+     <action>MENU mythbackup.xml</action>
+   </button>
+
+   <button>
+     <type>RESTORE</type>
+     <text>Restore LinHES</text>
+     <description>Restore the LinHES System</description>
+     <action>MENU mythrestore.xml</action>
+   </button>
+
+<!--#Check for updates-->
+   <button>
+     <type>UPGRADE</type>
+     <text>Update LinHES</text>
+     <description>Update the LinHES System</description>
+     <action>MENU update.xml</action>
+   </button>
+<!--#Check for updates-->
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/linhes_tools.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/linhes_tools.xml
new file mode 100644
index 0000000..feabe8e
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/linhes_tools.xml
@@ -0,0 +1,31 @@
+<mythmenu name="LH_TOOLS">
+
+   <button>
+     <type></type>
+     <text>Show Help</text>
+     <description>Display the LinHES help screen</description>
+     <action>EXEC mythinstall -H</action>
+   </button>
+
+   <button>
+     <type></type>
+     <text>Toggle Pointer</text>
+     <description>Show/Hide the mouse pointer</description>
+     <action>EXEC unclutter-toggle.sh</action>
+   </button>
+
+   <button>
+     <type></type>
+     <text>MythBackend</text>
+     <description>Start/Stop MythBackend</description>
+     <action>MENU lh_backend_control.xml</action>
+   </button>
+
+   <button>
+     <type></type>
+     <text>MythTV-Setup</text>
+     <description>Open mythtv-setup</description>
+     <action>EXEC mythtv-setup</action>
+   </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/mainmenu.xml.patch b/abs/core/mythtv/stable-29/mythtv/menu-xml/mainmenu.xml.patch
new file mode 100644
index 0000000..3ddce0b
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/mainmenu.xml.patch
@@ -0,0 +1,15 @@
+--- themes/defaultmenu/mainmenu.xml.orig	2014-09-02 20:03:34.658600292 +0000
++++ themes/defaultmenu/mainmenu.xml	2014-09-03 15:49:34.820056829 +0000
+@@ -45,9 +45,9 @@
+ 
+     <button>
+         <type>MENU_UTILITIES_SETUP</type>
+-        <text>Setup</text>
+-        <description>Configure MythTV and plugins</description>
+-        <action>MENU main_settings.xml</action>
++        <text>Service Menu</text>
++        <description>Configure your system</description>
++        <action>MENU linhes.xml</action>
+         <password>SetupPinCode</password>
+     </button>
+ 
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/mythbackup.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/mythbackup.xml
new file mode 100644
index 0000000..176591b
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/mythbackup.xml
@@ -0,0 +1,22 @@
+<mythmenu name="LH_BACKUP">
+   <button>
+     <type>BACKUP</type>
+     <text>Backup Now?</text>
+     <description></description>
+     <action>NONE</action>
+   </button>
+
+   <button>
+     <type>BACKUP</type>
+     <text>Yes</text>
+     <description>Start Backup</description>
+     <action>EXEC sudo /usr/LH/bin/lh_system_backup &amp;</action>
+   </button>
+
+   <button>
+     <type>JUMP_RELOAD_THEME</type>
+     <text>No</text>
+     <description>Return to Main Menu</description>
+     <action>JUMP Reload Theme</action>
+   </button>
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/mythrestore.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/mythrestore.xml
new file mode 100644
index 0000000..d37ba2b
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/mythrestore.xml
@@ -0,0 +1,24 @@
+<mythmenu name="LH_RESTORE">
+
+   <button>
+     <type>RESTORE</type>
+     <text>Restore Now?</text>
+     <description>Restore the database from the most recent backup</description>
+     <action>NONE</action>
+   </button>
+
+   <button>
+     <type>RESTORE</type>
+     <text>Yes</text>
+     <description>Start Restore</description>
+     <action>EXEC sudo /usr/LH/bin/lh_system_restore &amp;</action>
+   </button>
+
+   <button>
+     <type>JUMP_RELOAD_THEME</type>
+     <text>No</text>
+     <description>Return to Main Menu</description>
+     <action>JUMP Reload Theme</action>
+   </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/optical_menu.xml.patch b/abs/core/mythtv/stable-29/mythtv/menu-xml/optical_menu.xml.patch
new file mode 100644
index 0000000..b836e85
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/optical_menu.xml.patch
@@ -0,0 +1,23 @@
+--- themes/defaultmenu/optical_menu.xml.orig	2012-05-02 18:41:38.000000000 +0000
++++ themes/defaultmenu/optical_menu.xml	2012-07-30 05:33:03.000000000 +0000
+@@ -17,6 +17,20 @@
+     </button>
+ 
+     <button>
++        <type>DVD_RIP</type>
++        <text>Backup DVD</text>
++       <description>Backup your DVDs</description>
++        <action>MENU dvd_backup.xml</action>
++    </button>
++
++    <button>
++        <type>DVD_RIP</type>
++        <text>Import Files from DVD</text>
++       <description>Import all files from a data DVD</description>
++        <action>EXEC /usr/LH/bin/importfiles.sh &amp;</action>
++    </button>
++
++    <button>
+         <type>MUSIC_RIP</type>
+         <text>Import CD</text>
+         <description>Import music from an audio CD</description>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/original/create_patch.sh b/abs/core/mythtv/stable-29/mythtv/menu-xml/original/create_patch.sh
new file mode 100644
index 0000000..34d8b8c
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/original/create_patch.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+for i in *.xml
+do
+	diff -u $i.orig $i > ../$i.patch
+done
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/siriusmenu.xml.del b/abs/core/mythtv/stable-29/mythtv/menu-xml/siriusmenu.xml.del
new file mode 100644
index 0000000..e317b36
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/siriusmenu.xml.del
@@ -0,0 +1,419 @@
+<mythmenu name="SIRIUS">
+   <button>
+      <type>MUSIC</type>
+      <text>Sirius Hits 1</text>
+      <action>EXEC /usr/bin/cliSipie siriushits1</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>StarLite</text>
+      <action>EXEC /usr/bin/cliSipie starlite</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Sirius Love</text>
+      <action>EXEC /usr/bin/cliSipie siriuslove</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Movin EZ</text>
+      <action>EXEC /usr/bin/cliSipie movineasy</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Sirius Gold</text>
+      <action>EXEC /usr/bin/cliSipie siriusgold</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>'60s Vibrations</text>
+      <action>EXEC /usr/bin/cliSipie 60svibrations</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Totally '70s</text>
+      <action>EXEC /usr/bin/cliSipie totally70s</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Big '80s</text>
+      <action>EXEC /usr/bin/cliSipie big80s</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>ThePulse</text>
+      <action>EXEC /usr/bin/cliSipie thepulse</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Bridge</text>
+      <action>EXEC /usr/bin/cliSipie thebridge</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>BBC Radio 1</text>
+      <action>EXEC /usr/bin/cliSipie bbcradio1</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Super Shuffle</text>
+      <action>EXEC /usr/bin/cliSipie supershuffle</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Elvis Radio</text>
+      <action>EXEC /usr/bin/cliSipie elvisradio</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Classic Vinyl</text>
+      <action>EXEC /usr/bin/cliSipie classicvinyl</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Classic Rewind</text>
+      <action>EXEC /usr/bin/cliSipie classicrewind</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>TheVault</text>
+      <action>EXEC /usr/bin/cliSipie thevault</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Jam_ON</text>
+      <action>EXEC /usr/bin/cliSipie jamon</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Spectrum</text>
+      <action>EXEC /usr/bin/cliSipie thespectrum</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>BuzzSaw</text>
+      <action>EXEC /usr/bin/cliSipie buzzsaw</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Octane</text>
+      <action>EXEC /usr/bin/cliSipie octane</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Alt Nation</text>
+      <action>EXEC /usr/bin/cliSipie altnation</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>1st Wave</text>
+      <action>EXEC /usr/bin/cliSipie firstwave</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Hair Nation</text>
+      <action>EXEC /usr/bin/cliSipie hairnation</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>'90s Alternative</text>
+      <action>EXEC /usr/bin/cliSipie 90salternative</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Garage</text>
+      <action>EXEC /usr/bin/cliSipie undergroundgarage</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Left of Center</text>
+      <action>EXEC /usr/bin/cliSipie leftofcenter</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Hard Attack</text>
+      <action>EXEC /usr/bin/cliSipie hardattack</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Faction</text>
+      <action>EXEC /usr/bin/cliSipie faction</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Punk</text>
+      <action>EXEC /usr/bin/cliSipie punk</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>The Coffee House</text>
+      <action>EXEC /usr/bin/cliSipie coffeehouse</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Margaritaville</text>
+      <action>EXEC /usr/bin/cliSipie radiomargaritaville</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Sirius Disorder</text>
+      <action>EXEC /usr/bin/cliSipie siriusdisorder</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Reggae</text>
+      <action>EXEC /usr/bin/cliSipie reggaerhythms</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Area 33</text>
+      <action>EXEC /usr/bin/cliSipie area33</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Boombox</text>
+      <action>EXEC /usr/bin/cliSipie boombox</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Chill</text>
+      <action>EXEC /usr/bin/cliSipie chill</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>The Beat</text>
+      <action>EXEC /usr/bin/cliSipie thebeat</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Strobe</text>
+      <action>EXEC /usr/bin/cliSipie thestrobe</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Hip-Hop Nation</text>
+      <action>EXEC /usr/bin/cliSipie hiphopnation</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>BackSpin</text>
+      <action>EXEC /usr/bin/cliSipie backspin</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Shade 45</text>
+      <action>EXEC /usr/bin/cliSipie shade45</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Hot Jamz</text>
+      <action>EXEC /usr/bin/cliSipie hotjamz</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Heart  &amp; Soul</text>
+      <action>EXEC /usr/bin/cliSipie heartandsoul</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>SoulTown</text>
+      <action>EXEC /usr/bin/cliSipie soultown</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>New Country</text>
+      <action>EXEC /usr/bin/cliSipie newcountry</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Prime Country</text>
+      <action>EXEC /usr/bin/cliSipie primecountry</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Roadhouse</text>
+      <action>EXEC /usr/bin/cliSipie theroadhouse</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Outlaw Country</text>
+      <action>EXEC /usr/bin/cliSipie outlawcountry</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Bluegrass</text>
+      <action>EXEC /usr/bin/cliSipie bluegrass</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Spirit</text>
+      <action>EXEC /usr/bin/cliSipie spirit</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Praise</text>
+      <action>EXEC /usr/bin/cliSipie praise</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Planet Jazz</text>
+      <action>EXEC /usr/bin/cliSipie planetjazz</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>JazzCafe</text>
+      <action>EXEC /usr/bin/cliSipie jazzcafe</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>PureJazz</text>
+      <action>EXEC /usr/bin/cliSipie purejazz</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Spa 73</text>
+      <action>EXEC /usr/bin/cliSipie spa73</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Blues</text>
+      <action>EXEC /usr/bin/cliSipie siriusblues</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Siriusly Sinatra</text>
+      <action>EXEC /usr/bin/cliSipie siriuslysinatra</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Broadway's Best</text>
+      <action>EXEC /usr/bin/cliSipie broadwaysbest</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Symphony Hall</text>
+      <action>EXEC /usr/bin/cliSipie symphonyhall</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Met Opera Radio</text>
+      <action>EXEC /usr/bin/cliSipie metropolitanopera</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Sirius Pops</text>
+      <action>EXEC /usr/bin/cliSipie siriuspops</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Universo Latino</text>
+      <action>EXEC /usr/bin/cliSipie universolatino</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Rumbon</text>
+      <action>EXEC /usr/bin/cliSipie rumbon</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Martha Stewart</text>
+      <action>EXEC /usr/bin/cliSipie marthastewartlivingradio</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Sirius Stars</text>
+      <action>EXEC /usr/bin/cliSipie siriusstars</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>OutQ Gay Radio</text>
+      <action>EXEC /usr/bin/cliSipie siriusoutq</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Patriot</text>
+      <action>EXEC /usr/bin/cliSipie siriuspatriot</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Left</text>
+      <action>EXEC /usr/bin/cliSipie siriusleft</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>CNN</text>
+      <action>EXEC /usr/bin/cliSipie cnn</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>wrn</text>
+      <action>EXEC /usr/bin/cliSipie wrn</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Blue Collar Comedy</text>
+      <action>EXEC /usr/bin/cliSipie bluecollarcomedy</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Raw Dog Comedy</text>
+      <action>EXEC /usr/bin/cliSipie rawdog</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Laugh Break Comedy</text>
+      <action>EXEC /usr/bin/cliSipie laughbreak</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>thefoxxhole</text>
+      <action>EXEC /usr/bin/cliSipie thefoxxhole</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>lime</text>
+      <action>EXEC /usr/bin/cliSipie lime</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Kids Stuff</text>
+      <action>EXEC /usr/bin/cliSipie kidsstuff</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Catholic Channel</text>
+      <action>EXEC /usr/bin/cliSipie thecatholicchannel</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>EWTN</text>
+      <action>EXEC /usr/bin/cliSipie ewtnglobal</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>christiantalk</text>
+      <action>EXEC /usr/bin/cliSipie christiantalk</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Sirius NFL Radio</text>
+      <action>EXEC /usr/bin/cliSipie siriusnflradio</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Maxim Radio</text>
+      <action>EXEC /usr/bin/cliSipie maximradio</action>
+   </button>
+   <button>
+      <type>MUSIC</type>
+      <text>Cosmo Radio</text>
+      <action>EXEC /usr/bin/cliSipie cosmopolitanradio</action>
+   </button>
+   <button>
+     <type>TV_DELETE</type>
+     <text>Stop Listening</text>
+     <action>EXEC /usr/bin/sipie_kill</action>
+  </button>
+
+</mythmenu>
+
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/update.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/update.xml
new file mode 100644
index 0000000..2d47e7d
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/update.xml
@@ -0,0 +1,11 @@
+<mythmenu name="LH_UPDATE">
+
+   <button>
+     <type>JUMP Reload Theme</type>
+     <text>Check for Updates</text>
+     <description>Search for LinHES system updates</description>
+     <action>EXEC sudo /usr/LH/bin/linhes_update.sh</action>
+     <action>JUMP Reload Theme</action>
+   </button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/update2.xml b/abs/core/mythtv/stable-29/mythtv/menu-xml/update2.xml
new file mode 100644
index 0000000..4eee8cc
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/update2.xml
@@ -0,0 +1,25 @@
+<mythmenu name="LH_UPDATE">
+
+   <button>
+     <type>UPGRADE</type>
+     <text>Install Updates</text>
+     <description>Install updates for the LinHES system</description>
+     <action>EXEC sudo /usr/LH/bin/linhes_update2.sh install</action>
+     <action>JUMP Reload Theme</action>
+   </button>
+
+   <button>
+     <type>JUMP_RELOAD_THEME</type>
+     <text>Cancel Updates</text>
+     <description>Return to Main Menu</description>
+     <action>EXEC sudo /usr/LH/bin/linhes_update2.sh</action>
+     <action>JUMP Reload Theme</action>
+   </button>
+
+   <button>
+     <type>UPGRADE</type>
+     <text>View Updates</text>
+     <description>Displays the packages to be updated</description>
+     <action>MENU update3.xml</action>
+   </button>
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/menu-xml/xmmenu.xml.del b/abs/core/mythtv/stable-29/mythtv/menu-xml/xmmenu.xml.del
new file mode 100644
index 0000000..6b26d11
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/menu-xml/xmmenu.xml.del
@@ -0,0 +1,574 @@
+<!-- Current as of April 25, 2007 -->
+<mythmenu name="XM">
+
+	<button>
+		<type>MUSIC</type>
+		<text>The '40s</text>
+		<action>EXEC /usr/bin/xamp kill 4</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The '50s</text>
+		<action>EXEC /usr/bin/xamp kill 5</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The '60s</text>
+		<action>EXEC /usr/bin/xamp kill 6</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The '70s</text>
+		<action>EXEC /usr/bin/xamp kill 7</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The '80s</text>
+		<action>EXEC /usr/bin/xamp kill 8</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The '90s</text>
+		<action>EXEC /usr/bin/xamp kill 9</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>America</text>
+		<action>EXEC /usr/bin/xamp kill 10</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>X Country</text>
+		<action>EXEC /usr/bin/xamp kill 12</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Willie's Place</text>
+		<action>EXEC /usr/bin/xamp kill 13</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Bluegrass Junction</text>
+		<action>EXEC /usr/bin/xamp kill 14</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Village</text>
+		<action>EXEC /usr/bin/xamp kill 15</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Highway 16</text>
+		<action>EXEC /usr/bin/xamp kill 16</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>US Country</text>
+		<action>EXEC /usr/bin/xamp kill 17</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>20 on 20</text>
+		<action>EXEC /usr/bin/xamp kill 20</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Heart</text>
+		<action>EXEC /usr/bin/xamp kill 23</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Blend</text>
+		<action>EXEC /usr/bin/xamp kill 25</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Flight 26</text>
+		<action>EXEC /usr/bin/xamp kill 26</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Cinemagic</text>
+		<action>EXEC /usr/bin/xamp kill 27</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>On Broadway</text>
+		<action>EXEC /usr/bin/xamp kill 28</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>U-Pop</text>
+		<action>EXEC /usr/bin/xamp kill 29</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Hitlist</text>
+		<action>EXEC /usr/bin/xamp kill 30</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Torch</text>
+		<action>EXEC /usr/bin/xamp kill 31</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Message</text>
+		<action>EXEC /usr/bin/xamp kill 32</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Spirit</text>
+		<action>EXEC /usr/bin/xamp kill 33</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>enLighten</text>
+		<action>EXEC /usr/bin/xamp kill 34</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Deep Tracks</text>
+		<action>EXEC /usr/bin/xamp kill 40</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Boneyard</text>
+		<action>EXEC /usr/bin/xamp kill 41</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Liquid Metal</text>
+		<action>EXEC /usr/bin/xamp kill 42</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XMU</text>
+		<action>EXEC /usr/bin/xamp kill 43</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Fred</text>
+		<action>EXEC /usr/bin/xamp kill 44</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Cafe</text>
+		<action>EXEC /usr/bin/xamp kill 45</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Top Tracks</text>
+		<action>EXEC /usr/bin/xamp kill 46</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Ethel</text>
+		<action>EXEC /usr/bin/xamp kill 47</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Squizz</text>
+		<action>EXEC /usr/bin/xamp kill 48</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Big Tracks</text>
+		<action>EXEC /usr/bin/xamp kill 49</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Loft</text>
+		<action>EXEC /usr/bin/xamp kill 50</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Music Lab</text>
+		<action>EXEC /usr/bin/xamp kill 51</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Verge</text>
+		<action>EXEC /usr/bin/xamp kill 52</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Fungus</text>
+		<action>EXEC /usr/bin/xamp kill 53</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Lucy</text>
+		<action>EXEC /usr/bin/xamp kill 54</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Soul Street</text>
+		<action>EXEC /usr/bin/xamp kill 60</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Flow</text>
+		<action>EXEC /usr/bin/xamp kill 61</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Suite 62</text>
+		<action>EXEC /usr/bin/xamp kill 62</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Groove</text>
+		<action>EXEC /usr/bin/xamp kill 64</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Rhyme</text>
+		<action>EXEC /usr/bin/xamp kill 65</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>RAW</text>
+		<action>EXEC /usr/bin/xamp kill 66</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The City</text>
+		<action>EXEC /usr/bin/xamp kill 67</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Heat</text>
+		<action>EXEC /usr/bin/xamp kill 68</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Real Jazz</text>
+		<action>EXEC /usr/bin/xamp kill 70</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Watercolors</text>
+		<action>EXEC /usr/bin/xamp kill 71</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Beyond Jazz</text>
+		<action>EXEC /usr/bin/xamp kill 72</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>High Standards</text>
+		<action>EXEC /usr/bin/xamp kill 73</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Bluesville</text>
+		<action>EXEC /usr/bin/xamp kill 74</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Hear Music</text>
+		<action>EXEC /usr/bin/xamp kill 75</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Fine Tuning</text>
+		<action>EXEC /usr/bin/xamp kill 76</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Audio Visions</text>
+		<action>EXEC /usr/bin/xamp kill 77</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Escape</text>
+		<action>EXEC /usr/bin/xamp kill 78</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>On The Rocks</text>
+		<action>EXEC /usr/bin/xamp kill 79</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Move</text>
+		<action>EXEC /usr/bin/xamp kill 80</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>BPM</text>
+		<action>EXEC /usr/bin/xamp kill 81</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The System</text>
+		<action>EXEC /usr/bin/xamp kill 82</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Chrome</text>
+		<action>EXEC /usr/bin/xamp kill 83</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM-Chill</text>
+		<action>EXEC /usr/bin/xamp kill 84</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Fuego</text>
+		<action>EXEC /usr/bin/xamp kill 90</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Viva</text>
+		<action>EXEC /usr/bin/xamp kill 91</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Aguila</text>
+		<action>EXEC /usr/bin/xamp kill 92</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Caliente</text>
+		<action>EXEC /usr/bin/xamp kill 94</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Luna</text>
+		<action>EXEC /usr/bin/xamp kill 95</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Air Musique</text>
+		<action>EXEC /usr/bin/xamp kill 100</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Joint</text>
+		<action>EXEC /usr/bin/xamp kill 101</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Sur La Route</text>
+		<action>EXEC /usr/bin/xamp kill 102</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>World Zone</text>
+		<action>EXEC /usr/bin/xamp kill 103</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Ngoma</text>
+		<action>EXEC /usr/bin/xamp kill 104</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Classics</text>
+		<action>EXEC /usr/bin/xamp kill 110</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Vox</text>
+		<action>EXEC /usr/bin/xamp kill 112</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Pops</text>
+		<action>EXEC /usr/bin/xamp kill 113</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Kids</text>
+		<action>EXEC /usr/bin/xamp kill 116</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Bob Edwards Show</text>
+		<action>EXEC /usr/bin/xamp kill 133</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>XM Comedy</text>
+		<action>EXEC /usr/bin/xamp kill 150</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Laugh USA</text>
+		<action>EXEC /usr/bin/xamp kill 151</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Special X</text>
+		<action>EXEC /usr/bin/xamp kill 154</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Agenda</text>
+		<action>EXEC /usr/bin/xamp kill 134</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Oprah and Friends</text>
+		<action>EXEC /usr/bin/xamp kill 156</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>The Virus</text>
+		<action>EXEC /usr/bin/xamp kill 202</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>1 Hit Wonders</text>
+		<action>EXEC /usr/bin/xamp kill 300</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Metalcore</text>
+		<action>EXEC /usr/bin/xamp kill 301</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>New Indie First</text>
+		<action>EXEC /usr/bin/xamp kill 302</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Late Night Mix</text>
+		<action>EXEC /usr/bin/xamp kill 303</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Sessions@AOL</text>
+		<action>EXEC /usr/bin/xamp kill 304</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>Shuffle</text>
+		<action>EXEC /usr/bin/xamp kill 305</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>New Rock First</text>
+		<action>EXEC /usr/bin/xamp kill 306</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>New Country First</text>
+		<action>EXEC /usr/bin/xamp kill 307</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>New Hip Hop First</text>
+		<action>EXEC /usr/bin/xamp kill 308</action>
+	</button>
+
+	<button>
+		<type>MUSIC</type>
+		<text>New Pop First</text>
+		<action>EXEC /usr/bin/xamp kill 309</action>
+	</button>
+
+	<button>
+		<type>TV_DELETE</type>
+		<text>Stop Listening</text>
+		<action>EXEC /usr/bin/xamp kill</action>
+	</button>
+
+</mythmenu>
diff --git a/abs/core/mythtv/stable-29/mythtv/myth_settings.patch b/abs/core/mythtv/stable-29/mythtv/myth_settings.patch
new file mode 100644
index 0000000..aebff2a
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/myth_settings.patch
@@ -0,0 +1,1960 @@
+commit 0bfb6515f1c6f10d4d9d5d7297ca56a18ac3c138
+Author: James Meyer <james.meyer@operamail.com>
+Date:   Sun Nov 17 18:58:50 2013 -0600
+
+    mythutil updated with myth_settings for .27
+
+diff --git a/mythtv/libs/libmythbase/mythcorecontext.cpp b/mythtv/libs/libmythbase/mythcorecontext.cpp
+index e9cc880..4f7a3bd 100644
+--- a/mythtv/libs/libmythbase/mythcorecontext.cpp
++++ b/mythtv/libs/libmythbase/mythcorecontext.cpp
+@@ -1262,6 +1262,90 @@ void MythCoreContext::ResetLanguage(void)
+     d->language.clear();
+ }
+ 
++//JM ADDED
++void MythCoreContext::savesettings_togroup (QString src_hostname,
++                                            QString saved_settingsgroupname )
++{
++    return d->m_database->savesettings_togroup(src_hostname,
++                                        saved_settingsgroupname);
++}
++
++void MythCoreContext::deletesettings(QString delete_hostname,
++                                     QString saved_settingsgroupname)
++{
++    return d->m_database->deletesettings(delete_hostname,
++                                         saved_settingsgroupname);
++}
++
++QMap<QString,QStringList> MythCoreContext::list_settingsgroupname()
++{
++    return d->m_database->list_settingsgroupname();
++}
++
++QMap<QString,QStringList> MythCoreContext::diff_settingsgroupname(
++    QString diff_hostname1,
++    QString diff_hostname2,
++    QStringList table_list)
++{
++    return d->m_database->diff_settingsgroupname(diff_hostname1,
++                                                 diff_hostname2,
++                                                 table_list);
++}
++
++void MythCoreContext::clonesettings(QString src_hostname,
++                                    QString saved_settingsgroupname,
++                                    QStringList table_list,
++                                    bool is_full_clone,
++                                    QString dest_hostname)
++{
++    return d->m_database->clonesettings(src_hostname,
++                                        saved_settingsgroupname,
++                                        table_list,
++                                        is_full_clone,
++                                        dest_hostname);
++}
++
++void MythCoreContext::restoresettings(QString dest_hostname,
++                                      QString saved_settingsgroupname,
++                                      QStringList table_list )
++{
++    return d->m_database->restoresettings( dest_hostname,
++                                           saved_settingsgroupname,
++                                           table_list);
++}
++
++void MythCoreContext::change_hostname(QString old_hostname,
++                                      QString new_hostname)
++{
++    return d->m_database->change_hostname(old_hostname, new_hostname) ;
++}
++
++bool MythCoreContext::settings_check(QString src_hostname,
++                                     QString saved_settingsgroupname)
++{
++    return d->m_database->settings_check(src_hostname,saved_settingsgroupname);
++}
++
++void MythCoreContext::import_settings(QMap<QString,QString> vp_map,
++                                      QString table)
++{
++    return d->m_database->import_settings(vp_map, table);
++}
++
++
++QMap<QString, QMap<QString,QString> > MythCoreContext::export_settings(
++    QString src_hostname,
++    QString saved_settingsgroupname,
++    QStringList table_list, bool skip_host )
++{
++    return d->m_database->export_settings(src_hostname,
++                                          saved_settingsgroupname,
++                                          table_list , skip_host );
++}
++
++//END JM ADDED
++
++
+ void MythCoreContext::InitLocale(void )
+ {
+     if (!d->m_locale)
+diff --git a/mythtv/libs/libmythbase/mythcorecontext.h b/mythtv/libs/libmythbase/mythcorecontext.h
+index aed83d7..3f0de5e 100644
+--- a/mythtv/libs/libmythbase/mythcorecontext.h
++++ b/mythtv/libs/libmythbase/mythcorecontext.h
+@@ -240,6 +240,39 @@ class MBASE_PUBLIC MythCoreContext : pub
+     void emitTVPlaybackAborted(void)            { emit TVPlaybackAborted(); }
+     void emitTVPlaybackPlaying(void)            { emit TVPlaybackPlaying(); }
+
++    //JM ADDED
++    void savesettings_togroup(QString src_hostname,
++                              QString saved_settingsgroupname );
++
++    void deletesettings(QString delete_hostname,
++                        QString saved_settingsgroupname);
++
++    QMap<QString,QStringList> list_settingsgroupname();
++    QMap<QString,QStringList> diff_settingsgroupname(QString diff_hostname1,
++                                                     QString diff_hostname2,
++                                                     QStringList table_list);
++
++    void clonesettings(QString src_hostname,
++                       QString saved_settingsgroupname,
++                       QStringList table_list,
++                       bool is_full_clone = true,
++                       QString dest_hostname="");
++
++    void restoresettings (QString dest_hostname,
++                          QString saved_settingsgroupname,
++                          QStringList table_list);
++
++    void change_hostname (QString old_hostname, QString new_hostname);
++
++    bool settings_check (QString src_hostname ,QString saved_settingsgroupname);
++    void import_settings(QMap<QString,QString> vp_map, QString table);
++
++    QMap<QString,QMap <QString,QString> > export_settings(
++        QString src_hostname,
++        QString saved_settingsgroupname,
++        QStringList table_list,
++        bool skip_host = false );
++    //END JM ADDED
+
+   signals:
+     void TVPlaybackStarted(void);
+diff --git a/mythtv/libs/libmythbase/mythdb.cpp b/mythtv/libs/libmythbase/mythdb.cpp
+index e60fce0..ed3bdf7 100644
+--- a/mythtv/libs/libmythbase/mythdb.cpp
++++ b/mythtv/libs/libmythbase/mythdb.cpp
+@@ -896,6 +896,1015 @@ void MythDB::WriteDelayedSettings(void)
+     }
+ }
+ 
++//JM ADDED
++void MythDB::savesettings_togroup(QString src_hostname,
++                                  QString saved_settingsgroupname )
++{
++    LOG(VB_GENERAL, LOG_ERR, QString("Using hostname of : %1")
++                                    .arg(src_hostname));
++    LOG(VB_GENERAL, LOG_ERR, QString("Saving to group: %1")
++                                    .arg(saved_settingsgroupname));
++    if ( settings_check( src_hostname , "current" ) )
++    {
++        QStringList table_list;
++        QString hostname_clause;
++        table_list.append("settings");
++        table_list.append("keybindings");
++        table_list.append("jumppoints");
++        if ( src_hostname == "GLOBAL" )
++            hostname_clause = "hostname IS NULL";
++        else
++            hostname_clause ="hostname = :HOSTNAME";
++
++        foreach (QString table, table_list)
++        {
++            QString dest_tablename = table +"_" + saved_settingsgroupname ;
++            create_new_table(dest_tablename,table);
++
++            QString query_string;
++            // Remove old saved values
++            MSqlQuery query(MSqlQuery::InitCon());
++            query_string = QString("DELETE FROM %1 WHERE %2")
++                                   .arg(dest_tablename)
++                                   .arg(hostname_clause);
++
++            //query_string = QString("DELETE FROM %1 WHERE "
++            //                       "hostname = :HOSTNAME").arg(dest_tablename);
++
++            query.prepare(query_string);
++            query.bindValue(":HOSTNAME" ,src_hostname);
++            query.exec();
++
++            //insert all new settings
++            query_string = QString("REPLACE INTO %1 "
++                                   "SELECT  * from %2 where %3")
++                                   .arg(dest_tablename)
++                                   .arg(table)
++                                   .arg(hostname_clause);
++//             query_string = QString("REPLACE INTO %1 "
++//                               "SELECT  * from %2 where  hostname = :HOSTNAME)")
++//                               .arg(dest_tablename)
++//                               .arg(table);
++
++            query.prepare(query_string);
++            query.bindValue(":HOSTNAME",src_hostname);
++            query.exec();
++        }
++    }
++    else
++        LOG(VB_GENERAL| VB_STDIO|VB_FLUSH, LOG_ERR,
++            QString("Couldn't find settings for: %1 \n").arg(src_hostname));
++    return;
++
++};
++
++void MythDB::deletesettings(QString delete_hostname,
++                            QString saved_settingsgroupname)
++{
++    LOG(VB_GENERAL, LOG_ERR, QString("Using hostname of : %1")
++                                    .arg(delete_hostname));
++    LOG(VB_GENERAL, LOG_ERR, QString("Deleting: %1")
++                                    .arg(saved_settingsgroupname));
++    int tempItem;
++    QString src_tablename;
++    QStringList table_list;
++
++    table_list.append("settings");
++    table_list.append("keybindings");
++    table_list.append("jumppoints");
++    QString hostname_clause;
++    if ( delete_hostname == "GLOBAL" )
++        hostname_clause = "hostname IS NULL";
++    else
++        hostname_clause ="hostname = :HOSTNAME";
++
++    foreach (QString table, table_list)
++    {
++        src_tablename = find_group_table_name(table, saved_settingsgroupname);
++        MSqlQuery query(MSqlQuery::InitCon());
++        // Remove old saved values
++        if ( does_table_exist(src_tablename))
++        {
++            QString query_string = QString("DELETE from %1 "
++                                           "WHERE %2")
++                                           .arg(src_tablename)
++                                           .arg(hostname_clause);
++            query.prepare(query_string);
++            query.bindValue(":HOSTNAME" ,delete_hostname);
++            query.exec();
++
++            //check if ok to delete table
++            query_string = QString("SELECT count(*) from %1")
++                                   .arg(src_tablename);
++            query.prepare(query_string);
++            if (query.exec() && query.isActive() && query.size() > 0)
++            {
++                query.next();
++                tempItem = query.value(0).toInt();
++                if (  tempItem == 0 )
++                    drop_temp_table(src_tablename);
++            }
++        }
++        else
++            LOG(VB_GENERAL, LOG_ERR,
++                QString("Couldn't find table: %1").arg(src_tablename));
++    }
++    return;
++}; // end delete settings
++
++
++QMap<QString,QStringList> MythDB::list_settingsgroupname()
++{
++    //Returns a QMAP of  "settings_groups: hostname"
++    MSqlQuery query(MSqlQuery::InitCon());
++    MSqlQuery subquery(MSqlQuery::InitCon());
++    QString tempItem;
++    QString temp_hostnameItem;
++    QStringList hostname_list;
++    QMap<QString,QStringList> return_list;
++    QString full_table_name;
++    query.prepare( "show tables like \"settings%\" " );
++    if (query.exec() && query.isActive() && query.size() > 0)
++    {
++        while (query.next())
++        {
++            full_table_name = query.value(0).toString();
++            tempItem=query.value(0).toString().remove(QRegExp("settings_"));
++            if ( tempItem != "distro_default" )
++            {
++                //loop over tables looking for hostnames
++                QString query_string = QString("SELECT DISTINCT "
++                                               "hostname from %1")
++                                               .arg(full_table_name);
++                subquery.prepare(query_string);
++
++                if (subquery.exec() && subquery.isActive()
++                    && subquery.size() > 0)
++                {
++                    while (subquery.next())
++                    {
++                        temp_hostnameItem = subquery.value(0).toString();
++                        hostname_list.append(temp_hostnameItem);
++                    }
++                }
++                //Special case of naming for the settings table;
++                //This only affects output.
++                if ( tempItem  == "settings" )
++                    return_list["current"] = hostname_list;
++                else
++                    return_list[tempItem] = hostname_list;
++
++                //reset hostname_list for the next group
++                hostname_list = QStringList();
++            }
++        }
++    }
++    return return_list;
++}; // end list_settingsgroupname
++
++QMap<QString,QStringList> MythDB::diff_settingsgroupname(
++            QString diff_hostname1 ,
++            QString diff_hostname2,
++            QStringList table_list  )
++{
++   // Returns a QMAP of tablename : diff results
++    LOG(VB_GENERAL, LOG_ERR, QString("Comparing settings for:"));
++    LOG(VB_GENERAL, LOG_ERR, QString("host 1: %1").arg(diff_hostname1));
++    LOG(VB_GENERAL, LOG_ERR, QString("host 2: %1").arg(diff_hostname2));
++
++    QString qstr;
++    QString tempItem;
++    QString tempString;
++
++    QStringList diff_list;
++    QStringList settings_list;
++    QStringList keybinding_list;
++
++    QMap<QString,QStringList> return_list;
++    if ( table_list.isEmpty() )
++    {
++        table_list.append("settings");
++        table_list.append("keybindings");
++    }
++
++    MSqlQuery query(MSqlQuery::InitCon());
++    foreach (QString table, table_list)
++    {
++        if ( table == "settings")
++        {
++
++            qstr= "SELECT  distinct settings.value, :DIFF_HOSTNAME1 AS `hostname`, settings_a.data, :DIFF_HOSTNAME2 AS `hostname`"
++                  " , settings_b.data FROM settings LEFT JOIN settings AS settings_a ON settings_a.value = settings.value AND settings_a.hostname = :DIFF_HOSTNAME1"
++                  " LEFT JOIN settings AS settings_b ON settings_b.value = settings.value AND settings_b.hostname = :DIFF_HOSTNAME2"
++                  " WHERE settings_a.data != settings_b.data OR "
++                  " (settings_a.data IS NULL AND settings_b.data IS NOT NULL) OR (settings_a.data IS NOT NULL AND settings_b.data IS NULL);";
++
++            query.prepare(qstr);
++            query.bindValue(":DIFF_HOSTNAME1" , diff_hostname1);
++            query.bindValue(":DIFF_HOSTNAME2" , diff_hostname2);
++
++            if (query.exec() && query.isActive() && query.size() > 0)
++            {
++                while (query.next())
++                {
++                    tempString="";
++                    //value
++                    tempItem = query.value(0).toString();
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //hostname_1
++                    tempItem = query.value(1).toString();
++                    if (tempItem.isEmpty())
++                        tempItem=diff_hostname1;
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //data
++                    tempItem = query.value(2).toString();
++                    if (tempItem.isEmpty())
++                        tempItem="NULL";
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //hostname_2
++                    tempItem = query.value(3).toString();
++                    if (tempItem.isEmpty())
++                        tempItem=diff_hostname2;
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //data
++                    tempItem = query.value(4).toString();
++                    if (tempItem.isEmpty())
++                        tempItem="NULL";
++                    tempString.append(tempItem);
++
++                    settings_list.append(tempString);
++                }
++                return_list["Settings"] = settings_list;
++            }
++        }
++        else if ( table == "keybindings")
++        {
++
++            qstr="SELECT distinct  keybindings.context, keybindings.action, :DIFF_HOSTNAME1 AS `hostname`, keybindings_a.keylist, :DIFF_HOSTNAME2 AS `hostname`, keybindings_b.keylist FROM keybindings "
++                 " LEFT JOIN keybindings AS keybindings_a ON keybindings_a.context = keybindings.context AND keybindings_a.action = keybindings.action "
++                 " AND keybindings_a.hostname = :DIFF_HOSTNAME1 "
++                 " LEFT JOIN keybindings AS keybindings_b ON keybindings_b.context = keybindings.context "
++                 " AND keybindings_b.action = keybindings.action AND keybindings_b.hostname = :DIFF_HOSTNAME2 "
++                 " WHERE keybindings_a.keylist != keybindings_b.keylist OR "
++                 " (keybindings_a.keylist IS NULL AND keybindings_b.keylist IS NOT NULL) OR (keybindings_a.keylist IS NOT NULL AND keybindings_b.keylist IS NULL);";
++            query.prepare(qstr);
++            query.bindValue(":DIFF_HOSTNAME1" , diff_hostname1);
++            query.bindValue(":DIFF_HOSTNAME2" , diff_hostname2);
++
++            if (query.exec() && query.isActive() && query.size() > 0)
++            {
++                while (query.next())
++                {
++                    tempString="";
++                    //context
++                    tempItem = query.value(0).toString();
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //action
++                    tempItem = query.value(1).toString();
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //hostname
++                    tempItem = query.value(2).toString();
++                    if (tempItem.isEmpty())
++                        tempItem=diff_hostname1;
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //keylist
++                    tempItem = query.value(3).toString();
++                    if (tempItem.isEmpty())
++                        tempItem="NULL";
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //hostname
++                    tempItem = query.value(4).toString();
++                    if (tempItem.isEmpty())
++                        tempItem=diff_hostname2;
++                    tempString.append(tempItem);
++                    tempString.append("|");
++
++                    //keylist
++                    tempItem = query.value(5).toString();
++                    if (tempItem.isEmpty())
++                       tempItem="NULL";
++                    tempString.append(tempItem);
++                    keybinding_list.append(tempString);
++                }
++                return_list["Keybindings"] = keybinding_list;
++            }
++        }
++
++    }
++    return return_list;
++}; //end diff_settingsgroupname
++
++void MythDB::clonesettings(QString src_hostname,
++                           QString saved_settingsgroupname,
++                           QStringList table_list,
++                           bool is_full_clone, QString dest_hostname)
++{
++    LOG(VB_GENERAL, LOG_ERR, QString("Using src hostname of : %1")
++                                     .arg(src_hostname));
++    LOG(VB_GENERAL, LOG_ERR, QString("Using dest hostname of : %1")
++                                     .arg(dest_hostname));
++    LOG(VB_GENERAL, LOG_ERR, QString("Cloning setting group: %1")
++                                     .arg(saved_settingsgroupname));
++    LOG(VB_GENERAL, LOG_ERR, QString("Full Copy : %1")
++                                     .arg(is_full_clone));
++
++    MSqlQuery query(MSqlQuery::InitCon());
++    QStringList::Iterator it;
++    QString current_table;
++    QString dest_tablename;
++    QString temptable;
++
++    if ( table_list.isEmpty() )
++    {
++        table_list.append("settings");
++        table_list.append("keybindings");
++        table_list.append("jumppoints");
++    }
++
++    for ( it = table_list.begin(); it != table_list.end(); ++it )
++    {
++        current_table = *it ;
++        dest_tablename = find_group_table_name(current_table,
++                                               saved_settingsgroupname);
++
++        if ( does_table_exist(dest_tablename))
++        {
++            // create temp table for merging settings
++            temptable="temp_table_" + dest_tablename;
++            create_temp_table(temptable, current_table );
++
++            // copy in stored settings
++            QString query_string = QString("REPLACE INTO %1 "
++                             "(SELECT  * from %2 where  hostname = :HOSTNAME)")
++                             .arg(temptable)
++                             .arg(dest_tablename);
++
++            query.prepare(query_string);
++            query.bindValue(":HOSTNAME",src_hostname );
++            query.exec();
++
++            // update hostname for dest_hostname
++            query_string = QString("UPDATE   %1 set hostname = :HOSTNAME")
++                                   .arg(temptable);
++
++            query.prepare(query_string);
++            query.bindValue(":HOSTNAME" , dest_hostname );
++            query.exec();
++
++            //if not full clone remove HOST% settings from temp table;
++            if ( current_table == "settings" && !is_full_clone)
++            {
++                query_string = QString("DELETE FROM %1 WHERE "
++                                 "hostname=:HOSTNAME and value like 'HOST%' " )
++                                 .arg(temptable);
++
++                query.prepare(query_string);
++                query.bindValue( ":HOSTNAME" ,   dest_hostname  );
++                query.exec();
++            }
++
++            //remove current settings from dest table,
++            //if not full clone, then leave HOST%
++            //Need to remove because the old table allows for duplicates
++
++            if ( current_table == "settings" && !is_full_clone)
++                query_string = QString ("DELETE FROM %1 WHERE "
++                                        "hostname = :HOSTNAME "
++                                        "and value not like 'HOST%'")
++                                        .arg(dest_tablename);
++
++            else
++                query_string = QString ("DELETE FROM %1 WHERE "
++                                        "hostname = :HOSTNAME ")
++                                        .arg(dest_tablename);
++
++            query.prepare(query_string);
++            query.bindValue(":HOSTNAME",dest_hostname);
++            query.exec();
++
++            // copy new settings from temp to current
++            query_string = QString("REPLACE INTO %1 "
++                                   "(SELECT  * from %2)")
++                                   .arg(dest_tablename)
++                                   .arg(temptable);
++
++            query.prepare(query_string);
++            query.exec();
++
++            // drop temptable
++            drop_temp_table(temptable);
++        }
++        else
++            LOG(VB_GENERAL, LOG_NOTICE, QString("Couldn't find table: %1")
++                                                .arg(dest_tablename));
++    }
++}; //end clonesettings
++
++void MythDB::restoresettings (QString dest_hostname,
++                              QString saved_settingsgroupname,
++                              QStringList table_list )
++{
++    LOG(VB_GENERAL, LOG_NOTICE, QString("Restoring Settings:"));
++    LOG(VB_GENERAL, LOG_NOTICE, QString("    src: %1")
++                                        .arg(saved_settingsgroupname));
++    LOG(VB_GENERAL, LOG_NOTICE, QString("    dest:%1")
++                                        .arg(dest_hostname));
++
++    QString hostname_clause;
++    if ( dest_hostname == "GLOBAL" )
++        hostname_clause = "hostname IS NULL";
++    else
++        hostname_clause ="hostname = :HOSTNAME";
++
++    bool table_check;
++    if ( saved_settingsgroupname == "distro_default" )
++        table_check =  settings_check ( "distro_default" , saved_settingsgroupname );
++    else
++        table_check = settings_check ( dest_hostname , saved_settingsgroupname );
++
++
++    if ( table_check == true )
++    {
++        MSqlQuery query(MSqlQuery::InitCon());
++        QStringList::Iterator it;
++        QString current_table;
++        if ( table_list.isEmpty() )
++        {
++            table_list.append("settings");
++            table_list.append("keybindings");
++            table_list.append("jumppoints");
++        }
++
++        for ( it = table_list.begin(); it != table_list.end(); ++it )
++        {
++            current_table = *it ;
++            //find tablenames to use
++            QString src_tablename = find_group_table_name(current_table,
++                                         saved_settingsgroupname);
++
++            QString temptable="temp_table_" + src_tablename;
++            if ( ! does_table_exist(src_tablename))
++            {
++                LOG(VB_GENERAL, LOG_NOTICE, QString("table does not exist: %1")
++                        .arg(src_tablename));
++                continue;
++            }
++            // create temp table for merging settings
++            create_temp_table(temptable, current_table );
++
++            //could copy in current settings here to account for new stuff
++
++
++
++            // copy in stored settings
++            QString query_string;
++            if ( saved_settingsgroupname == "distro_default" )
++            {  //special case for restoring default settings
++                query_string = QString("REPLACE INTO %1 "
++                    "(SELECT  * from %2 WHERE %3)")
++                    .arg(temptable)
++                    .arg(src_tablename)
++                    .arg(hostname_clause);
++
++                query.prepare(query_string);
++                query.bindValue(":HOSTNAME", "distro_default" );
++                query.exec();
++
++                // update hostname in temp table from distro_default
++                query_string = QString("UPDATE  %1 set hostname = :HOSTNAME")
++                                       .arg(temptable);
++
++                query.prepare(query_string);
++                query.bindValue(":HOSTNAME" , dest_hostname );
++                query.exec();
++
++            }
++            else
++            {   //normal use case
++                query_string = QString("REPLACE INTO %1 "
++                                "(SELECT  * from %2 WHERE %3)")
++                                .arg(temptable)
++                                .arg(src_tablename)
++                                .arg(hostname_clause);
++
++                query.prepare(query_string);
++                query.bindValue(":HOSTNAME",dest_hostname );
++                query.exec();
++            }
++
++            //Remove current settings.
++            //Need to remove because the old table allows for duplicates
++            query_string = QString("DELETE FROM %1 WHERE "
++                                   "%2")
++                                   .arg(current_table)
++                                   .arg(hostname_clause);
++
++            query.prepare(query_string);
++            query.bindValue(":HOSTNAME",dest_hostname);
++            query.exec();
++
++            // copy new settings from temp to current
++            query_string = QString("REPLACE INTO %1 "
++                                   "(SELECT  * from %2)")
++                                   .arg(current_table)
++                                   .arg(temptable);
++
++            query.prepare(query_string);
++            query.exec();
++            // drop temptable
++            drop_temp_table(temptable);
++        }
++    }
++}; //end restore settings
++
++void MythDB::change_hostname (QString old_hostname, QString new_hostname)
++{
++    LOG(VB_GENERAL, LOG_NOTICE, QString("Changing hostname from %1 -> %2")
++                                        .arg(old_hostname)
++                                        .arg(new_hostname));
++
++    MSqlQuery query(MSqlQuery::InitCon());
++    MSqlQuery sub_query(MSqlQuery::InitCon());
++    query.prepare( "SHOW TABLES" );
++
++    if (query.exec() && query.isActive() && query.size() > 0)
++    {
++        while (query.next())
++        {
++            QString table_name = query.value(0).toString();
++            LOG(VB_GENERAL, LOG_NOTICE, QString("Scanning  %1")
++                                                .arg(table_name));
++
++            // LOOP OVER TABLES, CHECK IF IT HAS A HOSTNAME FIELD
++            QString query_string=QString("SHOW COLUMNS from %1 "
++                                         "where field='hostname'")
++                                         .arg(table_name);
++            sub_query.prepare(query_string);
++
++            if (sub_query.exec() && sub_query.size() > 0)
++            {  //update hostname
++               LOG(VB_GENERAL, LOG_NOTICE, QString("  Updating hostname in: %1")
++                                                   .arg(table_name));
++               query_string = QString("UPDATE %1 SET hostname = :NEW_HOSTNAME "
++                               "WHERE hostname = :OLD_HOSTNAME")
++                               .arg(table_name);
++               sub_query.prepare(query_string);
++               sub_query.bindValue(":NEW_HOSTNAME" , new_hostname);
++               sub_query.bindValue(":OLD_HOSTNAME" , old_hostname);
++               sub_query.exec();
++            }
++        }
++    }
++
++
++
++
++
++
++}
++
++bool MythDB::settings_check(QString src_hostname,
++                            QString saved_settingsgroupname)
++{
++    int tempItem;
++    bool returncode = false ;
++    QString table="settings";
++
++    QString tablename = find_group_table_name(table, saved_settingsgroupname);
++    QString hostname_clause;
++    if ( src_hostname == "GLOBAL" )
++        hostname_clause = "hostname IS NULL";
++    else
++        hostname_clause ="hostname = :HOSTNAME";
++
++    if (does_table_exist (tablename))
++    {
++        MSqlQuery query(MSqlQuery::InitCon());
++        QString query_string = QString("SELECT COUNT(data) from %1 "
++                                       "WHERE %2")
++                                       .arg(tablename)
++                                       .arg(hostname_clause);
++
++        query.prepare(query_string);
++        query.bindValue(":HOSTNAME" , src_hostname );
++
++        if (query.exec() && query.isActive() && query.size() > 0 )
++        {
++            while (query.next())
++            {
++                 tempItem = query.value(0).toInt();
++                 if (  tempItem >= 1 )
++                     returncode = true;
++                 else
++                 {
++                     LOG(VB_GENERAL, LOG_NOTICE,
++                         QString("Group %1 does not contain"
++                                 " valid settings")
++                                 .arg(saved_settingsgroupname));
++                 }
++             }
++        }
++    }
++    else
++       LOG(VB_GENERAL, LOG_NOTICE, QString("Couldn't find table: %1")
++                                           .arg(tablename));
++    return returncode;
++}; // end settings_check
++
++void MythDB::import_settings(QMap<QString,QString> vp_map,
++                             QString table)
++{
++    MSqlQuery query(MSqlQuery::InitCon());
++
++    //IMPORT SETTINGS TABLE
++    if (table.startsWith("settings"))
++    {
++         if ( table != "settings" )
++             create_new_table(table,"settings");
++         QString hostname = vp_map.value("hostname");
++         QString value = vp_map.value("value");
++         QString data = vp_map.value("data");
++
++         QString hostname_clause;
++         QVariant import_hostname = QVariant(QVariant::String);
++
++         if ( hostname.isEmpty())
++             hostname_clause = "hostname IS NULL";
++         else
++         {
++             hostname_clause ="hostname = :HOSTNAME";
++             import_hostname = hostname;
++         }
++
++         QString query_string=QString("SELECT  value, data, hostname "
++                              "FROM %1 "
++                              "WHERE %2 AND value = :VALUE "
++                              "ORDER BY value")
++                              .arg(table)
++                              .arg(hostname_clause);
++
++         query.prepare(query_string);
++         query.bindValue(":HOSTNAME", hostname);
++         query.bindValue(":VALUE", value);
++
++         // if already exisiting records then update, otherwise insert
++         if (query.exec() && query.isActive())
++         {
++            MSqlQuery sub_query(MSqlQuery::InitCon());
++            if ( query.size() > 0 )
++            {
++                query_string = QString("UPDATE  "
++                    "%1 "
++                    "set data = :DATA "
++                    "WHERE %2 AND "
++                    "value = :VALUE ")
++                    .arg(table)
++                    .arg(hostname_clause);
++
++                sub_query.prepare(query_string);
++                sub_query.bindValue(":HOSTNAME", import_hostname);
++                sub_query.bindValue(":VALUE", value);
++                sub_query.bindValue(":DATA", data);
++                sub_query.exec();
++            }
++            else
++            {
++                 query_string = QString("INSERT INTO   "
++                    " %1 "
++                    "(value,data,hostname) "
++                    "VALUES ( :VALUE , :DATA , :HOSTNAME)").arg(table);
++
++                sub_query.prepare(query_string);
++                sub_query.bindValue(":HOSTNAME", import_hostname);
++                sub_query.bindValue(":VALUE", value);
++                sub_query.bindValue(":DATA", data);
++                sub_query.exec();
++            }
++        }
++    }
++    //KEYBINDINGS TABLE
++    else if (table.startsWith("keybindings"))
++    {
++       if ( table !=  "keybindings" )
++           create_new_table(table,"keybindings");
++       QString hostname = vp_map.value("hostname");
++       QString context = vp_map.value("context");
++       QString action = vp_map.value("action");
++       QString description = vp_map.value("description");
++       QString keylist = vp_map.value("keylist");
++
++       QString query_string=QString("SELECT  context,action,hostname "
++           "FROM %1 "
++           "WHERE hostname = :HOSTNAME AND "
++           "context = :CONTEXT "
++           "AND action = :ACTION ").arg(table);
++       query.prepare(query_string);
++       query.bindValue(":HOSTNAME", hostname);
++       query.bindValue(":CONTEXT", context);
++       query.bindValue(":ACTION", action);
++
++       if (query.exec() && query.isActive())
++       {
++           MSqlQuery sub_query(MSqlQuery::InitCon());
++           if ( query.size() > 0 )
++           {
++               query_string = QString("UPDATE  "
++               " %1 "
++               "set keylist = :KEYLIST "
++               "WHERE hostname = :HOSTNAME AND "
++               "context = :CONTEXT "
++               "AND action = :ACTION ").arg(table);
++
++               sub_query.prepare(query_string);
++               sub_query.bindValue(":HOSTNAME", hostname);
++               sub_query.bindValue(":KEYLIST", keylist);
++               sub_query.bindValue(":CONTEXT", context);
++               sub_query.bindValue(":ACTION", action);
++               sub_query.exec();
++           }
++           else
++           {
++               query_string = QString("INSERT INTO "
++               " %1 "
++               " (context , action , description , keylist , hostname) "
++               " VALUES( "
++               " :CONTEXT ,"
++               " :ACTION , "
++               " :DESCRIPTION , "
++               " :KEYLIST , "
++               " :HOSTNAME)").arg(table) ;
++
++               sub_query.prepare(query_string);
++               sub_query.bindValue(":HOSTNAME", hostname);
++               sub_query.bindValue(":KEYLIST", keylist);
++               sub_query.bindValue(":CONTEXT", context);
++               sub_query.bindValue(":ACTION", action);
++               sub_query.bindValue(":DESCRIPTION", description);
++               sub_query.exec();
++           }
++       }
++   }
++   //JUMP POINTS
++   else if (table.startsWith("jumppoints"))
++   {
++       if ( table != "jumppoints" )
++           create_new_table(table,"jumppoints");
++       QString hostname = vp_map.value("hostname");
++       QString description = vp_map.value("description");
++       QString destination = vp_map.value("destination");
++       QString keylist = vp_map.value("keylist");
++
++       QString query_string=QString("SELECT  destination, keylist  "
++        "FROM %1 "
++        "WHERE hostname = :HOSTNAME AND "
++        "destination = :DESTINATION "
++        "AND keylist = :KEYLIST ").arg(table);
++       query.prepare(query_string);
++       query.bindValue(":HOSTNAME", hostname);
++       query.bindValue(":DESTINATION", destination);
++       query.bindValue(":KEYLIST", keylist);
++
++       if (query.exec() && query.isActive())
++       {
++           MSqlQuery sub_query(MSqlQuery::InitCon());
++           if ( query.size() > 0 )
++           {
++               query_string = QString("UPDATE  "
++               " %1 "
++               "set keylist = :KEYLIST "
++               "WHERE hostname = :HOSTNAME AND "
++               "destination = :DESTINATION ").arg(table);
++
++               sub_query.prepare(query_string);
++               sub_query.bindValue(":HOSTNAME", hostname);
++               sub_query.bindValue(":KEYLIST", keylist);
++               sub_query.bindValue(":DESTINATION", destination);
++               sub_query.exec();
++           }
++           else
++           {
++               query_string = QString("INSERT INTO "
++               " %1 "
++               " (description , destination,  keylist , hostname) "
++               " VALUES( "
++               " :DESCRIPTION ,"
++               " :DESTINATION , "
++               " :KEYLIST , "
++               " :HOSTNAME)").arg(table) ;
++
++               sub_query.prepare(query_string);
++               sub_query.bindValue(":HOSTNAME", hostname);
++               sub_query.bindValue(":KEYLIST", keylist);
++               sub_query.bindValue(":DESTINATION", destination);
++               sub_query.bindValue(":DESCRIPTION", description);
++               sub_query.exec();
++           }
++       }
++   }
++}; //end import_settings
++
++QMap<QString, QMap<QString,QString> >
++            MythDB::export_settings(QString src_hostname,
++                                    QString saved_settingsgroupname,
++                                    QStringList table_list, bool skip_host )
++{
++    QMap<QString, QMap<QString,QString> >  result_set;
++    QStringList::Iterator it;
++    QString current_table;
++    int record_count = 0;
++
++    if ( table_list.isEmpty() )
++    {
++        table_list.append("settings");
++        table_list.append("keybindings");
++        table_list.append("jumppoints");
++    }
++
++    MSqlQuery query(MSqlQuery::InitCon());
++    QString query_string;
++
++    //loop over tablelist
++    for ( it = table_list.begin(); it != table_list.end(); ++it )
++    {
++        current_table = *it ;
++        QString sub_sql;
++        QStringList fields;
++        QString field_query;
++
++        QString table_name = find_group_table_name(current_table,
++                                                   saved_settingsgroupname);
++
++        QString hostname_clause;
++        if ( src_hostname == "GLOBAL" )
++            hostname_clause = "hostname IS NULL";
++        else
++            hostname_clause ="hostname = :HOSTNAME";
++
++        // find field names
++        query_string = QString("SHOW COLUMNS from %1").arg(table_name);
++        query.prepare(query_string);
++
++        //build up field name vars
++        if (query.exec() && query.isActive() && query.size() > 0)
++        {
++            while (query.next())
++            {
++                if (! field_query.isEmpty())
++                    field_query +=',';
++                QString tempItem = query.value(0).toString();
++                fields.append(tempItem);
++                field_query += tempItem;
++            }
++        }
++        // when working with settings table skip HOST if skip_host is true
++        if ( current_table == "settings" && skip_host == true )
++        {
++            QString skip_host_clause;
++            skip_host_clause = " VALUE not like 'HOST%' AND DATA not like 'HardwareProfile%UUID'" ;
++            query_string = QString("SELECT %1 FROM %2 WHERE %3 AND %4")
++            .arg(field_query)
++            .arg(table_name)
++            .arg(hostname_clause)
++            .arg(skip_host_clause);
++
++        }
++        else
++        {
++            query_string = QString("SELECT %1 FROM %2 WHERE %3")
++                                .arg(field_query)
++                                .arg(table_name)
++                                .arg(hostname_clause);
++        }
++        query.prepare(query_string);
++        query.bindValue(":HOSTNAME" , src_hostname);
++
++        //looping over each record in the table query
++        if (query.exec() && query.isActive() && query.size() > 0)
++        {
++            while (query.next())
++            {
++                //construct qmap of elements
++                //add table name
++                QMap<QString,QString> value_pair;
++                value_pair["table"]=table_name;
++
++                for ( int i=0 ; i < fields.size();i++ )
++                {
++                    QString tempvalue = fields[i];
++                    QString tempItem = query.value(i).toString();
++                    value_pair[tempvalue]=tempItem;
++                }
++                result_set[QString(record_count)] = value_pair;
++                record_count++;
++            }
++        }
++
++    } // end table loop
++    return result_set;
++}; //end export_settings
++
++
++void MythDB::create_new_table (QString create_table_name,QString like_name)
++{
++    if ( ! does_table_exist(create_table_name))
++    {
++        MSqlQuery query(MSqlQuery::InitCon());
++        QString query_string = QString("CREATE TABLE %1 like %2")
++                                       .arg(create_table_name)
++                                       .arg(like_name);
++
++        query.prepare(query_string);
++        query.exec();
++    }
++    else
++        LOG(VB_GENERAL, LOG_NOTICE, QString("Table is already present,"
++                                            "will not create it: %1")
++                                            .arg(create_table_name));
++};
++
++
++void MythDB::drop_temp_table (QString table_name)
++{
++    MSqlQuery query(MSqlQuery::InitCon());
++    if (table_name == "settings" | table_name == "keybindings" | table_name == "jumppoints")
++        return;
++    QString query_string = QString("DROP TABLE %1").arg(table_name);
++    query.prepare(query_string);
++    query.exec();
++    return;
++}
++
++void MythDB::create_temp_table (QString create_table_name,QString like_name)
++{
++    MSqlQuery query(MSqlQuery::InitCon());
++    create_new_table(create_table_name,like_name);
++    QString query_string;
++    if ( like_name == "settings")
++    {
++         query_string = QString ("ALTER TABLE %1 ADD UNIQUE( value)")
++                                 .arg(create_table_name);
++         query.prepare(query_string);
++         query.exec();
++    }
++
++    query_string = QString("TRUNCATE %1").arg(create_table_name);
++    query.prepare(query_string);
++    query.exec();
++ return;
++}
++
++bool MythDB::does_table_exist(QString table_name)
++{
++    bool table_exist = false;
++    QString full_table_name;
++    MSqlQuery query(MSqlQuery::InitCon());
++
++    query.prepare( "SHOW TABLES" );
++    if (query.exec() && query.isActive() && query.size() > 0)
++    {
++        while (query.next())
++        {
++            full_table_name = query.value(0).toString();
++            if (table_name == full_table_name)
++            {
++                table_exist = true;
++                break;
++            }
++        }
++    }
++    return table_exist;
++};
++
++
++QString MythDB::find_group_table_name(QString current_table,
++                                      QString saved_settingsgroupname)
++{
++    QString table_name;
++    if ( saved_settingsgroupname.toLower() == "current" )
++        table_name =  current_table ;
++    else
++        table_name =  current_table + "_" + saved_settingsgroupname ;
++
++   return table_name;
++};
++//END JM ADDED
++
+ /**
+  *  \brief Set a flag indicating we have successfully connected to the database
+  */
+diff --git a/mythtv/libs/libmythbase/mythdb.h b/mythtv/libs/libmythbase/mythdb.h
+index ac2a8ec..f3689a5 100644
+--- a/mythtv/libs/libmythbase/mythdb.h
++++ b/mythtv/libs/libmythbase/mythdb.h
+@@ -74,6 +74,49 @@ class MBASE_PUBLIC MythDB
+ 
+     void WriteDelayedSettings(void);
+ 
++    //JM ADDED
++    void savesettings_togroup(QString src_hostname,
++                              QString saved_settingsgroupname );
++    void deletesettings(QString delete_hostname,
++                        QString saved_settingsgroupname);
++
++    QMap<QString,QStringList> list_settingsgroupname();
++
++    QMap<QString,QStringList> diff_settingsgroupname(QString diff_hostname1,
++                                                     QString diff_hostname2,
++                                                     QStringList table_list);
++
++    void clonesettings(QString src_hostname,
++                       QString saved_settingsgroupname,
++                       QStringList table_list,
++                       bool is_full_clone = true,
++                       QString dest_hostname="");
++
++    void restoresettings (QString dest_hostname,
++                          QString saved_settingsgroupname,
++                          QStringList table_list);
++
++    void change_hostname (QString old_hostname, QString new_hostname);
++    bool settings_check (QString src_hostname, QString saved_settingsgroupname);
++    void import_settings(QMap<QString,QString> vp_map, QString table);
++
++
++    QMap<QString,QMap <QString,QString> > export_settings(
++                         QString src_hostname,
++                         QString saved_settingsgroupname,
++                         QStringList table_list,
++                         bool skip_host = false);
++
++    void create_new_table (QString create_table_name,QString like_name);
++    void drop_temp_table (QString table_name);
++    void create_temp_table (QString create_table_name,QString like_name);
++    bool does_table_exist(QString table_name);
++    QString find_group_table_name(QString current_table,
++                                  QString saved_settingsgroupname);
++    //END JM ADDED
++
++
++
+     void SetHaveDBConnection(bool connected);
+     void SetHaveSchema(bool schema);
+     bool HaveSchema(void) const;
+diff --git a/mythtv/programs/mythutil/commandlineparser.cpp b/mythtv/programs/mythutil/commandlineparser.cpp
+index 902314d..d86b548 100644
+--- a/mythtv/programs/mythutil/commandlineparser.cpp
++++ b/mythtv/programs/mythutil/commandlineparser.cpp
+@@ -144,6 +144,37 @@ void MythUtilCommandLineParser::LoadArguments(void)
+         << add("--print-notification-template", "printntemplate", false,
+                 "Print the template to be sent to the frontend", "")
+                 ->SetGroup("Messaging")
++
++        //settingsutil.cpp
++        << add("--save-settings", "savesettings", false,
++                "Save current settings", "")
++                ->SetGroup("Settings")
++        << add("--delete-settings", "deletesettings", false,
++                "Delete current settings", "")
++                ->SetGroup("Settings")
++        << add("--restore-settings", "restoresettings", false,
++                "Restore settings from previous backup", "")
++                ->SetGroup("Settings")
++        << add("--list-groups", "listgroups", false,
++                "List hosts and groups of settings", "")
++                ->SetGroup("Settings")
++        << add("--copy-settings", "copysettings", false,
++                "Copy or Clone settings from one host to another", "")
++                ->SetGroup("Settings")
++        << add("--diff-settings", "diffsettings", false,
++                "Show settings that are different between two hosts", "")
++                ->SetGroup("Settings")
++        << add("--change-hostname", "changehostname", false,
++                 "Change the hostname", "")
++                ->SetGroup("Settings")
++        << add("--import-settings", "importsettings", false,
++               "import settings", "")
++                ->SetRequiredChild("infile")
++
++        << add("--export-settings", "exportsettings", false,
++               "export settings", "")
++               ->SetRequiredChild("outfile")
++
+
+        // musicmetautils.cpp
+        << add("--scanmusic", "scanmusic", false,
+@@ -194,6 +225,59 @@ void MythUtilCommandLineParser::LoadArguments(void)
+     add("--type", "type", "type", "(optional) type of notification (normal, error, warning, check, busy", "")
+     ->SetChildOf("notification");
+ 
++    //settingsutils.cpp
++    add("--groupname", "groupname", "", "Group of settings name", "")
++        ->SetRequiredChildOf("savesettings")
++        ->SetRequiredChildOf("restoresettings")
++        ->SetRequiredChildOf("deletesettings")
++        ->SetChildOf("copysettings");
++
++    add("--hostname", "hostname", "", "System name to save/restore settings", "")
++        ->SetChildOf("savesettings")
++        ->SetChildOf("restoresettings")
++        ->SetChildOf("copysettings")
++        ->SetChildOf("deletesettings")
++        ->SetChildOf("exportsettings")
++        ->SetChildOf("importsettings");
++
++    add("--host_1", "host_1", "", "First host in compare list", "")
++        ->SetRequiredChildOf("diffsettings");
++
++    add("--host_2", "host_2", "", "Second host in compare list", "")
++        ->SetRequiredChildOf("diffsettings");
++
++
++    add("--tablelist", "table_list", "", "List of tables to operate on "
++        "[keybindings,settings]", "")
++        ->SetChildOf("diffsettings")
++        ->SetChildOf("restoresettings")
++        ->SetChildOf("copysettings")
++        ->SetChildOf("exportsettings");
++
++    add("--clone", "fullclone", false, "Enable copy of all settings, "
++        "including those that are unique to each system.", "")
++        ->SetChildOf("copysettings");
++
++
++    add("--old-host", "oldhost", "", "Hostname to change", "")
++        ->SetRequiredChildOf("changehostname");
++
++    add("--new-host", "newhost", "", "New hostname", "")
++        ->SetRequiredChildOf("changehostname")
++        ->SetRequiredChildOf("copysettings");
++
++    add("--format", "format", false, "Format output of differences", "")
++        ->SetChildOf("diffsettings");
++    add("--distro-default", "distro-default", false, "Export settings for"
++        "import into the default table", "")
++        ->SetChildOf("exportsettings");
++    add("--generic", "generic", false, "export settings without saving "
++        "the hostname", "")
++        ->SetChildOf("exportsettings");
++
++
++
++
+     // Generic Options used by more than one utility
+     addRecording();
+     addInFile(true);
+diff --git a/mythtv/programs/mythutil/main.cpp b/mythtv/programs/mythutil/main.cpp
+index 0bc49f2..faada3d 100644
+--- a/mythtv/programs/mythutil/main.cpp
++++ b/mythtv/programs/mythutil/main.cpp
+@@ -26,6 +26,7 @@
+ #include "musicmetautils.h"
+ #include "recordingutils.h"
+ #include "signalhandling.h"
++#include "settingsutils.h"
+
+
+ int main(int argc, char *argv[])
+@@ -110,6 +111,7 @@
+     registerJobUtils(utilMap);
+     registerMarkupUtils(utilMap);
+     registerMessageUtils(utilMap);
++    registerSettingsUtils(utilMap);
+     registerMusicUtils(utilMap);
+     registerRecordingUtils(utilMap);
+
+diff --git a/mythtv/programs/mythutil/mythutil.pro b/mythtv/programs/mythutil/mythutil.pro
+index f0ecbf5..f9472fc 100644
+--- a/mythtv/programs/mythutil/mythutil.pro
++++ b/mythtv/programs/mythutil/mythutil.pro
+@@ -22,8 +22,10 @@ QMAKE_CLEAN += $(TARGET)
+ HEADERS += backendutils.h fileutils.h jobutils.h markuputils.h
+ HEADERS += messageutils.h mpegutils.h musicmetautils.h
+ HEADERS += recordingutils.h
++HEADERS += settingsutils.h
+ SOURCES += main.cpp mythutil.cpp commandlineparser.cpp
+ SOURCES += backendutils.cpp fileutils.cpp jobutils.cpp markuputils.cpp
+ SOURCES += messageutils.cpp mpegutils.cpp musicmetautils.cpp eitutils.cpp
+ SOURCES += recordingutils.cpp
++SOURCES += settingsutils.cpp
+ 
+ mingw|win32-msvc*: LIBS += -lwinmm -lws2_32
+diff --git a/mythtv/programs/mythutil/settingsutils.cpp b/mythtv/programs/mythutil/settingsutils.cpp
+new file mode 100644
+index 0000000..8fc7b0e
+--- /dev/null
++++ b/mythtv/programs/mythutil/settingsutils.cpp
+@@ -0,0 +1,586 @@
++// C++ includes
++#include <iostream>
++using namespace std;
++
++//QT includes
++#include <qdom.h>
++#include <QFile>
++#include <QDomElement>
++
++// libmyth* includes
++#include "compat.h"
++#include "exitcodes.h"
++#include "mythlogging.h"
++#include "mythcontext.h"
++
++
++#include "settingsutils.h"
++
++
++static int SaveSettings(const MythUtilCommandLineParser &cmdline)
++{
++    QString src_hostname;
++    QString groupname;
++
++    if (cmdline.toBool("groupname"))
++        groupname = cmdline.toString("groupname");
++
++    if (cmdline.toBool("hostname"))
++        src_hostname = cmdline.toString("hostname");
++    else
++        src_hostname = gCoreContext->GetHostName();
++
++    gCoreContext->savesettings_togroup(src_hostname,groupname);
++    return GENERIC_EXIT_OK;
++}
++
++static int DeleteSettings(const MythUtilCommandLineParser &cmdline)
++{
++
++    QString delete_hostname;
++    QString groupname;
++
++    if (cmdline.toBool("groupname"))
++        groupname = cmdline.toString("groupname");
++
++    if (cmdline.toBool("hostname"))
++        delete_hostname = cmdline.toString("hostname");
++    else
++        delete_hostname = gCoreContext->GetHostName();
++
++
++    gCoreContext->deletesettings(delete_hostname,groupname);
++
++    return GENERIC_EXIT_OK;
++}
++
++
++static int RestoreSettings(const MythUtilCommandLineParser &cmdline)
++{
++    QString dest_hostname;
++    QString groupname;
++    QString tablestring;
++    QStringList table_list;
++
++    if (cmdline.toBool("groupname"))
++        groupname = cmdline.toString("groupname");
++
++
++    if (cmdline.toBool("hostname"))
++        dest_hostname = cmdline.toString("hostname");
++    else
++        dest_hostname = gCoreContext->GetHostName();
++
++    if (cmdline.toBool("table_list"))
++    {
++        tablestring = QString(cmdline.toString("table_list"));
++        table_list = tablestring.split(",", QString::SkipEmptyParts);
++    }
++
++    gCoreContext->restoresettings(dest_hostname,
++                                  groupname,
++                                  table_list);
++
++    return GENERIC_EXIT_OK;
++}
++
++
++static int CopySettings(const MythUtilCommandLineParser &cmdline)
++{
++    QString src_hostname;
++    QString groupname;
++    QString tablestring;
++    QStringList table_list;
++    bool is_full_clone;
++    QString dest_hostname;
++
++    if (cmdline.toBool("groupname"))
++        groupname = cmdline.toString("groupname");
++    else
++        groupname = "Current";
++
++    if (cmdline.toBool("hostname"))
++        src_hostname = cmdline.toString("hostname");
++    else
++        src_hostname = gCoreContext->GetHostName();
++
++    if (cmdline.toBool("newhost"))
++        dest_hostname = cmdline.toString("newhost");
++
++    if (cmdline.toBool("table_list"))
++    {
++        tablestring = QString(cmdline.toString("table_list"));
++        table_list = tablestring.split(",", QString::SkipEmptyParts);
++    }
++
++    if (cmdline.toBool("fullclone"))
++        is_full_clone = true;
++    else
++        is_full_clone = false;
++
++    gCoreContext->clonesettings(src_hostname,
++                                groupname,
++                                table_list,
++                                is_full_clone,
++                                dest_hostname);
++
++    return GENERIC_EXIT_OK;
++}
++
++void print_out_diff_formated(QMap<QString, QStringList> resultset)
++{
++    QString settings_header;
++    QString keybindings_header;
++    QString tempString;
++    QString tempItem;
++    QString dashline_settings;
++    QString dashline_key;
++    QStringList tempList;
++
++    QString host_1;
++    QString host_2;
++    QString data_1;
++    QString data_2;
++    QString value;
++    QString context;
++    QString action;
++
++    int value_width = 35;
++    int data_width = 40;
++
++    int context_width = 22;
++    int action_width = 22;
++    int key_width = 35;
++
++    dashline_key = (tempString.fill('-', 133));
++    dashline_settings = (tempString.fill('-', 130));
++
++    QMap<QString, QStringList>::iterator i;
++
++
++    for (i = resultset.begin(); i != resultset.end(); ++i)
++    {
++        cout << endl<<i.key().toLocal8Bit().constData() << ": \t" << endl;;
++        //construct the headers
++        if (i.key() == "Settings")
++        {
++            //settings header
++            tempList = (i.value().at(0)).split("|", QString::SkipEmptyParts);
++            host_1 = tempList.at(1);
++            host_2 = tempList.at(3);
++            tempString="|";
++            tempItem = "Value";
++            tempString.append(tempItem.leftJustified(value_width));
++            tempString.append("|");
++            tempItem = host_1;                //hostname 1
++            tempString.append(tempItem.leftJustified(data_width));
++            tempString.append("|");
++            tempItem = host_2;    //hostname 2
++            tempString.append(tempItem.leftJustified(data_width));
++            tempString.append("|");
++            settings_header = tempString;
++
++            cout << settings_header.toLocal8Bit().constData() << endl;;
++            cout << dashline_settings.toLocal8Bit().constData() << endl;
++        }
++
++         if (i.key() == "Keybindings")
++         {
++             //keybindings_header
++             tempList = (i.value().at(0)).split("|", QString::SkipEmptyParts);
++             host_1 = tempList.at(2);
++             host_2 = tempList.at(4);
++             tempString="|";
++             tempItem = "Context";
++             tempString.append(tempItem.leftJustified(context_width));
++             tempString.append("|");
++             tempItem = "Action";
++             tempString.append(tempItem.leftJustified(action_width));
++             tempString.append("|");
++             tempItem = host_1;
++             tempString.append(tempItem.leftJustified(key_width));
++             tempString.append("|");
++             tempItem = host_2;
++             tempString.append(tempItem.leftJustified(key_width));
++             tempString.append("|");
++             keybindings_header = tempString;
++
++             cout << keybindings_header.toLocal8Bit().constData() << endl;;
++             cout << dashline_key.toLocal8Bit().constData() << endl;
++
++         }
++         // format each line
++         for (int y = 0; y < i.value().size(); ++y)
++         {
++             if (i.key() == "Settings")
++             {
++                 tempList = (i.value().at(y)).split("|",
++                                                    QString::SkipEmptyParts);
++                 data_1 = tempList.at(2);
++                 data_2 = tempList.at(4);
++                 value  = tempList.at(0);
++                 tempString="|";
++                 tempItem = value;
++                 tempString.append(tempItem.leftJustified(value_width));
++                 tempString.append("|");
++                 tempItem = data_1;
++                 tempString.append(tempItem.leftJustified(data_width));
++                 tempString.append("|");
++                 tempItem = data_2;
++                 tempString.append(tempItem.leftJustified(data_width));
++                 tempString.append("|");
++             }
++             if (i.key() == "Keybindings")
++             {
++                 tempList = (i.value().at(y)).split("|",
++                                                    QString::SkipEmptyParts);
++                 data_1 = tempList.at(3);
++                 data_2 = tempList.at(5);
++                 context  = tempList.at(0);
++                 action = tempList.at(1);
++
++                 tempString="|";
++                 tempItem = context;
++                 tempString.append(tempItem.leftJustified(context_width));
++                 tempString.append("|");
++                 tempItem = action;
++                 tempString.append(tempItem.leftJustified(action_width));
++                 tempString.append("|");
++                 tempItem = data_1;
++                 tempString.append(tempItem.leftJustified(key_width));
++                 tempString.append("|");
++                 tempItem = data_2;
++                 tempString.append(tempItem.leftJustified(key_width));
++                 tempString.append("|");
++             }
++
++             cout << tempString.toLocal8Bit().constData()<<endl;
++         }
++    }
++};
++
++static int DiffSettings(const MythUtilCommandLineParser &cmdline)
++{
++    QMap<QString, QStringList> resultset;
++    QString diff_hostname1;
++    QString diff_hostname2;
++    QStringList table_list;
++    bool format_results = false;
++    QMap<QString, QStringList>::iterator i;
++
++    if (cmdline.toBool("host_1"))
++        diff_hostname1 = cmdline.toString("host_1");
++    if (cmdline.toBool("host_2"))
++        diff_hostname2 = cmdline.toString("host_2");
++
++    if (cmdline.toBool("table_list"))
++    {
++        QString tablestring = QString(cmdline.toString("table_list"));
++        table_list = tablestring.split(",", QString::SkipEmptyParts);
++    }
++
++    if (cmdline.toBool("format"))
++        format_results = true;
++
++    resultset = gCoreContext->diff_settingsgroupname(diff_hostname1,
++                                                     diff_hostname2,
++                                                     table_list);
++    if  (resultset.isEmpty())
++        cout << "No differences found" << endl;
++    else
++    {
++        if (format_results)
++            print_out_diff_formated(resultset);
++        else
++        {
++            for (i = resultset.begin(); i != resultset.end(); ++i)
++            {
++                cout << i.key().toLocal8Bit().constData() << " : \t" << endl;;
++                for (int y = 0; y < i.value().size(); ++y)
++                    cout << i.value().at(y).toLocal8Bit().constData()<<endl;
++                cout << endl;
++            }
++        }
++    }
++    return GENERIC_EXIT_OK;
++};// DiffSettings
++
++static int ListGroups(const MythUtilCommandLineParser &cmdline)
++{
++    QMap<QString, QStringList> resultset;
++    resultset = gCoreContext->list_settingsgroupname();
++    QMap<QString, QStringList>::iterator i;
++    cout <<  endl;
++    for (i = resultset.begin(); i != resultset.end(); ++i)
++    {
++        cout << i.key().toLocal8Bit().constData() << " : \t";
++        for (int y = 0; y < i.value().size(); ++y)
++            cout << i.value().at(y).toLocal8Bit().constData()<<" " ;
++        cout << endl;
++    }
++    return GENERIC_EXIT_OK;
++};
++
++static int ImportSettings(const MythUtilCommandLineParser &cmdline)
++{
++
++    if (cmdline.toString("infile").isEmpty())
++    {
++        LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --infile option\n");
++        return GENERIC_EXIT_INVALID_CMDLINE;
++    }
++    QString import_hostname;
++    bool change_name = false;
++    if (cmdline.toBool("hostname"))
++    {
++        change_name = true;
++        import_hostname = cmdline.toString("hostname");
++    }
++    QString import_filename = cmdline.toString("infile");
++    QFile myFile(import_filename);
++
++    QDomDocument doc( "exported_xml" );
++    doc.setContent( &myFile );
++
++    QDomElement docElement = doc.documentElement();
++    QDomElement record_element;
++
++    if ( docElement.nodeName() != "exported_xml" )
++    {
++       cout << "not a valid exported xml file" << endl;
++       return 1;
++    }
++
++    QString out_string = "Importing records, please be patient";
++    cout << out_string.toLocal8Bit().constData()  << endl;
++    //Gives list of records in the file + count
++    QDomNodeList nodeList = docElement.childNodes();
++    int total_records = nodeList.count();
++    out_string = QString("\nFound %1 records \n").arg(total_records);
++    cout << out_string.toLocal8Bit().constData()  << endl;
++    LOG(VB_STDIO|VB_FLUSH, LOG_ERR, out_string);
++
++    for(QDomNode n = docElement.firstChild(); !n.isNull(); n = n.nextSibling())
++    {
++        QString table_name=QString();
++        QMap<QString,QString> value_pair_map ;
++
++        //find table name for this record
++        QDomNode tablenode=n.namedItem("table");
++        record_element = tablenode.toElement();
++        table_name = record_element.text();
++
++        //loop over childern of n and convert to element
++        for(QDomNode subn = n.firstChild();
++            !subn.isNull();
++            subn = subn.nextSibling())
++        {
++            record_element = subn.toElement();
++            if ( record_element.nodeName() == "table" )
++                    continue;
++            if ( change_name && record_element.nodeName() == "hostname" )
++                value_pair_map[record_element.nodeName()] = import_hostname;
++            else
++                value_pair_map[record_element.nodeName()] = record_element.text();
++        }
++        if (import_filename.endsWith("syssettings.xml"))
++        {
++            if  ( value_pair_map["value"] == "BackendServerIP")
++            {
++                out_string = "sysettings, ignoring backendserver ip record";
++                cout << out_string.toLocal8Bit().constData()  << endl;
++            }
++            else
++                gCoreContext->import_settings(value_pair_map,table_name);
++        }
++        else
++            //perform insert
++            gCoreContext->import_settings(value_pair_map,table_name);
++    }
++    return GENERIC_EXIT_OK;
++}; //end ImportSettings
++
++
++static int ExportSettings(const MythUtilCommandLineParser &cmdline)
++{
++    QMap<QString, QMap<QString,QString> > records;
++    QString src_hostname;
++    QString groupname;
++    QStringList table_list;
++    QString tablestring;
++    bool distro_default = false;
++    bool generic = false;
++    bool skip_host = false;
++
++
++
++    QDomDocument doc("mythutils_exported_settings");
++
++    if (cmdline.toBool("groupname"))
++        groupname = cmdline.toString("groupname");
++    else
++        groupname = "current";
++
++    if (cmdline.toBool("hostname"))
++        src_hostname = cmdline.toString("hostname");
++    else
++        src_hostname = gCoreContext->GetHostName();
++
++    if (cmdline.toBool("distro-default"))
++    {
++        distro_default = true;
++        skip_host = true;
++    }
++    if (cmdline.toBool("generic"))
++    {
++        generic = true;
++        //skip_host = true;
++    }
++    if (cmdline.toBool("table_list"))
++    {
++        tablestring = QString(cmdline.toString("table_list"));
++        table_list = tablestring.split(",", QString::SkipEmptyParts);
++    }
++    else
++        table_list << "settings" <<"keybindings" <<"jumppoints" ;
++
++    if (cmdline.toString("outfile").isEmpty())
++    {
++        LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing --outfile option\n");
++        return GENERIC_EXIT_INVALID_CMDLINE;
++    }
++
++    QString export_filename = cmdline.toString("outfile");
++
++    records = gCoreContext->export_settings(src_hostname,groupname,
++                                            table_list, skip_host);
++
++    QDomElement exported_xml = doc.createElement("exported_xml");
++    doc.appendChild(exported_xml);
++
++    QMap<QString,int> record_count;
++    QMap<QString,QMap<QString,QString>  >::iterator i;
++    for (i = records.begin(); i != records.end(); ++i )
++    {
++            QDomElement record = doc.createElement("record");
++            exported_xml.appendChild(record);
++
++            //loop over all values in the record
++            QMap<QString,QString> value_pair = i.value();
++            QMap<QString, QString>::iterator y;
++            //because we don't know the name of the key, we loop over it
++            for (y = value_pair.begin(); y != value_pair.end(); ++y)
++           {
++                //add key/pair to xml document
++                QDomElement tag = doc.createElement(y.key());
++                record.appendChild(tag);
++                QDomText  t;
++                if ( distro_default == true )
++                {   // If exporting distro_default then change hostname + table
++                    if ( y.key() == "hostname" )
++                    {   //check for global values here, empty value means global
++                        if ( y.value().isEmpty() )
++                            t = doc.createTextNode(y.value());
++                        else
++                            t = doc.createTextNode("distro_default");
++                    }
++                    else if ( y.key() == "table")
++                        t = doc.createTextNode(y.value()+"_distro_default");
++                    else
++                        t = doc.createTextNode(y.value());
++                }
++
++                else if ( generic == true )
++                {   // If exporting generic then change hostname
++                    if ( y.key() == "hostname" )
++                    {   //check for global values here, empty value means global
++                        if ( y.value().isEmpty() )
++                            t = doc.createTextNode(y.value());
++                        else
++                            t = doc.createTextNode("REPLACE_ME");
++                    }
++                    else
++                       t = doc.createTextNode(y.value());
++               }
++               else
++                   t = doc.createTextNode(y.value());
++
++               tag.appendChild(t);
++                //create record counts
++                if ( y.key() == "table" )
++                {
++                    if ( record_count.contains( y.value()) )
++                    {
++                        int record_num = record_count[y.value()];
++                        record_count[y.value()] = ++record_num;
++                    }
++                    else
++                        record_count[y.value()] = 1;
++                }
++           }
++     }
++     QFile file( export_filename );
++
++     if( !file.open(QIODevice::WriteOnly) )
++            return -1;
++
++     QTextStream ts( &file );
++     ts << doc.toString();
++     file.close();
++     QMap<QString, int >::iterator rc_it;
++     for ( rc_it = record_count.begin(); rc_it != record_count.end(); ++rc_it)
++     {
++            QString table = rc_it.key();
++            int rc_count = rc_it.value();
++            QString out_string = QString ("Exported table %1: %2 records")
++                                                            .arg(table)
++                                                            .arg(rc_count);
++            cout << out_string.toLocal8Bit().constData()  << endl;
++     }
++    return GENERIC_EXIT_OK;
++}; // end export_settings
++
++
++static int ChangeHostname(const MythUtilCommandLineParser &cmdline)
++{
++
++    QString old_hostname;
++    QString new_hostname;
++
++
++    if (cmdline.toBool("oldhost"))
++        old_hostname = cmdline.toString("oldhost");
++
++    if (cmdline.toBool("newhost"))
++        new_hostname = cmdline.toString("newhost");
++
++    if (old_hostname.isEmpty())
++    {
++        LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing or empty --old-host option\n");
++        return GENERIC_EXIT_INVALID_CMDLINE;
++    }
++
++    if (new_hostname.isEmpty())
++    {
++        LOG(VB_STDIO|VB_FLUSH, LOG_ERR, "Missing or empty --new-host option\n");
++        return GENERIC_EXIT_INVALID_CMDLINE;
++    }
++
++    gCoreContext->change_hostname(old_hostname, new_hostname);
++
++    return GENERIC_EXIT_OK;
++}; //end ChangeHostname
++
++void registerSettingsUtils(UtilMap &utilMap)
++{
++    utilMap["savesettings"]             = &SaveSettings;
++    utilMap["deletesettings"]           = &DeleteSettings;
++    utilMap["restoresettings"]          = &RestoreSettings;
++    utilMap["copysettings"]             = &CopySettings;
++    utilMap["diffsettings"]             = &DiffSettings;
++    utilMap["listgroups"]               = &ListGroups;
++    utilMap["importsettings"]           = &ImportSettings;
++    utilMap["exportsettings"]           = &ExportSettings;
++    utilMap["changehostname"]           = &ChangeHostname;
++}
++
++/* vim: set expandtab tabstop=4 shiftwidth=4: */
+\ No newline at end of file
+diff --git a/mythtv/programs/mythutil/settingsutils.h b/mythtv/programs/mythutil/settingsutils.h
+new file mode 100644
+index 0000000..413496c
+--- /dev/null
++++ b/mythtv/programs/mythutil/settingsutils.h
+@@ -0,0 +1,3 @@
++#include "mythutil.h"
++
++void registerSettingsUtils(UtilMap &utilMap);
diff --git a/abs/core/mythtv/stable-29/mythtv/mythfrontend_en_us.ts_Title_Case.patch b/abs/core/mythtv/stable-29/mythtv/mythfrontend_en_us.ts_Title_Case.patch
new file mode 100644
index 0000000..3e7a738
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/mythfrontend_en_us.ts_Title_Case.patch
@@ -0,0 +1,383 @@
+--- src/mythtv/i18n/mythfrontend_en_us.ts.orig	2017-03-17 14:20:37.088541193 +0000
++++ src/mythtv/i18n/mythfrontend_en_us.ts	2017-03-17 14:20:03.206227232 +0000
+@@ -3349,12 +3349,12 @@
+     <message>
+         <location filename="../programs/mythfrontend/main.cpp" line="206"/>
+         <source>Play from bookmark</source>
+-        <translation>Play from bookmark</translation>
++        <translation>Play from Bookmark</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/main.cpp" line="207"/>
+         <source>Play from beginning</source>
+-        <translation>Play from beginning</translation>
++        <translation>Play from Beginning</translation>
+     </message>
+ </context>
+ <context>
+@@ -3388,14 +3388,14 @@
+         <location filename="../libs/libmythtv/videosource.cpp" line="3817"/>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3852"/>
+         <source>Yes, delete capture cards</source>
+-        <translation>Yes, delete capture cards</translation>
++        <translation>Yes, Delete Capture Cards</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3818"/>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3853"/>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3876"/>
+         <source>No, don&apos;t</source>
+-        <translation>No, don&apos;t</translation>
++        <translation>No, Keep</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3834"/>
+@@ -3420,7 +3420,7 @@
+     <message>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3875"/>
+         <source>Yes, delete capture card</source>
+-        <translation>Yes, delete capture card</translation>
++        <translation>Yes, Delete Capture Card</translation>
+     </message>
+ </context>
+ <context>
+@@ -3674,12 +3674,12 @@
+     <message>
+         <location filename="../libs/libmythtv/channelgroupsettings.cpp" line="186"/>
+         <source>Yes, delete group</source>
+-        <translation>Yes, delete group</translation>
++        <translation>Yes, Delete Group</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/channelgroupsettings.cpp" line="187"/>
+         <source>No, Don&apos;t delete group</source>
+-        <translation>No, Don&apos;t delete group</translation>
++        <translation>No, Keep Group</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/channelgroupsettings.cpp" line="239"/>
+@@ -4116,7 +4116,7 @@
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="368"/>
+         <source>Skip %1</source>
+         <extracomment>%1 is the skip time</extracomment>
+-        <translation>Skip %1</translation>
++        <translation>Skip Commercial %1</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="241"/>
+@@ -4127,19 +4127,19 @@
+     <message>
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="272"/>
+         <source>Skipping Back.</source>
+-        <translation>Skipping Back.</translation>
++        <translation>Skipping Back</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="290"/>
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="316"/>
+         <source>Start of program.</source>
+-        <translation>Start of program.</translation>
++        <translation>Start of Program</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="300"/>
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="344"/>
+         <source>At End, cannot Skip.</source>
+-        <translation>At End, cannot Skip.</translation>
++        <translation>At End, Cannot Skip</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/commbreakmap.cpp" line="362"/>
+@@ -5611,7 +5611,7 @@
+     <message>
+         <location filename="../programs/mythfrontend/exitprompt.cpp" line="227"/>
+         <source>Yes, Exit now</source>
+-        <translation>Yes, Exit now</translation>
++        <translation>Yes, Exit</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/exitprompt.cpp" line="229"/>
+@@ -11873,7 +11873,7 @@
+         <location filename="../libs/libmythtv/mythplayer.cpp" line="4270"/>
+         <location filename="../libs/libmythtv/mythplayer.cpp" line="4306"/>
+         <source>New cut added.</source>
+-        <translation>New cut added.</translation>
++        <translation>New Cut Added</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/mythplayer.cpp" line="4275"/>
+@@ -12303,12 +12303,12 @@
+     <message>
+         <location filename="../libs/libmythui/myththemedmenu.cpp" line="322"/>
+         <source>Enter standby mode</source>
+-        <translation>Enter standby mode</translation>
++        <translation>Standby</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythui/myththemedmenu.cpp" line="326"/>
+         <source>Exit application</source>
+-        <translation>Exit application</translation>
++        <translation>Exit</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythui/myththemedmenu.cpp" line="333"/>
+@@ -12896,12 +12896,12 @@
+     <message>
+         <location filename="../libs/libmythtv/playgroup.cpp" line="288"/>
+         <source>Yes, delete group</source>
+-        <translation>Yes, delete group</translation>
++        <translation>Yes, Delete Group</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/playgroup.cpp" line="289"/>
+         <source>No, Don&apos;t delete group</source>
+-        <translation>No, Don&apos;t delete group</translation>
++        <translation>No, Keep Group</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/playgroup.cpp" line="312"/>
+@@ -13022,38 +13022,38 @@
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2623"/>
+         <source>Yes, and allow re-record</source>
+-        <translation>Yes, and allow re-record</translation>
++        <translation>Yes, Delete and Allow Re-record</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2631"/>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2635"/>
+         <source>Yes, delete it</source>
+-        <translation>Yes, delete it</translation>
++        <translation>Yes, Delete</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2639"/>
+         <source>Yes, stop recording</source>
+-        <translation>Yes, stop recording</translation>
++        <translation>Yes, Stop Recording</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2653"/>
+         <source>Yes, delete it and the remaining %1 list items</source>
+-        <translation>Yes, delete it and the remaining %1 list items</translation>
++        <translation>Yes, Delete Recording and the Remaining %1 List Items</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2663"/>
+         <source>No, keep it</source>
+-        <translation>No, keep it</translation>
++        <translation>No, Keep</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2667"/>
+         <source>No, continue recording</source>
+-        <translation>No, continue recording</translation>
++        <translation>No, Continue Recording</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2675"/>
+         <source>No, and keep the remaining %1 list items</source>
+-        <translation>No, and keep the remaining %1 list items</translation>
++        <translation>No, Keep the Remaining %1 List Items</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/playbackbox.cpp" line="2695"/>
+@@ -14340,12 +14340,12 @@
+     <message>
+         <location filename="../libs/libmythtv/profilegroup.cpp" line="360"/>
+         <source>Yes, delete group</source>
+-        <translation>Yes, delete group</translation>
++        <translation>Yes, Delete Group</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/profilegroup.cpp" line="361"/>
+         <source>No, Don&apos;t delete group</source>
+-        <translation>No, Don&apos;t delete group</translation>
++        <translation>No, Keep Group</translation>
+     </message>
+ </context>
+ <context>
+@@ -14576,7 +14576,7 @@
+     <message>
+         <location filename="../programs/mythfrontend/progdetails.cpp" line="633"/>
+         <source>Auto-expire off</source>
+-        <translation>Auto-expire off</translation>
++        <translation>Auto-Expire Off</translation>
+     </message>
+     <message>
+         <location filename="../programs/mythfrontend/progdetails.cpp" line="636"/>
+@@ -17786,12 +17786,12 @@
+     <message>
+         <location filename="../libs/libmythtv/tv.cpp" line="85"/>
+         <source>Auto-Skip OFF</source>
+-        <translation>Auto-Skip OFF</translation>
++        <translation>Auto-Skip Off</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv.cpp" line="86"/>
+         <source>Auto-Skip ON</source>
+-        <translation>Auto-Skip ON</translation>
++        <translation>Auto-Skip On</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv.cpp" line="87"/>
+@@ -21988,12 +21988,12 @@
+     <message>
+         <location filename="../libs/libmyth/storagegroupeditor.cpp" line="165"/>
+         <source>Yes, remove directory</source>
+-        <translation>Yes, remove directory</translation>
++        <translation>Yes, Remove Directory</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmyth/storagegroupeditor.cpp" line="166"/>
+         <source>No, Don&apos;t remove directory</source>
+-        <translation>No, Don&apos;t remove directory</translation>
++        <translation>No, Keep Directory</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmyth/storagegroupeditor.cpp" line="223"/>
+@@ -22052,12 +22052,12 @@
+     <message>
+         <location filename="../libs/libmyth/storagegroupeditor.cpp" line="323"/>
+         <source>Yes, delete group</source>
+-        <translation>Yes, delete group</translation>
++        <translation>Yes, Delete Group</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmyth/storagegroupeditor.cpp" line="324"/>
+         <source>No, Don&apos;t delete group</source>
+-        <translation>No, Don&apos;t delete group</translation>
++        <translation>No, Keep Group</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmyth/storagegroupeditor.cpp" line="437"/>
+@@ -22733,7 +22733,7 @@
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="10903"/>
+         <source>Zoom Mode ON</source>
+-        <translation>Zoom Mode ON</translation>
++        <translation>Zoom Mode On</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="11500"/>
+@@ -23030,12 +23030,12 @@
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="12226"/>
+         <source>Turn Auto-Expire OFF</source>
+-        <translation>Turn Auto-Expire OFF</translation>
++        <translation>Turn Auto-Expire Off</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="12226"/>
+         <source>Turn Auto-Expire ON</source>
+-        <translation>Turn Auto-Expire ON</translation>
++        <translation>Turn Auto-Expire On</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="12185"/>
+@@ -23233,7 +23233,7 @@
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13386"/>
+         <source>No, keep it</source>
+-        <translation>No, keep it</translation>
++        <translation>No, Keep</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="12527"/>
+@@ -23436,12 +23436,12 @@
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="12703"/>
+         <source>Auto-Expire OFF</source>
+-        <translation>Auto-Expire OFF</translation>
++        <translation>Auto-Expire Off</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="12708"/>
+         <source>Auto-Expire ON</source>
+-        <translation>Auto-Expire ON</translation>
++        <translation>Auto-Expire On</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="12951"/>
+@@ -23491,7 +23491,7 @@
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13245"/>
+         <source>this recording</source>
+-        <translation>this recording</translation>
++        <translation>this Recording</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13251"/>
+@@ -23541,27 +23541,27 @@
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13373"/>
+         <source>Delete it, but allow it to re-record</source>
+-        <translation>Delete it, but allow it to re-record</translation>
++        <translation>Delete Recording, and Allow Re-record</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13375"/>
+         <source>Delete it</source>
+-        <translation>Delete it</translation>
++        <translation>Delete Recording</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13377"/>
+         <source>Save it so I can watch it again</source>
+-        <translation>Save it so I can watch it again</translation>
++        <translation>Keep Recording</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13382"/>
+         <source>Yes, and allow re-record</source>
+-        <translation>Yes, and allow re-record</translation>
++        <translation>Yes, Delete and Allow Re-record</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/tv_play.cpp" line="13384"/>
+         <source>Yes, delete it</source>
+-        <translation>Yes, delete it</translation>
++        <translation>Yes, Delete</translation>
+     </message>
+ </context>
+ <context>
+@@ -30107,12 +30107,12 @@
+     <message>
+         <location filename="../libs/libmythtv/transporteditor.cpp" line="325"/>
+         <source>Yes, delete the transport</source>
+-        <translation>Yes, delete the transport</translation>
++        <translation>Yes, Delete Transport</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/transporteditor.cpp" line="326"/>
+         <source>No, don&apos;t</source>
+-        <translation>No, don&apos;t</translation>
++        <translation>No, Keep Transport</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/transporteditor.cpp" line="360"/>
+@@ -31302,13 +31302,13 @@
+     <message>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3950"/>
+         <source>Yes, delete video sources</source>
+-        <translation>Yes, delete video sources</translation>
++        <translation>Yes, Delete Video Sources</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3951"/>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3975"/>
+         <source>No, don&apos;t</source>
+-        <translation>No, don&apos;t</translation>
++        <translation>No, Keep</translation>
+     </message>
+     <message>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3972"/>
+@@ -31318,7 +31318,7 @@
+     <message>
+         <location filename="../libs/libmythtv/videosource.cpp" line="3974"/>
+         <source>Yes, delete video source</source>
+-        <translation>Yes, delete video source</translation>
++        <translation>Yes, Delete Video Source</translation>
+     </message>
+ </context>
+ <context>
diff --git a/abs/core/mythtv/stable-29/mythtv/mythtv.install b/abs/core/mythtv/stable-29/mythtv/mythtv.install
new file mode 100644
index 0000000..aedebbf
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/mythtv.install
@@ -0,0 +1,34 @@
+# arg 1:  the new package version
+post_install() {
+        gen_is_xml.py
+        gen_lib_xml.py
+        systemconfig.py -m config_xml
+}
+
+pre_upgrade() {
+        if [ "`vercmp $2 0.28`" -lt 0 ]
+        then
+            . /etc/systemconfig
+            if [ $SystemType = "Master_backend" -o $SystemType = "Standalone" ]
+            then
+                echo "upgrading from 0.27, adding new storage groups..."
+                add_storage.py --reconstruct_sg
+            fi
+        fi
+        /bin/true
+}
+
+post_upgrade() {
+        post_install
+}
+
+
+# arg 1:  the old package version
+post_remove() {
+        /bin/true
+
+}
+
+op=$1
+shift
+$op $*
diff --git a/abs/core/mythtv/stable-29/mythtv/recordings b/abs/core/mythtv/stable-29/mythtv/recordings
new file mode 100644
index 0000000..5dff16f
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/recordings
@@ -0,0 +1,145 @@
+#!/bin/bash
+
+#START=$(date +%s)
+
+#check if mythbackend is running and was just started
+for i in 1 2
+do
+if [ `cat /service/mythbackend/supervise/pid` ]
+then
+    now=$(date +%s)
+    mythbackendStartTime=`stat -c %Y /service/mythbackend/supervise/pid`
+    if [[ $(( $now - $mythbackendStartTime )) -lt 59 ]]
+    then
+        #echo "mythbackend started less than a minute ago. Sleeping..."
+        sleep 60
+    fi
+else
+    #echo "mythbackend not running. exiting."
+    exit
+fi
+done
+
+if [ -f /usr/share/mythtv/contrib/user_jobs/mythlink.pl ]
+then
+    recdir="/data/storage/disk0/media/recordings"
+    tmprecdir="/data/storage/disk0/media/tmp/recordings"
+    rm -r $tmprecdir
+    su - mythtv -c "perl /usr/share/mythtv/contrib/user_jobs/mythlink.pl --format '%Ct/%U/%T/%T %- S%ssE%ep %- %oY-%om-%od = %S' --link '$tmprecdir'"
+
+    # rename category_types (%Ct) from numbers to names
+    for cattype in $tmprecdir/*
+    do
+        if [ $cattype == "$tmprecdir/1" ]
+        then
+            rsync -a "$cattype/" "$tmprecdir/Movies"
+            rm -r "$cattype"
+        elif [[ $cattype == "$tmprecdir/2" ]] || [[ $cattype == "$tmprecdir/4" ]]
+        then
+            rsync -a "$cattype/" "$tmprecdir/TV Shows"
+            rm -r "$cattype"
+        elif [ $cattype == "$tmprecdir/3" ]
+        then
+            rsync -a "$cattype/" "$tmprecdir/Sports"
+            rm -r "$cattype"
+        else
+            #ignore Movies, TV Shows, Sports. Move all others to TV Shows
+            if [[ $cattype != "$tmprecdir/Movies" ]] && [[ $cattype != "$tmprecdir/TV Shows" ]] && [[ $cattype != "$tmprecdir/Sports" ]]
+            then
+                if [ ! -d "$tmprecdir/TV Shows" ]
+                then
+                    mkdir "$tmprecdir/TV Shows"
+                fi
+                rsync -a "$cattype" "$tmprecdir/TV Shows"
+                rm -r "$cattype"
+            fi
+        fi
+    done
+
+    #delete Deleted recgroup
+    for link in $tmprecdir/**/Deleted
+    do
+        rm -r "$link"
+    done
+
+    #move all links in recgroup dirs out to parent dir
+    for recgroup in $tmprecdir/**/*
+    do
+        if [ -d "$recgroup" ]
+        then
+            cd "$recgroup"
+            rsync -a "$recgroup/" ..
+            cd "$tmprecdir"
+            rm -r "$recgroup"
+        fi
+    done
+
+    #replace SE if no season/episode is in myth
+    for link in $tmprecdir/**/**/*\ -\ SE\ -\ *
+    do
+        newlink=`echo "$link" | sed 's/ - SE - / - /'`
+        mv "$link" "$newlink"
+    done
+    #replace SEyy if no season is in myth
+    for link in $tmprecdir/**/**/*\ -\ SE[0-9][0-9]\ -\ *
+    do
+        newlink=`echo "$link" | sed 's/ - SE/ - S00E/'`
+        mv "$link" "$newlink"
+    done
+    #replace SyyE if no episode is in myth
+    for link in $tmprecdir/**/**/*\ -\ S[0-9][0-9]E\ -\ *
+    do
+        newlink=`echo "$link" | sed 's/E - /E00 - /'`
+        mv "$link" "$newlink"
+    done
+    #replace blank original date
+    for link in $tmprecdir/**/**/*\ -\ 0000-00-00\ -\ *
+    do
+        newlink=`echo "$link" | sed 's/ - 0000-00-00 - / - /'`
+        mv "$link" "$newlink"
+    done
+    #add dash pt suffix if filename before the subtitle is the same
+    #so that plex will scan and include in library
+    uniqs="$(ls $tmprecdir/**/**/* | sed 's/ = .*//' | sort | uniq -d)"
+    SAVEIFS=$IFS
+    IFS=$'\n'
+    for link in $uniqs
+    do
+        i=1
+        for dup in `ls -v $link*`
+        do
+            newlink=`echo "$dup" | sed "s/ = /-pt$i = /"`
+            mv "$dup" "$newlink"
+            i=$((i+1))
+        done
+    done
+    IFS=$SAVEIFS
+
+    #change symlinks mtime to match the file it is linked to
+#    for link in $tmprecdir/**/*
+#    do
+#        if [ -L "$link" ]
+#        then
+#            file=`readlink "$link"`
+#            touch -hr "$file" "$link"
+#        fi
+#    done
+
+    #sync tmprecdir to recdir
+    #rsync -aOP --delete --ignore-existing "$tmprecdir/" "$recdir/"
+    rsync -aO --delete "$tmprecdir/" "$recdir/"
+
+    #check if plex media server is running
+    if [[ `pidof "Plex Media Server"` ]]
+    then
+        #get plex section and update
+        script -q -c '/usr/LH/bin/plexmediascanner.sh -l' | grep -i myth | cut -d: -f1 | while read -r line
+        do
+            /usr/LH/bin/plexmediascanner.sh --scan --refresh --section $line
+        done
+    fi
+fi
+
+#END=$(date +%s)
+#DIFF=$(( $END - $START ))
+#echo "It took $DIFF seconds"
diff --git a/abs/core/mythtv/stable-29/mythtv/searchMetatdataSelectedGrabber.patch b/abs/core/mythtv/stable-29/mythtv/searchMetatdataSelectedGrabber.patch
new file mode 100644
index 0000000..41e0871
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/searchMetatdataSelectedGrabber.patch
@@ -0,0 +1,18 @@
+--- src/mythtv/libs/libmythmetadata/metadatadownload.cpp.orig	2016-10-06 19:52:36.807746878 +0000
++++ src/mythtv/libs/libmythmetadata/metadatadownload.cpp	2016-10-06 19:42:06.045651726 +0000
+@@ -517,6 +517,7 @@
+ 
+     // initial search mode
+     if (!lookup->GetInetref().isEmpty() && lookup->GetInetref() != "00000000" &&
++        !lookup->GetInetref().endsWith("_") &&
+         (lookup->GetStep() == kLookupSearch || lookup->GetStep() == kLookupData))
+     {
+         // with inetref
+@@ -575,6 +576,7 @@
+ 
+     // initial search mode
+     if (!lookup->GetInetref().isEmpty() && lookup->GetInetref() != "00000000" &&
++        !lookup->GetInetref().endsWith("_") &&
+         (lookup->GetStep() == kLookupSearch || lookup->GetStep() == kLookupData))
+     {
+         // with inetref
diff --git a/abs/core/mythtv/stable-29/mythtv/suggestedstarttime.patch.v1 b/abs/core/mythtv/stable-29/mythtv/suggestedstarttime.patch.v1
new file mode 100644
index 0000000..26d4c36
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/suggestedstarttime.patch.v1
@@ -0,0 +1,32 @@
+diff --git a/mythtv/programs/mythbackend/httpstatus.cpp b/mythtv/programs/mythbackend/httpstatus.cpp
+index 8571a58..be0272f 100644
+--- a/mythtv/programs/mythbackend/httpstatus.cpp
++++ b/mythtv/programs/mythbackend/httpstatus.cpp
+@@ -1392,13 +1392,17 @@ int HttpStatus::PrintMachineInfo( QTextStream &os, QDomElement info )
+             QString sStatus = e.attribute( "status"   , ""  );
+             QDateTime next  = MythDate::fromString( e.attribute( "next"     , ""  ));
+             QString sNext   = next.isNull() ? "" :
+-                                MythDate::toString(next, MythDate::kDatabase);
++                                MythDate::toString(next, MythDate::kDateTimeFull);
+             QString sMsg    = "";
+ 
+             QDateTime thru  = MythDate::fromString( e.attribute( "guideThru", ""  ));
+ 
+             QDomText  text  = e.firstChild().toText();
+ 
++            QString mfdblrs =
++                gCoreContext->GetSetting("mythfilldatabaseLastRunStart");
++            QDateTime lastrunstart = MythDate::fromString(mfdblrs);
++
+             if (!text.isNull())
+                 sMsg = text.nodeValue();
+ 
+@@ -1412,7 +1416,7 @@ int HttpStatus::PrintMachineInfo( QTextStream &os, QDomElement info )
+ 
+             os << sStatus << "<br />\r\n";
+ 
+-            if (!next.isNull() && sNext >= sStart)
++            if (!next.isNull() && next >= lastrunstart)
+             {
+                 os << "    Suggested next mythfilldatabase run: "
+                     << sNext << ".<br />\r\n";
diff --git a/abs/core/mythtv/stable-29/mythtv/videoAlwaysUseBookmark.patch b/abs/core/mythtv/stable-29/mythtv/videoAlwaysUseBookmark.patch
new file mode 100644
index 0000000..7a0b428
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythtv/videoAlwaysUseBookmark.patch
@@ -0,0 +1,22 @@
+--- src/mythtv/programs/mythfrontend/main.cpp.orig	2014-10-05 21:16:54.226667223 +0000
++++ src/mythtv/programs/mythfrontend/main.cpp	2014-10-06 20:31:16.822482368 +0000
+@@ -1166,14 +1166,11 @@
+ 
+     if (useBookmark && bookmarkPresent)
+     {
+-        MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
+-        BookmarkDialog *bookmarkdialog = new BookmarkDialog(pginfo, mainStack);
+-        if (!bookmarkdialog->Create())
+-        {
+-            delete bookmarkdialog;
+-            delete pginfo;
+-            return res;
+-        }
++        TV::StartTV(pginfo, kStartTVNoFlags);
++
++        res = 0;
++
++        delete pginfo;
+     }
+     else
+     {
diff --git a/abs/core/mythtv/stable-29/mythweb/PKGBUILD b/abs/core/mythtv/stable-29/mythweb/PKGBUILD
new file mode 100644
index 0000000..9cd465e
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythweb/PKGBUILD
@@ -0,0 +1,58 @@
+pkgname=mythweb
+pkgver=29
+pkgrel=1
+commit_hash=`cat ../git_src/git_hash_web`
+pkgdesc="Web interface for MythTV's backend, $commit_hash"
+arch=('i686' 'x86_64')
+url="http://www.mythtv.org"
+license=('GPL')
+depends=('lighttpd' "mythtv>=${pkgver}" 'php' 'supplemental-web')
+groups=('mythtv-extras')
+install=mythweb.install
+
+patches=()
+source=(`echo ${patches[@]:0}` 
+        'mythweb.include'
+        'mythweb_gen_light.conf')
+
+build() {
+    if [ -e ${srcdir}/mythweb ]
+    then
+        msg "Removing old mythweb src"
+        rm -rf ${srcdir}/mythweb
+    fi
+
+    cd ${startdir}
+    msg "Copying in mythweb git_src"
+    cp -rp ../git_src/mythweb $srcdir
+    cd ${srcdir}/$pkgname
+
+    msg "--------------------------applying patches------------------------------"
+	for i in `echo ${patches[@]:0} `
+	do
+		echo applying $i
+		echo "-----------------------------"
+		patch -Np0  -i ${srcdir}/$i  || return 1
+	done
+    msg "--------------------------done applying patches-------------------------"
+
+	[ "$CARCH" = "i686"   ] && ARCH="i686"
+	[ "$CARCH" = "x86_64" ] && ARCH="x86-64"
+}
+
+package() {
+    DOCROOT=/data/srv/httpd/mythweb
+	mkdir -p $pkgdir/$DOCROOT/{image_cache,php_sessions,data}
+    rsync -arp --exclude .git* --delete-excluded  $srcdir/mythweb/* $pkgdir/$DOCROOT
+	rm $pkgdir/$DOCROOT/README
+	chown -R http:http $pkgdir/$DOCROOT
+	chmod -R 775 $pkgdir/$DOCROOT/{image_cache,php_sessions,data}
+
+    #install conf files for lighttpd
+    mkdir -p $pkgdir/etc/lighttpd
+    install -D -m 644 $srcdir/mythweb.include $pkgdir/etc/lighttpd/
+    #gen_light_conf
+    install -D -m0744 ${srcdir}/mythweb_gen_light.conf ${pkgdir}/etc/gen_light_conf.d/mythweb.conf
+}
+md5sums=('7645a6399434cbba35639713ac5d88e0'
+         'df190116b3aba35720fb6631885f973f')
diff --git a/abs/core/mythtv/stable-29/mythweb/mythweb.include b/abs/core/mythtv/stable-29/mythweb/mythweb.include
new file mode 100644
index 0000000..18e9be1
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythweb/mythweb.include
@@ -0,0 +1,8 @@
+alias.url += ( "/mythweb" => "/data/srv/httpd/mythweb/")
+
+url.rewrite-once = (
+"^/{1,2}mythweb/(css|data|images|js|themes|skins|[a-z_]+\.(php|pl)).*" => "$0",
+"^/{1,2}mythweb/(pl(/.*)?)$" => "/mythweb/mythweb.pl/$1",
+"^/{1,2}mythweb/(.+)$"       => "/mythweb/mythweb.php/$1",
+"^/{1,2}mythweb/(.*)$"       => "/mythweb/mythweb.php"
+)
\ No newline at end of file
diff --git a/abs/core/mythtv/stable-29/mythweb/mythweb.install b/abs/core/mythtv/stable-29/mythweb/mythweb.install
new file mode 100644
index 0000000..b8e31a8
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythweb/mythweb.install
@@ -0,0 +1,22 @@
+post_install() {
+ echo "==> Setting mythweb permissions."
+ chmod -R 755 /data/srv/httpd/mythweb/
+ chown mythtv:http /data/srv/httpd/mythweb/data/tv_icons
+ chmod -R 775 /data/srv/httpd/mythweb/{image_cache,php_sessions,data}
+ echo "==> Reading lighttpd's configuration file."
+ gen_light_include.py
+ echo "==> Restarting lighttpd."
+ /sbin/sv hup /service/lighttpd
+}
+
+post_upgrade() {
+  post_install
+}
+
+post_remove() {
+ gen_light_include.py
+ echo
+ echo "==> Forcing a re-read of lighttpd's configuration file."
+ echo ""
+ /sbin/sv hup /service/lighttpd
+}
diff --git a/abs/core/mythtv/stable-29/mythweb/mythweb_gen_light.conf b/abs/core/mythtv/stable-29/mythweb/mythweb_gen_light.conf
new file mode 100644
index 0000000..ddf0d2f
--- /dev/null
+++ b/abs/core/mythtv/stable-29/mythweb/mythweb_gen_light.conf
@@ -0,0 +1 @@
+include "/etc/lighttpd/mythweb.include"
-- 
cgit v0.12