diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..0782e6e --- /dev/null +++ b/README.rst @@ -0,0 +1,165 @@ +PyiCloud is a module which allows pythonistas to interact with iCloud webservices. It's powered by the fantastic [requests](https://github.com/kennethreitz/requests) HTTP library. + +At its core, PyiCloud connects to iCloud using your username and password, then performs calendar and iPhone queries against their API. + +============== +Authentication +============== + +Authentication is as simple as passing your username and password to the `PyiCloudService` class: + +>>> from pyicloud import PyiCloudService +>>> api = PyiCloudService('jappleseed@apple.com', 'password') + +In the event that the username/password combination is invalid, a `PyiCloudFailedLoginException` exception is thrown. + +======= +Devices +======= + +You can list which devices associated with your account by using the `devices` property: + +>>> api.devices +{ +u'i9vbKRGIcLYqJnXMd1b257kUWnoyEBcEh6yM+IfmiMLh7BmOpALS+w==': , +u'reGYDh9XwqNWTGIhNBuEwP1ds0F/Lg5t/fxNbI4V939hhXawByErk+HYVNSUzmWV': +} + +and you can access individual devices by either their index, or their ID: + +>>> api.devices[0] + +>>> api.devices['i9vbKRGIcLYqJnXMd1b257kUWnoyEBcEh6yM+IfmiMLh7BmOpALS+w=='] + + +or, as a shorthand if you have only one associated apple device, you can simply use the `iphone` property to access the first device associated with your account: + +>>> api.iphone + + +Note: the first device associated with your account may not necessarily be your iPhone. + +============== +Find My iPhone +============== + +Once you have successfully authenticated, you can start querying your data! + +******** +Location +******** + +Returns the device's last known location. The Find My iPhone app must have been installed and initialized. + +>>> api.iphone.location() +{u'timeStamp': 1357753796553, u'locationFinished': True, u'longitude': -0.14189, u'positionType': u'GPS', u'locationType': None, u'latitude': 51.501364, u'isOld': False, u'horizontalAccuracy': 5.0} + +****** +Status +****** + +The Find My iPhone response is quite bloated, so for simplicity's sake this method will return a subset of the properties. + +>>> api.iphone.status() +{'deviceDisplayName': u'iPhone 5', 'deviceStatus': u'200', 'batteryLevel': 0.6166913, 'name': u"Peter's iPhone"} + +If you wish to request further properties, you may do so by passing in a list of property names. + +********** +Play Sound +********** + +Sends a request to the device to play a sound, if you wish pass a custom message you can do so by changing the subject arg. + +>>> api.iphone.play_sound() + +A few moments later, the device will play a ringtone, display the default notification ("Find My iPhone Alert") and a confirmation email will be sent to you. + +********* +Lost Mode +********* + +Lost mode is slightly different to the "Play Sound" functionality in that it allows the person who picks up the phone to call a specific phone number *without having to enter the passcode*. Just like "Play Sound" you may pass a custom message which the device will display, if it's not overridden the custom message of "This iPhone has been lost. Please call me." is used. + +>>> phone_number = '555-373-383' +>>> message = 'Thief! Return my phone immediately.' +>>> api.iphone.lost_device(phone_number, message) + +======== +Calendar +======== + +The calendar webservice currently only supports fetching events. + +****** +Events +****** + +Returns this month's events: + +>>> api.calendar.events() + +Or, between a specific date range: + +>>> from_dt = datetime(2012, 1, 1) +>>> to_dt = datetime(2012, 1, 31) +>>> api.calendar.events(from_dt, to_dt) + +Alternatively, you may fetch a single event's details, like so: + +>>> api.calendar.get_event_detail('CALENDAR', 'EVENT_ID') + +======================= +File Storage (Ubiquity) +======================= + +You can access documents stored in your iCloud account by using the `files` property's `dir` method: + +>>> 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' +] + +You can access children and their children's children using the filename as an index: + +>>> api.files['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' + +And when you have a file that you'd like to download, the `open` method will return a response object from which you can read the `content`. + +>>> api.files['com~apple~Notes']['Documents']['Some Document'].open().content +'Hello, these are the file contents' + +Note: the object returned from the above `open` method is a [response object](http://www.python-requests.org/en/latest/api/#classes) and the `open` method can accept any parameters you might normally use in a request using [requests](https://github.com/kennethreitz/requests). + +For example, if you know that the file you're opening has JSON content: + +>>> api.files['com~apple~Notes']['Documents']['information.json'].open().json() +{'How much we love you': 'lots'} +>>> api.files['com~apple~Notes']['Documents']['information.json'].open().json()['How much we love you'] +'lots' + +Or, if you're downloading a particularly large file, you may want to use the `stream` keyword argument, and read directly from the raw response object: + +>>> download = api.files['com~apple~Notes']['Documents']['big_file.zip'].open(stream=True) +>>> with open('downloaded_file.zip', 'wb') as opened_file: + opened_file.write(download.raw.read()) \ No newline at end of file