Skip to content

Commit

Permalink
Misc fixes (#185)
Browse files Browse the repository at this point in the history
* hacky fix for issue with torrent contents not displaying
- update README with better setup instructions

* view more info for torrent by right-clicking the table row

* update README
  • Loading branch information
bill-ahmed authored Sep 8, 2022
1 parent d7c6ac9 commit c1a435e
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 34 deletions.
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@

A material-themed UI for [qBittorrent](https://github.com/qbittorrent/qBittorrent). This interface is more slimmed down, although still contains several features such as:

* See torrent contents _before_ downloading
* File system navigation (choose where to save a torrents, create sub-folders, etc.)
* Bulk edit (pause, resume, delete, prioritize, and more)
* Sorting by different metrics (name, size, date completed, etc.)
* See torrent contents _before_ downloading
* File system navigation (choose where to save a torrent, create sub-folders, etc.)
* Manage local & qBittorrent preferences
* A fully material-themed UI (Light & Dark themes)
* ... and more!

## Demo!
A live demo is available here: https://qbit-material-webui-demo.herokuapp.com/.
A live demo is available here: https://qbit-material-webui-demo.herokuapp.com/


## Installation
This app is tested with **v4.1.5** and higher of qBittorrent, any lower version are not guaranteed to work.
This app is tested with **v4.3.8** and higher of qBittorrent, any lower version are not guaranteed to work.

### Automatic -- Docker Mods Support!
Thanks to @marzzzello for adding support in LinuxServer.io's qBittorrent container: https://github.com/marzzzello/linuxserver-io-mod-qbit-matui


### Manual
1. Take a production-ready build from [releases](https://github.com/bill-ahmed/qbit-material-WebUI/releases), or [build it yourself](#build)
2. Extract the files into any folder
3. In qBittorrent, under Tools > Options > Web UI > Use alternative Web UI, set the file location as the folder you created in Step 2.
Expand All @@ -32,25 +37,22 @@ This app relies on a couple files to work properly.
Under `src/assets/` there are two files: `config.json` and `config.prod.json`. This will store general configuration, such as the delimeter used when parsing file paths (Unix vs. Windows).

### HTTP Config
If you wish to configure your endpoints and other data for dev/prod, do so here.
If you wish to configure your endpoints and other data for dev/prod, do so in `src/assets/http_config.json`.


## Running the App
To install the dependencies, run `npm install` in both the root directory and the `mock_backend/` folder.
In order to have the most accurate testing environment, we make use of a docker container running qBittorrent. Make
sure you have both Docker and docker-compose installed.

### Back-end
1. Navigate to `mock_backend` directory
2. Run `node index.js`
Checkout the instructions in the `dev/` folder on how to set it up.

### Front-end:
1. Run `ng serve` for a dev server
2. Navigate to `http://localhost:4200/`
3. Username: `admin`; Password: `password`; This can be changed under `mock_backend/config.json`

To run the login page standalone, do: `ng serve login` and navigate to `http://localhost:4200/`.

The app will automatically reload if you make changes to any of the Angular source code.
### Front-end:
1. Run `npm run dev` for a dev server
2. Navigate to `http://localhost:8090/`
3. Username: `admin`; Password: `adminadmin`; This can be changed through the default Web UI.

The app will re-compile everytime you save changes. To see the changes, you must hard-reload the web page (`CTRL + SHIFT + R` on Windows)

## Build

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ <h2 mat-dialog-title>Upload Torrents</h2>
<mat-dialog-content class="mat-typography dialog_content">
<mat-tab-group mat-align-tabs="start" (selectedTabChange)="handleTabChange($event)" [selectedIndex]="currentTab?.index || 0">
<mat-tab label="File Upload">
<div class="file_upload_container">
<div class="file_upload_container" style="padding-top: 25px;">
<br/>

<div [ngClass]="{'dark-theme': isDarkTheme | async}" class="upload_files" appDragAndDropFiles (fileDropped)="updateFiles($event, true)" (click)="torrentFileUpload.click()">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { TorrentDataStoreService } from '../../services/torrent-management/torre
import { FileSystemDialogComponent } from '../file-system-dialog/file-system-dialog.component';
import { ThemeService } from '../../services/theme.service';
import { Observable } from 'rxjs';
import { SerializedNode } from '../../services/file-system/file-system.service';
import {FileSystemService, SerializedNode} from '../../services/file-system/file-system.service';
import { GetDefaultSaveLocation, IsMobileUser } from 'src/utils/Helpers';
import { MatTabChangeEvent } from '@angular/material/tabs';
import { TorrentParserService } from 'src/app/services/torrent-management/torrent-parser.service';
Expand Down Expand Up @@ -45,6 +45,7 @@ export class AddTorrentDialogComponent implements OnInit {

constructor(private appConfig: ApplicationConfigService, private dialogRef:MatDialogRef<AddTorrentDialogComponent>, private data_store: TorrentDataStoreService,
private torrentParser: TorrentParserService, public fileSystemDialog: MatDialog, public snackbar: SnackbarService, private theme: ThemeService,
private fsService: FileSystemService,
@Inject(MAT_DIALOG_DATA) inputData) { this.inputData = inputData }

ngOnInit(): void {
Expand Down Expand Up @@ -221,6 +222,8 @@ export class AddTorrentDialogComponent implements OnInit {
this.fileSystemExplorerDialogREF.afterClosed().subscribe((res: string) => {
// If use confirmed choice of file path
if(res) {
// Hack: Unix-based OS use '/', so we need it to be leading
if (this.fsService.getFileSystemDelimeter() === '/') res = '/' + res
this.filesDestination = res
}
})
Expand Down
2 changes: 0 additions & 2 deletions src/app/services/file-system/FileSystemNodes/Inode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ export default class Inode extends TreeNode implements SerializableNode {
return this.parent.getAbsolutePath(delimiter) + this.value + delimiter;
}

// Hack: Unix-based OS use '/', so we need it to be leading
if (delimiter === '/') return '/' + this.value
return this.value
}

Expand Down
22 changes: 11 additions & 11 deletions src/app/torrents-table/torrents-table.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
[contextMenu]="cm"
[(contextMenuSelection)]="contextMenuSelectedTorrent"

[resizableColumns]="true"
[resizableColumns]="true"
columnResizeMode="expand"
responsiveLayout="scroll"

Expand All @@ -38,18 +38,18 @@
<!-- TABLE HEADER -->
<ng-template pTemplate="header">
<tr>
<th *ngFor="let col of displayedColumns"
[id]="getIdForColumns(col)"
[class]="getClassNameForColumns(col)"
pReorderableColumn
<th *ngFor="let col of displayedColumns"
[id]="getIdForColumns(col)"
[class]="getClassNameForColumns(col)"

pReorderableColumn

pResizableColumn
[pResizableColumnDisabled]="['select', 'Actions'].includes(col)"
[pResizableColumnDisabled]="['select', 'Actions'].includes(col)"

[pSortableColumn]="displayedColumnsMapping[col]"
>

<div style="display: flex;" [ngSwitch]="col">
<!-- Checkbox for selecting ALL torrents -->
<div *ngSwitchCase="'select'">
Expand Down Expand Up @@ -79,7 +79,7 @@
[ngClass]="{selected: isSelected(torrent)}"

(click)="handleTorrentSelected(torrent)"
(contextmenu)="handleTorrentSelected(torrent)"
(contextmenu)="torrentRightClicked = torrent"

[pContextMenuRow]="torrent"
>
Expand Down Expand Up @@ -206,7 +206,7 @@
</button>
</div>
</mat-card-header>

<mat-card-content class="torrent-card-view-content">
<!-- Show tags -->
<mat-card-subtitle style="width: max-content;">
Expand All @@ -233,7 +233,7 @@
<i class="pi pi-arrow-up"></i>&nbsp;: {{getFileSizeString(torrent.upspeed)}}/s
</p>
</div>

<!-- Progress bar -->
<div class="row">
<p-progressBar class="custom_progress_bar {{torrent.progress > 0.5 ? 'white_label' : ''}}"
Expand Down
10 changes: 7 additions & 3 deletions src/app/torrents-table/torrents-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ export class TorrentsTableComponent implements OnInit {
private torrentSearchValue = ""; // Keep track of which torrents are currently selected
private torrentFilterBy: TorrentFilter = { type: '', value: '' };

// When user right-clicks a row in the torrent table, so we can choose what to do with it
public torrentRightClicked: Torrent = null;

constructor(private appConfig: ApplicationConfigService, private data_store: TorrentDataStoreService,
private pp: PrettyPrintTorrentDataService, public deleteTorrentDialog: MatDialog, private infoTorDialog: MatDialog, private moveTorrentDialog: MatDialog,
private torrentSearchService: TorrentSearchServiceService, private filterService: TorrentFilterService, private torrentsSelectedService: RowSelectionService,
private torrentSearchService: TorrentSearchServiceService, private filterService: TorrentFilterService, private torrentsSelectedService: RowSelectionService,
private snackbar: SnackbarService, private theme: ThemeService) { }

ngOnInit(): void {
Expand Down Expand Up @@ -103,6 +106,7 @@ export class TorrentsTableComponent implements OnInit {
});

this.contextMenuItems = [
{ label: 'More Info', icon: 'pi pi-fw pi-info-circle', command: () => this.openInfoTorrentDialog(null, this.torrentRightClicked) },
{ label: 'Pause', icon: 'pi pi-fw pi-pause', command: () => this.pauseTorrentsBulk(this.selection.selected) },
{ label: 'Resume', icon: 'pi pi-fw pi-play', command: () => this.resumeTorrentsBulk(this.selection.selected) },
{ label: 'Force Resume', icon: 'pi pi-fw pi-forward', command: () => this.forceStartTorrentsBulk(this.selection.selected) },
Expand Down Expand Up @@ -215,7 +219,7 @@ export class TorrentsTableComponent implements OnInit {

if(this.torrentFilterBy.type === 'filter_status')
return Constants.TORRENT_STATE_MAPPING[this.torrentFilterBy.value]?.includes(tor.state);

if(this.torrentFilterBy.type === 'filter_tracker')
return this.allTorrentInformation.trackers[this.torrentFilterBy.value].includes(tor.hash)
});
Expand Down Expand Up @@ -306,7 +310,7 @@ export class TorrentsTableComponent implements OnInit {
this.colWidths = this.appConfig.getWebUISettings().torrent_table.column_widths;
this.updateTorrentData(this.allTorrentInformation);
}

/** Determine whether a torrent is selected or not */
isSelected(tor: Torrent): boolean {
return this.selection.isSelected(tor);
Expand Down

0 comments on commit c1a435e

Please sign in to comment.