- Автор flashr декабря 23, 2008
Как вы знаете, я транслирую свои записи в несколько популярных блогомест в интернете (за исключением ЖЖ). И это я делаю не с помощью встроенных средств копирования постов, а с
помощью самописного модуля (Extension) для движка BlogEngine.Net, работающем под ASP.NET. Почему так? Да потому, что часто при задании копирования постов с помощью сторонних средств, таких как трансляции на Ya.ru, посты помещаемые в блог выпадают из поискового индекса и ссылки в них не учитываются.
1) Модуль получился расширяемый, что позволяет дописать копирование постов куда вам только захочется. В вышеуказанный архив я вложил только два класса, которые позволяют копировать посты на Хабр и на Ярушечку. Так как ярушечка имеет херовый интерфейс, и код выглядит очень сложным (и, кстати, не рабовает, если Вы недавно заходили под своим же аккаунтом с другой машины), а также придется добавить следующие строчки в web.config:
- <system.net>
- <settings>
- <httpWebRequest useUnsafeHeaderParsing="true" />
- <servicePointManager expect100Continue="false"/>
- </settings>
- </system.net>
2) Далее, в настройках интерфейса у Вас появится такая вот картинка, позволяющая настроить копирование постов:

Отмечу, что все селективные значения прописываются вручную, так как в текущей версии BlogEngine нет возможностей задавать параметр группы настроек модуля в виде выбора из списка. Надеюсь это сделают в следующей версии, которую обещают в конце Января. Итак, первый параметр отвечает за копирование постов (bool=true/false). Второй за название категории, только из которой , если она указана, будут копироваться посты. Третий - BlogType - название класса отвечающего за копирование. Далее логин-пароль в удаленной системе. BlogParam - это дополнительный параметр, который может понадобиться для определенный систем. В частности для Яндекса я передаю номер моего блога, чтобы не извлекать его каждый раз. MaxAttempts(int) - количество попыток кпирования поста, если неуспех, то бросаем это дело. Последний - PostType(Public/Private/OnlyFriends) - тип записи. Как видим, для хабра стоит Private, что означает, что я планирую подредактировать запись и вставить в нее кат, прежде чем делать общедоступной хабрачанцам.
3) Из внутренностей работы модуля рассмотрю класс MultiPost:
- namespace MultiPost
- {
- /// <summary>
- /// Copy all your posts to blog at http://wow.ya.ru
- /// You have to assign an login and password inside constructor
- /// </summary>
- /// <remarks>
- /// Based on pure code - http://ya.topbot.ru
- /// </remarks>
- [Extension("Copy all your posts to blogs", "0.1.1", "http://ya.topbot.ru")]
- public class MultiPost
- {
- /// <summary>
- /// Name of Module
- /// </summary>
- private static String sExtensionName = "MultiPost";
-
- static protected ExtensionSettings _settings = null;
- /*....*/
- }
- }
Как видим к атрибутах класса задаются настройки модуля, чтобы BlogEngine его воспринял как расширение.
Конструктор достаточно простой, подписываемся на событие о размещении нового поста:
- static MultiPost()
- {
- // create settings object. You need to pass exactly your
- // extension class name (case sencitive)
- ExtensionSettings settings = new ExtensionSettings(sExtensionName);
- /*.......*/
- ExtensionManager.ImportSettings(settings);
- _settings = ExtensionManager.GetSettings(sExtensionName);
- Post.Saved += new EventHandler<SavedEventArgs>(Post_Saved);
- }
И кода происходит новый пост, то обрабатываем его создавая новый поток для этих целей
- /// <summary>
- /// Occurs on new post
- /// <remarks>
- /// It opens a new thread and executes
- /// because it takes some time to complete.
- /// </remarks>
- /// </summary>
- private static void Post_Saved(object sender, SavedEventArgs e)
- {
- if (e.Action != SaveAction.Insert)
- return;
-
- IPublishable item = (IPublishable)sender;
-
- //(HttpContext.Current == null || !HttpContext.Current.Request.IsLocal)
- if (item.IsVisible)
- {
- //getting new thread to do all crap
- ThreadPool.QueueUserWorkItem(delegate {
- PostCycle(item);
- });
- }
- }
-
- /// <summary>
- /// Main process to post
- /// </summary>
- /// <param name="item"></param>
- public static void PostCycle(IPublishable item){
- //перечисляем все блоги, что активны...
- DataTable dt = _settings.GetDataTable();
- //pure code, coz i cant change Categories class
- string catsline = "";
- foreach (Category c in item.Categories)
- {
- catsline += c.Title + ",";
- }
- for (int i = dt.Rows.Count - 1; i >= 0; i--)
- {
- SettingsCollection sets = new SettingsCollection(dt.Rows[i].ItemArray);
- if (!sets.Enabled ||
- (!String.IsNullOrEmpty(sets.CopyOnTags.Trim())
- && catsline.Contains(sets.CopyOnTags))
- )
- {//not allowed to post
- dt.Rows.RemoveAt(i);
- }
- }
- //lets finish the others
- for (int i = dt.Rows.Count - 1; dt.Rows.Count > 0; i--)
- {
- Thread.Sleep(5000);
- if (i < 0)//new cycle...bad...bad
- {
- i = dt.Rows.Count;
- }
- try
- {
- SettingsCollection sets = new SettingsCollection(dt.Rows[i].ItemArray);
- Type tBlog = Type.GetType("MultiPost.Blogs."+sets.BlogType);
- Object theBlog = Activator.CreateInstance(tBlog,
- new object[1] { sets });
- Type[] paramTypes = {
- typeof(IPublishable)
- };
- Object[] ps = new object[1] { item };
- MethodInfo mDefaults = tBlog.GetMethod("ProcessItem", paramTypes);
- if ((Boolean)mDefaults.Invoke(theBlog, ps))//if success
- {
- dt.Rows.RemoveAt(i);
- }
- //failed, lets continue
- }
- catch(Exception e)//toomanyattempts
- {
- dt.Rows.RemoveAt(i);
- }
-
- }
- }
В основном цикле, мы создаем объект класса, и вызываем нужную функцию размещения поста, передавая ей настройки. Как видно попытка разместить пост происходит каждые 5 секунд. Обработка объектов идет на объекте Rows, что некрасиво, но просто. Остальное Вы можете найти
внутри выложенного архива.
PS: Чтобы иметь возможность править настройки рекомендую заменить компонент admin/Extension Manager/Settings.ascx.cs на файл, вложенный архив. Там исправлена некоторая ошибка в функции редактирования настроек.
Метки: life | BlogEngine | Code