我使用 Shotwell 将照片存储在台式电脑上。最近我去度了个长假,想带上笔记本电脑使用 Shotwell 编辑和整理照片,所以我将所有照片复制到外部磁盘,并将 Shotwell 数据库复制到笔记本电脑。使用适当的符号链接,一切都运行正常。Shotwell 却什么都没有改变。此时我还备份了数据库。
然后我想,我不妨将新照片导入笔记本电脑的内置硬盘,这样就不用拖着外置硬盘到处跑了。所以我拆下了外置硬盘,当我再次打开 Shotwell 时,所有照片都被标记为“丢失”。正如预期的那样。我花了几个月的时间导入新照片、标记它们并进行编辑,只使用 Shotwell 的外部程序并将编辑保存为 _modified.jpg。一切都很顺利,我以为当我最终重新连接磁盘时,Shotwell 会拾取丢失的照片。
令我惊恐的是,我发现事情并没有我想象的那么顺利。当我回到家并重新连接外部磁盘时,Shotwell 确实重新扫描了照片 - 但丢失了所有对我编辑的照片的引用。我已经为此提交了一个错误。
我有一个数据库备份,里面正确地记录了我度假前的所有编辑,还有一个数据库备份,里面记录了我所有的新编辑。有没有办法合并这些来纠正缺失的编辑?
PS 最重要的一点是:一定要做好备份! Shotwell 有一个错误,即当照片丢失时,sqlite 数据库“phototable”中记录的“editable_id”字段会被删除。通过恢复自动 photos.db.bk 可以轻松修复此问题,但如果您继续导入和编辑照片,这将是一个大问题。
答案1
好的,我搞明白了。一般的想法是将数据库的新部分复制到旧部分,从而拥有一个完全正常工作的数据库。在整个过程中,我将“旧”照片/数据库称为在删除存储之前可以正常工作的照片/数据库,将“新”照片/数据库称为在某个日期之后可以正常工作的照片/数据库(可能具有不同的存储位置,或在删除照片后添加),但“旧”照片无法正常工作的照片/数据库。希望这有意义。:)
要实现此功能,您需要先备份 Shotwell 数据库。因此我假设您对数据库的存储位置有所了解。
准备
备份所有内容! 我不是在开玩笑,没有人能保证这会起作用。
第一步,安装 sqliteman
sudo apt-get install sqliteman
之后,使用 Sqliteman 打开备份的 Shotwell 数据库。然后在输入框中输入以下内容:
SELECT id, filename, flags FROM phototable;
按 F9 运行命令。您应该看到所有照片的引用都出现在滚动框中。滚动到底部,并验证最后一张照片的“标志”字段是否为“0”。这表明该文件在 Shotwell 上次运行时存在且正常工作。记下最后一个 ID 值。我们称之为“phototable_max”。
现在,删除上一个命令并运行以下命令:
SELECT id, filepath, flags FROM backingphototable;
这将显示您所做的所有编辑。再次记下最后一个 ID 值。将其命名为“backingphototable_max”。
再次删除该命令并运行以下命令:
SELECT id, name FROM eventtable;
您将看到事件列表。再次注意最后一个值。这个是“eventtable_max”。这有点重复,但现在删除该命令并运行此命令:
SELECT id, name FROM tagtable;
注意最高值“tagtable_max”。
好的,现在我们有了在 Shotwell 被破坏之前可以使用的 ID 号。此后,我假设数据库可以正常工作 - 即在您备份之后,所有照片都不会被标记为丢失。
SQLite 时间!
现在将新数据库复制到旧数据库。
一定要对你的备份进行多次备份。您很有可能会搞砸这一切。您不会想永远丢失 Shotwell 数据库。
好的,关闭 Sqliteman。是时候进行一些 CLI 工作了。在这里,我假设您的旧 shotwell 数据库位于“~/.local/share/shotwell-old/data/photo.db”,新数据库位于“~/.local/share/shotwell-new/data/photo.db”
sqlite3 ~/.local/share/shotwell-old/data/photo.db
现在您将看到 SQLite 提示符。在其中输入:
ATTACH "/home/sean/.local/share/shotwell-new/data/photo.db" AS new;
不要忘记 ; 并且显然要用您的用户名替换“sean”。是的,您必须使用完整路径。
现在我们只需执行这些命令,一切就大功告成了!您必须将 _max 值替换为您之前记下的值。
INSERT INTO phototable SELECT * FROM new.phototable WHERE new.phototable.id > phototable_max;
INSERT INTO backingphototable SELECT * FROM new.backingphototable WHERE new.backingphototable.id > backingphototable_max;
INSERT INTO eventtable SELECT * FROM new.eventtable WHERE new.eventtable.id > eventtable_max;
INSERT INTO tagtable SELECT * FROM new.tagtable WHERE new.tagtable.id > tagtable_max;
DELETE FROM videotable;
INSERT INTO videotable SELECT * FROM new.videotable;
我们在这里所做的是将所有较新的值从新数据库的工作部分复制到旧工作数据库中。最后两行删除然后复制视频表,在恢复丢失的文件时,它会自行整理好。
然后按Ctrl+D关闭sqlite3解释器。
您现在可以将 photo.db 文件移动到 Shotwell 位置,即“~/.local/share/shotwell/data/photo.db”,然后打开 Shotwell,一切就绪!请确保此时已连接硬盘或外部存储。
我发现 Shotwell 在第一次打开时运行得有点慢,但它最终重新缓存了所有内容并再次运行。
另外,请注意,我认为由于我们复制标签表的方式,应用于新照片的现有标签将会丢失。但是任何新标签都应该保留,同样,旧照片上的所有旧标签也会保留。这是因为 Shotwell 存储标签信息的方式很奇怪 - 数据库中的每个标签记录都存储它标记的照片。