Compare commits
2 Commits
8ba20cbc56
...
f969912c08
Author | SHA1 | Date |
---|---|---|
pegasust | f969912c08 | |
pegasust | 7b5a6cfa94 |
|
@ -0,0 +1 @@
|
|||
__pycache__
|
|
@ -0,0 +1,101 @@
|
|||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.2"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"},
|
||||
{file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "23.1"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.2.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
|
||||
{file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.4.0"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
|
||||
{file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "1cf751550a88abe6c6ea8896fe41073f08488ebbd3fb959572a2038d4d944ebc"
|
|
@ -0,0 +1,20 @@
|
|||
[tool.poetry]
|
||||
name = "pixi"
|
||||
version = "0.0.1"
|
||||
description = "Toy project to investigate about apple photos synced iphone -> mac"
|
||||
authors = ["Pegasust <pegasucksgg@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pytest = "^7.3.1"
|
||||
|
||||
[[tool.poetry.packages]]
|
||||
include = "repl"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
REPL-friendly python mono-module for importing and execution singleton
|
||||
"""
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from itertools import groupby
|
||||
from typing import Iterable
|
||||
|
||||
mac_photos = os.getenv("MAC_PHOTOS_PATH", default="mac_photos")
|
||||
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class PhotosKExt:
|
||||
name: str
|
||||
parent: tuple[str, ...]
|
||||
exts_lowered: tuple[str, ...]
|
||||
|
||||
@classmethod
|
||||
def from_root_file(cls, root: str, filename: str):
|
||||
ext_elems = filename.split('.')
|
||||
return cls(
|
||||
name=ext_elems[0],
|
||||
parent=os.path.split(root),
|
||||
exts_lowered=tuple(
|
||||
ext.lower() for ext in ext_elems[1:]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class PhotosKey:
|
||||
filename: str
|
||||
parent: tuple[str, ...]
|
||||
|
||||
@classmethod
|
||||
def from_key_ext(cls, ext: PhotosKExt):
|
||||
return cls(filename=ext.name, parent=ext.parent)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class PhotosValue:
|
||||
exts: dict[str, list[str]]
|
||||
|
||||
def heic_paths(self) -> list[str]:
|
||||
return self.exts.get("heic", list())
|
||||
|
||||
def mov_paths(self) -> list[str]:
|
||||
return self.exts.get("mov", list())
|
||||
|
||||
|
||||
def candidate_exts(file_exts: Iterable[PhotosKExt]):
|
||||
"""
|
||||
>>> {ext: len(files)for ext, files in cexts.items()}
|
||||
stdout> {... 'mov': 2769, 'heic': 2354 ...}
|
||||
|
||||
We could make a bold guess that iPhone 11 stores both `heic` and `mov`
|
||||
for materialized best capture and live movie for live capture.
|
||||
"""
|
||||
exts_rv: dict[str, list[PhotosKExt]] = dict()
|
||||
|
||||
for file in file_exts:
|
||||
for ext in file.exts_lowered:
|
||||
exts_rv.setdefault(ext, list()).append(file)
|
||||
|
||||
return exts_rv
|
||||
|
||||
|
||||
def file_exts(photos_dir: str = mac_photos):
|
||||
return {
|
||||
PhotosKExt.from_root_file(filename=file, root=root)
|
||||
for root, _, files in os.walk(photos_dir, followlinks=True)
|
||||
for file in files
|
||||
}
|
||||
|
||||
|
||||
def photos_exts(files_with_ext: Iterable[PhotosKExt]):
|
||||
return {
|
||||
k: list(v)
|
||||
for k, v in groupby(files_with_ext, key=lambda x: (x.name, x.parent))
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
fexts = file_exts()
|
||||
cexts = candidate_exts(fexts)
|
||||
print(f"{photos_exts(fexts)=}")
|
||||
print(f"{cexts=}")
|
||||
|
||||
ext_counts = {ext: len(files)for ext, files in cexts.items()}
|
||||
print(ext_counts)
|
||||
# stdout>
|
||||
"""
|
||||
{'jpeg': 6023, 'mov': 2769, 'heic': 2354, 'thm': 197, 'png': 168, 'plist': 163,
|
||||
'log': 1, 'aae': 102, 'kgdb': 3, 'mp4': 26, 'data': 3, 'db': 3, 'xml': 26,
|
||||
'cmap': 2, 'plj': 16, 'kgdb-wal': 3, 'sqlite-shm': 11, 'cloudphotodb-wal': 1,
|
||||
'kgdb-shm': 3, '00001]': 1, 'frag': 2, 'ithmb': 3, 'sqlite': 15, 'lock': 1,
|
||||
'sqlite-wal': 11, 'aoi': 3, '0': 1,
|
||||
'm3u8-8f37dbfb-b3a6-4d52-beca-d17aaed01606': 2, 'jpg': 2, 'roi': 3, 'poi': 3,
|
||||
'db-shm': 1, 'm3u8-37f64716-0b2d-4a82-854a-5a6c78ce505a': 1, 'descriptor': 3,
|
||||
'bin': 2, 'm3u8': 5, 'cloudphotodb': 1, 'db-wal': 1, 'nature': 3,
|
||||
'm3u8-d8faad08-4fcc-4161-a600-1562d755c97b': 1, 'initfrag': 2, '20201]': 1,
|
||||
'cloudphotodb-shm': 1}
|
||||
"""
|
||||
|
||||
movs = cexts['mov']
|
||||
heics = cexts['heic']
|
||||
heic_name_set = {heic.name.lower() for heic in heics}
|
||||
mov_name_set = {mov.name.lower() for mov in movs}
|
||||
print(len(heic_name_set - mov_name_set) - len(heic_name_set))
|
||||
# stdout> (not 0)
|
||||
# Hence, we are not able to match `.heic` with its `.mov` with just names
|
||||
# Could it be that the `.heic` also contains the high-quality live?
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
24
flake.lock
24
flake.lock
|
@ -811,11 +811,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1689495092,
|
||||
"narHash": "sha256-yZu2j5FpLZEPhJQQutMCPTxa1VMigLPabLYvLTq6ASM=",
|
||||
"lastModified": 1690846837,
|
||||
"narHash": "sha256-ZZ8YPOEdZG0zz61U4sfUAx28oEdqLdtG1iWTTH/98uc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "2f84579a70b8c74e5ebb37299a0c3ba279f09382",
|
||||
"rev": "4fd794d3df88735dcf9662155d77b08a2e2dde29",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -1011,11 +1011,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1689479461,
|
||||
"narHash": "sha256-Ak+PTYdmfOQEmcOsOEnrwqdP0HP20PLraRwpjSAzSeE=",
|
||||
"lastModified": 1690687539,
|
||||
"narHash": "sha256-Lnwz9XKtshm+5OeWqCbj/3tKuKK+DL5tUTdKSRrKBlY=",
|
||||
"owner": "mic92",
|
||||
"repo": "nix-index-database",
|
||||
"rev": "22fa44b7f14684d184733fb26a628f3878ff7aaf",
|
||||
"rev": "d74b8171153ae35d7d323a9b1ad6c4cf7a995591",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -1168,11 +1168,11 @@
|
|||
},
|
||||
"nixpkgs-latest": {
|
||||
"locked": {
|
||||
"lastModified": 1689615243,
|
||||
"narHash": "sha256-FbR3tYDggqSekDd2Yv+t/mY6n1F+2JOCpYBB0HVH38M=",
|
||||
"lastModified": 1690872690,
|
||||
"narHash": "sha256-vrU9U97zVpq+H4qJ4iywYNmxGbK4Y0bN2Q/vUcgVrQE=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "14ef6934ca5cdf2a17c0dda30d4bf3d3e8ecff23",
|
||||
"rev": "714bd4a3e3cc6d97dea0c658942204ef4d66fce5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -1267,11 +1267,11 @@
|
|||
},
|
||||
"nixpkgs_11": {
|
||||
"locked": {
|
||||
"lastModified": 1689534811,
|
||||
"narHash": "sha256-jnSUdzD/414d94plCyNlvTJJtiTogTep6t7ZgIKIHiE=",
|
||||
"lastModified": 1690789960,
|
||||
"narHash": "sha256-3K+2HuyGTiJUSZNJxXXvc0qj4xFx1FHC/ItYtEa7/Xs=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6cee3b5893090b0f5f0a06b4cf42ca4e60e5d222",
|
||||
"rev": "fb942492b7accdee4e6d17f5447091c65897dde4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
cellBlocks = let
|
||||
inherit (std.blockTypes) devshells functions anything installables runnables;
|
||||
in [
|
||||
(installables "shells")
|
||||
(devshells "devshells")
|
||||
(devshells "userShells")
|
||||
(functions "home-profiles")
|
||||
|
@ -69,9 +70,12 @@
|
|||
];
|
||||
}
|
||||
{
|
||||
devShells = std.harvest self [["dotfiles" "devshells"]];
|
||||
devShells = std.harvest self [["dotfiles" "devshells"] ["dev" "shells"]];
|
||||
homeModules = std.pick self [["repo" "home-modules"]];
|
||||
packages = std.harvest self [["repo" "packages"]];
|
||||
packages = std.harvest self [
|
||||
["repo" "packages"]
|
||||
["dev" "packages"]
|
||||
];
|
||||
legacyPackages = std.harvest self [["repo" "home-configs"]];
|
||||
lib = std.pick self [["repo" "lib"]];
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/Users/hungtran/Pictures/Photos Library.photoslibrary
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
inputs,
|
||||
cell,
|
||||
}: let
|
||||
inherit (inputs.nixpkgs) system;
|
||||
poetry2nix = inputs.nix-boost.inputs.poetry2nix.legacyPackages.${system};
|
||||
|
||||
pixi-src = "${inputs.self}/dev/pixi";
|
||||
in {
|
||||
pixi-deps = poetry2nix.mkPoetryEnv {
|
||||
projectDir = pixi-src;
|
||||
editablePackageSources = {
|
||||
pixi = pixi-src;
|
||||
};
|
||||
};
|
||||
pixi-edit = poetry2nix.mkPoetryEditablePackage {
|
||||
projectDir = pixi-src;
|
||||
editablePackageSources = {
|
||||
pixi = pixi-src;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
inputs,
|
||||
cell,
|
||||
}: let
|
||||
inherit (inputs.nixpkgs) system;
|
||||
inherit (cell.packages) pixi-deps pixi-edit;
|
||||
in {
|
||||
pixi = inputs.nixpkgs.mkShell {
|
||||
buildInputs = [
|
||||
pixi-deps
|
||||
# pixi-edit
|
||||
inputs.std.packages.${system}.default
|
||||
];
|
||||
};
|
||||
}
|
|
@ -34,4 +34,6 @@ in {
|
|||
description = "Wrapper for keepassxc and keepassxc-cli with additional Darwin-specific fixes";
|
||||
};
|
||||
};
|
||||
|
||||
pixi-edit = inputs.cells.dev.packages.pixi-edit;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue