2024-04-08 06:57:38 +00:00
import isodate
import yt_dlp
2024-03-10 14:27:21 +00:00
2024-04-06 06:27:43 +00:00
from files . classes . chats import *
2024-04-08 06:33:47 +00:00
from files . classes . orgy import *
2024-03-10 14:27:21 +00:00
from files . routes . wrappers import *
from files . helpers . config . const import *
from files . helpers . get import *
from files . __main__ import app , limiter
2024-04-06 04:31:51 +00:00
@app.get ( " /chat " )
@app.get ( " /orgy " )
def chat_redirect ( ) :
return redirect ( " /chat/1 " )
2024-03-10 14:27:21 +00:00
@app.post ( " /@<username>/chat " )
@limiter.limit ( ' 1/second ' , scope = rpath )
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
@limiter.limit ( " 10/minute;20/hour;50/day " , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( " 10/minute;20/hour;50/day " , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
@auth_required
def chat_user ( v , username ) :
user = get_user ( username , v = v , include_blocks = True )
if hasattr ( user , ' is_blocking ' ) and user . is_blocking :
abort ( 403 , f " You ' re blocking @ { user . username } " )
if v . admin_level < = PERMS [ ' MESSAGE_BLOCKED_USERS ' ] and hasattr ( user , ' is_blocked ' ) and user . is_blocked :
abort ( 403 , f " @ { user . username } is blocking you! " )
if user . has_muted ( v ) :
abort ( 403 , f " @ { user . username } is muting notifications from you, so you can ' t chat with them! " )
2024-04-09 06:59:05 +00:00
sq = g . db . query ( Chat . id ) . join ( ChatMembership , ChatMembership . chat_id == Chat . id ) . filter ( ChatMembership . user_id . in_ ( ( v . id , user . id ) ) ) . group_by ( Chat . id ) . having ( func . count ( Chat . id ) == 2 ) . subquery ( )
existing = g . db . query ( Chat . id ) . join ( ChatMembership , ChatMembership . chat_id == Chat . id ) . filter ( Chat . id == sq . c . id ) . group_by ( Chat . id ) . having ( func . count ( Chat . id ) == 2 ) . one_or_none ( )
2024-03-10 14:27:21 +00:00
if existing :
return redirect ( f " /chat/ { existing . id } " )
2024-04-07 08:46:34 +00:00
chat = Chat ( name = f " @ { v . username } , @ { user . username } " )
2024-03-10 14:27:21 +00:00
g . db . add ( chat )
g . db . flush ( )
chat_membership = ChatMembership (
user_id = v . id ,
chat_id = chat . id ,
)
g . db . add ( chat_membership )
chat_membership = ChatMembership (
user_id = user . id ,
chat_id = chat . id ,
)
2024-04-08 03:02:05 +00:00
chat_membership . created_utc + = 1
2024-03-10 14:27:21 +00:00
g . db . add ( chat_membership )
return redirect ( f " /chat/ { chat . id } " )
@app.get ( " /chat/<int:chat_id> " )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
@auth_required
2024-04-06 06:27:43 +00:00
def chat ( v , chat_id ) :
2024-03-10 14:27:21 +00:00
chat = g . db . get ( Chat , chat_id )
if not chat :
abort ( 404 , " Chat not found! " )
2024-04-06 04:50:04 +00:00
if chat . id == 1 :
if not v . allowed_in_chat :
2024-04-06 08:09:39 +00:00
abort ( 403 , f " To prevent spam, you ' ll need { TRUESCORE_MINIMUM } truescore (this is { TRUESCORE_MINIMUM } votes, either up or down, on any threads or comments you ' ve made) in order to access chat. Sorry! I love you 💖 " )
2024-04-06 04:50:04 +00:00
else :
membership = g . db . query ( ChatMembership ) . filter_by ( user_id = v . id , chat_id = chat_id ) . one_or_none ( )
if v . admin_level < PERMS [ ' VIEW_CHATS ' ] and not membership :
abort ( 403 , " You ' re not a member of this chat! " )
2024-03-10 14:27:21 +00:00
2024-04-08 05:12:08 +00:00
displayed_messages = reversed ( g . db . query ( ChatMessage ) . join ( ChatMessage . user ) . filter ( or_ ( User . id == v . id , User . shadowbanned == None ) ) . options ( joinedload ( ChatMessage . quoted_message ) ) . filter ( ChatMessage . chat_id == chat . id ) . order_by ( ChatMessage . id . desc ( ) ) . limit ( 250 ) . all ( ) )
2024-03-10 14:36:14 +00:00
displayed_messages = { m . id : m for m in displayed_messages }
2024-03-10 14:27:21 +00:00
2024-04-06 04:35:44 +00:00
if chat . id == 1 :
sorted_memberships = None
else :
2024-04-06 04:50:04 +00:00
if not session . get ( " GLOBAL " ) and membership :
membership . notification = False
g . db . add ( membership )
g . db . commit ( ) #to clear notif count
2024-04-07 00:50:51 +00:00
2024-04-06 04:35:44 +00:00
query = g . db . query ( ChatMembership ) . filter_by ( chat_id = chat . id )
2024-04-07 00:50:51 +00:00
sorted_memberships = query . filter ( ChatMembership . user_id != chat . owner_id ) . join ( ChatMembership . user ) . order_by ( func . lower ( User . username ) ) . all ( )
owner_membership = query . filter_by ( user_id = chat . owner_id ) . one_or_none ( )
if owner_membership :
sorted_memberships = [ owner_membership ] + sorted_memberships
2024-04-06 03:28:30 +00:00
2024-04-08 06:33:47 +00:00
orgy = get_running_orgy ( v , chat_id )
if orgy :
orgies = g . db . query ( Orgy ) . filter_by ( chat_id = chat_id ) . order_by ( Orgy . start_utc ) . all ( )
2024-04-08 07:13:43 +00:00
return render_template ( " orgy.html " , v = v , messages = displayed_messages , chat = chat , sorted_memberships = sorted_memberships , orgy = orgy , orgies = orgies )
2024-04-08 06:33:47 +00:00
2024-04-06 06:27:43 +00:00
return render_template ( " chat.html " , v = v , messages = displayed_messages , chat = chat , sorted_memberships = sorted_memberships )
2024-03-10 14:27:21 +00:00
@app.post ( " /chat/<int:chat_id>/name " )
2024-04-24 12:14:59 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2024-03-10 14:27:21 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
@auth_required
def change_chat_name ( v , chat_id ) :
chat = g . db . get ( Chat , chat_id )
if not chat :
abort ( 404 , " Chat not found! " )
if v . id != chat . owner_id :
abort ( 403 , " Only the chat owner can change its name! " )
new_name = request . values . get ( " new_name " ) . strip ( )
2024-03-10 18:21:10 +00:00
if len ( new_name ) > 40 :
abort ( 400 , " New name is too long (max 40 characters) " )
2024-03-10 14:27:21 +00:00
chat . name = new_name
g . db . add ( chat )
return redirect ( f " /chat/ { chat . id } " )
@app.post ( " /chat/<int:chat_id>/leave " )
2024-04-24 12:14:59 +00:00
@limiter.limit ( ' 1/second ' , scope = rpath )
@limiter.limit ( ' 1/second ' , scope = rpath , key_func = get_ID )
2024-03-10 14:27:21 +00:00
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 )
@limiter.limit ( DEFAULT_RATELIMIT , deduct_when = lambda response : response . status_code < 400 , key_func = get_ID )
@auth_required
def leave_chat ( v , chat_id ) :
chat = g . db . get ( Chat , chat_id )
if not chat :
abort ( 404 , " Chat not found! " )
if v . id == chat . owner_id :
abort ( 403 , " The chat owner can ' t leave it! " )
membership = g . db . query ( ChatMembership ) . filter_by ( user_id = v . id , chat_id = chat_id ) . one_or_none ( )
if not membership :
abort ( 400 , " You ' re not a member of this chat! " )
g . db . delete ( membership )
chat_leave = ChatLeave (
user_id = v . id ,
chat_id = chat_id ,
)
g . db . add ( chat_leave )
return { " message " : " Chat left successfully! " }
2024-04-08 06:33:47 +00:00
@app.get ( " /chat/<int:chat_id>/orgies " )
@auth_required
def orgy_control ( v , chat_id ) :
chat = g . db . get ( Chat , chat_id )
if not chat :
abort ( 404 , " Chat not found! " )
if chat . id == 1 :
if v . admin_level < PERMS [ " ORGIES " ] :
abort ( 403 , " Your admin-level is not sufficient enough for this action! " )
elif v . id != chat . owner_id :
abort ( 403 , " Only the chat owner can manage its orgies! " )
orgies = g . db . query ( Orgy ) . filter_by ( chat_id = chat_id ) . order_by ( Orgy . start_utc ) . all ( )
return render_template ( " orgy_control.html " , v = v , orgies = orgies , chat = chat )
@app.post ( " /chat/<int:chat_id>/schedule_orgy " )
@auth_required
def schedule_orgy ( v , chat_id ) :
chat = g . db . get ( Chat , chat_id )
if not chat :
abort ( 404 , " Chat not found! " )
if chat . id == 1 :
if v . admin_level < PERMS [ " ORGIES " ] :
abort ( 403 , " Your admin-level is not sufficient enough for this action! " )
elif v . id != chat . owner_id :
abort ( 403 , " Only the chat owner can manage its orgies! " )
link = request . values . get ( " link " , " " ) . strip ( )
title = request . values . get ( " title " , " " ) . strip ( )
start_utc = request . values . get ( " start_utc " , " " ) . strip ( )
if not link :
abort ( 400 , " A link is required! " )
if not title :
abort ( 400 , " A title is required! " )
2024-04-20 21:07:07 +00:00
if len ( title ) > 40 :
abort ( 400 , ' Title is too long (max 40 characters) ' )
2024-04-08 06:33:47 +00:00
normalized_link = normalize_url ( link )
if start_utc :
start_utc = int ( start_utc )
else :
last_orgy = g . db . query ( Orgy ) . order_by ( Orgy . start_utc . desc ( ) ) . first ( )
if last_orgy and last_orgy . end_utc :
start_utc = last_orgy . end_utc
else :
start_utc = int ( time . time ( ) )
end_utc = None
if bare_youtube_regex . match ( normalized_link ) :
orgy_type = ' youtube '
data , _ = get_youtube_id_and_t ( normalized_link )
2024-04-09 01:08:10 +00:00
if YOUTUBE_KEY != DEFAULT_CONFIG_VALUE :
2024-04-08 06:33:47 +00:00
req = requests . get ( f " https://www.googleapis.com/youtube/v3/videos?id= { data } &key= { YOUTUBE_KEY } &part=contentDetails " , headers = HEADERS , timeout = 5 ) . json ( )
duration = req [ ' items ' ] [ 0 ] [ ' contentDetails ' ] [ ' duration ' ]
if duration != ' P0D ' :
duration = isodate . parse_duration ( duration ) . total_seconds ( )
end_utc = int ( start_utc + duration )
orgy_type = ' file '
ydl_opts = {
2024-04-20 17:21:57 +00:00
" quiet " : True ,
2024-04-08 06:33:47 +00:00
" simulate " : True ,
" forceurl " : True ,
' format ' : ' b ' ,
' proxy ' : PROXY_URL
}
with yt_dlp . YoutubeDL ( ydl_opts ) as ydl :
info = ydl . extract_info ( f " https://www.youtube.com/watch?v= { data } " )
data = info [ " url " ]
elif rumble_regex . match ( normalized_link ) :
orgy_type = ' rumble '
data = normalized_link
elif twitch_regex . match ( normalized_link ) :
orgy_type = ' twitch '
data = twitch_regex . search ( normalized_link ) . group ( 3 )
elif any ( ( normalized_link . lower ( ) . endswith ( f ' . { x } ' ) for x in VIDEO_FORMATS ) ) :
2024-04-10 11:23:45 +00:00
domain = tldextract . extract ( normalized_link ) . registered_domain
if domain != ' archive.org ' and not is_safe_url ( normalized_link ) :
abort ( 400 , " For linking an mp4 file, you can only use archive.org or one of the approved media hosts outlined in https://rdrama.net/formatting#approved " )
2024-04-08 06:33:47 +00:00
orgy_type = ' file '
data = normalized_link
video_info = ffmpeg . probe ( data , headers = f ' referer: { SITE_FULL } /chat ' )
duration = float ( video_info [ ' streams ' ] [ 0 ] [ ' duration ' ] )
if duration == 2.0 : raise
if duration > 3000 :
duration + = 300 #account for break
end_utc = int ( start_utc + duration )
else :
abort ( 400 )
data = data . strip ( )
orgy = Orgy (
title = title ,
type = orgy_type ,
data = data ,
start_utc = start_utc ,
end_utc = end_utc ,
chat_id = chat_id ,
)
g . db . add ( orgy )
if chat . id == 1 :
ma = ModAction (
kind = " schedule_orgy " ,
user_id = v . id ,
2024-04-16 18:23:15 +00:00
_note = f ' <a href= " { normalized_link } " rel= " nofollow noopener " > { title } </a> ' ,
2024-04-08 06:33:47 +00:00
)
g . db . add ( ma )
2024-04-16 18:23:15 +00:00
if AEVANN_ID and v . id != AEVANN_ID :
text = f " @ { v . username } has started [ { title } ]( { normalized_link } ) in [ { chat . name } ](/chat/ { chat . id } ) "
send_repeatable_notification ( AEVANN_ID , text )
2024-04-08 06:33:47 +00:00
return redirect ( f " /chat/ { chat_id } /orgies " )
@app.post ( " /chat/<int:chat_id>/remove_orgy/<int:created_utc> " )
@auth_required
def remove_orgy ( v , created_utc , chat_id ) :
chat = g . db . get ( Chat , chat_id )
if not chat :
abort ( 404 , " Chat not found! " )
if chat . id == 1 :
if v . admin_level < PERMS [ " ORGIES " ] :
abort ( 403 , " Your admin-level is not sufficient enough for this action! " )
elif v . id != chat . owner_id :
abort ( 403 , " Only the chat owner can manage its orgies! " )
2024-04-16 21:31:07 +00:00
orgy = g . db . query ( Orgy ) . filter_by ( created_utc = created_utc ) . one_or_none ( )
2024-04-08 06:33:47 +00:00
2024-04-16 21:31:07 +00:00
if orgy :
if chat . id == 1 :
ma = ModAction (
kind = " remove_orgy " ,
user_id = v . id ,
_note = f ' <a href= " { orgy . data } " rel= " nofollow noopener " > { orgy . title } </a> ' ,
)
g . db . add ( ma )
started = orgy . started
g . db . delete ( orgy )
g . db . commit ( )
if started :
requests . post ( f ' http://localhost:5001/chat/ { chat_id } /refresh_chat ' , headers = { " User-Agent " : " refreshing_chat " , " Host " : SITE } )
2024-04-08 06:33:47 +00:00
return { " message " : " Orgy stopped successfully! " }