Skip to content

Commit

Permalink
Highlights comments. #783
Browse files Browse the repository at this point in the history
  • Loading branch information
ab-shrek committed Nov 2, 2023
1 parent aed4f12 commit e0a5119
Show file tree
Hide file tree
Showing 10 changed files with 401 additions and 30 deletions.
5 changes: 4 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ const DBActions = {
},

HIGHLIGHTED_COMMENTS: {
UPSERT_COMMENT: 'db-action-highlighted-comments-upsert-highlighted-comment-by-video-id'
UPSERT_COMMENT: 'db-action-highlighted-comments-upsert-comment',
DELETE_COMMENT: 'db-action-higlighted-comments-delete-comment',
UPSERT_REPLY: 'db-action-highlighted-comments-upsert-reply',
DELETE_REPLY: 'db-action-higlighted-comments-delete-reply'
}
}

Expand Down
116 changes: 110 additions & 6 deletions src/datastores/handlers/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,116 @@ class HighlightedComments {
return db.highlightedComments.findAsync({})
}

static upsertHighlightedCommentByVideoId(comment, videoId) {
return db.highlightedComments.updateAsync(
{ _id: videoId },
{ $push: { comments: comment } },
{ upsert: true }
)
static async upsertHighlightedComment(videoId, comment) {
const highlightedComment = await db.highlightedComments.findOneAsync(
{ _id: videoId })
let commentIndex = -1
if (highlightedComment !== null) {
commentIndex = highlightedComment.comments.findIndex(c => {
return JSON.parse(c.comment).commentId === JSON.parse(comment).commentId
})
}
if (commentIndex !== -1) {
// Update the 'isCommentHighlighted' field of the found comment
return db.highlightedComments.updateAsync(
{ _id: videoId },
{ $set: { [`comments.${commentIndex}.isCommentHighlighted`]: true } },
{}
)
} else {
// Append the comment to the 'comments' array.
return db.highlightedComments.updateAsync(
{ _id: videoId },
{ $push: { comments: { comment: comment, replies: [], isCommentHighlighted: true } } },
{ upsert: true }
)
}
}

static async deleteHighlightedComment(videoId, comment) {
const highlightedComment = await db.highlightedComments.findOneAsync(
{ _id: videoId })
let commentIndex = -1
if (highlightedComment !== null) {
commentIndex = highlightedComment.comments.findIndex(c => {
return JSON.parse(c.comment).commentId === JSON.parse(comment).commentId
})
}
if (commentIndex !== -1) {
const hasReplies = highlightedComment.comments[commentIndex].replies.length > 0
if (hasReplies) {
// Update 'isCommentHighlighted' to false if replies are non-empty
return db.highlightedComments.updateAsync(
{ _id: videoId },
{ $set: { [`comments.${commentIndex}.isCommentHighlighted`]: false } },
{}
)
} else {
// Remove the entire entry from the 'comments' array if replies are empty
highlightedComment.comments.splice(commentIndex, 1)
db.highlightedComments.updateAsync(
{ _id: videoId },
highlightedComment,
{}
)
}
}
}

static async upsertHighlightedReply(videoId, comment, reply) {
const highlightedComment = await db.highlightedComments.findOneAsync({ _id: videoId })
let commentIndex = -1
if (highlightedComment !== null) {
commentIndex = highlightedComment.comments.findIndex(c => {
return JSON.parse(c.comment).commentId === JSON.parse(comment).commentId
})
}
if (commentIndex === -1) {
// Append a new entry to the comments array
return db.highlightedComments.updateAsync(
{ _id: videoId },
{ $push: { comments: { comment: comment, replies: [reply], isCommentHighlighted: false } } },
{ upsert: true }
)
} else {
// Append the reply to found comment's replies entry
return db.highlightedComments.updateAsync(
{ _id: videoId },
{ $push: { [`comments.${commentIndex}.replies`]: reply } },
{ upsert: true }
)
}
}

static async deleteHighlightedReply(videoId, comment, reply) {
const highlightedComment = await db.highlightedComments.findOneAsync({ _id: videoId })
let commentIndex = -1
if (highlightedComment !== null) {
commentIndex = highlightedComment.comments.findIndex(c => {
return JSON.parse(c.comment).commentId === JSON.parse(comment).commentId
})
}
if (commentIndex !== -1) {
const moreReplies = highlightedComment.comments[commentIndex].replies.length > 1
const isCommentHighlighted = highlightedComment.comments[commentIndex].isCommentHighlighted
if (!moreReplies && !isCommentHighlighted) {
// Remove the entire entry from the 'comments' array if there are no more
// highlighted replies and the comment is not highlighted
highlightedComment.comments.splice(commentIndex, 1)
} else {
// Remove the reply entry from the 'replies' array for the found comment.
highlightedComment.comments[commentIndex].replies = (
highlightedComment.comments[commentIndex].replies.filter(
r => JSON.parse(r).commentId !== JSON.parse(reply).commentId
)
)
}
db.highlightedComments.updateAsync(
{ _id: videoId },
highlightedComment,
{}
)
}
}

static persist() {
Expand Down
32 changes: 31 additions & 1 deletion src/datastores/handlers/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class HighlightedComments {
)
}

static upsertHighlightedCommentByVideoId(comment, videoId) {
static upsertHighlightedComment(videoId, comment) {
return ipcRenderer.invoke(
IpcChannels.DB_HIGHLIGHTED_COMMENTS,
{
Expand All @@ -223,6 +223,36 @@ class HighlightedComments {
)
}

static deleteHighlightedComment(videoId, comment) {
return ipcRenderer.invoke(
IpcChannels.DB_HIGHLIGHTED_COMMENTS,
{
action: DBActions.HIGHLIGHTED_COMMENTS.DELETE_COMMENT,
data: { videoId: videoId, comment: JSON.stringify(comment) }
}
)
}

static upsertHighlightedReply(videoId, comment, reply) {
return ipcRenderer.invoke(
IpcChannels.DB_HIGHLIGHTED_COMMENTS,
{
action: DBActions.HIGHLIGHTED_COMMENTS.UPSERT_REPLY,
data: { videoId: videoId, comment: JSON.stringify(comment), reply: JSON.stringify(reply) }
}
)
}

static deleteHighlightedReply(videoId, comment, reply) {
return ipcRenderer.invoke(
IpcChannels.DB_HIGHLIGHTED_COMMENTS,
{
action: DBActions.HIGHLIGHTED_COMMENTS.DELETE_REPLY,
data: { videoId: videoId, comment: JSON.stringify(comment), reply: JSON.stringify(reply) }
}
)
}

static persist() {
return ipcRenderer.invoke(
IpcChannels.DB_HIGHLIGHTED_COMMENTS,
Expand Down
14 changes: 13 additions & 1 deletion src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,19 @@ function runApp() {
return await baseHandlers.highlightedComments.find()

case DBActions.HIGHLIGHTED_COMMENTS.UPSERT_COMMENT:
await baseHandlers.highlightedComments.upsertHighlightedCommentByVideoId(data.comment, data.videoId)
await baseHandlers.highlightedComments.upsertHighlightedComment(data.videoId, data.comment)
return null

case DBActions.HIGHLIGHTED_COMMENTS.DELETE_COMMENT:
await baseHandlers.highlightedComments.deleteHighlightedComment(data.videoId, data.comment)
return null

case DBActions.HIGHLIGHTED_COMMENTS.UPSERT_REPLY:
await baseHandlers.highlightedComments.upsertHighlightedReply(data.videoId, data.comment, data.reply)
return null

case DBActions.HIGHLIGHTED_COMMENTS.DELETE_REPLY:
await baseHandlers.highlightedComments.deleteHighlightedReply(data.videoId, data.comment, data.reply)
return null

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@
margin-block-end: 5px;
}

.replyHighlighted {
font-weight: normal;
font-size: 12px;
margin-block-start: 0;
margin-inline-start: 68px;
margin-block-end: 5px;
}

.commentDate {
font-weight: normal;
margin-inline-start: 5px;
Expand Down
108 changes: 103 additions & 5 deletions src/renderer/components/watch-video-comments/watch-video-comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,21 @@ export default defineComponent({

highlightedComments: function () {
return this.$store.getters.getHighlightedComments(this.id)
},
highlightedReplyComments: function () {
return this.$store.getters.getHighlightedReplyComments(this.id)
},
isCommentHighlighted: function () {
return (comment) => !!this.$store.getters.getHighlightedComments(this.id).find((entry) => entry.commentId === comment.commentId)
},
isReplyHighlighted: function () {
return (comment, reply) => !!this.$store.getters.getHighlightedReplies(this.id, comment.commentId).find(entry => entry.commentId === reply.commentId)
},
getHighlightedReplies: function () {
return (commentId) => this.$store.getters.getHighlightedReplies(this.id, commentId)
},
isCommentOrReplyHighlighted: function () {
return (comment) => this.isCommentHighlighted(comment) || this.getHighlightedReplies(comment.commentId).length > 0
}
},
mounted: function () {
Expand Down Expand Up @@ -156,7 +171,11 @@ export default defineComponent({

getCommentData: function () {
this.isLoading = true
this.commentIndexCount = -1
this.commentData = this.commentData.concat(this.highlightedComments)
this.commentData = Array.from([...this.commentData, ...this.highlightedReplyComments]
.reduce((m, o) => m.set(o.commentId, o), new Map())
.values())
if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') {
this.getCommentDataInvidious()
} else {
Expand Down Expand Up @@ -211,6 +230,11 @@ export default defineComponent({

const parsedComments = comments.contents
.map(commentThread => parseLocalComment(commentThread.comment, commentThread))
parsedComments.forEach(
comment => {
comment.commentIndex = ++this.commentIndexCount
}
)

// Append and remove duplicate comments based on commentId.
this.commentData = Array.from([...this.commentData, ...parsedComments]
Expand Down Expand Up @@ -274,6 +298,9 @@ export default defineComponent({
nextPageToken: this.nextPageToken,
sortNewest: this.sortNewest
}).then(({ response, commentData }) => {
commentData.forEach(function(comment) {
comment.commentIndex = ++this.commentIndexCount
}.bind(this))
this.commentData = Array.from([...this.commentData, ...commentData]
.reduce((m, o) => m.set(o.commentId, o), new Map())
.values())
Expand Down Expand Up @@ -327,14 +354,85 @@ export default defineComponent({
})
},

addHighlightedCommentAndReloadPage: function (comment) {
showToast(this.$t('Highlighting comment'))
this.$store.dispatch('addHighlightedComment', { videoId: this.id, comment: comment })
window.location.reload()
toggleCommentHighlight: async function (comment) {
if (this.isCommentHighlighted(comment)) {
showToast(this.$t('Unhighlighting comment'))
await this.$store.dispatch('unhighlightComment', { videoId: this.id, comment: comment })
const indexToRemove = this.commentData.findIndex(entry => entry.commentId === comment.commentId)
if (this.isCommentOrReplyHighlighted(comment)) {
this.commentData.splice(indexToRemove, 1)
this.commentData.unshift(comment)
} else {
// find number of highlighted comments before the comment
const highlightedOrReplyComments = this.$store.getters.getHighlightedComments(this.id).concat(this.$store.getters.getHighlightedReplyComments(this.id))
const filteredComments = highlightedOrReplyComments.filter(c => c.commentIndex < comment.commentIndex)
const uniqueCommentCount = new Set(filteredComments.map(comment => comment.commentId)).size
const highlightedCommentCount = new Set(highlightedOrReplyComments.map(comment => comment.commentId)).size
const newIndex = comment.commentIndex + highlightedCommentCount - uniqueCommentCount

// move comment to original index
if (indexToRemove !== -1) {
this.commentData.splice(indexToRemove, 1)
}
this.commentData.splice(newIndex, 0, comment)
}
} else {
showToast(this.$t('Highlighting comment'))
await this.$store.dispatch('highlightComment', { videoId: this.id, comment: comment })
// move comment to top
const indexToRemove = this.commentData.findIndex(entry => entry.commentId === comment.commentId)
if (indexToRemove !== -1) {
this.commentData.splice(indexToRemove, 1)
}
this.commentData.unshift(comment)
}
},

toggleReplyHighlight: async function (comment, reply) {
if (this.isReplyHighlighted(comment, reply)) {
showToast(this.$t('Unhighlighting reply'))
await this.$store.dispatch('unhighlightReply', { videoId: this.id, comment: comment, reply: reply })
if (!this.isCommentOrReplyHighlighted(comment)) {
const indexToRemove = this.commentData.findIndex(entry => entry.commentId === comment.commentId)
const highlightedOrReplyComments = this.$store.getters.getHighlightedComments(this.id).concat(this.$store.getters.getHighlightedReplyComments(this.id))
const filteredComments = highlightedOrReplyComments.filter(c => c.commentIndex < comment.commentIndex)
const uniqueCommentCount = new Set(filteredComments.map(comment => comment.commentId)).size
const highlightedCommentCount = new Set(highlightedOrReplyComments.map(comment => comment.commentId)).size
const newIndex = comment.commentIndex + highlightedCommentCount - uniqueCommentCount

// move comment to original index
if (indexToRemove !== -1) {
this.commentData.splice(indexToRemove, 1)
}
this.commentData.splice(newIndex, 0, comment)
}
const replyIndex = comment.replies.findIndex(entry => entry.commentId === reply.commentId)
if (replyIndex !== -1) {
comment.replies.splice(replyIndex, 1)
comment.replies.splice(replyIndex, 0, reply)
}
} else {
showToast(this.$t('Highlighting reply'))
await this.$store.dispatch('highlightReply', { videoId: this.id, comment: comment, reply: reply })
// move reply to top
const replyIndex = comment.replies.findIndex(entry => entry.commentId === reply.commentId)
if (replyIndex !== -1) {
comment.replies.splice(replyIndex, 1)
}
comment.replies.unshift(reply)

// move comment to top
const indexToRemove = this.commentData.findIndex(entry => entry.commentId === comment.commentId)
if (indexToRemove !== -1) {
this.commentData.splice(indexToRemove, 1)
}
this.commentData.unshift(comment)
}
},

...mapActions([
'addHighlightedComment'
'highlightComment',
'unhighlightComment'
])
}
})
Loading

0 comments on commit e0a5119

Please sign in to comment.