Tới thẳng nội dung

Định dạng mở

Định dạng .tmln, và vì sao lấy dữ liệu ra luôn miễn phí

Một tệp zip chứa một manifest, một data.json và một thư mục media. Hai định dạng mang được cả khu vườn cũng là hai định dạng chúng tôi không bao giờ thu tiền.

Đổi đuôi một tệp .tmln thành .zip rồi mở ra. Bên trong có ba thứ:

  • manifest.json — gói này là gì: định dạng, phiên bản schema, bản dựng nào ghi ra, ghi lúc nào, bao nhiêu cây và bao nhiêu kỷ niệm, bao nhiêu byte media, chế độ media nào, và một mã SHA-256 của tệp dữ liệu.
  • data.json — mọi dòng thời gian, kỷ niệm, bản ghi media, thẻ, người và số đo, dưới dạng văn bản đọc được.
  • media/ — các tệp thật. Ảnh, video, ghi âm, bản quét.

Cả định dạng chỉ có thế. Nó nhàm chán một cách có chủ ý, và hai thứ đáng nói về nó đều là hệ quả của cái thư mục cuối cùng kia.

Vì sao đóng gói byte trước

Bộ xuất ghi media/ xong mới ghi data.json, và thứ tự đó gánh việc thật.

Một tấm ảnh đã mã hoá lại là một tệp khác. Khác dung lượng, khác kích thước, khác mã băm. Nếu data.json được ghi ra từ cơ sở dữ liệu — tức là mô tả ảnh gốc — mà trong gói lại là ảnh đã thu nhỏ, thì lúc quay về, từng tệp một sẽ trượt kiểm tra toàn vẹn, và bộ nhập sẽ vứt sạch, một cách hoàn toàn có lý. Nên media được đóng trước, còn tệp dữ liệu được ghi để mô tả thứ thật sự đang nằm trong gói, không phải thứ nằm trong cơ sở dữ liệu lúc bắt đầu xuất.

Đây là loại lỗi không bao giờ lộ ra ở bài kiểm thử có đúng một tấm ảnh, và luôn lộ ra vào ngày ai đó khôi phục một khu vườn thật.

Ba cách đóng gói media

Hộp thoại xuất đưa ba chế độ, và chế độ ở giữa có một lưu ý mà chúng tôi nói thẳng:

  • Tệp gốc — từng byte, đúng như đang lưu. Chế độ duy nhất khôi phục lại được trọn vẹn.
  • Ảnh nhỏ hơn — ảnh mã hoá lại còn 1280 pixel cạnh dài, đưa một tấm gốc 4 MB xuống còn vài trăm KB. Video và ghi âm ở lại, vì “ảnh thu nhỏ” của một video là một khung hình đứng, còn của một bản ghi âm thì chẳng là gì cả.
  • Không kèm tệp — đúng phần nội dung mà bản xuất JSON mang, gói lại thành package.

Ở hai chế độ có mất mát, các dòng media vẫn nằm nguyên trong data.json dù byte của chúng không đi theo. Bỏ luôn cả dòng thì mất luôn cái sự thật rằng tấm ảnh đó từng tồn tại — và bộ nhập đếm riêng những trường hợp này để nói cho bạn biết khác biệt.

Lúc quay về

Bộ nhập kiểm tra toàn bộ gói trước khi động vào bất cứ thứ gì. Một tệp hỏng không bao giờ vào được nửa chừng: hoặc bạn nhập xong, hoặc bạn nhận một thông báo lỗi, chứ không bao giờ có một khu vườn ở trạng thái chẳng ai thiết kế ra.

Sau đó nó hợp nhất theo id, bản có updatedAt mới hơn thì thắng. Bản bị từ chối không bị xoá — nó nằm ở mục Xem lại phần đã nhập, nơi bạn xem cỗ máy đã quyết gì và có quyền không đồng ý. Byte media được đối chiếu với mã băm ghi trong data.json trước khi ghi xuống, và nếu trên máy đã có đúng dãy byte đó thì hệ thống trỏ vào bản cũ chứ không chép thêm.

Bốn kiểu hỏng, đếm riêng ra

Khi có chuyện, màn hình kết quả đếm bốn kiểu hỏng riêng ra, và chính chỗ phân biệt đó mới là điểm mấu chốt:

  • Thiếu — tệp có tên trong danh sách nhưng byte không nằm trong gói. Bạn đã xuất kiểu chỉ-JSON, hoặc một chế độ có mất mát.
  • Hỏng — byte có đó nhưng không khớp mã băm.
  • Không ghi được — byte có đó và còn nguyên, nhưng chiếc iPhone này không còn chỗ đặt. Tức là đầy ổ.
  • Dùng lại — byte vốn đã có sẵn ở đây, nên không chép gì cả.

“Tệp của bạn không chứa mấy cái này” và “máy này không còn chỗ để đặt” cần hai lời khuyên ngược nhau. Một dòng “12 tệp thất bại” thì dễ làm hơn nhiều, và vô dụng đúng vào lúc nó hiện ra.

Bản xuất JSON, và thứ nó cố ý không phải

Đứa em của .tmln là một tệp JSON thường, và khác biệt giữa hai bên đúng một thứ: phần byte. JSON mang toàn bộ kỷ niệm, thẻ, người, địa điểm và số đo dưới dạng văn bản đọc được — kể cả những cái riêng tư, vì đây là dữ liệu của chính bạn đi ra chứ không phải món kỷ niệm bạn có thể đưa cho ai đó xem, và nó chưa bao giờ bị đóng dấu ở gói nào. Tệp đính kèm chỉ hiện ra thành các mục có tên, loại và dung lượng; tệp thật không nằm bên trong. Hộp thời gian đã niêm phong thì vẫn niêm phong khi đi.

Đây là định dạng để bạn đọc khu vườn của mình bằng một trình soạn thảo văn bản, chạy một đoạn script lên nó, hoặc kiểm tra xem ứng dụng nghĩ nó biết gì về bạn. Nó không phải định dạng để khôi phục, và ứng dụng nói rõ cái nào ra cái nào, thay vì để bạn phát hiện ra trên một chiếc máy mới.

Phiên bản schema, và chuyện từ chối thay vì đoán

Cả hai tệp đều mang schemaVersion, hiện tại là 1. Một bản dựng đọc con số đó trước khi đọc bất cứ thứ gì khác, và nếu số ấy cao hơn số nó hiểu thì nó dừng lại bằng một câu gọi đúng tên tình huống: tệp này được tạo bằng một phiên bản Timegrove mới hơn.

Đó là một lời từ chối có chủ ý. Phương án kia — giải mã phần nào nhận ra, bỏ phần nào không — chính là cách một lần nhập âm thầm đánh rơi một trường dữ liệu mà phiên bản sau mới thêm vào, còn người dùng thì mấy năm sau mới biết, nếu có biết. Trong cùng một phiên bản thì bộ giải mã lại rộng lượng theo chiều ngược lại: chỉ schemaVersion, timelinesevents là bắt buộc, thiếu gì thì cái đó giải ra thành rỗng. Một tệp hoàn toàn hợp lệ mà không có media, hoặc không có thẻ, thì phải nhập được — mà có một dạo nó không nhập được: bộ giải mã Swift tự sinh đòi đủ mọi khoá bất kể đã có giá trị mặc định, và cách sửa là viết tay một bộ khác.

Nếu bạn muốn khoá lại

Để trống ô mật khẩu thì ra một tệp .tmln thường. Đặt mật khẩu thì cả gói được mã hoá AES-256-GCM trước khi rời khỏi ứng dụng, và đuôi tệp thành .tmlnx. Không có mật khẩu thì không đọc được gì trong đó — tên cây cũng không, số ảnh cũng không, cả manifest cũng không.

Và quên là không ai cứu được. Chẳng có tài khoản nào để đặt lại mật khẩu, mà đó cũng chính là cái kiến trúc khiến không có máy chủ nào đang giữ khu vườn của bạn, nhìn từ phía nó bắt bạn trả giá. Hộp thoại nói câu này bằng chữ đậm trước khi bạn bấm xác nhận, vì đó là màn hình duy nhất trong app mà một giọng vui vẻ sẽ thành nói dối.

Đồ kỷ niệm không phải bản sao lưu

Sách PDF và chuyện kể HTML thì đẹp, và chúng đi một chiều. Không thể biến ngược thứ gì bên trong chúng thành một cái cây. Thử nhập vào thì ứng dụng nói thẳng bằng một câu chứ không phải một đống lỗi kỹ thuật: sách PDF là thứ để đọc và giữ làm kỷ niệm, không phải bản sao lưu — trong đó không có gì để mang về cả.

Chúng tôi có thể im lặng cho nó thất bại. Nhưng gọi tên đúng sự khác biệt về chủng loại thì có ích hơn một dòng “tệp không được hỗ trợ”, vì người đang làm việc đó thường đang giữa chừng chuyển máy và không cần thêm một câu đố.

Vì sao lối ra miễn phí

JSON và .tmln miễn phí ở cả hai gói, không giới hạn số lần, và không bao giờ bị đóng dấu. Hai định dạng thu tiền là hai thứ đồ kỷ niệmcuốn sách PDF và trang HTML tương tác — nơi gói miễn phí có một bản mỗi tháng kèm dòng chân trang nhỏ ở mỗi trang thứ mười.

Cái vạch đó không tuỳ tiện. Một định dạng đưa dữ liệu của bạn ra ngoài thì không phải một tính năng; nó là lối ra. Thu tiền lối ra, bóp băng thông lối ra, hay đóng dấu lên lối ra, là biến một ứng dụng ký ức thành một vụ bắt giữ con tin có gói thuê bao đi kèm — và mọi lập luận ủng hộ chuyện đó đều là lập luận rằng khu vườn của bạn đáng giá với chúng tôi hơn khi bạn không mang nó đi đâu được. Một cuốn sách do chúng tôi thiết kế và dựng ra là thứ chúng tôi làm. Mười bốn năm ảnh của bạn thì không.

Nói cho thực tế hơn: nếu ứng dụng này ngừng phát triển, bạn vẫn đọc được dữ liệu của mình bằng một trình soạn thảo văn bản và một công cụ giải nén, trên máy nào cũng được, mãi mãi. Định dạng mở sinh ra để làm việc đó, và đó là lý do trang quyền riêng tư và bản đặc tả định dạng nói cùng một điều bằng hai giọng khác nhau. Thêm nữa ở mục Định dạng mở.