-
Notifications
You must be signed in to change notification settings - Fork 7
/
MSDrive.py
79 lines (62 loc) · 2.73 KB
/
MSDrive.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/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.
The send-to-onedrive pages using the Graph API
https://docs.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0
"""
from __future__ import unicode_literals
from contextlib import closing
import CloudStorage
class MSDriveSession(CloudStorage.CloudOAuth2Session):
""" Hold parameters for OAuth. """
#
# OAuth 2.0 flow see:
# http://tools.ietf.org/html/rfc6749
# http://msdn.microsoft.com/en-us/library/live/hh243649
#
name_prefix = 'msdrive'
oauth2_auth_endpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
oauth2_token_endpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
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",
}
filesize = len(response.content)
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)
}
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)