#!/usr/bin/perl -w # v 1.3 (2009-09-02) (c)dimio # Основной цикл работы скрипта. # 1. Получаем из соотв. таблицы базы кол-во блогов (BlogID = X), создаем из них массив1 на Х эл-тов. # 2. Производим перебор массива1, при этом в цикле перебора делаем следующее: # 2.1. Делаем запрос к локальной БД чтобы получить для текущего блога список GameID еще не опубл. игр; # 2.2. Для полученных значений BlogID и GameID делаем запрос к базе для формирования тела сообщения # (см. ф-ю prepare_message); # 2.3. Публикуем сообщение в соответствующем блоге (путем прямого внесения строк в соотв. таблицу БД # целевого блога). # 2.4. В случае успешной публикации - обновляем запись в столбце DateOfPost таблицы BlogsContent локальной БД. # 4. По окончанию перебора массива1 завершаем работу программы. use strict; use DBI; use encoding 'utf8'; # Настройки для подключения к локальной БД my $db_type = 'SQLite'; # путь к базе, применяемый в случае запуска на сервере dimio.org # my $db_name = '~/sqlite_db/gb_blogs.sqlite'; # путь к базе, прим. при запуске с домашней машины my $db_name = '../sqlite_db/gb_blogs.sqlite'; my $db_hostname = 'localhost'; my $db_dest_host = 'localhost'; # адрес базы данных блогов (localhost если запускать локально) my $db_login = ''; my $db_password = ''; ########## ТЕЛО ПРОГРАММЫ ########## my $dbh = &db_connect($db_type,$db_name,$db_hostname,$db_login,$db_password); # подключаемся к БД, получаем дескриптор подключения # 1. Получение массивов исходных данных my @BlogsID; # определяем массив исх. данных &prepare_BlogID($dbh, \@BlogsID); # 2. Перебор массива с номерами блогов foreach my $BlogID (@BlogsID){ # 2.1. Получаем список еще не публиковавшихся в текущем блоге игр. my @GamesID = &prepare_GameID($dbh, $BlogID); # 2.1.1. Если таковых игр нет - переходим к след. по списку блогу. if(!@GamesID){ print "No unposted messages for blog N$BlogID.\n" ; next; } my $GameID = $GamesID[int(rand($#GamesID+1))]; # Выбираем случайную игру из списка неопубликованных. # 2.2. Получаем данные для создания нового сообщения в блоге для текущей игры и текущего блога my ($PostHeader, $PostBody, $PostTags, $table_pref, $screens_URL) = &prepare_message($dbh, $BlogID, $GameID); next if !$table_pref; # 2.3. Публикация сообщения с описанием игры в блоге. redo if &posting_message($PostHeader,$PostBody,$PostTags,$table_pref,$screens_URL,$db_dest_host) != 1; # если публикация не состоялась - пробуем заново &update_local_data($BlogID, $GameID); # обновляем локальную БД, внося дату публикации игры в блоге } print "Bust blogging completed.\n"; $dbh->disconnect; print "Script done.\n"; exit 0; sub db_connect($$$$$) { my ($db_type,$db_name,$db_hostname,$db_login,$db_password) = @_; my $dbh; if ($db_type eq 'SQLite'){ $dbh = DBI->connect("DBI:$db_type:$db_name","$db_login","$db_password") or die "Connecting: $DBI::errstr\n"; # подключаемся к базе SQL (открывается дескриптор БД) $dbh->{unicode} = 1; } elsif ($db_type eq 'mysql'){ $dbh = DBI->connect("DBI:$db_type:$db_name:$db_hostname","$db_login","$db_password") or die "Connecting: $DBI::errstr\n"; # подключаемся к базе SQL (открывается дескриптор БД) $dbh->{'mysql_enable_utf8'} = 1; $dbh->do('SET NAMES utf8'); } return $dbh; } sub prepare_BlogID($$) { # Функция подготавливает массив исходных данных для дальнейшей работы программы. my ($dbh, $Blog) = @_; # 1. Получить массив, состоящий из BlogID # Этот запрос получает список из всех BlogID, хранящихся в таблице BlogsContent, для которых # не заполнены все строки с датой публикации описания игры (т.е. для которых имеются неопубликованные # описания игр). my $query = $dbh->prepare("SELECT BlogID FROM BlogsContent WHERE DateOfPost IS NULL GROUP BY BlogID"); $query->execute() or die "$dbh->errstr\n"; while ((my $BlogID) = $query->fetchrow_array){ push(@$Blog,$BlogID); } return 1; } sub prepare_GameID($$) { # Выполняет запрос к локальной базе для получения списка неопубликованных игр при заданном BlogID my ($dbh, $BlogID) = @_; # Получить массив, состоящий из GameID # Запрос возвращает список еще не опубликованных игр для данного блога. # Отбираются только игры с заполненными заголовками описаний, что должно гарантировать наличие самих описаний. my $query = $dbh->prepare("SELECT GameID FROM BlogsContent WHERE BlogID = $BlogID AND DateOfPost IS NULL AND PostHeader NOT NULL"); $query->execute() or die "$dbh->errstr\n"; my @GamesID; while ((my $GameID) = $query->fetchrow_array){ push(@GamesID,$GameID); } return @GamesID; } sub prepare_message($$$) { # Запрос к базе на получение нужных частей контента из разных таблиц. # Склеивание результирующего тела будущего сообщения из полученных данных. my ($dbh, $BlogID, $GameID) = @_; # Запрос получает из базы необходимые для формирования заметки в блоге данные. # Данные получаются для текущей игры и текущего блога и кладутся в соотв. переменные. my $query = $dbh->prepare("SELECT PostHeader,PostBody,PostTags FROM BlogsContent WHERE BlogID = $BlogID AND GameID = $GameID"); $query->execute() or die "$dbh->errstr\n"; (my $tmp) = $query->fetchall_arrayref; my $PostHeader = $tmp->[0][0]; my $PostBody = $tmp->[0][1]; my $PostTags = $tmp->[0][2]; # Запрос получает префикс для mysql-таблиц, используемых данным блогом. $query = $dbh->prepare("SELECT WPTablePrefix FROM BlogsMainData WHERE BlogID = $BlogID AND WPTablePrefix NOT NULL"); $query->execute() or die "$dbh->errstr\n"; (my $table_pref) = $query->fetchrow_array; # Получаем ссылки на скриншоты для текущей игры (ссылки подготавливаются вручную). $query = $dbh->prepare("SELECT ScreenShotsURL FROM Games WHERE GameID = $GameID"); $query->execute() or die "$dbh->errstr\n"; (my $screens_URL) = $query->fetchrow_array; return ($PostHeader, $PostBody, $PostTags, $table_pref, $screens_URL); } sub date_time { my ($DAY, $MONTH, $YEAR) = (localtime)[3..5]; my $DATE = join("-", $YEAR+1900, $MONTH+1, $DAY); my $locTIME = join(":", (localtime)[2,1,0]); my $gmTIME = join(":", (gmtime)[2,1,0]); return ($DATE, $locTIME, $gmTIME); } sub posting_message($$$$$$) { # Подключаемся к БД вордпресс и кладем пост в таблицу с соотв. префиксом в имени (префиксы # у каждого блога свои. # Вариант N2 - получать из своей локальной базы не префиксы имен таблиц, а имена баз данных # (если каждый блог будет иметь отдельную БД). my ($PostHeader, $PostBody, $PostTags, $table_pref, $screens_URL, $db_dest_host) = @_; # Настройки для подключения к БД блога. my $db_type = 'mysql'; my $db_name = 'db_namr'; # имя базы данных с таблицами wordpress блогов my $db_login = 'login'; # логин для неё же my $db_password = 'password'; # пароль для неё же # Подготовка необходимых для публикации сообщения данных my ($DATE, $locTIME, $gmTIME) = &date_time; # генерация времени и даты публикации сообщения $table_pref .= '_posts'; # определение имени таблицы, хранящей сообщения my $locdate = $DATE.' '.$locTIME; # создание локальной даты публикации сообщения в формате, пригодном для wordpress my $gmtdate = $DATE.' '.$gmTIME; # то же для даты по Гринвичу my $PostURLName = &prepare_post_URL($PostHeader); # генерация будещего адреса статьи с описанием игры на основании заголовка статьи my $dbh = &db_connect($db_type,$db_name,$db_dest_host,$db_login,$db_password); my $query = "INSERT INTO $table_pref (post_author, post_date, post_date_gmt, post_content, post_title, post_name) VALUES (1, '$locdate', '$gmtdate', '$screens_URL $PostBody', '$PostHeader', '$PostURLName');"; my $db_data = $dbh->do($query); print "$db_data lines added into $table_pref.\n"; $dbh->disconnect; return $db_data; } sub update_local_data($$) { my ($BlogID, $GameID) = @_; my $db_type = 'SQLite'; my $db_name = '../sqlite_db/gb_blogs.sqlite'; my $db_hostname = 'localhost'; my $db_login = ''; my $db_password = ''; my $dbh = &db_connect($db_type,$db_name,$db_hostname,$db_login,$db_password); my $DateOfPost = join(" ", (&date_time)[0,1]); my $db_data = $dbh->do("UPDATE BlogsContent SET DateOfPost = '$DateOfPost' WHERE BlogID = $BlogID AND GameID = $GameID"); print "$db_data lines updated on $db_name\n\n"; return $db_data; } sub prepare_post_URL($) { # Функция транслитерации кириллицы, сделанная для преобразования # заголовков сообщений в url-адреса, основана на коде nrg: # "Автор: nrg # Напиcано: Чтв Сен 13 00:04:14 SAMST 2007 # Обратная связь: nrg@jabber.snc.ru, icq: 813-793." # dimio - добавлена очистка от мусора и замена пробелов my $InLine = shift; my %hs=('аА'=>'a' , 'бБ'=>'b' , 'вВ'=>'v' , 'гГ'=>'g', 'дД'=>'d' , 'еЕ'=>'e' , 'ёЁ'=>'jo' , 'жЖ'=>'zh' , 'зЗ'=>'z', 'иИ'=>'i' , 'йЙ'=>'j' , 'кК'=>'k' , 'лЛ'=>'l' , 'мМ'=>'m', 'нН'=>'n' , 'оО'=>'o' , 'пП'=>'p' , 'рР'=>'r' , 'сС'=>'s', 'тТ'=>'t' , 'уУ'=>'u' , 'фФ'=>'f' , 'хХ'=>'h' , 'цЦ'=>'c', 'чЧ'=>'ch', 'шШ'=>'sh', 'щЩ'=>'shh', 'ъЪ'=>'' , 'ыЫ'=>'y', 'ьЬ'=>'' , 'эЭ'=>'eh', 'юЮ'=>'ju' , 'яЯ'=>'ja' ); pop@{([\map do{$InLine =~ s/[$_]/$hs{$_}/gi;}, keys %hs])}, $InLine; # преобразуем в транслит по шаблону из хэша $InLine =~ s/\s/_/g; # заменим пробелы на подчеркивания $InLine =~ s/[^\w]//g; # очистим будущий URL от возможного "мусора" - знаков препинания return $InLine; }