Skip to content

iLay1678/python-clouddrive2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 和 点号 . 会被移除。

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)

文档

正在编写中

Footnotes

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

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages