Skip to content

Commit 835e2e8

Browse files
committed
added more control for audio player: next/prev/shuffle/volume, added info about tracks that are converting
1 parent cdf777e commit 835e2e8

File tree

16 files changed

+230
-28
lines changed

16 files changed

+230
-28
lines changed

app.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func (state *AppState) telegramShareTracks(restart chan<- int) error {
235235
func (state *AppState) convertToMp3(restart chan<- int) error {
236236
if !state.Config.ConvertToMp3 {
237237
// if option is not enabled restart check after 30s
238-
time.Sleep(30 * time.Second)
238+
time.Sleep(10 * time.Second)
239239
restart <- 1
240240
return nil
241241
}
@@ -249,6 +249,9 @@ func (state *AppState) convertToMp3(restart chan<- int) error {
249249

250250
if entry.Type == "track" && entry.Track.Status == TrackStatusDownladed && !entry.Track.IsConvertedToMp3 && plugin.IsTrackFileExists(entry.Track, "webm") {
251251
fmt.Printf("Extracting audio for %s...\n", entry.Track.Name)
252+
entry.Track.ConvertingStatus.Status = TrakcConverting
253+
DbWriteEntry(entry.Track.ID, entry)
254+
state.runtime.Events.Emit("ytd:track", entry)
252255

253256
// ffmpeg -i "41qC3w3UUkU.webm" -vn -ab 128k -ar 44100 -y "41qC3w3UUkU.mp3"
254257
cmd := exec.Command(
@@ -266,7 +269,14 @@ func (state *AppState) convertToMp3(restart chan<- int) error {
266269

267270
if err := cmd.Run(); err != nil {
268271
fmt.Println("Failed to extract audio:", err)
272+
entry.Track.ConvertingStatus.Status = TrakcConvertFailed
273+
entry.Track.ConvertingStatus.Err = err.Error()
274+
entry.Track.ConvertingStatus.Attempts += 1
275+
DbWriteEntry(entry.Track.ID, entry)
276+
state.runtime.Events.Emit("ytd:track", entry)
277+
269278
} else {
279+
entry.Track.ConvertingStatus.Status = TrakcConverted
270280
entry.Track.IsConvertedToMp3 = true
271281
DbWriteEntry(entry.Track.ID, entry)
272282
state.runtime.Events.Emit("ytd:track", entry) // track:converted:mp3
@@ -285,7 +295,7 @@ func (state *AppState) convertToMp3(restart chan<- int) error {
285295
}
286296

287297
// if there are no tracks to convert delay between restart
288-
time.Sleep(30 * time.Second)
298+
time.Sleep(10 * time.Second)
289299
restart <- 1
290300
return nil
291301
}

constants/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ const (
66
TrackStatusFailed = "failed"
77
TrackStatusDownloading = "downloading"
88
TrackStatusDownladed = "downloaded"
9+
TrakcConverting = "converting"
10+
TrakcConverted = "converted"
11+
TrakcConvertFailed = "failed"
912
)

frontend/package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@wailsapp/runtime": "^1.1.1",
2828
"await-to-js": "^3.0.0",
2929
"core-js": "^3.15.1",
30+
"lodash": "^4.17.21",
3031
"ngx-build-plus": "^12.0.1",
3132
"rxjs": "~6.6.0",
3233
"tslib": "^2.2.0",
@@ -37,6 +38,7 @@
3738
"@angular/cli": "~12.1.0",
3839
"@angular/compiler-cli": "~12.1.0",
3940
"@types/jasmine": "~3.6.0",
41+
"@types/lodash": "^4.14.172",
4042
"@types/node": "^12.20.19",
4143
"jasmine-core": "~3.7.0",
4244
"karma": "~6.3.0",

frontend/package.json.md5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
15ba3baba8db13a28cf402c9ac5b016f
1+
d61c72832ec897e773f764f1b6961640

frontend/src/app/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { MatMenuModule } from '@angular/material/menu';
1717
import { MatProgressBarModule } from '@angular/material/progress-bar';
1818
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
1919
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
20+
import { MatSliderModule} from '@angular/material/slider';
2021
import { MatSnackBarModule, MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
2122
import { MatToolbarModule } from '@angular/material/toolbar';
2223
import { NG_EVENT_PLUGINS } from '@tinkoff/ng-event-plugins';
@@ -47,6 +48,7 @@ import { AudioPlayerComponent, SettingsComponent } from './components';
4748
MatProgressBarModule,
4849
MatProgressSpinnerModule,
4950
MatSlideToggleModule,
51+
MatSliderModule,
5052
MatSnackBarModule,
5153
MatToolbarModule
5254
],

frontend/src/app/components/audio-player/audio-player.component.html

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
</div>
1010
<div class="controls" fxFlex fxLayout="column">
1111
<div class="btns" fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="12px">
12-
<mat-icon class="prew clickable">skip_previous</mat-icon>
12+
<mat-icon class="shuffle clickable" title="Shuffle" (click)="shuffle()">shuffle</mat-icon>
13+
<mat-icon class="prew clickable" title="Previous track" (click)="prev()">skip_previous</mat-icon>
1314
<mat-icon class="play clickable" title="Play" [class.disabled]="!isReady()" (click)="play()" *ngIf="!isPlaying">play_arrow</mat-icon>
1415
<mat-icon class="stop clickable" title="Stop" (click)="stop()" *ngIf="isPlaying">stop</mat-icon>
15-
<mat-icon class="next clickable">skip_next</mat-icon>
16+
<mat-icon class="next clickable" title="Next track" (click)="next()">skip_next</mat-icon>
17+
<mat-icon class="replay clickable" title="Replay" (click)="replay()">replay</mat-icon>
1618
</div>
1719
<div class="" fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="8px">
1820
<div class="duration">{{ elapsedTime }}</div>
@@ -21,6 +23,18 @@
2123
<div class="duration">{{ duration * 1000 | date: 'mm:ss' }}</div>
2224
</div>
2325
</div>
24-
<div class="volume"></div>
26+
<div class="volume" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="4px">
27+
<mat-icon>{{ volume === 0 ? 'volume_off' : 'volume_up' }}</mat-icon>
28+
<mat-slider
29+
[max]="1"
30+
[min]="0"
31+
[step]="0.1"
32+
[tickInterval]="0.1"
33+
[value]="volume"
34+
(input)="changeVolume($event)"
35+
[vertical]="false">
36+
</mat-slider>
37+
</div>
38+
<mat-icon class="close-player clickable" (click)="closePlayer()">close</mat-icon>
2539
</ng-container>
2640
</div>

frontend/src/app/components/audio-player/audio-player.component.scss

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
audio-player {
22
.player {
33
width: calc(100% - 32px);
4+
max-width: calc(1024px - 32px);
45
height: 96px;
56
display: flex;
67
background: rgba(0, 0, 0, 0.85);
@@ -16,6 +17,11 @@ audio-player {
1617
z-index: 9999;
1718
color: #fff;
1819

20+
.close-player {
21+
margin-right: -10px;
22+
align-self: flex-start;
23+
}
24+
1925
.name {
2026
max-width: 300px;
2127
width: 300px;
@@ -38,7 +44,21 @@ audio-player {
3844

3945
.controls {
4046
.btns {
41-
margin-bottom: 8px;
47+
margin-bottom: 12px;
48+
}
49+
}
50+
51+
.volume {
52+
.mat-slider {
53+
.mat-slider-track-wrapper {
54+
background: #fff;
55+
}
56+
57+
&:not(.mat-slider.sliding) {
58+
.mat-slider-thumb, .mat-slider-thumb-label {
59+
background-color: #fff;
60+
}
61+
}
4262
}
4363
}
4464
}

frontend/src/app/components/audio-player/audio-player.component.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ import {
44
Component,
55
EventEmitter,
66
HostBinding,
7+
Inject,
78
Input,
89
OnInit,
910
Output,
11+
Renderer2,
1012
ViewEncapsulation,
1113
} from '@angular/core';
1214
import { filter } from 'rxjs/operators'
1315
import { Track } from '@models';
1416
import { AudioPlayerService } from './audio-player.service';
1517
import { SnackbarService } from 'app/services/snackbar.service';
18+
import { MatSliderChange } from '@angular/material/slider';
19+
import { DOCUMENT } from '@angular/common';
1620

1721
@Component({
1822
selector: 'audio-player',
@@ -27,6 +31,8 @@ export class AudioPlayerComponent implements OnInit {
2731

2832
public audio: HTMLAudioElement = null;
2933

34+
public volume: number = 0.5;
35+
3036
public isPlaying: Boolean = false;
3137

3238
public canPlay: Boolean = false;
@@ -45,6 +51,7 @@ export class AudioPlayerComponent implements OnInit {
4551

4652
constructor(
4753
private _cdr: ChangeDetectorRef,
54+
@Inject(DOCUMENT) private document: Document,
4855
private _snackbar: SnackbarService,
4956
private _audioPlayerService: AudioPlayerService
5057
) {}
@@ -73,6 +80,7 @@ export class AudioPlayerComponent implements OnInit {
7380
private _play(track: Track): void {
7481
const src = track.isConvertedToMp3 ? `http://localhost:8080/tracks/youtube/${track.id}.mp3` : `http://localhost:8080/tracks/youtube/${track.id}.webm`;
7582
this.audio = new Audio(src);
83+
this.audio.volume = this.volume;
7684

7785
this.audio.ontimeupdate = (e) => {
7886
const s = parseInt((this.audio.currentTime % 60).toString(), 10);
@@ -116,6 +124,7 @@ export class AudioPlayerComponent implements OnInit {
116124
}
117125

118126
play(): void {
127+
this.document.body.classList.add('player-visible');
119128
this.onPlayAudio.emit();
120129
this.isPlaying = true;
121130
this.audio.play();
@@ -130,10 +139,39 @@ export class AudioPlayerComponent implements OnInit {
130139
this._cdr.detectChanges();
131140
}
132141

142+
changeVolume(event: MatSliderChange): void {
143+
this.volume = event.value;
144+
this.audio.volume = event.value;
145+
}
146+
147+
prev(): void {
148+
this._audioPlayerService.onPrevTrackCmd.next(this.track);
149+
}
150+
151+
next(): void {
152+
this._audioPlayerService.onNextTrackCmd.next(this.track);
153+
}
154+
155+
replay(): void {
156+
this.audio.currentTime = 0;
157+
}
158+
159+
shuffle(): void {
160+
this._audioPlayerService.onShuffleTrackCmd.next(this.track);
161+
}
162+
133163
isReady(): Boolean {
134164
return this.audio && this.audio.readyState === 4;
135165
}
136166

167+
closePlayer(): void {
168+
this.audio.pause();
169+
this._audioPlayerService.onStopCmdTrack.next(this.track);
170+
this.audio = null;
171+
this.track = null;
172+
this.document.body.classList.remove('player-visible');
173+
}
174+
137175
ngOnDestroy(): void {
138176
this.audio.pause();
139177
this.audio = null;

frontend/src/app/components/audio-player/audio-player.service.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@ export class AudioPlayerService {
1717

1818
public onStopCmdTrack: BehaviorSubject<Track>;
1919

20-
public onTrackChanges: BehaviorSubject<string>;
20+
public onPrevTrack: BehaviorSubject<Track>;
21+
22+
public onPrevTrackCmd: BehaviorSubject<Track>;
23+
24+
public onNextTrack: BehaviorSubject<Track>;
25+
26+
public onNextTrackCmd: BehaviorSubject<Track>;
27+
28+
public onShuffleTrack: BehaviorSubject<Track>;
29+
30+
public onShuffleTrackCmd: BehaviorSubject<Track>;
2131

2232
public get trackId(): string {
2333
if(!this.track) {
@@ -27,11 +37,16 @@ export class AudioPlayerService {
2737
}
2838

2939
constructor() {
30-
this.onPlaybackTrack = new BehaviorSubject(null);
31-
this.onPlayCmdTrack = new BehaviorSubject(null);
32-
this.onStopTrack = new BehaviorSubject(null);
33-
this.onStopCmdTrack = new BehaviorSubject(null);
34-
this.onTrackChanges = new BehaviorSubject(null);
40+
this.onPlaybackTrack = new BehaviorSubject(null);
41+
this.onPlayCmdTrack = new BehaviorSubject(null);
42+
this.onStopTrack = new BehaviorSubject(null);
43+
this.onStopCmdTrack = new BehaviorSubject(null);
44+
this.onPrevTrack = new BehaviorSubject(null);
45+
this.onPrevTrackCmd = new BehaviorSubject(null);
46+
this.onNextTrack = new BehaviorSubject(null);
47+
this.onNextTrackCmd = new BehaviorSubject(null);
48+
this.onShuffleTrack = new BehaviorSubject(null);
49+
this.onShuffleTrackCmd = new BehaviorSubject(null);
3550

3651
this.onPlaybackTrack.subscribe(track => {
3752
this.action = 'play';

0 commit comments

Comments
 (0)