443 lines
14 KiB
HTML
443 lines
14 KiB
HTML
<html>
|
|
<head>
|
|
<link rel="stylesheet" href="https://pyscript.net/releases/2023.11.1/core.css" />
|
|
<script type="module" src="https://pyscript.net/releases/2023.11.1/core.js"></script>
|
|
<body>
|
|
|
|
<py-script output="out">
|
|
with open("venv/lib/python3.8/site-packages/pytube/innertube.py", "r+") as file:
|
|
data = file.read()
|
|
if not "headers.update(self.header)" in data:
|
|
data = data.split("\n")
|
|
data[240] += "\n\n headers.update(self.header)"
|
|
data = "\n".join(data)
|
|
if "self.api_key" in data.split("\n")[89]:
|
|
data = data.split("\n")
|
|
data[89] += "\n self.header = _default_clients[client]['header']"
|
|
data = "\n".join(data)
|
|
if "__init__(self, client='ANDROID'" in data.split("\n")[77]:
|
|
data = data.split("\n")
|
|
data[77] = data[77].replace("'ANDROID'", "'ANDROID_MUSIC'")
|
|
data = "\n".join(data)
|
|
if data.split("\n")[68] == " }":
|
|
data = data.split("\n")
|
|
data[68] = """ },
|
|
'ANDROID_MUSIC': {
|
|
'context': {
|
|
'client': {
|
|
'clientName': 'ANDROID_MUSIC',
|
|
'clientVersion': '5.16.51',
|
|
'androidSdkVersion': 30
|
|
}
|
|
},
|
|
'header': {
|
|
'User-Agent': 'com.google.android.apps.youtube.music/'
|
|
},
|
|
'api_key': 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8'
|
|
},"""
|
|
data = "\n".join(data)
|
|
file.seek(0)
|
|
file.write(data)
|
|
file.truncate()
|
|
|
|
with open("venv/lib/python3.8/site-packages/pytube/request.py", "r+") as file:
|
|
data = file.read()
|
|
if "e.s" in data.split("\n")[180]:
|
|
data = data.split("\n")
|
|
data[180] = ""
|
|
data[179] = """
|
|
resp = _execute_request(
|
|
url + f"&range={0}-{99999999999}",
|
|
method="GET",
|
|
timeout=timeout
|
|
)
|
|
content_range = resp.info()["Content-Length"]
|
|
file_size = int(content_range)"""
|
|
data = "\n".join(data)
|
|
if not "range" in data.split("\n")[157]:
|
|
data = data.split("\n")
|
|
data[157] = data[157].replace("url,", 'url + f"&range={downloaded}-{stop_pos}",')
|
|
data = "\n".join(data)
|
|
file.seek(0)
|
|
file.write(data)
|
|
file.truncate()
|
|
|
|
from twitchrealtimehandler import TwitchImageGrabber
|
|
import xml.etree.ElementTree as ElementTree
|
|
from moviepy.editor import VideoFileClip
|
|
from skimage.transform import resize
|
|
from getkey import getkey, keys
|
|
from replit import clear, audio
|
|
from pytube import YouTube
|
|
from html import unescape
|
|
import threading
|
|
import requests
|
|
import datetime
|
|
import math
|
|
import glob
|
|
import time
|
|
import os
|
|
|
|
isOwner = os.path.exists("/tmp/audioStatus.json")
|
|
|
|
# thx @hecker40
|
|
def fg(r, g, b):
|
|
return f"\033[38;2;{int(r)};{int(g)};{int(b)}m"
|
|
def bg(r, g, b):
|
|
return f"\033[48;2;{int(r)};{int(g)};{int(b)}m"
|
|
reset = "\033[0m"
|
|
|
|
# thx @ColoredHue
|
|
def hide_cursor():
|
|
print("\033[?25l", end="", flush=True)
|
|
def show_cursor():
|
|
print("\033[?25h", end="", flush=True)
|
|
|
|
for file in glob.glob("*.mp3"):
|
|
os.remove(file)
|
|
|
|
for file in glob.glob("*.mp4"):
|
|
os.remove(file)
|
|
|
|
show_cursor()
|
|
|
|
print("How would you like to calculate screen size?")
|
|
print("1: The Automatic Way")
|
|
print("2: The Cool Way")
|
|
option = input("> ")
|
|
|
|
if option == "1":
|
|
size = os.get_terminal_size()
|
|
width = size.columns
|
|
height = size.lines
|
|
else:
|
|
clear()
|
|
print("You're about to be asked questions so we can get the correct screen size. You may be asked to see which character appears in the corner, but oftern this is obscured by buttons. To remove them, click off the screen")
|
|
print()
|
|
input("Press enter to continue > ")
|
|
clear()
|
|
|
|
chars = "0123456789abcdef"
|
|
msg = "Which character appears in the top right corner of the screen? > "
|
|
|
|
print(chars*len(chars))
|
|
print()
|
|
c = input(msg).lower()
|
|
clear()
|
|
|
|
for x in chars:
|
|
print(" "*chars.find(c)+x+" "*(len(chars)-chars.find(c)-1), end="", flush=False)
|
|
print("\n", flush=True)
|
|
c2 = input(msg).lower()
|
|
clear()
|
|
|
|
width = chars.find(c2)*len(chars)+chars.find(c)+1
|
|
|
|
for x in chars:
|
|
for y in chars:
|
|
print(" "*(width-1), y, sep="", flush=False)
|
|
print(flush=True)
|
|
c = input(msg).lower()
|
|
clear()
|
|
|
|
i = 0
|
|
for x in chars:
|
|
for y in chars:
|
|
if y == c:
|
|
print(" "*(width-1), chars[i], sep="", flush=False)
|
|
i += 1
|
|
else:
|
|
print(flush=False)
|
|
print(flush=True)
|
|
c2 = input(msg).lower()
|
|
|
|
height = len(chars)**2 - (chars.find(c2) * len(chars) + chars.find(c)) + math.ceil((len(msg) + 1) / width) + 1
|
|
|
|
clear()
|
|
print("Choose an option")
|
|
print("1: Download from YouTube")
|
|
print("2: Livestream from Twitch")
|
|
|
|
if isOwner:
|
|
print("3: Custom MP4s")
|
|
option = input("> ")
|
|
youtube = option != "2" and option != "3"
|
|
twitch = option == "2"
|
|
custom = option == "3"
|
|
else:
|
|
option = input("> ")
|
|
youtube = option != "2"
|
|
twitch = option == "2"
|
|
custom = False
|
|
|
|
clear()
|
|
today = datetime.date.today()
|
|
aprilfools = today.month == 4 and today.day == 1
|
|
if youtube:
|
|
url = input("Enter a YouTube video url > ")
|
|
if aprilfools:
|
|
url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
|
elif custom:
|
|
print("Upload an mp4 file to continue")
|
|
while len(glob.glob("*.mp4")) == 0:
|
|
time.sleep(3)
|
|
else:
|
|
url = input("Enter a Twitch livestream url > ")
|
|
contents = requests.get(url).content.decode("utf-8")
|
|
if not "isLiveBroadcast" in contents:
|
|
clear()
|
|
print("This channel is not currently live. Please try again with a different channel")
|
|
while True:
|
|
pass
|
|
|
|
if isOwner and not twitch:
|
|
clear()
|
|
playAudio = input("Do you want audio? y/n > ") == "y"
|
|
if playAudio:
|
|
audio.play_tone(0.01, 262, 0)
|
|
input("Press enter to continue > ")
|
|
else:
|
|
playAudio = False
|
|
|
|
if youtube:
|
|
clear()
|
|
enableCaptions = input("Do you want captions? y/n > ") == "y" or aprilfools
|
|
else:
|
|
enableCaptions = False
|
|
|
|
clear()
|
|
print("Choose a quality")
|
|
print("1: 1x Resolution")
|
|
print("2: 4x Resolution (Warning: Glitchy)")
|
|
option = input("> ")
|
|
|
|
fourRes = option == "2"
|
|
|
|
pixWidth = width
|
|
pixHeight = height
|
|
|
|
if not fourRes:
|
|
pixWidth //= 2
|
|
pixHeight -= 1
|
|
else:
|
|
pixHeight *= 2
|
|
pixWidth -= 12
|
|
pixHeight -= 4
|
|
|
|
# This fixes a bug and also lets me download in a very easy format
|
|
# adapted from https://stackoverflow.com/a/69004322/17766761
|
|
def xml_caption_to_dict(xml):
|
|
segments = []
|
|
root = ElementTree.fromstring(xml)
|
|
count_line = 0
|
|
for i, child in enumerate(list(root.findall("body/p"))):
|
|
text = "".join(child.itertext()).strip()
|
|
if not text:
|
|
continue
|
|
count_line += 1
|
|
caption = unescape(text.replace("\n", " ").replace(" ", " "),)
|
|
try:
|
|
duration = float(child.attrib["d"])
|
|
except KeyError:
|
|
duration = 0.0
|
|
start = float(child.attrib["t"])
|
|
try:
|
|
end2 = float(root.findall("body/p")[i+2].attrib["t"])
|
|
except:
|
|
end2 = float(root.findall("body/p")[i].attrib["t"]) + duration
|
|
line = {
|
|
"start": start / 1000,
|
|
"end": end2 / 1000,
|
|
"text": caption,
|
|
}
|
|
segments.append(line)
|
|
return segments
|
|
|
|
def getFrame():
|
|
global currentFrame
|
|
while True:
|
|
start = time.time()
|
|
currentFrame = imageGrabber.grab()
|
|
duration = time.time()-start
|
|
time.sleep(max(1/fps-duration, 0))
|
|
|
|
if not twitch:
|
|
if youtube:
|
|
clear()
|
|
print("Downloading Video...")
|
|
|
|
yt = YouTube(url)
|
|
vid = yt.streams.filter(file_extension="mp4").first()
|
|
vid.download()
|
|
|
|
clear()
|
|
print("Opening Video...")
|
|
|
|
filename = glob.glob("*.mp4")[0]
|
|
os.replace(filename, "video.mp4")
|
|
vid = VideoFileClip("video.mp4")
|
|
|
|
clear()
|
|
print("Resizing Video...")
|
|
|
|
vidWidth, vidHeight = vid.size
|
|
ratio = min(pixWidth / vidWidth, pixHeight / vidHeight)
|
|
|
|
vid = vid.resize(ratio)
|
|
|
|
if playAudio:
|
|
clear()
|
|
print("Extracting Audio...")
|
|
|
|
vidAudio = vid.audio
|
|
vidAudio.write_audiofile("audio.mp3", logger=None)
|
|
|
|
if enableCaptions:
|
|
clear()
|
|
print("Downloading Captions...")
|
|
|
|
captions = yt.captions
|
|
if "en" in captions:
|
|
captions = captions.get_by_language_code("en")
|
|
elif "a.en" in captions:
|
|
captions = captions.get_by_language_code("a.en")
|
|
else:
|
|
enableCaptions = False
|
|
|
|
if enableCaptions:
|
|
captions = xml_caption_to_dict(captions.xml_captions)
|
|
|
|
hide_cursor()
|
|
clear()
|
|
|
|
if playAudio:
|
|
source = audio.play_file("audio.mp3")
|
|
else:
|
|
clear()
|
|
print("Connecting...")
|
|
fps = 4
|
|
|
|
try:
|
|
imageGrabber = TwitchImageGrabber(
|
|
twitch_url = url,
|
|
quality = "160p",
|
|
blocking = True,
|
|
rate = fps,
|
|
)
|
|
except ValueError:
|
|
imageGrabber = TwitchImageGrabber(
|
|
twitch_url = url,
|
|
quality = "480p",
|
|
blocking = True,
|
|
rate = fps,
|
|
)
|
|
|
|
currentFrame = None
|
|
|
|
threading.Thread(target=getFrame).start()
|
|
|
|
while currentFrame is None:
|
|
time.sleep(0.1)
|
|
|
|
start = time.time()
|
|
|
|
paused = False
|
|
stop = False
|
|
|
|
def controls():
|
|
global paused, start, playAudio, source
|
|
while stop is False:
|
|
key = getkey()
|
|
if key == " " or key == "k":
|
|
paused = not paused
|
|
if not twitch:
|
|
if key == keys.LEFT:
|
|
start += 10
|
|
if playAudio:
|
|
source.paused = True
|
|
playAudio = False
|
|
elif key == keys.RIGHT:
|
|
start -= 10
|
|
if playAudio:
|
|
source.paused = True
|
|
playAudio = False
|
|
elif key == "r":
|
|
if playAudio:
|
|
source.paused = True
|
|
source = audio.play_file("audio.mp3")
|
|
start = time.time()
|
|
if playAudio:
|
|
if key == "+" or key == "=":
|
|
source.volume += 0.1
|
|
elif key == "-":
|
|
if source.volume - 0.1 > 0:
|
|
source.volume -= 0.1
|
|
|
|
thread = threading.Thread(target=controls)
|
|
thread.start()
|
|
|
|
try:
|
|
while True:
|
|
if not twitch:
|
|
t = time.time() - start
|
|
frame = vid.make_frame(t=t)
|
|
else:
|
|
frame = currentFrame
|
|
vidWidth = len(frame[0])
|
|
vidHeight = len(frame)
|
|
ratio = min(pixWidth / vidWidth, pixHeight / vidHeight)*2
|
|
frame = resize(frame, (pixHeight*ratio, pixWidth*ratio))
|
|
for column in range(len(frame)):
|
|
for row in range(len(frame[column])):
|
|
frame[column][row] = [x*255 for x in frame[column][row]]
|
|
text = "\033c"
|
|
if fourRes:
|
|
for column in range(0, len(frame), 2):
|
|
for row in range(len(frame[column])):
|
|
try:
|
|
text += bg(*frame[column][row])+fg(*frame[column + 1][row])+"▄"
|
|
except IndexError:
|
|
text += reset+fg(*frame[column][row])+"▀"
|
|
text += "\n"
|
|
else:
|
|
for column in frame:
|
|
for pixel in column:
|
|
text += bg(*pixel)+" "
|
|
text += "\n"
|
|
text += reset
|
|
if enableCaptions:
|
|
for caption in captions:
|
|
if caption["start"] < t and caption["end"] > t:
|
|
text += "\n"
|
|
if not aprilfools:
|
|
text += caption["text"].center(width)
|
|
else:
|
|
text += "April Fools!".center(width)
|
|
print(text, end="", flush=True)
|
|
time.sleep(0.25)
|
|
if paused:
|
|
if not twitch:
|
|
if playAudio:
|
|
source.paused = True
|
|
pauseStart = time.time()
|
|
while paused:
|
|
pass
|
|
if not twitch:
|
|
start += time.time() - pauseStart
|
|
if playAudio:
|
|
source.paused = False
|
|
except OSError:
|
|
clear()
|
|
print("Video Finished! Don't forget to like and subscribe!")
|
|
stop = True
|
|
except KeyboardInterrupt:
|
|
stop = True
|
|
</py-script>
|
|
|
|
<div id="out"></div>
|
|
|
|
</body>
|
|
|
|
|
|
</head>
|
|
</html> |