Barely working

This commit is contained in:
2021-12-30 01:30:40 +03:00
parent e6d6dc4ca3
commit f9f2efcad0
24 changed files with 1237 additions and 160 deletions

View File

@@ -6,7 +6,7 @@ module.exports = {
extends: [
'plugin:vue/vue3-essential',
'@vue/airbnb',
'@vue/typescript/recommended',
'@vue/eslint-config-typescript',
],
parserOptions: {
ecmaVersion: 2020,
@@ -15,4 +15,15 @@ module.exports = {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
},
// settings: {
// 'import/resolver': {
// alias: {
// map: [['@', './src/']],
// extensions: ['.js', '.ts', '.vue'],
// },
// "node": {
// "paths": ["src"]
// },
// },
// },
};

5
.gitignore vendored
View File

@@ -2,10 +2,7 @@
node_modules
/dist
# local env files
.env.local
.env.*.local
.env
# Log files
npm-debug.log*

986
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
{
"name": "watch2gether-front",
"version": "0.1.0",
"author": "Anatoly Kopyl",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@@ -8,12 +9,15 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.24.0",
"core-js": "^3.6.5",
"reset-css": "^5.0.1",
"vue": "^3.0.0",
"vue-router": "^4.0.0-0",
"vuex": "^4.0.0-0"
},
"devDependencies": {
"@types/koa": "^2.13.4",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"@vue/cli-plugin-babel": "~4.5.0",
@@ -24,10 +28,10 @@
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"@vue/eslint-config-airbnb": "^5.0.2",
"@vue/eslint-config-typescript": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-vue": "^7.0.0",
"eslint-plugin-vue": "^7.0.0-beta.4",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"typescript": "~4.1.5"

View File

@@ -1,30 +1,7 @@
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</template>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
@import '@/scss/style.scss'
</style>

8
src/api/index.ts Normal file
View File

@@ -0,0 +1,8 @@
import axios from 'axios';
const api = axios.create({
baseURL: process.env.VUE_APP_API,
withCredentials: true,
});
export default api;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -1,63 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" target="_blank" rel="noopener">typescript</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'HelloWorld',
props: {
msg: String,
},
});
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

9
src/interfaces.ts Normal file
View File

@@ -0,0 +1,9 @@
export interface Room {
id: string;
magnet: string;
createdAt: Date;
movie?: string;
downloaded?: boolean;
downloadedAt?: Date;
position: number;
}

View File

@@ -3,4 +3,8 @@ import App from './App.vue';
import router from './router';
import store from './store';
createApp(App).use(store).use(router).mount('#app');
const app = createApp(App);
app.use(store);
app.use(router);
app.mount('#app');

View File

@@ -1,5 +1,6 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Home from '../views/Home.vue';
import Home from '@/views/Home/Index.vue';
import Room from '@/views/Room/Index.vue';
const routes: Array<RouteRecordRaw> = [
{
@@ -8,12 +9,10 @@ const routes: Array<RouteRecordRaw> = [
component: Home,
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
path: '/room/:id',
name: 'Room',
props: true,
component: Room,
},
];

0
src/scss/_variables.scss Normal file
View File

5
src/scss/style.scss Normal file
View File

@@ -0,0 +1,5 @@
@import 'reset-css';
* {
text-align: center;
}

View File

@@ -1,5 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

View File

@@ -1,18 +0,0 @@
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
export default defineComponent({
name: 'Home',
components: {
HelloWorld,
},
});
</script>

36
src/views/Home/Index.vue Normal file
View File

@@ -0,0 +1,36 @@
<template>
<div class="home">
<input
type="text"
v-model="magnet"
placeholder="magnet"
>
<button
@click="submit"
>
Create room
</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import createRoom from './createRoom';
import { Room } from '@/interfaces';
export default defineComponent({
name: 'Home',
data() {
return {
magnet: '',
};
},
methods: {
async submit() {
const room: Room = await createRoom(this.magnet);
this.$router.push({ name: 'Room', params: { id: room.id } });
},
},
});
</script>

View File

@@ -0,0 +1,5 @@
import api from '@/api/index';
export default (magnet:String) => api.post('/room', {
magnet,
}).then((response) => response.data);

123
src/views/Room/Index.vue Normal file
View File

@@ -0,0 +1,123 @@
<template>
<div class="room">
<h1>{{ room.movie }}</h1>
<div v-if="!room.downloaded">
<div>{{ progressPerc }}%</div>
<ProgressBar
:progress="progress"
class="progress-bar"
/>
</div>
<video
v-if="room.downloaded"
controls
:src="movieUrl"
ref="video"
@seeked="seeked"
@play="playing = true"
@pause="playing = false"
>
</video>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import getRoom from './getRoom';
import getStatus from './getStatus';
import setPosition from './setPosition';
import getPosition from './getPosition';
import ProgressBar from './components/ProgressBar.vue';
import { Room } from '@/interfaces';
export default defineComponent({
name: 'Room',
components: {
ProgressBar,
},
props: {
id: {
type: String,
required: true,
},
},
data() {
return {
room: {} as Room,
progress: 0,
playing: false,
progressInterval: undefined as undefined | number,
positionInterval: undefined as undefined | number,
};
},
computed: {
movieUrl() {
return `${process.env.VUE_APP_MOVIES}?id=${this.room.id}`;
},
progressPerc() {
return Math.floor(this.progress * 100);
},
},
async mounted() {
this.room = await getRoom(this.id);
if (!this.room.downloaded) {
this.progressInterval = setInterval(async () => {
const result = await getStatus(this.id);
this.progress = result.progress;
if (result.downloaded) {
this.room.downloaded = true;
clearInterval(this.progressInterval);
}
}, 2 * 1000);
} else {
this.room.downloaded = true;
this.$nextTick(() => {
const element = this.$refs.video as HTMLVideoElement;
this.positionInterval = setInterval(async () => {
if (this.playing) {
const serverPosition = await getPosition(this.id);
// this.room.position = element.currentTime;
if (Math.abs(this.room.position - serverPosition) > 2) {
this.room.position = serverPosition;
element.currentTime = serverPosition;
console.log('Synced');
}
}
}, 2 * 1000);
});
}
},
beforeUnmount() {
clearInterval(this.progressInterval);
clearInterval(this.positionInterval);
},
methods: {
seeked() {
const element = this.$refs.video as HTMLVideoElement;
const position = element.currentTime;
setPosition(this.id, position);
},
},
});
</script>
<style lang="scss" scoped>
h1 {
font-size: 32px;
}
.progress-bar {
width: 400px;
height: 25px;
border: 1px solid black;
margin: auto;
}
video {
width: 800px;
max-width: 100%;
}
</style>

View File

@@ -0,0 +1,30 @@
<template>
<div>
<div
class="fill"
:style="{
width: `${progress * 100}%`
}"
/>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
props: {
progress: {
type: Number,
default: 0,
},
},
});
</script>
<class lang="scss" scoped>
.fill {
background: lightblue;
height: 100%;
}
</class>

View File

@@ -0,0 +1,7 @@
import api from '@/api/index';
export default (id: String) => api.get('/position', {
params: {
id,
},
}).then((response) => response.data.position);

View File

@@ -0,0 +1,7 @@
import api from '@/api/index';
export default (id:String) => api.get('/room', {
params: {
id,
},
}).then((response) => response.data);

View File

@@ -0,0 +1,7 @@
import api from '@/api/index';
export default (id: String) => api.get('/status', {
params: {
id,
},
}).then((response) => response.data);

View File

@@ -0,0 +1,6 @@
import api from '@/api/index';
export default (id: String, position: number) => api.post('/position', {
id,
position,
}).then((response) => response.data);

12
vue.config.js Normal file
View File

@@ -0,0 +1,12 @@
module.exports = {
css: {
loaderOptions: {
sass: {
prependData: `
@use 'sass:math';
@import '~@/scss/_variables.scss';
`,
},
},
},
};