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.

204 lines
6.6 KiB

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 posixpath import join as pathjoin
  4. from googleapiclient.http import MediaFileUpload
  5. import re
  6. import os
  7. APPLICATION_NAME = "Google Calendar API Python"
  8. def path_translate(
  9. root,
  10. want,
  11. path,
  12. file
  13. ):
  14. l = len(root)+1
  15. rel = path[l:]
  16. new_rel = rel.replace(os.sep,'/')
  17. return pathjoin(want,new_rel,file)
  18. def is_folder(element):
  19. return element['mimeType'] == 'application/vnd.google-apps.folder'
  20. def split_path(path,rev=False):
  21. s = re.findall(r'(?:^/|[^/\x00]+)',path)
  22. if rev:
  23. return s[::-1]
  24. else:
  25. return s
  26. def without(node,*keys):
  27. node_meta = set(node.keys())
  28. nope = set(keys)
  29. ret = {}
  30. for key in node_meta-nope:
  31. ret[key] = node[key]
  32. return ret
  33. def remote_path_join(path,*paths):
  34. ret = path
  35. for path in paths:
  36. if not ret.endswith('/'):
  37. ret += '/'
  38. else:
  39. ret += path
  40. return ret
  41. class drive_api(API):
  42. def __init__(
  43. self,
  44. app_name,
  45. client_secret_file,
  46. credentials_dir,
  47. scopes = 'https://www.googleapis.com/auth/drive',
  48. version = 'v3',
  49. ):
  50. super().__init__('drive',scopes,app_name,client_secret_file,credentials_dir,version)
  51. root = {}
  52. self.filesystem = {'folders':{'/':root}}
  53. root_meta = self.service.files().get(fileId='root').execute()
  54. del root_meta['kind']
  55. root[0] = root_meta
  56. root['parent'] = self.filesystem
  57. self.__fill_in__(root)
  58. def get_file_by_path(self,path,ret_file = True,no_parent = True):
  59. '''gets a file or folder by remote path'''
  60. if isinstance(path,str):
  61. path = split_path(path)
  62. else:
  63. path = path.copy()
  64. parent = self.filesystem
  65. end = path.pop()
  66. for sub in path:
  67. try:
  68. if not 'folders' in parent.keys():
  69. self.__fill_in__(parent)
  70. parent = parent['folders'][sub]
  71. except KeyError:
  72. raise FileNotFoundError
  73. try:
  74. if ret_file:
  75. if not 'files' in parent.keys():
  76. self.__fill_in__(parent)
  77. ret = parent['files'][end]
  78. if no_parent:
  79. ret = without(ret,'parent')
  80. else:
  81. if not 'folders' in parent.keys():
  82. self.__fill_in__(parent)
  83. ret = parent['folders'][end]
  84. if no_parent:
  85. ret[0] = without(ret[0],'parent')
  86. return ret
  87. except KeyError:
  88. raise FileNotFoundError
  89. def mkdirs(self,path):
  90. '''makes directories if they do not exist already'''
  91. if isinstance(path,str):
  92. path = split_path(path)
  93. else:
  94. path = path.copy()
  95. missing = []
  96. for i in range(len(path),-1,-1):
  97. try:
  98. parent = self.get_file_by_path(path[:i],False,no_parent = False)
  99. break
  100. except FileNotFoundError:
  101. missing.append(path[i-1])
  102. while len(missing) > 0:
  103. new_folder = {'folders':{},'files':{}}
  104. new_folder['parent'] = parent
  105. name = missing.pop()
  106. new_meta = self.__create_remote_folder__(name,parent)
  107. del new_meta['name']
  108. del new_meta['kind']
  109. new_folder[0] = new_meta
  110. parent['folders'][name] = new_folder
  111. parent = new_folder
  112. return parent
  113. def upload(self,local_path,remote_path):
  114. if not isinstance(remote_path,str):
  115. remote_path = pathjoin(*remote_path)
  116. if os.path.isdir(local_path):
  117. for root,dirs,files in os.walk(local_path,topdown = False):
  118. for file in files:
  119. new_path = path_translate(local_path,remote_path,root,file)
  120. self.__upload_file__(os.path.join(root,file),new_path)
  121. print(new_path)
  122. return self.get_file_by_path(remote_path,False,False)
  123. else:
  124. return self.__upload_file__(local_path,remote_path)
  125. def __upload_file__(self,local_path,remote_path):
  126. '''creates file if it does not exists otherwise update the file'''
  127. if isinstance(remote_path,str):
  128. remote_path = split_path(remote_path)
  129. else:
  130. remote_path = remote_path.copy()
  131. _upload = MediaFileUpload(local_path)
  132. try:
  133. old_file = self.get_file_by_path(remote_path)
  134. self.service.files().update(fileId=old_file['id'],media_body=_upload).execute()
  135. return old_file
  136. except FileNotFoundError:
  137. path = remote_path
  138. end = path.pop()
  139. parent = self.mkdirs(path)
  140. parent_id = parent[0]['id']
  141. meta = {
  142. 'name':end,
  143. 'parents':[parent_id]
  144. }
  145. new_f_meta = self.service.files().create(
  146. body = meta,
  147. media_body = _upload
  148. ).execute()
  149. new_f_meta = without(new_f_meta,'kind')
  150. new_f_meta['parent'] = parent
  151. parent['files'][end] = new_f_meta
  152. return new_f_meta
  153. def __create_remote_folder__(self,name,parent):
  154. meta = {
  155. 'name':name,
  156. 'mimeType':'application/vnd.google-apps.folder',
  157. 'parents' : [parent[0]['id']]
  158. }
  159. return self.service.files().create(body = meta).execute()
  160. def __fill_in__(self,parent):
  161. '''finds all files and folders from a parent'''
  162. parent_id = parent[0]['id']
  163. child_list = self.__list_children__(parent_id)
  164. parent['files'] = {}
  165. parent['folders'] = {}
  166. for child in child_list:
  167. del child['kind']
  168. name = child.pop('name')
  169. child['parent'] = parent
  170. if is_folder(child):
  171. parent['folders'][name] = {}
  172. parent['folders'][name][0] = child
  173. else:
  174. parent['files'][name] = child
  175. def __list_children__(self,parent_id):
  176. page_token = None
  177. first = True
  178. while page_token or first:
  179. first = False
  180. response = self.service.files().list(q = "'{}' in parents and trashed = false".format(parent_id),pageToken=page_token).execute()
  181. page_token = response.get('nextPageToken',None)
  182. for file in response['files']:
  183. yield file
  184. if __name__ == "__main__":
  185. my_api = drive_api(APPLICATION_NAME,r'..\test\drive\client_secret.json',r'..\test\drive')
  186. service = my_api.service