Commit 87f4a9dd authored by SpinShare's avatar SpinShare

cleanup, error handling, social icons

parent a6707980
......@@ -12,9 +12,6 @@
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
export default {
name: 'SongItemPlaceholder',
}
......
......@@ -15,7 +15,7 @@
<script>
import { remote } from 'electron';
import path from 'path';
const { clipboard, shell } = remote;
const { shell } = remote;
export default {
name: 'SongLocalItem',
......@@ -51,9 +51,11 @@
});
},
openOnSpinShare: function() {
if(this.isSpinShare) {
if(this.isSpinShare.includes("spinshare_")) {
this.$router.push({ name: 'SongDetail', params: { id: this.isSpinShare } });
}
}
},
openInExplorer: function() {
shell.showItemInFolder(path.normalize(this.file));
......
......@@ -17,9 +17,6 @@
</template>
<script>
import { remote } from 'electron';
const { clipboard } = remote;
import CollapsableText from '@/components/CollapsableText.vue';
export default {
......@@ -34,10 +31,6 @@
'comment',
'reviewDate'
],
mounted: function() {
},
methods: {
}
}
</script>
......
......@@ -15,9 +15,6 @@
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
export default {
name: 'SongRow',
props: [
......
......@@ -54,6 +54,7 @@
<style scoped lang="less">
.staff-promo {
background: #fff;
background-position: right center;
border-radius: 6px;
padding: 50px;
height: 256px;
......
<template>
<div class="stream" v-if="isLive">
<div class="header">
<div class="viewers"><i class="mdi mdi-eye-outline"></i> {{ viewers }}</div>
<div class="title">{{ title }}</div>
</div>
<div class="video-container">
<iframe src="https://player.twitch.tv/?channel=spinshare&enableExtensions=true&muted=true&player=popout&volume=1"></iframe>
<iframe src="https://player.twitch.tv/?channel=spinshare&enableExtensions=true&muted=true&volume=1&parent=localhost"></iframe>
</div>
</div>
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
export default {
name: 'Stream',
props: [
......@@ -26,34 +19,14 @@
<style scoped lang="less">
.stream {
margin-top: 50px;
& .header {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 15px;
margin-bottom: 15px;
width: 720px;
margin: 0 auto;
margin-bottom: 50px;
& .viewers {
background: #ff294d;
color: #fff;
padding: 5px;
font-size: 12px;
font-weight: bold;
border-radius: 20px;
}
& .title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
align-self: center;
}
}
& .video-container {
position: relative;
width: 100%;
padding-top: 50%;
padding-top: 56.25%;
& iframe {
position: absolute;
......
......@@ -10,9 +10,6 @@
</template>
<script>
import { remote } from 'electron';
const { clipboard } = remote;
export default {
name: 'Useritem',
props: [
......@@ -21,11 +18,7 @@
'username',
'isPatreon',
'isVerified'
],
mounted: function() {
},
methods: {
}
]
}
</script>
......
......@@ -10,9 +10,6 @@
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
export default {
name: 'UserRow',
props: [
......
......@@ -14,6 +14,7 @@ import ViewSongDetailReviews from '../views/SongDetailReviews.vue';
import ViewSongDetailSpinPlays from '../views/SongDetailSpinPlays.vue';
import ViewUserDetail from '../views/UserDetail.vue';
import ViewSettings from '../views/Settings.vue';
import ViewError from '../views/Error.vue';
Vue.use(VueRouter);
Vue.use(VueAxios, axios);
......@@ -80,6 +81,10 @@ const routes = [{
path: '/settings',
name: 'Settings',
component: ViewSettings
}, {
path: '/error/:errorCode',
name: 'Error',
component: ViewError
}];
const router = new VueRouter({
......
<template>
<section class="section-error">
<header>
<div class="title">{{ errorCode }} - {{ errorTitle }}</div>
<div class="description">
{{ errorText }}
</div>
</header>
<div class="error-content">
<div class="button" v-on:click="retry()">Try again</div>
</div>
</section>
</template>
<script>
export default {
name: 'Error',
data: function() {
return {
errorCode: 500,
errorTitle: "",
errorText: "",
}
},
mounted: function() {
switch(status) {
default:
this.$data.errorCode = this.$route.params.errorCode;
this.$data.errorTitle = this.$t('connectionerror.server.title');
this.$data.errorText = this.$t('connectionerror.server.text');
break;
case 404:
case 403:
this.$data.errorCode = this.$route.params.errorCode;
this.$data.errorTitle = this.$t('connectionerror.notfound.title');
this.$data.errorText = this.$t('connectionerror.notfound.text');
break;
}
},
methods: {
retry: function() {
this.$router.back();
}
}
}
</script>
<style scoped lang="less">
.section-error {
& header {
background: rgba(0,0,0,0.3);
padding: 50px;
padding-bottom: 25px;
& .title {
font-size: 32px;
letter-spacing: 0.05em;
text-transform: uppercase;
margin-bottom: 15px;
font-family: 'Oswald', sans-serif;
}
& .actions {
display: grid;
grid-template-columns: auto auto auto auto 1fr;
grid-gap: 15px;
}
}
& .error-content {
padding: 25px 50px;
line-height: 1.5em;
display: flex;
}
}
</style>
\ No newline at end of file
......@@ -30,6 +30,10 @@
</template>
</SongRow>
<div class="loading" v-if="!apiFinished">
<Loading />
</div>
<DeleteOverlay v-if="showDeleteOverlay" v-bind:deleteFiles="deleteFiles" />
</section>
</template>
......@@ -46,9 +50,10 @@
import SSAPI from '@/modules/module.api.js';
import SRXD from '@/modules/module.srxd.js';
import DeleteOverlay from '@/components/Overlays/DeleteOverlay.vue';
import SongRow from '@/components/Song/SongRow.vue';
import SongLocalItem from '@/components/Song/SongLocalItem.vue';
import Loading from '@/components/Loading.vue';
import DeleteOverlay from '@/components/Overlays/DeleteOverlay.vue';
export default {
name: 'Library',
......@@ -57,12 +62,15 @@
librarySongs: [],
showDeleteOverlay: false,
deleteFiles: [],
hasUnusedFiles: false
hasUnusedFiles: false,
apiFinished: false,
useAPIForLibrary: false
}
},
components: {
SongRow,
SongLocalItem,
Loading,
DeleteOverlay
},
mounted: function() {
......@@ -96,32 +104,46 @@
this.$data.hasUnusedFiles = false;
this.$data.librarySongs = [];
this.$data.apiFinished = false;
await ssapi.ping().then((data) => {
this.$data.useAPIForLibrary = true;
console.log(data);
}).catch((error) => {
console.log(error);
this.$data.useAPIForLibrary = false;
console.log("ERROR WHILE PINGING API");
});
// Load local .srtb
glob(path.join(userSettings.get('gameDirectory'), "*.srtb"), (error, files) => {
files.forEach((file) => {
// Get Detail Data
let songDetail = this.getSongDetail(file);
let songCover = glob.sync(path.join(userSettings.get('gameDirectory'), "AlbumArt", songDetail.coverReference + ".*"))[0];
let songSpinShareReference = false;
this.getSongDetail(file).then((songDetail) => {
let librarySong = {};
let fileReference = false;
if(file.split("/")[file.split("/").length - 1].replace(".srtb", "").includes("spinshare_")) {
songSpinShareReference = file.split("/")[file.split("/").length - 1].replace(".srtb", "");
if(path.basename(file).includes("spinshare_")) {
fileReference = path.basename(file).replace(".srtb", "");
}
let songCover = glob.sync(path.join(userSettings.get('gameDirectory'), "AlbumArt", songDetail.coverReference + ".*"))[0];
if(songCover) {
songCover = "data:image/jpg;base64," + fs.readFileSync(songCover, { encoding: 'base64' });
}
let librarySong = {
librarySong = {
file: file,
detail: songDetail,
cover: songCover,
modifiedDate: fs.statSync(file).mtime,
isSpinShare: songSpinShareReference
isSpinShare: fileReference
};
this.$data.librarySongs.push(librarySong);
this.$data.apiFinished = true;
});
});
// Order library by modifiedDate
......@@ -146,10 +168,12 @@
install: function() {
this.$parent.$parent.$emit('install');
},
getSongDetail: function(filePath) {
let srtbContent = JSON.parse( fs.readFileSync(filePath) );
getSongDetail: async function(filePath) {
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
let trackInfo = {};
let fileReference = path.basename(filePath).replace(".srtb", "");
let srtbContent = JSON.parse( fs.readFileSync(filePath) );
let stringValueContainers = srtbContent['largeStringValuesContainer'].values;
stringValueContainers.forEach((stringValueContainer) => {
......
......@@ -74,7 +74,11 @@
this.$data.searchResultsUsers = data.data.users;
this.$data.searchResultsSongs = data.data.songs;
this.$data.apiFinished = true;
} else {
this.$router.push({ name: 'Error', params: { errorCode: data.status } });
}
}).catch(() => {
this.$router.push({ name: 'Error', params: { errorCode: 500 } });
});
},
search: function() {
......@@ -97,7 +101,11 @@
this.$data.searchResultsSongs = data.data.songs;
this.$data.apiFinished = true;
} else {
this.$router.push({ name: 'Error', params: { errorCode: data.status } });
}
}).catch(() => {
this.$router.push({ name: 'Error', params: { errorCode: 500 } });
});
} else {
this.$data.searchResultsUsers = [];
......
......@@ -170,6 +170,7 @@
let userSettings = new UserSettings();
ssapi.getSongDetail(this.$route.params.id).then((data) => {
if(data.status == 200) {
this.$data.id = data.data.id;
this.$data.cover = data.data.paths.cover;
this.$data.title = data.data.title;
......@@ -196,9 +197,20 @@
this.$data.isInstalled = fs.existsSync(path.join(userSettings.get('gameDirectory'), this.$data.fileReference + ".srtb"));
ssapi.getUserDetail(data.data.uploader).then((data) => {
if(data.status == 200) {
this.$data.uploader = data.data;
this.$data.apiFinished = true;
} else {
this.$router.push({ name: 'Error', params: { errorCode: data.status } });
}
}).catch((error) => {
this.$router.push({ name: 'Error', params: { errorCode: 500 } });
});
} else {
this.$router.push({ name: 'Error', params: { errorCode: data.status } });
}
}).catch((error) => {
this.$router.push({ name: 'Error', params: { errorCode: 500 } });
});
this.$on('closePlayOverlay', () => {
......
......@@ -55,9 +55,13 @@
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
ssapi.getSongDetailReviews(this.$route.params.id).then((data) => {
if(data.status == 200) {
this.$data.apiFinished = true;
this.$data.reviewAverage = data.data.average;
this.$data.reviews = data.data.reviews ? data.data.reviews : [];
} else {
this.$router.push({ name: 'Error', params: { errorCode: data.status } });
}
});
},
components: {
......
......@@ -48,8 +48,12 @@
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
ssapi.getSongDetailSpinPlays(this.$route.params.id).then((data) => {
if(data.status == 200) {
this.$data.apiFinished = true;
this.$data.spinPlays = data.data.spinPlays ? data.data.spinPlays : [];
} else {
this.$router.push({ name: 'Error', params: { errorCode: data.status } });
}
});
},
components: {
......
<template>
<div class="frontpage">
<Stream v-bind="streamStatus" />
<div class="staff-promos">
<StaffPromoPlaceholder
v-if="isPromoLoading"
......@@ -12,11 +14,19 @@
v-bind="staffPromo" />
</div>
<Stream v-bind="streamStatus" />
<div class="social-buttons">
<div v-on:click="OpenDiscord()" class="item item-discord"><i class="mdi mdi-discord"></i></div>
<div v-on:click="OpenTwitter()" class="item item-twitter"><i class="mdi mdi-twitter"></i></div>
<div v-on:click="OpenYouTube()" class="item item-youtube"><i class="mdi mdi-youtube"></i></div>
<div v-on:click="OpenTwitch()" class="item item-twitch"><i class="mdi mdi-twitch"></i></div>
</div>
</div>
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
import SSAPI from '@/modules/module.api.js';
import StaffPromo from '@/components/Startup/StaffPromo.vue';
import StaffPromoPlaceholder from '@/components/Startup/StaffPromoPlaceholder.vue';
......@@ -40,7 +50,10 @@
});
ssapi.getStreamStatus().then((data) => {
// Gracefully fail if Twitch API is ratelimited
if(data.status == 200) {
this.$data.streamStatus = data;
}
});
},
components: {
......@@ -49,6 +62,18 @@
Stream
},
methods: {
OpenDiscord: function() {
shell.openExternal("https://spinsha.re/discord");
},
OpenTwitter: function() {
shell.openExternal("https://twitter.com/WeAreSpinShare");
},
OpenYouTube: function() {
shell.openExternal("https://www.youtube.com/channel/UCh7ftpzIqlHw5p_-HXHwMBw");
},
OpenTwitch: function() {
shell.openExternal("https://twitch.tv/SpinShare");
}
}
}
</script>
......@@ -65,4 +90,42 @@
display: none;
}
}
.social-buttons {
display: grid;
width: 550px;
margin: 0 auto;
margin-top: 25px;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 15px;
& .item {
height: 75px;
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
background: rgba(255,255,255,0.2);
border-radius: 6px;
transition: 0.2s ease-in-out all;
&.item-discord {
background: linear-gradient(135deg, #99aab5, #7289da);
}
&.item-twitter {
background: linear-gradient(135deg, #d0e6f7, #1da1f2);
}
&.item-youtube {
background: linear-gradient(135deg, #ff0000, #c20000);
}
&.item-twitch {
background: linear-gradient(135deg, #b9a3e3, #6441a5);
}
&:hover {
transform: scale(1.1);
box-shadow: 0px 4px 16px rgba(0,0,0,0.4);
cursor: pointer;
}
}
}
</style>
\ No newline at end of file
......@@ -66,6 +66,7 @@
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
ssapi.getUserDetail(this.$route.params.id).then((data) => {
if(data.status == 200) {
this.$data.id = data.data.id;
this.$data.username = data.data.username;
this.$data.isVerified = data.data.isVerified;
......@@ -73,6 +74,9 @@
this.$data.avatar = data.data.avatar;
this.$data.songs = data.data.songs;
this.$data.apiFinished = true;
} else {
this.$router.push({ name: 'Error', params: { errorCode: data.status } });
}
});
},
methods: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment