More fixes

This commit is contained in:
root 2021-07-20 11:05:06 +05:30
parent d02641e802
commit d8be46d849
No known key found for this signature in database
GPG key ID: BB51838571827D85
18 changed files with 964 additions and 965 deletions

View file

@ -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

View file

@ -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>

View file

@ -8,9 +8,9 @@
<script> <script>
export default { export default {
props: { props: {
error: String, error: String,
message: String, message: String
}, }
}; }
</script> </script>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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')
} }
] ]