aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README27
-rwxr-xr-xarchive.sh2
-rwxr-xr-xawcli.sh51
-rw-r--r--config.py12
-rw-r--r--config.pycbin320 -> 0 bytes
-rw-r--r--fi.tvtools.finalstore.plist16
-rwxr-xr-xfinalstore.py12
-rwxr-xr-xrestore.sh2
8 files changed, 91 insertions, 31 deletions
diff --git a/README b/README
index c1f34ed..8d6db1d 100644
--- a/README
+++ b/README
@@ -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.
diff --git a/archive.sh b/archive.sh
index 7b8f8be..855e439 100755
--- a/archive.sh
+++ b/archive.sh
@@ -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
diff --git a/awcli.sh b/awcli.sh
index e682ebc..e0a2b12 100755
--- a/awcli.sh
+++ b/awcli.sh
@@ -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
diff --git a/config.py b/config.py
index 2ca0313..5d6d5d7 100644
--- a/config.py
+++ b/config.py
@@ -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
deleted file mode 100644
index d9e6926..0000000
--- a/config.pyc
+++ /dev/null
Binary files differ
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:
diff --git a/restore.sh b/restore.sh
index 1443eed..d6ee040 100755
--- a/restore.sh
+++ b/restore.sh
@@ -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