mirror of
https://github.com/TeamPiped/Piped.git
synced 2026-08-21 05:01:25 +00:00
Migrate code to composition api.
This commit is contained in:
@@ -152,7 +152,9 @@
|
||||
aria-label="RSS feed"
|
||||
title="RSS feed"
|
||||
role="button"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${video.uploaderUrl.split('/')[2]}`"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${
|
||||
video.uploaderUrl.split('/')[2]
|
||||
}`"
|
||||
target="_blank"
|
||||
class="btn flex items-center"
|
||||
>
|
||||
@@ -282,11 +284,11 @@
|
||||
<button
|
||||
v-if="!comments?.disabled"
|
||||
class="btn mb-2"
|
||||
@click="toggleComments"
|
||||
@click="toggleCommentsVisibility"
|
||||
v-text="
|
||||
`${$t(showComments ? 'actions.minimize_comments' : 'actions.show_comments')} (${numberFormat(
|
||||
comments?.commentCount,
|
||||
)})`
|
||||
`${$t(
|
||||
showComments ? 'actions.minimize_comments' : 'actions.show_comments',
|
||||
)} (${numberFormat(comments?.commentCount)})`
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
@@ -297,7 +299,7 @@
|
||||
<div v-else-if="comments.disabled" class="">
|
||||
<p v-t="'comment.disabled'" class="mt-8 text-center"></p>
|
||||
</div>
|
||||
<div v-else ref="comments" class="">
|
||||
<div v-else ref="commentsEl" class="">
|
||||
<CommentItem
|
||||
v-for="comment in comments.comments"
|
||||
:key="comment.commentId"
|
||||
@@ -346,7 +348,9 @@
|
||||
</LoadingIndicatorPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onActivated, onDeactivated, onUnmounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import VideoPlayer from "./VideoPlayer.vue";
|
||||
import ContentItem from "./ContentItem.vue";
|
||||
import ErrorHandler from "./ErrorHandler.vue";
|
||||
@@ -360,413 +364,428 @@ import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
|
||||
import ToastComponent from "./ToastComponent.vue";
|
||||
import { parseTimeParam } from "@/utils/Misc";
|
||||
import { purifyHTML, rewriteDescription } from "@/utils/HtmlUtils";
|
||||
import { fetchJson, apiUrl } from "@/composables/useApi.js";
|
||||
import {
|
||||
getPreferenceBoolean,
|
||||
getPreferenceNumber,
|
||||
getPreferenceString,
|
||||
getPreferenceJSON,
|
||||
setPreference,
|
||||
} from "@/composables/usePreferences.js";
|
||||
import { numberFormat, addCommas } from "@/composables/useFormatting.js";
|
||||
import {
|
||||
fetchSubscriptionStatus,
|
||||
toggleSubscriptionState,
|
||||
fetchDeArrowContent,
|
||||
} from "@/composables/useSubscriptions.js";
|
||||
import { updateWatched } from "@/composables/useMisc.js";
|
||||
import { getPlaylist } from "@/composables/usePlaylists.js";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: {
|
||||
VideoPlayer,
|
||||
ContentItem,
|
||||
ErrorHandler,
|
||||
CommentItem,
|
||||
ChaptersBar,
|
||||
PlaylistAddModal,
|
||||
ShareModal,
|
||||
PlaylistVideos,
|
||||
WatchOnButton,
|
||||
LoadingIndicatorPage,
|
||||
ToastComponent,
|
||||
},
|
||||
data() {
|
||||
const smallViewQuery = window.matchMedia("(max-width: 640px)");
|
||||
return {
|
||||
video: null,
|
||||
playlistId: null,
|
||||
playlist: null,
|
||||
index: null,
|
||||
sponsors: null,
|
||||
selectedAutoLoop: false,
|
||||
selectedAutoPlay: null,
|
||||
showComments: true,
|
||||
showDesc: false,
|
||||
showRecs: true,
|
||||
showChapters: true,
|
||||
comments: null,
|
||||
subscribed: false,
|
||||
channelId: null,
|
||||
active: true,
|
||||
smallViewQuery: smallViewQuery,
|
||||
smallView: smallViewQuery.matches,
|
||||
showModal: false,
|
||||
showShareModal: false,
|
||||
isMobile: true,
|
||||
currentTime: 0,
|
||||
shouldShowToast: false,
|
||||
timeoutCounter: null,
|
||||
counter: 0,
|
||||
theaterMode: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isListening(_this) {
|
||||
return _this.getPreferenceBoolean("listen", false);
|
||||
},
|
||||
toggleListenUrl(_this) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("listen", _this.isListening ? "0" : "1");
|
||||
url.searchParams.set("t", Math.floor(this.currentTime));
|
||||
return url.pathname + url.search;
|
||||
},
|
||||
isEmbed(_this) {
|
||||
return String(_this.$route.path).indexOf("/embed/") == 0;
|
||||
},
|
||||
uploadDate(_this) {
|
||||
return new Date(_this.video.uploadDate).toLocaleString(undefined, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
},
|
||||
defaultCounter(_this) {
|
||||
return _this.getPreferenceNumber("autoPlayNextCountdown", 5);
|
||||
},
|
||||
purifiedDescription() {
|
||||
return purifyHTML(this.video.description);
|
||||
},
|
||||
youtubeVideoHref() {
|
||||
let link = `https://youtu.be/${this.getVideoId()}?t=${Math.round(this.currentTime)}`;
|
||||
if (this.playlistId) link += `&list=${this.playlistId}`;
|
||||
return link;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// check screen size
|
||||
this.isMobile = window.innerWidth < 1024;
|
||||
// add an event listener to watch for screen size changes
|
||||
window.addEventListener("resize", () => {
|
||||
this.isMobile = window.innerWidth < 1024;
|
||||
});
|
||||
this.getVideoData().then(() => {
|
||||
(async () => {
|
||||
const videoId = this.getVideoId();
|
||||
const instance = this;
|
||||
if (window.db && this.getPreferenceBoolean("watchHistory", false) && !this.video.error) {
|
||||
var tx = window.db.transaction("watch_history", "readwrite");
|
||||
var store = tx.objectStore("watch_history");
|
||||
var request = store.get(videoId);
|
||||
request.onsuccess = function (event) {
|
||||
var video = event.target.result;
|
||||
if (video) {
|
||||
video.watchedAt = Date.now();
|
||||
} else {
|
||||
video = {
|
||||
videoId: videoId,
|
||||
title: instance.video.title,
|
||||
duration: instance.video.duration,
|
||||
thumbnail: instance.video.thumbnailUrl,
|
||||
uploaderUrl: instance.video.uploaderUrl,
|
||||
uploaderName: instance.video.uploader,
|
||||
watchedAt: Date.now(),
|
||||
};
|
||||
}
|
||||
store.put(video);
|
||||
};
|
||||
}
|
||||
})();
|
||||
if (this.active) this.$refs.videoPlayer.loadVideo();
|
||||
});
|
||||
this.playlistId = this.$route.query.list;
|
||||
this.index = Number(this.$route.query.index);
|
||||
this.getPlaylistData();
|
||||
this.getSponsors();
|
||||
if (!this.isEmbed && this.showComments) this.getComments();
|
||||
if (this.isEmbed) document.querySelector("html").style.overflow = "hidden";
|
||||
window.addEventListener("click", this.handleClick);
|
||||
window.addEventListener("resize", () => {
|
||||
this.smallView = this.smallViewQuery.matches;
|
||||
});
|
||||
},
|
||||
activated() {
|
||||
this.active = true;
|
||||
this.theaterMode = this.getPreferenceBoolean(
|
||||
"theaterMode",
|
||||
window.innerWidth < (window.innerHeight * 4) / 3 + 467, //if the video player is limited by width rather than height, then clear up some horizontal room
|
||||
);
|
||||
this.selectedAutoPlay = this.getPreferenceNumber("autoplay", 1);
|
||||
this.showComments = !this.getPreferenceBoolean("minimizeComments", false);
|
||||
this.showDesc = !this.getPreferenceBoolean("minimizeDescription", true);
|
||||
this.showRecs = !this.getPreferenceBoolean("minimizeRecommendations", false);
|
||||
this.showChapters = !this.getPreferenceBoolean("minimizeChapters", false);
|
||||
if (this.video?.duration) {
|
||||
document.title = this.video.title + " - Piped";
|
||||
this.$refs.videoPlayer.loadVideo();
|
||||
}
|
||||
window.addEventListener("scroll", this.handleScroll);
|
||||
},
|
||||
deactivated() {
|
||||
this.active = false;
|
||||
window.removeEventListener("scroll", this.handleScroll);
|
||||
this.dismiss();
|
||||
},
|
||||
unmounted() {
|
||||
window.removeEventListener("scroll", this.handleScroll);
|
||||
window.removeEventListener("click", this.handleClick);
|
||||
this.dismiss();
|
||||
},
|
||||
methods: {
|
||||
fetchVideo() {
|
||||
return this.fetchJson(this.apiUrl() + "/streams/" + this.getVideoId());
|
||||
},
|
||||
async fetchSponsors() {
|
||||
var selectedSkip = this.getPreferenceString(
|
||||
"selectedSkip",
|
||||
"sponsor,interaction,selfpromo,music_offtopic",
|
||||
).split(",");
|
||||
const skipOptions = this.getPreferenceJSON("skipOptions");
|
||||
if (skipOptions !== undefined) {
|
||||
selectedSkip = Object.keys(skipOptions).filter(
|
||||
k => skipOptions[k] !== undefined && skipOptions[k] !== "no",
|
||||
);
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const smallViewQuery = window.matchMedia("(max-width: 640px)");
|
||||
|
||||
const videoPlayer = ref(null);
|
||||
const commentsEl = ref(null);
|
||||
|
||||
const video = ref(null);
|
||||
const playlistId = ref(null);
|
||||
const playlist = ref(null);
|
||||
const index = ref(null);
|
||||
const sponsors = ref(null);
|
||||
const selectedAutoLoop = ref(false);
|
||||
const selectedAutoPlay = ref(null);
|
||||
const showComments = ref(true);
|
||||
const showDesc = ref(false);
|
||||
const showRecs = ref(true);
|
||||
const showChapters = ref(true);
|
||||
const comments = ref(null);
|
||||
const subscribed = ref(false);
|
||||
const channelId = ref(null);
|
||||
const active = ref(true);
|
||||
const smallView = ref(smallViewQuery.matches);
|
||||
const showModal = ref(false);
|
||||
const showShareModal = ref(false);
|
||||
const isMobile = ref(true);
|
||||
const currentTime = ref(0);
|
||||
const shouldShowToast = ref(false);
|
||||
let timeoutCounter = null;
|
||||
const counter = ref(0);
|
||||
const theaterMode = ref(false);
|
||||
let loading = false;
|
||||
|
||||
const isListening = computed(() => {
|
||||
return getPreferenceBoolean("listen", false);
|
||||
});
|
||||
|
||||
const toggleListenUrl = computed(() => {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("listen", isListening.value ? "0" : "1");
|
||||
url.searchParams.set("t", Math.floor(currentTime.value));
|
||||
return url.pathname + url.search;
|
||||
});
|
||||
|
||||
const isEmbed = computed(() => {
|
||||
return String(route.path).indexOf("/embed/") == 0;
|
||||
});
|
||||
|
||||
const uploadDate = computed(() => {
|
||||
return new Date(video.value.uploadDate).toLocaleString(undefined, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
});
|
||||
|
||||
const defaultCounter = computed(() => {
|
||||
return getPreferenceNumber("autoPlayNextCountdown", 5);
|
||||
});
|
||||
|
||||
const purifiedDescription = computed(() => {
|
||||
return purifyHTML(video.value.description);
|
||||
});
|
||||
|
||||
const youtubeVideoHref = computed(() => {
|
||||
let link = `https://youtu.be/${getVideoId()}?t=${Math.round(currentTime.value)}`;
|
||||
if (playlistId.value) link += `&list=${playlistId.value}`;
|
||||
return link;
|
||||
});
|
||||
|
||||
function fetchVideo() {
|
||||
return fetchJson(apiUrl() + "/streams/" + getVideoId());
|
||||
}
|
||||
|
||||
async function fetchSponsors() {
|
||||
var selectedSkip = getPreferenceString("selectedSkip", "sponsor,interaction,selfpromo,music_offtopic").split(",");
|
||||
const skipOptions = getPreferenceJSON("skipOptions");
|
||||
if (skipOptions !== undefined) {
|
||||
selectedSkip = Object.keys(skipOptions).filter(k => skipOptions[k] !== undefined && skipOptions[k] !== "no");
|
||||
}
|
||||
|
||||
const sponsorsData = await fetchJson(apiUrl() + "/sponsors/" + getVideoId(), {
|
||||
category: JSON.stringify(selectedSkip),
|
||||
});
|
||||
|
||||
sponsorsData?.segments?.forEach(segment => {
|
||||
const option = skipOptions?.[segment.category];
|
||||
segment.autoskip = option === undefined || option === "auto";
|
||||
});
|
||||
|
||||
const minSegmentLength = Math.max(getPreferenceNumber("minSegmentLength", 0), 0);
|
||||
sponsorsData.segments = sponsorsData.segments?.filter(segment => {
|
||||
const length = segment.segment[1] - segment.segment[0];
|
||||
return length >= minSegmentLength;
|
||||
});
|
||||
|
||||
return sponsorsData;
|
||||
}
|
||||
|
||||
function toggleCommentsVisibility() {
|
||||
showComments.value = !showComments.value;
|
||||
if (showComments.value && comments.value === null) {
|
||||
fetchCommentsData();
|
||||
}
|
||||
}
|
||||
|
||||
function fetchCommentsData() {
|
||||
return fetchJson(apiUrl() + "/comments/" + getVideoId());
|
||||
}
|
||||
|
||||
function onChange() {
|
||||
setPreference("autoplay", selectedAutoPlay.value, true);
|
||||
}
|
||||
|
||||
async function getVideoData() {
|
||||
await fetchVideo()
|
||||
.then(data => {
|
||||
video.value = data;
|
||||
video.value.id = getVideoId();
|
||||
})
|
||||
.then(() => {
|
||||
if (!video.value.error) {
|
||||
document.title = video.value.title + " - Piped";
|
||||
channelId.value = video.value.uploaderUrl.split("/")[2];
|
||||
if (!isEmbed.value) fetchSubscribedStatus();
|
||||
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(video.value.description, "text/html");
|
||||
xmlDoc.querySelectorAll("a").forEach(elem => {
|
||||
if (!elem.innerText.match(/(?:[\d]{1,2}:)?(?:[\d]{1,2}):(?:[\d]{1,2})/))
|
||||
elem.outerHTML = elem.getAttribute("href");
|
||||
});
|
||||
xmlDoc.querySelectorAll("br").forEach(elem => (elem.outerHTML = "\n"));
|
||||
video.value.description = rewriteDescription(xmlDoc.querySelector("body").innerHTML);
|
||||
updateWatched(video.value.relatedStreams);
|
||||
|
||||
fetchDeArrowContent(video.value.relatedStreams);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const sponsors = await this.fetchJson(this.apiUrl() + "/sponsors/" + this.getVideoId(), {
|
||||
category: JSON.stringify(selectedSkip),
|
||||
});
|
||||
|
||||
sponsors?.segments?.forEach(segment => {
|
||||
const option = skipOptions?.[segment.category];
|
||||
segment.autoskip = option === undefined || option === "auto";
|
||||
});
|
||||
|
||||
const minSegmentLength = Math.max(this.getPreferenceNumber("minSegmentLength", 0), 0);
|
||||
sponsors.segments = sponsors.segments?.filter(segment => {
|
||||
const length = segment.segment[1] - segment.segment[0];
|
||||
return length >= minSegmentLength;
|
||||
});
|
||||
|
||||
return sponsors;
|
||||
},
|
||||
toggleComments() {
|
||||
this.showComments = !this.showComments;
|
||||
if (this.showComments && this.comments === null) {
|
||||
this.fetchComments();
|
||||
}
|
||||
},
|
||||
fetchComments() {
|
||||
return this.fetchJson(this.apiUrl() + "/comments/" + this.getVideoId());
|
||||
},
|
||||
onChange() {
|
||||
this.setPreference("autoplay", this.selectedAutoPlay, true);
|
||||
},
|
||||
async getVideoData() {
|
||||
await this.fetchVideo()
|
||||
.then(data => {
|
||||
this.video = data;
|
||||
this.video.id = this.getVideoId();
|
||||
})
|
||||
.then(() => {
|
||||
if (!this.video.error) {
|
||||
document.title = this.video.title + " - Piped";
|
||||
this.channelId = this.video.uploaderUrl.split("/")[2];
|
||||
if (!this.isEmbed) this.fetchSubscribedStatus();
|
||||
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(this.video.description, "text/html");
|
||||
xmlDoc.querySelectorAll("a").forEach(elem => {
|
||||
if (!elem.innerText.match(/(?:[\d]{1,2}:)?(?:[\d]{1,2}):(?:[\d]{1,2})/))
|
||||
elem.outerHTML = elem.getAttribute("href");
|
||||
async function getPlaylistData() {
|
||||
if (playlistId.value) {
|
||||
playlist.value = await getPlaylist(playlistId.value);
|
||||
await fetchPlaylistPages().then(() => {
|
||||
if (!(index.value >= 0)) {
|
||||
for (let i = 0; i < playlist.value.relatedStreams.length; i++)
|
||||
if (playlist.value.relatedStreams[i].url.substr(-11) == getVideoId()) {
|
||||
index.value = i + 1;
|
||||
router.replace({
|
||||
query: { ...route.query, index: index.value },
|
||||
});
|
||||
xmlDoc.querySelectorAll("br").forEach(elem => (elem.outerHTML = "\n"));
|
||||
this.video.description = rewriteDescription(xmlDoc.querySelector("body").innerHTML);
|
||||
this.updateWatched(this.video.relatedStreams);
|
||||
|
||||
this.fetchDeArrowContent(this.video.relatedStreams);
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
async getPlaylistData() {
|
||||
if (this.playlistId) {
|
||||
this.playlist = await this.getPlaylist(this.playlistId);
|
||||
await this.fetchPlaylistPages().then(() => {
|
||||
if (!(this.index >= 0)) {
|
||||
for (let i = 0; i < this.playlist.relatedStreams.length; i++)
|
||||
if (this.playlist.relatedStreams[i].url.substr(-11) == this.getVideoId()) {
|
||||
this.index = i + 1;
|
||||
this.$router.replace({
|
||||
query: { ...this.$route.query, index: this.index },
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
await this.fetchPlaylistPages();
|
||||
}
|
||||
},
|
||||
async fetchPlaylistPages() {
|
||||
if (this.playlist.nextpage) {
|
||||
await this.fetchJson(this.apiUrl() + "/nextpage/playlists/" + this.playlistId, {
|
||||
nextpage: this.playlist.nextpage,
|
||||
}).then(json => {
|
||||
this.playlist.relatedStreams.push(...json.relatedStreams);
|
||||
this.playlist.nextpage = json.nextpage;
|
||||
this.fetchDeArrowContent(json.relatedStreams);
|
||||
});
|
||||
await this.fetchPlaylistPages();
|
||||
}
|
||||
},
|
||||
async getSponsors() {
|
||||
if (this.getPreferenceBoolean("sponsorblock", true))
|
||||
this.fetchSponsors().then(data => (this.sponsors = data));
|
||||
},
|
||||
async getComments() {
|
||||
this.comments = await this.fetchComments();
|
||||
},
|
||||
async fetchSubscribedStatus() {
|
||||
if (!this.channelId) return;
|
||||
});
|
||||
await fetchPlaylistPages();
|
||||
}
|
||||
}
|
||||
|
||||
this.subscribed = await this.fetchSubscriptionStatus(this.channelId);
|
||||
},
|
||||
subscribeHandler() {
|
||||
this.toggleSubscriptionState(this.channelId, this.subscribed).then(success => {
|
||||
if (success) this.subscribed = !this.subscribed;
|
||||
});
|
||||
},
|
||||
handleClick(event) {
|
||||
if (!event || !event.target) return;
|
||||
if (!event.target.matches("a[href]")) return;
|
||||
const target = event.target;
|
||||
if (!target.getAttribute("href")) return;
|
||||
if (this.handleTimestampLinks(target)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
handleTimestampLinks(target) {
|
||||
try {
|
||||
const url = new URL(target.getAttribute("href"), document.baseURI);
|
||||
if (
|
||||
url.searchParams.size > 2 ||
|
||||
url.searchParams.get("v") !== this.getVideoId() ||
|
||||
!url.searchParams.has("t")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const time = parseTimeParam(url.searchParams.get("t"));
|
||||
if (time) {
|
||||
this.navigate(time);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
async function fetchPlaylistPages() {
|
||||
if (playlist.value.nextpage) {
|
||||
await fetchJson(apiUrl() + "/nextpage/playlists/" + playlistId.value, {
|
||||
nextpage: playlist.value.nextpage,
|
||||
}).then(json => {
|
||||
playlist.value.relatedStreams.push(...json.relatedStreams);
|
||||
playlist.value.nextpage = json.nextpage;
|
||||
fetchDeArrowContent(json.relatedStreams);
|
||||
});
|
||||
await fetchPlaylistPages();
|
||||
}
|
||||
}
|
||||
|
||||
async function getSponsors() {
|
||||
if (getPreferenceBoolean("sponsorblock", true)) fetchSponsors().then(data => (sponsors.value = data));
|
||||
}
|
||||
|
||||
async function getComments() {
|
||||
comments.value = await fetchCommentsData();
|
||||
}
|
||||
|
||||
async function fetchSubscribedStatus() {
|
||||
if (!channelId.value) return;
|
||||
subscribed.value = await fetchSubscriptionStatus(channelId.value);
|
||||
}
|
||||
|
||||
function subscribeHandler() {
|
||||
toggleSubscriptionState(channelId.value, subscribed.value).then(success => {
|
||||
if (success) subscribed.value = !subscribed.value;
|
||||
});
|
||||
}
|
||||
|
||||
function handleClick(event) {
|
||||
if (!event || !event.target) return;
|
||||
if (!event.target.matches("a[href]")) return;
|
||||
const target = event.target;
|
||||
if (!target.getAttribute("href")) return;
|
||||
if (handleTimestampLinks(target)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function handleTimestampLinks(target) {
|
||||
try {
|
||||
const url = new URL(target.getAttribute("href"), document.baseURI);
|
||||
if (url.searchParams.size > 2 || url.searchParams.get("v") !== getVideoId() || !url.searchParams.has("t")) {
|
||||
return false;
|
||||
},
|
||||
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(), {
|
||||
nextpage: this.comments.nextpage,
|
||||
}).then(json => {
|
||||
this.comments.nextpage = json.nextpage;
|
||||
this.loading = false;
|
||||
this.comments.comments = this.comments.comments.concat(json.comments);
|
||||
});
|
||||
}
|
||||
},
|
||||
getVideoId() {
|
||||
if (this.$route.query.video_ids) {
|
||||
const videos_list = this.$route.query.video_ids.split(",");
|
||||
this.index = Number(this.$route.query.index ?? 0);
|
||||
return videos_list[this.index];
|
||||
}
|
||||
}
|
||||
const time = parseTimeParam(url.searchParams.get("t"));
|
||||
if (time) {
|
||||
navigate(time);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.$route.query.v || this.$route.params.v;
|
||||
},
|
||||
navigate(time) {
|
||||
this.$refs.videoPlayer.seek(time);
|
||||
},
|
||||
onTimeUpdate(time) {
|
||||
this.currentTime = time;
|
||||
},
|
||||
onVideoEnded() {
|
||||
if (
|
||||
!this.selectedAutoLoop &&
|
||||
((this.selectedAutoPlay >= 1 && this.playlist?.relatedStreams?.length > this.index) ||
|
||||
(this.selectedAutoPlay >= 2 && this.video.relatedStreams.length > 0))
|
||||
) {
|
||||
this.showToast();
|
||||
}
|
||||
},
|
||||
showToast() {
|
||||
this.counter = this.defaultCounter;
|
||||
if (this.counter < 1) {
|
||||
this.navigateNext();
|
||||
return;
|
||||
}
|
||||
if (this.timeoutCounter) clearInterval(this.timeoutCounter);
|
||||
this.timeoutCounter = setInterval(() => {
|
||||
this.counter--;
|
||||
if (this.counter === 0) {
|
||||
this.dismiss();
|
||||
this.navigateNext();
|
||||
}
|
||||
}, 1000);
|
||||
this.shouldShowToast = true;
|
||||
},
|
||||
dismiss() {
|
||||
clearInterval(this.timeoutCounter);
|
||||
this.shouldShowToast = false;
|
||||
},
|
||||
navigateNext() {
|
||||
const params = this.$route.query;
|
||||
const video_ids = this.$route.query.video_ids?.split(",") ?? [];
|
||||
let url;
|
||||
if (this.playlist) {
|
||||
url = this.playlist?.relatedStreams?.[this.index]?.url ?? this.video.relatedStreams[0].url;
|
||||
} else if (video_ids.length > this.index + 1) {
|
||||
url = `${this.$route.path}?index=${this.index + 1}`;
|
||||
} else {
|
||||
url = this.video.relatedStreams[0].url;
|
||||
}
|
||||
const searchParams = new URLSearchParams();
|
||||
for (var param in params)
|
||||
switch (param) {
|
||||
case "v":
|
||||
case "t":
|
||||
break;
|
||||
case "index":
|
||||
if (this.playlist && this.index < this.playlist.relatedStreams.length)
|
||||
searchParams.set("index", this.index + 1);
|
||||
break;
|
||||
case "list":
|
||||
if (this.index < this.playlist.relatedStreams.length) searchParams.set("list", params.list);
|
||||
break;
|
||||
default:
|
||||
searchParams.set(param, params[param]);
|
||||
break;
|
||||
}
|
||||
// save the fullscreen state
|
||||
searchParams.set("fullscreen", this.$refs.videoPlayer.$ui.getControls().isFullScreenEnabled());
|
||||
const paramStr = searchParams.toString();
|
||||
if (paramStr.length > 0) url += "&" + paramStr;
|
||||
this.$router.push(url);
|
||||
},
|
||||
downloadCurrentFrame() {
|
||||
const video = document.querySelector("video");
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
function handleScroll() {
|
||||
if (loading || !comments.value || !comments.value.nextpage) return;
|
||||
if (window.innerHeight + window.scrollY >= commentsEl.value?.offsetHeight - window.innerHeight) {
|
||||
loading = true;
|
||||
fetchJson(apiUrl() + "/nextpage/comments/" + getVideoId(), {
|
||||
nextpage: comments.value.nextpage,
|
||||
}).then(json => {
|
||||
comments.value.nextpage = json.nextpage;
|
||||
loading = false;
|
||||
comments.value.comments = comments.value.comments.concat(json.comments);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const context = canvas.getContext("2d");
|
||||
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
function getVideoId() {
|
||||
if (route.query.video_ids) {
|
||||
const videos_list = route.query.video_ids.split(",");
|
||||
index.value = Number(route.query.index ?? 0);
|
||||
return videos_list[index.value];
|
||||
}
|
||||
|
||||
let link = document.createElement("a");
|
||||
const currentTime = Math.round(video.currentTime * 1000) / 1000;
|
||||
link.download = `${this.video.title}_${currentTime}s.png`;
|
||||
link.href = canvas.toDataURL();
|
||||
link.click();
|
||||
},
|
||||
},
|
||||
};
|
||||
return route.query.v || route.params.v;
|
||||
}
|
||||
|
||||
function navigate(time) {
|
||||
videoPlayer.value.seek(time);
|
||||
}
|
||||
|
||||
function onTimeUpdate(time) {
|
||||
currentTime.value = time;
|
||||
}
|
||||
|
||||
function onVideoEnded() {
|
||||
if (
|
||||
!selectedAutoLoop.value &&
|
||||
((selectedAutoPlay.value >= 1 && playlist.value?.relatedStreams?.length > index.value) ||
|
||||
(selectedAutoPlay.value >= 2 && video.value.relatedStreams.length > 0))
|
||||
) {
|
||||
showToast();
|
||||
}
|
||||
}
|
||||
|
||||
function showToast() {
|
||||
counter.value = defaultCounter.value;
|
||||
if (counter.value < 1) {
|
||||
navigateNext();
|
||||
return;
|
||||
}
|
||||
if (timeoutCounter) clearInterval(timeoutCounter);
|
||||
timeoutCounter = setInterval(() => {
|
||||
counter.value--;
|
||||
if (counter.value === 0) {
|
||||
dismiss();
|
||||
navigateNext();
|
||||
}
|
||||
}, 1000);
|
||||
shouldShowToast.value = true;
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
clearInterval(timeoutCounter);
|
||||
shouldShowToast.value = false;
|
||||
}
|
||||
|
||||
function navigateNext() {
|
||||
const params = route.query;
|
||||
const video_ids = route.query.video_ids?.split(",") ?? [];
|
||||
let url;
|
||||
if (playlist.value) {
|
||||
url = playlist.value?.relatedStreams?.[index.value]?.url ?? video.value.relatedStreams[0].url;
|
||||
} else if (video_ids.length > index.value + 1) {
|
||||
url = `${route.path}?index=${index.value + 1}`;
|
||||
} else {
|
||||
url = video.value.relatedStreams[0].url;
|
||||
}
|
||||
const searchParams = new URLSearchParams();
|
||||
for (var param in params)
|
||||
switch (param) {
|
||||
case "v":
|
||||
case "t":
|
||||
break;
|
||||
case "index":
|
||||
if (playlist.value && index.value < playlist.value.relatedStreams.length)
|
||||
searchParams.set("index", index.value + 1);
|
||||
break;
|
||||
case "list":
|
||||
if (index.value < playlist.value.relatedStreams.length) searchParams.set("list", params.list);
|
||||
break;
|
||||
default:
|
||||
searchParams.set(param, params[param]);
|
||||
break;
|
||||
}
|
||||
searchParams.set("fullscreen", videoPlayer.value.isFullScreenEnabled());
|
||||
const paramStr = searchParams.toString();
|
||||
if (paramStr.length > 0) url += "&" + paramStr;
|
||||
router.push(url);
|
||||
}
|
||||
|
||||
function downloadCurrentFrame() {
|
||||
const videoEl = document.querySelector("video");
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = videoEl.videoWidth;
|
||||
canvas.height = videoEl.videoHeight;
|
||||
|
||||
const context = canvas.getContext("2d");
|
||||
context.drawImage(videoEl, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
let link = document.createElement("a");
|
||||
const ct = Math.round(videoEl.currentTime * 1000) / 1000;
|
||||
link.download = `${video.value.title}_${ct}s.png`;
|
||||
link.href = canvas.toDataURL();
|
||||
link.click();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
isMobile.value = window.innerWidth < 1024;
|
||||
window.addEventListener("resize", () => {
|
||||
isMobile.value = window.innerWidth < 1024;
|
||||
});
|
||||
getVideoData().then(() => {
|
||||
(async () => {
|
||||
const videoId = getVideoId();
|
||||
if (window.db && getPreferenceBoolean("watchHistory", false) && !video.value.error) {
|
||||
var tx = window.db.transaction("watch_history", "readwrite");
|
||||
var store = tx.objectStore("watch_history");
|
||||
var request = store.get(videoId);
|
||||
request.onsuccess = function (event) {
|
||||
var vid = event.target.result;
|
||||
if (vid) {
|
||||
vid.watchedAt = Date.now();
|
||||
} else {
|
||||
vid = {
|
||||
videoId: videoId,
|
||||
title: video.value.title,
|
||||
duration: video.value.duration,
|
||||
thumbnail: video.value.thumbnailUrl,
|
||||
uploaderUrl: video.value.uploaderUrl,
|
||||
uploaderName: video.value.uploader,
|
||||
watchedAt: Date.now(),
|
||||
};
|
||||
}
|
||||
store.put(vid);
|
||||
};
|
||||
}
|
||||
})();
|
||||
if (active.value) videoPlayer.value.loadVideo();
|
||||
});
|
||||
playlistId.value = route.query.list;
|
||||
index.value = Number(route.query.index);
|
||||
getPlaylistData();
|
||||
getSponsors();
|
||||
if (!isEmbed.value && showComments.value) getComments();
|
||||
if (isEmbed.value) document.querySelector("html").style.overflow = "hidden";
|
||||
window.addEventListener("click", handleClick);
|
||||
window.addEventListener("resize", () => {
|
||||
smallView.value = smallViewQuery.matches;
|
||||
});
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
active.value = true;
|
||||
theaterMode.value = getPreferenceBoolean("theaterMode", window.innerWidth < (window.innerHeight * 4) / 3 + 467);
|
||||
selectedAutoPlay.value = getPreferenceNumber("autoplay", 1);
|
||||
showComments.value = !getPreferenceBoolean("minimizeComments", false);
|
||||
showDesc.value = !getPreferenceBoolean("minimizeDescription", true);
|
||||
showRecs.value = !getPreferenceBoolean("minimizeRecommendations", false);
|
||||
showChapters.value = !getPreferenceBoolean("minimizeChapters", false);
|
||||
if (video.value?.duration) {
|
||||
document.title = video.value.title + " - Piped";
|
||||
videoPlayer.value.loadVideo();
|
||||
}
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
});
|
||||
|
||||
onDeactivated(() => {
|
||||
active.value = false;
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
dismiss();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
window.removeEventListener("click", handleClick);
|
||||
dismiss();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user