Skip to content

Commit 643d2a9

Browse files
author
Thang
committed
Updated to show how it's being used in production.
1 parent 393330e commit 643d2a9

File tree

1 file changed

+131
-29
lines changed

1 file changed

+131
-29
lines changed

update.py

Lines changed: 131 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,69 +4,171 @@
44
# Any time a folder is added to the monitored parent directory, that folder needs
55
# to be monitored as well [recursive monitoring is not fully supported]. This
66
# script will add to incrontab when a new folder is added.
7-
# Be sure to chmod +x this script!
7+
# This script will also convert any files uploaded to a monitored folder
8+
# to a VP8 [webm] and mobile version to be put into an .alternates folder.
9+
# This script will also handle arbitrary file/folder renaming, at any depth.
810
# '''
911

1012
import os,sys,pwd,subprocess, time
1113
from datetime import datetime
1214

1315
# CFG Variables
14-
scriptPath = '/path/to/this/update.py' # the path to THIS script.
15-
changedDir = sys.argv[1]
16-
workingDir = sys.argv[2]
17-
event = sys.argv[3]
16+
scriptPath = '/var/www/soundtrack/update.py' # the path to THIS script.
17+
changed = sys.argv[1].strip().replace(' ','\\ ') # spaces.
18+
if len(sys.argv) > 4:
19+
workingDir = '\\ '.join(sys.argv[2:-1]) # spaces
20+
else:
21+
workingDir = sys.argv[2] # no spaces
22+
event = sys.argv[-1]
1823
incrontemp = workingDir + '/temp'
19-
2024
curUser = 'thang' # ensure this runs under the correct user, for incrontab
2125
os.setuid(pwd.getpwnam(curUser)[2])
2226

2327
# Log to a timestamped log file
24-
def log(out, err):
28+
def log(out, err, cmd):
2529
curTime = datetime.time(datetime.now()).isoformat()
26-
f = open(workingDir + '/error.log' + curTime, 'w')
27-
f.write('Could not update incrontab for %s' % changedDir + '\n')
30+
f = open(workingDir + '/error.%s.log' % curTime , 'w')
31+
f.write('Could not update incrontab for %s' % changed + '\n')
2832
f.write('Failed output: \n')
33+
f.write('Attempted: %s \n' % cmd)
2934
f.write(out + '\n')
3035
f.write(err + '\n')
36+
f.write('Parameters: %s, %s, %s' % (changed,workingDir,event) + '\n')
3137
f.close()
3238

33-
def processCmd(cmdList):
34-
35-
# Copy the current incrontab, & modify the copy accordingly.
36-
cmdList = ['/usr/bin/incrontab -l > %s' % incrontemp] + cmdList
37-
# Replace with the changed incrontemp.
38-
cmdList += ['/usr/bin/incrontab %s' % incrontemp]
39-
39+
# Execute a list of shell commands, return the output as a list.
40+
def runCmd(cmdList):
41+
outList = []
4042
for cmd in cmdList:
4143
o = subprocess.Popen(cmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
4244
out, err = o.communicate()
45+
outList += [out]
4346
if o.returncode != 0:
44-
log(out,err)
47+
log(out,err,cmd)
4548
sys.exit('Process failed..' )
49+
50+
return outList
51+
52+
# Update Incrontab after modifying the current incrontab.
53+
def updateIncron(cmdList):
54+
# Copy the current incrontab, & modify the copy accordingly.
55+
cmdList = ['/usr/bin/incrontab -l > %s' % incrontemp] + cmdList
56+
# Replace with the changed incrontemp.
57+
cmdList += ['/usr/bin/incrontab %s' % incrontemp]
58+
runCmd(cmdList)
4659
os.remove(incrontemp)
4760

4861
# Process an uploaded file.
4962
def processFile():
50-
pass
63+
# full path to the file..
64+
in_file = workingDir + '/' + changed
65+
# Pop off the extension.
66+
out_file = '.'.join(changed.split('.')[:-1])
67+
# Put the file in the .alternates folder in the watched directory
68+
out_file = workingDir+'/.alternates/' + out_file
5169

52-
def main():
70+
# Make an iOS & Firefox playable version.
71+
cmds = ["HandBrakeCLI -i %s -o %s --preset=\"iPad\"" % ( in_file, out_file + '_ipad.mov' )]
72+
cmds += ["ffmpeg -y -i %s -threads 4 -f webm -vcodec libvpx -deinterlace -g 120 -level 216 -profile 0 -qmax 42 -qmin 10 -rc_buf_aggressivity 0.95 -vb 2M -acodec libvorbis -aq 70 -ac 2 %s" % (in_file, out_file + '_ffox.webm' )]
73+
runCmd(cmds)
5374

75+
def main():
5476
# A Sub-Directory is added.
5577
if 'IN_CREATE,IN_ISDIR' in event:
56-
cmds = ["echo '%s IN_CREATE,IN_DELETE,IN_MODIFY %s $# $@ $%%' >> %s" % (workingDir+'/'+changedDir, scriptPath, incrontemp)]
57-
processCmd(cmds)
78+
cmds = ["echo '%s IN_CREATE,IN_DELETE,IN_CLOSE_WRITE,IN_MOVED_TO %s $# $@ $%%' >> %s" % (workingDir+'/'+changed, scriptPath, incrontemp)]
79+
# Add the .alternates folder, but don't monitor it.
80+
cmds += ["mkdir %s" % (workingDir+'/'+changed+'/.alternates/')]
81+
# update incrontab to add/remove watches on the changed Directory
82+
updateIncron(cmds)
5883

5984
# A Sub-Directory is deleted.
6085
elif 'IN_DELETE,IN_ISDIR' in event:
61-
cmds = ["sed -i '/%s/d' %s" % (changedDir.strip('/'), incrontemp)]
62-
processCmd(cmds)
63-
64-
# A File is added...
65-
# We may need to watch when files are moved to the watched directory as well.
66-
elif 'IN_CREATE' in event or 'IN_MODIFY' in event:
67-
processFile()
68-
sys.exit()
86+
deletions = (workingDir+'/'+changed).replace('\\','\\\\').replace('/','\\/')
87+
# First we remove the exact entry, so something like foo/testx doesn't
88+
# get removed when foo/test is deleted.
89+
# Then, we remove instances of foo/test/ to take care of subdirs.
90+
91+
cmds = ["sed -i '/%s\\ /d' %s" % (deletions,incrontemp)]
92+
cmds += ["sed -i '/%s\//d' %s" % (deletions, incrontemp)]
93+
updateIncron(cmds)
94+
95+
# A File is added.
96+
elif 'IN_CLOSE_WRITE' in event:
97+
ext = changed.split('.')[-1]
98+
# Only process valid movie files.
99+
if 'mov' in ext:
100+
processFile()
101+
102+
# A directory was renamed.
103+
elif 'IN_MOVED_TO,IN_ISDIR' in event:
104+
105+
# Find the original name of the directory.
106+
# Compare with the directories in incrontab
107+
cmds = ['/usr/bin/incrontab -l']
108+
cmdOut = runCmd(cmds)[0]
109+
oldName = ''
110+
111+
for x in cmdOut.split('\n')[:-1]:
112+
tempDir = x.split(' IN_CREATE,')[0]
113+
# Ensure the basepath matches, and then check if it exists.
114+
# If it doesn't, we can assume that it was the renamed directory.
115+
# This does introduce a race condition, if a folder is deleted
116+
# while this script is running for a MOVED_TO event.
117+
# This race condition should be very rare.
118+
# I am not a doctor. Use at your own risk.
119+
120+
if workingDir in tempDir and not os.path.exists(tempDir.replace('\\ ', ' ')):
121+
oldName = tempDir
122+
break
123+
124+
# Now we need to pass this to sed, and {forward|back}slashes need to be
125+
# escaped.
126+
# Python needs backslashes escaped, and sed is weird about backslashes.
127+
# So I'm pretty sure this is the right amount of backslashes.
128+
129+
oldName = oldName.replace('\\','\\\\').replace('/','\\/')
130+
newName = (workingDir+'/'+changed).replace('\\','\\\\').replace('/','\\/')
131+
cmds = ["sed -i 's/%s /%s /g' %s" % (oldName,newName,incrontemp)]
132+
updateIncron(cmds)
133+
134+
# A file was renamed.
135+
elif 'IN_MOVED_TO' in event:
136+
changed = ''.join(sys.argv[1].split('.')[:-1]) # remove the extension
137+
wd = workingDir.replace('\\ ', ' ')
138+
altFolder = wd + '/.alternates/'
139+
files = os.walk(altFolder).next()[2]
140+
# Pop off extensions & remove dupes.
141+
files = list(set(map(lambda x: '_'.join(x.split('_')[:-1]),files)))
142+
moved = ''
143+
for f in files:
144+
if not os.path.exists(wd+'/'+f+'.*'):
145+
moved = f
146+
break
147+
148+
try:
149+
os.rename(altFolder + moved + '_ffox.webm',altFolder + changed + '_ffox.webm')
150+
os.rename(altFolder + moved + '_ipad.mov',altFolder + changed + '_ipad.mov')
151+
152+
# If we can't rename the files, so either one of these happened:
153+
# 1 - Only one of the alternates was created, in which case we still
154+
# need to make the alternates again
155+
# 2 - The file was deleted while this script was running, and we still
156+
# need to make the alternates again.
157+
except:
158+
processFile()
159+
160+
161+
# A file was removed.
162+
elif 'IN_DELETE' in event:
163+
altFolder = workingDir + '/.alternates/'
69164

165+
# Delete the alternates
166+
try:
167+
os.remove(altFolder + changed + '_ffox.webm')
168+
os.remove(altFolder + changed + '_ipad.webm')
169+
# Don't sweat if they don't exist.
170+
except:
171+
pass
70172

71173
if __name__ == "__main__":
72174
main()

0 commit comments

Comments
 (0)