You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
5.1 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. from magic import from_file
  2. from gapi.api import API
  3. from googleapiclient.http import MediaFileUpload
  4. import re
  5. APPLICATION_NAME = "Google Calendar API Python"
  6. def is_folder(element):
  7. return element['mimeType'] == 'application/vnd.google-apps.folder'
  8. def split_path(path,rev=False):
  9. s = re.findall(r'(?:^/|[^/\x00]+)',path)
  10. if rev:
  11. return s[::-1]
  12. else:
  13. return s
  14. def without(node,*keys):
  15. node_meta = set(node.keys())
  16. nope = set(keys)
  17. ret = {}
  18. for key in node_meta-nope:
  19. ret[key] = node[key]
  20. return ret
  21. class drive_api(API):
  22. def __init__(
  23. self,
  24. app_name,
  25. client_secret_file,
  26. credentials_dir,
  27. scopes = 'https://www.googleapis.com/auth/drive',
  28. version = 'v3',
  29. ):
  30. super().__init__('drive',scopes,app_name,client_secret_file,credentials_dir,version)
  31. root = {}
  32. self.filesystem = {'folders':{'/':root}}
  33. root_meta = self.service.files().get(fileId='root').execute()
  34. del root_meta['kind']
  35. root[0] = root_meta
  36. root['parent'] = self.filesystem
  37. self.__fill_in__(root)
  38. def get_file_by_path(self,path,ret_file = True,no_parent = True):
  39. '''gets a file or folder by remote path'''
  40. if isinstance(path,str):
  41. path = split_path(path)
  42. parent = self.filesystem
  43. end = path.pop()
  44. for sub in path:
  45. try:
  46. if not 'folders' in parent.keys():
  47. self.__fill_in__(parent)
  48. parent = parent['folders'][sub]
  49. except KeyError:
  50. raise FileNotFoundError
  51. try:
  52. if ret_file:
  53. if not 'files' in parent.keys():
  54. self.__fill_in__(parent)
  55. ret = parent['files'][end]
  56. else:
  57. if not 'folders' in parent.keys():
  58. self.__fill_in__(parent)
  59. ret = parent['folders'][end]
  60. if no_parent:
  61. ret[0] = without(ret[0],'parent')
  62. return ret
  63. except KeyError:
  64. raise FileNotFoundError
  65. def __upload_file__(self,local_path,remote_path):
  66. '''creates file if it does not exists otherwise update the file'''
  67. mimetype = from_file(local_path,mime_type=True)
  68. _upload = MeduaFileUpload(local_path,mimeType=mimetype)
  69. try:
  70. fid = get_file_by_path(remote_path)
  71. self.service.files().update(fileId=fid,mediaBody=_upload)
  72. except FileNotFoundError:
  73. path = split_path(remote_path)
  74. end = path.pop()
  75. parent = mkdirs(path)
  76. parent_id = parent[0]['id']
  77. meta = {
  78. 'name':end,
  79. 'parents':[parent_id]
  80. }
  81. new_f_meta = self.service.files().create(
  82. body = meta,
  83. mediaBody = _upload
  84. ).execute()
  85. parent['files']['end'] = new_f_meta
  86. def mkdirs(self,path):
  87. '''makes directories if they do not exist already'''
  88. if isinstance(path,str):
  89. path = split_path(path)
  90. missing = []
  91. for i in range(len(path),-1,-1):
  92. try:
  93. parent = self.get_file_by_path(path[:i],False,no_parent = False)
  94. break
  95. except FileNotFoundError:
  96. missing.append(path[i-1])
  97. while len(missing) > 0:
  98. new_folder = {'folders':{}}
  99. name = missing.pop()
  100. new_meta = self.__create_remote_folder__(name,parent)
  101. del new_meta['name']
  102. del new_meta['kind']
  103. new_folder[0] = new_meta
  104. parent['folders'][name] = new_folder
  105. parent = new_folder
  106. return parent
  107. def __create_remote_folder__(self,name,parent):
  108. meta = {
  109. 'name':name,
  110. 'mimeType':'application/vnd.google-apps.folder',
  111. 'parents' : [parent[0]['id']]
  112. }
  113. return self.service.files().create(body = meta).execute()
  114. def __fill_in__(self,parent):
  115. '''finds all files and folders from a parent'''
  116. parent_id = parent[0]['id']
  117. child_list = self.__list_children__(parent_id)
  118. parent['files'] = {}
  119. parent['folders'] = {}
  120. for child in child_list:
  121. del child['kind']
  122. name = child.pop('name')
  123. child['parent'] = parent
  124. if is_folder(child):
  125. parent['folders'][name] = {}
  126. parent['folders'][name][0] = child
  127. else:
  128. parent['files'][name] = child
  129. def __list_children__(self,parent_id):
  130. page_token = None
  131. first = True
  132. while page_token or first:
  133. first = False
  134. response = self.service.files().list(q = "'{}' in parents and trashed = false".format(parent_id),pageToken=page_token).execute()
  135. page_token = response.get('nextPageToken',None)
  136. for file in response['files']:
  137. yield file
  138. if __name__ == "__main__":
  139. my_api = drive_api(APPLICATION_NAME,r'..\test\drive\client_secret.json',r'..\test\drive')
  140. service = my_api.service