Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- {*************************************************************************************
- This file is part of Transmission Remote GUI.
- Copyright (c) 2008-2014 by Yury Sidorov.
- Transmission Remote GUI is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- Transmission Remote GUI is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Transmission Remote GUI; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *************************************************************************************}
- unit Main;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, FileUtil, zstream, LResources, Forms, Controls, Graphics, Dialogs, ComCtrls, Menus, ActnList,
- httpsend, StdCtrls, fpjson2, jsonparser2, ExtCtrls, rpc, syncobjs, variants, varlist, IpResolver,
- zipper, ResTranslator, VarGrid, StrUtils, LCLProc, Grids, BaseForm, utils, AddTorrent, data;
- const
- AppName = 'Transmission Remote GUI';
- AppVersion = '5.0.1';
- resourcestring
- sAll = 'All torrents';
- sWaiting = 'Waiting';
- sVerifying = 'Verifying';
- sDownloading = 'Downloading';
- sSeeding = 'Seeding';
- sFinished = 'Finished';
- sStopped = 'Stopped';
- sUnknown = 'Unknown';
- sCompleted = 'Completed';
- sConnected = 'connected';
- sActive = 'Active';
- sInactive = 'Inactive';
- sErrorState = 'Error';
- sUpdating = 'Updating...';
- sFinishedDownload = '''%s'' has finished downloading';
- sDownloadComplete = 'Download complete';
- sUpdateComplete = 'Update complete.';
- sTorrentVerification = 'Torrent verification may take a long time.' + LineEnding + 'Are you sure to start verification of torrent ''%s''?';
- sTorrentsVerification = 'Torrents verification may take a long time.' + LineEnding + 'Are you sure to start verification of %d torrents?';
- sReconnect = 'Reconnect in %d seconds.';
- sDisconnected = 'Disconnected';
- sConnectingToDaemon = 'Connecting to daemon...';
- sSecs = '%ds';
- sMins = '%dm';
- sHours = '%dh';
- sDays = '%dd';
- sDownloadingSeeding = '%s%s%d downloading, %d seeding%s%s, %s';
- sDownSpeed = 'D: %s/s';
- sUpSpeed = 'U: %s/s';
- SFreeSpace = 'Free: %s';
- sNoPathMapping = 'Unable to find path mapping.'+LineEnding+'Use the application''s options to setup path mappings.';
- sGeoIPConfirm = 'Geo IP database is needed to resolve country by IP address.' + LineEnding + 'Download this database now?';
- sFlagArchiveConfirm = 'Flag images archive is needed to display country flags.' + LineEnding + 'Download this archive now?';
- sInSwarm = 'in swarm';
- sHashfails = '%s (%d hashfails)';
- sDone = '%s (%s done)';
- sHave = '%d x %s (have %d)';
- sUnableExtractFlag = 'Unable to extract flag image.';
- sTrackerWorking = 'Working';
- sTrackerUpdating = 'Updating';
- sRestartRequired = 'You need to restart the application to apply changes.';
- sRemoveTorrentData = 'Are you sure to remove torrent ''%s'' and all associated DATA?';
- sRemoveTorrentDataMulti = 'Are you sure to remove %d selected torrents and all their associated DATA?';
- sRemoveTorrent = 'Are you sure to remove torrent ''%s''?';
- sRemoveTorrentMulti = 'Are you sure to remove %d selected torrents?';
- sUnableGetFilesList = 'Unable to get files list';
- sTrackerError = 'Tracker';
- sSkip = 'skip';
- sLow = 'low';
- sNormal = 'normal';
- sHigh = 'high';
- sByte = 'b';
- sKByte = 'KB';
- sMByte = 'MB';
- sGByte = 'GB';
- sTByte = 'TB';
- sPerSecond = '/s';
- sOf = 'of';
- sNoTracker = 'No tracker';
- sTorrents = 'Torrents';
- sBlocklistUpdateComplete = 'The block list has been updated successfully.' + LineEnding + 'The list entries count: %d.';
- sSeveralTorrents = '%d torrents';
- sUnableToExecute = 'Unable to execute "%s".';
- sSSLLoadError = 'Unable to load OpenSSL library files: %s and %s';
- SRemoveTracker = 'Are you sure to remove tracker ''%s''?';
- SUnlimited = 'Unlimited';
- SAverage = 'average';
- SCheckNewVersion = 'Do you wish to enable automatic checking for a new version of %s?';
- SDuplicateTorrent = 'Torrent already exists in the list';
- SUpdateTrackers = 'Update trackers for the existing torrent?';
- SDownloadingTorrent = 'Downloading torrent file...';
- SConnectTo = 'Connect to %s';
- SEnterPassword = 'Please enter a password to connect to %s:';
- SDownloaded = 'Downloaded';
- SUploaded = 'Uploaded';
- SFilesAdded = 'Files added';
- SActiveTime = 'Active time';
- type
- { TProgressImage }
- TProgressImage = class(TGraphicControl)
- private
- FBmp: TBitmap;
- FBorderColor: TColor;
- FEndIndex: integer;
- FImageIndex: integer;
- FImages: TImageList;
- FStartIndex: integer;
- FTimer: TTimer;
- function GetFrameDelay: integer;
- procedure SetBorderColor(const AValue: TColor);
- procedure SetEndIndex(const AValue: integer);
- procedure SetFrameDelay(const AValue: integer);
- procedure SetImageIndex(const AValue: integer);
- procedure SetImages(const AValue: TImageList);
- procedure SetStartIndex(const AValue: integer);
- procedure UpdateIndex;
- procedure DoTimer(Sender: TObject);
- protected
- procedure Paint; override;
- procedure VisibleChanged; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- property Images: TImageList read FImages write SetImages;
- property ImageIndex: integer read FImageIndex write SetImageIndex;
- property StartIndex: integer read FStartIndex write SetStartIndex;
- property EndIndex: integer read FEndIndex write SetEndIndex;
- property FrameDelay: integer read GetFrameDelay write SetFrameDelay;
- property BorderColor: TColor read FBorderColor write SetBorderColor;
- end;
- { TMainForm }
- TMainForm = class(TBaseForm)
- acConnect: TAction;
- acAddTorrent: TAction;
- acStopTorrent: TAction;
- acRemoveTorrent: TAction;
- acStartTorrent: TAction;
- acSetHighPriority: TAction;
- acSetNormalPriority: TAction;
- acSetLowPriority: TAction;
- acSetNotDownload: TAction;
- acOptions: TAction;
- acDaemonOptions: TAction;
- acStartAllTorrents: TAction;
- acStopAllTorrents: TAction;
- acExit: TAction;
- acResolveHost: TAction;
- acResolveCountry: TAction;
- acShowCountryFlag: TAction;
- acSetupColumns: TAction;
- acRemoveTorrentAndData: TAction;
- acOpenFile: TAction;
- acOpenContainingFolder: TAction;
- acAddLink: TAction;
- acReannounceTorrent: TAction;
- acMoveTorrent: TAction;
- acSelectAll: TAction;
- acShowApp: TAction;
- acHideApp: TAction;
- acAddTracker: TAction;
- acEditTracker: TAction;
- acDelTracker: TAction;
- acConnOptions: TAction;
- acNewConnection: TAction;
- acDisconnect: TAction;
- acAltSpeed: TAction;
- acForceStartTorrent: TAction;
- acQMoveTop: TAction;
- acQMoveUp: TAction;
- acQMoveDown: TAction;
- acQMoveBottom: TAction;
- acCheckNewVersion: TAction;
- acFolderGrouping: TAction;
- acAdvEditTrackers: TAction;
- acFilterPane: TAction;
- acInfoPane: TAction;
- acStatusBar: TAction;
- acCopyPath: TAction;
- acRename: TAction;
- acTrackerGrouping: TAction;
- acUpdateBlocklist: TAction;
- acUpdateGeoIP: TAction;
- acTorrentProps: TAction;
- acVerifyTorrent: TAction;
- ActionList: TActionList;
- ApplicationProperties: TApplicationProperties;
- edSearch: TEdit;
- imgSearch: TImage;
- imgFlags: TImageList;
- FilterTimer: TTimer;
- MenuItem100: TMenuItem;
- MenuItem68: TMenuItem;
- MenuItem93: TMenuItem;
- MenuItem94: TMenuItem;
- MenuItem95: TMenuItem;
- MenuItem96: TMenuItem;
- MenuItem97: TMenuItem;
- MenuItem98: TMenuItem;
- MenuItem99: TMenuItem;
- panDetailsWait: TPanel;
- txGlobalStats: TLabel;
- lvFilter: TVarGrid;
- lvTrackers: TVarGrid;
- MenuItem25: TMenuItem;
- MenuItem34: TMenuItem;
- MenuItem35: TMenuItem;
- MenuItem40: TMenuItem;
- MenuItem41: TMenuItem;
- MenuItem43: TMenuItem;
- MenuItem63: TMenuItem;
- MenuItem64: TMenuItem;
- MenuItem77: TMenuItem;
- MenuItem78: TMenuItem;
- MenuItem79: TMenuItem;
- MenuItem80: TMenuItem;
- MenuItem81: TMenuItem;
- MenuItem82: TMenuItem;
- MenuItem83: TMenuItem;
- MenuItem84: TMenuItem;
- MenuItem85: TMenuItem;
- MenuItem86: TMenuItem;
- MenuItem87: TMenuItem;
- MenuItem88: TMenuItem;
- MenuItem89: TMenuItem;
- MenuItem90: TMenuItem;
- MenuItem91: TMenuItem;
- MenuItem92: TMenuItem;
- miView: TMenuItem;
- miDonate: TMenuItem;
- miHomePage: TMenuItem;
- pmiQueue: TMenuItem;
- miQueue: TMenuItem;
- pmFilter: TPopupMenu;
- sepTrackers: TMenuItem;
- MenuItem65: TMenuItem;
- MenuItem66: TMenuItem;
- MenuItem67: TMenuItem;
- MenuItem69: TMenuItem;
- MenuItem70: TMenuItem;
- MenuItem72: TMenuItem;
- MenuItem76: TMenuItem;
- pmiUpSpeedLimit: TMenuItem;
- pmiDownSpeedLimit: TMenuItem;
- pmDownSpeeds: TPopupMenu;
- pmUpSpeeds: TPopupMenu;
- sepCon2: TMenuItem;
- MenuItem71: TMenuItem;
- sepCon1: TMenuItem;
- MenuItem73: TMenuItem;
- MenuItem74: TMenuItem;
- MenuItem75: TMenuItem;
- pmSepOpen2: TMenuItem;
- MenuItem42: TMenuItem;
- pmSepOpen1: TMenuItem;
- MenuItem44: TMenuItem;
- MenuItem45: TMenuItem;
- MenuItem46: TMenuItem;
- MenuItem47: TMenuItem;
- MenuItem48: TMenuItem;
- MenuItem49: TMenuItem;
- MenuItem50: TMenuItem;
- MenuItem51: TMenuItem;
- MenuItem52: TMenuItem;
- MenuItem53: TMenuItem;
- MenuItem54: TMenuItem;
- MenuItem55: TMenuItem;
- MenuItem56: TMenuItem;
- MenuItem58: TMenuItem;
- MenuItem59: TMenuItem;
- MenuItem60: TMenuItem;
- MenuItem61: TMenuItem;
- MenuItem62: TMenuItem;
- miPriority: TMenuItem;
- pmiPriority: TMenuItem;
- MenuItem57: TMenuItem;
- pbDownloaded: TPaintBox;
- pmTrackers: TPopupMenu;
- pmConnections: TPopupMenu;
- tabStats: TTabSheet;
- tabTrackers: TTabSheet;
- tbConnect: TToolButton;
- tbtAltSpeed: TToolButton;
- sepAltSpeed: TToolButton;
- sepQueue: TToolButton;
- tbQMoveUp: TToolButton;
- tbQMoveDown: TToolButton;
- ToolButton9: TToolButton;
- txConnErrorLabel: TLabel;
- panSearch: TPanel;
- panFilter: TPanel;
- panReconnectFrame: TShape;
- txReconnectSecs: TLabel;
- txConnError: TLabel;
- MenuItem38: TMenuItem;
- MenuItem39: TMenuItem;
- panReconnect: TPanel;
- txLastActive: TLabel;
- txLastActiveLabel: TLabel;
- txTracker: TLabel;
- txTrackerLabel: TLabel;
- txCompletedOn: TLabel;
- txCompletedOnLabel: TLabel;
- txAddedOn: TLabel;
- txAddedOnLabel: TLabel;
- MenuItem19: TMenuItem;
- MenuItem20: TMenuItem;
- MenuItem21: TMenuItem;
- MenuItem22: TMenuItem;
- MenuItem23: TMenuItem;
- MenuItem24: TMenuItem;
- miTSep1: TMenuItem;
- MenuItem26: TMenuItem;
- MenuItem27: TMenuItem;
- MenuItem28: TMenuItem;
- MenuItem29: TMenuItem;
- MenuItem30: TMenuItem;
- MenuItem31: TMenuItem;
- MenuItem32: TMenuItem;
- MenuItem33: TMenuItem;
- MenuItem36: TMenuItem;
- MenuItem37: TMenuItem;
- miAbout: TMenuItem;
- miHelp: TMenuItem;
- panTop: TPanel;
- pmTray: TPopupMenu;
- HSplitter: TSplitter;
- pmPeers: TPopupMenu;
- TrayIcon: TTrayIcon;
- txCreated: TLabel;
- txCreatedLabel: TLabel;
- txTorrentHeader: TPanel;
- txTorrentName: TLabel;
- txTorrentNameLabel: TLabel;
- txDownProgress: TLabel;
- txDownProgressLabel: TLabel;
- panProgress: TPanel;
- txMaxPeers: TLabel;
- txMaxPeersLabel: TLabel;
- txPeers: TLabel;
- txPeersLabel: TLabel;
- txSeeds: TLabel;
- txSeedsLabel: TLabel;
- txDummy2: TLabel;
- txTrackerUpdate: TLabel;
- txDummy1: TLabel;
- txRemaining: TLabel;
- txRemainingLabel: TLabel;
- txStatus: TLabel;
- txStatusLabel: TLabel;
- txRatio: TLabel;
- txRatioLabel: TLabel;
- txDownLimit: TLabel;
- txDownLimitLabel: TLabel;
- txTrackerUpdateLabel: TLabel;
- txTransferHeader: TPanel;
- txUpSpeed: TLabel;
- txUpLimit: TLabel;
- txUpSpeedLabel: TLabel;
- txDownSpeed: TLabel;
- txDownSpeedLabel: TLabel;
- txUploaded: TLabel;
- txUploadedLabel: TLabel;
- txDownloaded: TLabel;
- txDownloadedLabel: TLabel;
- txUpLimitLabel: TLabel;
- txWasted: TLabel;
- txWastedLabel: TLabel;
- miCopyLabel: TMenuItem;
- pmLabels: TPopupMenu;
- txError: TLabel;
- txErrorLabel: TLabel;
- MenuItem17: TMenuItem;
- MenuItem18: TMenuItem;
- miTools: TMenuItem;
- TickTimer: TTimer;
- MainToolBar: TToolBar;
- panTransfer: TPanel;
- ToolButton1: TToolButton;
- ToolButton2: TToolButton;
- ToolButton3: TToolButton;
- ToolButton4: TToolButton;
- tbStopTorrent: TToolButton;
- ToolButton6: TToolButton;
- ToolButton7: TToolButton;
- ToolButton8: TToolButton;
- txComment: TLabel;
- txCommentLabel: TLabel;
- txHash: TLabel;
- txHashLabel: TLabel;
- panGeneralInfo: TPanel;
- lvFiles: TVarGrid;
- lvPeers: TVarGrid;
- MainMenu: TMainMenu;
- MenuItem1: TMenuItem;
- MenuItem10: TMenuItem;
- MenuItem11: TMenuItem;
- MenuItem12: TMenuItem;
- MenuItem13: TMenuItem;
- MenuItem14: TMenuItem;
- MenuItem15: TMenuItem;
- MenuItem16: TMenuItem;
- MenuItem2: TMenuItem;
- MenuItem3: TMenuItem;
- MenuItem4: TMenuItem;
- MenuItem5: TMenuItem;
- MenuItem6: TMenuItem;
- MenuItem7: TMenuItem;
- MenuItem8: TMenuItem;
- MenuItem9: TMenuItem;
- miConnect: TMenuItem;
- miExit: TMenuItem;
- miTorrent: TMenuItem;
- OpenTorrentDlg: TOpenDialog;
- PageInfo: TPageControl;
- pmTorrents: TPopupMenu;
- pmFiles: TPopupMenu;
- sbGenInfo: TScrollBox;
- txPieces: TLabel;
- txPiecesLabel: TLabel;
- txTotalSize: TLabel;
- txTotalSizeLabel: TLabel;
- gTorrents: TVarGrid;
- gStats: TVarGrid;
- VSplitter: TSplitter;
- StatusBar: TStatusBar;
- tabPeers: TTabSheet;
- tabGeneral: TTabSheet;
- TorrentsListTimer: TTimer;
- tabFiles: TTabSheet;
- procedure acAddLinkExecute(Sender: TObject);
- procedure acAddTorrentExecute(Sender: TObject);
- procedure acAddTrackerExecute(Sender: TObject);
- procedure acAdvEditTrackersExecute(Sender: TObject);
- procedure acAltSpeedExecute(Sender: TObject);
- procedure acCheckNewVersionExecute(Sender: TObject);
- procedure acConnectExecute(Sender: TObject);
- procedure acConnOptionsExecute(Sender: TObject);
- procedure acCopyPathExecute(Sender: TObject);
- procedure acDelTrackerExecute(Sender: TObject);
- procedure acEditTrackerExecute(Sender: TObject);
- procedure acFilterPaneExecute(Sender: TObject);
- procedure acFolderGroupingExecute(Sender: TObject);
- procedure acForceStartTorrentExecute(Sender: TObject);
- procedure acHideAppExecute(Sender: TObject);
- procedure acInfoPaneExecute(Sender: TObject);
- procedure acMoveTorrentExecute(Sender: TObject);
- procedure acNewConnectionExecute(Sender: TObject);
- procedure acOpenContainingFolderExecute(Sender: TObject);
- procedure acOpenFileExecute(Sender: TObject);
- procedure acOptionsExecute(Sender: TObject);
- procedure acDisconnectExecute(Sender: TObject);
- procedure acExitExecute(Sender: TObject);
- procedure acDaemonOptionsExecute(Sender: TObject);
- procedure acQMoveBottomExecute(Sender: TObject);
- procedure acQMoveDownExecute(Sender: TObject);
- procedure acQMoveTopExecute(Sender: TObject);
- procedure acQMoveUpExecute(Sender: TObject);
- procedure acReannounceTorrentExecute(Sender: TObject);
- procedure acRemoveTorrentAndDataExecute(Sender: TObject);
- procedure acRemoveTorrentExecute(Sender: TObject);
- procedure acRenameExecute(Sender: TObject);
- procedure acResolveCountryExecute(Sender: TObject);
- procedure acResolveHostExecute(Sender: TObject);
- procedure acSelectAllExecute(Sender: TObject);
- procedure acSetHighPriorityExecute(Sender: TObject);
- procedure acSetLowPriorityExecute(Sender: TObject);
- procedure acSetNormalPriorityExecute(Sender: TObject);
- procedure acSetNotDownloadExecute(Sender: TObject);
- procedure acSetupColumnsExecute(Sender: TObject);
- procedure acShowAppExecute(Sender: TObject);
- procedure acShowCountryFlagExecute(Sender: TObject);
- procedure acStartAllTorrentsExecute(Sender: TObject);
- procedure acStartTorrentExecute(Sender: TObject);
- procedure acStatusBarExecute(Sender: TObject);
- procedure acStopAllTorrentsExecute(Sender: TObject);
- procedure acStopTorrentExecute(Sender: TObject);
- procedure acTorrentPropsExecute(Sender: TObject);
- procedure acTrackerGroupingExecute(Sender: TObject);
- procedure acUpdateBlocklistExecute(Sender: TObject);
- procedure acUpdateGeoIPExecute(Sender: TObject);
- procedure acVerifyTorrentExecute(Sender: TObject);
- procedure ApplicationPropertiesEndSession(Sender: TObject);
- procedure ApplicationPropertiesException(Sender: TObject; E: Exception);
- procedure ApplicationPropertiesIdle(Sender: TObject; var Done: Boolean);
- procedure ApplicationPropertiesMinimize(Sender: TObject);
- procedure ApplicationPropertiesRestore(Sender: TObject);
- procedure edSearchChange(Sender: TObject);
- procedure FormActivate(Sender: TObject);
- procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
- procedure FormWindowStateChange(Sender: TObject);
- procedure gTorrentsCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; var CellAttribs: TCellAttributes);
- procedure gTorrentsClick(Sender: TObject);
- procedure gTorrentsDblClick(Sender: TObject);
- procedure gTorrentsDrawCell(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; const R: TRect; var ADefaultDrawing: boolean);
- procedure gTorrentsEditorHide(Sender: TObject);
- procedure gTorrentsEditorShow(Sender: TObject);
- procedure gTorrentsQuickSearch(Sender: TVarGrid; var SearchText: string; var ARow: integer);
- procedure gTorrentsResize(Sender: TObject);
- procedure gTorrentsSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
- procedure gTorrentsSortColumn(Sender: TVarGrid; var ASortCol: integer);
- procedure HSplitterChangeBounds(Sender: TObject);
- procedure lvFilesDblClick(Sender: TObject);
- procedure lvFilesEditorHide(Sender: TObject);
- procedure lvFilesEditorShow(Sender: TObject);
- procedure lvFilesSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
- procedure lvFilterCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; var CellAttribs: TCellAttributes);
- procedure lvFilterClick(Sender: TObject);
- procedure lvFilterDrawCell(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; const R: TRect; var ADefaultDrawing: boolean);
- procedure lvPeersCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; var CellAttribs: TCellAttributes);
- procedure lvTrackersCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; var CellAttribs: TCellAttributes);
- procedure lvTrackersDblClick(Sender: TObject);
- procedure lvTrackersKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
- procedure miDonateClick(Sender: TObject);
- procedure miHomePageClick(Sender: TObject);
- procedure PageInfoResize(Sender: TObject);
- procedure panReconnectResize(Sender: TObject);
- procedure pbDownloadedPaint(Sender: TObject);
- procedure StatusBarMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- procedure TickTimerTimer(Sender: TObject);
- procedure FilterTimerTimer(Sender: TObject);
- procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
- procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- procedure FormResize(Sender: TObject);
- procedure FormShow(Sender: TObject);
- procedure lvFilterResize(Sender: TObject);
- procedure miAboutClick(Sender: TObject);
- procedure miCopyLabelClick(Sender: TObject);
- procedure PageInfoChange(Sender: TObject);
- procedure TorrentsListTimerTimer(Sender: TObject);
- procedure pmFilesPopup(Sender: TObject);
- procedure pmTorrentsPopup(Sender: TObject);
- procedure TrayIconDblClick(Sender: TObject);
- procedure VSplitterChangeBounds(Sender: TObject);
- private
- FStarted: boolean;
- FTorrents: TVarList;
- FFiles: TVarList;
- FTrackers: TStringList;
- FResolver: TIpResolver;
- FUnZip: TUnZipper;
- FReconnectWaitStart: TDateTime;
- FReconnectTimeOut: integer;
- FTorrentProgress: TBitmap;
- FLastPieces: string;
- FLastPieceCount: integer;
- FLastDone: double;
- FCurConn: string;
- FPathMap: TStringList;
- FLastFilerIndex: integer;
- FFilterChanged: boolean;
- FCurDownSpeedLimit: integer;
- FCurUpSpeedLimit: integer;
- FFlagsPath: string;
- FAddingTorrent: integer;
- FPendingTorrents: TStringList;
- FLinksFromClipboard: boolean;
- FLastClipboardLink: string;
- //Added by Antekgla
- FFileManagerDefault: string;
- FFileManagerDefaultParam: string;
- //End added by Antekgla
- {$ifdef LCLcarbon}
- FFormActive: boolean;
- {$endif LCLcarbon}
- FSlowResponse: TProgressImage;
- FDetailsWait: TProgressImage;
- FDetailsWaitStart: TDateTime;
- FMainFormShown: boolean;
- FFilesTree: TFilesTree;
- FFilesCapt: string;
- FCalcAvg: boolean;
- FPasswords: TStringList;
- procedure UpdateUI;
- procedure UpdateUIRpcVersion(RpcVersion: integer);
- function DoConnect: boolean;
- procedure DoCreateOutZipStream(Sender: TObject; var AStream: TStream; AItem: TFullZipFileEntry);
- procedure DoDisconnect;
- procedure DoOpenFlagsZip(Sender: TObject; var AStream: TStream);
- procedure TorrentProps(PageNo: integer);
- procedure ShowConnOptions(NewConnection: boolean);
- procedure SaveColumns(LV: TVarGrid; const AName: string; FullInfo: boolean = True);
- procedure LoadColumns(LV: TVarGrid; const AName: string; FullInfo: boolean = True);
- function GetTorrentError(t: TJSONObject; Status: integer): string;
- function SecondsToString(j: integer): string;
- function DoAddTorrent(const FileName: Utf8String): boolean;
- procedure UpdateTray;
- procedure HideApp;
- procedure ShowApp;
- procedure DownloadFinished(const TorrentName: string);
- function GetFlagImage(const CountryCode: string): integer;
- procedure BeforeCloseApp;
- function GetGeoIpDatabase: string;
- function GetFlagsArchive: string;
- function DownloadGeoIpDatabase(AUpdate: boolean): boolean;
- procedure TorrentColumnsChanged;
- function EtaToString(ETA: integer): string;
- function GetTorrentStatus(TorrentIdx: integer): string;
- function GetSeedsText(Seeds, SeedsTotal: integer): string;
- function GetPeersText(Peers, PeersTotal, Leechers: integer): string;
- function RatioToString(Ratio: double): string;
- function TorrentDateTimeToString(d: Int64): string;
- procedure DoRefresh(All: boolean = False);
- function GetFilesCommonPath(files: TJSONArray): string;
- procedure InternalRemoveTorrent(const Msg, MsgMulti: string; RemoveLocalData: boolean);
- function IncludeProperTrailingPathDelimiter(const s: string): string;
- procedure UrlLabelClick(Sender: TObject);
- procedure CenterReconnectWindow;
- procedure ProcessPieces(const Pieces: string; PieceCount: integer; const Done: double);
- function ExecRemoteFile(const FileName: string; SelectFile: boolean): boolean;
- function GetSelectedTorrents: variant;
- procedure FillDownloadDirs(CB: TComboBox; const CurFolderParam: string);
- procedure SaveDownloadDirs(CB: TComboBox; const CurFolderParam: string);
- procedure SetRefreshInterval;
- procedure AddTracker(EditMode: boolean);
- procedure UpdateConnections;
- procedure DoConnectToHost(Sender: TObject);
- procedure FillSpeedsMenu;
- procedure DoSetDownloadSpeed(Sender: TObject);
- procedure DoSetUploadSpeed(Sender: TObject);
- procedure SetSpeedLimit(const Dir: string; Speed: integer);
- function FixSeparators(const p: string): string;
- function MapRemoteToLocal(const RemotePath: string): string;
- procedure CheckAddTorrents;
- procedure CheckClipboardLink;
- procedure CenterDetailsWait;
- function GetPageInfoType(pg: TTabSheet): TAdvInfoType;
- procedure DetailsUpdated;
- function RenameTorrent(TorrentId: integer; const OldPath, NewName: string): boolean;
- procedure FilesTreeStateChanged(Sender: TObject);
- function SelectTorrent(TorrentId, TimeOut: integer): integer;
- procedure OpenCurrentTorrent(OpenFolderOnly: boolean);
- public
- procedure FillTorrentsList(list: TJSONArray);
- procedure FillPeersList(list: TJSONArray);
- procedure FillFilesList(ATorrentId: integer; list, priorities, wanted: TJSONArray; const DownloadDir: WideString);
- procedure FillGeneralInfo(t: TJSONObject);
- procedure FillTrackersList(TrackersData: TJSONObject);
- procedure FillSessionInfo(s: TJSONObject);
- procedure FillStatistics(s: TJSONObject);
- procedure CheckStatus(Fatal: boolean = True);
- function TorrentAction(const TorrentIds: variant; const AAction: string; args: TJSONObject = nil): boolean;
- function SetFilePriority(TorrentId: integer; const Files: array of integer; const APriority: string): boolean;
- function SetCurrentFilePriority(const APriority: string): boolean;
- procedure SetTorrentPriority(APriority: integer);
- procedure ClearDetailsInfo(Skip: TAdvInfoType = aiNone);
- function SelectRemoteFolder(const CurFolder, DialogTitle: string): string;
- procedure ConnectionSettingsChanged(const ActiveConnection: string; ForceReconnect: boolean);
- end;
- function CheckAppParams: boolean;
- function GetHumanSize(sz: double; RoundTo: integer = 0; const EmptyStr: string = '-'): string;
- function PriorityToStr(p: integer; var ImageIndex: integer): string;
- procedure DrawProgressCell(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; const ACellRect: TRect);
- var
- MainForm: TMainForm;
- RpcObj: TRpc;
- FTranslationFileName: string;
- FTranslationLanguage: string;
- FAlterColor: TColor;
- IsUnity: boolean;
- Ini: TIniFileUtf8;
- const
- // Torrents list
- idxName = 0;
- idxSize = 1;
- idxDone = 2;
- idxStatus = 3;
- idxSeeds = 4;
- idxPeers = 5;
- idxDownSpeed = 6;
- idxUpSpeed = 7;
- idxETA = 8;
- idxRatio = 9;
- idxDownloaded = 10;
- idxUploaded = 11;
- idxTracker = 12;
- idxTrackerStatus = 13;
- idxAddedOn = 14;
- idxCompletedOn = 15;
- idxLastActive = 16;
- idxPath = 17;
- idxPriority = 18;
- idxSizeToDowload = 19;
- idxTorrentId = 20;
- idxQueuePos = 21;
- idxSeedingTime = 22;
- idxTag = -1;
- idxSeedsTotal = -2;
- idxLeechersTotal = -3;
- idxStateImg = -4;
- idxDeleted = -5;
- idxDownSpeedHistory = -6;
- idxUpSpeedHistory = -7;
- TorrentsExtraColumns = 7;
- // Peers list
- idxPeerHost = 0;
- idxPeerPort = 1;
- idxPeerCountry = 2;
- idxPeerClient = 3;
- idxPeerFlags = 4;
- idxPeerDone = 5;
- idxPeerUpSpeed = 6;
- idxPeerDownSpeed = 7;
- idxPeerTag = -1;
- idxPeerIP = -2;
- idxPeerCountryImage = -3;
- PeersExtraColumns = 3;
- // Trackers list
- idxTrackersListName = 0;
- idxTrackersListStatus = 1;
- idxTrackersListUpdateIn = 2;
- idxTrackersListSeeds = 3;
- idxTrackerTag = -1;
- idxTrackerID = -2;
- TrackersExtraColumns = 2;
- // Filter idices
- fltAll = 0;
- fltDown = 1;
- fltDone = 2;
- fltActive = 3;
- fltInactive = 4;
- fltStopped = 5;
- fltError = 6;
- // Status images
- imgDown = 9;
- imgSeed = 10;
- imgDownError = 11;
- imgSeedError = 12;
- imgError = 13;
- imgDone = 14;
- imgStopped = 29;
- imgDownQueue = 16;
- imgSeedQueue = 17;
- imgAll = 19;
- imgActive = 20;
- StatusFiltersCount = 7;
- TorrentFieldsMap: array[idxName..idxSeedingTime] of string =
- ('', 'totalSize', '', 'status', 'peersSendingToUs,seeders',
- 'peersGettingFromUs,leechers', '', '', 'eta', 'uploadRatio',
- 'downloadedEver', 'uploadedEver', '', '', 'addedDate', 'doneDate', 'activityDate', '', 'bandwidthPriority',
- '', '', 'queuePosition', 'secondsSeeding');
- FinishedQueue = 1000000;
- TR_PRI_SKIP = -1000; // psedudo priority
- TR_PRI_LOW = -1;
- TR_PRI_NORMAL = 0;
- TR_PRI_HIGH = 1;
- implementation
- uses
- {$ifdef linux}
- process, dynlibs,
- {$endif linux}
- {$ifdef darwin}
- urllistenerosx,
- {$endif darwin}
- synacode, ConnOptions, clipbrd, DateUtils, TorrProps, DaemonOptions, About,
- ToolWin, download, ColSetup, types, AddLink, MoveTorrent, ssl_openssl_lib, AddTracker, lcltype,
- Options, ButtonPanel, BEncode, synautil;
- const
- TR_STATUS_CHECK_WAIT_1 = ( 1 shl 0 ); // Waiting in queue to check files
- TR_STATUS_CHECK_1 = ( 1 shl 1 ); // Checking files
- TR_STATUS_DOWNLOAD_1 = ( 1 shl 2 ); // Downloading
- TR_STATUS_SEED_1 = ( 1 shl 3 ); // Seeding
- TR_STATUS_STOPPED_1 = ( 1 shl 4 ); // Torrent is stopped
- TR_STATUS_STOPPED_2 = 0; // Torrent is stopped
- TR_STATUS_CHECK_WAIT_2 = 1; // Queued to check files
- TR_STATUS_CHECK_2 = 2; // Checking files
- TR_STATUS_DOWNLOAD_WAIT_2 = 3; // Queued to download
- TR_STATUS_DOWNLOAD_2 = 4; // Downloading
- TR_STATUS_SEED_WAIT_2 = 5; // Queued to seed
- TR_STATUS_SEED_2 = 6; // Seeding
- TR_STATUS_FINISHED = $100; // Torrent is finished (pseudo status)
- TR_SPEEDLIMIT_GLOBAL = 0; // only follow the overall speed limit
- TR_SPEEDLIMIT_SINGLE = 1; // only follow the per-torrent limit
- TR_SPEEDLIMIT_UNLIMITED = 2; // no limits at all
- SpeedHistorySize = 20;
- const
- SizeNames: array[1..5] of string = (sByte, sKByte, sMByte, sGByte, sTByte);
- var
- TR_STATUS_STOPPED, TR_STATUS_CHECK_WAIT, TR_STATUS_CHECK, TR_STATUS_DOWNLOAD_WAIT, TR_STATUS_DOWNLOAD, TR_STATUS_SEED_WAIT, TR_STATUS_SEED: integer;
- function GetHumanSize(sz: double; RoundTo: integer; const EmptyStr: string): string;
- var
- i: integer;
- begin
- if sz < 0 then begin
- Result:=EmptyStr;
- exit;
- end;
- i:=Low(SizeNames);
- if RoundTo > 0 then begin
- Inc(i);
- sz:=sz/1024;
- end;
- while i <= High(SizeNames) do begin
- if sz < 1024 then
- break;
- sz:=sz/1024;
- Inc(i);
- end;
- if (RoundTo = 0) and (i > 3) then
- RoundTo:=i - 2;
- Result:=Format('%.' + IntToStr(RoundTo) + 'f %s', [sz, SizeNames[i]]);
- end;
- function AddToChannel(Clr: TColor; Value: integer; Position: byte): TColor;
- var i: integer;
- begin
- i:=(Clr shr (Position*8)) and $FF;
- i:=i + Value;
- if i < 0 then i:=0;
- if i > $FF then i:=$FF;
- Result:=Clr and (not (Cardinal($FF) shl (Position*8))) or (Cardinal(i) shl (Position*8));
- end;
- function AddToColor(Color: TColor; R, G, B: integer): TColor;
- begin
- Result:=ColorToRGB(Color);
- Result:=AddToChannel(Result, R, 0);
- Result:=AddToChannel(Result, G, 1);
- Result:=AddToChannel(Result, B, 2);
- end;
- function GetLikeColor(Color: TColor; Delta: integer): TColor;
- var i, j: integer;
- begin
- Result:=ColorToRGB(Color);
- j:=Result and $FF; //red
- i:=(Result shr 8) and $FF; // green
- if i > j then
- j:=i;
- i:=((Result shr 16) and $FF) shr 1; // blue
- if i > j then
- j:=i;
- if j < $80 then
- i:=(($80 - j) div $20 + 1)*Delta
- else
- i:=Delta;
- if (i + j > 255) or (i + j < 0) then
- i:=-Delta;
- Result:=AddToColor(Result, i, i, i);
- end;
- function LocateFile(const FileName: string; const Paths: array of string): string;
- var
- i: integer;
- begin
- for i:=Low(Paths) to High(Paths) do begin
- Result:=IncludeTrailingPathDelimiter(Paths[i]) + FileName;
- if FileExistsUTF8(Result) then
- exit;
- end;
- Result:='';
- end;
- procedure OnTranslate(Sender: TResTranslator; const ResourceName: AnsiString; var Accept: boolean);
- const
- IgnoreUnits: array[0..12] of string =
- ('fpjson','jsonparser','jsonscanner','lclstrconsts','math',
- 'rtlconsts','sysconst','variants','zbase','zipper','zstream',
- 'xmlcfg', 'registry');
- IgnoreControls: array[0..3] of string =
- ('AboutForm.txAuthor', 'MainForm.miLn', 'ConnOptionsForm.cbUseSocks5', 'ConnOptionsForm.tabConnection');
- var
- i: integer;
- begin
- Accept := not AnsiMatchText(Copy2Symb(ResourceName, '.'), IgnoreUnits)
- or AnsiStartsText('lclstrconsts.rsMb', ResourceName) //<-- dialog buttons
- or AnsiStartsText('lclstrconsts.rsMt', ResourceName); //<-- dialog message
- if Accept then
- for i:=Low(IgnoreControls) to High(IgnoreControls) do
- if AnsiStartsText(IgnoreControls[i], ResourceName) then begin
- Accept:=False;
- exit;
- end;
- if Accept and (Copy(ResourceName, Length(ResourceName) - 8, MaxInt) = '.Category') then
- Accept:=False;
- end;
- var
- FHomeDir: string;
- FIPCFileName: string;
- FRunFileName: string;
- function IsProtocolSupported(const url: string): boolean;
- const
- Protocols: array [1..3] of string =
- ('http:', 'https:', 'magnet:');
- var
- i: integer;
- s: string;
- begin
- s:=AnsiLowerCase(url);
- for i:=Low(Protocols) to High(Protocols) do
- if Copy(s, 1, Length(Protocols[i])) = Protocols[i] then begin
- Result:=True;
- exit;
- end;
- Result:=False;
- end;
- procedure AddTorrentFile(const FileName: string);
- var
- h: System.THandle;
- t: TDateTime;
- s: string;
- begin
- if not IsProtocolSupported(FileName) and not FileExistsUTF8(FileName) then
- exit;
- t:=Now;
- repeat
- if FileExistsUTF8(FIPCFileName) then
- h:=FileOpenUTF8(FIPCFileName, fmOpenWrite or fmShareDenyRead or fmShareDenyWrite)
- else
- h:=FileCreateUTF8(FIPCFileName);
- if h <> System.THandle(-1) then begin
- s:=FileName + LineEnding;
- FileSeek(h, 0, soFromEnd);
- FileWrite(h, s[1], Length(s));
- FileClose(h);
- break;
- end;
- Sleep(20);
- until Now - t >= 3/SecsPerDay;
- end;
- procedure LoadTranslation;
- begin
- FTranslationFileName := Ini.ReadString('Interface', 'TranslationFile', '');
- if FTranslationFileName <> '-' then
- if (FTranslationFileName = '') or not IsTranslationFileValid(DefaultLangDir + FTranslationFileName) then
- FTranslationLanguage := LoadDefaultTranslationFile(@OnTranslate)
- else
- FTranslationLanguage := LoadTranslationFile(DefaultLangDir + FTranslationFileName, @OnTranslate);
- if FTranslationLanguage = '' then
- FTranslationLanguage := 'English'
- end;
- function CheckAppParams: boolean;
- var
- i: integer;
- s: string;
- h: System.THandle;
- pid: SizeUInt;
- {$ifdef linux}
- proc: TProcess;
- sr: TSearchRec;
- hLib: TLibHandle;
- {$endif linux}
- begin
- Application.Title:=AppName;
- {$ifdef linux}
- IsUnity:=CompareText(GetEnvironmentVariable('XDG_CURRENT_DESKTOP'), 'unity') = 0;
- if GetEnvironmentVariable('LIBOVERLAY_SCROLLBAR') <> '0' then begin
- i:=FindFirstUTF8('/usr/lib/liboverlay-scrollbar*', faAnyFile, sr);
- FindClose(sr);
- hLib:=LoadLibrary('liboverlay-scrollbar.so');
- if hLib <> 0 then
- FreeLibrary(hLib);
- if (i = 0) or (hLib <> 0) then begin
- // Turn off overlay scrollbars, since they are not supported yet.
- // Restart the app with the LIBOVERLAY_SCROLLBAR=0 env var.
- proc:=TProcess.Create(nil);
- try
- s:='';
- for i:=0 to ParamCount do
- s:=s + '"' + ParamStrUTF8(i) + '" ';
- proc.CommandLine:=s;
- for i:=0 to GetEnvironmentVariableCount - 1 do
- proc.Environment.Add(GetEnvironmentString(i));
- proc.Environment.Values['LIBOVERLAY_SCROLLBAR']:='0';
- proc.Execute;
- finally
- proc.Free;
- end;
- Result:=False;
- exit;
- end;
- end;
- {$endif linux}
- FHomeDir:=GetCmdSwitchValue('home');
- if FHomeDir = '' then begin
- if FileExistsUTF8(ChangeFileExt(ParamStrUTF8(0), '.ini')) then
- FHomeDir:=ExtractFilePath(ParamStrUTF8(0)) // Portable mode
- else
- FHomeDir:=IncludeTrailingPathDelimiter(GetAppConfigDirUTF8(False));
- end
- else
- FHomeDir:=IncludeTrailingPathDelimiter(FHomeDir);
- ForceDirectoriesUTF8(FHomeDir);
- FIPCFileName:=FHomeDir + 'ipc.txt';
- FRunFileName:=FHomeDir + 'run';
- Ini:=TIniFileUtf8.Create(FHomeDir+ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.ini'));
- Ini.CacheUpdates:=True;
- // Check for outdated IPC file
- if FileExistsUTF8(FIPCFileName) then begin
- h:=FileOpenUTF8(FIPCFileName, fmOpenRead or fmShareDenyNone);
- if h <> INVALID_HANDLE_VALUE then begin
- i:=FileGetDate(h);
- FileClose(h);
- if (i > 0) and (Abs(Now - FileDateToDateTime(i)) > 1/MinsPerDay) then
- DeleteFileUTF8(FIPCFileName);
- end;
- end;
- for i:=1 to ParamCount do begin
- s:=ParamStrUTF8(i);
- if IsProtocolSupported(s) or FileExistsUTF8(s) then
- AddTorrentFile(s);
- end;
- if FileExistsUTF8(FRunFileName) then begin
- // Another process is running
- h:=FileOpenUTF8(FRunFileName, fmOpenRead or fmShareDenyNone);
- if FileRead(h, pid, SizeOf(pid)) = SizeOf(pid) then begin
- {$ifdef mswindows}
- AllowSetForegroundWindow(pid);
- {$endif mswindows}
- end;
- FileClose(h);
- if not FileExistsUTF8(FIPCFileName) then
- FileClose(FileCreateUTF8(FIPCFileName));
- for i:=1 to 50 do
- if not FileExistsUTF8(FIPCFileName) then begin
- // The running process works normally. Exit application.
- Result:=False;
- exit;
- end
- else
- Sleep(200);
- // The running process is not responding
- DeleteFileUTF8(FRunFileName);
- // Delete IPC file if it is empty
- h:=FileOpenUTF8(FIPCFileName, fmOpenRead or fmShareDenyNone);
- i:=FileSeek(h, 0, soFromEnd);
- FileClose(h);
- if i = 0 then
- DeleteFileUTF8(FIPCFileName);
- end;
- // Create a new run file
- h:=FileCreateUTF8(FRunFileName);
- pid:=GetProcessID;
- FileWrite(h, pid, SizeOf(pid));
- FileClose(h);
- LoadTranslation;
- SizeNames[1]:=sByte;
- SizeNames[2]:=sKByte;
- SizeNames[3]:=sMByte;
- SizeNames[4]:=sGByte;
- SizeNames[5]:=sTByte;
- IntfScale:=Ini.ReadInteger('Interface', 'Scaling', 100);
- Result:=True;
- end;
- function PriorityToStr(p: integer; var ImageIndex: integer): string;
- begin
- case p of
- TR_PRI_SKIP: begin Result:=sSkip; ImageIndex:=23; end;
- TR_PRI_LOW: begin Result:=sLow; ImageIndex:=24; end;
- TR_PRI_NORMAL: begin Result:=sNormal; ImageIndex:=25; end;
- TR_PRI_HIGH: begin Result:=sHigh; ImageIndex:=26; end;
- else Result:='???';
- end;
- end;
- procedure DrawProgressCell(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; const ACellRect: TRect);
- var
- R, RR: TRect;
- i, j, h: integer;
- s: string;
- cl: TColor;
- Progress: double;
- sz: TSize;
- ts: TTextStyle;
- begin
- Progress:=double(Sender.Items[ADataCol, ARow]);
- with Sender.Canvas do begin
- R:=ACellRect;
- FrameRect(R);
- s:=Format('%.1f%%', [Progress]);
- sz:=TextExtent(s);
- InflateRect(R, -1, -1);
- Pen.Color:=clBtnFace;
- Rectangle(R);
- InflateRect(R, -1, -1);
- i:=R.Left + Round(Progress*(R.Right - R.Left)/100.0);
- j:=(R.Top + R.Bottom) div 2;
- h:=(R.Top + R.Bottom - sz.cy) div 2;
- cl:=GetLikeColor(clHighlight, 70);
- GradientFill(Rect(R.Left, R.Top, i, j), cl, clHighlight, gdVertical);
- GradientFill(Rect(R.Left, j, i, R.Bottom), clHighlight, cl, gdVertical);
- ts:=TextStyle;
- ts.Layout:=tlTop;
- ts.Alignment:=taLeftJustify;
- ts.Wordbreak:=False;
- TextStyle:=ts;
- j:=(R.Left + R.Right - sz.cx) div 2;
- if i > R.Left then begin
- RR:=Rect(R.Left, R.Top, i, R.Bottom);
- Font.Color:=clHighlightText;
- TextRect(RR, j, h, s);
- end;
- if i < R.Right then begin
- RR:=Rect(i, R.Top, R.Right, R.Bottom);
- Brush.Color:=Sender.Color;
- FillRect(RR);
- Font.Color:=clWindowText;
- TextRect(RR, j, h, s);
- end;
- end;
- end;
- { TProgressImage }
- procedure TProgressImage.SetImages(const AValue: TImageList);
- begin
- if FImages=AValue then exit;
- FImages:=AValue;
- Width:=FImages.Width;
- Height:=FImages.Height;
- end;
- procedure TProgressImage.SetStartIndex(const AValue: integer);
- begin
- if FStartIndex=AValue then exit;
- FStartIndex:=AValue;
- UpdateIndex;
- end;
- procedure TProgressImage.UpdateIndex;
- begin
- if (FImageIndex < FStartIndex) or (FImageIndex > FEndIndex) then
- FImageIndex:=FStartIndex;
- Invalidate;
- end;
- procedure TProgressImage.DoTimer(Sender: TObject);
- begin
- ImageIndex:=ImageIndex + 1;
- end;
- procedure TProgressImage.SetImageIndex(const AValue: integer);
- begin
- if FImageIndex=AValue then exit;
- FImageIndex:=AValue;
- UpdateIndex;
- end;
- procedure TProgressImage.SetEndIndex(const AValue: integer);
- begin
- if FEndIndex=AValue then exit;
- FEndIndex:=AValue;
- UpdateIndex;
- end;
- function TProgressImage.GetFrameDelay: integer;
- begin
- Result:=FTimer.Interval;
- end;
- procedure TProgressImage.SetBorderColor(const AValue: TColor);
- begin
- if FBorderColor=AValue then exit;
- FBorderColor:=AValue;
- end;
- procedure TProgressImage.SetFrameDelay(const AValue: integer);
- begin
- FTimer.Interval:=AValue;
- end;
- procedure TProgressImage.Paint;
- begin
- if FBmp = nil then begin
- FBmp:=TBitmap.Create;
- FBmp.Width:=Width;
- FBmp.Height:=Height;
- end;
- with FBmp.Canvas do begin
- Brush.Color:=clBtnFace;
- if FBorderColor <> clNone then begin
- Pen.Color:=FBorderColor;
- Rectangle(0, 0, FBmp.Width, FBmp.Height);
- end
- else
- FillRect(0, 0, FBmp.Width, FBmp.Height);
- if FImages <> nil then
- FImages.Draw(FBmp.Canvas, (Self.Width - FImages.Width) div 2, (Self.Height - FImages.Height) div 2, ImageIndex);
- end;
- Canvas.Draw(0, 0, FBmp);
- end;
- procedure TProgressImage.VisibleChanged;
- begin
- inherited VisibleChanged;
- if Visible then begin
- ImageIndex:=StartIndex;
- FTimer.Enabled:=True;
- end
- else
- FTimer.Enabled:=False;
- end;
- constructor TProgressImage.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FTimer:=TTimer.Create(Self);
- FTimer.Enabled:=False;
- FTimer.Interval:=100;
- FTimer.OnTimer:=@DoTimer;
- FBorderColor:=clNone;
- Visible:=False;
- end;
- destructor TProgressImage.Destroy;
- begin
- FBmp.Free;
- inherited Destroy;
- end;
- { TMainForm }
- procedure TMainForm.FormCreate(Sender: TObject);
- var
- ws: TWindowState;
- i, j: integer;
- R: TRect;
- {$ifdef darwin}
- s: string;
- pic: TPicture;
- {$endif darwin}
- begin
- {$ifdef darwin}
- // Load better icon if possible
- s:=ExtractFilePath(ParamStrUTF8(0)) + '..' + DirectorySeparator + 'Resources'
- + DirectorySeparator + ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '.icns');
- if FileExistsUTF8(s) then begin
- pic:=TPicture.Create;
- try
- pic.LoadFromFile(s);
- try
- Application.Icon.Assign(pic.Graphic);
- except
- end;
- finally
- pic.Free;
- end;
- end;
- RegisterURLHandler(@AddTorrentFile);
- {$endif darwin}
- Application.Title:=AppName;
- Caption:=Application.Title;
- txTransferHeader.Font.Size:=Font.Size + 2;
- txTorrentHeader.Font.Size:=txTransferHeader.Font.Size;
- TrayIcon.Icon.Assign(Application.Icon);
- RpcObj:=TRpc.Create;
- FTorrents:=TVarList.Create(gTorrents.Columns.Count, 0);
- FTorrents.ExtraColumns:=TorrentsExtraColumns;
- gTorrents.Items.ExtraColumns:=TorrentsExtraColumns;
- lvFiles.Items.ExtraColumns:=FilesExtraColumns;
- FFiles:=lvFiles.Items;
- FFilesTree:=TFilesTree.Create(lvFiles);
- FFilesTree.Checkboxes:=True;
- FFilesTree.OnStateChange:=@FilesTreeStateChanged;
- lvPeers.Items.ExtraColumns:=PeersExtraColumns;
- lvTrackers.Items.ExtraColumns:=TrackersExtraColumns;
- FTrackers:=TStringList.Create;
- FTrackers.Sorted:=True;
- FReconnectTimeOut:=-1;
- FAlterColor:=GetLikeColor(gTorrents.Color, -$10);
- lvFilter.Items.ExtraColumns:=1;
- gTorrents.AlternateColor:=FAlterColor;
- lvPeers.AlternateColor:=FAlterColor;
- lvTrackers.AlternateColor:=FAlterColor;
- gStats.AlternateColor:=FAlterColor;
- FPendingTorrents:=TStringList.Create;
- FFilesCapt:=tabFiles.Caption;
- FPasswords:=TStringList.Create;
- MainToolBar.ButtonWidth:=DM.ImageList16.Width + ScaleInt(8);
- MainToolBar.ButtonHeight:=MainToolBar.ButtonWidth;
- FSlowResponse:=TProgressImage.Create(MainToolBar);
- with FSlowResponse do begin
- Align:=alRight;
- Images:=DM.ImageList16;
- StartIndex:=30;
- EndIndex:=37;
- Width:=MainToolBar.ButtonWidth;
- Left:=MainToolBar.ClientWidth;
- Parent:=MainToolBar;
- end;
- FDetailsWait:=TProgressImage.Create(panDetailsWait);
- with FDetailsWait do begin
- Images:=DM.ImageList16;
- StartIndex:=FSlowResponse.StartIndex;
- EndIndex:=FSlowResponse.EndIndex;
- Width:=Images.Width*2;
- Height:=Width;
- BorderColor:=clBtnShadow;
- panDetailsWait.Width:=Width;
- panDetailsWait.Height:=Height;
- Parent:=panDetailsWait;
- end;
- DoDisconnect;
- PageInfo.ActivePageIndex:=0;
- PageInfoChange(nil);
- {$ifdef LCLgtk2}
- with MainToolBar do begin
- EdgeBorders:=[ebLeft, ebTop, ebRight, ebBottom];
- EdgeInner:=esNone;
- EdgeOuter:=esRaised;
- Flat:=True;
- end;
- i:=acAltSpeed.ImageIndex;
- acAltSpeed.ImageIndex:=-1;
- tbtAltSpeed.ImageIndex:=i;
- {$endif}
- txTransferHeader.Color:=GetLikeColor(clBtnFace, -15);
- txTorrentHeader.Color:=txTransferHeader.Color;
- txTransferHeader.Caption:=' ' + txTransferHeader.Caption;
- txTorrentHeader.Caption:=' ' + txTorrentHeader.Caption;
- txTransferHeader.Height:=txTransferHeader.Canvas.TextHeight(txTransferHeader.Caption) + 2;
- txTorrentHeader.Height:=txTorrentHeader.Canvas.TextHeight(txTorrentHeader.Caption) + 2;
- with gStats do begin
- BeginUpdate;
- try
- Items[0, 0]:=UTF8Decode(SDownloaded);
- Items[0, 1]:=UTF8Decode(SUploaded);
- Items[0, 2]:=UTF8Decode(SFilesAdded);
- Items[0, 3]:=UTF8Decode(SActiveTime);
- finally
- EndUpdate;
- end;
- end;
- if Ini.ReadInteger('MainForm', 'State', -1) = -1 then begin
- R:=Screen.MonitorFromRect(BoundsRect).WorkareaRect;
- if R.Right - R.Left < 300 then
- R:=Rect(0, 0, Screen.Width, Screen.Height);
- j:=R.Right - R.Left;
- i:=j*3 div 4;
- j:=j*95 div 100;
- if i > Width then
- Width:=i;
- if Width > j then
- Width:=j;
- Left:=(R.Right - R.Left - Width) div 2;
- j:=R.Bottom - R.Top;
- i:=j*3 div 4;
- j:=j*8 div 10;
- if i > Height then
- Height:=i;
- if Height > j then
- Height:=j;
- Top:=(R.Bottom - R.Top - Height) div 2;
- end
- else begin
- ws:=TWindowState(Ini.ReadInteger('MainForm', 'State', integer(WindowState)));
- Left:=Ini.ReadInteger('MainForm', 'Left', Left);
- Top:=Ini.ReadInteger('MainForm', 'Top', Top);
- Width:=Ini.ReadInteger('MainForm', 'Width', Width);
- Height:=Ini.ReadInteger('MainForm', 'Height', Height);
- if ws = wsMaximized then
- WindowState:=wsMaximized;
- end;
- if Ini.ReadBool('MainForm', 'FilterPane', acFilterPane.Checked) <> acFilterPane.Checked then
- acFilterPane.Execute;
- if Ini.ReadBool('MainForm', 'InfoPane', acInfoPane.Checked) <> acInfoPane.Checked then
- acInfoPane.Execute;
- if Ini.ReadBool('MainForm', 'StatusBar', acStatusBar.Checked) <> acStatusBar.Checked then
- acStatusBar.Execute;
- LoadColumns(gTorrents, 'TorrentsList');
- TorrentColumnsChanged;
- LoadColumns(lvFiles, 'FilesList');
- LoadColumns(lvPeers, 'PeerList');
- LoadColumns(lvTrackers, 'TrackersList');
- acResolveHost.Checked:=Ini.ReadBool('PeersList', 'ResolveHost', True);
- acResolveCountry.Checked:=Ini.ReadBool('PeersList', 'ResolveCountry', True) and (GetGeoIpDatabase <> '');
- acShowCountryFlag.Checked:=Ini.ReadBool('PeersList', 'ShowCountryFlag', True) and (GetFlagsArchive <> '');
- acShowCountryFlag.Enabled:=acResolveCountry.Checked;
- FCurConn:=Ini.ReadString('Hosts', 'CurHost', '');
- if FCurConn = '' then
- FCurConn:=Ini.ReadString('Connection', 'Host', '');
- FPathMap:=TStringList.Create;
- if Application.HasOption('hidden') then begin
- ApplicationProperties.ShowMainForm:=False;
- TickTimer.Enabled:=True;
- UpdateTray;
- end;
- UpdateConnections;
- i:=Ini.ReadInteger('Interface', 'LastRpcVersion', -1);
- if i >= 0 then
- UpdateUIRpcVersion(i);
- acFolderGrouping.Checked:=Ini.ReadBool('Interface', 'FolderGrouping', True);
- acTrackerGrouping.Checked:=Ini.ReadBool('Interface', 'TrackerGrouping', True);
- FLinksFromClipboard:=Ini.ReadBool('Interface', 'LinksFromClipboard', True);
- // Added by Antekgla
- FFileManagerDefault:=Ini.ReadString('Interface','FileManagerDefault','explorer.exe');
- FFileManagerDefaultParam:=Ini.ReadString('Interface', 'FileManagerDefaultParam', '/select,"%s"');
- // End Added by Antekgla
- Application.OnActivate:=@FormActivate;
- Application.OnException:=@ApplicationPropertiesException;
- end;
- procedure TMainForm.FormDestroy(Sender: TObject);
- procedure _CreateAllForms;
- begin
- // Create all application forms to properly update language files
- TAboutForm.Create(Self).Free;
- TAddLinkForm.Create(Self).Free;
- TAddTorrentForm.Create(Self).Free;
- TAddTrackerForm.Create(Self).Free;
- TColSetupForm.Create(Self).Free;
- TConnOptionsForm.Create(Self).Free;
- TDaemonOptionsForm.Create(Self).Free;
- TDownloadForm.Create(Self).Free;
- TMoveTorrentForm.Create(Self).Free;
- TOptionsForm.Create(Self).Free;
- TTorrPropsForm.Create(Self).Free;
- end;
- begin
- if Application.HasOption('updatelang') then begin
- _CreateAllForms;
- SupplementTranslationFiles;
- end;
- if Application.HasOption('makelang') then begin
- _CreateAllForms;
- MakeTranslationFile;
- end;
- DeleteFileUTF8(FRunFileName);
- FPasswords.Free;
- FResolver.Free;
- FTrackers.Free;
- FUnZip.Free;
- RpcObj.Free;
- FTorrentProgress.Free;
- FPathMap.Free;
- FTorrents.Free;
- FPendingTorrents.Free;
- try
- Ini.UpdateFile;
- except
- end;
- end;
- procedure TMainForm.FormResize(Sender: TObject);
- begin
- if panReconnect.Visible then
- CenterReconnectWindow;
- end;
- procedure TMainForm.FormShow(Sender: TObject);
- begin
- if not FMainFormShown then begin
- FMainFormShown:=True;
- VSplitter.SetSplitterPosition(Ini.ReadInteger('MainForm', 'VSplitter', VSplitter.GetSplitterPosition));
- HSplitter.SetSplitterPosition(Ini.ReadInteger('MainForm', 'HSplitter', HSplitter.GetSplitterPosition));
- MakeFullyVisible;
- end;
- if not FStarted then
- TickTimer.Enabled:=True;
- UpdateTray;
- end;
- procedure TMainForm.lvFilterResize(Sender: TObject);
- begin
- lvFilter.Columns[0].Width:=lvFilter.ClientWidth;
- end;
- procedure TMainForm.miAboutClick(Sender: TObject);
- begin
- with TAboutForm.Create(Self) do
- try
- ShowModal;
- finally
- Free;
- end;
- end;
- procedure TMainForm.miCopyLabelClick(Sender: TObject);
- begin
- with TLabel(pmLabels.PopupComponent) do
- if (Length(Name) > 5) and (Copy(Name, Length(Name) - 4, 5) = 'Label') then
- Clipboard.AsText:=TLabel(Parent.FindChildControl(Copy(Name, 1, Length(Name) - 5))).Caption
- else
- Clipboard.AsText:=Caption;
- end;
- procedure TMainForm.acConnectExecute(Sender: TObject);
- begin
- if RpcObj.Connected then begin
- tbConnect.CheckMenuDropdown;
- exit;
- end;
- if FCurConn = '' then
- ShowConnOptions(True)
- else
- DoConnect;
- end;
- procedure TMainForm.acConnOptionsExecute(Sender: TObject);
- begin
- ShowConnOptions(False);
- end;
- procedure TMainForm.acCopyPathExecute(Sender: TObject);
- begin
- if lvFiles.Items.Count > 0 then
- Clipboard.AsText:='"' + FFilesTree.GetFullPath(lvFiles.Row) + '"';
- end;
- procedure TMainForm.acDelTrackerExecute(Sender: TObject);
- var
- req, args: TJSONObject;
- id, torid: integer;
- begin
- id:=lvTrackers.Items[idxTrackerID, lvTrackers.Row];
- torid:=RpcObj.CurTorrentId;
- if MessageDlg('', Format(SRemoveTracker, [UTF8Encode(widestring(lvTrackers.Items[idxTrackersListName, lvTrackers.Row]))]), mtConfirmation, mbYesNo, 0, mbNo) <> mrYes then exit;
- AppBusy;
- Self.Update;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-set');
- args:=TJSONObject.Create;
- args.Add('ids', TJSONArray.Create([torid]));
- args.Add('trackerRemove', TJSONArray.Create([id]));
- req.Add('arguments', args);
- args:=nil;
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- finally
- req.Free;
- end;
- DoRefresh;
- AppNormal;
- end;
- procedure TMainForm.acEditTrackerExecute(Sender: TObject);
- begin
- AddTracker(True);
- end;
- procedure TMainForm.acFilterPaneExecute(Sender: TObject);
- begin
- acFilterPane.Checked:=not acFilterPane.Checked;
- panFilter.Visible:=acFilterPane.Checked;
- HSplitter.Visible:=acFilterPane.Checked;
- HSplitter.Left:=panFilter.Width;
- if lvFilter.Items.Count > 0 then
- lvFilter.Row:=0;
- end;
- procedure TMainForm.acFolderGroupingExecute(Sender: TObject);
- begin
- acFolderGrouping.Checked:=not acFolderGrouping.Checked;
- Ini.WriteBool('Interface', 'FolderGrouping', acFolderGrouping.Checked);
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtTorrents];
- end;
- procedure TMainForm.acForceStartTorrentExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'torrent-start-now');
- end;
- procedure TMainForm.acHideAppExecute(Sender: TObject);
- begin
- HideApp;
- end;
- procedure TMainForm.acInfoPaneExecute(Sender: TObject);
- begin
- acInfoPane.Checked:=not acInfoPane.Checked;
- PageInfo.Visible:=acInfoPane.Checked;
- VSplitter.Top:=PageInfo.Top - VSplitter.Height;
- VSplitter.Visible:=acInfoPane.Checked;
- if VSplitter.Visible then
- PageInfoChange(nil)
- else
- RpcObj.AdvInfo:=aiNone;
- end;
- procedure TMainForm.acMoveTorrentExecute(Sender: TObject);
- var
- ids: variant;
- i: integer;
- s: string;
- req: TJSONObject;
- aids: TJSONArray;
- args: TJSONObject;
- ok: boolean;
- t: TDateTime;
- begin
- if gTorrents.Items.Count = 0 then
- exit;
- AppBusy;
- with TMoveTorrentForm.Create(Self) do
- try
- gTorrents.Tag:=1;
- gTorrents.EnsureSelectionVisible;
- FillDownloadDirs(edTorrentDir, 'LastMoveDir');
- if gTorrents.SelCount = 0 then
- gTorrents.RowSelected[gTorrents.Row]:=True;
- ids:=GetSelectedTorrents;
- i:=gTorrents.Items.IndexOf(idxTorrentId, ids[0]);
- if VarIsEmpty(gTorrents.Items[idxPath, i]) then
- exit;
- edTorrentDir.Text:=UTF8Encode(widestring(gTorrents.Items[idxPath, i]));
- if gTorrents.SelCount > 1 then
- s:=Format(sSeveralTorrents, [gTorrents.SelCount])
- else
- s:=UTF8Encode(widestring(gTorrents.Items[idxName, i]));
- Caption:=Caption + ' - ' + s;
- AppNormal;
- if ShowModal = mrOk then begin
- Application.ProcessMessages;
- AppBusy;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-set-location');
- args:=TJSONObject.Create;
- aids:=TJSONArray.Create;
- for i:=VarArrayLowBound(ids, 1) to VarArrayHighBound(ids, 1) do
- aids.Add(integer(ids[i]));
- args.Add('ids', aids);
- args.Add('location', TJSONString.Create(UTF8Decode(edTorrentDir.Text)));
- args.Add('move', TJSONIntegerNumber.Create(integer(cbMoveData.Checked) and 1));
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req, False);
- args.Free;
- finally
- req.Free;
- end;
- gTorrents.Tag:=0;
- AppNormal;
- if args = nil then
- CheckStatus(False)
- else begin
- SaveDownloadDirs(edTorrentDir, 'LastMoveDir');
- ok:=False;
- t:=Now;
- with gTorrents do
- while not ok and not Application.Terminated and (Now - t < 20/SecsPerDay) do begin
- RpcObj.RequestFullInfo:=True;
- DoRefresh(True);
- Sleep(200);
- Application.ProcessMessages;
- ok:=True;
- for i:=0 to Items.Count - 1 do
- if RowSelected[i] then begin
- if VarIsEmpty(Items[idxPath, i]) or (AnsiCompareText(UTF8Encode(widestring(Items[idxPath, i])), edTorrentDir.Text) <> 0) then begin
- ok:=False;
- break;
- end;
- end;
- end;
- end;
- end;
- finally
- gTorrents.Tag:=0;
- Free;
- end;
- end;
- procedure TMainForm.acNewConnectionExecute(Sender: TObject);
- begin
- ShowConnOptions(True);
- end;
- procedure TMainForm.acOpenContainingFolderExecute(Sender: TObject);
- begin
- if gTorrents.Items.Count = 0 then
- exit;
- Application.ProcessMessages;
- if lvFiles.Focused and (lvFiles.Items.Count > 0) then begin
- AppBusy;
- ExecRemoteFile(FFilesTree.GetFullPath(lvFiles.Row), not FFilesTree.IsFolder(lvFiles.Row));
- AppNormal;
- end
- else
- OpenCurrentTorrent(True);
- end;
- procedure TMainForm.acOpenFileExecute(Sender: TObject);
- begin
- if gTorrents.Items.Count = 0 then
- exit;
- Application.ProcessMessages;
- if lvFiles.Focused then begin
- if lvFiles.Items.Count = 0 then exit;
- ExecRemoteFile(FFilesTree.GetFullPath(lvFiles.Row), False);
- end
- else
- OpenCurrentTorrent(False);
- end;
- procedure TMainForm.acOptionsExecute(Sender: TObject);
- var
- OldCheckVer: boolean;
- begin
- AppBusy;
- with TOptionsForm.Create(Self) do
- try
- ConnForm.ActiveConnection:=FCurConn;
- edRefreshInterval.Value:=Ini.ReadInteger('Interface', 'RefreshInterval', 5);
- edRefreshIntervalMin.Value:=Ini.ReadInteger('Interface', 'RefreshIntervalMin', 20);
- cbCalcAvg.Checked:=FCalcAvg;
- {$ifndef darwin}
- cbTrayMinimize.Checked:=Ini.ReadBool('Interface', 'TrayMinimize', True);
- {$else}
- cbTrayMinimize.Enabled:=False;
- {$endif}
- cbTrayClose.Checked:=Ini.ReadBool('Interface', 'TrayClose', False);
- cbTrayIconAlways.Checked:=Ini.ReadBool('Interface', 'TrayIconAlways', True);
- cbTrayNotify.Checked:=Ini.ReadBool('Interface', 'TrayNotify', True);
- cbShowAddTorrentWindow.Checked:=Ini.ReadBool('Interface', 'ShowAddTorrentWindow', True);
- cbDeleteTorrentFile.Checked:=Ini.ReadBool('Interface', 'DeleteTorrentFile', False);
- cbLinksFromClipboard.Checked:=Ini.ReadBool('Interface', 'LinksFromClipboard', True);
- edIntfScale.Value:=Ini.ReadInteger('Interface', 'Scaling', 100);
- cbCheckNewVersion.Checked:=Ini.ReadBool('Interface', 'CheckNewVersion', False);
- edCheckVersionDays.Value:=Ini.ReadInteger('Interface', 'CheckNewVersionDays', 5);
- cbCheckNewVersionClick(nil);
- OldCheckVer:=cbCheckNewVersion.Checked;
- {$ifdef linux}
- if IsUnity then begin
- cbTrayIconAlways.Enabled:=False;
- cbTrayIconAlways.Checked:=False;
- cbTrayMinimize.Enabled:=False;
- cbTrayMinimize.Checked:=False;
- cbTrayNotify.Enabled:=False;
- cbTrayNotify.Checked:=False;
- end;
- {$endif linux}
- AppNormal;
- if ShowModal = mrOk then begin
- AppBusy;
- Ini.WriteInteger('Interface', 'RefreshInterval', edRefreshInterval.Value);
- Ini.WriteInteger('Interface', 'RefreshIntervalMin', edRefreshIntervalMin.Value);
- Ini.WriteBool('Interface', 'CalcAvg', cbCalcAvg.Checked);
- {$ifndef darwin}
- Ini.WriteBool('Interface', 'TrayMinimize', cbTrayMinimize.Checked);
- {$endif}
- Ini.WriteBool('Interface', 'TrayClose', cbTrayClose.Checked);
- Ini.WriteBool('Interface', 'TrayIconAlways', cbTrayIconAlways.Checked);
- Ini.WriteBool('Interface', 'TrayNotify', cbTrayNotify.Checked);
- Ini.WriteBool('Interface', 'ShowAddTorrentWindow', cbShowAddTorrentWindow.Checked);
- Ini.WriteBool('Interface', 'DeleteTorrentFile', cbDeleteTorrentFile.Checked);
- Ini.WriteBool('Interface', 'LinksFromClipboard', cbLinksFromClipboard.Checked);
- FLinksFromClipboard:=cbLinksFromClipboard.Checked;
- Ini.WriteInteger('Interface', 'Scaling', edIntfScale.Value);
- Ini.WriteBool('Interface', 'CheckNewVersion', cbCheckNewVersion.Checked);
- Ini.WriteInteger('Interface', 'CheckNewVersionDays', edCheckVersionDays.Value);
- if cbCheckNewVersion.Checked and not OldCheckVer then
- CheckNewVersion;
- Ini.UpdateFile;
- UpdateTray;
- AppNormal;
- with ConnForm do
- ConnectionSettingsChanged(ActiveConnection, ActiveSettingChanged);
- end;
- finally
- Free;
- end;
- end;
- procedure TMainForm.acAddTorrentExecute(Sender: TObject);
- begin
- if not OpenTorrentDlg.Execute then exit;
- FPendingTorrents.AddStrings(OpenTorrentDlg.Files);
- TickTimerTimer(nil);
- end;
- procedure TMainForm.acAddTrackerExecute(Sender: TObject);
- begin
- AddTracker(False);
- end;
- procedure TMainForm.acAdvEditTrackersExecute(Sender: TObject);
- begin
- gTorrents.RemoveSelection;
- TorrentProps(1);
- end;
- procedure TMainForm.acAltSpeedExecute(Sender: TObject);
- var
- req, args: TJSONObject;
- begin
- AppBusy;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'session-set');
- args:=TJSONObject.Create;
- args.Add('alt-speed-enabled', integer(not acAltSpeed.Checked) and 1);
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- finally
- req.Free;
- end;
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtSession];
- AppNormal;
- end;
- procedure TMainForm.acCheckNewVersionExecute(Sender: TObject);
- begin
- Application.ProcessMessages;
- AppBusy;
- CheckNewVersion(False);
- AppNormal;
- end;
- procedure TMainForm.acAddLinkExecute(Sender: TObject);
- begin
- AppBusy;
- with TAddLinkForm.Create(Self) do
- try
- AppNormal;
- if ShowModal = mrOk then
- DoAddTorrent(edLink.Text);
- finally
- Free;
- end;
- end;
- function TMainForm.DoAddTorrent(const FileName: Utf8String): boolean;
- var
- torrent: string;
- WaitForm: TBaseForm;
- IsAppHidden: boolean;
- Procedure _AddTrackers(TorrentId: integer);
- var
- req, args: TJSONObject;
- fs: TFileStreamUTF8;
- TorData, AnnData, LData, LLData: TBEncoded;
- t: TJSONArray;
- tt: TJSONObject;
- trackers: TJSONArray;
- i, j: Integer;
- s, tfn, TorrentHash: string;
- TrackersList: TStringList;
- begin
- RpcObj.Status:='';
- s:='';
- if TorrentId <> 0 then begin
- i:=SelectTorrent(TorrentId, 2000);
- if i >= 0 then
- s:=Format(': %s', [UTF8Encode(widestring(gTorrents.Items[idxName, i]))]);
- end;
- ForceAppNormal;
- s:=SDuplicateTorrent + s + '.';
- if RpcObj.RPCVersion < 10 then begin
- MessageDlg(s, mtError, [mbOK], 0);
- exit;
- end;
- if MessageDlg(s + LineEnding + LineEnding + SUpdateTrackers, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
- exit;
- Application.ProcessMessages;
- TrackersList:=TStringList.Create;
- try
- TorrentHash:='';
- if AnsiCompareText('magnet:?', Copy(FileName, 1, 8)) = 0 then begin
- // Get trackers from the magnet link
- TrackersList.Delimiter:='&';
- TrackersList.DelimitedText:=Copy(FileName, 9, MaxInt);
- i:=0;
- while i < TrackersList.Count do begin
- s:=TrackersList.Names[i];
- if (TorrentId = 0) and (CompareText(s, 'xt') = 0) then begin
- s:=LowerCase(TrackersList.ValueFromIndex[i]);
- if (TorrentHash = '') and (Pos('urn:btih:', s) = 1) then begin
- s:=Copy(s, 10, MaxInt);
- if Length(s) = 32 then
- // base32 encoded hash
- TorrentHash:=StrToHex(Base32Decode(UpperCase(s)))
- else
- TorrentHash:=s;
- end;
- end
- else
- if CompareText(s, 'tr') = 0 then begin
- TrackersList[i]:=DecodeURL(TrackersList.ValueFromIndex[i]);
- Inc(i);
- continue;
- end;
- TrackersList.Delete(i);
- end;
- end
- else
- try
- if IsProtocolSupported(FileName) then begin
- // Downloading torrent file
- tfn:=SysToUTF8(GetTempDir(True)) + 'remote-torrent.torrent';
- if not DownloadFile(FileName, ExtractFilePath(tfn), ExtractFileName(tfn), SDownloadingTorrent) then
- exit;
- end
- else
- tfn:=FileName;
- // Read trackers from the torrent file...
- AppBusy;
- TorData:=nil;
- fs:=TFileStreamUTF8.Create(tfn, fmOpenRead or fmShareDenyNone);
- try
- TorData:=TBEncoded.Create(fs);
- if TorrentId = 0 then begin
- // Calculate torrent hash
- LData:=(TorData.ListData.FindElement('info') as TBEncoded);
- s:='';
- LData.Encode(LData, s);
- TorrentHash:=StrToHex(SHA1(s));
- end;
- AnnData:=(TorData.ListData.FindElement('announce-list', False) as TBEncoded);
- if AnnData <> nil then
- for i:=0 to AnnData.ListData.Count - 1 do begin
- LData:=AnnData.ListData.Items[i].Data as TBEncoded;
- for j:=0 to LData.ListData.Count - 1 do begin
- LLData:=LData.ListData.Items[j].Data as TBEncoded;
- TrackersList.Add(LLData.StringData);
- end;
- end
- else begin
- AnnData:=(TorData.ListData.FindElement('announce', False) as TBEncoded);
- if AnnData <> nil then
- TrackersList.Add(AnnData.StringData);
- end;
- finally
- TorData.Free;
- fs.Free;
- end;
- finally
- // Delete temp file
- if (tfn <> '') and (tfn <> FileName) then
- DeleteFileUTF8(tfn);
- end;
- // Request trackers from the existing torrent
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-get');
- args:=TJSONObject.Create;
- if TorrentId = 0 then
- args.Add('ids', TJSONArray.Create([TorrentHash]))
- else
- args.Add('ids', TJSONArray.Create([TorrentId]));
- args.Add('fields', TJSONArray.Create(['id', 'trackers']));
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- try
- t:=args.Arrays['torrents'];
- if t.Count = 0 then
- raise Exception.Create('Torrent not found.');
- tt:=t.Objects[0] as TJSONObject;
- i:=tt.Integers['id'];
- if TorrentId = 0 then
- SelectTorrent(i, 2000);
- TorrentId:=i;
- trackers:=tt.Arrays['trackers'];
- // Deleting existing trackers from the list
- for i:=0 to trackers.Count - 1 do begin
- s:=UTF8Encode((Trackers.Items[i] as TJSONObject).Strings['announce']);
- j:=TrackersList.IndexOf(s);
- if j >= 0 then
- TrackersList.Delete(j);
- end;
- finally
- args.Free;
- end;
- finally
- req.Free;
- end;
- if TrackersList.Count > 0 then begin
- trackers:=TJSONArray.Create;
- for i:=0 to TrackersList.Count - 1 do
- trackers.Add(TrackersList[i]);
- args:=TJSONObject.Create;
- args.Add('ids', TJSONArray.Create([TorrentId]));
- args.Add('trackerAdd', trackers);
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-set');
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- finally
- req.Free;
- end;
- DoRefresh;
- end;
- finally
- TrackersList.Free;
- AppNormal;
- end;
- end;
- function _AddTorrent(args: TJSONObject): integer;
- var
- req: TJSONObject;
- begin
- Result:=0;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-add');
- if torrent = '-' then
- args.Add('filename', TJSONString.Create(FileName))
- else
- args.Add('metainfo', TJSONString.Create(torrent));
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req);
- if args <> nil then
- try
- if args.IndexOfName('torrent-duplicate') >= 0 then begin
- _AddTrackers(args.Objects['torrent-duplicate'].Integers['id']);
- exit;
- end;
- Result:=args.Objects['torrent-added'].Integers['id'];
- finally
- args.Free;
- end
- else
- if RpcObj.Status='duplicate torrent' then begin
- _AddTrackers(0);
- exit;
- end;
- finally
- req.Free;
- end;
- if Result = 0 then
- CheckStatus(False);
- end;
- procedure ShowWaitMsg(const AText: string);
- begin
- if WaitForm = nil then begin
- WaitForm:=TBaseForm.CreateNew(Self);
- with WaitForm do begin
- {$ifndef windows}
- if IsAppHidden then
- ShowInTaskBar:=stAlways;
- {$endif windows}
- Caption:=AppName;
- BorderStyle:=bsToolWindow;
- BorderIcons:=[];
- Position:=poScreenCenter;
- Constraints.MinWidth:=300;
- AutoSize:=True;
- BorderWidth:=ScaleInt(16);
- with TLabel.Create(WaitForm) do begin
- Alignment:=taCenter;
- Align:=alClient;
- Parent:=WaitForm;
- end;
- end;
- end;
- with WaitForm do begin
- TLabel(Controls[0]).Caption:=AText + '...';
- Show;
- BringToFront;
- {$ifdef lclgtk2}
- Application.ProcessMessages;
- {$endif lclgtk2}
- Update;
- {$ifdef lclgtk2}
- sleep(100);
- Application.ProcessMessages;
- {$endif lclgtk2}
- end;
- end;
- procedure HideWaitMsg;
- begin
- if WaitForm <> nil then
- FreeAndNil(WaitForm);
- end;
- var
- req, args: TJSONObject;
- id: integer;
- t, files: TJSONArray;
- i: integer;
- fs: TFileStreamUTF8;
- s, OldDownloadDir, IniSec, OldName: string;
- ok: boolean;
- begin
- Result:=False;
- if not RpcObj.Connected and not RpcObj.Connecting then
- if not DoConnect then
- exit;
- WaitForm:=nil;
- id:=0;
- Inc(FAddingTorrent);
- try
- AppBusy;
- try
- IsAppHidden:=not Self.Visible or (Self.WindowState = wsMinimized);
- with TAddTorrentForm.Create(Self) do
- try
- if IsAppHidden then begin
- ShowWaitMsg(Caption);
- {$ifndef windows}
- ShowInTaskBar:=stAlways;
- {$endif windows}
- end;
- Application.ProcessMessages;
- if IsProtocolSupported(FileName) then
- torrent:='-'
- else begin
- fs:=TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyNone);
- try
- SetLength(torrent, fs.Size);
- fs.ReadBuffer(PChar(torrent)^, Length(torrent));
- finally
- fs.Free;
- end;
- torrent:=EncodeBase64(torrent);
- end;
- IniSec:='AddTorrent.' + FCurConn;
- FillDownloadDirs(cbDestFolder, 'LastDownloadDir');
- req:=TJSONObject.Create;
- try
- req.Add('method', 'session-get');
- args:=RpcObj.SendRequest(req);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- s:=UTF8Encode(args.Strings['download-dir']);
- if cbDestFolder.Items.IndexOf(s) < 0 then begin
- cbDestFolder.Items.Insert(0, s);
- cbDestFolder.ItemIndex:=0;
- end;
- if RpcObj.RPCVersion < 15 then
- if args.IndexOfName('download-dir-free-space') >= 0 then
- txDiskSpace.Caption:=txDiskSpace.Caption + ' ' + GetHumanSize(args.Floats['download-dir-free-space'])
- else begin
- txDiskSpace.Hide;
- txSize.Top:=(txSize.Top + txDiskSpace.Top) div 2;
- end;
- args.Free;
- finally
- req.Free;
- end;
- lvFilter.Row:=0;
- edSearch.Text:='';
- args:=TJSONObject.Create;
- args.Add('paused', TJSONIntegerNumber.Create(1));
- i:=Ini.ReadInteger(IniSec, 'PeerLimit', 0);
- if i <> 0 then
- args.Add('peer-limit', TJSONIntegerNumber.Create(i));
- args.Add('download-dir', TJSONString.Create(UTF8Decode(cbDestFolder.Text)));
- id:=_AddTorrent(args);
- if id = 0 then
- exit;
- DoRefresh(True);
- args:=RpcObj.RequestInfo(id, ['files','maxConnectedPeers','name','metadataPercentComplete']);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- try
- t:=args.Arrays['torrents'];
- if t.Count = 0 then
- raise Exception.Create(sUnableGetFilesList);
- OldName:=UTF8Encode(t.Objects[0].Strings['name']);
- edSaveAs.Caption:=OldName;
- if RpcObj.RPCVersion < 15 then begin
- edSaveAs.Enabled:=False;
- edSaveAs.ParentColor:=True;
- end;
- edPeerLimit.Value:=t.Objects[0].Integers['maxConnectedPeers'];
- FilesTree.FillTree(id, t.Objects[0].Arrays['files'], nil, nil);
- Width:=Ini.ReadInteger('AddTorrent', 'Width', Width);
- if (RpcObj.RPCVersion >= 7) and (lvFiles.Items.Count = 0) and (t.Objects[0].Floats['metadataPercentComplete'] <> 1.0) then begin
- // Magnet link
- gbContents.Hide;
- gbSaveAs.BorderSpacing.Bottom:=gbSaveAs.BorderSpacing.Top;
- BorderStyle:=bsDialog;
- AutoSizeForm(TCustomForm(gbContents.Parent));
- edSaveAs.Enabled:=False;
- edSaveAs.ParentColor:=True;
- end
- else
- // Torrent file
- Height:=Ini.ReadInteger('AddTorrent', 'Height', Height);
- finally
- args.Free;
- end;
- OldDownloadDir:=cbDestFolder.Text;
- AppNormal;
- ok:=not Ini.ReadBool('Interface', 'ShowAddTorrentWindow', True);
- if ok then
- btSelectAllClick(nil)
- else begin
- HideWaitMsg;
- ok:=ShowModal = mrOk;
- if BorderStyle = bsSizeable then begin
- Ini.WriteInteger('AddTorrent', 'Width', Width);
- Ini.WriteInteger('AddTorrent', 'Height', Height);
- end;
- end;
- if ok then begin
- if IsAppHidden then
- ShowWaitMsg(Caption);
- AppBusy;
- Self.Update;
- if OldDownloadDir <> cbDestFolder.Text then begin
- TorrentAction(id, 'torrent-remove');
- id:=0;
- args:=TJSONObject.Create;
- args.Add('paused', TJSONIntegerNumber.Create(1));
- args.Add('peer-limit', TJSONIntegerNumber.Create(edPeerLimit.Value));
- args.Add('download-dir', TJSONString.Create(UTF8Decode(cbDestFolder.Text)));
- id:=_AddTorrent(args);
- if id = 0 then
- exit;
- DoRefresh(True);
- Application.ProcessMessages;
- end;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-set');
- args:=TJSONObject.Create;
- args.Add('ids', TJSONArray.Create([id]));
- args.Add('peer-limit', TJSONIntegerNumber.Create(edPeerLimit.Value));
- files:=TJSONArray.Create;
- for i:=0 to lvFiles.Items.Count - 1 do
- if not FilesTree.IsFolder(i) and (FilesTree.Checked[i] = cbChecked) then
- files.Add(integer(lvFiles.Items[idxFileId, i]));
- if files.Count > 0 then
- args.Add('files-wanted', files)
- else
- files.Free;
- files:=TJSONArray.Create;
- for i:=0 to lvFiles.Items.Count - 1 do
- if not FilesTree.IsFolder(i) and (FilesTree.Checked[i] <> cbChecked) then
- files.Add(integer(lvFiles.Items[idxFileId, i]));
- if files.Count > 0 then
- args.Add('files-unwanted', files)
- else
- files.Free;
- req.Add('arguments', args);
- args:=nil;
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- edSaveAs.Text:=Trim(edSaveAs.Text);
- if OldName <> edSaveAs.Text then begin
- // Changing torrent name
- req.Free;
- req:=TJSONObject.Create;
- req.Add('method', 'torrent-rename-path');
- args:=TJSONObject.Create;
- args.Add('ids', TJSONArray.Create([id]));
- args.Add('path', UTF8Decode(OldName));
- args.Add('name', UTF8Decode(edSaveAs.Text));
- req.Add('arguments', args);
- args:=nil;
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- end;
- finally
- req.Free;
- end;
- if cbStartTorrent.Checked then
- TorrentAction(id, 'torrent-start');
- SelectTorrent(id, 2000);
- id:=0;
- if Ini.ReadBool('Interface', 'DeleteTorrentFile', False) and not IsProtocolSupported(FileName) then
- DeleteFileUTF8(FileName);
- Ini.WriteInteger(IniSec, 'PeerLimit', edPeerLimit.Value);
- SaveDownloadDirs(cbDestFolder, 'LastDownloadDir');
- Result:=True;
- AppNormal;
- end;
- finally
- Free;
- end;
- finally
- if id <> 0 then
- TorrentAction(id, 'torrent-remove');
- end;
- finally
- HideWaitMsg;
- Dec(FAddingTorrent);
- end;
- end;
- procedure TMainForm.UpdateTray;
- begin
- TrayIcon.Visible:=not IsUnity and
- ( Ini.ReadBool('Interface', 'TrayIconAlways', True)
- or ( (WindowState = wsMinimized) and Ini.ReadBool('Interface', 'TrayMinimize', True) )
- or ( not Self.Visible and Ini.ReadBool('Interface', 'TrayClose', False) )
- );
- {$ifdef darwin}
- acShowApp.Visible:=False;
- acHideApp.Visible:=False;
- miTSep1.Visible:=False;
- {$else}
- acHideApp.Visible:=Visible and (WindowState <> wsMinimized);
- {$endif darwin}
- SetRefreshInterval;
- FCalcAvg:=Ini.ReadBool('Interface', 'CalcAvg', True);
- end;
- procedure TMainForm.HideApp;
- begin
- if WindowState <> wsMinimized then
- Hide;
- HideTaskbarButton;
- UpdateTray;
- end;
- procedure TMainForm.ShowApp;
- var
- i: integer;
- begin
- ShowTaskbarButton;
- if WindowState = wsMinimized then
- Application.Restore;
- Application.ProcessMessages;
- Show;
- Application.BringToFront;
- BringToFront;
- for i:=0 to Screen.FormCount - 1 do
- with Screen.Forms[i] do
- if fsModal in FormState then
- BringToFront;
- UpdateTray;
- end;
- procedure TMainForm.DownloadFinished(const TorrentName: string);
- begin
- if not TrayIcon.Visible or not Ini.ReadBool('Interface', 'TrayNotify', True) then exit;
- TrayIcon.BalloonHint:=Format(sFinishedDownload, [TorrentName]);
- TrayIcon.BalloonTitle:=sDownloadComplete;
- TrayIcon.ShowBalloonHint;
- end;
- Procedure TMainForm.DoOpenFlagsZip(Sender: TObject; var AStream: TStream);
- begin
- AStream:=TFileStreamUTF8.Create(TUnZipper(Sender).FileName, fmOpenRead or fmShareDenyWrite);
- end;
- Procedure TMainForm.DoCreateOutZipStream(Sender : TObject; var AStream : TStream; AItem : TFullZipFileEntry);
- begin
- ForceDirectoriesUTF8(FFlagsPath);
- AStream:=TFileStreamUTF8.Create(FFlagsPath + AItem.DiskFileName, fmCreate);
- end;
- function TMainForm.GetFlagImage(const CountryCode: string): integer;
- var
- s, ImageName: string;
- pic: TPicture;
- fs: TFileStreamUTF8;
- begin
- Result:=0;
- if CountryCode = '' then exit;
- try
- ImageName:=CountryCode + '.png';
- if FFlagsPath = '' then
- FFlagsPath:=FHomeDir + 'flags' + DirectorySeparator;
- if not FileExistsUTF8(FFlagsPath + ImageName) then begin
- // Unzipping flag image
- if FUnZip = nil then begin
- s:=GetFlagsArchive;
- if s <> '' then begin
- FUnZip:=TUnZipper.Create;
- FUnZip.FileName:=s;
- FUnZip.OnOpenInputStream:=@DoOpenFlagsZip;
- FUnZip.OnCreateStream:=@DoCreateOutZipStream;
- end
- else
- exit;
- end;
- FUnZip.Files.Clear;
- FUnZip.Files.Add(ImageName);
- try
- FUnZip.UnZipAllFiles;
- except
- FreeAndNil(FUnZip);
- DeleteFileUTF8(GetFlagsArchive);
- acShowCountryFlag.Checked:=False;
- MessageDlg(sUnableExtractFlag + LineEnding + Exception(ExceptObject).Message, mtError, [mbOK], 0);
- exit;
- end;
- if not FileExistsUTF8(FFlagsPath + ImageName) then exit;
- end;
- fs:=nil;
- pic:=TPicture.Create;
- try
- fs:=TFileStreamUTF8.Create(FFlagsPath + ImageName, fmOpenRead or fmShareDenyWrite);
- pic.LoadFromStream(fs);
- if imgFlags.Count = 1 then begin
- imgFlags.Width:=pic.Width;
- imgFlags.Height:=pic.Height;
- end;
- Result:=imgFlags.AddMasked(pic.Bitmap, clNone);
- finally
- pic.Free;
- fs.Free;
- end;
- except
- end;
- end;
- procedure TMainForm.BeforeCloseApp;
- begin
- if WindowState = wsNormal then begin
- Ini.WriteInteger('MainForm', 'Left', Left);
- Ini.WriteInteger('MainForm', 'Top', Top);
- Ini.WriteInteger('MainForm', 'Width', Width);
- Ini.WriteInteger('MainForm', 'Height', Height);
- end;
- if WindowState <> wsMinimized then
- Ini.WriteInteger('MainForm', 'State', integer(WindowState));
- if VSplitter.Visible then
- Ini.WriteInteger('MainForm', 'VSplitter', VSplitter.GetSplitterPosition);
- if HSplitter.Visible then
- Ini.WriteInteger('MainForm', 'HSplitter', HSplitter.GetSplitterPosition);
- Ini.WriteBool('MainForm', 'FilterPane', acFilterPane.Checked);
- Ini.WriteBool('MainForm', 'InfoPane', acInfoPane.Checked);
- Ini.WriteBool('MainForm', 'StatusBar', acStatusBar.Checked);
- SaveColumns(gTorrents, 'TorrentsList');
- SaveColumns(lvFiles, 'FilesList');
- SaveColumns(lvPeers, 'PeerList');
- SaveColumns(lvTrackers, 'TrackersList');
- Ini.WriteBool('PeersList', 'ResolveHost', acResolveHost.Checked);
- Ini.WriteBool('PeersList', 'ResolveCountry', acResolveCountry.Checked);
- Ini.WriteBool('PeersList', 'ShowCountryFlag', acShowCountryFlag.Checked);
- if RpcObj.Connected then
- Ini.WriteInteger('Interface', 'LastRpcVersion', RpcObj.RPCVersion);
- try
- Ini.UpdateFile;
- except
- Application.HandleException(nil);
- end;
- DoDisconnect;
- Application.ProcessMessages;
- end;
- function TMainForm.GetGeoIpDatabase: string;
- begin
- Result:=LocateFile('GeoIP.dat', [FHomeDir, ExtractFilePath(ParamStrUTF8(0))]);
- end;
- function TMainForm.GetFlagsArchive: string;
- begin
- Result:=LocateFile('flags.zip', [FHomeDir, ExtractFilePath(ParamStrUTF8(0))]);
- end;
- function TMainForm.DownloadGeoIpDatabase(AUpdate: boolean): boolean;
- const
- GeoLiteURL = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz';
- var
- tmp: string;
- gz: TGZFileStream;
- fs: TFileStreamUTF8;
- buf: array[0..65535] of byte;
- i: integer;
- begin
- Result:=False;
- tmp:=SysToUTF8(GetTempDir(True)) + 'GeoIP.dat.gz';
- if not FileExistsUTF8(tmp) or AUpdate then begin
- if MessageDlg('', sGeoIPConfirm, mtConfirmation, mbYesNo, 0, mbYes) <> mrYes then
- exit;
- if not DownloadFile(GeoLiteURL, ExtractFilePath(tmp), ExtractFileName(tmp)) then
- exit;
- end;
- try
- FreeAndNil(FResolver);
- gz:=TGZFileStream.Create(tmp, gzopenread);
- try
- fs:=TFileStreamUTF8.Create(FHomeDir + 'GeoIP.dat', fmCreate);
- try
- repeat
- i:=gz.read(buf, SizeOf(buf));
- fs.WriteBuffer(buf, i);
- until i < SizeOf(buf);
- finally
- fs.Free;
- end;
- finally
- gz.Free;
- end;
- DeleteFileUTF8(tmp);
- except
- DeleteFileUTF8(FHomeDir + 'GeoIP.dat');
- DeleteFileUTF8(tmp);
- raise;
- end;
- Result:=True;
- end;
- procedure TMainForm.TorrentColumnsChanged;
- var
- i: integer;
- s: string;
- begin
- s:='';
- for i:=0 to gTorrents.Columns.Count - 1 do
- with gTorrents.Columns[i] do
- if Visible and (Width > 0) then begin
- if TorrentFieldsMap[ID - 1] <> '' then begin
- if s <> '' then
- s:=s + ',';
- s:=s + TorrentFieldsMap[ID - 1];
- end;
- end;
- RpcObj.TorrentFields:=s;
- DoRefresh(True);
- end;
- function TMainForm.EtaToString(ETA: integer): string;
- const
- r1 = 60;
- r2 = 5*60;
- r3 = 30*60;
- r4 = 60*60;
- begin
- if (ETA < 0) or (ETA = MaxInt) then
- Result:=''
- else begin
- if ETA > 2*60*60 then // > 5 hours - round to 1 hour
- ETA:=(ETA + r4 div 2) div r4 * r4
- else
- if ETA > 2*60*60 then // > 2 hours - round to 30 mins
- ETA:=(ETA + r3 div 2) div r3 * r3
- else
- if ETA > 30*60 then // > 30 mins - round to 5 mins
- ETA:=(ETA + r2 div 2) div r2 * r2
- else
- if ETA > 2*60 then // > 2 mins - round to 1 min
- ETA:=(ETA + r1 div 2) div r1 * r1;
- Result:=SecondsToString(ETA);
- end;
- end;
- function TMainForm.GetTorrentStatus(TorrentIdx: integer): string;
- var
- i: integer;
- begin
- i:=gTorrents.Items[idxStatus, TorrentIdx];
- if i = TR_STATUS_CHECK_WAIT then
- Result:=sWaiting
- else
- if i = TR_STATUS_CHECK then
- Result:=sVerifying
- else
- if i = TR_STATUS_DOWNLOAD_WAIT then
- Result:=sWaiting
- else
- if i = TR_STATUS_DOWNLOAD then
- Result:=sDownloading
- else
- if i = TR_STATUS_SEED_WAIT then
- Result:=sWaiting
- else
- if i = TR_STATUS_SEED then
- Result:=sSeeding
- else
- if i = TR_STATUS_STOPPED then
- Result:=sStopped
- else
- if i = TR_STATUS_FINISHED then
- Result:=sFinished
- else
- Result:=sUnknown;
- end;
- function TMainForm.GetSeedsText(Seeds, SeedsTotal: integer): string;
- begin
- if SeedsTotal <> -1 then
- Result:=Format('%d/%d', [Seeds, SeedsTotal])
- else
- Result:=Format('%d', [Seeds]);
- end;
- function TMainForm.GetPeersText(Peers, PeersTotal, Leechers: integer): string;
- begin
- Result:=Format('%d', [Peers]);
- if Leechers <> -1 then
- Result:=Format('%s/%d', [Result, Leechers]);
- Dec(PeersTotal);
- if PeersTotal >= 0 then
- Result:=Format('%s (%d)', [Result, PeersTotal]);
- end;
- function TMainForm.RatioToString(Ratio: double): string;
- begin
- if (Ratio = MaxInt) or (Ratio = -2) then
- Result:=Utf8Encode(WideString(WideChar($221E)))
- else
- if Ratio = -1 then
- Result:=''
- else
- Result:=Format('%.3f', [Ratio]);
- end;
- function TMainForm.TorrentDateTimeToString(d: Int64): string;
- begin
- if d = 0 then
- Result:=''
- else
- Result:=DateTimeToStr(UnixToDateTime(d) + GetTimeZoneDelta);
- end;
- procedure TMainForm.DoRefresh(All: boolean);
- begin
- if All then
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtTorrents, rtDetails]
- else
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtDetails];
- end;
- procedure TMainForm.acDisconnectExecute(Sender: TObject);
- begin
- DoDisconnect;
- end;
- procedure TMainForm.acExitExecute(Sender: TObject);
- begin
- BeforeCloseApp;
- Application.Terminate;
- end;
- procedure TMainForm.acDaemonOptionsExecute(Sender: TObject);
- var
- req, args: TJSONObject;
- s: string;
- i, j: integer;
- begin
- with TDaemonOptionsForm.Create(Self) do
- try
- AppBusy;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'session-get');
- args:=RpcObj.SendRequest(req);
- if args <> nil then
- try
- edDownloadDir.Text:=UTF8Encode(args.Strings['download-dir']);
- if RpcObj.RPCVersion >= 5 then begin
- // RPC version 5
- edPort.Value:=args.Integers['peer-port'];
- cbPEX.Checked:=args.Integers['pex-enabled'] <> 0;
- edMaxPeers.Value:=args.Integers['peer-limit-global'];
- cbRandomPort.Checked:=args.Integers['peer-port-random-on-start'] <> 0;
- cbDHT.Checked:=args.Integers['dht-enabled'] <> 0;
- cbSeedRatio.Checked:=args.Integers['seedRatioLimited'] <> 0;
- edSeedRatio.Value:=args.Floats['seedRatioLimit'];
- cbBlocklist.Checked:=args.Integers['blocklist-enabled'] <> 0;
- cbAltEnabled.Checked:=args.Integers['alt-speed-enabled'] <> 0;
- edAltDown.Value:=args.Integers['alt-speed-down'];
- edAltUp.Value:=args.Integers['alt-speed-up'];
- cbAutoAlt.Checked:=args.Integers['alt-speed-time-enabled'] <> 0;
- edAltTimeBegin.Text:=FormatDateTime('hh:nn', args.Integers['alt-speed-time-begin']/MinsPerDay);
- edAltTimeEnd.Text:=FormatDateTime('hh:nn', args.Integers['alt-speed-time-end']/MinsPerDay);
- j:=args.Integers['alt-speed-time-day'];
- for i:=1 to 7 do begin
- TCheckBox(gbAltSpeed.FindChildControl(Format('cbDay%d', [i]))).Checked:=LongBool(j and 1);
- j:=j shr 1;
- end;
- cbAutoAltClick(nil);
- end
- else begin
- // RPC versions prior to v5
- cbPortForwarding.Top:=cbRandomPort.Top;
- edPort.Value:=args.Integers['port'];
- cbPEX.Checked:=args.Integers['pex-allowed'] <> 0;
- edMaxPeers.Value:=args.Integers['peer-limit'];
- cbRandomPort.Visible:=False;
- cbDHT.Visible:=False;
- cbSeedRatio.Visible:=False;
- edSeedRatio.Visible:=False;
- btTestPort.Visible:=False;
- cbBlocklist.Visible:=False;
- gbAltSpeed.Visible:=False;
- end;
- if RpcObj.RPCVersion >= 7 then begin
- cbIncompleteDir.Checked:=args.Integers['incomplete-dir-enabled'] <> 0;
- edIncompleteDir.Text:=UTF8Encode(args.Strings['incomplete-dir']);
- cbIncompleteDirClick(nil);
- end
- else begin
- cbIncompleteDir.Visible:=False;
- edIncompleteDir.Visible:=False;
- end;
- if RpcObj.RPCVersion >= 8 then
- cbPartExt.Checked:=args.Integers['rename-partial-files'] <> 0
- else
- cbPartExt.Visible:=False;
- if RpcObj.RPCVersion >= 9 then
- cbLPD.Checked:=args.Integers['lpd-enabled'] <> 0
- else
- cbLPD.Visible:=False;
- if RpcObj.RPCVersion >= 10 then begin
- edCacheSize.Value:=args.Integers['cache-size-mb'];
- cbIdleSeedLimit.Checked:=args.Integers['idle-seeding-limit-enabled'] <> 0;
- edIdleSeedLimit.Value:=args.Integers['idle-seeding-limit'];
- cbIdleSeedLimitClick(nil);
- end
- else begin
- edCacheSize.Visible:=False;
- txCacheSize.Visible:=False;
- txMB.Visible:=False;
- cbIdleSeedLimit.Visible:=False;
- edIdleSeedLimit.Visible:=False;
- txMinutes.Visible:=False;
- end;
- if args.IndexOfName('blocklist-url') >= 0 then
- edBlocklistURL.Text:=UTF8Encode(args.Strings['blocklist-url'])
- else begin
- edBlocklistURL.Visible:=False;
- cbBlocklist.Left:=cbPEX.Left;
- cbBlocklist.Caption:=StringReplace(cbBlocklist.Caption, ':', '', [rfReplaceAll]);
- end;
- cbBlocklistClick(nil);
- if RpcObj.RPCVersion >= 13 then
- cbUTP.Checked:=args.Integers['utp-enabled'] <> 0
- else
- cbUTP.Visible:=False;
- if RpcObj.RPCVersion >= 14 then begin
- tabQueue.TabVisible:=True;
- cbDownQueue.Checked:=args.Integers['download-queue-enabled'] <> 0;
- edDownQueue.Value:=args.Integers['download-queue-size'];
- cbUpQueue.Checked:=args.Integers['seed-queue-enabled'] <> 0;
- edUpQueue.Value:=args.Integers['seed-queue-size'];
- cbStalled.Checked:=args.Integers['queue-stalled-enabled'] <> 0;
- edStalledTime.Value:=args.Integers['queue-stalled-minutes'];
- end
- else
- tabQueue.TabVisible:=False;
- cbPortForwarding.Checked:=args.Integers['port-forwarding-enabled'] <> 0;
- s:=args.Strings['encryption'];
- if s = 'preferred' then
- cbEncryption.ItemIndex:=1
- else
- if s = 'required' then
- cbEncryption.ItemIndex:=2
- else
- cbEncryption.ItemIndex:=0;
- cbMaxDown.Checked:=args.Integers['speed-limit-down-enabled'] <> 0;
- edMaxDown.Value:=args.Integers['speed-limit-down'];
- cbMaxUp.Checked:=args.Integers['speed-limit-up-enabled'] <> 0;
- edMaxUp.Value:=args.Integers['speed-limit-up'];
- finally
- args.Free;
- end
- else begin
- CheckStatus(False);
- exit;
- end;
- finally
- req.Free;
- end;
- cbMaxDownClick(nil);
- cbMaxUpClick(nil);
- cbRandomPortClick(nil);
- cbSeedRatioClick(nil);
- AppNormal;
- if ShowModal = mrOK then begin
- AppBusy;
- Self.Update;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'session-set');
- args:=TJSONObject.Create;
- args.Add('download-dir', UTF8Decode(edDownloadDir.Text));
- args.Add('port-forwarding-enabled', integer(cbPortForwarding.Checked) and 1);
- case cbEncryption.ItemIndex of
- 1: s:='preferred';
- 2: s:='required';
- else s:='tolerated';
- end;
- args.Add('encryption', s);
- args.Add('speed-limit-down-enabled', integer(cbMaxDown.Checked) and 1);
- if cbMaxDown.Checked then
- args.Add('speed-limit-down', edMaxDown.Value);
- args.Add('speed-limit-up-enabled', integer(cbMaxUp.Checked) and 1);
- if cbMaxUp.Checked then
- args.Add('speed-limit-up', edMaxUp.Value);
- if RpcObj.RPCVersion >= 5 then begin
- args.Add('peer-limit-global', edMaxPeers.Value);
- args.Add('peer-port', edPort.Value);
- args.Add('pex-enabled', integer(cbPEX.Checked) and 1);
- args.Add('peer-port-random-on-start', integer(cbRandomPort.Checked) and 1);
- args.Add('dht-enabled', integer(cbDHT.Checked) and 1);
- args.Add('seedRatioLimited', integer(cbSeedRatio.Checked) and 1);
- if cbSeedRatio.Checked then
- args.Add('seedRatioLimit', edSeedRatio.Value);
- args.Add('blocklist-enabled', integer(cbBlocklist.Checked) and 1);
- args.Add('alt-speed-enabled', integer(cbAltEnabled.Checked) and 1);
- args.Add('alt-speed-down', edAltDown.Value);
- args.Add('alt-speed-up', edAltUp.Value);
- args.Add('alt-speed-time-enabled', integer(cbAutoAlt.Checked) and 1);
- if cbAutoAlt.Checked then begin
- args.Add('alt-speed-time-begin', Round(Frac(StrToTime(edAltTimeBegin.Text))*MinsPerDay));
- args.Add('alt-speed-time-end', Round(Frac(StrToTime(edAltTimeEnd.Text))*MinsPerDay));
- j:=0;
- for i:=7 downto 1 do begin
- j:=j shl 1;
- j:=j or (integer(TCheckBox(gbAltSpeed.FindChildControl(Format('cbDay%d', [i]))).Checked) and 1);
- end;
- args.Add('alt-speed-time-day', j);
- end;
- end
- else begin
- args.Add('peer-limit', edMaxPeers.Value);
- args.Add('port', edPort.Value);
- args.Add('pex-allowed', integer(cbPEX.Checked) and 1);
- end;
- if RpcObj.RPCVersion >= 7 then begin
- args.Add('incomplete-dir-enabled', integer(cbIncompleteDir.Checked) and 1);
- if cbIncompleteDir.Checked then
- args.Add('incomplete-dir', UTF8Decode(edIncompleteDir.Text));
- end;
- if RpcObj.RPCVersion >= 8 then
- args.Add('rename-partial-files', integer(cbPartExt.Checked) and 1);
- if RpcObj.RPCVersion >= 9 then
- args.Add('lpd-enabled', integer(cbLPD.Checked) and 1);
- if RpcObj.RPCVersion >= 10 then begin
- args.Add('cache-size-mb', edCacheSize.Value);
- args.Add('idle-seeding-limit-enabled', integer(cbIdleSeedLimit.Checked) and 1);
- args.Add('idle-seeding-limit', edIdleSeedLimit.Value);
- end;
- if edBlocklistURL.Visible then
- if cbBlocklist.Checked then
- args.Add('blocklist-url', UTF8Decode(edBlocklistURL.Text));
- if RpcObj.RPCVersion >= 13 then
- args.Add('utp-enabled', integer(cbUTP.Checked) and 1);
- if RpcObj.RPCVersion >= 14 then begin
- args.Add('download-queue-enabled', integer(cbDownQueue.Checked) and 1);
- args.Add('download-queue-size', edDownQueue.Value);
- args.Add('seed-queue-enabled', integer(cbUpQueue.Checked) and 1);
- args.Add('seed-queue-size', edUpQueue.Value);
- args.Add('queue-stalled-enabled', integer(cbStalled.Checked) and 1);
- args.Add('queue-stalled-minutes', edStalledTime.Value);
- end;
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- finally
- req.Free;
- end;
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtSession];
- AppNormal;
- end;
- finally
- Free;
- end;
- end;
- procedure TMainForm.acQMoveBottomExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'queue-move-bottom');
- end;
- procedure TMainForm.acQMoveDownExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'queue-move-down');
- end;
- procedure TMainForm.acQMoveTopExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'queue-move-top');
- end;
- procedure TMainForm.acQMoveUpExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'queue-move-up');
- end;
- procedure TMainForm.acReannounceTorrentExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'torrent-reannounce');
- end;
- procedure TMainForm.acRemoveTorrentAndDataExecute(Sender: TObject);
- begin
- InternalRemoveTorrent(sRemoveTorrentData, sRemoveTorrentDataMulti, True);
- end;
- procedure TMainForm.acRemoveTorrentExecute(Sender: TObject);
- begin
- InternalRemoveTorrent(sRemoveTorrent, sRemoveTorrentMulti, False);
- end;
- procedure TMainForm.acRenameExecute(Sender: TObject);
- begin
- if lvFiles.Focused then
- lvFiles.EditCell(idxFileName, lvFiles.Row)
- else
- gTorrents.EditCell(idxName, gTorrents.Row);
- end;
- procedure TMainForm.acResolveCountryExecute(Sender: TObject);
- begin
- if not acResolveCountry.Checked then
- if GetGeoIpDatabase = '' then
- if not DownloadGeoIpDatabase(False) then
- exit;
- acResolveCountry.Checked:=not acResolveCountry.Checked;
- FreeAndNil(FResolver);
- DoRefresh;
- acShowCountryFlag.Enabled:=acResolveCountry.Checked;
- end;
- procedure TMainForm.acResolveHostExecute(Sender: TObject);
- begin
- acResolveHost.Checked:=not acResolveHost.Checked;
- FreeAndNil(FResolver);
- DoRefresh;
- end;
- procedure TMainForm.acSelectAllExecute(Sender: TObject);
- begin
- Application.ProcessMessages;
- if lvFiles.Focused then
- lvFiles.SelectAll
- else
- gTorrents.SelectAll;
- end;
- procedure TMainForm.acSetHighPriorityExecute(Sender: TObject);
- begin
- Application.ProcessMessages;
- if lvFiles.Focused then
- SetCurrentFilePriority('high')
- else
- SetTorrentPriority(TR_PRI_HIGH);
- end;
- procedure TMainForm.acSetLowPriorityExecute(Sender: TObject);
- begin
- Application.ProcessMessages;
- if lvFiles.Focused then
- SetCurrentFilePriority('low')
- else
- SetTorrentPriority(TR_PRI_LOW);
- end;
- procedure TMainForm.acSetNormalPriorityExecute(Sender: TObject);
- begin
- Application.ProcessMessages;
- if lvFiles.Focused then
- SetCurrentFilePriority('normal')
- else
- SetTorrentPriority(TR_PRI_NORMAL);
- end;
- procedure TMainForm.acSetNotDownloadExecute(Sender: TObject);
- begin
- SetCurrentFilePriority('skip');
- end;
- procedure TMainForm.acSetupColumnsExecute(Sender: TObject);
- var
- g: TVarGrid;
- s: string;
- begin
- Application.ProcessMessages;
- if lvTrackers.Focused then
- g:=lvTrackers
- else
- if lvPeers.Focused then
- g:=lvPeers
- else
- if lvFiles.Focused then
- g:=lvFiles
- else
- g:=gTorrents;
- if g = gTorrents then
- s:=sTorrents
- else
- if PageInfo.ActivePage = tabFiles then
- s:=FFilesCapt
- else
- s:=PageInfo.ActivePage.Caption;
- if not SetupColumns(g, 0, s) then exit;
- if g = gTorrents then
- TorrentColumnsChanged;
- end;
- procedure TMainForm.acShowAppExecute(Sender: TObject);
- begin
- ShowApp;
- end;
- procedure TMainForm.acShowCountryFlagExecute(Sender: TObject);
- const
- FlagsURL = 'http://transmisson-remote-gui.googlecode.com/files/flags.zip';
- begin
- if not acShowCountryFlag.Checked then
- if GetFlagsArchive = '' then begin
- if MessageDlg('', sFlagArchiveConfirm, mtConfirmation, mbYesNo, 0, mbYes) <> mrYes then
- exit;
- if not DownloadFile(FlagsURL, FHomeDir) then
- exit;
- end;
- acShowCountryFlag.Checked:=not acShowCountryFlag.Checked;
- DoRefresh;
- end;
- procedure TMainForm.acStartAllTorrentsExecute(Sender: TObject);
- begin
- TorrentAction(NULL, 'torrent-start');
- end;
- procedure TMainForm.acStartTorrentExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'torrent-start');
- end;
- procedure TMainForm.acStatusBarExecute(Sender: TObject);
- begin
- acStatusBar.Checked:=not acStatusBar.Checked;
- StatusBar.Visible:=acStatusBar.Checked;
- if StatusBar.Visible then
- StatusBar.Top:=ClientHeight;
- end;
- procedure TMainForm.acStopAllTorrentsExecute(Sender: TObject);
- begin
- TorrentAction(NULL, 'torrent-stop');
- end;
- procedure TMainForm.acStopTorrentExecute(Sender: TObject);
- begin
- TorrentAction(GetSelectedTorrents, 'torrent-stop');
- end;
- procedure TMainForm.acTorrentPropsExecute(Sender: TObject);
- begin
- TorrentProps(0);
- end;
- procedure TMainForm.TorrentProps(PageNo: integer);
- const
- TR_RATIOLIMIT_GLOBAL = 0; // follow the global settings
- TR_RATIOLIMIT_SINGLE = 1; // override the global settings, seeding until a certain ratio
- TR_RATIOLIMIT_UNLIMITED = 2; // override the global settings, seeding regardless of ratio
- TR_IDLELIMIT_GLOBAL = 0; // follow the global settings
- TR_IDLELIMIT_SINGLE = 1; // override the global settings, seeding until a certain idle time
- TR_IDLELIMIT_UNLIMITED = 2; // override the global settings, seeding regardless of activity
- var
- req, args, t, tr: TJSONObject;
- i, j, id: integer;
- ids, Trackers, AddT, EditT, DelT: TJSONArray;
- TorrentIds: variant;
- s: string;
- trlist, sl: TStringList;
- begin
- gTorrentsClick(nil);
- id:=RpcObj.CurTorrentId;
- if id = 0 then exit;
- AppBusy;
- trlist:=nil;
- with TTorrPropsForm.Create(Self) do
- try
- Page.ActivePageIndex:=PageNo;
- gTorrents.Tag:=1;
- gTorrents.EnsureSelectionVisible;
- TorrentIds:=GetSelectedTorrents;
- args:=RpcObj.RequestInfo(id, ['downloadLimit', 'downloadLimitMode', 'downloadLimited', 'uploadLimit', 'uploadLimitMode', 'uploadLimited',
- 'name', 'maxConnectedPeers', 'seedRatioMode', 'seedRatioLimit', 'seedIdleLimit', 'seedIdleMode', 'trackers']);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- try
- t:=args.Arrays['torrents'].Objects[0];
- if gTorrents.SelCount > 1 then
- s:=Format(sSeveralTorrents, [gTorrents.SelCount])
- else
- s:=UTF8Encode(t.Strings['name']);
- txName.Caption:=txName.Caption + ' ' + s;
- Caption:=Caption + ' - ' + s;
- if RpcObj.RPCVersion < 5 then begin
- // RPC versions prior to v5
- j:=t.Integers['downloadLimitMode'];
- cbMaxDown.Checked:=j = TR_SPEEDLIMIT_SINGLE;
- i:=t.Integers['downloadLimit'];
- if (i < 0) or (j = TR_SPEEDLIMIT_UNLIMITED) then
- edMaxDown.ValueEmpty:=True
- else
- edMaxDown.Value:=i;
- j:=t.Integers['uploadLimitMode'];
- cbMaxUp.Checked:=j = TR_SPEEDLIMIT_SINGLE;
- i:=t.Integers['uploadLimit'];
- if (i < 0) or (j = TR_SPEEDLIMIT_UNLIMITED) then
- edMaxUp.ValueEmpty:=True
- else
- edMaxUp.Value:=i;
- cbSeedRatio.Visible:=False;
- edSeedRatio.Visible:=False;
- end else begin
- // RPC version 5
- cbMaxDown.Checked:=t.Booleans['downloadLimited'];
- i:=t.Integers['downloadLimit'];
- if i < 0 then
- edMaxDown.ValueEmpty:=True
- else
- edMaxDown.Value:=i;
- cbMaxUp.Checked:=t.Booleans['uploadLimited'];
- i:=t.Integers['uploadLimit'];
- if i < 0 then
- edMaxUp.ValueEmpty:=True
- else
- edMaxUp.Value:=i;
- case t.Integers['seedRatioMode'] of
- TR_RATIOLIMIT_SINGLE:
- cbSeedRatio.State:=cbChecked;
- TR_RATIOLIMIT_UNLIMITED:
- cbSeedRatio.State:=cbUnchecked;
- else
- cbSeedRatio.State:=cbGrayed;
- end;
- edSeedRatio.Value:=t.Floats['seedRatioLimit'];
- end;
- if RpcObj.RPCVersion >= 10 then begin
- case t.Integers['seedIdleMode'] of
- TR_IDLELIMIT_SINGLE:
- cbIdleSeedLimit.State:=cbChecked;
- TR_IDLELIMIT_UNLIMITED:
- cbIdleSeedLimit.State:=cbUnchecked;
- else
- cbIdleSeedLimit.State:=cbGrayed;
- end;
- edIdleSeedLimit.Value:=t.Integers['seedIdleLimit'];
- cbIdleSeedLimitClick(nil);
- trlist:=TStringList.Create;
- Trackers:=t.Arrays['trackers'];
- for i:=0 to Trackers.Count - 1 do begin
- tr:=Trackers[i] as TJSONObject;
- trlist.AddObject(UTF8Decode(tr.Strings['announce']), TObject(PtrUInt(tr.Integers['id'])));
- end;
- edTrackers.Lines.Assign(trlist);
- end
- else begin
- cbIdleSeedLimit.Visible:=False;
- edIdleSeedLimit.Visible:=False;
- txMinutes.Visible:=False;
- tabAdvanced.TabVisible:=False;
- end;
- edPeerLimit.Value:=t.Integers['maxConnectedPeers'];
- finally
- args.Free;
- end;
- cbMaxDownClick(nil);
- cbMaxUpClick(nil);
- cbSeedRatioClick(nil);
- AppNormal;
- if ShowModal = mrOk then begin
- AppBusy;
- Self.Update;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-set');
- args:=TJSONObject.Create;
- ids:=TJSONArray.Create;
- for i:=VarArrayLowBound(TorrentIds, 1) to VarArrayHighBound(TorrentIds, 1) do
- ids.Add(integer(TorrentIds[i]));
- args.Add('ids', ids);
- if RpcObj.RPCVersion < 5 then
- begin
- // RPC versions prior to v5
- args.Add('speed-limit-down-enabled', integer(cbMaxDown.Checked) and 1);
- args.Add('speed-limit-up-enabled', integer(cbMaxUp.Checked) and 1);
- if cbMaxDown.Checked then
- args.Add('speed-limit-down', edMaxDown.Value);
- if cbMaxUp.Checked then
- args.Add('speed-limit-up', edMaxUp.Value);
- end else begin
- // RPC version 5
- args.Add('downloadLimited', integer(cbMaxDown.Checked) and 1);
- args.Add('uploadLimited', integer(cbMaxUp.Checked) and 1);
- if cbMaxDown.Checked then
- args.Add('downloadLimit', edMaxDown.Value);
- if cbMaxUp.Checked then
- args.Add('uploadLimit', edMaxUp.Value);
- case cbSeedRatio.State of
- cbChecked:
- i:=TR_RATIOLIMIT_SINGLE;
- cbUnchecked:
- i:=TR_RATIOLIMIT_UNLIMITED;
- else
- i:=TR_RATIOLIMIT_GLOBAL;
- end;
- args.Add('seedRatioMode', i);
- if cbSeedRatio.State = cbChecked then
- args.Add('seedRatioLimit', edSeedRatio.Value);
- end;
- if RpcObj.RPCVersion >= 10 then begin
- case cbIdleSeedLimit.State of
- cbChecked:
- i:=TR_IDLELIMIT_SINGLE;
- cbUnchecked:
- i:=TR_IDLELIMIT_UNLIMITED;
- else
- i:=TR_IDLELIMIT_GLOBAL;
- end;
- args.Add('seedIdleMode', i);
- if cbIdleSeedLimit.State = cbChecked then
- args.Add('seedIdleLimit', edIdleSeedLimit.Value);
- sl:=TStringList.Create;
- try
- sl.Assign(edTrackers.Lines);
- // Removing unchanged trackers
- i:=0;
- while i < sl.Count do begin
- s:=Trim(sl[i]);
- if s = '' then begin
- sl.Delete(i);
- continue;
- end;
- j:=trlist.IndexOf(s);
- if j >= 0 then begin
- trlist.Delete(j);
- sl.Delete(i);
- continue;
- end;
- Inc(i);
- end;
- AddT:=TJSONArray.Create;
- EditT:=TJSONArray.Create;
- DelT:=TJSONArray.Create;
- try
- for i:=0 to sl.Count - 1 do begin
- s:=Trim(sl[i]);
- if trlist.Count > 0 then begin
- EditT.Add(PtrUInt(trlist.Objects[0]));
- EditT.Add(UTF8Decode(s));
- trlist.Delete(0);
- end
- else
- AddT.Add(UTF8Decode(s));
- end;
- for i:=0 to trlist.Count - 1 do
- DelT.Add(PtrUInt(trlist.Objects[i]));
- if AddT.Count > 0 then begin
- args.Add('trackerAdd', AddT);
- AddT:=nil;
- end;
- if EditT.Count > 0 then begin
- args.Add('trackerReplace', EditT);
- EditT:=nil;
- end;
- if DelT.Count > 0 then begin
- args.Add('trackerRemove', DelT);
- DelT:=nil;
- end;
- finally
- DelT.Free;
- EditT.Free;
- AddT.Free;
- end;
- finally
- sl.Free;
- end;
- end;
- args.Add('peer-limit', edPeerLimit.Value);
- req.Add('arguments', args);
- args:=nil;
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- finally
- req.Free;
- end;
- DoRefresh;
- AppNormal;
- end;
- finally
- gTorrents.Tag:=0;
- Free;
- trlist.Free;
- end;
- end;
- procedure TMainForm.acTrackerGroupingExecute(Sender: TObject);
- begin
- acTrackerGrouping.Checked:=not acTrackerGrouping.Checked;
- Ini.WriteBool('Interface', 'TrackerGrouping', acTrackerGrouping.Checked);
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtTorrents];
- end;
- procedure TMainForm.acUpdateBlocklistExecute(Sender: TObject);
- var
- req: TJSONObject;
- res: TJSONObject;
- begin
- Application.ProcessMessages;
- AppBusy;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'blocklist-update');
- res:=RpcObj.SendRequest(req, True, 3*60000);
- AppNormal;
- if res = nil then begin
- CheckStatus(False);
- exit;
- end;
- MessageDlg(Format(sBlocklistUpdateComplete, [res.Integers[('blocklist-size')]]), mtInformation, [mbOK], 0);
- res.Free;
- finally
- req.Free;
- end;
- end;
- procedure TMainForm.acUpdateGeoIPExecute(Sender: TObject);
- begin
- if DownloadGeoIpDatabase(True) then
- MessageDlg(sUpdateComplete, mtInformation, [mbOK], 0);
- end;
- procedure TMainForm.acVerifyTorrentExecute(Sender: TObject);
- var
- ids: variant;
- s: string;
- begin
- if gTorrents.Items.Count = 0 then exit;
- gTorrents.Tag:=1;
- try
- gTorrents.EnsureSelectionVisible;
- ids:=GetSelectedTorrents;
- if gTorrents.SelCount < 2 then
- s:=Format(sTorrentVerification, [UTF8Encode(widestring(gTorrents.Items[idxName, gTorrents.Items.IndexOf(idxTorrentId, ids[0])]))])
- else
- s:=Format(sTorrentsVerification, [gTorrents.SelCount]);
- if MessageDlg('', s, mtConfirmation, mbYesNo, 0, mbNo) <> mrYes then
- exit;
- finally
- gTorrents.Tag:=0;
- end;
- TorrentAction(ids, 'torrent-verify');
- end;
- procedure TMainForm.ApplicationPropertiesEndSession(Sender: TObject);
- begin
- DeleteFileUTF8(FRunFileName);
- BeforeCloseApp;
- end;
- procedure TMainForm.ApplicationPropertiesException(Sender: TObject; E: Exception);
- var
- msg: string;
- {$ifdef CALLSTACK}
- sl: TStringList;
- {$endif CALLSTACK}
- begin
- ForceAppNormal;
- msg:=E.Message;
- {$ifdef CALLSTACK}
- try
- sl:=TStringList.Create;
- try
- sl.Text:=GetLastExceptionCallStack;
- Clipboard.AsText:=msg + LineEnding + sl.Text;
- DebugLn(msg + LineEnding + sl.Text);
- if sl.Count > 20 then begin
- while sl.Count > 20 do
- sl.Delete(20);
- sl.Add('...');
- end;
- msg:=msg + LineEnding + '---' + LineEnding + 'The error details has been copied to the clipboard.' + LineEnding + '---';
- msg:=msg + LineEnding + sl.Text;
- finally
- sl.Free;
- end;
- except
- ; // suppress exception
- end;
- {$endif CALLSTACK}
- MessageDlg(msg, mtError, [mbOK], 0);
- end;
- procedure TMainForm.ApplicationPropertiesIdle(Sender: TObject; var Done: Boolean);
- begin
- UpdateUI;
- {$ifdef LCLcarbon}
- CheckSynchronize;
- {$endif LCLcarbon}
- Done:=True;
- end;
- procedure TMainForm.ApplicationPropertiesMinimize(Sender: TObject);
- begin
- {$ifndef darwin}
- if not IsUnity and Ini.ReadBool('Interface', 'TrayMinimize', True) then
- HideApp;
- {$endif darwin}
- UpdateTray;
- end;
- procedure TMainForm.ApplicationPropertiesRestore(Sender: TObject);
- begin
- UpdateTray;
- CheckClipboardLink;
- end;
- procedure TMainForm.edSearchChange(Sender: TObject);
- begin
- DoRefresh(True);
- end;
- procedure TMainForm.FormActivate(Sender: TObject);
- begin
- CheckClipboardLink;
- end;
- procedure TMainForm.FormDropFiles(Sender: TObject; const FileNames: array of String);
- var
- i: integer;
- begin
- for i:=Low(FileNames) to High(FileNames) do
- AddTorrentFile(FileNames[i]);
- end;
- procedure TMainForm.FormWindowStateChange(Sender: TObject);
- begin
- {$ifdef lclgtk2}
- if WindowState = wsMinimized then
- ApplicationPropertiesMinimize(nil)
- else
- ApplicationPropertiesRestore(nil);
- {$endif lclgtk2}
- end;
- procedure TMainForm.gTorrentsCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState;
- var CellAttribs: TCellAttributes);
- var
- j: integer;
- begin
- if ARow < 0 then exit;
- with CellAttribs do begin
- if ACol = gTorrents.FirstVisibleColumn then
- ImageIndex:=integer(Sender.Items[idxStateImg, ARow]);
- if Text = '' then exit;
- if not VarIsEmpty(Sender.Items[idxDeleted, ARow]) then
- with Sender.Canvas.Font do
- Style:=Style + [fsStrikeOut];
- case ADataCol of
- idxStatus:
- Text:=GetTorrentStatus(ARow);
- idxSize, idxDownloaded, idxUploaded, idxSizeToDowload:
- Text:=GetHumanSize(Sender.Items[ADataCol, ARow], 0, '?');
- idxDone:
- Text:=Format('%.1f%%', [double(Sender.Items[idxDone, ARow])]);
- idxSeeds:
- if not VarIsNull(Sender.Items[idxSeedsTotal, ARow]) then
- Text:=GetSeedsText(Sender.Items[idxSeeds, ARow], Sender.Items[idxSeedsTotal, ARow]);
- idxPeers:
- Text:=GetPeersText(Sender.Items[idxPeers, ARow], -1, Sender.Items[idxLeechersTotal, ARow]);
- idxDownSpeed, idxUpSpeed:
- begin
- j:=Sender.Items[ADataCol, ARow];
- if j > 0 then
- Text:=GetHumanSize(j, 1) + sPerSecond
- else
- Text:='';
- end;
- idxETA:
- Text:=EtaToString(Sender.Items[idxETA, ARow]);
- idxRatio:
- Text:=RatioToString(Sender.Items[idxRatio, ARow]);
- idxAddedOn, idxCompletedOn, idxLastActive:
- Text:=TorrentDateTimeToString(Sender.Items[ADataCol, ARow]);
- idxPriority:
- Text:=PriorityToStr(Sender.Items[ADataCol, ARow], ImageIndex);
- idxQueuePos:
- begin
- j:=Sender.Items[ADataCol, ARow];
- if j >= FinishedQueue then
- Dec(j, FinishedQueue);
- Text:=IntToStr(j);
- end;
- idxSeedingTime:
- begin
- j:=Sender.Items[idxSeedingTime, ARow];
- if j > 0 then
- Text:=EtaToString(j)
- else
- Text:='';
- end;
- end;
- end;
- end;
- procedure TMainForm.gTorrentsClick(Sender: TObject);
- var
- i: integer;
- begin
- if gTorrents.Tag <> 0 then exit;
- RpcObj.Lock;
- try
- if gTorrents.Items.Count > 0 then
- i:=gTorrents.Items[idxTorrentId, gTorrents.Row]
- else
- i:=0;
- if RpcObj.CurTorrentId = i then
- exit;
- RpcObj.CurTorrentId:=i;
- finally
- RpcObj.Unlock;
- end;
- ClearDetailsInfo(GetPageInfoType(PageInfo.ActivePage));
- TorrentsListTimer.Enabled:=False;
- TorrentsListTimer.Enabled:=True;
- end;
- procedure TMainForm.gTorrentsDblClick(Sender: TObject);
- var
- res: TJSONObject;
- s, n: string;
- begin
- if gTorrents.Items.Count = 0 then
- exit;
- if gTorrents.Items[idxDone, gTorrents.Row] = 100.0 then begin
- // The torrent is finished. Check if it is possible to open its file/folder
- AppBusy;
- try
- res:=RpcObj.RequestInfo(gTorrents.Items[idxTorrentId, gTorrents.Row], ['downloadDir']);
- if res = nil then
- CheckStatus(False);
- with res.Arrays['torrents'].Objects[0] do
- n:=IncludeProperTrailingPathDelimiter(UTF8Encode(Strings['downloadDir'])) + UTF8Encode(widestring(gTorrents.Items[idxName, gTorrents.Row]));
- s:=MapRemoteToLocal(n);
- if s = '' then
- s:=n;
- if FileExistsUTF8(s) or DirectoryExistsUTF8(s) then begin
- // File/folder exists - open it
- OpenCurrentTorrent(False);
- exit;
- end;
- finally
- AppNormal;
- end;
- end;
- acTorrentProps.Execute;
- end;
- procedure TMainForm.gTorrentsDrawCell(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; const R: TRect; var ADefaultDrawing: boolean);
- begin
- if ARow < 0 then exit;
- if ADataCol = idxDone then begin
- ADefaultDrawing:=False;
- DrawProgressCell(Sender, ACol, ARow, ADataCol, AState, R);
- end;
- end;
- procedure TMainForm.gTorrentsEditorHide(Sender: TObject);
- begin
- gTorrents.Tag:=0;
- end;
- procedure TMainForm.gTorrentsEditorShow(Sender: TObject);
- begin
- gTorrents.Tag:=1;
- gTorrents.RemoveSelection;
- end;
- procedure TMainForm.gTorrentsQuickSearch(Sender: TVarGrid; var SearchText: string; var ARow: integer);
- var
- i: integer;
- s: string;
- v: variant;
- begin
- s:=UTF8UpperCase(SearchText);
- for i:=ARow to gTorrents.Items.Count - 1 do begin
- v:=gTorrents.Items[idxName, i];
- if VarIsEmpty(v) or VarIsNull(v) then
- continue;
- if Pos(s, Trim(UTF8UpperCase(UTF8Encode(widestring(v))))) > 0 then begin
- ARow:=i;
- break;
- end;
- end;
- end;
- procedure TMainForm.gTorrentsResize(Sender: TObject);
- begin
- if not FStarted then begin
- VSplitter.SetSplitterPosition(Ini.ReadInteger('MainForm', 'VSplitter', VSplitter.GetSplitterPosition));
- HSplitter.SetSplitterPosition(Ini.ReadInteger('MainForm', 'HSplitter', HSplitter.GetSplitterPosition));
- end;
- end;
- procedure TMainForm.gTorrentsSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
- begin
- if RenameTorrent(gTorrents.Items[idxTorrentId, ARow], UTF8Encode(widestring(gTorrents.Items[idxName, ARow])), Trim(Value)) then begin
- gTorrents.Items[idxName, ARow]:=UTF8Decode(Trim(Value));
- FFilesTree.Clear;
- end;
- end;
- procedure TMainForm.gTorrentsSortColumn(Sender: TVarGrid; var ASortCol: integer);
- begin
- if ASortCol = idxSeeds then
- ASortCol:=idxSeedsTotal;
- if ASortCol = idxPeers then
- ASortCol:=idxLeechersTotal;
- end;
- procedure TMainForm.HSplitterChangeBounds(Sender: TObject);
- begin
- {$ifdef windows}
- Update;
- {$endif windows}
- end;
- procedure TMainForm.lvFilesDblClick(Sender: TObject);
- begin
- acOpenFile.Execute;
- end;
- procedure TMainForm.lvFilesEditorHide(Sender: TObject);
- begin
- gTorrents.Tag:=0;
- lvFiles.Tag:=0;
- lvFiles.HideSelection:=True;
- end;
- procedure TMainForm.lvFilesEditorShow(Sender: TObject);
- begin
- gTorrents.Tag:=1;
- lvFiles.Tag:=1;
- lvFiles.RemoveSelection;
- lvFiles.HideSelection:=False;
- end;
- procedure TMainForm.lvFilesSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
- var
- p: string;
- i, lvl, len: integer;
- begin
- p:=FFilesTree.GetFullPath(ARow, False);
- if RenameTorrent(gTorrents.Items[idxTorrentId, gTorrents.Row], p, Trim(Value)) then begin
- FFiles[idxFileName, ARow]:=UTF8Decode(Trim(Value));
- if FFilesTree.IsFolder(ARow) then begin
- // Updating path for child elements
- len:=Length(p);
- p:=ExtractFilePath(p) + Trim(Value);
- lvl:=FFilesTree.RowLevel[ARow];
- FFiles.BeginUpdate;
- try
- FFiles[idxFileFullPath, ARow]:=UTF8Decode(p + RemotePathDelimiter);
- for i:=ARow + 1 to FFiles.Count - 1 do
- if FFilesTree.RowLevel[i] > lvl then
- FFiles[idxFileFullPath, i]:=UTF8Decode(p + Copy(UTF8Encode(widestring(FFiles[idxFileFullPath, i])), len + 1, MaxInt))
- else
- break;
- finally
- FFiles.EndUpdate;
- end;
- end;
- end;
- end;
- procedure TMainForm.lvFilterCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; var CellAttribs: TCellAttributes);
- begin
- if ARow < 0 then exit;
- with CellAttribs do begin
- case ARow of
- 0: ImageIndex:=imgAll;
- 1: ImageIndex:=imgDown;
- 2: ImageIndex:=imgSeed;
- 3: ImageIndex:=imgActive;
- 4: ImageIndex:=15;
- 5: ImageIndex:=imgStopped;
- 6: ImageIndex:=imgError;
- else
- if Text <> '' then
- if VarIsNull(Sender.Items[-1, ARow]) then
- ImageIndex:=5
- else
- ImageIndex:=22;
- end;
- end;
- end;
- procedure TMainForm.lvFilterClick(Sender: TObject);
- begin
- if VarIsNull(lvFilter.Items[0, lvFilter.Row]) then
- if (FLastFilerIndex > lvFilter.Row) or (lvFilter.Row = lvFilter.Items.Count - 1) then
- lvFilter.Row:=lvFilter.Row - 1
- else
- lvFilter.Row:=lvFilter.Row + 1;
- FLastFilerIndex:=lvFilter.Row;
- FilterTimer.Enabled:=False;
- FilterTimer.Enabled:=True;
- end;
- procedure TMainForm.lvFilterDrawCell(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; const R: TRect;
- var ADefaultDrawing: boolean);
- var
- i: integer;
- RR: TRect;
- begin
- ADefaultDrawing:=not VarIsNull(Sender.Items[0, ARow]);
- if ADefaultDrawing then exit;
- with lvFilter.Canvas do begin
- Brush.Color:=lvFilter.Color;
- FillRect(R);
- i:=(R.Bottom + R.Top) div 2;
- Brush.Color:=clBtnFace;
- RR:=R;
- InflateRect(RR, -4, 0);
- RR.Top:=i - 1;
- RR.Bottom:=i + 1;
- FillRect(RR);
- end;
- end;
- procedure TMainForm.lvPeersCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; var CellAttribs: TCellAttributes);
- var
- i: integer;
- begin
- if ARow < 0 then exit;
- with CellAttribs do begin
- if Text = '' then exit;
- if ACol = 0 then begin
- ImageIndex:=Sender.Items[idxPeerCountryImage, ARow];
- if ImageIndex = 0 then
- ImageIndex:=-1;
- end;
- case ADataCol of
- idxPeerDone:
- Text:=Format('%.1f%%', [double(Sender.Items[ADataCol, ARow])*100.0]);
- idxPeerDownSpeed, idxPeerUpSpeed:
- begin
- i:=Sender.Items[ADataCol, ARow];
- if i > 0 then
- Text:=GetHumanSize(i, 1) + sPerSecond
- else
- Text:='';
- end;
- end;
- end;
- end;
- procedure TMainForm.lvTrackersCellAttributes(Sender: TVarGrid; ACol, ARow, ADataCol: integer; AState: TGridDrawState; var CellAttribs: TCellAttributes);
- var
- f: double;
- begin
- if ARow < 0 then exit;
- with CellAttribs do begin
- if Text = '' then exit;
- case ADataCol of
- idxTrackersListSeeds:
- if lvTrackers.Items[ADataCol, ARow] < 0 then
- Text:='';
- idxTrackersListUpdateIn:
- begin
- f:=double(lvTrackers.Items[ADataCol, ARow]);
- if f = 0 then
- Text:='-'
- else
- if f = 1 then
- Text:=sUpdating
- else
- Text:=SecondsToString(Trunc(f));
- end;
- end;
- end;
- end;
- procedure TMainForm.lvTrackersDblClick(Sender: TObject);
- begin
- acEditTracker.Execute;
- end;
- procedure TMainForm.lvTrackersKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
- begin
- if Key = VK_DELETE then begin
- Key:=0;
- acDelTracker.Execute;
- end;
- end;
- procedure TMainForm.miDonateClick(Sender: TObject);
- begin
- GoDonate;
- end;
- procedure TMainForm.miHomePageClick(Sender: TObject);
- begin
- GoHomePage;
- end;
- procedure TMainForm.PageInfoResize(Sender: TObject);
- begin
- if FDetailsWait.Visible then
- CenterDetailsWait;
- end;
- procedure TMainForm.panReconnectResize(Sender: TObject);
- begin
- panReconnectFrame.BoundsRect:=panReconnect.ClientRect;
- end;
- procedure TMainForm.pbDownloadedPaint(Sender: TObject);
- begin
- if FTorrentProgress <> nil then
- pbDownloaded.Canvas.StretchDraw(pbDownloaded.ClientRect, FTorrentProgress);
- end;
- procedure TMainForm.StatusBarMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- var
- pt: TPoint;
- rb: boolean;
- begin
- rb:=(Button = mbRight) and RpcObj.Connected;
- pt:=StatusBar.ClientToScreen(Point(X, Y));
- case StatusBar.GetPanelIndexAt(X, Y) of
- 0: if Button = mbLeft then
- acConnOptions.Execute;
- 1: if rb then
- pmDownSpeeds.PopUp(pt.X, pt.Y);
- 2: if rb then
- pmUpSpeeds.PopUp(pt.X, pt.Y);
- end;
- end;
- {$ifdef LCLcarbon}
- type
- THackApplication = class(TApplication)
- end;
- {$endif LCLcarbon}
- procedure TMainForm.TickTimerTimer(Sender: TObject);
- var
- i: integer;
- begin
- TickTimer.Enabled:=False;
- try
- if not FStarted then begin
- Application.ProcessMessages;
- FStarted:=True;
- acConnect.Execute;
- Application.ProcessMessages;
- panTransfer.ChildSizing.Layout:=cclLeftToRightThenTopToBottom;
- panGeneralInfo.ChildSizing.Layout:=cclLeftToRightThenTopToBottom;
- panTransfer.ChildSizing.Layout:=cclNone;
- panGeneralInfo.ChildSizing.Layout:=cclNone;
- with panTransfer do
- ClientHeight:=Controls[ControlCount - 1].BoundsRect.Bottom + ChildSizing.TopBottomSpacing;
- with panGeneralInfo do
- ClientHeight:=Controls[ControlCount - 1].BoundsRect.Bottom + ChildSizing.TopBottomSpacing;
- panSearch.AutoSize:=False;
- if Ini.ReadBool('MainForm', 'FirstRun', True) then begin
- if not acResolveCountry.Checked then
- acResolveCountry.Execute;
- if acResolveCountry.Checked and not acShowCountryFlag.Checked then
- acShowCountryFlag.Execute;
- Ini.WriteBool('MainForm', 'FirstRun', False);
- end;
- i:=Ini.ReadInteger('Interface', 'LastNewVersionCheck', Trunc(Now));
- if i + Ini.ReadInteger('Interface', 'CheckNewVersionDays', 5) <= Trunc(Now) then begin
- if Ini.ReadBool('Interface', 'AskCheckNewVersion', True) then begin
- Ini.WriteBool('Interface', 'AskCheckNewVersion', False);
- if not Ini.ReadBool('Interface', 'CheckNewVersion', False) then
- if MessageDlg(Format(SCheckNewVersion, [AppName]), mtConfirmation, mbYesNo, 0) = mrYes then
- Ini.WriteBool('Interface', 'CheckNewVersion', True);
- end;
- if Ini.ReadBool('Interface', 'CheckNewVersion', False) then
- CheckNewVersion;
- end;
- end;
- CheckAddTorrents;
- if RpcObj.Connected then
- FReconnectTimeOut:=0
- else
- if panReconnect.Visible then
- if Now - FReconnectWaitStart >= FReconnectTimeOut/SecsPerDay then
- DoConnect
- else
- txReconnectSecs.Caption:=Format(sReconnect, [FReconnectTimeOut - Round(SecsPerDay*(Now - FReconnectWaitStart))]);
- if FSlowResponse.Visible then begin
- if RpcObj.RequestStartTime = 0 then
- FSlowResponse.Visible:=False;
- end
- else
- if (RpcObj.RequestStartTime <> 0) and (Now - RpcObj.RequestStartTime >= 1/SecsPerDay) then
- FSlowResponse.Visible:=True;
- if FDetailsWait.Visible then begin
- if (FDetailsWaitStart = 0) or not (rtDetails in RpcObj.RefreshNow) then begin
- FDetailsWaitStart:=0;
- FDetailsWait.Visible:=False;
- panDetailsWait.Visible:=False;
- end;
- end
- else
- if (FDetailsWaitStart <> 0) and (Now - FDetailsWaitStart >= 300/MSecsPerDay) then begin
- CenterDetailsWait;
- FDetailsWait.Visible:=True;
- panDetailsWait.Visible:=True;
- panDetailsWait.BringToFront;
- end;
- {$ifdef LCLcarbon}
- THackApplication(Application).ProcessAsyncCallQueue;
- if Active and (WindowState <> wsMinimized) then begin
- if not FFormActive then begin
- FFormActive:=True;
- CheckClipboardLink;
- end;
- end
- else
- FFormActive:=False;
- {$endif LCLcarbon}
- finally
- TickTimer.Enabled:=True;
- end;
- end;
- procedure TMainForm.FilterTimerTimer(Sender: TObject);
- begin
- FilterTimer.Enabled:=False;
- FFilterChanged:=True;
- DoRefresh(True);
- end;
- procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
- begin
- if Ini.ReadBool('Interface', 'TrayClose', False) then begin
- {$ifdef darwin}
- CloseAction:=caMinimize;
- {$else}
- {$ifdef linux}
- if IsUnity then
- CloseAction:=caMinimize
- else
- {$endif linux}
- begin
- CloseAction:=caHide;
- HideApp;
- UpdateTray;
- end;
- {$endif darwin}
- exit;
- end;
- BeforeCloseApp;
- end;
- procedure TMainForm.PageInfoChange(Sender: TObject);
- begin
- if PageInfo.ActivePage.Tag <> 0 then
- FDetailsWaitStart:=Now;
- RpcObj.Lock;
- try
- RpcObj.AdvInfo:=GetPageInfoType(PageInfo.ActivePage);
- DoRefresh;
- finally
- RpcObj.Unlock;
- end;
- end;
- procedure TMainForm.TorrentsListTimerTimer(Sender: TObject);
- begin
- TorrentsListTimer.Enabled:=False;
- if RpcObj.CurTorrentId <> 0 then
- FDetailsWaitStart:=Now;
- DoRefresh;
- end;
- procedure TMainForm.pmFilesPopup(Sender: TObject);
- begin
- UpdateUI;
- end;
- procedure TMainForm.pmTorrentsPopup(Sender: TObject);
- begin
- UpdateUI;
- end;
- procedure TMainForm.TrayIconDblClick(Sender: TObject);
- begin
- {$ifndef darwin}
- acShowApp.Execute;
- {$endif darwin}
- end;
- procedure TMainForm.VSplitterChangeBounds(Sender: TObject);
- begin
- {$ifdef windows}
- Update;
- {$endif windows}
- end;
- procedure TMainForm.UrlLabelClick(Sender: TObject);
- begin
- AppBusy;
- OpenURL((Sender as TLabel).Caption);
- AppNormal;
- end;
- procedure TMainForm.CenterReconnectWindow;
- begin
- CenterOnParent(panReconnect);
- end;
- function TMainForm.DoConnect: boolean;
- var
- Sec, pwd: string;
- i, j: integer;
- begin
- Result:=True;
- panReconnect.Hide;
- DoDisconnect;
- Sec:='Connection.' + FCurConn;
- if not Ini.SectionExists(Sec) then
- Sec:='Connection';
- i:=FPasswords.IndexOfName(FCurConn);
- pwd:=Ini.ReadString(Sec, 'Password', '');
- if pwd = '-' then begin
- if i >= 0 then
- pwd:=FPasswords.ValueFromIndex[i]
- else begin
- pwd:='';
- if not InputQuery(Format(SConnectTo, [FCurConn]), Format(SEnterPassword, [FCurConn]), pwd) then begin
- RpcObj.Url:='-';
- Result:=False;
- exit;
- end;
- end;
- end
- else
- pwd:=DecodeBase64(pwd);
- if i >= 0 then
- FPasswords.Delete(i);
- if Ini.ReadBool(Sec, 'UseSSL', False) then begin
- RpcObj.InitSSL;
- if not IsSSLloaded then begin
- MessageDlg(Format(sSSLLoadError, [DLLSSLName, DLLUtilName]), mtError, [mbOK], 0);
- exit;
- end;
- RpcObj.Url:='https';
- end
- else
- RpcObj.Url:='http';
- RpcObj.Http.UserName:=Ini.ReadString(Sec, 'UserName', '');
- RpcObj.Http.Password:=pwd;
- RpcObj.Http.ProxyHost:='';
- RpcObj.Http.ProxyPort:='';
- RpcObj.Http.ProxyUser:='';
- RpcObj.Http.ProxyPass:='';
- RpcObj.Http.Sock.SocksIP:='';
- RpcObj.Http.Sock.SocksPort:='';
- RpcObj.Http.Sock.SocksUsername:='';
- RpcObj.Http.Sock.SocksPassword:='';
- if Ini.ReadBool(Sec, 'UseProxy', False) then begin
- if Ini.ReadBool(Sec, 'UseSockProxy', False) then begin
- RpcObj.Http.Sock.SocksIP := Ini.ReadString(Sec, 'ProxyHost', '');
- RpcObj.Http.Sock.SocksPort := IntToStr(Ini.ReadInteger(Sec, 'ProxyPort', 8080));
- RpcObj.Http.Sock.SocksUsername := Ini.ReadString(Sec, 'ProxyUser', '');
- RpcObj.Http.Sock.SocksPassword := DecodeBase64(Ini.ReadString(Sec, 'ProxyPass', ''));
- end
- else begin
- RpcObj.Http.ProxyHost:=Ini.ReadString(Sec, 'ProxyHost', '');
- RpcObj.Http.ProxyPort:=IntToStr(Ini.ReadInteger(Sec, 'ProxyPort', 8080));
- RpcObj.Http.ProxyUser:=Ini.ReadString(Sec, 'ProxyUser', '');
- RpcObj.Http.ProxyPass:=DecodeBase64(Ini.ReadString(Sec, 'ProxyPass', ''));
- end;
- end;
- RpcObj.RpcPath:=Ini.ReadString(Sec, 'RpcPath', '');
- RpcObj.Url:=Format('%s://%s:%d', [RpcObj.Url, Ini.ReadString(Sec, 'Host', ''), Ini.ReadInteger(Sec, 'Port', 9091)]);
- SetRefreshInterval;
- RpcObj.InfoStatus:=sConnectingToDaemon;
- CheckStatus;
- TrayIcon.Hint:=RpcObj.InfoStatus;
- RpcObj.Connect;
- FPathMap.Text:=StringReplace(Ini.ReadString(Sec, 'PathMap', ''), '|', LineEnding, [rfReplaceAll]);
- i:=0;
- while i < FPathMap.Count do
- if Trim(FPathMap.ValueFromIndex[i]) = '' then
- FPathMap.Delete(i)
- else
- Inc(i);
- Ini.WriteString('Hosts', 'CurHost', FCurConn);
- if FCurConn <> Ini.ReadString('Hosts', 'Host1', '') then begin
- Ini.WriteString('Hosts', 'Host1', FCurConn);
- j:=2;
- for i:=0 to pmConnections.Items.Count - 1 do
- with pmConnections.Items[i] do
- if (Tag = 0) and (Caption <> FCurConn) then begin
- Ini.WriteString('Hosts', Format('Host%d', [j]), Caption);
- Inc(j);
- end;
- Ini.UpdateFile;
- UpdateConnections;
- end
- else
- if pmConnections.Items[0].Tag = 0 then begin
- pmConnections.Items[0].Checked:=True;
- miConnect.Items[0].Checked:=True;
- end;
- end;
- procedure TMainForm.DoDisconnect;
- var
- i: integer;
- begin
- TorrentsListTimer.Enabled:=False;
- FilterTimer.Enabled:=False;
- ClearDetailsInfo;
- gTorrents.Items.Clear;
- gTorrents.Enabled:=False;
- gTorrents.Color:=clBtnFace;
- lvPeers.Enabled:=False;
- lvPeers.Color:=gTorrents.Color;
- lvFiles.Enabled:=False;
- lvFiles.Color:=gTorrents.Color;
- lvTrackers.Enabled:=False;
- lvTrackers.Color:=gTorrents.Color;
- lvFilter.Enabled:=False;
- lvFilter.Color:=gTorrents.Color;
- with lvFilter do begin
- Items[0, 0]:=UTF8Decode(SAll);
- Items[0, 1]:=UTF8Decode(SDownloading);
- Items[0, 2]:=UTF8Decode(SCompleted);
- Items[0, 3]:=UTF8Decode(SActive);
- Items[0, 4]:=UTF8Decode(SInactive);
- Items[0, 5]:=UTF8Decode(sStopped);
- Items[0, 6]:=UTF8Decode(sErrorState);
- end;
- edSearch.Enabled:=False;
- edSearch.Color:=gTorrents.Color;
- edSearch.Text:='';
- with gStats do begin
- BeginUpdate;
- try
- for i:=0 to Items.Count - 1 do begin
- Items[1, i]:=NULL;
- Items[2, i]:=NULL;
- end;
- finally
- EndUpdate;
- end;
- Enabled:=False;
- Color:=gTorrents.Color;
- end;
- RpcObj.Disconnect;
- RpcObj.InfoStatus:=sDisconnected;
- CheckStatus;
- UpdateUI;
- TrayIcon.Hint:=RpcObj.InfoStatus;
- gTorrents.Items.RowCnt:=0;
- FTorrents.RowCnt:=0;
- lvFilter.Row:=0;
- lvFilter.Items.RowCnt:=StatusFiltersCount;
- TorrentsListTimer.Enabled:=False;
- FilterTimer.Enabled:=False;
- pmConnections.Items[0].Checked:=False;
- miConnect.Items[0].Checked:=False;
- FCurDownSpeedLimit:=-2;
- FCurUpSpeedLimit:=-2;
- FillSpeedsMenu;
- end;
- procedure TMainForm.ClearDetailsInfo(Skip: TAdvInfoType);
- procedure ClearChildren(AParent: TPanel);
- var
- i: integer;
- begin
- AParent.AutoSize:=False;
- AParent.ChildSizing.Layout:=cclNone;
- for i:=0 to AParent.ControlCount - 1 do begin
- if AParent.Controls[i] is TLabel then
- with AParent.Controls[i] as TLabel do begin
- if (Length(Name) < 5) or (Copy(Name, Length(Name) - 4, 5) <> 'Label') then
- Caption:='';
- PopupMenu:=pmLabels;
- end;
- end;
- end;
- var
- i, t: integer;
- begin
- if RpcObj.CurTorrentId = 0 then begin
- Skip:=aiNone;
- t:=0;
- end
- else
- t:=1;
- FDetailsWaitStart:=0;
- if Skip <> aiFiles then begin
- FFiles.Clear;
- tabFiles.Caption:=FFilesCapt;
- end;
- if Skip <> aiPeers then
- lvPeers.Items.Clear;
- if Skip <> aiTrackers then
- lvTrackers.Items.Clear;
- if Skip <> aiGeneral then begin
- ClearChildren(panGeneralInfo);
- ClearChildren(panTransfer);
- ProcessPieces('', 0, 0);
- txDownProgress.AutoSize:=False;
- txDownProgress.Caption:='';
- end;
- for i:=0 to PageInfo.PageCount - 1 do
- PageInfo.Pages[i].Tag:=t;
- end;
- function TMainForm.SelectRemoteFolder(const CurFolder, DialogTitle: string): string;
- var
- i, j: integer;
- s, ss, sss, fn: string;
- dlg: TSelectDirectoryDialog;
- d: char;
- begin
- Result:='';
- if Trim(FPathMap.Text) = '' then begin
- MessageDlg(sNoPathMapping, mtInformation, [mbOK], 0);
- exit;
- end;
- s:=MapRemoteToLocal(CurFolder);
- if (s = '') or not DirectoryExistsUTF8(s) then
- s:=FPathMap.ValueFromIndex[0];
- if not DirectoryExistsUTF8(s) then begin
- MessageDlg(sNoPathMapping, mtInformation, [mbOK], 0);
- exit;
- end;
- dlg:=TSelectDirectoryDialog.Create(nil);
- try
- dlg.Title:=DialogTitle;
- dlg.InitialDir:=s;
- if not dlg.Execute then
- exit;
- fn:=dlg.FileName;
- for i:=0 to FPathMap.Count - 1 do begin
- s:=FPathMap[i];
- j:=Pos('=', s);
- if j > 0 then begin
- ss:=FixSeparators(Copy(s, j + 1, MaxInt));
- sss:=IncludeTrailingPathDelimiter(ss);
- if (CompareFilePath(ss, fn) = 0) or (CompareFilePath(sss, Copy(fn, 1, Length(sss))) = 0) then begin
- Result:=Copy(s, 1, j - 1);
- d:='/';
- for j:=1 to Length(Result) do
- if Result[j] in ['/','\'] then begin
- d:=Result[j];
- break;
- end;
- if CompareFilePath(ss, fn) <> 0 then begin
- if (Result <> '') and (Copy(Result, Length(Result), 1) <> d) then
- Result:=Result + d;
- ss:=IncludeProperTrailingPathDelimiter(ss);
- Result:=Result + Copy(fn, Length(ss) + 1, MaxInt);
- end;
- Result:=StringReplace(Result, DirectorySeparator, d, [rfReplaceAll]);
- if Copy(Result, Length(Result), 1) = d then
- SetLength(Result, Length(Result) - 1);
- end;
- end;
- end;
- finally
- dlg.Free;
- end;
- if Result = '' then
- MessageDlg(sNoPathMapping, mtError, [mbOK], 0);
- end;
- procedure TMainForm.ConnectionSettingsChanged(const ActiveConnection: string; ForceReconnect: boolean);
- begin
- UpdateConnections;
- if (FCurConn <> ActiveConnection) or ForceReconnect then begin
- DoDisconnect;
- FReconnectTimeOut:=-1;
- FCurConn:=ActiveConnection;
- if FCurConn <> '' then
- DoConnect;
- end;
- end;
- procedure TMainForm.UpdateUI;
- var
- e: boolean;
- begin
- e:=((Screen.ActiveForm = Self) or not Visible or (WindowState = wsMinimized))
- and not gTorrents.EditorMode and not lvFiles.EditorMode;
- acConnect.Enabled:=e;
- acOptions.Enabled:=e;
- acConnOptions.Enabled:=e;
- e:=RpcObj.Connected and e;
- acDisconnect.Enabled:=e;
- acSelectAll.Enabled:=e;
- acAddTorrent.Enabled:=e;
- acAddLink.Enabled:=e;
- acDaemonOptions.Enabled:=e;
- acStartAllTorrents.Enabled:=e and RpcObj.Connected;
- acStopAllTorrents.Enabled:=acStartAllTorrents.Enabled;
- acStartTorrent.Enabled:=e and (gTorrents.Items.Count > 0);
- acForceStartTorrent.Enabled:=acStartTorrent.Enabled and (RpcObj.RPCVersion >= 14);
- acStopTorrent.Enabled:=e and (gTorrents.Items.Count > 0);
- acVerifyTorrent.Enabled:=e and (gTorrents.Items.Count > 0);
- acRemoveTorrent.Enabled:=e and (gTorrents.Items.Count > 0) and not edSearch.Focused;
- acRemoveTorrentAndData.Enabled:=acRemoveTorrent.Enabled and (RpcObj.RPCVersion >= 4);
- acReannounceTorrent.Enabled:=acVerifyTorrent.Enabled and (RpcObj.RPCVersion >= 5);
- acMoveTorrent.Enabled:=acVerifyTorrent.Enabled and (RpcObj.RPCVersion >= 6);
- acTorrentProps.Enabled:=acVerifyTorrent.Enabled;
- acOpenContainingFolder.Enabled:=acTorrentProps.Enabled and (RpcObj.RPCVersion >= 4);
- pmiPriority.Enabled:=e and (gTorrents.Items.Count > 0);
- miPriority.Enabled:=pmiPriority.Enabled;
- acSetHighPriority.Enabled:=e and (gTorrents.Items.Count > 0) and
- ( ( not lvFiles.Focused and (RpcObj.RPCVersion >= 5) ) or
- ((lvFiles.Items.Count > 0) and (PageInfo.ActivePage = tabFiles)) );
- acSetNormalPriority.Enabled:=acSetHighPriority.Enabled;
- acSetLowPriority.Enabled:=acSetHighPriority.Enabled;
- miQueue.Enabled:=e and (gTorrents.Items.Count > 0) and (RpcObj.RPCVersion >= 14);
- pmiQueue.Enabled:=miQueue.Enabled;
- acQMoveTop.Enabled:=miQueue.Enabled;
- acQMoveUp.Enabled:=miQueue.Enabled;
- acQMoveDown.Enabled:=miQueue.Enabled;
- acQMoveBottom.Enabled:=miQueue.Enabled;
- acOpenFile.Enabled:=acSetHighPriority.Enabled and (lvFiles.SelCount < 2) and (RpcObj.RPCVersion >= 4);
- acCopyPath.Enabled:=acOpenFile.Enabled;
- acSetNotDownload.Enabled:=acSetHighPriority.Enabled;
- acRename.Enabled:=(RpcObj.RPCVersion >= 15) and acSetHighPriority.Enabled;
- acSetupColumns.Enabled:=e;
- acUpdateBlocklist.Enabled:=(acUpdateBlocklist.Tag <> 0) and e and (RpcObj.RPCVersion >= 5);
- acAddTracker.Enabled:=acTorrentProps.Enabled and (RpcObj.RPCVersion >= 10);
- acAdvEditTrackers.Enabled:=acAddTracker.Enabled;
- acEditTracker.Enabled:=acAddTracker.Enabled and (lvTrackers.Items.Count > 0);
- acDelTracker.Enabled:=acEditTracker.Enabled;
- acAltSpeed.Enabled:=e and (RpcObj.RPCVersion >= 5);
- pmiDownSpeedLimit.Enabled:=RpcObj.Connected;
- pmiUpSpeedLimit.Enabled:=RpcObj.Connected;
- end;
- procedure TMainForm.ShowConnOptions(NewConnection: boolean);
- var
- frm: TConnOptionsForm;
- begin
- AppBusy;
- frm:=TConnOptionsForm.Create(Self);
- with frm do
- try
- ActiveConnection:=FCurConn;
- if NewConnection then begin
- Caption:=SNewConnection;
- btNewClick(nil);
- if Ini.ReadInteger('Hosts', 'Count', 0) = 0 then begin
- panTop.Visible:=False;
- {$ifdef LCLgtk2}
- panTop.Height:=0;
- {$endif LCLgtk2}
- with Page.BorderSpacing do
- Top:=Left;
- tabPaths.TabVisible:=False;
- tabMisc.TabVisible:=False;
- end
- else begin
- btNew.Hide;
- btRename.Hide;
- btDel.Hide;
- panTop.ClientHeight:=btNew.Top;
- end;
- cbShowAdvancedClick(nil);
- AutoSizeForm(frm);
- end;
- AppNormal;
- ShowModal;
- ConnectionSettingsChanged(ActiveConnection, ActiveSettingChanged);
- finally
- Free;
- end;
- end;
- procedure TMainForm.SaveColumns(LV: TVarGrid; const AName: string; FullInfo: boolean);
- var
- i: integer;
- begin
- for i:=0 to LV.Columns.Count - 1 do
- with LV.Columns[i] do begin
- Ini.WriteInteger(AName, Format('Id%d', [i]), ID - 1);
- Ini.WriteInteger(AName, Format('Width%d', [i]), Width);
- if FullInfo then begin
- Ini.WriteInteger(AName, Format('Index%d', [i]), Index);
- Ini.WriteBool(AName, Format('Visible%d', [i]), Visible);
- end;
- end;
- if LV.SortColumn >= 0 then begin
- Ini.WriteInteger(AName, 'SortColumn', LV.SortColumn);
- Ini.WriteInteger(AName, 'SortOrder', integer(LV.SortOrder));
- end;
- end;
- procedure TMainForm.LoadColumns(LV: TVarGrid; const AName: string; FullInfo: boolean);
- var
- i, j, ColId: integer;
- begin
- LV.Columns.BeginUpdate;
- try
- for i:=0 to LV.Columns.Count - 1 do begin
- ColId:=Ini.ReadInteger(AName, Format('Id%d', [i]), -1);
- if ColId = -1 then continue;
- for j:=0 to LV.Columns.Count - 1 do
- with LV.Columns[j] do
- if ID - 1 = ColId then begin
- if FullInfo then begin
- Index:=Ini.ReadInteger(AName, Format('Index%d', [i]), Index);
- Visible:=Ini.ReadBool(AName, Format('Visible%d', [i]), Visible);
- end;
- Width:=Ini.ReadInteger(AName, Format('Width%d', [i]), Width);
- break;
- end;
- end;
- finally
- LV.Columns.EndUpdate;
- end;
- LV.SortColumn:=Ini.ReadInteger(AName, 'SortColumn', LV.SortColumn);
- LV.SortOrder:=TSortOrder(Ini.ReadInteger(AName, 'SortOrder', integer(LV.SortOrder)));
- end;
- function TMainForm.GetTorrentError(t: TJSONObject; Status: integer): string;
- var
- i: integer;
- stats: TJSONArray;
- err, gerr: widestring;
- NoTrackerError: boolean;
- begin
- Result:='';
- gerr:=t.Strings['errorString'];
- if RpcObj.RPCVersion >= 7 then begin
- NoTrackerError:=False;
- stats:=t.Arrays['trackerStats'];
- for i:=0 to stats.Count - 1 do
- with stats.Objects[i] do begin
- err:='';
- if Booleans['hasAnnounced'] and not Booleans['lastAnnounceSucceeded'] then
- err:=Strings['lastAnnounceResult'];
- if err = 'Success' then
- err:='';
- if err = '' then begin
- // If at least one tracker is working, then report no error
- NoTrackerError:=True;
- Result:='';
- end
- else begin
- if not NoTrackerError and (Result = '') then
- Result:=sTrackerError + ': ' + UTF8Encode(err);
- // Workaround for transmission bug
- // If the global error string is equal to some tracker error string,
- // then igonore the global error string
- if gerr = err then
- gerr:='';
- end;
- end;
- end
- else begin
- Result:=UTF8Encode(t.Strings['announceResponse']);
- if Result = 'Success' then
- Result:=''
- else
- if Result <> '' then begin
- i:=Pos('(', Result);
- if i <> 0 then
- if Copy(Result, i, 5) = '(200)' then
- Result:=''
- else
- Result:=sTrackerError + ': ' + Copy(Result, 1, i - 1);
- end;
- end;
- if (Result = '') or (Status = TR_STATUS_STOPPED) or (Status = TR_STATUS_FINISHED) then
- Result:=UTF8Encode(gerr);
- end;
- function TMainForm.SecondsToString(j: integer): string;
- begin
- if j < 60 then
- Result:=Format(sSecs, [j])
- else
- if j < 60*60 then begin
- Result:=Format(sMins, [j div 60]);
- j:=j mod 60;
- if j > 0 then
- Result:=Format('%s, %s', [Result, Format(sSecs, [j])]);
- end
- else begin
- j:=(j + 30) div 60;
- if j < 60*24 then begin
- Result:=Format(sHours, [j div 60]);
- j:=j mod 60;
- if j > 0 then
- Result:=Format('%s, %s', [Result, Format(sMins, [j])]);
- end
- else begin
- j:=(j + 30) div 60;
- Result:=Format(sDays, [j div 24]);
- j:=j mod 24;
- if j > 0 then
- Result:=Format('%s, %s', [Result, Format(sHours, [j])]);
- end;
- end;
- end;
- procedure TMainForm.FillTorrentsList(list: TJSONArray);
- var
- i, j, row, crow, id, StateImg: integer;
- t: TJSONObject;
- f: double;
- ExistingRow: boolean;
- s, ss: string;
- function GetTorrentValue(AIndex: integer; const AName: string; AType: integer): boolean;
- var
- res: variant;
- i: integer;
- begin
- i:=t.IndexOfName(AName);
- Result:=i >= 0;
- if Result then
- case AType of
- vtInteger:
- res:=t.Items[i].AsInteger;
- vtExtended:
- res:=t.Items[i].AsFloat;
- else
- res:=t.Items[i].AsString;
- end
- else
- res:=NULL;
- FTorrents[AIndex, row]:=res;
- end;
- function StoreSpeed(var History: variant; Speed: integer): integer;
- var
- j, cnt: integer;
- p: PInteger;
- IsNew: boolean;
- res: Int64;
- begin
- IsNew:=VarIsEmpty(History);
- if IsNew then begin
- if Speed = 0 then begin
- Result:=0;
- exit;
- end;
- History:=VarArrayCreate([0, SpeedHistorySize], varInteger);
- end;
- p:=VarArrayLock(History);
- try
- if IsNew then begin
- for j:=1 to SpeedHistorySize do
- p[j]:=-1;
- j:=1;
- end
- else begin
- j:=Round((Now - cardinal(p[0])/SecsPerDay)/RpcObj.RefreshInterval);
- if j = 0 then
- j:=1;
- end;
- p[0]:=integer(cardinal(Round(Now*SecsPerDay)));
- // Shift speed array
- if j < SpeedHistorySize then
- Move(p[1], p[j + 1], (SpeedHistorySize - j)*SizeOf(integer))
- else
- j:=SpeedHistorySize;
- while j > 0 do begin
- p[j]:=Speed;
- Dec(j);
- end;
- // Calc average speed
- res:=Speed;
- cnt:=1;
- for j:=2 to SpeedHistorySize do
- if p[j] < 0 then
- break
- else begin
- Inc(res, p[j]);
- Inc(cnt);
- end;
- Result:=res div cnt;
- finally
- VarArrayUnlock(History);
- end;
- if Result = 0 then
- VarClear(History);
- end;
- var
- FilterIdx, OldId: integer;
- TrackerFilter, PathFilter: string;
- UpSpeed, DownSpeed: double;
- DownCnt, SeedCnt, CompletedCnt, ActiveCnt, StoppedCnt, ErrorCnt: integer;
- IsActive: boolean;
- Paths: TStringList;
- v: variant;
- FieldExists: array of boolean;
- begin
- if gTorrents.Tag <> 0 then exit;
- if list = nil then begin
- ClearDetailsInfo;
- exit;
- end;
- {
- for i:=1 to 1000 do begin
- t:=TJSONObject.Create;
- t.Integers['id']:=i + 10000;
- t.Strings['name']:=Format('ZName %d', [i]);
- t.Integers['status']:=TR_STATUS_STOPPED;
- t.Arrays['trackerStats']:=TJSONArray.Create;
- t.Floats['sizeWhenDone']:=0;
- t.Floats['leftUntilDone']:=0;
- t.Integers['rateDownload']:=0;
- t.Integers['rateUpload']:=0;
- list.Add(t);
- end;
- }
- Paths:=TStringList.Create;
- try
- Paths.Sorted:=True;
- OldId:=RpcObj.CurTorrentId;
- IsActive:=gTorrents.Enabled;
- gTorrents.Enabled:=True;
- lvFilter.Enabled:=True;
- gTorrents.Color:=clWindow;
- lvFilter.Color:=clWindow;
- edSearch.Enabled:=True;
- edSearch.Color:=clWindow;
- if not IsActive then
- ActiveControl:=gTorrents;
- for i:=0 to FTrackers.Count - 1 do
- FTrackers.Objects[i]:=nil;
- // Check fields' existence
- SetLength(FieldExists, FTorrents.ColCnt);
- if list.Count > 0 then begin
- t:=list[0] as TJSONObject;
- FieldExists[idxName]:=t.IndexOfName('name') >= 0;
- FieldExists[idxRatio]:=t.IndexOfName('uploadRatio') >= 0;
- FieldExists[idxTracker]:=t.IndexOfName('trackers') >= 0;
- FieldExists[idxPath]:=t.IndexOfName('downloadDir') >= 0;
- FieldExists[idxPriority]:=t.IndexOfName('bandwidthPriority') >= 0;
- FieldExists[idxQueuePos]:=t.IndexOfName('queuePosition') >= 0;
- FieldExists[idxSeedingTime]:=t.IndexOfName('secondsSeeding') >= 0;
- end;
- UpSpeed:=0;
- DownSpeed:=0;
- DownCnt:=0;
- SeedCnt:=0;
- CompletedCnt:=0;
- ActiveCnt:=0;
- StoppedCnt:=0;
- ErrorCnt:=0;
- FilterIdx:=lvFilter.Row;
- if VarIsNull(lvFilter.Items[0, FilterIdx]) then
- Dec(FilterIdx);
- if FilterIdx >= StatusFiltersCount then
- if not VarIsNull(lvFilter.Items[-1, FilterIdx]) then begin
- PathFilter:=UTF8Encode(widestring(lvFilter.Items[-1, FilterIdx]));
- FilterIdx:=fltAll;
- end
- else begin
- TrackerFilter:=UTF8Encode(widestring(lvFilter.Items[0, FilterIdx]));
- FilterIdx:=fltAll;
- i:=RPos('(', TrackerFilter);
- if i > 0 then
- TrackerFilter:=Trim(Copy(TrackerFilter, 1, i - 1));
- end;
- for i:=0 to FTorrents.Count - 1 do
- FTorrents[idxTag, i]:=0;
- for i:=0 to list.Count - 1 do begin
- StateImg:=-1;
- t:=list[i] as TJSONObject;
- id:=t.Integers['id'];
- ExistingRow:=FTorrents.Find(idxTorrentId, id, row);
- if not ExistingRow then
- FTorrents.InsertRow(row);
- FTorrents[idxTorrentId, row]:=t.Integers['id'];
- if FieldExists[idxName] then
- FTorrents[idxName, row]:=t.Strings['name'];
- j:=t.Integers['status'];
- if ExistingRow and (j = TR_STATUS_SEED) and (FTorrents[idxStatus, row] = TR_STATUS_DOWNLOAD) then
- DownloadFinished(UTF8Encode(widestring(FTorrents[idxName, row])));
- FTorrents[idxStatus, row]:=j;
- if j = TR_STATUS_CHECK_WAIT then StateImg:=imgDownQueue else
- if j = TR_STATUS_CHECK then StateImg:=imgDownQueue else
- if j = TR_STATUS_DOWNLOAD_WAIT then StateImg:=imgDownQueue else
- if j = TR_STATUS_DOWNLOAD then StateImg:=imgDown else
- if j = TR_STATUS_SEED_WAIT then StateImg:=imgSeedQueue else
- if j = TR_STATUS_SEED then StateImg:=imgSeed else
- if j = TR_STATUS_STOPPED then StateImg:=imgDone;
- if GetTorrentError(t, j) <> '' then
- if t.Strings['errorString'] <> '' then
- StateImg:=imgError
- else
- if StateImg in [imgDown,imgSeed] then
- Inc(StateImg, 2);
- if j <> TR_STATUS_STOPPED then begin
- s:=GetTorrentError(t, j);
- if s <> '' then
- if t.Strings['errorString'] <> '' then
- StateImg:=imgError
- else
- if StateImg in [imgDown,imgSeed] then
- Inc(StateImg, 2);
- if RpcObj.RPCVersion >= 7 then begin
- s:='';
- if t.Arrays['trackerStats'].Count > 0 then
- with t.Arrays['trackerStats'].Objects[0] do begin
- if integer(Integers['announceState']) in [2, 3] then
- s:=sTrackerUpdating
- else
- if Booleans['hasAnnounced'] then
- if Booleans['lastAnnounceSucceeded'] then
- s:=sTrackerWorking
- else
- s:=TranslateString(UTF8Encode(Strings['lastAnnounceResult']), True);
- if s = 'Success' then
- s:=sTrackerWorking;
- end;
- end
- else
- s:=t.Strings['announceResponse'];
- end
- else
- s:='';
- FTorrents[idxTrackerStatus, row]:=UTF8Decode(s);
- if FTorrents[idxStatus, row] = TR_STATUS_CHECK then
- f:=t.Floats['recheckProgress']*100.0
- else begin
- f:=t.Floats['sizeWhenDone'];
- if f <> 0 then
- f:=(f - t.Floats['leftUntilDone'])*100.0/f;
- if StateImg = imgDone then
- if (t.Floats['leftUntilDone'] <> 0) or (t.Floats['sizeWhenDone'] = 0) then
- StateImg:=imgStopped
- else
- FTorrents[idxStatus, row]:=TR_STATUS_FINISHED;
- end;
- if f < 0 then
- f:=0;
- FTorrents[idxDone, row]:=Int(f*10.0)/10.0;
- FTorrents[idxStateImg, row]:=StateImg;
- GetTorrentValue(idxDownSpeed, 'rateDownload', vtInteger);
- j:=StoreSpeed(FTorrents.ItemPtrs[idxDownSpeedHistory, row]^, FTorrents[idxDownSpeed, row]);
- if FCalcAvg and (StateImg in [imgDown, imgDownError]) then
- FTorrents[idxDownSpeed, row]:=j;
- GetTorrentValue(idxUpSpeed, 'rateUpload', vtInteger);
- j:=StoreSpeed(FTorrents.ItemPtrs[idxUpSpeedHistory, row]^, FTorrents[idxUpSpeed, row]);
- if FCalcAvg and (StateImg in [imgSeed, imgSeedError]) then
- FTorrents[idxUpSpeed, row]:=j;
- GetTorrentValue(idxSize, 'totalSize', vtExtended);
- GetTorrentValue(idxSizeToDowload, 'sizeWhenDone', vtExtended);
- GetTorrentValue(idxSeeds, 'peersSendingToUs', vtInteger);
- GetTorrentValue(idxPeers, 'peersGettingFromUs', vtInteger);
- GetTorrentValue(idxETA, 'eta', vtInteger);
- v:=FTorrents[idxETA, row];
- if not VarIsNull(v) then
- if v < 0 then
- FTorrents[idxETA, row]:=MaxInt
- else begin
- f:=FTorrents[idxDownSpeed, row];
- if f > 0 then
- FTorrents[idxETA, row]:=Round(t.Floats['leftUntilDone']/f);
- end;
- GetTorrentValue(idxDownloaded, 'downloadedEver', vtExtended);
- GetTorrentValue(idxUploaded, 'uploadedEver', vtExtended);
- GetTorrentValue(idxAddedOn, 'addedDate', vtExtended);
- GetTorrentValue(idxCompletedOn, 'doneDate', vtExtended);
- GetTorrentValue(idxLastActive, 'activityDate', vtExtended);
- if RpcObj.RPCVersion >= 7 then begin
- if t.Arrays['trackerStats'].Count > 0 then
- with t.Arrays['trackerStats'].Objects[0] do begin
- FTorrents[idxSeedsTotal, row]:=Integers['seederCount'];
- FTorrents[idxLeechersTotal, row]:=Integers['leecherCount'];
- end
- else begin
- FTorrents[idxSeedsTotal, row]:=-1;
- FTorrents[idxLeechersTotal, row]:=-1;
- end;
- if t.Floats['metadataPercentComplete'] <> 1.0 then begin
- FTorrents[idxSize, row]:=-1;
- FTorrents[idxSizeToDowload, row]:=-1;
- end;
- end
- else begin
- GetTorrentValue(idxSeedsTotal, 'seeders', vtInteger);
- GetTorrentValue(idxLeechersTotal, 'leechers', vtInteger);
- end;
- if FieldExists[idxRatio] then begin
- f:=t.Floats['uploadRatio'];
- if f = -2 then
- f:=MaxInt;
- FTorrents[idxRatio, row]:=f;
- end
- else
- FTorrents[idxRatio, row]:=NULL;
- if FieldExists[idxSeedingTime] then
- FTorrents[idxSeedingTime, row]:=t.Integers['secondsSeeding']
- else
- FTorrents[idxSeedingTime, row]:=NULL;
- if RpcObj.RPCVersion >= 7 then begin
- if t.Arrays['trackerStats'].Count > 0 then
- s:=t.Arrays['trackerStats'].Objects[0].Strings['announce']
- else
- s:=sNoTracker;
- end
- else
- if FieldExists[idxTracker] then
- s:=UTF8Encode(t.Arrays['trackers'].Objects[0].Strings['announce'])
- else begin
- s:='';
- if VarIsEmpty(FTorrents[idxTracker, row]) then
- RpcObj.RequestFullInfo:=True;
- end;
- if s <> '' then begin
- j:=Pos('://', s);
- if j > 0 then
- s:=Copy(s, j + 3, MaxInt);
- j:=Pos('/', s);
- if j > 0 then
- s:=Copy(s, 1, j - 1);
- j:=Pos('.', s);
- if j > 0 then begin
- ss:=Copy(s, 1, j - 1);
- if AnsiCompareText(ss, 'bt') = 0 then
- System.Delete(s, 1, 3)
- else
- if (Length(ss) = 3) and (AnsiCompareText(Copy(ss, 1, 2), 'bt') = 0) and (ss[3] in ['1'..'9']) then
- System.Delete(s, 1, 4);
- end;
- j:=Pos(':', s);
- if j > 0 then
- System.Delete(s, j, MaxInt);
- FTorrents[idxTracker, row]:=UTF8Decode(s);
- end;
- if FieldExists[idxPath] then
- FTorrents[idxPath, row]:=UTF8Decode(ExcludeTrailingPathDelimiter(UTF8Encode(t.Strings['downloadDir'])))
- else
- if VarIsEmpty(FTorrents[idxPath, row]) then
- RpcObj.RequestFullInfo:=True;
- if not VarIsEmpty(FTorrents[idxPath, row]) then begin
- s:=UTF8Encode(widestring(FTorrents[idxPath, row]));
- j:=Paths.IndexOf(s);
- if j < 0 then
- Paths.AddObject(s, TObject(1))
- else
- Paths.Objects[j]:=TObject(PtrInt(Paths.Objects[j]) + 1);
- end;
- if FieldExists[idxPriority] then
- FTorrents[idxPriority, row]:=t.Integers['bandwidthPriority'];
- if FieldExists[idxQueuePos] then begin
- j:=t.Integers['queuePosition'];
- if FTorrents[idxStatus, row] = TR_STATUS_FINISHED then
- Inc(j, FinishedQueue);
- FTorrents[idxQueuePos, row]:=j;
- end;
- DownSpeed:=DownSpeed + FTorrents[idxDownSpeed, row];
- UpSpeed:=UpSpeed + FTorrents[idxUpSpeed, row];
- FTorrents[idxTag, row]:=1;
- end;
- i:=0;
- while i < FTorrents.Count do
- if FTorrents[idxTag, i] = 0 then
- FTorrents.Delete(i)
- else
- Inc(i);
- gTorrents.Items.BeginUpdate;
- try
- for i:=0 to gTorrents.Items.Count - 1 do
- gTorrents.Items[idxTag, i]:=0;
- gTorrents.Items.Sort(idxTorrentId);
- for i:=0 to FTorrents.Count - 1 do begin
- IsActive:=(FTorrents[idxDownSpeed, i] <> 0) or (FTorrents[idxUpSpeed, i] <> 0);
- if IsActive then
- Inc(ActiveCnt);
- j:=FTorrents[idxStatus, i];
- if j = TR_STATUS_DOWNLOAD then
- Inc(DownCnt)
- else
- if j = TR_STATUS_SEED then begin
- Inc(SeedCnt);
- Inc(CompletedCnt);
- end
- else
- if j = TR_STATUS_FINISHED then
- Inc(CompletedCnt);
- StateImg:=FTorrents[idxStateImg, i];
- if StateImg in [imgStopped, imgDone] then
- Inc(StoppedCnt)
- else
- if StateImg in [imgDownError, imgSeedError, imgError] then
- Inc(ErrorCnt);
- if not VarIsEmpty(FTorrents[idxTracker, i]) then begin
- s:=UTF8Encode(widestring(FTorrents[idxTracker, i]));
- j:=FTrackers.IndexOf(s);
- if j < 0 then
- j:=FTrackers.Add(s);
- FTrackers.Objects[j]:=TObject(ptruint(FTrackers.Objects[j]) + 1);
- if (TrackerFilter <> '') and (TrackerFilter <> s) then
- continue;
- end;
- if (PathFilter <> '') and not VarIsEmpty(FTorrents[idxPath, i]) and (UTF8Decode(PathFilter) <> FTorrents[idxPath, i]) then
- continue;
- case FilterIdx of
- fltActive:
- if not IsActive then
- continue;
- fltInactive:
- if IsActive then
- continue;
- fltDown:
- if FTorrents[idxStatus, i] <> TR_STATUS_DOWNLOAD then
- continue;
- fltDone:
- if (StateImg <> imgDone) and (FTorrents[idxStatus, i] <> TR_STATUS_SEED) then
- continue;
- fltStopped:
- if not (StateImg in [imgStopped, imgDone]) then
- continue;
- fltError:
- if not (StateImg in [imgDownError, imgSeedError, imgError]) then
- continue;
- end;
- if edSearch.Text <> '' then
- if UTF8Pos(UTF8UpperCase(edSearch.Text), UTF8UpperCase(UTF8Encode(widestring(FTorrents[idxName, i])))) = 0 then
- continue;
- if not gTorrents.Items.Find(idxTorrentId, FTorrents[idxTorrentId, i], row) then
- gTorrents.Items.InsertRow(row);
- for j:=-TorrentsExtraColumns to FTorrents.ColCnt - 1 do
- if (j <> idxDownSpeedHistory) and (j <> idxUpSpeedHistory) then
- gTorrents.Items[j, row]:=FTorrents[j, i];
- gTorrents.Items[idxTag, row]:=1;
- end;
- i:=0;
- while i < gTorrents.Items.Count do
- if gTorrents.Items[idxTag, i] = 0 then
- gTorrents.Items.Delete(i)
- else
- Inc(i);
- gTorrents.Sort;
- if gTorrents.Items.Count > 0 then begin
- if OldId <> 0 then begin
- i:=gTorrents.Items.IndexOf(idxTorrentId, OldId);
- if i >= 0 then
- gTorrents.Row:=i
- else
- if FFilterChanged then
- OldId:=0;
- end;
- if OldId = 0 then
- gTorrents.Row:=0;
- end;
- FFilterChanged:=False;
- finally
- gTorrents.Items.EndUpdate;
- end;
- gTorrentsClick(nil);
- crow:=-1;
- lvFilter.Items.BeginUpdate;
- try
- lvFilter.Items[0, 0]:=UTF8Decode(Format('%s (%d)', [SAll, list.Count]));
- lvFilter.Items[0, 1]:=UTF8Decode(Format('%s (%d)', [SDownloading, DownCnt]));
- lvFilter.Items[0, 2]:=UTF8Decode(Format('%s (%d)', [SCompleted, CompletedCnt]));
- lvFilter.Items[0, 3]:=UTF8Decode(Format('%s (%d)', [SActive, ActiveCnt]));
- lvFilter.Items[0, 4]:=UTF8Decode(Format('%s (%d)', [SInactive, FTorrents.Count - ActiveCnt]));
- lvFilter.Items[0, 5]:=UTF8Decode(Format('%s (%d)', [sStopped, StoppedCnt]));
- lvFilter.Items[0, 6]:=UTF8Decode(Format('%s (%d)', [sErrorState, ErrorCnt]));
- j:=StatusFiltersCount;
- if acFolderGrouping.Checked then begin
- lvFilter.Items[0, j]:=NULL;
- Inc(j);
- for i:=0 to Paths.Count - 1 do begin
- s:=ExtractFileName(Paths[i]);
- for row:=StatusFiltersCount + 1 to j - 1 do
- if ExtractFileName(UTF8Encode(widestring(lvFilter.Items[-1, row]))) = s then begin
- s:=Paths[i];
- lvFilter.Items[0, row]:=UTF8Decode(Format('%s (%d)', [UTF8Encode(widestring(lvFilter.Items[-1, row])), ptruint(Paths.Objects[row - StatusFiltersCount - 1])]));
- end;
- lvFilter.Items[0, j]:=UTF8Decode(Format('%s (%d)', [s, ptruint(Paths.Objects[i])]));
- lvFilter.Items[-1, j]:=UTF8Decode(Paths[i]);
- if Paths[i] = PathFilter then
- crow:=j;
- Inc(j);
- end;
- end;
- row:=j;
- if acTrackerGrouping.Checked then begin
- if not VarIsNull(lvFilter.Items[0, row - 1]) then begin
- lvFilter.Items[0, row]:=NULL;
- Inc(row);
- end;
- i:=0;
- while i < FTrackers.Count do begin
- j:=ptruint(FTrackers.Objects[i]);
- if j > 0 then begin
- lvFilter.Items[0, row]:=UTF8Decode(Format('%s (%d)', [FTrackers[i], j]));
- lvFilter.Items[-1, row]:=NULL;
- if FTrackers[i] = TrackerFilter then
- crow:=row;
- Inc(i);
- Inc(row);
- end
- else
- FTrackers.Delete(i);
- end;
- end;
- lvFilter.Items.RowCnt:=row;
- finally
- lvFilter.Items.EndUpdate;
- end;
- if crow >= 0 then
- lvFilter.Row:=crow
- else
- if lvFilter.Row >= StatusFiltersCount then
- lvFilterClick(nil);
- CheckStatus;
- StatusBar.Panels[1].Text:=Format(sDownSpeed, [GetHumanSize(DownSpeed, 1)]);
- StatusBar.Panels[2].Text:=Format(sUpSpeed, [GetHumanSize(UpSpeed, 1)]);
- {$ifndef LCLcarbon}
- // There is memory leak in TTrayIcon implementation for Mac.
- // Disable tray icon update for Mac.
- TrayIcon.Hint:=Format(sDownloadingSeeding,
- [RpcObj.InfoStatus, LineEnding, DownCnt, SeedCnt, LineEnding, StatusBar.Panels[1].Text, StatusBar.Panels[2].Text]);
- {$endif LCLcarbon}
- finally
- Paths.Free;
- end;
- DetailsUpdated;
- end;
- procedure TMainForm.FillPeersList(list: TJSONArray);
- var
- i, j, row: integer;
- port: integer;
- d: TJSONData;
- p: TJSONObject;
- ip, s: string;
- hostinfo: PHostEntry;
- opt: TResolverOptions;
- WasEmpty: boolean;
- begin
- if list = nil then begin
- ClearDetailsInfo;
- exit;
- end;
- WasEmpty:=lvPeers.Items.Count = 0;
- lvPeers.Items.BeginUpdate;
- try
- lvPeers.Enabled:=True;
- lvPeers.Color:=clWindow;
- if FResolver = nil then begin
- opt:=[];
- if acResolveHost.Checked then
- Include(opt, roResolveIP);
- if acResolveCountry.Checked then
- Include(opt, roResolveCountry);
- if opt <> [] then
- FResolver:=TIpResolver.Create(GetGeoIpDatabase, opt);
- end;
- for i:=0 to lvPeers.Items.Count - 1 do
- lvPeers.Items[idxPeerTag, i]:=0;
- lvPeers.Items.Sort(idxPeerIP);
- for i:=0 to list.Count - 1 do begin
- d:=list[i];
- if not (d is TJSONObject) then continue;
- p:=d as TJSONObject;
- ip:=p.Strings['address'];
- if p.IndexOfName('port') >= 0 then
- port:=p.Integers['port']
- else
- port:=0;
- s:=ip + ':' + IntToStr(port);
- if not lvPeers.Items.Find(idxPeerIP, s, row) then
- lvPeers.Items.InsertRow(row);
- lvPeers.Items[idxPeerIP, row]:=s;
- lvPeers.Items[idxPeerPort, row]:=port;
- if FResolver <> nil then
- hostinfo:=FResolver.Resolve(ip)
- else
- hostinfo:=nil;
- if hostinfo <> nil then
- lvPeers.Items[idxPeerHost, row]:=hostinfo^.HostName
- else
- lvPeers.Items[idxPeerHost, row]:=ip;
- if hostinfo <> nil then
- lvPeers.Items[idxPeerCountry, row]:=hostinfo^.CountryName
- else
- lvPeers.Items[idxPeerCountry, row]:='';
- if acShowCountryFlag.Checked and (hostinfo <> nil) then begin
- if hostinfo^.ImageIndex = 0 then
- hostinfo^.ImageIndex:=GetFlagImage(hostinfo^.CountryCode);
- j:=hostinfo^.ImageIndex
- end
- else
- j:=0;
- lvPeers.Items[idxPeerCountryImage, row]:=j;
- lvPeers.Items[idxPeerClient, row]:=p.Strings['clientName'];
- lvPeers.Items[idxPeerFlags, row]:=p.Strings['flagStr'];
- lvPeers.Items[idxPeerDone, row]:=p.Floats['progress'];
- if p.IndexOfName('rateToClient') >= 0 then
- lvPeers.Items[idxPeerDownSpeed, row]:=p.Integers['rateToClient'];
- if p.IndexOfName('rateToPeer') >= 0 then
- lvPeers.Items[idxPeerUpSpeed, row]:=p.Integers['rateToPeer'];
- lvPeers.Items[idxPeerTag, row]:=1;
- end;
- i:=0;
- while i < lvPeers.Items.Count do
- if lvPeers.Items[idxPeerTag, i] = 0 then
- lvPeers.Items.Delete(i)
- else
- Inc(i);
- lvPeers.Sort;
- if WasEmpty and (lvPeers.Items.Count > 0) then
- lvPeers.Row:=0;
- finally
- lvPeers.Items.EndUpdate;
- end;
- DetailsUpdated;
- end;
- function TMainForm.GetFilesCommonPath(files: TJSONArray): string;
- var
- i: integer;
- d: TJSONData;
- f: TJSONObject;
- s: string;
- begin
- Result:='';
- for i:=0 to files.Count - 1 do begin
- d:=files[i];
- if not (d is TJSONObject) then continue;
- f:=d as TJSONObject;
- s:=UTF8Encode(f.Strings['name']);
- if i = 0 then
- Result:=ExtractFilePath(s)
- else begin
- while True do begin
- if Result = '' then
- exit;
- if Copy(s, 1, Length(Result)) <> Result then begin
- SetLength(Result, Length(Result) - 1);
- Result:=ExtractFilePath(Result);
- end
- else
- break;
- end;
- end;
- end;
- end;
- procedure TMainForm.InternalRemoveTorrent(const Msg, MsgMulti: string; RemoveLocalData: boolean);
- var
- args: TJSONObject;
- ids: variant;
- s: string;
- i, j, id: integer;
- begin
- if gTorrents.Items.Count = 0 then exit;
- gTorrents.Tag:=1;
- try
- gTorrents.EnsureSelectionVisible;
- ids:=GetSelectedTorrents;
- if gTorrents.SelCount < 2 then
- s:=Format(Msg, [UTF8Encode(widestring(gTorrents.Items[idxName, gTorrents.Items.IndexOf(idxTorrentId, ids[0])]))])
- else
- s:=Format(MsgMulti, [gTorrents.SelCount]);
- if MessageDlg('', s, mtConfirmation, mbYesNo, 0, mbNo) <> mrYes then exit;
- finally
- gTorrents.Tag:=0;
- end;
- args:=TJSONObject.Create;
- if RemoveLocalData then
- args.Add('delete-local-data', TJSONIntegerNumber.Create(1));
- if TorrentAction(ids, 'torrent-remove', args) then begin
- with gTorrents do begin
- BeginUpdate;
- try
- i:=0;
- while i < Items.Count do begin
- id:=Items[idxTorrentId, i];
- for j:=0 to VarArrayHighBound(ids, 1) do
- if id = ids[j] then begin
- Items.Items[idxDeleted, i]:=1;
- break;
- end;
- Inc(i);
- end;
- finally
- EndUpdate;
- end;
- end;
- if RemoveLocalData then
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtSession];
- end;
- end;
- function TMainForm.IncludeProperTrailingPathDelimiter(const s: string): string;
- var
- i: integer;
- d: char;
- begin
- Result:=s;
- if Result = '' then exit;
- d:='/';
- for i:=1 to Length(Result) do
- if Result[i] in ['/','\'] then begin
- d:=Result[i];
- break;
- end;
- if Result[Length(Result)] <> d then
- Result:=Result + d;
- end;
- procedure TMainForm.FillFilesList(ATorrentId: integer; list, priorities, wanted: TJSONArray; const DownloadDir: WideString);
- begin
- if lvFiles.Tag <> 0 then exit;
- if (list = nil) or (priorities = nil) or (wanted = nil) then begin
- ClearDetailsInfo;
- exit;
- end;
- lvFiles.Enabled:=True;
- lvFiles.Color:=clWindow;
- FFilesTree.DownloadDir:=UTF8Encode(DownloadDir);
- FFilesTree.FillTree(ATorrentId, list, priorities, wanted);
- tabFiles.Caption:=Format('%s (%d)', [FFilesCapt, list.Count]);
- DetailsUpdated;
- end;
- procedure TMainForm.FillGeneralInfo(t: TJSONObject);
- var
- i, j, idx: integer;
- s: string;
- f: double;
- begin
- if (gTorrents.Items.Count = 0) or (t = nil) then begin
- ClearDetailsInfo;
- exit;
- end;
- idx:=gTorrents.Items.IndexOf(idxTorrentId, t.Integers['id']);
- if idx = -1 then begin
- ClearDetailsInfo;
- exit;
- end;
- txDownProgress.Caption:=Format('%.1f%%', [double(gTorrents.Items[idxDone, idx])]);
- txDownProgress.AutoSize:=True;
- if RpcObj.RPCVersion >= 5 then
- s:=t.Strings['pieces']
- else
- s:='';
- ProcessPieces(s, t.Integers['pieceCount'], gTorrents.Items[idxDone, idx]);
- panTransfer.ChildSizing.Layout:=cclNone;
- txStatus.Caption:=GetTorrentStatus(idx);
- txError.Caption:=GetTorrentError(t, gTorrents.Items[idxStatus, idx]);
- i:=t.Integers['eta'];
- f:=gTorrents.Items[idxDownSpeed, idx];
- if f > 0 then
- i:=Round(t.Floats['leftUntilDone']/f);
- txRemaining.Caption:=EtaToString(i);
- txDownloaded.Caption:=GetHumanSize(t.Floats['downloadedEver']);
- txUploaded.Caption:=GetHumanSize(t.Floats['uploadedEver']);
- f:=t.Floats['pieceSize'];
- if f > 0 then
- i:=Round(t.Floats['corruptEver']/f)
- else
- i:=0;
- txWasted.Caption:=Format(sHashfails, [GetHumanSize(t.Floats['corruptEver']), i]);
- s:=GetHumanSize(gTorrents.Items[idxDownSpeed, idx], 1)+sPerSecond;
- if t.IndexOfName('secondsDownloading') >= 0 then begin
- f:=t.Integers['secondsDownloading'];
- if f > 0 then
- s:=Format('%s (%s: %s)', [s, SAverage, GetHumanSize(t.Floats['downloadedEver']/f, 1) + sPerSecond]);
- end;
- txDownSpeed.Caption:=s;
- txUpSpeed.Caption:=GetHumanSize(gTorrents.Items[idxUpSpeed, idx], 1)+sPerSecond;
- s:=RatioToString(t.Floats['uploadRatio']);
- if t.IndexOfName('secondsSeeding') >= 0 then begin
- i:=t.Integers['secondsSeeding'];
- if i > 0 then
- s:=Format('%s (%s)', [s, EtaToString(i)]);
- end;
- txRatio.Caption:=s;
- if RpcObj.RPCVersion < 5 then
- begin
- // RPC versions prior to v5
- j:=t.Integers['downloadLimitMode'];
- if j = TR_SPEEDLIMIT_GLOBAL then
- s:='-'
- else begin
- i:=t.Integers['downloadLimit'];
- if (i < 0) or (j = TR_SPEEDLIMIT_UNLIMITED) then
- s:=Utf8Encode(WideString(WideChar($221E)))
- else
- s:=GetHumanSize(i*1024)+sPerSecond;
- end;
- txDownLimit.Caption:=s;
- j:=t.Integers['uploadLimitMode'];
- if j = TR_SPEEDLIMIT_GLOBAL then
- s:='-'
- else begin
- i:=t.Integers['uploadLimit'];
- if (i < 0) or (j = TR_SPEEDLIMIT_UNLIMITED) then
- s:=Utf8Encode(WideString(WideChar($221E)))
- else
- s:=GetHumanSize(i*1024)+sPerSecond;
- end;
- txUpLimit.Caption:=s;
- end else begin
- // RPC version 5
- if t.Booleans['downloadLimited'] then
- begin
- i:=t.Integers['downloadLimit'];
- if i < 0 then
- s:=Utf8Encode(WideString(WideChar($221E)))
- else
- s:=GetHumanSize(i*1024)+sPerSecond;
- end else s:='-';
- txDownLimit.Caption:=s;
- if t.Booleans['uploadLimited'] then
- begin
- i:=t.Integers['uploadLimit'];
- if i < 0 then
- s:=Utf8Encode(WideString(WideChar($221E)))
- else
- s:=GetHumanSize(i*1024)+sPerSecond;
- end else s:='-';
- txUpLimit.Caption:=s;
- end;
- if RpcObj.RPCVersion >= 7 then
- with t.Arrays['trackerStats'] do begin
- if Count > 0 then begin
- if integer(Objects[0].Integers['announceState']) in [2, 3] then
- f:=1
- else
- f:=Objects[0].Floats['nextAnnounceTime'];
- end
- else
- f:=0;
- end
- else
- f:=t.Floats['nextAnnounceTime'];
- if f = 0 then
- s:='-'
- else
- if f = 1 then
- s:=sUpdating
- else
- s:=DateTimeToStr(UnixToDateTime(Trunc(f)) + GetTimeZoneDelta);
- txTrackerUpdate.Caption:=s;
- txTracker.Caption:=UTF8Encode(widestring(gTorrents.Items[idxTracker, idx]));
- if RpcObj.RPCVersion >= 7 then
- if t.Arrays['trackerStats'].Count > 0 then
- i:=t.Arrays['trackerStats'].Objects[0].Integers['seederCount']
- else
- i:=-1
- else
- i:=t.Integers['seeders'];
- s:=GetSeedsText(t.Integers['peersSendingToUs'], i);
- txSeeds.Caption:=StringReplace(s, '/', ' ' + sOf + ' ', []) + ' '+ sConnected;
- if RpcObj.RPCVersion >= 7 then
- if t.Arrays['trackerStats'].Count > 0 then
- i:=t.Arrays['trackerStats'].Objects[0].Integers['leecherCount']
- else
- i:=-1
- else
- i:=t.Integers['leechers'];
- s:=GetPeersText(t.Integers['peersGettingFromUs'], -1, i);
- s:=StringReplace(s, ' ', ' '+ sConnected +' ', []);
- s:=StringReplace(s, '/', ' ' + sOf + ' ', []);
- txPeers.Caption:=StringReplace(s, ')', ' '+ sInSwarm+ ')', []);
- txMaxPeers.Caption:=t.Strings['maxConnectedPeers'];
- txLastActive.Caption:=TorrentDateTimeToString(Trunc(t.Floats['activityDate']));
- panTransfer.ChildSizing.Layout:=cclLeftToRightThenTopToBottom;
- panGeneralInfo.ChildSizing.Layout:=cclNone;
- s:=UTF8Encode(widestring(gTorrents.Items[idxName, idx]));
- if RpcObj.RPCVersion >= 4 then
- s:=IncludeProperTrailingPathDelimiter(UTF8Encode(t.Strings['downloadDir'])) + s;
- txTorrentName.Caption:=s;
- s:=Trim(UTF8Encode(t.Strings['creator']));
- if s <> '' then
- s:=' by ' + s;
- txCreated.Caption:=TorrentDateTimeToString(Trunc(t.Floats['dateCreated'])) + s;
- if gTorrents.Items[idxSize, idx] >= 0 then begin
- txTotalSize.Caption:=Format(sDone, [GetHumanSize(t.Floats['totalSize']), GetHumanSize(t.Floats['sizeWhenDone'] - t.Floats['leftUntilDone'])]);
- if t.Floats['totalSize'] = t.Floats['haveValid'] then
- i:=t.Integers['pieceCount']
- else
- i:=Trunc(t.Floats['haveValid']/t.Floats['pieceSize']);
- txPieces.Caption:=Format(sHave, [t.Integers['pieceCount'], GetHumanSize(t.Floats['pieceSize']), i]);
- end
- else begin
- txTotalSize.Caption:='?';
- txPieces.Caption:='?';
- end;
- txHash.Caption:=t.Strings['hashString'];
- txComment.Caption:=UTF8Encode(t.Strings['comment']);
- if (AnsiCompareText(Copy(txComment.Caption, 1, 7), 'http://') = 0)
- or (AnsiCompareText(Copy(txComment.Caption, 1, 8), 'https://') = 0)
- then begin
- if not Assigned(txComment.OnClick) then begin
- txComment.OnClick:=@UrlLabelClick;
- txComment.Cursor:=crHandPoint;
- txComment.Font.Color:=clBlue;
- txComment.Font.Style:=[fsUnderline];
- end;
- end
- else begin
- if Assigned(txComment.OnClick) then begin
- txComment.OnClick:=nil;
- txComment.Cursor:=crDefault;
- txComment.ParentFont:=True;
- end;
- end;
- txAddedOn.Caption:=TorrentDateTimeToString(Trunc(t.Floats['addedDate']));
- txCompletedOn.Caption:=TorrentDateTimeToString(Trunc(t.Floats['doneDate']));
- panGeneralInfo.ChildSizing.Layout:=cclLeftToRightThenTopToBottom;
- DetailsUpdated;
- end;
- procedure TMainForm.FillTrackersList(TrackersData: TJSONObject);
- var
- i, tidx, row: integer;
- id: integer;
- d: TJSONData;
- t: TJSONObject;
- f: double;
- s: string;
- Trackers, TrackerStats: TJSONArray;
- WasEmpty, NoInfo: boolean;
- begin
- if TrackersData = nil then begin
- ClearDetailsInfo;
- exit;
- end;
- Trackers:=TrackersData.Arrays['trackers'];
- if RpcObj.RPCVersion >= 7 then
- TrackerStats:=TrackersData.Arrays['trackerStats']
- else
- TrackerStats:=nil;
- tidx:=gTorrents.Items.IndexOf(idxTorrentId, TrackersData.Integers['id']);
- if tidx = -1 then begin
- ClearDetailsInfo;
- exit;
- end;
- i:=gTorrents.Items[idxStatus, tidx];
- NoInfo:=(i = TR_STATUS_STOPPED) or (i = TR_STATUS_FINISHED);
- WasEmpty:=lvTrackers.Items.Count = 0;
- lvTrackers.Items.BeginUpdate;
- try
- lvTrackers.Enabled:=True;
- lvTrackers.Color:=clWindow;
- for i:=0 to lvTrackers.Items.Count - 1 do
- lvTrackers.Items[idxTrackerTag, i]:=0;
- lvTrackers.Items.Sort(idxTrackerID);
- for i:=0 to Trackers.Count - 1 do begin
- d:=Trackers[i];
- if not (d is TJSONObject) then continue;
- t:=d as TJSONObject;
- if t.IndexOfName('id') >= 0 then
- id:=t.Integers['id']
- else
- id:=i;
- if not lvTrackers.Items.Find(idxTrackerID, id, row) then
- lvTrackers.Items.InsertRow(row);
- lvTrackers.Items[idxTrackerID, row]:=id;
- lvTrackers.Items[idxTrackersListName, row]:=t.Strings['announce'];
- if NoInfo then begin
- lvTrackers.Items[idxTrackersListStatus, row]:=NULL;
- lvTrackers.Items[idxTrackersListSeeds, row]:=NULL;
- f:=0;
- end
- else
- if TrackerStats <> nil then begin
- f:=0;
- if i < TrackerStats.Count then
- with TrackerStats.Objects[i] do begin
- s:='';
- if integer(Integers['announceState']) in [2, 3] then
- s:=sTrackerUpdating
- else
- if Booleans['hasAnnounced'] then
- if Booleans['lastAnnounceSucceeded'] then
- s:=sTrackerWorking
- else
- s:=TranslateString(UTF8Encode(Strings['lastAnnounceResult']), True);
- if s = 'Success' then
- s:=sTrackerWorking;
- lvTrackers.Items[idxTrackersListStatus, row]:=UTF8Decode(s);
- lvTrackers.Items[idxTrackersListSeeds, row]:=Integers['seederCount'];
- if integer(Integers['announceState']) in [2, 3] then
- f:=1
- else
- f:=Floats['nextAnnounceTime'];
- end;
- end
- else begin
- if i = 0 then begin
- lvTrackers.Items[idxTrackersListStatus, row]:=gTorrents.Items[idxTrackerStatus, tidx];
- lvTrackers.Items[idxTrackersListSeeds, row]:=gTorrents.Items[idxSeedsTotal, tidx];
- end;
- f:=TrackersData.Floats['nextAnnounceTime'];
- end;
- if f > 1 then begin
- f:=(UnixToDateTime(Trunc(f)) + GetTimeZoneDelta - Now)*SecsPerDay;
- if f < 0 then
- f:=0;
- end;
- if (TrackerStats <> nil) or (i = 0) then
- lvTrackers.Items[idxTrackersListUpdateIn, row]:=f;
- lvTrackers.Items[idxTrackerTag, row]:=1;
- end;
- i:=0;
- while i < lvTrackers.Items.Count do
- if lvTrackers.Items[idxTrackerTag, i] = 0 then
- lvTrackers.Items.Delete(i)
- else
- Inc(i);
- lvTrackers.Sort;
- if WasEmpty and (lvTrackers.Items.Count > 0) then
- lvTrackers.Row:=0;
- finally
- lvTrackers.Items.EndUpdate;
- end;
- DetailsUpdated;
- end;
- procedure TMainForm.FillSessionInfo(s: TJSONObject);
- var
- d, u: integer;
- begin
- {$ifdef LCLcarbon}
- TrayIcon.Tag:=0;
- {$endif LCLcarbon}
- if RpcObj.RPCVersion < 14 then begin
- TR_STATUS_STOPPED:=TR_STATUS_STOPPED_1;
- TR_STATUS_CHECK_WAIT:=TR_STATUS_CHECK_WAIT_1;
- TR_STATUS_CHECK:=TR_STATUS_CHECK_1;
- TR_STATUS_DOWNLOAD_WAIT:=-1;
- TR_STATUS_DOWNLOAD:=TR_STATUS_DOWNLOAD_1;
- TR_STATUS_SEED_WAIT:=-1;
- TR_STATUS_SEED:=TR_STATUS_SEED_1;
- end
- else begin
- TR_STATUS_STOPPED:=TR_STATUS_STOPPED_2;
- TR_STATUS_CHECK_WAIT:=TR_STATUS_CHECK_WAIT_2;
- TR_STATUS_CHECK:=TR_STATUS_CHECK_2;
- TR_STATUS_DOWNLOAD_WAIT:=TR_STATUS_DOWNLOAD_WAIT_2;
- TR_STATUS_DOWNLOAD:=TR_STATUS_DOWNLOAD_2;
- TR_STATUS_SEED_WAIT:=TR_STATUS_SEED_WAIT_2;
- TR_STATUS_SEED:=TR_STATUS_SEED_2;
- end;
- UpdateUIRpcVersion(RpcObj.RPCVersion);
- if RpcObj.RPCVersion >= 5 then begin
- {$ifdef LCLcarbon}
- if acAltSpeed.Checked <> (s.Integers['alt-speed-enabled'] <> 0) then
- TrayIcon.Tag:=1;
- {$endif LCLcarbon}
- acAltSpeed.Checked:=s.Integers['alt-speed-enabled'] <> 0;
- acUpdateBlocklist.Tag:=s.Integers['blocklist-enabled'];
- acUpdateBlocklist.Enabled:=acUpdateBlocklist.Tag <> 0;
- end;
- if s.IndexOfName('download-dir-free-space') >= 0 then
- StatusBar.Panels[3].Text:=Format(SFreeSpace, [GetHumanSize(s.Floats['download-dir-free-space'])]);
- if (RpcObj.RPCVersion >= 5) and acAltSpeed.Checked then begin
- d:=s.Integers['alt-speed-down'];
- u:=s.Integers['alt-speed-up']
- end
- else begin
- if s.Integers['speed-limit-down-enabled'] <> 0 then
- d:=s.Integers['speed-limit-down']
- else
- d:=-1;
- if s.Integers['speed-limit-up-enabled'] <> 0 then
- u:=s.Integers['speed-limit-up']
- else
- u:=-1;
- end;
- {$ifdef LCLcarbon}
- UpdateUI;
- {$endif LCLcarbon}
- if (FCurDownSpeedLimit <> d) or (FCurUpSpeedLimit <> u) then begin
- FCurDownSpeedLimit:=d;
- FCurUpSpeedLimit:=u;
- FillSpeedsMenu;
- end;
- {$ifdef LCLcarbon}
- if TrayIcon.Tag <> 0 then
- TrayIcon.InternalUpdate;
- {$endif LCLcarbon}
- end;
- procedure TMainForm.FillStatistics(s: TJSONObject);
- procedure _Fill(idx: integer; s: TJSONObject);
- begin
- with gStats do begin
- Items[idx, 0]:=UTF8Decode(GetHumanSize(s.Floats['downloadedBytes']));
- Items[idx, 1]:=UTF8Decode(GetHumanSize(s.Floats['uploadedBytes']));
- Items[idx, 2]:=s.Integers['filesAdded'];
- Items[idx, 3]:=UTF8Decode(SecondsToString(s.Integers['secondsActive']));
- end;
- end;
- begin
- if RpcObj.RPCVersion < 4 then
- exit;
- if s = nil then begin
- ClearDetailsInfo;
- exit;
- end;
- gStats.BeginUpdate;
- try
- gStats.Enabled:=True;
- gStats.Color:=clWindow;
- _Fill(1, s.Objects['current-stats']);
- _Fill(2, s.Objects['cumulative-stats']);
- finally
- gStats.EndUpdate;
- end;
- DetailsUpdated;
- end;
- procedure TMainForm.CheckStatus(Fatal: boolean);
- var
- s: string;
- i: integer;
- begin
- with MainForm do begin
- s:=RpcObj.Status;
- if s <> '' then begin
- RpcObj.Status:='';
- if Fatal then
- DoDisconnect;
- ForceAppNormal;
- if Fatal and not RpcObj.Connected and RpcObj.ReconnectAllowed and (FReconnectTimeOut <> -1) then begin
- FReconnectWaitStart:=Now;
- if FReconnectTimeOut < 60 then
- if FReconnectTimeOut < 10 then
- Inc(FReconnectTimeOut, 5)
- else
- Inc(FReconnectTimeOut, 10);
- txConnError.Caption:=s;
- panReconnectFrame.Hide;
- panReconnect.AutoSize:=True;
- CenterReconnectWindow;
- panReconnect.Show;
- panReconnect.BringToFront;
- TickTimerTimer(nil);
- panReconnect.AutoSize:=False;
- panReconnectFrame.Show;
- CenterReconnectWindow;
- end
- else
- MessageDlg(s, mtError, [mbOK], 0);
- end;
- if StatusBar.Panels[0].Text <> RpcObj.InfoStatus then begin
- StatusBar.Panels[0].Text:=RpcObj.InfoStatus;
- TrayIcon.Hint:=RpcObj.InfoStatus;
- if (RpcObj.Connected) and (RpcObj.Http.UserName <> '') then
- FPasswords.Values[FCurConn]:=RpcObj.Http.Password; // Save password to cache
- end;
- if not RpcObj.Connected then
- for i:=1 to StatusBar.Panels.Count - 1 do
- StatusBar.Panels[i].Text:='';
- end;
- end;
- function TMainForm.TorrentAction(const TorrentIds: variant; const AAction: string; args: TJSONObject): boolean;
- var
- req: TJSONObject;
- ids: TJSONArray;
- i: integer;
- begin
- if VarIsEmpty(TorrentIds) then
- exit;
- Application.ProcessMessages;
- AppBusy;
- req:=TJSONObject.Create;
- try
- req.Add('method', AAction);
- if args = nil then
- args:=TJSONObject.Create;
- if not VarIsNull(TorrentIds) then begin
- ids:=TJSONArray.Create;
- if VarIsArray(TorrentIds) then begin
- for i:=VarArrayLowBound(TorrentIds, 1) to VarArrayHighBound(TorrentIds, 1) do
- ids.Add(integer(TorrentIds[i]));
- end
- else
- ids.Add(integer(TorrentIds));
- args.Add('ids', ids);
- end;
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req, False, 30000);
- Result:=args <> nil;
- args.Free;
- finally
- req.Free;
- end;
- if not Result then
- CheckStatus(False)
- else
- DoRefresh(True);
- AppNormal;
- end;
- function TMainForm.SetFilePriority(TorrentId: integer; const Files: array of integer; const APriority: string): boolean;
- function CreateFilesArray: TJSONArray;
- var
- i: integer;
- begin
- Result:=TJSONArray.Create;
- for i:=Low(Files) to High(Files) do
- Result.Add(Files[i]);
- end;
- var
- req, args: TJSONObject;
- begin
- AppBusy;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-set');
- args:=TJSONObject.Create;
- if TorrentId <> 0 then
- args.Add('ids', TJSONArray.Create([TorrentId]));
- if APriority = 'skip' then
- args.Add('files-unwanted', CreateFilesArray)
- else begin
- args.Add('files-wanted', CreateFilesArray);
- args.Add('priority-' + APriority, CreateFilesArray);
- end;
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req, False);
- Result:=args<> nil;
- args.Free;
- finally
- req.Free;
- end;
- if not Result then
- CheckStatus(False)
- else
- DoRefresh;
- AppNormal;
- end;
- function TMainForm.SetCurrentFilePriority(const APriority: string): boolean;
- var
- Files: array of integer;
- i, j, k, level: integer;
- pri: string;
- begin
- if (gTorrents.Items.Count = 0) or (PageInfo.ActivePage <> tabFiles) then exit;
- SetLength(Files, lvFiles.Items.Count);
- pri:=APriority;
- j:=0;
- if APriority <> '' then begin
- // Priority for currently selected rows
- if lvFiles.SelCount = 0 then
- lvFiles.RowSelected[lvFiles.Row]:=True;
- level:=-1;
- for i:=0 to lvFiles.Items.Count - 1 do begin
- k:=FFilesTree.RowLevel[i];
- if k <= level then
- level:=-1;
- if lvFiles.RowSelected[i] or ( (level <> -1) and (k > level) ) then begin
- if FFilesTree.IsFolder(i) then begin
- if level = -1 then
- level:=k;
- end
- else begin
- Files[j]:=FFiles[idxFileId, i];
- Inc(j);
- end;
- end;
- end;
- end
- else begin
- // Priority based on checkbox state
- for i:=0 to FFiles.Count - 1 do
- if not FFilesTree.IsFolder(i) then begin
- k:=FFiles[idxFilePriority, i];
- if (k <> TR_PRI_SKIP) <> (FFilesTree.Checked[i] = cbChecked) then begin
- if pri = '' then
- if FFilesTree.Checked[i] = cbChecked then
- pri:='normal'
- else
- pri:='skip';
- Files[j]:=FFiles[idxFileId, i];
- Inc(j);
- end;
- end;
- end;
- if j = 0 then exit;
- SetLength(Files, j);
- Result:=SetFilePriority(RpcObj.CurTorrentId, Files, pri);
- end;
- procedure TMainForm.SetTorrentPriority(APriority: integer);
- var
- args: TJSONObject;
- begin
- if gTorrents.Items.Count = 0 then exit;
- args:=TJSONObject.Create;
- args.Add('bandwidthPriority', TJSONIntegerNumber.Create(APriority));
- TorrentAction(GetSelectedTorrents, 'torrent-set', args);
- end;
- procedure TMainForm.ProcessPieces(const Pieces: string; PieceCount: integer; const Done: double);
- const
- MaxPieces = 4000;
- var
- i, j, k, x, xx: integer;
- s: string;
- R: TRect;
- bmp: TBitmap;
- c: double;
- begin
- FLastPieces:=Pieces;
- FLastPieceCount:=PieceCount;
- FLastDone:=Done;
- bmp:=nil;
- try
- if FTorrentProgress = nil then
- FTorrentProgress:=TBitmap.Create;
- if RpcObj.RPCVersion >= 5 then begin
- bmp:=TBitmap.Create;
- if PieceCount > MaxPieces then begin
- bmp.Width:=MaxPieces;
- c:=MaxPieces/PieceCount;
- end
- else begin
- bmp.Width:=PieceCount;
- c:=1;
- end;
- bmp.Height:=12;
- bmp.Canvas.Brush.Color:=clWindow;
- bmp.Canvas.FillRect(0, 0, bmp.Width, bmp.Height);
- bmp.Canvas.Brush.Color:=clHighlight;
- x:=0;
- s:=DecodeBase64(Pieces);
- for i:=1 to Length(s) do begin
- j:=byte(s[i]);
- for k:=1 to 8 do begin
- if PieceCount = 0 then
- break;
- if j and $80 <> 0 then begin
- xx:=Trunc(x*c);
- bmp.Canvas.FillRect(xx, 0, xx + 1, bmp.Height);
- end;
- Inc(x);
- j:=j shl 1;
- Dec(PieceCount);
- end;
- end;
- end;
- with FTorrentProgress.Canvas do begin
- FTorrentProgress.Width:=pbDownloaded.ClientWidth;
- if bmp <> nil then begin
- i:=bmp.Height div 3;
- FTorrentProgress.Height:=bmp.Height + 5 + i;
- Brush.Color:=clWindow;
- FillRect(0, 0, FTorrentProgress.Width, FTorrentProgress.Height);
- Brush.Color:=clBtnShadow;
- R:=Rect(0, i + 3, FTorrentProgress.Width, FTorrentProgress.Height);
- FillRect(R);
- InflateRect(R, -1, -1);
- if bmp.Width > 0 then
- StretchDraw(R, bmp)
- else begin
- Brush.Color:=clWindow;
- FillRect(R);
- end;
- R:=Rect(0, 0, FTorrentProgress.Width, i + 2);
- end
- else begin
- FTorrentProgress.Height:=14;
- R:=Rect(0, 0, FTorrentProgress.Width, FTorrentProgress.Height);
- end;
- Brush.Color:=clBtnShadow;
- FillRect(R);
- InflateRect(R, -1, -1);
- x:=R.Left + Round((R.Right - R.Left)*Done/100.0);
- Brush.Color:=clHighlight;
- FillRect(R.Left, R.Top, x, R.Bottom);
- Brush.Color:=clWindow;
- FillRect(x, R.Top, R.Right, R.Bottom);
- end;
- if pbDownloaded.Height <> FTorrentProgress.Height then begin
- pbDownloaded.Constraints.MaxHeight:=FTorrentProgress.Height;
- pbDownloaded.Height:=FTorrentProgress.Height;
- panProgress.AutoSize:=True;
- panProgress.AutoSize:=False;
- end;
- pbDownloaded.Invalidate;
- finally
- bmp.Free;
- end;
- end;
- function TMainForm.ExecRemoteFile(const FileName: string; SelectFile: boolean): boolean;
- procedure _Exec(s: string);
- var
- p: string;
- begin
- AppBusy;
- if SelectFile then
- if FileExistsUTF8(s) then begin
- {$ifdef mswindows}
- { Commented by Antekgla
- p:=Format('/select,"%s"', [s]);
- s:='explorer.exe';
- End Commented by Antekgla }
- // Added by Antekgla
- p:=Format(FFileManagerDefaultParam, [s]);
- s:=FFileManagerDefault;
- //End Added by Antekgla
- {$else}
- p:='';
- s:=ExtractFilePath(s);
- {$endif mswindows}
- end
- else begin
- p:='';
- s:=ExtractFilePath(s);
- end;
- Result:=OpenURL(s, p);
- AppNormal;
- if not Result then begin
- ForceAppNormal;
- MessageDlg(Format(sUnableToExecute, [s]), mtError, [mbOK], 0);
- end;
- end;
- var
- s: string;
- begin
- s:=MapRemoteToLocal(FileName);
- if s <> '' then begin
- _Exec(s);
- exit;
- end;
- if FileExistsUTF8(FileName) or DirectoryExistsUTF8(FileName) then begin
- _Exec(FileName);
- exit;
- end;
- ForceAppNormal;
- MessageDlg(sNoPathMapping, mtInformation, [mbOK], 0);
- end;
- function TMainForm.GetSelectedTorrents: variant;
- var
- i, j: integer;
- begin
- with gTorrents do begin
- if Items.Count = 0 then begin
- Result:=Unassigned;
- exit;
- end;
- if SelCount = 0 then
- Result:=VarArrayOf([Items[idxTorrentId, Row]])
- else begin
- Result:=VarArrayCreate([0, SelCount - 1], varinteger);
- j:=0;
- for i:=0 to gTorrents.Items.Count - 1 do
- if gTorrents.RowSelected[i] then begin
- Result[j]:=Items[idxTorrentId, i];
- Inc(j);
- end;
- end;
- end;
- end;
- procedure TMainForm.FillDownloadDirs(CB: TComboBox; const CurFolderParam: string);
- var
- i, j: integer;
- s, IniSec: string;
- begin
- CB.Items.Clear;
- IniSec:='AddTorrent.' + FCurConn;
- j:=Ini.ReadInteger(IniSec, 'FolderCount', 0);
- for i:=0 to j - 1 do begin
- s:=Ini.ReadString(IniSec, Format('Folder%d', [i]), '');
- if s <> '' then
- CB.Items.Add(s);
- end;
- s:=Ini.ReadString(IniSec, CurFolderParam, '');
- if s <> '' then begin
- i:=CB.Items.IndexOf(s);
- if i > 0 then
- CB.Items.Move(i, 0);
- end;
- if CB.Items.Count > 0 then
- CB.ItemIndex:=0;
- end;
- procedure TMainForm.SaveDownloadDirs(CB: TComboBox; const CurFolderParam: string);
- var
- i: integer;
- IniSec: string;
- begin
- IniSec:='AddTorrent.' + FCurConn;
- i:=CB.Items.IndexOf(CB.Text);
- if i >= 0 then
- CB.Items.Move(i, 0)
- else
- CB.Items.Insert(0, CB.Text);
- i:=Ini.ReadInteger('Interface', 'MaxFoldersHistory', 10);
- while CB.Items.Count > i do
- CB.Items.Delete(CB.Items.Count - 1);
- Ini.WriteInteger(IniSec, 'FolderCount', CB.Items.Count);
- for i:=0 to CB.Items.Count - 1 do
- Ini.WriteString(IniSec, Format('Folder%d', [i]), CB.Items[i]);
- Ini.WriteString(IniSec, CurFolderParam, CB.Items[0]);
- Ini.UpdateFile;
- end;
- procedure TMainForm.SetRefreshInterval;
- var
- i: TDateTime;
- begin
- if Visible and (WindowState <> wsMinimized) then
- i:=Ini.ReadInteger('Interface', 'RefreshInterval', 5)
- else
- i:=Ini.ReadInteger('Interface', 'RefreshIntervalMin', 20);
- if i < 1 then
- i:=1;
- RpcObj.RefreshInterval:=i/SecsPerDay;
- end;
- procedure TMainForm.AddTracker(EditMode: boolean);
- var
- req, args: TJSONObject;
- id, torid: integer;
- begin
- AppBusy;
- with TAddTrackerForm.Create(Self) do
- try
- id:=0;
- torid:=RpcObj.CurTorrentId;
- if EditMode then begin
- Caption:=STrackerProps;
- edTracker.Text:=UTF8Encode(widestring(lvTrackers.Items[idxTrackersListName, lvTrackers.Row]));
- id:=lvTrackers.Items[idxTrackerID, lvTrackers.Row];
- end;
- AppNormal;
- if ShowModal = mrOk then begin
- AppBusy;
- Self.Update;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'torrent-set');
- args:=TJSONObject.Create;
- args.Add('ids', TJSONArray.Create([torid]));
- if EditMode then
- args.Add('trackerReplace', TJSONArray.Create([id, UTF8Decode(edTracker.Text)]))
- else
- args.Add('trackerAdd', TJSONArray.Create([UTF8Decode(edTracker.Text)]));
- req.Add('arguments', args);
- args:=nil;
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- finally
- req.Free;
- end;
- DoRefresh;
- AppNormal;
- end;
- finally
- Free;
- end;
- end;
- procedure TMainForm.UpdateConnections;
- var
- i, j, cnt: integer;
- s, cur: string;
- mi: TMenuItem;
- begin
- while (pmConnections.Items.Count > 0) and (pmConnections.Items[0].Tag = 0) do
- pmConnections.Items[0].Free;
- while (miConnect.Count > 0) and (miConnect.Items[0].Tag = 0) do
- miConnect.Items[0].Free;
- cur:=Ini.ReadString('Hosts', 'CurHost', '');
- cnt:=Ini.ReadInteger('Hosts', 'Count', 0);
- j:=0;
- for i:=1 to cnt do begin
- s:=Ini.ReadString('Hosts', Format('Host%d', [i]), '');
- if s <> '' then begin
- mi:=TMenuItem.Create(pmConnections);
- mi.Caption:=s;
- if s = cur then
- mi.Checked:=True;
- mi.OnClick:=@DoConnectToHost;
- pmConnections.Items.Insert(j, mi);
- mi:=TMenuItem.Create(miConnect);
- mi.Caption:=s;
- if s = cur then
- mi.Checked:=True;
- mi.OnClick:=@DoConnectToHost;
- miConnect.Insert(j, mi);
- Inc(j);
- end;
- end;
- sepCon1.Visible:=j > 0;
- sepCon2.Visible:=j > 0;
- end;
- procedure TMainForm.DoConnectToHost(Sender: TObject);
- var
- mi: TMenuItem;
- begin
- mi:=TMenuItem(Sender);
- if RpcObj.Connected and (FCurConn = mi.Caption) then
- exit;
- DoDisconnect;
- FReconnectTimeOut:=-1;
- FCurConn:=mi.Caption;
- DoConnect;
- end;
- procedure TMainForm.DoSetDownloadSpeed(Sender: TObject);
- begin
- SetSpeedLimit('down', TMenuItem(Sender).Tag);
- end;
- procedure TMainForm.DoSetUploadSpeed(Sender: TObject);
- begin
- SetSpeedLimit('up', TMenuItem(Sender).Tag);
- end;
- procedure TMainForm.SetSpeedLimit(const Dir: string; Speed: integer);
- var
- req, args: TJSONObject;
- begin
- AppBusy;
- req:=TJSONObject.Create;
- try
- req.Add('method', 'session-set');
- args:=TJSONObject.Create;
- args.Add(Format('speed-limit-%s-enabled', [Dir]), integer(Speed >= 0) and 1);
- if Speed >= 0 then
- args.Add(Format('speed-limit-%s', [Dir]), Speed);
- args.Add('alt-speed-enabled', 0);
- req.Add('arguments', args);
- args:=RpcObj.SendRequest(req, False);
- if args = nil then begin
- CheckStatus(False);
- exit;
- end;
- args.Free;
- finally
- req.Free;
- end;
- RpcObj.RefreshNow:=RpcObj.RefreshNow + [rtSession];
- AppNormal;
- end;
- function TMainForm.FixSeparators(const p: string): string;
- begin
- Result:=StringReplace(p, '/', DirectorySeparator, [rfReplaceAll]);
- Result:=StringReplace(Result, '\', DirectorySeparator, [rfReplaceAll]);
- end;
- function TMainForm.MapRemoteToLocal(const RemotePath: string): string;
- var
- i, j: integer;
- s, ss, fn: string;
- begin
- Result:='';
- fn:=FixSeparators(Trim(RemotePath));
- for i:=0 to FPathMap.Count - 1 do begin
- s:=FPathMap[i];
- j:=Pos('=', s);
- if j > 0 then begin
- ss:=FixSeparators(Copy(s, 1, j - 1));
- if (ss = fn) or (Pos(IncludeProperTrailingPathDelimiter(ss), fn) = 1) then begin
- if ss = fn then
- ss:=Copy(s, j + 1, MaxInt)
- else begin
- ss:=IncludeProperTrailingPathDelimiter(ss);
- ss:=IncludeTrailingPathDelimiter(Copy(s, j + 1, MaxInt)) + Copy(fn, Length(ss) + 1, MaxInt);
- end;
- Result:=FixSeparators(ss);
- exit;
- end;
- end;
- end;
- end;
- procedure TMainForm.UpdateUIRpcVersion(RpcVersion: integer);
- var
- vc: boolean;
- begin
- acRemoveTorrentAndData.Visible:=RPCVersion >= 4;
- acReannounceTorrent.Visible:=RPCVersion >= 5;
- acUpdateBlocklist.Visible:=RPCVersion >= 5;
- acMoveTorrent.Visible:=RPCVersion >= 6;
- pmiPriority.Visible:=RPCVersion >= 5;
- miPriority.Visible:=pmiPriority.Visible;
- acOpenContainingFolder.Visible:=RPCVersion >= 4;
- acOpenFile.Visible:=acOpenContainingFolder.Visible;
- pmSepOpen1.Visible:=acOpenContainingFolder.Visible;
- pmSepOpen2.Visible:=acOpenContainingFolder.Visible;
- vc:=not sepAltSpeed.Visible and (RPCVersion >= 5);
- sepAltSpeed.Visible:=RPCVersion >= 5;
- acAltSpeed.Visible:=RPCVersion >= 5;
- if vc then begin
- sepAltSpeed.Left:=tbStopTorrent.Left + 1;
- tbtAltSpeed.Left:=sepAltSpeed.Left + 1;
- end;
- acAddTracker.Visible:=RPCVersion >= 10;
- acEditTracker.Visible:=acAddTracker.Visible;
- acDelTracker.Visible:=acAddTracker.Visible;
- acAdvEditTrackers.Visible:=acAddTracker.Visible;
- sepTrackers.Visible:=acAddTracker.Visible;
- vc:=not sepQueue.Visible and (RPCVersion >= 14);
- sepQueue.Visible:=RPCVersion >= 14;
- acQMoveUp.Visible:=RPCVersion >= 14;
- acQMoveDown.Visible:=RPCVersion >= 14;
- miQueue.Visible:=RPCVersion >= 14;
- pmiQueue.Visible:=RPCVersion >= 14;
- if vc then begin
- sepQueue.Left:=tbStopTorrent.Left + 1;
- tbQMoveUp.Left:=sepQueue.Left + 1;
- tbQMoveDown.Left:=tbQMoveUp.Left + 1;
- end;
- acForceStartTorrent.Visible:=RPCVersion >= 14;
- tabStats.Visible:=RpcVersion >= 4;
- acRename.Visible:=RpcVersion >= 15;
- end;
- procedure TMainForm.CheckAddTorrents;
- var
- i: integer;
- h: System.THandle;
- s: string;
- WasHidden: boolean;
- begin
- h:=FileOpenUTF8(FIPCFileName, fmOpenRead or fmShareDenyWrite);
- if h <> System.THandle(-1) then begin
- i:=FileSeek(h, 0, soFromEnd);
- SetLength(s, i);
- if i > 0 then begin
- FileSeek(h, 0, soFromBeginning);
- SetLength(s, FileRead(h, s[1], i));
- end;
- FileTruncate(h, 0);
- FileClose(h);
- DeleteFileUTF8(FIPCFileName);
- if s = '' then begin
- ShowApp;
- exit;
- end;
- FPendingTorrents.Text:=FPendingTorrents.Text + s;
- end;
- if FAddingTorrent <> 0 then
- exit;
- Inc(FAddingTorrent);
- try
- if FPendingTorrents.Count > 0 then begin
- Application.ProcessMessages;
- TickTimer.Enabled:=True;
- WasHidden:=not IsTaskbarButtonVisible;
- if WasHidden then
- Application.BringToFront
- else
- ShowApp;
- try
- while FPendingTorrents.Count > 0 do begin
- s:=FPendingTorrents[0];
- FPendingTorrents.Delete(0);
- if s <> '' then
- DoAddTorrent(s);
- end;
- finally
- if WasHidden then
- HideTaskbarButton;
- end;
- end;
- finally
- Dec(FAddingTorrent);
- end;
- end;
- procedure TMainForm.CheckClipboardLink;
- const
- strTorrentExt = '.torrent';
- var
- s: string;
- begin
- try
- if not FLinksFromClipboard then
- exit;
- s:=Clipboard.AsText;
- if s = FLastClipboardLink then
- exit;
- FLastClipboardLink:=s;
- if not IsProtocolSupported(s) then
- exit;
- if (Pos('magnet:', UTF8LowerCase(s)) <> 1) and (UTF8LowerCase(Copy(s, Length(s) - Length(strTorrentExt) + 1, MaxInt)) <> strTorrentExt) then
- exit;
- AddTorrentFile(s);
- Clipboard.AsText:='';
- except
- // Turn off this function if an error occurs
- FLinksFromClipboard:=False;
- end;
- end;
- procedure TMainForm.CenterDetailsWait;
- begin
- panDetailsWait.Left:=PageInfo.Left + (PageInfo.Width - panDetailsWait.Width) div 2;
- panDetailsWait.Top:=PageInfo.Top + (PageInfo.Height - panDetailsWait.Height) div 2;
- end;
- function TMainForm.GetPageInfoType(pg: TTabSheet): TAdvInfoType;
- begin
- if pg = tabGeneral then
- Result:=aiGeneral
- else
- if pg = tabPeers then
- Result:=aiPeers
- else
- if pg = tabFiles then
- Result:=aiFiles
- else
- if pg = tabTrackers then
- Result:=aiTrackers
- else
- if pg = tabStats then
- Result:=aiStats
- else
- Result:=aiNone;
- end;
- procedure TMainForm.DetailsUpdated;
- begin
- FDetailsWaitStart:=0;
- PageInfo.ActivePage.Tag:=0;
- end;
- function TMainForm.RenameTorrent(TorrentId: integer; const OldPath, NewName: string): boolean;
- var
- args: TJSONObject;
- begin
- Result:=False;
- if ExtractFileName(OldPath) = NewName then
- exit;
- args:=TJSONObject.Create;
- args.Add('path', UTF8Decode(OldPath));
- args.Add('name', UTF8Decode(NewName));
- Result:=TorrentAction(TorrentId, 'torrent-rename-path', args);
- end;
- procedure TMainForm.FilesTreeStateChanged(Sender: TObject);
- begin
- SetCurrentFilePriority('');
- end;
- function TMainForm.SelectTorrent(TorrentId, TimeOut: integer): integer;
- var
- tt: TDateTime;
- br: boolean;
- begin
- Result:=-1;
- if TorrentId = 0 then
- exit;
- br:=False;
- tt:=Now;
- while True do begin
- Application.ProcessMessages;
- Result:=gTorrents.Items.IndexOf(idxTorrentId, TorrentId);
- if Result >= 0 then begin
- gTorrents.RemoveSelection;
- gTorrents.Row:=Result;
- RpcObj.CurTorrentId:=TorrentId;
- if Self.Visible and (Self.WindowState <> wsMinimized) and gTorrents.Enabled then
- Self.ActiveControl:=gTorrents;
- break;
- end;
- if br then
- break;
- Sleep(100);
- if Now - tt >= TimeOut/MSecsPerDay then
- br:=True;
- end;
- end;
- procedure TMainForm.OpenCurrentTorrent(OpenFolderOnly: boolean);
- var
- res: TJSONObject;
- p, s: string;
- sel: boolean;
- files: TJSONArray;
- begin
- if gTorrents.Items.Count = 0 then
- exit;
- Application.ProcessMessages;
- AppBusy;
- try
- sel:=False;
- gTorrents.RemoveSelection;
- res:=RpcObj.RequestInfo(gTorrents.Items[idxTorrentId, gTorrents.Row], ['files', 'downloadDir']);
- if res = nil then
- CheckStatus(False)
- else
- try
- with res.Arrays['torrents'].Objects[0] do begin
- files:=Arrays['files'];
- if files.Count = 0 then exit;
- if files.Count = 1 then begin
- p:=UTF8Encode((files[0] as TJSONObject).Strings['name']);
- sel:=OpenFolderOnly;
- end
- else begin
- s:=GetFilesCommonPath(files);
- repeat
- p:=s;
- s:=ExtractFilePath(p);
- until (s = '') or (s = p);
- end;
- p:=IncludeTrailingPathDelimiter(UTF8Encode(Strings['downloadDir'])) + p;
- end;
- finally
- res.Free;
- end;
- ExecRemoteFile(p, sel);
- finally
- AppNormal;
- end;
- end;
- procedure TMainForm.FillSpeedsMenu;
- procedure _FillMenu(Items: TMenuItem; const Speeds: string; OnClickHandler: TNotifyEvent; CurSpeed: integer);
- var
- sl: TStringList;
- i, j: integer;
- mi: TMenuItem;
- begin
- Items.Clear;
- if not RpcObj.Connected then
- exit;
- sl:=TStringList.Create;
- try
- sl.Delimiter:=',';
- sl.DelimitedText:=Speeds;
- i:=0;
- while i < sl.Count do begin
- j:=StrToIntDef(Trim(sl[i]), -1);
- if j >= 0 then begin
- sl[i]:=Format('%.08d', [j]);
- Inc(i);
- end
- else
- sl.Delete(i);
- end;
- sl.Duplicates:=dupIgnore;
- sl.Sorted:=True;
- sl.Add(Format('%.08d', [CurSpeed]));
- for i:=0 to sl.Count - 1 do begin
- j:=StrToIntDef(Trim(sl[i]), -1);
- if j >= 0 then begin
- mi:=TMenuItem.Create(Items);
- mi.Caption:=Format('%d %s%s', [j, sKByte, sPerSecond]);
- mi.Tag:=j;
- mi.OnClick:=OnClickHandler;
- if j = CurSpeed then
- mi.Checked:=True;
- Items.Insert(0, mi);
- end;
- end;
- finally
- sl.Free;
- end;
- if Items.Count > 0 then begin
- mi:=TMenuItem.Create(Items);
- mi.Caption:='-';
- Items.Insert(0, mi);
- end;
- mi:=TMenuItem.Create(Items);
- mi.Caption:=SUnlimited;
- mi.Tag:=-1;
- mi.OnClick:=OnClickHandler;
- if CurSpeed = -1 then
- mi.Checked:=True;
- Items.Insert(0, mi);
- end;
- var
- s: string;
- begin
- s:=Ini.ReadString('Connection.' + FCurConn, 'DownSpeeds', DefSpeeds);
- _FillMenu(pmDownSpeeds.Items, s, @DoSetDownloadSpeed, FCurDownSpeedLimit);
- _FillMenu(pmiDownSpeedLimit, s, @DoSetDownloadSpeed, FCurDownSpeedLimit);
- s:=Ini.ReadString('Connection.' + FCurConn, 'UpSpeeds', DefSpeeds);
- _FillMenu(pmUpSpeeds.Items, s, @DoSetUploadSpeed, FCurUpSpeedLimit);
- _FillMenu(pmiUpSpeedLimit, s, @DoSetUploadSpeed, FCurUpSpeedLimit);
- {$ifdef LCLcarbon}
- TrayIcon.InternalUpdate;
- {$endif LCLcarbon}
- end;
- initialization
- {$I main.lrs}
- finalization
- try
- FreeAndNil(Ini);
- except
- end;
- end.
Add Comment
Please, Sign In to add comment