16 января 2011 17:10, Green

Время социализироваться, madru в Twitter и LiveJournal

madru в Twitter и LiveJournal

С сегодняшнего дня настроен кросспостинг в LiveJournal и в Twitter. При публикации любого поста на madru.ru сразу появляется анонс на LiveJournal и через полчаса на Twitter.

Посты, имеющие твиты, теперь показывают количество комментариев на Twitterе.

Этот пост собственно и был тестовым на момент публикации в ЖЖ.

В подвале сайта теперь стоит две иконки, по клику можно перейти на микроблог и в живой журнал. Постить там мы не будем принципиально, задача стоит в увеличении аудитории madru. Но это не значит что сливаться в социалки будет мусор — будем экспортировать полноценный анонс, правда с первым твитом как-то не вышло :)

Как оказалось, реализация такого функционала не простая. Для того чтобы не зависеть от сторонних библиотек, использовался FeedBurner для Twitter'а и xmlrpc для ЖЖ.

Про FeedBurner и твиттер писать не буду, функциональность там стандартная, никаких изменений в движке своего сайта делать не нужно. Так что Гугл вам в помощь. Но про LiveJournal напишу.

Что нам нужно?

  1. При публикации нового поста отправляем его анонс в ЖЖ.
  2. При правке существующего поста, правим его анонс в ЖЖ.
  3. При удалении поста — удаляем анонс из ЖЖ.

Вроде бы все несложно, да? :)

Итак, для работы с ЖЖ читаем сначала хелп: http://www.livejournal.com/doc/server/ljp.csp.xml-rpc.protocol.html. Видим два основных метода, которые могут нам понадобиться:

  • postevent: отправка нового поста в ЖЖ;
  • editevent: правка поста, который уже находится в ЖЖ;

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

Во-первых, нам понадобится библиотека xmlrpc.

Во-вторых, пишем небольшую функцию. Отмечу сразу, как человек, не пытающийся изобретать велосипед, за основу я брал аналог, но правил под себя. Поскольку от исходного варианта осталось лишь несколько комментариев и оригинальных строк кода - публикую свой вариант.

function livejournal_posting($from_cms)
	{
	$errorPrefix = 'LiveJournal: ';
	if ((!$from_cms or !$from_cms['title'] or !$from_cms['announcement'] or !$from_cms['uri'] or !$from_cms['data']) and !$from_cms['itemid'])
		return (array($errorPrefix.'неверна структура передаваемых данных!', false));
	else
		{
		//подключаем библиотеку
		require_once("путь до библиотеки/xmlrpc/lib/xmlrpc.inc");
		//выставляем внутреннюю кодировку,
		//чтоб не было проблем с перекодированием
		$GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';

		//логин и пароль к ЖЖ
		$u_name = 'тут пишем логин';
		$u_pass = 'тут пишем пароль';

		//обращаемся к www.livejournal.com/interface/xmlrpc
		$lj = new xmlrpc_client('/interface/xmlrpc','www.livejournal.com',80);
		//кодировка клиента
		$lj->request_charset_encoding = 'UTF-8';
		//чтоб возвращал в виде php-переменных
		$lj->return_type = 'phpvals';
		//если нужен дебаг
		//$lj->setDebug(3);

		//получаем chellange
		$chellange = $lj->send(
			new xmlrpcmsg('LJ.XMLRPC.getchallenge'));
		if($chellange->faultCode())
			return (array($errorPrefix.'невозможно получить chellange: '.$chellange->faultString(), false));
		$c = $chellange->value();

		//собираем данные для поста
		$data = array();
		//имя пользователя
		$data['username'] = new xmlrpcval($u_name,'string');
		//метод аутентификации: clear, cookie или challenge
		$data['auth_method'] = new xmlrpcval('challenge','string');
		//строка с challenge
		$data['auth_challenge'] = new xmlrpcval($c['challenge'],'string');
		//шифруем пароль
		$data['auth_response'] = new xmlrpcval(md5($c['challenge'] . md5($u_pass)),'string');
		//версия протокола 0 или 1
		//если используется 1, то все данные должны
		//быть в кодировке UTF-8
		$data['ver'] = new xmlrpcval('1','string');
		$data['itemid'] = new xmlrpcval($from_cms['itemid'],'string');
		if (!$from_cms['title'] && !$from_cms['announcement'] && !$from_cms['uri'] && !$from_cms['data'] && $from_cms['itemid'])
			{
			// не формируем элементы поста в $data, чтобы ЖЖ удалил указанный пост
			}
		else
			{
			//символ перевода строк \n или \r\n
			$data['lineendings']=new xmlrpcval("\r\n",'string');
			//название поста в UTF-8
			$data['subject'] = new xmlrpcval(htmlspecialchars(strip_tags($from_cms['title'])),'string');
			//текст поста в UTF-8
			if ($from_cms['announcement'])
				$data['event'] = new xmlrpcval($from_cms['announcement']."\r\n
<p><a href="\"".$from_cms['uri']."\"">читать полностью</a></p>",'string');
			else
				$data['event'] = '';
			//дата
			$data['day'] = new xmlrpcval(date('d', $from_cms['data']),'string');
			$data['mon'] = new xmlrpcval(date('m', $from_cms['data']),'string');
			$data['year'] = new xmlrpcval(date('Y', $from_cms['data']),'string');
			$data['hour'] = new xmlrpcval(date('H', $from_cms['data']),'string');
			$data['min'] = new xmlrpcval(date('i', $from_cms['data']),'string');
			//доступ к посту публичный
			$data['security'] = new xmlrpcval('public','string');

			// определяем не задним ли числом добавляется запись в жж
			$older = false; // по умолчанию нет
			if ($from_cms['data'] < date("U"))
				$older = true;

			//некоторые мета-данные
			$data['props'] = new xmlrpcval(array(
			//true, если пост в отформатирован в html
			'opt_preformatted' => new xmlrpcval(true,'boolean'),
			//true, если запись добавляем задним числом
			'opt_backdated' => new xmlrpcval($older,'boolean'),
			//список тегов через запятую в UTF-8
			'taglist' => new xmlrpcval($from_cms['labels'],'string'),
			),'struct');

			unset ($older);
			}

		$d = new xmlrpcval($data,'struct');
		if (!$from_cms['itemid'])
			{
			// новый пост в lj
			$result = $lj->send(new xmlrpcmsg('LJ.XMLRPC.postevent', array($d)),0,'http11');
			}
		else
			{
			// правка поста в lj или удаление
			$result = $lj->send(new xmlrpcmsg('LJ.XMLRPC.editevent', array($d)),0,'http11');
			}
		//если произошла ошибка, то сообщаем об ошибке
		if($result->faultCode())
			return (array($errorPrefix.'ошибка постинга: '.$result->faultString(), false));

		//если все нормально, то сервер вернет
		//структуру с 3-мя переменными:
		//itemid - идентификатор поста
		//url - URL-адрес поста
		//anum - аутентификационный номер,
		//созданный для этой записи
		$p_data = $result->value();
			return (array('', $p_data['itemid']));
		}
	}

В кратце - функция принимает набор данных от скрипта публикации поста:

  1. 'title' - заголовок поста в ЖЖ
  2. 'announcement' - текст поста в ЖЖ (для нас это анонс поста в нашем блоге)
  3. 'uri' - адрес нашего поста в нашем блоге, чтобы с анонса в ЖЖ поставить ссылку (она прописана внутри функции)
  4. 'data' - дата поста. ВАЖНО! Её нужно передавать в функцию в формате Unix-метки
  5. 'labels' - через запятую без пробелов указываем теги поста (метки)
  6. 'itemid' - идентификатор поста в ЖЖ. При постинге новых постов его вернет функция, для правки старых — его придется хранить в БД вместе с постом в вашем блоге.

На выходе функции всего два параметра:

  1. Текст ошибки (если она есть)
  2. 'itemid', тоже если есть. Для удаленного поста из ЖЖ вернется пустое поле.

Все что остается - правильно вызвать функцию в скрипте постинга вашего блога (или любой новостной ленты) и обработать ошибки. Как-то так.

2 комментария
Liya 17 января 2011, 12:05 Ответить

Здорово здорово! Давно пора!
А что имеется ввиду под анонсом? Абзац текста, который виден в ленте? А весь текст поста можно будет прочитать после перехода по ссылке на madru?

Green 17 января 2011, 12:20 Ответить

Вылезло несколько косяков и сразу наметился план по грандиозным улучшениям. Анонс будет уходить в том виде, в котором захочет админ. Да, весь пост — по ссылке на madru.

Ваше имя:
e-mail:
*не публикуется
Комментарий:
Код с картинки:Защитная картика