Add 'flickrscripts/' from commit '89393c390fe69e66bd2d9aa275ba652e320a3215'
git-subtree-dir: flickrscripts git-subtree-mainline:1037e390b5
git-subtree-split:89393c390f
This commit is contained in:
commit
fd87ec8fe9
1
flickrscripts/.gitignore
vendored
Normal file
1
flickrscripts/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.egg-info
|
5
flickrscripts/README.rst
Normal file
5
flickrscripts/README.rst
Normal file
@ -0,0 +1,5 @@
|
||||
==============
|
||||
Flickr Scripts
|
||||
==============
|
||||
|
||||
Miscellaneous crap for doing stuff with my Flickr photos.
|
30
flickrscripts/flickrscripts/__init__.py
Normal file
30
flickrscripts/flickrscripts/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from os.path import basename
|
||||
|
||||
|
||||
__meta__ = dict(
|
||||
name='flickrscripts',
|
||||
version='0.1.0',
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'flickrscripts = flickrscripts:route',
|
||||
],
|
||||
},
|
||||
test_suite='nose.collector',
|
||||
)
|
||||
USAGE = 'Usage: {prog} <subcommand> [args]'
|
||||
|
||||
|
||||
def route(sysargs=sys.argv[:]):
|
||||
try:
|
||||
subcommand = sysargs.pop(1)
|
||||
import_name = 'flickrscripts.{}'.format(subcommand)
|
||||
|
||||
module = __import__(import_name, fromlist=[import_name])
|
||||
return module.main(sysargs)
|
||||
except IndexError:
|
||||
print(USAGE.format(prog=basename(sysargs[0])), file=sys.stderr)
|
||||
print('You must provide a subcommand', file=sys.stderr)
|
||||
return 1
|
49
flickrscripts/flickrscripts/common.py
Normal file
49
flickrscripts/flickrscripts/common.py
Normal file
@ -0,0 +1,49 @@
|
||||
import json
|
||||
from hashlib import sha1
|
||||
from os.path import expanduser
|
||||
|
||||
import flickrapi
|
||||
|
||||
|
||||
def setup_flickr(api_key, api_secret):
|
||||
flickr = flickrapi.FlickrAPI(api_key, api_secret)
|
||||
|
||||
token, frob = flickr.get_token_part_one(perms='write')
|
||||
if not token:
|
||||
raw_input("Press ENTER after you authorized this program")
|
||||
|
||||
flickr.get_token_part_two((token, frob))
|
||||
return flickr
|
||||
|
||||
|
||||
def get_photo_signature(flickr, photo_id):
|
||||
info = flickr.photos_getInfo(photo_id=photo_id).find('photo')
|
||||
exif = flickr.photos_getExif(photo_id=photo_id).find('photo')
|
||||
|
||||
if not info or not exif:
|
||||
raise InvalidPhotoIdError(photo_id)
|
||||
|
||||
return [
|
||||
info.get('originalformat'), info.find('owner').get('location'),
|
||||
info.find('dates').get('taken')
|
||||
] + sorted(
|
||||
(e.get('label'), e.get('tag'), e.get('tagspace'), e.get('tagspaceid'),
|
||||
e.find('raw').text) for e in exif.findall('exif')
|
||||
)
|
||||
|
||||
|
||||
def get_photo_sha1sum(flickr, photo_id):
|
||||
return sha1(str(get_photo_signature(flickr, photo_id)))
|
||||
|
||||
|
||||
def get_flickr_from_rc_file(rc_file=expanduser('~/.flickrscripts.json')):
|
||||
rc_conf = json.load(open(rc_file))
|
||||
return setup_flickr(rc_conf['APIKEY'], rc_conf['APISECRET'])
|
||||
|
||||
|
||||
def load_rc_file(rc_file=expanduser('~/.flickrscripts.json')):
|
||||
return json.load(open(rc_file))
|
||||
|
||||
|
||||
class InvalidPhotoIdError(ValueError):
|
||||
pass
|
95
flickrscripts/flickrscripts/timewarp.py
Normal file
95
flickrscripts/flickrscripts/timewarp.py
Normal file
@ -0,0 +1,95 @@
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
from os.path import expanduser
|
||||
|
||||
from flickrscripts.common import setup_flickr
|
||||
|
||||
|
||||
class TimeWarper(object):
|
||||
flickr = None
|
||||
_base_query_args = dict(user_id='me', page=1)
|
||||
|
||||
def __init__(self, api_key, api_secret):
|
||||
self.flickr = setup_flickr(api_key, api_secret)
|
||||
self.log = logging.getLogger(self.__class__.__name__)
|
||||
self.log.level = logging.INFO
|
||||
|
||||
def run(self, set_to_date, **query_args):
|
||||
self.log.info(
|
||||
'Setting upload dates for photos matching query %r', query_args
|
||||
)
|
||||
query = self._base_query_args.copy()
|
||||
query.update(query_args)
|
||||
|
||||
for i, page in self._get_pages(query):
|
||||
self.log.info('Processing page %s, attributes=%r',
|
||||
i, page.attrib)
|
||||
self._set_upload_date_for_photos(i, page, set_to_date)
|
||||
|
||||
return 0
|
||||
|
||||
def _set_upload_date_for_photos(self, pagenum, page, set_to_date):
|
||||
for i, photo in enumerate(page.findall('photos/photo')):
|
||||
setdate_response = self.flickr.photos_setDates(
|
||||
photo_id=photo.attrib['id'],
|
||||
date_posted=set_to_date
|
||||
)
|
||||
self.log.info('page %s photo %s: response attribs=%s',
|
||||
pagenum, i, setdate_response.attrib)
|
||||
|
||||
def _get_pages(self, query):
|
||||
self.log.info('Getting pages for query %r', query)
|
||||
i = 1
|
||||
while True:
|
||||
page = self.flickr.photos_search(**query)
|
||||
if len(page.findall('photos/photo')):
|
||||
yield i, page
|
||||
i += 1
|
||||
else:
|
||||
raise StopIteration
|
||||
|
||||
|
||||
def main(sysargs=sys.argv[:]):
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog='flickrscripts timewarp')
|
||||
parser.add_argument('set_to_date')
|
||||
parser.add_argument('-q', '--search-query-param', default=[],
|
||||
action='append', help='Add a key=value param to the search query list')
|
||||
|
||||
parser.add_argument(
|
||||
'-c', '--rcfile', default=expanduser('~/.flickrscripts.json'),
|
||||
help='JSON file containing `APIKEY` and `APISECRET` keys',
|
||||
type=argparse.FileType('r')
|
||||
)
|
||||
|
||||
args = parser.parse_args(sysargs[1:])
|
||||
rc_conf = json.load(args.rcfile)
|
||||
|
||||
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
|
||||
log = logging.getLogger('main')
|
||||
log.level = logging.INFO
|
||||
log.info('Preparing query args')
|
||||
|
||||
query_args = {}
|
||||
for key_val in args.search_query_param:
|
||||
key, value = key_val.split('=', 1)
|
||||
query_args[key] = value
|
||||
|
||||
if len(query_args.keys()) == 0:
|
||||
query_args = dict(
|
||||
min_upload_date=(datetime.now() + timedelta(days=-1)),
|
||||
max_upload_date=(datetime.now() + timedelta(days=1))
|
||||
)
|
||||
log.warn('No query arguments provided! ' +
|
||||
'Defaulting to %r', query_args)
|
||||
|
||||
warper = TimeWarper(rc_conf['APIKEY'], rc_conf['APISECRET'])
|
||||
return warper.run(args.set_to_date, **query_args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
10
flickrscripts/setup.py
Normal file
10
flickrscripts/setup.py
Normal file
@ -0,0 +1,10 @@
|
||||
import sys
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
from flickrscripts import __meta__
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup(**__meta__)
|
||||
sys.exit(0)
|
19
flickrscripts/tests/itest_timewarp.py
Normal file
19
flickrscripts/tests/itest_timewarp.py
Normal file
@ -0,0 +1,19 @@
|
||||
import unittest
|
||||
|
||||
from flickrscripts.timewarp import TimeWarper
|
||||
from flickrscripts.common import load_rc_file
|
||||
|
||||
|
||||
class TimeWarperTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
rc_conf = load_rc_file()
|
||||
self.warper = TimeWarper(rc_conf['APIKEY'], rc_conf['APISECRET'])
|
||||
|
||||
def test_is_not_horribly_busted(self):
|
||||
self.assertTrue(True, 'please forgive the horrible test')
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user