mirror of
				https://github.com/TeamPiped/Piped.git
				synced 2024-08-14 23:57:27 +00:00 
			
		
		
		
	Preferences + Format code.
This commit is contained in:
		
							parent
							
								
									e853cb9840
								
							
						
					
					
						commit
						4891c57bbd
					
				
					 11 changed files with 379 additions and 219 deletions
				
			
		
							
								
								
									
										54
									
								
								src/App.vue
									
										
									
									
									
								
							
							
						
						
									
										54
									
								
								src/App.vue
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,33 +1,43 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="uk-container uk-container-expand uk-light uk-height-viewport" style="background:#0b0e0f">
 | 
			
		||||
    <nav class="uk-navbar-container uk-container-expand uk-light" style="background:#0b0e0f" uk-navbar>
 | 
			
		||||
        <div class="uk-navbar-left">
 | 
			
		||||
            <router-link class="uk-navbar-item uk-logo uk-text-bold" to="/">Piped</router-link>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="uk-navbar-right">
 | 
			
		||||
            <ul class="uk-navbar-nav">
 | 
			
		||||
                <li>
 | 
			
		||||
                    <router-link to="/login">Login</router-link>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li>
 | 
			
		||||
                    <router-link to="/feed">Feed</router-link>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
    </nav>
 | 
			
		||||
    <div
 | 
			
		||||
        class="uk-container uk-container-expand uk-light uk-height-viewport"
 | 
			
		||||
        style="background: #0b0e0f"
 | 
			
		||||
    >
 | 
			
		||||
        <nav
 | 
			
		||||
            class="uk-navbar-container uk-container-expand uk-light"
 | 
			
		||||
            style="background: #0b0e0f"
 | 
			
		||||
            uk-navbar
 | 
			
		||||
        >
 | 
			
		||||
            <div class="uk-navbar-left">
 | 
			
		||||
                <router-link class="uk-navbar-item uk-logo uk-text-bold" to="/"
 | 
			
		||||
                    >Piped</router-link
 | 
			
		||||
                >
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="uk-navbar-right">
 | 
			
		||||
                <ul class="uk-navbar-nav">
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <router-link to="/preferences">Preferences</router-link>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <router-link to="/login">Login</router-link>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li>
 | 
			
		||||
                        <router-link to="/feed">Feed</router-link>
 | 
			
		||||
                    </li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        </nav>
 | 
			
		||||
 | 
			
		||||
    <router-view />
 | 
			
		||||
</div>
 | 
			
		||||
        <router-view />
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
export default {
 | 
			
		||||
    BASE_URL: 'https://pipedapi.kavin.rocks',
 | 
			
		||||
}
 | 
			
		||||
    BASE_URL: localStorage.getItem("instance") || 'https://pipedapi.kavin.rocks',
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +1,32 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div v-if="channel">
 | 
			
		||||
    <h1 class="uk-text-center"><img v-bind:src="channel.avatarUrl">{{ channel.name }}</h1>
 | 
			
		||||
    <img v-bind:src="channel.bannerUrl" style="width: 100%">
 | 
			
		||||
    <p v-html="this.channel.description.replaceAll('\n', '<br>')"></p>
 | 
			
		||||
    <div v-if="channel">
 | 
			
		||||
        <h1 class="uk-text-center">
 | 
			
		||||
            <img v-bind:src="channel.avatarUrl" />{{ channel.name }}
 | 
			
		||||
        </h1>
 | 
			
		||||
        <img v-bind:src="channel.bannerUrl" style="width: 100%" />
 | 
			
		||||
        <p v-html="this.channel.description.replaceAll('\n', '<br>')"></p>
 | 
			
		||||
 | 
			
		||||
    <hr>
 | 
			
		||||
        <hr />
 | 
			
		||||
 | 
			
		||||
    <div class="uk-grid-small" style="width: 100%" uk-grid="parallax: 0">
 | 
			
		||||
        <div style="width: 288px" v-bind:key="item.url" v-for="item in this.channel.relatedStreams">
 | 
			
		||||
            <router-link class="uk-link-muted" style="height: 100px" v-bind:to="item.url || '/'">
 | 
			
		||||
                <img style="width: 100%" v-bind:src="item.thumbnail">
 | 
			
		||||
                <a>{{ item.title }}</a>
 | 
			
		||||
            </router-link>
 | 
			
		||||
            <br>
 | 
			
		||||
            <a>{{ timeFormat(item.duration) }}</a>
 | 
			
		||||
        <div class="uk-grid-small" style="width: 100%" uk-grid="parallax: 0">
 | 
			
		||||
            <div
 | 
			
		||||
                style="width: 288px"
 | 
			
		||||
                v-bind:key="item.url"
 | 
			
		||||
                v-for="item in this.channel.relatedStreams"
 | 
			
		||||
            >
 | 
			
		||||
                <router-link
 | 
			
		||||
                    class="uk-link-muted"
 | 
			
		||||
                    style="height: 100px"
 | 
			
		||||
                    v-bind:to="item.url || '/'"
 | 
			
		||||
                >
 | 
			
		||||
                    <img style="width: 100%" v-bind:src="item.thumbnail" />
 | 
			
		||||
                    <a>{{ item.title }}</a>
 | 
			
		||||
                </router-link>
 | 
			
		||||
                <br />
 | 
			
		||||
                <a>{{ timeFormat(item.duration) }}</a>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
| 
						 | 
				
			
			@ -25,27 +35,31 @@ import Constants from "@/Constants.js";
 | 
			
		|||
export default {
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            channel: null,
 | 
			
		||||
        }
 | 
			
		||||
            channel: null
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.getChannelData()
 | 
			
		||||
        this.getChannelData();
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        async fetchChannel() {
 | 
			
		||||
            return await (
 | 
			
		||||
                await fetch(Constants.BASE_URL + "/channels/" + this.$route.params.channelId)
 | 
			
		||||
                await fetch(
 | 
			
		||||
                    Constants.BASE_URL +
 | 
			
		||||
                        "/channels/" +
 | 
			
		||||
                        this.$route.params.channelId
 | 
			
		||||
                )
 | 
			
		||||
            ).json();
 | 
			
		||||
        },
 | 
			
		||||
        async getChannelData() {
 | 
			
		||||
            this.fetchChannel().then(data => this.channel = data)
 | 
			
		||||
                .then(() => document.title = this.channel.name + " - Piped")
 | 
			
		||||
            this.fetchChannel()
 | 
			
		||||
                .then(data => (this.channel = data))
 | 
			
		||||
                .then(() => (document.title = this.channel.name + " - Piped"));
 | 
			
		||||
        },
 | 
			
		||||
        timeFormat(duration) {
 | 
			
		||||
 | 
			
		||||
            var pad = function (num, size) {
 | 
			
		||||
                return ('000' + num).slice(size * -1);
 | 
			
		||||
            }
 | 
			
		||||
            var pad = function(num, size) {
 | 
			
		||||
                return ("000" + num).slice(size * -1);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var time = parseFloat(duration).toFixed(3),
 | 
			
		||||
                hours = Math.floor(time / 60 / 60),
 | 
			
		||||
| 
						 | 
				
			
			@ -54,14 +68,12 @@ export default {
 | 
			
		|||
 | 
			
		||||
            var str = "";
 | 
			
		||||
 | 
			
		||||
            if (hours > 0)
 | 
			
		||||
                str += pad(hours, 2) + ":"
 | 
			
		||||
            if (hours > 0) str += pad(hours, 2) + ":";
 | 
			
		||||
 | 
			
		||||
            str += pad(minutes, 2) + ':' + pad(seconds, 2)
 | 
			
		||||
            str += pad(minutes, 2) + ":" + pad(seconds, 2);
 | 
			
		||||
 | 
			
		||||
            return str;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										79
									
								
								src/components/Preferences.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/components/Preferences.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
<template>
 | 
			
		||||
    <table class="uk-table">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th>Instance Name</th>
 | 
			
		||||
                <th>Instance Locations</th>
 | 
			
		||||
                <th>Has CDN?</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody v-bind:key="instance.name" v-for="instance in instances">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{{ instance.name }}</td>
 | 
			
		||||
                <td>{{ instance.locations }}</td>
 | 
			
		||||
                <td>{{ instance.cdn }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
 | 
			
		||||
    <select
 | 
			
		||||
        class="uk-select"
 | 
			
		||||
        v-model="selectedInstance"
 | 
			
		||||
        @change="onChange($event)"
 | 
			
		||||
    >
 | 
			
		||||
        <option
 | 
			
		||||
            v-bind:key="instance.name"
 | 
			
		||||
            v-for="instance in instances"
 | 
			
		||||
            v-bind:value="instance.apiurl"
 | 
			
		||||
        >
 | 
			
		||||
            {{ instance.name }}
 | 
			
		||||
        </option>
 | 
			
		||||
    </select>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            selectedInstance: null,
 | 
			
		||||
            instances: []
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        fetch(
 | 
			
		||||
            "https://raw.githubusercontent.com/wiki/TeamPiped/Piped-Frontend/Instances.md"
 | 
			
		||||
        )
 | 
			
		||||
            .then(resp => resp.text())
 | 
			
		||||
            .then(body => {
 | 
			
		||||
                var skipped = 0;
 | 
			
		||||
                const lines = body.split("\n");
 | 
			
		||||
                lines.map(line => {
 | 
			
		||||
                    const split = line.split("|");
 | 
			
		||||
                    if (split.length == 4) {
 | 
			
		||||
                        if (skipped < 2) {
 | 
			
		||||
                            skipped++;
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        this.instances.push({
 | 
			
		||||
                            name: split[0].trim(),
 | 
			
		||||
                            apiurl: split[1].trim(),
 | 
			
		||||
                            locations: split[2].trim(),
 | 
			
		||||
                            cdn: split[3].trim()
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        if (localStorage)
 | 
			
		||||
            this.selectedInstance =
 | 
			
		||||
                localStorage.getItem("instance") ||
 | 
			
		||||
                "https://pipedapi.kavin.rocks";
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        onChange() {
 | 
			
		||||
            if (localStorage)
 | 
			
		||||
                localStorage.setItem("instance", this.selectedInstance);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,45 +1,58 @@
 | 
			
		|||
<template>
 | 
			
		||||
<h1 class="uk-text-bold uk-text-center">Trending</h1>
 | 
			
		||||
 | 
			
		||||
<hr>
 | 
			
		||||
 | 
			
		||||
<div class="uk-grid-collapse" style="width: 100%" uk-grid="parallax: 0">
 | 
			
		||||
    <div class="uk-tile-default" style="width: 300px; background: #0b0e0f" v-bind:key="video.url" v-for="video in videos">
 | 
			
		||||
        <div class="uk-card uk-card-default uk-card-body uk-grid-match uk-text-secondary" style="background: #0b0e0f">
 | 
			
		||||
            <router-link class="uk-text-emphasis" v-bind:to="video.url || '/'">
 | 
			
		||||
                <p>{{ video.title }}</p>
 | 
			
		||||
                <img style="width: 100%" v-bind:src="video.thumbnail" />
 | 
			
		||||
            </router-link>
 | 
			
		||||
            <router-link class="uk-link-muted" v-bind:to="video.uploaderUrl || '/'">
 | 
			
		||||
                <p>{{ video.uploaderName }}</p>
 | 
			
		||||
            </router-link>
 | 
			
		||||
            <font-awesome-icon icon="eye"></font-awesome-icon> {{ video.views }} views
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Constants from '@/Constants.js'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            videos: [],
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
 | 
			
		||||
        document.title = "Trending - Piped";
 | 
			
		||||
 | 
			
		||||
        this.fetchTrending().then(videos => this.videos = videos)
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        async fetchTrending() {
 | 
			
		||||
            return await (
 | 
			
		||||
                await fetch(Constants.BASE_URL + "/trending")
 | 
			
		||||
            ).json();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<template>
 | 
			
		||||
    <h1 class="uk-text-bold uk-text-center">Trending</h1>
 | 
			
		||||
 | 
			
		||||
    <hr />
 | 
			
		||||
 | 
			
		||||
    <div class="uk-grid-collapse" style="width: 100%" uk-grid="parallax: 0">
 | 
			
		||||
        <div
 | 
			
		||||
            class="uk-tile-default"
 | 
			
		||||
            style="width: 300px; background: #0b0e0f"
 | 
			
		||||
            v-bind:key="video.url"
 | 
			
		||||
            v-for="video in videos"
 | 
			
		||||
        >
 | 
			
		||||
            <div
 | 
			
		||||
                class="uk-card uk-card-default uk-card-body uk-grid-match uk-text-secondary"
 | 
			
		||||
                style="background: #0b0e0f"
 | 
			
		||||
            >
 | 
			
		||||
                <router-link
 | 
			
		||||
                    class="uk-text-emphasis"
 | 
			
		||||
                    v-bind:to="video.url || '/'"
 | 
			
		||||
                >
 | 
			
		||||
                    <p>{{ video.title }}</p>
 | 
			
		||||
                    <img style="width: 100%" v-bind:src="video.thumbnail" />
 | 
			
		||||
                </router-link>
 | 
			
		||||
                <router-link
 | 
			
		||||
                    class="uk-link-muted"
 | 
			
		||||
                    v-bind:to="video.uploaderUrl || '/'"
 | 
			
		||||
                >
 | 
			
		||||
                    <p>{{ video.uploaderName }}</p>
 | 
			
		||||
                </router-link>
 | 
			
		||||
                <font-awesome-icon icon="eye"></font-awesome-icon>
 | 
			
		||||
                {{ video.views }} views
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Constants from "@/Constants.js";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            videos: []
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        document.title = "Trending - Piped";
 | 
			
		||||
        console.log(Constants.BASE_URL);
 | 
			
		||||
 | 
			
		||||
        this.fetchTrending().then(videos => (this.videos = videos));
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        async fetchTrending() {
 | 
			
		||||
            return await (await fetch(Constants.BASE_URL + "/trending")).json();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,42 +1,56 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="uk-container uk-container-xlarge">
 | 
			
		||||
    <h1 class="uk-text-bold">{{ video.title }}</h1>
 | 
			
		||||
    <video controls ref="player" class="video-js preview-player-dimensions "></video>
 | 
			
		||||
    <div class="uk-container uk-container-xlarge">
 | 
			
		||||
        <h1 class="uk-text-bold">{{ video.title }}</h1>
 | 
			
		||||
        <video
 | 
			
		||||
            controls
 | 
			
		||||
            ref="player"
 | 
			
		||||
            class="video-js preview-player-dimensions"
 | 
			
		||||
        ></video>
 | 
			
		||||
 | 
			
		||||
    <img :src="video.uploaderAvatar" />
 | 
			
		||||
    <router-link class="uk-text-bold" v-bind:to="video.uploaderUrl || '/'">
 | 
			
		||||
        <a>{{ video.uploader }}</a>
 | 
			
		||||
    </router-link>
 | 
			
		||||
 | 
			
		||||
    <p class="uk-dark">
 | 
			
		||||
        <font-awesome-icon icon="thumbs-down"></font-awesome-icon>
 | 
			
		||||
        {{ video.likes }}
 | 
			
		||||
        <font-awesome-icon icon="thumbs-up"></font-awesome-icon>
 | 
			
		||||
        {{ video.dislikes }}
 | 
			
		||||
    </p>
 | 
			
		||||
    <p>
 | 
			
		||||
        <font-awesome-icon icon="eye"></font-awesome-icon> {{ video.views }} views
 | 
			
		||||
    </p>
 | 
			
		||||
    <p class="uk-light" v-html="video.description"></p>
 | 
			
		||||
    <a v-if="sponsors && sponsors.segments">Sponsors Segments: {{ sponsors.segments.length }}</a>
 | 
			
		||||
 | 
			
		||||
    <hr>
 | 
			
		||||
 | 
			
		||||
    <div class="uk-tile-default uk-text-secondary" style="background: #0b0e0f; width: 300px" v-bind:key="related.url" v-for="related in video.relatedStreams">
 | 
			
		||||
        <router-link class="uk-link-muted" v-bind:to="related.url">
 | 
			
		||||
            <p class="uk-text-emphasis">{{ related.title }}</p>
 | 
			
		||||
            <img style="width: 100%" v-bind:src="related.thumbnail" />
 | 
			
		||||
        <img :src="video.uploaderAvatar" />
 | 
			
		||||
        <router-link class="uk-text-bold" v-bind:to="video.uploaderUrl || '/'">
 | 
			
		||||
            <a>{{ video.uploader }}</a>
 | 
			
		||||
        </router-link>
 | 
			
		||||
        <p>
 | 
			
		||||
            <router-link class="uk-link-muted" v-bind:to="related.uploaderUrl || '/'">
 | 
			
		||||
                <p>{{ related.uploaderName }}</p>
 | 
			
		||||
            </router-link>
 | 
			
		||||
            <font-awesome-icon icon="eye"></font-awesome-icon>
 | 
			
		||||
            {{ related.views }} views
 | 
			
		||||
        </p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
        <p class="uk-dark">
 | 
			
		||||
            <font-awesome-icon icon="thumbs-down"></font-awesome-icon>
 | 
			
		||||
            {{ video.likes }}
 | 
			
		||||
            <font-awesome-icon icon="thumbs-up"></font-awesome-icon>
 | 
			
		||||
            {{ video.dislikes }}
 | 
			
		||||
        </p>
 | 
			
		||||
        <p>
 | 
			
		||||
            <font-awesome-icon icon="eye"></font-awesome-icon>
 | 
			
		||||
            {{ video.views }} views
 | 
			
		||||
        </p>
 | 
			
		||||
        <p class="uk-light" v-html="video.description"></p>
 | 
			
		||||
        <a v-if="sponsors && sponsors.segments"
 | 
			
		||||
            >Sponsors Segments: {{ sponsors.segments.length }}</a
 | 
			
		||||
        >
 | 
			
		||||
 | 
			
		||||
        <hr />
 | 
			
		||||
 | 
			
		||||
        <div
 | 
			
		||||
            class="uk-tile-default uk-text-secondary"
 | 
			
		||||
            style="background: #0b0e0f; width: 300px"
 | 
			
		||||
            v-bind:key="related.url"
 | 
			
		||||
            v-for="related in video.relatedStreams"
 | 
			
		||||
        >
 | 
			
		||||
            <router-link class="uk-link-muted" v-bind:to="related.url">
 | 
			
		||||
                <p class="uk-text-emphasis">{{ related.title }}</p>
 | 
			
		||||
                <img style="width: 100%" v-bind:src="related.thumbnail" />
 | 
			
		||||
            </router-link>
 | 
			
		||||
            <p>
 | 
			
		||||
                <router-link
 | 
			
		||||
                    class="uk-link-muted"
 | 
			
		||||
                    v-bind:to="related.uploaderUrl || '/'"
 | 
			
		||||
                >
 | 
			
		||||
                    <p>{{ related.uploaderName }}</p>
 | 
			
		||||
                </router-link>
 | 
			
		||||
                <font-awesome-icon icon="eye"></font-awesome-icon>
 | 
			
		||||
                {{ related.views }} views
 | 
			
		||||
            </p>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
| 
						 | 
				
			
			@ -52,11 +66,11 @@ export default {
 | 
			
		|||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            video: {
 | 
			
		||||
                title: "Loading...",
 | 
			
		||||
                title: "Loading..."
 | 
			
		||||
            },
 | 
			
		||||
            player: null,
 | 
			
		||||
            audioplayer: null,
 | 
			
		||||
            sponsors: null,
 | 
			
		||||
            sponsors: null
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
| 
						 | 
				
			
			@ -68,37 +82,45 @@ export default {
 | 
			
		|||
            this.player.dispose();
 | 
			
		||||
        }
 | 
			
		||||
        if (this.audioplayer) {
 | 
			
		||||
            this.audioplayer.pause()
 | 
			
		||||
            this.audioplayer.pause();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    watch: {
 | 
			
		||||
        "$route.query.v": function (v) {
 | 
			
		||||
        "$route.query.v": function(v) {
 | 
			
		||||
            if (v) {
 | 
			
		||||
                if (this.audioplayer)
 | 
			
		||||
                    this.audioplayer.pause()
 | 
			
		||||
                if (this.audioplayer) this.audioplayer.pause();
 | 
			
		||||
                this.getVideoData();
 | 
			
		||||
                this.getSponsors();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        async fetchVideo() {
 | 
			
		||||
            return await (
 | 
			
		||||
                await fetch(Constants.BASE_URL + "/streams/" + this.$route.query.v)
 | 
			
		||||
                await fetch(
 | 
			
		||||
                    Constants.BASE_URL + "/streams/" + this.$route.query.v
 | 
			
		||||
                )
 | 
			
		||||
            ).json();
 | 
			
		||||
        },
 | 
			
		||||
        async fetchSponsors() {
 | 
			
		||||
            return await (
 | 
			
		||||
                await fetch(Constants.BASE_URL + "/sponsors/" + this.$route.query.v + "?category=[\"sponsor\",\"interaction\",\"selfpromo\",\"music_offtopic\"]")
 | 
			
		||||
                await fetch(
 | 
			
		||||
                    Constants.BASE_URL +
 | 
			
		||||
                        "/sponsors/" +
 | 
			
		||||
                        this.$route.query.v +
 | 
			
		||||
                        '?category=["sponsor","interaction","selfpromo","music_offtopic"]'
 | 
			
		||||
                )
 | 
			
		||||
            ).json();
 | 
			
		||||
        },
 | 
			
		||||
        async getVideoData() {
 | 
			
		||||
            this.fetchVideo()
 | 
			
		||||
                .then((data) => (this.video = data))
 | 
			
		||||
                .then(data => (this.video = data))
 | 
			
		||||
                .then(() => {
 | 
			
		||||
                    document.title = this.video.title + " - Piped";
 | 
			
		||||
 | 
			
		||||
                    this.video.description = this.video.description.replaceAll("http://www.youtube.com", "").replaceAll("https://www.youtube.com", "")
 | 
			
		||||
                    this.video.description = this.video.description
 | 
			
		||||
                        .replaceAll("http://www.youtube.com", "")
 | 
			
		||||
                        .replaceAll("https://www.youtube.com", "");
 | 
			
		||||
 | 
			
		||||
                    const options = {
 | 
			
		||||
                        autoplay: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -110,22 +132,23 @@ export default {
 | 
			
		|||
                                "volumePanel",
 | 
			
		||||
                                "qualitySelector",
 | 
			
		||||
                                "captionsButton",
 | 
			
		||||
                                "fullscreenToggle",
 | 
			
		||||
                            ],
 | 
			
		||||
                                "fullscreenToggle"
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
                        responsive: false,
 | 
			
		||||
                        aspectRatio: '16:9'
 | 
			
		||||
                        aspectRatio: "16:9"
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    const noPrevPlayer = !this.player
 | 
			
		||||
                    const noPrevPlayer = !this.player;
 | 
			
		||||
 | 
			
		||||
                    if (noPrevPlayer) this.player = videojs(this.$refs.player, options);
 | 
			
		||||
                    if (noPrevPlayer)
 | 
			
		||||
                        this.player = videojs(this.$refs.player, options);
 | 
			
		||||
 | 
			
		||||
                    this.player.hotkeys({
 | 
			
		||||
                        volumeStep: 0.1,
 | 
			
		||||
                        seekStep: 5,
 | 
			
		||||
                        enableModifiersForNumbers: false,
 | 
			
		||||
                        enableHoverScroll: true,
 | 
			
		||||
                        enableHoverScroll: true
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    this.player.poster(this.video.thumbnailUrl);
 | 
			
		||||
| 
						 | 
				
			
			@ -133,96 +156,110 @@ export default {
 | 
			
		|||
                    var src = [];
 | 
			
		||||
 | 
			
		||||
                    if (this.video.livestream) {
 | 
			
		||||
 | 
			
		||||
                        src.push({
 | 
			
		||||
                            src: this.video.hls,
 | 
			
		||||
                            type: 'application/x-mpegURL'
 | 
			
		||||
                        })
 | 
			
		||||
 | 
			
		||||
                            type: "application/x-mpegURL"
 | 
			
		||||
                        });
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this.video.videoStreams.map((stream) =>
 | 
			
		||||
                        this.video.videoStreams.map(stream =>
 | 
			
		||||
                            src.push({
 | 
			
		||||
                                src: stream.url,
 | 
			
		||||
                            type: stream.mimeType,
 | 
			
		||||
                            label: stream.quality,
 | 
			
		||||
                        })
 | 
			
		||||
                    );
 | 
			
		||||
                                type: stream.mimeType,
 | 
			
		||||
                                label: stream.quality
 | 
			
		||||
                            })
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                    this.video.audioStreams.map((stream) =>
 | 
			
		||||
                        src.push({
 | 
			
		||||
                            src: stream.url,
 | 
			
		||||
                            type: stream.mimeType,
 | 
			
		||||
                                label: stream.quality,
 | 
			
		||||
                        this.video.audioStreams.map(stream =>
 | 
			
		||||
                            src.push({
 | 
			
		||||
                                src: stream.url,
 | 
			
		||||
                                type: stream.mimeType,
 | 
			
		||||
                                label: stream.quality
 | 
			
		||||
                            })
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    this.audioplayer = new Audio((this.video.audioStreams.slice(-1)[0].url));
 | 
			
		||||
                    this.audioplayer = new Audio(
 | 
			
		||||
                        this.video.audioStreams.slice(-1)[0].url
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
                    this.player.src(src);
 | 
			
		||||
 | 
			
		||||
                    if (noPrevPlayer) {
 | 
			
		||||
                        this.player.on('timeupdate', () => {
 | 
			
		||||
                        this.player.on("timeupdate", () => {
 | 
			
		||||
                            if (this.sponsors && this.sponsors.segments) {
 | 
			
		||||
                                const time = this.player.currentTime()
 | 
			
		||||
                                const time = this.player.currentTime();
 | 
			
		||||
                                this.sponsors.segments.map(segment => {
 | 
			
		||||
                                    if (!segment.skipped) {
 | 
			
		||||
                                        const end = segment.segment[1]
 | 
			
		||||
                                        if (time >= segment.segment[0] && time < end) {
 | 
			
		||||
                                            this.player.currentTime(end)
 | 
			
		||||
                                            this.audioplayer.currentTime = end
 | 
			
		||||
                                            segment.skipped = true
 | 
			
		||||
                                            return
 | 
			
		||||
                                        const end = segment.segment[1];
 | 
			
		||||
                                        if (
 | 
			
		||||
                                            time >= segment.segment[0] &&
 | 
			
		||||
                                            time < end
 | 
			
		||||
                                        ) {
 | 
			
		||||
                                            this.player.currentTime(end);
 | 
			
		||||
                                            this.audioplayer.currentTime = end;
 | 
			
		||||
                                            segment.skipped = true;
 | 
			
		||||
                                            return;
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                })
 | 
			
		||||
                                });
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            if (this.audioplayer) {
 | 
			
		||||
 | 
			
		||||
                                const delay = this.audioplayer.currentTime - this.player.currentTime()
 | 
			
		||||
                                const delay =
 | 
			
		||||
                                    this.audioplayer.currentTime -
 | 
			
		||||
                                    this.player.currentTime();
 | 
			
		||||
 | 
			
		||||
                                if (Math.abs(delay) > 0.1) {
 | 
			
		||||
                                    this.audioplayer.currentTime = this.player.currentTime() - delay
 | 
			
		||||
                                    this.audioplayer.currentTime =
 | 
			
		||||
                                        this.player.currentTime() - delay;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        this.player.on('play', () => {
 | 
			
		||||
                            this.audioplayer.play()
 | 
			
		||||
                        this.player.on("play", () => {
 | 
			
		||||
                            this.audioplayer.play();
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        this.player.on('pause', () => {
 | 
			
		||||
                            this.audioplayer.currentTime = this.player.currentTime()
 | 
			
		||||
                            this.audioplayer.pause()
 | 
			
		||||
                        this.player.on("pause", () => {
 | 
			
		||||
                            this.audioplayer.currentTime = this.player.currentTime();
 | 
			
		||||
                            this.audioplayer.pause();
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        this.player.on('volumechange', () => {
 | 
			
		||||
                            this.audioplayer.volume = this.player.volume()
 | 
			
		||||
                        })
 | 
			
		||||
 | 
			
		||||
                        this.player.on("volumechange", () => {
 | 
			
		||||
                            this.audioplayer.volume = this.player.volume();
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (!noPrevPlayer)
 | 
			
		||||
                        this.player.remoteTextTracks().map(track => this.player.removeRemoteTextTrack(track));
 | 
			
		||||
                        this.player
 | 
			
		||||
                            .remoteTextTracks()
 | 
			
		||||
                            .map(track =>
 | 
			
		||||
                                this.player.removeRemoteTextTrack(track)
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                    this.video.subtitles.map(subtitle => {
 | 
			
		||||
                        this.player.addRemoteTextTrack({
 | 
			
		||||
                            kind: "captions",
 | 
			
		||||
                            src: subtitle.url.replace("fmt=ttml", "fmt=vtt"),
 | 
			
		||||
                            label: "Track",
 | 
			
		||||
                            type: "captions/captions.vtt"
 | 
			
		||||
                        }, false).mode = "showing"
 | 
			
		||||
                    })
 | 
			
		||||
                        this.player.addRemoteTextTrack(
 | 
			
		||||
                            {
 | 
			
		||||
                                kind: "captions",
 | 
			
		||||
                                src: subtitle.url.replace(
 | 
			
		||||
                                    "fmt=ttml",
 | 
			
		||||
                                    "fmt=vtt"
 | 
			
		||||
                                ),
 | 
			
		||||
                                label: "Track",
 | 
			
		||||
                                type: "captions/captions.vtt"
 | 
			
		||||
                            },
 | 
			
		||||
                            false
 | 
			
		||||
                        ).mode = "showing";
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    //const parent = this.player.el().querySelector(".vjs-progress-holder")
 | 
			
		||||
                    //TODO: Add sponsors on seekbar: https://github.com/ajayyy/SponsorBlock/blob/e39de9fd852adb9196e0358ed827ad38d9933e29/src/js-components/previewBar.ts#L12
 | 
			
		||||
 | 
			
		||||
                });
 | 
			
		||||
        },
 | 
			
		||||
        async getSponsors() {
 | 
			
		||||
            this.fetchSponsors().then((data) => (this.sponsors = data));
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
            this.fetchSponsors().then(data => (this.sponsors = data));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										36
									
								
								src/main.js
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								src/main.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,18 +1,18 @@
 | 
			
		|||
import { createApp } from 'vue'
 | 
			
		||||
import { library } from '@fortawesome/fontawesome-svg-core'
 | 
			
		||||
import { faThumbsUp, faThumbsDown, faEye } from '@fortawesome/free-solid-svg-icons'
 | 
			
		||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
 | 
			
		||||
library.add(faThumbsUp, faThumbsDown, faEye)
 | 
			
		||||
 | 
			
		||||
require("uikit/src/less/uikit.less")
 | 
			
		||||
require("uikit/dist/js/uikit.min.js")
 | 
			
		||||
 | 
			
		||||
import router from '@/router/router'
 | 
			
		||||
import App from './App.vue'
 | 
			
		||||
 | 
			
		||||
import './registerServiceWorker'
 | 
			
		||||
 | 
			
		||||
const app = createApp(App)
 | 
			
		||||
app.use(router)
 | 
			
		||||
app.component('font-awesome-icon', FontAwesomeIcon)
 | 
			
		||||
app.mount('#app')
 | 
			
		||||
import { createApp } from 'vue'
 | 
			
		||||
import { library } from '@fortawesome/fontawesome-svg-core'
 | 
			
		||||
import { faThumbsUp, faThumbsDown, faEye } from '@fortawesome/free-solid-svg-icons'
 | 
			
		||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
 | 
			
		||||
library.add(faThumbsUp, faThumbsDown, faEye)
 | 
			
		||||
 | 
			
		||||
require("uikit/src/less/uikit.less")
 | 
			
		||||
require("uikit/dist/js/uikit.min.js")
 | 
			
		||||
 | 
			
		||||
import router from '@/router/router'
 | 
			
		||||
import App from './App.vue'
 | 
			
		||||
 | 
			
		||||
import './registerServiceWorker'
 | 
			
		||||
 | 
			
		||||
const app = createApp(App)
 | 
			
		||||
app.use(router)
 | 
			
		||||
app.component('font-awesome-icon', FontAwesomeIcon)
 | 
			
		||||
app.mount('#app')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ if (process.env.NODE_ENV === 'production') {
 | 
			
		|||
        },
 | 
			
		||||
        updated() {
 | 
			
		||||
            console.log('New content is available; please refresh.')
 | 
			
		||||
            caches.keys().then(function(names) {
 | 
			
		||||
            caches.keys().then(function (names) {
 | 
			
		||||
                for (let name of names) caches.delete(name);
 | 
			
		||||
            })
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
 | 
			
		|||
import Watch from '../components/WatchVideo.vue'
 | 
			
		||||
import Trending from '../components/TrendingPage.vue'
 | 
			
		||||
import Channel from '../components/Channel.vue'
 | 
			
		||||
import Preferences from '../components/Preferences.vue'
 | 
			
		||||
 | 
			
		||||
const routes = [{
 | 
			
		||||
    path: '/watch',
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +16,10 @@ const routes = [{
 | 
			
		|||
    path: '/channel/:channelId',
 | 
			
		||||
    name: 'Channel',
 | 
			
		||||
    component: Channel
 | 
			
		||||
}, {
 | 
			
		||||
    path: '/preferences',
 | 
			
		||||
    name: 'Preferences',
 | 
			
		||||
    component: Preferences
 | 
			
		||||
}]
 | 
			
		||||
 | 
			
		||||
const router = createRouter({
 | 
			
		||||
| 
						 | 
				
			
			@ -22,4 +27,4 @@ const router = createRouter({
 | 
			
		|||
    routes
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default router
 | 
			
		||||
export default router
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue