Last active
April 25, 2022 19:37
-
-
Save joshparkerj/41e576b304f01dced186633f3eb84c4c to your computer and use it in GitHub Desktop.
movers from the past three years chart to the past three months chart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name up and coming pages in wikipedia category | |
| // @namespace http://tampermonkey.net/ | |
| // @version 0.1 | |
| // @description movers from the past three years chart to the past three months chart | |
| // @author Josh Parker | |
| // @source https://github.com/joshparkerj/silly-internet-tricks/blob/main/wikipedia/up-and-coming.user.js | |
| // @downloadURL https://gist.github.com/joshparkerj/41e576b304f01dced186633f3eb84c4c/raw/up-and-coming.user.js | |
| // @updateURL https://gist.github.com/joshparkerj/41e576b304f01dced186633f3eb84c4c/raw/up-and-coming.meta.js | |
| // @match https://en.wikipedia.org/wiki/Category:* | |
| // @icon https://www.google.com/s2/favicons?domain=wikipedia.org | |
| // @grant none | |
| // ==/UserScript== |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name up and coming pages in wikipedia category | |
| // @namespace http://tampermonkey.net/ | |
| // @version 0.1 | |
| // @description movers from the past three years chart to the past three months chart | |
| // @author Josh Parker | |
| // @source https://github.com/joshparkerj/silly-internet-tricks/blob/main/wikipedia/up-and-coming.user.js | |
| // @downloadURL https://gist.github.com/joshparkerj/41e576b304f01dced186633f3eb84c4c/raw/up-and-coming.user.js | |
| // @updateURL https://gist.github.com/joshparkerj/41e576b304f01dced186633f3eb84c4c/raw/up-and-coming.meta.js | |
| // @match https://en.wikipedia.org/wiki/Category:* | |
| // @icon https://www.google.com/s2/favicons?domain=wikipedia.org | |
| // @grant none | |
| // ==/UserScript== | |
| (()=>{"use strict";function e(t,n,r){const o=document.querySelectorAll("#mw-pages .mw-category"),s=[...o].map((e=>e.innerHTML));document.styleSheets[0].deleteRule(0),document.styleSheets[0].deleteRule(0),o.forEach(((e,t)=>{e.innerHTML=s[t]})),t.removeEventListener("click",e),t.addEventListener("click",r),t.replaceChildren(new Text(n()))}function t(n,r){const o=document.querySelectorAll("#mw-pages li > a"),s=e=>{const t=e.innerText.match(/\(movement: (-?\d+)\)/);return t?+t[1]:-1},c=[...o].sort(((e,t)=>s(t)-s(e))),a=document.querySelector("#mw-pages .mw-category"),i=document.querySelector("#mw-pages .mw-content-ltr"),m=a||i;m.innerHTML="",document.styleSheets[0].insertRule("#mw-pages .mw-category a { display: block; }"),document.styleSheets[0].insertRule("#mw-pages .mw-category ~ .mw-category { display: none; }"),c.forEach((e=>m.appendChild(e))),n.removeEventListener("click",t),n.addEventListener("click",(()=>e(n,(()=>r),t))),n.replaceChildren(new Text("undo sort"))}function n(e){const t=e.toISOString().match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T\d\d:\d\d:\d\d.\d{3}Z/),{year:n,month:r,day:o}=t.groups;return`${n}${r}${o}`}!function(){const e=document.createElement("button");e.innerText="sort by chart movement";const r=document.createElement("button");r.innerText="get chart movement",e.addEventListener("click",(()=>t(e,"sort by chart movemenet"))),r.addEventListener("click",(()=>function(e,t,r){const o=function(e,t){const n=new Date(e);return n.setMonth(e.getMonth()+t),n},s=new Date,c=n(s),a=n(o(s,-3)),i=n(o(s,-36)),m=e=>`https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia/all-access/user/${e.href.match(/wiki\/(.*)$/)[1].replaceAll("/","%2F")}/monthly/`,l=e=>({months:`${e}${a}/${c}`,years:`${e}${i}/${c}`}),d=function(e,t){return e.map((e=>fetch(e[t]).then((e=>e.json())).then((e=>e.items?e.items.reduce(((e,t)=>e+t.views),0):e.title))))},u=function(e,t,n){return(r,o)=>{"number"==typeof r&&e[o+t].setAttribute(n,r)}},h=[];e.setAttribute("disabled",!0);const p=document.querySelectorAll("#mw-pages li > a"),y=Math.ceil(p.length/100);e.replaceChildren(new Text(`getting movement (${y} seconds)`));const w=(e=>[...e].map(m).map(l))(p);for(let e=0;e<w.length;e++){const t=w.slice(e,e+1),n=1e3*e*2/100;h.push((()=>new Promise((r=>{setTimeout((()=>{const n={};Promise.all(d(t,"months")).then((t=>{n.months=t,n.months.forEach(u(p,e,"views-months")),n.years&&r(n)})),Promise.all(d(t,"years")).then((t=>{n.years=t,n.years.forEach(u(p,e,"views-years")),n.months&&r(n)}))}),n)}))))}Promise.all(h.map((e=>e()))).then((()=>{const n=[...document.querySelectorAll("#mw-pages li > a")];n.sort(((e,t)=>t.getAttribute("views-months")-e.getAttribute("views-months"))),n.forEach(((e,t)=>e.setAttribute("rank-months",t))),n.sort(((e,t)=>t.getAttribute("views-years")-e.getAttribute("views-years"))),n.forEach(((e,t)=>e.setAttribute("rank-years",t))),n.forEach((e=>{const t=e.getAttribute("rank-years"),n=e.getAttribute("rank-months");e.appendChild(new Text(` (movement: ${t-n})`))})),document.querySelector("#mw-pages > h2").appendChild(t),e.replaceChildren(new Text("done"))}))}(r,e))),function(){let e=document.querySelector("#mw-pages > h2");if(!e){let t=document.querySelector("#mw-pages");t||(t=document.createElement("div"),t.id="mw-pages",document.querySelector("div#mw-content-text").after(t)),e=document.createElement("h2"),t.appendChild(e)}return e}().appendChild(r)}()})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name up and coming pages in wikipedia category | |
| // @namespace http://tampermonkey.net/ | |
| // @version 0.1 | |
| // @description movers from the past three years chart to the past three months chart | |
| // @author Josh Parker | |
| // @match https://en.wikipedia.org/wiki/Category:* | |
| // @icon https://www.google.com/s2/favicons?domain=wikipedia.org | |
| // @grant none | |
| // ==/UserScript== | |
| (function upAndComingUserScript() { | |
| const sortButton = document.createElement('button'); | |
| sortButton.innerText = 'sort by movement'; | |
| const movementButton = document.createElement('button'); | |
| movementButton.innerText = 'get chart movement'; | |
| const apiUrl = 'https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia/all-access/user/'; | |
| const yyyymmdd = function yyyymmdd(date) { | |
| const isoString = date.toISOString(); | |
| const isoMatch = isoString.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T\d\d:\d\d:\d\d.\d{3}Z/); | |
| const { year, month, day } = isoMatch.groups; | |
| return `${year}${month}${day}`; | |
| }; | |
| const addMonths = function addMonths(date, months) { | |
| const calculatedDate = new Date(date); | |
| calculatedDate.setMonth(date.getMonth() + months); | |
| return calculatedDate; | |
| }; | |
| const now = new Date(); | |
| const today = yyyymmdd(now); | |
| const threeMonths = yyyymmdd(addMonths(now, -3)); | |
| const threeYears = yyyymmdd(addMonths(now, -36)); | |
| const getPageViewUrls = (categoryLinks) => [...categoryLinks].map((a) => `${apiUrl}${a.href.match(/wiki\/(.*)$/)[1].replaceAll('/', '%2F')}/monthly/`).map((urlPrefix) => ({ months: `${urlPrefix}${threeMonths}/${today}`, years: `${urlPrefix}${threeYears}/${today}` })); | |
| const fetchUrls = function fetchUrls(urls, name) { | |
| return urls.map((url) => fetch(url[name]).then((r) => r.json()).then((json) => { | |
| if (json.items) { | |
| return json.items.reduce((sum, item) => sum + item.views, 0); | |
| } | |
| return json.title; | |
| })); | |
| }; | |
| const setViewAttribute = function setViewAttribute(categoryLinks, i, name) { | |
| return (views, index) => { | |
| if (typeof views === 'number') { | |
| categoryLinks[index + i].setAttribute(name, views); | |
| } | |
| }; | |
| }; | |
| const REQUESTS_PER_SECOND = 100; | |
| const timeouts = []; | |
| const getPageViews = function getPageViews() { | |
| movementButton.setAttribute('disabled', true); | |
| const categoryLinks = document.querySelectorAll('#mw-pages li > a'); | |
| const remainingSeconds = Math.ceil(categoryLinks.length / REQUESTS_PER_SECOND); | |
| movementButton.innerText = `getting movement (${remainingSeconds} seconds)`; | |
| const updateRemainingSeconds = function updateRemainingSeconds() { | |
| const remainingSecondsNow = Number(movementButton.innerText.match(/getting movement \((?<remainingSeconds>-?\d+(\.\d+)?) seconds\)/).groups.remainingSeconds) - 0.5; | |
| movementButton.innerText = `getting movement (${remainingSecondsNow} seconds)`; | |
| }; | |
| const pageViewUrls = getPageViewUrls(categoryLinks); | |
| for (let i = 0; i < pageViewUrls.length; i += Math.floor(REQUESTS_PER_SECOND / 2)) { | |
| const pageViewUrlsSlice = pageViewUrls.slice(i, i + Math.floor(REQUESTS_PER_SECOND / 2)); | |
| const timeoutDelayInMilliseconds = (i * 1000) / REQUESTS_PER_SECOND; | |
| timeouts.push(() => ( | |
| new Promise((resolve) => { | |
| setTimeout(() => { | |
| const results = {}; | |
| Promise.all(fetchUrls(pageViewUrlsSlice, 'months')) | |
| .then((monthResults) => { | |
| results.months = monthResults; | |
| results.months.forEach(setViewAttribute(categoryLinks, i, 'views-months')); | |
| if (results.years) { | |
| updateRemainingSeconds(); | |
| resolve(results); | |
| } | |
| }); | |
| Promise.all(fetchUrls(pageViewUrlsSlice, 'years')) | |
| .then((yearResults) => { | |
| results.years = yearResults; | |
| results.years.forEach(setViewAttribute(categoryLinks, i, 'views-years')); | |
| if (results.months) { | |
| updateRemainingSeconds(); | |
| resolve(results); | |
| } | |
| }); | |
| }, timeoutDelayInMilliseconds); | |
| }) | |
| )); | |
| } | |
| Promise.all(timeouts.map((timeout) => timeout())) | |
| .then(() => { | |
| const catLinks = [...document.querySelectorAll('#mw-pages li > a')]; | |
| catLinks.sort((a, b) => b.getAttribute('views-months') - a.getAttribute('views-months')); | |
| catLinks.forEach((link, i) => link.setAttribute('rank-months', i)); | |
| catLinks.sort((a, b) => b.getAttribute('views-years') - a.getAttribute('views-years')); | |
| catLinks.forEach((link, i) => link.setAttribute('rank-years', i)); | |
| catLinks.forEach((link) => { const a = link; a.innerText += ` (movement: ${a.getAttribute('rank-years') - a.getAttribute('rank-months')})`; }); | |
| document.querySelector('#mw-pages > h2').appendChild(sortButton); | |
| movementButton.innerText = 'done'; | |
| }); | |
| }; | |
| const sortByMovement = function sortByMovement() { | |
| const categoryLinks = document.querySelectorAll('#mw-pages li > a'); | |
| const linkSorter = (ab) => { | |
| const viewMatch = ab.innerText.match(/\(movement: (-?\d+)\)/); | |
| if (viewMatch) { | |
| return +(viewMatch[1]); | |
| } | |
| return -1; | |
| }; | |
| const sortedLinks = [...categoryLinks].sort((a, b) => linkSorter(b) - linkSorter(a)); | |
| const categorySection = document.querySelector('#mw-pages .mw-category') || document.querySelector('#mw-pages .mw-content-ltr'); | |
| const allCategorySections = document.querySelectorAll('#mw-pages .mw-category'); | |
| const unsorted = [...allCategorySections].map((section) => section.innerHTML); | |
| categorySection.innerHTML = ''; | |
| const undoSort = function undoSort() { | |
| document.styleSheets[0].deleteRule(0); | |
| document.styleSheets[0].deleteRule(0); | |
| allCategorySections.forEach((section, i) => { | |
| const s = section; | |
| s.innerHTML = unsorted[i]; | |
| }); | |
| sortButton.removeEventListener('click', undoSort); | |
| sortButton.addEventListener('click', sortByMovement); | |
| }; | |
| document.styleSheets[0].insertRule('#mw-pages .mw-category a { display: block; }'); | |
| document.styleSheets[0].insertRule('#mw-pages .mw-category ~ .mw-category { display: none; }'); | |
| sortedLinks.forEach((link) => categorySection.appendChild(link)); | |
| sortButton.removeEventListener('click', sortByMovement); | |
| sortButton.addEventListener('click', undoSort); | |
| sortButton.innerText = 'undo sort'; | |
| }; | |
| sortButton.addEventListener('click', sortByMovement); | |
| movementButton.addEventListener('click', getPageViews); | |
| let mwPagesH2 = document.querySelector('#mw-pages > h2'); | |
| if (!mwPagesH2) { | |
| let mwPages = document.querySelector('#mw-pages'); | |
| if (!mwPages) { | |
| mwPages = document.createElement('div'); | |
| mwPages.id = 'mw-pages'; | |
| document.querySelector('div#mw-content-text').after(mwPages); | |
| } | |
| mwPagesH2 = document.createElement('h2'); | |
| mwPages.appendChild(mwPagesH2); | |
| } | |
| mwPagesH2.appendChild(movementButton); | |
| }()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment