o2dazone / StravaKudos

Auto-kudos activities
20 stars 12 forks source link

Kudos to skip virtual activities #24

Open calcium opened 3 years ago

calcium commented 3 years ago

Hello, Is this feature possible? Was just wondering. :-)

o2dazone commented 3 years ago

the UI does expose a icon-virtualride class for virtual activities, so technically it would be possible to not include virtual activities in auto-kudos'ing. I think the more difficult part of implementing this would be offering the ability to choose, and store it in the extension itself. Perhaps a checkbox that saves your decision to Kudos virtual activities, this may require more browser permissions in the extension.

The reality is, I haven't used Strava in over a year, so my drive to implement it is pretty low 😬. I am happy to review and accept pull requests if you're willing to code it though :) Alternatively, if you use Violentmonkey or Tampermonkey , or any Chrome extension that allows dynamic injection of Javascript, I'm happy to whip up a modified version of this extension to only Kudos non virtual activities. This would prevent you from having to use my extension, and can just depend on the script instead.

o2dazone commented 3 years ago

Hey @calcium,

Here is a modified version of the script taken directly from the repo This should filter out any virtual activities, although it's not thoroughly tested.

// ==UserScript==
// @name        StravaKudos modified
// @namespace   Violentmonkey Scripts
// @match       https://www.strava.com/*
// @grant       none
// @version     1.0
// @author      -
// @description 7/30/2021, 2:57:49 PM
// ==/UserScript==
(function() {
  let kudosBtns = []
    , KUDOS_INTERVAL = 1000 // in milliseconds
    , KUDOS_LOCKOUT = 100 // https://github.com/o2dazone/StravaKudos/issues/13#issuecomment-356319221
    , btn
    , viewingAthleteId
    , els = '[data-testid=\'unfilled_kudos\']';

  const init =() => {
    const styles = document.createElement('style');
    styles.innerHTML = `
      #stravaKudos {
        display: flex;
        flex-direction: column;
        left: 5px;
        font-size: 20px;
        box-shadow: 0 2px 1px rgba(0, 0, 0, 0.2);
        z-index: 49;
        position: fixed;
        top: 61px
      }

      #stravaKudos div {
        margin: 0 auto
      }

      #stravaKudos p {
        margin: 0;
        font-size: 14px
      }

      #stravaKudos.hidden,
      #stravaKudos.lockout p {
        display: none !important;
        visibility: hidden !important
      }

      #stravaKudosCount {
        margin: 0 3px;
        font-weight: bold
      }
    `;
    document.head.prepend(styles);

    btn = document.createElement('button');
    btn.id = 'stravaKudos';
    btn.innerHTML = `
      <div>Give <span id="skCount"></span> Kudos</div>
      <p>Strava may throttle too<br/>many Kudos in one session</p>
    `;
    btn.className = 'btn btn-sm btn-primary hidden';

    btn.addEventListener('click', giveKudos);
    document.body.prepend(btn);
    updateCountNum();
  };
  /* eslint-disable-next-line */
  const mockFillKudo = btn => {
    btn.setAttribute('fill','#FC5200');
    btn.dataset.testid = 'filled_kudos';
  };

  // give ALL the kudos
  const giveKudos = () => {
    setTimeout(() => {
      const kudoBtn = getEligibleKudoButtons()?.[0];
      if(kudoBtn) {
        // mockFillKudo(kudoBtn); /* for testing purposes only */
        kudoBtn.parentNode.click();
        giveKudos();
      }
    }, KUDOS_INTERVAL);
  };

  // toggle box styles
  const toggleKudosBox = () => {
    const num = kudosBtns.length;
    if (num) {
      btn.classList.remove('hidden');

      if (num < KUDOS_LOCKOUT) {
        btn.classList.add('lockout');
      } else {
        btn.classList.remove('lockout');
      }
    } else {
      btn.classList.add('hidden');
    }
  };

  const getEligibleKudoButtons = () => {
    const activityAvatars = document.querySelectorAll('[data-testid="owner-avatar"]');
    const buttons = [];

    activityAvatars.forEach(avatar => {
      // activity card is not your own
      if (!avatar.href.includes(viewingAthleteId)) {
        const activityCard = avatar.closest('[class*="--child-entry"]') /* group activity */ ||
                             avatar.closest('[data-testid="web-feed-entry"]') /* solo activity */;

        const cardProps = activityCard.parentNode.dataset.reactProps;

        let isVirtual = false;
        if (cardProps) {
          const parsedCardProps = JSON.parse(cardProps);
          isVirtual = parsedCardProps.activity.isVirtual;
        }

        !isVirtual && activityCard.querySelector(els) && buttons.push(activityCard.querySelector(els));
      }
    });

    return buttons;
  };

  // publish number of kudos
  const updateCountNum = () => {
    const count = document.getElementById('skCount');
    viewingAthleteId = document.querySelector('.user-menu > a')?.href?.match(/\d+/)?.[0]; // store viewing athlete id

    if (count) {
      setInterval(() => {
        kudosBtns = getEligibleKudoButtons();
        count.innerHTML = kudosBtns.length;
        toggleKudosBox();
      }, KUDOS_INTERVAL);
    }
  };

  init();
}());

Here is a diff of just the things I've changed

-        activityCard.querySelector(els) && buttons.push(activityCard.querySelector(els));
+        const cardProps = activityCard.parentNode.dataset.reactProps;
+
+        let isVirtual = false;
+        if (cardProps) {
+          const parsedCardProps = JSON.parse(cardProps);
+          isVirtual = parsedCardProps.activity.isVirtual;
+        }
+
+        !isVirtual && activityCard.querySelector(els) && buttons.push(activityCard.querySelector(els));

You can sideload this with the chrome extensions I mentioned above - this would replace the existing StravaKudos extension, so you can disable/remove that extension from your browser.

Let me know if this doesn't work.