Search code examples
javascriptgoogle-chrome-extensionchrome-extension-manifest-v3

JavaScript can't count element inside a div element


I am working on a Chrome extension, which can sort the videos of a website. For example, I search for a word `stackoverflow' and many videos appear there, but these videos do not have the number of comments displayed in the search result, you have to open this video and get the number of comments. And this is my problem, I actually managed to do something similar, I can get the number of comments but it's not working properly

[UPDATED CODE]

function waitForElm(selector) {
        return new Promise((resolve) => {
          if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
          }
      
          const observer = new MutationObserver((mutations) => {
            if (document.querySelector(selector)) {
              resolve(document.querySelector(selector));
              observer.disconnect();
            }
          });
      
          observer.observe(document.body, {
            childList: true,
            subtree: true,
          });
        });
      }
      
      function simulateMouseClick(element) {
        // Send mouseover, mousedown, mouseup, click, mouseout
        const eventNames = [
          'mouseover',
          'mouseenter',
          'mousedown',
          'mouseup',
          'click',
          'mouseout',
        ];
        eventNames.forEach((eventName) => {
          const detail = eventName === 'mouseover' ? 0 : 1;
          const event = new MouseEvent(eventName, {
            detail: detail,
            view: window,
            bubbles: true,
            cancelable: true,
          });
          element.dispatchEvent(event);
        });
      }
      
      const openAndPrintVideoContent = async (videoTriggerElement) => {
        try {
          simulateMouseClick(videoTriggerElement);
      
          const commentCountElement = await waitForElm('[data-e2e="browse-comment-count"]');
          console.log("Comment Element Count:" +commentCountElement.textContent)
          const browserCloseElement = await waitForElm('[data-e2e="browse-close"]');
      
          simulateMouseClick(browserCloseElement);
      
          return commentCountElement.textContent;
        } catch (error) {
          console.log('ERROR: '+error);
          return 0;
        }
      };
      
      const getVideoList = async () => {
        const videos = document.querySelectorAll(".tiktok-18e9va3-DivContainer");
        // console.log(videos)
        return videos;
      };
      
      const hydrateVideoList = async () => {
        const videos = await getVideoList();
        const resources = [];
      
        for (const video of videos) {
          const videoInformation = await openAndPrintVideoContent(video);
          resources.push(videoInformation);
        }
      
        return resources;
      };
      
      hydrateVideoList().then((videoComments) => {
        console.log('Video Comments:', videoComments);
      });

This code returns the number of comments, but it also changes the URL in Chrome, and then takes me away from the page where I'm sorting, is there any other way I can do what I'm looking for?


Solution

  • yes the code is working you can customized it to your needs

    remove console logs and the wrapping functions if you want and add a scroll down function to load +100 videos and apply sorting

    (function () {
      class Video {
        link;
        title;
        comments;
        element;
        constructor(link, title, comments, element) {
          this.link = link;
          this.title = title;
          this.comments = comments;
          this.element = element;
        }
      }
    
      function waitForElm(selector) {
        return new Promise((resolve) => {
          if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
          }
    
          const observer = new MutationObserver((mutations) => {
            if (document.querySelector(selector)) {
              resolve(document.querySelector(selector));
              observer.disconnect();
            }
          });
    
          observer.observe(document.body, {
            childList: true,
            subtree: true,
          });
        });
      }
    
      function simulateMouseClick(element) {
        // Send mouseover, mousedown, mouseup, click, mouseout
        const eventNames = [
          "mouseover",
          "mouseenter",
          "mousedown",
          "mouseup",
          "click",
          "mouseout",
        ];
        eventNames.forEach((eventName) => {
          const detail = eventName === "mouseover" ? 0 : 1;
          const event = new MouseEvent(eventName, {
            detail: detail,
            view: window,
            bubbles: true,
            cancelable: true,
          });
          element.dispatchEvent(event);
        });
      }
    
      const getVideoInformations = async (videoTriggerElement) => {
        try {
          console.log("getVideoInformations");
          console.log(videoTriggerElement);
    
          simulateMouseClick(
            videoTriggerElement.querySelector('a')
          );
          console.log("getVideoInformations");
          console.log(videoTriggerElement);
    
          const commentCountElement = await waitForElm(
            '[data-e2e="browse-comment-count"]'
          );
    
          const descElement = await waitForElm('[data-e2e="browse-video-desc"]');
    
          const linkElement = await waitForElm('[data-e2e="browse-video-link"]');
          const video = new Video(
            linkElement.textContent,
            descElement.children[0].textContent,
            commentCountElement.textContent,
            videoTriggerElement
          );
    
          // const browserCloseElement = await waitForElm('[data-e2e="browse-close"]');
    
          //simulateMouseClick(browserCloseElement);
          history.back();
    
          // wait to go back to the video list
          await waitForElm('[data-e2e="search_top-item-list"]');
    
          return video;
        } catch (error) {
          console.log("ERROR: " + error);
          return;
        }
      };
    
      const getVideoElementList = async () => {
        const videos = document.querySelectorAll(
          ".tiktok-1soki6-DivItemContainerForSearch"
        );
        console.log("getVideoElementList");
        console.log(videos);
        return videos;
      };
    
      const hydrateVideoElementList = async (videos) => {
        const resources = [];
    
        for (const video of videos) {
          if (video) {
            const videoInformation = await getVideoInformations(video);
            resources.push(videoInformation);
          }
        }
    
        return resources;
      };
      const showSortingElements = (resources) => {
        for (const resource of resources) {
          resource.element.setAttribute("data-order", resource.comments);
        }
    
        SortData();
      };
    
      function comparator(a, b) {
        if (a.dataset.order < b.dataset.order) return -1;
        if (a.dataset.order > b.dataset.order) return 1;
        return 0;
      }
    
      // Function to sort Data
      function SortData() {
        var subjects = document.querySelectorAll("[data-order]");
        var subjectsArray = Array.from(subjects);
        let sorted = subjectsArray.sort(comparator);
        sorted.forEach((e) =>
          document.querySelector('[data-e2e="search_top-item-list"]').appendChild(e)
        );
      }
    
      (async () => {
        const videos = await getVideoElementList();
    
        const resources = await hydrateVideoElementList(videos);
    
        // sorting array of object by property
        resources.sort((a, b) => (a.comments > b.comments ? 1 : -1));
        console.log(resources);
    
        showSortingElements(resources);
      })();
    })();
    

    screenshots

    original videos

    original videos

    Ordred videos

    Ordred videos