diff --git a/CherryPy.conf b/CherryPy.conf index 05614d7..78ca2c0 100644 --- a/CherryPy.conf +++ b/CherryPy.conf @@ -23,6 +23,7 @@ host_mobile: 'm.gutenberg.org' host_https: 1 file_host: 'www.gutenberg.org' + sqlalchemy.pool_size: 20 sqlalchemy.max_overflow: 0 sqlalchemy.timeout: 3 @@ -35,7 +36,7 @@ dropbox_client_secret: 'add secret in .autocat3 or /etc/autocat3.conf files' gdrive_client_id: '586299000268.apps.googleusercontent.com' gdrive_client_secret: 'add secret in .autocat3 or /etc/autocat3.conf files' -msdrive_client_id: '0000000044111115' +msdrive_client_id: '6902b111-a9d6-461f-bd8a-83dafee3da66' msdrive_client_secret: 'add secret in .autocat3 or /etc/autocat3.conf files' recaptcha_public_key: '6Lf0cpkUAAAAAIHB6OW_6H0SIqt5O2xmgsnF4Is8' diff --git a/CloudStorage.py b/CloudStorage.py index 054b481..14b7f5e 100644 --- a/CloudStorage.py +++ b/CloudStorage.py @@ -135,7 +135,7 @@ class CloudStorage (object): session_class = CloudOAuth2Session user_agent = None upload_endpoint = None - re_filename = re.compile (r'[/\<>:"|?*]') + re_filename = re.compile (r'[/\<>:"|?* ]') def __init__ (self): diff --git a/MSDrive.py b/MSDrive.py index c95c2f9..2c6ad3f 100644 --- a/MSDrive.py +++ b/MSDrive.py @@ -4,11 +4,10 @@ """ MSDrive.py -Copyright 2014,15 by Marcello Perathoner - Distributable under the GNU General Public License Version 3 or newer. -The send-to-microsoft-drive pages. +The send-to-onedrive pages using the Graph API +https://docs.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0 """ @@ -18,8 +17,7 @@ from contextlib import closing import CloudStorage - -class MSDriveSession (CloudStorage.CloudOAuth2Session): +class MSDriveSession(CloudStorage.CloudOAuth2Session): """ Hold parameters for OAuth. """ # @@ -28,29 +26,55 @@ class MSDriveSession (CloudStorage.CloudOAuth2Session): # http://msdn.microsoft.com/en-us/library/live/hh243649 # - name_prefix = 'msdrive' - oauth2_auth_endpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize' + 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' + oauth2_scope = 'Files.ReadWrite' -class MSDrive (CloudStorage.CloudStorage): - """ Send files to Microsoft Drive. """ +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:/{filename}:/createUploadSession' + 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, request): - """ Upload a file to microsoft drive. """ + 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 = int(response.headers['Content-Length']) + 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() - url = self.upload_endpoint.format( - {'filename': self.fix_filename (session.ebook.get_filename ())} - ) + def headers(start, end, filesize): + return { + 'Content-Length': str(end - start + 1), + 'Content-Range': 'bytes {}-{}/{}'.format(start, end, filesize) + } - upload_session = session.post (url) - if 'uploadUrl' in upload_session: - with closing (session.put (upload_session['uploadUrl'], data = request.iter_content (1024 * 1024))) as r: - r.raise_for_status () + 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 = session.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) + session.close()