Merge pull request #254 from 404-Program-not-found/main

Additional comment features
This commit is contained in:
Alex 2022-04-21 22:55:23 +12:00 committed by GitHub
commit a75fa1ec86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 248 additions and 76 deletions

View File

@ -0,0 +1,41 @@
<template>
<div
class="author-comment-badge-renderer"
v-if="metadata && iconTypeMap.hasOwnProperty(metadata.icon.iconType)"
>
<v-tooltip top>
<template v-slot:activator="{ on, attrs }">
<v-icon v-bind="attrs" v-on="on" class="author-badge" small>{{
iconTypeMap[metadata.icon.iconType]
}}</v-icon>
</template>
<span>{{ metadata.iconTooltip }}</span>
</v-tooltip>
</div>
</template>
<script>
export default {
props: {
metadata: {
type: Object,
default: () => ({}),
},
},
data: () => ({
iconTypeMap: {
CHECK: "mdi-check-circle",
CHECK_CIRCLE_THICK: "mdi-check-circle",
OFFICIAL_ARTIST_BADGE: "mdi-music-note",
},
}),
};
</script>
<style scoped>
.author-comment-badge-renderer {
display: flex;
flex-direction: row;
align-items: center;
}
</style>

View File

@ -18,23 +18,45 @@
/> />
</a> </a>
<div class="comment-content"> <div class="comment-content">
<div class="comment-content--header"> <div class="comment-content--header subtitle-2">
<h3 class="author-name--wrapper"> <div
<span class="font-weight-bold subtitle-2 pr-1 author-name" emoji> class="author-badge-name mr-1"
{{ commentRenderer.authorText.runs[0].text }} :class="{ owner: commentRenderer.authorIsChannelOwner }"
</span> >
</h3> <div class="author-name--wrapper">
<span class="font-weight-bold author-name" v-emoji>
{{ commentRenderer.authorText.simpleText }}
</span>
</div>
<template
v-for="(badge, index) in commentRenderer.authorCommentBadge"
>
<author-comment-badge-renderer
:metadata="badge"
:key="index"
class="ml-1"
/>
</template>
<template
v-for="(badge, index) in commentRenderer.sponsorCommentBadge"
>
<sponsor-comment-badge-renderer
:metadata="badge"
:key="index"
class="ml-1"
/>
</template>
</div>
<span <span
:class="$vuetify.theme.dark ? 'text--lighten-4' : 'text--darken-4'" :class="$vuetify.theme.dark ? 'text--lighten-4' : 'text--darken-4'"
class="background--text subtitle-2 comment-timestamp" class="background--text comment-timestamp"
> >
{{ commentRenderer.publishedTimeText.runs[0].text }} {{ commentRenderer.publishedTimeText.runs[0].text }}
</span> </span>
</div> </div>
<collapsable-text :lines="4"> <collapsable-text :lines="4">
<template v-for="text in commentRenderer.contentText.runs">{{ <yt-text-formatter :textRuns="commentRenderer.contentText.runs">
text.text </yt-text-formatter>
}}</template>
</collapsable-text> </collapsable-text>
</div> </div>
</div> </div>
@ -71,25 +93,51 @@
display: flex; display: flex;
align-items: baseline; align-items: baseline;
.author-name--wrapper {
min-width: 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.comment-timestamp { .comment-timestamp {
white-space: nowrap; white-space: nowrap;
} }
} }
} }
} }
.author-badge-name {
display: flex;
flex-direction: row;
min-width: 0;
.author-name--wrapper {
min-width: 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
.owner {
padding: 0 0.6em;
background-color: #888888;
color: #fff;
border-radius: 1em;
&::v-deep .author-badge {
color: #fff;
}
}
</style> </style>
<script> <script>
import collapsableText from "~/components/UtilRenderers/collapsableText.vue"; import collapsableText from "~/components/UtilRenderers/collapsableText.vue";
import YtTextFormatter from "~/components/UtilRenderers/YtTextFormatter.vue";
import AuthorCommentBadgeRenderer from "~/components/Comments/authorCommentBadgeRenderer.vue";
import SponsorCommentBadgeRenderer from "~/components/Comments/sponsorCommentBadgeRenderer.vue";
export default { export default {
components: { collapsableText }, components: {
collapsableText,
YtTextFormatter,
AuthorCommentBadgeRenderer,
SponsorCommentBadgeRenderer,
},
props: ["comment"], props: ["comment"],
data() { data() {

View File

@ -10,7 +10,7 @@
</template> </template>
</v-toolbar-title> </v-toolbar-title>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn icon dark @click="$emit('changeState', false)"> <v-btn icon @click="$emit('changeState', false)">
<v-icon>mdi-close</v-icon> <v-icon>mdi-close</v-icon>
</v-btn> </v-btn>
</template> </template>
@ -48,7 +48,7 @@ import commentThreadRenderer from "~/components/Comments/commentThreadRenderer.v
import continuationItemRenderer from "~/components/observer.vue"; import continuationItemRenderer from "~/components/observer.vue";
export default { export default {
props: ["continuation", "commentData", "showComments"], props: ["defaultContinuation", "commentData", "showComments"],
model: { model: {
prop: "showComments", prop: "showComments",
@ -65,9 +65,11 @@ export default {
data: () => ({ data: () => ({
loading: true, loading: true,
comments: [], comments: [],
continuation: null,
}), }),
mounted() { mounted() {
if (!this.continuation) this.continuation = this.defaultContinuation;
this.paginate(); this.paginate();
}, },
@ -77,36 +79,38 @@ export default {
}, },
paginate() { paginate() {
this.loading = true; if (this.continuation) {
const watcherIndex = this.comments.findIndex( this.loading = true;
(comment) => comment.continuationItemRenderer const watcherIndex = this.comments.findIndex(
); (comment) => comment.continuationItemRenderer
if (watcherIndex) this.comments.splice(watcherIndex, 1); );
this.$youtube if (watcherIndex) this.comments.splice(watcherIndex, 1);
.getContinuation(this.continuation, "next", "web") this.$youtube
.then((result) => { .getContinuation(this.continuation, "next", "web")
let processed; .then((result) => {
if ( let processed;
result.data.onResponseReceivedEndpoints.find( if (
(endpoints) => endpoints.reloadContinuationItemsCommand result.data.onResponseReceivedEndpoints.find(
) (endpoints) => endpoints.reloadContinuationItemsCommand
) { )
processed = result.data.onResponseReceivedEndpoints.map( ) {
(endpoints) => processed = result.data.onResponseReceivedEndpoints.map(
endpoints.reloadContinuationItemsCommand.continuationItems (endpoints) =>
); endpoints.reloadContinuationItemsCommand.continuationItems
} else { );
processed = result.data.onResponseReceivedEndpoints.map( } else {
(endpoints) => processed = result.data.onResponseReceivedEndpoints.map(
endpoints.appendContinuationItemsAction.continuationItems (endpoints) =>
); endpoints.appendContinuationItemsAction.continuationItems
} );
processed = processed.flat(1); }
this.comments = this.comments.concat(processed); processed = processed.flat(1);
this.continuation = this.findContinuation(processed); this.comments = this.comments.concat(processed);
console.log("comments", this.comments); this.continuation = this.findContinuation(processed);
if (this.comments) this.loading = false; console.log("comments", this.comments);
}); if (this.comments) this.loading = false;
});
}
}, },
findContinuation(newResponses) { findContinuation(newResponses) {
@ -115,7 +119,7 @@ export default {
); );
const newContinuation = const newContinuation =
continuationItemParent.continuationItemRenderer.continuationEndpoint continuationItemParent?.continuationItemRenderer.continuationEndpoint
.continuationCommand.token; .continuationCommand.token;
return newContinuation; return newContinuation;

View File

@ -0,0 +1,43 @@
<template>
<div
class="author-comment-badge-renderer"
v-if="metadata && metadata.customBadge"
>
<v-tooltip top>
<template v-slot:activator="{ on, attrs }">
<img
v-bind="attrs"
v-on="on"
class="badge"
:src="metadata.customBadge.thumbnails[0].url"
:alt="metadata.tooltip"
/>
</template>
<span>{{ metadata.tooltip }}</span>
</v-tooltip>
</div>
</template>
<script>
export default {
props: {
metadata: {
type: Object,
default: () => ({}),
},
},
};
</script>
<style scoped>
.author-comment-badge-renderer {
display: flex;
flex-direction: row;
align-items: center;
}
.badge {
display: inline-block;
width: 1.25em;
height: 1.25em;
vertical-align: -0.1em;
}
</style>

View File

@ -0,0 +1,48 @@
<template>
<div class="yt-text-formatter" v-emoji>
<template v-for="(text, index) in textRuns">
<template v-if="$rendererUtils.checkInternal(text)">
<a
@click="openInternal($rendererUtils.getNavigationEndpoints(text))"
:key="index"
>{{ text.text }}</a
>
</template>
<template
v-else-if="
text.navigationEndpoint && text.navigationEndpoint.urlEndpoint
"
>
<a
@click="openExternal($rendererUtils.getNavigationEndpoints(text))"
:key="index"
>{{ text.text }}</a
>
</template>
<template v-else-if="text.emoji && text.emoji.isCustomEmoji">
<img
:src="
text.emoji.image.thumbnails[text.emoji.image.thumbnails.length - 1]
.url
"
:alt="text.text"
:key="index"
class="emoji"
draggable="false"
/>
</template>
<template v-else> {{ text.text }} </template>
</template>
</div>
</template>
<script>
export default {
props: {
textRuns: {
type: Array,
default: () => [],
},
},
};
</script>

View File

@ -1,26 +1,7 @@
<template> <template>
<div class="description" v-if="render.descriptionBodyText"> <div class="description" v-if="render.descriptionBodyText">
<template v-for="(text, index) in render.descriptionBodyText.runs"> <yt-text-formatter :textRuns="render.descriptionBodyText.runs">
<template v-if="$rendererUtils.checkInternal(text)"> </yt-text-formatter>
<a
@click="openInternal($rendererUtils.getNavigationEndpoints(text))"
:key="index"
>{{ text.text }}</a
>
</template>
<template
v-else-if="
text.navigationEndpoint && text.navigationEndpoint.urlEndpoint
"
>
<a
@click="openExternal($rendererUtils.getNavigationEndpoints(text))"
:key="index"
>{{ text.text }}</a
>
</template>
<template v-else> {{ text.text }} </template>
</template>
</div> </div>
</template> </template>
@ -32,9 +13,15 @@
<script> <script>
import { Browser } from "@capacitor/browser"; import { Browser } from "@capacitor/browser";
import YtTextFormatter from "~/components/UtilRenderers/YtTextFormatter.vue";
export default { export default {
props: ["render"], props: ["render"],
components: {
YtTextFormatter,
},
methods: { methods: {
async openExternal(url) { async openExternal(url) {
await Browser.open({ url: url }); await Browser.open({ url: url });

View File

@ -172,7 +172,7 @@
v-if="loaded && video.commentData" v-if="loaded && video.commentData"
> >
<mainCommentRenderer <mainCommentRenderer
:continuation="video.commentContinuation" :defaultContinuation="video.commentContinuation"
:commentData="video.commentData" :commentData="video.commentData"
v-model="showComments" v-model="showComments"
></mainCommentRenderer> ></mainCommentRenderer>

View File

@ -13,7 +13,8 @@ const ytApiVal = {
VERSION: "16.25", VERSION: "16.25",
CLIENTNAME: "ANDROID", CLIENTNAME: "ANDROID",
VERSION_WEB: "2.20220411.09.00", VERSION_WEB: "2.20220411.09.00",
CLIENT_WEB: 2, CLIENT_WEB_M: 2,
CLIENT_WEB_D: 1,
}; };
const filesystem = { const filesystem = {

View File

@ -159,7 +159,7 @@ class Innertube {
...{ ...{
context: { context: {
client: { client: {
clientName: constants.YT_API_VALUES.CLIENT_WEB, clientName: constants.YT_API_VALUES.CLIENT_WEB_M,
clientVersion: constants.YT_API_VALUES.VERSION_WEB, clientVersion: constants.YT_API_VALUES.VERSION_WEB,
}, },
}, },

View File

@ -152,7 +152,7 @@ const innertubeModule = {
...contextAdditional, ...contextAdditional,
...{ ...{
client: { client: {
clientName: constants.YT_API_VALUES.CLIENT_WEB, clientName: constants.YT_API_VALUES.CLIENT_WEB_D,
clientVersion: constants.YT_API_VALUES.VERSION_WEB, clientVersion: constants.YT_API_VALUES.VERSION_WEB,
}, },
}, },