Added filtering of requested movies. Also change the order of movies in sidebar and added support for rating of movie. Change path destinations to be more clear.

This commit is contained in:
2018-07-25 17:53:01 +02:00
parent aa9bfa12d9
commit 8c38f82dbe
13 changed files with 245 additions and 74 deletions

View File

@@ -109,6 +109,20 @@
<div id="app"></div>
<script src="dist/build.js"></script>
</body>
<script>
(function(w, d){
var b = d.getElementsByTagName('body')[0];
var s = d.createElement("script"); s.async = true;
var v = !("IntersectionObserver" in w) ? "8.7.1" : "10.5.2";
s.src = "https://cdnjs.cloudflare.com/ajax/libs/vanilla-lazyload/" + v + "/lazyload.min.js";
w.lazyLoadOptions = {
container: '.movies__list',
elements_selector: 'img',
threshold: 300,
}; // Your options here. See "recipes" for more information about async.
b.appendChild(s);
}(window, document));
</script>
<script src="https://cdn.jsdelivr.net/vue/2.0.0-rc/vue.min.js"></script>
<script src="https://cdn.ravenjs.com/3.23.1/vue/raven.min.js" crossorigin="anonymous"></script>
<script>Raven.config('https://c1fa1a17de3d4b24abcd05161648fe4d@sentry.io/300063').install();</script>

View File

@@ -5,19 +5,17 @@ var history = require('connect-history-api-fallback');
app = express();
app.use('/dist', express.static(path.join(__dirname + "/dist")));
app.use('/dist', express.static(path.join(__dirname + "/dist/")));
app.use('/favicons', express.static(path.join(__dirname + "/favicons")));
app.use(history({
index: '/'
}));
var port = process.env.PORT || 5000;
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(port);
console.log('server started '+ port);

View File

@@ -3,7 +3,7 @@
<navigation></navigation>
<header class="header">
<div class="header__search">
<input class="header__search-input" type="text" v-model.trim="searchQuery" @keyup.enter="search" @blur="search" placeholder="Search for a movie or show...">
<input class="header__search-input" type="text" v-model.trim="searchQuery" @keyup.enter="search" placeholder="Search for a movie or show...">
<svg class="header__search-icon">
<use xlink:href="#iconSearch"></use>
</svg>
@@ -301,6 +301,11 @@ img{
background: $c-dark;
color: $c-white;
}
&__active {
@extend .button;
background: $c-dark;
color: $c-white;
}
}

View File

@@ -19,6 +19,9 @@
</header>
<div class="movie__main">
<div class="movie__wrap movie__wrap--main" :class="{'movie__wrap--page': type=='page'}">
<!-- <div class="movie__ratings">
<p>here</p>
</div> -->
<!-- <div class="movie__actions" v-if="userLoggedIn && favoriteChecked"> -->
<div class="movie__actions">
@@ -76,20 +79,18 @@
</div>
</div> -->
<div v-if="movie.year" class="movie__details-block">
<h2 class="movie__details-title">
Release Date
</h2>
<div class="movie__details-text">
{{ movie.year }}
</div>
<h2 class="movie__details-title">Release Date</h2>
<div class="movie__details-text">{{ movie.year }}</div>
</div>
<!-- <div v-if="movie.score" class="movie__details-block">
<h2 class="movie__details-title">Rating</h2>
<div class="movie__details-text">{{ rating }}</div>
</div> -->
<div v-if="movie.type == 'show'" class="movie__details-block">
<h2 class="movie__details-title">
Seasons
</h2>
<div class="movie__details-text">
10
</div>
<h2 class="movie__details-title">Seasons</h2>
<div class="movie__details-text">{{ movie.seasons }}</div>
</div>
</div>
</div>
@@ -130,7 +131,9 @@ export default {
favoriteChecked: false,
requested: false,
admin: localStorage.getItem('admin'),
showTorrents: false
showTorrents: false,
rating_int: 0,
rating_dec: 0
}
},
computed: {
@@ -161,7 +164,7 @@ export default {
}
// Push state
if(storage.createMoviePopup){
storage.moviePath = '/request/' + this.mediaType + '/' + id;
storage.moviePath = this.mediaType + '/' + id;
history.pushState({ popup: true }, null, storage.moviePath);
storage.createMoviePopup = false;
}
@@ -219,6 +222,13 @@ export default {
axios.post(`https://api.kevinmidboe.com/api/v1/plex/request/${this.id}?type=${this.mediaType}`,
{ headers: {authorization: storage.token} },
)
axios({
method: 'post', //you can set what request you want to be
url: `https://api.kevinmidboe.com/api/v1/plex/request/${this.id}?type=${this.mediaType}`,
headers: {
authorization: storage.token
}
})
// axios.post(`https://api.kevinmidboe.com/api/v1/plex/request/${this.id}?api_key=${storage.apiKey}&session_id=${storage.sessionId}`, {
.then(function(resp){
if (resp.data.success)

View File

@@ -40,20 +40,30 @@ let removed;
export default {
props: ['type', 'mode', 'category', 'shortList'],
components: { MoviesListItem },
beforeRouteLeave (to, from, next) {
if(from.name == 'search'){
eventHub.$emit('setSearchQuery', true);
}
next();
},
// beforeRouteLeave (to, from, next) {
// if(from.name == 'search'){
// eventHub.$emit('setSearchQuery', true);
// }
// next();
// },
data() {
return {
listTitle: '',
movies: [],
unfiltered_movies: [],
pages: '',
filter: '',
filter_query: '',
results: '',
currentPage: 1,
listLoaded: false
listLoaded: false,
showFilter: false,
filters: {
status: {
elms: ['all', 'requested', 'downloading', 'downloaded'],
selected: 0,
}
}
}
},
computed: {
@@ -68,7 +78,7 @@ export default {
if(this.mode == 'search'){
return `https://api.kevinmidboe.com/api/v1/plex/request?query=${this.query}&page=${this.currentPage}`;
} else if(this.mode == 'requests' || this.$route.params.category == 'requests') {
return `https://api.kevinmidboe.com/api/v1/plex/requests/all?page=${this.currentPage}&status=requested`;
return `https://api.kevinmidboe.com/api/v1/plex/requests/all?page=${this.currentPage}&status=${this.filter}`;
} else if(this.mode == 'collection') {
let category = this.$route.params.category || this.category;
return `https://api.kevinmidboe.com/api/v1/tmdb/list/${category}?page=${this.currentPage}`;
@@ -104,6 +114,7 @@ export default {
this.pages = data.total_pages;
this.results = data.total_results;
}
this.unfiltered_movies = this.movies;
this.listLoaded = true;
// Change Page title
if(this.type == 'page'){
@@ -123,32 +134,51 @@ export default {
this.movies = newData;
}.bind(this));
},
updateFavorite(){
if(this.mode == 'favorite'){
let promises = [], movies = [], pages, results;
for(let i = 1; i <= this.currentPage; i++){
promises.push(axios.get(`https://api.themoviedb.org/3/account/${storage.userId}/favorite/movies?api_key=${storage.apiKey}&session_id=${storage.sessionId}&language=en-US&sort_by=created_at.desc&page=${i}`))
}
axios.all(promises).then(function(results) {
results.forEach(function(resp) {
let data = resp.data;
movies = movies.concat(data.results);
pages = data.total_pages;
results = data.total_results;
});
this.movies = movies;
this.pages = pages;
if(this.currentPage > pages){
this.currentPage -= 1;
}
this.results = results;
}.bind(this));
}
sortt() {
console.log(this.showFilters)
},
toggleFilter(item, index){
this.showFilter = this.showFilter ? false : true;
// this.results = this.results.filter(result => result.status != 'downloaded')
},
applyFilter(item, index) {
this.filter = item;
this.filters.status.selected = index;
console.log('applied query filter: ', item, index)
this.fetchCategory()
}
// updateFavorite(){
// if(this.mode == 'favorite'){
// let promises = [], movies = [], pages, results;
// for(let i = 1; i <= this.currentPage; i++){
// promises.push(axios.get(`https://api.themoviedb.org/3/account/${storage.userId}/favorite/movies?api_key=${storage.apiKey}&session_id=${storage.sessionId}&language=en-US&sort_by=created_at.desc&page=${i}`))
// }
// axios.all(promises).then(function(results) {
// results.forEach(function(resp) {
// let data = resp.data;
// movies = movies.concat(data.results);
// pages = data.total_pages;
// results = data.total_results;
// });
// this.movies = movies;
// this.pages = pages;
// if(this.currentPage > pages){
// this.currentPage -= 1;
// }
// this.results = results;
// }.bind(this));
// }
// }
},
watch: {
query(value){
this.fetchCategory(value);
filter_query: function(val, oldVal) {
let movies = this.unfiltered_movies;
val = val.toLowerCase()
if (val.length > 0)
movies = movies.filter(movie => movie.title.toLowerCase().startsWith(val))
if (movies.length > 0)
this.movies = movies;
}
},
created(){
@@ -171,7 +201,21 @@ export default {
}
}
</script>
<style lang="scss" scoped>
@import "./src/scss/media-queries";
.form__group-input {
padding: 10px 5px 10px 15px;
margin-left: 0;
height: 38px;
width: 150px;
font-size: 15px;
@include desktop-min {
width: 200px;
font-size: 17px;
}
}
</style>
<style lang="scss">
@import "./src/scss/variables";
@import "./src/scss/media-queries";
@@ -188,6 +232,7 @@ export default {
}
&__header{
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: space-between;
padding: 20px 10px;
@@ -207,6 +252,8 @@ export default {
line-height: 16px;
color: $c-dark;
font-weight: 300;
flex-basis: 50%;
@include tablet-min{
font-size: 18px;
line-height: 18px;
@@ -217,6 +264,12 @@ export default {
font-weight: 300;
letter-spacing: 0.5px;
color: rgba($c-dark, 0.5);
text-align: right;
flex-basis: 50%;
@include mobile-only {
display: none;
}
}
&__link{
font-size: 12px;
@@ -232,6 +285,71 @@ export default {
color: $c-dark;
}
}
&__filters{
margin-top: 10px;
line-height: 22px;
color: $c-dark;
font-size: 18px;
display: flex;
justify-content: flex-end;
transition: opacity 1s ease;
&__button-spacing {
@include tablet-min {
width: 15px;
}
@include mobile-only {
width: 10px;
}
}
&-list {
margin: 0px 10px;
padding: 0;
list-style: none;
border: solid 1px;
border-radius: 2px;
overflow: hidden;
display: flex;
transition: color 0.2s ease;
justify-content: space-evenly;
@include tablet-min{
margin: 0px 15px;
}
@include tablet-landscape-min {
margin: 0px 25px;
}
@include desktop-min{
margin: 0px 30px;
}
li {
padding: 6px 14px;
background-color: $c-white;
transition: color 0.2s ease;
font-size: 13px;
font-weight: 200;
text-transform: capitalize;
text-align: center;
width: 100%;
&:nth-child(n+2) {
border-left: solid 1px;
}
&.active, &:hover {
border-color: transparent;
background-color: #091c24;
color: $c-white;
cursor: pointer;
}
@include tablet-min {
font-size: 16px;
}
}
}
&-toggle {
margin-left: 15px;
}
}
&__list{
padding: 0;
margin: 0;

View File

@@ -3,9 +3,18 @@
<div class="profile__content" v-if="userLoggedIn">
<header class="profile__header">
<h2 class="profile__title">{{ emoji }} Welcome {{ userName }}</h2>
<button class="button" @click="logOut">Log Out</button>
<div>
<router-link class="" :to="{name: 'settings'}">
</router-link>
<button v-if="showSettings" class="button__active" @click="toggleSettings" style="margin-right: 2em;">Hide settings</button>
<button v-else class="button" @click="toggleSettings" style="margin-right: 2em;">Show settings</button>
<button class="button" @click="logOut">Log Out</button>
</div>
</header>
<movies-list v-for="item in listTypes" v-if="item.isProfileContent" :type="'component'" :mode="item.type" :category="item.query" :shortList="true"></movies-list>
<settings v-if="showSettings"></settings>
<movies-list v-for="item in listTypes" v-if="!showSettings && item.isProfileContent" :type="'component'" :mode="item.type" :category="item.query" :shortList="true"></movies-list>
<!-- <movies-list v-for="item in listTypes" v-if="item.isCategory" :type="'component'" :mode="item.type" :shortList="true"></movies-list> -->
<!-- <created-lists></created-lists> -->
</div>
@@ -24,15 +33,17 @@
import axios from 'axios'
import storage from '../storage.js'
import MoviesList from './MoviesList.vue'
import Settings from './Settings.vue'
// import CreatedLists from './CreatedLists.vue'
export default {
components: { MoviesList },
components: { MoviesList, Settings },
data(){
return{
userLoggedIn: '',
userName: '',
emoji: '',
showSettings: false,
listTypes: storage.listTypes
}
},
@@ -62,6 +73,9 @@ export default {
requestToken(){
eventHub.$emit('requestToken');
},
toggleSettings() {
this.showSettings = this.showSettings ? false : true;
},
logOut(){
localStorage.clear();
eventHub.$emit('setUserStatus');

View File

@@ -8,7 +8,7 @@
<form class="form">
<div class="form__buffer"></div>
<div>
<div class="center">
<div class="form__group">
<svg class="form__group__input-icon">
<use xlink:href="#iconEmail"></use>
@@ -203,6 +203,9 @@ export default {
color: #3e7549;
}
.center {
justify-content: center;
}
.form{
z-index: 15;
background-color: $c-light;
@@ -229,7 +232,6 @@ export default {
font-weight: 100;
font-size: 20px;
border: 1px solid $c-dark;
margin-bottom: 1rem;
margin-left: -2.2rem;
z-index: 3;
&:focus, &:hover {

View File

@@ -18,7 +18,7 @@
<svg class="form__group__input-icon">
<use xlink:href="#iconKeyhole"></use>
</svg>
<input class="form__group-input" type="password" ref="password" placeholder="Password">
<input class="form__group-input" type="password" ref="password" placeholder="Password" v-on:keyup.enter="signin">
</div>
<transition name="message-fade">

View File

@@ -63,7 +63,7 @@ export default {
renderName: tablet,
cols: [
{ label: 'Name', field: 'name', sort: true, hidden: tablet },
{ label: 'Seeders', field: 'seed', sort: true },
{ label: 'Seeders', field: 'seed', sort: (a, b) => parseInt(a) - parseInt(b) },
{ label: 'Size', field: 'size', sort: (a, b) => this.sortableSize(a) - this.sortableSize(b) },
{ label: 'Add', align: 'center' }
],

View File

@@ -2,7 +2,9 @@ import Vue from 'vue'
import VueRouter from 'vue-router'
import axios from 'axios'
import router from './routes'
import DataTablee from 'vue-data-tablee'
import VModal from 'vue-js-modal'
import App from './App.vue'
@@ -10,6 +12,7 @@ window.eventHub = new Vue();
Vue.use(VueRouter, axios)
Vue.use(DataTablee)
Vue.use(VModal, { dialog: true })
new Vue({
el: '#app',

View File

@@ -85,6 +85,13 @@ let routes = [
'search-router-view': require('./components/Profile.vue')
}
},
{
name: 'settings',
path: '/profile/settings',
components: {
'search-router-view': require('./components/Settings.vue')
}
},
{
name: '404',
path: '/404',
@@ -99,8 +106,8 @@ let routes = [
];
const router = new VueRouter({
mode: 'history',
base: '/request',
// mode: 'history',
base: '/request/',
routes,
linkActiveClass: 'is-active'
});

View File

@@ -6,12 +6,13 @@ let storage = {
pageTitlePostfix: ' — ' + document.title,
listTypes: [
{
title: 'Upcoming Movies',
shortTitle: 'Upcoming',
query: 'upcoming',
name: 'home-category',
type: 'collection',
isCategory: true
title: 'Your Requests',
shortTitle: 'User Requests',
query: 'user-requests',
name: 'user-requests',
type: 'user-requests',
isProfileContent: true
// isCategory: true,
},
{
title: 'Requested Movies & Shows',
@@ -22,6 +23,14 @@ let storage = {
isCategory: true,
isProfileContent: true
},
{
title: 'Upcoming Movies',
shortTitle: 'Upcoming',
query: 'upcoming',
name: 'home-category',
type: 'collection',
isCategory: true
},
{
title: 'Now Playing Movies',
shortTitle: 'Now Playing',
@@ -47,15 +56,6 @@ let storage = {
title: 'Your Favorite Movies',
query: 'favorite',
isCategory: false
},
{
title: 'Your Requests',
shortTitle: 'User Requests',
query: 'user-requests',
name: 'user-requests',
type: 'user-requests',
isProfileContent: true
// isCategory: true,
}
],
categories: {},

View File

@@ -5,7 +5,7 @@ module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/request/dist/',
publicPath: '/dist/',
filename: 'build.js'
},
module: {