Syncronizing files with AJA Ki Pro using Python - python

We have an AJA Ki Pro recorder at another location and I a need to created an automated system that pulls the recorded files over to my editing studio. So far I have successfully been able to pull recordings using a python script run via an Applescript through Automator. I than can trigger the application from iCal. Basically my script involves setting the "MediaState" parameter on my recorder to "Data" (value=1) so I can pull files, comparing the files on the recorder to my local files (it only downloads what I dont already have locally), and then setting the "MediaState" property back to "Rec" (value=0) so the recorder is ready to go again.
Here are the 2 problems I have been unable to resolve so far. Bear with me, I have about 2 days worth of experience with Python :) It seems that I have somehow created a loop where it constantly says "Looking for new clips" and "No new clips found". Ideally I would like to have the script terminate if no new clips are found. I would also like to set this up so that when it finishes a download through cURL, it automatically sets my "MediaState" back to value=0 and ends the script. Here is my code so far:
# This script polls the unit downloads any new clips it hasn't already downloaded to the current directory
# Arguments: hostname or IP address of Ki Pro unit
import urllib, sys, string, os, posix, time
def is_download_allowed(address):
f = urllib.urlopen("http://"+address+"/config?action=get&paramid=eParamID_MediaState")
response = f.read()
if (response.find('"value":"1"') > -1):
return True
f = urllib.urlopen("http://"+address+"/config?action=set&paramid=eParamID_MediaState&value=1")
def download_clip(clip):
url = "http://" + address + "/media/" + clip
print url
posix.system("curl --output " + clip + " " + url);
def download_clips(response):
values = response.split(":")
i = 0
for word in values:
i += 1
if(word.find('clipname') > -1):
clip = values[i].split(',')[0].translate(string.maketrans("",""), '[]{} \,\"\" ')
if not os.path.exists(clip):
print "Downloading clip: " + clip
download_clip(clip)
else:
f = urllib.urlopen("http://"+address+"/config?action=set&paramid=eParamID_MediaState&value=0")
print "No new clips found"
address = sys.argv[1]
while 1:
if (is_download_allowed(address)):
print "Looking for new clips"
f = urllib.urlopen("http://"+address+"/clips")
response = f.read()
download_clips(response)

If the download_clips function is looping through the clip names, why you need that infinite while 1 loop? I think it is not necessary. Just remove it and dedent the block.

Related

VLC Python Binding only playing the first mp4 file in the folder

I was trying to Play multiple small mp4 files that is in a folder. And i was using this example as my reference:
https://github.com/oaubert/python-vlc/blob/master/generated/3.0/examples/play_buffer.py
But when i ran the py file giving that particular folder it read all of the files but closes after playing the first file. Can Someone Help me with this.
And i know i can just use a for loop to play all the files in a folder but i don't want any stutter between transitioning those files(Or in simple words i want seamless transition between those files). So any help would be appreciated.
i don't want any stutter between transitioning those files
What you are looking for is called "gapless playback". Sadly, this is not currently supported by LibVLC.
Regardless, to play multiple individual files, you need to either feed them one after the other to the mediaplayer (by subscribing to the EndReached event, for example) or use a MediaList object.
You have picked a complicated and arguably inappropriate code example for your scenario.
Try something like this (without ctypes):
import vlc
import glob
import time
base_folder = './'
# vlc State 0: Nowt, 1 Opening, 2 Buffering, 3 Playing, 4 Paused, 5 Stopped, 6 Ended, 7 Error
playing = set([1,2,3,4])
def add_media(inst, media_list, playlist):
for song in playlist:
print('Loading: - {0}'.format(song))
media = inst.media_new(song)
media_list.add_media(media)
playlist = glob.glob(base_folder + "/" + "*.mp3")
playlist = sorted(playlist)
media_player = vlc.MediaListPlayer()
inst = vlc.Instance('--no-xlib --quiet ')
media_list = vlc.MediaList()
add_media(inst, media_list, playlist)
media_player.set_media_list(media_list)
media_player.play()
time.sleep(0.1)
current = ""
idx = 1
player = media_player.get_media_player()
while True:
state = player.get_state()
if state.value == vlc.State.Ended or state == vlc.State.Error:
if idx == len(playlist)+1:
break
title = player.get_media().get_mrl()
if title != current:
print("\nPlaying - {0}\t{1} of {2}".format(str(title), idx, len(playlist)))
current = title
idx += 1
time.sleep(0.1)
print("\nPlaylist Finished")
Here, we use a MediaListPlayer() rather than a media.player_new_from_media() or a media_player_new() because we are playing a set of media, not a single instance.
You can improve on this by controlling it via events using the event_manager() and attaching appropriate events for the player to listen for.

Examining file on different node (different IP address), same network - possible?

I have a small group of Raspberry Pis, all on the same local network (192.168.1.2xx) All are running Python 3.7.3, one (R Pi CM3) on Raspbian Buster, the other (R Pi 4B 8gig) on Raspberry Pi OS 64.
I have a file on one device (the Pi 4B), located at /tmp/speech.wav, that is generated on the fly, real-time:
192.168.1.201 - /tmp/speech.wav
I have a script that works well on that device, that tells me the play duration time of the .wav file in seconds:
import wave
import contextlib
def getPlayTime():
fname = '/tmp/speech.wav'
with contextlib.closing(wave.open(fname,'r')) as f:
frames = f.getnframes()
rate = f.getframerate()
duration = round(frames / float(rate), 2)
return duration
However - the node that needs to operate on that duration information is running on another node at 192.168.1.210. I cannot simply move the various files all to the same node as there is a LOT going on, things are where they are for a reason.
So what I need to know is how to alter my approach such that I can change the script reference to something like this pseudocode:
fname = '/tmp/speech.wav # 192.168.1.201'
Is such a thing possible? Searching the web it seems that I am up against millions of people looking for how to obtain IP addresses, fix multiple IP address issues, fix duplicate ip address issues... but I can't seem yet to find how to simply examine a file on a different ip address as I have described here. I have no network security restrictions, so any setting is up for consideration. Help would be much appreciated.
There are lots of possibilities, and it probably comes down to how often you need to check the duration, from how many clients, and how often the file changes and whether you have other information that you want to share between the nodes.
Here are some options:
set up an SMB (Samba) server on the Pi that has the WAV file and let the other nodes mount the filesystem and access the file as if it was local
set up an NFS server on the Pi that has the WAV file and let the other nodes mount the filesystem and access the file as if it was local
let other nodes use ssh to login and extract the duration, or scp to retrieve the file - see paramiko in Python
set up Redis on one node and throw the WAV file in there so anyone can get it - this is potentially attractive if you have lots of lists, arrays, strings, integers, hashes, queues or sets that you want to share between Raspberry Pis very fast. Example here.
Here is a very simple example of writing a sound track into Redis from one node (say Redis is on 192.168.0.200) and reading it back from any other. Of course, you may just want the writing node to write the duration in there rather than the whole track - which would be more efficient. Or you may want to store loads of other shared data or settings.
This is the writer:
#!/usr/bin/env python3
import redis
from pathlib import Path
host='192.168.1.200'
# Connect to Redis
r = redis.Redis(host)
# Load some music, or otherwise create it
music = Path('song.wav').read_bytes()
# Put music into Redis where others can see it
r.set("music",music)
And this is the reader:
#!/usr/bin/env python3
import redis
from pathlib import Path
host='192.168.1.200'
# Connect to Redis
r = redis.Redis(host)
# Retrieve music track from Redis
music = r.get("music")
print(f'{len(music)} bytes read from Redis')
Then, during testing, you may want to manually push a track into Redis from the Terminal:
redis-cli -x -h 192.168.0.200 set music < OtherTrack.wav
Or manually retrieve the track from Redis to a file:
redis-cli -h 192.168.0.200 get music > RetrievedFromRedis.wav
OK, this is what I finally settled on - and it works great. Using ZeroMQ for message passing, I have the function to get the playtime of the wav, and another gathers data about the speech about to be spoken, then all that is sent to the motor core prior to sending the speech. The motor core handles the timing issues to sync the jaw to the speech. So, I'm not actually putting the code that generates the wav and also returns the length of the wav playback time onto the node that ultimately makes use of it, but it turns out that message passing is fast enough so there is plenty of time space to receive, process and implement the motion control to match the speech perfectly. Posting this here in case it's helpful for folks in the future working on similar issues.
import time
import zmq
import os
import re
import wave
import contextlib
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555") #Listens for speech to output
print("Connecting to Motor Control")
jawCmd = context.socket(zmq.PUB)
jawCmd.connect("tcp://192.168.1.210:5554") #Sends to MotorFunctions for Jaw Movement
def getPlayTime(): # Checks to see if current file duration has changed
fname = '/tmp/speech.wav' # and if yes, sends new duration
with contextlib.closing(wave.open(fname,'r')) as f:
frames = f.getnframes()
rate = f.getframerate()
duration = round(frames / float(rate), 3)
speakTime = str(duration)
return speakTime
def set_voice(V,T):
T2 = '"' + T + '"'
audioFile = "/tmp/speech.wav" # /tmp set as tmpfs, or RAMDISK to reduce SD Card write ops
if V == "A":
voice = "Allison"
elif V == "B":
voice = "Belle"
elif V == "C":
voice = "Callie"
elif V == "D":
voice = "Dallas"
elif V == "V":
voice = "David"
else:
voice = "Belle"
os.system("swift -n " + voice + " -o " + audioFile + " " +T2) # Record audio
tailTrim = .5 # Calculate Jaw Timing
speakTime = eval(getPlayTime()) # Start by getting playlength
speakTime = round((speakTime - tailTrim), 2) # Chop .5 s for trailing silence
wordList = T.split()
jawString = []
for index in range(len(wordList)):
wordLen = len(wordList[index])
jawString.append(wordLen)
jawString = str(jawString)
speakTime = str(speakTime)
jawString = speakTime + "|" + jawString # 3.456|[4, 2, 7, 4, 2, 9, 3, 4, 3, 6] - will split on "|"
jawCmd.send_string(jawString) # Send Jaw Operating Sequence
os.system("aplay " + audioFile) # Play audio
pronunciationDict = {'teh':'the','process':'prawcess','Maeve':'Mayve','Mariposa':'May-reeposah','Lila':'Lala','Trump':'Ass hole'}
def adjustResponse(response): # Adjusts spellings in output string to create better speech output.
for key, value in pronunciationDict.items():
if key in response or key.lower() in response:
response = re.sub(key, value, response, flags=re.I)
return response
SpeakText="Speech center connected and online."
set_voice(V,SpeakText) # Cepstral Voices: A = Allison; B = Belle; C = Callie; D = Dallas; V = David;
while True:
SpeakText = socket.recv().decode('utf-8') # .decode gets rid of the b' in front of the string
SpeakTextX = adjustResponse(SpeakText) # Run the string through the pronunciation dictionary
print("SpeakText = ",SpeakTextX)
set_voice(V,SpeakTextX)
print("Received request: %s" % SpeakTextX)
socket.send_string(str(SpeakTextX)) # Send data back to source for confirmation

Using win32com to download attachments through outlook with python

I've written a short code to download and rename files from a specific folder in my outlook account. The code works great, the only problem is that I typically need to run the code several times to actually download all of the messages. It seems the code is just failing to acknowledge some of the messages, there are no errors when I run through it.
I've tried a few things like walking through each line step by step in the python window, running the code with outlook closed or opened, and trying to print the files after they're successfully saved to see if there are specific messages that are causing the problem.
Here's my code
#! python3
# downloadAttachments.py - Downloads all of the weight tickets from Bucky
# Currently saves to desktop due to instability of I: drive connection
import win32com.client, os, re
#This line opens the outlook application
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
#Not exactly sure why the inbox is default folder 6 but it works
inbox = outlook.GetDefaultFolder(6)
#box where the messages are to save
TicketSave = inbox.Folders('WDE').Folders('SAVE').Folders('TicketSave')
#box where the messages are moved to
done = inbox.Folders('WDE').Folders('CHES').Folders('Weight Tickets')
ticketMessages = TicketSave.Items
#Key is used to verify the subject line is correct. This script only works if the person sends
# their emails with a consistent subject line (can be altered for other cases)
key = re.compile(r'wde load \d{3}') #requires regulars expressions (i.e. 'import re')
for message in ticketMessages:
#will skip any message that does not match the correct subject line format (non-case sensitive)
check = str(message.Subject).lower()
if key.search(check) == None:
continue
attachments = message.Attachments
tic = attachments.item(1)
ticnum = str(message.Subject).split()[2]
name = str(tic).split()[0] + ' ticket ' + ticnum + '.pdf' #changes the filename
tic.SaveAsFile('C:\\Users\\bhalvorson\\Desktop\\Attachments' + os.sep + str(name))
if message.UnRead == True:
message.UnRead = False
message.Move(done)
print('Ticket pdf: ' + name + ' save successfully')
Alright I found the answer to my own question. I'll post it here in case any other youngster runs into the same problem as me.
The main problem is the "message.Move(done)" second from the bottom.
Apparently the move function alters the current folder thus altering the number of loops that the for loop will go through. So, the way it's written above, the code only ever processes half of the items in the folder.
An easy work around is to switch the main line of the for loop to "for message in list(ticketMessages):" the list is not affected by the Move function and therefore you'll be able to loop through every message.
Hope this helps someone.

How do I run python '__main__' program file from bash prompt in Windows10?

I am trying to run a python3 program file and am getting some unexpected behaviors.
I'll start off first with my PATH and env setup configuration. When I run:
which Python
I get:
/c/Program Files/Python36/python
From there, I cd into the directory where my python program is located to prepare to run the program.
Roughly speaking this is how my python program is set up:
import modulesNeeded
print('1st debug statement to show program execution')
# variables declared as needed
def aFunctionNeeded():
print('2nd debug statement to show fxn exe, never prints')
... function logic...
if __name__ == '__main__':
aFunctionNeeded() # Never gets called
Here is a link to the repository with the code I am working with in case you would like more details as to the implementation. Keep in mind that API keys are not published, but API keys are in local file correctly:
https://github.com/lopezdp/API.Mashups
My question revolves around why my 1st debug statements inside the files are printing to the terminal, but not the 2nd debug statements inside the functions?
This is happening in both of the findRestaurant.py file and the geocode.py file.
I know I have written my if __name__ == '__main__': program entry point correctly as this is the same exact way I have done it for other programs, but in this case I may be missing something that I am not noticing.
If this is my output when I run my program in my bash terminal:
$ python findRestaurant.py
inside geo
inside find
then, why does it appear that my aFunctionNeeded() method shown in my pseudo code is not being called from the main?
Why do both programs seem to fail immediately after the first debug statements are printed to the terminal?
findRestaurant.py File that can also be found in link above
from geocode import getGeocodeLocation
import json
import httplib2
import sys
import codecs
print('inside find')
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
sys.stderr = codecs.getwriter('utf8')(sys.stderr)
foursquare_client_id = "..."
foursquare_client_secret = "..."
def findARestaurant(mealType,location):
print('inside findFxn')
#1. Use getGeocodeLocation to get the latitude and longitude coordinates of the location string.
latitude, longitude = getGeocodeLocation(location)
#2. Use foursquare API to find a nearby restaurant with the latitude, longitude, and mealType strings.
#HINT: format for url will be something like https://api.foursquare.com/v2/venues/search?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&v=20130815&ll=40.7,-74&query=sushi
url = ('https://api.foursquare.com/v2/venues/search?client_id=%s&client_secret=%s&v=20130815&ll=%s,%s&query=%s' % (foursquare_client_id, foursquare_client_secret,latitude,longitude,mealType))
h = httplib2.Http()
result = json.loads(h.request(url,'GET')[1])
if result['response']['venues']:
#3. Grab the first restaurant
restaurant = result['response']['venues'][0]
venue_id = restaurant['id']
restaurant_name = restaurant['name']
restaurant_address = restaurant['location']['formattedAddress']
address = ""
for i in restaurant_address:
address += i + " "
restaurant_address = address
#4. Get a 300x300 picture of the restaurant using the venue_id (you can change this by altering the 300x300 value in the URL or replacing it with 'orginal' to get the original picture
url = ('https://api.foursquare.com/v2/venues/%s/photos?client_id=%s&v=20150603&client_secret=%s' % ((venue_id,foursquare_client_id,foursquare_client_secret)))
result = json.loads(h.request(url, 'GET')[1])
#5. Grab the first image
if result['response']['photos']['items']:
firstpic = result['response']['photos']['items'][0]
prefix = firstpic['prefix']
suffix = firstpic['suffix']
imageURL = prefix + "300x300" + suffix
else:
#6. if no image available, insert default image url
imageURL = "http://pixabay.com/get/8926af5eb597ca51ca4c/1433440765/cheeseburger-34314_1280.png?direct"
#7. return a dictionary containing the restaurant name, address, and image url
restaurantInfo = {'name':restaurant_name, 'address':restaurant_address, 'image':imageURL}
print ("Restaurant Name: %s" % restaurantInfo['name'])
print ("Restaurant Address: %s" % restaurantInfo['address'])
print ("Image: %s \n" % restaurantInfo['image'])
return restaurantInfo
else:
print ("No Restaurants Found for %s" % location)
return "No Restaurants Found"
if __name__ == '__main__':
findARestaurant("Pizza", "Tokyo, Japan")
geocode.py File that can also be found in link above
import httplib2
import json
print('inside geo')
def getGeocodeLocation(inputString):
print('inside of geoFxn')
# Use Google Maps to convert a location into Latitute/Longitute coordinates
# FORMAT: https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=API_KEY
google_api_key = "..."
locationString = inputString.replace(" ", "+")
url = ('https://maps.googleapis.com/maps/api/geocode/json?address=%s&key=%s' % (locationString, google_api_key))
h = httplib2.Http()
result = json.loads(h.request(url,'GET')[1])
latitude = result['results'][0]['geometry']['location']['lat']
longitude = result['results'][0]['geometry']['location']['lng']
return (latitude,longitude)
The reason you're not seeing the output of the later parts of your code is that you've rebound the standard output and error streams with these lines:
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
sys.stderr = codecs.getwriter('utf8')(sys.stderr)
I'm not exactly sure why those lines are breaking things for you, perhaps your console does not expect utf8 encoded output... But because they don't work as intended, you're not seeing anything from the rest of your code, including error messages, since you rebound the stderr stream along with the stdout stream.

How to make a python Script wait until download has finished

My Script downloads a zipfile, exctracts the relevant parts replaced files and folders etc. It used to work flawlessly, for some reason its has now decided to stop working and only partly downloads the zipfile, and of course, as the zipfile is incomplete I get an error, saying the downloaded file is not a zipfile. my script is as follows.
def downloadupdate():
xbmcgui.Dialog().ok(
"[B][COLOR white]Daily Updater[/B][/COLOR]",
"Favourites and some software will now update",
"Elements of your system will be cleaned",
"Daily Update will take at most 2 minutes")
#ONLY HAVE THE SUPER FAVOURITES FOLDER IN THE ZIPFILE!!
url = 'http://x.com/x/x/Super Favourites.zip'
destination = xbmc.translatePath('special://home/userdata/addon_data/iupdatefix/Super Favourites.zip')
favzip = urllib.urlopen(url)
xbmc.executebuiltin("Notification(Downloading new updates, PLEASE WAIT,()")
with open(xbmc.translatePath('special://home/userdata/addon_data/iupdatefix/Super Favourites.zip'), "wb") as zipFile:
zipFile.write(favzip.read())
xbmc.executebuiltin("Notification(Download Complete, Please wait,()")
time.sleep(5)
xbmc.executebuiltin("Notification(Updating Click and Play channels, Please wait,()")
updatezip = xbmc.translatePath('special://home/userdata/addon_data/iupdatefix/Super Favourites.zip')
extractupdate = xbmc.translatePath('special://home/userdata/addon_data/plugin.program.super.favourites/')
oldfav = xbmc.translatePath('special://home/userdata/addon_data/plugin.program.super.favourites/Super Favourites')
yeszip = os.path.exists(updatezip)
time.sleep(5)
if yeszip:
xbmc.executebuiltin("Notification(Removing previous, Please wait,()")
shutil.rmtree(oldfav, ignore_errors=False)
xbmc.executebuiltin("Notification(Updating, now,()")
gh = open(updatezip, 'rb')
zp = zipfile.ZipFile(gh)
zp.extractall(extractupdate)
gh.close()
time.sleep(3)
xbmc.executebuiltin("Notification(updated, Now Checking sd,()")
# put this command at the end of whole script --->>>os.remove(updatezip)
else:
xbmc.executebuiltin("Notification(Update file Corrupt, Please try again,()")
The problem has been solved, It was not the code. It was the hosting service, I had to reset the File permissions on the server and after that all works perfectly again.

Categories

Resources