mirror of
				https://github.com/TeamPiped/Piped.git
				synced 2025-11-04 06:31:55 +00:00 
			
		
		
		
	Tree shake DomPurify.
This commit is contained in:
		@@ -31,6 +31,7 @@
 | 
			
		||||
        "@iconify-json/fa6-solid": "1.1.13",
 | 
			
		||||
        "@intlify/unplugin-vue-i18n": "0.12.2",
 | 
			
		||||
        "@unocss/preset-icons": "0.53.6",
 | 
			
		||||
        "@unocss/preset-uno": "0.53.6",
 | 
			
		||||
        "@unocss/preset-web-fonts": "0.53.6",
 | 
			
		||||
        "@unocss/reset": "0.53.6",
 | 
			
		||||
        "@unocss/transformer-directives": "0.53.6",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							@@ -64,6 +64,9 @@ devDependencies:
 | 
			
		||||
  '@unocss/preset-icons':
 | 
			
		||||
    specifier: 0.53.6
 | 
			
		||||
    version: 0.53.6
 | 
			
		||||
  '@unocss/preset-uno':
 | 
			
		||||
    specifier: 0.53.6
 | 
			
		||||
    version: 0.53.6
 | 
			
		||||
  '@unocss/preset-web-fonts':
 | 
			
		||||
    specifier: 0.53.6
 | 
			
		||||
    version: 0.53.6
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <!-- eslint-disable-next-line vue/no-v-html -->
 | 
			
		||||
    <div v-if="text" class="whitespace-pre-wrap py-2 mx-1">
 | 
			
		||||
        <span v-if="showFullText" v-html="purifyHTML(rewriteDescription(text))" />
 | 
			
		||||
        <span v-else v-html="purifyHTML(rewriteDescription(text.slice(0, 100)))" />
 | 
			
		||||
        <span v-if="showFullText" v-html="fullText()" />
 | 
			
		||||
        <span v-else v-html="colapsedText()" />
 | 
			
		||||
        <span v-if="text.length > 100 && !showFullText">...</span>
 | 
			
		||||
        <button
 | 
			
		||||
            v-if="text.length > 100"
 | 
			
		||||
@@ -15,6 +15,8 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { purifyHTML, rewriteDescription } from "@/utils/HtmlUtils";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        text: String,
 | 
			
		||||
@@ -24,5 +26,13 @@ export default {
 | 
			
		||||
            showFullText: false,
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        fullText() {
 | 
			
		||||
            return purifyHTML(rewriteDescription(this.text));
 | 
			
		||||
        },
 | 
			
		||||
        colapsedText() {
 | 
			
		||||
            return purifyHTML(rewriteDescription(this.text.slice(0, 100)));
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="comment-meta text-sm mb-1.5" v-text="comment.commentedTime" />
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="whitespace-pre-wrap" v-html="purifyHTML(comment.commentText)" />
 | 
			
		||||
            <div class="whitespace-pre-wrap" v-html="purifiedText" />
 | 
			
		||||
            <div class="comment-footer mt-1 flex items-center">
 | 
			
		||||
                <div class="i-fa6-solid:thumbs-up" />
 | 
			
		||||
                <span class="ml-1" v-text="numberFormat(comment.likeCount)" />
 | 
			
		||||
@@ -60,6 +60,8 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { purifyHTML } from "@/utils/HtmlUtils";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        comment: {
 | 
			
		||||
@@ -79,6 +81,11 @@ export default {
 | 
			
		||||
            nextpage: null,
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        purifiedText() {
 | 
			
		||||
            return purifyHTML(this.comment.commentText);
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        async loadReplies() {
 | 
			
		||||
            if (!this.showingReplies && this.loadingReplies) {
 | 
			
		||||
 
 | 
			
		||||
@@ -158,7 +158,7 @@
 | 
			
		||||
            </span>
 | 
			
		||||
 | 
			
		||||
            <!-- eslint-disable-next-line vue/no-v-html -->
 | 
			
		||||
            <div v-show="showDesc" class="break-words description" v-html="purifyHTML(video.description)" />
 | 
			
		||||
            <div v-show="showDesc" class="break-words description" v-html="purifiedDescription" />
 | 
			
		||||
            <template v-if="showDesc">
 | 
			
		||||
                <div
 | 
			
		||||
                    v-if="sponsors && sponsors.segments"
 | 
			
		||||
@@ -248,6 +248,7 @@ import WatchOnButton from "./WatchOnButton.vue";
 | 
			
		||||
import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
 | 
			
		||||
import ToastComponent from "./ToastComponent.vue";
 | 
			
		||||
import { parseTimeParam } from "@/utils/Misc";
 | 
			
		||||
import { purifyHTML, rewriteDescription } from "@/utils/HtmlUtils";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: "App",
 | 
			
		||||
@@ -315,6 +316,9 @@ export default {
 | 
			
		||||
        defaultCounter(_this) {
 | 
			
		||||
            return _this.getPreferenceNumber("autoPlayNextCountdown", 5);
 | 
			
		||||
        },
 | 
			
		||||
        purifiedDescription() {
 | 
			
		||||
            return purifyHTML(this.video.description);
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        // check screen size
 | 
			
		||||
@@ -451,7 +455,7 @@ export default {
 | 
			
		||||
                                elem.outerHTML = elem.getAttribute("href");
 | 
			
		||||
                        });
 | 
			
		||||
                        xmlDoc.querySelectorAll("br").forEach(elem => (elem.outerHTML = "\n"));
 | 
			
		||||
                        this.video.description = this.rewriteDescription(xmlDoc.querySelector("body").innerHTML);
 | 
			
		||||
                        this.video.description = rewriteDescription(xmlDoc.querySelector("body").innerHTML);
 | 
			
		||||
                        this.updateWatched(this.video.relatedStreams);
 | 
			
		||||
 | 
			
		||||
                        this.fetchDeArrowContent(this.video.relatedStreams);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								src/main.js
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								src/main.js
									
									
									
									
									
								
							@@ -56,8 +56,6 @@ library.add(
 | 
			
		||||
import router from "@/router/router.js";
 | 
			
		||||
import App from "./App.vue";
 | 
			
		||||
 | 
			
		||||
import DOMPurify from "dompurify";
 | 
			
		||||
 | 
			
		||||
import TimeAgo from "javascript-time-ago";
 | 
			
		||||
 | 
			
		||||
import en from "javascript-time-ago/locale/en";
 | 
			
		||||
@@ -120,9 +118,6 @@ const mixin = {
 | 
			
		||||
                return response.json();
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        purifyHTML(original) {
 | 
			
		||||
            return DOMPurify.sanitize(original);
 | 
			
		||||
        },
 | 
			
		||||
        setPreference(key, value, disableAlert = false) {
 | 
			
		||||
            try {
 | 
			
		||||
                localStorage.setItem(key, value);
 | 
			
		||||
@@ -195,19 +190,6 @@ const mixin = {
 | 
			
		||||
        timeAgo(time) {
 | 
			
		||||
            return timeAgo.format(time);
 | 
			
		||||
        },
 | 
			
		||||
        urlify(string) {
 | 
			
		||||
            if (!string) return "";
 | 
			
		||||
            const urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
 | 
			
		||||
            const emailRegex = /([\w-\\.]+@(?:[\w-]+\.)+[\w-]{2,4})/g;
 | 
			
		||||
            return string
 | 
			
		||||
                .replace(urlRegex, url => {
 | 
			
		||||
                    if (url.endsWith("</a>") || url.endsWith("<a")) return url;
 | 
			
		||||
                    return `<a href="${url}" target="_blank">${url}</a>`;
 | 
			
		||||
                })
 | 
			
		||||
                .replace(emailRegex, email => {
 | 
			
		||||
                    return `<a href="mailto:${email}">${email}</a>`;
 | 
			
		||||
                });
 | 
			
		||||
        },
 | 
			
		||||
        async updateWatched(videos) {
 | 
			
		||||
            if (window.db && this.getPreferenceBoolean("watchHistory", false)) {
 | 
			
		||||
                var tx = window.db.transaction("watch_history", "readonly");
 | 
			
		||||
@@ -265,15 +247,6 @@ const mixin = {
 | 
			
		||||
            elem.click();
 | 
			
		||||
            elem.remove();
 | 
			
		||||
        },
 | 
			
		||||
        rewriteDescription(text) {
 | 
			
		||||
            return this.urlify(text)
 | 
			
		||||
                .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",
 | 
			
		||||
                )
 | 
			
		||||
                .replaceAll("\n", "<br>");
 | 
			
		||||
        },
 | 
			
		||||
        getChannelGroupsCursor() {
 | 
			
		||||
            if (!window.db) return;
 | 
			
		||||
            var tx = window.db.transaction("channel_groups", "readonly");
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								src/utils/HtmlUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/utils/HtmlUtils.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
import DOMPurify from "dompurify";
 | 
			
		||||
 | 
			
		||||
export const purifyHTML = html => {
 | 
			
		||||
    return DOMPurify.sanitize(html);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const urlify = string => {
 | 
			
		||||
    if (!string) return "";
 | 
			
		||||
    const urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/g;
 | 
			
		||||
    const emailRegex = /([\w-\\.]+@(?:[\w-]+\.)+[\w-]{2,4})/g;
 | 
			
		||||
    return string
 | 
			
		||||
        .replace(urlRegex, url => {
 | 
			
		||||
            if (url.endsWith("</a>") || url.endsWith("<a")) return url;
 | 
			
		||||
            return `<a href="${url}" target="_blank">${url}</a>`;
 | 
			
		||||
        })
 | 
			
		||||
        .replace(emailRegex, email => {
 | 
			
		||||
            return `<a href="mailto:${email}">${email}</a>`;
 | 
			
		||||
        });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const rewriteDescription = text => {
 | 
			
		||||
    return urlify(text)
 | 
			
		||||
        .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")
 | 
			
		||||
        .replaceAll("\n", "<br>");
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user