Skip to content

Commit

Permalink
Add pak to info result and merge file and url
Browse files Browse the repository at this point in the history
  • Loading branch information
AT0myks committed May 27, 2023
1 parent c426690 commit 2eefe1f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 44 deletions.
57 changes: 28 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
* [Requirements](#requirements)
* [Installation](#installation)
* [Usage](#usage)
* [Example](#example)
* [Notes](#notes)
* [Issues](#issues)

Expand Down Expand Up @@ -59,9 +58,36 @@ pip install reolinkfw
### Command line

```
reolinkfw info file_or_url
$ reolinkfw info file_or_url
```

Example:

```
$ reolinkfw info RLC-410-5MP_20_20052300.zip -i 2
[
{
"firmware_version_prefix": "v3.0.0",
"board_type": "IPC_51516M5M",
"board_name": "IPC_51516M5M",
"build_date": "200523",
"display_type_info": "RLC-410-5MP",
"detail_machine_type": "IPC_51516M5M",
"type": "IPC",
"version_file": "20_20052300",
"sha256": "6ef371a51b61d7b21d8f7016d90b5fc1ed3eaa8a3f30f1e202a3474bfb4807e5",
"file": "RLC-410-5MP_20_20052300.zip",
"pak": "IPC_51516M5M.20_20052300.RLC-410-5MP.OV05A10.5MP.REOLINK.pak"
}
]
```

`file` is the given argument, a file or URL. The value of `pak` depends on the
argument. If it's a local or remote ZIP file it will be the path of the PAK file
inside it. If it's a remote PAK file, it will be the value of the `name` query
parameter or `None` if not found. And finally for a local PAK file it will be
file name.

### As a library

```py
Expand All @@ -80,33 +106,6 @@ These URLs are automatically handled so that you don't have to figure out the "r

However the Google Drive folder links (`drive.google.com/drive/folders`) are not handled and in these cases you must find the real URL, or you can also download the file.

## Example

The command

```
reolinkfw info RLC-410-5MP_20_20052300.zip -i 2
```

will give something like this:

```json
[
{
"firmware_version_prefix": "v3.0.0",
"board_type": "IPC_51516M5M",
"board_name": "IPC_51516M5M",
"build_date": "200523",
"display_type_info": "RLC-410-5MP",
"detail_machine_type": "IPC_51516M5M",
"type": "IPC",
"version_file": "20_20052300",
"sha256": "6ef371a51b61d7b21d8f7016d90b5fc1ed3eaa8a3f30f1e202a3474bfb4807e5",
"file": "RLC-410-5MP_20_20052300.zip"
}
]
```

## Notes

There are at least 3 types of file systems used for Reolink firmwares:
Expand Down
29 changes: 15 additions & 14 deletions reolinkfw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io
import re
from pathlib import Path, PurePosixPath
from urllib.parse import parse_qsl, urlparse
from zipfile import ZipFile, is_zipfile

import aiohttp
Expand Down Expand Up @@ -55,15 +56,15 @@ def extract_fs(pakbytes):
return "No section found"


def extract_paks(zip):
"""Return a list of unique PAK files found in the ZIP."""
paks = set()
def extract_paks(zip) -> list[tuple[str, bytes]]:
"""Return a list of tuples, one for each PAK file found in the ZIP."""
paks = []
with ZipFile(zip) as myzip:
for name in myzip.namelist():
with myzip.open(name) as file:
if is_pak(file):
paks.add(myzip.read(name))
return sorted(paks) # Always return in the same order.
paks.append((file.name, myzip.read(name)))
return paks


def get_info_from_files(files):
Expand Down Expand Up @@ -192,30 +193,30 @@ async def get_info(file_or_url):
The file or resource may be a ZIP or a PAK.
"""
if is_url(file_or_url):
type_ = "url"
file_or_url = await direct_download_url(file_or_url)
zip_or_pak_bytes = await download(file_or_url)
if isinstance(zip_or_pak_bytes, int):
return [{type_: file_or_url, "error": zip_or_pak_bytes}]
return [{"file": file_or_url, "error": zip_or_pak_bytes}]
elif is_pak(zip_or_pak_bytes):
paks = [zip_or_pak_bytes]
pakname = dict(parse_qsl(urlparse(file_or_url).query)).get("name")
paks = [(pakname, zip_or_pak_bytes)]
else:
with io.BytesIO(zip_or_pak_bytes) as f:
if is_zipfile(f):
paks = await asyncio.to_thread(extract_paks, f)
else:
return [{type_: file_or_url, "error": "Not a ZIP or a PAK file"}]
return [{"file": file_or_url, "error": "Not a ZIP or a PAK file"}]
elif is_local_file(file_or_url):
type_ = "file"
file_or_url = Path(file_or_url)
if is_zipfile(file_or_url):
paks = await asyncio.to_thread(extract_paks, file_or_url)
elif is_pak(file_or_url):
with open(file_or_url, "rb") as f:
paks = [f.read()]
paks = [(file_or_url.name, f.read())]
else:
return [{type_: file_or_url, "error": "Not a ZIP or a PAK file"}]
return [{"file": file_or_url, "error": "Not a ZIP or a PAK file"}]
else:
return [{"arg": file_or_url, "error": "Not a URL or file"}]
if not paks:
return [{type_: file_or_url, "error": "no PAKs found in ZIP file"}]
return [{**await get_info_from_pak(pak), type_: file_or_url} for pak in paks]
return [{"file": file_or_url, "error": "no PAKs found in ZIP file"}]
return [{**await get_info_from_pak(pakbytes), "file": file_or_url, "pak": pakname} for pakname, pakbytes in paks]
2 changes: 1 addition & 1 deletion reolinkfw/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

def info(args):
info = asyncio.run(get_info(args.file_or_url))
print(json.dumps(info, indent=args.indent))
print(json.dumps(info, indent=args.indent, default=str))


def main():
Expand Down

0 comments on commit 2eefe1f

Please sign in to comment.