Отправка отложенных постов в livejournal.com

Немного рекламы

Эта статья продолжает серию статей про работу с сервером Живого Журнала. Предыдущие статьи вы можете найти в разделе .NET/C#

С недавних пор в Живом Журнале (он же livejournal.com, он же ЖЖ) появилась возможность делать отложенную отправку записей. То есть вы отправляете пост в любое удобное вам время, но в ленте пользователей, которые вас читают, он появится только в определенное время. Раньше такой возможностью можно было воспользоваться с помощью сторонних сервисов (принадлежащих СУП'у), а теперь такая возможность появилась в самом сервере ЖЖ.

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

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

Демонстрационная программа

Для демонстрации работы отправки постов в ЖЖ я написал простенькую программку ljdelay, интерфейс которой показан на следующем скриншоте:

С помощью этой программы можно отправлять посты, задавая им определенные даты. Если не установлен флажок "Использовать отложенную отправку", то введенная дата будет установлена, как дата поста, но сама запись в ленте ваших друзей появится сразу же. Если этот флажок установлен, то запись появится в ленте ваших друзей в заданное время, при этом вы сможете ее увидеть в списке отложенных записей.

Рассмотрим исходники этой программы и заодно разберемся, как же все-таки использовать отложенную отправку.

Работа с сервером ЖЖ

Если вы не читали предыдущие статьи серии, особенно статью Основы работы с сервером livejournal.com, коротко напомню основные моменты, связанные с работой сервера.

Сервер ЖЖ может работать по двум протоколам - Flat, когда данные передаются в виде параметр=значение и XML-RPC, когда они оформляются в виде XML. В указанной выше статье приводились два класса для работы по обоим протоколам. В этой статье будет использоваться класс FlatLjServer для работы по протоколу Flat.

Отправка постов на сервер состоит из двух этапов: авторизация и, собственно, отправка сообщения. Статья Основы работы с сервером livejournal.com большей частью была посвящена различным способам авторизации. В данной статье будет использоваться метод challenge / response. Суть его состоит в том, что сначала клиент получает от сервера так называемый challenge, затем он вычисляет выражение по формуле MD5 (challenge + MD5(password)), где password - пароль от вашего аккаунта ЖЖ, после чего полученное выражение используется для авторизации вместо пароля. Таким образом удается избежать отправки пароля в явном виде.

Чтобы использовать отложенную отправку постов, по сравнению с обычным запросом postevent необходимо добавить или изменить всего несколько параметров:

  • Номер версии протокола (параметр ver) должен быть больше 3, то есть логично использовать 4.
  • Параметр custom_time, равный 1, обозначает, что используется отложенная отправка.
  • Параметр tz (от слов "time zone"), задающий часовой пояс пользователя (разницу во времени по сравнению с UTC). Задается строкой в виде "+0400" (смещение на +4 часа), или "-0400" (Смещение на -4 часа), или "-0130" (смещение на -1 час 30 минут ) и т.д.

Давайте посмотрим, как такая работа с сервером реализована в программе. Как уже было сказано, для работы с сервером ЖЖ в программе используется класс FlatLjServer, UML-диаграмма которого показана ниже:

Класс FlatLjServer имеет два публичных метода: PostEvent для обычной отправки поста в блог и PostDelayEvent для отложенной отправки. Они очень похожи и отличаются только добавлением новых параметров для отправки отложенных постов.

/// <summary>
/// Отправить поств блог без задержки
/// </summary>
/// <param name="user">Имя пользователя</param>
/// <param name="password">Пароль</param>
/// <param name="subj">Заголовок</param>
/// <param name="text">Текст поста</param>
/// <param name="dateTime">Дата поста</param>
public void PostEvent (string user,
    string password,
    string subj,
    string text,
    DateTime dateTime)
{
    Dictionary<string, string> paramItems =
        GetPostEventParams (user, password, subj, text, dateTime);

    string request = Dict2Request (paramItems);
    SendRequest (request);
}


/// <summary>
/// Отправить пост в блог с использованием отложенной отправки
/// </summary>
/// <param name="user">Имя пользователя</param>
/// <param name="password">Пароль</param>
/// <param name="subj">Заголовок</param>
/// <param name="text">Текст поста</param>
/// <param name="dateTime">Дата отправки поста</param>
public void PostDelayEvent(string user,
    string password,
    string subj,
    string text,
    DateTime dateTime)
{
    Dictionary<string, string> paramItems =
        GetPostEventParams (user, password, subj, text, dateTime);

    // Изменения в запросе по сравнению с отправкой поста без задержки
    // Номер протокола должен быть >3
    paramItems["ver"] = "4";

    // Указываем, что используем отложенную отправку поста
    paramItems["custom_time"] = "1";

    // Часовой пояс. Задается в формате +0400 или -0400
    paramItems["tz"] = HttpUtility.UrlEncode (GetTimeZone ());

    string request = Dict2Request (paramItems);
    SendRequest (request);
}

Метод GetPostEventParams создает словарь с параметрами для обычной (не отложенной) отправки поста.

private Dictionary<string, string> GetPostEventParams (string user,
    string password,
    string subj,
    string text,
    DateTime dateTime)
{
    string challenge = GetChallenge ();
    string auth_response = GetAuthResponse (password, challenge);

    Dictionary<string, string> paramItems = new Dictionary<string, string> ();
    paramItems["mode"] = "postevent";
    paramItems["auth_method"] = "challenge";
    paramItems["auth_challenge"] = challenge;
    paramItems["auth_response"] = auth_response;
    paramItems["user"] = user;
    paramItems["event"] = HttpUtility.UrlEncode (text);
    paramItems["subject"] = HttpUtility.UrlEncode (subj);
    paramItems["allowmask"] = 0.ToString ();
    paramItems["year"] = dateTime.Year.ToString ();
    paramItems["mon"] = dateTime.Month.ToString ();
    paramItems["day"] = dateTime.Day.ToString ();
    paramItems["hour"] = dateTime.Hour.ToString ();
    paramItems["min"] = dateTime.Minute.ToString ();
    paramItems["ver"] = "1";
    return paramItems;
}

После этого с помощью метода Dict2Request словарь преобразуется в строку вида "param1=value1&param2=value2&...", а с помощью метода SendRequest посылается запрос на добавление поста в блог. Метод SendRequest не изменился по сравнению с одноименным методом из статьи Основы работы с сервером livejournal.com, поэтому подробно на нем останавливаться не будем, вот его текст:

protected string SendRequest (string textRequest)
{
    // Выводим в лог посылаемый запрос
    _log.WriteLine ("\r\n*** Request:");
    _log.WriteLine (textRequest);

    // Преобразуем запрос из строки в byte[]
    byte[] byteArray = Encoding.UTF8.GetBytes (textRequest);

    // Получаем класс запроса
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create (ServerUri);

    // Заполняем параметры запроса
    request.Credentials = CredentialCache.DefaultCredentials;
    request.Method = "POST";
    request.ContentLength = textRequest.Length;
    request.ContentType = this.ContentType;
    request.UserAgent = "LJTest";

    // Очищаем коллекцию от старых cookie и добавляем туда новые
    request.CookieContainer = new CookieContainer ();
    request.CookieContainer.Add (_cookies);

    // Заполняем параметры Proxy (_proxy == null, если прокси не используется)
    request.Proxy = null;

    // Если есть cookie с именем "ljsession", то для авторизации с ее помощью
    // необходимо добавить заголовок с именем "X-LJ-Auth" и значением "cookie"
    if (_cookies["ljsession"] != null)
    {
        request.Headers.Add ("X-LJ-Auth", "cookie");
    }

    // Отправляем данные запроса
    Stream requestStream = request.GetRequestStream ();
    requestStream.Write (byteArray, 0, textRequest.Length);

    // Получаем класс ответа
    HttpWebResponse response = (HttpWebResponse)request.GetResponse ();

    // Читаем ответ
    Stream responseStream = response.GetResponseStream ();
    StreamReader readStream = new StreamReader (responseStream, Encoding.UTF8);

    string currResponse = readStream.ReadToEnd ();

    // Выводим в лог ответ сервера
    _log.WriteLine ("\r\n*** Response:");
    _log.WriteLine (currResponse);

    // Выведем в лог полученные в ответе cookie
    _log.WriteLine ("\r\n*** Cookies:");
    for (int i = 0; i < response.Cookies.Count; i++)
    {
        _log.WriteLine (response.Cookies[i].ToString ());
    }

    readStream.Close ();
    response.Close ();

    return currResponse;
}

Примеры

Программа ljdelay в нижней части окна выводит лог общения с сервером, в случае отправки поста без задержки ответ сервера выглядит следующим образом (в качестве даты поста в обоих случаях будет использоваться 01.01.2014 15:00, параметр auth_response изменен):

 *** Response:

anum
83
itemid
106
success
OK
url
http://jenyay-test.livejournal.com/27219.html

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

А вот как выглядит ответ сервера в случае отложенного поста:

 *** Response:

itemid

success
OK
url
http://jenyay-test.livejournal.com/d16.html

Запрос также прошел удачно, мы получили ссылку на отправленный пост, в качестве доказательства, что пост действительно отправился, мы можем увидеть его на странице отложенных записей.

delaypost.png: 919x590, 78k (09.09.2012 14:34)

Вот и все, с помощью такого нехитрого дополнения вы можете заставить вашу программу использовать отложенную отправку постов.

В завершение статьи еще раз напомню ссылку, откуда вы можете скачать исходники программы ljdelay.


Немного рекламы

Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.
4 stars

Рейтинг 4.0/5. Всего 1 голос(а, ов)




Подписаться на комментарии
Автор:
Тема:
 Ваш комментарий
 
 
Введите код 131