Синхронизация с LiveJournal

Статья была написана для HostInfo.ru.

Думаю, мало кто поспорит, что блоги (в частности, сервис LiveJournal) стабильно обосновались в нашей жизни как (как минимум) довольно удобный способ узнать, что нового происходит в жизни друзей и знакомых. Еще интересно бывает следить за блогами незнакомых, но пишущих интересные статьи людей. Не стоит забывать и сообщества, коих великое множество. Таким образом, довольно приличное количество людей начинают свой день (или, напротив, завершают его) просмотром так называемой «френдленты», в которой к одной колонке сводятся все записи из интересующих журналов. Некоторые даже специально заводят аккаунты, которыми пользуются исключительно для того, чтобы одной страницей читать все новости. И нет-нет да и проскакивает мысль: «А как удобно было бы читать вот тот вот сайт в этой же френдленте». Действительно, есть огромное количество сайтов-блогов, ведущихся по тому же принципу, что и на LiveJournal, но на собственном хостинге. Если у вас подобный блог, почему не сделать синхронизацию, чтобы при изменениях на сайте автоматически изменялось его «зеркало» в LiveJournal?

В принципе, например, если ваш блог построен на CMS WordPress, то можно взять готовый плагин, синхронизирующий записи с сайта с аккаунтом в LiveJournal. Но это типовое решение, и в данной статье мы рассмотрим процесс чуть глубже, на уровне интерфейсов LiveJournal.

Будем считать, что процесс добавления новостей на свой собственный сайт вы наладили, и сосредоточимся на дублировании этих записей непосредственно в «Живой журнал». Собственно, для добавления записи у нас масса возможностей: через SMS, через Jabber, электронную почту. Однако нас интересуют два более гибких интерфейса: Flat- и XML-RPC-протоколы.

Flat Client/Server Protocol Flat Client/Server Protocol представляет собой обработку обычных POST-запросов. Например, страница, содержащая такую форму, может быть использована для добавления сообщений в любой дневник:

 <form accept-charset="UTF-8" method="post" name="postform"

 action="http://www.livejournal.com/interface/flat">

 <input type=hidden name=mode value="postevent">

 <input type=hidden name=user value="username">

 <input type=hidden name=password value="password">

 <input type=hidden name=auth_method value="clear">

 <input type=text name=year value="2007">

 <input type=text name=mon value="05">

 <input type=text name=day value="31">

 <input type=text name=hour value="17">

 <input type=text name=min value="0">

 <input type=text name=subject value="тема"><br /><br />

 <textarea name=event>сообщение</textarea><br /><br />

 <input type=button value="Ok" onclick="postform.submit()"><br />

 </form><br />


Естественно, в поля user и password вписываются логин и пароль журнала, в который, собственно, мы хотим добавить запись. В ответ на эту форму сервер (если данные учетной записи верны) выдаст ответ подобного вида:


 anum

 192

 itemid

 7

 success

 OK

 url

 http://user.livejournal.com/1984.html


Значение success, равное «OK», говорит о том, что сообщение успешно добавлено в журнал. В случае неудачи этот параметр будет равен FAIL. Параметр anum, судя по документации, предназначен для вычисления публичного itemid записи. На самом же деле я так и не встретил ситуации, когда бы этот параметр пригодился. Параметр itemid содержит номер записи в данном дневнике, и его можно, например, запомнить в базе – он может понадобиться для редактирования записи. Последний параметр – url – содержит прямую ссылку на запись.

Вуаля, треть нашей задачи мы осуществили: теперь при добавлении новости на сайт эта же новость без труда дублируется в «ЖЖ». Две оставшиеся трети проблемы решаются следующим образом:


 <form accept-charset="UTF-8" method="post" name="postform"

 action="http://www.livejournal.com/interface/flat">

 <input type=hidden name=mode value="editevent">

 <input type=hidden name=itemid value="7">

 <input type=hidden name=ver value="1">

 <input type=hidden name=user value="username">

 <input type=hidden name=password value="password">

 <input type=hidden name=mode value="editevent">

 <input type=hidden name=auth_method value="clear">

 <input type=text name=year value="2007">

 <input type=text name=mon value="05">

 <input type=text name=day value="31">

 <input type=text name=hour value="17">

 <input type=text name=min value="0">

 <input type=text name=subject value="тема"><br /><br />

 <textarea name=event>сообщение</textarea><br /><br />

 <input type=button value="Ok" onclick="postform.submit()">

 </form> 


Эта форма отличается от первой рассмотренной только второй и третьей строками. Параметр mode мы установили равным editevent и ввели параметр itemid, который содержит номер редактируемой записи в LiveJournal. Причем если поле event будет пустым, сообщение будет стерто.

XML-RPC Interface
Но Flat-интерфейс все-таки не очень удобен. Более гибким и мощным инструментом является XML-RPC-интерфейс. Для реализации работы с этим интерфейсом на PHP я выбрал библиотеку XML-RPC for PHP. Вот пример функции для добавления сообщения в журнал:


 function post_LJ($year,$month,$day,$hour,$minute,$subject,$event) {

 $lj_userid="user";

 $lj_passwd="password";

 

 $client=new xmlrpc_client("/interface/xmlrpc", "www.livejournal.com", 80);

 

 $params = new xmlrpcval( array(

 	 'username' => new xmlrpcval($lj_userid,'string'),

 	 'password' => new xmlrpcval($lj_passwd,'string'),

 	 'ver' => new xmlrpcval('1','string'),

 	 'lineendings' => new xmlrpcval('pc','string'),

 	 'event' => new xmlrpcval($event,'string'),

 	 'subject' => new xmlrpcval($subject,'string'),

 	 'year' => new xmlrpcval($year,'int'),

 	 'mon' => new xmlrpcval($month,'int'),

 	 'day' => new xmlrpcval($day,'int'),

 	 'hour' => new xmlrpcval($hour,'int'),

 	 'min' => new xmlrpcval($minute,'int')),'struct'

 );

 

 $msg = new xmlrpcmsg('LJ.XMLRPC.postevent');

 $msg->addparam($params);

 $client->setDebug(0);

 $result = $client->send($msg);

 if ($result->faultCode() != 0) {

 print "Ошибка: " . $result->faultString();

 } else {

 printf("Сообщение добавлено");

 };

 };


Если рассматривать процедуру вкратце, то мы сначала формируем XML-запрос, а затем отсылаем его серверу на обработку. В ответ мы получаем тоже XML-файл, но уже с результатами. Мы можем получить и распечатать любую запись из дневника:


 function view_LJ($itemid) {

 $lj_userid="user";

 $lj_passwd="password";

 

 $client=new xmlrpc_client("/interface/xmlrpc", "www.livejournal.com", 80);

 

 $params = new xmlrpcval( array(

 	 'username' => new xmlrpcval($lj_userid,'string'),

 	 'password' => new xmlrpcval($lj_passwd,'string'),

 	 'ver' => new xmlrpcval('1','string'),

 	 'lineendings' => new xmlrpcval('pc','string'),

 	 'selecttype' => new xmlrpcval('one','string'),

 	 'itemid' => new xmlrpcval('itemid','string'),

 	 'year' => new xmlrpcval($year,'int'),

 	 'month' => new xmlrpcval($month,'int'),

 	 'day' => new xmlrpcval($day,'int')),'struct'

 );

 

 $msg = new xmlrpcmsg('LJ.XMLRPC.getevents');

 $msg->addparam($params);

 $client->setDebug(0);

 $result = $client->send($msg);

 if ($result->faultCode() != 0) {

 print "Ошибка: ".$result->faultString();

 return;

 };

 

 $v=$result->value();

 $events=$v->structMem('events');

 $event = $events->arrayMem(0);

 $itemid_xml=$event->structMem('itemid');

 $eventtime_xml=$event->structMem('eventtime');

 $subject_xml=$event->structMem('subject');

 $event_xml=$event->structMem('event');

 

 $itemid=$itemid_xml->scalarVal();

 $subject=$subject_xml->scalarVal();

 $eventtime=$eventtime_xml->scalarVal();

 $event=$event_xml->scalarVal();

 

 printf("$eventtime<br /><br />");

 printf("$subject<br /><br />");

 printf("$event<br />");

 

 };


То есть при большом желании можно не хранить записи на сайте, а получать их в момент формирования страницы со своего «ЖЖ»-аккаунта.

Редактирование и удаление записей производится по аналогии с примером, приведенном для Flat-интерфейса:


 function post_LJ($itemid,$year,$month,$day,$hour,$minute,$title,$message) {

 $lj_userid="user";

 $lj_passwd="password";

 

 $client=new xmlrpc_client("/interface/xmlrpc", "www.livejournal.com", 80);

 

 $params = new xmlrpcval( array(

 	 'username' => new xmlrpcval($lj_userid,'string'),

 	 'password' => new xmlrpcval($lj_passwd,'string'),

 	 'ver' => new xmlrpcval('1','string'),

 	 'itemid' => new xmlrpcval($itemid,'int'),

 	 'event' => new xmlrpcval($message,'string'),

 	 'lineendings' => new xmlrpcval('pc','string'),

 	 'subject' => new xmlrpcval($title,'string'),

 	 'year' => new xmlrpcval($year,'int'),

 	 'mon' => new xmlrpcval($month,'int'),

 	 'day' => new xmlrpcval($day,'int'),

 	 'hour' => new xmlrpcval($hour,'int'),

 	 'min' => new xmlrpcval($minute,'int')),'struct'

 );

 

 $msg = new xmlrpcmsg('LJ.XMLRPC.editevent');

 $msg->addparam($params);

 $client->setDebug(0);

 $result = $client->send($msg);

 if ($result->faultCode() != 0) {

 print "Couldn't process request: ".$result->faultString();

 return;

 };

 };


Таким образом можно реализовывать довольно интересные комбинации. Например, вы можете вести дневник на LiveJournal и вкраплять в ленту записей новости своего сайта. Или, напротив, разбавлять новости на главной странице записями из своего «ЖЖ». Также можно не ограничиваться одним аккаунтом, а, допустим, если у вас музыкальная группа, то на странице сайта можно собрать до кучи записи из «ЖЖ»-аккаунтов всех участников. В общем, возможности ограничиваются исключительно вашей фантазией и производительностью сервера.


28 июня 2007

Опубликовано на HostInfo.ru 29 июня 2007.