Skip to main content

CloudDrive2 gRPC 客户端库,提供简洁易用的 Python API 来操作 CloudDrive2 服务

Project description

clouddrive web API 的 Python 封装

修改自ChenyangGao大佬的web-mount-packs

PyPI - Python Version PyPI - Version PyPI - Downloads PyPI - Format PyPI - Status

安装

通过 pypi

pip install -U python-clouddrive2

入门介绍

1. 导入模块和创建实例

导入模块

from clouddrive import CloudDriveClient, CloudDriveFileSystem

创建客户端对象,登录 CloudDrive:此处,后台服务地址: "http://localhost:19798",用户名: "test",密码: "test@test"

请确保 CloudDrive 已经启动,并且可通过 http://localhost:19798 访问

client = CloudDriveClient("http://localhost:19798", "test", "test@test")

绝大部分 CloudDriveClient 的方法带有 async_ 参数,意味着它支持异步 IO。

>>> import asyncio
>>> loop = asyncio.get_event_loop()

>>> from clouddrive import CloudDriveClient, CloudDriveFileSystem
>>> client = CloudDriveClient("http://localhost:19798", "test", "test@test")

>>> from clouddrive.proto import CloudDrive_pb2
>>> client.FindFileByPath(CloudDrive_pb2.FindFileByPathRequest(path="/"))
id: "60512951-88d8-4b5a-bea4-fbcb5d86ce6f"
name: "/"
fullPathName: "/"
createTime {
  seconds: 1703821474
  nanos: 152897000
}
writeTime {
  seconds: 1703821474
  nanos: 152897000
}
accessTime {
  seconds: 1703821474
  nanos: 152897000
}
CloudAPI {
  name: "BaseFsApi"
}
isDirectory: true
isRoot: true

>>> client.FindFileByPath(CloudDrive_pb2.FindFileByPathRequest(path="/"), async_=True)
<coroutine object UnaryUnaryMethod.__call__ at 0x107518f20>
>>> loop.run_until_complete(client.FindFileByPath(CloudDrive_pb2.FindFileByPathRequest(path="/"), async_=True))
id: "60512951-88d8-4b5a-bea4-fbcb5d86ce6f"
name: "/"
fullPathName: "/"
createTime {
  seconds: 1703821474
  nanos: 152897000
}
writeTime {
  seconds: 1703821474
  nanos: 152897000
}
accessTime {
  seconds: 1703821474
  nanos: 152897000
}
CloudAPI {
  name: "BaseFsApi"
}
isDirectory: true
isRoot: true

创建文件系统对象

fs = CloudDriveFileSystem(client)

或者直接在 client 上就可获取文件系统对象

fs = client.fs

或者直接用 CloudDriveFileSystem 登录

fs = CloudDriveFileSystem.login("http://localhost:19798", "test", "test@test")

2. 操作网盘使用 Python 式的文件系统方法

文件系统对象的方法,设计和行为参考了 osposixpathpathlib.Pathshutil 等模块。

clouddrive.CloudDriveFileSystem 实现了读写的文件系统方法。

clouddrive.CloudDrivePath 实现了二次封装,从路径的角度来进行操作。

使用 getcwd 方法,获取当前工作目录的路径,参考 os.getcwd

>>> fs.getcwd()
'/'

使用 listdir 方法,罗列当前目录的文件名,参考 os.listdir

>>> fs.listdir()
['115', '阿里云盘Open']

使用 chdir 方法,切换当前工作目录,参考 os.chdir

>>> fs.chdir("/115")

使用 listdir_attr 方法,罗列当前目录时,还可以获取属性

>>> fs.listdir_attr()
[{'id': '2592968610464922758',
  'name': '000阅读·乱七八糟',
  'fullPathName': '/115/000阅读·乱七八糟',
  'createTime': '2023-03-18T06:45:45Z',
  'writeTime': '2023-12-14T06:54:20Z',
  'accessTime': '2023-12-14T06:54:20Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/000阅读·乱七八糟',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2644648816430546428',
  'name': 'libgen',
  'fullPathName': '/115/libgen',
  'createTime': '2023-05-28T14:05:06Z',
  'writeTime': '2023-12-14T06:54:20Z',
  'accessTime': '2023-12-14T06:54:20Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/libgen',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2593093001609739968',
  'name': '云下载',
  'fullPathName': '/115/云下载',
  'createTime': '2023-03-18T10:52:54Z',
  'writeTime': '2023-12-16T13:58:22Z',
  'accessTime': '2023-12-16T13:58:22Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/云下载',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2580587204111760961',
  'name': '电影',
  'fullPathName': '/115/电影',
  'createTime': '2023-03-01T04:46:07Z',
  'writeTime': '2023-12-14T06:54:20Z',
  'accessTime': '2023-12-14T06:54:20Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/电影',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2614100250469596984',
  'name': '电视剧',
  'fullPathName': '/115/电视剧',
  'createTime': '2023-04-16T10:30:33Z',
  'writeTime': '2023-12-23T14:26:17Z',
  'accessTime': '2023-12-23T14:26:17Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/电视剧',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2576930424647319247',
  'name': '纪录片',
  'fullPathName': '/115/纪录片',
  'createTime': '2023-02-24T03:40:45Z',
  'writeTime': '2023-12-18T10:49:29Z',
  'accessTime': '2023-12-18T10:49:29Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/纪录片',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2580131407544188592',
  'name': '👾0号:重要资源',
  'fullPathName': '/115/👾0号:重要资源',
  'createTime': '2023-02-28T13:40:32Z',
  'writeTime': '2023-12-14T06:54:20Z',
  'accessTime': '2023-12-14T06:54:20Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/👾0号:重要资源',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2580246506904748007',
  'name': '📚1号:书籍大礼包',
  'fullPathName': '/115/📚1号:书籍大礼包',
  'createTime': '2023-02-28T17:29:12Z',
  'writeTime': '2023-12-14T06:54:20Z',
  'accessTime': '2023-12-14T06:54:20Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/📚1号:书籍大礼包',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},
 {'id': '2673432528538303699',
  'name': '📼资料备份',
  'fullPathName': '/115/📼资料备份',
  'createTime': '2023-07-07T07:13:12Z',
  'writeTime': '2023-12-14T06:54:20Z',
  'accessTime': '2023-12-14T06:54:20Z',
  'CloudAPI': {'name': '115',
   'userName': '306576686',
   'nickName': '306576686'},
  'isDirectory': True,
  'isCloudDirectory': True,
  'canSearch': True,
  'hasDetailProperties': True,
  'canOfflineDownload': True,
  'path': '/115/📼资料备份',
  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)}]

使用 listdir_path 方法,罗列当前目录时,还可以获取 clouddrive.CloudDrivePath 对象

>>> fs.listdir_path()
[<clouddrive.CloudDrivePath(id='2592968610464922758', name='000阅读·乱七八糟', fullPathName='/115/000阅读·乱七八糟', createTime='2023-03-18T06:45:45Z', writeTime='2023-12-14T06:54:20Z', accessTime='2023-12-14T06:54:20Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/000阅读·乱七八糟')>,
 <clouddrive.CloudDrivePath(id='2644648816430546428', name='libgen', fullPathName='/115/libgen', createTime='2023-05-28T14:05:06Z', writeTime='2023-12-14T06:54:20Z', accessTime='2023-12-14T06:54:20Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/libgen')>,
 <clouddrive.CloudDrivePath(id='2593093001609739968', name='云下载', fullPathName='/115/云下载', createTime='2023-03-18T10:52:54Z', writeTime='2023-12-16T13:58:22Z', accessTime='2023-12-16T13:58:22Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/云下载')>,
 <clouddrive.CloudDrivePath(id='2580587204111760961', name='电影', fullPathName='/115/电影', createTime='2023-03-01T04:46:07Z', writeTime='2023-12-14T06:54:20Z', accessTime='2023-12-14T06:54:20Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/电影')>,
 <clouddrive.CloudDrivePath(id='2614100250469596984', name='电视剧', fullPathName='/115/电视剧', createTime='2023-04-16T10:30:33Z', writeTime='2023-12-23T14:26:17Z', accessTime='2023-12-23T14:26:17Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/电视剧')>,
 <clouddrive.CloudDrivePath(id='2576930424647319247', name='纪录片', fullPathName='/115/纪录片', createTime='2023-02-24T03:40:45Z', writeTime='2023-12-18T10:49:29Z', accessTime='2023-12-18T10:49:29Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/纪录片')>,
 <clouddrive.CloudDrivePath(id='2580131407544188592', name='👾0号:重要资源', fullPathName='/115/👾0号:重要资源', createTime='2023-02-28T13:40:32Z', writeTime='2023-12-14T06:54:20Z', accessTime='2023-12-14T06:54:20Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/👾0号:重要资源')>,
 <clouddrive.CloudDrivePath(id='2580246506904748007', name='📚1号:书籍大礼包', fullPathName='/115/📚1号:书籍大礼包', createTime='2023-02-28T17:29:12Z', writeTime='2023-12-14T06:54:20Z', accessTime='2023-12-14T06:54:20Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/📚1号:书籍大礼包')>,
 <clouddrive.CloudDrivePath(id='2673432528538303699', name='📼资料备份', fullPathName='/115/📼资料备份', createTime='2023-07-07T07:13:12Z', writeTime='2023-12-14T06:54:20Z', accessTime='2023-12-14T06:54:20Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, lastest_update=datetime.datetime(2023, 12, 29, 13, 15, 21, 23281), fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x105e9a850>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/115', refresh=False), path='/115/📼资料备份')>]

再次使用 chdir ,进入一些目录

>>> fs.chdir("电视剧/欧美剧/A")
>>> fs.getcwd()
'/115/电视剧/欧美剧/A'
>>> fs.listdir()
['A《爱、死亡和机器人》(Love.Death.and.Robot)[tt9561862]']
>>> fs.chdir("A《爱、死亡和机器人》(Love.Death.and.Robot)[tt9561862]/爱、死亡和机器人S01.Love.Death.and.Robots.1080p.NF.WEB-DL.DDP5.1.x264-NTG(18集)")
>>> fs.listdir()
['Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.简体&英文.ass', 'Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv']

使用 attr 方法,获取文件或文件夹的属性

>>> fs.attr("Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv")
{'id': '2576931481393823441',
 'name': 'Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv',
 'fullPathName': '/115/电视剧/欧美剧/A/A《爱、死亡和机器人》(Love.Death.and.Robot)[tt9561862]/爱、死亡和机器人S01.Love.Death.and.Robots.1080p.NF.WEB-DL.DDP5.1.x264-NTG(18集)/Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv',
 'size': '924544482',
 'fileType': 'File',
 'createTime': '2023-02-24T03:42:51Z',
 'writeTime': '2023-02-24T03:42:51Z',
 'accessTime': '2023-02-24T03:42:51Z',
 'CloudAPI': {'name': '115', 'userName': '306576686', 'nickName': '306576686'},
 'isCloudFile': True,
 'hasDetailProperties': True,
 'canOfflineDownload': True,
 'fileHashes': {'2': '7F4121B68A4E467ABF30A84627E20A8978895A4E'},
 'path': '/115/电视剧/欧美剧/A/A《爱、死亡和机器人》(Love.Death.and.Robot)[tt9561862]/爱、死亡和机器人S01.Love.Death.and.Robots.1080p.NF.WEB-DL.DDP5.1.x264-NTG(18集)/Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv',
 'lastest_update': datetime.datetime(2023, 12, 29, 13, 18, 27, 395024)}

使用 stat 方法,获取文件或文件夹的部分,参考 os.stat

>>> fs.stat("Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv")
os.stat_result(st_mode=33279, st_ino=0, st_dev=0, st_nlink=1, st_uid=0, st_gid=0, st_size=924544482, st_atime=1677210171.0, st_mtime=1677210171.0, st_ctime=1677210171.0)

使用 open 方法,打开一个文件(目前只支持读取,不支持写入),参考 open

>>> f = fs.open("Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.简体&英文.ass", encoding="UTF-16")
>>> f
<_io.TextIOWrapper name='Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.简体&英文.ass' encoding='UTF-16'>

读取此文件的前 100 个字符

>>> f.read(100)
'[Script Info]\n;SrtEdit 6.3.2012.1001\n;Copyright(C) 2005-2012 Yuan Weiguo\n\nTitle: YYeTs\nOriginal Scri'

用完后请及时关闭文件(其实不主动关闭也可以,只要文件不被引用,就会自动关闭)

>>> f.close()

以二进制模式打开一个文件,此时 mode="rb"

>>> f = fs.open("Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv", "rb")
>>> f
clouddrive.util.file.HTTPFileReader('http://localhost:19798/static/http/localhost:19798/False/%2F115%2F%E7%94%B5%E8%A7%86%E5%89%A7%2F%E6%AC%A7%E7%BE%8E%E5%89%A7%2FA%2FA%E3%80%8A%E7%88%B1%E3%80%81%E6%AD%BB%E4%BA%A1%E5%92%8C%E6%9C%BA%E5%99%A8%E4%BA%BA%E3%80%8B%28Love.Death.and.Robot%29%5Btt9561862%5D%2F%E7%88%B1%E3%80%81%E6%AD%BB%E4%BA%A1%E5%92%8C%E6%9C%BA%E5%99%A8%E4%BA%BAS01.Love.Death.and.Robots.1080p.NF.WEB-DL.DDP5.1.x264-NTG%EF%BC%8818%E9%9B%86%EF%BC%89%2FLove.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv', urlopen=<function urlopen at 0x1069200e0>, headers=mappingproxy({'Accept-Encoding': 'identity'}))

读取前 10 个字节

>>> f.read(10)
b'\x1aE\xdf\xa3\xa3B\x86\x81\x01B'

再读取 10 个字节

>>> f.read(10)
b'\xf7\x81\x01B\xf2\x81\x04B\xf3\x81'

当前文件偏移位置(从 0 开始计算)

>>> f.tell()
20

把读取位置重新变为文件开头

>>> f.seek(0)
0
>>> f.tell()
0

再次读取 20 字节,应该等于上面两次结果的拼接

>>> f.read(20)
b'\x1aE\xdf\xa3\xa3B\x86\x81\x01B\xf7\x81\x01B\xf2\x81\x04B\xf3\x81'
>>> f.tell()
20

回到根目录,我们继续其它试验

>>> fs.chdir("/")

使用 walk 方法,可以遍历一个目录,参考 os.walk

>>> next(fs.walk())
('/', ['115', '阿里云盘'], [])

使用 walk_path 方法,可以遍历一个目录时,获取 clouddrive.CloudDrivePath 对象

>>> next(fs.walk_path())
('/',
 [<clouddrive.CloudDrivePath(id='0', name='115', fullPathName='/115', createTime='2023-12-29T03:44:34.427131Z', writeTime='2023-12-29T03:44:34.427131Z', accessTime='2023-12-29T03:44:34.427131Z', CloudAPI={'name': '115', 'userName': '306576686', 'nickName': '306576686'}, isDirectory=True, isCloudRoot=True, isCloudDirectory=True, canSearch=True, hasDetailProperties=True, canOfflineDownload=True, fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x1064ee350>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/', refresh=False), path='/115')>,
  <clouddrive.CloudDrivePath(id='58188691_root', name='阿里云盘Open', fullPathName='/阿里云盘Open', createTime='2023-12-29T03:44:34.952368Z', writeTime='2023-12-29T03:44:34.952368Z', accessTime='2023-12-29T03:44:34.952368Z', CloudAPI={'name': '阿里云盘Open', 'userName': '4d1769fb91ba4752ac417f77c1da8082', 'nickName': '请设置昵称?'}, isDirectory=True, isCloudRoot=True, isCloudDirectory=True, canSearch=True, canDeletePermanently=True, fs=clouddrive.CloudDriveFileSystem(client=clouddrive.CloudDriveClient(origin='http://localhost:19798', username='2339083510@qq.com', password='******', channel=<grpc._channel.Channel object at 0x1064ee350>, async_channel=Channel('localhost', 19798, ..., path=None)), path='/', refresh=False), path='/阿里云盘Open')>],
 [])

在根目录下不能创建文件,因此进入 /115 下,继续做实验

>>> fs.chdir("/115")

使用 mkdir 方法,可以创建空文件夹,参考 os.mkdir

>>> fs.mkdir("test")
'/115/test'

CloudDrive 会对文件名进行一些转换,以确保即便在 Windows 上文件名也是有效的。一个比较彻底的办法是,名字中如果包含 *?:/\<>|",会被转换成对应的全角字符 *?:/\<>|",尾部如果有空白符号 (空格)\r\n\t\v\f\xa0 和 点号 . 会被移除。

[^1]: 可以用下面 2 个帮助函数,来解释这一行为:

def normalize_name(
    s: str, 
    /, 
    _transtab = {c: c + 65248 for c in b'*?:/\\<>|"'}, 
) -> str:
    return s.translate(_transtab).rstrip(" \r\n\v\t\f\xa0.")

def normalize_path(s: str, /) -> str:
    return "/"[:s.startswith("/")] + "/".join(filter(None, map(normalize_name, s.split("/"))))

不妨创建一个名字很特殊的文件夹试一下

>>> fs.mkdir("*?:\\<>| \r\n\v\t\f\xa0.")
'/115/*?:《》|'

可以看到返回的名字中,半角转全角,且尾部空白符号和 . 都被移除了。

>>> fs.listdir()
['000阅读·乱七八糟',
 'libgen',
 'test',
 '云下载',
 '电影',
 '电视剧',
 '纪录片',
 '*?:《》|',
 '👾0号:重要资源',
 '📚1号:书籍大礼包',
 '📼资料备份']

使用 rmdir 方法,可以删除空文件夹,参考 os.rmdir

>>> fs.rmdir('test')
>>> fs.rmdir('*?:《》|')
>>> fs.listdir()
['000阅读·乱七八糟',
 'libgen',
 '云下载',
 '电影',
 '电视剧',
 '纪录片',
 '👾0号:重要资源',
 '📚1号:书籍大礼包',
 '📼资料备份']

使用 makedirs 方法,可以创建多级的空目录,参考 os.makedirs

>>> fs.makedirs("a/b/c/d", exist_ok=True)
'/115/a/b/c/d'
>>> fs.listdir()
['000阅读·乱七八糟',
 'a',
 'libgen',
 '云下载',
 '电影',
 '电视剧',
 '纪录片',
 '👾0号:重要资源',
 '📚1号:书籍大礼包',
 '📼资料备份']

使用 removedirs 方法,可以(自底向上地)删除多级的空目录,参考 os.removedirs

>>> fs.removedirs("a/b/c/d")
>>> fs.listdir()
['000阅读·乱七八糟',
 'libgen',
 '云下载',
 '电影',
 '电视剧',
 '纪录片',
 '👾0号:重要资源',
 '📚1号:书籍大礼包',
 '📼资料备份']

使用 upload 方法上传文件(提示:文件只是上传到 CloudDrive 服务器上,至于 CloudDrive 什么时候上传完成,得等待)

>>> from io import BytesIO
>>> fs.upload(BytesIO(b"123"), "test.txt")
'/115/test.txt'
>>> fs.read_text("test.txt")
'123'
>>> fs.upload("file.py")
'/115/file.py'
>>> fs.listdir()
['000阅读·乱七八糟',
 'file.py',
 'libgen',
 'test.txt',
 '云下载',
 '电影',
 '电视剧',
 '纪录片',
 '👾0号:重要资源',
 '📚1号:书籍大礼包',
 '📼资料备份']

使用 remove 方法可以删除文件,参考 os.remove

>>> fs.remove("test.txt")
>>> fs.remove("file.py")
>>> fs.listdir()
['000阅读·乱七八糟',
 'libgen',
 '云下载',
 '电影',
 '电视剧',
 '纪录片',
 '👾0号:重要资源',
 '📚1号:书籍大礼包',
 '📼资料备份']

使用 rmtree 方法可以删除文件或文件夹,并且在删除文件夹时,也删除其中的文件和文件夹,参考 shutil.rmtree

>>> fs.makedirs("a/b/c/d")
'/115/a/b/c/d'
>>> fs.removedirs("a")
Traceback (most recent call last):
    ...
OSError: [Errno 66] directory not empty: '/115/a'
>>> fs.rmtree("a")

使用 rename 方法可以对文件或文件夹进行改名或移动,参考 os.rename

>>> fs.touch("a")
'/115/a'
>>> fs.attr("a")
{'id': '0/a',
 'name': 'a',
 'fullPathName': '/115/a',
 'fileType': 'File',
 'createTime': '2023-12-29T06:28:12.869507Z',
 'writeTime': '2023-12-29T06:28:12.869507Z',
 'accessTime': '2023-12-29T06:28:12.869507Z',
 'CloudAPI': {'name': '115', 'userName': '306576686', 'nickName': '306576686'},
 'isCloudFile': True,
 'hasDetailProperties': True,
 'canOfflineDownload': True,
 'path': '/115/a',
 'lastest_update': datetime.datetime(2023, 12, 29, 14, 28, 16, 470077)}
>>> fs.rename('a', 'b')
'/115/b'
>>> fs.attr("b")
{'id': '2800245724120349982',
 'name': 'b',
 'fullPathName': '/115/b',
 'fileType': 'File',
 'createTime': '2023-12-29T06:28:12.869507Z',
 'writeTime': '2023-12-29T06:28:12.869507Z',
 'accessTime': '2023-12-29T06:28:12.869507Z',
 'CloudAPI': {'name': '115', 'userName': '306576686', 'nickName': '306576686'},
 'isCloudFile': True,
 'hasDetailProperties': True,
 'canOfflineDownload': True,
 'fileHashes': {'2': 'da39a3ee5e6b4b0d3255bfef95601890afd80709'},
 'path': '/115/b',
 'lastest_update': datetime.datetime(2023, 12, 29, 14, 29, 18, 273151)}

说明:由于目前,CloudDrive 只在创建空文件夹后返回名字,而在上传和改名后,并不返回名字,而我目前也并不完全确定 CloudDrive 对于文件名规范化的完整逻辑,因此就直接返回用户传入的名字(而不进行半角转全角、清理后缀等)。如果你的名字里面可能有特殊符号,或者你不放心,就自行进行二次处理,参考 [^1]

使用 renames 方法可以对文件或文件夹进行改名或移动,并且在移动后如果原来所在目录为空,则会删除那个目录,参考 os.renames

使用 replace 方法可以对文件或文件夹进行改名或移动,并且如果原始路径上是文件,目标路径上也存在一个文件,则会先把目标路径上的文件删除,参考 os.replace

使用 move 方法可以对文件或文件夹进行改名或移动,目标路径存在且是一个目录,则把文件移动到其中(但是目录中有同名的文件或文件夹,还是会报错),参考 shutil.move

3. 遍历文件系统和查找文件

1. 获取当前目录下所有 .mkv 文件的 url

第 1 种方法,使用 iter,返回 clouddrive.CloudDrivePath 对象的迭代器

for path in fs.iter(max_depth=-1):
    if path.name.endswith(".mkv"):
        print(path.url)

第 2 种方法,使用 glob,参考 pathlib.Path.globglob.iglob,使用通配符查找

for path in fs.glob("**/*.mkv"):
    print(path.url)

第 3 种方法,使用 rglob,参考 pathlib.Path.rglob

for path in fs.rglob("*.mkv"):
    print(path.url)

4. 任务列表

CloudDrive 目前支持 2 种类型的任务,我分别进行了封装,大部分方法都支持异步调用 (async_=True)

  • clouddrive.CloudDriveDownloadTaskList 封装了 下载 的任务列表。
  • clouddrive.CloudDriveUploadTaskList 封装了 上传 的任务列表。
from clouddrive import CloudDriveClient

client = CloudDriveClient("http://localhost:19798", "test", "test@test")

# 获取各种任务列表
download_tasklist = client.download_tasklist
upload_tasklist = client.upload_tasklist

# 或者自己创建实例

# 创建 下载 任务列表实例
from clouddrive import CloudDriveDownloadTaskList
download_tasklist = CloudDriveDownloadTaskList(client)

# 创建 上传 任务列表实例
from clouddrive import CloudDriveUploadTaskList
upload_tasklist = CloudDriveUploadTaskList(client)

文档

正在编写中

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_clouddrive2-2.0.8.1.1.tar.gz (97.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_clouddrive2-2.0.8.1.1-py3-none-any.whl (90.6 kB view details)

Uploaded Python 3

File details

Details for the file python_clouddrive2-2.0.8.1.1.tar.gz.

File metadata

File hashes

Hashes for python_clouddrive2-2.0.8.1.1.tar.gz
Algorithm Hash digest
SHA256 bbdab185d9cd5bf01ca010cc789f4a216077c7624e07c273715f1e250c49da60
MD5 bb8d6f046b2186f56ee4543d5766fa2c
BLAKE2b-256 2aef8a324b84bfa203916a9282f803a5b2ec0eed65b0bda7f32568496c6fdd17

See more details on using hashes here.

File details

Details for the file python_clouddrive2-2.0.8.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for python_clouddrive2-2.0.8.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 32373dda7c6bd6a0b27870538d1d46e77c264b97e451e84e559ac284a29c3677
MD5 51bd67f5ddd7d172b4723cbc61ba0157
BLAKE2b-256 3c6c53d685dfc53490e4b57485042429184f8bf397dcc9b35465a5449f4ddde3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page