-
-
Save mathix420/e0604ab0e916622972372711d2829555 to your computer and use it in GitHub Desktop.
// ==UserScript== | |
// @name Medium Paywall Bypass | |
// @namespace Violentmonkey Scripts | |
// @run-at document-start | |
// @match *://*.medium.com/* | |
// @match *://medium.com/* | |
// @match *://*/* | |
// @grant none | |
// @version 2.4 | |
// @inject-into content | |
// @updateURL https://gist.githubusercontent.com/mathix420/e0604ab0e916622972372711d2829555/raw/medium.user.js | |
// @downloadURL https://gist.githubusercontent.com/mathix420/e0604ab0e916622972372711d2829555/raw/medium.user.js | |
// @website https://freedium.cfd | |
// @author Mathix420, ZhymabekRoman | |
// @description Don't forget to remove `@match` filters you don't want. | |
// ==/UserScript== | |
// initCall is telling us if we need to inject the title observer | |
function mediumRedirecter(initCall = false) { | |
if ( | |
// Allow seeing original articles that were already redirected to freedium. | |
!window.location.href.endsWith('#bypass') && | |
// Do not redirect when editing on medium. | |
!window.location.href.includes("/edit?source=") && | |
// Detect if we are on a medium website (regardless of the domain) | |
document.head?.querySelector('meta[property="al:android:url"]')?.content?.includes('medium://p/') | |
) { | |
window.location.href = 'https://freedium.cfd/' + window.location.href; | |
} else if (initCall && /(.*\.|^)medium\.com$/.test(window.location.host)) { | |
// Observe <title> changes | |
new MutationObserver(function(mutations) { | |
// If title change is detected, check if a freedium redirect is required | |
if (mutations[0].target.textContent) mediumRedirecter(); | |
}).observe( | |
document.querySelector('title'), | |
{ subtree: true, characterData: true, childList: true } | |
); | |
} | |
} | |
mediumRedirecter(true); |
But I can't find any reference to
document-body
online, where did you find this value? Maybe it is defaulting todocument-end
if it's recognized as a bad value. Or most likely I just didn't find a great source of documentation.
Hmmm, yeah, I think document-body
is only Tampermonkey specific : https://www.tampermonkey.net/documentation.php?locale=en#meta:run_at
Violentmonkey
doesn't support it: https://violentmonkey.github.io/api/metadata-block/#run-at
to automatically redirect to the freedium site:
// ==UserScript==
// @name Medium Paywall Bypass
// @namespace Violentmonkey Scripts
// @run-at document-start
// @match *://*.medium.com/*
// @match *://medium.com/*
// @match *://*/*
// @grant none
// @version 1.5
// @inject-into content
// @updateURL https://gist.githubusercontent.com/mathix420/e0604ab0e916622972372711d2829555/raw/medium.user.js
// @downloadURL https://gist.githubusercontent.com/mathix420/e0604ab0e916622972372711d2829555/raw/medium.user.js
// @website https://freedium.cfd
// @author Mathix420, ZhymabekRoman
// @description Don't forget to remove `@match` filters you don't want.
// ==/UserScript==
(setInterval(function () {
// 1. Allow seeing original articles that were already redirected to freedium.
// 2. Do not redirect when editing on medium.
if (window.location.href.endsWith('#bypass') || window.location.href.includes("/edit?source=")) {
return;
}
const mediumPostUrlProperty = document.head.querySelector('meta[property="al:android:url"]')
if ((mediumPostUrlProperty || {}).content && mediumPostUrlProperty.content.includes('medium://p/')
&& window.location.href.match(/^https?:\/\/(www\.)?(medium\.com\/|[\w-]+\.medium\.com\/|[\w-]+\.[\w-]+\/).*/
)) {
window.location.href = 'https://freedium.cfd/' + window.location.href;
}
}), 1000);
Violentmonkey
doesn't support it
Surprisingly I just saw it in the settings of my Violentmonkey. Anyway I'm surprised that using document-body
as the docs says The script will be injected **if** the body element exists.
maybe it's a typo but all the other descriptions says when
. It's pretty strange.
Sorry for being this picky on this change, but as it drastically increase the time of redirect I'm a bit reluctant to it. Also it works perfectly on my end with violentmonkey, would you consider trying with this one ? Might also be better for your privacy.
Hello @lonelam, thanks for your recommendation, but I don't understand your change can you give me some context? As the condition checking for medium meta tag meta[property="al:android:url"]
already allows us to redirect every medium article (even those not hosted by the medium domain).
I'm using Violentmonkey
, maybe the other extensions are breaking headers loading (I have about ~45 extensions).
Violentmonkey
doesn't support itSurprisingly I just saw it in the settings of my Violentmonkey. Anyway I'm surprised that using
document-body
as the docs saysThe script will be injected **if** the body element exists.
maybe it's a typo but all the other descriptions sayswhen
. It's pretty strange. Sorry for being this picky on this change, but as it drastically increase the time of redirect I'm a bit reluctant to it. Also it works perfectly on my end with violentmonkey, would you consider trying with this one ? Might also be better for your privacy.Hello @lonelam, thanks for your recommendation, but I don't understand your change can you give me some context? As the condition checking for medium meta tag
meta[property="al:android:url"]
already allows us to redirect every medium article (even those not hosted by the medium domain).
The Medium site is an SPA and navigating to a new page will not trigger a 'load' event. And therefore, the script will not triggered if I navigate from a medium's page to another,
So a manual refresh is needed before I jump to freedium, do the detection intervally will prevent the extra manual operation.
@ZhymabekRoman okay, let me know if I still need to change the code !
@lonelam Oh I see! Sorry I missed the setTimeout
part from your code! I also noticed this behavior earlier, I was thinking about implementing something like this https://stackoverflow.com/q/6390341/9799292
@ZhymabekRoman okay, let me know if I still need to change the code !
@lonelam Oh I see! Sorry I missed the
setTimeout
part from your code! I also noticed this behavior earlier, I was thinking about implementing something like this https://stackoverflow.com/q/6390341/9799292
That's an awesome performance impovement, Listening the events like locationchange or hashchange will be more economically and more effective for the detection.
@lonelam I just updated the script, it can now detect title changes (only when using medium.com
domain as custom domains does not seems to host SPAs) and trigger a redirect if needed!
PS: small bug fix, make sure to be on V2.1
Achtung!
Sooo, it was going to take a while, but now we have it. Our whole Github organization is not public for now.
Reddit community, that was beginning all of that also gone - https://www.reddit.com/r/paywall/comments/15jsr6z/bypass_mediumcom_paywall/
We have moved to Codeberg - https://codeberg.org/Freedium-cfd
Medium, thank you >.
Thanks all Freedium-cfd members!
@mathix420 Can you fix this error? Sometimes this error appears:
TypeError: can't access property "querySelector", document.head is null
@ZhymabekRoman I've fixed the type error, but if the head tag is missing it won't be able to detect the medium page before js load.
Sorry for the delay, I got lot of work these days!
@mathix420 Thank you! I really appreciate your efforts
I think you can simplify the below lines using Optional chaining (?.):
First, completely remove
- const mediumPostUrlProperty = ((document.head || {}).querySelector ? document.head.querySelector('meta[property="al:android:url"]') : {}) || {}
Then inside the first if
statement, replace
- (mediumPostUrlProperty.content && mediumPostUrlProperty.content.includes('medium://p/'))
+ document.head?.querySelector('meta[property="al:android:url"]')?.content?.includes('medium://p/')
Personally, I'm not going to use // @match *://*/*
. So I put this into a detectMediumWebsite()
function and commented it out.
Thanks for your work.
P.S. By the way, are you sure that the MutationObserver
is actually registered?
Can you remove? // @match *://*/*
do not make sense to be for all sites.
do not make sense to be for all sites.
Medium has too many sub-domains
Medium has too many sub-domains
// @match *://*.medium.com/*
Should be enough for matching sub-domains.
Should be enough for matching sub-domains.
What about devopsquare.com, blog.devops.dev, blog.stackademic.com, ai.plainenglish.io, bettermarketing.pub
and etc? It's impossible for us to say how many Medium sites there are.
You are right. I didn't know those type of sites exist. But they are just different domains, technically speaking.
To recap:
// @match *://*.medium.com/*
Is enough for matching sub-domains.
// @match *://*/*
Is needed for matching any possible domain who happens to be a Medium website.
freedium is offline so unfortunately this script doesn't work anymore for now
All works as expected. Yeah, we made some codebase refactor, to improve speed and some big bug fixes. And there were some minor downtimes.
Thanks @a-pav I wasn't aware that optional chaining was supported on tampermonkey. Yes, the mutationobserver is being registered, try commenting the section and click a link in this page for example https://medium.com/@francais you'll notice no redirect.
What a wonderful script. Thank you for sharing 🙇
In case freedium goes unstable, how about disabling redirects for free posts? This is the predicate to check if it is a premium content: document.querySelector('.meteredContent') != null
@zzJinux yes, I thought about that too a couple months ago, I will try to implement it once I have more free time
@mathix420 I have already locally patched the script to add the predicate. I hope your version will do so.
@zzJinux if you want you can fork this gist and update it so I can replicate your changes
@mathix420 Just a few lines change: https://gist.github.com/zzJinux/364725e7c61810719286d94e88a4e38c I haven't had any issues.
Guys, sorry, yeah I known that's my fault. I need your help: Freedium-cfd/web#16 (comment)
@ZhymabekRoman interesting, and yes it might be possible that the body is not fully loaded when
document.head
is run I guess.But I can't find any reference to
document-body
online, where did you find this value? Maybe it is defaulting todocument-end
if it's recognized as a bad value. Or most likely I just didn't find a great source of documentation.