Adding support for ubiquity (file synchronization/storage) API.
Borrowed many implementation details from @matin's lovely icloud implementation; thanks @matin!
This commit is contained in:
parent
5d3b2e3e9b
commit
1d45ad9e7d
4 changed files with 157 additions and 1 deletions
37
README.md
37
README.md
|
@ -108,3 +108,40 @@ from_dt = datetime(2012, 1, 1)
|
||||||
to_dt = datetime(2012, 1, 31)
|
to_dt = datetime(2012, 1, 31)
|
||||||
api.calendar.events(from_dt, to_dt)
|
api.calendar.events(from_dt, to_dt)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### File Storage (Ubiquity)
|
||||||
|
|
||||||
|
You can access documents stored in your iCloud account by using the `files` property's `dir` method:
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> api.files.dir()
|
||||||
|
[u'.do-not-delete',
|
||||||
|
u'.localized',
|
||||||
|
u'com~apple~Notes',
|
||||||
|
u'com~apple~Preview',
|
||||||
|
u'com~apple~mail',
|
||||||
|
u'com~apple~shoebox',
|
||||||
|
u'com~apple~system~spotlight'
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
And, you can access children and their children's children using the filename as an index:
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> api.files['com~apple~Notes']
|
||||||
|
<Folder: u'com~apple~Notes'>
|
||||||
|
>>> api.files['com~apple~Notes'].type
|
||||||
|
u'folder'
|
||||||
|
>>> api.files['com~apple~Notes'].dir()
|
||||||
|
[u'Documents']
|
||||||
|
>>> api.files['com~apple~Notes']['Documents'].dir()
|
||||||
|
[u'Some Document']
|
||||||
|
>>> api.files['com~apple~Notes']['Documents']['Some Document'].name
|
||||||
|
u'Some Document'
|
||||||
|
>>> api.files['com~apple~Notes']['Documents']['Some Document'].modified
|
||||||
|
datetime.datetime(2012, 9, 13, 2, 26, 17)
|
||||||
|
>>> api.files['com~apple~Notes']['Documents']['Some Document'].size
|
||||||
|
1308134
|
||||||
|
>>> api.files['com~apple~Notes']['Documents']['Some Document'].type
|
||||||
|
u'file'
|
||||||
|
```
|
||||||
|
|
|
@ -5,7 +5,11 @@ import json
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from exceptions import PyiCloudFailedLoginException
|
from exceptions import PyiCloudFailedLoginException
|
||||||
from services import FindMyiPhoneServiceManager, CalendarService
|
from services import (
|
||||||
|
FindMyiPhoneServiceManager,
|
||||||
|
CalendarService,
|
||||||
|
UbiquityService
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PyiCloudService(object):
|
class PyiCloudService(object):
|
||||||
|
@ -101,6 +105,13 @@ class PyiCloudService(object):
|
||||||
def iphone(self):
|
def iphone(self):
|
||||||
return self.devices[0]
|
return self.devices[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def files(self):
|
||||||
|
if not hasattr(self, '_files'):
|
||||||
|
service_root = self.webservices['ubiquity']['url']
|
||||||
|
self._files = UbiquityService(service_root, self.session, self.params)
|
||||||
|
return self._files
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def calendar(self):
|
def calendar(self):
|
||||||
service_root = self.webservices['calendar']['url']
|
service_root = self.webservices['calendar']['url']
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from calendar import CalendarService
|
from calendar import CalendarService
|
||||||
from findmyiphone import FindMyiPhoneServiceManager
|
from findmyiphone import FindMyiPhoneServiceManager
|
||||||
|
from ubiquity import UbiquityService
|
||||||
|
|
107
pyicloud/services/ubiquity.py
Normal file
107
pyicloud/services/ubiquity.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class UbiquityService(object):
|
||||||
|
""" The 'Ubiquity' iCloud service."""
|
||||||
|
|
||||||
|
def __init__(self, service_root, session, params):
|
||||||
|
self.session = session
|
||||||
|
self.params = params
|
||||||
|
self._root = None
|
||||||
|
|
||||||
|
self._service_root = service_root
|
||||||
|
self._node_url = '/ws/%s/%s/%s'
|
||||||
|
|
||||||
|
host = self._service_root.split('//')[1].split(':')[0]
|
||||||
|
self.session.headers.update({'host': host})
|
||||||
|
|
||||||
|
def get_node_url(self, id, variant='item'):
|
||||||
|
return self._service_root + self._node_url % (
|
||||||
|
self.params['dsid'],
|
||||||
|
variant,
|
||||||
|
id
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_node(self, id):
|
||||||
|
request = self.session.get(self.get_node_url(id))
|
||||||
|
return UbiquityNode(self, request.json())
|
||||||
|
|
||||||
|
def get_children(self, id):
|
||||||
|
request = self.session.get(
|
||||||
|
self.get_node_url(id, 'parent')
|
||||||
|
)
|
||||||
|
items = request.json()['item_list']
|
||||||
|
return [UbiquityNode(self, item) for item in items]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def root(self):
|
||||||
|
if not self._root:
|
||||||
|
self._root = self.get_node(0)
|
||||||
|
return self._root
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return getattr(self.root, attr)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.root[key]
|
||||||
|
|
||||||
|
|
||||||
|
class UbiquityNode(object):
|
||||||
|
def __init__(self, conn, data):
|
||||||
|
self.data = data
|
||||||
|
self.connection = conn
|
||||||
|
|
||||||
|
@property
|
||||||
|
def item_id(self):
|
||||||
|
return self.data.get('item_id')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.data.get('name')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return self.data.get('type')
|
||||||
|
|
||||||
|
def get_children(self):
|
||||||
|
if not hasattr(self, '_children'):
|
||||||
|
self._children = self.connection.get_children(self.item_id)
|
||||||
|
return self._children
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self):
|
||||||
|
try:
|
||||||
|
return int(self.data.get('size'))
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def modified(self):
|
||||||
|
return datetime.strptime(
|
||||||
|
self.data.get('modified'),
|
||||||
|
'%Y-%m-%dT%H:%M:%SZ'
|
||||||
|
)
|
||||||
|
|
||||||
|
def dir(self):
|
||||||
|
return [child.name for child in self.get_children()]
|
||||||
|
|
||||||
|
def get(self, name):
|
||||||
|
return [child for child in self.get_children() if child.name == name][0]
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
try:
|
||||||
|
return self.get(key)
|
||||||
|
except IndexError:
|
||||||
|
raise KeyError('No child named %s exists' % key)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name.encode('unicode-escape')
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s: u'%s'>" % (
|
||||||
|
self.type.capitalize(),
|
||||||
|
str(self)
|
||||||
|
)
|
Loading…
Reference in a new issue