尤其是家庭环境下,同一个照片会存在好几个设备中,每次备份会产生大量的重复照片和合并冲突(重名文件),同时,
同一个照片进行复制,传输,移动等操作后,其文件属性时间会被修改或丢失,
大部分图片处理工具会将最新的修改时间作为照片创建日期,最终的结果就是多年前拍的照片被放在了今年的目录中。
这个工具将获取所有的文件时间信息,并取最早时间作为照片的创建日期,进行分类处理,同时确保对同一文件的每次处理结果都保持一致。
日期数据来自于 文件元数据 和 文件属性 看到的时间,并取最早时间作为最终结果。
基于该工具,当前我的照片备份方案
graph LR
A[手机/电脑/平板等设备] --> B{同步}
B -->|自动| C[NAS服务器]
C --> D[挂载到电脑]
D --> E[ALL_PHOTOS
├── PhoneA
├── PhoneB
├── Others.]
B -->|手动| F[增量同步到电脑<br>(如 FreeFileSync)]
F --> E
E --> G[增量处理<br>mmfplace place -i ALL_PHOTOS -o 备份磁盘]
G --> H[备份磁盘]
经过几次的实际验证和优化,已经帮我处理了超过10W+照片(处理完大概300G) 🎉
整理之前的目录:
❯ tree tests
tests
├── 10x12x16bit-CMYK.psd
├── 16color-10x10.bmp
├── 24bpp-10x10.bmp
├── 256color-10x10.bmp
├── 8x4x8bit-Grayscale.eps
├── 8x4x8bit-Grayscale.psd
├── adobeJpeg1.eps
├── adobeJpeg1.jpg
├── adobeJpeg1.jpg.app2
├── crash01.jpg
├── dotnet-256x256-alpha-palette.png
├── gimp-8x12-greyscale-alpha-time-background.png
├── iccDataInvalid1.jpg.app2
├── invalid-iCCP-missing-adler32-checksum.png
├── manuallyAddedThumbnail.jpg
├── mspaint-10x10.gif
├── mspaint-8x10.png
├── nikonMakernoteType1.jpg
├── nikonMakernoteType2b.jpg
...
整理之后的目录:
❯ tree tests_output
├── 1996
│ ├── 11
│ │ ├── withuncompressedycbcrthumbnail3.jpg
│ │ └── withuncompressedycbcrthumbnail.jpg
│ └── 12
│ └── withuncompressedycbcrthumbnail2.jpg
├── 2000
│ ├── 01
│ │ └── withiptc.jpg
│ └── 10
│ └── withuncompressedrgbthumbnail.jpg
├── 2001
│ ├── 01
│ │ └── withexif.jpg
│ └── 04
│ └── nikonmakernotetype1.jpg
├── 2002
│ ├── 05
│ │ └── crash01.jpg
│ ├── 06
│ │ └── withiptcexifgps.jpg
│ ├── 08
│ │ └── nikonmakernotetype2b.jpg
│ └── 11
│ ├── manuallyaddedthumbnail.jpg
│ ├── simple.jpg
│ └── simple.png
├── 2003
│ └── 11
│ └── adobejpeg1.jpg
├── 2004
│ └── 04
│ └── windowsxpfields.jpg
├── 2010
│ └── 06
│ └── withpanasonicfaces.jpg
├── 2012
│ ├── 05
│ │ ├── 10x12x16bit-cmyk.psd
│ │ └── 8x4x8bit-grayscale.psd
│ └── 12
│ └── photoshop-8x12-rgb24-all-metadata.png
├── 2013
│ └── 01
│ └── gimp-8x12-greyscale-alpha-time-background.png
...默认情况下文件会复制到 %Y/%m/xxx 并会保留原始文件名, 如 simple.jpg -> 2002/11/simple.jpg
可以通过参数 --rename-with-ymd 将文件重命名,如 simple.jpg -> 2025/11/2025-11-16.jpg
❯ tree tests_output
├── 1996
│ ├── 11
│ │ ├── 1996-11-04.jpg
│ │ └── 1996-11-10.jpg
│ └── 12
│ └── 1996-12-20.jpg
├── 2000
│ ├── 01
│ │ └── 2000-01-01.jpg
│ └── 10
│ └── 2000-10-26.jpg
├── 2001
│ ├── 01
│ │ └── 2001-01-28.jpg
│ └── 04
│ └── 2001-04-06.jpg
├── 2002
│ ├── 05
│ │ └── 2002-05-08.jpg
│ ├── 06
│ │ └── 2002-06-20.jpg
│ ├── 08
│ │ └── 2002-08-29.jpg
│ └── 11
│ ├── 2002-11-16.jpg
│ ├── 2002-11-16_01.jpg
│ └── 2002-11-27.jpg
├── 2003
│ └── 11
│ └── 2003-11-17.jpg
├── 2004
...release 直接下载二进制文件
或者本地构建
cd builder
cargo build -- release或者采用交叉编译
╰─ ./xbuild
1) x86_64-unknown-linux-musl
2) aarch64-unknown-linux-musl
3) x86_64-apple-darwin
4) aarch64-apple-darwin
5) x86_64-pc-windows-gnu
选择目标平台的编号:交叉编译后的文件存放在 dist 文件夹
╰─ tree dist
dist
├── mmfplace.aarch64-apple-darwin.tar.gz
├── mmfplace.aarch64-unknown-linux-musl.tar.gz
├── mmfplace.x86_64-apple-darwin.tar.gz
├── mmfplace.x86_64-pc-windows-gnu.tar.gz
└── mmfplace.x86_64-unknown-linux-musl.tar.gz如果在主机运行,使用前请确保系统中已经安装 java 运行环境,当前测试基于 java-11 环境,其他版本请自行验证。
程序执行后会在同级目录下释放必要的依赖文件(请勿删除)
├── config.toml # 配置文件,可配置并发数、java路径、数据库路径以及解析规则
├── mmfplace.exe # 主程序
├── place.db # 同步数据库,请勿删除,否则无法实现增量同步
└── tools # 依赖工具包
├── metadata-extractor-2.19.0.jar
└── xmpcore-6.1.11.jar可运行多次测试样例查看处理结果是否一致
> rm place.db
> mmfplace.exe place -i .\tests -o .\tests.output1
> rm place.db
> mmfplace.exe place -i .\tests -o .\tests.output2
> diff -r .\tests.output1 .\tests.output2执行测试样例完整的日志
> mmfplace.exe place -i .\tests -o .\tests.output -l .\log.ansi
2025-04-01T07:43:13.004857Z INFO place::process: start process input=".\\tests" total=53 output=".\\tests.output" test=false
2025-04-01T07:43:13.005258Z WARN config: 🚨 The first run creates a default config file at D:\Working\MySpace\mmfplace\dist\config.toml
2025-04-01T07:43:13.023632Z INFO place::db: Loading database once path=".\\place.db"
2025-04-01T07:43:13.369426Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2001:04:06 11:51:40" datetime=2001-04-06 00:00:00 UTC
2025-04-01T07:43:13.369753Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2001:04:06 11:51:40" datetime=2001-04-06 00:00:00 UTC
2025-04-01T07:43:13.369907Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2001:04:06 11:51:40" datetime=2001-04-06 00:00:00 UTC
2025-04-01T07:43:13.370417Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.372684Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2001\\04\\nikonmakernotetype1.jpg" earliest=Some(2001-04-06T08:00:00+08:00)
2025-04-01T07:43:13.378306Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.378383Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 1996:11:04 14:55:52" datetime=1996-11-04 00:00:00 UTC
2025-04-01T07:43:13.378487Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2001:01:28 13:59:33" datetime=2001-01-28 00:00:00 UTC
2025-04-01T07:43:13.378627Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.378705Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2001:01:28 13:59:33" datetime=2001-01-28 00:00:00 UTC
2025-04-01T07:43:13.378828Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2001:01:28 13:59:33" datetime=2001-01-28 00:00:00 UTC
2025-04-01T07:43:13.378899Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\1996\\11\\withuncompressedycbcrthumbnail3.jpg" earliest=Some(1996-11-04T08:00:00+08:00)
2025-04-01T07:43:13.379060Z INFO place::process: 🎉 success parse datetime from text text="[Exif Thumbnail] Date/Time = 2001:01:28 13:59:33" datetime=2001-01-28 00:00:00 UTC
2025-04-01T07:43:13.379228Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2001\\01\\withexif.jpg" earliest=Some(2001-01-28T08:00:00+08:00)
2025-04-01T07:43:13.382652Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2001\\04\\nikonmakernotetype1.jpg"
2025-04-01T07:43:13.385636Z INFO place::process: ✅ [1/53] success place with new parsed finish from=".\\tests\\2001\\04\\nikonmakernotetype1.jpg" to=".\\tests.output\\2001\\04\\nikonmakernotetype1.jpg"
2025-04-01T07:43:13.388927Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2002:08:29 17:31:40" datetime=2002-08-29 00:00:00 UTC
2025-04-01T07:43:13.389069Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.389194Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2002:08:29 17:31:40" datetime=2002-08-29 00:00:00 UTC
2025-04-01T07:43:13.389271Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.389347Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2002:05:08 17:28:03" datetime=2002-05-08 00:00:00 UTC
2025-04-01T07:43:13.389429Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.389499Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.389574Z INFO place::process: 🎉 success parse datetime from text text="[IPTC] Date Created = 2000:01:01" datetime=2000-01-01 00:00:00 UTC
2025-04-01T07:43:13.389666Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2002:05:08 17:28:03" datetime=2002-05-08 00:00:00 UTC
2025-04-01T07:43:13.389749Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 1996:11:10 20:59:21" datetime=1996-11-10 00:00:00 UTC
2025-04-01T07:43:13.389815Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2002:08:29 17:31:40" datetime=2002-08-29 00:00:00 UTC
2025-04-01T07:43:13.389879Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\1996\\11\\withuncompressedycbcrthumbnail.jpg" earliest=Some(1996-11-10T08:00:00+08:00)
2025-04-01T07:43:13.389978Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2002\\05\\crash01.jpg" earliest=Some(2002-05-08T08:00:00+08:00)
2025-04-01T07:43:13.390067Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2000\\01\\withiptc.jpg" earliest=Some(2000-01-01T08:00:00+08:00)
2025-04-01T07:43:13.390153Z INFO place::process: 🎉 success parse datetime from text text="Aufnahmedatum : 2002/08/29 17:31:40" datetime=2002-08-29 00:00:00 UTC
2025-04-01T07:43:13.390382Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2002\\08\\nikonmakernotetype2b.jpg" earliest=Some(2002-08-29T08:00:00+08:00)
2025-04-01T07:43:13.392656Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\1996\\11\\withuncompressedycbcrthumbnail3.jpg"
2025-04-01T07:43:13.393703Z INFO place::process: ✅ [2/53] success place with new parsed finish from=".\\tests\\1996\\11\\withuncompressedycbcrthumbnail3.jpg" to=".\\tests.output\\1996\\11\\withuncompressedycbcrthumbnail3.jpg"
2025-04-01T07:43:13.400550Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2001\\01\\withexif.jpg"
2025-04-01T07:43:13.401542Z INFO place::process: ✅ [3/53] success place with new parsed finish from=".\\tests\\2001\\01\\withexif.jpg" to=".\\tests.output\\2001\\01\\withexif.jpg"
2025-04-01T07:43:13.404043Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.404169Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.404252Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 1996:12:20 18:32:02" datetime=1996-12-20 00:00:00 UTC
2025-04-01T07:43:13.404369Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2000:10:26 16:46:51" datetime=2000-10-26 00:00:00 UTC
2025-04-01T07:43:13.404541Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\1996\\12\\withuncompressedycbcrthumbnail2.jpg" earliest=Some(1996-12-20T08:00:00+08:00)
2025-04-01T07:43:13.404626Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2000\\10\\withuncompressedrgbthumbnail.jpg" earliest=Some(2000-10-26T08:00:00+08:00)
2025-04-01T07:43:13.408511Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\1996\\11\\withuncompressedycbcrthumbnail.jpg"
2025-04-01T07:43:13.409209Z INFO place::process: ✅ [4/53] success place with new parsed finish from=".\\tests\\1996\\11\\withuncompressedycbcrthumbnail.jpg" to=".\\tests.output\\1996\\11\\withuncompressedycbcrthumbnail.jpg"
2025-04-01T07:43:13.416414Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2002\\05\\crash01.jpg"
2025-04-01T07:43:13.417497Z INFO place::process: ✅ [5/53] success place with new parsed finish from=".\\tests\\2002\\05\\crash01.jpg" to=".\\tests.output\\2002\\05\\crash01.jpg"
2025-04-01T07:43:13.425287Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2000\\01\\withiptc.jpg"
2025-04-01T07:43:13.426702Z INFO place::process: ✅ [6/53] success place with new parsed finish from=".\\tests\\2000\\01\\withiptc.jpg" to=".\\tests.output\\2000\\01\\withiptc.jpg"
2025-04-01T07:43:13.434880Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2002\\08\\nikonmakernotetype2b.jpg"
2025-04-01T07:43:13.436917Z INFO place::process: ✅ [7/53] success place with new parsed finish from=".\\tests\\2002\\08\\nikonmakernotetype2b.jpg" to=".\\tests.output\\2002\\08\\nikonmakernotetype2b.jpg"
2025-04-01T07:43:13.445207Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\1996\\12\\withuncompressedycbcrthumbnail2.jpg"
2025-04-01T07:43:13.446709Z INFO place::process: ✅ [8/53] success place with new parsed finish from=".\\tests\\1996\\12\\withuncompressedycbcrthumbnail2.jpg" to=".\\tests.output\\1996\\12\\withuncompressedycbcrthumbnail2.jpg"
2025-04-01T07:43:13.453925Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2000\\10\\withuncompressedrgbthumbnail.jpg"
2025-04-01T07:43:13.454952Z INFO place::process: ✅ [9/53] success place with new parsed finish from=".\\tests\\2000\\10\\withuncompressedrgbthumbnail.jpg" to=".\\tests.output\\2000\\10\\withuncompressedrgbthumbnail.jpg"
2025-04-01T07:43:13.484650Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2002:07:13 15:58:28" datetime=2002-07-13 00:00:00 UTC
2025-04-01T07:43:13.484793Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.484961Z INFO place::process: 🎉 success parse datetime from text text="[IPTC] Date Created = 2002:06:20" datetime=2002-06-20 00:00:00 UTC
2025-04-01T07:43:13.485277Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2002:07:19 13:28:10" datetime=2002-07-19 00:00:00 UTC
2025-04-01T07:43:13.485470Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2002:07:13 15:58:28" datetime=2002-07-13 00:00:00 UTC
2025-04-01T07:43:13.485659Z INFO place::process: 🎉 success parse datetime from text text="[XMP] photoshop:DateCreated = 2002-06-20" datetime=2002-06-20 00:00:00 UTC
2025-04-01T07:43:13.485815Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2002\\06\\withiptcexifgps.jpg" earliest=Some(2002-06-20T08:00:00+08:00)
2025-04-01T07:43:13.495270Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2002\\06\\withiptcexifgps.jpg"
2025-04-01T07:43:13.496512Z INFO place::process: ✅ [10/53] success place with new parsed finish from=".\\tests\\2002\\06\\withiptcexifgps.jpg" to=".\\tests.output\\2002\\06\\withiptcexifgps.jpg"
2025-04-01T07:43:13.659682Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2002:11:27 18:00:35" datetime=2002-11-27 00:00:00 UTC
2025-04-01T07:43:13.659953Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.660336Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2002\\11\\manuallyaddedthumbnail.jpg" earliest=Some(2002-11-27T08:00:00+08:00)
2025-04-01T07:43:13.668676Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2002\\11\\manuallyaddedthumbnail.jpg"
2025-04-01T07:43:13.669981Z INFO place::process: ✅ [11/53] success place with new parsed finish from=".\\tests\\2002\\11\\manuallyaddedthumbnail.jpg" to=".\\tests.output\\2002\\11\\manuallyaddedthumbnail.jpg"
2025-04-01T07:43:13.670741Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2002:11:16 15:27:01" datetime=2002-11-16 00:00:00 UTC
2025-04-01T07:43:13.671778Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2002:11:16 15:27:01" datetime=2002-11-16 00:00:00 UTC
2025-04-01T07:43:13.672214Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2002:11:18 22:46:09" datetime=2002-11-18 00:00:00 UTC
2025-04-01T07:43:13.672667Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.672766Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.673387Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2002:11:16 15:27:01" datetime=2002-11-16 00:00:00 UTC
2025-04-01T07:43:13.673514Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2002:11:16 15:27:01" datetime=2002-11-16 00:00:00 UTC
2025-04-01T07:43:13.673747Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2002\\11\\simple.png" earliest=Some(2002-11-16T08:00:00+08:00)
2025-04-01T07:43:13.675763Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2002:11:18 22:46:09" datetime=2002-11-18 00:00:00 UTC
2025-04-01T07:43:13.676618Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2002\\11\\simple.jpg" earliest=Some(2002-11-16T08:00:00+08:00)
2025-04-01T07:43:13.681492Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2002\\11\\simple.jpg"
2025-04-01T07:43:13.682549Z INFO place::process: ✅ [12/53] success place with new parsed finish from=".\\tests\\2002\\11\\simple.png" to=".\\tests.output\\2002\\11\\simple.jpg"
2025-04-01T07:43:13.683271Z INFO place::process: same hash file found, compare the time and overwrite it current=["2002", "11", "simple_01.jpg"] history=["2002", "11", "simple.jpg"]
2025-04-01T07:43:13.683552Z INFO place::process: ✅ [13/53] success place (>=history) finish from=".\\tests\\2002\\11\\simple.jpg" to=".\\tests.output\\2002\\11\\simple_01.jpg"
2025-04-01T07:43:13.709007Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2010:06:24 14:17:04" datetime=2010-06-24 00:00:00 UTC
2025-04-01T07:43:13.710847Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.713356Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2010:06:24 14:17:04" datetime=2010-06-24 00:00:00 UTC
2025-04-01T07:43:13.714425Z INFO place::process: 🎉 success parse datetime from text text="[GPS] GPS Date Stamp = 2010:06:24" datetime=2010-06-24 00:00:00 UTC
2025-04-01T07:43:13.715093Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2010:06:24 14:17:04" datetime=2010-06-24 00:00:00 UTC
2025-04-01T07:43:13.715338Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2010\\06\\withpanasonicfaces.jpg" earliest=Some(2010-06-24T08:00:00+08:00)
2025-04-01T07:43:13.723711Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2010\\06\\withpanasonicfaces.jpg"
2025-04-01T07:43:13.725427Z INFO place::process: ✅ [14/53] success place with new parsed finish from=".\\tests\\2010\\06\\withpanasonicfaces.jpg" to=".\\tests.output\\2010\\06\\withpanasonicfaces.jpg"
2025-04-01T07:43:13.757622Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.758190Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2004:04:05 08:09:40" datetime=2004-04-05 00:00:00 UTC
2025-04-01T07:43:13.759694Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2004:04:02 08:32:09" datetime=2004-04-02 00:00:00 UTC
2025-04-01T07:43:13.759961Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2004:04:02 08:32:09" datetime=2004-04-02 00:00:00 UTC
2025-04-01T07:43:13.760258Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2004\\04\\windowsxpfields.jpg" earliest=Some(2004-04-02T08:00:00+08:00)
2025-04-01T07:43:13.765517Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:ModifyDate = 2012-05-22T15:52:27+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.765607Z INFO place::process: 🎉 success parse datetime from text text="[PNG-tIME] Last Modification Time = 2013:01:01 04:08:30" datetime=2013-01-01 00:00:00 UTC
2025-04-01T07:43:13.765708Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmpMM:History[1]/stEvt:when = 2012-05-22T15:52:27+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.765795Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:13.765878Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:13.766011Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:CreateDate = 2012-05-22T15:52:27+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.766110Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2013\\01\\gimp-8x12-greyscale-alpha-time-background.png" earliest=Some(2013-01-01T08:00:00+08:00)
2025-04-01T07:43:13.766184Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:CreateDate = 2003-11-17T10:04:03-08:00" datetime=2003-11-17 00:00:00 UTC
2025-04-01T07:43:13.766248Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2012:05:22 15:52:27" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.766310Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:ModifyDate = 2003-11-17T17:23:11-08:00" datetime=2003-11-17 00:00:00 UTC
2025-04-01T07:43:13.766417Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = psd" ftype="psd"
2025-04-01T07:43:13.766510Z INFO place::process: 🎉 success parse datetime from text text="<date>2003-11-18T01:19:18Z</date>" datetime=2003-11-18 00:00:00 UTC
2025-04-01T07:43:13.766577Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:MetadataDate = 2012-05-22T15:52:27+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.766713Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:MetadataDate = 2003-11-17T17:23:11-08:00" datetime=2003-11-17 00:00:00 UTC
2025-04-01T07:43:13.766910Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2003:11:17 17:23:11" datetime=2003-11-17 00:00:00 UTC
2025-04-01T07:43:13.767054Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2004\\04\\windowsxpfields.jpg"
2025-04-01T07:43:13.767187Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2003\\11\\adobejpeg1.jpg" earliest=Some(2003-11-17T08:00:00+08:00)
2025-04-01T07:43:13.767997Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2012\\05\\8x4x8bit-grayscale.psd" earliest=Some(2012-05-22T08:00:00+08:00)
2025-04-01T07:43:13.768470Z INFO place::process: ✅ [15/53] success place with new parsed finish from=".\\tests\\2004\\04\\windowsxpfields.jpg" to=".\\tests.output\\2004\\04\\windowsxpfields.jpg"
2025-04-01T07:43:13.778246Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2013\\01\\gimp-8x12-greyscale-alpha-time-background.png"
2025-04-01T07:43:13.779490Z INFO place::process: ✅ [16/53] success place with new parsed finish from=".\\tests\\2013\\01\\gimp-8x12-greyscale-alpha-time-background.png" to=".\\tests.output\\2013\\01\\gimp-8x12-greyscale-alpha-time-background.png"
2025-04-01T07:43:13.782489Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:CreateDate = 2012-12-31T04:35:10Z" datetime=2012-12-31 00:00:00 UTC
2025-04-01T07:43:13.782654Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:MetadataDate = 2013-01-01T02:13:24" datetime=2013-01-01 00:00:00 UTC
2025-04-01T07:43:13.782783Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:ModifyDate = 2013-01-01T02:13:24" datetime=2013-01-01 00:00:00 UTC
2025-04-01T07:43:13.782900Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:13.783038Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2012\\12\\photoshop-8x12-rgb24-all-metadata.png" earliest=Some(2012-12-31T08:00:00+08:00)
2025-04-01T07:43:13.786918Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2003\\11\\adobejpeg1.jpg"
2025-04-01T07:43:13.788229Z INFO place::process: ✅ [17/53] success place with new parsed finish from=".\\tests\\2003\\11\\adobejpeg1.jpg" to=".\\tests.output\\2003\\11\\adobejpeg1.jpg"
2025-04-01T07:43:13.795492Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2012\\05\\8x4x8bit-grayscale.psd"
2025-04-01T07:43:13.797166Z INFO place::process: ✅ [18/53] success place with new parsed finish from=".\\tests\\2012\\05\\8x4x8bit-grayscale.psd" to=".\\tests.output\\2012\\05\\8x4x8bit-grayscale.psd"
2025-04-01T07:43:13.798253Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:CreateDate = 2012-05-22T15:51:47+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.798401Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:MetadataDate = 2012-05-22T15:51:47+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.798583Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmpMM:History[1]/stEvt:when = 2012-05-22T15:51:47+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.798742Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = psd" ftype="psd"
2025-04-01T07:43:13.798877Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2012:05:22 15:51:47" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.799006Z INFO place::process: 🎉 success parse datetime from text text="[XMP] xmp:ModifyDate = 2012-05-22T15:51:47+01:00" datetime=2012-05-22 00:00:00 UTC
2025-04-01T07:43:13.800423Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2012\\05\\10x12x16bit-cmyk.psd" earliest=Some(2012-05-22T08:00:00+08:00)
2025-04-01T07:43:13.804985Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2012\\12\\photoshop-8x12-rgb24-all-metadata.png"
2025-04-01T07:43:13.805854Z INFO place::process: ✅ [19/53] success place with new parsed finish from=".\\tests\\2012\\12\\photoshop-8x12-rgb24-all-metadata.png" to=".\\tests.output\\2012\\12\\photoshop-8x12-rgb24-all-metadata.png"
2025-04-01T07:43:13.813590Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2012\\05\\10x12x16bit-cmyk.psd"
2025-04-01T07:43:13.814670Z INFO place::process: ✅ [20/53] success place with new parsed finish from=".\\tests\\2012\\05\\10x12x16bit-cmyk.psd" to=".\\tests.output\\2012\\05\\10x12x16bit-cmyk.psd"
2025-04-01T07:43:13.954341Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2017:08:16 12:18:34" datetime=2017-08-16 00:00:00 UTC
2025-04-01T07:43:13.954843Z INFO place::process: 🎉 success parse datetime from text text="[EPS] Creator = Adobe Photoshop Version 2017.1.1 20170425.r.252 2017/04/25:23:00:00 CL 1113967" datetime=2017-04-25 00:00:00 UTC
2025-04-01T07:43:13.954943Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = eps" ftype="eps"
2025-04-01T07:43:13.955523Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2017:08:16 12:18:36" datetime=2017-08-16 00:00:00 UTC
2025-04-01T07:43:13.955687Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2017\\04\\8x4x8bit-grayscale.eps" earliest=Some(2017-04-25T08:00:00+08:00)
2025-04-01T07:43:13.965031Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2017\\04\\8x4x8bit-grayscale.eps"
2025-04-01T07:43:13.974997Z INFO place::process: ✅ [21/53] success place with new parsed finish from=".\\tests\\2017\\04\\8x4x8bit-grayscale.eps" to=".\\tests.output\\2017\\04\\8x4x8bit-grayscale.eps"
2025-04-01T07:43:13.989348Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:13.989636Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\16color-10x10.mmfplace\\2025\\07\\16color-10x10.bmp"
2025-04-01T07:43:13.989748Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\16color-10x10.mmfplace\\2025\\07\\16color-10x10.bmp" earliest=Some(2025-07-02T18:59:40.313330200+08:00)
2025-04-01T07:43:13.998179Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\16color-10x10.bmp"
2025-04-01T07:43:14.000206Z INFO place::process: ✅ [22/53] success place with new parsed finish from=".\\tests\\2025\\07\\16color-10x10.mmfplace\\2025\\07\\16color-10x10.bmp" to=".\\tests.output\\2025\\07\\16color-10x10.bmp"
2025-04-01T07:43:14.007358Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.007416Z INFO place::process: 🎉 success parse datetime from text text="[EPS] Creator = Adobe Photoshop Version 2017.1.1 20170425.r.252 2017/04/25:23:00:00 CL 1113967" datetime=2017-04-25 00:00:00 UTC
2025-04-01T07:43:14.007485Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\16color-10x10.bmp"
2025-04-01T07:43:14.008034Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\16color-10x10.bmp" earliest=Some(2025-07-09T16:50:22.058821900+08:00)
2025-04-01T07:43:14.009023Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = eps" ftype="eps"
2025-04-01T07:43:14.009199Z INFO place::process: same hash file found, compare the time and overwrite it current=["2025", "07", "16color-10x10_01.bmp"] history=["2025", "07", "16color-10x10.bmp"]
2025-04-01T07:43:14.009246Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2017:08:16 12:24:54" datetime=2017-08-16 00:00:00 UTC
2025-04-01T07:43:14.009417Z INFO place::process: ✅ [23/53] success place (>=history) finish from=".\\tests\\2025\\07\\16color-10x10.bmp" to=".\\tests.output\\2025\\07\\16color-10x10_01.bmp"
2025-04-01T07:43:14.009527Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2017:08:16 12:24:56" datetime=2017-08-16 00:00:00 UTC
2025-04-01T07:43:14.009623Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2017\\04\\adobejpeg1.eps" earliest=Some(2017-04-25T08:00:00+08:00)
2025-04-01T07:43:14.017067Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2017\\04\\adobejpeg1.eps"
2025-04-01T07:43:14.017141Z INFO place::process: 🎉 success parse datetime from text text="[XMP] photoshop:DateCreated = 2015-01-22T00:00:00 +00:00" datetime=2015-01-22 00:00:00 UTC
2025-04-01T07:43:14.017361Z INFO place::process: 🎉 success parse datetime from text text="[IPTC] Date Created = 2015-01-22" datetime=2015-01-22 00:00:00 UTC
2025-04-01T07:43:14.017510Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:14.017667Z WARN place::process: 💡 skip the datetime < 1975 file=".\\tests\\2015\\01\\withxmp.jpg" datetime=0001-01-01 00:00:00 UTC
2025-04-01T07:43:14.017789Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2015\\01\\withxmp.jpg" earliest=Some(2015-01-22T08:00:00+08:00)
2025-04-01T07:43:14.018229Z INFO place::process: ✅ [24/53] success place with new parsed finish from=".\\tests\\2017\\04\\adobejpeg1.eps" to=".\\tests.output\\2017\\04\\adobejpeg1.eps"
2025-04-01T07:43:14.024396Z INFO place::process: 🎉 success parse datetime from text text="[IPTC] Digital Date Created = 2022:02:24" datetime=2022-02-24 00:00:00 UTC
2025-04-01T07:43:14.025011Z INFO place::process: 🎉 success parse datetime from text text="[Exif IFD0] Date/Time = 2022:02:24 20:28:15" datetime=2022-02-24 00:00:00 UTC
2025-04-01T07:43:14.025083Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:14.025172Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2022:02:24 20:28:15" datetime=2022-02-24 00:00:00 UTC
2025-04-01T07:43:14.025334Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Digitized = 2022:02:24 20:28:15" datetime=2022-02-24 00:00:00 UTC
2025-04-01T07:43:14.025395Z INFO place::process: 🎉 success parse datetime from text text="[IPTC] Date Created = 2022:02:24" datetime=2022-02-24 00:00:00 UTC
2025-04-01T07:43:14.025657Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2022\\02\\strangebird.jpg" earliest=Some(2022-02-24T08:00:00+08:00)
2025-04-01T07:43:14.027951Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2015\\01\\withxmp.jpg"
2025-04-01T07:43:14.030685Z INFO place::process: ✅ [25/53] success place with new parsed finish from=".\\tests\\2015\\01\\withxmp.jpg" to=".\\tests.output\\2015\\01\\withxmp.jpg"
2025-04-01T07:43:14.037784Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2022\\02\\strangebird.jpg"
2025-04-01T07:43:14.039066Z INFO place::process: ✅ [26/53] success place with new parsed finish from=".\\tests\\2022\\02\\strangebird.jpg" to=".\\tests.output\\2022\\02\\strangebird.jpg"
2025-04-01T07:43:14.052124Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.053519Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\256color-10x10.bmp"
2025-04-01T07:43:14.053710Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\256color-10x10.bmp" earliest=Some(2025-07-09T16:50:22.059818300+08:00)
2025-04-01T07:43:14.058563Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:14.058830Z INFO place::process: 🎉 success parse datetime from text text="[IPTC] Date Created = 2015-01-22" datetime=2015-01-22 00:00:00 UTC
2025-04-01T07:43:14.059005Z INFO place::process: 🎉 success parse datetime from text text="[XMP] photoshop:DateCreated = 2015-01-22T00:00:00 +00:00" datetime=2015-01-22 00:00:00 UTC
2025-04-01T07:43:14.059200Z WARN place::process: 💡 skip the datetime < 1975 file=".\\tests\\2015\\01\\withxmp.jpg.jpg" datetime=0001-01-01 00:00:00 UTC
2025-04-01T07:43:14.059407Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2015\\01\\withxmp.jpg.jpg" earliest=Some(2015-01-22T08:00:00+08:00)
2025-04-01T07:43:14.062097Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\256color-10x10.bmp"
2025-04-01T07:43:14.062848Z INFO place::process: ✅ [27/53] success place with new parsed finish from=".\\tests\\2025\\07\\256color-10x10.bmp" to=".\\tests.output\\2025\\07\\256color-10x10.bmp"
2025-04-01T07:43:14.063410Z INFO place::process: same hash file found, compare the time and overwrite it current=["2015", "01", "withxmp.jpg.jpg"] history=["2015", "01", "withxmp.jpg"]
2025-04-01T07:43:14.063545Z INFO place::process: ✅ [28/53] success place (>=history) finish from=".\\tests\\2015\\01\\withxmp.jpg.jpg" to=".\\tests.output\\2015\\01\\withxmp.jpg.jpg"
2025-04-01T07:43:14.064995Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.065257Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\16color-10x10.mmfplace\\2025\\07\\16color-10x10_01.bmp"
2025-04-01T07:43:14.065378Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\16color-10x10.mmfplace\\2025\\07\\16color-10x10_01.bmp" earliest=Some(2025-07-02T18:59:40.313330200+08:00)
2025-04-01T07:43:14.065738Z INFO place::process: same hash file found, compare the time and overwrite it current=["2025", "07", "16color-10x10_01.bmp"] history=["2025", "07", "16color-10x10.bmp"]
2025-04-01T07:43:14.065907Z INFO place::process: ✅ [29/53] success place (>=history) finish from=".\\tests\\2025\\07\\16color-10x10.mmfplace\\2025\\07\\16color-10x10_01.bmp" to=".\\tests.output\\2025\\07\\16color-10x10_01.bmp"
2025-04-01T07:43:14.143284Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.143461Z INFO place::process: 🎉 success parse datetime from text text="[Exif SubIFD] Date/Time Original = 2022:04:02 08:20:27" datetime=2022-04-02 00:00:00 UTC
2025-04-01T07:43:14.143605Z INFO place::process: 🎉 success parse datetime from text text="[XMP] photoshop:DateCreated = 2022-04-02T08:20:27" datetime=2022-04-02 00:00:00 UTC
2025-04-01T07:43:14.143821Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2022\\04\\iphone13screenshot.png" earliest=Some(2022-04-02T08:00:00+08:00)
2025-04-01T07:43:14.150689Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2022\\04\\iphone13screenshot.png"
2025-04-01T07:43:14.155361Z INFO place::process: ✅ [30/53] success place with new parsed finish from=".\\tests\\2022\\04\\iphone13screenshot.png" to=".\\tests.output\\2022\\04\\iphone13screenshot.png"
2025-04-01T07:43:14.206055Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.206209Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\24bpp-10x10.bmp"
2025-04-01T07:43:14.206333Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\24bpp-10x10.bmp" earliest=Some(2025-07-09T16:50:22.059818300+08:00)
2025-04-01T07:43:14.214516Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\24bpp-10x10.bmp"
2025-04-01T07:43:14.216907Z INFO place::process: ✅ [31/53] success place with new parsed finish from=".\\tests\\2025\\07\\24bpp-10x10.bmp" to=".\\tests.output\\2025\\07\\24bpp-10x10.bmp"
2025-04-01T07:43:14.236430Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.236692Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\adobejpeg1.jpg.bmp"
2025-04-01T07:43:14.236844Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\adobejpeg1.jpg.bmp" earliest=Some(2025-07-09T16:50:22.059818300+08:00)
2025-04-01T07:43:14.246401Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\adobejpeg1.jpg.bmp"
2025-04-01T07:43:14.247431Z INFO place::process: ✅ [32/53] success place with new parsed finish from=".\\tests\\2025\\07\\adobejpeg1.jpg.bmp" to=".\\tests.output\\2025\\07\\adobejpeg1.jpg.bmp"
2025-04-01T07:43:14.259572Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\apple.heic"
2025-04-01T07:43:14.259652Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\apple.heic" earliest=Some(2025-07-02T18:59:40.316332400+08:00)
2025-04-01T07:43:14.269028Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\apple.heic"
2025-04-01T07:43:14.271461Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\apple01.heif"
2025-04-01T07:43:14.272818Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\apple01.heif" earliest=Some(2025-07-09T16:50:22.060819400+08:00)
2025-04-01T07:43:14.273737Z INFO place::process: ✅ [33/53] success place with new parsed finish from=".\\tests\\2025\\07\\apple.heic" to=".\\tests.output\\2025\\07\\apple.heic"
2025-04-01T07:43:14.274086Z INFO place::process: same hash file found, compare the time and overwrite it current=["2025", "07", "apple01.heif"] history=["2025", "07", "apple.heic"]
2025-04-01T07:43:14.274196Z INFO place::process: ✅ [34/53] success place (>=history) finish from=".\\tests\\2025\\07\\apple01.heif" to=".\\tests.output\\2025\\07\\apple01.heif"
2025-04-01T07:43:14.276272Z INFO place::process: 🎉 success parse datetime from text text="[File] File Name = 2025-07-02.heif" datetime=2025-07-02 00:00:00 UTC
2025-04-01T07:43:14.277132Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\apple01.mmfplace\\2025\\07\\2025-07-02.heif" earliest=Some(2025-07-02T08:00:00+08:00)
2025-04-01T07:43:14.277467Z INFO place::process: same hash file found, compare the time and overwrite it current=["2025", "07", "2025-07-02.heif"] history=["2025", "07", "apple.heic"]
2025-04-01T07:43:14.284639Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.284724Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\2025-07-02.heif"
2025-04-01T07:43:14.284870Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\dotnet-256x256-alpha-palette.png"
2025-04-01T07:43:14.285003Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\dotnet-256x256-alpha-palette.png" earliest=Some(2025-07-09T16:50:22.060819400+08:00)
2025-04-01T07:43:14.286217Z INFO place::process: ✅ [35/53] success place (<history) update finish from=".\\tests\\2025\\07\\apple01.mmfplace\\2025\\07\\2025-07-02.heif" to=".\\tests.output\\2025\\07\\2025-07-02.heif"
2025-04-01T07:43:14.293311Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\dotnet-256x256-alpha-palette.png"
2025-04-01T07:43:14.296071Z INFO place::process: ✅ [36/53] success place with new parsed finish from=".\\tests\\2025\\07\\dotnet-256x256-alpha-palette.png" to=".\\tests.output\\2025\\07\\dotnet-256x256-alpha-palette.png"
2025-04-01T07:43:14.300367Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = gif" ftype="gif"
2025-04-01T07:43:14.300691Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.300741Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\mspaint-10x10.gif"
2025-04-01T07:43:14.300805Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\iccdatainvalid1.jpg.bmp"
2025-04-01T07:43:14.300857Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\mspaint-10x10.gif" earliest=Some(2025-07-09T16:50:22.061818700+08:00)
2025-04-01T07:43:14.301293Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\iccdatainvalid1.jpg.bmp" earliest=Some(2025-07-09T16:50:22.061818700+08:00)
2025-04-01T07:43:14.311336Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\mspaint-10x10.gif"
2025-04-01T07:43:14.312312Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.312439Z INFO place::process: ✅ [37/53] success place with new parsed finish from=".\\tests\\2025\\07\\mspaint-10x10.gif" to=".\\tests.output\\2025\\07\\mspaint-10x10.gif"
2025-04-01T07:43:14.312569Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\invalid-iccp-missing-adler32-checksum.png"
2025-04-01T07:43:14.313125Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\invalid-iccp-missing-adler32-checksum.png" earliest=Some(2025-07-09T16:50:22.061818700+08:00)
2025-04-01T07:43:14.319539Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\iccdatainvalid1.jpg.bmp"
2025-04-01T07:43:14.320285Z INFO place::process: ✅ [38/53] success place with new parsed finish from=".\\tests\\2025\\07\\iccdatainvalid1.jpg.bmp" to=".\\tests.output\\2025\\07\\iccdatainvalid1.jpg.bmp"
2025-04-01T07:43:14.332964Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\invalid-iccp-missing-adler32-checksum.png"
2025-04-01T07:43:14.334034Z INFO place::process: ✅ [39/53] success place with new parsed finish from=".\\tests\\2025\\07\\invalid-iccp-missing-adler32-checksum.png" to=".\\tests.output\\2025\\07\\invalid-iccp-missing-adler32-checksum.png"
2025-04-01T07:43:14.456983Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.457825Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\mspaint-8x10.png"
2025-04-01T07:43:14.457885Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\mspaint-8x10.png" earliest=Some(2025-07-09T16:50:22.061818700+08:00)
2025-04-01T07:43:14.467647Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\mspaint-8x10.png"
2025-04-01T07:43:14.468618Z INFO place::process: ✅ [40/53] success place with new parsed finish from=".\\tests\\2025\\07\\mspaint-8x10.png" to=".\\tests.output\\2025\\07\\mspaint-8x10.png"
2025-04-01T07:43:14.477223Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.477368Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\photoshop-8x12-16colorpalette.png"
2025-04-01T07:43:14.477576Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\photoshop-8x12-16colorpalette.png" earliest=Some(2025-07-09T16:50:22.062818800+08:00)
2025-04-01T07:43:14.485902Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\photoshop-8x12-16colorpalette.png"
2025-04-01T07:43:14.487402Z INFO place::process: ✅ [41/53] success place with new parsed finish from=".\\tests\\2025\\07\\photoshop-8x12-16colorpalette.png" to=".\\tests.output\\2025\\07\\photoshop-8x12-16colorpalette.png"
2025-04-01T07:43:14.508920Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:14.511043Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\noexif.jpg"
2025-04-01T07:43:14.511404Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\noexif.jpg" earliest=Some(2025-07-09T16:50:22.061818700+08:00)
2025-04-01T07:43:14.521402Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\noexif.jpg"
2025-04-01T07:43:14.525698Z INFO place::process: ✅ [42/53] success place with new parsed finish from=".\\tests\\2025\\07\\noexif.jpg" to=".\\tests.output\\2025\\07\\noexif.jpg"
2025-04-01T07:43:14.564500Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:14.564676Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\withtypicalhuffman.jpg"
2025-04-01T07:43:14.565608Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\withtypicalhuffman.jpg" earliest=Some(2025-07-09T16:50:22.063819+08:00)
2025-04-01T07:43:14.574217Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\withtypicalhuffman.jpg"
2025-04-01T07:43:14.575122Z INFO place::process: ✅ [43/53] success place with new parsed finish from=".\\tests\\2025\\07\\withtypicalhuffman.jpg" to=".\\tests.output\\2025\\07\\withtypicalhuffman.jpg"
2025-04-01T07:43:14.586044Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = gif" ftype="gif"
2025-04-01T07:43:14.587025Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\小鸡动画.gif"
2025-04-01T07:43:14.587280Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\小鸡动画.gif" earliest=Some(2025-07-09T16:50:22.064818900+08:00)
2025-04-01T07:43:14.594967Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\小鸡动画.gif"
2025-04-01T07:43:14.595053Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:14.595144Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.595258Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\withxmpandiptc.jpg.bmp"
2025-04-01T07:43:14.595342Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\withxmpandiptc.jpg.bmp" earliest=Some(2025-07-09T16:50:22.064818900+08:00)
2025-04-01T07:43:14.595387Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\withuncompressedycbcrthumbnail4.jpg"
2025-04-01T07:43:14.595437Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\withuncompressedycbcrthumbnail4.jpg" earliest=Some(2025-07-09T16:50:22.064818900+08:00)
2025-04-01T07:43:14.596144Z INFO place::process: ✅ [44/53] success place with new parsed finish from=".\\tests\\2025\\07\\小鸡动画.gif" to=".\\tests.output\\2025\\07\\小鸡动画.gif"
2025-04-01T07:43:14.603748Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\withxmpandiptc.jpg.bmp"
2025-04-01T07:43:14.605071Z INFO place::process: ✅ [45/53] success place with new parsed finish from=".\\tests\\2025\\07\\withxmpandiptc.jpg.bmp" to=".\\tests.output\\2025\\07\\withxmpandiptc.jpg.bmp"
2025-04-01T07:43:14.613351Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\withuncompressedycbcrthumbnail4.jpg"
2025-04-01T07:43:14.614343Z INFO place::process: ✅ [46/53] success place with new parsed finish from=".\\tests\\2025\\07\\withuncompressedycbcrthumbnail4.jpg" to=".\\tests.output\\2025\\07\\withuncompressedycbcrthumbnail4.jpg"
2025-04-01T07:43:14.625528Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.625681Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\photoshop-8x12-rgb24.png"
2025-04-01T07:43:14.626436Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\photoshop-8x12-rgb24.png" earliest=Some(2025-07-09T16:50:22.062818800+08:00)
2025-04-01T07:43:14.635753Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\photoshop-8x12-rgb24.png"
2025-04-01T07:43:14.636482Z INFO place::process: ✅ [47/53] success place with new parsed finish from=".\\tests\\2025\\07\\photoshop-8x12-rgb24.png" to=".\\tests.output\\2025\\07\\photoshop-8x12-rgb24.png"
2025-04-01T07:43:14.640789Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.640874Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = gif" ftype="gif"
2025-04-01T07:43:14.640960Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\photoshop-8x12-rgb24-interlaced.png"
2025-04-01T07:43:14.641056Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\photoshop-8x12-32colors-alpha.gif"
2025-04-01T07:43:14.641129Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\photoshop-8x12-rgb24-interlaced.png" earliest=Some(2025-07-09T16:50:22.062818800+08:00)
2025-04-01T07:43:14.641193Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\photoshop-8x12-32colors-alpha.gif" earliest=Some(2025-07-09T16:50:22.062818800+08:00)
2025-04-01T07:43:14.647776Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\photoshop-8x12-rgb24-interlaced.png"
2025-04-01T07:43:14.648524Z INFO place::process: ✅ [48/53] success place with new parsed finish from=".\\tests\\2025\\07\\photoshop-8x12-rgb24-interlaced.png" to=".\\tests.output\\2025\\07\\photoshop-8x12-rgb24-interlaced.png"
2025-04-01T07:43:14.656028Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\photoshop-8x12-32colors-alpha.gif"
2025-04-01T07:43:14.656895Z INFO place::process: ✅ [49/53] success place with new parsed finish from=".\\tests\\2025\\07\\photoshop-8x12-32colors-alpha.gif" to=".\\tests.output\\2025\\07\\photoshop-8x12-32colors-alpha.gif"
2025-04-01T07:43:14.733222Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = bmp" ftype="bmp"
2025-04-01T07:43:14.733384Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\windowsxpfields.jpg.bmp"
2025-04-01T07:43:14.733465Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\windowsxpfields.jpg.bmp" earliest=Some(2025-07-09T16:50:22.063819+08:00)
2025-04-01T07:43:14.740221Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\windowsxpfields.jpg.bmp"
2025-04-01T07:43:14.741023Z INFO place::process: ✅ [50/53] success place with new parsed finish from=".\\tests\\2025\\07\\windowsxpfields.jpg.bmp" to=".\\tests.output\\2025\\07\\windowsxpfields.jpg.bmp"
2025-04-01T07:43:14.762875Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = jpg" ftype="jpg"
2025-04-01T07:43:14.762960Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.763067Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\photoshop-8x12-rgba32.png"
2025-04-01T07:43:14.763129Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\withiptcphotoshop6.jpg"
2025-04-01T07:43:14.763195Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\photoshop-8x12-rgba32.png" earliest=Some(2025-07-09T16:50:22.063819+08:00)
2025-04-01T07:43:14.763291Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\withiptcphotoshop6.jpg" earliest=Some(2025-07-09T16:50:22.063819+08:00)
2025-04-01T07:43:14.769856Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\photoshop-8x12-rgba32.png"
2025-04-01T07:43:14.770608Z INFO place::process: ✅ [51/53] success place with new parsed finish from=".\\tests\\2025\\07\\photoshop-8x12-rgba32.png" to=".\\tests.output\\2025\\07\\photoshop-8x12-rgba32.png"
2025-04-01T07:43:14.777117Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\withiptcphotoshop6.jpg"
2025-04-01T07:43:14.778014Z INFO place::process: ✅ [52/53] success place with new parsed finish from=".\\tests\\2025\\07\\withiptcphotoshop6.jpg" to=".\\tests.output\\2025\\07\\withiptcphotoshop6.jpg"
2025-04-01T07:43:14.795609Z INFO place::process: 🎉 success parse filetype from text text="[File Type] Expected File Name Extension = png" ftype="png"
2025-04-01T07:43:14.795797Z WARN place::target: 💡 time not found by dateparser, use the attrtimes as earliest time file=".\\tests\\2025\\07\\photoshop-8x12-rgba32-interlaced.png"
2025-04-01T07:43:14.795933Z INFO place::target: 🎉 success set earliest datetime file=".\\tests\\2025\\07\\photoshop-8x12-rgba32-interlaced.png" earliest=Some(2025-07-09T16:50:22.062818800+08:00)
2025-04-01T07:43:14.796049Z INFO place::process: finished producer
2025-04-01T07:43:14.802361Z INFO place::target: 🚚 copy with file not exist file=".\\tests.output\\2025\\07\\photoshop-8x12-rgba32-interlaced.png"
2025-04-01T07:43:14.803145Z INFO place::process: ✅ [53/53] success place with new parsed finish from=".\\tests\\2025\\07\\photoshop-8x12-rgba32-interlaced.png" to=".\\tests.output\\2025\\07\\photoshop-8x12-rgba32-interlaced.png"
2025-04-01T07:43:14.803238Z INFO place::process: finished consumer
2025-04-01T07:43:14.803346Z INFO place::process: all done