mirror of
https://github.com/TeamPiped/Piped.git
synced 2024-08-14 23:57:27 +00:00
Beta (#38)
This commit is contained in:
commit
995be6bed1
17 changed files with 101 additions and 85 deletions
|
@ -3,7 +3,7 @@
|
|||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<span v-if="showFullText" class="contentText" v-html="fullText()" />
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<span v-else v-html="colapsedText()" />
|
||||
<span v-else v-html="collapsedText()" />
|
||||
<span v-if="text.length > visibleLimit && !showFullText">...</span>
|
||||
<button
|
||||
v-if="text.length > visibleLimit"
|
||||
|
@ -38,7 +38,7 @@ export default {
|
|||
fullText() {
|
||||
return purifyHTML(rewriteDescription(this.text));
|
||||
},
|
||||
colapsedText() {
|
||||
collapsedText() {
|
||||
return purifyHTML(rewriteDescription(this.text.slice(0, this.visibleLimit)));
|
||||
},
|
||||
},
|
||||
|
|
|
@ -33,8 +33,13 @@
|
|||
<div class="comment-footer my-1 flex items-center gap-3">
|
||||
<div class="i-fa6-solid:thumbs-up" />
|
||||
<span v-text="numberFormat(comment.likeCount)" />
|
||||
<i v-if="comment.hearted" class="i-fa6-solid:heart" />
|
||||
<img v-if="comment.creatorReplied" :src="uploaderAvatarUrl" class="h-5 w-5 rounded-full" />
|
||||
<i v-if="comment.hearted" class="i-fa6-solid:heart" :title="$t('actions.creator_liked')" />
|
||||
<img
|
||||
v-if="comment.creatorReplied"
|
||||
:src="uploaderAvatarUrl"
|
||||
class="h-5 w-5 rounded-full"
|
||||
:title="$t('actions.creator_replied')"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="comment.repliesPage && (!loadingReplies || !showingReplies)">
|
||||
<div class="cursor-pointer" @click="loadReplies">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="flex justify-center">
|
||||
<h1 v-t="'titles.login'" class="my-4 text-center font-bold" />
|
||||
<TooltipIcon class="mb-6" icon="i-fa6-solid:circle-info" :tooltip="$t('info.login_note')" />
|
||||
<i class="i-fa6-solid:circle-info ml-2 mt-6 cursor-pointer" :title="$t('info.login_note')" />
|
||||
</div>
|
||||
<hr />
|
||||
<div class="w-full flex items-center justify-center text-center">
|
||||
|
@ -36,12 +36,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import TooltipIcon from "./TooltipIcon.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TooltipIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<nav class="relative w-full flex flex-wrap items-center justify-center px-2 pb-2.5 sm:px-4">
|
||||
<nav class="relative w-full flex flex-wrap items-center justify-center px-2 pb-2.5 sm:px-4 sticky top-0">
|
||||
<div class="flex flex-1 justify-start">
|
||||
<router-link class="flex items-center text-3xl font-bold font-sans" :to="homePagePath"
|
||||
><img
|
||||
|
@ -216,7 +216,7 @@ export default {
|
|||
|
||||
<style>
|
||||
.search-container {
|
||||
@apply relative inline-flex items-center;
|
||||
@apply relative inline-flex items-center sticky top-12;
|
||||
}
|
||||
.delete-search {
|
||||
@apply absolute right-3 cursor-pointer rounded-full bg-[#ccc] w-4 h-4 text-center text-black opacity-50 hover:(opacity-70) text-size-[10px];
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
|
||||
<CollapsableText v-if="playlist?.description" :text="playlist.description" />
|
||||
|
||||
<div class="mt-1 flex <md:flex-col md:items-center justify-between">
|
||||
<div class="mt-1 flex justify-between <md:flex-col md:items-center">
|
||||
<div>
|
||||
<router-link class="link flex items-center gap-3" :to="playlist.uploaderUrl || '/'">
|
||||
<img loading="lazy" :src="playlist.uploaderAvatar" class="rounded-full h-12" />
|
||||
<img loading="lazy" :src="playlist.uploaderAvatar" class="h-12 rounded-full" />
|
||||
<strong v-text="playlist.uploader" />
|
||||
</router-link>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="flex justify-center">
|
||||
<h1 v-t="'titles.register'" class="my-4 text-center font-bold" />
|
||||
<TooltipIcon class="mb-6" icon="i-fa6-solid:circle-info" :tooltip="$t('info.register_note')" />
|
||||
<i class="i-fa6-solid:circle-info ml-2 mt-6 cursor-pointer" :title="$t('info.register_note')" />
|
||||
</div>
|
||||
<hr />
|
||||
<div class="flex flex-col items-center justify-center text-center">
|
||||
|
@ -20,7 +20,7 @@
|
|||
<div class="flex justify-center">
|
||||
<input
|
||||
v-model="password"
|
||||
class="input w-full"
|
||||
class="input h-auto w-full"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
autocomplete="password"
|
||||
:placeholder="$t('login.password')"
|
||||
|
@ -34,7 +34,7 @@
|
|||
<div class="flex justify-center">
|
||||
<input
|
||||
v-model="passwordConfirm"
|
||||
class="input w-full"
|
||||
class="input h-auto w-full"
|
||||
:type="showConfirmPassword ? 'text' : 'password'"
|
||||
autocomplete="password"
|
||||
:placeholder="$t('login.password_confirm')"
|
||||
|
@ -65,10 +65,9 @@
|
|||
<script>
|
||||
import { isEmail } from "../utils/Misc.js";
|
||||
import ConfirmModal from "./ConfirmModal.vue";
|
||||
import TooltipIcon from "./TooltipIcon.vue";
|
||||
|
||||
export default {
|
||||
components: { ConfirmModal, TooltipIcon },
|
||||
components: { ConfirmModal },
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
<template>
|
||||
<div id="container" class="m-2 self-center">
|
||||
<div :class="icon" class="cursor-pointer"></div>
|
||||
<p id="tooltip" class="absolute mr-[20vw] mt-2 hidden rounded-l bg-gray-800 px-2 py-1 text-gray-200">
|
||||
{{ tooltip }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
icon: {
|
||||
type: String, // the class name of a font awesome icon
|
||||
required: true,
|
||||
},
|
||||
tooltip: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#container:hover #tooltip {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
|
@ -31,16 +31,32 @@
|
|||
class="absolute top-8 rounded bg-black/80 p-2 text-lg backdrop-blur-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ModalComponent v-if="showSpeedModal" @close="showSpeedModal = false">
|
||||
<h2 v-t="'actions.playback_speed'" />
|
||||
<div class="flex flex-col">
|
||||
<input
|
||||
v-model="playbackSpeedInput"
|
||||
class="input my-3"
|
||||
type="text"
|
||||
:placeholder="$t('actions.playback_speed')"
|
||||
@keyup.enter="setSpeedFromInput()"
|
||||
/>
|
||||
<button v-t="'actions.okay'" class="btn ml-auto w-min" @click="setSpeedFromInput()" />
|
||||
</div>
|
||||
</ModalComponent>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import "shaka-player/dist/controls.css";
|
||||
import { parseTimeParam } from "@/utils/Misc";
|
||||
import ModalComponent from "./ModalComponent.vue";
|
||||
|
||||
const shaka = import("shaka-player/dist/shaka-player.ui.js");
|
||||
const hotkeys = import("hotkeys-js");
|
||||
|
||||
export default {
|
||||
components: { ModalComponent },
|
||||
props: {
|
||||
video: {
|
||||
type: Object,
|
||||
|
@ -66,6 +82,8 @@ export default {
|
|||
destroying: false,
|
||||
inSegment: false,
|
||||
isHoveringTimebar: false,
|
||||
showSpeedModal: false,
|
||||
playbackSpeedInput: null,
|
||||
currentTime: 0,
|
||||
seekbarPadding: 2,
|
||||
error: 0,
|
||||
|
@ -106,7 +124,7 @@ export default {
|
|||
this.hotkeysPromise.then(() => {
|
||||
var self = this;
|
||||
this.$hotkeys(
|
||||
"f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+,,shift+.,alt+p,return,.,,",
|
||||
"f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+s,shift+,,shift+.,alt+p,return,.,,",
|
||||
function (e, handler) {
|
||||
const videoEl = self.$refs.videoEl;
|
||||
switch (handler.key) {
|
||||
|
@ -196,11 +214,14 @@ export default {
|
|||
self.$emit("navigateNext");
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "shift+s":
|
||||
self.showSpeedModal = true;
|
||||
break;
|
||||
case "shift+,":
|
||||
self.$player.trickPlay(Math.max(videoEl.playbackRate - 0.25, 0.25));
|
||||
self.adjustPlaybackSpeed(videoEl.playbackRate - 0.25);
|
||||
break;
|
||||
case "shift+.":
|
||||
self.$player.trickPlay(Math.min(videoEl.playbackRate + 0.25, 2));
|
||||
self.adjustPlaybackSpeed(videoEl.playbackRate + 0.25);
|
||||
break;
|
||||
case "alt+p":
|
||||
document.pictureInPictureElement
|
||||
|
@ -651,7 +672,19 @@ export default {
|
|||
this.$refs.videoEl.currentTime = time;
|
||||
}
|
||||
},
|
||||
|
||||
adjustPlaybackSpeed(newSpeed) {
|
||||
const normalizedSpeed = Math.min(4, Math.max(0.25, newSpeed));
|
||||
this.$player.trickPlay(normalizedSpeed);
|
||||
},
|
||||
setSpeedFromInput() {
|
||||
try {
|
||||
const newSpeed = Number(this.playbackSpeedInput);
|
||||
this.adjustPlaybackSpeed(newSpeed);
|
||||
} catch (err) {
|
||||
alert(this.$t("actions.invalid_input"));
|
||||
}
|
||||
this.showSpeedModal = false;
|
||||
},
|
||||
updateMarkers() {
|
||||
const markers = this.$refs.container.querySelector(".shaka-ad-markers");
|
||||
const array = ["to right"];
|
||||
|
|
|
@ -546,33 +546,13 @@ export default {
|
|||
this.fetchSponsors().then(data => (this.sponsors = data));
|
||||
},
|
||||
async getComments() {
|
||||
this.fetchComments().then(data => {
|
||||
this.rewriteComments(data.comments);
|
||||
this.comments = data;
|
||||
});
|
||||
this.comments = await this.fetchComments();
|
||||
},
|
||||
async fetchSubscribedStatus() {
|
||||
if (!this.channelId) return;
|
||||
|
||||
this.subscribed = await this.fetchSubscriptionStatus(this.channelId);
|
||||
},
|
||||
rewriteComments(data) {
|
||||
data.forEach(comment => {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(comment.commentText, "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");
|
||||
});
|
||||
comment.commentText = xmlDoc
|
||||
.querySelector("body")
|
||||
.innerHTML.replaceAll(/(?:http(?:s)?:\/\/)?(?:www\.)?youtube\.com(\/[/a-zA-Z0-9_?=&-]*)/gm, "$1")
|
||||
.replaceAll(
|
||||
/(?:http(?:s)?:\/\/)?(?:www\.)?youtu\.be\/(?:watch\?v=)?([/a-zA-Z0-9_?=&-]*)/gm,
|
||||
"/watch?v=$1",
|
||||
);
|
||||
});
|
||||
},
|
||||
subscribeHandler() {
|
||||
this.toggleSubscriptionState(this.channelId, this.subscribed).then(success => {
|
||||
if (success) this.subscribed = !this.subscribed;
|
||||
|
@ -616,7 +596,6 @@ export default {
|
|||
}).then(json => {
|
||||
this.comments.nextpage = json.nextpage;
|
||||
this.loading = false;
|
||||
this.rewriteComments(json.comments);
|
||||
this.comments.comments = this.comments.comments.concat(json.comments);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -156,7 +156,11 @@
|
|||
"concurrent_prefetch_limit": "Concurrent Stream Prefetch Limit",
|
||||
"customize": "Customize",
|
||||
"invalid_url": "Invalid URL!",
|
||||
"add": "Add"
|
||||
"add": "Add",
|
||||
"creator_replied": "Creator replied",
|
||||
"creator_liked": "Creator liked",
|
||||
"playback_speed": "Playback speed",
|
||||
"invalid_input": "Invalid input"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Pinned by {author}",
|
||||
|
|
|
@ -156,7 +156,9 @@
|
|||
"customize": "Kohanda",
|
||||
"invalid_url": "Vigane URL!",
|
||||
"add": "Lisa",
|
||||
"delete_group_confirm": "Kas kustutame selle grupi?"
|
||||
"delete_group_confirm": "Kas kustutame selle grupi?",
|
||||
"creator_replied": "Autor vastas",
|
||||
"creator_liked": "Autorile meeldis see"
|
||||
},
|
||||
"preferences": {
|
||||
"has_cdn": "CDN'i olek?",
|
||||
|
|
|
@ -151,7 +151,12 @@
|
|||
"download_frame": "Keret letöltése",
|
||||
"customize": "Testreszab",
|
||||
"invalid_url": "Érvénytelen URL!",
|
||||
"add": "Hozzáadás"
|
||||
"add": "Hozzáadás",
|
||||
"delete_group_confirm": "Törli ezt a csoportot?",
|
||||
"creator_replied": "A készítő válaszolt",
|
||||
"creator_liked": "A készítő kedvelte",
|
||||
"playback_speed": "Visszajátszási sebesség",
|
||||
"invalid_input": "Érvénytelen bevitel"
|
||||
},
|
||||
"video": {
|
||||
"ratings_disabled": "Értékelések Letiltva",
|
||||
|
|
|
@ -155,7 +155,8 @@
|
|||
"concurrent_prefetch_limit": "同時に先読みするストリーム数上限",
|
||||
"add": "追加",
|
||||
"invalid_url": "無効なURLです!",
|
||||
"customize": "追加"
|
||||
"customize": "追加",
|
||||
"delete_group_confirm": "このグループを削除しますか?"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "{author} によって固定",
|
||||
|
|
|
@ -127,7 +127,12 @@
|
|||
"clone_playlist": "Klonēt Atskaņošanas Saturu",
|
||||
"uses_api_from": "Izmanto API no ",
|
||||
"add_to_playlist": "Pievienot Atskaņošanas Sarakstam",
|
||||
"instances_not_shown": "Publiskās instances, kas šeit nav redzamas, pašlaik nav pieejamas."
|
||||
"instances_not_shown": "Publiskās instances, kas šeit nav redzamas, pašlaik nav pieejamas.",
|
||||
"delete_group_confirm": "Vai vēlaties dzēst šo grupu?",
|
||||
"concurrent_prefetch_limit": "Vienlaicīgu Straumju Ielādes Limits",
|
||||
"customize": "Pielāgot",
|
||||
"invalid_url": "Nederīgs URL!",
|
||||
"add": "Pievienot"
|
||||
},
|
||||
"search": {
|
||||
"all": "YouTube: Visi",
|
||||
|
@ -161,7 +166,9 @@
|
|||
"playlists": "Atskaņošanas saraksts",
|
||||
"register": "Reģistrēties",
|
||||
"player": "Atskaņotājs",
|
||||
"dearrow": "DeArrow"
|
||||
"dearrow": "DeArrow",
|
||||
"albums": "Albumi",
|
||||
"custom_instances": "Pielāgotas instances"
|
||||
},
|
||||
"video": {
|
||||
"all": "Visi",
|
||||
|
@ -207,7 +214,9 @@
|
|||
"has_cdn": "Vai ir satura piegādes tīkls?",
|
||||
"instance_name": "Instances Nosaukums",
|
||||
"registered_users": "Reģistrētie Lietotāji",
|
||||
"instance_locations": "Instances Atrašanās Vietas"
|
||||
"instance_locations": "Instances Atrašanās Vietas",
|
||||
"uptime_30d": "Darbspējas laiks (30d)",
|
||||
"api_url": "Api URL"
|
||||
},
|
||||
"login": {
|
||||
"username": "Lietotājvārds",
|
||||
|
|
|
@ -156,7 +156,11 @@
|
|||
"customize": "Dostosuj",
|
||||
"invalid_url": "Nieprawidłowy adres URL!",
|
||||
"add": "Dodaj",
|
||||
"delete_group_confirm": "Usunąć tę grupę?"
|
||||
"delete_group_confirm": "Usunąć tę grupę?",
|
||||
"creator_replied": "Twórca odpowiedział",
|
||||
"creator_liked": "Twórca polubił",
|
||||
"invalid_input": "Nieprawidłowe dane wejściowe",
|
||||
"playback_speed": "Szybkość odtwarzania"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Przypięty przez {author}",
|
||||
|
|
|
@ -155,7 +155,12 @@
|
|||
"concurrent_prefetch_limit": "Предел одновременной предзагрузки трансляций",
|
||||
"customize": "Персонализация",
|
||||
"invalid_url": "Неправильная ссылка!",
|
||||
"add": "Добавить"
|
||||
"add": "Добавить",
|
||||
"creator_replied": "Ответ автора",
|
||||
"creator_liked": "Автор оценил",
|
||||
"playback_speed": "Скорость воспроизведения",
|
||||
"invalid_input": "Некорректный ввод",
|
||||
"delete_group_confirm": "Удалить группу?"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Закреплено пользователем {author}",
|
||||
|
|
|
@ -132,7 +132,11 @@
|
|||
"invalid_url": "Geçersiz URL!",
|
||||
"customize": "Özelleştir",
|
||||
"add": "Ekle",
|
||||
"delete_group_confirm": "Bu grup silinsin mi?"
|
||||
"delete_group_confirm": "Bu grup silinsin mi?",
|
||||
"creator_replied": "Oluşturan yanıtladı",
|
||||
"creator_liked": "Oluşturan beğendi",
|
||||
"playback_speed": "Oynatma hızı",
|
||||
"invalid_input": "Geçersiz giriş"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "{0} üzerinde görüntüle",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue