読者です 読者をやめる 読者になる 読者になる

モロ屋

アキバではたらくWebエンジニア。JavaScript / AWS / Mac

PHPでnasneの録画情報を取得する

やってみた

nasneなら出来そうな気がした

ソニーが出してるnasneというネットワークレコーダーがありまして、わしはこれを使って毎日アニメを録画する日々を送っています。かなり未視聴が貯まってますが。

nasne (ナスネ) (CECH-ZNR1J)

nasne (ナスネ) (CECH-ZNR1J)

その名の通りNASなのでネットワークに繋いで色々出来るんですね。

DTCP-IPっていうのに対応してるクライアントを使えばスマホタブレットで録画番組が見れたり、CHAN-TORUっていうサイトにnasneを登録しておけば外出先からでも予約を入れられたり凄い便利なんです。

で、これならAPIとか探すだけで簡単に予約入れられそうな気がしたので調べてみました。

DLNA

こういったメディア機器間の通信は、DLNAという業界標準が策定されている模様。

今回はメディアのコーデックとかその辺はどうでもよくて、録画の操作をしたいだけなのでいろいろ割愛。

nasneは、このDLNAをさらに拡張して録画の投入や情報取得を行っているようなので、パケットを解析して調査。

nasneが提供しているService

http://(nasneIPアドレス):58888/

に接続すると、以下のようなXMLが取得出来る

<root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:dlna="urn:schemas-dlna-org:device-1-0" xmlns:av="urn:schemas-sony-com:av" xmlns:s-bras="urn:s-bras-org:s-bras">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMS-1.50</dlna:X_DLNADOC>
<dlna:X_DLNACAP xmlns:dlna="urn:schemas-dlna-org:device-1-0">dtcp-move</dlna:X_DLNACAP>
<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>
<friendlyName>molonasne</friendlyName>
<manufacturer>Sony Computer Entertainment Inc.</manufacturer>
<manufacturerURL>http://www.playstation.com/</manufacturerURL>
<modelDescription>nasne</modelDescription>
<modelName>nasne</modelName>
<av:standardCDS>5.0</av:standardCDS>
<av:videoRoot>0/video</av:videoRoot>
<av:musicRoot>0/music</av:musicRoot>
<av:photoRoot>0/photo</av:photoRoot>
<av:X_WakeupOnLAN>1</av:X_WakeupOnLAN>
<av:videoLiveTunerContainer>0/video/LiveTuner</av:videoLiveTunerContainer>
<s-bras:productName xmlns:s-bras="urn:s-bras-org:s-bras">CECH-ZNR1J</s-bras:productName>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:ContentDirectory:1</serviceType>
<serviceId>urn:upnp-org:serviceId:ContentDirectory</serviceId>
<SCPDURL>
http://192.168.11.100:58888/MediaServer_ContentDirectory/scpd.xml
</SCPDURL>
<controlURL>
http://192.168.11.100:58888/MediaServer_ContentDirectory/control
</controlURL>
<eventSubURL>
http://192.168.11.100:58888/MediaServer_ContentDirectory/event
</eventSubURL>
</service>
<service>
<serviceType>
urn:schemas-xsrs-org:service:X_ScheduledRecording:2
</serviceType>
<serviceId>urn:xsrs-org:serviceId:X_ScheduledRecording</serviceId>
<SCPDURL>http://192.168.11.100:64230/XSRS.xml</SCPDURL>
<controlURL>http://192.168.11.100:64230/XSRS</controlURL>
<eventSubURL>http://192.168.11.100:64230/XSRS</eventSubURL>
</service>
</serviceList>
</device>
</root>

一部省略しているが、SOAPでやりとり出来ることが分かる。
(192.168.11.100は、我が家のnasneのローカルIP)

この中でも「urn:schemas-upnp-org:service:ContentDirectory」などはDLNAで定義されている部分だが「urn:schemas-xsrs-org:service:X_ScheduledRecording」はnasneが拡張した部分っぽい。

XSRS.xmlをのぞいてみると

<scpd xmlns="urn:schemas-upnp-org:service-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<actionList>
<action>
<name>X_CreateRecordSchedule</name>
<argumentList>
<argument>
<name>Elements</name>
<relatedStateVariable>A_ARG_TYPE_Result</relatedStateVariable>
<direction>in</direction>
</argument>
<argument>
<name>RecordScheduleID</name>
<relatedStateVariable>A_ARG_TYPE_ObjectID</relatedStateVariable>
<direction>out</direction>
</argument>
<argument>
<name>Result</name>
<relatedStateVariable>A_ARG_TYPE_Result</relatedStateVariable>
<direction>out</direction>
</argument>
<argument>
<name>UpdateID</name>
<relatedStateVariable>StateUpdateID</relatedStateVariable>
<direction>out</direction>
</argument>
</argumentList>
</action>
</serviceStateTable>
</scpd>

長いのでがっつり省略しているがこんな感じ。

これはSCPDというもので、SOAPWSDLにあたる。

まぁ提供しているAPIの種類と、パラメータなどが書いてある説明書みたいなものだと考えれば楽。

ではリクエストを投げてみましょう

SOAPなのでHTTPリクエストを投げればOKだけど、64230ポートから投げる必要がある。

PHPでfsockopenでソケットを開いて、HTTPリクエストを組み立ててそのまま送ってみた。これと同じことはTelnetでも出来る。

<?php
$fp = fsockopen('192.168.11.100', 64230);

$data = <<<EOM
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <u:X_GetTitleList xmlns:u="urn:schemas-xsrs-org:service:X_ScheduledRecording:2">
         <SearchCriteria />
         <Filter />
         <StartingIndex>0</StartingIndex>
         <RequestedCount>0</RequestedCount>
         <SortCriteria />
      </u:X_GetTitleList>
   </s:Body>
</s:Envelope>
EOM;
$data = str_replace("\n", "\r\n", $data);
$length = strlen($data);

$request = <<<EOM
POST /XSRS HTTP/1.1
HOST: 192.168.11.100:64230
SOAPACTION: "urn:schemas-xsrs-org:service:X_ScheduledRecording:2#X_GetTitleList"
CONTENT-TYPE: text/xml; charset="utf-8"
Content-Length: {$length}
EOM;
$request = str_replace("\n", "\r\n", $request);

fwrite($fp, $request . "\r\n\r\n" . $data);
ob_start();
fpassthru($fp);
$response = ob_get_clean();
fclose($fp);

$response = explode("\r\n\r\n", $response, 2);

var_dump($response);

192.168.11.100 になっている部分は、適宜自分の家のnasneのローカルIPに書き換えればOK

するとXMLが返ってくる。

XMLよりJSONの方が好きなので、JSONに変換すると以下のようなデータが取得できる。

[
{
attributes: {
id: "13779485880000000254"
},
title: "きんいろモザイク #9",
scheduledStartDateTime: "2013-08-31T20_29_49+0900",
scheduledDuration: "1814",
scheduledChannelID: "0x014d",
desiredQualityMode: "230",
genreID: "112",
reservationCreatorID: "2210",
titleProtectFlag: "0",
titleNewFlag: "1",
recordingFlag: "0",
recordDestinationID: "USBHDD",
recordSize: "634",
lastPlaybackTime: "notplayed",
portableRecordFile: "255"
},
{
attributes: {
id: "13779611860000000255"
},
title: "<物語>シリーズ セカンドシーズン",
scheduledStartDateTime: "2013-08-31T23_59_46+0900",
scheduledDuration: "1817",
scheduledChannelID: "0x5c38",
desiredQualityMode: "230",
genreID: "112",
reservationCreatorID: "2000",
titleProtectFlag: "0",
titleNewFlag: "0",
recordingFlag: "0",
recordDestinationID: "USBHDD",
recordSize: "1480",
lastPlaybackTime: "2013-09-02T01_33_25+0900",
portableRecordFile: "276"
}]

予約も入れたい

情報は取得出来たんだけど、予約を入れるパラメータがまだ解析し終わってないので入れられない。

そのうち時間があれば、予約入れる方法も確立して「$ php nasne.php rec 2013_autumn_anime」とか出来るようにしたいね…