照片整理以及各种形式的除旧迎新

2025-04-25 20:00:00   技术   python ffmpeg

这篇整理了大半年,毕竟家里有了比较大的变革。

除旧迎新

我发现我不仅修好了十年老笔记本,还修好了坏了的DVD播放器、电钢琴,最后把20多年的数码照片给整理了。

因为各种原因,我把很久不用的老笔记本拿出来折腾了一下,事实上我的目的是为了整理所有数码照片,而整理照片的目的是因为迎合变革——我有一种做事渐渐失去了本来目标的感觉,这叫什么,发散思维?

修笔记本电脑

老笔记本购于2014年,是真真正正的十年老机。其实我对硬件、品牌、设备之类的并不敏感,最近才搜索到一些信息,比如这个型号似乎是ThinkPad下坡路的开始之类的。

这台笔记本上一次被使用的时候我记得应该是尝试安装Ubuntu18.04,没有记错的话,上次安装到一半它就罢工了。因为平时使用的频率非常低,所以当时就搁置在一边了,一搁置就是6年。

我掏出来的第一件事就是安装Ubuntu24.04。不出所料,第一遍安装失败了,装到一半就死机了。但是第二遍居然成功了。成功是成功了,一开机就接到了警报。

A hard disk is likely to fail soon

等一下,这个意思是,硬盘快要报废了是吗?

我把语言换成中文,看看是不是有什么歧义。

磁盘看起来即将在不久后损坏

看来这个十年老机的十年(虽然六年没用)老硬盘真的不行了,我估计很早就有坏磁区了,可能之前装系统的时候总是写到坏的地方,所以总是死机。这回运气好,能让安装系统的所有步骤走完。当然,这台机器的续航(不是指电池)非常糟糕,随便打开点什么就报错了,大概就是这样吧:

磁盘看起来即将在不久后损坏

有点模糊了,关键行是这样的:

ata1.00: failed to enable AA(error_mask=0x1)
I/O error, dev sda, sector 13385600 op 0x0:(READ) flags ox80700 phys_seg 32 prio class 0

行吧,挠挠头。考虑到预算问题,我还是没有买新的笔记本电脑,换个硬盘吧。我自己都不能确定自己就算修好了会以怎样的频率来使用笔记本,说不定又往旁边一扔……幸好是硬盘,现在价格也不贵。

在新的硬盘到货之前,我这个几乎没怎么拆机装机的人也练练手,学习下怎么拆解笔记本。幸运的是现在网上的教程视频真的很多,什么老旧型号的破电脑都有拆机教程。我付出的唯一代价是装回去的时候2个钉子可能放错了位置,拧太深了,直接顶到了表面。

拆机演练

:point_up:左边被包裹住的就是即将报废的使劲报错的老硬盘。而且令我惊讶的是,我当时居然买的是高配版本,带有附加电池(就是右下那个),我居然完全没有注意到——难怪,在我印象中,以前笔记本的电池续航时间更长,从某个我不记得的时间开始续航直接短了一半,没错,自从那个时间开始,这个附加电池坏了。我再三思索了一下,决定不需要这个附加电池了,而是买了一个老式的扩展坞固定放置笔记本,一直插电使用。现在应该没有什么需要抱着笔记本进被窝的需求了,直接拿着手机不是更香吗?

新的硬盘

很快——其实大约有三个星期,因为我在控制自己的月度预算,所以才在9月的最后一周下单,又因为十一长假和孩子生病住院的缘故,我到十月的第三周才拿到——我的新硬盘到货了。

欢迎来到Ubuntu24.04.1 LTS

再安装好系统之后试了一下,除了猫咪在键盘上跳舞之后可能会死机(原因不明,好像是按同一个键太久了),其他都挺好。接着我就配上了比较廉价的鼠标和键盘,愉快地下载了Minecraft Linux版开始和小伙伴们玩新服务器了(喂!不是说好了整理照片吗?)

修理DVD机

修好老电脑之后,我突然发现,家里的东西一夜之间都坏了——其实可能是错觉,以前就坏了,我没有发现或者用得很少就懒得修了。

比如某个几百块淘来的老旧DVD播放机——当时家里的音响坏了,音响的功能是放DVD+音响+广播,于是那个时候我买了老旧DVD机+外接小喇叭+德生收音机(可以听航空频率的那种),把功能拆解开,满足了我以下需求:

  1. 早上定时放广播当闹钟
  2. 偶尔听CD
  3. 连接电视屏幕陪孩子看迪士尼《幻想2000》DVD

DVD皮带断了

DVD机一夜之间突然不出仓了,仔细研究了一下,皮带断了。

如果以前碰到这个情况,我可能会直接买一个新的DVD机。不过这次我只花了几块钱换了个皮带,自己修一修也挺开心的。

DVD满血复活

修理电钢琴

在修好了笔记本和DVD机之后,我似乎有了一些小小的膨胀,有种天不怕地不怕的感觉,好像家里什么坏了都不用买新的,自己动手修一修就好了。直到电钢琴出现了爆音故障。

师傅修理电钢琴

这台电钢琴也不是什么新物品,是前两年买着玩儿的。想着即便小孩不愿意好好学,我自己也可以当作玩具玩,当然现在是天天逼着孩子练着。从价格来说,和三十年前的立式低档钢琴差不了多少,除了货币购买力的变化,钢琴本身的贬值更是主要因素。我想着电钢琴体积小,还不用调音,总觉得能省下很多钱。

结果居然有爆音这种故障。我完全不会修也不敢拆,最终还是用了将近1000块的一半请了专业师傅上门,想想和真钢琴的调音价格也差不了多少了。其中价格的大头是琴键下面的橡胶垫,这个零件真的太精细了,灰尘猫毛掉进去都会影响它,更严重的是,这个垫子是消耗品而且寿命挺短的。我一边看着师傅拆一边记着他的步骤,想,下次就不用支付师傅上门费用,自己买替换的垫子自己动手换吧。

整理数码照片

言归正传。

弯弯绕了好久,我终于想起来为什么想要修理笔记本电脑了。

前几年高中校庆的时候,我把各种照片从各种犄角旮旯里面翻出来,发现照片的载体很堪忧。比如有坏扇区的旧硬盘、用硬盘改装的接触不良的移动硬盘(摇一摇才能被电脑识别出来)、16M/32M/64M/128M/512M的各种陈年U盘。我不由开始思考大学课堂上说的各种不同存储方式的优缺点。在闲着无事搜索了最新的蓝光光盘技术大开眼界之后,我还是把和十年老机一起购买的外置DVD光驱刻录机拿出来,决定把照片都做一份硬拷贝到DVD或者CD光盘上。当时并不知道照片的总大小,觉得100G顶天了(事实上就58G),蓝光就太大材小用了,而且我也不愿意1200+买个蓝光刻录机,觉得不值得。

第一步把照片们从各种糟糕的环境中找出来,集合到修好的笔记本硬盘上,期间就碰到了一些事故。除了各种载体摇一摇才能读取,确实有不少文件损坏了。而且我某个移动硬盘里面保存了大学时期信息安全课的实验材料,没错,有个文件夹养了一圈病毒+木马,在用工作电脑中转的时候直接触发了警报,公司的安全部门都发邮件找我了……这事我觉得很丢脸,感觉是在用公司资源做自己的事情,笔记本修好以后我再也不用公司电脑中转文件了。

接着我开始整理照片。首先我非常愚蠢地手动把照片按照年份和月份分门别类。做了大概几个月的照片,我就罢工了,觉得自己是傻子。这种无聊的重复工作,我为什么要做?

于是我写了几个脚本:

其中一个版本,后面处理图片大多我都用这个版本:

import ffmpeg
from datetime import datetime
import os
import exifread
import shutil

source_folder ='/home/jiyou/ycy/2024'
result_folder ='/home/jiyou/ycy/photo/'

def get_creation_time(file_path):
    creation_time = None
    if creation_time is None:
        f = open(file_path, 'rb')
        tags = exifread.process_file(f)
        if 'EXIF DateTimeOriginal' in tags:
            creation_time = tags['EXIF DateTimeOriginal']
        if creation_time is None:
            if 'Image DateTime' in tags:
                creation_time = tags['Image DateTime']
    if creation_time is None:
        creation_time = datetime.fromtimestamp(os.path.getmtime(file_path))
    return creation_time

def get_file_size(file_path):
    probe = ffmpeg.probe(file_path)
    format_info = probe['format']
    file_size = format_info.get('size', None)
    return file_size

def parse_date_with_am_pm(date_string):
    formats = [
        '%Y:%m:%d %H:%M:%S%P',
        '%Y-%m-%dT%H:%M:%S.%fZ',
        '%Y-%m-%d %H:%M:%S',
        '%Y-%m-%d %H:%M:%S.%f',
        '%Y:%m:%d %H:%M:%S',
        '%Y:%m:%d %H:%M:%S下午',
        '%Y:%m:%d %H:%M:%S上午',
    ]
    if date_string == "0000:00:00 00:00:00":
        return None

    if date_string:
        for fmt in formats:
            try:
                return datetime.strptime(date_string, fmt)
            except ValueError:
                continue
        raise Exception(date_string)
    else:
        return None

def traverse_directory(root_dir):
    for root, dirs, files in os.walk(root_dir):
        for file in files:
            file_path = os.path.join(root, file)
            time_string = get_creation_time(file_path)
            date = parse_date_with_am_pm(str(time_string))
            if date is None:
                print("%s拍摄时间有问题"%file_path)
            else:
                if not os.path.exists(result_folder + str(date.year)):
                    os.makedirs(result_folder + str(date.year))
                if not os.path.exists(result_folder + str(date.year) + "/" + str(date.month)):
                    os.makedirs(result_folder + str(date.year) + "/" + str(date.month))
                new_file_path = result_folder + str(date.year) + "/" + str(date.month) + "/" + file
                if os.path.exists(new_file_path):
                    old_stats = os.stat(new_file_path)
                    new_stats = os.stat(file_path)
                    if old_stats.st_size >= new_stats.st_size:
                        os.remove(file_path)
                        print ("%s新的比较小"%file_path)
                    else:
                        os.remove(new_file_path)
                        shutil.move(file_path, new_file_path)
                        print ("%s新的比较大"%file_path)
                else:
                    print ("%s移动"%file_path)
                    shutil.move(file_path, new_file_path)

traverse_directory(source_folder)

其实一开始很简单,查找图片的拍摄时间然后放进文件夹就好了。

然后我就发现有的图片没有EXIF信息,即便有,这个拍摄时间的格式也是五花八门(我统计到了8种)。对于没有EXIF的图片,我直接取创建时间。有很多微信模式拍摄的照片就很糟糕,只能依靠创建时间来分辨。有的图片创建时间等于今天(从其他存储载体移动到新硬盘的这天),更糟的一种是时间写了“0000:00:00 00:00:00”,信誓旦旦的表示这就是自己的拍摄时间……

接着我发现有的图片有复制体,还有网络传输压缩体,就根据同名比了下大小。

最后做完了图片,发现还有很多视频,然后就用其他方法再整了一下。其实具体最终版本是怎么样的我都忘了

另一个版本,好像是比较早先的区分视频和照片的版本

import exifread
from datetime import datetime
import os
import shutil

result_folder = "/home/jiyou/ycy/photos/"
movie_folder = "/home/jiyou/ycy/movies/"

def recursive_list_dir(path):
    files = os.listdir(path)
    for file in files:
        file_path = os.path.join(path, file)
        if os.path.isfile(file_path):
            ext = file.split(".")[-1]
            if ext in ['jpeg','JPEG','JPG', 'jpg','jpg', 'png', 'PNG', 'gif', 'GIF']:
                process_img(os.path.abspath(file_path), file)
            elif ext in ['MOV', 'mov', 'mp4', 'MP4']:
                process_mov(os.path.abspath(file_path), file)
            else:
                print ("%s不是图片 %s"%(os.path.abspath(file),ext))
        elif os.path.isdir(file_path):
            recursive_list_dir(file_path)


def process_img(image_path, image_name):
    img = exifread.process_file(open(image_path,'rb'))
    if 'Image DateTime' in img:
        time = img['Image DateTime']
        if str(time) == "0000:00:00 00:00:00":
            print("%s拍摄时间有问题"%image_path)
        else:
            format = "%Y:%m:%d %H:%M:%S"
            try:
                date = datetime.strptime(str(time).replace('下午',''), format)
                if not os.path.exists(result_folder + str(date.year)):
                    os.makedirs(result_folder + str(date.year))
                if not os.path.exists(result_folder + str(date.year) + "/" + str(date.month)):
                    os.makedirs(result_folder + str(date.year) + "/" + str(date.month))
                
                new_file_path = result_folder + str(date.year) + "/" + str(date.month) + "/" + image_name
                if os.path.exists(new_file_path):
                    old_stats = os.stat(new_file_path)
                    new_stats = os.stat(image_path)
                    if old_stats.st_size >= new_stats.st_size:
                        os.remove(image_path)
                    else:
                        os.remove(new_file_path)
                        shutil.move(image_path, new_file_path)
                        print ("%s新的比较大"%image_path)
                else:
                    shutil.move(image_path, new_file_path)
            except Exception as e:
                print (e)
    else:
        print ("%s没有拍摄信息"%image_path)

def process_mov(image_path, image_name):
    new_file_path = movie_folder +  "/" + image_name
    if os.path.exists(new_file_path):
        old_stats = os.stat(new_file_path)
        new_stats = os.stat(image_path)
        if old_stats.st_size == new_stats.st_size:
            os.remove(image_path)
        else:
            print ("%s已经存在,尺寸不一样"%new_file_path)
    else:
        shutil.move(image_path, new_file_path)

recursive_list_dir(".")

全部按照年份和月份分门别类之后,我就把照片和视频都拷贝到光盘上。在此期间对比学习了下Linux的各种刻录软件,最后发现最适合我的是Brasero。

一些各种设备拍摄的照片(压缩版本)

之前整理校庆照片的时候,我就和老同学戏说,说我的本体是照相机,我已经不记得以前的事情了,但是照相机和照片帮我记得了很多事情。

现在整理也有不少感慨,我明显看到我装备的变迁和拍照习惯的改变。

一开始我还是拿着长辈的尼康和佳能在拍照。大学以及毕业之后我开始有了自己的手机,虽然当时图像的质量很差。接着我有了自己的相机。然而相机的好景不长,手机相机取代了其他的照相设备,而我也不是花大价钱买单反的那种玩家,所以照相机就几乎没有再更新。

早先几年我还是很喜欢在城市里面到处乱走各种乱拍,现在称之为citywalk。之后我就渐渐的越来越宅,照片题材也变成了各种生活琐事鸡毛蒜皮,即便是街景也变成了公司家两点一线的通勤景色合辑。

:point_up:我高中的行政楼

  • 拍摄设备:NIKON E3500 这个相机并不属于我,是我爸的
  • 拍摄时间:2004年9月3日

:point_up:我大学时期的寝室书桌

  • 拍摄设备:NOKIA 6700c,我记得是我妈淘汰下来的一个手机
  • 拍摄时间:2009年11月23日

:point_up:香港街景

  • 拍摄设备:SAMSUNG GT-S5830,好像是我工作后第一部自己买的手机
  • 拍摄时间:2011年10月3日

:point_up:高中60周年校庆时拍摄的食堂

  • 拍摄设备: Canon IXUS 245 HS, 这是真正属于我自己的相机,目前还在服役
  • 拍摄时间:2013年10月26日

:point_up:浏河镇风景

  • 拍摄设备:SAMSUNG SM-A3000,我的另一个手机,想想曾经我也是三星脑残粉
  • 拍摄时间:2015年8月15日

:point_up:邮电新村车站

  • 拍摄设备:HUAWEI VKY-AL00 巨大的水印正在喊:“快看我!快看我!不会不知道是哪个手机拍的了吧!”到后来我就把水印关掉了。后面我再从P10plus换到了P30pro,设备信息变成了VOG-AL10
  • 拍摄时间:2018年6月20日
评论共