Сегодня сделаю такую фишку, как автоматическая отправка фотографий в группу, простым закидыванием фотки в папку. Что-то вроде Mail Cloud'а или dropbox клиента, только у нас синхронизация будет не с серверами mail или dropbox, а с группой vk. А что? Тоже весьма надёжное место для хранения фотографий (в нашем случае не хранения, а обычной публикации.) :).
Если подумать, то можно догадаться, что при заливании новой фотографии в папку, размер сей папки меняется. (Загорелась лампочка, осенившая: а ведь так можно отлавливать, когда закинута новая фотка!). Так же можно догадаться, что у каждой фотографии есть своё имя. При появлении новой в группе, её имя будет проверяться с массивом имён уже закинутых фотографий, и если такой нет в массиве, то отправляем её в альбом, а имя ложим в массив. Идея простая, а приложение - полезное :)
Начали реализовывать. Пока я не буду смешивать код этого проекта с кодом предыдущего и сделаю всё на новой форме. Собственно, вот и моя форма:
Итак, сначала забиндим процедуру, которая даст нам выбор папки для фотографий, и запишет в ini-файл её размер, а в текстовик имена файлов:
В var:
ini: TIniFile;
dir: String;
path_ini: string;
file_settings: File;
file_name: TextFile;
namefiles: TStringList;
procedure searchsize;
var
mnf: array [1..1000] of string;
size: Int64;
List: TStringList;
I: Integer;
begin
AssignFile(file_settings, ExtractFilePath(Application.ExeName)+'init.ini');
Rewrite(file_settings);
CloseFile(file_settings);
AssignFile(file_name, ExtractFilePath(Application.ExeName)+'list.txt');
if FileExists((Application.ExeName)+'list.txt') = false then Rewrite(file_name);
CloseFile(file_name);
List:= TStringList.Create;
if ini.ValueExists('file','directory_root') = false then
begin
SelectDirectory ('Выберите папку для сохранения фотографий', 'C:\', dir);
ini.WriteString('file','directory_root',dir); // INI : пишем имя дирректории для изображений
List:= GetAllFiles(dir);
end;
size:=0;
GetDirSize(dir, size);
ini.WriteInteger('file', 'size_one', size); // INI: пишем первоначальный размер файла
{записываем имена файлов в текстовик}
Append(file_name);
for I := 0 to list.Count-1 do
begin
ShowMessage(list.Strings[i]);
writeln(file_name, list.Strings[i]);
end;
CloseFile(file_name);
end;
Для определения размера дирректории служит процедура GetDirSize (путь до дирректории, переменная (в которую ляжет размер));
GetDirSize:
Функция, собирающая в стринглист имена всех файлов:
function GetAllFiles( Path: string): TStringList;
var
sRec: TSearchRec;
isFound: boolean;
Lb: TStringList;
begin
Lb:= TStringList.Create;
isFound := FindFirst( Path + '\*.*', faAnyFile, sRec ) = 0;
while isFound do
begin
if ( sRec.Name <> '.' ) and ( sRec.Name <> '..' ) then
begin
if ( sRec.Attr and faDirectory ) = faDirectory then
GetAllFiles( Path + '\' + sRec.Name);
Lb.Add(sRec.Name);
end;
Application.ProcessMessages;
isFound := FindNext( sRec ) = 0;
end;
FindClose( sRec );
Result:= lb;
end;
Запуск, проверка:
Файлы создаются, данные заносятся. Дальше напишем код, который будет определять были ли изменения в папке. В данном случае будем ловить только новые фото, удалённые нас пока, в этой версии программы, не интересуют.
var value_one: integer;
value_new: int64;
i, size: Integer;
path: string;
namefiles_new, file_old: TStringList;
begin
//привязка переменных к файлам
AssignFile(file_name, ExtractFilePath(Application.ExeName)+'list.txt');
//Инициализация переменных
namefiles_new:= TStringList.Create;
file_old:= TStringList.Create;
value_one:= ini.ReadInteger('file', 'size_one', 0);
path:= ini.ReadString('file', 'directory_root', 'nil');
GetDirSize(path, value_new); //получаем новый размер
if value_new <> value_one then
begin
namefiles_new:= GetAllFiles(path); //Получаем список новых имён
Reset(file_name);
file_old.LoadFromFile(ExtractFilePath(Application.ExeName)+'list.txt'); //Загружаем список старых имён в стринглист
//Проверяем, кто новенький:
for i := 0 to namefiles_new.Count-1 do
begin
if pos(namefiles_new.Strings[i], file_old.Text) = 0 then ShowMessage('Новый - '+ namefiles_new.Strings[i]);
end;
end;
end;
В событии создания формы (OnCreate) у меня прописана инициализация ini-переменной:
ini:= TIniFile.Create(ExtractFilePath(Application.ExeName)+'init.ini');
Кидаем в папку с изображениями какое-либо новое, назовём его к примеру "фото-12". Запускаем, проверяем:
Отловили, отлично.
Теперь на моменте отлова нужно прилепить api-функции, которые загрузят этот самый новый файл на сервера vk, а затем сохранят его в альбом. Напомню, что что бы понять нижеизложенный код, его логику и принцип работы, прочитайте ранее описанные статьи, описанные ранее. Было уже достаточно статей по работе с vk api, как для определённых api-шек, так и описание общего алгоритма работы с api vk.
var
path, url_no_pars, buf_2, url, server, photos_list, hash, temp : string;
namefiles_new, file_old: TStringList;
data: Tidmultipartformdatastream;
dir: string;
//добавляем в основной блок begin..end:
data:=Tidmultipartformdatastream.Create;
dir:= ExtractFileDir(path);
if pos(namefiles_new.Strings[i], file_old.Text) = 0 then // если имя нового файла не найдено в массиве старых, то:
begin
{
ШАГ 1
}
//Отправляем запрос с методом getUploadServer , который вернёт нам URL для загрузки изображений.
url_no_pars:= http.Get('https://api.vk.com/method/photos.getUploadServer?album_id=ID_альбома&group_id=ID_группы&access_token='+key+'&v=5.8');
data.AddFile('file1',dir+'\фото\'+namefiles_new.Strings[i], 'image/jpeg');
{парсинг URL}
for j := 1 to length(url_no_pars) do
begin
if url_no_pars[j] = '\' then
begin
delete(url_no_pars, pos(url_no_pars[j], url_no_pars), 1);
end;
end;
if pos (',"album_id":', url_no_pars) <> 0 then delete(url_no_pars, pos(',"album_id":', url_no_pars)-1, length(url_no_pars));
url:= copy(url_no_pars, pos('http://',url_no_pars), length(url_no_pars));
{/парсинг URL}
{
ШАГ 2
}
buf_2:= http.Post(url, data); //передаём изображения (data) на URL, полученный в предыдущем шаге
//Pars HASH
temp:= buf_2;
delete(temp, pos('","gid"', temp), length(temp));
hash:= copy (temp, pos('"hash":"', temp)+8, length(temp));
//Pars HASH
//Pars server
delete(temp, pos(',"photos_list', temp), length(temp));
server:= copy (temp, pos('{"server":', temp)+10, length(temp));
//Pars server
//Pars photos_list
temp:= buf_2;
delete(temp, pos('","aid":', temp), length(temp));
photos_list:= copy (temp, pos('photos_list":"', temp)+14, length(temp));
for j := 1 to length(photos_list) do
begin
if photos_list[j] = '\' then delete (photos_list, pos('\', photos_list), 1);
end;
ShowMessage(photos_list);
//Pars photos_list
{
ШАГ 3
}
//Конечная загрузка изображений на сервер
http.Get('https://api.vk.com/method/photos.save?album_id=ID_альбома&group_id=ID_группы&server='+server+'&photos_list='+photos_list+'&hash='+hash+'&caption=Описание&description=Текст_описания_альбома&access_token='+key+'&v=5.8');
end;
end;
Всё таки прокомментирую. Работа с изображениями в vk, а в частности загрузкой и пуликацией, происходит в 3 эпата:
шаг 1) Получение строки с запросом, происходит с помощью отправки запроса с методом getUploadServer. Он вернёт нам URL для загрузки файлов.
шаг 2) Затем на этот адрес отсылаем POST-запрос, где передаём файлы в потоке типа Tidmultipartformdatastream. В итоге получаем в ответ адрес сервера, массив адресов на фото и hash.
шаг 3) Отсылаем финальный запрос на сервер с помощью метода photos.save, передав параметры полученные в шаге 2. Открываем альбом и смотрим:
Это именно то, что я закинул в папку, т.е. что является новым. Осталось добавить лишь добавление имён этих фоток в текстовик, а размера дирректории в ini-файл и кинуть код в таймер. Но с этим, я думаю, вы и сами справитесь :)
В ближайшее время запилю доработанный и законченный проект. А у нас же, на данный момент написан полноценный (хоть и примитивный) клиент для загрузки фотографий из папки, не заходя на сайт.
На самом деле отлов файлов по имени - это крайне простой метод, который можно было задействовать. Его минус в том, что при добавлении файла с таким же именем (т.е. перезаписи файлов) на сервере он не перезапишется. Но это исправимо, например, если сохранять размеры всех файлов и сравнивать их (в байтах).
Возможностей усовершенствовать клиента - огромное количество, так что дерзайте!