ErsatzTV Mass Channel Automate

This guide demonstrates how to automate the addition of multiple channels to ErsatzTV using a Python script with Selenium WebDriver. If you regularly need to add a variety of channels to ErsatzTV and find the manual process time-consuming, this solution can streamline your workflow by automating channel and genre inputs.

Why Automation?

Automating the channel addition process in ErsatzTV provides several benefits:

  • Efficiency: Automates repetitive tasks, saving you significant time.
  • Accuracy: Reduces the risk of human error in data entry.
  • Scalability: Easily manage large lists of channels, adding them consistently without additional effort.

Prerequisites

Before you start, ensure you have the following:

  1. Python Installation: Python must be installed on your system. Download it from Python’s official website.
  2. Selenium WebDriver: Selenium is a powerful tool for web browser automation. You will need the Chrome WebDriver:
    • Download Chrome from ChromeDriver downloads. If using windows use chrome-win64.zip then unzip.
    • Download chromedriver if using windows chromedriver-win64.zip and unzip it.
    • Drop the chromedriver.exe in the chrome-win64 directory.
  3. Access to ErsatzTV: Ensure you have administrative access to ErsatzTV where you intend to add channels.

Setting Up Your Environment

  1. Install Selenium:
    • Open your command line interface (CLI) and run:Copy codepip install selenium
  2. Script Configuration:
    • Modify the webdriver_path in the script to point to where youโ€™ve placed chromedriver.exe.

Script Breakdown

The script automates these key steps:

  1. Initializes the Chrome WebDriver to interact with the web browser.
  2. Navigates to the ErsatzTV channel addition page using a predefined URL.
  3. Dynamically inputs the data for each channel’s name, genre, and group from a list into the ErsatzTV form. If a channel does not have a specified group, the script automatically assigns a user-defined default group.
  4. Submits the form for each channel entry using Selenium’s automation capabilities, ensuring that all fields are correctly filled before proceeding.

Running the Script

Prepare the Script:

  1. Save the provided Python script to a file named add_channels.py or whatever you want.
  2. Ensure your channels list in the script is updated according to your needs, especially paying attention to the group fieldโ€”if it’s empty, the default group will be used.

Execute the Script:

  1. Open a terminal or command prompt.
  2. Navigate to the directory containing add_channels.py.
  3. Run the script: python3 add_channels.py
  4. Watch the automated browser perform the data entry on ErsatzTV.

Monitoring:

  • The script will output logs in the console for each step, helping you track the automation process and troubleshoot if needed.
  • Logs include confirmation messages for each field, ensuring the correct data is entered before submitting the form.

Conclusion

Using this Selenium-based script to add channels to ErsatzTV transforms a manual, repetitive task into a seamless and efficient process. The script is designed with flexibility in mind, automatically applying a default group if none is provided for a channel. Customize the script as needed to accommodate different types or numbers of channels, enhancing your productivity and data management in ErsatzTV.

Script:

# ============================================
# ๐Ÿงญ CONFIGURATION
# ============================================
WEBDRIVER_PATH = 'chromedriver.exe'              # Path to ChromeDriver
URL = 'http://172.30.33.15:8409/channels/add'    # Target page URL
DEFAULT_GROUP = "Default Group"                  # Fallback group name
FIELD_WAIT = 10                                  # Seconds to wait for fields
CLICK_WAIT = 10                                  # Seconds to wait for buttons
DELAY_BETWEEN_ACTIONS = 0.5                      # Delay between typing
RELOAD_DELAY = 1                                 # Delay after adding a channel
CONFIG_FILE = 'channels.json'                    # Channel config file

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import os
import json
import sys

EXAMPLE_CHANNELS = [
    {"categories": "Comedy", "name": "LaughStream", "group": "General Entertainment"},
    {"categories": "Comedy", "name": "Comedy Central", "group": "General Entertainment"}
]

def load_or_create_config():
    if not os.path.exists(CONFIG_FILE):
        with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
            json.dump(EXAMPLE_CHANNELS, f, indent=4)
        print(f"'{CONFIG_FILE}' created. Edit it and rerun.")
        sys.exit(0)
    with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
        return json.load(f)

channels = load_or_create_config()

options = Options()
options.add_argument("--start-maximized")
service = Service(WEBDRIVER_PATH)
driver = webdriver.Chrome(service=service, options=options)

driver.get(URL)
time.sleep(2)

for channel in channels:
    try:
        name = channel.get("name", "")
        group = channel.get("group", DEFAULT_GROUP)
        categories = channel.get("categories", "")

        name_field = WebDriverWait(driver, FIELD_WAIT).until(
            EC.presence_of_element_located(
                (By.XPATH, '(//input[@type="text" and not(@readonly) and not(@disabled)])[3]')
            )
        )
        name_field.clear()
        name_field.send_keys(name)
        time.sleep(DELAY_BETWEEN_ACTIONS)

        group_field = WebDriverWait(driver, FIELD_WAIT).until(
            EC.presence_of_element_located(
                (By.XPATH, '(//input[@type="text" and not(@readonly) and not(@disabled)])[4]')
            )
        )
        group_field.clear()
        group_field.send_keys(group)
        time.sleep(DELAY_BETWEEN_ACTIONS)

        category_field = WebDriverWait(driver, FIELD_WAIT).until(
            EC.presence_of_element_located(
                (By.XPATH, '(//input[@type="text" and not(@readonly) and not(@disabled)])[5]')
            )
        )
        category_field.clear()
        category_field.send_keys(categories)
        time.sleep(DELAY_BETWEEN_ACTIONS)

        add_button = WebDriverWait(driver, CLICK_WAIT).until(
            EC.element_to_be_clickable(
                (By.XPATH, '//button[@type="button" and .//span[contains(text(), "Add Channel")]]')
            )
        )
        add_button.click()
        time.sleep(RELOAD_DELAY)

        driver.get(URL)
        time.sleep(1)

    except Exception as e:
        print(f"Error on {channel.get('name','(unknown)')}: {e}")
        driver.quit()
        sys.exit(1)

driver.quit()

Here is a list off a Ton of Channels Pre-formatted.

[
    {"categories": "Latest Movies", "name": "Epic 2024", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "CinemaNow 2024", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Spotlight 2024", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Premiere 2024", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Silver Screen 2023", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Cinematic 2022", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Blockbuster 2021", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Cinematic Era 2020", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Screen Spectacle 2018", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Blockbuster Vault 2017", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "NeoFlix 2016", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Screen Scene 2015", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Cinema 2013", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Flashback 2011", "group": "Random Movies"},
    {"categories": "Latest Movies", "name": "Reel 2010", "group": "Random Movies"},

    {"categories": "Comedy", "name": "LaughStream", "group": "General Entertainment"},
    {"categories": "Comedy", "name": "Comedy Central", "group": "General Entertainment"},
    {"categories": "Comedy", "name": "JokeBox", "group": "General Entertainment"},
    {"categories": "Comedy", "name": "GiggleTV", "group": "General Entertainment"},
    {"categories": "Comedy", "name": "Chuckle Channel", "group": "General Entertainment"},

    {"categories": "Drama", "name": "TurbulentTV", "group": "General Entertainment"},
    {"categories": "Drama", "name": "PassionPointe", "group": "General Entertainment"},
    {"categories": "Drama", "name": "FeelTheEmotion", "group": "General Entertainment"},
    {"categories": "Drama", "name": "VitalSignsTV", "group": "General Entertainment"},
    {"categories": "Drama", "name": "HeartbeatTV", "group": "General Entertainment"},

    {"categories": "Reality", "name": "RealWorld TV", "group": "General Entertainment"},
    {"categories": "Reality", "name": "Reality Stars", "group": "General Entertainment"},
    {"categories": "Reality", "name": "Survival TV", "group": "General Entertainment"},
    {"categories": "Reality", "name": "House & Home", "group": "General Entertainment"},
    {"categories": "Reality", "name": "Talent Quest", "group": "General Entertainment"},

    {"categories": "Family", "name": "FamilyTime", "group": "General Entertainment"},
    {"categories": "Family", "name": "KidsWorld", "group": "General Entertainment"},
    {"categories": "Family", "name": "Adventure Kids", "group": "General Entertainment"},
    {"categories": "Family", "name": "Toon Planet", "group": "General Entertainment"},
    {"categories": "Family", "name": "Family Classics", "group": "General Entertainment"},

    {"categories": "Crime", "name": "Crime Scene", "group": "Genre Specific"},
    {"categories": "Crime", "name": "Law & Order", "group": "Genre Specific"},
    {"categories": "Crime", "name": "Detective's Den", "group": "Genre Specific"},
    {"categories": "Crime", "name": "Underworld", "group": "Genre Specific"},
    {"categories": "Crime", "name": "CrimeWatch", "group": "Genre Specific"},

    {"categories": "Horror", "name": "Nightmare Cinema", "group": "Genre Specific"},
    {"categories": "Horror", "name": "HauntTV", "group": "Genre Specific"},
    {"categories": "Horror", "name": "Fright Night", "group": "Genre Specific"},
    {"categories": "Horror", "name": "ScreamStream", "group": "Genre Specific"},
    {"categories": "Horror", "name": "Dark Shadows", "group": "Genre Specific"},

    {"categories": "Science Fiction", "name": "Sci-Fi Spectrum", "group": "Genre Specific"},
    {"categories": "Science Fiction", "name": "Galactic TV", "group": "Genre Specific"},
    {"categories": "Science Fiction", "name": "Future Vision", "group": "Genre Specific"},
    {"categories": "Science Fiction", "name": "Alien Encounters", "group": "Genre Specific"},
    {"categories": "Science Fiction", "name": "CyberStream", "group": "Genre Specific"},

    {"categories": "Fantasy", "name": "MythosTV", "group": "Genre Specific"},
    {"categories": "Fantasy", "name": "Enchanted Realm", "group": "Genre Specific"},
    {"categories": "Fantasy", "name": "FantasyQuest", "group": "Genre Specific"},
    {"categories": "Fantasy", "name": "Dragon's Lair", "group": "Genre Specific"},
    {"categories": "Fantasy", "name": "Mystic Lands", "group": "Genre Specific"},

    {"categories": "Animation", "name": "Animotion", "group": "Niche and Special Interest"},
    {"categories": "Animation", "name": "ToonTime", "group": "Niche and Special Interest"},
    {"categories": "Animation", "name": "EpicToons", "group": "Niche and Special Interest"},
    {"categories": "Animation", "name": "Cartoon Galaxy", "group": "Niche and Special Interest"},
    {"categories": "Animation", "name": "Animagic", "group": "Niche and Special Interest"},

    {"categories": "Adult Cartoons", "name": "Nocturne Animations", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "Outlaw Toons", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "Twisted Laughs", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "PsycheToons", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "Retro Rebellion", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "DarkHumor TV", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "MatureToons", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "WickedCartoons", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "Edgy Animation", "group": "Niche and Special Interest"},
    {"categories": "Adult Cartoons", "name": "RebelToons", "group": "Niche and Special Interest"},

    {"categories": "Documentaries", "name": "Insight Films", "group": "Niche and Special Interest"},
    {"categories": "Documentaries", "name": "TrueVision", "group": "Niche and Special Interest"},
    {"categories": "Documentaries", "name": "LifeDoc", "group": "Niche and Special Interest"},
    {"categories": "Documentaries", "name": "DocuWorld", "group": "Niche and Special Interest"},
    {"categories": "Documentaries", "name": "Deep Dive", "group": "Niche and Special Interest"},

    {"categories": "Biography", "name": "BioPix", "group": "Niche and Special Interest"},
    {"categories": "Biography", "name": "Life Stories", "group": "Niche and Special Interest"},
    {"categories": "Biography", "name": "Portraits TV", "group": "Niche and Special Interest"},
    {"categories": "Biography", "name": "Icons Network", "group": "Niche and Special Interest"},
    {"categories": "Biography", "name": "Legendary Lives", "group": "Niche and Special Interest"},

    {"categories": "Adventure", "name": "Questline", "group": "Action and Adventure"},
    {"categories": "Adventure", "name": "Journey TV", "group": "Action and Adventure"},
    {"categories": "Adventure", "name": "Adventure Realm", "group": "Action and Adventure"},
    {"categories": "Adventure", "name": "Explorer's Edge", "group": "Action and Adventure"},
    {"categories": "Adventure", "name": "Epic Trails", "group": "Action and Adventure"},
    {"categories": "Adventure", "name": "Frontier TV", "group": "Action and Adventure"},
    {"categories": "Adventure", "name": "Odyssey Channel", "group": "Action and Adventure"},

    {"categories": "Action", "name": "Adrenaline Rush", "group": "Action and Adventure"},
    {"categories": "Action", "name": "Strike Force TV", "group": "Action and Adventure"},
    {"categories": "Action", "name": "Action Zone", "group": "Action and Adventure"},
    {"categories": "Action", "name": "PowerPlay", "group": "Action and Adventure"},
    {"categories": "Action", "name": "Impact TV", "group": "Action and Adventure"},
    {"categories": "Action", "name": "Shockwave", "group": "Action and Adventure"},
    {"categories": "Action", "name": "TurboMax", "group": "Action and Adventure"},
    {"categories": "Action", "name": "Combat Kings", "group": "Action and Adventure"},

    {"categories": "War", "name": "Battlefront TV", "group": "Action and Adventure"},
    {"categories": "War", "name": "Warriors' Legacy", "group": "Action and Adventure"},
    {"categories": "War", "name": "Conflict Chronicles", "group": "Action and Adventure"},
    {"categories": "War", "name": "ValorTV", "group": "Action and Adventure"},
    {"categories": "War", "name": "WarZone", "group": "Action and Adventure"},
    {"categories": "War", "name": "Patriot Films", "group": "Action and Adventure"},
    {"categories": "War", "name": "The Frontline", "group": "Action and Adventure"},

    {"categories": "Medical", "name": "MedixTV", "group": "Special Themes"},
    {"categories": "Medical", "name": "HealthScape", "group": "Special Themes"},
    {"categories": "Medical", "name": "VitalSigns", "group": "Special Themes"},
    {"categories": "Medical", "name": "MediVision", "group": "Special Themes"},
    {"categories": "Medical", "name": "DocuMed", "group": "Special Themes"},
    {"categories": "Medical", "name": "ER Chronicles", "group": "Special Themes"},
    {"categories": "Medical", "name": "Pulse Network", "group": "Special Themes"},
    {"categories": "Medical", "name": "MediStream", "group": "Special Themes"},
    {"categories": "Medical", "name": "The Med Channel", "group": "Special Themes"},
    {"categories": "Medical", "name": "ER TV", "group": "Special Themes"},
    {"categories": "Medical", "name": "LifeLine", "group": "Special Themes"},
    {"categories": "Medical", "name": "VitalWatch", "group": "Special Themes"},
    {"categories": "Medical", "name": "MediFocus", "group": "Special Themes"},
    {"categories": "Medical", "name": "CureTV", "group": "Special Themes"},

    {"categories": "Marijuana", "name": "Cannabis Chronicles", "group": "Special Themes"},
    {"categories": "Marijuana", "name": "GreenWave TV", "group": "Special Themes"},
    {"categories": "Marijuana", "name": "The High Life", "group": "Special Themes"},
    {"categories": "Marijuana", "name": "BlazeTV", "group": "Special Themes"},
    {"categories": "Marijuana", "name": "Weed World", "group": "Special Themes"},
    {"categories": "Marijuana", "name": "HerbVision", "group": "Special Themes"},

    {"categories": "Music and Musicals", "name": "Hits & Classics", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "RockOn TV", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "Rhythm & Blues", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "PopNation", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "Indie Beats", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "MelodyTV", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "SingAlong", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "Broadway Classics", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "DanceFloor", "group": "Music and Musicals"},
    {"categories": "Music and Musicals", "name": "Harmony Channel", "group": "Music and Musicals"},

    {"categories": "Food", "name": "Culinary Creations", "group": "Niche and Special Interest"},
    {"categories": "Food", "name": "Foodie Network", "group": "Niche and Special Interest"},
    {"categories": "Food", "name": "BakeTV", "group": "Niche and Special Interest"},
    {"categories": "Food", "name": "Gourmet Adventures", "group": "Niche and Special Interest"},
    {"categories": "Food", "name": "Healthy Eats", "group": "Niche and Special Interest"},

    {"categories": "Home Improvement", "name": "HomeRevive", "group": "Niche and Special Interest"},
    {"categories": "Home Improvement", "name": "Fixer Upper TV", "group": "Niche and Special Interest"},
    {"categories": "Home Improvement", "name": "DIY Dream", "group": "Niche and Special Interest"},
    {"categories": "Home Improvement", "name": "Renovation Nation", "group": "Niche and Special Interest"},
    {"categories": "Home Improvement", "name": "Home & Garden TV", "group": "Niche and Special Interest"}
]

Download all logos there are multiple of each. If any are missing or you have ideas for more just leave a comment!

Leave a Reply

Your email address will not be published. Required fields are marked *