Allow to replace URL dynamically (for Nitter, Teddit...)
parent
4de4178c3d
commit
8cfac8df6a
|
@ -2,6 +2,7 @@ import hashlib
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import pydantic
|
import pydantic
|
||||||
from bs4 import BeautifulSoup # type: ignore
|
from bs4 import BeautifulSoup # type: ignore
|
||||||
|
@ -11,6 +12,7 @@ from app import activitypub as ap
|
||||||
from app.actor import LOCAL_ACTOR
|
from app.actor import LOCAL_ACTOR
|
||||||
from app.actor import Actor
|
from app.actor import Actor
|
||||||
from app.actor import RemoteActor
|
from app.actor import RemoteActor
|
||||||
|
from app.config import PRIVACY_REPLACE
|
||||||
from app.media import proxied_media_url
|
from app.media import proxied_media_url
|
||||||
from app.utils.datetime import now
|
from app.utils.datetime import now
|
||||||
from app.utils.datetime import parse_isoformat
|
from app.utils.datetime import parse_isoformat
|
||||||
|
@ -175,10 +177,23 @@ class Object:
|
||||||
|
|
||||||
# PeerTube returns the content as markdown
|
# PeerTube returns the content as markdown
|
||||||
if self.ap_object.get("mediaType") == "text/markdown":
|
if self.ap_object.get("mediaType") == "text/markdown":
|
||||||
return markdown(content, extensions=["mdx_linkify"])
|
content = markdown(content, extensions=["mdx_linkify"])
|
||||||
|
|
||||||
|
if not PRIVACY_REPLACE:
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
soup = BeautifulSoup(content, "html5lib")
|
||||||
|
links = soup.find_all("a", href=True)
|
||||||
|
|
||||||
|
for link in links:
|
||||||
|
parsed_href = urlparse(link.attrs["href"])
|
||||||
|
if new_netloc := PRIVACY_REPLACE.get(
|
||||||
|
parsed_href.netloc.removeprefix("www.")
|
||||||
|
):
|
||||||
|
link.attrs["href"] = parsed_href._replace(netloc=new_netloc).geturl()
|
||||||
|
|
||||||
|
return soup.find("body").decode_contents()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def summary(self) -> str | None:
|
def summary(self) -> str | None:
|
||||||
return self.ap_object.get("summary")
|
return self.ap_object.get("summary")
|
||||||
|
|
|
@ -31,6 +31,11 @@ USER_AGENT = f"microblogpub/{VERSION}"
|
||||||
AP_CONTENT_TYPE = "application/activity+json"
|
AP_CONTENT_TYPE = "application/activity+json"
|
||||||
|
|
||||||
|
|
||||||
|
class _PrivacyReplace(pydantic.BaseModel):
|
||||||
|
domain: str
|
||||||
|
replace_by: str
|
||||||
|
|
||||||
|
|
||||||
class Config(pydantic.BaseModel):
|
class Config(pydantic.BaseModel):
|
||||||
domain: str
|
domain: str
|
||||||
username: str
|
username: str
|
||||||
|
@ -43,6 +48,7 @@ class Config(pydantic.BaseModel):
|
||||||
debug: bool = False
|
debug: bool = False
|
||||||
trusted_hosts: list[str] = ["127.0.0.1"]
|
trusted_hosts: list[str] = ["127.0.0.1"]
|
||||||
manually_approves_followers: bool = False
|
manually_approves_followers: bool = False
|
||||||
|
privacy_replace: list[_PrivacyReplace] | None = None
|
||||||
|
|
||||||
# Config items to make tests easier
|
# Config items to make tests easier
|
||||||
sqlalchemy_database: str | None = None
|
sqlalchemy_database: str | None = None
|
||||||
|
@ -84,6 +90,9 @@ _SCHEME = "https" if CONFIG.https else "http"
|
||||||
ID = f"{_SCHEME}://{DOMAIN}"
|
ID = f"{_SCHEME}://{DOMAIN}"
|
||||||
USERNAME = CONFIG.username
|
USERNAME = CONFIG.username
|
||||||
MANUALLY_APPROVES_FOLLOWERS = CONFIG.manually_approves_followers
|
MANUALLY_APPROVES_FOLLOWERS = CONFIG.manually_approves_followers
|
||||||
|
PRIVACY_REPLACE = None
|
||||||
|
if CONFIG.privacy_replace:
|
||||||
|
PRIVACY_REPLACE = {pr.domain: pr.replace_by for pr in CONFIG.privacy_replace}
|
||||||
BASE_URL = ID
|
BASE_URL = ID
|
||||||
DEBUG = CONFIG.debug
|
DEBUG = CONFIG.debug
|
||||||
DB_PATH = CONFIG.sqlalchemy_database or ROOT_DIR / "data" / "microblogpub.db"
|
DB_PATH = CONFIG.sqlalchemy_database or ROOT_DIR / "data" / "microblogpub.db"
|
||||||
|
|
|
@ -31,6 +31,28 @@ You can tweak your profile by tweaking these items:
|
||||||
|
|
||||||
Whenever one of these config items is updated, an `Update` activity will be sent to all know server to update your remote profile.
|
Whenever one of these config items is updated, an `Update` activity will be sent to all know server to update your remote profile.
|
||||||
|
|
||||||
|
### Privacy replace
|
||||||
|
|
||||||
|
You can define domain to be rewrited to more "privacy friendly" alternatives, like [Invidious](https://invidious.io/)
|
||||||
|
or [Nitter](https://nitter.net/about).
|
||||||
|
|
||||||
|
To do so, just add as these extra config items, this is a sample config that rewrite URLs for Twitter, Youtube, Reddit and Medium:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[privacy_replace]]
|
||||||
|
domain = "youtube.com"
|
||||||
|
replace_by ="yewtu.be"
|
||||||
|
[[privacy_replace]]
|
||||||
|
domain = "twitter.com"
|
||||||
|
replace_by = "nitter.net"
|
||||||
|
[[privacy_replace]]
|
||||||
|
domain = "medium.com"
|
||||||
|
replace_by = "scribe.rip"
|
||||||
|
[[privacy_replace]]
|
||||||
|
domain = "reddit.com"
|
||||||
|
replace_by = "teddit.net"
|
||||||
|
```
|
||||||
|
|
||||||
### Customization
|
### Customization
|
||||||
|
|
||||||
#### Custom emoji
|
#### Custom emoji
|
||||||
|
|
Loading…
Reference in New Issue