Download manager

0

Witam, piszę aplikację (akcelerator pobierania plików) po dwurocznej przerwie od delphi. Wszystko ładnie pięknie, ale mam dwa podstawowe problemy..

Pierwszy:
Aktualnie do pobierania plików stworzyłem sobie nową klasę, a sam proces wykonuje przy użyciu komponentu IdHTTP z użyciem onWork, progress bar musi być cały czas aktualizowany więc robię to w tej procedurze przy użyciu Application.ProcessMessages, ale już widzę, że ma to swoje minusy. Mianowicie nie mogę zamknąć aplikacji wcześniej niż zakończy się ściąganie, ani nie mogę tego ściągania przerwać, zatrzymać.

Drugi:
Dzielenie na party i ściąganie jednocześnie, jak na razie używam TFileStream, a co jeśli zabraknie prądu, komputer się wyłączy czy cokolwiek, jak później sprawdzić w którym miejscu przerwane zostało ściąganie? Dodam, że przy użyciu FS aplikacja tworzy plik o rozmiarze takim jaki ściąga, gdyby rozmiar rósł w miarę dopisywania bajtów to nie było by z tym większego problemu. TStreamMemory nie nadaje się ze względu na duże rozmiary plików..

Proszę o sugestie, propozycje i podpowiedzi.

0

Co do pierwszego to pobieranie zrób w osobnym wątku, wtedy będzie można normalnie obsługiwać apke i pod przyciskiem anuluj po prostu wywołasz funkcje odpowiedzialną za zakończenie wątku pobocznego odpowiedzialnego za pobieranie i tyle ;)

0

Co do drugiego TFileStream przecież nie tworzy od razu pliku o rozmiarze docelowym tylko zwiększa go stopniowo podczas "dopisywania", poza tym jak dzielisz go na party to musisz znać ich kolejność i np. wielkość ostatniej części, więc musisz zapisywać gdzieś te informacje żeby wiedzieć jak to poskładać - tam możesz zapisać postęp pobierania poszczególnych części (o ile to konieczne).
Najlepiej pokaż jak pobierasz te części.

0

Inne rozwiązanie dla przyrostowych plików to nie używac Indy ani Synapse. Tylko zrobić obslugę pod prawie gołe sockety TCP z użyciem Simple Tcp. Moduł do pobrania z http://piechnat.pl/article/simpletcp.html - na stronie jest prosty przykład dla HTTP. Przykład pobierania poniżej. Dorób sobie pokazywanie postępu lub zmień kod dla swoich potrzeb.

//...
const
  WWW_Prefix = 'www.';
  Default_Http_Port = 80;
  Http_Prefix = 'http://';
  OperaUserAgent = 'Opera/9.80 (Windows NT 6.1; WOW64; U; pl) Presto/2.10.229 Version/11.62';

function GetOnlyHostName(Url : string; OnlyDomain : boolean) : string;
var
  I, Cnt : integer;
  AddWWWPrefix : boolean;
begin
  Url := AnsiLowerCase(Url);
  if Pos(Http_Prefix, Url) = 1 then
  begin
    Delete(Url, 1, Length(Http_Prefix));
  end;
  if not OnlyDomain then
  begin
    AddWWWPrefix := Pos(WWW_Prefix, Url) = 1;
    if AddWwwPrefix then
    begin
      Delete(Url, 1, Length(WWW_Prefix));
    end;
    I := Pos('/', Url);
    if (I > 0) then
    begin
      I := I - 1;
    end
    else
    begin
      I := Length(Url);
    end;
    Result := Copy(Url, 1, I);
  end
  else
  begin
    AddWWWPrefix := Pos(WWW_Prefix, Url) = 1;
    if AddWWWPrefix then
    begin
      Delete(Url, 1, Length(WWW_Prefix));
    end;
    I := Pos('/', Url);
    if (I > 0) then
    begin
      I := I - 1;
    end
    else
    begin
      I := Length(Url);
    end;
    Url := Copy(Url, 1, I);
    Cnt := 0;
    for I := Length(Url) downto 1 do
    begin
      if Url[I] = '.' then
      begin
        Cnt := Cnt + 1;
        if Url[I - 1] = '.' then
        begin
          Url[I - 1] := '\';
        end;
      end;
      if Cnt > 1 then
      begin
        Break;
      end;
    end;
    Delete(Url, 1, I);
    repeat
      Cnt := Pos('\', Url);
      if Cnt > 0 then
      begin
        Delete(Url, Cnt, 1);
      end;
    until Cnt = 0;
    Result := Url;
  end;
end;

function DownloadFileFromWeb(Url, AFileName : string) : boolean;
const
  Content_Length_Prefix = 'Content-Length: ';
var
  Clnt : TTcpClient;
  BytesWritten : DWORD;
  Header, OnlyHost, S : string;
  Buffer : array[0..65535 - 1] of Byte;
  Cnt, SlashPos, Tmp, TotalFileSize : integer;
begin
  TotalFileSize := 0;
  OnlyHost := GetOnlyHostName(Url, False);
  if Pos(Http_Prefix, Url) = 1 then
  begin
    Delete(Url, 1, Length(Http_Prefix));
  end;
  SlashPos := Pos('/', Url);
  if SlashPos > 0 then
  begin
    Url := Copy(Url, SlashPos, MaxInt);
  end;
  Clnt := TTcpClient.Create(OnlyHost, Default_Http_Port);
  Clnt.WriteLn('GET ' + Url + ' HTTP/1.0' + CRLF + 'Host: ' + OnlyHost +
    CRLF + 'User-Agent: ' + OperaUserAgent + CRLF);
  Header := '';
  repeat
    Clnt.ReadLn(S);
    Header := Header + S + CRLF;
  until S = '';
  Tmp := Pos(Content_Length_Prefix, Header);
  if Tmp > 0 then
  begin
    Tmp := Tmp + Length(Content_Length_Prefix);
    Header := Copy(Header, Tmp, MaxInt);
    Tmp := 1;
    while Header[Tmp] <> CR do
    begin
      Tmp := Tmp + 1;
    end;
    Delete(Header, Tmp, MaxInt);
    Val(Header, TotalFileSize, Tmp);
  end;
  Result := TotalFileSize > 0;
  if Result then
  begin
    OutFile := CreateFile(PChar(AFileName), GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_ALWAYS, 0, 0);
    if OutFile > 0 then
    begin
      repeat
        Cnt := Clnt.Read(Buffer, SizeOf(Buffer));
        WriteFile(OutFile, Buffer[0], Cnt, BytesWritten, nil);
      until Cnt = 0;
    end;
    CloseHandle(OutFile);
  end;
  Clnt.Free;
end;
0

@olesio: Zasada DRY w tym kodzie to się chyba zgubiła dawno temu w lesie.

0

@Demonical Monk: wiem, daleko temu kodowi do ideału. To kiedyś na szybko pisane, tak jak umiałem wtedy żeby działało. Nie chciało mi się rzeźbić osobnej klasy do obsługi HTTP dla Simple Tcp Pytający niech sobie zrobi z tym co chce. Chodzi o to żeby zrozumiał ideę.

1

Dzięki, postaram się dzisiaj nad tym siąść i dać znać czy się uporałem ;)

0

Podsyłam wam wersję bardzo ubogą, ale z czasem dodam więcej funkcji etc. :)

Nie wiem jak z kompatybilnością, testowałem na win 7 :)

http://yorki-dev.com/files/dwn.rar

0

a jakies dodatkowe komponenty oprocz indy uzywales? jakies graficzne?

0

Nie, no pr0. Szacun. Pomijając rozmiar exeka dla aplikacji nie robiącej za wiele i to że można maksymalizować okna, które się później nie rozciągną, jak na przykład dodawanie nowego linku oraz jakiś link do gg.rar, który się mi Twój program sugeruje, a który pobrać nie mogę. Poza tym tytuł dialogu Confirm w komunikacje w języku polskim. Elegancja. Powtarzające się wpisy w logu. Niemożność zamknięcia programu po dodaniu tego gg.rar. Nie możnośc jego usunięcia. I ta zakładka TabSeet1. Do tego standardowa ikonka Delphi 7 jako ikona exeka. Pomijam takie drobnostki, że nawet dla na 100% prawidłowego linka i tak mi nie ściąga, a za pewne na systemach z włączonym UAC bez minifestu, próba utworzenia data.dwl i settings.ini w tym samym katalogu co program (o ile nie będzie to folder ze standardowo dozwolonymi do zapisu prawami, a exeka nie uruchomimy jako Admin) spełznie na niczym lub zakończy się błedem. Wiadomo po kiego nam choćby %AppData%. I ten profesjonalnie ustawiony na defaultowo Application.Tittle. Ogółnie tak świetnie napisanemu programowi, wróżę stanie się drugim FireFoxem :/ I nie zarzucajcie mi przypadkiem złośliwości. Autor postuje tutaj tak "dopracowany" program jako publiczną wersję, to pewnie chciał by ktoś tego używał albo przetestował. Także to zrobiłem.

0
olesio napisał(a):

Nie, no pr0. Szacun. Pomijając rozmiar exeka dla aplikacji nie robiącej za wiele i to że można maksymalizować okna, które się później nie rozciągną, jak na przykład dodawanie nowego linku oraz jakiś link do gg.rar, który się mi Twój program sugeruje, a który pobrać nie mogę. Poza tym tytuł dialogu Confirm w komunikacje w języku polskim. Elegancja. Powtarzające się wpisy w logu. Niemożność zamknięcia programu po dodaniu tego gg.rar. Nie możnośc jego usunięcia. I ta zakładka TabSeet1. Do tego standardowa ikonka Delphi 7 jako ikona exeka. Pomijam takie drobnostki, że nawet dla na 100% prawidłowego linka i tak mi nie ściąga, a za pewne na systemach z włączonym UAC bez minifestu, próba utworzenia data.dwl i settings.ini w tym samym katalogu co program (o ile nie będzie to folder ze standardowo dozwolonymi do zapisu prawami, a exeka nie uruchomimy jako Admin) spełznie na niczym lub zakończy się błedem. Wiadomo po kiego nam choćby %AppData%. I ten profesjonalnie ustawiony na defaultowo Application.Tittle. Ogółnie tak świetnie napisanemu programowi, wróżę stanie się drugim FireFoxem :/ I nie zarzucajcie mi przypadkiem złośliwości. Autor postuje tutaj tak "dopracowany" program jako publiczną wersję, to pewnie chciał by ktoś tego używał albo przetestował. Także to zrobiłem.

Dzięki za krytykę i wytknięcie błędów :) Nigdzie nie napisałem, że to publiczna czy finalna wersja, jedynie chciałem pokazać co do tej pory zrobiłem :) bardziej od strony technicznej, czyli ściąganie, partowanie, zapisywanie stanu etc., a nie wygląd :)

0
dsdsd napisał(a):

a jakies dodatkowe komponenty oprocz indy uzywales? jakies graficzne?

Tak, TPNGButton :P

0

Yorki: fajnie, ale jak coś udostępniasz to znaczy, że jest to wersja z której można skorzystać. A tutaj nie da się nawet pobrać żadnego pliku, skutecznie usunąc pobierania z listy czy też nawet czasami zamknąć programu. Wątpie że Tobie to w ogóle działało jak trzeba. Sorry, ale zapodałeś byle co i niedopracowane. I to chyba tylko w celu krtycznej oceny.

0
olesio napisał(a)

Pomijając rozmiar exeka dla aplikacji nie robiącej za wiele

To uroki VCL - rozmiar i tak jest nie najgorszy; Poza tym wiesz jak to początkujący - obce są im praktyki optymalizacji kodu, zmniejszanie rozmiaru plików przez odpowiednie dobieranie plików graficznych, rozdzielanie jego zawartości na pod-pliki, stosowanie striperów czy kompresorów itd. Po spakowaniu poczciwym UPX rozmiar z 919KB zmniejszył się do 382KB, więc nie jest źle; Jednak trzeba zwracać uwagę na rozmiar pliku, bo niepotrzebne pakowanie zbędnych rzeczy nie jest pożądane - jeśli program może zajmować trochę mniej - trzeba to zrobić;

To ja może też coś napiszę na temat tego programiku;


Brak własnej ikony, tytułu aplikacji na pasku zadań i brak tagów o autorze i innych danych odnośnie samej aplikacji - to bardzo smutne... Zaglądnij czasem do właściwości projektu i wzbogać aplikację o kilka ważnych elementów (skrót Shift+Ctrl+F11); Dodanie własnej ikony to przecież nie problem, a bez niej aplikacja prezentuje się nie najlepiej; Jeśli nie masz programu do przygotowania ikon - pobierz sobie ArtIcons - bardzo fajna aplikacja dająca duże możliwości; Jak nie masz ikon - znajdź w sieci - polecam IconsPedia - jest tam mnóstwo ikon, z czego większość darmowych - jest w czym wybierać; Ja od dawna pobieram wszystkie ikonki, jakie tylko pojawiają się na tej stronie (mam już ok. 70.000 ikon) i zawsze mam z czego wybierać przy tworzeniu nowego projektu;

Toolbar dość ubogi - mało opcji, do tego przyciski są za duże - zmniejsz je i dodaj więcej opcji; Optymalna wielkość przycisków paska narzędzi to 32x32 piksele, no maksymalnie 48x48 - większe zbyt rozpraszają uwagę i przeszkadzają;

Brak menu głównego i kontekstowego na liście plików - a to bardzo ogranicza program; Z regóły w programach tworzone jest menu główne, kontekstowe i pasek narzędzi z mniej więcej tymi samymi pozycjami po to, by użytkownik mógł korzystać z tych elementów, z których lubi; Ja lubię menu główne i kontekstowe - tutaj brak; Poza tym w menu głównym powinny znaleźć się wszystkie najważniejsze funkcje - dzięki temu w 10 sekund można przelecieć po wszystkich pozycjach i dowiedzieć się co program oferuje;

W module dodawania pliku do ściągnięcia w ścieżce docelowej można wpisać niedozwolone znaki; Jeśli pozwalasz użyszkodnikowi wpisać ręcznie ścieżkę, to po kliknięciu przycisku Dodaj sprawdź najpierw poprawność danych; Jeśli użytkownik nie może wpisywać ręcznie ścieżki to zablokuj to pole - ustaw ReadOnly i pozwól jedynie wybrać ścieżkę przez SelectDirectory czy podobne;

Okno dialogowe confirm jest tragiczne - brak tytułu, przyciski w języku angielskim... Zrób własne okno z własną grafiką - jeśli nie wiesz jak to polecam mój artykuł - Własne okna dialogowe - w pierwszym przykładzie opisuję w jaki sposób wykonać właśnie prostego MessageBox'a;

Pozakujący się i znikający komponent z zakładkami jest denerwujący - ustal go na stałe; Zobacz sobie jak wygląda uTorrent i na nim się wzoruj; Oczywiście ma dużo więcej możliwości, ale przynajmniej zobaczysz jak powinien wyglądać solidny downloader;

I to, co mnie najbardziej irytuje - dlaczego mogę dodać do listy pozycję, jeśli nie podam linku do pliku? A jakby tego było mało - nie mogę go w ogóle usunąć z listy... Trzeba wyrzucić tworzone dynamicznie dwa pliki obok exeka i tym samym zresetować program;

Ten Twój SelectDirectory strasznie staro wygląda... Wykorzystaj jakiś nowszy, gdzie lokalizację wybiera się z drzewa katalogów tak, jak to ma miejsce w normalnych w obecnych czasach programach;


To tyle - masz nad czym popracować, więc do dzieła! :]

1 użytkowników online, w tym zalogowanych: 0, gości: 1