diff options
-rw-r--r-- | README | 27 | ||||
-rwxr-xr-x | archive.sh | 2 | ||||
-rwxr-xr-x | awcli.sh | 51 | ||||
-rw-r--r-- | config.py | 12 | ||||
-rw-r--r-- | config.pyc | bin | 320 -> 0 bytes | |||
-rw-r--r-- | fi.tvtools.finalstore.plist | 16 | ||||
-rwxr-xr-x | finalstore.py | 12 | ||||
-rwxr-xr-x | restore.sh | 2 |
8 files changed, 91 insertions, 31 deletions
@@ -1,25 +1,38 @@ +## Features ## +- Uses Growl for status notifications +- Smart enough to only archive an asset once +- Allows running archive and FCSvr services on separate machines +- Keeps a log of tasks +- Supports archiving/restoring multiple assets at once + ## How it works ## ### Archive ### - User selects assets in FCSvr and clicks Archive. FCSvr moves the asset to it's Archive Device and marks it as archived -- archive.sh writes the file paths to /tmp/fcs_toArchive -- launchd job (fi.tvtools.finalstore) runs finalstore.py every n seconds +- archive.sh writes the archived file path(s) to /tmp/finalstore/archive/<timestamp>.txt +- launchd job (fi.tvtools.finalstore) runs finalstore.py every 20 seconds - finalstore.py forwards the file list to a customized awcli.sh, waits for the job to finish and runs growlnotify to let the user know of what happened ### Restore ### - User selects assets in FCSvr and clicks Restore. -- restore.sh writes the file paths to /tmp/fcs_toRestore +- restore.sh writes the file paths to /tmp/finalstore/restore/<timestamp>.txt - launchd job (fi.tvtools.finalstore) runs finalstore.py every n seconds - finalstore.py forwards the file list to a customized awcli.sh, waits for the job to finish and runs growlnotify to let the user know what happened ## Installation ## - -- Drag the finalstore folder to /Library/Application Support/TV Tools/finalstore +- Drag the FinalStore folder to /Library/Application Support/TV Tools - In FCSvr, open Administration > Devices > Archive and set the pahts of the archive and restore scripts - Configure your PressSTORE archive plan +- In System Preferences > Final Cut Server, increase the Retry Count and Timeout values (for example 100/10). This is necessary for the restore process, to give PresSTORE time to retrieve the assets. +- Edit FinalStore/config.py to match your configuration +- Load the launchd job. Either create an alias or copy fi.tvtools.finalstore.plist into /Library/LaunchDaemons and: + + sudo launchctl load -w /Library/LaunchDaemons/fi.tvtools.finalstore.plist + +- Install Growl + growlnotify on the Final Cut Server. Optionally enable network notifications, if you want to send them to your Final Cut Server.app users. -##Configuration## -... +## Why is this thing so complicated? ## +The main reason is because Final Cut Server only sends one archive/restore asset path at a time. This means we need a lot more files to keep track of them. @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Collect archived assets to a text file +# Collect archive asset to a text file DST="/tmp/finalstore/archive" if [ ! -d $DST ]; then mkdir -p $DST @@ -3,6 +3,8 @@ # The differences are: # - returning the Job ID # - support for servers running on other hosts +# - store the "asset id" as the description +# - separating configuration data into an external file # # See the file "license.txt" for information on usage and # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -13,6 +15,11 @@ source /Library/Application\ Support/TV\ Tools/FinalStore/config.py +if [[ -z $AWUSER ]]; then + echo "Configuration incomplete, please check config.py" + exit 1 +fi + LC_ALL="C"; export LC_ALL usage() { @@ -24,15 +31,7 @@ clierr() { exit 1 } -# -# Locate the nsdchat utility -# - -if test -z "$AWPST_HOME"; then - nc="${NC} -s awsock:/${USER}:${PASSWORD}@${HOST}:9001" -else - nc=$AWPST_HOME/bin/nsdchat -fi +nc="${NC} -s awsock:/${AWUSER}:${AWPASSWORD}@${AWHOST}:${AWPORT}" # # Check the operation. @@ -77,24 +76,45 @@ case $task in if test $? -ne 0; then clierr fi + # Create restore selection for checking if asset's been already archived + rs=`$nc -c RestoreSelection create localhost` + if test $? -ne 0; then + clierr + fi # Add files to it adfile=0 for file do + if [[ ! -z $FSLOG ]]; then + echo "$(date) $task $file" >> $FSLOG + fi if test ! -r "$file"; then echo "$0: $file: no such file" elif test ! -f "$file"; then echo "$0: $file: not a plain file" else - aentry=`$nc -c ArchiveSelection $as addentry "{$file}"` - if test $? -ne 0; then - clierr + aid=$(echo -n "$file" | md5) + # Check if asset has already been archived + dummy=`$nc -c RestoreSelection $rs findentry $aplan {description == $aid}` + if [[ -z "$dummy" ]]; then + clierr + fi + if [[ "$dummy" -lt 1 ]]; then + aentry=`$nc -c ArchiveSelection $as addentry "{$file}" description $aid` + if test $? -ne 0; then + clierr + fi + adfile=`expr $adfile + 1` + else + # Asset already in archive, just delete from FCSvr archive device + rm "$file" fi - adfile=`expr $adfile + 1` fi done # Submit archive job if test $adfile -eq 0; then - echo "$0: no files selected for $task" + # Nothing to archive - either no valid files, or all already archived + echo "-1" + exit 0 else jobid=`$nc -c ArchiveSelection $as submit 1` echo $jobid @@ -117,6 +137,9 @@ case $task in fi # Add files to it for file do + if [[ ! -z $FSLOG ]]; then + echo "$(date) $task $file" >> $FSLOG + fi aentry=`$nc -c ArchiveEntry handle localhost "{$file}" $dbase` if test $? -ne 0; then clierr @@ -1,7 +1,9 @@ # This file is shared between Bash and Python -# so keep it clean! -USER="" -HOST="" -ARCHIVEPLAN="10001" -PASSWORD="" +# so keep it tight (no spaces between names and values)! +AWUSER="" +AWHOST="" +AWPORT="9001" +AWPASSWORD="" +ARCHIVEPLAN="" +FSLOG="/var/log/finalstore.log" NC="/usr/local/aw/bin/nsdchat" diff --git a/config.pyc b/config.pyc Binary files differdeleted file mode 100644 index d9e6926..0000000 --- a/config.pyc +++ /dev/null diff --git a/fi.tvtools.finalstore.plist b/fi.tvtools.finalstore.plist new file mode 100644 index 0000000..b55efe2 --- /dev/null +++ b/fi.tvtools.finalstore.plist @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>Label</key> + <string>fi.tvtools.finalstore</string> + <key>ProgramArguments</key> + <array> + <string>/Library/Application Support/TV Tools/FinalStore/finalstore.py</string> + </array> + <key>StartInterval</key> + <integer>20</integer> + <key>AbandonProcessGroup</key> + <true/> +</dict> +</plist> diff --git a/finalstore.py b/finalstore.py index f7d9cd9..218cc37 100755 --- a/finalstore.py +++ b/finalstore.py @@ -18,7 +18,6 @@ def growl(str): Popen(cmd, shell=False).communicate() except Exception, e: print "Failed to initialize Growl" - """ Forward the files to awcli @@ -41,11 +40,18 @@ def doit(task, f, ap): r = Popen([awcli, task, ap] + assets, stdout=PIPE, shell=False).communicate() jid = r[0].strip() + if jid == "-1": + growl("Asset already archived") + sys.exit(0) + print task + " job ID is " + jid - growl("Started %s job %s (%d assets)" % (task, jid, len(assets))) + ac = len(assets) + sfx = "s" + if ac == 1 : sfx = "" + growl("Started %s job %s (%d asset%s)" % (task, jid, ac, sfx)) # Wait for the job to finish - sock = "awsock:/%s:%s@%s:9001" % (USER, PASSWORD, HOST) + sock = "awsock:/%s:%s@%s:%s" % (AWUSER, AWPASSWORD, AWHOST, AWPORT) cmd = "Job %s status" % (jid) while True: @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Collect restored assets to a text file +# Collect restore asset to a text file DST="/tmp/finalstore/restore" if [ ! -d $DST ]; then mkdir -p $DST |