Merge pull request #116 from TeamPiped/fix/prettier-config

Add Prettier config and format code
This commit is contained in:
Maurice Oegerli 2021-04-07 14:20:05 +02:00 committed by GitHub
commit 4700b198e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 336 additions and 525 deletions

2
.prettierignore Normal file
View file

@ -0,0 +1,2 @@
dist
node_modules

11
.prettierrc.json Normal file
View file

@ -0,0 +1,11 @@
{
"singleQuote": false,
"trailingComma": "all",
"semi": true,
"tabWidth": 4,
"embeddedLanguageFormatting": "auto",
"endOfLine": "lf",
"printWidth": 120,
"vueIndentScriptAndStyle": false,
"quoteProps": "as-needed"
}

View file

@ -8,15 +8,11 @@
<div style="text-align: center"> <div style="text-align: center">
<a href="https://github.com/TeamPiped/Piped"> <a href="https://github.com/TeamPiped/Piped">
<font-awesome-icon <font-awesome-icon :icon="['fab', 'github']"></font-awesome-icon>
:icon="['fab', 'github']"
></font-awesome-icon>
</a> </a>
&nbsp; &nbsp;
<a href="bitcoin://13MoHioctZkC7LDSZSb4m32TDT8xNmei1p"> <a href="bitcoin://13MoHioctZkC7LDSZSb4m32TDT8xNmei1p">
<font-awesome-icon <font-awesome-icon :icon="['fab', 'bitcoin']"></font-awesome-icon>
:icon="['fab', 'bitcoin']"
></font-awesome-icon>
13MoHioctZkC7LDSZSb4m32TDT8xNmei1p 13MoHioctZkC7LDSZSb4m32TDT8xNmei1p
</a> </a>
</div> </div>

View file

@ -1,4 +1,4 @@
export default { export default {
BASE_URL: localStorage.getItem("instance") || 'https://pipedapi.kavin.rocks', BASE_URL: localStorage.getItem("instance") || "https://pipedapi.kavin.rocks",
AUTO_PLAY: localStorage.getItem("autoplay") || false AUTO_PLAY: localStorage.getItem("autoplay") || false,
} };

View file

@ -1,14 +1,7 @@
<template> <template>
<div v-if="channel"> <div v-if="channel">
<h1 class="uk-text-center"> <h1 class="uk-text-center"><img v-bind:src="channel.avatarUrl" />{{ channel.name }}</h1>
<img v-bind:src="channel.avatarUrl" />{{ channel.name }} <img v-if="channel.bannerUrl" v-bind:src="channel.bannerUrl" style="width: 100%" loading="lazy" />
</h1>
<img
v-if="channel.bannerUrl"
v-bind:src="channel.bannerUrl"
style="width: 100%"
loading="lazy"
/>
<p v-html="this.channel.description.replaceAll('\n', '<br>')"></p> <p v-html="this.channel.description.replaceAll('\n', '<br>')"></p>
<hr /> <hr />
@ -19,15 +12,8 @@
v-bind:key="item.url" v-bind:key="item.url"
v-for="item in this.channel.relatedStreams" v-for="item in this.channel.relatedStreams"
> >
<router-link <router-link class="uk-link-muted uk-text-justify" v-bind:to="item.url || '/'">
class="uk-link-muted uk-text-justify" <img style="width: 100%" v-bind:src="item.thumbnail" loading="lazy" />
v-bind:to="item.url || '/'"
>
<img
style="width: 100%"
v-bind:src="item.thumbnail"
loading="lazy"
/>
<a>{{ item.title }}</a> <a>{{ item.title }}</a>
</router-link> </router-link>
<br /> <br />
@ -53,7 +39,7 @@ import Constants from "@/Constants.js";
export default { export default {
data() { data() {
return { return {
channel: null channel: null,
}; };
}, },
mounted() { mounted() {
@ -65,9 +51,7 @@ export default {
}, },
methods: { methods: {
async fetchChannel() { async fetchChannel() {
return await this.fetchJson( return await this.fetchJson(Constants.BASE_URL + "/channels/" + this.$route.params.channelId);
Constants.BASE_URL + "/channels/" + this.$route.params.channelId
);
}, },
async getChannelData() { async getChannelData() {
this.fetchChannel() this.fetchChannel()
@ -75,17 +59,8 @@ export default {
.then(() => (document.title = this.channel.name + " - Piped")); .then(() => (document.title = this.channel.name + " - Piped"));
}, },
handleScroll() { handleScroll() {
if ( if (this.loading || !this.channel || !this.channel.nextpage || !this.channel.nextid) return;
this.loading || if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
!this.channel ||
!this.channel.nextpage ||
!this.channel.nextid
)
return;
if (
window.innerHeight + window.scrollY >=
document.body.offsetHeight - window.innerHeight
) {
this.loading = true; this.loading = true;
this.fetchJson( this.fetchJson(
Constants.BASE_URL + Constants.BASE_URL +
@ -94,18 +69,16 @@ export default {
"?url=" + "?url=" +
encodeURIComponent(this.channel.nextpage) + encodeURIComponent(this.channel.nextpage) +
"&id=" + "&id=" +
encodeURIComponent(this.channel.nextid) encodeURIComponent(this.channel.nextid),
).then(json => { ).then(json => {
this.channel.relatedStreams.concat(json.relatedStreams); this.channel.relatedStreams.concat(json.relatedStreams);
this.channel.nextpage = json.nextpage; this.channel.nextpage = json.nextpage;
this.channel.nextid = json.nextid; this.channel.nextid = json.nextid;
this.loading = false; this.loading = false;
json.relatedStreams.map(stream => json.relatedStreams.map(stream => this.channel.relatedStreams.push(stream));
this.channel.relatedStreams.push(stream)
);
}); });
} }
} },
} },
}; };
</script> </script>

View file

@ -1,11 +1,7 @@
<template> <template>
<div class="uk-container-expand"> <div class="uk-container-expand">
<div data-shaka-player-container> <div data-shaka-player-container>
<video <video data-shaka-player autoplay style="width: 100%; height: 100%"></video>
data-shaka-player
autoplay
style="width: 100%; height: 100%"
></video>
</div> </div>
</div> </div>
</template> </template>
@ -18,7 +14,7 @@ export default {
props: { props: {
video: Object, video: Object,
sponsors: Object, sponsors: Object,
selectedAutoPlay: Boolean selectedAutoPlay: Boolean,
}, },
methods: { methods: {
loadVideo() { loadVideo() {
@ -37,7 +33,7 @@ export default {
const dash = require("@/utils/DashUtils.js").default.generate_dash_file_from_formats( const dash = require("@/utils/DashUtils.js").default.generate_dash_file_from_formats(
streams, streams,
this.video.duration this.video.duration,
); );
if (noPrevPlayer) if (noPrevPlayer)
@ -74,15 +70,11 @@ export default {
}); });
videoEl.addEventListener("volumechange", () => { videoEl.addEventListener("volumechange", () => {
if (localStorage) if (localStorage) localStorage.setItem("volume", videoEl.volume);
localStorage.setItem("volume", videoEl.volume);
}); });
videoEl.addEventListener("ended", () => { videoEl.addEventListener("ended", () => {
if ( if (this.selectedAutoPlay && this.video.relatedStreams.length > 0)
this.selectedAutoPlay &&
this.video.relatedStreams.length > 0
)
this.$router.push(this.video.relatedStreams[0].url); this.$router.push(this.video.relatedStreams[0].url);
}); });
} }
@ -90,52 +82,33 @@ export default {
//TODO: Add sponsors on seekbar: https://github.com/ajayyy/SponsorBlock/blob/e39de9fd852adb9196e0358ed827ad38d9933e29/src/js-components/previewBar.ts#L12 //TODO: Add sponsors on seekbar: https://github.com/ajayyy/SponsorBlock/blob/e39de9fd852adb9196e0358ed827ad38d9933e29/src/js-components/previewBar.ts#L12
}, },
setPlayerAttrs(player, videoEl, dash, shaka) { setPlayerAttrs(player, videoEl, dash, shaka) {
player player.load("data:application/dash+xml;charset=utf-8;base64," + btoa(dash)).then(() => {
.load(
"data:application/dash+xml;charset=utf-8;base64," +
btoa(dash)
)
.then(() => {
this.video.subtitles.map(subtitle => { this.video.subtitles.map(subtitle => {
player.addTextTrack( player.addTextTrack(subtitle.url, "eng", "SUBTITLE", subtitle.mimeType, null, "English");
subtitle.url,
"eng",
"SUBTITLE",
subtitle.mimeType,
null,
"English"
);
player.setTextTrackVisibility(true); player.setTextTrackVisibility(true);
}); });
if (localStorage) if (localStorage) videoEl.volume = localStorage.getItem("volume") || 1;
videoEl.volume = localStorage.getItem("volume") || 1;
const ui = const ui =
this.ui || this.ui ||
(this.ui = new shaka.ui.Overlay( (this.ui = new shaka.ui.Overlay(
player, player,
document.querySelector( document.querySelector("div[data-shaka-player-container]"),
"div[data-shaka-player-container]" videoEl,
),
videoEl
)); ));
const config = { const config = {
overflowMenuButtons: [ overflowMenuButtons: ["quality", "captions", "playback_rate"],
"quality",
"captions",
"playback_rate"
],
seekBarColors: { seekBarColors: {
base: "rgba(255, 255, 255, 0.3)", base: "rgba(255, 255, 255, 0.3)",
buffered: "rgba(255, 255, 255, 0.54)", buffered: "rgba(255, 255, 255, 0.54)",
played: "rgb(255, 0, 0)" played: "rgb(255, 0, 0)",
} },
}; };
ui.configure(config); ui.configure(config);
}); });
} },
}, },
beforeUnmount() { beforeUnmount() {
if (this.player) { if (this.player) {
@ -143,6 +116,6 @@ export default {
this.player = undefined; this.player = undefined;
this.ui = undefined; this.ui = undefined;
} }
} },
}; };
</script> </script>

View file

@ -6,10 +6,7 @@
</h1> </h1>
<b <b
><router-link ><router-link class="uk-text-justify" v-bind:to="playlist.uploaderUrl || '/'">
class="uk-text-justify"
v-bind:to="playlist.uploaderUrl || '/'"
>
<img v-bind:src="playlist.uploaderAvatar" loading="lazy" /> <img v-bind:src="playlist.uploaderAvatar" loading="lazy" />
{{ playlist.uploader }}</router-link {{ playlist.uploader }}</router-link
></b ></b
@ -25,25 +22,16 @@
v-bind:key="item.url" v-bind:key="item.url"
v-for="item in this.playlist.relatedStreams" v-for="item in this.playlist.relatedStreams"
> >
<router-link <router-link class="uk-link-muted uk-text-justify" v-bind:to="item.url || '/'">
class="uk-link-muted uk-text-justify" <img style="width: 100%" v-bind:src="item.thumbnail" loading="lazy" />
v-bind:to="item.url || '/'"
>
<img
style="width: 100%"
v-bind:src="item.thumbnail"
loading="lazy"
/>
<a>{{ item.title }}</a> <a>{{ item.title }}</a>
</router-link> </router-link>
<br /> <br />
<div> <div>
<b class="uk-text-small uk-align-left"> <b class="uk-text-small uk-align-left">
<router-link <router-link class="uk-text-justify" v-bind:to="item.uploaderUrl || '/'">{{
class="uk-text-justify" item.uploaderName
v-bind:to="item.uploaderUrl || '/'" }}</router-link>
>{{ item.uploaderName }}</router-link
>
</b> </b>
<b class="uk-text-small uk-align-right"> <b class="uk-text-small uk-align-right">
{{ timeFormat(item.duration) }} {{ timeFormat(item.duration) }}
@ -60,7 +48,7 @@ import Constants from "@/Constants.js";
export default { export default {
data() { data() {
return { return {
playlist: null playlist: null,
}; };
}, },
mounted() { mounted() {
@ -72,9 +60,7 @@ export default {
}, },
methods: { methods: {
async fetchPlaylist() { async fetchPlaylist() {
return await await this.fetchJson( return await await this.fetchJson(Constants.BASE_URL + "/playlists/" + this.$route.query.list);
Constants.BASE_URL + "/playlists/" + this.$route.query.list
);
}, },
async getPlaylistData() { async getPlaylistData() {
this.fetchPlaylist() this.fetchPlaylist()
@ -82,17 +68,8 @@ export default {
.then(() => (document.title = this.playlist.name + " - Piped")); .then(() => (document.title = this.playlist.name + " - Piped"));
}, },
handleScroll() { handleScroll() {
if ( if (this.loading || !this.playlist || !this.playlist.nextpage || !this.playlist.nextid) return;
this.loading || if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
!this.playlist ||
!this.playlist.nextpage ||
!this.playlist.nextid
)
return;
if (
window.innerHeight + window.scrollY >=
document.body.offsetHeight - window.innerHeight
) {
this.loading = true; this.loading = true;
this.fetchJson( this.fetchJson(
Constants.BASE_URL + Constants.BASE_URL +
@ -101,18 +78,16 @@ export default {
"?url=" + "?url=" +
encodeURIComponent(this.playlist.nextpage) + encodeURIComponent(this.playlist.nextpage) +
"&id=" + "&id=" +
encodeURIComponent(this.playlist.nextid) encodeURIComponent(this.playlist.nextid),
).then(json => { ).then(json => {
this.playlist.relatedStreams.concat(json.relatedStreams); this.playlist.relatedStreams.concat(json.relatedStreams);
this.playlist.nextpage = json.nextpage; this.playlist.nextpage = json.nextpage;
this.playlist.nextid = json.nextid; this.playlist.nextid = json.nextid;
this.loading = false; this.loading = false;
json.relatedStreams.map(stream => json.relatedStreams.map(stream => this.playlist.relatedStreams.push(stream));
this.playlist.relatedStreams.push(stream)
);
}); });
} }
} },
} },
}; };
</script> </script>

View file

@ -2,71 +2,34 @@
<h1 class="uk-text-bold uk-text-center">Preferences</h1> <h1 class="uk-text-bold uk-text-center">Preferences</h1>
<hr /> <hr />
<h2>SponsorBlock</h2> <h2>SponsorBlock</h2>
<p> <p>Uses the API from <a href="https://sponsor.ajay.app/">sponsor.ajay.app</a></p>
Uses the API from <a href="https://sponsor.ajay.app/">sponsor.ajay.app</a>
</p>
<b>Enable Sponsorblock</b> <b>Enable Sponsorblock</b>
<br /> <br />
<input <input class="uk-checkbox" v-model="sponsorBlock" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="sponsorBlock"
@change="onChange($event)"
type="checkbox"
/>
<br /> <br />
<b>Skip Sponsors</b> <b>Skip Sponsors</b>
<br /> <br />
<input <input class="uk-checkbox" v-model="skipSponsor" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="skipSponsor"
@change="onChange($event)"
type="checkbox"
/>
<br /> <br />
<b>Skip Intermission/Intro Animation</b> <b>Skip Intermission/Intro Animation</b>
<br /> <br />
<input <input class="uk-checkbox" v-model="skipIntro" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="skipIntro"
@change="onChange($event)"
type="checkbox"
/>
<br /> <br />
<b>Skip Endcards/Credits</b> <b>Skip Endcards/Credits</b>
<br /> <br />
<input <input class="uk-checkbox" v-model="skipOutro" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="skipOutro"
@change="onChange($event)"
type="checkbox"
/>
<br /> <br />
<b>Skip Interaction Reminder (Subscribe)</b> <b>Skip Interaction Reminder (Subscribe)</b>
<br /> <br />
<input <input class="uk-checkbox" v-model="skipInteraction" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="skipInteraction"
@change="onChange($event)"
type="checkbox"
/>
<br /> <br />
<b>Skip Unpaid/Self Promotion</b> <b>Skip Unpaid/Self Promotion</b>
<br /> <br />
<input <input class="uk-checkbox" v-model="skipSelfPromo" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="skipSelfPromo"
@change="onChange($event)"
type="checkbox"
/>
<br /> <br />
<b>Skip Music: Non-Music Section</b> <b>Skip Music: Non-Music Section</b>
<br /> <br />
<input <input class="uk-checkbox" v-model="skipMusicOffTopic" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="skipMusicOffTopic"
@change="onChange($event)"
type="checkbox"
/>
<h2>Instances List</h2> <h2>Instances List</h2>
<table class="uk-table"> <table class="uk-table">
<thead> <thead>
@ -83,9 +46,7 @@
<td>{{ instance.locations }}</td> <td>{{ instance.locations }}</td>
<td>{{ instance.cdn }}</td> <td>{{ instance.cdn }}</td>
<td> <td>
<a :href="sslScore(instance.apiurl)" target="_blank" <a :href="sslScore(instance.apiurl)" target="_blank">Click Here</a>
>Click Here</a
>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -94,16 +55,8 @@
<hr /> <hr />
<b>Instance Selection:</b> <b>Instance Selection:</b>
<select <select class="uk-select" v-model="selectedInstance" @change="onChange($event)">
class="uk-select" <option v-bind:key="instance.name" v-for="instance in instances" v-bind:value="instance.apiurl">
v-model="selectedInstance"
@change="onChange($event)"
>
<option
v-bind:key="instance.name"
v-for="instance in instances"
v-bind:value="instance.apiurl"
>
{{ instance.name }} {{ instance.name }}
</option> </option>
</select> </select>
@ -121,13 +74,11 @@ export default {
skipOutro: false, skipOutro: false,
skipInteraction: true, skipInteraction: true,
skipSelfPromo: true, skipSelfPromo: true,
skipMusicOffTopic: true skipMusicOffTopic: true,
}; };
}, },
mounted() { mounted() {
fetch( fetch("https://raw.githubusercontent.com/wiki/TeamPiped/Piped-Frontend/Instances.md")
"https://raw.githubusercontent.com/wiki/TeamPiped/Piped-Frontend/Instances.md"
)
.then(resp => resp.text()) .then(resp => resp.text())
.then(body => { .then(body => {
var skipped = 0; var skipped = 0;
@ -143,16 +94,14 @@ export default {
name: split[0].trim(), name: split[0].trim(),
apiurl: split[1].trim(), apiurl: split[1].trim(),
locations: split[2].trim(), locations: split[2].trim(),
cdn: split[3].trim() cdn: split[3].trim(),
}); });
} }
}); });
}); });
if (localStorage) { if (localStorage) {
this.selectedInstance = this.selectedInstance = localStorage.getItem("instance") || "https://pipedapi.kavin.rocks";
localStorage.getItem("instance") ||
"https://pipedapi.kavin.rocks";
this.sponsorBlock = localStorage.getItem("sponsorblock") || true; this.sponsorBlock = localStorage.getItem("sponsorblock") || true;
if (localStorage.getItem("selectedSkip")) { if (localStorage.getItem("selectedSkip")) {
@ -198,18 +147,13 @@ export default {
if (this.skipOutro) sponsorSelected.push("outro"); if (this.skipOutro) sponsorSelected.push("outro");
if (this.skipInteraction) sponsorSelected.push("interaction"); if (this.skipInteraction) sponsorSelected.push("interaction");
if (this.skipSelfPromo) sponsorSelected.push("selfpromo"); if (this.skipSelfPromo) sponsorSelected.push("selfpromo");
if (this.skipMusicOffTopic) if (this.skipMusicOffTopic) sponsorSelected.push("music_offtopic");
sponsorSelected.push("music_offtopic");
localStorage.setItem("selectedSkip", sponsorSelected); localStorage.setItem("selectedSkip", sponsorSelected);
} }
}, },
sslScore(url) { sslScore(url) {
return ( return "https://www.ssllabs.com/ssltest/analyze.html?d=" + new URL(url).host + "&latest";
"https://www.ssllabs.com/ssltest/analyze.html?d=" + },
new URL(url).host + },
"&latest"
);
}
}
}; };
</script> </script>

View file

@ -11,21 +11,11 @@
v-for="result in results.items" v-for="result in results.items"
> >
<div class="uk-text-secondary" style="background: #0b0e0f"> <div class="uk-text-secondary" style="background: #0b0e0f">
<router-link <router-link class="uk-text-emphasis" v-bind:to="result.url || '/'">
class="uk-text-emphasis" <img style="width: 100%" v-bind:src="result.thumbnail" loading="lazy" />
v-bind:to="result.url || '/'"
>
<img
style="width: 100%"
v-bind:src="result.thumbnail"
loading="lazy"
/>
<p>{{ result.name }}</p> <p>{{ result.name }}</p>
</router-link> </router-link>
<router-link <router-link class="uk-link-muted" v-bind:to="result.uploaderUrl || '/'">
class="uk-link-muted"
v-bind:to="result.uploaderUrl || '/'"
>
<p>{{ result.uploaderName }}</p> <p>{{ result.uploaderName }}</p>
</router-link> </router-link>
{{ result.duration ? timeFormat(result.duration) : "" }} {{ result.duration ? timeFormat(result.duration) : "" }}
@ -48,7 +38,7 @@ import Constants from "@/Constants.js";
export default { export default {
data() { data() {
return { return {
results: null results: null,
}; };
}, },
mounted() { mounted() {
@ -61,28 +51,21 @@ export default {
watch: { watch: {
"$route.query.search_query": function(q) { "$route.query.search_query": function(q) {
if (q) this.updateResults(); if (q) this.updateResults();
} },
}, },
methods: { methods: {
async fetchResults() { async fetchResults() {
return await await this.fetchJson( return await await this.fetchJson(
Constants.BASE_URL + Constants.BASE_URL + "/search?q=" + encodeURIComponent(this.$route.query.search_query),
"/search?q=" +
encodeURIComponent(this.$route.query.search_query)
); );
}, },
async updateResults() { async updateResults() {
document.title = this.$route.query.search_query + " - Piped"; document.title = this.$route.query.search_query + " - Piped";
this.results = this.fetchResults().then( this.results = this.fetchResults().then(json => (this.results = json));
json => (this.results = json)
);
}, },
handleScroll() { handleScroll() {
if (this.loading || !this.results || !this.results.nextpage) return; if (this.loading || !this.results || !this.results.nextpage) return;
if ( if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
window.innerHeight + window.scrollY >=
document.body.offsetHeight - window.innerHeight
) {
this.loading = true; this.loading = true;
this.fetchJson( this.fetchJson(
Constants.BASE_URL + Constants.BASE_URL +
@ -92,7 +75,7 @@ export default {
"&id=" + "&id=" +
encodeURIComponent(this.results.id) + encodeURIComponent(this.results.id) +
"&q=" + "&q=" +
encodeURIComponent(this.$route.query.search_query) encodeURIComponent(this.$route.query.search_query),
).then(json => { ).then(json => {
this.results.nextpage = json.nextpage; this.results.nextpage = json.nextpage;
this.results.id = json.id; this.results.id = json.id;
@ -100,7 +83,7 @@ export default {
json.items.map(stream => this.results.items.push(stream)); json.items.map(stream => this.results.items.push(stream));
}); });
} }
} },
} },
}; };
</script> </script>

View file

@ -11,21 +11,11 @@
v-for="video in videos" v-for="video in videos"
> >
<div class="uk-text-secondary" style="background: #0b0e0f"> <div class="uk-text-secondary" style="background: #0b0e0f">
<router-link <router-link class="uk-text-emphasis" v-bind:to="video.url || '/'">
class="uk-text-emphasis" <img style="width: 100%" v-bind:src="video.thumbnail" loading="lazy" />
v-bind:to="video.url || '/'"
>
<img
style="width: 100%"
v-bind:src="video.thumbnail"
loading="lazy"
/>
<p>{{ video.title }}</p> <p>{{ video.title }}</p>
</router-link> </router-link>
<router-link <router-link class="uk-link-muted" v-bind:to="video.uploaderUrl || '/'">
class="uk-link-muted"
v-bind:to="video.uploaderUrl || '/'"
>
<p>{{ video.uploaderName }}</p> <p>{{ video.uploaderName }}</p>
</router-link> </router-link>
<b class="uk-text-small uk-align-left"> <b class="uk-text-small uk-align-left">
@ -48,7 +38,7 @@ import Constants from "@/Constants.js";
export default { export default {
data() { data() {
return { return {
videos: [] videos: [],
}; };
}, },
mounted() { mounted() {
@ -59,7 +49,7 @@ export default {
methods: { methods: {
async fetchTrending() { async fetchTrending() {
return await this.fetchJson(Constants.BASE_URL + "/trending"); return await this.fetchJson(Constants.BASE_URL + "/trending");
} },
} },
}; };
</script> </script>

View file

@ -1,11 +1,6 @@
<template> <template>
<div class="uk-container uk-container-xlarge"> <div class="uk-container uk-container-xlarge">
<Player <Player ref="videoPlayer" :video="video" :sponsors="sponsors" :selectedAutoPlay="selectedAutoPlay" />
ref="videoPlayer"
:video="video"
:sponsors="sponsors"
:selectedAutoPlay="selectedAutoPlay"
/>
<h1 class="uk-text-bold">{{ video.title }}</h1> <h1 class="uk-text-bold">{{ video.title }}</h1>
<img :src="video.uploaderAvatar" loading="lazy" /> <img :src="video.uploaderAvatar" loading="lazy" />
@ -27,27 +22,16 @@
<p> <p>
Uploaded on <b>{{ video.uploadDate }}</b> Uploaded on <b>{{ video.uploadDate }}</b>
</p> </p>
<a <a class="uk-button uk-button-small" style="background: #222" @click="showDesc = !showDesc">
class="uk-button uk-button-small"
style="background: #222"
@click="showDesc = !showDesc"
>
{{ showDesc ? "+" : "-" }} {{ showDesc ? "+" : "-" }}
</a> </a>
<p v-show="showDesc" class="uk-light" v-html="video.description"></p> <p v-show="showDesc" class="uk-light" v-html="video.description"></p>
<a v-if="sponsors && sponsors.segments" <a v-if="sponsors && sponsors.segments">Sponsors Segments: {{ sponsors.segments.length }}</a>
>Sponsors Segments: {{ sponsors.segments.length }}</a
>
<hr /> <hr />
<b>Auto Play next Video:</b>&nbsp; <b>Auto Play next Video:</b>&nbsp;
<input <input class="uk-checkbox" v-model="selectedAutoPlay" @change="onChange($event)" type="checkbox" />
class="uk-checkbox"
v-model="selectedAutoPlay"
@change="onChange($event)"
type="checkbox"
/>
<div <div
class="uk-tile-default uk-text-secondary" class="uk-tile-default uk-text-secondary"
@ -57,17 +41,10 @@
> >
<router-link class="uk-link-muted" v-bind:to="related.url"> <router-link class="uk-link-muted" v-bind:to="related.url">
<p class="uk-text-emphasis">{{ related.title }}</p> <p class="uk-text-emphasis">{{ related.title }}</p>
<img <img style="width: 100%" v-bind:src="related.thumbnail" loading="lazy" />
style="width: 100%"
v-bind:src="related.thumbnail"
loading="lazy"
/>
</router-link> </router-link>
<p> <p>
<router-link <router-link class="uk-link-muted" v-bind:to="related.uploaderUrl || '/'">
class="uk-link-muted"
v-bind:to="related.uploaderUrl || '/'"
>
<p>{{ related.uploaderName }}</p> <p>{{ related.uploaderName }}</p>
</router-link> </router-link>
<font-awesome-icon icon="eye"></font-awesome-icon> <font-awesome-icon icon="eye"></font-awesome-icon>
@ -86,11 +63,11 @@ export default {
data() { data() {
return { return {
video: { video: {
title: "Loading..." title: "Loading...",
}, },
sponsors: null, sponsors: null,
selectedAutoPlay: null, selectedAutoPlay: null,
showDesc: true showDesc: true,
}; };
}, },
mounted() { mounted() {
@ -104,13 +81,11 @@ export default {
this.getVideoData(); this.getVideoData();
this.getSponsors(); this.getSponsors();
} }
} },
}, },
methods: { methods: {
fetchVideo() { fetchVideo() {
return this.fetchJson( return this.fetchJson(Constants.BASE_URL + "/streams/" + this.$route.query.v);
Constants.BASE_URL + "/streams/" + this.$route.query.v
);
}, },
async fetchSponsors() { async fetchSponsors() {
return await this.fetchJson( return await this.fetchJson(
@ -119,21 +94,12 @@ export default {
this.$route.query.v + this.$route.query.v +
"?category=" + "?category=" +
(localStorage && localStorage.getItem("selectedSkip") (localStorage && localStorage.getItem("selectedSkip")
? encodeURIComponent( ? encodeURIComponent('["' + localStorage.getItem("selectedSkip").replace(",", '","') + '"]')
'["' + : encodeURIComponent('["sponsor", "interaction", "selfpromo", "music_offtopic"]')),
localStorage
.getItem("selectedSkip")
.replace(",", '","') +
'"]'
)
: encodeURIComponent(
'["sponsor", "interaction", "selfpromo", "music_offtopic"]'
))
); );
}, },
onChange() { onChange() {
if (localStorage) if (localStorage) localStorage.setItem("autoplay", this.selectedAutoPlay);
localStorage.setItem("autoplay", this.selectedAutoPlay);
}, },
async getVideoData() { async getVideoData() {
this.fetchVideo() this.fetchVideo()
@ -154,10 +120,10 @@ export default {
async getSponsors() { async getSponsors() {
if (!localStorage || localStorage.getItem("sponsorblock") !== false) if (!localStorage || localStorage.getItem("sponsorblock") !== false)
this.fetchSponsors().then(data => (this.sponsors = data)); this.fetchSponsors().then(data => (this.sponsors = data));
} },
}, },
components: { components: {
Player Player,
} },
}; };
</script> </script>

View file

@ -1,23 +1,22 @@
import { createApp } from 'vue' import { createApp } from "vue";
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from "@fortawesome/fontawesome-svg-core";
import { faThumbsUp, faThumbsDown, faEye } from '@fortawesome/free-solid-svg-icons' import { faThumbsUp, faThumbsDown, faEye } from "@fortawesome/free-solid-svg-icons";
import { faGithub, faBitcoin } from '@fortawesome/free-brands-svg-icons' import { faGithub, faBitcoin } from "@fortawesome/free-brands-svg-icons";
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
library.add(faThumbsUp, faThumbsDown, faEye, faGithub, faBitcoin) library.add(faThumbsUp, faThumbsDown, faEye, faGithub, faBitcoin);
import("uikit/src/less/uikit.less") import("uikit/src/less/uikit.less");
import("uikit/dist/js/uikit.min.js") import("uikit/dist/js/uikit.min.js");
import router from '@/router/router' import router from "@/router/router";
import App from './App.vue' import App from "./App.vue";
import './registerServiceWorker' import "./registerServiceWorker";
const mixin = { const mixin = {
methods: { methods: {
timeFormat: function (duration) { timeFormat: function(duration) {
var pad = function(num, size) {
var pad = function (num, size) {
return ("000" + num).slice(size * -1); return ("000" + num).slice(size * -1);
}; };
@ -33,19 +32,17 @@ const mixin = {
str += pad(minutes, 2) + ":" + pad(seconds, 2); str += pad(minutes, 2) + ":" + pad(seconds, 2);
return str; return str;
}, },
fetchJson: function (url, options) { fetchJson: function(url, options) {
return fetch(url, options) return fetch(url, options).then(response => {
.then(response => {
return response.json(); return response.json();
}) });
} },
} },
} };
const app = createApp(App) const app = createApp(App);
app.use(router) app.use(router);
app.mixin(mixin) app.mixin(mixin);
app.component('font-awesome-icon', FontAwesomeIcon) app.component("font-awesome-icon", FontAwesomeIcon);
app.mount('#app') app.mount("#app");

View file

@ -1,33 +1,33 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import { register } from 'register-service-worker' import { register } from "register-service-worker";
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === "production") {
register(`/service-worker.js`, { register(`/service-worker.js`, {
ready() { ready() {
console.log( console.log(
'App is being served from cache by a service worker.\n' + "App is being served from cache by a service worker.\n" +
'For more details, visit https://goo.gl/AFskqB' "For more details, visit https://goo.gl/AFskqB",
) );
}, },
registered() { registered() {
console.log('Service worker has been registered.') console.log("Service worker has been registered.");
}, },
cached() { cached() {
console.log('Content has been cached for offline use.') console.log("Content has been cached for offline use.");
}, },
updatefound() { updatefound() {
console.log('New content is downloading.') console.log("New content is downloading.");
}, },
updated() { updated() {
console.log('New content is available; please refresh.') console.log("New content is available; please refresh.");
window.location.reload() window.location.reload();
}, },
offline() { offline() {
console.log('No internet connection found. App is running in offline mode.') console.log("No internet connection found. App is running in offline mode.");
}, },
error(error) { error(error) {
console.error('Error during service worker registration:', error) console.error("Error during service worker registration:", error);
} },
}) });
} }

View file

@ -1,34 +1,41 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from "vue-router";
const routes = [{ const routes = [
path: '/watch', {
name: 'Watch', path: "/watch",
component: () => import('../components/WatchVideo.vue') name: "Watch",
}, { component: () => import("../components/WatchVideo.vue"),
path: '/', },
name: 'Trending', {
component: () => import('../components/TrendingPage.vue') path: "/",
}, { name: "Trending",
path: '/channel/:channelId', component: () => import("../components/TrendingPage.vue"),
name: 'Channel', },
component: () => import('../components/Channel.vue') {
}, { path: "/channel/:channelId",
path: '/preferences', name: "Channel",
name: 'Preferences', component: () => import("../components/Channel.vue"),
component: () => import('../components/Preferences.vue') },
}, { {
path: '/results', path: "/preferences",
name: 'SearchResults', name: "Preferences",
component: () => import('../components/SearchResults.vue') component: () => import("../components/Preferences.vue"),
}, { },
path: '/playlist', {
name: 'Playlist', path: "/results",
component: () => import('../components/Playlist.vue') name: "SearchResults",
}] component: () => import("../components/SearchResults.vue"),
},
{
path: "/playlist",
name: "Playlist",
component: () => import("../components/Playlist.vue"),
},
];
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),
routes routes,
}) });
export default router export default router;

View file

@ -1,189 +1,188 @@
// Based of https://github.com/GilgusMaximus/yt-dash-manifest-generator/blob/master/src/DashGenerator.js // Based of https://github.com/GilgusMaximus/yt-dash-manifest-generator/blob/master/src/DashGenerator.js
const xml = require('xml-js') const xml = require("xml-js");
const DashUtils = { const DashUtils = {
generate_dash_file_from_formats(VideoFormats, VideoLength) { generate_dash_file_from_formats(VideoFormats, VideoLength) {
const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength) const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength);
return xml.json2xml(generatedJSON) return xml.json2xml(generatedJSON);
}, },
generate_xmljs_json_from_data(VideoFormatArray, VideoLength) { generate_xmljs_json_from_data(VideoFormatArray, VideoLength) {
const convertJSON = { const convertJSON = {
"declaration": { declaration: {
"attributes": { attributes: {
"version": "1.0", version: "1.0",
"encoding": "utf-8" encoding: "utf-8",
}
}, },
"elements": [
{
"type": "element",
"name": "MPD",
"attributes": {
"xmlns": "urn:mpeg:dash:schema:mpd:2011",
"profiles": "urn:mpeg:dash:profile:full:2011",
"minBufferTime": "PT1.5S",
"type": "static",
"mediaPresentationDuration": `PT${VideoLength}S`
}, },
"elements": [ elements: [
{ {
"type": "element", type: "element",
"name": "Period", name: "MPD",
"elements": this.generate_adaptation_set(VideoFormatArray) attributes: {
} xmlns: "urn:mpeg:dash:schema:mpd:2011",
] profiles: "urn:mpeg:dash:profile:full:2011",
} minBufferTime: "PT1.5S",
] type: "static",
} mediaPresentationDuration: `PT${VideoLength}S`,
return convertJSON },
elements: [
{
type: "element",
name: "Period",
elements: this.generate_adaptation_set(VideoFormatArray),
},
],
},
],
};
return convertJSON;
}, },
generate_adaptation_set(VideoFormatArray) { generate_adaptation_set(VideoFormatArray) {
const adaptationSets = [] const adaptationSets = [];
const mimeTypes = [] const mimeTypes = [];
const mimeObjects = [[]] const mimeObjects = [[]];
// sort the formats by mime types // sort the formats by mime types
VideoFormatArray.forEach((videoFormat) => { VideoFormatArray.forEach(videoFormat => {
// the dual formats should not be used // the dual formats should not be used
if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) { if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) {
return return;
} }
// if these properties are not available, then we skip it because we cannot set these properties // if these properties are not available, then we skip it because we cannot set these properties
//if (!(videoFormat.hasOwnProperty('initRange') && videoFormat.hasOwnProperty('indexRange'))) { //if (!(videoFormat.hasOwnProperty('initRange') && videoFormat.hasOwnProperty('indexRange'))) {
// return // return
//} //}
const mimeType = videoFormat.mimeType const mimeType = videoFormat.mimeType;
const mimeTypeIndex = mimeTypes.indexOf(mimeType) const mimeTypeIndex = mimeTypes.indexOf(mimeType);
if (mimeTypeIndex > -1) { if (mimeTypeIndex > -1) {
mimeObjects[mimeTypeIndex].push(videoFormat) mimeObjects[mimeTypeIndex].push(videoFormat);
} else { } else {
mimeTypes.push(mimeType) mimeTypes.push(mimeType);
mimeObjects.push([]) mimeObjects.push([]);
mimeObjects[mimeTypes.length - 1].push(videoFormat) mimeObjects[mimeTypes.length - 1].push(videoFormat);
} }
}) });
// for each MimeType generate a new Adaptation set with Representations as sub elements // for each MimeType generate a new Adaptation set with Representations as sub elements
for (let i = 0; i < mimeTypes.length; i++) { for (let i = 0; i < mimeTypes.length; i++) {
let isVideoFormat = false let isVideoFormat = false;
const adapSet = { const adapSet = {
"type": "element", type: "element",
"name": "AdaptationSet", name: "AdaptationSet",
"attributes": { attributes: {
"id": i, id: i,
"mimeType": mimeTypes[i], mimeType: mimeTypes[i],
"startWithSAP": "1", startWithSAP: "1",
"subsegmentAlignment": "true" subsegmentAlignment: "true",
}, },
"elements": [] elements: [],
} };
if (!mimeTypes[i].includes("audio")) { if (!mimeTypes[i].includes("audio")) {
adapSet.attributes.scanType = "progressive" adapSet.attributes.scanType = "progressive";
isVideoFormat = true isVideoFormat = true;
} }
mimeObjects[i].forEach((format) => { mimeObjects[i].forEach(format => {
if (isVideoFormat) { if (isVideoFormat) {
adapSet.elements.push(this.generate_representation_video(format)) adapSet.elements.push(this.generate_representation_video(format));
} else { } else {
adapSet.elements.push(this.generate_representation_audio(format)) adapSet.elements.push(this.generate_representation_audio(format));
} }
}) });
adaptationSets.push(adapSet) adaptationSets.push(adapSet);
} }
return adaptationSets return adaptationSets;
}, generate_representation_audio(Format) {
const representation =
{
"type": "element",
"name": "Representation",
"attributes": {
"id": Format.itag,
"codecs": Format.codec,
"bandwidth": Format.bitrate
}, },
"elements": [ generate_representation_audio(Format) {
const representation = {
type: "element",
name: "Representation",
attributes: {
id: Format.itag,
codecs: Format.codec,
bandwidth: Format.bitrate,
},
elements: [
{ {
"type": "element", type: "element",
"name": "AudioChannelConfiguration", name: "AudioChannelConfiguration",
"attributes": { attributes: {
"schemeIdUri": "urn:mpeg:dash:23003:3:audio_channel_configuration:2011", schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
"value": "2" value: "2",
}, },
}, },
{ {
"type": "element", type: "element",
"name": "BaseURL", name: "BaseURL",
"elements": [ elements: [
{ {
"type": "text", type: "text",
"text": Format.url text: Format.url,
} },
] ],
}, },
{ {
"type": "element", type: "element",
"name": "SegmentBase", name: "SegmentBase",
"attributes": { attributes: {
"indexRange": `${Format.indexStart}-${Format.indexEnd}` indexRange: `${Format.indexStart}-${Format.indexEnd}`,
}, },
"elements": [ elements: [
{ {
"type": "element", type: "element",
"name": "Initialization", name: "Initialization",
"attributes": { attributes: {
"range": `${Format.initStart}-${Format.initEnd}` range: `${Format.initStart}-${Format.initEnd}`,
} },
} },
] ],
} },
] ],
} };
return representation return representation;
}, },
generate_representation_video(Format) { generate_representation_video(Format) {
const representation = const representation = {
{ type: "element",
"type": "element", name: "Representation",
"name": "Representation", attributes: {
"attributes": { id: Format.itag,
"id": Format.itag, codecs: Format.codec,
"codecs": Format.codec, bandwidth: Format.bitrate,
"bandwidth": Format.bitrate, width: Format.width,
"width": Format.width, height: Format.height,
"height": Format.height, maxPlayoutRate: "1",
"maxPlayoutRate": "1", frameRate: Format.fps,
"frameRate": Format.fps
}, },
"elements": [ elements: [
{ {
"type": "element", type: "element",
"name": "BaseURL", name: "BaseURL",
"elements": [ elements: [
{ {
"type": "text", type: "text",
"text": Format.url text: Format.url,
} },
] ],
}, },
{ {
"type": "element", type: "element",
"name": "SegmentBase", name: "SegmentBase",
"attributes": { attributes: {
"indexRange": `${Format.indexStart}-${Format.indexEnd}` indexRange: `${Format.indexStart}-${Format.indexEnd}`,
}, },
"elements": [ elements: [
{ {
"type": "element", type: "element",
"name": "Initialization", name: "Initialization",
"attributes": { attributes: {
"range": `${Format.initStart}-${Format.initEnd}` range: `${Format.initStart}-${Format.initEnd}`,
} },
} },
] ],
} },
] ],
} };
return representation return representation;
} },
} };
export default DashUtils; export default DashUtils;

View file

@ -2907,16 +2907,11 @@ core-js@^2.4.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-js@^3.10.0: core-js@^3.10.0, core-js@^3.6.5:
version "3.10.0" version "3.10.0"
resolved "https://registry.npm.taobao.org/core-js/download/core-js-3.10.0.tgz?cache=0&sync_timestamp=1617182041689&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.10.0.tgz#9a020547c8b6879f929306949e31496bbe2ae9b3" resolved "https://registry.npm.taobao.org/core-js/download/core-js-3.10.0.tgz?cache=0&sync_timestamp=1617182041689&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.10.0.tgz#9a020547c8b6879f929306949e31496bbe2ae9b3"
integrity sha1-mgIFR8i2h5+SkwaUnjFJa74q6bM= integrity sha1-mgIFR8i2h5+SkwaUnjFJa74q6bM=
core-js@^3.6.5:
version "3.10.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.10.0.tgz#9a020547c8b6879f929306949e31496bbe2ae9b3"
integrity sha512-MQx/7TLgmmDVamSyfE+O+5BHvG1aUGj/gHhLn1wVtm2B5u1eVIPvh7vkfjwWKNCjrTJB8+He99IntSQ1qP+vYQ==
core-util-is@1.0.2, core-util-is@~1.0.0: core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"