From f8a5935701afa5c60424bcff5f975f62fc8bd618 Mon Sep 17 00:00:00 2001 From: Pg Date: Wed, 17 Jul 2024 22:12:50 +0200 Subject: [PATCH 1/2] Meta liker to keep with youtube evolution --- app/manifest.json | 2 +- app/scripts/content.js | 11 +- app/scripts/modules/liker-grid.js | 35 ++ app/scripts/modules/liker-paper.js | 469 +----------------- .../{liker-material.js => metaliker.js} | 237 +++------ app/scripts/modules/miscellaneous.js | 26 +- 6 files changed, 148 insertions(+), 632 deletions(-) create mode 100644 app/scripts/modules/liker-grid.js rename app/scripts/modules/{liker-material.js => metaliker.js} (61%) diff --git a/app/manifest.json b/app/manifest.json index d9ee25b..44b95f3 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -25,7 +25,7 @@ "content_scripts": [ { "matches": ["*://youtube.com/*", "*://*.youtube.com/*"], - "js": ["scripts/constants.js", "scripts/modules/option-manager.js", "scripts/modules/miscellaneous.js", "scripts/modules/liker-material.js", "scripts/modules/liker-paper.js", "scripts/content.js"], + "js": ["scripts/constants.js", "scripts/modules/option-manager.js", "scripts/modules/miscellaneous.js", "scripts/modules/metaliker.js", "scripts/modules/liker-paper.js", "scripts/modules/liker-grid.js", "scripts/content.js"], "run_at": "document_end" } ], diff --git a/app/scripts/content.js b/app/scripts/content.js index 4b3439d..9285237 100644 --- a/app/scripts/content.js +++ b/app/scripts/content.js @@ -29,15 +29,18 @@ browser.runtime.onMessage.addListener( function(msg, sender, sendResponse) { function startLikerProcess(options) { var IS_PAPER = document.querySelector("ytd-subscribe-button-renderer") !== null; + var IS_GRID = document.querySelectorAll("ytd-watch-grid").length !== 0; window.IS_PAPER = IS_PAPER; + window.IS_GRID = IS_GRID; let liker = null; - if (IS_PAPER) { + if (IS_GRID) { + log("grid liker init"); + liker = new GridLiker(options); + } else if (IS_PAPER) { log("paper liker init"); liker = new PaperLiker(options); - } else { - log("material liker init"); - liker = new MaterialLiker(options); } + if (IS_CLASSIC) { log("Classic youtube detected"); liker.init(); diff --git a/app/scripts/modules/liker-grid.js b/app/scripts/modules/liker-grid.js new file mode 100644 index 0000000..f891332 --- /dev/null +++ b/app/scripts/modules/liker-grid.js @@ -0,0 +1,35 @@ +/* + * Likes YouTube videos. + * For the newer paper design layout + */ +class GridLiker extends MetaLiker { + + VIDEO_SELECTOR = ".video-stream"; + ACTION_ELEMENTS_SELECTOR = "#secondary-inner ytd-watch-metadata ytd-menu-renderer segmented-like-dislike-button-view-model"; + LIKE_SELECTOR = "like-button-view-model button"; + DISLIKE_SELECTOR = "dislike-button-view-model button"; + LIVE_SELECTOR = ".ytp-live-badge[disabled='']"; + + isVideoRated(like, dislike) { + return like.attributes["aria-pressed"].nodeValue === "true" || + dislike.attributes["aria-pressed"].nodeValue === "true"; + } + + /* + * Another tough one + * @return {Boolean} True if the user is subscribed to + * the current video's channel + */ + isUserSubscribed() { + let subscribeButtons = document.querySelectorAll("ytd-subscribe-button-renderer :not(*[hidden]) button.yt-spec-button-shape-next--tonal") + // the ':not(*[hidden]) ytd-subscribe-button-renderer :not(*[hidden]) button.yt-spec-button-shape-next--tonal' + // does not work, thus use isHidden + let buttonExist = subscribeButtons.length > 0 + log("sub button exist: ", buttonExist) + if (!buttonExist) return false + + let subscribeButton = Array.from(subscribeButtons).find(isNotHidden) + log("sub button not hidden: ", subscribeButton) + return subscribeButton !== undefined; + } +} diff --git a/app/scripts/modules/liker-paper.js b/app/scripts/modules/liker-paper.js index 430ba68..3ef0ea1 100644 --- a/app/scripts/modules/liker-paper.js +++ b/app/scripts/modules/liker-paper.js @@ -2,302 +2,17 @@ * Likes YouTube videos. * For the newer paper design layout */ -class PaperLiker { - /* - * @constructor - * @param {OptionManager} options Object that must have the option - * 'like_what', indicating whether to like all videos or just - * subscribed. - */ - constructor(options) { - this.options = options; - this.icon = {} - this.btns = {} - } - - async update_options() { - this.options = await optionManager.get(); - log("options updated"); - return; - } - - /** - * Reset the attributes - */ - reset() { - this.icon = {} - this.btns = {} - } - - getActionsElements() { - if (document.getElementById("menu-container")?.offsetParent === undefined) { - log("No visible ActionsElements found.") - return - } - - let elem = null; - if (document.getElementById("menu-container")?.offsetParent === null) { - elem = document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div"); - } else { - elem = document.getElementById("menu-container").querySelector("#top-level-buttons-computed"); - } - - // if null or undefined - if (elem == null) { - log("No visible ActionsElements found.") - return - } else { - log("ActionsElements found.") - return elem - } - - } - - /** - * Search the svg that has .style-scope.yt-icon (which is the svg used in yt-app) - * @param {string} id The id of the svg to query - */ - getUsedSVG(id) { - var likeSvgRawList = document.querySelectorAll(`g#${id} path`); - - let svgs = null; - let p = null; - for (let item of likeSvgRawList) { - p = item.getAttribute("d"); - svgs = document.querySelectorAll(`path[d="${p}"]`); - for (let i of svgs) { - if (i.matches(".style-scope.yt-icon")) return p; - } - } - log("No active svg found."); - return null; - } - - getUsedLikeSVG() { - return this.getUsedSVG("like"); - } - - getUsedDislikeSVG() { - return this.getUsedSVG("dislike"); - } - - getUsedLikeFilledSVG() { - return this.getUsedSVG("like-filled"); - } - - getUsedDislikeFilledSVG() { - return this.getUsedSVG("dislike-filled"); - } - - getLikeDislikeElements() { - let likeElement, dislikeElement; - let actionsElements = this.getActionsElements(); - - likeElement = actionsElements.querySelector("#segmented-like-button button"); - dislikeElement = actionsElements.querySelector("#segmented-dislike-button button"); - - // update youtube paper layout 30/11/2023 - if (likeElement === null) { - likeElement = actionsElements.querySelector(".YtLikeButtonViewModelHost button"); - } - if (dislikeElement === null) { - dislikeElement = actionsElements.querySelector(".YtDislikeButtonViewModelHost button"); - } - - return [likeElement, dislikeElement]; - } - - getButtons() { - let [likeElement, dislikeElement] = this.getLikeDislikeElements(); - if (likeElement === null || dislikeElement === null) { - log("Cannot find buttons"); - } - log("got buttons"); - return [likeElement, dislikeElement]; - } - - updateButtons() { - [this.btns.like, this.btns.dislike] = this.getButtons(); - - } - - isNewLayout() { - return this.getUsedLikeFilledSVG() === null; - } - - isLive() { - var liveBadge = document.querySelector('.ytp-live-badge'); - return liveBadge && !liveBadge.getAttribute('disabled'); - } - - /** - * Detects when like/dislike buttons have loaded (so we can press them) - * and register element in the attributes - * @param {function} callback The function to execute after the buttons - * have loaded - */ - waitForButtons(callback) { - // wait button box load - let box = this.getActionsElements(); - - if (!box) { - log("wait 1s for box"); - setTimeout(() => this.waitForButtons(callback), 1000 ); - } else { - this.updateButtons(); - callback(); - } - - } - - /** - * Search video across all dom each time, to prevent modification (see #59) - * A mutation observer could be done, but may be overkill - */ - video() { - return document.querySelectorAll(".video-stream")[0]; - } +class PaperLiker extends MetaLiker { - /** - * Detects when the video player has loaded - * @param {function} callback The function to execute once the video has - * loaded. - */ - waitForVideo(callback) { - if (this.video()) { - log("Get Video.") - if (this.isLive()) { - log("Video is live"); - this.liveStartedAt = this.video().currentTime; - log("Start watching live at", this.liveStartedAt); - } - callback(); - } else { - setTimeout(() => this.waitForVideo(callback), 1000); - } - } - - /** - * Return a random integer in a given range - * @param {number} min An integer representing the start of the range - * @param {number} max An integer representing the end of the range - * @return {number} The random integer selected in the range - */ - randomIntFromInterval(min, max) { // min and max included - return Math.floor(Math.random() * (max - min + 1) + min); - } - - /** - * Wait the number of minutes or % specified by user in the plugin option - * @param {function} callback The function to execute at the end of - * the timer - */ - waitTimer(callback) { - // if Instant like, direct return to like - if (this.options.like_timer == "instant") { - log("waitTimer: instant") - callback(); - return; - } - else if (this.video().closest(".ad-showing,.ad-interrupting") !== null) { - log("waitTimer: ad") - setTimeout(() => this.waitTimer(callback), 1000 ); - } - else if (this.options.like_timer == "random") { - let duration = this.video().duration; - - let nowInPercent = this.video().currentTime / duration * 100; - - if (nowInPercent >= this.randomTimerPercent) { - callback(); - } else { - setTimeout(() => this.waitTimer(callback), 1000 ); - } - } - else { - let duration = this.video().duration; - - if (this.options.percentage_timer && !this.isLive()) { - log("waitTimer: percent") - let percentageAtLike = this.options.percentage_value; - let nowInPercent = this.video().currentTime / duration * 100; - log(nowInPercent, percentageAtLike) - - if (nowInPercent >= percentageAtLike) { - callback(); - return; - } - } - - let currentT = this.isLive() ? (this.video().currentTime - this.liveStartedAt) : this.video().currentTime; - if (this.options.minute_timer) { - log("waitTimer: minute") - let timeAtLike = this.options.minute_value * 60; - // change timeAtLike if vid shorter than time set by user - log(currentT, duration, timeAtLike) - if (duration < timeAtLike) { - timeAtLike = duration; - } - if (currentT >= timeAtLike) { - callback(); - return; - } - } - - // if both are disable event if custom timer is set - if (!this.options.minute_timer && !this.options.percentage_timer) { - // instant like - callback(); - return; - } + VIDEO_SELECTOR = ".video-stream"; + ACTION_ELEMENTS_SELECTOR = "ytd-menu-renderer.ytd-watch-metadata segmented-like-dislike-button-view-model"; + LIKE_SELECTOR = "like-button-view-model button"; + DISLIKE_SELECTOR = "dislike-button-view-model button"; + LIVE_SELECTOR = ".ytp-live-badge[disabled='']"; - setTimeout(() => this.waitTimer(callback), 1000 ); - } - } - - /** - * Wait the video time indicator is greater the timer - * @param {int} timer The time in second to wait - * @param {function} callback The function to execute when timer is over - */ - waitTimerTwo(timer, callback) { - if (this.video().currentTime >= timer) { - callback(); - return; - } - setTimeout(() => this.waitTimerTwo(timer, callback), 1000); - } - - /** - * Check timer not greater than video length and wait the video - * time indicator to be greater than the seconds requested - * @param {int} timer The time in second to wait - * @param {function} callback The function to execute when timer is over - */ - startTimer(timer, callback) { - let duration = this.video().duration; - // change timer if vid shorter than time requested - if (duration < timer) { - timer = duration; - } - this.waitTimerTwo(timer, callback) - - } - - /** - * Take a wild guess - * @return {Boolean} True if the like or dislike button is active - */ - isVideoRated() { - log("checking if video is rated"); - if (IS_CLASSIC) { - let isRated = this.btns.like.attributes["aria-pressed"].nodeValue === "true" || - this.btns.dislike.attributes["aria-pressed"].nodeValue === "true"; - log("is rated: ", isRated); - return isRated; - } else { - throw "Unknow youtube type"; - } + isVideoRated(like, dislike) { + return like.attributes["aria-pressed"].nodeValue === "true" || + dislike.attributes["aria-pressed"].nodeValue === "true"; } /* @@ -316,171 +31,5 @@ class PaperLiker { let subscribeButton = Array.from(subscribeButtons).find(isNotHidden) log("sub button not hidden: ", subscribeButton) return subscribeButton !== undefined; - - } - - shouldLike() { - this.updateButtons(); - let rated = this.isVideoRated(); - if (rated) { - log("Not like: already liked video"); - return false; - } - - let mode_should_like = false; - if (this.options.like_what === "subscribed") { - log("Sub mode"); - mode_should_like = this.isUserSubscribed(); - } else { // it all mode - log("All mode"); - mode_should_like = true; - } - - log("Use list:", this.options.use_list); - if (this.options.use_list) { - let list_should_like = ""; - let creator = getCreatorFromVideo(); - let creator_list = this.options.creator_list; - let in_list = false; - for (var i = 0; i < creator_list.length; i++) { - if ( creator_list[i].URL === creator.URL ) { - log("Creator is in list"); - in_list = true; - break; - } - } - - if (this.options.type_list === "white") { - log("List is in white mode") - list_should_like = in_list; - // in white list only the list matter - let should_like = list_should_like; - log(`Should like: ${should_like}`); - return should_like; - } else if (this.options.type_list === "black") { - log("List is in black mode") - list_should_like = !in_list; - - let should_like = list_should_like && mode_should_like; - log(`Should like: ${should_like}`); - return should_like; - } else { - console.error("Unknow list type for liker") - } - } else { - log(`Should like: ${mode_should_like}`) - return mode_should_like; - } - } - - /* - * Clickity click the button - */ - attemptLike() { - this.btns.like.click(); - } - - /* - * Clickity click the skip button - */ -/* attemptSkip() { - this.btns.skip.click(); - }*/ - - /** - * Prevent multiple run if the listen event is triggered multiples times - */ - blockMultipleRun() { - //if not defined this is the 1st run - if (!this.hasOwnProperty("IS_STARTED")) { - this.IS_STARTED = true; - log("blockMultipleRun: allow") - return false; - } else { - if (this.IS_STARTED) { - log("blockMultipleRun: blocked"); - return true - } else { //could be a new video in playlist - this.IS_STARTED = true; - log("blockMultipleRun: allow, next video in playlist") - return false; - } - } - } - - /** - * Free the block to reset the multipleRun - */ - finish() { - this.IS_STARTED = false; - } - - /** - * Starts the liking. - * The liker won't do anything unless this method is called. - */ - async init() { - if (this.options.like_what === "none") { - log("yt-autolike disabled") - return; - } - - function isVideo() { - return window.location.href.indexOf("watch") > -1 - } - if (!isVideo()) { - log("not a video"); - return; - } - - if (this.blockMultipleRun()) { - return; - } - this.reset() - log('yt-autolike start') - // this.skipAd(() => { - // if(this.isAdPlaying) { - // document.getElementsByClassName('videoAdUiSkipButton')[0].click; - // } - // }); - await this.update_options(); - this.waitForVideo(() => { - this.waitForButtons(() => { - /* - If the video is already liked/disliked - or the user isn't subscribed to this channel, - then we don't need to do anything. - */ - if ( !this.shouldLike() ) { - log("not liked check 1"); - this.finish(); - return; - } - /* - Else do the stuff - */ - // Define a random timer if selected - if (this.options.like_timer == "random") { - this.randomTimerPercent = this.randomIntFromInterval(0, 99); - } - - this.waitTimer(() => { - /* - Maybe the use did an action while we was waiting, so check again - */ - if ( !this.shouldLike() ) { - log("not liked check 2"); - this.finish(); - return; - } - this.attemptLike(); - log('liked'); - this.options.counter += 1; - optionManager.set(this.options).then(() => { - this.finish(); - }); - }); - }); - }); } } diff --git a/app/scripts/modules/liker-material.js b/app/scripts/modules/metaliker.js similarity index 61% rename from app/scripts/modules/liker-material.js rename to app/scripts/modules/metaliker.js index e675d14..9145006 100644 --- a/app/scripts/modules/liker-material.js +++ b/app/scripts/modules/metaliker.js @@ -1,8 +1,8 @@ /* * Likes YouTube videos. - * For the newer material design layout + * For the newer paper design layout */ -class MaterialLiker { +class MetaLiker { /* * @constructor * @param {OptionManager} options Object that must have the option @@ -11,15 +11,6 @@ class MaterialLiker { */ constructor(options) { this.options = options; - /* - Youtube gaming hasn't the svg path in code like youtube - */ - this.iconSvgData = { - like: 'M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-1.91l-.01-.01L23 10z', - dislike: 'M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v1.91l.01.01L1 14c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z' - }; - this.icon = {} - this.btns = {} } async update_options() { @@ -28,120 +19,76 @@ class MaterialLiker { return; } + VIDEO_SELECTOR = null; + ACTION_ELEMENTS_SELECTOR = null; + LIKE_SELECTOR = null; + DISLIKE_SELECTOR = null; + LIVE_SELECTOR = null; + /** - * Reset the attributes + * Search video across all dom each time, to prevent modification (see #59) + * A mutation observer could be done, but may be overkill + * @Return: the video element */ - reset() { - this.icon = {} - this.btns = {} + video() { + if (this.VIDEO_SELECTOR === null) { + NotImplementedError(); + } + return document.querySelector(this.VIDEO_SELECTOR); } getActionsElements() { - if (document.getElementById("menu-container")?.offsetParent === undefined) { - log("No visible ActionsElements found.") - return + if (this.ACTION_ELEMENTS_SELECTOR === null) { + NotImplementedError(); } - - let elem = null; - if (document.getElementById("menu-container")?.offsetParent === null) { - elem = document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div"); - } else { - elem = document.getElementById("menu-container").querySelector("#top-level-buttons-computed"); - } - - // if null or undefined - if (elem == null) { - log("No visible ActionsElements found.") - return - } else { - log("ActionsElements found.") - return elem - } - + return document.querySelector(this.ACTION_ELEMENTS_SELECTOR); } /** - * Search the svg that has .style-scope.yt-icon (which is the svg used in yt-app) - * @param {string} id The id of the svg to query + * @param {block} actionsElements The actionElements block containing like and dislike buttons + * @return {array} [likeElement, dislikeElement] The two clickable buttons */ - getUsedSVG(id) { - var likeSvgRawList = document.querySelectorAll(`g#${id} path`); - - let svgs = null; - let p = null; - for (let item of likeSvgRawList) { - p = item.getAttribute("d"); - svgs = document.querySelectorAll(`path[d="${p}"]`); - for (let i of svgs) { - if (i.matches(".style-scope.yt-icon")) return p; - } - } - log("No active svg found."); - return null; - } - - getUsedLikeSVG() { - return this.getUsedSVG("like"); - } - - getUsedDislikeSVG() { - return this.getUsedSVG("dislike"); - } - - getUsedLikeFilledSVG() { - return this.getUsedSVG("like-filled"); - } - - getUsedDislikeFilledSVG() { - return this.getUsedSVG("dislike-filled"); - } - - getLikeDislikeElements(likePath, dislikePath) { + getLikeDislikeElements(actionsElements) { let likeElement, dislikeElement; - let actionsElements = this.getActionsElements(); + + if (this.LIKE_SELECTOR === null || this.DISLIKE_SELECTOR === null) { + NotImplementedError + } - likeElement = actionsElements.querySelector(`g.yt-icon path[d="${likePath}"], g.iron-icon path[d="${likePath}"]`); - dislikeElement = actionsElements.querySelector(`g.yt-icon path[d="${dislikePath}"], g.iron-icon path[d="${dislikePath}"]`); + likeElement = actionsElements.querySelector(this.LIKE_SELECTOR); + dislikeElement = actionsElements.querySelector(this.DISLIKE_SELECTOR); return [likeElement, dislikeElement]; } - getButtons() { - let _; - let [likeElement, dislikeElement] = this.getLikeDislikeElements(this.getUsedLikeSVG(), this.getUsedDislikeSVG()); - - // if a button is not found, maybe it is due to svg-filled (and the video is liked) - if (likeElement === null) { - [likeElement, _] = this.getLikeDislikeElements(this.getUsedLikeFilledSVG(), this.getUsedDislikeSVG()); - } - if (dislikeElement === null) { - [_, dislikeElement] = this.getLikeDislikeElements(this.getUsedLikeSVG(), this.getUsedDislikeFilledSVG()) - } - - // Make sure both icons exist - if (likeElement && dislikeElement) { - // Find and store closest buttons - log("got buttons"); - let btnLike = likeElement - .closest('yt-icon-button, paper-icon-button'); - let btnDislike = dislikeElement - .closest('yt-icon-button, paper-icon-button'); - - return [btnLike, btnDislike]; - ; - } else { - log ("did not get buttons"); - return [null, null]; + isLive() { + if (this.LIVE_SELECTOR === null) { + NotImplementedError(); } + return document.querySelector(this.LIVE_SELECTOR); } - updateButtons() { - [this.btns.like, this.btns.dislike] = this.getButtons(); + isVideoRated(like, dislike) { + NotImplementedError(); + } + /* + * Another tough one + * @return {Boolean} True if the user is subscribed to + * the current video's channel + */ + isUserSubscribed() { + NotImplementedError(); } - isNewLayout() { - return this.getUsedLikeFilledSVG() === null; + getButtons() { + let box = this.getActionsElements(); + let [likeElement, dislikeElement] = this.getLikeDislikeElements(box); + if (likeElement === null || dislikeElement === null) { + log("Cannot find buttons"); + } + log("got buttons"); + return [likeElement, dislikeElement]; } /** @@ -158,18 +105,8 @@ class MaterialLiker { log("wait 1s for box"); setTimeout(() => this.waitForButtons(callback), 1000 ); } else { - this.updateButtons(); callback(); } - - } - - /** - * Search video across all dom each time, to prevent modification (see #59) - * A mutation observer could be done, but may be overkill - */ - video() { - return document.querySelectorAll(".video-stream")[0]; } /** @@ -180,6 +117,11 @@ class MaterialLiker { waitForVideo(callback) { if (this.video()) { log("Get Video.") + if (this.isLive()) { + log("Video is live"); + this.liveStartedAt = this.video().currentTime; + log("Start watching live at", this.liveStartedAt); + } callback(); } else { setTimeout(() => this.waitForVideo(callback), 1000); @@ -226,7 +168,7 @@ class MaterialLiker { else { let duration = this.video().duration; - if (this.options.percentage_timer) { + if (this.options.percentage_timer && !this.isLive()) { log("waitTimer: percent") let percentageAtLike = this.options.percentage_value; let nowInPercent = this.video().currentTime / duration * 100; @@ -238,18 +180,16 @@ class MaterialLiker { } } + let currentT = this.isLive() ? (this.video().currentTime - this.liveStartedAt) : this.video().currentTime; if (this.options.minute_timer) { log("waitTimer: minute") - let timeAtLike = this.options.minute_value; + let timeAtLike = this.options.minute_value * 60; // change timeAtLike if vid shorter than time set by user - log(this.video().currentTime, this.video().duration, timeAtLike) - if (this.video().duration < timeAtLike) { - timeAtLike = this.video().duration; - } else { - // convert in second - timeAtLike *= 60; + log(currentT, duration, timeAtLike) + if (duration < timeAtLike) { + timeAtLike = duration; } - if (this.video().currentTime >= timeAtLike) { + if (currentT >= timeAtLike) { callback(); return; } @@ -299,50 +239,23 @@ class MaterialLiker { * Take a wild guess * @return {Boolean} True if the like or dislike button is active */ - isVideoRated() { + isVideoRatedMeta() { log("checking if video is rated"); - if (IS_CLASSIC) { - return this.btns.like.parentNode.parentNode.classList - .contains("style-default-active") || - this.btns.dislike.parentNode.parentNode.classList - .contains("style-default-active"); - - } else if (IS_GAMING) { - return this.btns.like.classList.contains("active") || - this.btns.dislike.classList.contains("active"); - } else { - throw "Unknow youtube type"; - } + let [like, dislike] = this.getButtons(); + log([like, dislike]); + let isRated = this.isVideoRated(like, dislike); + log("is rated: ", isRated); + return isRated; } - /* - * Another tough one - * @return {Boolean} True if the user is subscribed to - * the current video's channel - */ - isUserSubscribed() { - let subscribeButton = document.querySelector( - 'ytd-subscribe-button-renderer > paper-button, ytg-subscribe-button > paper-button, ytd-subscribe-button-renderer > .ytd-subscribe-button-renderer' - ); - // if new youtube 06/2022 - if (subscribeButton.hasAttribute("hidden")) { - subscribeButton = document.querySelector( - 'ytd-subscribe-button-renderer > tp-yt-paper-button.ytd-subscribe-button-renderer' - ) - } - return subscribeButton && (subscribeButton.hasAttribute('subscribed') || - subscribeButton.getAttribute("aria-pressed") === "true"); - } - shouldLike() { - this.updateButtons(); - let rated = this.isVideoRated(); + let rated = this.isVideoRatedMeta(); if (rated) { log("Not like: already liked video"); return false; } - let mode_should_like = ""; + let mode_should_like = false; if (this.options.like_what === "subscribed") { log("Sub mode"); mode_should_like = this.isUserSubscribed(); @@ -392,16 +305,9 @@ class MaterialLiker { * Clickity click the button */ attemptLike() { - this.btns.like.click(); + this.getButtons()[0].click(); } - /* - * Clickity click the skip button - */ -/* attemptSkip() { - this.btns.skip.click(); - }*/ - /** * Prevent multiple run if the listen event is triggered multiples times */ @@ -451,7 +357,6 @@ class MaterialLiker { if (this.blockMultipleRun()) { return; } - this.reset() log('yt-autolike start') // this.skipAd(() => { // if(this.isAdPlaying) { diff --git a/app/scripts/modules/miscellaneous.js b/app/scripts/modules/miscellaneous.js index 58ce9e3..289c73c 100644 --- a/app/scripts/modules/miscellaneous.js +++ b/app/scripts/modules/miscellaneous.js @@ -108,4 +108,28 @@ function isHidden(node) { function isNotHidden(node){ return !isHidden(node); -} \ No newline at end of file +} + +/** + * @summary A error thrown when a method is defined but not implemented (yet). + * @param {any} message An additional message for the error. + */ +function NotImplementedError(message) { + /// The error thrown when the given function isn't implemented. + const sender = (new Error()) + .stack + .split('\n')[2] + .replace(' at ', ''); + this.message = `The method ${sender} isn't implemented.`; + + // Append the message if given. + if (message) { this.message += ` Message: "${message}".`; } + + let str = this.message; + + while (str.indexOf(' ') > -1) { + str = str.replace(' ', ' '); + } + + this.message = str; +}; From 4048ecd060b49c86bb9348d43e45dffecdb9fd83 Mon Sep 17 00:00:00 2001 From: Pg Date: Mon, 29 Jul 2024 23:17:58 +0200 Subject: [PATCH 2/2] 4.0.0 --- app/manifest.json | 2 +- app/scripts/modules/miscellaneous.js | 4 ++-- app/update_info.html | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/manifest.json b/app/manifest.json index 44b95f3..2f61a4d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,6 +1,6 @@ { "name": "__MSG_appName__", - "version": "3.9.1", + "version": "4.0.0", "manifest_version": 2, "description": "__MSG_appDesc__", "icons": { diff --git a/app/scripts/modules/miscellaneous.js b/app/scripts/modules/miscellaneous.js index 289c73c..51963ae 100644 --- a/app/scripts/modules/miscellaneous.js +++ b/app/scripts/modules/miscellaneous.js @@ -106,7 +106,7 @@ function isHidden(node) { } } -function isNotHidden(node){ +function isNotHidden(node) { return !isHidden(node); } @@ -132,4 +132,4 @@ function NotImplementedError(message) { } this.message = str; -}; +} diff --git a/app/update_info.html b/app/update_info.html index eec72b9..89800de 100644 --- a/app/update_info.html +++ b/app/update_info.html @@ -14,10 +14,7 @@

YouTube Auto Like

You can opt out of notification update from option menu !

What's new :

-

Feel free to report any bug on Github.