├── tests
├── __init__.py
├── files
│ └── latimes.jpg
├── test_extract.py
├── test_adstxt.py
├── test_hyperlinks.py
├── test_accessibility.py
├── test_screenshot.py
├── test_robotstxt.py
└── test_archive.py
├── newshomepages
├── __init__.py
├── extensions
│ ├── adguard
│ │ ├── web-accessible-resources
│ │ │ └── redirects
│ │ │ │ ├── noopcss.css
│ │ │ │ ├── noopjson.json
│ │ │ │ ├── nooptext.js
│ │ │ │ ├── noopjs.js
│ │ │ │ ├── noopvast02.xml
│ │ │ │ ├── noopvast03.xml
│ │ │ │ ├── noopvast04.xml
│ │ │ │ ├── noopvmap01.xml
│ │ │ │ ├── noopframe.html
│ │ │ │ ├── noopmp3.mp3
│ │ │ │ ├── noopmp4.mp4
│ │ │ │ ├── 1x1-transparent.gif
│ │ │ │ ├── 2x2-transparent.png
│ │ │ │ ├── 3x2-transparent.png
│ │ │ │ ├── 32x32-transparent.png
│ │ │ │ ├── prebid-ads.js
│ │ │ │ ├── noeval.js
│ │ │ │ ├── naver-wcslog.js
│ │ │ │ └── scorecardresearch-beacon.js
│ │ ├── assets
│ │ │ ├── css
│ │ │ │ ├── main.css
│ │ │ │ ├── nanobar.css
│ │ │ │ ├── fonts.css
│ │ │ │ ├── devtools
│ │ │ │ │ └── custom.css
│ │ │ │ └── layout.css
│ │ │ ├── icons
│ │ │ │ ├── gray-19.png
│ │ │ │ ├── gray-38.png
│ │ │ │ ├── b13-on-19.png
│ │ │ │ ├── b13-on-38.png
│ │ │ │ ├── green-128.png
│ │ │ │ ├── green-16.png
│ │ │ │ ├── green-19.png
│ │ │ │ ├── green-38.png
│ │ │ │ ├── b13-off-19.png
│ │ │ │ └── b13-off-38.png
│ │ │ ├── images
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── link.svg
│ │ │ │ ├── shield.svg
│ │ │ │ ├── trash.svg
│ │ │ │ ├── reload-ico-green.svg
│ │ │ │ ├── cross.svg
│ │ │ │ ├── arrow-down.svg
│ │ │ │ ├── tick.svg
│ │ │ │ ├── arrow-down-grey.svg
│ │ │ │ ├── checked.svg
│ │ │ │ ├── dropbox.svg
│ │ │ │ ├── toggler-bg.svg
│ │ │ │ ├── alert.svg
│ │ │ │ ├── logo-shield.svg
│ │ │ │ ├── reload-ico.svg
│ │ │ │ └── chrome.svg
│ │ │ ├── fonts
│ │ │ │ ├── Roboto-Bold.woff2
│ │ │ │ ├── Roboto-Medium.woff2
│ │ │ │ └── Roboto-Regular.woff2
│ │ │ └── js
│ │ │ │ └── preload-theme.js
│ │ ├── pages
│ │ │ ├── background.html
│ │ │ ├── devtools.html
│ │ │ ├── popup.html
│ │ │ ├── ad-blocked.html
│ │ │ ├── filtering-log.html
│ │ │ ├── safebrowsing.html
│ │ │ ├── options.html
│ │ │ ├── filter-download.html
│ │ │ ├── fullscreen-user-rules.html
│ │ │ ├── devtools.js
│ │ │ └── devtools-elements-sidebar.html
│ │ ├── _locales
│ │ │ ├── bn
│ │ │ │ └── messages.json
│ │ │ ├── kn
│ │ │ │ └── messages.json
│ │ │ ├── lv
│ │ │ │ └── messages.json
│ │ │ ├── sr
│ │ │ │ └── messages.json
│ │ │ ├── ta
│ │ │ │ └── messages.json
│ │ │ ├── te
│ │ │ │ └── messages.json
│ │ │ ├── fil
│ │ │ │ └── messages.json
│ │ │ └── mk-MK
│ │ │ │ └── messages.json
│ │ └── manifest.json
│ └── adguardextra
│ │ ├── assets
│ │ └── images
│ │ │ ├── extra_logo.png
│ │ │ ├── extra_icon_16.png
│ │ │ ├── extra_icon_19.png
│ │ │ ├── extra_icon_38.png
│ │ │ ├── extra_icon_128.png
│ │ │ └── extra_installed.png
│ │ ├── _locales
│ │ ├── ar
│ │ │ └── messages.json
│ │ ├── bg
│ │ │ └── messages.json
│ │ ├── et
│ │ │ └── messages.json
│ │ ├── fa
│ │ │ └── messages.json
│ │ ├── hy
│ │ │ └── messages.json
│ │ ├── sv
│ │ │ └── messages.json
│ │ ├── zh
│ │ │ └── messages.json
│ │ ├── ja
│ │ │ └── messages.json
│ │ ├── zh-TW
│ │ │ └── messages.json
│ │ ├── ko
│ │ │ └── messages.json
│ │ ├── he
│ │ │ └── messages.json
│ │ ├── da
│ │ │ └── messages.json
│ │ ├── cs
│ │ │ └── messages.json
│ │ ├── en
│ │ │ └── messages.json
│ │ ├── hr
│ │ │ └── messages.json
│ │ ├── nl
│ │ │ └── messages.json
│ │ ├── ro
│ │ │ └── messages.json
│ │ ├── sk
│ │ │ └── messages.json
│ │ ├── fi
│ │ │ └── messages.json
│ │ ├── no
│ │ │ └── messages.json
│ │ ├── sr
│ │ │ └── messages.json
│ │ ├── lt
│ │ │ └── messages.json
│ │ ├── uk
│ │ │ └── messages.json
│ │ ├── id
│ │ │ └── messages.json
│ │ ├── sl
│ │ │ └── messages.json
│ │ ├── pt
│ │ │ └── messages.json
│ │ ├── be
│ │ │ └── messages.json
│ │ ├── pt-PT
│ │ │ └── messages.json
│ │ ├── de
│ │ │ └── messages.json
│ │ ├── es
│ │ │ └── messages.json
│ │ ├── it
│ │ │ └── messages.json
│ │ ├── pl
│ │ │ └── messages.json
│ │ ├── ru
│ │ │ └── messages.json
│ │ ├── tr
│ │ │ └── messages.json
│ │ ├── fr
│ │ │ └── messages.json
│ │ ├── hu
│ │ │ └── messages.json
│ │ └── vi
│ │ │ └── messages.json
│ │ ├── popup.css
│ │ ├── popup.html
│ │ ├── content-script.js
│ │ └── options.js
├── site
│ ├── __init__.py
│ ├── __main__.py
│ ├── source_list.py
│ ├── bundle_list.py
│ ├── latest_screenshots.py
│ ├── language_list.py
│ ├── status_report.py
│ ├── country_list.py
│ ├── country_detail.py
│ ├── language_detail.py
│ ├── bundle_detail.py
│ ├── cli.py
│ └── performance_ranking.py
├── sources
│ └── javascript
│ │ ├── lavozdegalicia.js
│ │ ├── asahi.js
│ │ ├── fiquemsabendo.js
│ │ ├── nikkei.js
│ │ ├── sankei_news.js
│ │ ├── newshour.js
│ │ ├── sputnikint.js
│ │ ├── bariweiss.js
│ │ ├── le_figaro.js
│ │ ├── maroelamedia.js
│ │ ├── mediapart.js
│ │ ├── platformer.js
│ │ ├── wonkette.js
│ │ ├── adnkronos.js
│ │ ├── dallasnews.js
│ │ ├── diariope.js
│ │ ├── examinationnews.js
│ │ ├── ilmanifesto.js
│ │ ├── jessicavalenti.js
│ │ ├── lanacion.js
│ │ ├── opensecretsdc.js
│ │ ├── realdailywire.js
│ │ ├── seikyoofficial.js
│ │ ├── thedispatch.js
│ │ ├── 404mediaco.js
│ │ ├── bonginoreport.js
│ │ ├── capradionews.js
│ │ ├── daily_record.js
│ │ ├── eltiempo.js
│ │ ├── fortunemagazine.js
│ │ ├── georgiastraight.js
│ │ ├── globalnews.js
│ │ ├── izvestia_ru.js
│ │ ├── kcautv.js
│ │ ├── kpbs.js
│ │ ├── kpcc.js
│ │ ├── mtnstspotlight.js
│ │ ├── spotlightpa.js
│ │ ├── theathletic.js
│ │ ├── thebabylonbee.js
│ │ ├── theintercept.js
│ │ ├── thesun.js
│ │ ├── washingtonpost.js
│ │ ├── zerohora.js
│ │ ├── 20minutes.js
│ │ ├── baltimorebanner.js
│ │ ├── bbc.js
│ │ ├── bloombergjapan.js
│ │ ├── chess24com.js
│ │ ├── drudge.js
│ │ ├── firstthingsmag.js
│ │ ├── humanevents.js
│ │ ├── jdemontreal.js
│ │ ├── le_parisien.js
│ │ ├── motherjones.js
│ │ ├── openvallejo.js
│ │ ├── votebeatus.js
│ │ ├── foxnews.js
│ │ ├── globeandmail.js
│ │ ├── harpers.js
│ │ ├── laist.js
│ │ ├── nybooks.js
│ │ ├── propublica.js
│ │ ├── sjvwater.js
│ │ ├── uvaldenews.js
│ │ ├── lastampa.js
│ │ ├── lp_lapresse.js
│ │ ├── publicintegrity.js
│ │ ├── arthasarokar.js
│ │ ├── franceinfo.js
│ │ ├── gazettedotcom.js
│ │ ├── gfherald.js
│ │ ├── kccinews.js
│ │ ├── occrp.js
│ │ ├── repubblica.js
│ │ ├── lobs.js
│ │ ├── sdut.js
│ │ ├── tribunedelyon.js
│ │ ├── blaw.js
│ │ ├── breitbartnews.js
│ │ ├── dmregister.js
│ │ ├── oann.js
│ │ ├── postcrescent.js
│ │ ├── presscitizen.js
│ │ ├── teamtrace.js
│ │ ├── crucessunnews.js
│ │ ├── dailycaller.js
│ │ ├── gbpressgazette.js
│ │ ├── independent.js
│ │ ├── jornaloglobo.js
│ │ ├── journalsentinel.js
│ │ ├── larazon_es.js
│ │ ├── nationalpost.js
│ │ ├── stevenspointjrl.js
│ │ ├── cbcnews.js
│ │ ├── mtlgazette.js
│ │ ├── nbcnews.js
│ │ ├── theriotimes.js
│ │ ├── calgaryherald.js
│ │ ├── financialpost.js
│ │ ├── htrnews.js
│ │ ├── nhk_news.js
│ │ ├── ottawacitizen.js
│ │ ├── sahanjournal.js
│ │ ├── sowetanlive.js
│ │ ├── startribune.js
│ │ ├── thetorontosun.js
│ │ ├── timeslive.js
│ │ ├── vancouversun.js
│ │ ├── vryeweekblad.js
│ │ ├── andscape.js
│ │ ├── dailymirror.js
│ │ ├── ft.js
│ │ ├── gridnews.js
│ │ ├── sfchronicle.js
│ │ ├── theinterceptbr.js
│ │ ├── rfi.js
│ │ ├── theblaze.js
│ │ ├── theeconomist.js
│ │ ├── theonion.js
│ │ ├── torontostar.js
│ │ ├── lehuffpost.js
│ │ ├── qctimes.js
│ │ ├── thedbk.js
│ │ ├── baltimoremag.js
│ │ ├── wcfcourier.js
│ │ ├── ledevoir.js
│ │ ├── elcorreo_com.js
│ │ ├── vcstar.js
│ │ ├── nytimes.js
│ │ ├── france24.js
│ │ ├── frednewspost.js
│ │ ├── lajornada.js
│ │ ├── lemonde_en.js
│ │ ├── lemondefr.js
│ │ ├── france24_en.js
│ │ ├── baltimoresun.js
│ │ ├── telegraph.js
│ │ ├── thephilacitizen.js
│ │ ├── abc_es.js
│ │ ├── guardian.js
│ │ ├── libe.js
│ │ ├── cnn.js
│ │ ├── corriere.js
│ │ ├── pajaropolitico.js
│ │ ├── pioneerpress.js
│ │ ├── statnews.js
│ │ ├── thetriibe.js
│ │ ├── thewrap.js
│ │ ├── usatoday.js
│ │ ├── estadao.js
│ │ ├── el_universal_mx.js
│ │ ├── moreperfectus.js
│ │ ├── ntdaily.js
│ │ ├── latimes.js
│ │ ├── chicagotribune.js
│ │ ├── msnbc.js
│ │ ├── pulitzercenter.js
│ │ ├── civilbeat.js
│ │ ├── thehilltimes.js
│ │ ├── thetimes.js
│ │ └── news_letter.js
├── analyze
│ ├── __init__.py
│ ├── __main__.py
│ └── cli.py
├── extract
│ ├── __init__.py
│ ├── __main__.py
│ ├── cli.py
│ ├── utils.py
│ ├── items.py
│ ├── wayback.py
│ └── accessibility.py
├── batch.py
├── accessibility.py
└── adstxt.py
├── .flake8
├── mypy.ini
├── .github
├── FUNDING.yml
├── dependabot.yml
├── ISSUE_TEMPLATE
│ ├── report-a-broken-site.md
│ └── add-a-site.yaml
└── workflows
│ └── site.yml
├── _site
├── _static
│ ├── img
│ │ └── slack-baltimore-sun.png
│ └── custom.css
├── _templates
│ ├── bundles.md.tmpl
│ ├── languages.md.tmpl
│ ├── sources.md.tmpl
│ ├── drudge-top-words.svg.tmpl
│ ├── latest.md.tmpl
│ ├── countries.md.tmpl
│ ├── language_detail.md.tmpl
│ ├── country_detail.md.tmpl
│ ├── bundle_detail.md.tmpl
│ └── site_detail.md.tmpl
├── Makefile
├── conf.py
├── gettingstarted.md
├── reference.rst
└── index.md
├── SECURITY.md
├── CONTRIBUTING.md
├── MANIFEST.in
├── README.md
├── Pipfile
└── .pre-commit-config.yaml
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | extend-ignore = D100,D104,E203,E501
3 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopcss.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopjson.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/nooptext.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/mypy.ini:
--------------------------------------------------------------------------------
1 | [mypy]
2 | ignore_missing_imports = True
3 | exclude = newshomepages/extensions
4 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: palewire
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopjs.js:
--------------------------------------------------------------------------------
1 | (function() {})()
--------------------------------------------------------------------------------
/newshomepages/site/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli_group as cli
2 |
3 | __all__ = ("cli",)
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lavozdegalicia.js:
--------------------------------------------------------------------------------
1 | document.body.classList.remove("blocked");
2 |
--------------------------------------------------------------------------------
/newshomepages/analyze/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli_group as cli
2 |
3 | __all__ = ("cli",)
4 |
--------------------------------------------------------------------------------
/newshomepages/extract/__init__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli_group as cli
2 |
3 | __all__ = ("cli",)
4 |
--------------------------------------------------------------------------------
/tests/files/latimes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/tests/files/latimes.jpg
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopvast02.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopvast03.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopvast04.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/site/__main__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli_group
2 |
3 | if __name__ == "__main__":
4 | cli_group()
5 |
--------------------------------------------------------------------------------
/newshomepages/analyze/__main__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli_group
2 |
3 | if __name__ == "__main__":
4 | cli_group()
5 |
--------------------------------------------------------------------------------
/newshomepages/extract/__main__.py:
--------------------------------------------------------------------------------
1 | from .cli import cli_group
2 |
3 | if __name__ == "__main__":
4 | cli_group()
5 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/asahi.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('#befb-cmp-dialog').forEach((e) => e.remove());
2 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/fiquemsabendo.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('.maybe-later').forEach((e) => e.click());
2 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/nikkei.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('.modalStyle_modrqv7').forEach((e) => e.remove());
2 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/sankei_news.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('.CookieConsent').forEach((e) => e.remove());
2 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/newshour.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('#pbs-confirm-station').forEach((e) => e.remove());
2 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/sputnikint.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('#iubenda-cs-banner').forEach((e) => e.remove());
2 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/bariweiss.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.maybe-later'
3 | ).forEach((e) => e.click());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/le_figaro.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#appconsent'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/maroelamedia.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#mm-nb-1'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/mediapart.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('#js-cc-modal').forEach(
2 | el => el.remove()
3 | )
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/platformer.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.maybe-later'
3 | ).forEach((e) => e.click());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/wonkette.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.maybe-later'
3 | ).forEach((e) => e.click());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/adnkronos.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.qc-cmp2-container'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/dallasnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".dmn-overlay"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/diariope.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('.wpcc-container').forEach(
2 | el => el.remove()
3 | )
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/examinationnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.bg-grey-300'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/ilmanifesto.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".info-banner"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/jessicavalenti.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.maybe-later'
3 | ).forEach((e) => e.click());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lanacion.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.ln-banner-container'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/opensecretsdc.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.Modal,#Modal'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/realdailywire.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#wisepops-root'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/seikyoofficial.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('#cookiePopUp').forEach(
2 | el => el.remove()
3 | )
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thedispatch.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('.maybe-later').forEach((e) => {
2 | e.click()
3 | })
4 |
--------------------------------------------------------------------------------
/_site/_static/img/slack-baltimore-sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/_site/_static/img/slack-baltimore-sun.png
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/404mediaco.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.popup,.popup-content'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/bonginoreport.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#onetrust-consent-sdk'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/capradionews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | "#banner-pushdown"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/daily_record.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.qc-cmp-cleanslate'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/eltiempo.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.barra-aviso-privacidad'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/fortunemagazine.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('#Leaderboard0').forEach(
2 | el => el.remove()
3 | )
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/georgiastraight.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.slide-down'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/globalnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.slide-down,.ads'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/izvestia_ru.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.partner_before_head'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/kcautv.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.js-banner'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/kpbs.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | 'ps-google-dfp-ad'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/kpcc.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.CampaignType--popup,.AdModule'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/mtnstspotlight.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.newspack-lightbox'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/spotlightpa.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.overflow-y-scroll'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/theathletic.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gieWyh,.sc-9e0fc4d0-2'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thebabylonbee.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('.overscroll-contain').forEach(
2 | el => el.remove()
3 | )
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/theintercept.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".tp-container-inner"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thesun.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.billboard'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/washingtonpost.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.paywall-overlay'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/zerohora.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.overlay,.page-last'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/20minutes.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#didomi-popup,.ad-toppage'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/baltimorebanner.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.tp-modal,.tp-backdrop'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/bbc.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.nw-c-advert,.nw-c-leaderboard-ad'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/bloombergjapan.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.leaderboard-container'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/chess24com.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.background,.bubble.modal'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/drudge.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '[id^="div-gpt-ad"],#dr_consent'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/firstthingsmag.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#cboxOverlay,#colorbox'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/humanevents.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".grid-modal,#grid-modal"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/jdemontreal.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.piano_auth_wrapper'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/le_parisien.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#didomi-popup,.ad_element'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/motherjones.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.mj-adblock-widget,#ticker'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/openvallejo.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.mc-modal,.mc-modal-bg'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/votebeatus.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.Form-newsletter-breaker-bg'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/css/main.css:
--------------------------------------------------------------------------------
1 | @import "fonts.css";
2 | @import "layout.css";
3 | @import "style.css";
4 | @import "log.css";
5 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/foxnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.pre-content,.pf-widget,.fc-ab-root'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/globeandmail.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#subscription-pencil-area'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/harpers.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".cta-popup,#ctas,.modal-backdrop"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/laist.js:
--------------------------------------------------------------------------------
1 | // ad campaign for LAist
2 | document.querySelectorAll(".bankston-campaign").forEach((e) => e.remove())
3 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/nybooks.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.sumo-form-wrapper,#homepage-top-ad'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/propublica.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.syndicated-modal'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/sjvwater.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.dialog-widget,#dialog-widget'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/uvaldenews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sgcolorbox,#sgcboxOverlay'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lastampa.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.iubenda-cs-banner,#iubenda-cs-banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lp_lapresse.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.homeHeadlinesRow__adWrapper'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/publicintegrity.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.newspack-lightbox'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/background.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/arthasarokar.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#esn_road_block_ad-8,.esn_road_block_ad'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/franceinfo.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#didomi-popup,#newsletterSubContainer'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/gazettedotcom.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.modal-scrollable,.connext-modal-backdrop'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/gfherald.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".modal-scrollable,.connext-modal-backdrop"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/kccinews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.ab-iam-root,.listing-page-ad'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/occrp.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.occrp-cookie-overlay,.cookie,#mc_embed_signup'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/repubblica.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#iubenda-cs-banner,.iubenda-cs-banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopvmap01.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lobs.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gdpr-glm-wall,#gdpr-glm-wall,.event-notification'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/sdut.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '[data-ad-rendered],#ensNotifyBanner'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/tribunedelyon.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".cookie-law-info-bar,#cookie-law-info-bar"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/gray-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/gray-19.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/gray-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/gray-38.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/b13-on-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/b13-on-19.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/b13-on-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/b13-on-38.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/green-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/green-128.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/green-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/green-16.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/green-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/green-19.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/green-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/green-38.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/images/favicon.ico
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/blaw.js:
--------------------------------------------------------------------------------
1 | // Scroll down 1000 pixels
2 | window.scrollBy(0, 1000);
3 |
4 | // Scroll back up to the top of the page
5 | window.scrollTo(0, 0);
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/breitbartnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#onetrust-consent-sdk,#HaDW,#ISCTO_overlay,#ISCTO_div'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/dmregister.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gnt_mol_oy,.gnt_x__hi,#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/oann.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.cc_dialog,#IL_INSEARCH,.PD_modal_container,.PD_modal_overlay'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/postcrescent.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gnt_mol_oy,.gnt_x__hi,#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/presscitizen.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gnt_mol_oy,.gnt_x__hi,#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/teamtrace.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.js-donation-banner,.brocton-campaign,.CampaignType--popup'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/b13-off-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/b13-off-19.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/icons/b13-off-38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/icons/b13-off-38.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/crucessunnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gnt_mol_oy,.gnt_x__hi,#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/dailycaller.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.adcontainer,#unit,.dc-sticky,#onesignal-slidedown-container'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/gbpressgazette.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gnt_mol_oy,.gnt_x__hi,#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/independent.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#ad_unit,#footerPrompt,.tp-modal,.tp-backdrop'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/jornaloglobo.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.tp-container-inner,.mobiliarioNaoBarreira,.mobiliarioAdblock'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/journalsentinel.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gnt_mol_oy,.gnt_x__hi,#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/larazon_es.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.sibbo-layout,#__blockNavigationOverlay,.advertising,.henneoHB'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/nationalpost.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay,.consent__banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/stevenspointjrl.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gnt_mol_oy,.gnt_x__hi,#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/fonts/Roboto-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/fonts/Roboto-Bold.woff2
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/cbcnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.privacyNotification,.bigBoxContainer,.ad-risingstar-container'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/mtlgazette.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay,.consent__banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/nbcnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.header-and-footer--banner-ad,.notification-soft-optin'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/theriotimes.js:
--------------------------------------------------------------------------------
1 | // Scroll down 1000 pixels
2 | window.scrollBy(0, 1000);
3 |
4 | // Scroll back up to the top of the page
5 | window.scrollTo(0, 0);
6 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/fonts/Roboto-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/fonts/Roboto-Medium.woff2
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/fonts/Roboto-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/assets/fonts/Roboto-Regular.woff2
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/assets/images/extra_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguardextra/assets/images/extra_logo.png
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/calgaryherald.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay,.consent__banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/financialpost.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay,.consent__banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/htrnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#gnt_mol_oy,[aria-label="advertisement"],#onetrust-banner-sdk'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/nhk_news.js:
--------------------------------------------------------------------------------
1 | document.documentElement.style.overflowY = 'hidden'
2 |
3 | document.querySelectorAll('#bottom_optout_announce').forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/ottawacitizen.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay,.consent__banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/sahanjournal.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.newspack-popup,.newspack_global_ad global_above_header'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/sowetanlive.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#register-popup-backdrop, #register-popup-modal, #gdpr-overlay, .viafoura'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/startribune.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#overlay-main-container,.overlay-main-container,.ad-mod'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thetorontosun.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay,.consent__banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/timeslive.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#register-popup-backdrop, #register-popup-modal, #gdpr-overlay, .viafoura'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/vancouversun.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay,.consent__banner'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/assets/images/extra_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguardextra/assets/images/extra_icon_16.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/assets/images/extra_icon_19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguardextra/assets/images/extra_icon_19.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/assets/images/extra_icon_38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguardextra/assets/images/extra_icon_38.png
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/vryeweekblad.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#register-popup-backdrop, #register-popup-modal, #gdpr-overlay, .viafoura'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/assets/images/extra_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguardextra/assets/images/extra_icon_128.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/assets/images/extra_installed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguardextra/assets/images/extra_installed.png
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/andscape.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#popup-interstitial-dialog,#dialogContainer,#overlayContainer,#attentive_overlay'
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/dailymirror.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#takeover,.qc-cmp2-container,#qc-cmp2-container,.ad-placeholder,#ad-placeholder'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/ft.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.o-cookie-message,.o-ads,.o-message__container,.n-feedback__survey-trigger'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/gridnews.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#onetrust-consent-sdk,.falkner-campaign,.CampaignType--popup,.wapella-campaign'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/sfchronicle.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.fancybox-overlay.fancybox-overlay-fixed,.belowMastheadWrapper'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/theinterceptbr.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".tp-container-inner,.sgpb-popup-overlay,#sgpb-popup-dialog-main-div-wrapper"
3 | ).forEach((e) => e.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopmp3.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopmp3.mp3
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopmp4.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/web-accessible-resources/redirects/noopmp4.mp4
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/rfi.js:
--------------------------------------------------------------------------------
1 | document.getElementsByTagName('body')[0].classList.remove("didomi-popup-open")
2 |
3 | document.querySelectorAll(
4 | '#didomi-host'
5 | ).forEach(el => el.remove())
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/theblaze.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sailthru-overlay-container,.sailthru-overlay-container,[id^="sFooter_"],#push-overlay,.overlay-bg'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/theeconomist.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | 'div[id^="sp_message_container"],#sp_message_container_658357,.advert,#piano-ribbon'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/theonion.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.js_modal_exit_intent,.js_sticky-top-ad,.js_welcome-ad-mobile--container,.ad-container'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/torontostar.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.c-article-list-ad,.leaderboard-ad-component,.c-recommended-for-you__cta,.c-googleadslot'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lehuffpost.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.gdpr-glm-standard,.leaderboard-flex-placeholder-desktop,.leaderboard-flex-placeholder,.gdpr-hfp-wall'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/qctimes.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#x-reveal-ad'
3 | ).forEach(el => el.style.display = 'none')
4 |
5 |
6 | document.querySelector('#site-container').style.marginTop = 0;
7 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thedbk.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#div-gpt-ad-1598471439011-0,#div-gpt-ad-1596391450199-0,#panel-375410-0-1-0,#panel-375410-0-1-1'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/1x1-transparent.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/web-accessible-resources/redirects/1x1-transparent.gif
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/2x2-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/web-accessible-resources/redirects/2x2-transparent.png
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/3x2-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/web-accessible-resources/redirects/3x2-transparent.png
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/baltimoremag.js:
--------------------------------------------------------------------------------
1 | document
2 | .querySelectorAll(".leadinModal-overlay,.leadinModal-content,#hs-interactives-modal-overlay,#hs-web-interactives-top-anchor")
3 | .forEach((el) => el.remove());
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/wcfcourier.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#x-reveal-ad'
3 | ).forEach(el => el.style.display = 'none')
4 |
5 |
6 | document.querySelectorAll('#site-container').forEach((e) => e.remove());
7 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/32x32-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/palewire/news-homepages/HEAD/newshomepages/extensions/adguard/web-accessible-resources/redirects/32x32-transparent.png
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/ledevoir.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#alertesNavigateur,.modal-backdrop,.modal'
3 | ).forEach(el => el.remove())
4 |
5 | document.getElementsByTagName('body')[0].classList.remove("modal-open")
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/elcorreo_com.js:
--------------------------------------------------------------------------------
1 | const firstDiv = document.querySelector('div');
2 | if (firstDiv.innerHTML === '') {
3 | firstDiv.remove();
4 | }
5 |
6 | document.querySelectorAll(
7 | '.v-adv'
8 | ).forEach(el => el.remove())
9 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/vcstar.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#gnt_mol_oy'
3 | ).forEach(el => el.style.display = 'none')
4 |
5 | document.querySelectorAll('[aria-label="advertisement"]').forEach(el => el.style.display = 'none')
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/nytimes.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('[data-testid="StandardAd"],#complianceOverlay').forEach(el => el.remove())
2 |
3 | document.querySelectorAll(
4 | '.ad,.e1xxpj0j0'
5 | ).forEach(el => el.style.display = "none")
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/france24.js:
--------------------------------------------------------------------------------
1 | document.getElementsByTagName('body')[0].classList.remove("didomi-popup-open")
2 |
3 | document.querySelectorAll(
4 | '.m-block-ad,.o-pwa-ah2s,.o-ad-container,#didomi-host'
5 | ).forEach(el => el.remove())
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/frednewspost.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#tncms-block-779600,#tncms-block-779599,#ad-779608,#carousel-617349,#ad-985838,#tncms-region-global-container-top,#ad-779608'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lajornada.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.ad,.ad-content' // <-- Pull your page’s identifiers here. If there's more than one thing to target you can comma seperate them.
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lemonde_en.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#banniere_haute,#pave_haut,.gdpr-lmd-wall,.gdpr-lmd-standard,.gdpr-lmd-standard gdpr-lmd-standard--transparent-deny,.gdpr-lmd-wall__content'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/lemondefr.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#banniere_haute,#pave_haut,.gdpr-lmd-wall,.gdpr-lmd-standard,.gdpr-lmd-standard gdpr-lmd-standard--transparent-denys,.gdpr-lmd-wall__content'
3 | ).forEach(el => el.remove())
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/france24_en.js:
--------------------------------------------------------------------------------
1 | document.getElementsByTagName('body')[0].classList.remove("didomi-popup-open")
2 |
3 | document.querySelectorAll(
4 | '.m-block-ad,.o-pwa-ah2s,.o-ad-container,#didomi-host'
5 | ).forEach(el => el.remove())
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/baltimoresun.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | 'div#fPennS1oKJvw1t,.met-footer-toast,.met-toaster-zepcomponent,#ad_unit,.dfp-feature wrapper,.bxc,#onesignal-slidedown-container,.dfp-feature'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/telegraph.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.martech-modal-component-overlay'
3 | ).forEach(el => el.remove())
4 |
5 | document.querySelectorAll(
6 | '.subscribe-banner,#advert_tmg_ban'
7 | ).forEach(el => el.style.display = 'none')
8 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "pip"
4 | directory: "/"
5 | schedule:
6 | interval: "monthly"
7 | - package-ecosystem: "github-actions"
8 | directory: "/"
9 | schedule:
10 | interval: "monthly"
11 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thephilacitizen.js:
--------------------------------------------------------------------------------
1 | // Loop through all elements in the document
2 | // and remove any with a z-index over 9999
3 | document.querySelectorAll('*').forEach(el => {
4 | if (window.getComputedStyle(el).zIndex > 9999) {
5 | el.remove()
6 | }
7 | })
8 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Reporting a Vulnerability
4 |
5 | If you've found a vulnerability in the project, please contact maintainer Ben Welsh at [b@palewi.re](mailto:b@palewi.re) or send him a direct message on Twitter at [@palewire](https://www.twitter.com/palewire).
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/abc_es.js:
--------------------------------------------------------------------------------
1 | const firstDiv = document.querySelector('div');
2 | if (firstDiv.innerHTML === '') {
3 | firstDiv.remove();
4 | }
5 |
6 | document.querySelectorAll(
7 | '.v-adv,.voc-container-fw,.voc-container--bg-color'
8 | ).forEach(el => el.remove())
9 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/guardian.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.ad_unit,div[id^="sp_message_container"],#sp_message_container_597005,.top-banner-ad-container,.site-message--banner,.remote-banner,.message-container,#notice'
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/libe.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '[class^="StickyAd"]'
3 | ).forEach(el => el.style.display = 'none')
4 |
5 | document.querySelectorAll(
6 | '.message-container,.message-container,[id^="sp_message_container"]'
7 | ).forEach(el => el.remove())
8 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/cnn.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll('#scrollover-ad-wrap').forEach((e) => e.remove());
2 |
3 | document.querySelectorAll(
4 | '.ad,.ad--epic'
5 | ).forEach(el => el.remove())
6 |
7 | document.querySelectorAll('body').forEach((e) => {
8 | e.style.paddingTop = 0;
9 | })
10 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/corriere.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#ac-Overlay,#ac-notice,.privacy-cp-wall,.bck-adblock,.tp-modal'
3 | ).forEach(el => el.remove())
4 |
5 | // Remove the has--adblock class from the html tag element
6 | document.querySelector('html').classList.remove('has--adblock')
7 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/pajaropolitico.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#div-gpt-ad-8828989-1,#div-gpt-ad-8828989-2,#div-gpt-ad-8828989-3,.app_fondea' // <-- Pull your page’s identifiers here. If there's more than one thing to target you can comma seperate them.
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | A guide on how to contribute to the repository can be found at [https://homepages.news](https://palewi.re/docs/news-homepages/#contributing). It includes [how to add a site](https://palewi.re/docs/news-homepages/adding.html) or a [Slack bot](https://palewi.re/docs/news-homepages/slack.html).
4 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/css/nanobar.css:
--------------------------------------------------------------------------------
1 | .adg-progress-bar {
2 | height: 2px;
3 | }
4 |
5 | .adg-progress-bar .bar {
6 | background: #66b574;
7 | background: linear-gradient(45deg, rgba(99, 125, 120, 1) 0%, rgba(88, 177, 101, 1) 100%);
8 | box-shadow: 0 0 10px #66b574, 0 0 5px #66b574;
9 | }
10 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md LICENSE CONTRIBUTING.md CODE_OF_CONDUCT.md SECURITY.md
2 | recursive-include newshomepages/extensions *
3 | recursive-include newshomepages/sources *
4 | recursive-exclude extracts *
5 | recursive-exclude _notebooks *
6 | recursive-exclude _site *
7 | recursive-exclude _dist *
8 | recursive-exclude tests *
9 |
--------------------------------------------------------------------------------
/_site/_templates/bundles.md.tmpl:
--------------------------------------------------------------------------------
1 | # Categories
2 |
3 | Sites are grouped into {{ bundle_list|length }} bundles based on location, ideology and topic.
4 |
5 | | Bundle |
6 | | :----- |
7 | {% for obj in bundle_list -%}
8 | |[{{ obj.name }}](https://palewi.re/docs/news-homepages/bundles/{{ obj.slug }}.html)|
9 | {% endfor %}
10 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/pioneerpress.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.Mg2-connext,.mg2bn-body,.pushly_popover-box,.div-gpt-ad-interstitial,[id^="google_ads_"],.pushly_popover,#pushnav-container,#zeus_interstitial,.dfp-ad'
3 | ).forEach(el => el.style.display = 'none')
4 |
5 | document.querySelector('#page').style.paddingTop = 0;
6 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/statnews.js:
--------------------------------------------------------------------------------
1 | var styles = `
2 | .stat-modal-base {
3 | display: none;
4 | `;
5 | var styleSheet = document.createElement("style")
6 | styleSheet.innerText = styles
7 | document.head.appendChild(styleSheet)
8 |
9 | document.querySelectorAll(
10 | '.stat-modal-base'
11 | ).forEach(el => el.remove())
12 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thetriibe.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.triibe-modal,.pum-overlay'
3 | ).forEach(el => el.remove())
4 |
5 | const text = 'ad blocker';
6 |
7 | for (const div of document.querySelectorAll('div')) {
8 | if (div.textContent.toLowerCase().includes(text)) {
9 | div.remove();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thewrap.js:
--------------------------------------------------------------------------------
1 | var styles = `
2 | #attentive_overlay {
3 | display: none;
4 | `;
5 | var styleSheet = document.createElement("style")
6 | styleSheet.innerText = styles
7 | document.head.appendChild(styleSheet)
8 |
9 | document.querySelectorAll(
10 | '#attentive_overlay'
11 | ).forEach(el => el.remove())
12 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/usatoday.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#gnt_mol_oy'
3 | ).forEach(el => el.style.display = 'none')
4 |
5 | document.querySelectorAll('[aria-label="advertisement"]').forEach(el => el.style.display = 'none')
6 | document.querySelectorAll('#onetrust-banner-sdk').forEach(el => el.style.display = 'none')
7 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/estadao.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | ".evg-overlay,.evg-popup,#lgpd,#house-ad-link,.house-ad-link"
3 | ).forEach((e) => e.remove());
4 |
5 | // Remove any element with a class that starts with styles__Container-sc-
6 | document.querySelectorAll("[class^='styles__Container-sc-']").forEach((e) => e.remove());
7 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/el_universal_mx.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#sliding-popup,.popup-content,#canvas,#dfp-ad-portada_desk_skin1-wrapper,#dfp-ad-portada_desk_bottom1-wrapper' // <-- Pull your page’s identifiers here. If there's more than one thing to target you can comma seperate them.
3 | ).forEach(el => el.style.display = 'none')
4 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/moreperfectus.js:
--------------------------------------------------------------------------------
1 | var styles = `
2 | .glow, .glow--active {
3 | display: none;
4 | `;
5 | var styleSheet = document.createElement("style")
6 | styleSheet.innerText = styles
7 | document.head.appendChild(styleSheet)
8 |
9 | document.querySelectorAll(
10 | '.glow,.glow--active'
11 | ).forEach(el => el.remove())
12 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/ntdaily.js:
--------------------------------------------------------------------------------
1 | var styles = `
2 | .mc-modal,.mc-modal-bg {
3 | display: none;
4 | `;
5 | var styleSheet = document.createElement("style")
6 | styleSheet.innerText = styles
7 | document.head.appendChild(styleSheet)
8 |
9 | document.querySelectorAll(
10 | '.mc-modal,.mc-modal-bg'
11 | ).forEach(el => el.remove())
12 |
--------------------------------------------------------------------------------
/tests/test_extract.py:
--------------------------------------------------------------------------------
1 | from click.testing import CliRunner
2 |
3 | from newshomepages.extract import cli
4 |
5 |
6 | def test_extract_item(tmp_path):
7 | """Test a site's item download."""
8 | runner = CliRunner()
9 | result = runner.invoke(cli, ["items", "latimes", "--output-dir", tmp_path])
10 | assert result.exit_code == 0
11 |
--------------------------------------------------------------------------------
/tests/test_adstxt.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from click.testing import CliRunner
3 |
4 | from newshomepages import adstxt
5 |
6 |
7 | @pytest.mark.vcr()
8 | def test_adstxt_cli(tmp_path):
9 | """Test a single ads.txt request."""
10 | runner = CliRunner()
11 | result = runner.invoke(adstxt.cli, ["reuters", "-o", tmp_path])
12 | assert result.exit_code == 0
13 |
--------------------------------------------------------------------------------
/_site/_templates/languages.md.tmpl:
--------------------------------------------------------------------------------
1 | # Languages
2 |
3 | The archiving routine is currently saving sites in {{ language_list|length }} languages.
4 |
5 | | Country | Sites |
6 | | :------- | :---- |
7 | {% for obj in language_list -%}
8 | |[{{ obj.name }}](https://palewi.re/docs/news-homepages/languages/{{ obj.part1|lower }}.html)|{{ obj.site_list|length }}|
9 | {% endfor %}
10 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/bn/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/kn/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/lv/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/sr/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/ta/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/te/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/latimes.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '[data-ad-rendered],#ensNotifyBanner'
3 | ).forEach(el => el.style.display = 'none');
4 |
5 | setTimeout(function(){
6 | scroll(0, 100);
7 | setTimeout( function(){
8 | document.querySelectorAll('modality-custom-element').forEach(el => el.remove());
9 | }, 1000)
10 | } , 1000)
11 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/fil/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/_locales/mk-MK/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": {
3 | "message": "AdGuard AdBlocker"
4 | },
5 | "short_name": {
6 | "message": "AdGuard"
7 | },
8 | "description": {
9 | "message": "Unmatched adblock extension against advertising and pop-ups. Blocks ads on Facebook, Youtube and all other websites."
10 | }
11 | }
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/chicagotribune.js:
--------------------------------------------------------------------------------
1 | window.onload = function() {
2 | var sels = ['.met-footer-toast', '#onesignal-slidedown-container']
3 | sels.forEach( function(d){
4 | var el = document.querySelector(d)
5 | if (el != undefined) {
6 | el.remove()
7 | }
8 | })
9 | }
10 | location.reload()
11 |
--------------------------------------------------------------------------------
/tests/test_hyperlinks.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from click.testing import CliRunner
3 |
4 | from newshomepages import hyperlinks
5 |
6 |
7 | @pytest.mark.vcr()
8 | def test_single(tmp_path):
9 | """Test a single hyperlinks download."""
10 | runner = CliRunner()
11 | result = runner.invoke(hyperlinks.cli, ["latimes", "-o", tmp_path])
12 | assert result.exit_code == 0
13 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/msnbc.js:
--------------------------------------------------------------------------------
1 | var styles = `
2 | .notification-soft-optin {
3 | display: none;
4 | `;
5 |
6 | var styleSheet = document.createElement("style")
7 | styleSheet.innerText = styles
8 | document.head.appendChild(styleSheet)
9 |
10 | document.querySelectorAll(
11 | '.header-and-footer--banner-ad,.notification-soft-optin'
12 | ).forEach(el => el.style.display = 'none')
13 |
--------------------------------------------------------------------------------
/tests/test_accessibility.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from click.testing import CliRunner
3 |
4 | from newshomepages import accessibility
5 |
6 |
7 | @pytest.mark.vcr()
8 | def test_accessibility_cli(tmp_path):
9 | """Test a single accessibility run."""
10 | runner = CliRunner()
11 | result = runner.invoke(accessibility.cli, ["drudge", "-o", tmp_path])
12 | assert result.exit_code == 0
13 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/pulitzercenter.js:
--------------------------------------------------------------------------------
1 | var styles = `
2 | .sumo-form-wrapper, .sumo-form-wrapper.listbuilder-popup {
3 | display: none;
4 | `;
5 |
6 | var styleSheet = document.createElement("style")
7 | styleSheet.innerText = styles
8 | document.head.appendChild(styleSheet)
9 |
10 | document.querySelectorAll(
11 | '.sumo-form-wrapper,.listbuilder-popup'
12 | ).forEach(el => el.remove())
13 |
--------------------------------------------------------------------------------
/newshomepages/analyze/cli.py:
--------------------------------------------------------------------------------
1 | import click
2 |
3 | from .drudge import cli as cli_drudge
4 | from .lighthouse import cli as cli_lighthouse
5 | from .us_right_wing import cli as cli_us_right_wing
6 |
7 | cli_group = click.CommandCollection(
8 | sources=[
9 | cli_drudge,
10 | cli_lighthouse,
11 | cli_us_right_wing,
12 | ]
13 | )
14 |
15 | if __name__ == "__main__":
16 | cli_group()
17 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/shield.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/devtools.html:
--------------------------------------------------------------------------------
1 | AdGuard devtools
--------------------------------------------------------------------------------
/_site/_templates/sources.md.tmpl:
--------------------------------------------------------------------------------
1 | # Sites
2 |
3 | The archiving routine is currently capturing {{ site_list|length }} sites.
4 |
5 | | Site | Latest screenshot |
6 | | :---- | :---------------: |
7 | {% for obj in site_list -%}
8 | |[{{ obj.name }}](https://palewi.re/docs/news-homepages/sites/{{ obj.handle }}.html)|[🔗](https://raw.githubusercontent.com/palewire/news-homepages/main/latest-screenshots/{{ obj.handle }}.jpg)|
9 | {% endfor %}
10 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/popup.html:
--------------------------------------------------------------------------------
1 | AdGuard Popup
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/civilbeat.js:
--------------------------------------------------------------------------------
1 | var styles = `
2 | .poston-campaign, #om-h8bkg1lyokdvbncwkfgg, .Campaign, .CampaignType--popup, .Campaign--css {
3 | display: none !important;
4 | }
5 | `;
6 | var styleSheet = document.createElement("style")
7 | styleSheet.innerText = styles
8 | document.head.appendChild(styleSheet)
9 |
10 | document.querySelectorAll(
11 | '.poston-campaign,#om-h8bkg1lyokdvbncwkfgg,.Campaign,.CampaignType--popup,.Campaign--css'
12 | ).forEach(el => el.remove())
13 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thehilltimes.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '.slide-down,.ads'
3 | ).forEach(el => el.remove())
4 |
5 | var styleSheet = document.createElement('style');
6 | styleSheet.innerText = '.content-section { padding-top: 0 !important; }';
7 | document.head.appendChild(styleSheet);
8 |
9 | document.querySelectorAll(
10 | '.content-section'
11 | ).forEach(el => {
12 | el.style.removeProperty('paddingTop');
13 | el.style.paddingTop = "0px";
14 | })
15 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/trash.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/ar/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": ""
4 | },
5 | "userscriptDescription": {
6 | "message": ""
7 | },
8 | "browserExtensionName": {
9 | "message": ""
10 | },
11 | "browserExtensionDescription": {
12 | "message": ""
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": ""
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": ""
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/bg/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": ""
4 | },
5 | "userscriptDescription": {
6 | "message": ""
7 | },
8 | "browserExtensionName": {
9 | "message": ""
10 | },
11 | "browserExtensionDescription": {
12 | "message": ""
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": ""
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": ""
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/et/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": ""
4 | },
5 | "userscriptDescription": {
6 | "message": ""
7 | },
8 | "browserExtensionName": {
9 | "message": ""
10 | },
11 | "browserExtensionDescription": {
12 | "message": ""
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": ""
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": ""
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/fa/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": ""
4 | },
5 | "userscriptDescription": {
6 | "message": ""
7 | },
8 | "browserExtensionName": {
9 | "message": ""
10 | },
11 | "browserExtensionDescription": {
12 | "message": ""
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": ""
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": ""
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/hy/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": ""
4 | },
5 | "userscriptDescription": {
6 | "message": ""
7 | },
8 | "browserExtensionName": {
9 | "message": ""
10 | },
11 | "browserExtensionDescription": {
12 | "message": ""
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": ""
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": ""
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/sv/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": ""
4 | },
5 | "userscriptDescription": {
6 | "message": ""
7 | },
8 | "browserExtensionName": {
9 | "message": ""
10 | },
11 | "browserExtensionDescription": {
12 | "message": ""
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": ""
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": ""
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/report-a-broken-site.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Report a broken site
3 | about: Is a screenshot busted? Are there popups or ads in the way? Let's get it fixed.
4 | title: "[Fix site]: "
5 | labels: bug, good first issue, help wanted
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Screenshot
11 | [Upload screenshot here]
12 |
13 | A solution is often found by adding JavaScript or CSS via a site-specific include, [as covered in our documentation](https://palewi.re/docs/news-homepages/adding.html#hide-ads-and-popups).
14 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/ad-blocked.html:
--------------------------------------------------------------------------------
1 | Access Denied Loading Blocked by AdGuard
Javascript is required to unblock this request.
--------------------------------------------------------------------------------
/newshomepages/site/source_list.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 |
4 | from .. import utils
5 | from .utils import _write_template
6 |
7 |
8 | @click.group()
9 | def cli():
10 | """Create source list."""
11 | pass
12 |
13 |
14 | @cli.command()
15 | def source_list():
16 | """Create source list."""
17 | site_list = sorted(utils.get_site_list(), key=lambda x: x["name"].lower())
18 | print(":newspaper: Creating site list page")
19 | _write_template("sources.md", dict(site_list=site_list))
20 |
--------------------------------------------------------------------------------
/newshomepages/site/bundle_list.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 |
4 | from .. import utils
5 | from .utils import _write_template
6 |
7 |
8 | @click.group()
9 | def cli():
10 | """Create bundle list."""
11 | pass
12 |
13 |
14 | @cli.command()
15 | def bundle_list():
16 | """Create bundle list."""
17 | bundle_list = sorted(utils.get_bundle_list(), key=lambda x: x["name"].lower())
18 | print(":basket: Creating bundle list page")
19 | _write_template("bundles.md", dict(bundle_list=bundle_list))
20 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/filtering-log.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/safebrowsing.html:
--------------------------------------------------------------------------------
1 | Access Denied Loading AdGuard has blocked access to this page
Javascript is required to unblock this request.
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/popup.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: #eee;
3 | background: rgb(41, 42, 45);
4 | font-family: sans-serif;
5 | }
6 |
7 | .container {
8 | padding: 10px 20px;
9 | width: 232px;
10 | }
11 |
12 | a {
13 | color: rgb(220, 149, 255);
14 | text-decoration: underline;
15 | }
16 |
17 | a:hover {
18 | color: rgb(124, 66, 178);
19 | }
20 |
21 | h2 {
22 | margin-top: 1px;
23 | }
24 |
25 | p {
26 | font-size: 13px;
27 | line-height: 17px;
28 | }
29 |
30 | .logo {
31 | width: 170px;
32 | }
33 |
--------------------------------------------------------------------------------
/_site/_templates/drudge-top-words.svg.tmpl:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% for value in obj.timeseries %}
4 |
11 |
12 | {%- endfor %}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/thetimes.js:
--------------------------------------------------------------------------------
1 | const style = document.createElement('style')
2 | style.innerHTML = `
3 | #sp_message_container_523772 {
4 | display:none!important
5 | }
6 |
7 | #ad-news {
8 | display:none!important
9 | }
10 |
11 | react-edition-personalised-article-rail {
12 | display: none!important
13 | }`
14 |
15 | document.head.appendChild(style)
16 |
17 | document.querySelectorAll(
18 | '.type-modal,#ad-header,.Tooltip,#sticky-ad-header,#react-edition-subscription-marketing-banner-slice'
19 | ).forEach(el => el.style.display = 'none')
20 |
--------------------------------------------------------------------------------
/tests/test_screenshot.py:
--------------------------------------------------------------------------------
1 | from click.testing import CliRunner
2 |
3 | from newshomepages import screenshot
4 |
5 |
6 | def test_cropped(tmp_path):
7 | """Test a cropped screenshot."""
8 | runner = CliRunner()
9 | result = runner.invoke(screenshot.cli, ["drudge", "-o", tmp_path])
10 | assert result.exit_code == 0
11 |
12 |
13 | def test_full(tmp_path):
14 | """Test a full-page screenshot."""
15 | runner = CliRunner()
16 | result = runner.invoke(screenshot.cli, ["drudge", "-o", tmp_path, "--full-page"])
17 | assert result.exit_code == 0
18 |
--------------------------------------------------------------------------------
/_site/_templates/latest.md.tmpl:
--------------------------------------------------------------------------------
1 | # Latest screenshots
2 |
3 | The most recent homepages captured from {{ site_list|length }} news sites.
4 |
5 |
6 | {% for obj in site_list %}
7 |
15 | {% endfor %}
16 |
17 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/css/fonts.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | @font-face {
3 | font-family: 'Open Sans';
4 | url('../fonts/opensans-regular-webfont.woff2') format('woff2'),
5 | font-weight: normal;
6 | font-style: normal;
7 | }
8 |
9 | @font-face {
10 | font-family: 'Open Sans';
11 | url('../fonts/opensans-semibold-webfont.woff2') format('woff2'),
12 | font-weight: 600;
13 | font-style: normal;
14 | }
15 |
16 | @font-face {
17 | font-family: 'Open Sans';
18 | url('../fonts/opensans-bold-webfont.woff2') format('woff2'),
19 | font-weight: bold;
20 | font-style: normal;
21 | }
22 |
--------------------------------------------------------------------------------
/newshomepages/site/latest_screenshots.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 |
4 | from .. import utils
5 | from .utils import _write_template
6 |
7 |
8 | @click.group()
9 | def cli():
10 | """Create a page showing all of the latest screenshots."""
11 | pass
12 |
13 |
14 | @cli.command()
15 | def latest_screenshots():
16 | """Create page showing all of the latest screenshots."""
17 | site_list = sorted(utils.get_site_list(), key=lambda x: x["name"].lower())
18 | print(f":camera: Creating latest screenshots page with {len(site_list)} sites")
19 | _write_template("latest.md", dict(site_list=site_list))
20 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Options
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/newshomepages/site/language_list.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 |
4 | from .. import utils
5 | from .utils import _write_template
6 |
7 |
8 | @click.group()
9 | def cli():
10 | """Create language list."""
11 | pass
12 |
13 |
14 | @cli.command()
15 | def language_list():
16 | """Create language list."""
17 | language_list = utils.get_language_list()
18 | for d in language_list:
19 | d["site_list"] = utils.get_sites_in_language(d["part1"])
20 | print("🗣️ Creating language list page")
21 | _write_template(
22 | "languages.md",
23 | dict(language_list=language_list),
24 | )
25 |
--------------------------------------------------------------------------------
/_site/_templates/countries.md.tmpl:
--------------------------------------------------------------------------------
1 | # Countries
2 |
3 | The archiving routine is currently saving sites in {{ has_list|length }} countries.
4 |
5 | | Country | Sites |
6 | | :------- | :---- |
7 | {% for obj in has_list -%}
8 | |[{{ obj.name }}](https://palewi.re/docs/news-homepages/countries/{{ obj.alpha2|lower }}.html)|
9 | {% endfor %}
10 |
11 | The system is not yet archiving sites in the following {{ hasnot_list|length }} countries. Help us expand our coverage. Read [our guide to adding sites](https://palewi.re/docs/news-homepages/adding.html) and make a contribution.
12 |
13 | {% for obj in hasnot_list -%}
14 | * {{ obj.name }}
15 | {% endfor %}
16 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/options.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/content-script.js:
--------------------------------------------------------------------------------
1 | 'use strict';(() => {
2 | const scriptTag = document.createElement('script');
3 | scriptTag.setAttribute('type', 'text/javascript');
4 | scriptTag.className = 'extra';
5 | const browser = window.browser || chrome;
6 | const scriptSource = browser.runtime.getURL('userscript.js');
7 | const hash = Math.random().toString(36).substring(5);
8 | scriptTag.setAttribute('src', `${scriptSource}?${hash}`);
9 | const parent = document.head || document.documentElement;
10 | parent.appendChild(scriptTag);
11 | if (scriptTag.parentNode) {
12 | scriptTag.parentNode.removeChild(scriptTag);
13 | }
14 | })();
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/reload-ico-green.svg:
--------------------------------------------------------------------------------
1 | Group 20
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/cross.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/newshomepages/site/status_report.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 |
4 | from .. import utils
5 | from .utils import _write_template
6 |
7 |
8 | @click.group()
9 | def cli():
10 | """Create a status report."""
11 | pass
12 |
13 |
14 | @cli.command()
15 | def status_report():
16 | """Create a status report."""
17 | print("📊 Creating status report")
18 |
19 | # Get the latest status report extract
20 | url = "https://archive.org/download/news-homepages-extracts/status-report.json"
21 | context = utils.get_json_url(url, verbose=True)
22 |
23 | # Write the template
24 | _write_template("status-report.md", context)
25 |
26 |
27 | if __name__ == "__main__":
28 | cli()
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | An open-source archive that gathers, saves, shares and analyzes news homepages
2 |
3 | ## Links
4 |
5 | - Task runner: [github.com/palewire/news-homepages-runner](https://github.com/palewire/news-homepages-runner)
6 | - Internet Archive: [archive.org/details/news-homepages](https://archive.org/details/news-homepages)
7 | - Mastodon [mastodon.palewi.re/@newshomepages](https://mastodon.palewi.re/@newshomepages)
8 | - Documentation: [palewi.re/docs/news-homepages/](https://palewi.re/docs/news-homepages/index.html)
9 | - Packaging: [pypi.org/project/newshomepages](https://pypi.org/project/newshomepages/)
10 | - How to add a site: [palewi.re/docs/news-homepages/adding.html](https://palewi.re/docs/news-homepages/adding.html)
11 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/zh/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra 旨在解决常规的广告拦截规则无能为力的复杂情况。"
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra 浏览器扩展"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra 是一款应与 AdGuard 或其他全面广告拦截器一起使用的扩展。除了工具栏中的扩展程序图标外,它不提供任何用户界面。"
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "点击{link}此处{/link},您可以查看其生效的网站列表。 请注意,对不在此列表中的网站,它没有任何作用。"
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "如果您遇到任何问题,请{link}将其报告给我们{/link}。"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/ja/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extraは、通常の広告ブロックルールが十分ではない複雑なケースを解決するために設計されています。"
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extraブラウザ拡張機能"
10 | },
11 | "browserExtensionDescription": {
12 | "message": ""
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}こちら{/link}では、AdGuard Extraが動作するウェブサイトのリストを確認することができます。※このリストに載っていないサイトではAdGuard Extraは何もしません。"
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "問題がある場合は、{link}こちらから{/link}ご報告いただくようお願いいたします。"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/zh-TW/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "當常規的廣告封鎖規則不夠時,AdGuard Extra 旨在解決複雜的情況。"
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra 瀏覽器擴充功能"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra 是一款被假設與像 AdGuard 或任何其它之全面的廣告封鎖器一起被使用之夥伴擴充功能。除在該工具列中的擴充功能圖示之外,它沒提供使用者介面。"
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}於此{/link},您可查看它起作用的網站之清單。請注意,它於非在此清單中的網站上不做任何事情。"
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "如果您遇到有關這個的任何問題,請{link}向我們報告它們{/link}。"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/test_robotstxt.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 |
3 | import pytest
4 | import sqlite_robotstxt
5 | from click.testing import CliRunner
6 |
7 | from newshomepages import robotstxt
8 |
9 |
10 | @pytest.mark.vcr()
11 | def test_robotstxt_cli(tmp_path):
12 | """Test a single robots.txt request."""
13 | runner = CliRunner()
14 | result = runner.invoke(robotstxt.cli, ["latimes", "-o", tmp_path])
15 | assert result.exit_code == 0
16 |
17 |
18 | def test_sqlite_extensions():
19 | """Verify that the sqlite extension can be loaded."""
20 | db = sqlite3.connect(":memory:")
21 | db.enable_load_extension(True)
22 | sqlite_robotstxt.load(db)
23 | db.enable_load_extension(False)
24 | db.execute("select robotstxt_version()").fetchone()
25 | db.close()
26 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/css/devtools/custom.css:
--------------------------------------------------------------------------------
1 | .styles-section .style-properties .enabled-button {
2 | visibility: visible !important;
3 | }
4 |
5 | #select-attributes-checkbox {
6 | margin-left: 0px;
7 | vertical-align: middle;
8 | }
9 |
10 | .action-button {
11 | margin-top: 4px;
12 | margin-bottom: 4px;
13 | margin-left: 4px;
14 | }
15 |
16 | .rule-input {
17 | padding: 4px;
18 | }
19 |
20 | .webkit-css-property {
21 | color: #5a5a5a;
22 | }
23 |
24 | #filter-rule-text {
25 | border-left: none;
26 | border-right: none;
27 | border-top: none;
28 | border-bottom-width: 1px;
29 | }
30 |
31 | .separator-attributes {
32 | min-height: 21px;
33 | }
34 |
35 | .separator-properties {
36 | min-height: 17px;
37 | }
--------------------------------------------------------------------------------
/newshomepages/site/country_list.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 |
4 | from .. import utils
5 | from .utils import _write_template
6 |
7 |
8 | @click.group()
9 | def cli():
10 | """Create country list."""
11 | pass
12 |
13 |
14 | @cli.command()
15 | def country_list():
16 | """Create country list."""
17 | country_list = utils.get_country_list()
18 | for c in country_list:
19 | c["site_list"] = utils.get_sites_in_country(c["alpha2"])
20 | print("🗺️ Creating country list page")
21 | _write_template(
22 | "countries.md",
23 | dict(
24 | has_list=[c for c in country_list if len(c["site_list"])],
25 | hasnot_list=[c for c in country_list if not len(c["site_list"])],
26 | ),
27 | )
28 |
--------------------------------------------------------------------------------
/newshomepages/sources/javascript/news_letter.js:
--------------------------------------------------------------------------------
1 | document.querySelectorAll(
2 | '#top_banner,#topBanner'
3 | ).forEach(el => el.remove())
4 |
5 | var styles = `
6 | .onesignal-slidedown-container {
7 | display: none !important;
8 | visibility: hidden;
9 | position: absolute;
10 | right: -1000000;
11 | }
12 | `;
13 | var styleSheet = document.createElement("style")
14 | styleSheet.innerText = styles
15 | document.head.appendChild(styleSheet)
16 |
17 | function getZ (el) {
18 | const z = parseFloat(window.getComputedStyle(el).zIndex);
19 | if (Number.isNaN(z)) {
20 | return 0;
21 | } else {
22 | return z;
23 | }
24 | }
25 | const eleList = Array.from(document.querySelectorAll('body *'));
26 | eleList.filter(el => getZ(el) > 10000).forEach(el => el.remove());
27 |
--------------------------------------------------------------------------------
/_site/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
22 | livehtml:
23 | sphinx-autobuild -b html $(SOURCEDIR) $(BUILDDIR)/html
24 |
--------------------------------------------------------------------------------
/newshomepages/extract/cli.py:
--------------------------------------------------------------------------------
1 | import click
2 |
3 | from .accessibility import cli as cli_accessibility
4 | from .consolidate import cli as cli_consolidate
5 | from .hyperlinks import cli as cli_hyperlinks
6 | from .items import cli as cli_items
7 | from .lighthouse import cli as cli_lighthouse
8 | from .robotstxt import cli as cli_robotstxt
9 | from .status_report import cli as cli_status_report
10 | from .wayback import cli as cli_wayback
11 |
12 | cli_group = click.CommandCollection(
13 | sources=[
14 | cli_consolidate,
15 | cli_items,
16 | cli_accessibility,
17 | cli_hyperlinks,
18 | cli_lighthouse,
19 | cli_robotstxt,
20 | cli_status_report,
21 | cli_wayback,
22 | ]
23 | )
24 |
25 | if __name__ == "__main__":
26 | cli_group()
27 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/filter-download.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Triangle
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/ko/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra는 일반적인 광고 차단 규칙이 충분하지 않은 복잡한 문제를 해결하도록 설계되었습니다."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra 브라우저 확장 프로그램"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra는 AdGuard 같은 풀스케일 광고 차단기와 사용되어야 하는 컴패니언 확장 프로그램입니다. 툴바에서 확장 프로그램 아이콘에 대한 사용자 인터페이스 저장을 제공하지 않습니다."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}여기{/link}에서 작동하는 웹사이트 목록을 확인할 수 있습니다. 목록에 없는 웹사이트에는 아무 것도 하지 않는다는 것을 알아두세요."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "이것과 관련해서 문제가 있다면 {link}우리에게 알려주세요{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/tick.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/js/preload-theme.js:
--------------------------------------------------------------------------------
1 | /*
2 | this script is injected at the top of the page to display
3 | the desired color theme before the main bundle is loaded
4 | */
5 | (function () {
6 | const urlSearchParams = new URLSearchParams(window.location.search);
7 | const theme = urlSearchParams.get('theme');
8 | /*
9 | if theme parameter is missing or a system theme is selected,
10 | the desired color is selected using the css media query
11 | */
12 | if (!theme || theme === 'system') {
13 | return;
14 | }
15 | // the color changes through the selector so that it could be rewritten by css from the main bundle
16 | if (theme === 'dark') {
17 | document.body.classList.add('body_dark');
18 | }
19 | if (theme === 'light') {
20 | document.body.classList.add('body_light');
21 | }
22 | })();
23 |
--------------------------------------------------------------------------------
/newshomepages/site/country_detail.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 | from rich.progress import track
4 |
5 | from .. import utils
6 | from .utils import _write_template
7 |
8 |
9 | @click.group()
10 | def cli():
11 | """Create country detail pages."""
12 | pass
13 |
14 |
15 | @cli.command()
16 | def country_detail():
17 | """Create country detail pages."""
18 | country_list = utils.get_country_list()
19 | print(f"🗺️ Creating {len(country_list)} country detail pages")
20 |
21 | # For each site ...
22 | for obj in track(country_list):
23 | site_list = utils.get_sites_in_country(obj["alpha2"])
24 | if not len(site_list):
25 | continue
26 | context = {
27 | "country": obj,
28 | "site_list": sorted(site_list, key=lambda x: x["name"].lower()),
29 | }
30 | _write_template(
31 | "country_detail.md", context, f"countries/{obj['alpha2'].lower()}.md"
32 | )
33 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/he/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra מתוכנן לפתור מקרים מורכבים בהם כללים רגילים של חסימת פרסומות אינם מספיקים."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra הרחבת דפדפן"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra הוא הרחבה מלווה אשר אמורה להיות בשימוש עם חוסם פרסומות בקנה מידה מלא כמו AdGuard או כל אחד אחר. הוא אינו מספק ממשק משתמש עבור איקון ההרחבה בסרגל הכלים."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}כאן{/link} אתה יכול לבדוק את הרשימה של אתרים שבהם הוא עובד. אנא שים לב שהוא אינו עושה שום דבר באתרים אשר אינם נמצאים ברשימה."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "אם אתה נתקל בסוגיות כלשהן, אנא {link}דווח לנו עליהן{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/arrow-down-grey.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Icons/24/search green Copy
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/checked.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Line
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/newshomepages/site/language_detail.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 | from rich.progress import track
4 |
5 | from .. import utils
6 | from .utils import _write_template
7 |
8 |
9 | @click.group()
10 | def cli():
11 | """Create languages detail pages."""
12 | pass
13 |
14 |
15 | @cli.command()
16 | def language_detail():
17 | """Create languages detail pages."""
18 | language_list = utils.get_language_list()
19 | print(f"🗣️ Creating {len(language_list)} language detail pages")
20 |
21 | # For each site ...
22 | for obj in track(language_list):
23 | site_list = utils.get_sites_in_language(obj["part1"])
24 | if not len(site_list):
25 | continue
26 | context = {
27 | "language": obj,
28 | "site_list": sorted(site_list, key=lambda x: x["name"].lower()),
29 | }
30 | _write_template(
31 | "language_detail.md", context, f"languages/{obj['part1'].lower()}.md"
32 | )
33 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/fullscreen-user-rules.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/newshomepages/site/bundle_detail.py:
--------------------------------------------------------------------------------
1 | import click
2 | from rich import print
3 | from rich.progress import track
4 | from slugify import slugify
5 |
6 | from .. import utils
7 | from .utils import _write_template
8 |
9 |
10 | @click.group()
11 | def cli():
12 | """Create bundle detail pages."""
13 | pass
14 |
15 |
16 | @cli.command()
17 | def bundle_detail():
18 | """Create bundle detail pages."""
19 | # Get all bundles
20 | bundle_list = sorted(utils.get_bundle_list(), key=lambda x: x["name"].lower())
21 | print(f":basket: Creating {len(bundle_list)} bundle detail pages")
22 |
23 | # For each site ...
24 | for bundle in track(bundle_list):
25 | bundle["hashtag"] = slugify(bundle["name"], separator="")
26 | site_list = utils.get_sites_in_bundle(bundle["slug"])
27 | context = {
28 | "bundle": bundle,
29 | "site_list": sorted(site_list, key=lambda x: x["name"].lower()),
30 | }
31 | _write_template("bundle_detail.md", context, f"bundles/{bundle['slug']}.md")
32 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/da/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra er designet til at løse komplicerede tilfælde, hvor alm. adblockingregler ikke er nok."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra-browserudvidelse"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra er en ledsagerudvidelse, der forudsætter brug sammen med en fuldblods adblocker såsom AdGuard el.lign. Den har ingen grænseflade gem-mulighed til udvidelsesikonet på værktøjsbjælken."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Hér{/link} kan du tjekke listen over de websteder, hvor den fungerer. Bemærk, at den intet gør på de websteder, som ikke er på denne liste."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Støder du på problemer, så {link}anmeld dem venligst til os{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/cs/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra má za úkol řešit složité případy, když běžná pravidla pro blokování reklam nestačí."
7 | },
8 | "browserExtensionName": {
9 | "message": "Rozšíření prohlížeče AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra je další rozšíření, které lze použít spolu s plnohodnotnými blokátory reklam, jako je AdGuard nebo jiné. Nemá žádné uživatelské rozhraní kromě ikony rozšíření na panelu nástrojů."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Zde{/link} si můžete prohlédnout seznam webových stránek, na kterých funguje. Upozorňujeme, že na webových stránkách, které nejsou na tomto seznamu, nedělá nic."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Pokud narazíte na nějaké problémy, prosím {link}nahlaste nám je{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra is designed to solve complicated cases when regular ad blocking rules aren't enough."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra browser extension"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra is a companion extension that is supposed to be used with a full-scale ad blocker like AdGuard or any other. It provides no user interface save for the extension icon in the toolbar."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Here{/link} you can check out the list of the websites where it works. Please note that it doesn't do anything on the websites that are not on this list."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "If you encounter any issues with this, please {link}report them to us{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/hr/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra je dizajniran za rješavanje kompleksnih slučajeva kada opća pravila blokade oglasa nisu dovoljna."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra proširenje preglednika"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra je popratno proširenje koje se koristi za upotrebu s opsežnim blokerom oglasa poput AdGuarda ili bilo kojeg drugog. Ne nudi spremanje korisničkog sučelja za ikonu proširenja na alatnoj traci."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Ovdje{/link} možete pogledati popis web stranica na kojima to radi. Imajte na umu da ne čini ništa na web stranicama koje nisu na ovom popisu."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Ako naiđete na bilo kakve probleme, {link}prijavite nam ih{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/nl/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra is bedoeld om ingewikkelde gevallen op te lossen wanneer de standaard advertentie blokkeringsregels niet voldoende blijken."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra browser uitbreiding"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra is een uitbreiding die bedoeld is om te gebruiken naast een complete ad blocker zoals AdGuard of een andere. Het heeft zelf geen interface behalve het pictogram van de uitbreiding in de werkbalk."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Hier{/link} kan je nagaan op welke websites het werkt. Noteer dat het niks doet op websites die niet op de lijst staan."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Bij problemen hiermee, ajb {link}rapporteer ze aan ons{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/ro/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra este creeat să rezolve cazuri complexe când regulile uzuale de blocat reclame sunt insuficiente."
7 | },
8 | "browserExtensionName": {
9 | "message": "Extensie browser AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra este o extensie companion folosită cu un blocant de reclame complet ca AdGuard sau oricare altul. Nu oferă o interfață utilizator ci doar pictograma extensiei în bara de instrumente."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Aici{/link} puteți consulta lista de site-uri web unde funcționează. Vă rugăm să rețineți că nu face nimic pe site-uri web care nu sunt pe această listă."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Orice problemă întâlnită cu aceasta, vă rugăm {link}să ne-o raportați{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/sk/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra má za úlohu riešiť zložité prípady, keď bežné pravidlá blokovania reklám nestačia."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra rozšírenie prehliadača"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra je sprievodné rozšírenie, ktoré sa má používať s blokovaním reklám v plnom rozsahu, ako je AdGuard alebo iné. Neposkytuje žiadne užívateľské rozhranie na uloženie ikony rozšírenia na paneli nástrojov."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Tu{/link} si môžete pozrieť zoznam webových stránok, na ktorých funguje. Upozorňujeme, že na webových stránkach, ktoré nie sú na tomto zozname, nerobí nič."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Ak narazíte na akékoľvek problémy, {link}nahláste nám ich{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/fi/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra on suunniteltu ratkaisemaan monimutkaisia tapauksia kun tavalliset mainosten estosäännöt eivät riitä."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra -laajennus"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra on kumppanilaajennus, jota on tarkoitus käyttää laajamittaisen mainoseston kuten AdGuardin tai vastaavan kanssa. Se ei sisällä työkalupalkin kuvakketta lukuunottamatta lainkaan käyttöliittymää."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Täällä{/link} voit tarkastella listaa verkkosivustoista, joilla laajennus toimii. Huomioithan, että toiminto vaikuttaa vain sivustoihin, jotka ovat tällä listalla."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Jos havaitset ongelmia, pyydämme, että {link}raportoisit ne meille{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/no/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra er utformet for å løse kompliserte saker der vanlige blokkeringsoppføringer ikke strekker til."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra-nettleserutvidelse"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra er en følgesutvidelse som er ment å brukes sammen med en fullskala reklameblokkerer som AdGuard eller en annen en. Den har ikke noe brukergrensesnitt, bortsett fra utvidelsesikonet i verktøylinjen."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Her{/link} kan du sjekke ut listen over nettsteder som det fungerer på. Bemerk at den ikke gjør noe på nettsteder som ikke er på denne listen."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Hvis du støter på noen problemer med dette, vennligst {link}meld dem inn til oss{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/sr/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard ekstra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra bi trebalo da reši komplikovane slučajeve u kojima standardna pravila blokiranja reklama nisu dovoljna."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard ekstra proširenje za preglednike"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra je saradničko proširenje koje je predviđeno da se koristi sa potpunim blokatorom reklama kao što je AdGuard ili neki drugi. On nema korisničko okruženje osim ikonice proširenja na alatnoj traci."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Ovde{/link} možete proveriti listu sajtova gde to radi. Imajte na umu da se ništa neće dogoditi sa sajtovima koji nisu na listi."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Ako naiđete na bilo koji problem sa ovim, molimo vas da nam to {link}prijavite{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/lt/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra yra skirtas išspręsti sudėtingesnius atvejus, kai nepakanka įprastų skelbimų blokavimo taisyklių."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra naršyklės plėtinys"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra yra papildomas plėtinys, kuris turėtų būti naudojamas su visaverčiu reklamos blokatoriumi, pvz., AdGuard ar bet kuriuo kitu. Jis neturi vartotojo sąsajos, išskyrus įrankių juostoje esančią plėtinio piktogramą."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Čia{/link} galite peržiūrėti svetainių, kuriose jis veikia, sąrašą. Atkreipkite dėmesį, kad jis nieko nedaro svetainėse, kurių nėra šiame sąraše."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Jei kyla kokių nors problemų dėl to, {link}praneškite mums apie jas{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/uk/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra призначений для вирішення складних завдань, коли звичайних правил для блокування реклами недостатньо."
7 | },
8 | "browserExtensionName": {
9 | "message": "Розширення для браузера AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra — це додаткове розширення, призначене для використання з повноцінними блокувальниками вмісту, наприклад, AdGuard чи будь-якими іншими. Воно не має користувацького інтерфейсу, а лише піктограму в панелі завдань."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "Розширення працює не всюди, а лише на{link}вебсайтах зі списку{/link}. Зауважте, що в разі відсутності сайту в списку, розширення не працюватиме там."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Якщо у вас виникли проблеми, {link}повідомте про них{/link}, будь ласка."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/test_archive.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pathlib import Path
3 |
4 | from newshomepages import archive, utils
5 |
6 |
7 | def test_archive_clean_handle():
8 | """Test archive handle cleaning."""
9 |
10 | def _get_handle(x):
11 | return utils.safe_ia_handle(utils.get_site(x)["handle"])
12 |
13 | assert _get_handle("latimes") == "latimes"
14 | assert _get_handle("CNN") == "cnn"
15 |
16 |
17 | def test_archive_metadata():
18 | """Test the method that creates a metadata dict for uploading to archive.org."""
19 | data = utils.get_site("latimes")
20 | metadata = archive._get_item_metadata(data)
21 | assert metadata["collection"] == os.getenv("IA_COLLECTION")
22 | assert metadata["title"].startswith(f"{data['name']} homepages in ")
23 |
24 |
25 | def test_archive_file_dict():
26 | """Test the method that creates a file dict that's uploaded to archive.org."""
27 | data = utils.get_site("latimes")
28 | this_dir = Path(__file__).parent.absolute()
29 | input_dir = this_dir / "files"
30 | d = archive._get_file_dict(data, input_dir)
31 | assert len(d.keys()) == 1
32 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/id/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra dirancang untuk menyelesaikan kasus rumit saat aturan pemblokiran iklan biasa tidak cukup."
7 | },
8 | "browserExtensionName": {
9 | "message": "Ekstensi Peramban AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra adalah ekstensi pendamping yang seharusnya digunakan dengan pemblokir iklan skala penuh seperti AdGuard atau lainnya. Ini tidak menyediakan antarmuka pengguna kecuali ikon ekstensi di bilah alat."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Di sini{/link} anda bisa mengecek daftar situs web di mana bisa berfungsi. Perlu diketahui bahwa itu tidak akan melakukan apapun kepada situs web yang tidak tercantum di dalam daftar."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Jika Anda mengalami masalah dengan ini, harap {link}laporkan ke kami{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/sl/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "Uporabi AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra naj bi rešil zapletene primere, ko običajna pravila za zaviranje oglasov niso dovolj."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Dodatna razširitev brskalnika"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra je spremljevalna razširitev, ki naj bi se uporabljala s splošnim zaviralcem oglasov, kot je AdGuard ali kateri koli drug. Ne omogoča nobenega shranjevanja uporabniškega vmesnika z ikono razširitve v orodni vrstici."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Tukaj{/link} si lahko ogledate seznam spletnih strani na katerih deluje. Upoštevajte, da ne deluje na spletnih straneh, ki niso na tem seznamu."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Če naletite na kakršne koli težave s tem, prosimo, da nam to {link} prijavite{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/pt/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "O AdGuard Extra é indicado para resolver casos complicados onde as regras regulares de bloqueio de anúncios não são suficientes."
7 | },
8 | "browserExtensionName": {
9 | "message": "Extensão para navegador do AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra é uma extensão complementar que deve ser usada com um bloqueador de anúncios em escala real como o AdGuard ou qualquer outro. Ele não fornece nenhuma interface de usuário exceto o ícone da extensão na barra de ferramentas."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Aqui{/link} você pode conferir a lista dos sites onde ele funciona. Observe que ele não faz nada nos sites que não estão nesta lista."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Se você encontrar algum problema. Por favor, {link}informe-nos{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/be/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra прызначаны для вырашэння складаных выпадкаў, калі звычайных правілаў блакавання рэкламы недастаткова."
7 | },
8 | "browserExtensionName": {
9 | "message": "Браўзарнае пашырэнне AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra - гэта спадарожнае пашырэнне, якое мяркуецца выкарыстоўваць з поўнапамерным блакавальнікам рэкламы, такім як AdGuard ці любым іншым. Ён не падае карыстацкага інтэрфейсу, апроч значка пашырэння на панэлі прылад."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link} Тут {/ link} вы можаце азнаёміцца са спісам сайтаў, дзе ён працуе. Звярніце ўвагу, што ён нічога не робіць на сайтах, якіх няма ў гэтым спісе."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Калі ў вас паўстануць якія-небудзь праблемы, калі ласка, {link} паведаміце пра іх нам {/ link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/pt-PT/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "O AdGuard Extra é indicado para resolver casos complicados onde as regras regulares de bloqueio de anúncios não são suficientes."
7 | },
8 | "browserExtensionName": {
9 | "message": "Extensão do AdGuard Extra para navegador"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra é uma extensão complementar que deve ser usada com um bloqueador de anúncios em escala real como o AdGuard ou qualquer outro. Ele não fornece nenhuma interface de utilizador exceto o ícone da extensão na barra de ferramentas."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Aqui{/link} tu podes conferir a lista dos sítios onde ele funciona. Observe que ele não faz nada nos sítios que não estão nesta lista."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Se você encontrar algum problema. Por favor, {link}informe-nos{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/de/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra wurde entwickelt, um komplexe Fälle zu lösen, wenn normalen Regeln zum Sperren von Werbung nicht ausreichen."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra-Browsererweiterung"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra ist eine Zusatzerweiterung, die mit vollwertigem Werbeblocker wie AdGuard oder anderen verwendet werden kann. Sie bietet keine Benutzeroberfläche außer dem Symbol für die Erweiterung in der Symbolleiste."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Hier{/link} können Sie die Liste der Websites einsehen, auf denen es funktioniert. Bitte beachten Sie, dass nur Websites gefiltert werden, die in der Liste enthalten sind."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Wenn Sie dabei auf Probleme stoßen, {link}melden Sie uns diese bitte{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/es/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra está diseñado para resolver casos complicados cuando las reglas regulares para bloqueo de anuncios no son suficientes."
7 | },
8 | "browserExtensionName": {
9 | "message": "Extensión de navegador AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra es una extensión complementaria que se utiliza con un bloqueador de anuncios a gran escala como AdGuard o cualquier otro. No proporciona ninguna interfaz de usuario, salvo el icono de la extensión en la barra de herramientas."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Aquí{/link} puedes consultar la lista de los sitios web donde funciona. Ten en cuenta que no hace nada en los sitios web que no están en esta lista."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Si encuentras algún problema, por favor {link}infórmanos{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/it/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra è progettato per risolvere casi complicati in cui le normali regole di blocca-annunci non sono sufficienti."
7 | },
8 | "browserExtensionName": {
9 | "message": "Estensione browser AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra è un'estensione complementare che dovrebbe essere utilizzata con un blocco degli annunci su vasta scala come AdGuard o qualsiasi altro. Non fornisce alcuna interfaccia utente tranne l'icona dell'estensione nella barra degli strumenti."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Qui{/link} potrai verificare l'elenco dei siti in cui risulterà funzionante. Si prega di notare che non esegue alcuna operazione sui siti non in elenco."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Se dovessi riscontrare problemi, ti preghiamo di {link}riportaceli{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/pl/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra jest przeznaczony do rozwiązywania skomplikowanych przypadków, gdy zwykłe reguły blokowania reklam nie wystarczą."
7 | },
8 | "browserExtensionName": {
9 | "message": "Rozszerzenie przeglądarki AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra to rozszerzenie towarzyszące, które powinno być używane z pełni funkcjonalnym programem do blokowania reklam, takim jak AdGuard lub jakikolwiek inny. Nie zapewnia żadnego interfejsu użytkownika poza ikoną rozszerzenia na pasku narzędzi."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Tutaj{/link} możesz sprawdzić listę stron internetowych, na których to działa. Należy pamiętać, że nie działa to w witrynach, których nie ma na tej liście."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Jeśli napotkasz jakiekolwiek problemy, {link}zgłoś je nam{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/ru/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra предназначен для решения более сложных задач, когда обычных правил блокировки рекламы недостаточно."
7 | },
8 | "browserExtensionName": {
9 | "message": "Браузерное расширение AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra — это сопутствующее расширение, которое предполагается использовать с полноценным блокировщиком рекламы, таким как AdGuard или любым другим. У него нет пользовательского интерфейса, кроме значка расширения на панели инструментов."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Здесь{/link} вы можете ознакомиться со списком сайтов, где расширение работает. Обратите внимание, что оно ничего не делает на сайтах, которых нет в этом списке."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Если у вас возникнут какие-либо проблемы, пожалуйста, {link}сообщите о них нам{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/tr/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra, normal reklam engelleme kurallarının yeterli olmadığı karmaşık durumları çözmek için tasarlanmıştır."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra tarayıcı eklentisi"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra, AdGuard veya başka herhangi bir reklam aracı gibi tam ölçekli bir reklam engelleyiciyle kullanılması beklenen tamamlayıcı bir eklentidir. Araç çubuğundaki uzantı simgesi için kullanıcı arabirimi kaydetme olanağı sağlamaz."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Buraya{/link} tıklayarak çalıştığı web sitelerin listesine göz atabilirsiniz. Lütfen, bu listede bulunmayan web sitelerinde hiçbir şey yapmadığını unutmayın."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Bununla ilgili herhangi bir sorunla karşılaşırsanız, lütfen {link}bunları bize bildirin{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/_site/conf.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | from datetime import datetime
4 | from pathlib import Path
5 |
6 | THIS_DIR = Path(__file__).parent.absolute()
7 |
8 | sys.path.insert(0, os.path.abspath(".."))
9 | sys.path.insert(0, str(THIS_DIR.parent))
10 |
11 | extensions = [
12 | "myst_parser",
13 | "sphinx.ext.autodoc",
14 | "sphinx_click",
15 | ]
16 | templates_path = ["_templates"]
17 | source_suffix = {".rst": "restructuredtext"}
18 | master_doc = "index"
19 | html_extra_path = ["_extra"]
20 |
21 | project = "News Homepages"
22 | year = datetime.now().year
23 | copyright = f"{year} palewire"
24 |
25 | exclude_patterns = ["_build"]
26 |
27 | html_theme = "palewire"
28 | html_sidebars = {
29 | "**": [
30 | "about.html",
31 | "navigation.html",
32 | ]
33 | }
34 | html_theme_options = {
35 | "canonical_url": "https://palewi.re/docs/news-homepages/",
36 | }
37 |
38 | html_static_path = ["_static"]
39 | html_js_files = [
40 | "https://cdn.jsdelivr.net/npm/vega@5.22.1",
41 | "https://cdn.jsdelivr.net/npm/vega-lite@5.2.0",
42 | "https://cdn.jsdelivr.net/npm/vega-embed@6.20.8",
43 | ]
44 |
45 | pygments_style = "sphinx"
46 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/fr/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra est conçu pour résoudre les cas complexes lorsque les règles de blocage des publicités ne suffisent pas."
7 | },
8 | "browserExtensionName": {
9 | "message": "Extension pour le navigateur AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra est une extension complémentaire qui est censée être utilisée avec un bloqueur de publicité complet comme AdGuard ou autre. Il ne fournit aucune interface utilisateur, sauf pour l’icône d’extension dans la barre d’outils."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Ici{/link} vous pouvez consulter la liste des sites Web sur lesquels elle fonctionne. Veuillez noter qu’elle ne fait rien sur les sites Web qui ne figurent pas sur cette liste."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Si vous rencontrez des problèmes, veuillez {link}nous les signaler{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/hu/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "Az AdGuard Extra olyan bonyolultabb esetek megoldására szolgál, amikor a hagyományos hirdetésblokkolási szabályok nem elegendőek."
7 | },
8 | "browserExtensionName": {
9 | "message": "AdGuard Extra böngésző kiegészítő"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "Az AdGuard Extra egy kiegészítő, amelyet egy teljesértékű hirdetésblokkolóval együtt kell használni, mint például az AdGuard vagy bármi más. Nem biztosít felhasználói felületet, az eszközsoron található kiterjesztés ikont leszámítva."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Itt{/link} megtekintheti azon webhelyek listáját, amelyeken működik. Felhívjuk figyelmét, hogy nem csinál semmit azokon a webhelyeken, amelyek nem szerepelnek a listán."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Ha bármilyen észrevétele merülne fel ezzel kapcsolatban, kérjük, {link}jelentse nekünk{/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/_locales/vi/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "userscriptName": {
3 | "message": "AdGuard Extra"
4 | },
5 | "userscriptDescription": {
6 | "message": "AdGuard Extra được thiết kế để giải quyết các vấn đề khi mà các quy tắc chặn quảng cáo thông thường chưa đủ."
7 | },
8 | "browserExtensionName": {
9 | "message": "Tiện ích mở rộng Trình duyệt AdGuard Extra"
10 | },
11 | "browserExtensionDescription": {
12 | "message": "AdGuard Extra là một tiện ích mở rộng đồng hành được cho là sẽ được sử dụng với trình chặn quảng cáo toàn diện như AdGuard hoặc bất kỳ tiện ích nào khác. Nó không cung cấp lưu giao diện người dùng cho biểu tượng tiện ích mở rộng trên thanh công cụ."
13 | },
14 | "browserExtensionHostsMessage": {
15 | "message": "{link}Đây{/link} là nơi bạn có thể kiểm tra danh sách những trang web mà Adguard Extra hoạt động. Xin lưu ý rằng phần mềm sẽ không thay đổi bất cứ gì trên những trang web không được liệt kê ở danh sách này."
16 | },
17 | "browserExtensionReportMessage": {
18 | "message": "Nếu bạn không gặp bất cứ vấn đề nào với nó, xin vui lòng {link}báo cáo nó cho chúng tôi {/link}."
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | url = "https://pypi.org/simple"
3 | verify_ssl = true
4 | name = "pypi"
5 |
6 | [packages]
7 | click = "*"
8 | pytz = "*"
9 | internetarchive = ">=5.0.4"
10 | python-slugify = "*"
11 | playwright = "*"
12 | jinja2 = "*"
13 | shot-scraper = "*"
14 | pillow = "*"
15 | pandas = "*"
16 | rich = "*"
17 | iso3166 = "*"
18 | python-iso639 = "*"
19 | requests = "*"
20 | retry = "*"
21 | storysniffer = "*"
22 | spacy = "*"
23 | spectra = "*"
24 | "mastodon.py" = "*"
25 | sqlite-robotstxt = "*"
26 | "sqlean.py" = "*"
27 | libtorrent = "*"
28 |
29 | [dev-packages]
30 | pre-commit = "*"
31 | sphinx = "*"
32 | sphinx-autobuild = "*"
33 | myst-parser = "*"
34 | pytest = "*"
35 | flake8 = "*"
36 | flake8-docstrings = "*"
37 | flake8-bugbear = "*"
38 | mypy = "*"
39 | types-requests = "*"
40 | types-python-slugify = "*"
41 | types-pytz = "*"
42 | types-pyyaml = "*"
43 | sphinxcontrib-napoleon = "*"
44 | sphinx-click = "*"
45 | sphinx-palewire-theme = "==0.1.2"
46 | types-retry = "*"
47 | storysniffer = "*"
48 | ipywidgets = "*"
49 | setuptools-scm = "*"
50 | twine = "*"
51 | xlwt = "*"
52 | pytest-env = "*"
53 | pytest-cov = "*"
54 | pytest-vcr = "*"
55 | pytest-xdist = "*"
56 | exceptiongroup = "*"
57 | tomli = "*"
58 | jupyterlab = "*"
59 |
60 | [requires]
61 | python_version = "3.10"
62 |
--------------------------------------------------------------------------------
/_site/_templates/language_detail.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | orphan: true
3 | ---
4 |
5 | # {{ language.name }}
6 |
7 | The most recent homepages from {{ site_list|length }} news sites in this language.
8 |
9 |
10 | {% for obj in site_list %}
11 |
19 | {% endfor %}
20 |
21 |
22 | ## About this country
23 |
24 | | Attribute | Value |
25 | | :------------- | :---------------------------------------------------------------------------------- |
26 | | ISO code | {{ language.part1 }} |
27 |
28 | ## Site directory
29 |
30 | | Site | Latest screenshot |
31 | | :---- | :---------------: |
32 | {% for obj in site_list -%}
33 | |[{{ obj.name }}](https://palewi.re/docs/news-homepages/sites/{{ obj.handle }}.html)|[🔗](https://raw.githubusercontent.com/palewire/news-homepages/main/latest-screenshots/{{ obj.handle }}.jpg)|
34 | {% endfor %}
35 |
--------------------------------------------------------------------------------
/newshomepages/extract/utils.py:
--------------------------------------------------------------------------------
1 | import time
2 | from pathlib import Path
3 | from urllib.parse import urlparse
4 |
5 | import pandas as pd
6 | from rich import print
7 |
8 | from .. import utils
9 |
10 |
11 | def _get_json_url(url):
12 | # Prepare a cache
13 | cache_dir = Path("~/.cache").expanduser()
14 | cache_dir.mkdir(parents=True, exist_ok=True)
15 |
16 | # Check if the file has been downloaded
17 | output_path = cache_dir / urlparse(url).path.split("/")[-1]
18 | if output_path.exists():
19 | print(f":book: Reading in cached file {output_path}")
20 | return pd.read_json(output_path)
21 | else:
22 | # Get the URL
23 | data = utils.get_json_url(url, timeout=60, verbose=True)
24 |
25 | # Parse as a dataframe
26 | df = pd.DataFrame(data)
27 |
28 | # Write to cache
29 | df.to_json(output_path, orient="records", indent=2)
30 | print(f":pencil: Writing to cached file {output_path}")
31 | time.sleep(0.25)
32 |
33 | # Add columns
34 | metadata = utils.parse_archive_url(url)
35 | df["site_handle"] = metadata["handle"]
36 | df["item_identifier"] = metadata["identifier"]
37 | df["file_timestamp"] = metadata["timestamp"]
38 | df["file_url"] = url
39 |
40 | # Return dataframe
41 | return df
42 |
--------------------------------------------------------------------------------
/_site/_templates/country_detail.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | orphan: true
3 | ---
4 |
5 | # {{ country.name }}
6 |
7 | The most recent homepages from {{ site_list|length }} news sites in this country.
8 |
9 |
10 | {% for obj in site_list %}
11 |
19 | {% endfor %}
20 |
21 |
22 | ## About this country
23 |
24 | | Attribute | Value |
25 | | :------------- | :---------------------------------------------------------------------------------- |
26 | | ISO code | {{ country.alpha2 }} |
27 | | Twitter hashtag | [#{{ country.alpha2 }}](https://twitter.com/search?q=%23{{ country.alpha2 }}%20from%3A%40newshomepages) |
28 |
29 | ## Site directory
30 |
31 | | Site | Latest screenshot |
32 | | :---- | :---------------: |
33 | {% for obj in site_list -%}
34 | |[{{ obj.name }}](https://palewi.re/docs/news-homepages/sites/{{ obj.handle }}.html)|
35 | {% endfor %}
36 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/dropbox.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguardextra/options.js:
--------------------------------------------------------------------------------
1 | 'use strict';const LOCALE_TAG = 'i18n';
2 | const EXTRA_ISSUES_URL = 'https://github.com/AdguardTeam/AdGuardExtra/issues';
3 | const EXTRA_HOSTS_URL = 'https://github.com/AdguardTeam/AdGuardExtra#websites-where-adguard-extra-can-be-useful';
4 | const LINK_MARKER_START = '{link}';
5 | const LINK_MARKER_END = '{/link}';
6 | const getLocale = (key) => {
7 | const browser = window.browser || chrome;
8 | const translation = browser.i18n.getMessage(key);
9 | if (!translation) {
10 | return false;
11 | }
12 | return translation;
13 | };
14 | const translateAll = () => {
15 | const stringsI18n = document.querySelectorAll(`[${LOCALE_TAG}]`);
16 | [...stringsI18n].forEach((str) => {
17 | const attr = str.getAttribute(LOCALE_TAG);
18 | const locale = getLocale(attr);
19 | if (locale) {
20 | str.innerHTML = locale;
21 | }
22 | });
23 | };
24 | const addLink = (id, url) => {
25 | const element = document.querySelector(id);
26 | element.innerHTML = element.innerText
27 | .replace(LINK_MARKER_START, ``)
28 | .replace(LINK_MARKER_END, ' ');
29 | };
30 | window.onblur = () => {
31 | window.close();
32 | };
33 | translateAll();
34 | addLink('#hosts-message', EXTRA_HOSTS_URL);
35 | addLink('#report-message', EXTRA_ISSUES_URL);
--------------------------------------------------------------------------------
/newshomepages/site/cli.py:
--------------------------------------------------------------------------------
1 | import click
2 |
3 | from .accessibility_ranking import cli as cli_accessibility_ranking
4 | from .bundle_detail import cli as cli_bundle_detail
5 | from .bundle_list import cli as cli_bundle_list
6 | from .country_detail import cli as cli_country_detail
7 | from .country_list import cli as cli_country_list
8 | from .drudge import cli as cli_drudge
9 | from .language_detail import cli as cli_language_detail
10 | from .language_list import cli as cli_language_list
11 | from .latest_screenshots import cli as cli_latest_screenshots
12 | from .openai import cli as cli_openai
13 | from .performance_ranking import cli as cli_performance_ranking
14 | from .site_detail import cli as cli_site_detail
15 | from .source_list import cli as cli_source_list
16 | from .status_report import cli as cli_status_report
17 |
18 | cli_group = click.CommandCollection(
19 | sources=[
20 | cli_accessibility_ranking,
21 | cli_bundle_detail,
22 | cli_bundle_list,
23 | cli_country_detail,
24 | cli_country_list,
25 | cli_drudge,
26 | cli_language_detail,
27 | cli_language_list,
28 | cli_latest_screenshots,
29 | cli_openai,
30 | cli_performance_ranking,
31 | cli_site_detail,
32 | cli_source_list,
33 | cli_status_report,
34 | ]
35 | )
36 |
37 | if __name__ == "__main__":
38 | cli_group()
39 |
--------------------------------------------------------------------------------
/newshomepages/extract/items.py:
--------------------------------------------------------------------------------
1 | import typing
2 | from datetime import datetime
3 | from pathlib import Path
4 |
5 | import click
6 | import internetarchive
7 | from retry import retry
8 | from rich import print
9 |
10 | from .. import utils
11 |
12 |
13 | @click.group()
14 | def cli():
15 | """Download items from our archive.org collection as JSON."""
16 | pass
17 |
18 |
19 | @cli.command()
20 | @click.argument("handle")
21 | @click.option("-y", "--year", "year", default=None)
22 | @click.option("-o", "--output-dir", "output_dir", default="./")
23 | def items(
24 | handle: str,
25 | year: typing.Optional[typing.Any] = None,
26 | output_dir: str = "./",
27 | ):
28 | """Download items from our archive.org collection as JSON."""
29 | # Sanitize the year
30 | if year:
31 | year = int(year)
32 | else:
33 | year = datetime.now().year
34 |
35 | # Set the path
36 | output_path = Path(output_dir)
37 |
38 | # Pull the site
39 | site = utils.get_site(handle)
40 | _save_item(site, year, output_path)
41 |
42 |
43 | @retry(tries=5, delay=30, backoff=2)
44 | def _save_item(site: typing.Dict, year: int, output_path: Path):
45 | """Save an item as JSON to disk."""
46 | identifier = f"{site['handle']}-{year}"
47 | print(f"Downloading `{identifier}` from archive.org")
48 | item = internetarchive.get_item(identifier)
49 | utils.write_json(item.item_metadata, output_path / f"{item.identifier}.json")
50 |
--------------------------------------------------------------------------------
/newshomepages/batch.py:
--------------------------------------------------------------------------------
1 | import json
2 | import typing
3 |
4 | import click
5 |
6 | from . import utils
7 |
8 |
9 | @click.group()
10 | def cli():
11 | """Print a batch of sites."""
12 | pass
13 |
14 |
15 | @cli.command()
16 | @click.argument("batch")
17 | @click.option("-b", "--batches", "batches", default=10)
18 | def sites_by_batch(batch: str, batches: str):
19 | """Print site handles in the provided batch as a JSON list."""
20 | site_list = utils.get_site_list()
21 | batch_list = list(utils.batch(site_list, int(batches)))
22 | if int(batch) - 1 not in range(int(batches)):
23 | raise ValueError("Batch number not found")
24 | _dump(batch_list[int(batch) - 1])
25 |
26 |
27 | @cli.command()
28 | @click.argument("bundle")
29 | def sites_by_bundle(bundle: str):
30 | """Print site handles in the provided bundle as a JSON list."""
31 | site_list = utils.get_sites_in_bundle(bundle)
32 | _dump(site_list)
33 |
34 |
35 | @cli.command()
36 | @click.argument("country")
37 | def sites_by_country(country: str):
38 | """Print site handles in the provided country as a JSON list."""
39 | site_list = utils.get_sites_in_country(country)
40 | _dump(site_list)
41 |
42 |
43 | def _dump(site_list: typing.List):
44 | """Print out the provided site list as JSON."""
45 | handle_list = [s["handle"] for s in site_list]
46 | data = json.dumps(handle_list, indent=2)
47 | click.echo(data)
48 |
49 |
50 | if __name__ == "__main__":
51 | cli()
52 |
--------------------------------------------------------------------------------
/_site/_templates/bundle_detail.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | orphan: true
3 | ---
4 |
5 | # {{ bundle.name }}
6 |
7 | The most recent homepages from {{ site_list|length }} news sites in this bundle.
8 |
9 |
10 | {% for obj in site_list %}
11 |
19 | {% endfor %}
20 |
21 |
22 | ## About this bundle
23 |
24 | | Attribute | Value |
25 | | :------------- | :---------------------------------------------------------------------------------- |
26 | | Twitter hashtag | [#{{ bundle.hashtag }}](https://twitter.com/search?q=%23{{ bundle.hashtag }}%20from%3A%40newshomepages) |
27 | | Location | {{ bundle.location }} |
28 | | Timezone | {{ bundle.timezone }} |
29 |
30 | ## Site directory
31 |
32 | | Site | Latest screenshot |
33 | | :---- | :---------------: |
34 | {% for obj in site_list -%}
35 | |[{{ obj.name }}](https://palewi.re/docs/news-homepages/sites/{{ obj.handle }}.html)|[🔗](https://raw.githubusercontent.com/palewire/news-homepages/main/latest-screenshots/{{ obj.handle }}.jpg)|
36 | {% endfor %}
37 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/devtools.js:
--------------------------------------------------------------------------------
1 | (self["webpackChunkbrowser_extension"] = self["webpackChunkbrowser_extension"] || []).push([[893],{
2 |
3 | /***/ 968:
4 | /***/ (() => {
5 |
6 | /**
7 | * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
8 | *
9 | * Adguard Browser Extension is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * Adguard Browser Extension is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU General Public License
20 | * along with Adguard Browser Extension. If not, see .
21 | */
22 | const browser = window.browser || chrome; // TODO: Try to move it to first cell
23 |
24 | browser.devtools.panels.elements.createSidebarPane('AdGuard', sidebar => {
25 | sidebar.setHeight('400px');
26 | sidebar.setPage('../pages/devtools-elements-sidebar.html');
27 | });
28 |
29 | /***/ })
30 |
31 | },
32 | /******/ __webpack_require__ => { // webpackRuntimeModules
33 | /******/ var __webpack_exec__ = (moduleId) => (__webpack_require__(__webpack_require__.s = moduleId))
34 | /******/ var __webpack_exports__ = (__webpack_exec__(968));
35 | /******/ }
36 | ]);
--------------------------------------------------------------------------------
/_site/_templates/site_detail.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | orphan: true
3 | ---
4 |
5 | # {{ site.name }}
6 |
7 | 
8 |
9 | | Attribute | Value |
10 | | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------- |
11 | | Site | [{{ site.url }}]({{ site.url }}) |
12 | | Twitter handle | [@{{ site.handle }}](https://www.twitter.com/{{ site.handle }}) |
13 | | Location | {{ site.location }} |
14 | | Timezone | {{ site.timezone }} |
15 | | Country | [{{ site.country_name }}](https://palewi.re/docs/news-homepages/countries/{{ site.country|lower }}.html)
16 | | Language | [{{ site.language_name }}](https://palewi.re/docs/news-homepages/languages/{{ site.language|lower }}.html)
17 | {% if site.bundle_list %}| Bundles | {% for b in site.bundle_list %}{{ b.name }} {% if not loop.last %}, {% endif %} {% endfor %} |{% endif %}
18 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/toggler-bg.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | checked
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/_site/_static/custom.css:
--------------------------------------------------------------------------------
1 | table.align-default {
2 | margin-left: 0 !important;
3 | margin-right: 0 !important;
4 | }
5 |
6 | .latest-parent {
7 | display: flex;
8 | flex-wrap: wrap;
9 | justify-content: flex-start;
10 | }
11 |
12 | .latest-child {
13 | width: 212px;
14 | margin: 0 8px 8px 0;
15 | }
16 |
17 | .latest-child p {
18 | margin-top: 0;
19 | }
20 |
21 | @media (max-width: 550px) {
22 | .latest-child {
23 | width: 190px;
24 | }
25 | }
26 |
27 | .table-container {
28 | overflow-x: auto;
29 | }
30 |
31 | table.drudge-table {
32 | font-size: 16px;
33 | line-height: 22px;
34 | border: 0 !important;
35 | box-shadow: none !important;
36 | width: 100%;
37 | }
38 |
39 | table.drudge-table th {
40 | border: 0;
41 | padding-bottom: 0;
42 | }
43 |
44 | table.drudge-table td, table.drudge-table th {
45 | border-right: 0;
46 | border-left: 0;
47 | border-top: 0;
48 | }
49 |
50 | table.drudge-table tbody td {
51 | border-bottom: 0;
52 | padding: 0.5em 0.7em;
53 | vertical-align: bottom;
54 | }
55 |
56 | table.drudge-entities tbody td:first-of-type {
57 | padding-top: 0;
58 | }
59 |
60 | table.drudge-table tbody tr {
61 | border-bottom: 1px #e5e5e5 solid;
62 | }
63 |
64 | table.drudge-table tbody tr:last-of-type {
65 | border-bottom: 0 !important;
66 | }
67 |
68 | .drudge-table .rank {
69 | width: 40px;
70 | padding-left: 0;
71 | }
72 |
73 | .drudge-table .trend-chart {
74 | line-height: 16px;
75 | padding-top: 5px;
76 | }
77 |
78 | .trend-axis-label {
79 | font-size: 9px;
80 | width: 168px;
81 | }
82 |
83 | .trend-axis-right {
84 | float: right;
85 | }
86 |
--------------------------------------------------------------------------------
/_site/gettingstarted.md:
--------------------------------------------------------------------------------
1 | # Installing the repository
2 |
3 | ```{contents} Sections
4 | :local:
5 | :depth: 1
6 | ```
7 |
8 | ## Code
9 |
10 | Fork the [palewire/news-homepages](https://github.com/palewire/news-homepages) repository on GitHub and clone it on your computer. Move into the code directory and install the Python dependencies.
11 |
12 | ```bash
13 | pipenv install --dev
14 | ```
15 |
16 | Install pre-commit hooks.
17 |
18 | ```bash
19 | pipenv run pre-commit install
20 | ```
21 |
22 | Install Chrome for our web scraper.
23 |
24 | ```bash
25 | pipenv run playwright install --with-deps chromium
26 | ```
27 |
28 | You're ready to work. Try a screenshot with the `screenshot.py` command. As with other commands, it expects you pass in the unique handle of the target site. The supported sites are listed in [`newshomepages/sources/sites.csv`](https://github.com/palewire/news-homepages/blob/main/newshomepages/sources/sites.csv). We use them as a unique identifier across the project.
29 |
30 | ```bash
31 | pipenv run python -m newshomepages.screenshot latimes
32 | ```
33 |
34 | ## Environment variables
35 |
36 | Some of the commands require that you set environment variables with secret credentials. I recommend you create a `.env` file at the root of the project for use with pipenv. Here's all of them.
37 |
38 | ### Discord
39 |
40 | ```
41 | DISCORD_BOT_TOKEN=
42 | ```
43 |
44 | ### Slack
45 |
46 | ```
47 | SLACK_WEBHOOK_URL=
48 | ```
49 |
50 | ### Twitter
51 |
52 | ```
53 | TWITTER_CONSUMER_KEY=
54 | TWITTER_CONSUMER_SECRET=
55 | TWITTER_ACCESS_TOKEN_KEY=
56 | TWITTER_ACCESS_TOKEN_SECRET=
57 | ```
58 |
59 | ### The Internet Archive
60 |
61 | ```
62 | IA_ACCESS_KEY=
63 | IA_SECRET_KEY=
64 | IA_COLLECTION=
65 | ```
66 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/alert.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Group 18
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/newshomepages/extract/wayback.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | import click
4 | import pandas as pd
5 | from rich import print
6 |
7 | from .. import utils
8 | from .utils import _get_json_url
9 |
10 |
11 | @click.group()
12 | def cli():
13 | """Download and parse the provided site's Wayback Machine files."""
14 | pass
15 |
16 |
17 | @cli.command()
18 | @click.argument("handle")
19 | def wayback(handle):
20 | """Download and parse the provided site's Wayback Machine files."""
21 | # Get the site data
22 | site = utils.get_site(handle)
23 |
24 | # Get all files
25 | wayback_df = utils.get_wayback_df()
26 |
27 | # Filter it down to files for the provided site
28 | site_df = wayback_df[wayback_df.handle == site["handle"]]
29 | print(f"{len(site_df)} wayback files found")
30 |
31 | # Read in the output file
32 | output_path = utils.THIS_DIR / f"{site['handle']}-wayback.csv"
33 | try:
34 | output_df = pd.read_csv(output_path)
35 | downloaded_files = set(output_df.file_url.unique())
36 | except FileNotFoundError:
37 | output_df = pd.DataFrame()
38 | downloaded_files = set()
39 |
40 | # See how many files we don't have yet
41 | archived_files = set(site_df.url.unique())
42 | missing_files = list(archived_files - downloaded_files)
43 | print(f"{len(missing_files)} files need to be download")
44 |
45 | # Quit if there's nothing there
46 | if not len(missing_files):
47 | return
48 |
49 | # Go get the files
50 | for url in missing_files:
51 | df = _get_json_url(url)
52 | output_df = pd.concat([output_df, df])
53 | time.sleep(1)
54 |
55 | print(f":pencil: Writing {len(output_df)} rows to {output_path}")
56 | output_df.to_csv(output_path, index=False)
57 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/logo-shield.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Group 9
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/newshomepages/extract/accessibility.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | import click
4 | import pandas as pd
5 | from rich import print
6 |
7 | from .. import utils
8 | from .utils import _get_json_url
9 |
10 |
11 | @click.group()
12 | def cli():
13 | """Download and parse the provided site's accessibility files."""
14 | pass
15 |
16 |
17 | @cli.command()
18 | @click.argument("handle")
19 | def accessibility(handle):
20 | """Download and parse the provided site's accessibility files."""
21 | # Get the site data
22 | site = utils.get_site(handle)
23 |
24 | # Get all hyperlinks
25 | accessibility_df = utils.get_accessibility_df()
26 |
27 | # Filter it down to files for the provided site
28 | site_df = accessibility_df[accessibility_df.handle == site["handle"]]
29 | print(f"{len(site_df)} accessibility files found")
30 |
31 | # Read in the output file
32 | output_path = utils.THIS_DIR / f"{site['handle']}-accessibility.csv"
33 | try:
34 | output_df = pd.read_csv(output_path)
35 | downloaded_files = set(output_df.file_url.unique())
36 | except FileNotFoundError:
37 | output_df = pd.DataFrame()
38 | downloaded_files = set()
39 |
40 | # See how many files we don't have yet
41 | archived_files = set(site_df.url.unique())
42 | missing_files = list(archived_files - downloaded_files)
43 | print(f"{len(missing_files)} files need to be download")
44 |
45 | # Quit if there's nothing there
46 | if not len(missing_files):
47 | return
48 |
49 | # Go get the files
50 | for url in missing_files:
51 | df = _get_json_url(url)
52 | output_df = pd.concat([output_df, df])
53 | time.sleep(1)
54 |
55 | print(f":pencil: Writing {len(output_df)} rows to {output_path}")
56 | output_df.to_csv(output_path, index=False)
57 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/reload-ico.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Group 20
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/_site/reference.rst:
--------------------------------------------------------------------------------
1 | #########
2 | Reference
3 | #########
4 |
5 | Documentation for a selection of our system’s common internal tools
6 |
7 | .. contents:: Table of contents
8 | :depth: 2
9 | :local:
10 |
11 | Commands
12 | ########
13 |
14 | .. click:: newshomepages.accessibility:cli
15 | :prog: accessibility
16 | :nested: full
17 |
18 | .. click:: newshomepages.adstxt:cli
19 | :prog: adstxt
20 | :nested: full
21 |
22 | .. click:: newshomepages.analyze:cli
23 | :prog: analyze
24 | :nested: full
25 |
26 | .. click:: newshomepages.archive:cli
27 | :prog: archive
28 | :nested: full
29 |
30 | .. click:: newshomepages.batch:cli
31 | :prog: batch
32 | :nested: full
33 |
34 | .. click:: newshomepages.discorder:cli
35 | :prog: discorder
36 | :nested: full
37 |
38 | .. click:: newshomepages.site:cli
39 | :prog: site
40 | :nested: full
41 |
42 | .. click:: newshomepages.extract:cli
43 | :prog: extract
44 | :nested: full
45 |
46 | .. click:: newshomepages.hyperlinks:cli
47 | :prog: hyperlinks
48 | :nested: full
49 |
50 | .. click:: newshomepages.mosaic:cli
51 | :prog: mosaic
52 | :nested: full
53 |
54 | .. click:: newshomepages.robotstxt:cli
55 | :prog: robotstxt
56 | :nested: full
57 |
58 | .. click:: newshomepages.screenshot:cli
59 | :prog: screenshot
60 | :nested: full
61 |
62 | .. click:: newshomepages.slack:cli
63 | :prog: slack
64 | :nested: full
65 |
66 | .. click:: newshomepages.toot:cli
67 | :prog: toot
68 | :nested: full
69 |
70 | .. click:: newshomepages.wayback:cli
71 | :prog: wayback
72 | :nested: full
73 |
74 | Utilities
75 | #########
76 |
77 | The `utils `_ module contains a variety of functions used by our commands.
78 |
79 | .. automodule:: newshomepages.utils
80 | :members:
81 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/css/layout.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | html, body, div, span, applet, object, iframe,
3 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
4 | a, abbr, acronym, address, big, cite, code,
5 | del, dfn, em, img, ins, kbd, q, s, samp,
6 | small, strike, strong, sub, sup, tt, var,
7 | b, u, i, center,
8 | dl, dt, dd, ol, ul, li,
9 | fieldset, form, label, legend,
10 | table, caption, tbody, tfoot, thead, tr, th, td,
11 | article, aside, canvas, details, embed,
12 | figure, figcaption, footer, header, hgroup,
13 | menu, nav, output, ruby, section, summary,
14 | time, mark, audio, video {
15 | margin: 0;
16 | padding: 0;
17 | border: 0;
18 | font-size: 100%;
19 | font: inherit;
20 | vertical-align: baseline;
21 | }
22 | article, aside, details, figcaption, figure,
23 | footer, header, hgroup, menu, nav, section {
24 | display: block;
25 | }
26 | ol, ul {
27 | list-style: none;
28 | }
29 | blockquote, q {
30 | quotes: none;
31 | }
32 | blockquote:before, blockquote:after,
33 | q:before, q:after {
34 | content: '';
35 | content: none;
36 | }
37 | table {
38 | border-collapse: collapse;
39 | border-spacing: 0;
40 | }
41 | :root {
42 | font-size: 16px;
43 | }
44 | * {
45 | -webkit-box-sizing: border-box;
46 | box-sizing: border-box;
47 | }
48 | html {
49 | padding: 0;
50 | margin: 0;
51 | height: 100%;
52 | }
53 | body {
54 | background-color: #fff;
55 | font-family: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Arial, sans-serif;
56 | padding: 0;
57 | margin: 0;
58 | font-size: 12px;
59 | height: 100%;
60 | line-height: 1;
61 | overflow-y: scroll;
62 | }
63 |
64 | a {
65 | color: currentColor;
66 | }
67 |
68 | button, a, select, span, label, .toggler-wr {
69 | outline: none;
70 | }
71 |
72 | .hidden{
73 | display: none !important;
74 | }
--------------------------------------------------------------------------------
/newshomepages/accessibility.py:
--------------------------------------------------------------------------------
1 | """Save the accessiblity tree of the provided site."""
2 |
3 | from __future__ import annotations
4 |
5 | import json
6 | from pathlib import Path
7 |
8 | import click
9 | from playwright.sync_api import sync_playwright
10 | from playwright.sync_api._generated import BrowserContext
11 | from retry import retry
12 | from rich import print
13 |
14 | from . import utils
15 |
16 |
17 | @click.command()
18 | @click.argument("handle")
19 | @click.option("-o", "--output-dir", "output_dir", default="./")
20 | @click.option("--verbose", "verbose", default=False, is_flag=True)
21 | def cli(handle, output_dir, verbose=False):
22 | """Save the accessiblity tree of the provided site."""
23 | # Get metadata
24 | site = utils.get_site(handle)
25 |
26 | # Set the output path
27 | output_path = Path(output_dir) / f"{site['handle']}.accessibility.json"
28 | output_path.parent.mkdir(parents=True, exist_ok=True)
29 |
30 | # Do the thing
31 | if verbose:
32 | print(f":newspaper: Fetching a11y tree from {site['url']}")
33 | with sync_playwright() as p:
34 | context = utils._load_persistent_context(p)
35 | _get_accessibility(context, site["url"], site["handle"], output_path)
36 | context.close()
37 |
38 |
39 | @retry(tries=3, delay=5, backoff=2)
40 | def _get_accessibility(
41 | context: BrowserContext, url: str, handle: str, output_path: Path
42 | ):
43 | """Run a command that fetches the accessibility tree for the provided site."""
44 | with open(output_path, "w") as fp:
45 | page = utils._load_new_page_disable_javascript(
46 | context=context,
47 | url=url,
48 | handle=handle,
49 | )
50 | snapshot = page.accessibility.snapshot()
51 | page.close()
52 | fp.write(json.dumps(snapshot, indent=4))
53 | fp.write("\n")
54 |
55 |
56 | if __name__ == "__main__":
57 | cli()
58 |
--------------------------------------------------------------------------------
/.github/workflows/site.yml:
--------------------------------------------------------------------------------
1 | name: Update website
2 |
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: '0 0 * * *'
7 |
8 | concurrency:
9 | group: site
10 | cancel-in-progress: true
11 |
12 | jobs:
13 | build:
14 | name: Build and deploy
15 | runs-on: ubuntu-latest
16 | steps:
17 | - id: checkout
18 | name: Checkout
19 | uses: actions/checkout@v4
20 |
21 | - id: setup-python
22 | name: Setup Python
23 | uses: actions/setup-python@v5
24 | with:
25 | python-version: '3.10'
26 | cache: 'pipenv'
27 |
28 | - id: install-pipenv
29 | name: Install pipenv
30 | run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
31 | shell: bash
32 |
33 | - id: install-python-dependencies
34 | name: Install Python dependencies
35 | run: pipenv sync --dev
36 | shell: bash
37 |
38 | - id: render-templates
39 | name: Render site templates
40 | run: pipenv run make site
41 | shell: bash
42 |
43 | - id: build-site
44 | name: Build site
45 | run: cd _site && pipenv run make html
46 | shell: bash
47 |
48 | - id: configure-aws
49 | name: Configure AWS Credentials
50 | uses: aws-actions/configure-aws-credentials@v4
51 | with:
52 | aws-access-key-id: ${{ secrets.PALEWIRE_DOCS_AWS_ACCESS_KEY_ID }}
53 | aws-secret-access-key: ${{ secrets.PALEWIRE_DOCS_AWS_SECRET_ACCESS_KEY }}
54 | aws-region: us-east-1
55 |
56 | - id: npm-deploy
57 | name: Upload the prepared files
58 | uses: datadesk/delivery-deploy-action@v1
59 | with:
60 | bucket: ${{ secrets.PALEWIRE_DOCS_AWS_BUCKET }}
61 | base-path: news-homepages
62 | dir: _site/_build/html/
63 | should-cache: false
64 | use-accelerate-endpoint: false
65 | public: true
66 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # See https://pre-commit.com for more information
2 | # See https://pre-commit.com/hooks.html for more hooks
3 | repos:
4 | - repo: https://github.com/pre-commit/pre-commit-hooks
5 | rev: v5.0.0
6 | hooks:
7 | - id: trailing-whitespace
8 | exclude: newshomepages/extensions/
9 | - id: end-of-file-fixer
10 | exclude: newshomepages/extensions/
11 | - id: check-yaml
12 | exclude: newshomepages/extensions/
13 | - id: check-added-large-files
14 | args: ['--maxkb=10000']
15 | - id: check-byte-order-marker
16 | exclude: newshomepages/extensions
17 | - id: check-case-conflict
18 | exclude: newshomepages/extensions/
19 | - id: check-json
20 | exclude: newshomepages/extensions/
21 | - id: mixed-line-ending
22 | exclude: newshomepages/extensions/
23 |
24 | - repo: https://github.com/psf/black
25 | rev: 25.1.0
26 | hooks:
27 | - id: black
28 | exclude: newshomepages/extensions/
29 |
30 | - repo: https://github.com/asottile/blacken-docs
31 | rev: 1.19.1
32 | hooks:
33 | - id: blacken-docs
34 | additional_dependencies: [black]
35 | exclude: newshomepages/extensions/
36 |
37 | - repo: https://github.com/timothycrosley/isort
38 | rev: 6.0.1
39 | hooks:
40 | - id: isort
41 |
42 | - repo: https://github.com/pycqa/flake8
43 | rev: 7.2.0
44 | hooks:
45 | - id: flake8
46 | additional_dependencies:
47 | - flake8-docstrings
48 | - flake8-bugbear
49 |
50 | - repo: https://github.com/asottile/pyupgrade
51 | rev: v3.20.0
52 | hooks:
53 | - id: pyupgrade
54 | args: [--py37-plus]
55 |
56 | - repo: https://github.com/pre-commit/mirrors-mypy
57 | rev: 'v1.16.0' # Use the sha / tag you want to point at
58 | hooks:
59 | - id: mypy
60 | exclude: newshomepages/extensions
61 | additional_dependencies:
62 | - types-requests
63 | - types-retry
64 | - types-python-slugify
65 | - types-pytz
66 | - types-PyYAML
67 |
--------------------------------------------------------------------------------
/_site/index.md:
--------------------------------------------------------------------------------
1 | # homepages.news
2 |
3 | An open-source archive that gathers, saves, shares and analyzes news homepages
4 |
5 | ## Features
6 |
7 | ```{toctree}
8 | :maxdepth: 1
9 | :name: mastertoc
10 |
11 | latest
12 | accessibility
13 | performance
14 | drudge
15 | openai-gptbot-robotstxt
16 | extracts
17 | status-report
18 | ```
19 |
20 | ## Directory
21 |
22 | ```{toctree}
23 | :maxdepth: 1
24 | :name: directory
25 |
26 | sources
27 | countries
28 | languages
29 | bundles
30 | ```
31 |
32 | ## About
33 |
34 | The archive at [homepages.news](https://homepages.news) is an [open-source software project](https://github.com/palewire/news-homepages) managed by [Ben Welsh](https://palewi.re/who-is-ben-welsh/). Each day it gathers screenshots, accessibility trees, hyperlink lists, robots.txt and Lighthouse audits from hundreds of news homepages around the world. It also ensures that all sites are routinely saved by the [Wayback Machine at archive.org](https://web.archive.org/).
35 |
36 | The assets are archived in a permanent collection [at the Internet Archive](https://archive.org/details/news-homepages). The latest screenshots, analysis and data are published here, as well as on [Mastodon](https://mastodon.palewi.re/@newshomepages).
37 |
38 | The system supports the creation of bots to post a newsroom’s latest screenshots into a private Slack channel. [The tool](https://palewi.re/docs/news-homepages/slack.html) is used by organizations in the U.S. and abroad to save and share images each day.
39 |
40 | ## Contributing
41 |
42 | ```{toctree}
43 | :maxdepth: 1
44 | :name: contributing
45 |
46 | gettingstarted
47 | adding
48 | slack
49 | reference
50 | ```
51 |
52 | ## Links
53 |
54 | - Internet Archive: [archive.org/details/news-homepages](https://archive.org/details/news-homepages)
55 | - Mastodon: [@newshomepages](https://mastodon.palewi.re/@newshomepages)
56 | - Code: [github.com/palewire/news-homepages](https://github.com/palewire/news-homepages)
57 | - Task runner: [github.com/palewire/news-homepages/actions](https://github.com/palewire/news-homepages/actions)
58 | - Packaging: [pypi.org/project/newshomepages](https://pypi.org/project/newshomepages/)
59 | - Issues: [github.com/palewire/news-homepages/issues](https://github.com/palewire/news-homepages/issues)
60 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/pages/devtools-elements-sidebar.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/add-a-site.yaml:
--------------------------------------------------------------------------------
1 | name: Add a site
2 | description: Suggest a news homepage for inclusion
3 | title: "[Add site]: "
4 | labels:
5 | - enhancement
6 | - good first issue
7 | - help wanted
8 | assignees:
9 | - palewire
10 | body:
11 | - type: markdown
12 | attributes:
13 | value: |
14 | The process for adding a site is spelled out in [our documentation](https://palewi.re/docs/news-homepages/adding.html). Users who aren't comfortable suggesting the change via a [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) can submit a request here.
15 | - type: input
16 | id: handle
17 | attributes:
18 | label: X.com handle
19 | description: What is the site's handle on X? Without an @ prefix, please.
20 | validations:
21 | required: true
22 | - type: input
23 | id: url
24 | attributes:
25 | label: Homepage URL
26 | description: What is the site's homepage URL? Include the https:// prefix, please.
27 | validations:
28 | required: true
29 | - type: input
30 | id: name
31 | attributes:
32 | label: Name
33 | description: What is the site's name?
34 | validations:
35 | required: true
36 | - type: input
37 | id: location
38 | attributes:
39 | label: Location
40 | description: What is the location of the newsroom's headquarters?
41 | validations:
42 | required: false
43 | - type: input
44 | id: timezone
45 | attributes:
46 | label: Timezone
47 | description: What is the timezone of the newsroom's headquarters? A list of all accepted timezones can be found [here](https://gist.github.com/heyalexej/8bf688fd67d7199be4a1682b3eec7568).
48 | validations:
49 | required: false
50 | - type: input
51 | id: country
52 | attributes:
53 | label: Country
54 | description: What is the country of the newsroom's headquarters? Please submit the two-letter code from [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).
55 | validations:
56 | required: false
57 | - type: input
58 | id: language
59 | attributes:
60 | label: Language
61 | description: What is the primary language of the newsroom's homepage? Please submit the two-letter code from [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1).
62 | validations:
63 | required: false
64 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/prebid-ads.js:
--------------------------------------------------------------------------------
1 | (function(source, args){
2 | function prebidAds(source) {
3 | window.canRunAds = true;
4 | window.isAdBlockActive = false;
5 | hit(source);
6 | }
7 | function hit(source, message) {
8 | if (source.verbose !== true) {
9 | return;
10 | }
11 |
12 | try {
13 | var log = console.log.bind(console);
14 | var trace = console.trace.bind(console); // eslint-disable-line compat/compat
15 |
16 | var prefix = source.ruleText || '';
17 |
18 | if (source.domainName) {
19 | var AG_SCRIPTLET_MARKER = '#%#//';
20 | var UBO_SCRIPTLET_MARKER = '##+js';
21 | var ruleStartIndex;
22 |
23 | if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) {
24 | ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER);
25 | } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) {
26 | ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER);
27 | } // delete all domains from ruleText and leave just rule part
28 |
29 |
30 | var rulePart = source.ruleText.slice(ruleStartIndex); // prepare applied scriptlet rule for specific domain
31 |
32 | prefix = "".concat(source.domainName).concat(rulePart);
33 | } // Used to check if scriptlet uses 'hit' function for logging
34 |
35 |
36 | var LOG_MARKER = 'log: ';
37 |
38 | if (message) {
39 | if (message.indexOf(LOG_MARKER) === -1) {
40 | log("".concat(prefix, " message:\n").concat(message));
41 | } else {
42 | log(message.slice(LOG_MARKER.length));
43 | }
44 | }
45 |
46 | log("".concat(prefix, " trace start"));
47 |
48 | if (trace) {
49 | trace();
50 | }
51 |
52 | log("".concat(prefix, " trace end"));
53 | } catch (e) {// try catch for Edge 15
54 | // In according to this issue https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14495220/
55 | // console.log throws an error
56 | } // This is necessary for unit-tests only!
57 |
58 |
59 | if (typeof window.__debug === 'function') {
60 | window.__debug(source);
61 | }
62 | };
63 | const updatedArgs = args ? [].concat(source).concat(args) : [source];
64 | try {
65 | prebidAds.apply(this, updatedArgs);
66 | } catch (e) {
67 | console.log(e);
68 | }
69 |
70 | })({"name":"prebid-ads","args":[]}, []);
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/noeval.js:
--------------------------------------------------------------------------------
1 | (function(source, args){
2 | function noeval(source) {
3 | window.eval = function evalWrapper(s) {
4 | hit(source, "AdGuard has prevented eval:\n".concat(s));
5 | }.bind();
6 | }
7 | function hit(source, message) {
8 | if (source.verbose !== true) {
9 | return;
10 | }
11 |
12 | try {
13 | var log = console.log.bind(console);
14 | var trace = console.trace.bind(console); // eslint-disable-line compat/compat
15 |
16 | var prefix = source.ruleText || '';
17 |
18 | if (source.domainName) {
19 | var AG_SCRIPTLET_MARKER = '#%#//';
20 | var UBO_SCRIPTLET_MARKER = '##+js';
21 | var ruleStartIndex;
22 |
23 | if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) {
24 | ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER);
25 | } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) {
26 | ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER);
27 | } // delete all domains from ruleText and leave just rule part
28 |
29 |
30 | var rulePart = source.ruleText.slice(ruleStartIndex); // prepare applied scriptlet rule for specific domain
31 |
32 | prefix = "".concat(source.domainName).concat(rulePart);
33 | } // Used to check if scriptlet uses 'hit' function for logging
34 |
35 |
36 | var LOG_MARKER = 'log: ';
37 |
38 | if (message) {
39 | if (message.indexOf(LOG_MARKER) === -1) {
40 | log("".concat(prefix, " message:\n").concat(message));
41 | } else {
42 | log(message.slice(LOG_MARKER.length));
43 | }
44 | }
45 |
46 | log("".concat(prefix, " trace start"));
47 |
48 | if (trace) {
49 | trace();
50 | }
51 |
52 | log("".concat(prefix, " trace end"));
53 | } catch (e) {// try catch for Edge 15
54 | // In according to this issue https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14495220/
55 | // console.log throws an error
56 | } // This is necessary for unit-tests only!
57 |
58 |
59 | if (typeof window.__debug === 'function') {
60 | window.__debug(source);
61 | }
62 | };
63 | const updatedArgs = args ? [].concat(source).concat(args) : [source];
64 | try {
65 | noeval.apply(this, updatedArgs);
66 | } catch (e) {
67 | console.log(e);
68 | }
69 |
70 | })({"name":"noeval","args":[]}, []);
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/naver-wcslog.js:
--------------------------------------------------------------------------------
1 | (function(source, args){
2 | function NaverWcslog(source) {
3 | window.wcs_add = {};
4 | window.wcs_do = noopFunc;
5 | window.wcs = {
6 | inflow: noopFunc
7 | };
8 | hit(source);
9 | }
10 | function hit(source, message) {
11 | if (source.verbose !== true) {
12 | return;
13 | }
14 |
15 | try {
16 | var log = console.log.bind(console);
17 | var trace = console.trace.bind(console); // eslint-disable-line compat/compat
18 |
19 | var prefix = source.ruleText || '';
20 |
21 | if (source.domainName) {
22 | var AG_SCRIPTLET_MARKER = '#%#//';
23 | var UBO_SCRIPTLET_MARKER = '##+js';
24 | var ruleStartIndex;
25 |
26 | if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) {
27 | ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER);
28 | } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) {
29 | ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER);
30 | } // delete all domains from ruleText and leave just rule part
31 |
32 |
33 | var rulePart = source.ruleText.slice(ruleStartIndex); // prepare applied scriptlet rule for specific domain
34 |
35 | prefix = "".concat(source.domainName).concat(rulePart);
36 | } // Used to check if scriptlet uses 'hit' function for logging
37 |
38 |
39 | var LOG_MARKER = 'log: ';
40 |
41 | if (message) {
42 | if (message.indexOf(LOG_MARKER) === -1) {
43 | log("".concat(prefix, " message:\n").concat(message));
44 | } else {
45 | log(message.slice(LOG_MARKER.length));
46 | }
47 | }
48 |
49 | log("".concat(prefix, " trace start"));
50 |
51 | if (trace) {
52 | trace();
53 | }
54 |
55 | log("".concat(prefix, " trace end"));
56 | } catch (e) {// try catch for Edge 15
57 | // In according to this issue https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14495220/
58 | // console.log throws an error
59 | } // This is necessary for unit-tests only!
60 |
61 |
62 | if (typeof window.__debug === 'function') {
63 | window.__debug(source);
64 | }
65 | }
66 | function noopFunc() {};
67 | const updatedArgs = args ? [].concat(source).concat(args) : [source];
68 | try {
69 | NaverWcslog.apply(this, updatedArgs);
70 | } catch (e) {
71 | console.log(e);
72 | }
73 |
74 | })({"name":"naver-wcslog","args":[]}, []);
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/assets/images/chrome.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
12 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "4.0.178",
3 | "manifest_version": 2,
4 | "name": "__MSG_name__",
5 | "short_name": "__MSG_short_name__",
6 | "author": "Adguard Software Ltd",
7 | "default_locale": "en",
8 | "description": "__MSG_description__",
9 | "icons": {
10 | "16": "assets/icons/green-16.png",
11 | "128": "assets/icons/green-128.png"
12 | },
13 | "browser_action": {
14 | "default_icon": {
15 | "19": "assets/icons/green-19.png",
16 | "38": "assets/icons/green-38.png"
17 | },
18 | "default_title": "__MSG_name__",
19 | "default_popup": "pages/popup.html"
20 | },
21 | "background": {
22 | "page": "pages/background.html",
23 | "persistent": true
24 | },
25 | "content_scripts": [
26 | {
27 | "all_frames": true,
28 | "js": [
29 | "pages/content-script-start.js"
30 | ],
31 | "matches": [
32 | "http://*/*",
33 | "https://*/*"
34 | ],
35 | "match_about_blank": true,
36 | "run_at": "document_start"
37 | },
38 | {
39 | "all_frames": true,
40 | "js": [
41 | "pages/content-script-end.js"
42 | ],
43 | "matches": [
44 | "http://*/*",
45 | "https://*/*"
46 | ],
47 | "match_about_blank": true,
48 | "run_at": "document_end"
49 | },
50 | {
51 | "all_frames": false,
52 | "js": [
53 | "pages/thankyou.js"
54 | ],
55 | "matches": [
56 | "*://*.adguard.com/*/thankyou.html*"
57 | ],
58 | "run_at": "document_start"
59 | }
60 | ],
61 | "minimum_chrome_version": "79.0",
62 | "web_accessible_resources": [
63 | "/web-accessible-resources/*"
64 | ],
65 | "options_page": "pages/options.html",
66 | "devtools_page": "pages/devtools.html",
67 | "permissions": [
68 | "tabs",
69 | "",
70 | "webRequest",
71 | "webRequestBlocking",
72 | "webNavigation",
73 | "storage",
74 | "unlimitedStorage",
75 | "contextMenus",
76 | "cookies"
77 | ],
78 | "optional_permissions": [
79 | "privacy"
80 | ],
81 | "content_security_policy": "script-src 'self' 'sha256-CA6h8X2PlfpQX4tMUn1T0JjKVVC7t6WCcAxnAPhndGk='; object-src 'self'"
82 | }
83 |
--------------------------------------------------------------------------------
/newshomepages/site/performance_ranking.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | import click
4 | import numpy as np
5 | import pandas as pd
6 | from rich import print
7 |
8 | from .. import utils
9 | from .utils import _write_template
10 |
11 |
12 | @click.group()
13 | def cli():
14 | """Create page ranking sites by Lighthouse performance score."""
15 | pass
16 |
17 |
18 | @cli.command()
19 | def performance_ranking():
20 | """Create page ranking sites by Lighthouse performance score."""
21 | # Read in our dataset
22 | performance_df = utils.get_extract_df(
23 | "lighthouse-analysis.csv",
24 | dtype={
25 | "handle": str,
26 | "performance_median": float,
27 | "performance_color": str,
28 | "performance_rank": float,
29 | },
30 | )
31 |
32 | # Convert the rank to an integer
33 | performance_df.performance_rank = performance_df.performance_rank.astype(int)
34 |
35 | # Filter out nulls
36 | performance_df = performance_df[
37 | ~pd.isnull(performance_df.performance_median)
38 | ].copy()
39 |
40 | # Calculate the grand total
41 | median = performance_df.performance_median.median() * 100
42 |
43 | # Generate a distribution for our chart
44 | def _round(val: float) -> int:
45 | return int(np.floor(np.floor(val * 1000) / 100) * 10)
46 |
47 | performance_df["performance_decile"] = performance_df.performance_median.apply(
48 | _round
49 | )
50 | histogram_df = (
51 | performance_df.groupby("performance_decile").size().rename("n").reset_index()
52 | )
53 | histogram_df = histogram_df.merge(
54 | pd.DataFrame(range(0, 101, 10), columns=["performance_decile"]),
55 | how="right",
56 | on="performance_decile",
57 | ).fillna(0)
58 |
59 | # Prep the ranking table
60 | performance_df.performance_median = performance_df.performance_median * 100
61 | performance_df.performance_median = performance_df.performance_median.astype(int)
62 | site_df = utils.get_site_df()
63 | merged_df = site_df.merge(performance_df, on="handle", how="inner")
64 |
65 | # Create the page
66 | site_list = merged_df.sort_values(["performance_rank", "name"]).to_dict(
67 | orient="records"
68 | )
69 | print(
70 | f":abacus: Creating performance ranking page for {len(site_list)} qualified sites"
71 | )
72 | context = dict(
73 | median=median,
74 | histogram_json=json.dumps(histogram_df.to_dict(orient="records")),
75 | site_list=site_list,
76 | )
77 | _write_template("performance.md", context)
78 |
--------------------------------------------------------------------------------
/newshomepages/extensions/adguard/web-accessible-resources/redirects/scorecardresearch-beacon.js:
--------------------------------------------------------------------------------
1 | (function(source, args){
2 | function ScoreCardResearchBeacon(source) {
3 | window.COMSCORE = {
4 | purge: function purge() {
5 | // eslint-disable-next-line no-underscore-dangle
6 | window._comscore = [];
7 | },
8 | beacon: function beacon() {}
9 | };
10 | hit(source);
11 | }
12 | function hit(source, message) {
13 | if (source.verbose !== true) {
14 | return;
15 | }
16 |
17 | try {
18 | var log = console.log.bind(console);
19 | var trace = console.trace.bind(console); // eslint-disable-line compat/compat
20 |
21 | var prefix = source.ruleText || '';
22 |
23 | if (source.domainName) {
24 | var AG_SCRIPTLET_MARKER = '#%#//';
25 | var UBO_SCRIPTLET_MARKER = '##+js';
26 | var ruleStartIndex;
27 |
28 | if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) {
29 | ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER);
30 | } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) {
31 | ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER);
32 | } // delete all domains from ruleText and leave just rule part
33 |
34 |
35 | var rulePart = source.ruleText.slice(ruleStartIndex); // prepare applied scriptlet rule for specific domain
36 |
37 | prefix = "".concat(source.domainName).concat(rulePart);
38 | } // Used to check if scriptlet uses 'hit' function for logging
39 |
40 |
41 | var LOG_MARKER = 'log: ';
42 |
43 | if (message) {
44 | if (message.indexOf(LOG_MARKER) === -1) {
45 | log("".concat(prefix, " message:\n").concat(message));
46 | } else {
47 | log(message.slice(LOG_MARKER.length));
48 | }
49 | }
50 |
51 | log("".concat(prefix, " trace start"));
52 |
53 | if (trace) {
54 | trace();
55 | }
56 |
57 | log("".concat(prefix, " trace end"));
58 | } catch (e) {// try catch for Edge 15
59 | // In according to this issue https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14495220/
60 | // console.log throws an error
61 | } // This is necessary for unit-tests only!
62 |
63 |
64 | if (typeof window.__debug === 'function') {
65 | window.__debug(source);
66 | }
67 | };
68 | const updatedArgs = args ? [].concat(source).concat(args) : [source];
69 | try {
70 | ScoreCardResearchBeacon.apply(this, updatedArgs);
71 | } catch (e) {
72 | console.log(e);
73 | }
74 |
75 | })({"name":"scorecardresearch-beacon","args":[]}, []);
--------------------------------------------------------------------------------
/newshomepages/adstxt.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | from pathlib import Path
4 | from urllib.parse import urlparse
5 |
6 | import click
7 | import requests
8 | from retry import retry
9 | from rich import print
10 |
11 | from . import utils
12 |
13 |
14 | @click.command()
15 | @click.argument("handle")
16 | @click.option("-o", "--output-dir", "output_dir", default="./")
17 | @click.option("--timeout", "timeout", default="5")
18 | @click.option("--verbose", "verbose", default=False, is_flag=True)
19 | def cli(handle: str, output_dir: str, timeout: str = "5", verbose: bool = False):
20 | """Save the raw ads.txt of the provided site."""
21 | # Get the site
22 | site = utils.get_site(handle)
23 |
24 | # Get the ads.txt
25 | adstxt = _get_adstxt(site["url"], int(timeout), verbose=verbose)
26 |
27 | if adstxt is None:
28 | # If there is no ads.txt, we drop out now
29 | print(f":robot: No ads.txt for {site['handle']}")
30 | adstxt = "404: No file found"
31 |
32 | # Set the output path
33 | output_path = Path(output_dir) / f"{site['handle']}.ads.txt"
34 | output_path.parent.mkdir(parents=True, exist_ok=True)
35 |
36 | # Write it out
37 | if verbose:
38 | print(f":robot: Writing {output_path}")
39 | with output_path.open("w") as f:
40 | f.write(adstxt)
41 |
42 |
43 | @retry(tries=3, delay=15, backoff=2)
44 | def _get_adstxt(
45 | site_url: str,
46 | timeout: int = 5,
47 | verbose: bool = False,
48 | ) -> str | None:
49 | """Get the raw ads.txt for a site."""
50 | # Create the ads.txt URL
51 | adstxt_url = (
52 | urlparse(site_url)
53 | ._replace(path="")
54 | ._replace(query="")
55 | ._replace(path="ads.txt")
56 | .geturl()
57 | )
58 | if verbose:
59 | print(f":robot: Fetching {adstxt_url}")
60 |
61 | # Set the headers
62 | headers = {"User-Agent": utils.get_user_agent()}
63 |
64 | # Make the request
65 | r = requests.get(adstxt_url, timeout=timeout, headers=headers)
66 |
67 | # Check if the request is a 404
68 | if r.status_code == 404:
69 | # In this case, there is no ads.txt
70 | # so we return None
71 | return None
72 | else:
73 | # Otherwise, we return the text,
74 | # after checking that the request was successful
75 | try:
76 | assert r.ok
77 | except AssertionError:
78 | msg = f"Request failed with status code {r.status_code}"
79 | if verbose:
80 | print(msg)
81 | raise AssertionError(msg)
82 | return r.text
83 |
84 |
85 | if __name__ == "__main__":
86 | cli()
87 |
--------------------------------------------------------------------------------