2024-10-12 19:37:06 +00:00
import obsws_python
import yt_dlp
from time import sleep
import time
import disnake
import random
from urllib . parse import urlparse
from disnake . ext import commands , tasks
from disnake import TextInputStyle
import asyncio
from dotenv import load_dotenv
import os
import datetime
import logging
import math
from tempfile import TemporaryDirectory
from pathlib import Path
#https://stackoverflow.com/a/11706463
def randshuffle ( x , start = 0 , stop = None , seed = 10 ) :
if stop is None :
stop = len ( x )
loop = 0
for i in reversed ( range ( start + 1 , stop ) ) :
random . seed ( seed + loop )
j = random . randint ( start , i )
x [ i ] , x [ j ] = x [ j ] , x [ i ]
loop = loop + 1
load_dotenv ( )
queue = [ ]
user_queue = [ ]
skip_list = [ ]
shuffle = True
downloading = False
failures = 0
vidcounter = 0
temp_dir = TemporaryDirectory ( )
vid_dir = Path ( temp_dir . name )
download_dir = TemporaryDirectory ( )
full_dl_dir = Path ( download_dir . name )
vid_details = { " title " : " " , " channel " : " " }
def video_check ( info , * , incomplete ) :
duration = info . get ( ' duration ' )
vid_details [ " title " ] = info . get ( " title " )
vid_details [ " channel " ] = info . get ( " channel " )
print ( info . get ( " channel " ) )
print ( info . get ( " title " ) )
if duration and duration > = ( ( float ( os . getenv ( " MAX_MIN " ) ) * 60 ) + 480 ) :
queue . pop ( 0 )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
user_queue . pop ( 0 )
skip_list . clear ( )
if queue :
ydl . download ( queue [ 0 ] )
return " video too long... :( "
ydl_opts = {
' match_filter ' : video_check ,
' hls_prefer_native ' : True ,
' extract_flat ' : ' discard_in_playlist ' ,
' format ' : ' bestvideo[height<=1080][ext=mp4]+bestaudio[abr<=256][ext=m4a]/best[ext=mp4]/best ' ,
' fragment_retries ' : 10 ,
' noplaylist ' : True ,
' restrictfilenames ' : True ,
' source_address ' : ' 0.0.0.0 ' ,
' concurrent_fragment_downloads ' : 3 ,
' paths ' : { ' home ' : f ' { vid_dir } ' , ' temp ' : f ' { full_dl_dir } ' } ,
' outtmpl ' : { ' default ' : f ' 999zznext ' } ,
' postprocessors ' : [ { ' api ' : ' https://sponsor.ajay.app ' ,
' categories ' : { ' sponsor ' , ' selfpromo ' } ,
' key ' : ' SponsorBlock ' ,
' when ' : ' after_filter ' } ,
{ ' force_keyframes ' : False ,
' key ' : ' ModifyChapters ' ,
' remove_chapters_patterns ' : [ ] ,
' remove_ranges ' : [ ] ,
' remove_sponsor_segments ' : { ' sponsor ' , ' selfpromo ' } ,
' sponsorblock_chapter_title ' : ' [SponsorBlock]: '
' % (category_names)l ' } ,
{ ' key ' : ' FFmpegConcat ' ,
' only_multi_video ' : True ,
' when ' : ' playlist ' } ,
{ ' format ' : ' vtt ' ,
' key ' : ' FFmpegSubtitlesConvertor ' ,
' when ' : ' before_dl ' } ,
{ ' already_have_subtitle ' : False ,
' key ' : ' FFmpegEmbedSubtitle ' } ] ,
' proxy ' : f ' { os . getenv ( " PROXY " ) } ' ,
' subtitlesformat ' : ' vtt ' ,
' subtitleslangs ' : [ ' en.* ' ] ,
' writesubtitles ' : True ,
' retries ' : 10 ,
}
#logging.basicConfig(level=logging.DEBUG)
ydl = yt_dlp . YoutubeDL ( ydl_opts )
obs = obsws_python . ReqClient ( )
obse = obsws_python . EventClient ( )
intents = disnake . Intents . all ( )
intents . message_content = False
bot = commands . Bot ( intents = intents , command_prefix = " . " , test_guilds = [ int ( os . getenv ( " GUILD_ID " ) ) ] )
ver = obs . get_version ( )
print ( f " OBS Version: { ver . obs_version } " )
@bot.event
async def on_ready ( ) :
obs . set_current_program_scene ( " waiting " )
obse . callback . register ( on_media_input_playback_ended )
videotimer . start ( )
ensurewaiting . start ( )
titlehandler . start ( )
if ( not os . path . isfile ( f " { vid_dir } / { vidcounter } .mp4 " ) ) and len ( queue ) > 1 :
print ( " predefined queue! " )
loop = asyncio . get_running_loop ( )
await loop . run_in_executor ( None , cold_run )
def download_video ( index ) :
while len ( os . listdir ( full_dl_dir ) ) != 0 :
pass
try :
ydl . download ( queue [ index ] )
sleep ( 2 ) #allow ytdlp to fully cleanup
except Exception :
print ( " handling youtube exception " )
global failures
if failures % 2 == 0 :
queue . pop ( index )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
user_queue . pop ( index )
failures = failures + 1
download_video ( index )
def wait_for_next_video ( ) :
counter = 0
if len ( queue ) < = 1 :
return
stat = obs . get_scene_item_id ( " youtube " , " notice " )
print ( stat . scene_item_id )
#if not os.path.isfile(f"{vid_dir}/{vidcounter+1}.mp4"):
print ( " Attempting to enable " )
obs . set_scene_item_enabled ( " youtube " , stat . scene_item_id , True )
while not os . path . isfile ( f " { vid_dir } / { vidcounter + 1 } .mp4 " ) :
counter = counter + 1
sleep ( 0.5 )
if counter == 20 and len ( os . listdir ( full_dl_dir ) ) == 0 :
print ( " failsafe activated " )
download_video ( 0 )
os . rename ( f " { vid_dir } /999zznext.mp4 " , f " { vid_dir } / { vidcounter + 1 } .mp4 " )
obs . set_scene_item_enabled ( " youtube " , stat . scene_item_id , False )
return
def cold_run ( ) :
download_video ( 0 )
os . rename ( f " { vid_dir } /999zznext.mp4 " , f " { vid_dir } / { vidcounter } .mp4 " )
obs . set_current_program_scene ( " youtube " )
nowplayingid = obs . get_scene_item_id ( " youtube " , " nowplaying " )
stat = obs . get_scene_item_id ( " youtube " , " notice " )
obs . set_scene_item_enabled ( " youtube " , stat . scene_item_id , False )
obs . set_input_settings ( " player " , { ' playlist ' : [ { ' hidden ' : False , ' selected ' : False , ' value ' : f " { str ( vid_dir ) } " } ] } , True )
obs . set_input_settings ( " nowplaying " , { ' text ' : f ' { vid_details [ " title " ] } \n By { vid_details [ " channel " ] } ' } , True )
obs . set_scene_item_enabled ( " youtube " , nowplayingid . scene_item_id , True )
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART " )
if len ( queue ) > 1 :
download_video ( 1 )
os . rename ( f " { vid_dir } /999zznext.mp4 " , f " { vid_dir } / { vidcounter + 1 } .mp4 " )
def on_media_input_playback_ended ( data ) :
global vidcounter
queue . pop ( 0 )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
user_queue . pop ( 0 )
skip_list . clear ( )
if not queue :
obs . set_current_program_scene ( " waiting " )
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
return
wait_for_next_video ( )
print ( queue )
print ( user_queue )
if shuffle :
seed = time . time ( )
randshuffle ( queue , 1 , None , seed )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
randshuffle ( user_queue , 1 , None , seed )
print ( queue )
print ( user_queue )
#obs.set_current_program_scene("youtube2")
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
#os.rename(f"{vid_dir}/999zznext.mp4", f"{vid_dir}/{vidcounter}.mp4")
print ( " changing obs settigs " )
scene = obs . get_current_program_scene ( )
if scene . scene_name != " youtube " :
obs . set_current_program_scene ( " youtube " )
nowplayingid = obs . get_scene_item_id ( " youtube " , " nowplaying " )
obs . set_input_settings ( " player " , { ' playlist ' : [ { ' hidden ' : False , ' selected ' : False , ' value ' : f " { str ( vid_dir ) } " } ] } , True )
obs . set_input_settings ( " nowplaying " , { ' text ' : f ' { vid_details [ " title " ] } \n By { vid_details [ " channel " ] } ' } , True )
obs . set_input_settings ( " nowplaying " , { ' text ' : f ' { vid_details [ " title " ] } \n By { vid_details [ " channel " ] } ' } , True ) #sometimes it doesn't apply for some reason TODO: investigate further
print ( " starting playback " )
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART " )
obs . set_scene_item_enabled ( " youtube " , nowplayingid . scene_item_id , True )
obs . set_scene_item_enabled ( " youtube " , nowplayingid . scene_item_id , True ) #same as above
if len ( queue ) > 1 :
download_video ( 1 )
os . rename ( f " { vid_dir } /999zznext.mp4 " , f " { vid_dir } / { vidcounter + 1 } .mp4 " )
@bot.slash_command (
name = " stats " ,
description = " get information about whats happening " ,
)
async def stats ( inter : disnake . AppCmdInter ) :
scene = obs . get_current_program_scene ( )
if scene . scene_name != " youtube " :
await inter . response . send_message ( " Stats can only be shown while a video is playing " , ephemeral = True )
return
await inter . response . defer ( ephemeral = True )
ver = obs . get_version ( )
message = f " OBS Version: { ver . obs_version } \n "
message = message + f " Failures: { failures } \n "
nowplaying = obs . get_input_settings ( " nowplaying " )
message = message + f " Title: { nowplaying . input_settings [ ' text ' ] } \n "
playing = obs . get_media_input_status ( " player " )
message = message + f " Video Duration: { str ( datetime . timedelta ( seconds = ( round ( playing . media_cursor / 1000 ) ) ) ) } / { str ( datetime . timedelta ( seconds = ( round ( playing . media_duration / 1000 ) ) ) ) } \n "
2024-10-19 12:28:11 +00:00
if inter . permissions . moderate_members and not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
2024-10-12 19:37:06 +00:00
message = message + f " Queued by <@ { user_queue [ 0 ] } > "
await inter . edit_original_response ( message )
@bot.slash_command (
name = " play " ,
description = " adds a video to the queue " ,
)
async def play ( inter : disnake . AppCmdInter , link : str ) :
await inter . response . defer ( ephemeral = True )
if user_queue . count ( inter . user . id ) > = ( int ( os . getenv ( " MAX_QUEUE " ) ) ) :
await inter . edit_original_response ( f " You have reached the queue limit of { os . getenv ( ' MAX_QUEUE ' ) } , " + ( " try again after one of your videos has played. " if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) else " you may not queue videos for the rest of the session. " ) )
return
if urlparse ( link ) . netloc == ' youtube.com ' or urlparse ( link ) . netloc == ' www.youtube.com ' or urlparse ( link ) . netloc == ' youtu.be ' :
queue . append ( link )
user_queue . append ( inter . user . id )
await inter . edit_original_response ( f " added to queue! " )
if ( not os . path . isfile ( f " { vid_dir } / { vidcounter } .mp4 " ) ) and len ( queue ) > 1 :
loop = asyncio . get_running_loop ( )
await loop . run_in_executor ( None , cold_run )
return
else :
await inter . edit_original_response ( f " This bot only accepts youtube links " )
return
@bot.slash_command (
name = " shuffle " ,
description = " toggles shuffle on or off, the queue cannot be unshuffled once it is shuffled " ,
)
async def shuffleplay ( inter : disnake . AppCmdInter , toggle : str = commands . Param ( choices = [ " on " , " off " ] ) ) :
if os . getenv ( " LOCK_SHUFFLE " , " FALSE " ) == " TRUE " :
await inter . response . send_message ( " the bot owner has locked shuffling " , ephemeral = True )
return
await inter . response . defer ( ephemeral = True )
global shuffle
if toggle == " on " :
shuffle = True
await inter . edit_original_response ( f " shuffle enabled " )
return
else :
shuffle = False
await inter . edit_original_response ( f " shuffle disabled " )
return
@bot.slash_command (
name = " queue " ,
description = " list the videos in queue " ,
)
async def getqueue ( inter : disnake . AppCmdInter ) :
await inter . response . defer ( ephemeral = True )
if not queue :
await inter . edit_original_response ( " There are no items in queue " )
return
message = f " Now Playing: < { queue [ 0 ] } > \n "
message = message + f " Shuffle is currently " + ( " off \n " if not shuffle else " on! \n " )
for i in range ( 11 ) :
if i == 0 :
continue
try :
message = message + f " { i } . < { queue [ i ] } > \n "
except IndexError :
break
message = message + f " 1 of { math . ceil ( ( len ( queue ) - 1 ) / 10 ) if ( len ( queue ) - 1 ) / 10 > 1 else 1 } "
if math . ceil ( ( len ( queue ) - 1 ) / 10 ) > 1 :
await inter . edit_original_response ( message , components = [ disnake . ui . Button ( label = " >> " , style = disnake . ButtonStyle . primary , custom_id = " Forward " ) , ] )
else :
await inter . edit_original_response ( message )
@bot.listen ( " on_button_click " )
async def button_listener ( inter : disnake . MessageInteraction ) :
if not queue :
await inter . response . edit_message ( " There are no items in queue " )
return
ogmsg = inter . message . content
page = ogmsg . split ( " \n " )
page = page [ - 1 ] . split ( " of " )
if inter . component . custom_id == " Forward " :
message = f " Now Playing: < { queue [ 0 ] } > \n "
message = message + f " Shuffle is currently " + ( " off \n " if not shuffle else " on! \n " )
offset = int ( int ( page [ 0 ] ) * 10 )
for i in range ( 11 ) :
if i == 0 :
continue
try :
message = message + f " { int ( i + offset ) } . < { queue [ int ( i + offset ) ] } > \n "
except IndexError :
break
message = message + f " { int ( page [ 0 ] ) + 1 } of { math . ceil ( ( len ( queue ) - 1 ) / 10 ) if ( len ( queue ) - 1 ) / 10 > 1 else 1 } "
if ( int ( page [ 0 ] ) + 1 ) > = int ( page [ 1 ] ) :
await inter . response . edit_message ( message , components = [ disnake . ui . Button ( label = " << " , style = disnake . ButtonStyle . primary , custom_id = " Backward " ) , ] )
else :
await inter . response . edit_message ( message , components = [ disnake . ui . Button ( label = " << " , style = disnake . ButtonStyle . primary , custom_id = " Backward " ) ,
disnake . ui . Button ( label = " >> " , style = disnake . ButtonStyle . primary , custom_id = " Forward " ) , ] )
return
if inter . component . custom_id == " Backward " :
message = f " Now Playing: < { queue [ 0 ] } > \n "
message = message + f " Shuffle is currently " + ( " off \n " if not shuffle else " on! \n " )
offset = int ( ( int ( page [ 0 ] ) - 2 ) * 10 )
for i in range ( 11 ) :
if i == 0 :
continue
try :
message = message + f " { int ( i + offset ) } . < { queue [ int ( i + offset ) ] } > \n "
except IndexError :
break
message = message + f " { int ( page [ 0 ] ) - 1 } of { math . ceil ( ( len ( queue ) - 1 ) / 10 ) if ( len ( queue ) - 1 ) / 10 > 1 else 1 } "
if ( int ( page [ 0 ] ) - 1 ) < = 1 and int ( int ( page [ 1 ] ) == 1 ) :
await inter . response . edit_message ( message )
elif ( int ( page [ 0 ] ) - 1 ) < = 1 and int ( int ( page [ 1 ] ) > 1 ) :
await inter . response . edit_message ( message , components = [ disnake . ui . Button ( label = " >> " , style = disnake . ButtonStyle . primary , custom_id = " Forward " ) , ] )
else :
await inter . response . edit_message ( message , components = [ disnake . ui . Button ( label = " << " , style = disnake . ButtonStyle . primary , custom_id = " Backward " ) ,
disnake . ui . Button ( label = " >> " , style = disnake . ButtonStyle . primary , custom_id = " Forward " ) , ] )
await inter . response . edit_message ( message , components = [ ] )
return
@bot.slash_command (
name = " toggleplayback " ,
description = " play or pause the video " ,
)
async def toggleplayback ( inter : disnake . AppCmdInter ) :
stat = obs . get_media_input_status ( " player " )
print ( stat . media_state )
if stat . media_state == " OBS_MEDIA_STATE_PLAYING " :
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE " )
elif stat . media_state == " OBS_MEDIA_STATE_PAUSED " :
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PLAY " )
await inter . response . send_message ( " done " , ephemeral = True )
@bot.slash_command (
name = " skip " ,
description = " skips the current video " ,
default_member_permissions = disnake . Permissions ( 8192 ) ,
)
async def skip ( inter : disnake . AppCmdInter ) :
if os . getenv ( " ALLOW_SKIP " , " TRUE " ) == " FALSE " :
await inter . response . send_message ( " the bot owner has disabled skipping " , ephemeral = True )
return
await inter . response . defer ( ephemeral = False )
loop = asyncio . get_running_loop ( )
global vidcounter
queue . pop ( 0 )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
user_queue . pop ( 0 )
skip_list . clear ( )
if not queue :
obs . set_current_program_scene ( " waiting " )
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
await inter . edit_original_response ( " skipped as sufficient votes were reached " )
return
await loop . run_in_executor ( None , wait_for_next_video )
print ( " stopping video " )
#obs.trigger_media_input_action("player", "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE")
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
nowplayingid = obs . get_scene_item_id ( " youtube " , " nowplaying " )
obs . set_input_settings ( " player " , { ' playlist ' : [ { ' hidden ' : False , ' selected ' : False , ' value ' : f " { str ( vid_dir ) } " } ] } , True )
obs . set_input_settings ( " nowplaying " , { ' text ' : f ' { vid_details [ " title " ] } \n By { vid_details [ " channel " ] } ' } , True )
obs . set_scene_item_enabled ( " youtube " , nowplayingid . scene_item_id , True )
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART " )
await inter . edit_original_response ( " skipped as sufficient votes were reached " )
if len ( queue ) > 1 :
await loop . run_in_executor ( None , download_video , 1 )
os . rename ( f " { vid_dir } /999zznext.mp4 " , f " { vid_dir } / { vidcounter + 1 } .mp4 " )
@bot.slash_command (
name = " voteskip " ,
description = " vote to skip the current video " ,
)
async def voteskip ( inter : disnake . AppCmdInter ) :
if os . getenv ( " ALLOW_SKIP " , " TRUE " ) == " FALSE " :
await inter . response . send_message ( " the bot owner has disabled skipping " , ephemeral = True )
return
await inter . response . defer ( ephemeral = False )
if not inter . user . voice :
await inter . edit_original_response ( " You are not in the voice channel " )
return
if inter . user . id in skip_list :
await inter . edit_original_response ( " You have already voted to skip this video " )
return
vc = inter . user . voice . channel . members #this could be better due to potential for abuse, but it's fine for now
print ( inter . user . voice . channel . name )
broadcaster = False
for m in vc :
if m . voice . self_video or m . voice . self_stream :
broadcaster = True
break
if not broadcaster :
await inter . edit_original_response ( " No one is playing video so how can this be the correct vc? " )
return
skip_list . append ( inter . user . id )
print ( len ( skip_list ) )
print ( math . floor ( len ( vc ) / 2 ) )
print ( vc )
if len ( skip_list ) > = ( math . floor ( len ( vc ) / 2 ) ) :
loop = asyncio . get_running_loop ( )
global vidcounter
queue . pop ( 0 )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
user_queue . pop ( 0 )
skip_list . clear ( )
if not queue :
obs . set_current_program_scene ( " waiting " )
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
await inter . edit_original_response ( " skipped as sufficient votes were reached " )
return
await loop . run_in_executor ( None , wait_for_next_video )
print ( " stopping video " )
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE " )
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
nowplayingid = obs . get_scene_item_id ( " youtube " , " nowplaying " )
obs . set_input_settings ( " player " , { ' playlist ' : [ { ' hidden ' : False , ' selected ' : False , ' value ' : f " { str ( vid_dir ) } " } ] } , True )
obs . set_input_settings ( " nowplaying " , { ' text ' : f ' { vid_details [ " title " ] } \n By { vid_details [ " channel " ] } ' } , True )
obs . set_scene_item_enabled ( " youtube " , nowplayingid . scene_item_id , True )
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART " )
await inter . edit_original_response ( " skipped as sufficient votes were reached " )
if len ( queue ) > 1 :
await loop . run_in_executor ( None , download_video , 1 )
os . rename ( f " { vid_dir } /999zznext.mp4 " , f " { vid_dir } / { vidcounter + 1 } .mp4 " )
else :
await inter . edit_original_response ( f " ** { inter . user . display_name } ** has voted to skip the video, { len ( skip_list ) } / { math . floor ( len ( vc ) / 2 ) } " )
@bot.slash_command (
name = " remove " ,
description = " removes a video from the queue " ,
default_member_permissions = disnake . Permissions ( 8192 ) ,
)
async def remove ( inter : disnake . AppCmdInter , toremove : int ) :
await inter . response . defer ( ephemeral = True )
if toremove == 0 or toremove == 1 :
await inter . edit_original_response ( " that is the currently playing video! " , ephemeral = True )
return
else :
queue . pop ( toremove )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
user_queue . pop ( toremove )
await inter . edit_original_response ( " removed! " )
@tasks.loop ( seconds = 5.0 )
async def videotimer ( ) :
try :
scene = obs . get_current_program_scene ( )
if scene . scene_name != " youtube " :
return
playing = obs . get_media_input_status ( " player " )
if playing . media_cursor > = ( ( float ( os . getenv ( " MAX_MIN " ) ) * 60000 ) ) :
#skip
loop = asyncio . get_running_loop ( )
global vidcounter
playing = obs . get_media_input_status ( " player " )
if playing . media_state == " OBS_MEDIA_STATE_STOPPED " or playing . media_state == " OBS_MEDIA_STATE_ENDED " :
#we are already handling it
print ( " skip return " )
return
queue . pop ( 0 )
if not ( os . getenv ( " PERMANENT_MAX_QUEUE " , " FALSE " ) == " TRUE " ) :
user_queue . pop ( 0 )
skip_list . clear ( )
if not queue :
obs . set_current_program_scene ( " waiting " )
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
return
await loop . run_in_executor ( None , wait_for_next_video )
print ( " stopping video " )
#obs.trigger_media_input_action("player", "OBS_WEBSOCKET_MEDIA_INPUT_ACTION_PAUSE")
os . remove ( f " { vid_dir } / { vidcounter } .mp4 " )
vidcounter = vidcounter + 1
obs . set_input_settings ( " player " , { ' playlist ' : [ { ' hidden ' : False , ' selected ' : False , ' value ' : f " { str ( vid_dir ) } " } ] } , True )
obs . trigger_media_input_action ( " player " , " OBS_WEBSOCKET_MEDIA_INPUT_ACTION_RESTART " )
if len ( queue ) > 1 :
await loop . run_in_executor ( None , download_video , 1 )
os . rename ( f " { vid_dir } /999zznext.mp4 " , f " { vid_dir } / { vidcounter + 1 } .mp4 " )
except Exception :
pass
return
@tasks.loop ( seconds = 20 )
async def ensurewaiting ( ) :
scene = obs . get_current_program_scene ( )
if scene . scene_name == " waiting " :
return
if scene . scene_name == " error " and len ( os . listdir ( full_dl_dir ) ) == 0 :
obs . set_current_program_scene ( " waiting " )
return
elif scene . scene_name == " error " :
return
stat = obs . get_scene_item_id ( " youtube " , " notice " )
enabled = obs . get_scene_item_enabled ( " youtube " , stat . scene_item_id )
if enabled . scene_item_enabled :
return
playing = obs . get_media_input_status ( " player " )
if playing . media_cursor == None :
obs . set_current_program_scene ( " error " )
if len ( os . listdir ( full_dl_dir ) ) == 0 and len ( queue ) > = 1 : #just in case
2024-10-19 12:28:11 +00:00
loop = asyncio . get_running_loop ( )
2024-10-12 19:37:06 +00:00
await loop . run_in_executor ( None , download_video , 0 )
@tasks.loop ( seconds = 5 )
async def titlehandler ( ) :
scene = obs . get_current_program_scene ( )
if scene . scene_name != " youtube " :
return
nowplayingid = obs . get_scene_item_id ( " youtube " , " nowplaying " )
enabled = obs . get_scene_item_enabled ( " youtube " , nowplayingid . scene_item_id )
if enabled . scene_item_enabled :
await asyncio . sleep ( 4 )
obs . set_scene_item_enabled ( " youtube " , nowplayingid . scene_item_id , False )
return
bot . run ( os . getenv ( " TOKEN " ) )
print ( " cleaning up tempdir " )
temp_dir . cleanup ( )
2024-10-19 12:28:11 +00:00
download_dir . cleanup ( )
obs . set_current_program_scene ( " nosignal " )