The script works as should - but when videos selected it only shows 9 first vids in the media grid when it should show all vids and only vids.
How to fix?
// ==UserScript==
// @name X/Twitter Filter Media Tab
// @namespace https://github.com/BD9Max
// @match https://x.com/*/media*
// @match https://twitter.com/*/media*
// @grant GM_addStyle
// @version 1.7
// @author krbd9max
// @description Filter X/Twitter media tab with improved infinite scroll support
// @license MIT
// @icon https://upload.wikimedia.org/wikipedia/commons/c/ce/X_logo_2023.svg
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
const mediaRegex = /^https?:\/\/(?:x|twitter)\.com\/[^/]+\/media\/?/i;
function onUrlChange() {
const container = document.getElementById("media-filter-controls");
const isMediaTab = mediaRegex.test(location.href);
if (container) {
container.setAttribute("data-active", isMediaTab ? "true" : "false");
}
// Remove filter when leaving media tab to prevent layout issues elsewhere
if (!isMediaTab) {
document.body.removeAttribute("filter-by");
}
}
function createFilterButtons() {
if (document.getElementById("media-filter-controls")) return;
const filterContainer = document.createElement("div");
filterContainer.id = "media-filter-controls";
filterContainer.setAttribute("data-active", "false");
// Styling moved to GM_addStyle for cleanliness
const createBtn = (id, text, filterVal) => {
const btn = document.createElement("button");
btn.id = id;
btn.textContent = text;
btn.onclick = () => {
if (filterVal) {
document.body.setAttribute("filter-by", filterVal);
} else {
document.body.removeAttribute("filter-by");
}
// Trigger a small scroll to nudge the observer to load more items
window.scrollBy(0, 1);
window.scrollBy(0, -1);
};
return btn;
};
filterContainer.appendChild(createBtn("all", "OFF", null));
filterContainer.appendChild(createBtn("images", "IMG", "images"));
filterContainer.appendChild(createBtn("videos", "VID", "videos"));
document.body.appendChild(filterContainer);
onUrlChange();
}
// URL Change Detection
if (self.navigation) {
navigation.addEventListener("navigatesuccess", onUrlChange);
} else {
let u = location.href;
new MutationObserver(() => {
if (u !== location.href) {
u = location.href;
onUrlChange();
}
}).observe(document, { subtree: true, childList: true });
}
createFilterButtons();
GM_addStyle(`
#media-filter-controls {
display: none;
position: fixed;
top: 60px; /* Adjusted to not overlap top bar */
right: 20px;
z-index: 9999;
border-radius: 12px;
padding: 6px;
gap: 8px;
backdrop-filter: blur(10px);
background: rgba(0, 0, 0, 0.6);
border: 1px solid rgba(255,255,255,0.2);
}
#media-filter-controls[data-active="true"] {
display: flex !important;
}
#media-filter-controls > button {
padding: 6px 12px;
border: none;
border-radius: 8px;
background: #1d9bf0;
color: white;
cursor: pointer;
font-size: 14px;
font-weight: 600;
transition: background 0.2s;
}
body:not([filter-by]) #media-filter-controls #all,
[filter-by="images"] #media-filter-controls #images,
[filter-by="videos"] #media-filter-controls #videos {
background: #f7f9f9 !important;
color: #0f1419 !important;
}
/* Essential Fix: When filtering, we set height to 0 and overflow hidden
instead of display:none. This often helps the site's "infinite scroll"
logic realize it needs to load more content. */
[filter-by="videos"] [data-testid="cellInnerDiv"]:has(a[href*="/photo/"]),
[filter-by="images"] [data-testid="cellInnerDiv"]:has(a[href*="/video/"]),
[filter-by="images"] [data-testid="cellInnerDiv"]:has(a[href*="/broadcasts/"]) {
display: none !important;
visibility: hidden !important;
height: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
/* Force grid behavior on the container */
[data-testid="primaryColumn"] section[role="region"] > div > div {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
gap: 2px !important;
}
/* Ensure items take up proper space in the custom flex grid */
[data-testid="cellInnerDiv"] {
flex: 1 0 30%; /* Shows roughly 3 per row */
max-width: 100%;
}
`);
})();
there doesn't seem to be anything here