Compare commits

..

11 Commits

Author SHA1 Message Date
ed2f65bee5 Should maybe make requests a requirement 2024-04-06 23:47:07 -04:00
18c0f2123d Fixed stream saved location 2024-04-06 22:44:51 -04:00
91582c67bd Have to use the shell argument for the subprocess 2024-04-06 22:30:51 -04:00
bd874d7245 Hell transfer2 2024-04-06 21:05:40 -04:00
fe61cdf07e Hell transfer 2024-04-06 21:04:41 -04:00
d519900ba8 What is this path issue? 2024-04-05 20:49:48 -04:00
a0ae115748 Fixed f-string 2024-04-05 17:02:58 -04:00
5ee8e47c54 Attempt to switch from dl-stream to streamlink 2024-04-05 16:55:42 -04:00
3957eb40ca Start to read the config file 2024-04-05 15:54:40 -04:00
3ed0035dd7 F is for f-strings 2024-04-05 15:11:59 -04:00
f987443654 Begin working with config file 2024-04-05 14:01:42 -04:00
4 changed files with 76 additions and 14 deletions

View File

@ -1,8 +1,13 @@
# 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 [dl-stream](https://codeberg.org/bashuser30/dl-stream) being in your systems path. This script relies on [streamlink](https://streamlink.github.io) 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 see if the channel is live via a HTTP request.
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>`) 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>`)

5
config.ini Normal file
View File

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

69
main.py
View File

@ -1,16 +1,47 @@
#!/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"""
@ -22,8 +53,15 @@ 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(
["dl-stream", "-r", channel], [cmd],
shell=True,
start_new_session=True, start_new_session=True,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
@ -33,11 +71,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"""
# TODO: Make it fallback to streamlink if dl-stream not present # Checks if streamlink is in the systems path
# Checks if dl-stream is in the systems path if not shutil.which("streamlink"):
if not shutil.which("dl-stream"): sys.exit("ERROR: streamlink is not found in the systems path!")
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!")
@ -45,13 +83,20 @@ 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("Stopping download of " + name) print(f"Stopping download of {name}")
def main(): def main():
@ -71,21 +116,22 @@ 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("\033[1m" + channel + "\033[0m is \033[32mlive\033[0m!") print(f"\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(channel + " is already downloading") print(f"{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(channel + " is no longer downloading") print(f"{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"
@ -97,6 +143,7 @@ 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:

5
requirements.txt Normal file
View File

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