mirror of
https://github.com/TeamPiped/Piped.git
synced 2024-08-14 23:57:27 +00:00
More fixes
This commit is contained in:
parent
d02641e802
commit
d8be46d849
18 changed files with 964 additions and 965 deletions
|
@ -36,7 +36,7 @@ export default {
|
||||||
case 'trending':
|
case 'trending':
|
||||||
break
|
break
|
||||||
case 'feed':
|
case 'feed':
|
||||||
this.$router.push('/feed')
|
this.$router.replace('/feed')
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|
|
@ -31,86 +31,86 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ErrorHandler from "@/components/ErrorHandler.vue";
|
import ErrorHandler from '@/components/ErrorHandler.vue'
|
||||||
import VideoItem from "@/components/VideoItem.vue";
|
import VideoItem from '@/components/VideoItem.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
channel: null,
|
channel: null,
|
||||||
subscribed: false,
|
subscribed: false
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
this.getChannelData();
|
this.getChannelData()
|
||||||
},
|
},
|
||||||
activated() {
|
activated () {
|
||||||
window.addEventListener("scroll", this.handleScroll);
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
},
|
},
|
||||||
deactivated() {
|
deactivated () {
|
||||||
window.removeEventListener("scroll", this.handleScroll);
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchSubscribedStatus() {
|
async fetchSubscribedStatus () {
|
||||||
this.fetchJson(
|
this.fetchJson(
|
||||||
this.apiUrl() + "/subscribed",
|
this.apiUrl() + '/subscribed',
|
||||||
{
|
{
|
||||||
channelId: this.channel.id,
|
channelId: this.channel.id
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: this.getAuthToken(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
).then(json => {
|
|
||||||
this.subscribed = json.subscribed;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async fetchChannel() {
|
|
||||||
const url = this.apiUrl() + "/" + this.$route.params.path + "/" + this.$route.params.channelId;
|
|
||||||
return await this.fetchJson(url);
|
|
||||||
},
|
|
||||||
async getChannelData() {
|
|
||||||
this.fetchChannel()
|
|
||||||
.then(data => (this.channel = data))
|
|
||||||
.then(() => {
|
|
||||||
if (!this.channel.error) {
|
|
||||||
document.title = this.channel.name + " - Piped";
|
|
||||||
if (this.authenticated) this.fetchSubscribedStatus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handleScroll() {
|
|
||||||
if (this.loading || !this.channel || !this.channel.nextpage) return;
|
|
||||||
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
|
|
||||||
this.loading = true;
|
|
||||||
this.fetchJson(this.apiUrl() + "/nextpage/channel/" + this.channel.id, {
|
|
||||||
nextpage: this.channel.nextpage,
|
|
||||||
}).then(json => {
|
|
||||||
this.channel.relatedStreams.concat(json.relatedStreams);
|
|
||||||
this.channel.nextpage = json.nextpage;
|
|
||||||
this.loading = false;
|
|
||||||
json.relatedStreams.map(stream => this.channel.relatedStreams.push(stream));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
subscribeHandler() {
|
|
||||||
this.fetchJson(this.apiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({
|
|
||||||
channelId: this.channel.id,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
Authorization: this.getAuthToken(),
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.subscribed = !this.subscribed;
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: this.getAuthToken()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(json => {
|
||||||
|
this.subscribed = json.subscribed
|
||||||
|
})
|
||||||
},
|
},
|
||||||
components: {
|
async fetchChannel () {
|
||||||
ErrorHandler,
|
const url = this.apiUrl() + '/' + this.$route.params.path + '/' + this.$route.params.channelId
|
||||||
VideoItem,
|
return await this.fetchJson(url)
|
||||||
},
|
},
|
||||||
};
|
async getChannelData () {
|
||||||
|
this.fetchChannel()
|
||||||
|
.then(data => (this.channel = data))
|
||||||
|
.then(() => {
|
||||||
|
if (!this.channel.error) {
|
||||||
|
document.title = this.channel.name + ' - Piped'
|
||||||
|
if (this.authenticated) this.fetchSubscribedStatus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleScroll () {
|
||||||
|
if (this.loading || !this.channel || !this.channel.nextpage) return
|
||||||
|
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
|
||||||
|
this.loading = true
|
||||||
|
this.fetchJson(this.apiUrl() + '/nextpage/channel/' + this.channel.id, {
|
||||||
|
nextpage: this.channel.nextpage
|
||||||
|
}).then(json => {
|
||||||
|
this.channel.relatedStreams.concat(json.relatedStreams)
|
||||||
|
this.channel.nextpage = json.nextpage
|
||||||
|
this.loading = false
|
||||||
|
json.relatedStreams.map(stream => this.channel.relatedStreams.push(stream))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
subscribeHandler () {
|
||||||
|
this.fetchJson(this.apiUrl() + (this.subscribed ? '/unsubscribe' : '/subscribe'), null, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
channelId: this.channel.id
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
Authorization: this.getAuthToken(),
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.subscribed = !this.subscribed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ErrorHandler,
|
||||||
|
VideoItem
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
error: String,
|
error: String,
|
||||||
message: String,
|
message: String
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -57,27 +57,27 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
videos: [],
|
videos: []
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
document.title = "Feed - Piped";
|
document.title = 'Feed - Piped'
|
||||||
|
|
||||||
this.fetchFeed().then(videos => (this.videos = videos));
|
this.fetchFeed().then(videos => (this.videos = videos))
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchFeed() {
|
async fetchFeed () {
|
||||||
return await this.fetchJson(this.apiUrl() + "/feed", {
|
return await this.fetchJson(this.apiUrl() + '/feed', {
|
||||||
authToken: this.getAuthToken(),
|
authToken: this.getAuthToken()
|
||||||
});
|
})
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getRssUrl(_this) {
|
getRssUrl (_this) {
|
||||||
return _this.apiUrl() + "/feed/rss?authToken=" + _this.getAuthToken();
|
return _this.apiUrl() + '/feed/rss?authToken=' + _this.getAuthToken()
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -59,71 +59,71 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
subscriptions: [],
|
subscriptions: []
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
selectedSubscriptions() {
|
selectedSubscriptions () {
|
||||||
return this.subscriptions.length;
|
return this.subscriptions.length
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
activated() {
|
activated () {
|
||||||
if (!this.authenticated) this.$router.push("/login");
|
if (!this.authenticated) this.$router.push('/login')
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fileChange() {
|
fileChange () {
|
||||||
this.$refs.fileSelector.files[0].text().then(text => {
|
this.$refs.fileSelector.files[0].text().then(text => {
|
||||||
this.subscriptions = [];
|
this.subscriptions = []
|
||||||
|
|
||||||
// Invidious
|
// Invidious
|
||||||
if (text.indexOf("opml") != -1) {
|
if (text.indexOf('opml') !== -1) {
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser()
|
||||||
const xmlDoc = parser.parseFromString(text, "text/xml");
|
const xmlDoc = parser.parseFromString(text, 'text/xml')
|
||||||
xmlDoc.querySelectorAll("outline[xmlUrl]").forEach(item => {
|
xmlDoc.querySelectorAll('outline[xmlUrl]').forEach(item => {
|
||||||
const url = item.getAttribute("xmlUrl");
|
const url = item.getAttribute('xmlUrl')
|
||||||
const id = url.substr(-24);
|
const id = url.substr(-24)
|
||||||
this.subscriptions.push(id);
|
this.subscriptions.push(id)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
// NewPipe
|
// NewPipe
|
||||||
if (text.indexOf("app_version") != -1) {
|
if (text.indexOf('app_version') !== -1) {
|
||||||
const json = JSON.parse(text);
|
const json = JSON.parse(text)
|
||||||
json.subscriptions
|
json.subscriptions
|
||||||
.filter(item => item.service_id == 0)
|
.filter(item => item.service_id === 0)
|
||||||
.forEach(item => {
|
.forEach(item => {
|
||||||
const url = item.url;
|
const url = item.url
|
||||||
const id = url.substr(-24);
|
const id = url.substr(-24)
|
||||||
this.subscriptions.push(id);
|
this.subscriptions.push(id)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
// Invidious JSON
|
// Invidious JSON
|
||||||
if (text.indexOf("thin_mode") != -1) {
|
if (text.indexOf('thin_mode') !== -1) {
|
||||||
const json = JSON.parse(text);
|
const json = JSON.parse(text)
|
||||||
this.subscriptions = json.subscriptions;
|
this.subscriptions = json.subscriptions
|
||||||
}
|
}
|
||||||
// Google Takeout
|
// Google Takeout
|
||||||
if (text.indexOf("contentDetails") != -1) {
|
if (text.indexOf('contentDetails') !== -1) {
|
||||||
const json = JSON.parse(text);
|
const json = JSON.parse(text)
|
||||||
json.forEach(item => {
|
json.forEach(item => {
|
||||||
const id = item.snippet.resourceId.channelId;
|
const id = item.snippet.resourceId.channelId
|
||||||
this.subscriptions.push(id);
|
this.subscriptions.push(id)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
},
|
|
||||||
handleImport() {
|
|
||||||
this.fetchJson(this.apiUrl() + "/import", null, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
Authorization: this.getAuthToken(),
|
|
||||||
},
|
|
||||||
body: JSON.stringify(this.subscriptions),
|
|
||||||
}).then(json => {
|
|
||||||
if (json.message === "ok") window.location = "/feed";
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
handleImport () {
|
||||||
|
this.fetchJson(this.apiUrl() + '/import', null, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: this.getAuthToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify(this.subscriptions)
|
||||||
|
}).then(json => {
|
||||||
|
if (json.message === 'ok') window.location = '/feed'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -33,34 +33,34 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
username: null,
|
username: null,
|
||||||
password: null,
|
password: null
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
//TODO: Add Server Side check
|
// TODO: Add Server Side check
|
||||||
if (this.getAuthToken()) {
|
if (this.getAuthToken()) {
|
||||||
this.$router.push("/");
|
this.$router.push('/')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
login() {
|
login () {
|
||||||
console.log("authToken" + this.hashCode(this.apiUrl()));
|
console.log('authToken' + this.hashCode(this.apiUrl()))
|
||||||
this.fetchJson(this.apiUrl() + "/login", null, {
|
this.fetchJson(this.apiUrl() + '/login', null, {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password,
|
password: this.password
|
||||||
}),
|
})
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
if (resp.token) {
|
if (resp.token) {
|
||||||
this.setPreference("authToken" + this.hashCode(this.apiUrl()), resp.token);
|
this.setPreference('authToken' + this.hashCode(this.apiUrl()), resp.token)
|
||||||
window.location = "/"; // done to bypass cache
|
window.location = '/' // done to bypass cache
|
||||||
} else alert(resp.error);
|
} else alert(resp.error)
|
||||||
});
|
})
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -57,48 +57,48 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SearchSuggestions from "@/components/SearchSuggestions";
|
import SearchSuggestions from '@/components/SearchSuggestions'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SearchSuggestions,
|
SearchSuggestions
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
searchText: '',
|
||||||
|
suggestionsVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
shouldShowLogin (_this) {
|
||||||
|
return _this.getAuthToken() == null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onKeyUp (e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.target.blur()
|
||||||
|
this.$router.push({
|
||||||
|
name: 'SearchResults',
|
||||||
|
query: { search_query: this.searchText }
|
||||||
|
})
|
||||||
|
return
|
||||||
|
} else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
this.$refs.searchSuggestions.onKeyUp(e)
|
||||||
},
|
},
|
||||||
data() {
|
onInputFocus () {
|
||||||
return {
|
this.suggestionsVisible = true
|
||||||
searchText: "",
|
|
||||||
suggestionsVisible: false,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
computed: {
|
onInputBlur () {
|
||||||
shouldShowLogin(_this) {
|
this.suggestionsVisible = false
|
||||||
return _this.getAuthToken() == null;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
onSearchTextChange (searchText) {
|
||||||
onKeyUp(e) {
|
this.searchText = searchText
|
||||||
if (e.key === "Enter") {
|
}
|
||||||
e.target.blur();
|
}
|
||||||
this.$router.push({
|
}
|
||||||
name: "SearchResults",
|
|
||||||
query: { search_query: this.searchText },
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
} else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
this.$refs.searchSuggestions.onKeyUp(e);
|
|
||||||
},
|
|
||||||
onInputFocus() {
|
|
||||||
this.suggestionsVisible = true;
|
|
||||||
},
|
|
||||||
onInputBlur() {
|
|
||||||
this.suggestionsVisible = false;
|
|
||||||
},
|
|
||||||
onSearchTextChange(searchText) {
|
|
||||||
this.searchText = searchText;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|
|
@ -17,255 +17,255 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import("shaka-player/dist/controls.css");
|
import muxjs from 'mux.js'
|
||||||
const shaka = import("shaka-player/dist/shaka-player.ui.js");
|
import('shaka-player/dist/controls.css')
|
||||||
import muxjs from "mux.js";
|
const shaka = import('shaka-player/dist/shaka-player.ui.js')
|
||||||
window.muxjs = muxjs;
|
window.muxjs = muxjs
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
video: Object,
|
video: Object,
|
||||||
sponsors: Object,
|
sponsors: Object,
|
||||||
selectedAutoPlay: Boolean,
|
selectedAutoPlay: Boolean,
|
||||||
selectedAutoLoop: Boolean,
|
selectedAutoLoop: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
player: null,
|
player: null
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
shouldAutoPlay: _this => {
|
shouldAutoPlay: _this => {
|
||||||
return _this.getPreferenceBoolean("playerAutoPlay", true);
|
return _this.getPreferenceBoolean('playerAutoPlay', true)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
if (!this.shaka) this.shakaPromise = shaka.then(shaka => shaka.default).then(shaka => (this.shaka = shaka));
|
if (!this.shaka) this.shakaPromise = shaka.then(shaka => shaka.default).then(shaka => (this.shaka = shaka))
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadVideo() {
|
loadVideo () {
|
||||||
const component = this;
|
const component = this
|
||||||
const videoEl = this.$refs.videoEl;
|
const videoEl = this.$refs.videoEl
|
||||||
|
|
||||||
videoEl.setAttribute("poster", this.video.thumbnailUrl);
|
videoEl.setAttribute('poster', this.video.thumbnailUrl)
|
||||||
|
|
||||||
if (this.$route.query.t) videoEl.currentTime = this.$route.query.t;
|
if (this.$route.query.t) videoEl.currentTime = this.$route.query.t
|
||||||
|
|
||||||
const noPrevPlayer = !this.player;
|
const noPrevPlayer = !this.player
|
||||||
|
|
||||||
var streams = [];
|
const streams = []
|
||||||
|
|
||||||
streams.push(...this.video.audioStreams);
|
streams.push(...this.video.audioStreams)
|
||||||
streams.push(...this.video.videoStreams);
|
streams.push(...this.video.videoStreams)
|
||||||
|
|
||||||
const MseSupport = window.MediaSource !== undefined;
|
const MseSupport = window.MediaSource !== undefined
|
||||||
|
|
||||||
var uri;
|
let uri
|
||||||
|
|
||||||
if (this.video.livestream) {
|
if (this.video.livestream) {
|
||||||
uri = this.video.hls;
|
uri = this.video.hls
|
||||||
} else if (this.video.audioStreams.length > 0 && MseSupport) {
|
} else if (this.video.audioStreams.length > 0 && MseSupport) {
|
||||||
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
|
||||||
);
|
)
|
||||||
|
|
||||||
uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(dash);
|
uri = 'data:application/dash+xml;charset=utf-8;base64,' + btoa(dash)
|
||||||
} else {
|
} else {
|
||||||
uri = this.video.videoStreams.filter(stream => stream.codec == null).slice(-1)[0].url;
|
uri = this.video.videoStreams.filter(stream => stream.codec == null).slice(-1)[0].url
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noPrevPlayer) {
|
||||||
|
this.shakaPromise.then(() => {
|
||||||
|
this.shaka.polyfill.installAll()
|
||||||
|
|
||||||
|
const localPlayer = new this.shaka.Player(videoEl)
|
||||||
|
|
||||||
|
localPlayer.getNetworkingEngine().registerRequestFilter((_type, request) => {
|
||||||
|
const uri = request.uris[0]
|
||||||
|
const url = new URL(uri)
|
||||||
|
if (url.host.endsWith('.googlevideo.com')) {
|
||||||
|
url.searchParams.set('host', url.host)
|
||||||
|
url.host = new URL(component.video.proxyUrl).host
|
||||||
|
request.uris[0] = url.toString()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if (noPrevPlayer)
|
localPlayer.configure(
|
||||||
this.shakaPromise.then(() => {
|
'streaming.bufferingGoal',
|
||||||
this.shaka.polyfill.installAll();
|
Math.max(this.getPreferenceNumber('bufferGoal', 10), 10)
|
||||||
|
)
|
||||||
|
|
||||||
const localPlayer = new this.shaka.Player(videoEl);
|
this.setPlayerAttrs(localPlayer, videoEl, uri, this.shaka)
|
||||||
|
})
|
||||||
|
} else this.setPlayerAttrs(this.player, videoEl, uri, this.shaka)
|
||||||
|
|
||||||
localPlayer.getNetworkingEngine().registerRequestFilter((_type, request) => {
|
if (noPrevPlayer) {
|
||||||
const uri = request.uris[0];
|
videoEl.addEventListener('timeupdate', () => {
|
||||||
var url = new URL(uri);
|
if (this.sponsors && this.sponsors.segments) {
|
||||||
if (url.host.endsWith(".googlevideo.com")) {
|
const time = videoEl.currentTime
|
||||||
url.searchParams.set("host", url.host);
|
this.sponsors.segments.forEach(segment => {
|
||||||
url.host = new URL(component.video.proxyUrl).host;
|
if (!segment.skipped || this.selectedAutoLoop) {
|
||||||
request.uris[0] = url.toString();
|
const end = segment.segment[1]
|
||||||
}
|
if (time >= segment.segment[0] && time < end) {
|
||||||
});
|
console.log('Skipped segment at ' + time)
|
||||||
|
videoEl.currentTime = end
|
||||||
localPlayer.configure(
|
segment.skipped = true
|
||||||
"streaming.bufferingGoal",
|
|
||||||
Math.max(this.getPreferenceNumber("bufferGoal", 10), 10),
|
|
||||||
);
|
|
||||||
|
|
||||||
this.setPlayerAttrs(localPlayer, videoEl, uri, this.shaka);
|
|
||||||
});
|
|
||||||
else this.setPlayerAttrs(this.player, videoEl, uri, this.shaka);
|
|
||||||
|
|
||||||
if (noPrevPlayer) {
|
|
||||||
videoEl.addEventListener("timeupdate", () => {
|
|
||||||
if (this.sponsors && this.sponsors.segments) {
|
|
||||||
const time = videoEl.currentTime;
|
|
||||||
this.sponsors.segments.map(segment => {
|
|
||||||
if (!segment.skipped || this.selectedAutoLoop) {
|
|
||||||
const end = segment.segment[1];
|
|
||||||
if (time >= segment.segment[0] && time < end) {
|
|
||||||
console.log("Skipped segment at " + time);
|
|
||||||
videoEl.currentTime = end;
|
|
||||||
segment.skipped = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
videoEl.addEventListener("volumechange", () => {
|
|
||||||
this.setPreference("volume", videoEl.volume);
|
|
||||||
});
|
|
||||||
|
|
||||||
videoEl.addEventListener("ended", () => {
|
|
||||||
if (!this.selectedAutoLoop && this.selectedAutoPlay && this.video.relatedStreams.length > 0) {
|
|
||||||
const params = this.$route.query;
|
|
||||||
let url = this.video.relatedStreams[0].url;
|
|
||||||
const searchParams = new URLSearchParams();
|
|
||||||
for (var param in params)
|
|
||||||
switch (param) {
|
|
||||||
case "v":
|
|
||||||
case "t":
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
searchParams.set(param, params[param]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const paramStr = searchParams.toString();
|
|
||||||
if (paramStr.length > 0) url += "&" + paramStr;
|
|
||||||
this.$router.push(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Add sponsors on seekbar: https://github.com/ajayyy/SponsorBlock/blob/e39de9fd852adb9196e0358ed827ad38d9933e29/src/js-components/previewBar.ts#L12
|
|
||||||
},
|
|
||||||
setPlayerAttrs(localPlayer, videoEl, uri, shaka) {
|
|
||||||
if (!this.ui) {
|
|
||||||
this.ui = new shaka.ui.Overlay(localPlayer, this.$refs.container, videoEl);
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
overflowMenuButtons: ["quality", "captions", "picture_in_picture", "playback_rate"],
|
|
||||||
seekBarColors: {
|
|
||||||
base: "rgba(255, 255, 255, 0.3)",
|
|
||||||
buffered: "rgba(255, 255, 255, 0.54)",
|
|
||||||
played: "rgb(255, 0, 0)",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
this.ui.configure(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
const player = this.ui.getControls().getPlayer();
|
|
||||||
|
|
||||||
this.player = player;
|
|
||||||
|
|
||||||
const disableVideo = this.getPreferenceBoolean("listen", false) && !this.video.livestream;
|
|
||||||
|
|
||||||
this.player.configure({
|
|
||||||
preferredVideoCodecs: ["av01", "vp9", "avc1"],
|
|
||||||
preferredAudioCodecs: ["opus", "mp4a"],
|
|
||||||
manifest: {
|
|
||||||
disableVideo: disableVideo,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const quality = this.getPreferenceNumber("quality", 0);
|
|
||||||
const qualityConds =
|
|
||||||
quality > 0 && (this.video.audioStreams.length > 0 || this.video.livestream) && !disableVideo;
|
|
||||||
if (qualityConds) this.player.configure("abr.enabled", false);
|
|
||||||
|
|
||||||
player.load(uri, 0, uri.indexOf("dash+xml") >= 0 ? "application/dash+xml" : "video/mp4").then(() => {
|
|
||||||
if (qualityConds) {
|
|
||||||
var leastDiff = Number.MAX_VALUE;
|
|
||||||
var bestStream = null;
|
|
||||||
player
|
|
||||||
.getVariantTracks()
|
|
||||||
.sort((a, b) => a.bandwidth - b.bandwidth)
|
|
||||||
.forEach(stream => {
|
|
||||||
const diff = Math.abs(quality - stream.height);
|
|
||||||
if (diff < leastDiff) {
|
|
||||||
leastDiff = diff;
|
|
||||||
bestStream = stream;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
player.selectVariantTrack(bestStream);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.video.subtitles.map(subtitle => {
|
videoEl.addEventListener('volumechange', () => {
|
||||||
player.addTextTrackAsync(
|
this.setPreference('volume', videoEl.volume)
|
||||||
subtitle.url,
|
})
|
||||||
subtitle.code,
|
|
||||||
"SUBTITLE",
|
videoEl.addEventListener('ended', () => {
|
||||||
subtitle.mimeType,
|
if (!this.selectedAutoLoop && this.selectedAutoPlay && this.video.relatedStreams.length > 0) {
|
||||||
null,
|
const params = this.$route.query
|
||||||
subtitle.name,
|
let url = this.video.relatedStreams[0].url
|
||||||
);
|
const searchParams = new URLSearchParams()
|
||||||
});
|
for (const param in params) {
|
||||||
videoEl.volume = this.getPreferenceNumber("volume", 1);
|
switch (param) {
|
||||||
});
|
case 'v':
|
||||||
},
|
case 't':
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
searchParams.set(param, params[param])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const paramStr = searchParams.toString()
|
||||||
|
if (paramStr.length > 0) url += '&' + paramStr
|
||||||
|
this.$router.push(url)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add sponsors on seekbar: https://github.com/ajayyy/SponsorBlock/blob/e39de9fd852adb9196e0358ed827ad38d9933e29/src/js-components/previewBar.ts#L12
|
||||||
},
|
},
|
||||||
activated() {
|
setPlayerAttrs (localPlayer, videoEl, uri, shaka) {
|
||||||
import("hotkeys-js")
|
if (!this.ui) {
|
||||||
.then(mod => mod.default)
|
this.ui = new shaka.ui.Overlay(localPlayer, this.$refs.container, videoEl)
|
||||||
.then(hotkeys => {
|
|
||||||
this.hotkeys = hotkeys;
|
const config = {
|
||||||
var self = this;
|
overflowMenuButtons: ['quality', 'captions', 'picture_in_picture', 'playback_rate'],
|
||||||
hotkeys("f,m,space,up,down,left,right", function(e, handler) {
|
seekBarColors: {
|
||||||
const videoEl = self.$refs.videoEl;
|
base: 'rgba(255, 255, 255, 0.3)',
|
||||||
switch (handler.key) {
|
buffered: 'rgba(255, 255, 255, 0.54)',
|
||||||
case "f":
|
played: 'rgb(255, 0, 0)'
|
||||||
if (document.fullscreenElement) document.exitFullscreen();
|
}
|
||||||
else self.$refs.container.requestFullscreen();
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
case "m":
|
|
||||||
videoEl.muted = !videoEl.muted;
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
case "space":
|
|
||||||
if (videoEl.paused) videoEl.play();
|
|
||||||
else videoEl.pause();
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
case "up":
|
|
||||||
videoEl.volume = Math.min(videoEl.volume + 0.05, 1);
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
case "down":
|
|
||||||
videoEl.volume = Math.max(videoEl.volume - 0.05, 0);
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
case "left":
|
|
||||||
videoEl.currentTime = Math.max(videoEl.currentTime - 5, 0);
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
case "right":
|
|
||||||
videoEl.currentTime = videoEl.currentTime + 5;
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deactivated() {
|
|
||||||
if (this.ui) {
|
|
||||||
this.ui.destroy();
|
|
||||||
this.ui = undefined;
|
|
||||||
this.player = undefined;
|
|
||||||
}
|
}
|
||||||
if (this.player) {
|
|
||||||
this.player.destroy();
|
this.ui.configure(config)
|
||||||
this.player = undefined;
|
}
|
||||||
|
|
||||||
|
const player = this.ui.getControls().getPlayer()
|
||||||
|
|
||||||
|
this.player = player
|
||||||
|
|
||||||
|
const disableVideo = this.getPreferenceBoolean('listen', false) && !this.video.livestream
|
||||||
|
|
||||||
|
this.player.configure({
|
||||||
|
preferredVideoCodecs: ['av01', 'vp9', 'avc1'],
|
||||||
|
preferredAudioCodecs: ['opus', 'mp4a'],
|
||||||
|
manifest: {
|
||||||
|
disableVideo: disableVideo
|
||||||
}
|
}
|
||||||
if (this.hotkeys) this.hotkeys.unbind();
|
})
|
||||||
this.$refs.container.querySelectorAll("div").forEach(node => node.remove());
|
|
||||||
},
|
const quality = this.getPreferenceNumber('quality', 0)
|
||||||
};
|
const qualityConds =
|
||||||
|
quality > 0 && (this.video.audioStreams.length > 0 || this.video.livestream) && !disableVideo
|
||||||
|
if (qualityConds) this.player.configure('abr.enabled', false)
|
||||||
|
|
||||||
|
player.load(uri, 0, uri.indexOf('dash+xml') >= 0 ? 'application/dash+xml' : 'video/mp4').then(() => {
|
||||||
|
if (qualityConds) {
|
||||||
|
let leastDiff = Number.MAX_VALUE
|
||||||
|
let bestStream = null
|
||||||
|
player
|
||||||
|
.getVariantTracks()
|
||||||
|
.sort((a, b) => a.bandwidth - b.bandwidth)
|
||||||
|
.forEach(stream => {
|
||||||
|
const diff = Math.abs(quality - stream.height)
|
||||||
|
if (diff < leastDiff) {
|
||||||
|
leastDiff = diff
|
||||||
|
bestStream = stream
|
||||||
|
}
|
||||||
|
})
|
||||||
|
player.selectVariantTrack(bestStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.video.subtitles.forEach(subtitle => {
|
||||||
|
player.addTextTrackAsync(
|
||||||
|
subtitle.url,
|
||||||
|
subtitle.code,
|
||||||
|
'SUBTITLE',
|
||||||
|
subtitle.mimeType,
|
||||||
|
null,
|
||||||
|
subtitle.name
|
||||||
|
)
|
||||||
|
})
|
||||||
|
videoEl.volume = this.getPreferenceNumber('volume', 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activated () {
|
||||||
|
import('hotkeys-js')
|
||||||
|
.then(mod => mod.default)
|
||||||
|
.then(hotkeys => {
|
||||||
|
this.hotkeys = hotkeys
|
||||||
|
const self = this
|
||||||
|
hotkeys('f,m,space,up,down,left,right', function (e, handler) {
|
||||||
|
const videoEl = self.$refs.videoEl
|
||||||
|
switch (handler.key) {
|
||||||
|
case 'f':
|
||||||
|
if (document.fullscreenElement) document.exitFullscreen()
|
||||||
|
else self.$refs.container.requestFullscreen()
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
case 'm':
|
||||||
|
videoEl.muted = !videoEl.muted
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
case 'space':
|
||||||
|
if (videoEl.paused) videoEl.play()
|
||||||
|
else videoEl.pause()
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
case 'up':
|
||||||
|
videoEl.volume = Math.min(videoEl.volume + 0.05, 1)
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
case 'down':
|
||||||
|
videoEl.volume = Math.max(videoEl.volume - 0.05, 0)
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
case 'left':
|
||||||
|
videoEl.currentTime = Math.max(videoEl.currentTime - 5, 0)
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
case 'right':
|
||||||
|
videoEl.currentTime = videoEl.currentTime + 5
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deactivated () {
|
||||||
|
if (this.ui) {
|
||||||
|
this.ui.destroy()
|
||||||
|
this.ui = undefined
|
||||||
|
this.player = undefined
|
||||||
|
}
|
||||||
|
if (this.player) {
|
||||||
|
this.player.destroy()
|
||||||
|
this.player = undefined
|
||||||
|
}
|
||||||
|
if (this.hotkeys) this.hotkeys.unbind()
|
||||||
|
this.$refs.container.querySelectorAll('div').forEach(node => node.remove())
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -35,56 +35,56 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ErrorHandler from "@/components/ErrorHandler.vue";
|
import ErrorHandler from '@/components/ErrorHandler.vue'
|
||||||
import VideoItem from "@/components/VideoItem.vue";
|
import VideoItem from '@/components/VideoItem.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
playlist: null,
|
playlist: null
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.getPlaylistData()
|
||||||
|
},
|
||||||
|
activated () {
|
||||||
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
deactivated () {
|
||||||
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
getRssUrl: _this => {
|
||||||
|
return _this.apiUrl() + '/rss/playlists/' + _this.$route.query.list
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchPlaylist () {
|
||||||
|
return await await this.fetchJson(this.apiUrl() + '/playlists/' + this.$route.query.list)
|
||||||
},
|
},
|
||||||
mounted() {
|
async getPlaylistData () {
|
||||||
this.getPlaylistData();
|
this.fetchPlaylist()
|
||||||
|
.then(data => (this.playlist = data))
|
||||||
|
.then(() => (document.title = this.playlist.name + ' - Piped'))
|
||||||
},
|
},
|
||||||
activated() {
|
handleScroll () {
|
||||||
window.addEventListener("scroll", this.handleScroll);
|
if (this.loading || !this.playlist || !this.playlist.nextpage) return
|
||||||
},
|
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
|
||||||
deactivated() {
|
this.loading = true
|
||||||
window.removeEventListener("scroll", this.handleScroll);
|
this.fetchJson(this.apiUrl() + '/nextpage/playlists/' + this.$route.query.list, {
|
||||||
},
|
nextpage: this.playlist.nextpage
|
||||||
computed: {
|
}).then(json => {
|
||||||
getRssUrl: _this => {
|
this.playlist.relatedStreams.concat(json.relatedStreams)
|
||||||
return _this.apiUrl() + "/rss/playlists/" + _this.$route.query.list;
|
this.playlist.nextpage = json.nextpage
|
||||||
},
|
this.loading = false
|
||||||
},
|
json.relatedStreams.map(stream => this.playlist.relatedStreams.push(stream))
|
||||||
methods: {
|
})
|
||||||
async fetchPlaylist() {
|
}
|
||||||
return await await this.fetchJson(this.apiUrl() + "/playlists/" + this.$route.query.list);
|
}
|
||||||
},
|
},
|
||||||
async getPlaylistData() {
|
components: {
|
||||||
this.fetchPlaylist()
|
ErrorHandler,
|
||||||
.then(data => (this.playlist = data))
|
VideoItem
|
||||||
.then(() => (document.title = this.playlist.name + " - Piped"));
|
}
|
||||||
},
|
}
|
||||||
handleScroll() {
|
|
||||||
if (this.loading || !this.playlist || !this.playlist.nextpage) return;
|
|
||||||
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
|
|
||||||
this.loading = true;
|
|
||||||
this.fetchJson(this.apiUrl() + "/nextpage/playlists/" + this.$route.query.list, {
|
|
||||||
nextpage: this.playlist.nextpage,
|
|
||||||
}).then(json => {
|
|
||||||
this.playlist.relatedStreams.concat(json.relatedStreams);
|
|
||||||
this.playlist.nextpage = json.nextpage;
|
|
||||||
this.loading = false;
|
|
||||||
json.relatedStreams.map(stream => this.playlist.relatedStreams.push(stream));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
ErrorHandler,
|
|
||||||
VideoItem,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -112,139 +112,139 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CountryMap from "@/utils/CountryMap.js";
|
import CountryMap from '@/utils/CountryMap.js'
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
selectedInstance: null,
|
selectedInstance: null,
|
||||||
instances: [],
|
instances: [],
|
||||||
sponsorBlock: true,
|
sponsorBlock: true,
|
||||||
skipSponsor: true,
|
skipSponsor: true,
|
||||||
skipIntro: false,
|
skipIntro: false,
|
||||||
skipOutro: false,
|
skipOutro: false,
|
||||||
skipPreview: false,
|
skipPreview: false,
|
||||||
skipInteraction: true,
|
skipInteraction: true,
|
||||||
skipSelfPromo: true,
|
skipSelfPromo: true,
|
||||||
skipMusicOffTopic: true,
|
skipMusicOffTopic: true,
|
||||||
selectedTheme: "dark",
|
selectedTheme: 'dark',
|
||||||
autoPlayVideo: true,
|
autoPlayVideo: true,
|
||||||
listen: false,
|
listen: false,
|
||||||
resolutions: [144, 240, 360, 480, 720, 1080, 1440, 2160, 4320],
|
resolutions: [144, 240, 360, 480, 720, 1080, 1440, 2160, 4320],
|
||||||
defaultQuality: 0,
|
defaultQuality: 0,
|
||||||
bufferingGoal: 10,
|
bufferingGoal: 10,
|
||||||
countryMap: CountryMap.COUNTRIES,
|
countryMap: CountryMap.COUNTRIES,
|
||||||
country: "US",
|
country: 'US',
|
||||||
defaultHomepage: "trending",
|
defaultHomepage: 'trending',
|
||||||
showComments: true,
|
showComments: true
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
if (Object.keys(this.$route.query).length > 0) this.$router.replace({ query: {} });
|
if (Object.keys(this.$route.query).length > 0) this.$router.replace({ query: {} })
|
||||||
|
|
||||||
fetch("https://raw.githubusercontent.com/wiki/TeamPiped/Piped-Frontend/Instances.md")
|
fetch('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;
|
let skipped = 0
|
||||||
const lines = body.split("\n");
|
const lines = body.split('\n')
|
||||||
lines.map(line => {
|
lines.forEach(line => {
|
||||||
const split = line.split("|");
|
const split = line.split('|')
|
||||||
if (split.length == 4) {
|
if (split.length === 4) {
|
||||||
if (skipped < 2) {
|
if (skipped < 2) {
|
||||||
skipped++;
|
skipped++
|
||||||
return;
|
return
|
||||||
}
|
|
||||||
this.instances.push({
|
|
||||||
name: split[0].trim(),
|
|
||||||
apiurl: split[1].trim(),
|
|
||||||
locations: split[2].trim(),
|
|
||||||
cdn: split[3].trim(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (localStorage) {
|
|
||||||
this.selectedInstance = this.getPreferenceString("instance", "https://pipedapi.kavin.rocks");
|
|
||||||
|
|
||||||
this.sponsorBlock = this.getPreferenceBoolean("sponsorblock", true);
|
|
||||||
if (localStorage.getItem("selectedSkip") !== null) {
|
|
||||||
var skipList = localStorage.getItem("selectedSkip").split(",");
|
|
||||||
this.skipSponsor = this.skipIntro = this.skipOutro = this.skipPreview = this.skipInteraction = this.skipSelfPromo = this.skipMusicOffTopic = false;
|
|
||||||
skipList.forEach(skip => {
|
|
||||||
switch (skip) {
|
|
||||||
case "sponsor":
|
|
||||||
this.skipSponsor = true;
|
|
||||||
break;
|
|
||||||
case "intro":
|
|
||||||
this.skipIntro = true;
|
|
||||||
break;
|
|
||||||
case "outro":
|
|
||||||
this.skipOutro = true;
|
|
||||||
break;
|
|
||||||
case "preview":
|
|
||||||
this.skipPreview = true;
|
|
||||||
break;
|
|
||||||
case "interaction":
|
|
||||||
this.skipInteraction = true;
|
|
||||||
break;
|
|
||||||
case "selfpromo":
|
|
||||||
this.skipSelfPromo = true;
|
|
||||||
break;
|
|
||||||
case "music_offtopic":
|
|
||||||
this.skipMusicOffTopic = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.log("Unknown sponsor type: " + skip);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
this.instances.push({
|
||||||
|
name: split[0].trim(),
|
||||||
|
apiurl: split[1].trim(),
|
||||||
|
locations: split[2].trim(),
|
||||||
|
cdn: split[3].trim()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
this.selectedTheme = this.getPreferenceString("theme", "dark");
|
if (localStorage) {
|
||||||
this.autoPlayVideo = this.getPreferenceBoolean(localStorage.getItem("playerAutoPlay"), true);
|
this.selectedInstance = this.getPreferenceString('instance', 'https://pipedapi.kavin.rocks')
|
||||||
this.listen = this.getPreferenceBoolean("listen", false);
|
|
||||||
this.defaultQuality = Number(localStorage.getItem("quality"));
|
this.sponsorBlock = this.getPreferenceBoolean('sponsorblock', true)
|
||||||
this.bufferingGoal = Math.max(Number(localStorage.getItem("bufferGoal")), 10);
|
if (localStorage.getItem('selectedSkip') !== null) {
|
||||||
this.country = this.getPreferenceString("region", "US");
|
const skipList = localStorage.getItem('selectedSkip').split(',')
|
||||||
this.defaultHomepage = this.getPreferenceString("homepage", "trending");
|
this.skipSponsor = this.skipIntro = this.skipOutro = this.skipPreview = this.skipInteraction = this.skipSelfPromo = this.skipMusicOffTopic = false
|
||||||
this.showComments = this.getPreferenceBoolean("comments", true);
|
skipList.forEach(skip => {
|
||||||
}
|
switch (skip) {
|
||||||
|
case 'sponsor':
|
||||||
|
this.skipSponsor = true
|
||||||
|
break
|
||||||
|
case 'intro':
|
||||||
|
this.skipIntro = true
|
||||||
|
break
|
||||||
|
case 'outro':
|
||||||
|
this.skipOutro = true
|
||||||
|
break
|
||||||
|
case 'preview':
|
||||||
|
this.skipPreview = true
|
||||||
|
break
|
||||||
|
case 'interaction':
|
||||||
|
this.skipInteraction = true
|
||||||
|
break
|
||||||
|
case 'selfpromo':
|
||||||
|
this.skipSelfPromo = true
|
||||||
|
break
|
||||||
|
case 'music_offtopic':
|
||||||
|
this.skipMusicOffTopic = true
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log('Unknown sponsor type: ' + skip)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedTheme = this.getPreferenceString('theme', 'dark')
|
||||||
|
this.autoPlayVideo = this.getPreferenceBoolean(localStorage.getItem('playerAutoPlay'), true)
|
||||||
|
this.listen = this.getPreferenceBoolean('listen', false)
|
||||||
|
this.defaultQuality = Number(localStorage.getItem('quality'))
|
||||||
|
this.bufferingGoal = Math.max(Number(localStorage.getItem('bufferGoal')), 10)
|
||||||
|
this.country = this.getPreferenceString('region', 'US')
|
||||||
|
this.defaultHomepage = this.getPreferenceString('homepage', 'trending')
|
||||||
|
this.showComments = this.getPreferenceBoolean('comments', true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange () {
|
||||||
|
if (localStorage) {
|
||||||
|
let shouldReload = false
|
||||||
|
|
||||||
|
if (this.getPreferenceString('theme', 'dark') !== this.selectedTheme) shouldReload = true
|
||||||
|
|
||||||
|
localStorage.setItem('instance', this.selectedInstance)
|
||||||
|
localStorage.setItem('sponsorblock', this.sponsorBlock)
|
||||||
|
|
||||||
|
const sponsorSelected = []
|
||||||
|
if (this.skipSponsor) sponsorSelected.push('sponsor')
|
||||||
|
if (this.skipIntro) sponsorSelected.push('intro')
|
||||||
|
if (this.skipOutro) sponsorSelected.push('outro')
|
||||||
|
if (this.skipPreview) sponsorSelected.push('preview')
|
||||||
|
if (this.skipInteraction) sponsorSelected.push('interaction')
|
||||||
|
if (this.skipSelfPromo) sponsorSelected.push('selfpromo')
|
||||||
|
if (this.skipMusicOffTopic) sponsorSelected.push('music_offtopic')
|
||||||
|
localStorage.setItem('selectedSkip', sponsorSelected)
|
||||||
|
|
||||||
|
localStorage.setItem('theme', this.selectedTheme)
|
||||||
|
localStorage.setItem('playerAutoPlay', this.autoPlayVideo)
|
||||||
|
localStorage.setItem('listen', this.listen)
|
||||||
|
localStorage.setItem('quality', this.defaultQuality)
|
||||||
|
localStorage.setItem('bufferGoal', this.bufferingGoal)
|
||||||
|
localStorage.setItem('region', this.country)
|
||||||
|
localStorage.setItem('homepage', this.defaultHomepage)
|
||||||
|
localStorage.setItem('comments', this.showComments)
|
||||||
|
|
||||||
|
if (shouldReload) window.location.reload()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
sslScore (url) {
|
||||||
onChange() {
|
return 'https://www.ssllabs.com/ssltest/analyze.html?d=' + new URL(url).host + '&latest'
|
||||||
if (localStorage) {
|
}
|
||||||
var shouldReload = false;
|
}
|
||||||
|
}
|
||||||
if (this.getPreferenceString("theme", "dark") !== this.selectedTheme) shouldReload = true;
|
|
||||||
|
|
||||||
localStorage.setItem("instance", this.selectedInstance);
|
|
||||||
localStorage.setItem("sponsorblock", this.sponsorBlock);
|
|
||||||
|
|
||||||
var sponsorSelected = [];
|
|
||||||
if (this.skipSponsor) sponsorSelected.push("sponsor");
|
|
||||||
if (this.skipIntro) sponsorSelected.push("intro");
|
|
||||||
if (this.skipOutro) sponsorSelected.push("outro");
|
|
||||||
if (this.skipPreview) sponsorSelected.push("preview");
|
|
||||||
if (this.skipInteraction) sponsorSelected.push("interaction");
|
|
||||||
if (this.skipSelfPromo) sponsorSelected.push("selfpromo");
|
|
||||||
if (this.skipMusicOffTopic) sponsorSelected.push("music_offtopic");
|
|
||||||
localStorage.setItem("selectedSkip", sponsorSelected);
|
|
||||||
|
|
||||||
localStorage.setItem("theme", this.selectedTheme);
|
|
||||||
localStorage.setItem("playerAutoPlay", this.autoPlayVideo);
|
|
||||||
localStorage.setItem("listen", this.listen);
|
|
||||||
localStorage.setItem("quality", this.defaultQuality);
|
|
||||||
localStorage.setItem("bufferGoal", this.bufferingGoal);
|
|
||||||
localStorage.setItem("region", this.country);
|
|
||||||
localStorage.setItem("homepage", this.defaultHomepage);
|
|
||||||
localStorage.setItem("comments", this.showComments);
|
|
||||||
|
|
||||||
if (shouldReload) window.location.reload();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sslScore(url) {
|
|
||||||
return "https://www.ssllabs.com/ssltest/analyze.html?d=" + new URL(url).host + "&latest";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -33,34 +33,34 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
username: null,
|
username: null,
|
||||||
password: null,
|
password: null
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
//TODO: Add Server Side check
|
// TODO: Add Server Side check
|
||||||
if (this.getAuthToken()) {
|
if (this.getAuthToken()) {
|
||||||
this.$router.push("/");
|
this.$router.push('/')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
register() {
|
register () {
|
||||||
console.log("authToken" + this.hashCode(this.apiUrl()));
|
console.log('authToken' + this.hashCode(this.apiUrl()))
|
||||||
this.fetchJson(this.apiUrl() + "/register", null, {
|
this.fetchJson(this.apiUrl() + '/register', null, {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password,
|
password: this.password
|
||||||
}),
|
})
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
if (resp.token) {
|
if (resp.token) {
|
||||||
this.setPreference("authToken" + this.hashCode(this.apiUrl()), resp.token);
|
this.setPreference('authToken' + this.hashCode(this.apiUrl()), resp.token)
|
||||||
window.location = "/"; // done to bypass cache
|
window.location = '/' // done to bypass cache
|
||||||
} else alert(resp.error);
|
} else alert(resp.error)
|
||||||
});
|
})
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -68,58 +68,58 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
results: null,
|
results: null,
|
||||||
availableFilters: [
|
availableFilters: [
|
||||||
"all",
|
'all',
|
||||||
"videos",
|
'videos',
|
||||||
"channels",
|
'channels',
|
||||||
"playlists",
|
'playlists',
|
||||||
"music_songs",
|
'music_songs',
|
||||||
"music_videos",
|
'music_videos',
|
||||||
"music_albums",
|
'music_albums',
|
||||||
"music_playlists",
|
'music_playlists'
|
||||||
],
|
],
|
||||||
selectedFilter: "all",
|
selectedFilter: 'all'
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.updateResults()
|
||||||
|
},
|
||||||
|
activated () {
|
||||||
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
deactivated () {
|
||||||
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchResults () {
|
||||||
|
return await await this.fetchJson(this.apiUrl() + '/search', {
|
||||||
|
q: this.$route.query.search_query,
|
||||||
|
filter: this.selectedFilter
|
||||||
|
})
|
||||||
},
|
},
|
||||||
mounted() {
|
async updateResults () {
|
||||||
this.updateResults();
|
document.title = this.$route.query.search_query + ' - Piped'
|
||||||
|
this.results = this.fetchResults().then(json => (this.results = json))
|
||||||
},
|
},
|
||||||
activated() {
|
handleScroll () {
|
||||||
window.addEventListener("scroll", this.handleScroll);
|
if (this.loading || !this.results || !this.results.nextpage) return
|
||||||
},
|
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
|
||||||
deactivated() {
|
this.loading = true
|
||||||
window.removeEventListener("scroll", this.handleScroll);
|
this.fetchJson(this.apiUrl() + '/nextpage/search', {
|
||||||
},
|
nextpage: this.results.nextpage,
|
||||||
methods: {
|
q: this.$route.query.search_query,
|
||||||
async fetchResults() {
|
filter: this.selectedFilter
|
||||||
return await await this.fetchJson(this.apiUrl() + "/search", {
|
}).then(json => {
|
||||||
q: this.$route.query.search_query,
|
this.results.nextpage = json.nextpage
|
||||||
filter: this.selectedFilter,
|
this.results.id = json.id
|
||||||
});
|
this.loading = false
|
||||||
},
|
json.items.map(stream => this.results.items.push(stream))
|
||||||
async updateResults() {
|
})
|
||||||
document.title = this.$route.query.search_query + " - Piped";
|
}
|
||||||
this.results = this.fetchResults().then(json => (this.results = json));
|
}
|
||||||
},
|
}
|
||||||
handleScroll() {
|
}
|
||||||
if (this.loading || !this.results || !this.results.nextpage) return;
|
|
||||||
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
|
|
||||||
this.loading = true;
|
|
||||||
this.fetchJson(this.apiUrl() + "/nextpage/search", {
|
|
||||||
nextpage: this.results.nextpage,
|
|
||||||
q: this.$route.query.search_query,
|
|
||||||
filter: this.selectedFilter,
|
|
||||||
}).then(json => {
|
|
||||||
this.results.nextpage = json.nextpage;
|
|
||||||
this.results.id = json.id;
|
|
||||||
this.loading = false;
|
|
||||||
json.items.map(stream => this.results.items.push(stream));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -20,60 +20,60 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
searchText: String,
|
searchText: String
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
selected: 0,
|
||||||
|
searchSuggestions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onKeyUp (e) {
|
||||||
|
if (e.key === 'ArrowUp') {
|
||||||
|
if (this.selected <= 0) {
|
||||||
|
this.setSelected(this.searchSuggestions.length - 1)
|
||||||
|
} else {
|
||||||
|
this.setSelected(this.selected - 1)
|
||||||
|
}
|
||||||
|
e.preventDefault()
|
||||||
|
} else if (e.key === 'ArrowDown') {
|
||||||
|
if (this.selected >= this.searchSuggestions.length - 1) {
|
||||||
|
this.setSelected(0)
|
||||||
|
} else {
|
||||||
|
this.setSelected(this.selected + 1)
|
||||||
|
}
|
||||||
|
e.preventDefault()
|
||||||
|
} else {
|
||||||
|
this.refreshSuggestions()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
async refreshSuggestions () {
|
||||||
return {
|
this.searchSuggestions = await this.fetchJson(this.apiUrl() + '/suggestions', {
|
||||||
selected: 0,
|
query: this.searchText
|
||||||
searchSuggestions: [],
|
})
|
||||||
};
|
this.searchSuggestions.unshift(this.searchText)
|
||||||
|
this.setSelected(0)
|
||||||
},
|
},
|
||||||
methods: {
|
onMouseOver (i) {
|
||||||
onKeyUp(e) {
|
if (i !== this.selected) {
|
||||||
if (e.key === "ArrowUp") {
|
this.selected = i
|
||||||
if (this.selected <= 0) {
|
}
|
||||||
this.setSelected(this.searchSuggestions.length - 1);
|
|
||||||
} else {
|
|
||||||
this.setSelected(this.selected - 1);
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
} else if (e.key === "ArrowDown") {
|
|
||||||
if (this.selected >= this.searchSuggestions.length - 1) {
|
|
||||||
this.setSelected(0);
|
|
||||||
} else {
|
|
||||||
this.setSelected(this.selected + 1);
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
} else {
|
|
||||||
this.refreshSuggestions();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async refreshSuggestions() {
|
|
||||||
this.searchSuggestions = await this.fetchJson(this.apiUrl() + "/suggestions", {
|
|
||||||
query: this.searchText,
|
|
||||||
});
|
|
||||||
this.searchSuggestions.unshift(this.searchText);
|
|
||||||
this.setSelected(0);
|
|
||||||
},
|
|
||||||
onMouseOver(i) {
|
|
||||||
if (i !== this.selected) {
|
|
||||||
this.selected = i;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onClick(i) {
|
|
||||||
this.setSelected(i);
|
|
||||||
this.$router.push({
|
|
||||||
name: "SearchResults",
|
|
||||||
query: { search_query: this.searchSuggestions[i] },
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setSelected(val) {
|
|
||||||
this.selected = val;
|
|
||||||
this.$emit("searchchange", this.searchSuggestions[this.selected]);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
onClick (i) {
|
||||||
|
this.setSelected(i)
|
||||||
|
this.$router.push({
|
||||||
|
name: 'SearchResults',
|
||||||
|
query: { search_query: this.searchSuggestions[i] }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setSelected (val) {
|
||||||
|
this.selected = val
|
||||||
|
this.$emit('searchchange', this.searchSuggestions[this.selected])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -16,30 +16,30 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import VideoItem from "@/components/VideoItem.vue";
|
import VideoItem from '@/components/VideoItem.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
videos: [],
|
videos: []
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
document.title = "Trending - Piped";
|
document.title = 'Trending - Piped'
|
||||||
|
|
||||||
let region = this.getPreferenceString("region", "US");
|
const region = this.getPreferenceString('region', 'US')
|
||||||
|
|
||||||
this.fetchTrending(region).then(videos => (this.videos = videos));
|
this.fetchTrending(region).then(videos => (this.videos = videos))
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchTrending(region) {
|
async fetchTrending (region) {
|
||||||
return await this.fetchJson(this.apiUrl() + "/trending", {
|
return await this.fetchJson(this.apiUrl() + '/trending', {
|
||||||
region: region || "US",
|
region: region || 'US'
|
||||||
});
|
})
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
VideoItem,
|
VideoItem
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -45,11 +45,11 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
video: Object,
|
video: Object,
|
||||||
height: String,
|
height: String,
|
||||||
width: String,
|
width: String,
|
||||||
hideChannel: Boolean,
|
hideChannel: Boolean
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
<div>Loading...</div>
|
<div>Loading...</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
activated() {
|
activated () {
|
||||||
const videoId = this.$route.params.videoId;
|
const videoId = this.$route.params.videoId
|
||||||
if (videoId)
|
if (videoId) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: "/watch",
|
path: '/watch',
|
||||||
query: { v: videoId },
|
query: { v: videoId }
|
||||||
});
|
})
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -125,147 +125,146 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Player from "@/components/Player.vue";
|
import Player from '@/components/Player.vue'
|
||||||
import VideoItem from "@/components/VideoItem.vue";
|
import VideoItem from '@/components/VideoItem.vue'
|
||||||
import ErrorHandler from "@/components/ErrorHandler.vue";
|
import ErrorHandler from '@/components/ErrorHandler.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: 'App',
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
video: {
|
video: {
|
||||||
title: "Loading...",
|
title: 'Loading...'
|
||||||
},
|
},
|
||||||
sponsors: null,
|
sponsors: null,
|
||||||
selectedAutoLoop: false,
|
selectedAutoLoop: false,
|
||||||
selectedAutoPlay: null,
|
selectedAutoPlay: null,
|
||||||
showDesc: true,
|
showDesc: true,
|
||||||
comments: null,
|
comments: null,
|
||||||
subscribed: false,
|
subscribed: false,
|
||||||
channelId: null,
|
channelId: null
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.getVideoData().then(() => {
|
||||||
|
this.$refs.videoPlayer.loadVideo()
|
||||||
|
})
|
||||||
|
this.getSponsors()
|
||||||
|
if (this.getPreferenceBoolean('comments', true)) this.getComments()
|
||||||
|
},
|
||||||
|
activated () {
|
||||||
|
this.selectedAutoPlay = this.getPreferenceBoolean('autoplay', true)
|
||||||
|
if (this.video.duration) this.$refs.videoPlayer.loadVideo()
|
||||||
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
deactivated () {
|
||||||
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$route.query.v': function (v) {
|
||||||
|
if (v) {
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchVideo () {
|
||||||
|
return this.fetchJson(this.apiUrl() + '/streams/' + this.getVideoId())
|
||||||
},
|
},
|
||||||
mounted() {
|
async fetchSponsors () {
|
||||||
this.getVideoData().then(() => {
|
return await this.fetchJson(this.apiUrl() + '/sponsors/' + this.getVideoId(), {
|
||||||
this.$refs.videoPlayer.loadVideo();
|
category:
|
||||||
});
|
|
||||||
this.getSponsors();
|
|
||||||
if (this.getPreferenceBoolean("comments", true)) this.getComments();
|
|
||||||
},
|
|
||||||
activated() {
|
|
||||||
this.selectedAutoPlay = this.getPreferenceBoolean("autoplay", true);
|
|
||||||
if (this.video.duration) this.$refs.videoPlayer.loadVideo();
|
|
||||||
window.addEventListener("scroll", this.handleScroll);
|
|
||||||
},
|
|
||||||
deactivated() {
|
|
||||||
window.removeEventListener("scroll", this.handleScroll);
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
"$route.query.v": function(v) {
|
|
||||||
if (v) {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fetchVideo() {
|
|
||||||
return this.fetchJson(this.apiUrl() + "/streams/" + this.getVideoId());
|
|
||||||
},
|
|
||||||
async fetchSponsors() {
|
|
||||||
return await this.fetchJson(this.apiUrl() + "/sponsors/" + this.getVideoId(), {
|
|
||||||
category:
|
|
||||||
'["' +
|
'["' +
|
||||||
this.getPreferenceString("selectedSkip", "sponsor,interaction,selfpromo,music_offtopic").replaceAll(
|
this.getPreferenceString('selectedSkip', 'sponsor,interaction,selfpromo,music_offtopic').replaceAll(
|
||||||
",",
|
',',
|
||||||
'","',
|
'","'
|
||||||
) +
|
) +
|
||||||
'"]',
|
'"]'
|
||||||
});
|
})
|
||||||
},
|
|
||||||
fetchComments() {
|
|
||||||
return this.fetchJson(this.apiUrl() + "/comments/" + this.getVideoId());
|
|
||||||
},
|
|
||||||
onChange() {
|
|
||||||
this.setPreference("autoplay", this.selectedAutoPlay);
|
|
||||||
},
|
|
||||||
async getVideoData() {
|
|
||||||
await this.fetchVideo()
|
|
||||||
.then(data => {
|
|
||||||
this.video = data;
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
if (!this.video.error) {
|
|
||||||
document.title = this.video.title + " - Piped";
|
|
||||||
this.channelId = this.video.uploaderUrl.split("/")[2];
|
|
||||||
this.fetchSubscribedStatus();
|
|
||||||
|
|
||||||
this.video.description = this.purifyHTML(
|
|
||||||
this.video.description
|
|
||||||
.replaceAll("http://www.youtube.com", "")
|
|
||||||
.replaceAll("https://www.youtube.com", "")
|
|
||||||
.replaceAll("\n", "<br>"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async getSponsors() {
|
|
||||||
if (this.getPreferenceBoolean("sponsorblock", true))
|
|
||||||
this.fetchSponsors().then(data => (this.sponsors = data));
|
|
||||||
},
|
|
||||||
async getComments() {
|
|
||||||
this.fetchComments().then(data => (this.comments = data));
|
|
||||||
},
|
|
||||||
async fetchSubscribedStatus() {
|
|
||||||
if (!this.channelId) return;
|
|
||||||
|
|
||||||
this.fetchJson(
|
|
||||||
this.apiUrl() + "/subscribed",
|
|
||||||
{
|
|
||||||
channelId: this.channelId,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: this.getAuthToken(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
).then(json => {
|
|
||||||
this.subscribed = json.subscribed;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
subscribeHandler() {
|
|
||||||
this.fetchJson(this.apiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({
|
|
||||||
channelId: this.channelId,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
Authorization: this.getAuthToken(),
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.subscribed = !this.subscribed;
|
|
||||||
},
|
|
||||||
handleScroll() {
|
|
||||||
if (this.loading || !this.comments || !this.comments.nextpage) return;
|
|
||||||
if (window.innerHeight + window.scrollY >= this.$refs.comments.offsetHeight - window.innerHeight) {
|
|
||||||
this.loading = true;
|
|
||||||
this.fetchJson(this.apiUrl() + "/nextpage/comments/" + this.getVideoId(), {
|
|
||||||
url: this.comments.nextpage,
|
|
||||||
}).then(json => {
|
|
||||||
this.comments.nextpage = json.nextpage;
|
|
||||||
this.loading = false;
|
|
||||||
json.comments.map(comment => this.comments.comments.push(comment));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getVideoId() {
|
|
||||||
return this.$route.query.v || this.$route.params.v;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
components: {
|
fetchComments () {
|
||||||
Player,
|
return this.fetchJson(this.apiUrl() + '/comments/' + this.getVideoId())
|
||||||
VideoItem,
|
|
||||||
ErrorHandler,
|
|
||||||
},
|
},
|
||||||
};
|
onChange () {
|
||||||
|
this.setPreference('autoplay', this.selectedAutoPlay)
|
||||||
|
},
|
||||||
|
async getVideoData () {
|
||||||
|
await this.fetchVideo()
|
||||||
|
.then(data => {
|
||||||
|
this.video = data
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
if (!this.video.error) {
|
||||||
|
document.title = this.video.title + ' - Piped'
|
||||||
|
this.channelId = this.video.uploaderUrl.split('/')[2]
|
||||||
|
this.fetchSubscribedStatus()
|
||||||
|
|
||||||
|
this.video.description = this.purifyHTML(
|
||||||
|
this.video.description
|
||||||
|
.replaceAll('http://www.youtube.com', '')
|
||||||
|
.replaceAll('https://www.youtube.com', '')
|
||||||
|
.replaceAll('\n', '<br>')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async getSponsors () {
|
||||||
|
if (this.getPreferenceBoolean('sponsorblock', true)) { this.fetchSponsors().then(data => (this.sponsors = data)) }
|
||||||
|
},
|
||||||
|
async getComments () {
|
||||||
|
this.fetchComments().then(data => (this.comments = data))
|
||||||
|
},
|
||||||
|
async fetchSubscribedStatus () {
|
||||||
|
if (!this.channelId) return
|
||||||
|
|
||||||
|
this.fetchJson(
|
||||||
|
this.apiUrl() + '/subscribed',
|
||||||
|
{
|
||||||
|
channelId: this.channelId
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: this.getAuthToken()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(json => {
|
||||||
|
this.subscribed = json.subscribed
|
||||||
|
})
|
||||||
|
},
|
||||||
|
subscribeHandler () {
|
||||||
|
this.fetchJson(this.apiUrl() + (this.subscribed ? '/unsubscribe' : '/subscribe'), null, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
channelId: this.channelId
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
Authorization: this.getAuthToken(),
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.subscribed = !this.subscribed
|
||||||
|
},
|
||||||
|
handleScroll () {
|
||||||
|
if (this.loading || !this.comments || !this.comments.nextpage) return
|
||||||
|
if (window.innerHeight + window.scrollY >= this.$refs.comments.offsetHeight - window.innerHeight) {
|
||||||
|
this.loading = true
|
||||||
|
this.fetchJson(this.apiUrl() + '/nextpage/comments/' + this.getVideoId(), {
|
||||||
|
url: this.comments.nextpage
|
||||||
|
}).then(json => {
|
||||||
|
this.comments.nextpage = json.nextpage
|
||||||
|
this.loading = false
|
||||||
|
json.comments.map(comment => this.comments.comments.push(comment))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getVideoId () {
|
||||||
|
return this.$route.query.v || this.$route.params.v
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Player,
|
||||||
|
VideoItem,
|
||||||
|
ErrorHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -4,56 +4,56 @@ const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Trending',
|
name: 'Trending',
|
||||||
component: () => import('@/components/TrendingPage.vue')
|
component: () => import('@/components/TrendingPage')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/preferences',
|
path: '/preferences',
|
||||||
name: 'Preferences',
|
name: 'Preferences',
|
||||||
component: () => import('@/components/Preferences.vue')
|
component: () => import('@/components/Preferences')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/results',
|
path: '/results',
|
||||||
name: 'SearchResults',
|
name: 'SearchResults',
|
||||||
component: () => import('@/components/SearchResults.vue')
|
component: () => import('@/components/SearchResults')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/playlist',
|
path: '/playlist',
|
||||||
name: 'Playlist',
|
name: 'Playlist',
|
||||||
component: () => import('@/components/Playlist.vue')
|
component: () => import('@/components/Playlist')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:path(v|w|embed|shorts|watch)/:v?',
|
path: '/:path(v|w|embed|shorts|watch)/:v?',
|
||||||
name: 'WatchVideo',
|
name: 'WatchVideo',
|
||||||
component: () => import('@/components/WatchVideo.vue')
|
component: () => import('@/components/WatchVideo')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:path(channel|user|c)/:channelId/:videos?',
|
path: '/:path(channel|user|c)/:channelId/:videos?',
|
||||||
name: 'Channel',
|
name: 'Channel',
|
||||||
component: () => import('@/components/Channel.vue')
|
component: () => import('@/components/Channel')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
name: 'Login',
|
name: 'Login',
|
||||||
component: () => import('@/components/LoginPage.vue')
|
component: () => import('@/components/LoginPage')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/register',
|
path: '/register',
|
||||||
name: 'Register',
|
name: 'Register',
|
||||||
component: () => import('@/components/RegisterPage.vue')
|
component: () => import('@/components/RegisterPage')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/feed',
|
path: '/feed',
|
||||||
name: 'Feed',
|
name: 'Feed',
|
||||||
component: () => import('@/components/FeedPage.vue')
|
component: () => import('@/components/FeedPage')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/import',
|
path: '/import',
|
||||||
name: 'Import',
|
name: 'Import',
|
||||||
component: () => import('@/components/ImportPage.vue')
|
component: () => import('@/components/ImportPage')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/:videoId([a-zA-Z0-9_-]{11})',
|
path: '/:videoId([a-zA-Z0-9_-]{11})',
|
||||||
component: () => import('@/components/VideoRedirect.vue')
|
component: () => import('@/components/VideoRedirect')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue