{ "info": { "author": "Paul Heasley", "author_email": "paul@phdesign.com.au", "bugtrack_url": null, "classifiers": [], "description": "# album-rsync [![Build Status](https://travis-ci.org/phdesign/album-rsync.svg?branch=master)](https://travis-ci.org/phdesign/album-rsync)\n\nA python script to manage synchronising a local directory of photos with a remote storage provider based on an rsync interaction pattern.\n\n## Requirements\n\nSee [requirements.txt](requirements.txt) for list of dependencies. \nSupports Python 3.6+ \nFor Python 2, see https://github.com/phdesign/flickr-rsync\n\n## Installation\n\n### Via PyPI\n\nInstall from the python package manager by\n```\n$ pip install album-rsync\n```\n\n### From GitHub repo\n\nClone the GitHub repo locally\n\nTo install globally:\n```\n$ python setup.py install\n```\n\nTo install for the current user only:\n```\n$ python setup.py install --user\n```\n\n## Storage providers\n\nCurrently the local file system, Flickr and Google Photos are supported. Below is a list of supported features for each.\n\n| | Local | Flickr | Google |\n| ------------------ | ----- | ------ | ------ |\n| Root files | Yes | Yes | No |\n| Delete extra files | Yes | Yes | No |\n| Logout | No | Yes | Yes |\n\n## Authenticating\n\nTo authenticate against a storage provider, you will need to setup API keys, and then authorise your account.\n\nTo create API keys, visit:\n**Flickr:** https://www.flickr.com/services/api/misc.api_keys.html\n**Google:** https://console.developers.google.com/apis/library/photoslibrary.googleapis.com\n\nYou will be issued an api key and a secret. To enable the app to use these keys, either:\n\n* For Flickr, provide `--flickr-api-key` and `--flickr-api-secret` arguments to the command line\n* For Google, provide `--google-api-key` and `--google-api-secret` arguments to the command line\n* create a config file in $HOME/.album-rsync.ini with the following entries\n\n```\n# For Flickr\nFLICKR_API_KEY = xxxxxxxxxxxxxxxxxxx\nFLICKR_API_SECRET = yyyyyyyyyyyyyy\n\n# For Google\nGOOGLE_API_KEY = xxxxxxxxxxxxxxxxxxx\nGOOGLE_API_SECRET = yyyyyyyyyyyyyy\n```\n\nThe first time you perform any action against the storage provider, this app will prompt you to authorise access to your account. For Flickr you may choose to request delete permissions, or write only permissions if you do not want any photos deleted by this app.\n\n### Logout\n\nTo remove the authentication token for a storage provider, specify the storage provider as the source and pass the `--logout` argument. E.g.\n\n```\n$ album-rsync flickr --logout\n```\n\n## Listing files\n\nThe `--list-only` flag will print a list of files in the source storage provider, this can either be Flickr by specifying the `src` as `flickr`, `google` or a local file system path. Use `--list-sort` to sort the files alphabetically (slower). This feature is useful for manually creating a diff between your local files and Flickr files.\n\ne.g. List all files in Flickr photo sets\n\n```\n$ album-rsync flickr --list-only\n```\n\nor list sorted files from Google \n\n```\n$ album-rsync google --list-only --list-sort\n```\n\nor list all files in a local folder\n\n```\n$ album-rsync ~/Pictures --list-only\n```\n\n### Tree view vs. csv view\n\nYou can change the output from a tree view to a comma separated values view by using `--list-format=tree` or `--list-format=csv`. By default the tree view is used.\n\ne.g. Print in tree format\n\n```\n$ album-rsync flickr --list-only --list-format=tree\n\n\u251c\u2500\u2500\u2500 2017-04-24 Family Holiday\n\u2502 \u251c\u2500\u2500\u2500 IMG_2546.jpg [70ebf9]\n\u2502 \u251c\u2500\u2500\u2500 IMG_2547.jpg [3d3046]\n\u2502 \u251c\u2500\u2500\u2500 IMG_2548.jpg [2f2385]\n\u2502 \u2514\u2500\u2500\u2500 IMG_2549.jpg [d8e946]\n\u2502 \n\u2514\u2500\u2500\u2500 2017-04-16 Easter Camping\n \u251c\u2500\u2500\u2500 IMG_2515.jpg [aabe74]\n \u251c\u2500\u2500\u2500 IMG_2516.jpg [0eb4f2]\n \u2514\u2500\u2500\u2500 IMG_2517.jpg [4fe908]\n```\n\nOr csv format\n\n```\n$ album-rsync flickr --list-only --list-format=csv\n\nFolder, Filename, Checksum\n2017-04-24 Family Holiday, IMG_2546.jpg, 70ebf9be4d8301e94c65582977332754\n2017-04-24 Family Holiday, IMG_2547.jpg, 3d3046b37ba338793a762ab7bd83e85c\n2017-04-24 Family Holiday, IMG_2548.jpg, 2f23853abeb742551043a3514ba4315b\n2017-04-24 Family Holiday, IMG_2549.jpg, d8e946e73700b9c2890d3681c3c0fa0b\n2017-04-16 Easter Camping, IMG_2515.jpg, aabe74b06c3a53e801893347eb6bd7f5\n2017-04-16 Easter Camping, IMG_2516.jpg, 0eb4f2519f6562ff66069618637a7b10\n2017-04-16 Easter Camping, IMG_2517.jpg, 4fe9085b9f320a67988f84e85338a3ff\n```\n\n## Listing folders\n\nTo just list the top level folders (without all the files). use `--list-folders`. \n\n```\n$ album-rsync ~/Pictures --list-folders\n```\n## Syncing files\n\ne.g. To copy all files from Flickr to a local folder\n\n```\n$ album-rsync flickr ~/Pictures/flickr\n```\n\nOr to copy all files from a local folder up to Flickr\t\n\n```\n$ album-rsync ~/Pictures/flickr flickr\n```\n\nYou can even copy from a local folder to another local folder\n\n```\n$ album-rsync ~/Pictures/from ~/Pictures/to\n```\n\nFiles are matched by folder names and file names, case insensitively. E.g. if you have a Flickr photoset called `2017-04-16 Easter Camping` and a file called `IMG_2517.jpg`, and you are trying to copy from a folder with `2017-04-16 Easter Camping\\IMG_2517.jpg` it will assume this file is the same and will not try to copy it.\n\n### Dry run\n\nBefore performing any operations, it's recommended to perform a dry run first, just pass `-n` or `--dry-run` to simulate syncing, without actually copying anything.\n\n### Deleting extra files\n\n> WARNING: Use of this feature will permanently delete files, be sure you know what you're doing. \n\nNOTE: Deleting extra files is not supported by the Google storage provider.\n\nPass `--delete` to delete any extra files from the destination that don't exist in the source. E.g.\n\n```\n$ album-rsync ~/Pictures/flickr flickr --delete\n```\n\n## Filtering\n\nFiltering is done using regular expressions. The following four options control filtering the files:\n\n* `--include=` specifies a pattern that **file names** must match to be included in the operation\n* `--include-dir=` specifies a pattern that **folder names** must match to be included in the operation\n* `--exclude=` specifies a pattern that **file names** must NOT match to be included in the operation\n* `--exclude-dir=` specifies a pattern that **folder names** must NOT match to be included in the operation\n\nNote that filtering by folders is more performant than by file names, prefer folder name filtering where possible.\n\nAlso note that exclude filters take preference and will override include filters.\n\n### Root files\n\nNote that filtering does not apply to root files, root files (files in the target folder if local file system, or files not in a photoset on Flickr) are excluded by default. To include them, use `--root-files`.\n\n## Options\n\nAll options can be provided by either editing the config file `album-rsync.ini` or using the command line interface.\n\n```\nusage: album-rsync [-h] [-l] [--list-format {tree,csv}] [--list-sort]\n [--list-folders] [--delete] [-c] [--include REGEX]\n [--include-dir REGEX] [--exclude REGEX]\n [--exclude-dir REGEX] [--root-files] [-n]\n [--throttling SEC] [--retry NUM]\n [--flickr-api-key FLICKR_API_KEY]\n [--flickr-api-secret FLICKR_API_SECRET]\n [--flickr-tags \"TAG1 TAG2\"]\n [--google-api-key GOOGLE_API_KEY]\n [--google-api-secret GOOGLE_API_SECRET] [--logout] [-v]\n [--version]\n [src] [dest]\n\nA python script to manage synchronising a local directory of photos with a\nremote storage provider based on an rsync interaction pattern.\n\npositional arguments:\n src the source directory to copy or list files from, or\n FLICKR to specify flickr\n dest the destination directory to copy files to, or FLICKR\n to specify flickr\n\noptional arguments:\n -h, --help show this help message and exit\n -l, --list-only list the files in --src instead of copying them\n --list-format {tree,csv}\n output format for --list-only, TREE for a tree based\n output or CSV\n --list-sort sort alphabetically when --list-only, note that this\n forces buffering of remote sources so will be slower\n --list-folders lists only folders (no files, implies --list-only)\n --delete WARNING: permanently deletes additional files in\n destination\n -c, --checksum calculate file checksums for local files. Print\n checksum when listing, use checksum for comparison\n when syncing\n --include REGEX include only files matching REGEX. Defaults to media\n file extensions only\n --include-dir REGEX include only directories matching REGEX\n --exclude REGEX exclude any files matching REGEX, note this takes\n precedent over --include\n --exclude-dir REGEX exclude any directories matching REGEX, note this\n takes precedent over --include-dir\n --root-files includes roots files (not in a directory or a\n photoset) in the list or copy\n -n, --dry-run in sync mode, don't actually copy anything, just\n simulate the process and output\n --throttling SEC the delay in seconds (may be decimal) before each\n network call\n --retry NUM the number of times to retry a network call (using\n exponential backoff) before failing\n --flickr-api-key FLICKR_API_KEY\n flickr API key\n --flickr-api-secret FLICKR_API_SECRET\n flickr API secret\n --flickr-tags \"TAG1 TAG2\"\n space seperated list of tags to apply to uploaded\n files on flickr\n --google-api-key GOOGLE_API_KEY\n Google API key\n --google-api-secret GOOGLE_API_SECRET\n Google API secret\n --logout logout of remote storage provider (determined by src)\n -v, --verbose increase verbosity\n --version show program's version number and exit\n```\n\n### Config and token file discovery\n\nThe config file `album-rsync.ini` and token file `album-rsync.token` are searched for in the following locations in order:\n* `/album-rsync.ini`\n* `/.album-rsync.ini`\n* `/album-rsync.ini`\n* `/.album-rsync.ini`\n* `/album-rsync.ini`\n* `/.album-rsync.ini`\n\nThe token file is auto generated file containing the authorisation token to access the API. If deleted you will need to authorise the app again when next using it.\n\n## Developing\n\nInstall in development mode so source files are symlinked, meaning changes you make to the source files are reflected when you run the package anywhere.\n```\n$ python setup.py develop\n```\n\nThen to uninstall\n```\n$ python setup.py develop --uninstall\n```\n\n## Debugging\n\nUse pdb\n\n```\npython -m pdb ./flickr_rsync/__main__.py \n```\n\nSet a breakpoint\n\n```\nb ./flickr_rsync/flickr_storage.py:74\n```\n\nThen `c(ontinue)` or `n(ext)` to step over or `s(tep)` to step into. \n\n`l(ist)` to show current line and 11 lines of context.\n\n`p(print)` or `pp` (pretty print) to print a variable. E.g.\n\n```\np dir(photo)\npp photo.__dict__\n```\n\nTo print all properties of variable photo.\n\n`q(uit)` to exit.\n\nCheckout https://medium.com/instamojo-matters/become-a-pdb-power-user-e3fc4e2774b2\n\n## Publishing\n\nBased on [http://peterdowns.com/posts/first-time-with-pypi.html](http://peterdowns.com/posts/first-time-with-pypi.html)\n\n1. Update `album_rsync/_version.py` with the new version number (e.g. 1.1.1)\n2. Create a new GitHub release (e.g. `git tag -a v1.1.1 -m \"Version v1.1.1\" && git push --tags`)\n3. Push to PyPI\n```\n$ make deploy\n```\n\n## Running tests\n\nIf `make` is installed, you can run tests using a virtual environment\n\n```\n$ make venv\n$ make test\n```\n\nwhich will lint the code and run tests. To just run the linter\n\n```\n$ make lint\n```\n\nTo run the tests without make, use\n\n```\n$ python setup.py test\n```\n\n### To mark a focused test\n\nAdd decorator `@pytest.mark.focus` to test. Run with\n\n```\n$ pytest -m focus\n```\n\n## Tips\n\nTo list just root files only:\n```\n$ album-rsync flickr --exclude-dir '.*' --root-files --list-only\n```\n\n### Videos\nMovies should work, but flickr doesn't seem to return the original video when you download it again, it returns a processed video that may have slightly downgraded quality and will not have the same checksum.\n\n## Troubleshooting\n\n#### I get a Version conflict error with the six python package when installing on my Mac\n\nIf you're running Mac OSX El Capitan and you get the following error when running `python setup.py test`\n\n```\npkg_resources.VersionConflict: (six 1.4.1 (/System/Library/Frameworks/Python.fra\nmework/Versions/2.7/Extras/lib/python), Requirement.parse('six>=1.9'))\n```\n\nDo the following:\n```\n$ sudo pip install --ignore-installed six\n```\n\nMore details [https://github.com/pypa/pip/issues/3165](https://github.com/pypa/pip/issues/3165)\n\n#### I get an error 'The Flickr API keys have not been set'\n\nTo access Flickr this application needs API keys, go to http://www.flickr.com/services/apps/create/apply to sign up for a free personal API key\n\n#### I get an error 'The Flickr API keys have not been set' but I've set them in my config (ini) file\n\nGetting an error `The Flickr API keys have not been set` but you've set them in the config file? Perhaps the application can't find the config file location. Use `-v` or `--verbose` option to print the location of the config file being used.\n\n#### Why are some files are not being shown in the file list / sync?\n\nBy default only media files are included in file listings and sync operations. Media files are defined as `\\.(jpg|jpeg|png|gif|tiff|tif|bmp|psd|svg|raw|wmv|avi|mov|mpg|mp4|3gp|ogg|ogv|m2ts)$`. Use `--include=.*` to include all files.\n\n#### I get an error 'The filename, directory name or volume label syntax is incorrect'\n\nIf you're seeing an error like this\n\n```\nWindowsError: [Error 123] The filename, directory name, or volume label syntax is incorrect: 'C:\\\\Users\\\\xxx\\\\Pictures\" --list-only/*.*'\n```\n\nEnsure that you are not using single quotes `'` around a folder path in windows, instead use double quotes `\"`. e.g.\n\n```\n$ album-rsync \"C:\\Users\\xxx\\Pictures\" --list-only\n```\n\n#### When I try list list in a local folder called 'flickr' it lists my remote flickr files\n\nalbum-rsync uses the keyword `flickr` as a src or dest to denote pulling the list from flickr. If you have a folder called flickr, just give it a relative or absolute path make it obvious that it's a file path, e.g.\n\n```\n$ album-rsync ./flickr --list-only\n```\n\n#### If I add tags, they get changed by flickr, e.g. 'extn=mov becomes extnmov'.\nInternally flickr removes all whitespace and special characters, so 'extn mov' and 'extn=mov' match 'extnmov'. You can \nedit a tag using this URL:\nhttps://www.flickr.com/photos/{username}/tags/{tagname}/edit/\nor go here to manage all tags:\nhttps://www.flickr.com/photos/{username}/tags\nAnd in future put double quotes around your tag to retain special characters\n\n#### I get an error 'UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-3: character maps to \\'\n\nThis error occurs on Windows when you redirect stdout. To fix this, set PYTHONIOENCODING=utf-8. e.g.\n\n```\n$ PYTHONIOENCODING=utf-8 album-rsync ./flickr --list-only\n```\n\n## Release notes\n\n### v2.0.4 (14 Mar 2019)\n\n* Renamed to `album-rsync`\n* Converted to Python 3\n* Added Google Photos storage provider\n* Continues to next file when an error occurs copying a file (after retry policies have been applied)\n* Support for deleting extra files in destination\n\n### v1.0.5 (21 Mar 2018)\n\n* Support for videos\n* Add tag to maintain original extension \n\n### v1.0.4 (2 Nov 2017)\n* Improve retry and throttling, now uses exponential backoff\n* Use python logging framework, outputs log messages to stderr\n\n### v1.0.3 (16 Sep 2017)\n* Flickr converts .jpeg to .jpg extensions, so consider them the same when comparing for sync\n\n\n## TODO\n\n- [ ] Handle nested directories. Merge with separator like `parent_child`. Apply --include-dir after merging\n- [ ] List duplicate files\n- [ ] Webpage for successful Flickr login\n- [ ] Optimise - why does sort files seem to run faster?!\n- [ ] Fix duplicate albums issue\n- [ ] Why does it make 3 api calls for every photo in --list-only --list-sort mode?\n- [ ] --init to setup a new .ini file and walk through auth process\n- [ ] Add throttling and delay to Google", "description_content_type": "text/markdown", "docs_url": null, "download_url": "https://github.com/phdesign/album-rsync/archive/v2.0.5.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://www.phdesign.com.au/album-rsync", "keywords": "flickr,sync,rsync,photo,media,google,photos", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "album-rsync", "package_url": "https://pypi.org/project/album-rsync/", "platform": "", "project_url": "https://pypi.org/project/album-rsync/", "project_urls": { "Download": "https://github.com/phdesign/album-rsync/archive/v2.0.5.tar.gz", "Homepage": "http://www.phdesign.com.au/album-rsync" }, "release_url": "https://pypi.org/project/album-rsync/2.0.5/", "requires_dist": null, "requires_python": "", "summary": "A python script to manage synchronising a local directory of photos with a remote service based on an rsync interaction pattern", "version": "2.0.5" }, "last_serial": 5762924, "releases": { "2.0.0": [ { "comment_text": "", "digests": { "md5": "29717587e3379f7d74b455557ac50998", "sha256": "156d02ff9b21fefe2c094187cc82960571517e1f8e64f6a56dbca4886cf7e6e3" }, "downloads": -1, "filename": "album-rsync-2.0.0.tar.gz", "has_sig": false, "md5_digest": "29717587e3379f7d74b455557ac50998", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23129, "upload_time": "2018-12-27T02:00:50", "url": "https://files.pythonhosted.org/packages/35/2f/faccc35a953d9b0e913505cf90b158e730a0d2d675518c6123b0ee89e2a2/album-rsync-2.0.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "ca5a6c300f41f71a4554562add2a2b9b", "sha256": "f400281c1d857a9d4e475e4ef5b49a496df8aa7da7ff06883754c494bf070f16" }, "downloads": -1, "filename": "album-rsync-2.0.1.tar.gz", "has_sig": false, "md5_digest": "ca5a6c300f41f71a4554562add2a2b9b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23509, "upload_time": "2018-12-27T14:15:27", "url": "https://files.pythonhosted.org/packages/86/d3/ad0fc3df7894b6d3006000c013bb482c308a09550a059e8f55b9e784c412/album-rsync-2.0.1.tar.gz" } ], "2.0.4": [ { "comment_text": "", "digests": { "md5": "21fd09020ffb851fed6ac7e897802750", "sha256": "bd6849f64c1d8f5c33112263094751666e9448c53a0a496c6f420496f6946fb4" }, "downloads": -1, "filename": "album-rsync-2.0.4.tar.gz", "has_sig": false, "md5_digest": "21fd09020ffb851fed6ac7e897802750", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28728, "upload_time": "2019-03-14T13:45:32", "url": "https://files.pythonhosted.org/packages/0d/fa/4bdf01dd7615877d9333ac80c096d023eaa39207910a0dbcc4851ee1bf8e/album-rsync-2.0.4.tar.gz" } ], "2.0.5": [ { "comment_text": "", "digests": { "md5": "05d87fbc73365e1b4096477934840f5b", "sha256": "72bd95b2b5519e701d883a80e3d2da008ef5d81735bec16689c265e98ee3f6c4" }, "downloads": -1, "filename": "album-rsync-2.0.5.tar.gz", "has_sig": false, "md5_digest": "05d87fbc73365e1b4096477934840f5b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29346, "upload_time": "2019-08-31T02:09:39", "url": "https://files.pythonhosted.org/packages/5a/6a/ec4a0ba0ceb6574a583022907e8f0534b9fa27b5f4846f310e9b09dc2bcf/album-rsync-2.0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "05d87fbc73365e1b4096477934840f5b", "sha256": "72bd95b2b5519e701d883a80e3d2da008ef5d81735bec16689c265e98ee3f6c4" }, "downloads": -1, "filename": "album-rsync-2.0.5.tar.gz", "has_sig": false, "md5_digest": "05d87fbc73365e1b4096477934840f5b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29346, "upload_time": "2019-08-31T02:09:39", "url": "https://files.pythonhosted.org/packages/5a/6a/ec4a0ba0ceb6574a583022907e8f0534b9fa27b5f4846f310e9b09dc2bcf/album-rsync-2.0.5.tar.gz" } ] }