AQUOS(液晶テレビ)の死にかけた録画用外付HDDをUbuntuで復活させた話

 

1. HDDが見られなくなった

長年使っていたシャープAQUOS(昔流行った亀山モデルの液晶テレビ)の録画用外付HDDが再生中にカクカクとコマ送りのようになったり、再生が数秒間ストップしてしまったりなど、調子が悪いなと思っていた矢先のことだった。

そしてその時は突然やってきた。遂にHDDが認識されなくなってしまったのだ😱

HDDには2012年頃から2026年まで、10年以上の長きにわたる思い出とも呼べる番組の数々が録画されていた。

この記事はそんな思い出の詰まった死にかけのHDDを復活させるまでの記録である。

  • テレビ:シャープ LC-40LX3
  • 故障した外付HDD:アイ・オー・データ機器 HDCR-U2.0E(2TB)
  • 新しい外付HDD:アイ・オー・データ機器 HDC-LA2.0(2TB)

2. HDDを読み込めるか確認する

まず、ネットを検索すると以下を見つけた。
(このサイトはhttpなのでブラウザの警告が出ると思います。自己責任で閲覧下さい。)

つまらない日記 - livedoor Blog

これを頼りにチャッピー(ChatGPT)に相談。Ubuntuでの作業を薦められたので従った。Ubuntuのインストール方法についてはこの記事では触れない。

早速作業開始、

lsblk -b -d -o NAME,SIZE,MODEL,SERIAL

でHDDを確認した。

sdb 2000398934016 HDCR-U 000010B121700704 

Ubuntuからは2TBのHDDとして認識されていた。
一縷の望みがつながった😂
つまり、HDDそのものが完全に読めなくなったわけではなさそうだった。

HDDが /dev/sdb として認識されていることを確認したうえで、カーネルログを確認した。以下はLinuxカーネルが出したメッセージのうち、最新50行を表示するものだ。

sudo dmesg | tail -50

すると /dev/sdb について次のメッセージが出ていた。

sdb: p3 size 4085446656 extends beyond EOD, truncated

extends beyond EOD の EOD は End Of Device(ディスクの終端) を意味する。つまり、パーティションテーブル上の第3パーティションが、実際のHDD容量を越える位置まで存在することになっていた。Linuxはその矛盾を検出し、実際のディスク終端までに切り詰めて(truncated)扱っていた。

HDD自体の容量がおかしいのではなく、HDDに記録されたパーティション情報と実際のディスク容量が整合していない状態だった。

3. 故障HDDを丸ごとコピーする

この状態で元HDDを直接いじるのは危険なので、まず別の2TB HDDへ丸ごとコピーした。コピー先HDDは自宅に転がっていたものを使用(廃棄した会社サーバーから抜き取って破壊して捨てようとしていたもの)。

GNU ddrescueを使用した。

sudo ddrescue -f -n /dev/sdc /dev/sdb /run/media/ubuntu/Jet64/aquos-rescue.map

今回、日を改めて2台のHDDをつなげたので、

/dev/sdc → 故障HDD
/dev/sdb → コピー先HDD

だった。

コピーには約18時間かかった。

最終的には、

rescued:     2000 GB
pct rescued: 99.99%
read errors: 55
bad-sector:  17920 B

となった。

以降は故障した元HDDではなく、このコピー先HDDを救出HDDとして使用した。

0BF18141-08A3-42F9-B061-14751AF6D403.PNG

4. 救出HDDから録画ファイルを読み出す

ddrescueで丸ごとコピーしたHDDを故障HDDのケースに入れ替え、一度AQUOSへ接続してみたが、認識されなかった。そんなに甘くはなかった。

そこでUbuntuから直接中身を読むことにした。

XFSがディスク先頭から2048セクタ後に存在していた。

2048 × 512
= 1,048,576 bytes

そこでパーティションテーブルを使わず、この位置からloopデバイスを作成した。

sudo losetup --find --show --read-only --offset 1048576 /dev/sdb

今回は /dev/loop18 が作成された。

これを読み取り専用でマウントする。

sudo mkdir -p /mnt/aquos_old
sudo mount -t xfs -o ro,norecovery /dev/loop18 /mnt/aquos_old

中を見ると、

20120826204539489.tts
20130329173955715.tts
...
20260820215955067.tts

という大量の .tts ファイルが見えた。

さらに、

.AquosMediaInfo
AquosDB.edb
AquosDB.edb.bkup
aquos.conf

も存在していた。

.tts は140本、合計約1.28TB。録画データは残っていた。

5. 新しいHDDをAQUOSで初期化する

次に、録画を移すための新しい2TB HDDを用意した。

ここで一つ問題にぶち当たった。

AQUOSの設定画面には旧HDDの登録情報が残っており、新しいHDDを追加するためのメニューがグレーアウトして選択できない状態だった。

どうやら先へ進むには、テレビに残っている旧HDDの登録情報を削除する必要があるようだ。

しかし、ここは迷った。

旧HDDの登録を削除したら、録画を見るために必要な情報までテレビ側から消えてしまうのではないか?

これを削除してしまえば、元には戻せないかもしれない。

ただ、新HDDを登録しない限り先に進めない。もう進むしか道は無いのだ。
覚悟を決めて旧HDDの登録情報を削除、新HDDをAQUOSに登録・初期化した。

結果的には、この操作を行っても後の復旧には問題なかった。

新HDDを初期化後、Ubuntuへ接続するとXFSとして認識された。

sudo mkdir -p /mnt/aquos_new
sudo mount -t xfs /dev/sdc1 /mnt/aquos_new

新HDDには最初から、

.AquosMediaInfo
AquosDB.edb
AquosDB.edb.bkup
aquos.conf

が作成されていた。

6. まず.ttsだけをコピーする

最初は、冒頭のサイトに従って .tts だけをコピーした。

sudo rsync -avh --info=progress2 /mnt/aquos_old/*.tts /mnt/aquos_new/

約1.28TBのコピーに約8時間かかった。

ファイル数も確認した。

sudo find /mnt/aquos_new -maxdepth 1 -type f -name '*.tts' | wc -l

結果は、

140

だった。

7. 認識せず、.ttsも消えた

新HDDをAQUOSへ戻した。

しかし、録画一覧は復活しなかった。

さらにUbuntuへ戻して確認すると、コピーした .tts も消えていた😭

ここで、

AQUOSはHDD内の.ttsを探して録画一覧を作っているわけではない

ことが分かった。

冒頭のサイトに従ったのだが、サイトをもう一度見返すと記事の下部のコメント欄の中にAquosDB.edb、AquosDB.edb.bkup、aquos.confもコピーする必要があると投稿している人がいた💡

8. .ttsと管理ファイルをコピーする

新HDDをもう一度AQUOSで初期化。

今度は .tts に加えて、

AquosDB.edb
AquosDB.edb.bkup
aquos.conf

も旧HDDからコピーした。(またもや8時間)

sudo rsync -avh --info=progress2 /mnt/aquos_old/*.tts /mnt/aquos_new/

sudo cp -a /mnt/aquos_old/AquosDB.edb /mnt/aquos_new/
sudo cp -a /mnt/aquos_old/AquosDB.edb.bkup /mnt/aquos_new/
sudo cp -a /mnt/aquos_old/aquos.conf /mnt/aquos_new/

管理ファイルについてはSHA-256も確認し、コピー元とコピー先が一致していることを確認した。

9. .AquosMediaInfoだけは新HDDのものを残す

旧HDDには、

.AquosMediaInfo

というファイルも存在していた。
しかし、これはコピーしなかった。先ほどの記事のコメント投稿を重視した。

最終的な構成はこうなった。

新HDD
│
├─ .AquosMediaInfo     ← 新HDDのもの
│
├─ AquosDB.edb         ← 旧HDDからコピー
├─ AquosDB.edb.bkup    ← 旧HDDからコピー
├─ aquos.conf          ← 旧HDDからコピー
│
└─ *.tts               ← 旧HDDから140本コピー

10. HDDを安全に取り外す

コピー後、

sync

を実行して未書き込みデータをHDDへ反映。

続いて、

sudo umount /mnt/aquos_new
sudo udisksctl power-off -b /dev/sdc

としてHDDを停止してからUSBを抜いた。

11. 復活

新HDDをAQUOSへ戻した。
読み込まれるまで微妙な時間がかかる。嫌な待ち時間だ。

時を見計らってリモコンのボタンを押すと、

録画一覧が復活した‼️

再生もできた。新たに予約による録画もできた。

10数年分の録画が蘇ったのだ。感動した。ありがとうチャッピー💕

まとめ

今回の流れをまとめると、

AQUOSが旧HDDを認識しなくなる
        ↓
UbuntuからHDDを調査
        ↓
XFS自体は残っていることを確認
        ↓
ddrescueでHDDを丸ごと救出
        ↓
救出HDDから140本・約1.28TBの.ttsを確認
        ↓
AQUOSに残った旧HDD登録を削除
        ↓
新HDDをAQUOSで登録・初期化
        ↓
.ttsだけをコピー
        ↓
失敗・.ttsも消える
        ↓
新HDDを再初期化
        ↓
.ttsと3つの録画管理ファイルをコピー
        ↓
.AquosMediaInfoだけ新HDDのものを残す
        ↓
AQUOSへ接続
        ↓
録画一覧復活!

今回の作業のポイントは、


  • 録画本体の.ttsだけでは復元できず、録画管理ファイルも必要
  • 修復より先に故障HDDを複製して救出用HDDを作成する


特に最初にddrescueで故障HDDを救出しておいたため、その後の調査や失敗も、故障HDD本体を触らずに救出HDDで進めることができた。

救出HDDは、しばらくの間は救出マスタとしてそのまま保存しておくつもりである💾



Google Apps Script (GAS) の setValue() で文字列が日付に化ける問題と対策

 

この記事の前提

この記事は、これまで手書きで作成していた仕入伝票を、Googleスプレッドシートからの印字に置き換える作業の中で起こったことを記録したものである。

データシートと伝票レイアウトシートを用意してデータシートの内容を伝票レイアウトシートに吐き出す。紙の仕入伝票の表示位置に合わせてフォントサイズや列幅などを工夫しながらデータが用紙にはまり込むようにレイアウトを整えていく。

図のように金額を記載する場所は3桁ずつ書けるように目盛線で区切られていた。

22B35868-57F1-45D8-96C1-2495308F38CE.PNG

色々とやり様はあるが、今回は数字を通常の数値として右寄せで表示するのではなく、3桁ずつを一定の間隔で配置することにした。

金額を伝票へ吐き出す際には、金額を文字列として扱い、3桁単位に分割する。3桁に満たない部分については、上の桁が存在する場合、必要に応じてゼロ埋めする。
図の例だと、315と000に分割する。

さらに、それぞれの3桁文字列について文字間に半角スペースを挿入し、伝票の桁枠に数字が収まるような表示用文字列を作成する。

例えば、

315

であれば、

3 1 5

という文字列に変換してセルへ書き込む。

ところが、この "3 1 5" を GAS からスプレッドシートに吐き出したところ、意図しない問題が発生した:dizzy_face:

意図しない問題

GASで setValue("3 1 5") のようにスペース区切りの数字文字列をセルに書き込むと、Google スプレッドシートが 日付として自動解釈 してしまう。

// 数量 315 を文字間スペース挿入して書き込みたい
var value = "3 1 5";
ws.getRange("H5").setValue(value);
// → セルには「2003 1 5」が表示される

JavaScript 上では typeof value === 'string' で間違いなく文字列だが、setValue() を経由してスプレッドシートに渡った時点でシート側の自動型変換が働く。

なぜ起きるか

Google スプレッドシートには セルに入力された値を自動的に型推定する機能 がある。これは setValue() による書き込みでも同様に動作する。

スペース区切りの数字(例: "3 1 5")は、シートの日付パーサーが「3月1日 2005年」や「2003年1月5日」のように解釈できるパターンに合致してしまう。

つまり:

  1. GAS側でセル値 315 を文字列 "3 1 5" を生成
  2. setValue("3 1 5") で書き込み
  3. シート側で "3 1 5" → 日付 2003年1月5日 と自動解釈
  4. セル値が Date オブジェクトに変換される

この挙動は GAS の setValue() に限らず、セルに手入力した場合も同じ。セルに 3 1 5 と打つと日付になる。

影響を受けるパターンの例

入力文字列 シートの解釈 左からどう解釈されるか
"3 1 5" 2003年1月5日 年 → 月 → 日
"1 2 3" 2001年2月3日 年 → 月 → 日
"1 3 0" 2000年1月3日 月 → 日 → 年
"2 0 3" 真ん中は月か日のいずれかとなるため日付と解釈されない "2 0 3" のまま

どう解釈されるかはロケール設定にもよると思われるが、今回は日本語環境のみで未検証。

解決方法

方法1: setNumberFormat('@') でテキスト形式を強制する(推奨)

// セルの表示形式をテキストに設定してから値を書き込む
ws.getRange("H5").setNumberFormat('@').setValue("3 1 5");

setNumberFormat('@') は Excel の「セルの書式設定 → 文字列」と同等。セルの書式が「テキスト」になるため、どんな値を setValue() しても自動型変換が行われない。

ヘルパー関数にまとめると使いやすい:

function setTextValue_(range, value) {
  range.setNumberFormat('@').setValue(value);
}

// 使用例
setTextValue_(ws.getRange("H5"), spaceChars(315));

方法2: 先頭にアポストロフィを付ける

ws.getRange("H5").setValue("'" + "3 1 5");

スプレッドシートではセル先頭の '(アポストロフィ)はテキストプレフィックスとして扱われ、表示には現れない。getValue() で読み戻した際には、当然アポストロフィは残らない:sunglasses:

方法3: 範囲全体に事前にテキスト書式を設定する

転記先の範囲が決まっている場合は、書き込み前に一括で設定しておく:

// 明細行 B5:W10 をテキスト書式に
ws.getRange(5, 2, 6, 22).setNumberFormat('@');

まとめ

  • setValue() は JavaScript の型に関係なく、シート側で自動型変換される
  • スペース区切りの数字は日付として解釈されるケースがある
  • setNumberFormat('@') を setValue() の前に呼ぶことで確実にテキストとして書き込める
  • 文字間スペース挿入のような帳票向け加工を行う場合は、この対策が必須:ramen: