2019-03-28 13:45:03 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- mode: python; indent-tabs-mode: nil; -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""
|
|
|
|
MSDrive.py
|
|
|
|
|
|
|
|
Distributable under the GNU General Public License Version 3 or newer.
|
|
|
|
|
2019-04-24 17:38:14 +00:00
|
|
|
The send-to-onedrive pages using the Graph API
|
|
|
|
https://docs.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0
|
2019-03-28 13:45:03 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
|
|
from contextlib import closing
|
|
|
|
|
|
|
|
import CloudStorage
|
|
|
|
|
2019-04-24 17:38:14 +00:00
|
|
|
class MSDriveSession(CloudStorage.CloudOAuth2Session):
|
2019-03-28 13:45:03 +00:00
|
|
|
""" Hold parameters for OAuth. """
|
|
|
|
|
|
|
|
#
|
|
|
|
# OAuth 2.0 flow see:
|
|
|
|
# http://tools.ietf.org/html/rfc6749
|
|
|
|
# http://msdn.microsoft.com/en-us/library/live/hh243649
|
|
|
|
#
|
|
|
|
|
2019-04-24 17:38:14 +00:00
|
|
|
name_prefix = 'msdrive'
|
|
|
|
oauth2_auth_endpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
|
2019-04-11 19:08:46 +00:00
|
|
|
oauth2_token_endpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
|
2019-04-24 17:38:14 +00:00
|
|
|
oauth2_scope = 'Files.ReadWrite'
|
|
|
|
|
|
|
|
class MSDrive(CloudStorage.CloudStorage):
|
|
|
|
""" Send files to Microsoft OneDrive. """
|
|
|
|
|
|
|
|
name = 'OneDrive'
|
|
|
|
session_class = MSDriveSession
|
|
|
|
user_agent = 'PG2OneDrive/2019.0'
|
|
|
|
#upload_endpoint = 'https://apis.live.net/v5.0/me/skydrive/files/'
|
|
|
|
upload_endpoint = 'https://graph.microsoft.com/v1.0/me/drive/items/root:/Documents/Gutenberg/{filename}:/createUploadSession'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def upload_file(self, session, response):
|
|
|
|
""" Upload a file to microsoft onedrive. """
|
|
|
|
filename = self.fix_filename(session.ebook.get_filename())
|
|
|
|
item_data = {
|
|
|
|
'name': filename,
|
|
|
|
'description': 'A Project Gutenberg Ebook',
|
|
|
|
"@microsoft.graph.conflictBehavior": "rename",
|
|
|
|
}
|
2019-06-19 19:03:16 +00:00
|
|
|
filesize = len(response.content)
|
2019-04-24 17:38:14 +00:00
|
|
|
url = self.upload_endpoint.format(filename=filename)
|
|
|
|
chunk_size = 327680 # weird onedrive thing related to FAT tables
|
|
|
|
upload_data = session.post(url, json={'item': item_data}).json()
|
|
|
|
|
|
|
|
def headers(start, end, filesize):
|
|
|
|
return {
|
|
|
|
'Content-Length': str(end - start + 1),
|
|
|
|
'Content-Range': 'bytes {}-{}/{}'.format(start, end, filesize)
|
|
|
|
}
|
2019-06-19 19:03:16 +00:00
|
|
|
with session as s:
|
|
|
|
if 'uploadUrl' in upload_data:
|
|
|
|
session_uri = upload_data['uploadUrl']
|
|
|
|
start = 0
|
|
|
|
end = min(chunk_size - 1, filesize - 1)
|
|
|
|
|
|
|
|
for chunk in response.iter_content(chunk_size):
|
|
|
|
r = s.put(
|
|
|
|
session_uri,
|
|
|
|
data=chunk,
|
|
|
|
headers=headers(start, end, filesize),
|
|
|
|
)
|
|
|
|
start = start + chunk_size
|
|
|
|
end = min(end + chunk_size, filesize - 1)
|
|
|
|
r.raise_for_status()
|
|
|
|
else:
|
|
|
|
CloudStorage.log('no uploadUrl in %s' % upload_data)
|