Merge pull request 'Sharing' (#1) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing

Reviewed-on: #1
This commit is contained in:
Artem Anufrij 2023-02-17 00:06:13 +01:00
commit c79a8fc52c
18 changed files with 629 additions and 76 deletions

View File

@ -1,5 +1,5 @@
{
"backend_de": "http://localhost:31204",
"backend_dev": "https://webplay.rocks",
"backend_dev": "http://localhost:31204",
"backend_de": "https://webplay.rocks",
"backend": "https://webplay.rocks"
}

View File

@ -272,6 +272,7 @@ td.fillCell>* {
overflow: hidden;
text-overflow: ellipsis;
flex-grow: 1;
text-align: left;
}
.radioCover {
@ -593,6 +594,7 @@ td.fillCell>* {
.z1 {
z-index: 1;
}
.z2 {
z-index: 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
<template>
<div id="app">
<nav
v-show="$route.path != '/login' && $route.path != '/setup'"
v-show="$route.path != '/login' && $route.path != '/setup' && $route.path != '/share' "
:class="{ slideOverTop: $store.getters.isDialogOpen }"
>
<div>
@ -245,7 +245,7 @@ export default {
},
login() {
let hash = window.location.hash.replace("#/", "");
if (!hash.startsWith("login") && !hash.startsWith("setup")) {
if (!hash.startsWith("login") && !hash.startsWith("setup") && !hash.startsWith("share")) {
let redirect = encodeURIComponent(hash);
if (redirect) {
this.$router.replace({

View File

@ -0,0 +1,72 @@
<template>
<div id="content" class="flex-column">
<div class="flex-column ma-horizontal">
<h1>{{ album.title }}</h1>
<h2>{{ album.artist_name }}</h2>
</div>
<div id="tracks" class="flex-row border-top">
<div class="flex-column">
<img id="cover" class="shadow ma24" :src="cover" />
<p class="center ma-off hideOnMobile">
<b>{{ album.tracks.length }}</b> Tracks
</p>
</div>
<ul id="trackList" class="tracks">
<li v-for="track in album.tracks" :key="track._id">
<TrackItem :track="track" :showCover="false" />
</li>
</ul>
</div>
</div>
</template>
<script>
import TrackItem from "../components/Track";
export default {
data() {
return {
album: {
covers: {},
tracks: [],
},
};
},
methods: {
show(album) {
this.album = album;
},
},
computed: {
cover() {
if (!this.album.covers) {
return "/static/icons/dummy/album.svg";
}
return this.album.covers.cover256;
},
},
components: {
TrackItem,
},
};
</script>
<style scoped>
#cover {
align-self: center;
width: 256px;
}
#content,
#tracks {
overflow: auto;
}
@media (max-width: 480px) {
#tracks {
flex-direction: column;
}
#trackList {
border-top: 1px solid var(--light-border);
}
}
</style>

View File

@ -0,0 +1,78 @@
<template>
<div id="content" class="flex-column">
<div class="flex-column ma-horizontal">
<h1>{{ box.title }}</h1>
</div>
<div id="videos" class="flex-row border-top">
<div class="flex-column">
<img id="cover" class="shadow ma24" :src="cover" />
<p class="center ma-off hideOnMobile">
<b>{{ box.videos.length }}</b> Videos
</p>
</div>
<ul id="videoList" class="videos">
<li v-for="video in box.videos" :key="video._id">
<VideoItem :video="video" />
</li>
</ul>
</div>
</div>
</template>
<script>
import VideoItem from "../components/Video.vue";
export default {
data() {
return {
box: {
covers: {},
videos: [],
},
};
},
methods: {
show(box) {
this.box = box;
},
},
computed: {
cover() {
if (!this.box.covers) {
return "/static/icons/dummy/box.svg";
}
return this.box.covers.cover256;
},
},
components: {
VideoItem,
},
};
</script>
<style scoped>
#cover {
align-self: center;
width: 256px;
}
#content,
#videos {
overflow: auto;
}
.video {
max-width: 256px;
}
@media (max-width: 480px) {
#videos {
flex-direction: column;
}
#videoList {
border-top: 1px solid var(--light-border);
}
.video {
max-width: inherit;
}
}
</style>

View File

@ -181,6 +181,13 @@ export default {
this.audio.pause();
this.audio.src = url;
this.pushHistoryItem();
},
pushHistoryItem() {
if (!this.currentUser._id) {
return;
}
let item = {
id: this.currentTrackParent._id,
type: this.currentTrackParentType,
@ -258,15 +265,17 @@ export default {
}
},
gotoContainer() {
switch (this.selectedTrack.parentType) {
case "album":
this.$router.push("/albums?id=" + this.selectedTrack.parent._id);
break;
case "artist":
this.$router.push(
"/artists?id=" + this.selectedTrack.parent.parent._id
);
break;
if (this.currentUser._id) {
switch (this.selectedTrack.parentType) {
case "album":
this.$router.push("/albums?id=" + this.selectedTrack.parent._id);
break;
case "artist":
this.$router.push(
"/artists?id=" + this.selectedTrack.parent.parent._id
);
break;
}
}
},
switchShuffle() {
@ -275,9 +284,15 @@ export default {
},
switchRepeatType() {
this.$store.dispatch("player/switchPlayerRepeatMode");
if (!this.currentUser._id) {
return;
}
this.saveUserSettings();
},
saveUserSettings() {
if (!this.currentUser._id) {
return;
}
this.$store.dispatch("user/savePlayerSettings");
},
timeUpdate(event) {
@ -314,6 +329,9 @@ export default {
}
return type;
},
currentUser() {
return this.$store.getters["user/user"];
},
formatedD() {
let m = Math.floor(this.duration / 60);
let s = Math.floor(this.duration - m * 60);

View File

@ -40,7 +40,13 @@
<button v-if="!selectedAlbum.share._id" @click="shareEnable">
<awesome-icon icon="share" />Share this album
</button>
<button v-else @click="shareDisable">
<button
v-if="selectedAlbum.share._id"
@click="addShareUrlToClipboard"
>
<awesome-icon icon="clipboard" />Copy url into clipboard
</button>
<button v-if="selectedAlbum.share._id" @click="shareDisable">
<awesome-icon icon="share" />Remove share
</button>
</div>
@ -102,7 +108,6 @@ import { mapGetters } from "vuex";
export default {
data() {
return {
move: 152,
albums: [],
scrollTimer: 0,
loadingPrev: false,
@ -110,12 +115,12 @@ export default {
elements: {},
};
},
mounted() {
if (window.innerWidth <= 480 || window.innerHeight <= 480) {
this.move = 120;
}
},
methods: {
addShareUrlToClipboard() {
let url =
window.location.origin + "/#/share?id=" + this.selectedAlbum.share._id;
navigator.clipboard.writeText(url);
},
dblclick() {
this.$store.commit("tracks/resetSelectedTrack");
this.$store.commit("radios/resetSelectedRadio");
@ -214,7 +219,11 @@ export default {
this.$store.dispatch("albums/selectAlbum", album);
},
shareEnable() {
this.$store.dispatch("albums/shareEnable", this.selectedAlbum);
this.$store
.dispatch("albums/shareEnable", this.selectedAlbum)
.then(() => {
this.addShareUrlToClipboard();
});
},
shareDisable() {
this.$store.dispatch("albums/shareDisable", this.selectedAlbum);
@ -348,7 +357,7 @@ export default {
border-top: 1px solid #ffffff20;
border-bottom: 1px solid #00000020;
}
#stats button {
.dropdown-activator button {
width: 32px;
height: 32px;
}

View File

@ -41,7 +41,13 @@
<button v-if="!selectedBox.share._id" @click="shareEnable">
<awesome-icon icon="share" />Share this box
</button>
<button v-else @click="shareDisable">
<button
v-if="selectedBox.share._id"
@click="addShareUrlToClipboard"
>
<awesome-icon icon="clipboard" />Copy url into clipboard
</button>
<button v-if="selectedBox.share._id" @click="shareDisable">
<awesome-icon icon="share" />Remove share
</button>
</div>
@ -95,6 +101,11 @@ import { mapGetters } from "vuex";
export default {
methods: {
addShareUrlToClipboard() {
let url =
window.location.origin + "/#/share?id=" + this.selectedBox.share._id;
navigator.clipboard.writeText(url);
},
dblclick() {
this.$store.commit("tracks/resetSelectedTrack");
this.$store.commit("radios/resetSelectedRadio");
@ -174,7 +185,9 @@ export default {
this.$store.dispatch("boxes/resetCover", this.selectedBox);
},
shareEnable() {
this.$store.dispatch("boxes/shareEnable", this.selectedBox);
this.$store.dispatch("boxes/shareEnable", this.selectedBox).then(() => {
this.addShareUrlToClipboard();
});
},
shareDisable() {
this.$store.dispatch("boxes/shareDisable", this.selectedBox);
@ -274,7 +287,7 @@ export default {
border-top: 1px solid #ffffff20;
border-bottom: 1px solid #00000020;
}
#stats button {
.dropdown-activator button {
width: 32px;
height: 32px;
}

View File

@ -89,6 +89,9 @@ export default {
this.$store.dispatch("videos/playNextTo", this.selectedVideo);
},
pushHistoryItem() {
if (!this.currentUser._id) {
return;
}
let item = {
id: this.selectedVideo.parent._id,
type: "box",
@ -154,6 +157,9 @@ export default {
},
},
computed: {
currentUser() {
return this.$store.getters["user/user"];
},
selectedVideo() {
return this.$store.getters["videos/selectedVideo"];
},

View File

@ -7,6 +7,7 @@ import RadiosView from "./views/Radios";
import BoxesView from "./views/Boxes";
import SearchView from "./views/Search";
import SetupView from "./views/Setup";
import ShareView from "./views/Share";
import HomeView from "./views/Home";
import UsersView from "./views/Users";
import FavouritesView from "./views/Favourites"
@ -56,6 +57,10 @@ const routes = [
path: "/setup",
component: SetupView
},
{
path: "/share",
component: ShareView
},
{
path: "/me",
component: UsersView

View File

@ -15,6 +15,7 @@ import user from "./modules/user"
import videos from "./modules/videos"
import system from "./modules/system"
import search from "./modules/search"
import share from "./modules/share"
export default createStore({
state,
@ -31,6 +32,7 @@ export default createStore({
user,
videos,
system,
search
search,
share
}
})

View File

@ -155,8 +155,11 @@ export default {
axios.put(context.rootGetters.server + "/api/albums/" + album._id, body, context.rootGetters.headers);
},
shareEnable(context, album) {
axios.post(context.rootGetters.server + "/api/albums/" + album._id + "/share", {}, context.rootGetters.headers).then(res => {
album.share = res.data;
return new Promise(resolve => {
axios.post(context.rootGetters.server + "/api/albums/" + album._id + "/share", {}, context.rootGetters.headers).then(res => {
album.share = res.data;
resolve();
});
});
},
shareDisable(context, album) {

View File

@ -131,8 +131,11 @@ export default {
});
},
shareEnable(context, box) {
axios.post(context.rootGetters.server + "/api/boxes/" + box._id + "/share", {}, context.rootGetters.headers).then(res => {
box.share = res.data;
return new Promise(resolve => {
axios.post(context.rootGetters.server + "/api/boxes/" + box._id + "/share", {}, context.rootGetters.headers).then(res => {
box.share = res.data;
resolve();
});
});
},
shareDisable(context, box) {

View File

@ -0,0 +1,29 @@
import axios from 'axios'
export default {
get(context, id) {
return new Promise((resolve) => {
axios.get(context.rootGetters.server + "/api/shares/" + id, context.rootGetters.headers).then((res) => {
if (!res.data._id) {
resolve(res.data);
return;
}
switch (res.data.object.type) {
case "album":
res.data.object.tracks.forEach(track => {
track.parent = res.data.object;
track.parentType = "album"
});
break;
case "box":
res.data.object.videos.forEach(video => {
video.parent = res.data.object;
video.parentType = "box"
});
break;
}
resolve(res.data);
});
});
},
}

View File

@ -0,0 +1,9 @@
//import state from './state.js';
//import getters from './getters.js';
//import mutations from './mutations.js';
import actions from './actions.js';
export default {
namespaced: true,
actions
}

View File

@ -4,7 +4,7 @@ import router from '../../../router'
export default {
play(context, video) {
context.commit("selectVideo", video);
if (context.rootGetters.routerQuery.play != video._id) {
if (context.rootGetters.routerQuery.play != video._id && context.rootGetters.routerPath != "/share") {
router.push("/boxes?id=" + video.parent._id + "&play=" + video._id);
}
},

68
src/views/Share.vue Normal file
View File

@ -0,0 +1,68 @@
<template>
<div ref="share" id="share" class="flex-column">
<AlbumContent ref="album" v-if="type == 'album'" />
<BoxContent ref="box" v-if="type == 'box'" />
</div>
</template>
<script>
import AlbumContent from "../components/AlbumContent.vue";
import BoxContent from "../components/BoxContent.vue";
export default {
name: "ShareView",
data() {
return {
type: "",
};
},
methods: {
loadShare() {
if (this.$route.query.id) {
this.$store.dispatch("share/get", this.$route.query.id).then((res) => {
if (!res._id) {
this.$router.replace("/login");
return;
}
this.type = res.object.type;
this.$nextTick(() => {
switch (this.type) {
case "album":
this.$refs.album.show(res.object);
break;
case "box":
this.$refs.box.show(res.object);
break;
}
});
});
} else {
this.$router.replace("/login");
}
},
},
computed: {
server() {
return this.$store.getters.server;
},
},
components: {
AlbumContent,
BoxContent,
},
watch: {
server() {
this.loadShare();
},
"$route.query.id": function () {
this.loadShare();
},
},
};
</script>
<style scoped>
#share {
overflow: auto;
}
</style>