//************************************************************************
//*** Парсинг информации о фильме с сайта http://animator.ru/          *** 
//***                                                                  ***
//*** Автор:   Reset (http://www.videodb.info/forum_ru)                ***
//*** E-Mail:  pvd_ag@mail.ru                                          ***
//************************************************************************


const
  createLink       = false;    // Признак добавления тегов <link> в пользовательские поля
  titleCase        = 0;        // Регистр букв названия фильма
                               // 0 - не изменять
                               // 1 - все слова с большой буквы
                               // 2 - начало предложений с большой буквы
  loadSongs        = 2;        // Вид загрузки песен
                               // 0 - только названия
                               // 1 - названия, информация о песне и ссылка файл с музыкой
                               // 2 - 1 + текст песен
  categoryLinks    = 0;        // Типы категорий в связях
                               // 0 - добавляется одна категория: "Фильмы из серии"
                               // 1 - производится попытка деления связей
                               //     на две категории: "Начало" и "Продолжение".
                               //     В некоторых сериях деление производится некорректно

  ufPrefix         = '';       // Префикс  для имен пользовательских полей
  ufPostfix        = ':';      // Постфикс для имен пользовательских полей (можно добавить ":")

  // Настройки заполнения полей
  Enabled          = true;     // Равносильно установленной черной галочке в настройках (значение не менять!)
  Disabled         = false;    // Равносильно отсутствию галочки (значение не менять!)

  // Стандартные поля
  optTitle         = Enabled;  // Название
  optOrigTitle     = Enabled;  // Оригинальное название
  optPoster        = Enabled;  // Постер
  optYear          = Enabled;  // Год
  optGenre         = Enabled;  // Жанр
  optCategory      = Enabled;  // Категория
  optDirector      = Enabled;  // Режиссёр
  optProducer      = Enabled;  // Продюсер
  optScenario      = Enabled;  // Сценарий
  optComposer      = Enabled;  // Композитор
  optActor         = Enabled;  // Актеры
  optCountry       = Enabled;  // Страна
  optURL           = Enabled;  // URL
  optStudio        = Enabled;  // Студии
  optConnection    = Enabled;  // Связи

  // Пользовательские поля
  optTime          = Enabled;  // Длительность
  optQuotes        = Enabled;  // Цитаты
  optSongs         = Enabled;  // Песни
  optAnimator      = Enabled;  // Аниматоры
  optManager       = Enabled;  // Директор
  optSoundMan      = Enabled;  // Звукооператоры
  optPuppetScenery = Enabled;  // Куклы и декорации
  optFilmEditor    = Enabled;  // Монтажер
  optOperator      = Enabled;  // Операторы
  optEditor        = Enabled;  // Редактор
  optSongWriter    = Enabled;  // Текст песен
  optTextReads     = Enabled;  // Текст читают
  optDesigner      = Enabled;  // Художники
  optProductDesign = Enabled;  // Художники-постановщики

  // Названия пользовательских полей
  ufTime           = ufPrefix + 'Длительность'           + ufPostfix;  // Короткий текст
  ufQuotes         = ufPrefix + 'Цитаты'                 + ufPostfix;  // Momo
  ufSongs          = ufPrefix + 'Песни'                  + ufPostfix;  // Memo
  ufAnimator       = ufPrefix + 'Аниматоры'              + ufPostfix;  // Memo
  ufManager        = ufPrefix + 'Директор'               + ufPostfix;  // Memo
  ufSoundMan       = ufPrefix + 'Звукооператоры'         + ufPostfix;  // Memo
  ufPuppetScenery  = ufPrefix + 'Куклы и декорации'      + ufPostfix;  // Memo
  ufFilmEditor     = ufPrefix + 'Монтажеры'              + ufPostfix;  // Memo
  ufOperator       = ufPrefix + 'Операторы'              + ufPostfix;  // Memo
  ufEditor         = ufPrefix + 'Редакторы'              + ufPostfix;  // Memo
  ufSongWriter     = ufPrefix + 'Текст песен (стихов)'   + ufPostfix;  // Memo
  ufTextReads      = ufPrefix + 'Текст читают'           + ufPostfix;  // Memo
  ufDesigner       = ufPrefix + 'Художники'              + ufPostfix;  // Memo
  ufProductDesign  = ufPrefix + 'Художники-постановщики' + ufPostfix;  // Memo

const
  //Результаты парсинга
  prError     = 0; 
  prFinished  = 1;
  prList      = 2;
  prListImage = 3;
  prDownload  = 4;

  //Типы работы скрипта
  stMovies = 0;
  stPeople = 1; 
  stPoster = 2;

  // Типы страниц
  smSearch   = 0;
  smQuote    = 1;
  smSong     = 2;
  smLinks    = 3;
  smPoster   = 4;
  smFinished = 5;

  //Поля фильма для добавления
  mfURL         = 0;
  mfTitle       = 1;
  mfOrigTitle   = 2;
  mfAka         = 3;
  mfYear        = 4;
  mfGenre       = 5;
  mfCategory    = 6;
  mfCountry     = 7;
  mfStudio      = 8;
  mfMPAA        = 9;
  mfRating      = 10;
  mfTags        = 11;
  mfTagline     = 12;
  mfDescription = 13;
  mfDuration    = 14;
  mfFeatures    = 15;

  //Участники фильмов
  mpActor       = 0;
  mpDirector    = 1;
  mpScenario    = 2;
  mpComposer    = 3;
  mpProducer    = 4;

  //Методы загрузки
  dmGET  = 0;
  dmPOST = 1;


const
  SCRIPT_VERSION = '0.1.0.0'; 
  SCRIPT_NAME    = 'Аниматор.ру';
  SCRIPT_DESC    = '[RU] Импортировать информацию о фильме из Аниматор.ру';
  SCRIPT_LANG    = $19; //Russian
  SCRIPT_TYPE    = stMovies;

  BASE_URL       = 'http://animator.ru';

  RATING_NAME 	  = 'Аниматор.ру';
  SEARCH_STR	    = 'http://animator.ru/db/index.phtml?p=search&SearchMask=1&text=%s';
  CODE_PAGE   	  = 1251;
  
  
const
  FilmStudioAnchor   = '<span class="MiddleLinks" onclick="showStudia';  // Привязка в студиям
  FoundMovieTitleRef = 'href="/db/?p=show_film&fid=';


var
  Mode       : Byte;
  ExtraLinks : array [smQuote..smFinished] of WideString;
  URLSongs   : WideString;
  TitleMovie : WideString;  // Название фильма


//========== Вспомогательные функции ==========//
function GetScriptVersion : WideString;
begin
  Result := SCRIPT_VERSION;
end; 
 
function GetScriptName : WideString;
begin
  Result := SCRIPT_NAME;
end;

function GetScriptDesc : WideString;
begin
 Result := SCRIPT_DESC;
end;

function GetRatingName : WideString;
begin
 Result := RATING_NAME;
end;

function GetBaseURL : String;
begin
 Result := BASE_URL;
end;

function GetScriptLang: Cardinal;
begin
 Result := SCRIPT_LANG;
end;

function GetCodePage : Cardinal;
begin
 Result := CODE_PAGE;
end;

function GetScriptType : Byte; 
begin
 Result := SCRIPT_TYPE;
end;

function GetCurrentMode : Byte; 
begin
 Result := Mode;
end;

function GetDownloadURL : String;
begin
  if mode = smSearch then 
    Result := SEARCH_STR
  else
    Result := ExtraLinks[mode];
end;

function GetDownloadMethod : Byte;
begin
//  if Mode = smSearch then
//    Result := dmPOST;
//  else
    Result := dmGET;
end;

{procedure GetLoginInfo(out URL : String; out Params : String);
begin
  URL := BASE_URL + '';
  Params := '' + login + '' + password;
end;}


//****** Replace ******** Функция замены мнемоник и кодов на символы **********
function Replace (inStr: WideString): WideString;
Var
  I: Integer;
  Before, After : array of WideString;
Begin
//  inStr := HTMLToText (inStr);

  SetLength (Before, 53);
  SetLength (After, 53);
  // Мнемоники
  Before[ 1] := '&bdquo;';   After [ 1] := '„';
  Before[ 2] := '&bull;';    After [ 2] := '•';
  Before[ 3] := '&copy;';    After [ 3] := '©';
  Before[ 4] := '&deg;';     After [ 4] := '°';
  Before[ 5] := '&euro;';    After [ 5] := '€';
  Before[ 6] := '&hellip;';  After [ 6] := '…';
  Before[ 7] := '&laquo;';   After [ 7] := '«';
  Before[ 8] := '&ldquo;';   After [ 8] := '“';
  Before[ 9] := '&lsaquo;';  After [ 9] := '‹';
  Before[10] := '&lsquo;';   After [10] := '‘';
  Before[11] := '&mdash;';   After [11] := '—';
  Before[12] := '&middot;';  After [12] := '·';
  Before[13] := '&ndash;';   After [13] := '–';
  Before[14] := '&plusmn;';  After [14] := '±';
  Before[15] := '&raquo;';   After [15] := '»';
  Before[16] := '&rdquo;';   After [16] := '”';
  Before[17] := '&reg;';     After [17] := '®';
  Before[18] := '&rsaquo;';  After [18] := '›';
  Before[19] := '&rsquo;';   After [19] := '’';
  Before[20] := '&sbquo;';   After [20] := '‚';
  Before[21] := '&sect;';    After [21] := '§';
  Before[22] := '&shy;';     After [22] := '';   // «мягкий» дефис (место возможного переноса)

  // Коды
  Before[23] := '&#130;';    After [23] := '‚';
  Before[24] := '&#132;';    After [24] := '„';
  Before[25] := '&#133;';    After [25] := '…';
  Before[26] := '&#136;';    After [26] := '€';
  Before[27] := '&#137;';    After [27] := '‰';
  Before[28] := '&#139;';    After [28] := '‹';
  Before[30] := '&#145;';    After [30] := '‘';
  Before[31] := '&#146;';    After [31] := '’';
  Before[32] := '&#147;';    After [32] := '“';
  Before[33] := '&#148;';    After [33] := '”';
  Before[34] := '&#149;';    After [34] := '•';
  Before[35] := '&#150;';    After [35] := '–';
  Before[36] := '&#151;';    After [36] := '—';
  Before[37] := '&#153;';    After [37] := '™';
  Before[38] := '&#155;';    After [38] := '›';
  Before[39] := '&#171;';    After [39] := '«';
  Before[40] := '&#185;';    After [40] := '№';
  Before[41] := '&#187;';    After [41] := '»';

  // Символы
  Before[50] := '	';         After [50] := '';   // табуляция
  Before[51] := #13#10' ';   After [51] := #13#10;  // пробел в начале абзаца
  Before[52] := '';       After [52] := '';  // и попадается же хреновина всякая (http://www.kinopoisk.ru/level/1/film/5619/)

  For I := Low (Before) To High (Before) Do
    inStr := StringReplace (inStr, Before [i], After [i], true, false, false);
  Result := HTMLToText (inStr);
End;


//******* TrimQuotes ******** Удаление обрамляющих кавычек **********
procedure TrimQuotes (var Value: WideString);
var
  c: String;
begin
  Value := Trim (Value);
  if Length (Value) <= 0 then
    Exit;
  c := Value[1];
  if (c = '''') or (c = '"') or (c = '«') or (c = '<') then
    Delete (Value, 1, 1);
  c := Value [Length (Value)];
  if (c = '''') or (c = '"') or (c = '»') or (c = '>') then
    Delete (Value, Length (Value), 1);
end;


//****** CorrectTime ****** Отображение времени в виде чч:мм:сс ******
function CorrectTime (Tmp : WideString) : WideString;
Var
  pos1, hour, min, sec : Integer;
  digits : TWideArray;
Begin
  pos1 := Pos ('час.', Tmp);
  if pos1 > 0 then
    Begin
    pos1 := pos1 - 3;
    if pos1 = 0 then
      pos1 := 1;
    hour := StrToInt (Trim (Copy (Tmp, pos1, 2)));
    End;
  pos1 := Pos ('мин.', Tmp);
  if pos1 > 0 then
    Begin
    pos1 := pos1 - 3;
    if pos1 = 0 then
      pos1 := 1;
    min := StrToInt (Trim (Copy (Tmp, pos1, 2)));
    End;
  pos1 := Pos ('сек.', Tmp);
  if pos1 > 0 then
    Begin
    pos1 := pos1 - 3;
    if pos1 = 0 then
      pos1 := 1;
    sec := StrToInt (Trim (Copy (Tmp, pos1, 2)));
    End;

  Result := '';
  if hour < 10 then Result := Result + '0';
  Result := Result + IntToStr (hour) + ':';
  if min < 10 then Result := Result + '0';
  Result := Result + IntToStr (min) + ':';
  if sec < 10 then Result := Result + '0';
  Result := Result + IntToStr (sec);
end;


//******* MixedCase ******** Приводит текст к виду "Предложения с большой буквы" **********
const
  alphabet = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNMёйцукенгшщзхъфывапролджэячсмитьбюЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ';
  stop = '.!?';
function MixedCase (Str: WideString): WideString;
Var
  i, len, posStop, posLetter: Integer;
Begin
  Result := Str;

  if titleCase = 1 then
    Begin
    Result := LowerCase (Result);
    Result[1] := UpperCase (Copy (Result, 1, 1))[1];
    For i := 2 to Length (Result) do
      Begin
      if Pos (Result[i-1], alphabet) = 0 then
        Result[i] := UpperCase (Copy (Result, i, 1))[1];
      End;
    End

  else if titleCase = 2 then
    Begin
    Result := LowerCase (Result);
    len := Length (Result);
    Result[1] := UpperCase (Copy (Result, 1, 1))[1];
    For i := 1 to Length (stop) do
      Begin
      posStop := 1;
      while true do
        Begin
        posStop := PosFrom (stop[i], Result, posStop);
        if posStop = 0 then
          Break;
        posLetter := posStop;
        while true do
          Begin
          Inc (posLetter);
          if posLetter > Length (Result) then
            Break;
          if Pos (Result[posLetter], alphabet) > 0 then
            Begin
            Result[posLetter] := UpperCase (Copy (Result, posLetter, 1))[1];
            Break;
            End;
          End;
        Inc (posStop);
        End;
      End;
    End;
End;

//******* AddFoundMoviesTitles ******** Добавление найденных фильмов в список поиска **********
procedure AddFoundMoviesTitles (Table: String);
var
  Title, URL, Year     : WideString;
  curPos, len, posYear : Integer;
begin
  len := Length (Table);
  curPos := 1;
  while Pos (FoundMovieTitleRef, Table) > 0 do
    Begin
    Table := Copy (Table, Pos (FoundMovieTitleRef, Table) + Length ('href="'), len);
    curPos := pos ('"', Table);
    URL := BASE_URL + Copy (Table, 1, curPos - 1);
    Table := Copy (Table, pos ('>', Table) + 1, len);
    curPos := pos ('<', Table);
    Title := Copy (Table, 1, curPos - 1);
    Title := Replace (Title);
    if Pos ('Фильмы | ', Title) <> 1 then
      Continue;
    Title := Copy (Title, 10, Length (Title) - 10);
    
    if Pos ('г.)', Title) + 2 = Length (Title)  then
      Begin
      posYear := LastPos ('(', Title);
      Year := Copy (Title, posYear + 1, 4);
      Title := Copy (Title, 1, posYear - 1);
      End
    else
      Year := '';
    TrimQuotes (Title);
    Title := MixedCase (Title);
    
    Table := Copy (Table, curPos + 1, len);
    AddSearchResult (Title, '', Year, URL, '');
  end;
end;


//******* ParseSearchResults ****** Парсим результаты поиска *****
const
  FoundLabel = #10'Найдено ';
procedure ParseSearchResults (HTML: string);
var
//  Page: TStringList;
  FoundTable, SelectedURL: string;
  curPos, pos2, i: integer;
begin
//  PickTreeClear;
//  Page := TStringList.Create;
//  Page.Text := PostPage(URL, Params);
//  Page.Text := KOIToWin(GetPage(URL));
//  DebugOutputFile(DEBUG_FOUND_FILMS_FILENAME, Page.Text);
  curPos := Pos (#10'Найдено ', HTML);
  FoundTable := Copy (HTML, curPos, PosFrom ('</td', HTML, curPos) - curPos);
//  curPos := 1;
  if Pos (FoundMovieTitleRef, FoundTable) > 0 then
    AddFoundMoviesTitles (FoundTable);
end;


//******* ParseOnePerson ********** Добавление одного типа персон в стандартное поле *********
procedure ParseOnePerson (const HTML, Category : WideString; opt: Boolean; mp : Integer);
Var
  startPos, endPos : Integer;
  Value, URL, Name : WideString;
Begin
  if Not opt then
    Exit;

  startPos := Pos ('<tr><td valign="top" class="PProf">' + Category, HTML);
  if startPos <= 0 then
    Exit;

  endPos := PosFrom ('</td></tr>', HTML, startPos);
  Value := Copy (HTML, startPos, endPos - startPos);

  startPos := 1;
  while true do
    Begin
    startPos := PosFrom ('onclick="showPerson(', Value, startPos);
    if startPos <= 0 then
      Break;

    startPos := startPos + 20;
    endPos := PosFrom (')">', Value, startPos);
    URL := 'http://animator.ru/db/?p=show_person&pid=' + Copy (Value, startPos, endPos - startPos);

    startPos := endPos + 3;
    endPos := PosFrom ('</span>', Value, startPos);
    Name := Copy (Value, startPos, endPos - startPos);
  
    AddMoviePerson (Replace (Name), '', '', URL, mp);
    End;
End;


//******* ParseOneUserPerson ********** Добавление одного типа персон в пользовательское поле *********
procedure ParseOneUserPerson (const HTML, Category : WideString; opt: Boolean; uf : String);
Var
  startPos, endPos : Integer;
  Value, URL, Name, Tmp : WideString;
Begin
  if Not opt then
    Exit;

  startPos := Pos ('<tr><td valign="top" class="PProf">' + Category, HTML);
  if startPos <= 0 then
    Exit;

  endPos := PosFrom ('</td></tr>', HTML, startPos);
  Value := Copy (HTML, startPos, endPos - startPos);

  startPos := 1;
  while true do
    Begin
    startPos := PosFrom ('onclick="showPerson(', Value, startPos);
    if startPos <= 0 then
      Break;

    startPos := startPos + 20;
    endPos := PosFrom (')">', Value, startPos);
    URL := 'http://animator.ru/db/?p=show_person&pid=' + Copy (Value, startPos, endPos - startPos);

    startPos := endPos + 3;
    endPos := PosFrom ('</span>', Value, startPos);
    Name := Copy (Value, startPos, endPos - startPos);

    if Tmp <> '' then
      Tmp := Tmp + ', ';
    if createLink then
      Tmp := Tmp + '<link name="' + Name + '">' + Name + '</link>'
    else
      Tmp := Tmp + Name;
    End;

  AddCustomFieldValueByName (uf, Replace (Tmp));
End;


//******* ParseMovie ********** Парсинг страницы с фильмом **********
function ParseMovie (const URL, HTML: WideString): Integer;
var
//  Page: TStringList;
  Year, Value, Value2, FilmType, Actors, Creators, Studio, Country, URLActor, Name, Role, Tmp: WideString;
  Values : TWideArray;
  pos1, pos2, len, startPos, endPos, i: Integer;
begin
  Result := prDownload;

  if optQuotes And (Pos ('>Цитаты<', HTML) > 0) then
    ExtraLinks[smQuote] := URL + '&sp=3';
  if optConnection then
    Begin
    startPos := Pos ('>фильм из серии <', HTML);
    if startPos > 0 then
      Begin
      startPos := PosFrom ('onclick="showFilm(', HTML, startPos) + 18;
      endPos := PosFrom (')">', HTML, startPos);
      ExtraLinks[smLinks] := 'http://www.animator.ru/db/?p=show_film&fid=' + Copy (HTML, startPos, endPos - startPos);
      End;
    End;

  // URL
  if optURL then
    AddFieldValue (mfURL, URL);

  // Постер
  if optPoster then
    Begin
    startPos := Pos ('/film_img/', HTML);
    if startPos > 0 then
      Begin
      startPos := startPos;
      endPos := PosFrom ('"', HTML, startPos);
      Value := BASE_URL + Copy (HTML, startPos, endPos - startPos);
      ExtraLinks [smPoster] := Value;
      End;
    End;

  // Название фильма
  if optTitle Or optOrigTitle then
    Begin
    startPos := Pos ('class="FilmName"><B>', HTML);
    if startPos = 0 then
      Begin
      Result := prError;
      Exit;
      End;
    startPos := startPos + 20;
    endPos := PosFrom ('<', HTML, startPos);
    Value := Copy (HTML, startPos, endPos - startPos);
    Value := Replace (Value);
    TrimQuotes (Value);
    Value := MixedCase (Value);
    TitleMovie := Value;
    if optTitle then AddFieldValue (mfTitle, Value);
    if optOrigTitle then AddFieldValue (mfOrigTitle, Value);
    End;

  // Категория
  if optCategory then
    Begin
    startPos := Pos ('class="FilmType">(', HTML);
    if startPos > 0 then
      Begin
      startPos := startPos + 18;
      endPos := PosFrom (')</td>', HTML, startPos);
      Value := Copy (HTML, startPos, endPos - startPos);
      AddFieldValue (mfCategory, Replace (Value));
      End;
    End;

  // Жанр и время
  if optGenre Or optTime then
    Begin
    startPos := Pos ('class="FilmType"><i>', HTML);
    if startPos > 0 then
      Begin
      startPos := startPos + 20;
      endPos := PosFrom ('<', HTML, startPos);
      Value := Copy (HTML, startPos, endPos - startPos);
      if optTime then
        Begin
        endPos := LastPos ('.', Value);
        if endPos > 0 then
          Begin
          endPos := PrevPos (',', Value, endPos);
          if (endPos = 0) And (Length (Value) >= 1) then
            Begin
            startPos := 1;
            endPos := 1;
            End
          else if (endPos > 0) And (Length (Value) >= endPos + 2) then
            startPos := endPos + 2
          else
            startPos := 0;
          if (startPos > 0) And (StrToInt (Value[startPos]) > 0) then
            Begin
            Value2 := Copy (Value, startPos, Length (Value) + 1 - startPos);
            AddCustomFieldValueByName (ufTime, CorrectTime (Value2));
            Delete (Value, endPos, Length (Value) + 1 - endPos);
            End;
          End;
        End;
      if optGenre then
        AddFieldValue (mfGenre, Replace (Value));
      End;
    End;


  // Год
  startPos := Pos ('?p=films&year=', HTML);
  if startPos > 0 then
    Begin
    startPos := PosFrom ('">', HTML, startPos) + 2;
    endPos := PosFrom ('<', HTML, startPos);
    Year := Copy (HTML, startPos, endPos - startPos);
    Year := '   ' + Year;
    Year := Trim (Replace (Year));
    Year := Copy (Year, 1, 4);
    if optYear then
      AddFieldValue (mfYear, Year);
    End;

  // Студии и год
  startPos := Pos ('onclick="showStudia(', HTML);
  if startPos > 0 then
    Begin
    Value := HTMLValues2 (HTML, 'onclick="showStudia(', '</td>', '">', '</span>', ';', startPos);
    ExplodeString (Value, Values, ';');
    For i := 0 to High (Values) do
      Begin
      if Pos (' г.', Values[i]) > 0 then
        Break;
      //if Country <> '' then
      //  Country := Country + ', ';
      startPos := LastPos ('(', Values[i]);
      if startPos > 0 then
        Begin
        endPos := PosFrom (')', Values[i], startPos);
      //  Country := Country + Copy (Values[i], startPos + 1, endPos - startPos - 1);
        Delete (Values[i], startPos - 1, endPos + 1 - startPos + 1);
        End;
      if Studio <> '' then
        Studio := Studio + ', ';
      Studio := Studio + Values[i];
      End;
    if optStudio then
      AddFieldValue (mfStudio, Replace (Studio));
    End;

  // Страна
  if optCountry then
    Begin
    if (Year <> '') And (StrToInt (Year) >= 1992) then
      Country := 'Россия'
    else
      Country := 'СССР';
    if optCountry then
      AddFieldValue (mfCountry, Replace (Country));
    End;

  // Описание
  startPos := Pos ('class="FilmComments">', HTML);
  if startPos > 0 then
    Begin
    endPos := PosFrom ('</table>', HTML, startPos) + 8;
    Value := Copy (HTML, startPos, endPos - startPos);
    Value := StringReplace (Value, #10, '<br>', true, true, false);
    startPos := 1;
    Value := TextBetween (Value, 'class="FilmComments">', '</table>', true, startPos);
    while Pos (#13#10#13#10, Value) > 0 do
      Value := StringReplace (Value, #13#10#13#10, #13#10, true, true, false);
    Value := Replace (Value);
    startPos := Pos ('фильм из серии «', Value);
    if startPos = 1 then
      Begin
      endPos := Pos (#13#10, Value);
      Delete (Value, 1, endPos + 2 - 1);
      End;
    AddFieldValue (mfDescription, Value);
    End;

  // Роли озвучивали
  if optActor then
    Begin
    startPos := Pos ('<tr><td valign="top" class="PProf">' + 'роли озвучивали', HTML);
    if startPos > 0 then
      Begin
      endPos := PosFrom ('</td></tr>', HTML, startPos);
      Value := Copy (HTML, startPos, endPos - startPos);

      startPos := 1;
      while true do
        Begin
        startPos := PosFrom ('onclick="showPerson(', Value, startPos);
        if startPos <= 0 then
          Break;

        startPos := startPos + 20;
        endPos := PosFrom (')">', Value, startPos);
        URLActor := 'http://animator.ru/db/?p=show_person&pid=' + Copy (Value, startPos, endPos - startPos);

        startPos := endPos + 3;
        endPos := PosFrom ('</span>', Value, startPos);
        Name := Copy (Value, startPos, endPos - startPos);

        startPos := endPos + 7;
        endPos := PosFrom ('<', Value, startPos);
        Role := Copy (Value, startPos, endPos - startPos);
        pos1 := Pos ('(', Role);
        if pos1 > 0 then
          Role := Copy (Role, pos1 + 1, LastPos (')', Role) - pos1 - 1)
        else
          Role := '';
      
        AddMoviePerson (Replace (Name), '', Replace (Role), URLActor, mpActor);
        End;
      End;
    End;

  // Стандартные персоны
  ParseOnePerson (HTML, 'композитор', optComposer, mpComposer);
  ParseOnePerson (HTML, 'продюсер',   optProducer, mpProducer);
  ParseOnePerson (HTML, 'режиссер',   optDirector, mpDirector);
  ParseOnePerson (HTML, 'сценарист',  optScenario, mpScenario);

  // Персоны в пользовательских полях
  ParseOneUserPerson (HTML, 'аниматор',          optAnimator,      ufAnimator);
  ParseOneUserPerson (HTML, 'директор',          optManager,       ufManager);
  ParseOneUserPerson (HTML, 'звукооператор',     optSoundMan,      ufSoundMan);
  ParseOneUserPerson (HTML, 'куклы и декорации', optPuppetScenery, ufPuppetScenery);
  ParseOneUserPerson (HTML, 'монтажер',          optFilmEditor,    ufFilmEditor);
  ParseOneUserPerson (HTML, 'оператор',          optOperator,      ufOperator);
  ParseOneUserPerson (HTML, 'редактор',          optEditor,        ufEditor);
  ParseOneUserPerson (HTML, 'текст песен',       optSongWriter,    ufSongWriter);
  ParseOneUserPerson (HTML, 'текст чита',        optTextReads,     ufTextReads);
  ParseOneUserPerson (HTML, 'художник<',         optDesigner,      ufDesigner);
  ParseOneUserPerson (HTML, 'xудожник<',         optDesigner,      ufDesigner);  // английское 'x'
  ParseOneUserPerson (HTML, 'художники<',        optDesigner,      ufDesigner);
  ParseOneUserPerson (HTML, 'xудожники<',        optDesigner,      ufDesigner);  // английское 'x'
  ParseOneUserPerson (HTML, 'художник-п',        optProductDesign, ufProductDesign);
  ParseOneUserPerson (HTML, 'художники-п',       optProductDesign, ufProductDesign);

  // Песни
  if optSongs then
    Begin
    startPos := Pos ('>Песни<', HTML);
    if startPos > 0 then
      Begin
      endPos := PosFrom ('<table', HTML, startPos);
      Tmp := Copy (HTML, startPos, endPos - startPos);
      startPos := 1;
      Value := '';
      while true do
        Begin
        startPos := PosFrom ('?p=show_song&id=', Tmp, startPos);
        if startPos = 0 then
          Break;
        startPos := startPos + 16;
        endPos := PosFrom ('">', Tmp, startPos);
        URL := 'http://www.animator.ru/db/?p=show_song&id=' + Copy (Tmp, startPos, endPos - startPos);
        URLSongs := URLSongs + URL + ';';
        
        if loadSongs = 0 then
          Begin
          startPos := endPos + 2;
          endPos := PosFrom ('</a>', Tmp, startPos);
          Name := Replace (Copy (Tmp, startPos, endPos - startPos));
          
          if Value <> '' then
            Value := Value + #13#10;
          if createLink then
            Value := Value + '<link url="' + URL + '">' + Name + '</link>'
          else
            Value := Value + Name;
          End;
        End;
      if loadSongs = 0 then
        AddCustomFieldValueByName (ufSongs, Value);
      End;
    if (loadSongs > 0) And (Length (URLSongs) > 1) then
      Begin
      ExtraLinks[smSong] := Copy (URLSongs, 1, Pos (';', URLSongs) - 1);
      Delete (URLSongs, 1, Pos (';', URLSongs));
      End;
    End;
end;


//******* ParseQuote ******** Парсим цитаты ********
procedure ParseQuote (const HTML: WideString);
var
  Quotes : WideString;
  startPos, endPos : Integer;
Begin
  startPos := 1;
  while true do
    Begin
    startPos := PosFrom ('class=FilmComments>', HTML, startPos);
    if startPos = 0 then
      Break;
    startPos := startPos + 19;
    endPos := PosFrom ('</td>', HTML, startPos);
    if Quotes <> '' then
      Quotes := Quotes + #13#10#13#10;
    Quotes := Quotes + Replace (RemoveTags (Copy (HTML, startPos, endPos - startPos), true));
    End;

  while Pos (#13#10#13#10#13#10, Quotes) > 0 do
    Quotes := StringReplace (Quotes, #13#10#13#10#13#10, #13#10#13#10, true, true, false);
  AddCustomFieldValueByName (ufQuotes, Quotes);
End;


//******* ParseSong ******** Парсим песню **********
var
  ValueSongs : WideString;
procedure ParseSong (const URL, HTML: WideString);
Var
  startPos, endPos : Integer;
  ExtraInfo, Tmp, URLFile, Name, Value : WideString;
Begin
  if ValueSongs <> '' then
    ValueSongs := ValueSongs + '==============================' + #13#10#13#10;

  // Название
  startPos := Pos ('Песни | ', HTML) + 8;
  endPos := PosFrom ('</title>', HTML, startPos);
  Name := Replace (Copy (HTML, startPos, endPos - startPos));
  if createLink then
    Value := Value + '<link url="' + URL + '">' + Name + '</link>'
  else
    Value := Value + Name;
  ValueSongs := ValueSongs + Value;
  
  // Ссылки на файлы
  startPos := 1;
  Value := '';
  while true do
    Begin
    startPos := PosFrom ('<a href="../songs/', HTML, startPos);
    if startPos = 0 then
      Break;
    startPos := startPos + 11;
    endPos := PosFrom ('">', HTML, startPos);
    URLFile := Copy (HTML, startPos, endPos - startPos);
    
    startPos := PosFrom ('alt="cкачать ', HTML, endPos) + 13;
    endPos := PosFrom ('"', HTML, startPos);
    Name := Copy (HTML, startPos, endPos - startPos);
    
    if Value <> '' then
      Value := Value + ', ';
    if createLink then
      Value := Value + '<link url="' + URLFile + '">' + Name + '</link>'
    else
      Value := Value + Name;
    End;
  if Value <> '' then
    ValueSongs := ValueSongs + ' (' + Value + ')';

  ValueSongs := ValueSongs + #13#10;
  
  // Доп. информация
  startPos := Pos ('<tr><td valign="top" class="PProf">', HTML);
  if startPos > 0 then
    Begin
    endPos := PosFrom ('</table>', HTML, startPos) + 8;
    Tmp := Copy (HTML, startPos, endPos - startPos);
    Tmp := StringReplace (Tmp, #10, '<br>', true, true, false);
    Tmp := StringReplace (Tmp, '<td class="PersonsList">', ': ', true, true, false);
    ExtraInfo := RemoveTags (Tmp, true);
    ValueSongs := ValueSongs + Replace (ExtraInfo) + #13#10;
    End;

  // Песня
  if loadSongs >= 2 then
    Begin
    startPos := Pos ('<pre style="font-family:Arial; font-size:12px;">', HTML);
    if startPos > 0 then
      Begin
      endPos := PosFrom ('</pre>', HTML, startPos) + 6;
      Tmp := Copy (HTML, startPos, endPos - startPos);
      Tmp := StringReplace (Tmp, #10, '<br>', true, true, false);
      startPos := 1;
      Value := TextBetween (Tmp, '<pre style="font-family:Arial; font-size:12px;">', '</pre>', true, startPos);
      if Value <> '' then
        ValueSongs := ValueSongs + Value + #13#10#13#10;
      End;
    End;

  // Следующая песня или окнчание обработки
  if Length (URLSongs) > 1 then
    Begin
    Dec (Mode);
    ExtraLinks[smSong] := Copy (URLSongs, 1, Pos (';', URLSongs) - 1);
    Delete (URLSongs, 1, Pos (';', URLSongs));
    End
  else
    Begin
    ExtraLinks[smSong] := '';
    AddCustomFieldValueByName (ufSongs, ValueSongs);
    End;
End;


//******* ParseLinks ******** Парсим связи ********
procedure ParseLinks (const HTML : WideString);
Var
  startPos, endPos : Integer;
  Tmp, URL, Title, Year : WideString;
  Category : String;
Begin
  startPos := Pos ('>Фильмы из серии <', HTML);
  if startPos = 0 then
    Exit;
  endPos := PosFrom ('</td></tr>', HTML, startPos);
  Tmp := Copy (HTML, startPos, endPos - startPos);
  
  endPos := 1;
  if categoryLinks = 0 then
    Category := 'Фильмы из серии:'
  else
    Category := 'Начало:';
  while true do
    Begin
    startPos := PosFrom ('onclick="showFilm(', Tmp, endPos);
    if startPos = 0 then
      Break;
    startPos := startPos + 18;
    endPos := PosFrom (')">', Tmp, startPos);
    URL := 'http://www.animator.ru/db/?p=show_film&fid=' + Copy (Tmp, startPos, endPos - startPos);

    startPos := endPos + 3;
    endPos := PosFrom ('</span>', Tmp, startPos);
    Title := Replace (Copy (Tmp, startPos, endPos - startPos));
    
    startPos := Pos (' г.)', Title);
    if startPos > 0 then
      Begin
      Year := Copy (Title, startPos - 4, 4);
      Delete (Title, startPos - 6, Length (Title));
      End;
     
    TrimQuotes (Title);
    
    if Title = TitleMovie then
      Begin
      if categoryLinks = 1 then
        Category := 'Продолжение:';
      Continue;
      End;

    AddConnection (Title, Title, Category, URL, Year);
    End;

End;

// ******** ParsePage *************** Парсим заданный URL **********
function ParsePage (HTML : WideString; URL : String) : Cardinal;
//var
//  i: longint;
// Tmp : WideString;
begin
{  Tmp := HTMLToText ('---&#1025;---');
  ShowMessage (Tmp, '');
  Result := prFinished;
  Exit;}
  // Если пришла не HTML-страница
  if Pos('<html>', HTML) = 0 then 
     begin
     Result := prError; //произошла ошибка
     Exit;
     end

  // Если нет результатов поиска
  else if Pos (#10'Ничего не найдено по запросу &quot;', HTML) > 0 then
    begin
    Result := prList;
    Exit;
    end

  // Если есть результат поиска
  else if Pos (#10'Найдено ', HTML) > 0 then 
    begin
    // Парсим эти результаты
    ParseSearchResults (HTML);
    Result := prList; //получен список фильмов/персон
    Exit;
    end

  else 
    begin
//    if MsgDelay Then ShowMessage ('Ручная задержка', 'Инфо') else
//    for i := 1 to delay do begin end;
    //ShowMessage (IntToStr (Mode), '');
    Result := prDownload;
    Case Mode Of
      smSearch : Result := ParseMovie (URL, HTML);
      smQuote  : ParseQuote (HTML);
      smSong   : ParseSong (URL, HTML);
      smLinks  : ParseLinks (HTML);
      end;

    // Перебираем следующие режимы, пока не найдем режим с непустой страницей
    Repeat
      Inc (Mode);
    until (mode >= smFinished) Or (GetDownloadURL <> '');
    if Mode >= smFinished then
      Result := prFinished;
  end; 
end;


{
История версий:
v0.0.0.1 от 29.03.2009
+ Загрузка основной информации о фильме (название, год, жанр, категория,
  страна, студии).
+ Загрузка дополнительной информации о фильме (длительность).
+ Загрузка информации о персонах в стандартные поля (режиссеры, продюсеры,
  сценаристы, композиторы, актёры).
+ Загрузка информации о персонах в пользовательские поля (аниматоры, директоры,
  звукооператоры, куклы и декорации, монтажеры, операторы, редакторы, текст
  песен, текст читают, художники, художники-постановщики).
+ Загрузка цитат.
+ Загрузка песен (только названия; названия и доп. информация; названия, доп.
  информация и тексты).

v0.1.0.0 от 12.04.2009
+ Добавлена загрузка связей. См. опции categoryLinks и optConnection.
! Исправлены ссылки у персон в пользовательских полях.
! Устранено отсутствие ссылки на страницу песни при опции loadSongs, не равной
  нулю.


Планы на будущее:
+ Загружать все страницы поиска
+ Загружать английские названия 
+ Проблемный фильм (http://animator.ru/db/?p=show_film&fid=7053)
}