clouddrive


Nameclouddrive JSON
Version 0.0.11.2 PyPI version JSON
download
home_pagehttps://github.com/ChenyangGao/web-mount-packs/tree/main/python-wrap-clouddrive-web-api
SummaryPython wrapper for CloudDrive.
upload_time2024-04-19 17:08:25
maintainerNone
docs_urlNone
authorChenyangGao
requires_python<4.0,>=3.10
licenseMIT
keywords nas clouddrive
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # clouddrive web API 的 Python 封装

![PyPI - Python Version](https://img.shields.io/pypi/pyversions/clouddrive)
![PyPI - Version](https://img.shields.io/pypi/v/clouddrive)
![PyPI - Downloads](https://img.shields.io/pypi/dm/clouddrive)
![PyPI - Format](https://img.shields.io/pypi/format/clouddrive)
![PyPI - Status](https://img.shields.io/pypi/status/clouddrive)

## 安装

通过 [pypi](https://pypi.org/project/clouddrive/)

```console
pip install -U clouddrive
```

## 入门介绍

### 1. 导入模块和创建实例

**导入模块**

```python
from clouddrive import CloudDriveClient, CloudDriveFileSystem
```

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

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

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

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

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

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

>>> 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
```

**创建文件系统对象**

```python
fs = CloudDriveFileSystem(client)
```

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

```python
fs = client.fs
```

或者直接用 <kbd>CloudDriveFileSystem</kbd> 登录

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

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

文件系统对象的方法,设计和行为参考了 <kbd>[os](https://docs.python.org/3/library/os.html)</kbd>、<kbd>[posixpath](https://docs.python.org/3/library/os.path.html)</kbd>、<kbd>[pathlib.Path](https://docs.python.org/3/library/pathlib.html)</kbd> 和 <kbd>[shutil](https://docs.python.org/3/library/shutil.html)</kbd> 等模块。

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

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

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

```python
>>> fs.getcwd()
'/'
```

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

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

**使用** <kbd>chdir</kbd> **方法,切换当前工作目录,参考** <kbd>os.chdir</kbd>

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

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

```python
>>> 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)}]
```

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

```python
>>> 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/📼资料备份')>]
```

**再次使用** <kbd>chdir</kbd> **,进入一些目录**

```python
>>> 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']
```

**使用** <kbd>attr</kbd> **方法,获取文件或文件夹的属性** 

```python
>>> 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)}
```

**使用** <kbd>stat</kbd> **方法,获取文件或文件夹的部分,参考** <kbd>os.stat</kbd>

```python
>>> 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)
```

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

```python
>>> 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 个字符

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

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

```python
>>> f.close()
```

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

```python
>>> 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 个字节

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

再读取 10 个字节

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

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

```python
>>> f.tell()
20
```

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

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

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

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

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

```python
>>> fs.chdir("/")
```

**使用** <kbd>walk</kbd> **方法,可以遍历一个目录,参考** <kbd>os.walk</kbd>

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

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

```python
>>> 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` 下,继续做实验**

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

**使用** <kbd>mkdir</kbd> **方法,可以创建空文件夹,参考** <kbd>os.mkdir</kbd>

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

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

[^1]: 可以用下面 2 个帮助函数,来解释这一行为:
```python
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("/"))))
```

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

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

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

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

**使用** <kbd>rmdir</kbd> **方法,可以删除空文件夹,参考** <kbd>os.rmdir</kbd>

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

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

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

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

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

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

```python
>>> 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号:书籍大礼包',
 '📼资料备份']
```

**使用** <kbd>remove</kbd> **方法可以删除文件,参考** <kbd>os.remove</kbd>

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

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

```python
>>> 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")
```

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

```python
>>> 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)}
```

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

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

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

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

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

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

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

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

**第 2 种方法,使用** <kbd>glob</kbd>,参考 <kbd>pathlib.Path.glob</kbd> 和 <kbd>glob.iglob</kbd>,使用通配符查找

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

**第 3 种方法,使用** <kbd>rglob</kbd>,参考 <kbd>pathlib.Path.rglob</kbd>

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

### 4. 任务列表

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

- <kbd>clouddrive.CloudDriveDownloadTaskList</kbd> 封装了 `下载` 的任务列表。
- <kbd>clouddrive.CloudDriveUploadTaskList</kbd> 封装了 `上传` 的任务列表。

```python
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)
```

## 文档

> 正在编写中

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-wrap-clouddrive-web-api",
    "name": "clouddrive",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": null,
    "keywords": "nas, clouddrive",
    "author": "ChenyangGao",
    "author_email": "wosiwujm@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/39/6b/9f9f15016e90fa9b6733fd643f402f1cebb752cf19fb46b5e34626002ae3/clouddrive-0.0.11.2.tar.gz",
    "platform": null,
    "description": "# clouddrive web API \u7684 Python \u5c01\u88c5\n\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/clouddrive)\n![PyPI - Version](https://img.shields.io/pypi/v/clouddrive)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/clouddrive)\n![PyPI - Format](https://img.shields.io/pypi/format/clouddrive)\n![PyPI - Status](https://img.shields.io/pypi/status/clouddrive)\n\n## \u5b89\u88c5\n\n\u901a\u8fc7 [pypi](https://pypi.org/project/clouddrive/)\n\n```console\npip install -U clouddrive\n```\n\n## \u5165\u95e8\u4ecb\u7ecd\n\n### 1. \u5bfc\u5165\u6a21\u5757\u548c\u521b\u5efa\u5b9e\u4f8b\n\n**\u5bfc\u5165\u6a21\u5757**\n\n```python\nfrom clouddrive import CloudDriveClient, CloudDriveFileSystem\n```\n\n**\u521b\u5efa\u5ba2\u6237\u7aef\u5bf9\u8c61\uff0c\u767b\u5f55 <kbd>CloudDrive</kbd>\uff1a\u6b64\u5904\uff0c\u540e\u53f0\u670d\u52a1\u5730\u5740: `\"http://localhost:19798\"`\uff0c\u7528\u6237\u540d: `\"test\"`\uff0c\u5bc6\u7801: `\"test@test\"`**\n\n> \u8bf7\u786e\u4fdd <kbd>CloudDrive</kbd> \u5df2\u7ecf\u542f\u52a8\uff0c\u5e76\u4e14\u53ef\u901a\u8fc7 <kbd>http://localhost:19798</kbd> \u8bbf\u95ee\n\n```python\nclient = CloudDriveClient(\"http://localhost:19798\", \"test\", \"test@test\")\n```\n\n\u7edd\u5927\u90e8\u5206 <kbd>CloudDriveClient</kbd> \u7684\u65b9\u6cd5\u5e26\u6709 `async_` \u53c2\u6570\uff0c\u610f\u5473\u7740\u5b83\u652f\u6301\u5f02\u6b65 IO\u3002\n\n```python\n>>> import asyncio\n>>> loop = asyncio.get_event_loop()\n\n>>> from clouddrive import CloudDriveClient, CloudDriveFileSystem\n>>> client = CloudDriveClient(\"http://localhost:19798\", \"test\", \"test@test\")\n\n>>> import CloudDrive_pb2\n>>> client.FindFileByPath(CloudDrive_pb2.FindFileByPathRequest(path=\"/\"))\nid: \"60512951-88d8-4b5a-bea4-fbcb5d86ce6f\"\nname: \"/\"\nfullPathName: \"/\"\ncreateTime {\n  seconds: 1703821474\n  nanos: 152897000\n}\nwriteTime {\n  seconds: 1703821474\n  nanos: 152897000\n}\naccessTime {\n  seconds: 1703821474\n  nanos: 152897000\n}\nCloudAPI {\n  name: \"BaseFsApi\"\n}\nisDirectory: true\nisRoot: true\n\n>>> client.FindFileByPath(CloudDrive_pb2.FindFileByPathRequest(path=\"/\"), async_=True)\n<coroutine object UnaryUnaryMethod.__call__ at 0x107518f20>\n>>> loop.run_until_complete(client.FindFileByPath(CloudDrive_pb2.FindFileByPathRequest(path=\"/\"), async_=True))\nid: \"60512951-88d8-4b5a-bea4-fbcb5d86ce6f\"\nname: \"/\"\nfullPathName: \"/\"\ncreateTime {\n  seconds: 1703821474\n  nanos: 152897000\n}\nwriteTime {\n  seconds: 1703821474\n  nanos: 152897000\n}\naccessTime {\n  seconds: 1703821474\n  nanos: 152897000\n}\nCloudAPI {\n  name: \"BaseFsApi\"\n}\nisDirectory: true\nisRoot: true\n```\n\n**\u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61**\n\n```python\nfs = CloudDriveFileSystem(client)\n```\n\n\u6216\u8005\u76f4\u63a5\u5728 <kbd>client</kbd> \u4e0a\u5c31\u53ef\u83b7\u53d6\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\n\n```python\nfs = client.fs\n```\n\n\u6216\u8005\u76f4\u63a5\u7528 <kbd>CloudDriveFileSystem</kbd> \u767b\u5f55\n\n```python\nfs = CloudDriveFileSystem.login(\"http://localhost:19798\", \"test\", \"test@test\")\n```\n\n### 2. \u64cd\u4f5c\u7f51\u76d8\u4f7f\u7528 Python \u5f0f\u7684\u6587\u4ef6\u7cfb\u7edf\u65b9\u6cd5\n\n\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u65b9\u6cd5\uff0c\u8bbe\u8ba1\u548c\u884c\u4e3a\u53c2\u8003\u4e86 <kbd>[os](https://docs.python.org/3/library/os.html)</kbd>\u3001<kbd>[posixpath](https://docs.python.org/3/library/os.path.html)</kbd>\u3001<kbd>[pathlib.Path](https://docs.python.org/3/library/pathlib.html)</kbd> \u548c <kbd>[shutil](https://docs.python.org/3/library/shutil.html)</kbd> \u7b49\u6a21\u5757\u3002\n\n<kbd>clouddrive.CloudDriveFileSystem</kbd> \u5b9e\u73b0\u4e86\u8bfb\u5199\u7684\u6587\u4ef6\u7cfb\u7edf\u65b9\u6cd5\u3002\n\n<kbd>clouddrive.CloudDrivePath</kbd> \u5b9e\u73b0\u4e86\u4e8c\u6b21\u5c01\u88c5\uff0c\u4ece\u8def\u5f84\u7684\u89d2\u5ea6\u6765\u8fdb\u884c\u64cd\u4f5c\u3002\n\n**\u4f7f\u7528** <kbd>getcwd</kbd> **\u65b9\u6cd5\uff0c\u83b7\u53d6\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u7684\u8def\u5f84\uff0c\u53c2\u8003** <kbd>os.getcwd</kbd>\n\n```python\n>>> fs.getcwd()\n'/'\n```\n\n**\u4f7f\u7528** <kbd>listdir</kbd> **\u65b9\u6cd5\uff0c\u7f57\u5217\u5f53\u524d\u76ee\u5f55\u7684\u6587\u4ef6\u540d\uff0c\u53c2\u8003** <kbd>os.listdir</kbd>\n\n```python\n>>> fs.listdir()\n['115', '\u963f\u91cc\u4e91\u76d8Open']\n```\n\n**\u4f7f\u7528** <kbd>chdir</kbd> **\u65b9\u6cd5\uff0c\u5207\u6362\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\uff0c\u53c2\u8003** <kbd>os.chdir</kbd>\n\n```python\n>>> fs.chdir(\"/115\")\n```\n\n**\u4f7f\u7528** <kbd>listdir_attr</kbd> **\u65b9\u6cd5\uff0c\u7f57\u5217\u5f53\u524d\u76ee\u5f55\u65f6\uff0c\u8fd8\u53ef\u4ee5\u83b7\u53d6\u5c5e\u6027**\n\n```python\n>>> fs.listdir_attr()\n[{'id': '2592968610464922758',\n  'name': '000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n  'fullPathName': '/115/000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n  'createTime': '2023-03-18T06:45:45Z',\n  'writeTime': '2023-12-14T06:54:20Z',\n  'accessTime': '2023-12-14T06:54:20Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2644648816430546428',\n  'name': 'libgen',\n  'fullPathName': '/115/libgen',\n  'createTime': '2023-05-28T14:05:06Z',\n  'writeTime': '2023-12-14T06:54:20Z',\n  'accessTime': '2023-12-14T06:54:20Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/libgen',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2593093001609739968',\n  'name': '\u4e91\u4e0b\u8f7d',\n  'fullPathName': '/115/\u4e91\u4e0b\u8f7d',\n  'createTime': '2023-03-18T10:52:54Z',\n  'writeTime': '2023-12-16T13:58:22Z',\n  'accessTime': '2023-12-16T13:58:22Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/\u4e91\u4e0b\u8f7d',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2580587204111760961',\n  'name': '\u7535\u5f71',\n  'fullPathName': '/115/\u7535\u5f71',\n  'createTime': '2023-03-01T04:46:07Z',\n  'writeTime': '2023-12-14T06:54:20Z',\n  'accessTime': '2023-12-14T06:54:20Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/\u7535\u5f71',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2614100250469596984',\n  'name': '\u7535\u89c6\u5267',\n  'fullPathName': '/115/\u7535\u89c6\u5267',\n  'createTime': '2023-04-16T10:30:33Z',\n  'writeTime': '2023-12-23T14:26:17Z',\n  'accessTime': '2023-12-23T14:26:17Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/\u7535\u89c6\u5267',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2576930424647319247',\n  'name': '\u7eaa\u5f55\u7247',\n  'fullPathName': '/115/\u7eaa\u5f55\u7247',\n  'createTime': '2023-02-24T03:40:45Z',\n  'writeTime': '2023-12-18T10:49:29Z',\n  'accessTime': '2023-12-18T10:49:29Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/\u7eaa\u5f55\u7247',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2580131407544188592',\n  'name': '\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n  'fullPathName': '/115/\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n  'createTime': '2023-02-28T13:40:32Z',\n  'writeTime': '2023-12-14T06:54:20Z',\n  'accessTime': '2023-12-14T06:54:20Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2580246506904748007',\n  'name': '\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n  'fullPathName': '/115/\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n  'createTime': '2023-02-28T17:29:12Z',\n  'writeTime': '2023-12-14T06:54:20Z',\n  'accessTime': '2023-12-14T06:54:20Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)},\n {'id': '2673432528538303699',\n  'name': '\ud83d\udcfc\u8d44\u6599\u5907\u4efd',\n  'fullPathName': '/115/\ud83d\udcfc\u8d44\u6599\u5907\u4efd',\n  'createTime': '2023-07-07T07:13:12Z',\n  'writeTime': '2023-12-14T06:54:20Z',\n  'accessTime': '2023-12-14T06:54:20Z',\n  'CloudAPI': {'name': '115',\n   'userName': '306576686',\n   'nickName': '306576686'},\n  'isDirectory': True,\n  'isCloudDirectory': True,\n  'canSearch': True,\n  'hasDetailProperties': True,\n  'canOfflineDownload': True,\n  'path': '/115/\ud83d\udcfc\u8d44\u6599\u5907\u4efd',\n  'lastest_update': datetime.datetime(2023, 12, 29, 13, 14, 2, 172632)}]\n```\n\n**\u4f7f\u7528** <kbd>listdir_path</kbd> **\u65b9\u6cd5\uff0c\u7f57\u5217\u5f53\u524d\u76ee\u5f55\u65f6\uff0c\u8fd8\u53ef\u4ee5\u83b7\u53d6** <kbd>clouddrive.CloudDrivePath</kbd> **\u5bf9\u8c61**\n\n```python\n>>> fs.listdir_path()\n[<clouddrive.CloudDrivePath(id='2592968610464922758', name='000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf', fullPathName='/115/000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf', 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\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf')>,\n <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')>,\n <clouddrive.CloudDrivePath(id='2593093001609739968', name='\u4e91\u4e0b\u8f7d', fullPathName='/115/\u4e91\u4e0b\u8f7d', 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/\u4e91\u4e0b\u8f7d')>,\n <clouddrive.CloudDrivePath(id='2580587204111760961', name='\u7535\u5f71', fullPathName='/115/\u7535\u5f71', 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/\u7535\u5f71')>,\n <clouddrive.CloudDrivePath(id='2614100250469596984', name='\u7535\u89c6\u5267', fullPathName='/115/\u7535\u89c6\u5267', 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/\u7535\u89c6\u5267')>,\n <clouddrive.CloudDrivePath(id='2576930424647319247', name='\u7eaa\u5f55\u7247', fullPathName='/115/\u7eaa\u5f55\u7247', 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/\u7eaa\u5f55\u7247')>,\n <clouddrive.CloudDrivePath(id='2580131407544188592', name='\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90', fullPathName='/115/\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90', 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/\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90')>,\n <clouddrive.CloudDrivePath(id='2580246506904748007', name='\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305', fullPathName='/115/\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305', 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/\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305')>,\n <clouddrive.CloudDrivePath(id='2673432528538303699', name='\ud83d\udcfc\u8d44\u6599\u5907\u4efd', fullPathName='/115/\ud83d\udcfc\u8d44\u6599\u5907\u4efd', 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/\ud83d\udcfc\u8d44\u6599\u5907\u4efd')>]\n```\n\n**\u518d\u6b21\u4f7f\u7528** <kbd>chdir</kbd> **\uff0c\u8fdb\u5165\u4e00\u4e9b\u76ee\u5f55**\n\n```python\n>>> fs.chdir(\"\u7535\u89c6\u5267/\u6b27\u7f8e\u5267/A\")\n>>> fs.getcwd()\n'/115/\u7535\u89c6\u5267/\u6b27\u7f8e\u5267/A'\n>>> fs.listdir()\n['A\u300a\u7231\u3001\u6b7b\u4ea1\u548c\u673a\u5668\u4eba\u300b(Love.Death.and.Robot)[tt9561862]']\n>>> fs.chdir(\"A\u300a\u7231\u3001\u6b7b\u4ea1\u548c\u673a\u5668\u4eba\u300b(Love.Death.and.Robot)[tt9561862]/\u7231\u3001\u6b7b\u4ea1\u548c\u673a\u5668\u4ebaS01.Love.Death.and.Robots.1080p.NF.WEB-DL.DDP5.1.x264-NTG\uff0818\u96c6\uff09\")\n>>> fs.listdir()\n['Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.\u7b80\u4f53&\u82f1\u6587.ass', 'Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv']\n```\n\n**\u4f7f\u7528** <kbd>attr</kbd> **\u65b9\u6cd5\uff0c\u83b7\u53d6\u6587\u4ef6\u6216\u6587\u4ef6\u5939\u7684\u5c5e\u6027** \n\n```python\n>>> fs.attr(\"Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv\")\n{'id': '2576931481393823441',\n 'name': 'Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv',\n 'fullPathName': '/115/\u7535\u89c6\u5267/\u6b27\u7f8e\u5267/A/A\u300a\u7231\u3001\u6b7b\u4ea1\u548c\u673a\u5668\u4eba\u300b(Love.Death.and.Robot)[tt9561862]/\u7231\u3001\u6b7b\u4ea1\u548c\u673a\u5668\u4ebaS01.Love.Death.and.Robots.1080p.NF.WEB-DL.DDP5.1.x264-NTG\uff0818\u96c6\uff09/Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv',\n 'size': '924544482',\n 'fileType': 'File',\n 'createTime': '2023-02-24T03:42:51Z',\n 'writeTime': '2023-02-24T03:42:51Z',\n 'accessTime': '2023-02-24T03:42:51Z',\n 'CloudAPI': {'name': '115', 'userName': '306576686', 'nickName': '306576686'},\n 'isCloudFile': True,\n 'hasDetailProperties': True,\n 'canOfflineDownload': True,\n 'fileHashes': {'2': '7F4121B68A4E467ABF30A84627E20A8978895A4E'},\n 'path': '/115/\u7535\u89c6\u5267/\u6b27\u7f8e\u5267/A/A\u300a\u7231\u3001\u6b7b\u4ea1\u548c\u673a\u5668\u4eba\u300b(Love.Death.and.Robot)[tt9561862]/\u7231\u3001\u6b7b\u4ea1\u548c\u673a\u5668\u4ebaS01.Love.Death.and.Robots.1080p.NF.WEB-DL.DDP5.1.x264-NTG\uff0818\u96c6\uff09/Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv',\n 'lastest_update': datetime.datetime(2023, 12, 29, 13, 18, 27, 395024)}\n```\n\n**\u4f7f\u7528** <kbd>stat</kbd> **\u65b9\u6cd5\uff0c\u83b7\u53d6\u6587\u4ef6\u6216\u6587\u4ef6\u5939\u7684\u90e8\u5206\uff0c\u53c2\u8003** <kbd>os.stat</kbd>\n\n```python\n>>> fs.stat(\"Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv\")\nos.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)\n```\n\n**\u4f7f\u7528** <kbd>open</kbd> **\u65b9\u6cd5\uff0c\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff08\u76ee\u524d\u53ea\u652f\u6301\u8bfb\u53d6\uff0c\u4e0d\u652f\u6301\u5199\u5165\uff09\uff0c\u53c2\u8003** <kbd>open</kbd>\n\n```python\n>>> f = fs.open(\"Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.\u7b80\u4f53&\u82f1\u6587.ass\", encoding=\"UTF-16\")\n>>> f\n<_io.TextIOWrapper name='Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.\u7b80\u4f53&\u82f1\u6587.ass' encoding='UTF-16'>\n```\n\n\u8bfb\u53d6\u6b64\u6587\u4ef6\u7684\u524d 100 \u4e2a\u5b57\u7b26\n\n```python\n>>> f.read(100)\n'[Script Info]\\n;SrtEdit 6.3.2012.1001\\n;Copyright(C) 2005-2012 Yuan Weiguo\\n\\nTitle: YYeTs\\nOriginal Scri'\n```\n\n\u7528\u5b8c\u540e\u8bf7\u53ca\u65f6\u5173\u95ed\u6587\u4ef6\uff08\u5176\u5b9e\u4e0d\u4e3b\u52a8\u5173\u95ed\u4e5f\u53ef\u4ee5\uff0c\u53ea\u8981\u6587\u4ef6\u4e0d\u88ab\u5f15\u7528\uff0c\u5c31\u4f1a\u81ea\u52a8\u5173\u95ed\uff09\n\n```python\n>>> f.close()\n```\n\n**\u4ee5\u4e8c\u8fdb\u5236\u6a21\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u6b64\u65f6** `mode=\"rb\"`\n\n```python\n>>> f = fs.open(\"Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv\", \"rb\")\n>>> f\nclouddrive.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'}))\n```\n\n\u8bfb\u53d6\u524d 10 \u4e2a\u5b57\u8282\n\n```python\n>>> f.read(10)\nb'\\x1aE\\xdf\\xa3\\xa3B\\x86\\x81\\x01B'\n```\n\n\u518d\u8bfb\u53d6 10 \u4e2a\u5b57\u8282\n\n```python\n>>> f.read(10)\nb'\\xf7\\x81\\x01B\\xf2\\x81\\x04B\\xf3\\x81'\n```\n\n\u5f53\u524d\u6587\u4ef6\u504f\u79fb\u4f4d\u7f6e\uff08\u4ece 0 \u5f00\u59cb\u8ba1\u7b97\uff09\n\n```python\n>>> f.tell()\n20\n```\n\n\u628a\u8bfb\u53d6\u4f4d\u7f6e\u91cd\u65b0\u53d8\u4e3a\u6587\u4ef6\u5f00\u5934\n\n```python\n>>> f.seek(0)\n0\n>>> f.tell()\n0\n```\n\n\u518d\u6b21\u8bfb\u53d6 20 \u5b57\u8282\uff0c\u5e94\u8be5\u7b49\u4e8e\u4e0a\u9762\u4e24\u6b21\u7ed3\u679c\u7684\u62fc\u63a5\n\n```python\n>>> f.read(20)\nb'\\x1aE\\xdf\\xa3\\xa3B\\x86\\x81\\x01B\\xf7\\x81\\x01B\\xf2\\x81\\x04B\\xf3\\x81'\n>>> f.tell()\n20\n```\n\n**\u56de\u5230\u6839\u76ee\u5f55\uff0c\u6211\u4eec\u7ee7\u7eed\u5176\u5b83\u8bd5\u9a8c**\n\n```python\n>>> fs.chdir(\"/\")\n```\n\n**\u4f7f\u7528** <kbd>walk</kbd> **\u65b9\u6cd5\uff0c\u53ef\u4ee5\u904d\u5386\u4e00\u4e2a\u76ee\u5f55\uff0c\u53c2\u8003** <kbd>os.walk</kbd>\n\n```python\n>>> next(fs.walk())\n('/', ['115', '\u963f\u91cc\u4e91\u76d8'], [])\n```\n\n**\u4f7f\u7528** <kbd>walk_path</kbd> **\u65b9\u6cd5\uff0c\u53ef\u4ee5\u904d\u5386\u4e00\u4e2a\u76ee\u5f55\u65f6\uff0c\u83b7\u53d6** <kbd>clouddrive.CloudDrivePath</kbd> \u5bf9\u8c61\n\n```python\n>>> next(fs.walk_path())\n('/',\n [<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')>,\n  <clouddrive.CloudDrivePath(id='58188691_root', name='\u963f\u91cc\u4e91\u76d8Open', fullPathName='/\u963f\u91cc\u4e91\u76d8Open', createTime='2023-12-29T03:44:34.952368Z', writeTime='2023-12-29T03:44:34.952368Z', accessTime='2023-12-29T03:44:34.952368Z', CloudAPI={'name': '\u963f\u91cc\u4e91\u76d8Open', 'userName': '4d1769fb91ba4752ac417f77c1da8082', 'nickName': '\u8bf7\u8bbe\u7f6e\u6635\u79f0\uff1f'}, 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='/\u963f\u91cc\u4e91\u76d8Open')>],\n [])\n```\n\n**\u5728\u6839\u76ee\u5f55\u4e0b\u4e0d\u80fd\u521b\u5efa\u6587\u4ef6\uff0c\u56e0\u6b64\u8fdb\u5165 `/115` \u4e0b\uff0c\u7ee7\u7eed\u505a\u5b9e\u9a8c**\n\n```python\n>>> fs.chdir(\"/115\")\n```\n\n**\u4f7f\u7528** <kbd>mkdir</kbd> **\u65b9\u6cd5\uff0c\u53ef\u4ee5\u521b\u5efa\u7a7a\u6587\u4ef6\u5939\uff0c\u53c2\u8003** <kbd>os.mkdir</kbd>\n\n```python\n>>> fs.mkdir(\"test\")\n'/115/test'\n```\n\n<kbd>CloudDrive</kbd> \u4f1a\u5bf9\u6587\u4ef6\u540d\u8fdb\u884c\u4e00\u4e9b\u8f6c\u6362\uff0c\u4ee5\u786e\u4fdd\u5373\u4fbf\u5728 <kbd>Windows</kbd> \u4e0a\u6587\u4ef6\u540d\u4e5f\u662f\u6709\u6548\u7684\u3002\u4e00\u4e2a\u6bd4\u8f83\u5f7b\u5e95\u7684\u529e\u6cd5\u662f\uff0c\u540d\u5b57\u4e2d\u5982\u679c\u5305\u542b `*?:/\\<>|\"`\uff0c\u4f1a\u88ab\u8f6c\u6362\u6210\u5bf9\u5e94\u7684\u5168\u89d2\u5b57\u7b26 `\uff0a\uff1f\uff1a\uff0f\uff3c\uff1c\uff1e\uff5c\uff02`\uff0c\u5c3e\u90e8\u5982\u679c\u6709\u7a7a\u767d\u7b26\u53f7 <code> </code>(\u7a7a\u683c)`\\r\\n\\t\\v\\f\\xa0` \u548c \u70b9\u53f7 `.` \u4f1a\u88ab\u79fb\u9664\u3002\n\n[^1]: \u53ef\u4ee5\u7528\u4e0b\u9762 2 \u4e2a\u5e2e\u52a9\u51fd\u6570\uff0c\u6765\u89e3\u91ca\u8fd9\u4e00\u884c\u4e3a\uff1a\n```python\ndef normalize_name(\n    s: str, \n    /, \n    _transtab = {c: c + 65248 for c in b'*?:/\\\\<>|\"'}, \n) -> str:\n    return s.translate(_transtab).rstrip(\" \\r\\n\\v\\t\\f\\xa0.\")\n\ndef normalize_path(s: str, /) -> str:\n    return \"/\"[:s.startswith(\"/\")] + \"/\".join(filter(None, map(normalize_name, s.split(\"/\"))))\n```\n\n\u4e0d\u59a8\u521b\u5efa\u4e00\u4e2a\u540d\u5b57\u5f88\u7279\u6b8a\u7684\u6587\u4ef6\u5939\u8bd5\u4e00\u4e0b\n\n```python\n>>> fs.mkdir(\"*?:\\\\<>| \\r\\n\\v\\t\\f\\xa0.\")\n'/115/\uff0a\uff1f\uff1a\u300a\u300b\uff5c'\n```\n\n\u53ef\u4ee5\u770b\u5230\u8fd4\u56de\u7684\u540d\u5b57\u4e2d\uff0c\u534a\u89d2\u8f6c\u5168\u89d2\uff0c\u4e14\u5c3e\u90e8\u7a7a\u767d\u7b26\u53f7\u548c `.` \u90fd\u88ab\u79fb\u9664\u4e86\u3002\n\n```python\n>>> fs.listdir()\n['000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n 'libgen',\n 'test',\n '\u4e91\u4e0b\u8f7d',\n '\u7535\u5f71',\n '\u7535\u89c6\u5267',\n '\u7eaa\u5f55\u7247',\n '\uff0a\uff1f\uff1a\u300a\u300b\uff5c',\n '\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n '\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n '\ud83d\udcfc\u8d44\u6599\u5907\u4efd']\n```\n\n**\u4f7f\u7528** <kbd>rmdir</kbd> **\u65b9\u6cd5\uff0c\u53ef\u4ee5\u5220\u9664\u7a7a\u6587\u4ef6\u5939\uff0c\u53c2\u8003** <kbd>os.rmdir</kbd>\n\n```python\n>>> fs.rmdir('test')\n>>> fs.rmdir('\uff0a\uff1f\uff1a\u300a\u300b\uff5c')\n>>> fs.listdir()\n['000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n 'libgen',\n '\u4e91\u4e0b\u8f7d',\n '\u7535\u5f71',\n '\u7535\u89c6\u5267',\n '\u7eaa\u5f55\u7247',\n '\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n '\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n '\ud83d\udcfc\u8d44\u6599\u5907\u4efd']\n```\n\n**\u4f7f\u7528** <kbd>makedirs</kbd> **\u65b9\u6cd5\uff0c\u53ef\u4ee5\u521b\u5efa\u591a\u7ea7\u7684\u7a7a\u76ee\u5f55\uff0c\u53c2\u8003** <kbd>os.makedirs</kbd>\n\n```python\n>>> fs.makedirs(\"a/b/c/d\", exist_ok=True)\n'/115/a/b/c/d'\n>>> fs.listdir()\n['000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n 'a',\n 'libgen',\n '\u4e91\u4e0b\u8f7d',\n '\u7535\u5f71',\n '\u7535\u89c6\u5267',\n '\u7eaa\u5f55\u7247',\n '\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n '\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n '\ud83d\udcfc\u8d44\u6599\u5907\u4efd']\n```\n\n**\u4f7f\u7528** <kbd>removedirs</kbd> **\u65b9\u6cd5\uff0c\u53ef\u4ee5\uff08\u81ea\u5e95\u5411\u4e0a\u5730\uff09\u5220\u9664\u591a\u7ea7\u7684\u7a7a\u76ee\u5f55\uff0c\u53c2\u8003** <kbd>os.removedirs</kbd>\n\n```python\n>>> fs.removedirs(\"a/b/c/d\")\n>>> fs.listdir()\n['000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n 'libgen',\n '\u4e91\u4e0b\u8f7d',\n '\u7535\u5f71',\n '\u7535\u89c6\u5267',\n '\u7eaa\u5f55\u7247',\n '\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n '\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n '\ud83d\udcfc\u8d44\u6599\u5907\u4efd']\n```\n\n**\u4f7f\u7528** <kbd>upload</kbd> **\u65b9\u6cd5\u4e0a\u4f20\u6587\u4ef6\uff08\u63d0\u793a\uff1a\u6587\u4ef6\u53ea\u662f\u4e0a\u4f20\u5230 <kbd>CloudDrive</kbd> \u670d\u52a1\u5668\u4e0a\uff0c\u81f3\u4e8e <kbd>CloudDrive</kbd> \u4ec0\u4e48\u65f6\u5019\u4e0a\u4f20\u5b8c\u6210\uff0c\u5f97\u7b49\u5f85\uff09**\n\n```python\n>>> from io import BytesIO\n>>> fs.upload(BytesIO(b\"123\"), \"test.txt\")\n'/115/test.txt'\n>>> fs.read_text(\"test.txt\")\n'123'\n>>> fs.upload(\"file.py\")\n'/115/file.py'\n>>> fs.listdir()\n['000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n 'file.py',\n 'libgen',\n 'test.txt',\n '\u4e91\u4e0b\u8f7d',\n '\u7535\u5f71',\n '\u7535\u89c6\u5267',\n '\u7eaa\u5f55\u7247',\n '\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n '\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n '\ud83d\udcfc\u8d44\u6599\u5907\u4efd']\n```\n\n**\u4f7f\u7528** <kbd>remove</kbd> **\u65b9\u6cd5\u53ef\u4ee5\u5220\u9664\u6587\u4ef6\uff0c\u53c2\u8003** <kbd>os.remove</kbd>\n\n```python\n>>> fs.remove(\"test.txt\")\n>>> fs.remove(\"file.py\")\n>>> fs.listdir()\n['000\u9605\u8bfb\u00b7\u4e71\u4e03\u516b\u7cdf',\n 'libgen',\n '\u4e91\u4e0b\u8f7d',\n '\u7535\u5f71',\n '\u7535\u89c6\u5267',\n '\u7eaa\u5f55\u7247',\n '\ud83d\udc7e0\u53f7\uff1a\u91cd\u8981\u8d44\u6e90',\n '\ud83d\udcda1\u53f7\uff1a\u4e66\u7c4d\u5927\u793c\u5305',\n '\ud83d\udcfc\u8d44\u6599\u5907\u4efd']\n```\n\n**\u4f7f\u7528** <kbd>rmtree</kbd> **\u65b9\u6cd5\u53ef\u4ee5\u5220\u9664\u6587\u4ef6\u6216\u6587\u4ef6\u5939\uff0c\u5e76\u4e14\u5728\u5220\u9664\u6587\u4ef6\u5939\u65f6\uff0c\u4e5f\u5220\u9664\u5176\u4e2d\u7684\u6587\u4ef6\u548c\u6587\u4ef6\u5939\uff0c\u53c2\u8003** <kbd>shutil.rmtree</kbd>\n\n```python\n>>> fs.makedirs(\"a/b/c/d\")\n'/115/a/b/c/d'\n>>> fs.removedirs(\"a\")\nTraceback (most recent call last):\n    ...\nOSError: [Errno 66] directory not empty: '/115/a'\n>>> fs.rmtree(\"a\")\n```\n\n**\u4f7f\u7528** <kbd>rename</kbd> **\u65b9\u6cd5\u53ef\u4ee5\u5bf9\u6587\u4ef6\u6216\u6587\u4ef6\u5939\u8fdb\u884c\u6539\u540d\u6216\u79fb\u52a8\uff0c\u53c2\u8003** <kbd>os.rename</kbd>\n\n```python\n>>> fs.touch(\"a\")\n'/115/a'\n>>> fs.attr(\"a\")\n{'id': '0/a',\n 'name': 'a',\n 'fullPathName': '/115/a',\n 'fileType': 'File',\n 'createTime': '2023-12-29T06:28:12.869507Z',\n 'writeTime': '2023-12-29T06:28:12.869507Z',\n 'accessTime': '2023-12-29T06:28:12.869507Z',\n 'CloudAPI': {'name': '115', 'userName': '306576686', 'nickName': '306576686'},\n 'isCloudFile': True,\n 'hasDetailProperties': True,\n 'canOfflineDownload': True,\n 'path': '/115/a',\n 'lastest_update': datetime.datetime(2023, 12, 29, 14, 28, 16, 470077)}\n>>> fs.rename('a', 'b')\n'/115/b'\n>>> fs.attr(\"b\")\n{'id': '2800245724120349982',\n 'name': 'b',\n 'fullPathName': '/115/b',\n 'fileType': 'File',\n 'createTime': '2023-12-29T06:28:12.869507Z',\n 'writeTime': '2023-12-29T06:28:12.869507Z',\n 'accessTime': '2023-12-29T06:28:12.869507Z',\n 'CloudAPI': {'name': '115', 'userName': '306576686', 'nickName': '306576686'},\n 'isCloudFile': True,\n 'hasDetailProperties': True,\n 'canOfflineDownload': True,\n 'fileHashes': {'2': 'da39a3ee5e6b4b0d3255bfef95601890afd80709'},\n 'path': '/115/b',\n 'lastest_update': datetime.datetime(2023, 12, 29, 14, 29, 18, 273151)}\n```\n\n**\u8bf4\u660e**\uff1a\u7531\u4e8e\u76ee\u524d\uff0c<kbd>CloudDrive</kbd> \u53ea\u5728\u521b\u5efa\u7a7a\u6587\u4ef6\u5939\u540e\u8fd4\u56de\u540d\u5b57\uff0c\u800c\u5728\u4e0a\u4f20\u548c\u6539\u540d\u540e\uff0c\u5e76\u4e0d\u8fd4\u56de\u540d\u5b57\uff0c\u800c\u6211\u76ee\u524d\u4e5f\u5e76\u4e0d\u5b8c\u5168\u786e\u5b9a <kbd>CloudDrive</kbd> \u5bf9\u4e8e\u6587\u4ef6\u540d**\u89c4\u8303\u5316**\u7684\u5b8c\u6574\u903b\u8f91\uff0c\u56e0\u6b64\u5c31\u76f4\u63a5\u8fd4\u56de\u7528\u6237\u4f20\u5165\u7684\u540d\u5b57\uff08\u800c\u4e0d\u8fdb\u884c\u534a\u89d2\u8f6c\u5168\u89d2\u3001\u6e05\u7406\u540e\u7f00\u7b49\uff09\u3002\u5982\u679c\u4f60\u7684\u540d\u5b57\u91cc\u9762\u53ef\u80fd\u6709\u7279\u6b8a\u7b26\u53f7\uff0c\u6216\u8005\u4f60\u4e0d\u653e\u5fc3\uff0c\u5c31\u81ea\u884c\u8fdb\u884c\u4e8c\u6b21\u5904\u7406\uff0c\u53c2\u8003 [^1]\n\n**\u4f7f\u7528** <kbd>renames</kbd> **\u65b9\u6cd5\u53ef\u4ee5\u5bf9\u6587\u4ef6\u6216\u6587\u4ef6\u5939\u8fdb\u884c\u6539\u540d\u6216\u79fb\u52a8\uff0c\u5e76\u4e14\u5728\u79fb\u52a8\u540e\u5982\u679c\u539f\u6765\u6240\u5728\u76ee\u5f55\u4e3a\u7a7a\uff0c\u5219\u4f1a\u5220\u9664\u90a3\u4e2a\u76ee\u5f55\uff0c\u53c2\u8003** <kbd>os.renames</kbd>\n\n**\u4f7f\u7528** <kbd>replace</kbd> **\u65b9\u6cd5\u53ef\u4ee5\u5bf9\u6587\u4ef6\u6216\u6587\u4ef6\u5939\u8fdb\u884c\u6539\u540d\u6216\u79fb\u52a8\uff0c\u5e76\u4e14\u5982\u679c\u539f\u59cb\u8def\u5f84\u4e0a\u662f\u6587\u4ef6\uff0c\u76ee\u6807\u8def\u5f84\u4e0a\u4e5f\u5b58\u5728\u4e00\u4e2a\u6587\u4ef6\uff0c\u5219\u4f1a\u5148\u628a\u76ee\u6807\u8def\u5f84\u4e0a\u7684\u6587\u4ef6\u5220\u9664\uff0c\u53c2\u8003** <kbd>os.replace</kbd>\n\n**\u4f7f\u7528** <kbd>move</kbd> **\u65b9\u6cd5\u53ef\u4ee5\u5bf9\u6587\u4ef6\u6216\u6587\u4ef6\u5939\u8fdb\u884c\u6539\u540d\u6216\u79fb\u52a8\uff0c\u76ee\u6807\u8def\u5f84\u5b58\u5728\u4e14\u662f\u4e00\u4e2a\u76ee\u5f55\uff0c\u5219\u628a\u6587\u4ef6\u79fb\u52a8\u5230\u5176\u4e2d\uff08\u4f46\u662f\u76ee\u5f55\u4e2d\u6709\u540c\u540d\u7684\u6587\u4ef6\u6216\u6587\u4ef6\u5939\uff0c\u8fd8\u662f\u4f1a\u62a5\u9519\uff09\uff0c\u53c2\u8003** <kbd>shutil.move</kbd>\n\n### 3. \u904d\u5386\u6587\u4ef6\u7cfb\u7edf\u548c\u67e5\u627e\u6587\u4ef6\n\n#### 1. \u83b7\u53d6\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709 .mkv \u6587\u4ef6\u7684 url\n\n**\u7b2c 1 \u79cd\u65b9\u6cd5\uff0c\u4f7f\u7528** <kbd>iter</kbd>\uff0c\u8fd4\u56de <kbd>clouddrive.CloudDrivePath</kbd> \u5bf9\u8c61\u7684\u8fed\u4ee3\u5668\n\n```python\nfor path in fs.iter(max_depth=-1):\n    if path.name.endswith(\".mkv\"):\n        print(path.url)\n```\n\n**\u7b2c 2 \u79cd\u65b9\u6cd5\uff0c\u4f7f\u7528** <kbd>glob</kbd>\uff0c\u53c2\u8003 <kbd>pathlib.Path.glob</kbd> \u548c <kbd>glob.iglob</kbd>\uff0c\u4f7f\u7528\u901a\u914d\u7b26\u67e5\u627e\n\n```python\nfor path in fs.glob(\"**/*.mkv\"):\n    print(path.url)\n```\n\n**\u7b2c 3 \u79cd\u65b9\u6cd5\uff0c\u4f7f\u7528** <kbd>rglob</kbd>\uff0c\u53c2\u8003 <kbd>pathlib.Path.rglob</kbd>\n\n```python\nfor path in fs.rglob(\"*.mkv\"):\n    print(path.url)\n```\n\n### 4. \u4efb\u52a1\u5217\u8868\n\n<kbd>CloudDrive</kbd> \u76ee\u524d\u652f\u6301 `2` \u79cd\u7c7b\u578b\u7684\u4efb\u52a1\uff0c\u6211\u5206\u522b\u8fdb\u884c\u4e86\u5c01\u88c5\uff0c\u5927\u90e8\u5206\u65b9\u6cd5\u90fd\u652f\u6301\u5f02\u6b65\u8c03\u7528 (`async_=True`)\n\n- <kbd>clouddrive.CloudDriveDownloadTaskList</kbd> \u5c01\u88c5\u4e86 `\u4e0b\u8f7d` \u7684\u4efb\u52a1\u5217\u8868\u3002\n- <kbd>clouddrive.CloudDriveUploadTaskList</kbd> \u5c01\u88c5\u4e86 `\u4e0a\u4f20` \u7684\u4efb\u52a1\u5217\u8868\u3002\n\n```python\nfrom clouddrive import CloudDriveClient\n\nclient = CloudDriveClient(\"http://localhost:19798\", \"test\", \"test@test\")\n\n# \u83b7\u53d6\u5404\u79cd\u4efb\u52a1\u5217\u8868\ndownload_tasklist = client.download_tasklist\nupload_tasklist = client.upload_tasklist\n\n# \u6216\u8005\u81ea\u5df1\u521b\u5efa\u5b9e\u4f8b\n\n# \u521b\u5efa \u4e0b\u8f7d \u4efb\u52a1\u5217\u8868\u5b9e\u4f8b\nfrom clouddrive import CloudDriveDownloadTaskList\ndownload_tasklist = CloudDriveDownloadTaskList(client)\n\n# \u521b\u5efa \u4e0a\u4f20 \u4efb\u52a1\u5217\u8868\u5b9e\u4f8b\nfrom clouddrive import CloudDriveUploadTaskList\nupload_tasklist = CloudDriveUploadTaskList(client)\n```\n\n## \u6587\u6863\n\n> \u6b63\u5728\u7f16\u5199\u4e2d\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python wrapper for CloudDrive.",
    "version": "0.0.11.2",
    "project_urls": {
        "Homepage": "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-wrap-clouddrive-web-api",
        "Repository": "https://github.com/ChenyangGao/web-mount-packs/tree/main/python-wrap-clouddrive-web-api"
    },
    "split_keywords": [
        "nas",
        " clouddrive"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6e4c69e983523577ce15648ddf758a1015b0ccaf8effe801331df38b79b26956",
                "md5": "5ea5bd382d8e1d009d6f2964eace2bbd",
                "sha256": "6b2bf6bcdd978c0693d2aeecc875942910f620acc2721134dd7686046b149341"
            },
            "downloads": -1,
            "filename": "clouddrive-0.0.11.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5ea5bd382d8e1d009d6f2964eace2bbd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 102935,
            "upload_time": "2024-04-19T17:08:23",
            "upload_time_iso_8601": "2024-04-19T17:08:23.328761Z",
            "url": "https://files.pythonhosted.org/packages/6e/4c/69e983523577ce15648ddf758a1015b0ccaf8effe801331df38b79b26956/clouddrive-0.0.11.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "396b9f9f15016e90fa9b6733fd643f402f1cebb752cf19fb46b5e34626002ae3",
                "md5": "55259811d691d51e250bac67cadb46c4",
                "sha256": "8aa62049b1fee28a5aa6eb861a09e3c31d0214e46ac9aa67cdabfab842423de0"
            },
            "downloads": -1,
            "filename": "clouddrive-0.0.11.2.tar.gz",
            "has_sig": false,
            "md5_digest": "55259811d691d51e250bac67cadb46c4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 93626,
            "upload_time": "2024-04-19T17:08:25",
            "upload_time_iso_8601": "2024-04-19T17:08:25.399462Z",
            "url": "https://files.pythonhosted.org/packages/39/6b/9f9f15016e90fa9b6733fd643f402f1cebb752cf19fb46b5e34626002ae3/clouddrive-0.0.11.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-19 17:08:25",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ChenyangGao",
    "github_project": "web-mount-packs",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "clouddrive"
}
        
Elapsed time: 0.34060s