//**************************************************** // IEMultiDownload * // For Delphi 5 - 2009 * // Freeware Component * // by * // * // Eran Bodankin (bsalsa) * // bsalsa@gmail.com * // * // Documentation and updated versions: * // http://www.bsalsa.com * //**************************************************** {*******************************************************************************} {LICENSE: THIS SOFTWARE IS PROVIDED TO YOU "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED INCLUDING BUT NOT LIMITED TO THE APPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. YOU ASSUME THE ENTIRE RISK AS TO THE ACCURACY AND THE USE OF THE SOFTWARE AND ALL OTHER RISK ARISING OUT OF THE USE OR PERFORMANCE OF THIS SOFTWARE AND DOCUMENTATION. BSALSA PRODUCTIONS DOES NOT WARRANT THAT THE SOFTWARE IS ERROR-FREE OR WILL OPERATE WITHOUT INTERRUPTION. THE SOFTWARE IS NOT DESIGNED, INTENDED OR LICENSED FOR USE IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE CONTROLS, INCLUDING WITHOUT LIMITATION, THE DESIGN, CONSTRUCTION, MAINTENANCE OR OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION OR COMMUNICATION SystemS, AIR TRAFFIC CONTROL, AND LIFE SUPPORT OR WEAPONS SystemS. VSOFT SPECIFICALLY DISCLAIMS ANY EXPRES OR IMPLIED WARRANTY OF FITNESS FOR SUCH PURPOSE. You may use, change or modify the component under 4 conditions: 1. In your website, add a Link to "http://www.bsalsa.com" 2. In your application, add credits to "Embedded Web Browser" 3. Mail me (bsalsa@gmail.com) any code change in the unit for the benefit of the other users. 4. Please consider donation in our web site! {*******************************************************************************} unit IEMultiDownload; {$I EWB.inc} interface uses WinInet, MSHTML_EWB, Windows, SysUtils, Classes, Forms, ExtCtrls, IEDownload, IEParser, EwbUrl; type TIEMultiDownload = class; TMultiState = (msBusy, msReady, msStopped); TMultiDownloadOptions = (doAll, doImages, doPages, doVideo, doMusic); TDownloadItem = class(TCollectionItem) private FFileName: WideString; FPassword: WideString; FPath: WideString; FPort: integer; FProtocol: WideString; FRef: WideString; FRoot: WideString; FUser: WideString; procedure Set_Ref(const Value: WideString); procedure SetFileName(const Value: WideString); procedure SetPassword(const Value: WideString); procedure SetPath(const Value: WideString); procedure SetPort(const Value: integer); procedure SetProtocol(const Value: WideString); procedure SetRoot(const Value: WideString); procedure SetUser(const Value: WideString); public procedure Assign(Source: TPersistent); override; published property FileName: WideString read FFileName write SetFileName; property Ref: WideString read FRef write Set_Ref; property Password: WideString read FPassword write SetPassword; property Path: WideString read FPath write SetPath; property Port: integer read FPort write SetPort; property Protocol: WideString read FProtocol write SetProtocol; property Root: WideString read FRoot write SetRoot; property User: WideString read FUser write SetUser; end; TDownloadList = class(TCollection) private FIEMD: TIEMultiDownload; function GetItem(Index: Integer): TDownloadItem; procedure SetItem(Index: Integer; Value: TDownloadItem); protected function GetOwner: TPersistent; override; public constructor Create(IEMD: TIEMultiDownload); function Add: TDownloadItem; function Insert(Index: Integer): TDownloadItem; function IsListed(const aRef: WideString): Boolean; procedure DeleteItem(Index: Integer); procedure ClearItems; public property Items[index: Integer]: TDownloadItem read GetItem write SetItem; default; end; TOnMultiBeforeDownloadEvent = procedure(Sender: TObject; const hRef: WideString; const Item: TDownloadItem; var Cancel: boolean) of object; TOnMultiCompleteEvent = procedure(Sender: TObject; const DownloadedList: TStrings) of object; TOnMultiGetDocInfoEvent = procedure(Sender: TObject; const Text: string) of object; TOnMultiGetImageEvent = procedure(Sender: TObject; const ImgName: string; var Cancel: Boolean) of object; TOnMultiGetLinkEvent = procedure(Sender: TObject; const hRef, Host, HostName, PathName, Port, Protocol, MimeType, NameProp: string; var Cancel: Boolean) of object; TOnMultiGetQueryInfoEvent = procedure(const MimeType, Encoding, Disposition: string) of object; TOnMultiItemAddedEvent = procedure(Sender: TObject; const hRef, hProtocol, hRoot, hPath, hFileName, hUser, hPassword: WideString; const hPort: integer) of object; TOnMultiParseCompleteEvent = procedure(Sender: TObject; Doc: IhtmlDocument2; All: IHtmlElementCollection) of object; TOnMultiParseDocumentEvent = procedure(Sender: TObject; const Res: HRESULT; stMessage: string) of object; TOnMultiParseErrorEvent = procedure(Sender: TObject; const ErrorCode: integer; const Url, stError: string) of object; TOnMultiParseProgressEvent = procedure(Sender: TObject; const ulProgress, ulProgressMax: integer) of object; TOnMultiStateChangeEvent = procedure(Sender: TObject; const State: TMultiState) of object; TOnMultiStartParsingEvent = procedure(Sender: TObject; const aUrl: WideString) of object; TIEMultiDownload = class(TCustomIEDownload) private FAbout: string; FBaseFolder: WideString; FBaseUrl: WideString; FAbort: Boolean; FDownloadLevel: integer; FFromBaseSiteOnly: Boolean; FGetCompleteBaseSite: Boolean; FItems: TDownloadList; FMultiDownloadOptions: TMultiDownloadOptions; FMultiState: TMultiState; FMaxItems: integer; FOnMultiBeforeDownload: TOnMultiBeforeDownloadEvent; FOnMultiComplete: TOnMultiCompleteEvent; FOnMultiGetDocInfo: TOnMultiGetDocInfoEvent; FOnMultiGetImage: TOnMultiGetImageEvent; FOnMultiGetLink: TOnMultiGetLinkEvent; FOnMultiGetQueryInfo: TOnMultiGetQueryInfoEvent; FOnMultiItemAdded: TOnMultiItemAddedEvent; FOnMultiParseComplete: TOnMultiParseCompleteEvent; FOnMultiParseDocument: TOnMultiParseDocumentEvent; FOnMultiParseError: TOnMultiParseErrorEvent; FOnMultiParseProgress: TOnMultiParseProgressEvent; FOnMultiStateChange: TOnMultiStateChangeEvent; FOnMultiStartParsing: TOnMultiStartParsingEvent; FOpenFolder: boolean; FProgress, FProgressMax: integer; FTimer: TTimer; FRoorUrl: string; HtmlParser: TIEParser; slDownloadedList: TStringList; UrlParser: TUrl; procedure DoOnExit; procedure DownloadList(const aItems: TDownloadList); procedure MultiAnchor(Sender: TObject; hRef, Target, Rel, Rev, Urn, Methods, Name, Host, HostName, PathName, Port, Protocol, Search, Hash, AccessKey, ProtocolLong, MimeType, NameProp: string; Element: TElementInfo); procedure MultiGetDocInfo(Sender: TObject; const Text: string); procedure MultiGetQueryInfo(const MimeType, Encoding, Disposition: string); procedure MultiImage(Sender: TObject; Source: string; ImgElement: IHTMLImgElement; Element: TElementInfo); procedure MultiParseComplete(Sender: TObject; Doc: IhtmlDocument2; All: IHtmlElementCollection); procedure MultiParseDocument(Sender: TObject; const Res: HRESULT; stMessage: string); procedure MultiParseError(Sender: TObject; const ErrorCode: integer; const Url, stError: string); procedure MultiStartParsing(Sender: TObject; const aUrl: WideString); procedure SetAbout(Value: string); procedure SetItems(Value: TDownloadList); procedure SetMaxItems(Value: Integer); procedure MultiTimer(Sender: TObject); protected public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function AddItem(const aRef: string): TDownloadItem; procedure GoMulti(BaseUrl: WideString); procedure SetDownloadOptions(const Value: TMultiDownloadOptions); procedure Stop; public property DownloadedList: TStringList read slDownloadedList; property MultiState: TMultiState read FMultiState; published property About: string read FAbout write SetAbout; property BaseUrl: WideString read FBaseUrl write FBaseUrl; property DownloadLevel: integer read FDownloadLevel write FDownloadLevel default 1; property DownloadOptions: TMultiDownloadOptions read FMultiDownloadOptions write SetDownloadOptions default doAll; property FromBaseSiteOnly: boolean read FFromBaseSiteOnly write FFromBaseSiteOnly default True; property GetCompleteBaseSite: boolean read FGetCompleteBaseSite write FGetCompleteBaseSite default False; property Items: TDownloadList read FItems write SetItems; property MaxItems: integer read FMaxItems write SetMaxItems default 100; property OnMultiBeforeDownload: TOnMultiBeforeDownloadEvent read FOnMultiBeforeDownload write FOnMultiBeforeDownload; property OnMultiComplete: TOnMultiCompleteEvent read FOnMultiComplete write FOnMultiComplete; property OnMultiGetDocInfo: TOnMultiGetDocInfoEvent read FOnMultiGetDocInfo write FOnMultiGetDocInfo; property OnMultiGetImage: TOnMultiGetImageEvent read FOnMultiGetImage write FOnMultiGetImage; property OnMultiGetLink: TOnMultiGetLinkEvent read FOnMultiGetLink write FOnMultiGetLink; property OnMultiGetQueryInfo: TOnMultiGetQueryInfoEvent read FOnMultiGetQueryInfo write FOnMultiGetQueryInfo; property OnMultiItemAdded: TOnMultiItemAddedEvent read FOnMultiItemAdded write FOnMultiItemAdded; property OnMultiParseComplete: TOnMultiParseCompleteEvent read FOnMultiParseComplete write FOnMultiParseComplete; property OnMultiParseDocument: TOnMultiParseDocumentEvent read FOnMultiParseDocument write FOnMultiParseDocument; property OnMultiParseError: TOnMultiParseErrorEvent read FOnMultiParseError write FOnMultiParseError; property OnMultiParseProgress: TOnMultiParseProgressEvent read FOnMultiParseProgress write FOnMultiParseProgress; property OnMultiStateChange: TOnMultiStateChangeEvent read FOnMultiStateChange write FOnMultiStateChange; property OnMultiStartParsing: TOnMultiStartParsingEvent read FOnMultiStartParsing write FOnMultiStartParsing; end; implementation uses IEDownloadTools; procedure TDownloadItem.Assign(Source: TPersistent); var Item: TDownloadItem; begin if (Source is TDownloadItem) then begin Item := (Source as TDownloadItem); FRef := Item.Ref; FProtocol := Item.Protocol; FRoot := Item.Root; FPort := Item.Port; FFileName := Item.FileName; FUser := Item.User; FPassword := Item.Password; FPath := Item.Path; end else begin inherited Assign(Source); end; end; procedure TDownloadItem.SetFileName(const Value: WideString); begin if FFileName <> Value then FFileName := Value; end; procedure TDownloadItem.SetPath(const Value: WideString); begin if FPath <> Value then FPath := Value; end; procedure TDownloadItem.SetRoot(const Value: WideString); begin if FRoot <> Value then FRoot := Value; end; procedure TDownloadItem.SetPort(const Value: integer); begin if FPort <> Value then FPort := Value; end; procedure TDownloadItem.SetUser(const Value: WideString); begin if FUser <> Value then FUser := Value; end; procedure TDownloadItem.SetPassword(const Value: WideString); begin if FPassword <> Value then FPassword := Value; end; procedure TDownloadItem.Set_Ref(const Value: WideString); begin if FRef <> Value then FRef := Value; end; procedure TDownloadItem.SetProtocol(const Value: WideString); begin if FProtocol <> Value then FProtocol := Value; end; //------------------------------------------------------------------------------- procedure TDownloadList.DeleteItem(Index: Integer); begin Delete(Index); end; procedure TDownloadList.ClearItems; begin Clear; end; function TDownloadList.GetItem(Index: Integer): TDownloadItem; begin Result := TDownloadItem(inherited GetItem(Index)); end; procedure TDownloadList.SetItem(Index: Integer; Value: TDownloadItem); begin inherited SetItem(Index, Value); end; function TDownloadList.Add: TDownloadItem; begin Result := TDownloadItem(inherited Add); end; function TDownloadList.Insert(Index: Integer): TDownloadItem; begin Result := Add; Result.Index := Index; end; function TDownloadList.IsListed(const aRef: WideString): Boolean; var I: Integer; begin Result := True; for I := 0 to Count - 1 do if CompareText(LowerCase(Items[I].FRef), LowerCase(aRef)) = 0 then Exit; Result := False; end; constructor TDownloadList.Create(IEMD: TIEMultiDownload); begin inherited Create(TDownloadItem); FIEMD := IEMD; end; function TDownloadList.GetOwner: TPersistent; begin Result := FIEMD; end; //------------------------------------------------------------------------------- function TIEMultiDownload.AddItem(const aRef: string): TDownloadItem; var UP: TUrl; begin Result := nil; if (not FItems.isListed(aRef)) and (FItems.Count <> FMaxItems) and (IEDownloadTools.IsValidURL(aRef)) then begin slDownloadedList.Add(aRef); UP := TUrl.Create(aRef); UP.Clear; UP.QueryUrl(aRef); with FItems.Add do begin FRef := aRef; FProtocol := UP.Protocol; FRoot := UP.HostName; FPort := UP.Port; FFileName := UP.Document; FUser := UP.UserName; FPassword := UP.Password; FPath := CharReplace(UP.UrlPath, '/', '\'); ; if (FPath = Trim('/')) or (FPath = Trim('\')) then FPath := EmptyStr; if Assigned(FOnMultiItemAdded) then FOnMultiItemAdded(Self, FRef, FProtocol, FRoot, FPath, FFileName, FUser, FPassword, FPort); end; UP.Free; end; end; procedure TIEMultiDownload.DownloadList(const aItems: TDownloadList); var bCancel: Boolean; I: integer; FDLFolder: WideString; begin if (not FAbort) then for I := 0 to aItems.Count - 1 do begin if FAbort then Exit; with aItems.Items[I] do begin bCancel := False; if Assigned(FOnMultiBeforeDownload) then FOnMultiBeforeDownload(Self, aItems.Items[I].FRef, aItems.Items[I], bCancel); if not bCancel then begin FDLFolder := FBaseFolder + aItems.Items[I].FRoot + IncludeTrailingPathDelimiter(aItems.Items[I].FPath); if (aItems.Items[I].FRef <> EmptyStr) then Go(aItems.Items[I].FRef, aItems.Items[I].FFileName, FDLFolder); FDLFolder := EmptyStr; end; end; end; end; procedure TIEMultiDownload.GoMulti(BaseUrl: WideString); var I: integer; begin Reset; FAbort := False; FProgress := 0; FProgressMax := 100; FMultiState := msBusy; if Assigned(FOnMultiStateChange) then FOnMultiStateChange(Self, FMultiState); if OpenDownloadFolder = True then begin FOpenFolder := True; OpenDownloadFolder := False; end; if DownloadFolder = EmptyStr then DownloadFolder := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName) + 'Downloads'); FBaseFolder := DownloadFolder; for I := 0 to FItems.Count - 1 do begin if (FItems[i].FRef <> EmptyStr) then DownloadList(FItems); end; if (BaseUrl <> EmptyStr) then begin UrlParser := TUrl.Create(BaseUrl); UrlParser.CrackUrl(BaseUrl, ICU_ESCAPE); FRoorUrl := UrlParser.HostName; with HtmlParser do begin FTimer := TTimer.Create(nil); FTimer.Enabled := True; FTimer.Interval := 500; FTimer.OnTimer := MultiTimer; OnAnchor := MultiAnchor; OnImage := MultiImage; OnParseDocument := MultiParseDocument; OnParseComplete := MultiParseComplete; OnParseError := MultiParseError; OnDocInfo := MultiGetDocInfo; OnQueryInfo := MultiGetQueryInfo; OnStartParsing := MultiStartParsing; Parse(BaseUrl); if (not FGetCompleteBaseSite) then begin if Assigned(FTimer) then FreeAndNil(FTimer); DownloadList(FItems); end else begin if (not FAbort) then for I := 0 to slDownloadedList.Count - 1 do begin Parse(slDownloadedList[I]); if Assigned(FTimer) then FreeAndNil(FTimer); end; DownloadList(FItems); end; end; if UrlParser <> nil then FreeAndNil(UrlParser); end; DoOnExit; end; procedure TIEMultiDownload.MultiTimer(Sender: TObject); begin FProgress := FProgress + 10; if FProgress = FProgressMax then FProgress := 1; if Assigned(FOnMultiParseProgress) then FOnMultiParseProgress(Self, FProgress, FProgressMax); end; procedure TIEMultiDownload.DoOnExit; begin if FOpenFolder then OpenFolder(FBaseFolder); if Assigned(FOnMultiComplete) then FOnMultiComplete(Self, slDownloadedList); slDownloadedList.Clear; Items.Clear; FMultiState := msStopped; if Assigned(FOnMultiStateChange) then FOnMultiStateChange(Self, FMultiState); end; procedure TIEMultiDownload.Stop; begin if FMultiState <> msBusy then Exit; FAbort := True; HtmlParser.Stop; CancelAll; while State <> sBusy do Forms.Application.ProcessMessages; DoOnExit; end; constructor TIEMultiDownload.Create(AOwner: Tcomponent); begin inherited Create(AOwner); FAbout := 'TIEMultiDownload from: http://www.bsalsa.com'; FDownloadLevel := 1; FFromBaseSiteOnly := True; FItems := TDownloadList.Create(Self); FMaxItems := 100; FMultiDownloadOptions := doAll; slDownloadedList := TStringList.Create; with slDownloadedList do begin {$IFDEF DELPHI6UP} CaseSensitive := False; {$ENDIF} Sorted := True; Duplicates := dupIgnore; end; FMultiState := msReady; HtmlParser := TIEParser.Create(nil); end; destructor TIEMultiDownload.Destroy; begin slDownloadedList.Free; if HtmlParser <> nil then FreeAndNil(HtmlParser); FItems.Free; inherited Destroy; end; procedure TIEMultiDownload.SetAbout(Value: string); begin Exit; end; procedure TIEMultiDownload.SetDownloadOptions(const Value: TMultiDownloadOptions); begin FMultiDownloadOptions := Value; end; procedure TIEMultiDownload.SetItems(Value: TDownloadList); begin FItems.Assign(Value); end; procedure TIEMultiDownload.SetMaxItems(Value: Integer); begin {$IFDEF DELPHI10_UP} if (Value <> FItems.Capacity) then FItems.Capacity := Value; {$ENDIF} end; procedure TIEMultiDownload.MultiAnchor(Sender: TObject; hRef, Target, Rel, Rev, Urn, Methods, Name, Host, HostName, PathName, Port, Protocol, Search, Hash, AccessKey, ProtocolLong, MimeType, NameProp: string; Element: TElementInfo); var bCancel: Boolean; begin if FMultiDownloadOptions = doImages then Exit; bCancel := False; if (hRef <> EmptyStr) and (not StrContain('mailto', hRef)) then begin if FFromBaseSiteOnly and (not StrContain(FRoorUrl, hRef)) then Exit; if Assigned(FOnMultiGetLink) then FOnMultiGetLink(Self, hRef, Host, HostName, PathName, Port, Protocol, MimeType, NameProp, bCancel); if (not bCancel) and (not FAbort) and ((FMultiDownloadOptions = doAll) and (not FAbort) or (FMultiDownloadOptions = doPages)) then begin AddItem(LowerCase(hRef)); end; end; end; procedure TIEMultiDownload.MultiImage(Sender: TObject; Source: string; ImgElement: IHTMLImgElement; Element: TElementInfo); var bCancel: Boolean; begin if FMultiDownloadOptions = doPages then Exit; bCancel := False; if Source <> EmptyStr then begin if Assigned(FOnMultiGetImage) then FOnMultiGetImage(Self, Source, bCancel); if (not bCancel) and (not FAbort) and ((FMultiDownloadOptions = doAll) or (FMultiDownloadOptions = doImages)) then begin AddItem(LowerCase(Source)); end; end; end; procedure TIEMultiDownload.MultiGetDocInfo(Sender: TObject; const Text: string); begin if Assigned(FOnMultiGetDocInfo) and not (FAbort) then FOnMultiGetDocInfo(Self, Text); end; procedure TIEMultiDownload.MultiParseError(Sender: TObject; const ErrorCode: integer; const Url, stError: string); begin if Assigned(FOnMultiParseError) then FOnMultiParseError(Self, ErrorCode, Url, stError); end; procedure TIEMultiDownload.MultiStartParsing(Sender: TObject; const aUrl: WideString); begin if Assigned(FOnMultiStartParsing) then FOnMultiStartParsing(Self, aUrl); end; procedure TIEMultiDownload.MultiGetQueryInfo(const MimeType, Encoding, Disposition: string); begin if Assigned(FOnMultiGetQueryInfo) and not (FAbort) then FOnMultiGetQueryInfo(MimeType, Encoding, Disposition); end; procedure TIEMultiDownload.MultiParseDocument(Sender: TObject; const Res: HRESULT; stMessage: string); begin if (Assigned(FOnMultiParseDocument)) and not (FAbort) then FOnMultiParseDocument(Self, Res, stMessage); end; procedure TIEMultiDownload.MultiParseComplete(Sender: TObject; Doc: IhtmlDocument2; All: IHtmlElementCollection); begin if Assigned(FOnMultiParseComplete) then FOnMultiParseComplete(Self, Doc, All); if Assigned(FOnMultiParseProgress) then FOnMultiParseProgress(Self, 0, 0); end; end.