MarseyWorld/files/routes/static.py

580 lines
17 KiB
Python
Raw Normal View History

2022-05-04 23:09:46 +00:00
from files.mail import *
2022-10-08 00:44:02 +00:00
from files.__main__ import app, limiter
2022-05-04 23:09:46 +00:00
from files.helpers.alerts import *
from files.helpers.const import *
2022-09-09 09:13:50 +00:00
from files.helpers.actions import *
2022-05-04 23:09:46 +00:00
from files.classes.award import AWARDS
2022-10-01 22:27:51 +00:00
from sqlalchemy import func, nullslast
2022-05-18 19:29:07 +00:00
import os
2022-05-04 23:09:46 +00:00
from files.classes.mod_logs import ACTIONTYPES, ACTIONTYPES2
from files.classes.badges import BadgeDef
import files.helpers.stats as statshelper
2022-09-10 01:09:33 +00:00
from shutil import move, copyfile
2022-05-04 23:09:46 +00:00
2022-05-04 23:09:46 +00:00
@app.get("/r/drama/comments/<id>/<title>")
@app.get("/r/Drama/comments/<id>/<title>")
def rdrama(id, title):
id = ''.join(f'{x}/' for x in id)
return redirect(f'/archives/drama/comments/{id}{title}.html')
@app.get("/marseys")
@auth_required
def marseys(v):
2022-11-11 13:52:18 +00:00
if SITE == 'rdrama.net':
2022-09-09 09:13:50 +00:00
marseys = g.db.query(Marsey, User).join(User, Marsey.author_id == User.id).filter(Marsey.submitter_id==None)
2022-05-04 23:09:46 +00:00
sort = request.values.get("sort", "usage")
2022-10-01 22:27:51 +00:00
if sort == "usage":
marseys = marseys.order_by(Marsey.count.desc(), User.username).all()
elif sort == "added":
marseys = marseys.order_by(nullslast(Marsey.created_utc.desc()), User.username).all()
else: # implied sort == "author"
marseys = marseys.order_by(User.username, Marsey.count.desc()).all()
2022-09-14 10:55:35 +00:00
original = os.listdir("/asset_submissions/marseys/original")
2022-09-14 11:02:46 +00:00
for marsey, user in marseys:
for x in IMAGE_FORMATS:
if f'{marsey.name}.{x}' in original:
marsey.og = f'{marsey.name}.{x}'
break
2022-05-04 23:09:46 +00:00
else:
2022-09-09 09:13:50 +00:00
marseys = g.db.query(Marsey).filter(Marsey.submitter_id==None).order_by(Marsey.count.desc())
2022-05-04 23:09:46 +00:00
return render_template("marseys.html", v=v, marseys=marseys)
@app.get("/marsey_list.json")
@cache.memoize(timeout=600)
2022-05-04 23:09:46 +00:00
def marsey_list():
2022-07-09 04:32:48 +00:00
emojis = []
2022-07-09 04:32:48 +00:00
# From database
if EMOJI_MARSEYS:
emojis = [{
"name": emoji.name,
2022-11-11 13:52:18 +00:00
"author": author if SITE == 'rdrama.net' or author == "anton-d" else None,
2022-07-09 04:32:48 +00:00
# yikes, I don't really like this DB schema. Next time be better
"tags": emoji.tags.split(" ") + [emoji.name[len("marsey"):] \
if emoji.name.startswith("marsey") else emoji.name],
"count": emoji.count,
"class": "Marsey"
2022-09-09 09:13:50 +00:00
} for emoji, author in g.db.query(Marsey, User.username).join(User, Marsey.author_id == User.id).filter(Marsey.submitter_id==None) \
2022-07-09 04:32:48 +00:00
.order_by(Marsey.count.desc())]
2022-07-09 04:32:48 +00:00
# Static shit
for src in EMOJI_SRCS:
with open(src, "r", encoding="utf-8") as f:
emojis = emojis + json.load(f)
2022-05-04 23:09:46 +00:00
return jsonify(emojis)
2022-05-04 23:09:46 +00:00
@app.get('/sidebar')
@auth_desired
2022-05-04 23:09:46 +00:00
def sidebar(v):
return render_template('sidebar.html', v=v)
@app.get("/stats")
@auth_required
def participation_stats(v):
if v.client: return stats_cached()
2022-09-05 20:23:35 +00:00
return render_template("stats.html", v=v, title="Content Statistics", data=stats_cached())
2022-05-04 23:09:46 +00:00
@cache.memoize(timeout=86400)
def stats_cached():
return statshelper.stats(SITE_NAME)
2022-05-04 23:09:46 +00:00
@app.get("/chart")
def chart():
return redirect('/weekly_chart')
@app.get("/weekly_chart")
@auth_required
def weekly_chart(v):
return send_file(statshelper.chart_path(kind="weekly", site=SITE))
2022-05-04 23:09:46 +00:00
@app.get("/daily_chart")
@auth_required
def daily_chart(v):
return send_file(statshelper.chart_path(kind="daily", site=SITE))
2022-05-04 23:09:46 +00:00
@app.get("/patrons")
@app.get("/paypigs")
2022-10-06 05:48:55 +00:00
@admin_level_required(PERMS['VIEW_PATRONS'])
2022-05-04 23:09:46 +00:00
def patrons(v):
2022-09-30 21:07:53 +00:00
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, SNAKES_ID): abort(404)
2022-09-17 22:06:29 +00:00
2022-05-04 23:09:46 +00:00
users = g.db.query(User).filter(User.patron > 0).order_by(User.patron.desc(), User.id).all()
2022-10-02 19:37:07 +00:00
return render_template("patrons.html", v=v, users=users, benefactor_def=AWARDS['benefactor'])
2022-05-04 23:09:46 +00:00
@app.get("/admins")
@app.get("/badmins")
@auth_required
def admins(v):
if v.admin_level >= PERMS['VIEW_SORTED_ADMIN_LIST']:
2022-11-07 07:03:58 +00:00
admins = g.db.query(User).filter(User.admin_level>1).order_by(User.truescore.desc()).all()
admins += g.db.query(User).filter(User.admin_level==1).order_by(User.truescore.desc()).all()
else: admins = g.db.query(User).filter(User.admin_level>0).order_by(User.truescore.desc()).all()
2022-05-04 23:09:46 +00:00
return render_template("admins.html", v=v, admins=admins)
@app.get("/log")
@app.get("/modlog")
@auth_required
def log(v):
try: page = max(int(request.values.get("page", 1)), 1)
except: page = 1
admin = request.values.get("admin")
2022-10-01 05:15:56 +00:00
if admin: admin_id = get_id(admin)
2022-05-04 23:09:46 +00:00
else: admin_id = 0
kind = request.values.get("kind")
2022-10-06 05:56:19 +00:00
if v and v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
2022-05-04 23:09:46 +00:00
else: types = ACTIONTYPES2
if kind and kind not in types:
kind = None
actions = []
else:
actions = g.db.query(ModAction)
2022-10-06 02:24:37 +00:00
if not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
2022-11-13 02:37:33 +00:00
actions = actions.filter(ModAction.kind.notin_([
"shadowban","unshadowban",
"mod_mute_user","mod_unmute_user",
account linking improvements (#448) currently account delinking is very messy and can sometimes just not work we do codey stuff so it's not as bad also we create a pretty page for mops to mop up borked account links * alts: allow proper delinking * fix prev commit * url fix * fix 500 * fixes * :pepodrool: * flag * :pepodrool: redux * sdsdsdsds * correct endpoint * fix html page * alts: only adjust session history if flag is set * fix 500 * allow relinking * fsdsds * :pepodrool: redux * alts: don't fail if an alt isn't history * use postToastSwitch + some API changes * remove unnecessary variables * d-none * delink accounts mod action * fa-link-slash * alts: add form to create alt * remove copied and pasted template * rounded section * UI improvement + fix * \n * fix status * admin: remove duplicate route admin: do a permissions check on 2 pages that need it admin: set the manual flag for manually flagged alts * variable change * fix 500 * alts * add shadowban icon to alt link tool * shadowbanned tooltip * add user info section * fix 500, remove unnecessary form, and add alt votes button * trans and also link to page * margin * sdsdsd * stop the count * fix prev commit * with ctx * plural * alts * don't show shadowbanned users to those who can't see them this is... extremely rare and won't ever be seen in production however if perms were ever rearranged in the future, this keeps permissions correct * shadowban check in alt list * let shadow realm enthusiasts see shadowban alts * sdsdsds * test * be graceful where needed * sdsdsdsds * alts: don't allow adding the same account alts: clarify wording * rename and reorder on admin panel * EOL * remove frankly unnecessary check * try with a set * test * Revert "try with a set" This reverts commit 72be353fba5ffa39b37590cc5d3bf584c94ee06e. * Revert "Revert "try with a set"" This reverts commit 81e41890a192e8b46d0463477998e905fddf56ba. * Revert "Revert "Revert "try with a set""" This reverts commit be51592135a3c09848f993f0154bd2ac862ae505. * clean up test
2022-11-14 17:32:13 +00:00
"link_accounts","delink_accounts",
2022-11-13 02:37:33 +00:00
]))
if admin_id:
actions = actions.filter_by(user_id=admin_id)
kinds = set([x.kind for x in actions])
kinds.add(kind)
types2 = {}
for k,val in types.items():
if k in kinds: types2[k] = val
types = types2
if kind: actions = actions.filter_by(kind=kind)
actions = actions.order_by(ModAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all()
next_exists=len(actions) > PAGE_SIZE
actions=actions[:PAGE_SIZE]
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).order_by(User.username).all()]
2022-05-04 23:09:46 +00:00
2022-11-04 23:51:42 +00:00
return render_template("log.html", v=v, admins=admins, types=types, admin=admin, type=kind, actions=actions, next_exists=next_exists, page=page, single_user_url='admin')
2022-05-04 23:09:46 +00:00
@app.get("/log/<id>")
@auth_required
def log_item(id, v):
try: id = int(id)
except: abort(404)
action=g.db.get(ModAction, id)
2022-05-04 23:09:46 +00:00
if not action: abort(404)
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).all()]
2022-05-04 23:09:46 +00:00
if v and v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
2022-05-04 23:09:46 +00:00
else: types = ACTIONTYPES2
2022-11-04 23:51:42 +00:00
return render_template("log.html", v=v, actions=[action], next_exists=False, page=1, action=action, admins=admins, types=types, single_user_url='admin')
2022-05-04 23:09:46 +00:00
@app.get("/directory")
@auth_required
def static_megathread_index(v):
return render_template("megathread_index.html", v=v)
2022-05-04 23:09:46 +00:00
@app.get("/api")
2022-05-22 16:14:32 +00:00
@auth_required
def api(v):
return render_template("api.html", v=v)
2022-05-04 23:09:46 +00:00
@app.get("/contact")
2022-09-09 09:13:50 +00:00
@app.get("/contactus")
@app.get("/contact_us")
2022-05-04 23:09:46 +00:00
@app.get("/press")
@app.get("/media")
@auth_desired
2022-05-04 23:09:46 +00:00
def contact(v):
return render_template("contact.html", v=v)
@app.post("/send_admin")
2022-11-13 02:37:33 +00:00
@limiter.limit("1/second;1/2 minutes;10/day")
@limiter.limit("1/second;1/2 minutes;10/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
2022-05-04 23:09:46 +00:00
@auth_required
def submit_contact(v):
body = request.values.get("message")
if not body: abort(400)
if v.is_muted:
abort(403)
2022-05-04 23:09:46 +00:00
body = f'This message has been sent automatically to all admins via [/contact](/contact)\n\nMessage:\n\n' + body
body += process_files()
body = body.strip()
body_html = sanitize(body)
2022-05-04 23:09:46 +00:00
2022-11-14 03:48:52 +00:00
execute_antispam_duplicate_comment_check(v, body_html)
2022-11-13 02:48:33 +00:00
2022-05-04 23:09:46 +00:00
new_comment = Comment(author_id=v.id,
2022-09-04 23:15:37 +00:00
parent_submission=None,
level=1,
body_html=body_html,
sentto=2
)
2022-05-04 23:09:46 +00:00
g.db.add(new_comment)
g.db.flush()
2022-11-14 02:43:26 +00:00
execute_blackjack(v, new_comment, new_comment.body_html, 'modmail')
2022-05-04 23:09:46 +00:00
new_comment.top_comment_id = new_comment.id
admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'])
2022-10-17 19:13:33 +00:00
if SITE == 'watchpeopledie.tv':
2022-09-21 19:38:29 +00:00
admins = admins.filter(User.id != AEVANN_ID)
for admin in admins.all():
2022-05-04 23:09:46 +00:00
notif = Notification(comment_id=new_comment.id, user_id=admin.id)
g.db.add(notif)
2022-09-12 05:23:08 +00:00
return render_template("contact.html", v=v, msg="Your message has been sent to the admins!")
2022-05-04 23:09:46 +00:00
@app.get('/archives')
def archivesindex():
return redirect("/archives/index.html")
@app.get('/archives/<path:path>')
def archives(path):
resp = make_response(send_from_directory('/archives', path))
if request.path.endswith('.css'): resp.headers.add("Content-Type", "text/css")
return resp
def static_file(dir:str, path:str, should_cache:bool, is_webp:bool) -> Response:
resp = make_response(send_from_directory(dir, path))
if should_cache:
resp.headers.remove("Cache-Control")
resp.headers.add("Cache-Control", "public, max-age=3153600")
if is_webp:
resp.headers.remove("Content-Type")
resp.headers.add("Content-Type", "image/webp")
return resp
2022-05-04 23:09:46 +00:00
@app.get('/e/<emoji>')
2022-05-22 17:23:52 +00:00
@limiter.exempt
2022-05-04 23:09:46 +00:00
def emoji(emoji):
if not emoji.endswith('.webp'): abort(404)
return static_file('assets/images/emojis', emoji, True, True)
2022-05-04 23:09:46 +00:00
2022-06-22 15:54:25 +00:00
@app.get('/i/<path:path>')
@limiter.exempt
2022-06-22 15:54:25 +00:00
def image(path):
is_webp = path.endswith('.webp')
return static_file('assets/images', path, is_webp or path.endswith('.gif') or path.endswith('.ttf') or path.endswith('.woff2'), is_webp)
2022-05-04 23:09:46 +00:00
@app.get('/assets/<path:path>')
@app.get('/static/assets/<path:path>')
2022-05-22 17:23:52 +00:00
@limiter.exempt
2022-05-04 23:09:46 +00:00
def static_service(path):
is_webp = path.endswith('.webp')
return static_file('assets', path, is_webp or path.endswith('.gif') or path.endswith('.ttf') or path.endswith('.woff2'), is_webp)
2022-05-04 23:09:46 +00:00
### BEGIN FALLBACK ASSET SERVING
# In production, we have nginx serve these locations now.
# These routes stay for local testing. Requests don't reach them on prod.
@app.get('/images/<path>')
@app.get('/hostedimages/<path>')
@app.get("/static/images/<path>")
@limiter.exempt
def images(path):
return static_file('/images', path, True, True)
@app.get('/videos/<path>')
@limiter.exempt
def videos(path):
return static_file('/videos', path, True, False)
@app.get('/audio/<path>')
@limiter.exempt
def audio(path):
return static_file('/audio', path, True, False)
### END FALLBACK ASSET SERVING
2022-05-04 23:09:46 +00:00
@app.get("/robots.txt")
def robots_txt():
2022-09-11 01:56:47 +00:00
return send_file("assets/robots.txt")
2022-05-04 23:09:46 +00:00
no = (21,22,23,24,25,26,27)
@cache.memoize(timeout=3600)
def badge_list(site):
badges = g.db.query(BadgeDef).filter(BadgeDef.id.notin_(no)).order_by(BadgeDef.id).all()
counts_raw = g.db.query(Badge.badge_id, func.count()).group_by(Badge.badge_id).all()
2022-05-09 11:21:49 +00:00
users = g.db.query(User).count()
2022-05-04 23:09:46 +00:00
counts = {}
for c in counts_raw:
counts[c[0]] = (c[1], float(c[1]) * 100 / max(users, 1))
return badges, counts
@app.get("/badges")
2022-10-11 07:29:24 +00:00
@feature_required('BADGES')
2022-11-14 15:11:05 +00:00
@auth_required
2022-05-04 23:09:46 +00:00
def badges(v):
badges, counts = badge_list(SITE)
return render_template("badges.html", v=v, badges=badges, counts=counts)
@app.get("/blocks")
@admin_level_required(PERMS['USER_BLOCKS_VISIBLE'])
2022-05-04 23:09:46 +00:00
def blocks(v):
blocks=g.db.query(UserBlock).all()
users = []
targets = []
for x in blocks:
acc_user = get_account(x.user_id)
2022-09-04 23:15:37 +00:00
acc_tgt = get_account(x.target_id)
if acc_user.shadowbanned or acc_tgt.shadowbanned: continue
users.append(acc_user)
targets.append(acc_tgt)
2022-05-04 23:09:46 +00:00
return render_template("blocks.html", v=v, users=users, targets=targets)
@app.get("/banned")
@auth_required
def banned(v):
users = g.db.query(User).filter(User.is_banned > 0, User.unban_utc == 0)
if not v.can_see_shadowbanned:
users = users.filter(User.shadowbanned == None)
users = users.all()
2022-05-04 23:09:46 +00:00
return render_template("banned.html", v=v, users=users)
@app.get("/formatting")
@auth_required
def formatting(v):
return render_template("formatting.html", v=v)
2022-06-10 22:14:03 +00:00
@app.get("/service-worker.js")
2022-05-04 23:09:46 +00:00
def serviceworker():
2022-06-10 22:14:03 +00:00
with open("files/assets/js/service-worker.js", "r", encoding="utf-8") as f:
return Response(f.read(), mimetype='application/javascript')
2022-05-04 23:09:46 +00:00
@app.post("/dismiss_mobile_tip")
def dismiss_mobile_tip():
session["tooltip_last_dismissed"] = int(time.time())
return "", 204
@app.get("/transfers/<id>")
@auth_required
def transfers_id(id, v):
try: id = int(id)
except: abort(404)
transfer = g.db.get(Comment, id)
if not transfer: abort(404)
return render_template("transfers.html", v=v, page=1, comments=[transfer], standalone=True, next_exists=False)
@app.get("/transfers")
@auth_required
def transfers(v):
comments = g.db.query(Comment).filter(Comment.author_id == AUTOJANNY_ID, Comment.parent_submission == None, Comment.body_html.like("%</a> has transferred %")).order_by(Comment.id.desc())
try: page = max(int(request.values.get("page", 1)), 1)
except: page = 1
comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
next_exists = len(comments) > PAGE_SIZE
comments = comments[:PAGE_SIZE]
if v.client:
return {"data": [x.json for x in comments]}
else:
return render_template("transfers.html", v=v, page=page, comments=comments, standalone=True, next_exists=next_exists)
2022-09-19 23:59:24 +00:00
if not os.path.exists(f'files/templates/donate_{SITE_NAME}.html'):
copyfile(f'files/templates/donate_rDrama.html', f'files/templates/donate_{SITE_NAME}.html')
@app.get('/donate')
2022-10-30 18:43:06 +00:00
@auth_desired_with_logingate
2022-09-19 23:59:24 +00:00
def donate(v):
return render_template(f'donate_{SITE_NAME}.html', v=v)
2022-09-25 04:11:06 +00:00
if SITE == 'pcmemes.net':
from files.classes.streamers import *
2022-09-25 06:27:58 +00:00
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)
2022-10-29 23:33:23 +00:00
offline_details_regex = re.compile('simpleText":"Streamed ([0-9]*?) ([^"]*?)"\},.*?"viewCountText":\{"simpleText":"([0-9,]*?) views"', flags=re.A)
2022-09-25 04:11:06 +00:00
2022-09-25 05:24:59 +00:00
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)
2022-09-25 04:11:06 +00:00
text = req.text
if '"videoDetails":{"videoId"' in text:
y = live_regex.search(text)
2022-09-25 05:24:59 +00:00
count = y.group(3)
2022-09-29 18:25:01 +00:00
2022-10-29 02:20:23 +00:00
if count == '1 watching now':
2022-09-30 12:19:48 +00:00
count = "1"
2022-09-29 18:25:01 +00:00
2022-10-29 02:20:23 +00:00
if 'waiting' in count:
if live != '':
return process_streamer(id, '')
else:
return None
2022-09-25 05:24:59 +00:00
2022-10-29 02:20:23 +00:00
count = int(count.replace(',', ''))
2022-09-25 05:24:59 +00:00
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))
2022-09-25 04:11:06 +00:00
else:
t = offline_regex.search(text)
if not t:
if live != '':
return process_streamer(id, '')
else:
return None
2022-09-29 18:29:44 +00:00
2022-09-25 04:11:06 +00:00
y = offline_details_regex.search(text)
2022-09-25 04:37:16 +00:00
if y:
views = y.group(3).replace(',', '')
2022-09-25 04:37:16 +00:00
quantity = int(y.group(1))
unit = y.group(2)
if unit.startswith('second'):
2022-10-01 09:43:16 +00:00
modifier = 1/60
elif unit.startswith('minute'):
2022-09-25 04:37:16 +00:00
modifier = 1
elif unit.startswith('hour'):
2022-09-25 04:37:16 +00:00
modifier = 60
elif unit.startswith('day'):
2022-09-25 04:38:43 +00:00
modifier = 1440
elif unit.startswith('week'):
2022-09-25 04:37:16 +00:00
modifier = 10080
elif unit.startswith('month'):
2022-09-25 04:37:16 +00:00
modifier = 43800
elif unit.startswith('year'):
2022-09-25 04:37:16 +00:00
modifier = 525600
2022-10-01 09:43:16 +00:00
minutes = quantity * modifier
2022-09-25 04:37:16 +00:00
actual = f'{quantity} {unit}'
2022-09-25 04:33:55 +00:00
else:
2022-10-06 22:50:36 +00:00
minutes = 9999999999
2022-09-25 04:37:16 +00:00
actual = '???'
2022-09-25 04:38:43 +00:00
views = 0
2022-09-25 04:11:06 +00:00
2022-09-29 18:29:44 +00:00
thumb = t.group(2)
2022-09-26 02:46:56 +00:00
2022-09-25 05:24:59 +00:00
name = t.group(1)
return (False, (id, req.url.rstrip('/live'), thumb, name, minutes, actual, views))
2022-09-25 04:11:06 +00:00
def live_cached():
live = []
offline = []
db = db_session()
streamers = [x[0] for x in db.query(Streamer.id).all()]
db.close()
2022-09-25 04:11:06 +00:00
for id in streamers:
processed = process_streamer(id)
if processed:
if processed[0]: live.append(processed[1])
else: offline.append(processed[1])
2022-09-23 21:09:19 +00:00
live = sorted(live, key=lambda x: x[5], reverse=True)
2022-09-25 04:11:06 +00:00
offline = sorted(offline, key=lambda x: x[4])
2022-09-25 11:28:53 +00:00
if live: cache.set('live', live)
if offline: cache.set('offline', offline)
2022-09-22 02:33:45 +00:00
@app.get('/live')
@auth_desired_with_logingate
def live_list(v):
live = cache.get('live') or []
offline = cache.get('offline') or []
2022-09-23 20:58:10 +00:00
return render_template('live.html', v=v, live=live, offline=offline)
@app.post('/live/add')
2022-10-06 06:22:42 +00:00
@admin_level_required(PERMS['STREAMERS_MODERATION'])
def live_add(v):
2022-09-25 06:45:19 +00:00
link = request.values.get('link').strip()
2022-09-22 22:02:15 +00:00
2022-09-25 06:45:19 +00:00
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
2022-09-25 06:27:58 +00:00
try: id = id_regex.search(text).group(1)
except: abort(400, "Invalid ID")
live = cache.get('live') or []
offline = cache.get('offline') or []
2022-09-23 20:58:10 +00:00
2022-09-22 22:02:15 +00:00
if not id or len(id) != 24:
abort(400, "Invalid ID")
2022-09-22 22:02:15 +00:00
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})")
2022-09-22 22:27:38 +00:00
2022-09-25 04:11:06 +00:00
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])
2022-09-25 11:28:53 +00:00
if live: cache.set('live', live)
if offline: cache.set('offline', offline)
2022-09-25 03:21:41 +00:00
return redirect('/live')
@app.post('/live/remove')
2022-10-06 06:22:42 +00:00
@admin_level_required(PERMS['STREAMERS_MODERATION'])
def live_remove(v):
2022-09-24 00:21:32 +00:00
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)
2022-09-23 20:58:10 +00:00
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]
2022-09-25 11:28:53 +00:00
if live: cache.set('live', live)
if offline: cache.set('offline', offline)
return redirect('/live')