diff --git a/source/decodetorrent.pas b/source/decodetorrent.pas index e34be6f..c1ed5c5 100644 --- a/source/decodetorrent.pas +++ b/source/decodetorrent.pas @@ -47,7 +47,7 @@ TDecodeTorrent = class FTotalFileSize: int64; //Torrent file must have 'info' item. - FBEncoded_Info:TBEncoded; + FBEncoded_Info: TBEncoded; FBEncoded_Comment: TBEncoded; FInfoHash: utf8string; @@ -149,10 +149,12 @@ constructor TDecodeTorrent.Create; //Every torrent have FObjectListFileNameAndLength := TObjectList.Create; - + //List for all the trackers. TrackerList := TStringList.Create; TrackerList.Duplicates := dupIgnore; - TrackerList.Sorted := True; + //Must keep the original order. + TrackerList.Sorted := False; + FMemoryStream := TMemoryStream.Create; end; @@ -207,32 +209,42 @@ function TDecodeTorrent.GetAnnounceList: boolean; var TempBEncoded: TBEncoded; i, Count: integer; + TrackerStr: UTF8String; begin //return false, if crash at decoding. Announce is optional in torrent file. TrackerList.Clear; Result := True; try {find 'announce-list' and copy the list content to TrackerList} - //process 'announce' - TempBEncoded := FBEncoded.ListData.FindElement('announce'); - if assigned(TempBEncoded) then - begin - TrackerList.Add(TempBEncoded.StringData); - end; + //process 'announce' + TempBEncoded := FBEncoded.ListData.FindElement('announce'); + if assigned(TempBEncoded) then + begin + TrackerList.Add(TempBEncoded.StringData); + end; - //process 'announce-list' - TempBEncoded := FBEncoded.ListData.FindElement('announce-list'); - if assigned(TempBEncoded) then + //process 'announce-list' + TempBEncoded := FBEncoded.ListData.FindElement('announce-list'); + if assigned(TempBEncoded) then + begin + Count := TempBEncoded.ListData.Count; + if Count > 0 then begin - Count := TempBEncoded.ListData.Count; - if Count > 0 then + for i := 0 to Count - 1 do begin - for i := 0 to Count - 1 do - begin//there is a list in side a list! - TrackerList.Add(TempBEncoded.ListData.Items[i].Data.ListData.First.Data.StringData); + //there is a list in side a list! + TrackerStr := TempBEncoded.ListData.Items[ + i].Data.ListData.First.Data.StringData; + + // TrackerList is not sorted. Must use IndexOf to ignore duplicated enteries. + if TrackerList.IndexOf(TrackerStr) < 0 then + begin + TrackerList.Add(TrackerStr); end; + end; end; + end; except Result := False; @@ -242,7 +254,7 @@ function TDecodeTorrent.GetAnnounceList: boolean; function TDecodeTorrent.GetFileList: boolean; var //TempBEncodedInfo, - TempBEncodedInfoFiles, TempBEncodedInfoFilesPath: TBEncoded; + TempBEncodedInfoFiles, TempBEncodedInfoFilesPath: TBEncoded; TempBEncodedInfoFilesData: TBEncodedData; i, x, countFiles, countPath: integer; @@ -262,60 +274,60 @@ function TDecodeTorrent.GetFileList: boolean; try {find 'info.files' } - TempBEncodedInfoFiles := FBEncoded_Info.ListData.FindElement('files'); + TempBEncodedInfoFiles := FBEncoded_Info.ListData.FindElement('files'); - if assigned(TempBEncodedInfoFiles) then - begin //'info.files' found - countFiles := TempBEncodedInfoFiles.ListData.Count; - if countFiles > 0 then + if assigned(TempBEncodedInfoFiles) then + begin //'info.files' found + countFiles := TempBEncodedInfoFiles.ListData.Count; + if countFiles > 0 then + begin + for i := 0 to countFiles - 1 do begin - for i := 0 to countFiles - 1 do + //Get the info.files node. + TempBEncodedInfoFilesData := TempBEncodedInfoFiles.ListData.Items[i]; + + //Get the file name with path + FilenameWithPathStr := ''; + TempBEncodedInfoFilesPath := + TempBEncodedInfoFilesData.Data.ListData.FindElement('path'); + countPath := TempBEncodedInfoFilesPath.ListData.Count; + for x := 0 to countPath - 1 do begin - //Get the info.files node. - TempBEncodedInfoFilesData := TempBEncodedInfoFiles.ListData.Items[i]; - - //Get the file name with path - FilenameWithPathStr := ''; - TempBEncodedInfoFilesPath := - TempBEncodedInfoFilesData.Data.ListData.FindElement('path'); - countPath := TempBEncodedInfoFilesPath.ListData.Count; - for x := 0 to countPath - 1 do - begin - FilenameWithPathStr := - FilenameWithPathStr + DirectorySeparator + - TempBEncodedInfoFilesPath.ListData.Items[x].Data.StringData; - end; - - - //Get the file length - FileLength := TempBEncodedInfoFilesData.Data.ListData.FindElement( - 'length').IntegerData; - - DecodeTorrentFileName := TDecodeTorrentFileNameAndLength.Create; - DecodeTorrentFileName.Filename := FilenameWithPathStr; - DecodeTorrentFileName.FileLength := FileLength; - FObjectListFileNameAndLength.Add(DecodeTorrentFileName); - //add it to the total sum of all files inside the torrent. - Inc(FTotalFileSize, FileLength); + FilenameWithPathStr := + FilenameWithPathStr + DirectorySeparator + + TempBEncodedInfoFilesPath.ListData.Items[x].Data.StringData; end; + + //Get the file length + FileLength := TempBEncodedInfoFilesData.Data.ListData.FindElement( + 'length').IntegerData; + + DecodeTorrentFileName := TDecodeTorrentFileNameAndLength.Create; + DecodeTorrentFileName.Filename := FilenameWithPathStr; + DecodeTorrentFileName.FileLength := FileLength; + FObjectListFileNameAndLength.Add(DecodeTorrentFileName); + //add it to the total sum of all files inside the torrent. + Inc(FTotalFileSize, FileLength); end; - end - else //there is no 'info.files' found. This is an 'one file' torrent. - begin// Look for'info.name' and 'info.length' - //Get the file name - Filename := FBEncoded_Info.ListData.FindElement('name').StringData; - FileLength := FBEncoded_Info.ListData.FindElement('length').IntegerData; + end; + end + else //there is no 'info.files' found. This is an 'one file' torrent. + begin// Look for'info.name' and 'info.length' + //Get the file name + Filename := FBEncoded_Info.ListData.FindElement('name').StringData; - DecodeTorrentFileName := TDecodeTorrentFileNameAndLength.Create; - DecodeTorrentFileName.Filename := Filename; - DecodeTorrentFileName.FileLength := FileLength; - FObjectListFileNameAndLength.Add(DecodeTorrentFileName); + FileLength := FBEncoded_Info.ListData.FindElement('length').IntegerData; + DecodeTorrentFileName := TDecodeTorrentFileNameAndLength.Create; + DecodeTorrentFileName.Filename := Filename; + DecodeTorrentFileName.FileLength := FileLength; + FObjectListFileNameAndLength.Add(DecodeTorrentFileName); - Inc(FTotalFileSize, FileLength); - end; + + Inc(FTotalFileSize, FileLength); + end; @@ -358,12 +370,12 @@ function TDecodeTorrent.DecodeTorrent: boolean; //torrent file MUST begin with befDictionary. if FBEncoded.Format <> befDictionary then - exit; //error + exit; //error //torrent MUST have 'info' FBEncoded_Info := FBEncoded.ListData.FindElement('info'); if not assigned(FBEncoded_Info) then - exit; //error + exit; //error //Accept torrent only when there is no issue in reading AnnounceList and file list @@ -372,13 +384,13 @@ function TDecodeTorrent.DecodeTorrent: boolean; Result := True; end; - FInfoHash := GetInfoHash; - FCreatedBy := GetCreatedBy; - FCreatedDate := GetCreatedDate; - FComment := GetComment; - FName := GetName; - FPieceLenght := GetPieceLenght; - FPrivateTorrent:=GetPrivateTorrent; + FInfoHash := GetInfoHash; + FCreatedBy := GetCreatedBy; + FCreatedDate := GetCreatedDate; + FComment := GetComment; + FName := GetName; + FPieceLenght := GetPieceLenght; + FPrivateTorrent := GetPrivateTorrent; except end; @@ -417,11 +429,12 @@ function TDecodeTorrent.GetPrivateTorrent: boolean; procedure TDecodeTorrent.SetComment(const AValue: utf8string); var -// Encoded: TBEncoded; + // Encoded: TBEncoded; Data: TBEncodedData; begin - if FComment=AValue then Exit; - FComment:=AValue; + if FComment = AValue then + Exit; + FComment := AValue; try //if empty comment then remove the element. if FComment = '' then @@ -477,18 +490,18 @@ procedure TDecodeTorrent.RemovePrivateTorrentFlag; procedure TDecodeTorrent.AddPrivateTorrentFlag; var - Encoded: TBEncoded; + Encoded: TBEncoded; Data: TBEncodedData; begin//remove the old one and create a new one RemovePrivateTorrentFlag; try - Encoded := TBEncoded.Create; - Encoded.Format := befInteger; - Encoded.IntegerData := 1; - Data := TBEncodedData.Create(Encoded); - Data.Header := 'private'; - FBEncoded_Info.ListData.Add(Data); - FBEncoded_Info.ListData.Sort(@sort_);//text must be in alfabetical order. + Encoded := TBEncoded.Create; + Encoded.Format := befInteger; + Encoded.IntegerData := 1; + Data := TBEncodedData.Create(Encoded); + Data.Header := 'private'; + FBEncoded_Info.ListData.Add(Data); + FBEncoded_Info.ListData.Sort(@sort_);//text must be in alfabetical order. except end; //read databack again @@ -498,7 +511,7 @@ procedure TDecodeTorrent.AddPrivateTorrentFlag; procedure TDecodeTorrent.RemoveAnnounce; begin try - FBEncoded.ListData.RemoveElement('announce'); + FBEncoded.ListData.RemoveElement('announce'); except end; end; @@ -506,7 +519,7 @@ procedure TDecodeTorrent.RemoveAnnounce; procedure TDecodeTorrent.RemoveAnnounceList; begin try - FBEncoded.ListData.RemoveElement('announce-list'); + FBEncoded.ListData.RemoveElement('announce-list'); except end; end; @@ -542,13 +555,13 @@ procedure TDecodeTorrent.ChangeAnnounce(const TrackerURL: utf8string); begin//remove the old one and create a new one RemoveAnnounce; try - Encoded := TBEncoded.Create; - Encoded.Format := befString; - Encoded.StringData := TrackerURL; - Data := TBEncodedData.Create(Encoded); - Data.Header := 'announce'; - FBEncoded.ListData.Add(Data); - FBEncoded.ListData.Sort(@sort_);//text must be in alfabetical order. + Encoded := TBEncoded.Create; + Encoded.Format := befString; + Encoded.StringData := TrackerURL; + Data := TBEncodedData.Create(Encoded); + Data.Header := 'announce'; + FBEncoded.ListData.Add(Data); + FBEncoded.ListData.Sort(@sort_);//text must be in alfabetical order. except end; end; @@ -556,47 +569,45 @@ procedure TDecodeTorrent.ChangeAnnounce(const TrackerURL: utf8string); procedure TDecodeTorrent.ChangeAnnounceList(StringList: TStringList); var EncodedListRoot, EncodedList, EncodedString: TBEncoded; - Data, Data2, DataRootBEncodedData: TBEncodedData; + DataRootBEncodedData: TBEncodedData; i: integer; begin //remove the present one. RemoveAnnounceList; + //if there is nothing in the list then exit. if StringList.Count = 0 then Exit; + //create a new anounce list try - //Create the 'announce-list' - EncodedListRoot := TBEncoded.Create; - EncodedListRoot.Format := befList; - EncodedListRoot.ListData := TBEncodedDataList.Create; - DataRootBEncodedData := TBEncodedData.Create(EncodedListRoot); - DataRootBEncodedData.Header := 'announce-list'; - FBEncoded.ListData.Add(DataRootBEncodedData); //root - - //Create list inside 'announce-list' - // Str := TempBEncoded.ListData.Items[i].Data.ListData.First.Data.StringData; - - for i := 0 to StringList.Count - 1 do - begin - //create a list with string element - EncodedList := TBEncoded.Create; - EncodedList.Format := befList; - EncodedList.ListData := TBEncodedDataList.Create; - Data := TBEncodedData.Create(EncodedList); - // add list to the list - EncodedListRoot.ListData.Add(Data); - - //String ellement inside the list - EncodedString := TBEncoded.Create; - EncodedString.Format := befString; - EncodedString.StringData := StringList[i]; - Data2 := TBEncodedData.Create(EncodedString); - - EncodedList.ListData.Add(DAta2); - end; + //Create the 'announce-list' + EncodedListRoot := TBEncoded.Create; + EncodedListRoot.Format := befList; + DataRootBEncodedData := TBEncodedData.Create(EncodedListRoot); + DataRootBEncodedData.Header := 'announce-list'; + FBEncoded.ListData.Add(DataRootBEncodedData); //root - FBEncoded.ListData.Sort(@sort_);//text must be in alfabetical order. + //Create list inside 'announce-list' + // Str := TempBEncoded.ListData.Items[i].Data.ListData.First.Data.StringData; + + for i := 0 to StringList.Count - 1 do + begin + //create a list with string element + EncodedList := TBEncoded.Create; + EncodedList.Format := befList; + // add list to the list via TBEncodedData + EncodedListRoot.ListData.Add(TBEncodedData.Create(EncodedList)); + + //String ellement inside the list + EncodedString := TBEncoded.Create; + EncodedString.Format := befString; + EncodedString.StringData := StringList[i]; + // add string to the list via TBEncodedData + EncodedList.ListData.Add(TBEncodedData.Create(EncodedString)); + end; + + FBEncoded.ListData.Sort(@sort_);//text must be in alfabetical order. except end; end; @@ -606,8 +617,8 @@ function TDecodeTorrent.GetInfoHash: utf8string; Result := ''; try //The info.value will be hash with SHA1 - TBEncoded.Encode(FBEncoded_Info, Result); - Result := UpperCase( SHA1Print(SHA1String(Result))); + TBEncoded.Encode(FBEncoded_Info, Result); + Result := UpperCase(SHA1Print(SHA1String(Result))); except end; end; @@ -618,9 +629,9 @@ function TDecodeTorrent.GetCreatedBy: utf8string; begin Result := ''; try - TempBEncoded := FBEncoded.ListData.FindElement('created by'); - if assigned(TempBEncoded) then - Result := TempBEncoded.StringData; + TempBEncoded := FBEncoded.ListData.FindElement('created by'); + if assigned(TempBEncoded) then + Result := TempBEncoded.StringData; except end; @@ -632,9 +643,9 @@ function TDecodeTorrent.GetCreatedDate: TDateTime; begin Result := 0; //Some torrent have no creation date try - TempBEncoded := FBEncoded.ListData.FindElement('creation date'); - if assigned(TempBEncoded) then - Result := UnixToDateTime(TempBEncoded.IntegerData); + TempBEncoded := FBEncoded.ListData.FindElement('creation date'); + if assigned(TempBEncoded) then + Result := UnixToDateTime(TempBEncoded.IntegerData); except end; end; @@ -643,9 +654,9 @@ function TDecodeTorrent.GetComment: utf8string; begin Result := ''; try - FBEncoded_Comment := FBEncoded.ListData.FindElement('comment'); - if assigned(FBEncoded_Comment) then - Result := UTF8Trim( FBEncoded_Comment.StringData); + FBEncoded_Comment := FBEncoded.ListData.FindElement('comment'); + if assigned(FBEncoded_Comment) then + Result := UTF8Trim(FBEncoded_Comment.StringData); except end; end; @@ -657,7 +668,7 @@ function TDecodeTorrent.GetName: utf8string; Result := ''; try {find 'name' } - TempBEncoded := FBEncoded_Info.ListData.FindElement('name'); + TempBEncoded := FBEncoded_Info.ListData.FindElement('name'); if assigned(TempBEncoded) then Result := TempBEncoded.StringData; except diff --git a/source/main.lfm b/source/main.lfm index 9cb2541..4949e56 100644 --- a/source/main.lfm +++ b/source/main.lfm @@ -1,7 +1,7 @@ object FormTrackerModify: TFormTrackerModify - Left = 635 + Left = 743 Height = 607 - Top = 177 + Top = 103 Width = 1179 AllowDropFiles = True Caption = 'Bittorrent Tracker Editor' @@ -16,7 +16,7 @@ object FormTrackerModify: TFormTrackerModify OnDropFiles = FormDropFiles OnShow = FormShow Position = poScreenCenter - LCLVersion = '1.2.6.0' + LCLVersion = '1.4.2.0' object PageControl: TPageControl Left = 0 Height = 587 @@ -301,7 +301,18 @@ object FormTrackerModify: TFormTrackerModify object MenuUpdateTorrent: TMenuItem Caption = '&Update torrent' Hint = 'Update the torrent files' - OnClick = MenuUpdateTorrentClick + object MenuUpdateTorrentAddBefore: TMenuItem + Caption = 'Add new trackers &Before original trackers (new trackers + original trackers)' + OnClick = MenuUpdateTorrentAddBeforeClick + end + object MenuUpdateTorrentAddAfter: TMenuItem + Caption = 'Add new trackers &After original trackers (original trackers + new trackers)' + OnClick = MenuUpdateTorrentAddAfterClick + end + object MenuUpdateTorrentSort: TMenuItem + Caption = '&Sort the trackers by name.' + OnClick = MenuUpdateTorrentSortClick + end end object MenuHelp: TMenuItem Caption = '&Help' diff --git a/source/main.pas b/source/main.pas index 7972d9e..5388fc4 100644 --- a/source/main.pas +++ b/source/main.pas @@ -22,6 +22,10 @@ interface type + //Updated torrent file trackers list order. + TTrackerListOrder = (tloInsertBefore, tloAppendAfter, tloSort); + + { TFormTrackerModify } TFormTrackerModify = class(TForm) @@ -37,6 +41,9 @@ TFormTrackerModify = class(TForm) MenuFileTorrentFolder: TMenuItem; MenuFileOpenTrackerList: TMenuItem; MenuHelpReportingIssue: TMenuItem; + MenuUpdateTorrentSort: TMenuItem; + MenuUpdateTorrentAddAfter: TMenuItem; + MenuUpdateTorrentAddBefore: TMenuItem; MenuItemTorrentFilesTreeHideAll: TMenuItem; MenuItemTorrentFilesTreeShowTrackers: TMenuItem; MenuItemTorrentFilesTreeShowInfo: TMenuItem; @@ -92,7 +99,9 @@ TFormTrackerModify = class(TForm) procedure MenuTrackersKeepOrDeleteAllTrackersClick(Sender: TObject); //Menu update torrent - procedure MenuUpdateTorrentClick(Sender: TObject); + procedure MenuUpdateTorrentAddAfterClick(Sender: TObject); + procedure MenuUpdateTorrentAddBeforeClick(Sender: TObject); + procedure MenuUpdateTorrentSortClick(Sender: TObject); private { private declarations } @@ -100,6 +109,8 @@ TFormTrackerModify = class(TForm) FTrackerAddedByUserList, //Trackers that we want too add. FTrackerBanByUserList, //trackers that must not be present inside torrent. FTrackerFromInsideTorrentFilesList, //Trackers that are already inside the torrent. + FTrackerDeselectedByUserList, //trackers that must not be present inside torrent. + FTorrentFileNameList,// All the torrent files that must be updated FLogStringList //Log string text output : TStringList; @@ -107,6 +118,10 @@ TFormTrackerModify = class(TForm) FConcoleMode, //user have start the program in console mode FFilePresentBanByUserList//There is a file 'remove_trackers.txt' detected : boolean; + + //The new trackers list order + FTrackerListOrderForUpdatedTorrent: TTrackerListOrder; + FLogFile, FTrackerFile: TextFile; FTotalFileInsideTorrent: integer; FTotalFileSizeInsideTorrent: int64; @@ -114,6 +129,10 @@ TFormTrackerModify = class(TForm) FTreeNodeRoot: TTreeNode; FControlerGridTorrentData: TControlerGridTorrentData; + procedure RemoveTrackersFromList(RemoveList, UpdatedList: TStringList); + procedure UpdateTorrent; + procedure AddButIngnoreDuplicates(StringList: TStringList; const Str: UTF8String); + function ByteSizeToBiggerSizeFormatStr(ByteSize: int64): string; procedure ShowHourGlassCursor(HourGlass: boolean); @@ -136,7 +155,8 @@ TFormTrackerModify = class(TForm) function DecodeTorrentFile(const FileName: UTF8String): boolean; procedure UpdateTrackerInsideFileList; procedure UpdateTorrentTrackerList; - procedure CombineThreeTrackerListToOne; + procedure CombineFourTrackerListToOne; + procedure CombineFiveTrackerListToOne(TrackerListOrder: TTrackerListOrder); procedure ShowTrackerInsideFileList; procedure CheckedOnOffAllTrackers(Value: boolean); @@ -206,25 +226,30 @@ procedure TFormTrackerModify.FormCreate(Sender: TObject); FTrackerBanByUserList.Duplicates := dupIgnore; FTrackerBanByUserList.Sorted := False; + //Create deselect tracker list where the user select via user interface checkbox + FTrackerDeselectedByUserList := TStringList.Create; + FTrackerDeselectedByUserList.Duplicates := dupIgnore; + FTrackerDeselectedByUserList.Sorted := False; + //Create tracker list where the user can manualy add items to it FTrackerAddedByUserList := TStringList.Create; FTrackerAddedByUserList.Duplicates := dupIgnore; - //must be sorted. is visible to user. + //Trackers List added by user must keep in the same order. + FTrackerAddedByUserList.Sorted := False; + //drag and drop tracker list will accept duplicates in memo text, if false. Need to check out why. - FTrackerAddedByUserList.Sorted := True; //Create tracker list where all the trackers from all the torrent files are collected FTrackerFromInsideTorrentFilesList := TStringList.Create; FTrackerFromInsideTorrentFilesList.Duplicates := dupIgnore; - //must be sorted. is visible to user. In tracker list tab page. + //Must be sorted. is visible to user. In tracker list tab page. FTrackerFromInsideTorrentFilesList.Sorted := True; - //Create tracker list that combine FTrackerFromInsideTorrentFilesList + FTrackerAddedByUserList together. + //Create tracker list that combine all other together. FTrackerFinalList := TStringList.Create; FTrackerFinalList.Duplicates := dupIgnore; - - //must be sorted. because we want to insert it in torrent files. - FTrackerFinalList.Sorted := True; + //must NOT be sorted. Must keep the original order intact. + FTrackerFinalList.Sorted := False; //Decoding class for torrent. @@ -257,6 +282,7 @@ procedure TFormTrackerModify.FormDestroy(Sender: TObject); FTrackerFromInsideTorrentFilesList.Free; FTorrentFileNameList.Free; FControlerGridTorrentData.Free; + FTrackerDeselectedByUserList.Free; end; procedure TFormTrackerModify.MenuFileTorrentFolderClick(Sender: TObject); @@ -344,8 +370,10 @@ procedure TFormTrackerModify.MenuItemTorrentFilesTreeShowOrHideItemClick( //The tag number define if it is for files, trackers or info items itemsNr := TMenuItem(Sender).tag; + //Must show or hide the items ShowNode := TMenuItem(Sender).Checked; + //process all the torrent files one by one. for i := 0 to CountTorrents - 1 do begin @@ -361,14 +389,13 @@ procedure TFormTrackerModify.MenuItemTorrentFilesTreeShowOrHideItemClick( end; end; - -procedure TFormTrackerModify.MenuUpdateTorrentClick(Sender: TObject); +procedure TFormTrackerModify.UpdateTorrent; var Reply, BoxStyle, i, CountTrackers: integer; PopUpMenuStr: string; begin - //Update the all the torrent files. + //Update all the torrent files. //The StringGridTorrentData where the comment are place by user // must be in sync again with FTorrentFileNameList. @@ -420,10 +447,19 @@ procedure TFormTrackerModify.MenuUpdateTorrentClick(Sender: TObject); //There are 3 list that must be combine //FTrackerFinalList := FTrackerAddedByUserList + FTrackerFromInsideTorrentFilesList // - FTrackerBanByUserList - CombineThreeTrackerListToOne; + CombineFourTrackerListToOne; + + //for tloSort we only need to update the list one time for all the torrent files. + if FTrackerListOrderForUpdatedTorrent = tloSort then + begin + FTrackerFinalList.Sort; + end; + + //How many trackers must be put inside each torrent file. + CountTrackers := FTrackerFinalList.Count; //In console mode we can ignore this warning - if not FConcoleMode and (FTrackerFinalList.Count = 0) then + if not FConcoleMode and (CountTrackers = 0) then begin //Torrent without a tracker is posible. But is this what the user realy want? a DHT torrent. BoxStyle := MB_ICONWARNING + MB_OKCANCEL; Reply := Application.MessageBox( @@ -438,9 +474,6 @@ procedure TFormTrackerModify.MenuUpdateTorrentClick(Sender: TObject); ShowHourGlassCursor(True); end; - //How many trackers must be put inside each torrent file - CountTrackers := FTrackerFinalList.Count; - //process all the files one by one. //FTorrentFileNameList is not sorted it is still in sync with CheckListBoxPublicPrivateTorrent for i := 0 to FTorrentFileNameList.Count - 1 do @@ -450,6 +483,17 @@ procedure TFormTrackerModify.MenuUpdateTorrentClick(Sender: TObject); if not FDecodePresentTorrent.DecodeTorrent(FTorrentFileNameList[i]) then Continue; + //tloInsertBefore and tloAppendAfter need the list be updated or each torrent file. + if (FTrackerListOrderForUpdatedTorrent = tloInsertBefore) or + (FTrackerListOrderForUpdatedTorrent = tloAppendAfter) then + begin + //Add the new tracker before of after the original trackers inside the torrent. + CombineFiveTrackerListToOne(FTrackerListOrderForUpdatedTorrent); + + //How many trackers must be put inside each torrent file + CountTrackers := FTrackerFinalList.Count; + end; + case CountTrackers of 0://if no tracker selected then delete 'announce' and 'announce-list' begin @@ -470,8 +514,6 @@ procedure TFormTrackerModify.MenuUpdateTorrentClick(Sender: TObject); end; end; - - //update the torrent public/private flag if CheckListBoxPublicPrivateTorrent.Checked[i] then begin @@ -524,6 +566,25 @@ procedure TFormTrackerModify.MenuUpdateTorrentClick(Sender: TObject); end; +procedure TFormTrackerModify.AddButIngnoreDuplicates(StringList: TStringList; + const Str: UTF8String); +begin + //Stringlist that are not sorted must use IndexOf to ignore Duplicates. + if not StringList.Sorted then + begin + if StringList.IndexOf(Str) < 0 then + begin + StringList.add(Str); + end; + end + else + begin + StringList.add(Str); + end; + +end; + + function TFormTrackerModify.ByteSizeToBiggerSizeFormatStr(ByteSize: int64): string; begin if ByteSize >= (1024 * 1024 * 1024) then @@ -605,7 +666,8 @@ procedure TFormTrackerModify.ConsoleMode; //Some tracker must be removed. Console and windows mode. UpdateViewRemoveTracker; //update torrent - MenuUpdateTorrentClick(self); + FTrackerListOrderForUpdatedTorrent := tloSort; + UpdateTorrent; end; end else //a torrent file is selected? @@ -625,7 +687,8 @@ procedure TFormTrackerModify.ConsoleMode; //Some tracker must be removed. Console and windows mode. UpdateViewRemoveTracker; //update torrent - MenuUpdateTorrentClick(self); + FTrackerListOrderForUpdatedTorrent := tloSort; + UpdateTorrent; finally StringList.Free; end; @@ -719,7 +782,7 @@ procedure TFormTrackerModify.UpdateTorrentTrackerList; begin //Copy the trackers found in one torrent file to FTrackerFromInsideTorrentFilesList for TrackerStr in FDecodePresentTorrent.TrackerList do - FTrackerFromInsideTorrentFilesList.Add(TrackerStr); + AddButIngnoreDuplicates(FTrackerFromInsideTorrentFilesList, TrackerStr); end; procedure TFormTrackerModify.ShowTrackerInsideFileList; @@ -754,7 +817,8 @@ procedure TFormTrackerModify.CheckedOnOffAllTrackers(Value: boolean); function TFormTrackerModify.ValidTrackerURL(const TrackerURL: UTF8String): boolean; begin //TrackerURL should be cleanup with UTF8trim() - Result := (Pos('http://', TrackerURL) = 1) or (Pos('https://', TrackerURL) = 1) or (Pos('udp://', TrackerURL) = 1); + Result := (Pos('http://', TrackerURL) = 1) or (Pos('https://', TrackerURL) = 1) or + (Pos('udp://', TrackerURL) = 1); end; function TFormTrackerModify.CopyUserInputNewTrackersToList: boolean; @@ -778,7 +842,7 @@ function TFormTrackerModify.CopyUserInputNewTrackersToList: boolean; //All the tracker must begin with 'http(s)://' or 'udp://' if ValidTrackerURL(TrackerStr) then begin - FTrackerAddedByUserList.Add(TrackerStr); + AddButIngnoreDuplicates(FTrackerAddedByUserList, TrackerStr); end else begin @@ -793,7 +857,7 @@ function TFormTrackerModify.CopyUserInputNewTrackersToList: boolean; Application.MessageBox(PChar(@TrackerStr[1]), 'Error: Tracker URL must begin with http(s):// or udp://', MB_ICONERROR); end; - //dot not continue with error. + //do not continue with error. Result := False; exit; end; @@ -808,31 +872,115 @@ function TFormTrackerModify.CopyUserInputNewTrackersToList: boolean; end; - - -procedure TFormTrackerModify.CombineThreeTrackerListToOne; +procedure TFormTrackerModify.CombineFourTrackerListToOne; var TrackerStr: UTF8String; - i: integer; begin - // FTrackerFinalList = (FTrackerAddedByUserList + FTrackerFromInsideTorrentFilesList) - // - FTrackerBanByUserList + // FTrackerFinalList = + // (FTrackerAddedByUserList + // + FTrackerFromInsideTorrentFilesList) + // - FTrackerBanByUserList + // - FTrackerDeselectedByUserList FTrackerFinalList.Clear; for TrackerStr in FTrackerAddedByUserList do - FTrackerFinalList.Add(TrackerStr); + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); for TrackerStr in FTrackerFromInsideTorrentFilesList do - FTrackerFinalList.Add(TrackerStr); + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); - //Remove the trackers must be the last step. - for TrackerStr in FTrackerBanByUserList do - begin - //Find the tracker and remove it from the list. - //FTrackerBanByUserList is not UTF8Trim() before. Must use with UTF8Trim() - i := FTrackerFinalList.IndexOf(UTF8Trim(TrackerStr)); - if i >= 0 then - FTrackerFinalList.Delete(i); + //Trackers from FTrackerAddedByUserList overrule the one from FTrackerDeselectedByUserList + RemoveTrackersFromList(FTrackerAddedByUserList, FTrackerDeselectedByUserList); + + //Remove the trackers that we do not want must be the last step. + RemoveTrackersFromList(FTrackerBanByUserList, FTrackerFinalList); + RemoveTrackersFromList(FTrackerDeselectedByUserList, FTrackerFinalList); + +end; + +procedure TFormTrackerModify.CombineFiveTrackerListToOne( + TrackerListOrder: TTrackerListOrder); +var + TrackerStr: UTF8String; + TrackerFromInsideOneTorrentFile: TStringList; +begin + //Must keep the original order of trackers inside the torrent file. + //The new trackers can be added at the begin of end of the list. + + // FTrackerFinalList = + // (TrackerFromInsideOneTorrentFile + // + FTrackerAddedByUserList + // + FTrackerFromInsideTorrentFilesList) + // - FTrackerBanByUserList + // - FTrackerDeselectedByUserList + + + TrackerFromInsideOneTorrentFile := TStringList.Create; + + try + //Begin with a empty list + FTrackerFinalList.Clear; + + //Read the trackers inside the torrent file + //Copy the trackers found in one torrent file to TrackerFromInsideOneTorrentFile + for TrackerStr in FDecodePresentTorrent.TrackerList do + begin + AddButIngnoreDuplicates(TrackerFromInsideOneTorrentFile, TrackerStr); + end; + + //Add the new tracker list before of after the original trackers list inside the torrent file. + case TrackerListOrder of + + tloInsertBefore: + begin + //Before + + //Must be place as first FTrackerAddedByUserList + for TrackerStr in FTrackerAddedByUserList do + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); + + //original tracker list is second place + for TrackerStr in TrackerFromInsideOneTorrentFile do + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); + + //'Others' trackers added as last. + for TrackerStr in FTrackerFromInsideTorrentFilesList do + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); + end; + + tloAppendAfter: + begin + //After + + //original tracker list must be place first. + for TrackerStr in TrackerFromInsideOneTorrentFile do + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); + + //Must be place after TrackerFromInsideOneTorrentFile + for TrackerStr in FTrackerAddedByUserList do + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); + + //'Others' trackers added as last. + for TrackerStr in FTrackerFromInsideTorrentFilesList do + AddButIngnoreDuplicates(FTrackerFinalList, TrackerStr); + + end; + + else + begin + Assert(True, 'case else: Should never been called. CombineFourTrackerListToOne'); + end; + end; + + //Trackers from FTrackerAddedByUserList overrule the one from FTrackerDeselectedByUserList + RemoveTrackersFromList(FTrackerAddedByUserList, FTrackerDeselectedByUserList); + + //Remove the trackers that we do not want must be the last step. + RemoveTrackersFromList(FTrackerBanByUserList, FTrackerFinalList); + RemoveTrackersFromList(FTrackerDeselectedByUserList, FTrackerFinalList); + + finally + TrackerFromInsideOneTorrentFile.Free; end; end; @@ -842,12 +990,31 @@ procedure TFormTrackerModify.UpdateTrackerInsideFileList; i: integer; begin //Copy items from CheckListBoxTrackersList to FTrackerFromInsideTorrentFilesList + //Copy items from CheckListBoxTrackersList to FTrackerDeselectedByUserList + FTrackerFromInsideTorrentFilesList.Clear; - with CheckListBoxTrackersList do - if Count > 0 then - for i := 0 to Count - 1 do - if Checked[i] then - FTrackerFromInsideTorrentFilesList.add(Items[i]); + FTrackerDeselectedByUserList.Clear; + + if CheckListBoxTrackersList.Count > 0 then + begin + for i := 0 to CheckListBoxTrackersList.Count - 1 do + begin + + if CheckListBoxTrackersList.Checked[i] then + begin + //Selected by user + AddButIngnoreDuplicates(FTrackerFromInsideTorrentFilesList, + CheckListBoxTrackersList.Items[i]); + end + else + begin + //Delected by user + AddButIngnoreDuplicates( + FTrackerDeselectedByUserList, CheckListBoxTrackersList.Items[i]); + end; + + end; + end; end; procedure TFormTrackerModify.LoadTrackersTextFileAddTrackers; @@ -983,6 +1150,43 @@ procedure TFormTrackerModify.MenuTrackersKeepOrDeleteAllTrackersClick(Sender: TO CheckedOnOffAllTrackers(TMenuItem(Sender).Tag = 1); end; +procedure TFormTrackerModify.MenuUpdateTorrentAddAfterClick(Sender: TObject); +begin + //User can select to add new tracker before after the original + FTrackerListOrderForUpdatedTorrent := tloAppendAfter; + UpdateTorrent; +end; + +procedure TFormTrackerModify.MenuUpdateTorrentAddBeforeClick(Sender: TObject); +begin + //User can select to add new tracker before after the original + FTrackerListOrderForUpdatedTorrent := tloInsertBefore; + UpdateTorrent; +end; + +procedure TFormTrackerModify.MenuUpdateTorrentSortClick(Sender: TObject); +begin + //User can select to add new tracker as sorted. + FTrackerListOrderForUpdatedTorrent := tloSort; + UpdateTorrent; +end; + +procedure TFormTrackerModify.RemoveTrackersFromList(RemoveList, + UpdatedList: TStringList); +var + TrackerStr: string; + i: integer; +begin + //Remove the trackers that we do not want in the list + for TrackerStr in RemoveList do + begin + //Find the tracker and remove it from the list. + i := UpdatedList.IndexOf(UTF8Trim(TrackerStr)); + if i >= 0 then + UpdatedList.Delete(i); + end; +end; + function TFormTrackerModify.LoadTorrentViaDir(const Dir: UTF8String): boolean; var @@ -1018,9 +1222,12 @@ procedure TFormTrackerModify.FormDropFiles(Sender: TObject; TorrentFileNameStringList, //for the torrent files TrackerFileNameStringList //for the trackers files : TStringList; - TorrentFileSelectionDetected, ViewUpdateBeginActiveOneTimeOnly + + TorrentFileSelectionDetected, + //ViewUpdateBegin must be called one time. Keep track of it. - : boolean; + ViewUpdateBeginActiveOneTimeOnly: boolean; + FileNameOrDirStr: UTF8String; begin //Drag and drop a folder or files? @@ -1431,7 +1638,7 @@ procedure TFormTrackerModify.ViewUpdateEnd; procedure TFormTrackerModify.ViewUpdateFormCaption; //var - //ProcessTimeStr: string; +//ProcessTimeStr: string; // Hour, Minute, Second, MilliSecond: word; begin //Called when user load the torrent + update the torrent. @@ -1460,9 +1667,6 @@ procedure TFormTrackerModify.ShowHourGlassCursor(HourGlass: boolean); FProcessTimeTotal := now - FProcessTimeStart; end; - - - end; diff --git a/source/trackereditor.lpi b/source/trackereditor.lpi index 9e400cc..7455455 100644 --- a/source/trackereditor.lpi +++ b/source/trackereditor.lpi @@ -9,7 +9,6 @@ - @@ -35,17 +34,13 @@ - + - - - - + - @@ -53,44 +48,38 @@ - - - - - + + + + + - - - + - - - + - - + - - - - + + + @@ -98,549 +87,467 @@ - - - - + + + - - - + + - - - + - - + - - + - - + - - + - - - + - - + - - + - - + - - + - - + - - - + - - + - - - - + - - - + - - + - - + - - - + + - - - - + - - - + + - - + - - + - - + - - - - + + - - + - - - - + + + + + - - - - + + + + + - - - + + - - + - - + - - + - - - + + - - - + - - - - + - - + - - + - - + - - - + + - - - + + - - + - - - + - - - - - + + + + + - - + - - + - - + - - + - - + - - - + + - - + - - + - - + - - + - - + - - + - - + - - - + - - + - - - - - - - + + - - - - - - + + + + + + + + + + - + - - + + - - + + - - + - - + + - - + + - - + + - - + + - + - + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - @@ -658,8 +565,7 @@ - - + @@ -669,12 +575,6 @@ - - - - - - @@ -689,5 +589,4 @@ -