// ==UserScript==
// @name Instagram - visible images counter
// @namespace darkred
// @version 2024.2.23
// @description Shows in instagram profile pages how many images out of total (as a number and as a percentage) are currently visible, as you scroll down the page.
// @author darkred
// @license MIT
// @include https://www.instagram.com/*
// @grant none
// @require https://code.jquery.com/jquery-3.2.1.min.js
// @require https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js
// @supportURL https://github.com/darkred/Userscripts/issues
// ==/UserScript==
/* eslint-disable no-console */
const escapeHTMLPolicy = (({ trustedTypes }, policy) =>
trustedTypes
? trustedTypes.createPolicy('myEscapePolicy', policy)
: policy)(window, {
createHTML: (str) => str,
});
var stylesheet =
`<style>
.counter {
color: #D9D9D9 !important;
}
</style>`;
$('head').append(stylesheet);
// Not needed anymore
/*
// If you scroll down, beyond the first 12 images, then the "LOAD MORE" button(to show more images) will be automatically clicked
$(window).scroll(function() {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
var element = $(`a:contains('Load more')`)[0];
element.click();
}
});
*/
var hrefselems = [];
var hrefs = [];
var total;
function showCounter() {
// var totalString = $(`span:contains('posts'):last-child > span, .g47SY`).html(); // The 'total' value (it's a string). The ".g47SY" selector is for localized pages, e.g. https://www.instagram.com/instagram/?hl=de
// var totalString = document.querySelector(`#react-root > section > main > div > header > section > ul > li:nth-child(1) > * > span`).textContent; // The 'total' value (it's a string). The ".g47SY" selector is for localized pages, e.g. https://www.instagram.com/instagram/?hl=de
var totalString = document.querySelector(`[id^=mount_0_0_] section > main > div > header > section > ul > li:nth-child(1) > * > span`).textContent; // The 'total' value (it's a string). The ".g47SY" selector is for localized pages, e.g. https://www.instagram.com/instagram/?hl=de
total = totalString.replace(',', '').replace('.', ''); // strip the thousand comma/dot seperator
// hrefselems = document.querySelectorAll(`a[href*='taken-by']`);
// hrefselems = document.querySelectorAll(`._aabd._aa8k._aanf > a`);
// hrefselems = document.querySelectorAll(`._aabd._aa8k._al3l > a`);
hrefselems = document.querySelectorAll(`._aabd._aa8k.x2pgyrj > a`);
$.each(hrefselems, function(index, value) {
// hrefs.indexOf(String(value)) === -1 ? hrefs.push(String(value)) : console.log("This item already exists"); // https://stackoverflow.com/a/36683363
if (hrefs.indexOf(String(value)) === -1) { // hrefs.count -below- serves as a counter for the newly added displayed images (on each infinite scrolling event)
hrefs.push(String(value));
}
});
var visibleCount = hrefs.length;
var visiblePercent = ((visibleCount / total) * 100).toFixed(1); // Visible images count as percentage
if (isNaN(visiblePercent)) {
visiblePercent = 0 ; // avoid NaN
}
var counter = visibleCount + ' / ' + totalString + ' that is ' + visiblePercent + '%';
return counter;
}
function createDiv() {
// Creation of the counter element
document.body.appendChild(div);
// div.innerHTML = showCounter(); // Initial display of the counter
div.innerHTML = escapeHTMLPolicy.createHTML(showCounter()); // Initial display of the counter
div.style.top = '1px';
div.style.right = '1px';
div.style.position = 'fixed';
div.className = 'counter';
}
function createObserver() {
// var thePics = document.querySelector('div[style="flex-direction: column; padding-bottom: 0px; padding-top: 0px;"]');
var thePics = document.querySelector('div[style*="flex-direction: column;"], div[style$="padding-top: 0px;"]'); // the "pics" area element, with rows that contain 3 pics each (watching for 'row' element additions) --> https://stackoverflow.com/a/5110337 ("wildcard * in CSS") starting (^=) with x and ending ($=) with y
if (!thePics){
return;
}
hrefselems.length = 0; // empty the array (see https://stackoverflow.com/a/1232046, method #2)
hrefs.length = 0;
/// ---------------------------------
/// mutation observer -monitors the Posts grid for infinite scrolling event-.
/// ---------------------------------
observer = new MutationObserver(function() { // --> Callback function to execute when mutations are observed
if (div.innerHTML.indexOf(total + ' / ' + total) === -1) {
// div.innerHTML = showCounter(); // On each infinite scrolling event, re-calculate counter
div.innerHTML = escapeHTMLPolicy.createHTML(showCounter()); // On each infinite scrolling event, re-calculate counter
}
// }).observe(document.querySelector('._havey'), // target of the observer: the "pics" area element, with rows that contain 3 pics each (watching for 'row' element additions)
// }).observe(document.querySelector('div[style="flex-direction: column; padding-bottom: 0px; padding-top: 0px;"]'), // target of the observer: the "pics" area element, with rows that contain 3 pics each (watching for 'row' element additions)
});
observer.observe(thePics, // target of the observer
{ // attributes: true,
childList: true,
// characterData: true,
// subtree: true,
}); // config of the observer
}
var div = document.createElement('div');
var observer;
// var avatarSelector = 'span[style="width: 152px; height: 152px;"]'; // the profile's photo/avatar element
// var avatarSelector = 'main > article > header > section > div._ienqf > div > button'; // the 3-dots icon
// var avatarSelector = 'div[style="flex-direction: column; padding-bottom: 0px; padding-top: 0px;"]'; // the 3-dots icon
// var avatarSelector = '._mainc'; // the profile's bio area element
// var avatarSelector = 'h1.notranslate'; // the profile name element
// var avatarSelector = 'h1.rhpdm'; // the profile name element
// var avatarSelector = 'span.-nal3'; // the 'posts' count element, e.g. 683 posts
// var avatarSelector = 'ul.k9GMp'; // the profile's 3 counters container element
// var avatarSelector = '.eC4Dz'; // the profile's username container element
// var avatarSelector = '._aa_m'; // the profile's username container element
// var avatarSelector = '._aa_c'; // the profile's username container element
// var avatarSelector = 'main > article > header > section > div._ienqf > div > button'; // the 3-dots icon
// var avatarSelector = 'div[style="flex-direction: column; padding-bottom: 0px; padding-top: 0px;"]'; // the 3-dots icon
var avatarSelector = '.x1q0g3np.x2lah0s.x8j4wrb'; // the 3-dots icon
if (document.querySelector(avatarSelector) ) {
if (!document.querySelector('.counter')){
createDiv();
createObserver();
}
} else {
console.log('ERROR: Cannot create the Counter element, the avatarSelector element ( ' + avatarSelector + ' ) doesn\'t exist !!');
}
document.arrive(avatarSelector, function() { // the avatar in the profile page
createDiv();
createObserver();
// alert()
});
function removeCounter(){
div.remove();
hrefselems.length = 0; // empty the array (see https://stackoverflow.com/a/1232046, method #2)
hrefs.length = 0;
total = '';
observer.disconnect();
// if (observer) {
// observer.disconnect();
// }
}
document.leave(avatarSelector, function() {
if (!document.querySelector(avatarSelector)){
removeCounter();
}
});
// when navigating using the browser's back/forth
window.addEventListener('popstate', function () {
// alert()
removeCounter();
console.log('COUNTER IS REMOVED');
// TODO
// createDiv();
// createObserver();
});
// when navigating from a profile to another via searchbox // history API)
// https://stackoverflow.com/questions/56760727/how-to-observe-a-change-in-the-url-using-javascript
(function(){
var rs = history.pushState;
history.pushState = function(state, title, url){
if ( !url.includes('/following/') && !url.includes('/followers/') && !url.includes('/p/') && !url.includes('/direct/') && !window.location.href.includes('/p/') ){ // avoid all possible in-page/popup "pages" (a profile's following/followers, and posts -opened by clicking on a thumb-)
rs.apply(history, arguments); // preserve normal functionality
console.log('navigating', arguments); // do something extra here; raise an event
removeCounter();
// alert()
}
};
}());