Compare commits

..

No commits in common. "ed2f65bee521d7124d8d5dd90bd990e33e7a992a" and "2dc8ac2af75f8e05d640a890250f1c688fd18ac9" have entirely different histories.

4 changed files with 14 additions and 76 deletions

View File

@ -1,13 +1,8 @@
# Auto TTV Grabber # Auto TTV Grabber
<!--toc:start-->
- [Auto TTV Grabber](#auto-ttv-grabber)
- [Getting started](#getting-started)
<!--toc:end-->
## Getting started ## Getting started
This script relies on [streamlink](https://streamlink.github.io) being in your systems path. This script relies on [dl-stream](https://codeberg.org/bashuser30/dl-stream) being in your systems path.
You can find all of its requirements on the their project page. You can find all of its requirements on the their project page.
This script loops through all of the channels in `channel_list.txt` once per minute checking to seeif the channel is live via a HTTP request. This script loops through all of the channels in `channel_list.txt` once per minute checking to seeif the channel is live via a HTTP request.
Once a channel is live a [streamlink](https://streamlink.github.io) subprocess spawns in the background downloading the stream to it's default location (`$HOME/Downloads/Stream/<channel_name>`) Once a channel is live a [dl-stream](https://codeberg.org/bashuser30/dl-stream) subprocess spawns in the background downloading the stream to it's default location (`$HOME/Videos/dl-stream/<channel_name>`)

View File

@ -1,5 +0,0 @@
[settings]
streamlink_location = ""
download_location = ""
skip_ads =

69
main.py
View File

@ -1,47 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import configparser
import os import os
import requests
import shutil import shutil
import subprocess import subprocess
import sys import sys
import time import time
from datetime import datetime from datetime import datetime
from pathlib import Path
import requests
channel_list = [] channel_list = []
downloading = {} downloading = {}
# Default Config Settings
config = configparser.ConfigParser()
streamlink_location = "streamlink"
download_location = f"{Path.home()}/Downloads/Streams"
skip_ads = False
def load_config():
print("Reading config file...")
if os.path.exists("config.ini"):
config.read("config.ini")
if (
config.has_option("settings", "streamlink_location")
and not config["settings"]["streamlink_location"].strip()
):
streamlink_location = config["settings"]["streamlink_location"]
if (
config.has_option("settings", "download_location")
and not config["settings"]["download_location"].strip()
):
download_location = config["settings"]["download_location"]
if (
config.has_option("settings", "skip_ads")
and not config["settings"]["skip_ads"]
):
skip_ads = bool(config["settings"]["skip_ads"])
print("Config file loaded")
else:
print("No config file found using default values!")
def write_log(channel): def write_log(channel):
"""Writes the latest stdout of a process to log.txt""" """Writes the latest stdout of a process to log.txt"""
@ -53,15 +22,8 @@ def write_log(channel):
def download_stream(channel): def download_stream(channel):
"""Downloads a given channel name in its own subprocess""" """Downloads a given channel name in its own subprocess"""
# TODO: Just clean this up at somepoint
addtional_parms = ""
if skip_ads:
addtional_parms = "--twitch-proxy-playlist=https://lb-eu.cdn-perfprod.com,https://lb-eu2.cdn-perfprod.com,https://lb-na.cdn-perfprod.com,https://lb-as.cdn-perfprod.com,https://as.luminous.dev --twitch-disable-ads"
file_name = f"{channel}_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.ts"
cmd = f"{streamlink_location} --loglevel none --retry-max 10 {addtional_parms} -o {download_location}/{channel}/{file_name} twitch.tv/{channel} best"
downloading[channel] = subprocess.Popen( downloading[channel] = subprocess.Popen(
[cmd], ["dl-stream", "-r", channel],
shell=True,
start_new_session=True, start_new_session=True,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
@ -71,11 +33,11 @@ def download_stream(channel):
def check_system(): def check_system():
"""Makes sure everything is place for the script to run""" """Makes sure everything is place for the script to run"""
# Checks if streamlink is in the systems path # TODO: Make it fallback to streamlink if dl-stream not present
if not shutil.which("streamlink"): # Checks if dl-stream is in the systems path
sys.exit("ERROR: streamlink is not found in the systems path!") if not shutil.which("dl-stream"):
sys.exit("ERROR: dl-stream is not found in the systems path!")
# TODO: Combine the channel_list into the config
# Checks if the channel_list exists and if not makes one # Checks if the channel_list exists and if not makes one
if not os.path.exists("channel_list.txt"): if not os.path.exists("channel_list.txt"):
print("ERROR:'channel_list.txt' does not exist, creating now!") print("ERROR:'channel_list.txt' does not exist, creating now!")
@ -83,20 +45,13 @@ def check_system():
pass # Creates empty file pass # Creates empty file
sys.exit("Please populate the channel_list.txt with one channel per line!") sys.exit("Please populate the channel_list.txt with one channel per line!")
# Make sure the download location exists
if not os.path.exists(download_location):
print(
f"Download destination does not exist.\n Creating now at {download_location}"
)
os.makedirs(download_location)
def stop_downloads(): def stop_downloads():
"""Goes through every process and stops it if running""" """Goes through every process and stops it if running"""
print("\nCleaning up...") print("\nCleaning up...")
for name, proc in downloading.items(): for name, proc in downloading.items():
proc.terminate() proc.terminate()
print(f"Stopping download of {name}") print("Stopping download of " + name)
def main(): def main():
@ -116,22 +71,21 @@ def main():
print("\n------------------------------------") print("\n------------------------------------")
for channel in channel_list: for channel in channel_list:
channel = channel.strip() channel = channel.strip()
# TODO: Have steamlink itself check if the channel is live
contents = requests.get("https://www.twitch.tv/" + channel).content.decode( contents = requests.get("https://www.twitch.tv/" + channel).content.decode(
"utf-8" "utf-8"
) )
if "isLiveBroadcast" in contents: if "isLiveBroadcast" in contents:
print(f"\033[1m{channel}\033[0m is \033[32mlive\033[0m!") print("\033[1m" + channel + "\033[0m is \033[32mlive\033[0m!")
if channel not in downloading: if channel not in downloading:
download_stream(channel) download_stream(channel)
else: else:
print(f"{channel} is already downloading") print(channel + " is already downloading")
write_log(channel) write_log(channel)
else: else:
print("\033[1m" + channel + "\033[0m is \033[31mnot live\033[0m.") print("\033[1m" + channel + "\033[0m is \033[31mnot live\033[0m.")
if channel in downloading: if channel in downloading:
del downloading[channel] del downloading[channel]
print(f"{channel} is no longer downloading") print(channel + " is no longer downloading")
time.sleep(1) # Wait one second before going to next channel time.sleep(1) # Wait one second before going to next channel
print( print(
"\n\033[3mLast checked: " + datetime.now().strftime("%H:%M:%S") + "\033[0m" "\n\033[3mLast checked: " + datetime.now().strftime("%H:%M:%S") + "\033[0m"
@ -143,7 +97,6 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
""" This is executed when run from the command line """ """ This is executed when run from the command line """
try: try:
load_config()
check_system() check_system()
main() main()
finally: finally:

View File

@ -1,5 +0,0 @@
certifi==2024.2.2
charset-normalizer==3.3.2
idna==3.6
requests==2.31.0
urllib3==2.2.1