Создание копии сайта Drupal в живом журнале


Захотелось/потребовалось дублировать информацию с сайта под друпалом в LiveJournal.

Нашел модуль LiveJournal CrossPoster (он же ljxp), который умеет кроспостить материал создаваемый на сайте сразу в жж. Установил, настроил - все заработало. Но у него было два не очень удобных, для меня, момента:

  1. Он требует настройку для каждого пользователя отдельно, что при задаче ведения одного журнала разными пользователями несколько неудобно.
  2. При публикации старого материала живой журнал ругается, что были записи более свежей даты и не дает сохранять материал прошедшим временем (не верит он в создание машин времени). Для установки нужной даты, требуется сначала опубликовать материал текущей датой и временем, а потом уже поправить время публикации на нужное. Что тоже является не очень удобным.

Т.к. с PHP дружу не очень, а на нем написаны этот модуль и сам друпал, и еще хуже представляю как пишутся модули под друпал, пришлось все делать с помощью жесткого лома (на сколько я понял, в сообществе друпалистов, называется это хаком).

Дальше опищу как что делал, в конце прикреплю поправленный мною файл ljxp.module модуля.

Делаем публикацию статей в ЖЖ всех пользователей сайта с настройками определенного пользователя.

Тут возникло два момента:

  1. Нужно брать все настройки от одного пользователя
  2. Нужно убрать проверку, что статья принадлежит тому же пользователю, который ее правит. Иначе модуль не позволяет ее публиковать, удалять или изменять в живом журнале.

Привожу patch файла ljxp.module этого модуля для этого решения:

43,44c43
<     !user_access('can crosspost to livejournal') ||
<     $user->uid != $form['uid']['#value']) {
---
>     !user_access('can crosspost to livejournal') ) {
93c92
<   if (!user_access('can crosspost to livejournal') || $GLOBALS['user']->uid != $node->uid) {
---
>   if (!user_access('can crosspost to livejournal') ) {
239c238
<         if (user_access('can crosspost to livejournal', $account) && ($user->uid == $account->uid || user_access('administer site configuration'))) {
---
>         if (user_access('can crosspost to livejournal', $account) && (user_access('administer site configuration'))) {
298a298
>       $uid=1;
315a316
>   $uid=1;

Соответственно, в данном случае у нас все настройки берутся от пользователя с UID равным 1. С точки зрения безопасности не очень красиво, т.к. любой пользователь, которому разрешено пользоваться этим модулем может изменить настройки публикации. При желании, можно после настройки вырезать лишние части из функции ljxp_user. Не очень красиво, но очень надежно.

Публикация всех статей с сайта Drupal в ЖЖ с текущим или будущим временем

Изначально, хотел сделать красиво, т.е. чтобы статья сначала публиковалась в ЖуЖу с текущим временем и сразу же автоматом изменяла на время публикации, но терпения и мозгов не хватило и сделал публикацию всех статей с текущим временем.

P.S. Несколько поменялась стратегия. Первый раз все публикуется с текущим временем + несколько лет вперед. При обновлении поста, дата публикации меняется на правильную. Уже немного удобнее, но так и не получилось сделать , чтобы не требовалось два раза ручками публиковать. :-(

Для этого, в том же файле ljxp.module изменил строки:

$message['year'] = format_date($node->created, 'custom', 'Y');
$message['mon'] = format_date($node->created, 'custom', 'n');
$message['day'] = format_date($node->created, 'custom', 'j');
$message['hour'] = format_date($node->created, 'custom', 'G');
$message['min'] = format_date($node->created, 'custom', 'i');

На:

$publish_time=$node->created;

// Если статья публикуется первый раз, то дату публикации в LJ увеличиваем на несколько лет.
if (!$node->ljid) $publish_time=time()+100000000;

$message['year'] = format_date($publish_time, 'custom', 'Y');
$message['mon'] = format_date($publish_time, 'custom', 'n');
$message['day'] = format_date($publish_time, 'custom', 'j');
$message['hour'] = format_date($publish_time, 'custom', 'G');
$message['min'] = format_date($publish_time, 'custom', 'i');

Соответственно, для того чтобы все снова публиковалось с правильным временем или все возвращаем обратно или  комментируем строку "if (!$node->ljid) $publish_time=time()+100000000;".

Автоматизация копирования всех статей с сайта в Live Journal

Т.к. одной большой кнопки "сделать все зашибись" не нашлось, а руками протыкивать по два раза по всем материалам было тоскливо и при этом расковыривать друпал дальше было лень, начал вспоминать, как можно автоматизировать работу в браузере.

У фаерфокса есть дополнение iMacros, с помощью его и sh данный процес и автоматизировал.

На баше нарисовал скриптик, который формировал сценарий действий для iMacros следующего содержания:

#!/bin/sh
site=$1
cur_post=$2
LIMIT=$3
echo "VERSION BUILD=7401110 RECORDER=FX"
while [ $cur_post -le "$LIMIT" ]
do
        echo "URL GOTO=${site}/node/${cur_post}/edit
TAG POS=1 TYPE=LABEL ATTR=TXT:Crosspost<SP>to<SP>LiveJournal
TAG POS=1 TYPE=INPUT:CHECKBOX FORM=ACTION:/node/${cur_post}/edit ATTR=ID:edit-ljxp-crosspost CONTENT=YES
TAG POS=1 TYPE=LABEL ATTR=TXT:Создать<SP>новую<SP>редакцию
TAG POS=1 TYPE=INPUT:CHECKBOX FORM=ACTION:/node/${cur_post}/edit ATTR=ID:edit-revision CONTENT=NO
TAG POS=1 TYPE=INPUT:SUBMIT FORM=ID:node-form ATTR=ID:edit-submit
"
        cur_post=$(($cur_post+1))
done

Запускаем его соответственно со следующими параметрами site start_post end_post, где:

  • site - адрес сайта в виде "http://www.my-site.ru"
  • start_post - id первого поста/ноды с которого начинаем перенос в ЖЖ
  • end_post - id последнего поста, которым заканчиваем перенос в ЖЖ

Полученный сценарий скармливаем уже iMacros'у. В итоге фаерфокс пробегает по всем нодам, выставляет у них галочку "публиковать в живом журнале", снимает галочку "Создать новую редакцию" и сохраняет их.

Т.к. на сайте, с которым я все это делал, было порядка 100 нод, оно вполне нормально отработало. К сожалению, в случае удаленных публикаций скрипт переставал работать и вставал. Найти галочку "продолжать работу в случае ошибок" у меня на вскидку не получилось, по этому пришлось делать кусками.

Более правильный подход - анализировать sitemap. Скрипт который наваял под это дело:

#!/bin/sh

site=$1
sitemap=$2
if [ $# -lt 3 ]; then
        type_content="node"
    else
        type_content=$3
fi
echo "VERSION BUILD=7401110 RECORDER=FX"

for cur_post in ` wget -q -O - $2 | grep $type_content | grep -v "#comments" | sed "s/^.*\/${type_content}/${type_content}/" | sed 's/<.*$//'`
do
        echo "URL GOTO=${site}/${cur_post}/edit
TAG POS=1 TYPE=LABEL ATTR=TXT:Crosspost<SP>to<SP>LiveJournal
TAG POS=1 TYPE=INPUT:CHECKBOX FORM=ACTION:/${cur_post}/edit ATTR=ID:edit-ljxp-crosspost CONTENT=YES
TAG POS=1 TYPE=LABEL ATTR=TXT:Создать<SP>новую<SP>редакцию
TAG POS=1 TYPE=INPUT:CHECKBOX FORM=ACTION:/${cur_post}/edit ATTR=ID:edit-revision CONTENT=NO
TAG POS=1 TYPE=INPUT:SUBMIT FORM=ID:node-form ATTR=ID:edit-submit
"
done

Принимает следующие параметры site sitemap node_type, где:

  • site - адрес сайта в виде "http://www.my-site.ru"
  • sitemap - ссылка на карту сайта вида "http://www.my-site.ru/sitemap.xml"
  • node_type - тип нод, которые нужно перепубликовать. У меня это node и content. Если не задать, принимается за node

Была мысля сделать чтобы разбирало RSS и тому подобное, но пока сломался.