From 97a0588deb344756990bd5350314ccfe3484cc7a Mon Sep 17 00:00:00 2001
From: wxy1343 <1343890272@qq.com>
Date: Sun, 3 Oct 2021 16:50:57 +0800
Subject: [PATCH] =?UTF-8?q?[+]=E5=88=86=E4=BA=AB=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E6=9F=A5=E7=9C=8B=20#46=20[+]=E5=88=86=E4=BA=AB=E6=96=87?=
=?UTF-8?q?=E4=BB=B6=E8=BD=AC=E5=AD=98=20#52?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 8 +++++
aliyunpan/about.py | 2 +-
aliyunpan/api/core.py | 80 ++++++++++++++++++++++++++++++++++-------
aliyunpan/api/models.py | 16 +++++----
aliyunpan/api/type.py | 13 ++++++-
aliyunpan/cli/cli.py | 6 ++--
aliyunpan/cli/tui.py | 11 ++++--
main.py | 8 +++--
8 files changed, 115 insertions(+), 29 deletions(-)
diff --git a/README.md b/README.md
index 91701d7..d6adaf0 100644
--- a/README.md
+++ b/README.md
@@ -164,6 +164,14 @@ python main.py -h
-a, --album |
是否访问相册 |
+
+ -s, --share-id |
+ 指定分享id |
+
+
+ -sp, --share-pwd |
+ 指定分享密码 |
+
diff --git a/aliyunpan/about.py b/aliyunpan/about.py
index c0072c6..f2df444 100644
--- a/aliyunpan/about.py
+++ b/aliyunpan/about.py
@@ -1 +1 @@
-__version__ = '2.7.15'
+__version__ = '2.8.0'
diff --git a/aliyunpan/api/core.py b/aliyunpan/api/core.py
index c51ae06..bc152d6 100644
--- a/aliyunpan/api/core.py
+++ b/aliyunpan/api/core.py
@@ -4,13 +4,14 @@
from datetime import datetime
from pathlib import Path
from threading import RLock
+from typing import List
import requests
import simplejson
# from aliyunpan.api import ua
from aliyunpan.api.req import *
-from aliyunpan.api.type import UserInfo, AlibumInfo
+from aliyunpan.api.type import UserInfo, AlibumInfo, Share
from aliyunpan.api.utils import *
from aliyunpan.common import *
from aliyunpan.exceptions import InvalidRefreshToken, AliyunpanException, AliyunpanCode, LoginFailed, \
@@ -22,11 +23,12 @@
class AliyunPan(object):
- def __init__(self, refresh_token: str = None, album: bool = False):
+ def __init__(self, refresh_token: str = None, album: bool = False, share: Share = Share()):
self._req = Req(self)
self._user_info = None
self._alibum_info = None
self._album = album
+ self._share = share
self._access_token = None
self._drive_id = None
self._username = None
@@ -46,6 +48,7 @@ def __init__(self, refresh_token: str = None, album: bool = False):
drive_id = property(lambda self: (self._lock.acquire(), next(self._drive_id_gen_), self._lock.release())[1],
lambda self, value: setattr(self, '_drive_id', value))
album = property(lambda self: self._album, lambda self, value: setattr(self, '_album', value))
+ share = property(lambda self: self._share)
def login(self, username: str = None, password: str = None, ua: str = None):
"""
@@ -104,10 +107,21 @@ def get_file_list(self, parent_file_id: str = 'root', next_marker: str = None, r
:param next_marker:
:return:
"""
- url = 'https://api.aliyundrive.com/v2/file/list'
- json = {"drive_id": self.drive_id, "parent_file_id": parent_file_id, 'fields': '*', 'marker': next_marker}
+ json = {"parent_file_id": parent_file_id}
+ if next_marker:
+ json['marker'] = next_marker
+ headers = {}
+ kwargs = {}
+ if self._share.share_id:
+ url = 'https://api.aliyundrive.com/adrive/v3/file/list'
+ json.update({'share_id': self._share.share_id, 'share_pwd': self._share.share_pwd})
+ headers = {'x-share-token': self.get_share_token()}
+ kwargs = {'access_token': None}
+ else:
+ url = 'https://api.aliyundrive.com/v2/file/list'
+ json.update({"drive_id": self.drive_id, 'fields': '*'})
logger.info(f'Get the list of parent_file_id {parent_file_id}.')
- r = self._req.post(url, json=json)
+ r = self._req.post(url, json=json, headers=headers, **kwargs)
try:
logger.debug(r.json())
except simplejson.errors.JSONDecodeError:
@@ -140,21 +154,43 @@ def delete_file(self, file_id: str):
return r.json()['responses'][0]['id']
return False
- def move_file(self, file_id: str, parent_file_id: str):
+ def batch(self, file_id_list: list, parent_file_id: str, force: bool = False) -> requests.models.Response:
+ """
+ 移动文件
+ """
+ file_json_list = []
+ auto_rename = False if force else True
+ headers = {}
+ for file_id in file_id_list:
+ body = {'file_id': file_id, 'to_parent_file_id': parent_file_id, 'auto_rename': auto_rename}
+ file_json = {'body': body,
+ 'headers': {'Content-Type': 'application/json'}, 'id': 0, 'method': 'POST',
+ 'url': '/file/move'}
+ file_json_list.append(file_json)
+ if self._share.share_id:
+ url = 'https://api.aliyundrive.com/adrive/v2/batch'
+ for i, file_json in enumerate(file_json_list):
+ file_json_list[i]['body']['to_drive_id'] = self.drive_id
+ file_json_list[i]['body']['share_id'] = self._share.share_id
+ file_json_list[i]['url'] = '/file/copy'
+ headers['x-share-token'] = self.get_share_token()
+ else:
+ url = 'https://api.aliyundrive.com/v2/batch'
+ for i, file_json in enumerate(file_json_list):
+ file_json_list[i]['id'] = file_json['body']['file_id']
+ file_json_list[i]['body']['drive_id'] = self.drive_id
+ json = {'requests': file_json_list, 'resource': "file"}
+ return self._req.post(url, json=json, headers=headers)
+
+ def move_file(self, file_id: List[str], parent_file_id: str):
"""
移动文件
:param file_id:
:param parent_file_id:
:return:
"""
- url = 'https://api.aliyundrive.com/v2/batch'
- json = {"requests": [{"body": {"drive_id": self.drive_id, "file_id": file_id,
- "to_parent_file_id": parent_file_id},
- "headers": {"Content-Type": "application/json"},
- "id": file_id, "method": "POST", "url": "/file/move"}],
- "resource": "file"}
logger.info(f'Move files {file_id} to {parent_file_id}')
- r = self._req.post(url, json=json)
+ r = self.batch([file_id], parent_file_id)
if r.status_code == 200:
if 'message' in r.json()['responses'][0]['body']:
print(r.json()['responses'][0]['body']['message'])
@@ -724,6 +760,24 @@ def share_link(self, file_id_list: list, expiration=''):
return r.json()['share_url']
def get_share_by_anonymous(self, share_id: str):
+ """
+ 获取分享文件列表
+ """
url = f'https://api.aliyundrive.com/adrive/v3/share_link/get_share_by_anonymous'
r = self._req.post(url, json={'share_id': share_id})
return r.json()['file_infos']
+
+ def get_share_token(self, share: Share = None):
+ """
+ 获取share_token
+ """
+ if not share:
+ share = self._share
+ if share.share_token:
+ return share.share_token
+ url = 'https://api.aliyundrive.com/v2/share_link/get_share_token'
+ json = {'share_id': share.share_id, 'share_pwd': share.share_pwd}
+ r = self._req.post(url, json=json)
+ share_token = r.json().get('share_token', '')
+ share.share_token = share_token
+ return share_token
diff --git a/aliyunpan/api/models.py b/aliyunpan/api/models.py
index f1c3da8..f093e48 100644
--- a/aliyunpan/api/models.py
+++ b/aliyunpan/api/models.py
@@ -101,12 +101,13 @@ def get_file_info(info):
for info in info_list:
if info['type'] == 'file':
file_info = FileInfo(name=info['name'], id=info['file_id'], pid=info['parent_file_id'], type=True,
- ctime=time.strptime(info['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ'),
+ ctime=time.strptime(info['created_at'],
+ '%Y-%m-%dT%H:%M:%S.%fZ') if 'created_at' in info else time.localtime(),
update_time=time.strptime(info['updated_at'], '%Y-%m-%dT%H:%M:%S.%fZ'),
- hidden=info['hidden'], category=info['category'],
- content_type=info['content_type'],
- size=info['size'], content_hash_name=info['content_hash_name'],
- content_hash=info['content_hash'],
+ hidden=info.get('hidden'), category=info['category'],
+ content_type=info.get('content_type'),
+ size=info['size'], content_hash_name=info.get('content_hash_name'),
+ content_hash=info.get('content_hash'),
download_url=info['download_url'] if 'download_url' in info else '',
video_media_metadata=info[
'video_media_metadata'] if 'video_media_metadata' in info else None,
@@ -114,9 +115,10 @@ def get_file_info(info):
'video_preview_metadata'] if 'video_preview_metadata' in info else None)
else:
file_info = FileInfo(name=info['name'], id=info['file_id'], pid=info['parent_file_id'], type=False,
- ctime=time.strptime(info['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ'),
+ ctime=time.strptime(info['created_at'],
+ '%Y-%m-%dT%H:%M:%S.%fZ') if 'created_at' in info else time.time(),
update_time=time.strptime(info['updated_at'], '%Y-%m-%dT%H:%M:%S.%fZ'),
- hidden=info['hidden'])
+ hidden=info.get('hidden'))
file_info_list.append(file_info)
return file_info_list
diff --git a/aliyunpan/api/type.py b/aliyunpan/api/type.py
index 4ff54e9..f9a70bb 100644
--- a/aliyunpan/api/type.py
+++ b/aliyunpan/api/type.py
@@ -1,6 +1,6 @@
from collections import namedtuple
-__all__ = ['FileInfo', 'UserInfo', 'ShareInfo', 'AlibumInfo']
+__all__ = ['FileInfo', 'UserInfo', 'ShareInfo', 'AlibumInfo', 'Share']
_file_info = (
'name', 'id', 'pid', 'type', 'ctime', 'update_time', 'hidden', 'category', 'content_type', 'size',
@@ -15,3 +15,14 @@
ShareInfo.__new__.__defaults__ = ('',) * 6
AlibumInfo = namedtuple('AlibumInfo', ['drive_name', 'drive_id'])
AlibumInfo.__new__.__defaults__ = ('',) * 2
+
+
+class Share:
+ share_id = ''
+ share_pwd = ''
+ share_token = ''
+
+ def __init__(self, share_id='', share_pwd='', share_token=''):
+ self.share_id = share_id
+ self.share_pwd = share_pwd
+ self.share_token = share_token
diff --git a/aliyunpan/cli/cli.py b/aliyunpan/cli/cli.py
index 0cc0f3c..adf24cc 100644
--- a/aliyunpan/cli/cli.py
+++ b/aliyunpan/cli/cli.py
@@ -9,6 +9,7 @@
from aliyunpan.api.core import AliyunPan
from aliyunpan.api.models import *
from aliyunpan.api.req import *
+from aliyunpan.api.type import Share
from aliyunpan.api.utils import *
from aliyunpan.cli.config import Config
from aliyunpan.cli.tui import AliyunpanTUI
@@ -23,7 +24,7 @@ class Commander:
def __init__(self, init=True, *args, **kwargs):
self._disk = AliyunPan()
self._path_list = PathList(self._disk)
- self._req = Req()
+ self._req = Req(self._disk)
self._config = Config()
self._task_config = Config(ROOT_DIR / Path('tasks.yaml'))
self._share_link = 'aliyunpan://'
@@ -46,11 +47,12 @@ def __del__(self):
pass
def init(self, config_file=None, refresh_token=None, username=None, password=None, depth=3, timeout=None,
- drive_id=None, album=False):
+ drive_id=None, album=False, share_id='', share_pwd=''):
self._path_list.depth = depth
self._req.timeout = timeout
self._disk.drive_id = drive_id
self._disk.album = album
+ self._disk._share = Share(share_id, share_pwd)
config_file_list = list(
filter(lambda x: get_real_path(x).is_file(), map(lambda x: get_real_path(x), self._config_set)))
if config_file:
diff --git a/aliyunpan/cli/tui.py b/aliyunpan/cli/tui.py
index 5f8a4e9..8883fe8 100644
--- a/aliyunpan/cli/tui.py
+++ b/aliyunpan/cli/tui.py
@@ -427,7 +427,11 @@ def update_file_list(self, name=None, file_id=None):
# 保存当前目录信息
self._parent_file_info = None
if file_id != 'root':
- self._parent_file_info = self.parent.parentApp._cli._path_list._tree.get_node(file_id).data
+ file_node = self.parent.parentApp._cli._path_list._tree.get_node(file_id)
+ if file_node:
+ self._parent_file_info = file_node.data
+ else:
+ self._file_list = self.parent.parentApp._cli._path_list.get_fid_list('root', update=False)
else:
self._file_list = self.parent.parentApp._cli._path_list.get_fid_list(self._parent_file_info.id,
update=False)
@@ -447,7 +451,10 @@ def update_path(self):
pid = self._parent_file_info.pid if self._parent_file_info else None
while True:
if pid:
- file_info = self.parent.parentApp._cli._path_list._tree.get_node(pid).data
+ file_node = self.parent.parentApp._cli._path_list._tree.get_node(pid)
+ if not file_node:
+ file_node = self.parent.parentApp._cli._path_list._tree.get_node('root')
+ file_info = file_node.data
if file_info:
path = file_info.name / path
pid = file_info.pid
diff --git a/main.py b/main.py
index cced74a..c255e63 100755
--- a/main.py
+++ b/main.py
@@ -20,14 +20,16 @@
@click.option('-D', '--debug', is_flag=True, help='Debug mode.')
@click.option('-T', '--timeout', type=click.FLOAT, help='Api request timeout.')
@click.option('-id', '--drive-id', type=click.STRING, help='Specify DRIVE_ID.')
-@click.option('-a', '--album', is_flag=True, help='Specify album')
-def cli(config_file, refresh_token, username, password, depth, debug, timeout, drive_id, album):
+@click.option('-a', '--album', is_flag=True, help='Specify album.')
+@click.option('-s', '--share-id', type=click.STRING, help='Specify share_id.')
+@click.option('-sp', '--share-pwd', type=click.STRING, help='Specify share_pwd.')
+def cli(config_file, refresh_token, username, password, depth, debug, timeout, drive_id, album, share_id, share_pwd):
logger.info(f'Version:{__version__}')
if debug:
logger.setLevel('DEBUG')
commander.init(config_file=None if refresh_token or username else config_file,
refresh_token=None if username else refresh_token, username=username, password=password, depth=depth,
- timeout=timeout, drive_id=drive_id, album=album)
+ timeout=timeout, drive_id=drive_id, album=album, share_id=share_id, share_pwd=share_pwd)
@cli.command(aliases=['l', 'list', 'dir'], help='List files.')