How to install Mythtv Pre-34-Master on EndeavourOS (Archlinux)

For discussion of topics specific to MythTV on linux
Post Reply
User avatar
jfabernathy
Senior
Posts: 560
Joined: Wed Feb 18, 2015 2:37 pm
Location: Raleigh, NC
United States of America

How to install Mythtv Pre-34-Master on EndeavourOS (Archlinux)

Post by jfabernathy »

EDIT: I'm assuming you know something about Archlinux and it's packaging system, particularly the AUR and makepkg. If not, then the Archlinux wiki is an excellent resource. In fact many Linux forums will point to it in answering questions on their own distro.

I was having some issues with installing MythTV Master on EndeavourOS (EOS), which is Archlinux underneath. So I started over on a clean VM to test all of the instructions below. Now it's documented for me moving forward and maybe it will help someone else.

EDIT: this has been tested on both VM and real Intel PC with Intel GFX.

I created the VM on a Linux system using KVM/QEMU and libvirt-manager. The system that hosts the VM has a network bridge installed and configured so the VMs can be on the same subnet as my home network which contains my HDHomerun tuners.

1. Install EOS using defaults, ext4. no swap, KDE Plasma.
2. After reboot, install zramd with

Code: Select all

yay -S zramd
ignoring permission errors.
3. Edit /etc/default/zramd and set swap size as needed.
3. Enable zramd with

Code: Select all

sudo systemctl enable --now zramd.service
4. Disable firewalld because I can't get mythtv to work unless I do.

Code: Select all

sudo systemctl disable --now firewalld.service
5. Create the mythtv user exactly the way I like.

Code: Select all

 sudo useradd -m --groups optical,audio,video --home /home/mythtv --shell /bin/bash mythtv
6. Add my user (jim) to the mythtv group

Code: Select all

sudo usermod -aG mythtv jim
7. NOTE: this step is not needed if you installed with the latest (Endeavouros-Galileo-11-2023.iso) Edit /etc/nsswitch.conf so avahi will work on local network and find my nas. Change the hosts line to:

Code: Select all

hosts: mymachines mdns_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] files myhostname dns
8. Reboot for good measure.
9. Fix makepkg options for maximum parallel compiles by editing /etc/makepkg.conf. Set MAKEFLAGS="-j$(nproc)"
10. Install and build the mythtv-git AUR package

Code: Select all

yay -S mythtv-git --editmenu
take defaults on options, except the package to edit. Select the number of "mythtv-git".
Change the source= for
"git+https://github.com/MythTV/mythtv#branch=fixes/33"
and change to
"git+https://github.com/MythTV/mythtv#branch=master"

save and exit to continue build. Take defaults and enter password when required.

11. Setup mariadb per the Archlinux wiki

Code: Select all

sudo pacman -S --needed mariadb
sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
sudo systemctl enable --now mariadb.service
NOTE: the comments while running the command below tell you what to enter and it may not be the default option.

Code: Select all

sudo mysql_secure_installation
mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -uroot mysql
sudo systemctl restart mysql
12. Create a script to setup storage directories called create-dir.sh and add this text.

Code: Select all

#! /bin/bash

# Globals
mythtv_storagegroup_path=/srv/mythtv/
mythtv_storagegroups="banners coverart fanart recordings streaming videos bare-client db_backups livetv sports screenshots trailers music musicart"

sudo mkdir -p $mythtv_storagegroup_path
cd $mythtv_storagegroup_path
sudo mkdir -p $mythtv_storagegroups
sudo chown -R mythtv:mythtv $mythtv_storagegroup_path
sudo chmod -R  2775 $mythtv_storagegroup_path
Make the script executable and run it.

13. We now need to setup mythtv-backend.service and make it run as user 'mythtv'. Below is a script that will do that by copying the one that MythTV Debian packaging created. Copy the text below to a .sh file, make it executable, and run it.

Code: Select all

 #! /bin/bash
# Globals
mythtv_git_directory=/tmp/build
mythtv_git_branch=master

# this gets git source for mythtv/packaging
fn_get_git()
{
mkdir -p $mythtv_git_directory
cd $mythtv_git_directory

#mythtv packaging - we only need a few files
git clone -b $mythtv_git_branch https://github.com/MythTV/packaging.git
}

fn_setup_mythtv_backend_service()
{
sudo cp -n $mythtv_git_directory/packaging/deb/debian/mythtv-backend.service /lib/systemd/system/
sudo systemctl enable --now mythtv-backend
sudo systemctl daemon-reload
echo -e "\nmythtv-backend.service has been setup and enabled \n"

}

fn_tidy_up()
{
# remove local packaging repositories

rm -fr  $mythtv_git_directory/packaging

}

#main
# make sure we are not root
RUNNINGAS=`whoami`
if [ $RUNNINGAS = "root" ] ; then
    echo "Please run as ordinary user, not with sudo"
    exit 1
fi

fn_get_git
fn_setup_mythtv_backend_service
fn_tidy_up

exit 0
14. Point browser to localhost:6544
15. Click on Test Database Connection. Under Instructions, select Mariadb.
16. Create a file called setup.sql and paste in the content of the copy/paste from the browser window. save and exit.
17. Run

Code: Select all

sudo mysql -u root < setup.sql
18. Run

Code: Select all

mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql
19. Click Save button at bottom, and scroll back to top and click Restart Backend. The indicators should all be good now and the Next button should be enabled.
20. Some key settings:
General -> Host Address backend setup -> Primary IP address. Select from drop down.
Capture Card: in my case for the VM setup I created a couple of HDHomerun tuners to match my dual tuner hardware. I selected the IP of the tuner I wanted and clicked on EIT scan for this test.
Video Source: I create one named OTA using the Transmitted Guide only (EIT) grabber.
Input Connection: For Input Name I selected MPEG2TS. For Video Source I selected OTA. On Scan for Channels I selected Import HDHomerun channels since my Favorites are all properly setup on my HDHR. On the subsequent tuners I do not do the Scan for channels. Lastly I select Starting channel.
This is repeated for all tuners but the Scan for channels is only done on the first tuner.

21. On Storage Groups, I matched up all the Storage groups to the directories I setup earlier.
22. Click Restart Backend.

23. If this was on real hardware instead of a VM, we would need to account for the delay needed to allow the tuner to get itself stable prior to mythbackend to start running. The method below is one way of doing this:

Add an override to the mythtv-backend.service with:

Code: Select all

sudo --login systemctl edit mythtv-backend.service
Add or adjust the override file to include:

Code: Select all

[Service]
ExecStartPre=-/usr/local/bin/hdhomerun_check.py
Note the dash in the line above. That means that if the command fails, the backend will still start (so you
can watch recordings etc.) If you want to prevent the backend from starting, remove the dash.

You'll need to put the hdhomerun_check.py in /usr/local/bin and make it executable, owner/group root.

hdhomerun_check.py

Code: Select all

#!/usr/bin/python3
# -*- coding: utf-8 -*-

""" See if the HD Homerun box(s) are accessible and running

Requires Python 3.6 or later.

For backends started by systemd, use:

    sudo --preserve-env systemctl edit --force mythtv-backend.service

and enter or add as needed by your service:

    [Service]
    ExecStartPre=-/usr/local/bin/hdhomerun_check.py

Can be called with optional IP address(s) for users that
have multiple HDHRs that have STATIC addresses.

Use --help to see all options.

If run from the command line, then output will be to the screen.
Otherwise, a log file in /tmp named hdhr_discovery.log is made.
Changable with the --logfile switch.

Exit codes:

    0 = success (for *ALL* HDHRs if multiple IPs were specified)
    1 = no output from the hdhomerun_config discover command
    2 = IPv4 and IPv6 addresses found, disable IPv6 on NIC
    3 = logfile isn't writable, delete it and try again
    4 = keyboard interrupt
    5 x the number of HDHRs = HDHR is most likely not up

"""

__version__ = '1.28'

import argparse
import signal
import subprocess
import sys
from datetime import datetime
from os.path import basename
from os import _exit
from time import sleep


# pylint: disable=too-many-arguments,unused-argument
def keyboard_interrupt_handler(sigint, frame):
    ''' Handle all KeyboardInterrupts here. And, just leave. '''
    _exit(4)
# pylint: enable=unused-argument


def get_program_arguments():
    ''' Process the command line. '''

    parser = argparse.ArgumentParser(description='HDHR Access Test',
                                     epilog='*  Default values are in ()s')

    parser.add_argument('HOSTS', type=str,  default=None, nargs='*',
                        help='optional hostname(s)/IP(s) (%(default)s)')

    parser.add_argument('--attempts', default=20, type=int, metavar='<num>',
                        help='number of tries to find HDHRs (%(default)i)')

    parser.add_argument('--debug', action='store_true',
                        help='output additional information (%(default)s)')

    parser.add_argument('--logfile', default='/tmp/hdhomerun_check.log',
                        type=str, metavar='<lf>',
                        help='optional path + name of log file (%(default)s)')

    parser.add_argument('--sleep', default=1.5, type=float, metavar='<sec>',
                        help='seconds betweem attempts (%(default)s)')

    parser.add_argument('--version', action='version',
                        version='%(prog)s ' + __version__)

    return parser.parse_args()


def get_elapsed_time(start):
    ''' Calculate the time spent waiting for the HDHR to come up. '''

    delta = datetime.utcnow() - start
    rounded_delta = f'{delta.seconds + (delta.microseconds / 1000000):.3f}'
    return rounded_delta


def log_or_print(loglevel, message, output):
    ''' Add timestamp, log level then print to the selected location. '''

    print(datetime.now().strftime("%F %T.%f")[:-3], f'{loglevel:8}', message,
          file=output)


def last_message(loglevel, result, host, start, attempt, output):
    ''' Common success or failure message text. '''

    log_or_print(loglevel, f'{result} {"at " + host  + " " if host else ""}'
                 f'in {get_elapsed_time(start)} seconds '
                 f'and {attempt} attempt{"s"[attempt == 1:]}\n', output)


def check_one_device(host, args, output):
    ''' Try to discover the HDHR(s). '''

    attempt = 0
    command = ['hdhomerun_config', 'discover']
    start = datetime.utcnow()

    if host:
        command.append(host)

    for attempt in range(1, args.attempts+1):

        try:
            discovery_response = subprocess.check_output(
                command, text=True, stderr=subprocess.STDOUT).split()
        except subprocess.CalledProcessError:
            log_or_print('WARNING', f'{command[0]}: got no response, attempt: '
                         f'{attempt:2}', output)
            sleep(args.sleep)
            continue

        if not discovery_response:
            log_or_print('ERROR', f'No output from {command[0]}, aborting!',
                         output)
            sys.exit(1)

        if args.debug:
            log_or_print('DEBUG', f'Got: {" ".join(discovery_response)}',
                         output)

        if discovery_response.count('hdhomerun') > 1:
            log_or_print('ERROR', f'{command[0]}: more than 1 IP, aborting!',
                         output)
            sys.exit(2)

        if discovery_response[0] != 'hdhomerun':
            # Consider making this an ERROR and exiting not sleeping...
            log_or_print('WARNING', f'{command[0]} got an unexpected response:'
                         f' {" ".join(discovery_response)}',
                         output)
            sleep(args.sleep)
        else:
            last_message('INFO', f'Found HDHR {discovery_response[2]}', host,
                         start, attempt, output)
            return 0

    last_message('ERROR', 'No HDHR found', host, start, attempt, output)

    return 5


def main(args, output=None):
    ''' Control checking of one or more devices. '''

    log_or_print('INFO', f'Starting {basename(__file__)} v{__version__}, '
                 f'attempts={args.attempts}, sleep={args.sleep:.2f}', output)

    if args.HOSTS:

        return_value = 0

        for host in args.HOSTS:
            return_value += check_one_device(host, args, output)

    else:
        return_value = check_one_device(None, args, output)

    return return_value


if __name__ == '__main__':

    signal.signal(signal.SIGINT, keyboard_interrupt_handler)

    ARGS = get_program_arguments()

    if sys.stdin and sys.stdin.isatty():
        RETURN_VALUE = main(ARGS)
    else:
        try:
            with open(ARGS.logfile, encoding='ascii', mode='a') as file_obj:
                RETURN_VALUE = main(ARGS, output=file_obj)
        except PermissionError:
            print(f'Can\'t write to {ARGS.logfile}, aborting!')
            sys.exit(3)

    sys.exit(RETURN_VALUE)

# vim: set expandtab tabstop=4 shiftwidth=4 smartindent colorcolumn=80:

At this point you can run mythfrontend and test it out with EIT program guide information.
Last edited by jfabernathy on Sat Dec 02, 2023 12:21 am, edited 7 times in total.
User avatar
jfabernathy
Senior
Posts: 560
Joined: Wed Feb 18, 2015 2:37 pm
Location: Raleigh, NC
United States of America

Re: How to install Mythtv Pre-34-Master on EndeavourOS (Archlinux)

Post by jfabernathy »

Below is a bash shell script that can be used to add things to the mythtv backend that the first topic created. It provides the following functions:
1. Setup mythconverg daily backup and optimizing service/timer
2. Install xmltv
3. Setup mythfilldatabase service/timer

It's implemented as functions and you can comment out the call to any of them if they are not needed. Just save the text below to a .sh file and make it executable. Then run it.

Code: Select all

#! /bin/bash
# Globals
mythtv_git_directory=/tmp/build
mythtv_git_branch=master

fn_get_git()
{
mkdir -p $mythtv_git_directory
cd $mythtv_git_directory

#mythtv packaging - we only need a few files
git clone -b $mythtv_git_branch https://github.com/MythTV/packaging.git
git clone -b $mythtv_git_branch https://github.com/MythTV/mythtv.git
}

fn_setup_xmltv()
{
# install repository version (gets required perl modules)
yay -S xmltv
sudo ln -s /usr/bin/vendor_perl/tv_* /usr/local/bin/
echo -e "\nxmltv has been installed and updated to latest version"

}

fn_mythconverg_daily_backup()
{
# setup mythconverg daily backup, instead of weekly (personal preference)
sudo bash -c "cat >/etc/systemd/system/mythtv-database-backup.service" <<ENDOFSCRIPTINPUT
# This service unit is for backing up the mythtv database called mythconverg
#
[Unit]
Description=Backup MythTV Database 'mythconverg'
Requires=mysql.service
After=mysql.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/mythtv-database-backup.sh

ENDOFSCRIPTINPUT

sudo bash -c "cat >/etc/systemd/system/mythtv-database-backup.timer" <<ENDOFSCRIPTINPUT
# This timer unit is for mythtv-database-backup
#

[Unit]
Description=start mythtv-database-backup

[Timer]
Unit=mythtv-database-backup.service
OnCalendar=*-*-* 05:30:00
Persistent=true

[Install]
WantedBy=timers.target

ENDOFSCRIPTINPUT

sudo cp /tmp/build/mythtv/mythtv/contrib/maintenance/optimize_mythdb.pl /usr/local/bin/

sudo chmod a+x /usr/local/bin/optimize_mythdb.pl

sudo bash -c "cat >/usr/local/bin/mythtv-database-backup.sh" <<ENDOFSCRIPTINPUT
#!/bin/sh
# /etc/cron.weekly/mythtv-database script - check and backup mythconverg tables
# Copyright 2005/12/02 2006/10/08 Paul Andreassen
#                      2010 Mario Limonciello

set -e -u

DBNAME="mythconverg"
USER=mythtv
EMAILADDRESS="your-email-here@gmail.com"

/usr/bin/mysqlcheck -s \$DBNAME

BKUP_LOG=/tmp/backup-mythconverg.log

export MYTHCONFDIR=/home/\$USER/.mythtv/

/usr/local/bin/optimize_mythdb.pl | grep -v "^Analyzed:" 2>&1 >> \$BKUP_LOG

sudo --preserve-env --user=\$USER /usr/share/mythtv/mythconverg_backup.pl --rotate=5 --verbose 2>&1 >> \$BKUP_LOG

if [ \$? -eq 0 ]; then
    MSG="den-pc \$DBNAME Checked and Backed Up, RC=\$?"
else
    MSG="den-pc \$DBNAME Back Up Failed, RC=\$?"
fi

cd /srv/mythtv/db_backups
ls -l --directory --block-size=K * | tail -10 >> \$BKUP_LOG

#mail -s "\$MSG" \$EMAILADDRESS < \$BKUP_LOG

ENDOFSCRIPTINPUT

sudo chmod 755 /usr/local/bin/mythtv-database-backup.sh
sudo systemctl enable mythtv-database-backup.timer

echo -e "daily backup of mythconverg database has been setup"

}

fn_setup_mythfilldatabase()
{
sudo bash -c "cat >/etc/systemd/system/mythfilldatabase.timer" <<ENDOFSCRIPTINPUT
[Unit]
Description=MythTV mythfilldatabase timer.

[Timer]
OnCalendar=05:10:00
Persistent=true

[Install]
WantedBy=timers.target

ENDOFSCRIPTINPUT

sudo bash -c "cat >/etc/systemd/system/mythfilldatabase.service" <<ENDOFSCRIPTINPUT
[Unit]
Description=MythTV mythfilldatabase service.
Wants=mythtv-backend.service
After=mythtv-backend.service

[Service]
User=mythtv
Group=mythtv
Type=simple
ExecStart=/usr/bin/mythfilldatabase

[Install]
WantedBy=multi-user.target

ENDOFSCRIPTINPUT
sudo systemctl enable mythfilldatabase.timer
}

#main
# make sure we are not root
RUNNINGAS=`whoami`
if [ $RUNNINGAS = "root" ] ; then
    echo "Please run as ordinary user, not with sudo"
    exit 1
fi

#check mythbackend has been installed, if not abort with message
MYTHBACKEND=`which mythbackend`
if [ -z "$MYTHBACKEND" ]; then
    echo -e "mythbackend not found"
    exit 1
fi

# to disable any fn_ call just put # in front
# change the order at own risk - not tested!

fn_get_git
fn_mythconverg_daily_backup
fn_setup_mythfilldatabase
fn_setup_xmltv

echo -e "\n**************************************************"
echo -e "\nxmltv installed and updated to latest version"
echo -e "When using xmltv e.g. tv_grab_zz_sdjson"
echo -e "\nReferences:"
echo -e "  https://www.mythtv.org/wiki/Database_Setup"
echo -e "  https://www.mythtv.org/wiki/Build_from_Source"
echo -e "  https://www.mythtv.org/wiki/Systemd_mythbackend_Configuration"
echo -e "  https://www.mythtv.org/wiki/Setup_Storage_Directories"
echo -e "  https://www.mythtv.org/wiki/Mythfilldatabase"
echo -e "\nFinished setting up for mythtv-backend - Please reboot\n"
exit 0
Last edited by jfabernathy on Tue Nov 21, 2023 4:29 pm, edited 1 time in total.
User avatar
jfabernathy
Senior
Posts: 560
Joined: Wed Feb 18, 2015 2:37 pm
Location: Raleigh, NC
United States of America

Re: How to install Mythtv Pre-34-Master on EndeavourOS (Archlinux)

Post by jfabernathy »

If you want to change from EIT OTA program guide to Schedules Direct json sqlite grabber you need to do the xmltv part of the previous post and then follow along below:

The Electronic Program Guides (EPG) received over-the-air (OTA) are not ideal and we will not be using them here. We will be using SchedulesDirect (SD) EPG. XMLTV will be used to gather the EPG from SD. In this case, it will be for OTA ATSC 1.0 TV. We will use the XMLTV grabber called 'tv_grab_zz_sdjson_sqlite' and follow the instructions at:https://www.mythtv.org/wiki/XMLTV

This must be run as user 'mythtv'

Code: Select all

sudo su mythtv
cd
tv_grab_zz_sdjson_sqlite --manage-lineups --config-file $HOME/.mythtv/SD.xmltv
You can at this point add a lineup to your account or use your existing lineup.

Then select the "Initialize/update the local database"
Take the defaults on the next several questions until it exits.

Code: Select all

tv_grab_zz_sdjson_sqlite --configure --config-file $HOME/.mythtv/SD.xmltv
Take the default on database name/location.

Select the Lineup. If you only have one it will be listed and you can reply yes.

Take the defaults until the command exits.

Code: Select all

tv_grab_zz_sdjson_sqlite --days 0 --config-file $HOME/.mythtv/SD.xmltv
tv_grab_zz_sdjson_sqlite --manage-lineups --config-file $HOME/.mythtv/SD.xmltv
Select 'Manage database lineup channel selection'
Confirm your lineup.
Choose which channels are selected. Walk thru the channels and select yes or no.

When you're done with the list of channels, just exit.
Exit back to your normal user with 'exit' or ctrl-d

Now point the browser back to localhost:6544 and make the changes needed for SD EPG.

1. Click on the gear for backend setup and then Enable updates.
2. In Capture cards, I turn off the EIT scan
3. In Video Sources, I Delete All Video sources and then add a new one.
Video Source Name: SD (to match how we setup XMLTV
Listings grabber: Multnational (SD JSON web Services with SQLight DB)
Input Connection: Video Source = SD, Scan Type HDHomeRun Channel Import, select starting channel.
On subsequent tuners duplicate except for Scanning.
4. Restart Backend by clicking button.

If you did the setup in post 2 of this topic and setup mythfilldatabase service/timer then you just need to wait for the update tomorrow or force it to run now by:

Code: Select all

sudo systemctl start mythfilldatabase.service
Post Reply