Change OBS Filename before replay buffer is saved using obspython - python

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.

Related

python console terminal sholuld stay on top of any window

Would like your opinion and support on an issue i am trying to overcome. This will be the last piece of puzzle for completion of a small project i am building. Its based on OCR. I am reading text from a live screen ( using below python script ) and able to get the results logged into a file. However, the output is only getting logged once i make the python console window ( in which the script prints the output ) is active/focused by keyboad using alt+tab.
But doing this halts the software from where i am reading the text, breaking the whole process. Toggling the window to the front of the software is a failure to the scripts purpose.
So, i added code after searching from other users about keeping the python console window on top always no matter what the software is doing. I am not able to keep this python console window on top of this sw screen. The SW uses all screen for its purpose of work.
Is there an alternative to this? How can i make the python console become on top of any other window no matter what is on the screen? If not this, please suggest an alternative.
import numpy as nm
from datetime import datetime
import pytesseract
import cv2
import PIL
from PIL import ImageGrab
import win32gui, win32process, win32con
import os
hwnd = win32gui.GetForegroundWindow()
win32gui.SetWindowPos(hwnd,win32con.HWND_TOPMOST,0,0,100,300,0)
#Define function for OCR to enable on multiple screens.
def imToString():
# Path of tesseract executable
pytesseract.pytesseract.tesseract_cmd ='C:\\Tesseract-OCR\\tesseract.exe'
while(True):
# ImageGrab-To capture the screen image in a loop.
# Bbox used to capture a specific area.
#screen base
cap1 = PIL.ImageGrab.grab(bbox =(0, 917, 1913, 1065), include_layered_windows=False, all_screens=True)
date = datetime.now().strftime("%Y-%m-%d %I:%M:%S")
#str config - OCR Engine settings for ONLY text based capture.
config1 = ('-l eng --oem 2 --psm 6')
#configuring tesseract engine for OCR
tess1 = pytesseract.image_to_string(
cv2.cvtColor(nm.array(cap1), cv2.COLOR_BGR2GRAY),
config=config1)
#Defining log pattern to generate
a = [ date, " State: ", tess1 ]
#writing logging output to file
file1 = open("C:\\Users\\User\\Desktop\\rev2.log", "a", encoding='UTF8')
file1.writelines(a)
file1.writelines("\n")
file1.close()
#OUTPUT on colse for Logging verification
print (date, "State: ", tess1)
# Calling the function
imToString()
By requirement, i am not allowed to use a keyboad while operating the screen. I am fairly new to python and have been seeing similar solutions and adding it to the script to make a proper solution.
Please advise.
Here is the tkinter method:
from tkinter import Tk, Text
import subprocess
import threading
from queue import Queue, Empty
filename = 'test.py'
def stream_from(queue):
command = f'python {filename}'
with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
for out in process.stdout:
queue.put(out.decode())
def update_text(queue):
try:
data = queue.get(block=False)
except Empty:
pass
else:
text.config(state='normal')
text.insert('end', data.strip() + '\n')
text.config(state='disabled')
finally:
root.after(100, update_text, queue)
def loop():
root.attributes('-topmost', True)
root.after(1, loop)
root = Tk()
text = Text(root, state='disabled')
text.pack()
data_queue = Queue()
threading.Thread(target=stream_from, args=(data_queue, ), daemon=True).start()
update_text(data_queue)
loop()
root.mainloop()
Just change the filename to the name of the file you are running and place this script in the same directory
Change delay_in_ms (delay in milliseconds so each 1000 units is one second) and see if that helps (could also leave the 10 seconds and see if it works now, if not there is still another thing to try)
If you are using print to output then this should work (tho I maybe didn't exactly get what you want), if you use logging then there is a slightly different solution

Open random video file on a keypress

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)

Python program disregards button input

I'm new to python and linux, and I recently set up a twitter bot with my Raspberry Pi to mess around and have fun with. I want to set up a system where my RasPi sends a tweet every time I press a button. I followed the instructions on https://raspberrypihq.com/use-a-push-button-with-raspberry-pi-gpio to set up the basic input.
I have two .py files, tweet_test.py and buttonPress.py
tweet_test:
#!/usr/bin/env python
import os
import random
from twython import Twython
# your twitter consumer and access information goes here
apiKey = ''
apiSecret = ''
accessToken = ''
accessTokenSecret = ''
api = Twython(apiKey,apiSecret,accessToken,accessTokenSecret)
messages = [
"A button was pressed!!",
"My creator pressed a button.",
"This tweet was triggered by a button press.",
]
message = random.choice(messages)
api.update_status(status=message)
print("Tweeted: " + message)
buttonPress:
import tweet_test
import RPi.GPIO as GPIO #Import Raspberry Pi GPIO library
def button_callback(channel):
tweet_test
print("Button was pushed!")
GPIO.setwarnings(False) #Ignore warning for now
GPIO.setmode(GPIO.BOARD) #Use physical pin numbering
GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) #Set pin 10 to be an
input pin and set initial value to be pulled low (off)
GPIO.add_event_detect(10,GPIO.RISING,callback=button_callback) #Set up
event on pin 10 rising edge
message = input("Press enter to quit\n\n") #Run until someone presses
enter
GPIO.cleanup() #Clean Up
However, when I run buttonPress.py in the command line, the first thing it does is tweet, without even having received any input from the button. Then, it begins receiving button inputs, but doesn't tweet anything. Please help!
Sample output:
user1#raspberrypi:~/TwitterBot $ sudo python buttonPress.py
Tweeted: A button was pressed!!
Press enter to quit
Button was pushed!
Button was pushed!
Button was pushed!
You import tweet_test.py at the very beginning and it will run first, which will run as exactly it is supposed to do, i.e. to send a tweet. You need to wrap the tweeting part as a function so that it only run when it is called:
In tweet_test.py
def tweet():
message = random.choice(messages)
api.update_status(status=message)
print("Tweeted: " + message)
In buttonPress.py
Call the tweet() function in your button_callback like this:
def button_callback(channel):
tweet()
print("Button was pushed!")
Alternatively, just move the tweeting part to the button_call function, and combined both into your button_callback:
def button_callback(channel):
message = random.choice(messages)
api.update_status(status=message)
print("Button was pushed! Tweeted: %s" % message)
Update
Please also change the line import tweet_test to from tweet_test import *

How to capture frames from Apple iSight using Python and PyObjC?

I am trying to capture a single frame from the Apple iSight camera built into a Macbook Pro using Python (version 2.7 or 2.6) and the PyObjC (version 2.2).
As a starting point, I used this old StackOverflow question. To verify that it makes sense, I cross-referenced against Apple's MyRecorder example that it seems to be based on. Unfortunately, my script does not work.
My big questions are:
Am I initializing the camera correctly?
Am I starting the event loop correctly?
Was there any other setup I was supposed to do?
In the example script pasted below, the intended operation is that after calling startImageCapture(), I should start printing "Got a frame..." messages from the CaptureDelegate. However, the camera's light never turns on and the delegate's callback is never executed.
Also, there are no failures during startImageCapture(), all functions claim to succeed, and it successfully finds the iSight device. Analyzing the session object in pdb shows that it has valid input and output objects, the output has a delegate assigned, the device is not in use by another processes, and the session is marked as running after startRunning() is called.
Here's the code:
#!/usr/bin/env python2.7
import sys
import os
import time
import objc
import QTKit
import AppKit
from Foundation import NSObject
from Foundation import NSTimer
from PyObjCTools import AppHelper
objc.setVerbose(True)
class CaptureDelegate(NSObject):
def captureOutput_didOutputVideoFrame_withSampleBuffer_fromConnection_(self, captureOutput,
videoFrame, sampleBuffer,
connection):
# This should get called for every captured frame
print "Got a frame: %s" % videoFrame
class QuitClass(NSObject):
def quitMainLoop_(self, aTimer):
# Just stop the main loop.
print "Quitting main loop."
AppHelper.stopEventLoop()
def startImageCapture():
error = None
# Create a QT Capture session
session = QTKit.QTCaptureSession.alloc().init()
# Find iSight device and open it
dev = QTKit.QTCaptureDevice.defaultInputDeviceWithMediaType_(QTKit.QTMediaTypeVideo)
print "Device: %s" % dev
if not dev.open_(error):
print "Couldn't open capture device."
return
# Create an input instance with the device we found and add to session
input = QTKit.QTCaptureDeviceInput.alloc().initWithDevice_(dev)
if not session.addInput_error_(input, error):
print "Couldn't add input device."
return
# Create an output instance with a delegate for callbacks and add to session
output = QTKit.QTCaptureDecompressedVideoOutput.alloc().init()
delegate = CaptureDelegate.alloc().init()
output.setDelegate_(delegate)
if not session.addOutput_error_(output, error):
print "Failed to add output delegate."
return
# Start the capture
print "Initiating capture..."
session.startRunning()
def main():
# Open camera and start capturing frames
startImageCapture()
# Setup a timer to quit in 10 seconds (hack for now)
quitInst = QuitClass.alloc().init()
NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(10.0,
quitInst,
'quitMainLoop:',
None,
False)
# Start Cocoa's main event loop
AppHelper.runConsoleEventLoop(installInterrupt=True)
print "After event loop"
if __name__ == "__main__":
main()
Thanks for any help you can provide!
OK, I spent a day diving through the depths of PyObjC and got it working.
For future record, the reason the code in the question did not work: variable scope and garbage collection. The session variable was deleted when it fell out of scope, which happened before the event processor ran. Something must be done to retain it so it is not freed before it has time to run.
Moving everything into a class and making session a class variable made the callbacks start working. Additionally, the code below demonstrates getting the frame's pixel data into bitmap format and saving it via Cocoa calls, and also how to copy it back into Python's world-view as a buffer or string.
The script below will capture a single frame
#!/usr/bin/env python2.7
#
# camera.py -- by Trevor Bentley (02/04/2011)
#
# This work is licensed under a Creative Commons Attribution 3.0 Unported License.
#
# Run from the command line on an Apple laptop running OS X 10.6, this script will
# take a single frame capture using the built-in iSight camera and save it to disk
# using three methods.
#
import sys
import os
import time
import objc
import QTKit
from AppKit import *
from Foundation import NSObject
from Foundation import NSTimer
from PyObjCTools import AppHelper
class NSImageTest(NSObject):
def init(self):
self = super(NSImageTest, self).init()
if self is None:
return None
self.session = None
self.running = True
return self
def captureOutput_didOutputVideoFrame_withSampleBuffer_fromConnection_(self, captureOutput,
videoFrame, sampleBuffer,
connection):
self.session.stopRunning() # I just want one frame
# Get a bitmap representation of the frame using CoreImage and Cocoa calls
ciimage = CIImage.imageWithCVImageBuffer_(videoFrame)
rep = NSCIImageRep.imageRepWithCIImage_(ciimage)
bitrep = NSBitmapImageRep.alloc().initWithCIImage_(ciimage)
bitdata = bitrep.representationUsingType_properties_(NSBMPFileType, objc.NULL)
# Save image to disk using Cocoa
t0 = time.time()
bitdata.writeToFile_atomically_("grab.bmp", False)
t1 = time.time()
print "Cocoa saved in %.5f seconds" % (t1-t0)
# Save a read-only buffer of image to disk using Python
t0 = time.time()
bitbuf = bitdata.bytes()
f = open("python.bmp", "w")
f.write(bitbuf)
f.close()
t1 = time.time()
print "Python saved buffer in %.5f seconds" % (t1-t0)
# Save a string-copy of the buffer to disk using Python
t0 = time.time()
bitbufstr = str(bitbuf)
f = open("python2.bmp", "w")
f.write(bitbufstr)
f.close()
t1 = time.time()
print "Python saved string in %.5f seconds" % (t1-t0)
# Will exit on next execution of quitMainLoop_()
self.running = False
def quitMainLoop_(self, aTimer):
# Stop the main loop after one frame is captured. Call rapidly from timer.
if not self.running:
AppHelper.stopEventLoop()
def startImageCapture(self, aTimer):
error = None
print "Finding camera"
# Create a QT Capture session
self.session = QTKit.QTCaptureSession.alloc().init()
# Find iSight device and open it
dev = QTKit.QTCaptureDevice.defaultInputDeviceWithMediaType_(QTKit.QTMediaTypeVideo)
print "Device: %s" % dev
if not dev.open_(error):
print "Couldn't open capture device."
return
# Create an input instance with the device we found and add to session
input = QTKit.QTCaptureDeviceInput.alloc().initWithDevice_(dev)
if not self.session.addInput_error_(input, error):
print "Couldn't add input device."
return
# Create an output instance with a delegate for callbacks and add to session
output = QTKit.QTCaptureDecompressedVideoOutput.alloc().init()
output.setDelegate_(self)
if not self.session.addOutput_error_(output, error):
print "Failed to add output delegate."
return
# Start the capture
print "Initiating capture..."
self.session.startRunning()
def main(self):
# Callback that quits after a frame is captured
NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(0.1,
self,
'quitMainLoop:',
None,
True)
# Turn on the camera and start the capture
self.startImageCapture(None)
# Start Cocoa's main event loop
AppHelper.runConsoleEventLoop(installInterrupt=True)
print "Frame capture completed."
if __name__ == "__main__":
test = NSImageTest.alloc().init()
test.main()
QTKit is deprecated and PyObjC is a big dependency (and seems to be tricky to build if you want it in HomeBrew). Plus PyObjC did not have most of AVFoundation so I created a simple camera extension for Python that uses AVFoundation to record a video or snap a picture, it requires no dependencies (Cython intermediate files are committed to avoid the need to have Cython for most users).
It should be possible to build it like this:
pip install -e git+https://github.com/dashesy/pyavfcam.git
Then we can use it to take a picture:
import pyavfcam
# Open the default video source
cam = pyavfcam.AVFCam(sinks='image')
frame = cam.snap_picture('test.jpg') # frame is a memory buffer np.asarray(frame) can retrieve
Not related to this question, but if the AVFCam class is sub-classed, the overridden methods will be called with the result.

How to continuously monitor rhythmbox for track change using python

I want to monitor the change of track in Rhythmbox using python. I want to continuously check for change of track and execute a set of functions if the track is changed. I have written a piece of code which gets hold of the Rhythmbox interfaces from the dbus and gets the current track details. But this program has to be run manually to check for any change.
I am new to this and I would like to know how we can create a background process which continuously runs and checks Rhythmbox.
I dont want to make a Rhythmbox plugin(which rather would make my work simple) as I will be extending the application to listen to multiple music players.
Please suggest me what exactly I would have to do to achieve the functionality.
The Rhythmbox player object (/org/gnome/Rhythmbox/Player) sends a playingUriChanged signal whenever the current song changes. Connect a function to the signal to have it run whenever the signal is received. Here's an example that prints the title of the song whenever a new song starts, using the GLib main loop to process DBus messages:
#! /usr/bin/env python
import dbus
import dbus.mainloop.glib
import glib
# This gets called whenever Rhythmbox sends the playingUriChanged signal
def playing_song_changed (uri):
global shell
if uri != "":
song = shell.getSongProperties (uri)
print "Now playing: {0}".format (song["title"])
else:
print "Not playing anything"
dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
bus = dbus.SessionBus ()
proxy = bus.get_object ("org.gnome.Rhythmbox", "/org/gnome/Rhythmbox/Player")
player = dbus.Interface (proxy, "org.gnome.Rhythmbox.Player")
player.connect_to_signal ("playingUriChanged", playing_song_changed)
proxy = bus.get_object ("org.gnome.Rhythmbox", "/org/gnome/Rhythmbox/Shell")
shell = dbus.Interface (proxy, "org.gnome.Rhythmbox.Shell")
# Run the GLib event loop to process DBus signals as they arrive
mainloop = glib.MainLoop ()
mainloop.run ()
Take a look at the Conky script here:
https://launchpad.net/~conkyhardcore/+archive/ppa/+files/conkyrhythmbox_2.12.tar.gz
That uses dbus to talk to rhythmbox, like so:
bus = dbus.SessionBus()
remote_object_shell = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell')
iface_shell = dbus.Interface(remote_object_shell, 'org.gnome.Rhythmbox.Shell')
remote_object_player = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Player')
iface_player = dbus.Interface(remote_object_player, 'org.gnome.Rhythmbox.Player')
You can call a number of functions on iface_player to get the required information. It looks like you'll have to poll from this example though. If you want to receive a message from dbus on track change you'll have to do that in a different way. This discusses from avenues to explore:
http://ubuntuforums.org/showthread.php?t=156706
I am using Ubuntu 14.04.1 and the above script is deprecated for Rhythmbox 3. I am using this script to write the current song to ~/.now_playing for BUTT to read, but you can update it for your needs. Rhythmbox uses MPRIS now and you can get info here:
http://specifications.freedesktop.org/mpris-spec/latest/index.html
#!/usr/bin/python
import dbus
import dbus.mainloop.glib
import glib
# This gets called whenever Rhythmbox sends the playingUriChanged signal
def playing_song_changed (Player,two,three):
global iface
global track
global home
track2 = iface.Get(Player,"Metadata").get(dbus.String(u'xesam:artist'))[0] + " - "+ iface.Get(Player,"Metadata").get(dbus.String(u'xesam:title'))
if track != track2:
track = iface.Get(Player,"Metadata").get(dbus.String(u'xesam:artist'))[0] + " - "+ iface.Get(Player,"Metadata").get(dbus.String(u'xesam:title'))
f = open( home + '/.now_playing', 'w' )
f.write( track + '\n' )
f.close()
dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
bus = dbus.SessionBus ()
from os.path import expanduser
home = expanduser("~")
player = bus.get_object ("org.mpris.MediaPlayer2.rhythmbox", "/org/mpris/MediaPlayer2")
iface = dbus.Interface (player, "org.freedesktop.DBus.Properties")
track = iface.Get("org.mpris.MediaPlayer2.Player","Metadata").get(dbus.String(u'xesam:artist'))[0] + " - "+ iface.Get("org.mpris.MediaPlayer2.Player","Metadata").get(dbus.Strin$
f = open( home + "/.now_playing", 'w' )
f.write( track + '\n' )
f.close()
iface.connect_to_signal ("PropertiesChanged", playing_song_changed)
# Run the GLib event loop to process DBus signals as they arrive
mainloop = glib.MainLoop ()
mainloop.run ()
Something like:
from time import sleep
execute = True
while execute:
your_function_call()
sleep(30) # in seconds; prevent busy polling
Should work just fine. If that was hooked up to something that listened to signals (import signal) so that you could set execute to False when someone ctrl-c's the application, that'd be basically what you're after.
Otherwise, have a Google for daemonisation (which involves forking the process a couple of times); from memory, there's even a decent Python library now (which, from memory, requires 2.5/2.6 with statements) which would help make that side of things easier :).

Categories

Resources