Skip to content

Commit 91cd5bd

Browse files
committed
Changed wording around Playlists to be Queue. Added automatic logout if user get 401 error code. Fixes issues #7 and #9
1 parent 7686a05 commit 91cd5bd

File tree

14 files changed

+137
-81
lines changed

14 files changed

+137
-81
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</p>
88

99
## About
10-
A stylish, cross-platform desktop client for listening to music from a Jellyfin server. Inspired by Plexamp.
10+
A stylish, cross-platform desktop client for listening to music from a Jellyfin server. Inspired by Plexamp.
1111

1212
## In Action
1313

@@ -36,7 +36,7 @@ A stylish, cross-platform desktop client for listening to music from a Jellyfin
3636
<img src="https://i.imgur.com/HmVRw8r.png" width="400">
3737
</p>
3838

39-
### Playlist Page
39+
### Queue Page
4040
<p>
4141
<img src="https://i.imgur.com/6dTb11U.png" width="400">
4242
</p>

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jellyamp",
3-
"version": "0.9.6",
3+
"version": "0.9.7",
44
"private": true,
55
"description": "Desktop client for listening to music from a Jellyfin server",
66
"license": "MIT",

src/App.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,19 @@
2424
import Vue from 'vue';
2525
import Component from 'vue-class-component';
2626
27+
import {Notifications} from './services/notifications';
28+
2729
@Component({
2830
name: 'App',
2931
})
3032
export default class App extends Vue {
3133
isElectron = window.ipcRenderer ? true : false;
3234
distro = process.env.VUE_APP_OS;
3335
36+
mounted() {
37+
Notifications.service = this.$buefy.toast;
38+
}
39+
3440
close() {
3541
if (this.isElectron) {
3642
window.electronRemote.getCurrentWindow().close();

src/components/Player.vue

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<template>
22
<div v-if="player.player">
3-
<Playlist v-if="player.showPlaylist"></Playlist>
3+
<Queue v-if="player.showQueue"></Queue>
44
<div class="player" v-show="!miniPlayer" :style="`height: calc(100vh ${isElectron ? '- 26px' : ''});`">
55
<img class="bg-album update-img">
66
<div class="container">
77
<div class="level-bottom level is-mobile" style="padding: 15px 15px 0px 15px;">
88
<div level-left @click="togglePlayer()">
99
<b-icon level-item size="is-medium" icon="chevron-down" class="pointer"></b-icon>
1010
</div>
11-
<div level-right @click="player.showPlaylist = true">
11+
<div level-right @click="player.showQueue = true">
1212
<b-icon level-item size="is-medium" icon="playlist-music" class="pointer"></b-icon>
1313
</div>
1414
</div>
@@ -25,11 +25,11 @@
2525
<div class="level-bottom level is-mobile">
2626
<div level-item style="width: 30px"></div>
2727
<div level-item class="middle" style="width: 100%; text-align: center">
28-
<h6 class="title is-5 song-title">{{ player.playlist[player.index].Name }}</h6>
29-
<h6 class="subtitle is-6 song-title">{{ player.playlist[player.index].artist }}</h6>
28+
<h6 class="title is-5 song-title">{{ player.queue[player.index].Name }}</h6>
29+
<h6 class="subtitle is-6 song-title">{{ player.queue[player.index].artist }}</h6>
3030
</div>
3131
<div level-item class="ends" style="text-align: right; width: 30px;" @click="likeSong">
32-
<b-icon level-item :icon="`${player.playlist[player.index].loved ? 'heart' : 'heart-outline'}`" :type="`${player.playlist[player.index].loved ? 'is-danger' : ''}`" class="pointer"></b-icon>
32+
<b-icon level-item :icon="`${player.queue[player.index].loved ? 'heart' : 'heart-outline'}`" :type="`${player.queue[player.index].loved ? 'is-danger' : ''}`" class="pointer"></b-icon>
3333
</div>
3434
</div>
3535
<div class="level-bottom level is-mobile" style="margin-bottom: 0">
@@ -83,12 +83,12 @@
8383
<img level-item src="../assets/logo.png" class="album-art update-img">
8484
</div>
8585
<div level-item class="middle" @click="miniPlayer = false">
86-
<h6 class="title is-6 song-title">{{ player.playlist[player.index].Name }}</h6>
87-
<h6 class="subtitle is-6 song-title">{{ player.playlist[player.index].artist }}</h6>
86+
<h6 class="title is-6 song-title">{{ player.queue[player.index].Name }}</h6>
87+
<h6 class="subtitle is-6 song-title">{{ player.queue[player.index].artist }}</h6>
8888
</div>
8989
<div level-right class="ends">
9090
<span @click="likeSong">
91-
<b-icon level-item :icon="`${player.playlist[player.index].loved ? 'heart' : 'heart-outline'}`" :type="`${player.playlist[player.index].loved ? 'is-danger' : ''}`"></b-icon>
91+
<b-icon level-item :icon="`${player.queue[player.index].loved ? 'heart' : 'heart-outline'}`" :type="`${player.queue[player.index].loved ? 'is-danger' : ''}`"></b-icon>
9292
</span>
9393
<span @click="playPause">
9494
<b-icon level-item :icon="`${player.playing ? 'pause' : 'play'}`"></b-icon>
@@ -106,12 +106,12 @@ import Component from 'vue-class-component';
106106
import JellyfinService from '../services/jellyfin';
107107
import PlayerService from '../services/player';
108108
109-
import Playlist from '../components/Playlist';
109+
import Queue from '../components/Queue';
110110
111111
@Component({
112112
name: 'Player',
113113
components: {
114-
Playlist,
114+
Queue,
115115
}
116116
})
117117
export default class Player extends Vue {

src/components/Playlist.vue renamed to src/components/Queue.vue

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
<template>
22
<div
3-
class="playlist overflowY"
3+
class="queue overflowY"
44
:style="`height: calc(100vh ${isElectron ? '- 26px' : ''}); top: ${isElectron ? 26 : 0}px`"
55
>
66
<div class="container">
77
<div class="level is-mobile">
8-
<div class="level-left" @click="player.showPlaylist = false">
8+
<div class="level-left" @click="player.showQueue = false">
99
<b-icon level-item size="is-medium" icon="chevron-left" class="pointer"></b-icon>
10-
<p level-item class="title">Playlist</p>
10+
<p level-item class="title">Queue</p>
1111
</div>
1212
</div>
1313
<div
14-
class="playlist-item pointer"
15-
v-for="(song, index) of player.playlist"
14+
class="queue-item pointer"
15+
v-for="(song, index) of player.queue"
1616
v-bind:key="`${song.Id}${index}`"
1717
>
1818
<div class="level is-mobile">
@@ -40,9 +40,9 @@ import JellyfinService from '../services/jellyfin';
4040
import PlayerService from '../services/player';
4141
4242
@Component({
43-
name: 'Playlist',
43+
name: 'Queue',
4444
})
45-
export default class Playlist extends Vue {
45+
export default class Queue extends Vue {
4646
isElectron = window.ipcRenderer ? true : false;
4747
player = PlayerService;
4848
@@ -57,15 +57,15 @@ export default class Playlist extends Vue {
5757
</script>
5858

5959
<style scoped>
60-
.playlist {
60+
.queue {
6161
padding: 15px;
6262
background-color: #000B25;
6363
z-index: 150;
6464
position: fixed;
6565
width: 100%;
6666
}
6767
68-
.playlist-item {
68+
.queue-item {
6969
height: 60px;
7070
width: 100%;
7171
}

src/services/jellyfin.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {v4 as uuidv4 } from 'uuid';
22

3-
import {getItemOrDefault, setItem} from './localstorage';
3+
import router from '../router/index';
4+
import {getItemOrDefault, setItem, removeItem} from './localstorage';
45
import {Requests} from './requests';
56

67
const cleanUrl = url => {
@@ -56,6 +57,13 @@ const JellyfinService = {
5657
throw new Error('Could not login');
5758
}
5859
},
60+
logout: () => {
61+
removeItem('api-token');
62+
removeItem('server');
63+
removeItem('user');
64+
65+
router.push({name: 'Login'});
66+
},
5967
getUsers: async () => {
6068
const users = await Requests.get('users/public', null, true, false);
6169
console.log(users);

src/services/localstorage.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,11 @@ export function setItem(key, data) {
1919

2020
localStorage.setItem(key, JSON.stringify(data));
2121
}
22+
23+
export function removeItem(key) {
24+
if (!typeof (Storage)) {
25+
return;
26+
}
27+
28+
localStorage.removeItem(key);
29+
}

src/services/notifications.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const Notifications = {
2+
service: null,
3+
};

src/services/player.js

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ Vue.filter('duration', value => {
1818
});
1919

2020
class Player {
21-
playlist = [];
21+
queue = [];
2222
index = null;
2323
player = null;
2424
viewModel = null;
25-
showPlaylist = false;
25+
showQueue = false;
2626
playing = true;
2727

2828
lastPrev = -1;
@@ -32,8 +32,8 @@ class Player {
3232
IsPaused: false,
3333
PositionTicks: ticks, // Convert to ticks/ns
3434
PlayMethod: 'Transcode',
35-
PlaySessionId: this.playlist[this.index].params.PlaySessionId,
36-
ItemId: this.playlist[this.index].Id,
35+
PlaySessionId: this.queue[this.index].params.PlaySessionId,
36+
ItemId: this.queue[this.index].Id,
3737
EventName: 'timeupdate',
3838
};
3939

@@ -58,25 +58,25 @@ class Player {
5858
clearHowl() {
5959
this.player.unload();
6060
this.player = null;
61-
this.playlist[this.index].howl = null;
61+
this.queue[this.index].howl = null;
6262
}
6363

64-
setPlaylist(playlist) {
64+
setQueue(queue) {
6565
if (this.player) {
6666
this.player.stop();
6767
this.player = null;
6868
}
6969

7070
Howler.stop();
7171

72-
this.playlist = _.map(playlist, (item, index) => {
72+
this.queue = _.map(queue, (item, index) => {
7373
const songUrl = JellyfinService.getItemImageUrl(item);
7474
item.thumbnailImage = songUrl ? songUrl : placeholderImg;
7575

7676
item.artist = item.Artists[0] || item.AlbumArtist;
7777
item.loved = item.UserData.IsFavorite || false;
7878

79-
// Preload the first 3 items in the playlist
79+
// Preload the first 3 items in the queue
8080
if (index < 3) {
8181
item.howl = this.createHowl(item);
8282
}
@@ -87,8 +87,8 @@ class Player {
8787
this.play(0);
8888
}
8989

90-
injectPlaylist(playlist) {
91-
const updatePlaylist = _.map(playlist, item => {
90+
injectQueue(queue) {
91+
const updateQueue = _.map(queue, item => {
9292
const songUrl = JellyfinService.getItemImageUrl(item);
9393
item.thumbnailImage = songUrl ? songUrl : placeholderImg;
9494

@@ -98,15 +98,15 @@ class Player {
9898
return item;
9999
});
100100

101-
if (this.index === this.playlist.length - 1) {
102-
this.playlist = [...this.playlist, ...updatePlaylist];
101+
if (this.index === this.queue.length - 1) {
102+
this.queue = [...this.queue, ...updateQueue];
103103
} else {
104-
this.playlist.splice(this.index + 1, 0, ...playlist);
104+
this.queue.splice(this.index + 1, 0, ...queue);
105105
}
106106
}
107107

108108
removeItem(index) {
109-
this.playlist.splice(index, 1);
109+
this.queue.splice(index, 1);
110110

111111
if (index < this.index) {
112112
this.index -= 1;
@@ -119,12 +119,12 @@ class Player {
119119
}
120120

121121
try {
122-
if (this.playlist[this.index].loved) {
123-
await JellyfinService.unlikeId(this.playlist[this.index].Id);
124-
this.playlist[this.index].loved = false;
122+
if (this.queue[this.index].loved) {
123+
await JellyfinService.unlikeId(this.queue[this.index].Id);
124+
this.queue[this.index].loved = false;
125125
} else {
126-
await JellyfinService.likeId(this.playlist[this.index].Id);
127-
this.playlist[this.index].loved = true;
126+
await JellyfinService.likeId(this.queue[this.index].Id);
127+
this.queue[this.index].loved = true;
128128
}
129129
} catch (e) {
130130
console.log(e);
@@ -145,9 +145,9 @@ class Player {
145145
if (this.viewModel && this.viewModel.$el) {
146146
const images = this.viewModel.$el.querySelectorAll('.update-img');
147147
images.forEach((image, index) => {
148-
image.setAttribute('src', this.playlist[this.index].thumbnailImage);
148+
image.setAttribute('src', this.queue[this.index].thumbnailImage);
149149

150-
if (this.playlist[this.index].thumbnailImage === placeholderImg && index === 0) {
150+
if (this.queue[this.index].thumbnailImage === placeholderImg && index === 0) {
151151
image.removeAttribute('src');
152152
}
153153
});
@@ -255,7 +255,7 @@ class Player {
255255
}
256256

257257
play(index) {
258-
if (!this.playlist.length || index < 0 || index >= this.playlist.length) {
258+
if (!this.queue.length || index < 0 || index >= this.queue.length) {
259259
return;
260260
}
261261

@@ -264,7 +264,7 @@ class Player {
264264
}
265265

266266
this.index = index;
267-
const data = this.playlist[index];
267+
const data = this.queue[index];
268268

269269
if (!data.howl) {
270270
data.howl = this.createHowl(data);
@@ -323,7 +323,7 @@ class Player {
323323

324324
const ticks = Math.round(seek * 10000000);
325325

326-
this.playlist[this.index].progressInTicks = ticks;
326+
this.queue[this.index].progressInTicks = ticks;
327327
this.updateProgress(ticks);
328328
this.updateProgressMpris(ticks);
329329
}
@@ -349,7 +349,7 @@ class Player {
349349

350350
if (dir === 'next') {
351351
index = index + 1;
352-
if (index >= this.playlist.length) {
352+
if (index >= this.queue.length) {
353353
this.clearHowl();
354354
}
355355
} else {

0 commit comments

Comments
 (0)