• Increase font size
  • Default font size
  • Decrease font size
Those who desire to give up freedom in order to gain security will not have, nor do they deserve, either one - Benjamin Franklin
Home Geek stuff Synology Synchronize pictures with Cloud Station and Photo Station

Synchronize pictures with Cloud Station and Photo Station

Synology offers great tools: Cloud Station automatically synchronizes your files between your PC and the Synology NAS, and Photo Station has a nice web interface to let your family and friends access your pictures.

Unfortunately, these tools do not play together. I want my pictures to be automatically synchronized with my Synology NAS and be available from Photo Station. The Photo Station includes a transfer tool but that's not an automatic solution. I'll use Cloud Station since it can also be used to synchronize other files. The solution has three parts:

  • First, install Cloud station and create a folder to put the pictures in.
  • Then, mount the folder into a subfolder of Photos to make it available from Photo Station.
  • Finally, monitor any change to the folder to force generation of a thumbnail for each new picture.

Install Cloud station

I won't go into details for this package provided by Synology: just follow their tutorial: Once done, create a folder to store the pictures.

Mount folder

Assuming the picture folder is named "Photos", the absolute path should look like /volume1/homes/<username>/CloudStation/Photos. To make the folder content available from Photo Station, use mount with --bind option:

mount --bind /volume1/homes/<username>/CloudStation/Photos /volume1/photo/<username>

Monitor changes

To monitor every change in the folder, we use a Python script. First install the Python package in Synology to be able to run Python scripts. Then, install pyinotifiy

~$ wget
~$ python pyinotify
Searching for pyinotify
Best match: pyinotify 0.9.4
Processing pyinotify-0.9.4.tar.gz
Running pyinotify-0.9.4/ -q bdist_egg --dist-dir /tmp/easy_install-wjy0eW/pyinotify-0.9.4/egg-dist-tmp-eOvHXs
zip_safe flag not set; analyzing archive contents...
Adding pyinotify 0.9.4 to easy-install.pth file

Installed /usr/local/packages/@appstore/Python/usr/local/lib/python2.7/site-packages/pyinotify-0.9.4-py2.7.egg
Processing dependencies for pyinotify
Finished processing dependencies for pyinotify

Now the Python script: it can be created in any location (I created a /volume1/Extensions/scripts folder):

cat > /volume1/Extensions/scripts/ << EOF
import pyinotify
import sys
import os.path
from subprocess import call
import signal

log_file = open("/var/log/monitor.log", "a")

def log(text):
log_file.write(text + "\n")

def signal_handler(signal, frame):


signal.signal(signal.SIGTERM, signal_handler)

allowed_exts = ["jpg", "jpeg", "png", "tga", "gif", "bmp", "mp3", "flac", "aac", "wma", "ogg", "ogv", "mp4", "avi"]

wm = pyinotify.WatchManager()  # Watch Manager
mask = pyinotify.IN_CLOSE_WRITE | pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MOVED_TO | pyinotify.IN_MOVED_FROM  # watched events

class EventHandler(pyinotify.ProcessEvent):
def __init__(self):
self.modified_files = set()

def process_IN_CREATE(self, event):

def process_IN_MOVED_TO(self, event):

def process_IN_MOVED_FROM(self, event):

def process_IN_DELETE(self, event):

def process_create(self, event):
arg = ''
if event.dir:
arg = "-A"
arg = "-a"
self.do_index_command(event, arg)

def process_delete(self, event):
arg = ''
if event.dir:
arg = "-D"
arg = "-d"
self.do_index_command(event, arg)

def process_IN_MODIFY(self, event):
if self.is_allowed_path(event.pathname, event.dir):

def process_IN_CLOSE_WRITE(self, event):
# ignore close_write unlesss the file has previously been modified.
if (event.pathname in self.modified_files):
self.do_index_command(event, "-a")

def do_index_command(self, event, index_argument):
if self.is_allowed_path(event.pathname, event.dir):
log("synoindex %s %s" % (index_argument, event.pathname))
call(["synoindex", index_argument, event.pathname])

# Remove from list of modified files.
except KeyError, e:
# Don't care.
log("%s is not an allowed path" % event.pathname)

def is_allowed_path(self, filename, is_dir):
# Don't check the extension for directories
if not is_dir:
ext = os.path.splitext(filename)[1][1:].lower()
if ext not in allowed_exts:
return False
if filename.find("@eaDir") > 0:
return False
return True

handler = EventHandler()
notifier = pyinotify.Notifier(wm, handler)
wdd = wm.add_watch(["/volume1/music", "/volume1/photo", "/volume1/video"], mask, rec=True, auto_add=True)

notifier.loop(daemonize=True, pid_file='/var/run/')
except pyinotify.NotifierError, err:
print >> sys.stderr, err

To run the script, just type:

python /volume1/Extensions/scripts/

Automate Loading

This final part is about making sure the new system works after a NAS upgrade or reboot. Create a startup script that will handle the mount and startup of the monitoring script.

~$ cat > /usr/local/etc/rc.d/ << EOF
~$ mount --bind /volume1/homes/<username>/CloudStation/Photos /volume1/photo/<username>
~$ # Install pyinotify package (in case Python package had an update on Synology).
~$ cd /tmp
~$ wget
~$ python pyinotify
~$ rm
~$ # Start monitoring script
~$ python /volume1/Extensions/scripts/
~$ EOF
~$ chmod u+x /usr/local/etc/rc.d/

To check the setup is working, just restart the NAS and add some pictures using Cloud Station.

Source for Python notify script:

Add New Search
Josef  - python beginner   | |2015-09-20 16:04:47
hello neo73,

this should be that i need, but iám a absolute beginner in python
and i didn´t found a beginner tutorial about python in conjunction with a
synology nas. Do you have a link or a little tutorial how to use this script
above to use Cloud and Photostation together

iostrym  - great   | |2016-07-11 15:28:42
thanks a lot, it is exactly what I was looking for.
But did you try symbolic
link instead of the "mount" procedure ?
It seems that there is no more
the indexing problem that need the python script and symbolic link don't need to
be created at each startup :
Write comment
[b] [i] [u] [url] [quote] [code] [img] 
Please input the anti-spam code that you can read in the image.

3.26 Copyright (C) 2008 / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved."