MarseyWorld/files/routes/streamers.py

174 lines
4.7 KiB
Python
Raw Normal View History

[DO NOT MERGE] import detanglation (#442) * move Base definition to files.classes.__init__.py * fix ImportError * move userpage listing to users.py * don't import the app from classes * consts: set default values to avoid crashes consts: warn if the secret key is the default config value * card view: sneed (user db schema) * cloudflare: use DEFAULT_CONFIG_VALUE * const: set default values * decouple media.py from __main__ * pass database to avoid imports * import cleanup and import request not in const, but in the requests mega import * move asset_submissions site check to __init__ * asset submissions feature flag * flag * g.is_tor * don't import request where it's not needed * i think this is fine * mail: move to own routes and helper * wrappers * required wrappers move * unfuck wrappers a bit * move snappy quotes and marseys to stateful consts * marsify * :pepodrool: * fix missing import * import cache * ...and settings.py * and static.py * static needs cache * route * lmao all of the jinja shit was in feeds.py amazing * classes should only import what they need from flask * import Response * hdjbjdhbhjf * ... * dfdfdfdf * make get a non-required import * isort imports (mostly) * but actually * configs * reload config on import * fgfgfgfg * config * config * initialize snappy and test * cookie of doom debug * edfjnkf * xikscdfd * debug config * set session cookie domain, i think this fixes the can't login bug * sdfbgnhvfdsghbnjfbdvvfghnn * hrsfxgf * dump the entire config on a request * kyskyskyskyskyskyskyskyskys * duifhdskfjdfd * dfdfdfdfdfdfdfdfdfdfdfdf * dfdfdfdf * imoprt all of the consts beacuse fuck it * 😭 * dfdfdfdfdfdfsdasdf * print the entire session * rffdfdfjkfksj * fgbhffh * not the secret keys * minor bug fixes * be helpful in the warning * gfgfgfg * move warning lower * isort main imports (i hope this doesn't fuck something up) * test * session cookie domain redux * dfdfdfd * try only importing Flask * formkeys fix * y * :pepodrool: * route helper * remove before flight * dfdfdfdfdf * isort classes * isort helpers * move check_for_alts to routehelpers and also sort imports and get rid of unused ones * that previous commit but actkally * readd the cache in a dozen places they were implicitly imported * use g.is_tor instead of request.headers. bla bla bla * upgrade streamers to their own route file * get rid of unused imports in __main__ * fgfgf * don't pull in the entire ORM where we don't need it * features * explicit imports for the get helper * explicit imports for the get helper redux * testing allroutes * remove unused import * decouple flask from classes * syntax fix also remember these have side fx for some reason (why?) * move side effects out of the class * posts * testing on devrama * settings * reloading * settingssdsdsds * streamer features * site settings * testing settings on devrama * import * fix modlog * remove debug stuff * revert commit 67275b21ab6e2f2520819e84d10bfc1c746a15b6 * archiveorg to _archiveorg * skhudkfkjfd * fix cron for PCM * fix bugs that snekky wants me to * Fix call to realbody passing db, standardize kwarg * test * import check_for_alts from the right place * cloudflare * testing on devrama * fix cron i think * shadow properly * tasks * Remove print which will surely be annoying in prod. * v and create new session * use files.classes * make errors import little and fix rare 500 in /allow_nsfw * Revert "use files.classes" This reverts commit 98c10b876cf86ce058b7fb955cf1ec0bfb9996c6. * pass v to media functions rather than using g * fix * dfdfdfdfd * cleanup, py type checking is dumb so don't use it where it causes issues * Fix some merge bugs, add DEFAULT_RATELIMIT to main. * Fix imports on sqlalchemy expressions. * `from random import random` is an error. * Fix replies db param. * errors: fix missing import * fix rare 500: only send to GIFT_NOTIF_ID if it exists, and send them the right text * Fix signup formkey. * fix 2 500s * propagate db to submissions * fix replies * dfdfdfdf * Fix verifiedcolor. * is_manual * can't use getters outside of an app context * don't attempt to do gumroad on sites where it's not enabled * don't attempt to do gumraod on sites's where it's unnecessary * Revert "don't attempt to do gumroad on sites where it's not enabled" This reverts commit 6f8a6331878655492dfaf1907b27f8be513c14d3. * fix 500 * validate media type Co-authored-by: TLSM <duolsm@outlook.com>
2022-11-15 09:19:08 +00:00
import re
import requests
from files.classes.streamers import Streamer
from files.helpers.alerts import send_repeatable_notification
from files.helpers.const import *
from files.routes.wrappers import *
from files.__main__ import app, cache
id_regex = re.compile('"externalId":"([^"]*?)"', flags=re.A)
live_regex = re.compile('playerOverlayVideoDetailsRenderer":\{"title":\{"simpleText":"(.*?)"\},"subtitle":\{"runs":\[\{"text":"(.*?)"\},\{"text":" • "\},\{"text":"(.*?)"\}', flags=re.A)
live_thumb_regex = re.compile('\{"thumbnail":\{"thumbnails":\[\{"url":"(.*?)"', flags=re.A)
offline_regex = re.compile('","title":"(.*?)".*?"width":48,"height":48\},\{"url":"(.*?)"', flags=re.A)
offline_details_regex = re.compile('simpleText":"Streamed ([0-9]*?) ([^"]*?)"\},.*?"viewCountText":\{"simpleText":"([0-9,]*?) views"', flags=re.A)
def process_streamer(id, live='live'):
url = f'https://www.youtube.com/channel/{id}/{live}'
req = requests.get(url, cookies={'CONSENT': 'YES+1'}, timeout=5)
text = req.text
if '"videoDetails":{"videoId"' in text:
y = live_regex.search(text)
count = y.group(3)
if count == '1 watching now':
count = "1"
if 'waiting' in count:
if live != '':
return process_streamer(id, '')
else:
return None
count = int(count.replace(',', ''))
t = live_thumb_regex.search(text)
thumb = t.group(1)
name = y.group(2)
title = y.group(1)
return (True, (id, req.url, thumb, name, title, count))
else:
t = offline_regex.search(text)
if not t:
if live != '':
return process_streamer(id, '')
else:
return None
y = offline_details_regex.search(text)
if y:
views = y.group(3).replace(',', '')
quantity = int(y.group(1))
unit = y.group(2)
if unit.startswith('second'):
modifier = 1/60
elif unit.startswith('minute'):
modifier = 1
elif unit.startswith('hour'):
modifier = 60
elif unit.startswith('day'):
modifier = 1440
elif unit.startswith('week'):
modifier = 10080
elif unit.startswith('month'):
modifier = 43800
elif unit.startswith('year'):
modifier = 525600
minutes = quantity * modifier
actual = f'{quantity} {unit}'
else:
minutes = 9999999999
actual = '???'
views = 0
thumb = t.group(2)
name = t.group(1)
return (False, (id, req.url.rstrip('/live'), thumb, name, minutes, actual, views))
def live_cached():
live = []
offline = []
db = db_session()
streamers = [x[0] for x in db.query(Streamer.id).all()]
db.close()
for id in streamers:
processed = process_streamer(id)
if processed:
if processed[0]: live.append(processed[1])
else: offline.append(processed[1])
live = sorted(live, key=lambda x: x[5], reverse=True)
offline = sorted(offline, key=lambda x: x[4])
if live: cache.set('live', live)
if offline: cache.set('offline', offline)
@app.get('/live')
@auth_desired_with_logingate
def live_list(v):
live = cache.get('live') or []
offline = cache.get('offline') or []
return render_template('live.html', v=v, live=live, offline=offline)
@app.post('/live/add')
@admin_level_required(PERMS['STREAMERS_MODERATION'])
def live_add(v):
link = request.values.get('link').strip()
if 'youtube.com/channel/' in link:
id = link.split('youtube.com/channel/')[1].rstrip('/')
else:
text = requests.get(link, cookies={'CONSENT': 'YES+1'}, timeout=5).text
try: id = id_regex.search(text).group(1)
except: abort(400, "Invalid ID")
live = cache.get('live') or []
offline = cache.get('offline') or []
if not id or len(id) != 24:
abort(400, "Invalid ID")
existing = g.db.get(Streamer, id)
if not existing:
streamer = Streamer(id=id)
g.db.add(streamer)
g.db.flush()
if v.id != KIPPY_ID:
send_repeatable_notification(KIPPY_ID, f"@{v.username} (Admin) has added a [new YouTube channel](https://www.youtube.com/channel/{streamer.id})")
processed = process_streamer(id)
if processed:
if processed[0]: live.append(processed[1])
else: offline.append(processed[1])
live = sorted(live, key=lambda x: x[5], reverse=True)
offline = sorted(offline, key=lambda x: x[4])
if live: cache.set('live', live)
if offline: cache.set('offline', offline)
return redirect('/live')
@app.post('/live/remove')
@admin_level_required(PERMS['STREAMERS_MODERATION'])
def live_remove(v):
id = request.values.get('id').strip()
if not id: abort(400)
streamer = g.db.get(Streamer, id)
if streamer:
if v.id != KIPPY_ID:
send_repeatable_notification(KIPPY_ID, f"@{v.username} (Admin) has removed a [YouTube channel](https://www.youtube.com/channel/{streamer.id})")
g.db.delete(streamer)
live = cache.get('live') or []
offline = cache.get('offline') or []
live = [x for x in live if x[0] != id]
offline = [x for x in offline if x[0] != id]
if live: cache.set('live', live)
if offline: cache.set('offline', offline)
return redirect('/live')