This commit is contained in:
J.P 2024-05-17 02:26:17 +02:00 committed by GitHub
commit 995be6bed1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 101 additions and 85 deletions

View file

@ -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)));
},
},

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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"];

View file

@ -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);
});
}

View file

@ -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}",
@ -227,4 +231,4 @@
"register_note": "Register an account for this Piped instance. This will allow you to sync your subscriptions and playlists with your account, so they're stored on the server side. You can use all features without an account, but all data will be stored in your browser's local cache. Please make sure you do NOT use an email address as your username and choose a secure password that you do not use elsewhere.",
"login_note": "Log in with an account created on this instance."
}
}
}

View file

@ -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?",

View file

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

View file

@ -155,7 +155,8 @@
"concurrent_prefetch_limit": "同時に先読みするストリーム数上限",
"add": "追加",
"invalid_url": "無効なURLです",
"customize": "追加"
"customize": "追加",
"delete_group_confirm": "このグループを削除しますか?"
},
"comment": {
"pinned_by": "{author} によって固定",

View file

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

View file

@ -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}",

View file

@ -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}",

View file

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