?

Log in

No account? Create an account
о ЖЖ и разметке (компьютерное) - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

о ЖЖ и разметке (компьютерное) [мар. 20, 2006|02:56 pm]
Anatoly Vorobey

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

После возвращения к Линуксу на новом ноутбуке я решил вернуться к старому и очень удобному способу отсылать комментарии в ЖЖ, и заодно улучшить его и расширить на записи. У меня был скрипт, позволяющий мне отвечать на комментарии в ЖЖ просто путем "обычного" ответа на письма с комментами из почты. Не та HTML-формочка, которая ведет на сайт ЖЖ, нет, это уродливо и неудобно, а отвечая в тексте на текстовые письма, как будто это обычное письмо. Мой скрипт перехватывал такие ответы, форматировал их специально (например, переводил цитирование строк, на которые отвечаещь, с помощью ">", обычное для почты, в цитирование всего абзаца курсивом, итд.). А потом строил правильный запрос к серверу ЖЖ и отсылал его, притворяясь той самой HTML-формочкой из писем с комментариями в HTML-формате.

Оставалась, однако, такая проблема: для того, чтобы отправить такой комментарий, нужно быть в сети. А новый ноутбук я собираюсь носить с собой и пользоваться им, и когда нет интернета. С обычными письмами это не проблема, они просто сидят себе в очереди и ждут, пока я подключусь, мне об этом не нужно и помнить. А с таким псевдо-письмами - проблема. Очевидно, нужна какая-то система отложенных задач (неотосланный комментарий - отложенная задача), которые сами выполнятся, когда я подключусь к сети, и все сделают. Кроме того, то же желательно иметь для записей. Меня не устраивает ни один из популярных ЖЖ-клиентов. Писать текст записей проще всего, по-моему, в текстовом редакторе, а хранить черновики и недописанные записи - просто в виде файлов в отведенной для этого директории. Послать запись на сервер должно быть просто - написать что-то вроде "ljpost file", а если связи в этот момент нет - пусть оно само запомнит где надо и позже отошлет, я не хочу об этом думать.

Я решил, что система отложенных задач должна быть настолько простой, насколько это возможно, и не требовать от меня никаких действий. И написать ее должно быть очень просто.

Вот мое решение. Расскажу сначала на примере скрипта для записей ljpost, проще понять. Это небольшой (4.5kb) скрипт на перле, получает текст записи либо в виде имени файла в командной строке, либо в потоке стандартного входа. Первым делом, или почти первым делом, он проверяет, есть ли сеть (пинг на www.livejournal.com). Если нет, он создает отложенную задачу.

О таких задачах. Считаем, что всё, что находится в каталоге ~/jobs - отложенные задачи. Любая такая задача - это файл, который просто можно выполнить, и больше никаких условий нет. Т.е. попытка выполнить отложенные задачи - это всего лишь пройтись по каталогу ~/jobs и запустить в нем все файлы, которые в принципе можно запустить (executable).

Теперь обозначим вход скрипту ljpost (т.е. весь текст записи) [INPUT] для примера, и предположим, что ему нужно отложить отсылку этой записи. Он создает в каталоге ~/jobs файл со случайным именем и следующим содержимым:

#!/bin/bash
/path/to/ljpost --canfail <<'DELIM-random'
[INPUT]
DELIM-random
if [ "\$?" -eq "0" ]; then
  echo "[removing \$0]"
  rm \$0
  exit 0
else
  exit 1
fi

Смысл: мы создаем shell-скрипт, который запускает ту же программу на том же тексте, подающемся на стандартный вход. Запускаем себя с опцией --canfail, которая говорит нам, что если нам опять не удастся (например, опять нет сети), можно просто вернуть код ошибки >0 и не создавать еще одну отложенную задачу (когда же я запускаю скрипт с командной строки без этой опции, неудача заставляет его создать отложенную задачу). Если при следующем запуске мы вернем код ошибки >0, ничего не случится, останемся в списке задач; если вернем код удачной отработки =0, то shell-скрипт удалит сам себя, задача выполнена и ее больше нет.

Теперь достаточно запускать через crontab раз в полчаса, скажем, команду запуска всего, что можно, из ~/jobs, и все.

Теперь об обработке текста записи. Мы хотим в ней передать не только сам текст, но также заголовок, название коммьюнити (если не в свой журнал), current music итд. Следующая очень простая система мне подходит идеально. Текст может начинаться с любого числа контрольных строк вида: to: communityname, mood: moodname, music: current music, subj: заголовок записи. Кроме этого, если то, что после этих контрольных строк, начинается с одной строки и после нее пустая строка - это считается заголовком, а все остальное главным текстом. Т.е. если, например, просто написать запись в свой дневник с заголовком и без всяких опций, то это написать заголовок, пропустить строку, и дальше текст всей записи.

Скрипт это все понимает, правильно разделяет, строит запрос к www.livejournal.com по протоколу XMLRPC, и отсылает. Если есть ошибка, опять-таки создает отложенную задачу, чтобы позже попробовать.

О разметке в теле записи. Тело записи скрипт перед отсылкой пропускает через простую программу markdown. Markdown существует для того, чтобы быстро и удобно писать текст с разметкой, который превращается в HTML. Например, не надо писать <i> </i>, достаточно выделить кусок текста звездочками. Не надо писать <blockquote>, достаточно начать абзац со знака "> " (как в почте). Вместо HTML-тагов для построения списка, просто пишем элементы списка через звездочки с новой строки. Ссылки тоже немного удобней, чем выписывать в HTML, и многое другое. Подробности см. на его сайте. Я давно хотел попробовать им пользоваться, и вот теперь с этим моим скриптом живу уже неделю и очень доволен скоростью и удобством сочинения записей.

Наконец, о комментариях. Я изменил и упростил то, как запускается скрипт для отсылки комментариев. Раньше для него был специальный отдельный пользователь на моей машине, которому пересылались псевдо-письма ответов; теперь он просто ведет себя так же, как обычный sendmail, а моя почтовая программа для отсылки писем вызывает его, а не sendmail, если письмо идет на определенный псевдо-адрес (тут необходима определенная помощь во время получения писем с комментариями, нужно простым фильтром вытащить из них имя журнала, номер записи и комментария-"отца", составить из них псевдо-адрес и вставить в поле Reply-to:, чтобы ответы автоматически шли на него. Три строки в моем файле фильтровки входящей почты). Он обрабатывает текст комментария, удаляет из него лишнее (например, весь текст того, на что я отвечаю, если он остался полностью непроцитированным внизу, чтобы мне не надо было удалять), и, если получается, отсылает на сервер описанным выше способом, а если нет, создает отложенную задачу по тому же точно принципу, что и ljpost.

Если кому-то нужно/интересно, выложу исходники скриптов. Да, предваряя вопрос, имя пользователя/пароль в данный момент в них забиты прямо в тексте, что не есть хорошо с точки зрения секьюрити. По сути дела пароль нужен только для того, чтобы делать md5 некоторым строкам, включающим его. Намного более безопасным вариантом было бы, например, запустить простенький сервис (на том же компьютере другим пользователем, или на другом компьютере), который слушает какой-то порт, принимает по нему строку X и возвращает МД5(X+password), или другие варианты, какие там нужны. Наверное, я это сделаю в том или ином виде в ближайшие дни.

СсылкаОтветить

Comments:
[User Picture]From: sartoris
2006-03-20 01:22 pm
Мне кажется ты усложнил систему... В принципе тебе нужна обычная очередь, в которой порядок не обязательно соблюдать. Запускать каждый "пост" отдельно мне кажется не очень логичным, когда достаточно иметь скрипт немного более разумный, который сначала проверяет доступность ЖЖ вообще, а потом читает один файл за другим из директории ~/jobs и отправляет его. Если результат положителен, то файл стирается. Если отрицателен, то файл остается на месте.

Почему мне не нравится идея с тем, что каждый "пост" - сгенерированый скрипт? Потому что в случае каких-то изменений, несостыковок и прочих возможных бед, не хватит прозрачности для определения и исправления источника. Это первая причина. Системная, так сказать. А вторая причина заключается в том, что если ты обнаружишь некю ошибку в скрипте в то время как в очереди стоит энное колличество "постов" (теоретически возможная ситуация) то придется ручками переписывать каждый "пост". Третья же причина заключается в моей маниакальной привычке разделять функциональный ряд и данные.
(Ответить) (Thread)
[User Picture]From: dimrub
2006-03-20 01:24 pm
Continuation :).
(Ответить) (Thread)
[User Picture]From: cmm
2006-03-20 01:27 pm

title

a comment that reminds everyone about the well-known m-word
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: gaius_julius
2006-03-20 01:43 pm
давно размышляю, почему такой способ оставлять комментарии не реализован для жж нативно - смотрелось бы преотлично:

отвечаешь на адрес reply-to прямо на уведомление о комменте (с e-mail'а, указанного в профиле), для указания заголовка можно использовать прямиком subject письма, на сервере уже это всё переворматируется и коммент добавляется в нужное место в ветке. mail-list и комментарии в одном флаконе.

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

нигде не видел такого (кроме web-зеркал к почтовым конференциям, конечно), хотя идея, казалось бы, лежит на поверхности...
(Ответить) (Thread)
[User Picture]From: avva
2006-03-20 01:45 pm
Нет реальной причины того, что это не сделано, кроме того, что это недостаточно было нужно/недостаточно просилось/не нашлось разработчиков, достаточно в этом заинтересованных/не нашлось у них времени.
(Ответить) (Parent) (Thread) (Развернуть)
From: _fallingfree_
2006-03-20 01:49 pm
Гейтом http://4lj.mivlad.net/ не пользуетесь по соображениям безопасности?
(Ответить) (Thread)
[User Picture]From: avva
2006-03-20 01:53 pm
Да. Плюс еще одно потенциально слабое звено в цепочке.

Идея хорошая, я не критикую. Но не для меня.
(Ответить) (Parent) (Thread)
[User Picture]From: aburachil
2006-03-20 10:28 pm
А как он постит комменты --- анонимно или ему надо свой пароль сказать?
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: auto194419
2006-03-20 02:04 pm
у меня только один вопрос - как это "когда нет интернета"?! ты бываешь в местах, где нет GPRS-покрытия?
(Ответить) (Thread)
[User Picture]From: avva
2006-03-20 02:10 pm
Я не собираюсь подключать ноутбук к мобильнику и через GPRS к интернету, мне это не нужно реально. Может, в будущем, когда будет машина и буду на ней реально много разъезжать - да. Пока что речь идет о том, чтобы, скажем, сесть в кафе, а в нем нет WiFi или глючит. Или приехать к кому-то в гости не на вечер, а на выходные, а у них интернета нет, или глючит, или лень настраивать подключение. Или принести ноутбук на работу, а включать его в рабочую сеть не дают корпоративные правила. Или еще что-то в этом роде. Короче, чтобы не задумываться вообще, отвечая на коммент или сочиняя запись, есть сеть или нет, как не надо задумываться, отвечая на письмо.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: aburachil
2006-03-20 02:49 pm
Ой, а дайте всё это, я наверное такими бы вещами пользоваться бы стала. Заранее спасибо ;-)
(Ответить) (Thread)
[User Picture]From: avva
2006-03-20 03:00 pm
Ага, пользуйтесь на здоровье ;)

http://www.forum2.org/mellon/lj/ljscripts.zip
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: madfire
2006-03-20 07:45 pm
Конечно же, имеет смысл выложить :)
Я сам давно думал, какого же клиента мне использовать для постинга, потом плюнул и пишу в KJots, а потом copypaste в браузер.
(Ответить) (Thread)
[User Picture]From: avva
2006-03-20 08:39 pm
Ага, выложил, см. ссылку выше в комментах.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: aburachil
2006-03-24 10:20 am
Я теперь посылаю "криатифы" скриптом ljpost. Меня очень умиляет сообщение "[no net]". Совершенно невозможно читать его по-английски. Это ж транслитная кириллица --- "НУ УЖ НЕТ!".
(Ответить) (Thread)