I have written this little script to show current track playing on xmms2 on a notification widget using xmms client and pynotify, so when i run it i can see the widget popup with current artist and title using xmmsclient methods.
Can anybody give some hints about how to detect track change to notify automatically without having to run the script manually?
You connect the client library to a main loop, and register as a listener via the broadcast_ playback_current_id method. If you want the currently playing id when the script starts as well you can call the playback_current_id method.
Here is a small adaptation of tutorial6 in the xmms2-tutorial.git which uses the GLib Mainloop to drive the connection:
import xmmsclient
import xmmsclient.glib
import os
import sys
import gobject
def cb(result):
if not result.is_error():
print "Current: %(artist)s - %(title)s" % result.value()
ml = gobject.MainLoop(None, False)
xc = xmmsclient.XMMS("stackoverflow")
xc.connect()
conn = xmmsclient.glib.GLibConnector(xc)
xc.broadcast_playback_current_id(lambda r: xc.medialib_get_info(r.value(), cb))
ml.run()
Related
How to reset Systemd Watchdog using Python? I'm implementing a watchdog for a multi-threaded picture detection software with many dependencies. Previously, the service started a shell script, but now it starts the Python file directly. However, the watchdog implementation is not functioning correctly. Is there a more effective alternative? The goal is to restart the "Picture Detection Main Application" service if the program gets stuck in a loop for 30 seconds or more.
Following the service in the systemd folder
[Unit]
Description=Picturedetection Main application
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=user
WorkingDirectory=/home/user/detection/
ExecStart=/usr/bin/python3 /home/user/detection/picturedetection.py
Environment=TF_CUDNN_USE_AUTOTUNE=0
WatchdogSec=30
Restart=always
WatchdogTimestamp=30
[Install]
WantedBy=multi-user.target
Following the python main i currently use
import sys
import syslog
from multiprocessing import Queue
from DetectionDefines import Detection_Version as OV
import time
print("OPTICONTROL START")
syslog.syslog(syslog.LOG_NOTICE, "PICTUREDETECTION START --- Version " + OV.major + "." + OV.minor)
from config.Config import Config as conf
from prediction.ImageFeed import ImageFeed
from prediction.ResultHandler import ResultHandler
from dataflow.CommServer import CommServer
from dataflow.FTLComm import FTLComm
from dataflow.MiniHTTPServer import MiniHTTPServer
from dataflow.GraphDownloader import GraphDownloader
from tools.Logger import Logger
from dataflow.FTPHandler import FTPHandler
from tools.FileJanitor import FileJanitor
from prediction.PredictionPipeline import PredictionPipeline
#Watchdog test
import os
import time
import systemd
# Communication
CommServer().start()
FTLComm()
#Experimental not working right now. Probably even delete
test = Logger("<WATCHDOGWATCHDOG> ")
def WatchdogReset():
test.notice("WATCHDOG has been reseted")
with open("/dev/watchdog", "w") as f:
f.write("1")
#End of Experimental
# Other subprocesses
MiniHTTPServer().start()
FileJanitor().start()
FTPHandler().start()
GraphDownloader().start()
# Detection subprocesses
img_queue = Queue(maxsize = 1)
rst_queue = Queue(maxsize = conf.result_buffer)
ImageFeed(img_queue).start()
ResultHandler(rst_queue).start()
while True:
# CUDA / TensorFlow need to be in the main process
PredictionPipeline(img_queue, rst_queue).predict()
systemd.daemon.notify("WATCHDOG=1")
Additionally, I want to ensure that the program restarts if it gets stuck in an infinite loop. However, this is a multi-threaded program. Will it still be able to restart while other processes are running?
I attempted to activate the watchdog using the method, but it seems to have no effect. The script restarts every 30 seconds. I considered the possibility of an error in my implementation, but using an "os" query didn't resolve the issue.
Additionally, I attempted to use a custom "FileWatchdog" that sends error messages and restarts the service by executing a shell script. However, this requires superuser rights, and I don't want to distribute software with a hardcoded password. Additionally, I believe this solution would pose a challenge in the long term.
I found the solution
Instead I used the sdnotify library which you can download via pip. Then I checked the currend processes if they´re still alive.
Like this:
import sdnotify
from tools.Logger import Logger
from tools import Watchdog
test = Logger("<WATCHDOGWATCHDOG> ")
n = sdnotify.SystemdNotifier()
n.notify("READY=1")
imdfg = ImageFeed(img_queue)
rslt = ResultHandler(rst_queue)
imdfg.start()
rslt.start()
if(Watchdog.check(imdfg)):
n.notify("WATCHDOG=1")
test.notice("OPTICONTROL_WATCHDOG Reset")
time.sleep(2)
#Watchdog file
from multiprocessing import process
def check(prc):
return prc.is_alive()
I have an application in the hidden part of the systray in Windows 10. I am trying to connect to the application, right-click on it, and then select something like "About". I understand that once I have the target application, I need to connect to the application, which I do in line 25 of the code, but I cannot get further from there.
This is the code I have so far:
from pywinauto import Application
import time
app = Application(backend="uia").connect(path="explorer.exe")
systemTray = app.window(class_name="Shell_TrayWnd")
systemTray.child_window(title="Notification Chevron").click_input(button="left")
#systemTray.print_control_identifiers()
time.sleep(0.25)
list_box = Application(backend="uia").connect(class_name="NotifyIconOverflowWindow")
list_box_win = list_box.window(class_name="NotifyIconOverflowWindow")
list_box_win.wait('visible', timeout=30, retry_interval=3)
# List all the icons in the systray
for notification_area in list_box_win.children():
for app_in_tray in notification_area.children():
print(str(app_in_tray))
target_app = list_box_win.child_window(title="TrayStatus Pro Trial 4.6\r\nCaps Lock: Off")
target_app.wait('visible', timeout=30, retry_interval=3)
target_app.click_input(button="right")
target_app.target_app.print_control_identifiers()
target_app.dump_tree()
sysapp = Application().connect(path='TrayStatus.exe')
sysapp.menu_select('About') #This part fails
Application() class represents the application and sometime it fails to identify the window. Having said that, you have not mentioned the backend of the application at the beginning you have used UIA backend so figure out for the line sysapp = Application().connect(path='TrayStatus.exe') as well and add, Also adding timeout=10 parameter to the connect() works many times.
Still if the above option doesn't not work for you then try using Desktop class.
again you can mention backend of your choice and compatibility, there is no such way to identify backend of application.
window2 = Desktop(backend="win32").window(title='title of the rayStatus.exe window')
you will need to import -
from pywinauto import Desktop.
Finally you can print the titile of windows using
list_window = Desktop().windows()
for window in list_window:
window.window_texts() # this should print the all open window names on desktop
I am writing a script intended to be used by members of a project team. As part of the script, I am launching a 3rd party proprietary application run through Citrix. I am going to use the script mostly to send keys to this application, but the first step once it launches is for the user to log in.
Because I would like the user to log in while the script is running, rather than asking for user/pass from some kind of GUI input earlier, and because the time it takes Citrix to launch varies, I would like to include some kind of logic that detects when the user has logged in and then resume the script from there, rather than including an obnoxiously long implicit wait or risking the script timing out.
Is there a way to detect user keystrokes using win32com.client (or to detect a change in state of the application itself)? See below for the relevant code to launch the app:
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('C:\Citrix\[rest of path])
EDIT:
Per Vasily's suggestion in the comments below, I attempted to adapt the "hook and listen" code to my scenario, but was unsuccessful. When I launch my file, I don't even get an exception message in my terminal, I get a Windows pop-up that says Python encountered a problem and needs to quit.
This is how I adapted it:
#[omitting import lines for brevity]
def on_timer():
"""Callback by timer out"""
win32api.PostThreadMessage(main_thread_id, win32con.WM_QUIT, 0, 0);
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
for i in range(1,100):
time.sleep(1)
if args.pressed_key == 'Lcontrol':
break
def init():
hk = Hook()
hk.handler = on_event
main_thread_id = win32api.GetCurrentThreadId()
t = Timer(55.0, on_timer) # Quit after 55 seconds
t.start()
hk.hook(keyboard=True, mouse=True)
At the point when the 3rd party Citrix app begins to launch in my main script, I call hookandlisten.init().
As a reminder, my goal is to wait until the user sends a certain keystroke (here I chose Control) before proceeding with the rest of the main script.
Solved this by eliminating the timer and unhooking the keyboard upon the correct keystroke:
import win32api
import win32con
from pywinauto.win32_hooks import Hook
from pywinauto.win32_hooks import KeyboardEvent
from pywinauto.win32_hooks import MouseEvent
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
if args.current_key == 'Lcontrol' and args.event_type == 'key down':
print("Success")
hk.unhook_keyboard()
return
def init():
hk.handler = on_event
hk.hook(keyboard=True, mouse=False)
hk = Hook()
I'm developing my first app on python for OS X (and also generally on python) and i faced the problem… My current script parses sounds from iTunes and prints it in to the window. It looks like this
from Cocoa import *
from Foundation import *
from ScriptingBridge import *
class SocialTunesController(NSWindowController):
testLabel = objc.IBOutlet()
def windowDidLoad(self):
NSWindowController.windowDidLoad(self)
self.updateTrack()
def updateTrack(self):
iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
current_track_info = "Name: " + iTunes.currentTrack().name() + "\nArtist: " + iTunes.currentTrack().artist() + "\nAlbum: " + iTunes.currentTrack().album()
self.testLabel.setStringValue_(current_track_info)
if __name__ == "__main__":
app = NSApplication.sharedApplication()
viewController = SocialTunesController.alloc().initWithWindowNibName_("SocialTunes")
viewController.showWindow_(viewController)
from PyObjCTools import AppHelper
AppHelper.runEventLoop()
The main problem is how to fire event when track is changes that it automatically would update the track info in current window…
iTunes posts a distributed notification when a track change occurs. You need to register a controller to listen for those notifications:
noteCenter = NSDistributedNotificationCenter.defaultCenter()
noteCenter.addObserver_selector_name_object_(theController,
objc.selector(theController.updateTrack_,
signature="v#:#"),
"com.apple.iTunes.playerInfo",
None)
And your updateTrack_() method needs to take one argument (aside from self), which is the posted notification.
You can use events with PyObjC, whether or not you can receive iTunes events depends on whether of not iTunes sends events. For all I know all iTunes status widgets just regularly poll if the iTunes track has changed.
I need to detect when the user pressed "quit" in the dock menu.
My application is actually just a launcher for the backend server of a web interface. I keep it in the dock menu by manually waiting for the launched process to end (with poll and sleep). The actvity monitor showed it as not responding so I added a native function to process events like "touches". Not responding flag is now gone, but the user cannot quit this application (because the native functions processes the event, I guess).
I used ctypes to access that native function.
TVB = subprocess.popen(args)
coreFoundation = cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')
CFRunLoopRunInMode = coreFoundation.CFRunLoopRunInMode # the native function
CFRunLoopRunInMode.restype = c_int32 # its return type
CFRunLoopRunInMode.argtypes = [ c_void_p, c_double, c_bool ] # its arguments types
defaultMode = c_void_p.in_dll(coreFoundation, u'kCFRunLoopDefaultMode') # the default mode to process events
sleepTime = c_double(5) # the duration to process the events
retAfterSourceHandled = c_bool(0) # do NOT return after processing
while not TVB.poll(): # keep alive as long as TVB is alive
CFRunLoopRunInMode(defaultMode, sleepTime, retAfterSourceHandled)
sleep(5)
#detect 'quit' here and stop TVB, then quit
I will also consider other solutions to CFRunLoopRunInMode... Something like processNextEvent() would be ideal.
A possible solution to this problem is to use PyObjC and a custom UIApplicationDelegate implementation.
import AppKit
import Foundation
from PyObjCTools import AppHelper
class ApplicationDelegate(Foundation.NSObject):
""" MAC OS UI specific Delegate class """
def applicationDidFinishLaunching_(self, notification):
""" Here you could register a timer to pull your sub-processes, for example. """
pass
def applicationWillTerminate_(self, notification):
""" This is the hook you get for when the user clicks QUIT in dock """
pass
app = AppKit.NSApplication.sharedApplication()
delegate = ApplicationDelegate.alloc().init()
app.setDelegate_(delegate)
AppHelper.runEventLoop()
In the end PyObjC is not much different than the ctypes loads you tried, but it has some helper methods (like AppKit.NSRunLoop.currentRunLoop(), or AppHelper.stopEventLoop()) which could make the python code clearer.
For this solution I assume to have a Python project further packed for deployment with py2app. I used pyObjc version 2.3 (installed with easy_install in Python 2.7 on Mac OS x 10.7.5).