Compare commits
12 Commits
a9dc57e77a
...
4c11ee4630
Author | SHA1 | Date | |
---|---|---|---|
4c11ee4630 | |||
f8a1e6f79c | |||
![]() |
95616fef4a | ||
![]() |
0b3a43088b | ||
![]() |
ac503b0b06 | ||
![]() |
883c609412 | ||
![]() |
8ee266d846 | ||
![]() |
c07c5798d9 | ||
![]() |
63ef7f75ba | ||
![]() |
b53ac22ba4 | ||
![]() |
88c7914f96 | ||
![]() |
d3b4ae0952 |
28
.gitea/workflows/build.yml
Normal file
28
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Build and publish the docker image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["custom"]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: git.ngn.tf
|
||||||
|
IMAGE: ${{gitea.repository}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: "https://github.com/actions/checkout@v4"
|
||||||
|
|
||||||
|
- name: Login to container repo
|
||||||
|
uses: "https://github.com/docker/login-action@v1"
|
||||||
|
with:
|
||||||
|
registry: ${{env.REGISTRY}}
|
||||||
|
username: ${{gitea.actor}}
|
||||||
|
password: ${{secrets.PACKAGES_TOKEN}}
|
||||||
|
|
||||||
|
- name: Build image
|
||||||
|
run: |
|
||||||
|
docker build . --tag ${{env.REGISTRY}}/${{env.IMAGE}}:latest
|
||||||
|
docker push ${{env.REGISTRY}}/${{env.IMAGE}}:latest
|
12
.github/FUNDING.yml
vendored
12
.github/FUNDING.yml
vendored
@ -1,12 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
# github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
|
||||||
# patreon: # Replace with a single Patreon username
|
|
||||||
open_collective: # Replace with a single Open Collective username
|
|
||||||
# ko_fi: # Replace with a single Ko-fi username
|
|
||||||
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
||||||
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
||||||
liberapay: realaravinth
|
|
||||||
issuehunt: # Replace with a single IssueHunt username
|
|
||||||
# otechie: # Replace with a single Otechie username
|
|
||||||
custom: ['https://batsense.net/donate']
|
|
43
.github/workflows/clippy-fmt.yml
vendored
43
.github/workflows/clippy-fmt.yml
vendored
@ -1,43 +0,0 @@
|
|||||||
name: Lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
fmt:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Install Rust
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
components: rustfmt
|
|
||||||
- name: Check with rustfmt
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --all -- --check
|
|
||||||
|
|
||||||
clippy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Install Rust
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
components: clippy
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Check with Clippy
|
|
||||||
uses: actions-rs/clippy-check@v1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
args: --workspace --tests --all-features
|
|
49
.github/workflows/coverage.yml
vendored
49
.github/workflows/coverage.yml
vendored
@ -1,49 +0,0 @@
|
|||||||
name: Coverage
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_and_test:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
version:
|
|
||||||
- nightly
|
|
||||||
|
|
||||||
name: ${{ matrix.version }} - x86_64-unknown-linux-gnu
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: ⚡ Cache
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cargo/registry
|
|
||||||
~/.cargo/git
|
|
||||||
target
|
|
||||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
||||||
|
|
||||||
- name: Install ${{ matrix.version }}
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: ${{ matrix.version }}-x86_64-unknown-linux-gnu
|
|
||||||
profile: minimal
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Generate coverage file
|
|
||||||
if: (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
|
|
||||||
uses: actions-rs/tarpaulin@v0.1
|
|
||||||
with:
|
|
||||||
args: "-t 1200"
|
|
||||||
env:
|
|
||||||
GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61
|
|
||||||
|
|
||||||
- name: Upload to Codecov
|
|
||||||
uses: codecov/codecov-action@v2
|
|
||||||
if: github.ref == 'refs/heads/master'
|
|
70
.github/workflows/linux.yml
vendored
70
.github/workflows/linux.yml
vendored
@ -1,70 +0,0 @@
|
|||||||
name: Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened]
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_and_test:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
version:
|
|
||||||
#- 1.51.0
|
|
||||||
- stable
|
|
||||||
# - nightly
|
|
||||||
|
|
||||||
name: ${{ matrix.version }} - x86_64-unknown-linux-gnu
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: ⚡ Cache
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
/var/lib/docker
|
|
||||||
~/.cargo/registry
|
|
||||||
~/.cargo/git
|
|
||||||
target
|
|
||||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'realaravinth/libmedium'
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Install ${{ matrix.version }}
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: ${{ matrix.version }}-x86_64-unknown-linux-gnu
|
|
||||||
profile: minimal
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: build
|
|
||||||
run: make
|
|
||||||
|
|
||||||
- name: run tests
|
|
||||||
run: make test
|
|
||||||
|
|
||||||
- name: build and publish docker images
|
|
||||||
run: make docker-publish
|
|
||||||
|
|
||||||
- name: generate documentation
|
|
||||||
if: matrix.version == 'stable' && (github.repository == 'realaravinth/libmedium')
|
|
||||||
run: make doc
|
|
||||||
env:
|
|
||||||
GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61 # dummy value
|
|
||||||
|
|
||||||
- name: Deploy to GitHub libmedium
|
|
||||||
if: matrix.version == 'stable' && (github.repository == 'realaravinth/libmedium')
|
|
||||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
|
||||||
with:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
BRANCH: gh-libmedium
|
|
||||||
FOLDER: target/doc
|
|
638
Cargo.lock
generated
638
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,25 @@
|
|||||||
FROM rust:slim as rust
|
FROM rust:slim as rust
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
RUN apt-get update && apt-get install -y git pkg-config libssl-dev
|
RUN apt-get update && apt-get install -y git pkg-config libssl-dev
|
||||||
RUN mkdir src && echo "fn main() {}" > src/main.rs
|
RUN mkdir src && echo "fn main() {}" > src/main.rs
|
||||||
|
|
||||||
COPY Cargo.toml .
|
COPY Cargo.toml .
|
||||||
RUN sed -i '/.*build.rs.*/d' Cargo.toml
|
|
||||||
COPY Cargo.lock .
|
COPY Cargo.lock .
|
||||||
|
|
||||||
|
RUN sed -i '/.*build.rs.*/d' Cargo.toml
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
||||||
COPY . /src
|
COPY . /src
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
RUN useradd -ms /bin/bash -u 1001 libmedium
|
RUN useradd -ms /bin/bash -u 1001 libmedium
|
||||||
RUN apt-get update && apt-get install -y ca-certificates
|
RUN apt-get update && apt-get install -y ca-certificates
|
||||||
RUN mkdir /var/lib/libmedium && chown libmedium /var/lib/libmedium
|
RUN mkdir /var/lib/libmedium && chown libmedium /var/lib/libmedium
|
||||||
|
|
||||||
COPY --from=rust /src/target/release/libmedium /usr/local/bin/
|
COPY --from=rust /src/target/release/libmedium /usr/local/bin/
|
||||||
|
|
||||||
USER libmedium
|
USER libmedium
|
||||||
ENTRYPOINT ["/usr/local/bin/libmedium"]
|
ENTRYPOINT ["/usr/local/bin/libmedium"]
|
||||||
|
38
Makefile
38
Makefile
@ -1,42 +1,20 @@
|
|||||||
default: ## Debug build
|
all:
|
||||||
cargo build
|
cargo build
|
||||||
|
|
||||||
clean: ## Clean all build artifacts and dependencies
|
clean:
|
||||||
@cargo clean
|
cargo clean
|
||||||
|
|
||||||
check: ## Check for syntax errors on all workspaces
|
check:
|
||||||
cargo check --workspace --tests --all-features
|
cargo check --workspace --tests --all-features
|
||||||
#cd utils/cache-bust && cargo check --tests --all-features
|
|
||||||
|
|
||||||
coverage: ## Generate HTML code coverage
|
lint:
|
||||||
./scripts/coverage.sh --coverage
|
|
||||||
|
|
||||||
|
|
||||||
dev-env: ## Download development dependencies
|
|
||||||
cargo fetch
|
|
||||||
|
|
||||||
doc: ## Prepare documentation
|
|
||||||
cargo doc --no-deps --workspace --all-features
|
|
||||||
|
|
||||||
docker: ## Build docker images
|
|
||||||
docker build -t realaravinth/libmedium:master -t realaravinth/libmedium:latest .
|
|
||||||
|
|
||||||
docker-publish: docker ## Build and publish docker images
|
|
||||||
docker push realaravinth/libmedium:master
|
|
||||||
docker push realaravinth/libmedium:latest
|
|
||||||
|
|
||||||
lint: ## Lint codebase
|
|
||||||
cargo fmt -v --all -- --emit files
|
cargo fmt -v --all -- --emit files
|
||||||
cargo clippy --workspace --tests --all-features
|
cargo clippy --workspace --tests --all-features
|
||||||
|
|
||||||
release: ## Release build
|
run:
|
||||||
cargo build --release
|
|
||||||
|
|
||||||
run: default ## Run debug build
|
|
||||||
cargo run
|
cargo run
|
||||||
|
|
||||||
test: ## Run tests
|
test:
|
||||||
cargo test --all-features --no-fail-fast
|
cargo test --all-features --no-fail-fast
|
||||||
|
|
||||||
help: ## Prints help for targets with comments
|
.PHONY: clean check lint run test
|
||||||
@cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
|
||||||
|
88
README.md
88
README.md
@ -1,87 +1,5 @@
|
|||||||
<div align="center">
|
# [ngn.tf] | libmedium
|
||||||
<h1> LibMedium </h1>
|
|
||||||
<p>
|
|
||||||
|
|
||||||
**Privacy-focused proxy for medium.com**
|

|
||||||
|
|
||||||
</p>
|
A fork of the [libmedium](https://github.com/realaravinth/libmedium) project, with my personal changes.
|
||||||
|
|
||||||
[](https://github.com/humanetech-community/awesome-humane-tech)
|
|
||||||
[](https://ci.batsense.net/realaravinth/libmedium)
|
|
||||||
[](https://codecov.io/gh/realaravinth/libmedium)
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
Usable. Should you run into a `HTTP 500 Internal Server Error`, please
|
|
||||||
file a bug report with the URL of the post you were trying to read and
|
|
||||||
the git commit hash of the build. Git commit hash can be obtained from
|
|
||||||
[/api/v1/meta/build](https://libmedium.batsense.net/api/v1/meta/build).
|
|
||||||
|
|
||||||
This proxy works by interacting with Medium's undocumented(probably
|
|
||||||
private but unauthenticated) API. So I've had to make assumptions and
|
|
||||||
tweak API schematics as I run into errors.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- [x] proxy images
|
|
||||||
- [x] proxy GitHub gists
|
|
||||||
- [x] render posts
|
|
||||||
- [x] syntax highlighting for gists
|
|
||||||
- [ ] user pages(WIP)
|
|
||||||
- [ ] RSS feeds
|
|
||||||
|
|
||||||
## Why?
|
|
||||||
|
|
||||||
Knowledge is the true wealth of humanity. If it weren't for our
|
|
||||||
ancestors, who chose to pass down their knowledge and experiences, we
|
|
||||||
would still be a primitive species. Whatever advancement that we as
|
|
||||||
a species have achieved is because we chose to share information.
|
|
||||||
|
|
||||||
To put a paywall on knowledge like that is both obscene and goes against
|
|
||||||
the very nature of humanity.
|
|
||||||
|
|
||||||
It is possible to run a sustainable publication business while still
|
|
||||||
respecting freedom. [LWN.net](https://lwn.net) is one of my favourite
|
|
||||||
publications that has been around forever. So it is possible. I hope
|
|
||||||
medium.com comes up with other, non-harmful ways to run a sustainable
|
|
||||||
business.
|
|
||||||
|
|
||||||
## Instances
|
|
||||||
|
|
||||||
| Instance | Country | Provider | Host |
|
|
||||||
| ------------------------------------------------------------------------- | ------- | ---------- | -------------------------------------- |
|
|
||||||
| https://libmedium.batsense.net | India | Airtel | @realaravinth |
|
|
||||||
| https://md.vern.cc | US | Hetzner | [~vern](https://vern.cc) |
|
|
||||||
| http://md.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/ | N/A | Hetzner | [~vern](https://vern.cc) |
|
|
||||||
| http://vernaqj2qr2pijpgvf3od6ssc3ulz3nv52gwr3hba5l6humuzmgq.b32.i2p/ | N/A | Hetzner | [~vern](https://vern.cc) |
|
|
||||||
| https://medium.hostux.net | France | Gandi | [hostux](https://hostux.net) |
|
|
||||||
| https://read.sudovanilla.com | US | Cloudflare | [SudoVanilla](https://sudovanilla.com) |
|
|
||||||
| https://libmedium.ducks.party | DE | Datalix | [ducks.party](https://ducks.party) |
|
|
||||||
## Deploy
|
|
||||||
|
|
||||||
1. Grab [`./config/default.toml`](./config/default.toml) and make
|
|
||||||
necessary changes
|
|
||||||
|
|
||||||
2. AMD64 pre-compiled images are available on DockerHub.
|
|
||||||
|
|
||||||
```
|
|
||||||
docker run -d \
|
|
||||||
-v ./config/default.toml:/etc/libmedium/config.toml \
|
|
||||||
-p 8082:7000 \
|
|
||||||
--restart always \
|
|
||||||
--name libmedium \
|
|
||||||
realaravinth/libmedium
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are on a different architecture, run make docker and then run the
|
|
||||||
above command.
|
|
||||||
|
|
||||||
```
|
|
||||||
make docker
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Inspired by [Scribe - An Alternative Medium Frontend](https://sr.ht/~edwardloveall/scribe)
|
|
||||||
|
7
config.toml
Normal file
7
config.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
debug = true
|
||||||
|
#cache = "/var/lib/libmedium"
|
||||||
|
port = 7000
|
||||||
|
ip= "0.0.0.0"
|
||||||
|
domain = "example.com"
|
||||||
|
proxy_has_tls = false
|
||||||
|
#workers = 2
|
@ -1,15 +0,0 @@
|
|||||||
debug = true
|
|
||||||
source_code = "https://git.batsense.net/realaravinth/libmedium"
|
|
||||||
#cache = "/var/lib/libmedium"
|
|
||||||
|
|
||||||
[server]
|
|
||||||
# The port at which you want authentication to listen to
|
|
||||||
# takes a number, choose from 1000-10000 if you dont know what you are doing
|
|
||||||
port = 7000
|
|
||||||
#IP address. Enter 0.0.0.0 to listen on all availale addresses
|
|
||||||
ip= "0.0.0.0"
|
|
||||||
# enter your hostname, eg: example.com
|
|
||||||
domain = "localhost"
|
|
||||||
allow_registration = true
|
|
||||||
proxy_has_tls = false
|
|
||||||
#workers = 2
|
|
@ -1,70 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name LibMedium proxy
|
|
||||||
// @version 0.1.1
|
|
||||||
// @description Re-writes medium.com URLs in point to libmedium
|
|
||||||
// @author Aravinth Manivannan
|
|
||||||
// @match https://*/*
|
|
||||||
// @match http://*/*
|
|
||||||
// @grant AGPLv3 or above
|
|
||||||
// ==/UserScript==
|
|
||||||
|
|
||||||
// websites to be proxied
|
|
||||||
const blacklist = [
|
|
||||||
"medium.com",
|
|
||||||
"blog.discord.com",
|
|
||||||
"uxdesign.cc",
|
|
||||||
"towardsdatascience.com",
|
|
||||||
"hackernoon.com",
|
|
||||||
"medium.freecodecamp.org",
|
|
||||||
"psiloveyou.xyz",
|
|
||||||
"betterhumans.coach.me",
|
|
||||||
"codeburst.io",
|
|
||||||
"theascent.pub",
|
|
||||||
"medium.mybridge.co",
|
|
||||||
"uxdesign.cc",
|
|
||||||
"levelup.gitconnected.com",
|
|
||||||
"itnext.io",
|
|
||||||
"entrepreneurshandbook.co",
|
|
||||||
"proandroiddev.com",
|
|
||||||
"blog.prototypr.io",
|
|
||||||
"thebolditalic.com",
|
|
||||||
"blog.usejournal.com",
|
|
||||||
];
|
|
||||||
|
|
||||||
// Location of the proxy
|
|
||||||
const libmediumHost = new URL("https://libmedium.batsense.net");
|
|
||||||
|
|
||||||
const isMedium = (url) => {
|
|
||||||
url = new URL(url);
|
|
||||||
|
|
||||||
if (blacklist.find((bl) => url.host.includes(bl))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let componenets = url.host.split(".");
|
|
||||||
let len = componenets.length;
|
|
||||||
if (
|
|
||||||
len > 1 &&
|
|
||||||
componenets[len - 1] == "com" &&
|
|
||||||
componenets[len - 2] == "medium"
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
if (!window.location.href.includes(libmediumHost.host)) {
|
|
||||||
let urls = document.links;
|
|
||||||
for (let i = 0; i < urls.length; i++) {
|
|
||||||
if (isMedium(urls[i])) {
|
|
||||||
let url = urls[i];
|
|
||||||
let path = url.pathname.split("-");
|
|
||||||
urls[i].pathname = `/utils/post/${path[path.length - 1]}`;
|
|
||||||
urls[i].host = libmediumHost.host;
|
|
||||||
urls[i].search = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
@ -1,12 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"extends": ["config:recommended"],
|
||||||
"extends": ["config:recommended", ":dependencyDashboard"],
|
"timezone": "Europe/Istanbul",
|
||||||
"labels": ["renovate-bot"],
|
"prHourlyLimit": 20
|
||||||
"prHourlyLimit": 0,
|
|
||||||
"timezone": "Asia/kolkata",
|
|
||||||
"prCreation": "immediate",
|
|
||||||
"vulnerabilityAlerts": {
|
|
||||||
"enabled": true,
|
|
||||||
"labels": ["renovate-bot", "renovate-security", "security"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
readonly GRCOV_DOWNLOAD="https://github.com/mozilla/grcov/releases/download/v0.8.2/grcov-linux-x86_64.tar.bz2"
|
|
||||||
readonly TMP_DIR=$(pwd)/tmp
|
|
||||||
readonly PROJECT_ROOT=$(pwd)
|
|
||||||
readonly GRCOV_TARBAL="$TMP_DIR/grcov.tar.bz2"
|
|
||||||
readonly GRCOV="$TMP_DIR/grcov"
|
|
||||||
|
|
||||||
clean_up() {
|
|
||||||
cd $PROJECT_ROOT
|
|
||||||
/bin/rm default.profraw lcov.info *.profraw || true
|
|
||||||
cd target
|
|
||||||
/bin/rm default.profraw lcov.info *.profraw || true
|
|
||||||
cargo clean
|
|
||||||
}
|
|
||||||
|
|
||||||
check_arg(){
|
|
||||||
if [ -z $1 ]
|
|
||||||
then
|
|
||||||
help
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
match_arg() {
|
|
||||||
if [ $1 == $2 ] || [ $1 == $3 ]
|
|
||||||
then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
download() {
|
|
||||||
if [ ! -e $GRCOV ];
|
|
||||||
then
|
|
||||||
echo "[*] Downloading grcov"
|
|
||||||
wget --quiet --output-doc=$GRCOV_TARBAL $GRCOV_DOWNLOAD;
|
|
||||||
cd $TMP_DIR
|
|
||||||
tar -xf $GRCOV_TARBAL;
|
|
||||||
cd $PROJECT_ROOT
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
build_and_test() {
|
|
||||||
export RUSTFLAGS="-Zinstrument-coverage"
|
|
||||||
cd $PROJECT_ROOT
|
|
||||||
|
|
||||||
echo "[*] Building project"
|
|
||||||
cargo build
|
|
||||||
|
|
||||||
export LLVM_PROFILE_FILE="target/libmedium-%p-%m.profraw"
|
|
||||||
|
|
||||||
echo "[*] Running tests"
|
|
||||||
cargo test
|
|
||||||
|
|
||||||
echo "[*] Generating coverage"
|
|
||||||
$GRCOV target/ --binary-path \
|
|
||||||
./target/debug/ \
|
|
||||||
-s . -t lcov --branch \
|
|
||||||
--ignore-not-existing \
|
|
||||||
--ignore "../*" -o target/lcov.info
|
|
||||||
|
|
||||||
$GRCOV target/ --binary-path \
|
|
||||||
./target/debug/ \
|
|
||||||
-s . -t html --branch \
|
|
||||||
--ignore-not-existing \
|
|
||||||
--ignore "../*" -o target/coverage.html
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
run_coverage() {
|
|
||||||
cd $PROJECT_ROOT
|
|
||||||
mkdir $TMP_DIR || true
|
|
||||||
clean_up
|
|
||||||
download
|
|
||||||
build_and_test
|
|
||||||
}
|
|
||||||
|
|
||||||
check_arg $1
|
|
||||||
|
|
||||||
if match_arg $1 'c' '--coverage'
|
|
||||||
then
|
|
||||||
run_coverage
|
|
||||||
else
|
|
||||||
echo "undefined option"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
@ -60,7 +60,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
PKG_NAME, PKG_DESCRIPTION, PKG_HOMEPAGE, VERSION, GIT_COMMIT_HASH
|
PKG_NAME, PKG_DESCRIPTION, PKG_HOMEPAGE, VERSION, GIT_COMMIT_HASH
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("Starting server on: http://{}", SETTINGS.server.get_ip());
|
println!("Starting server on: http://{}", SETTINGS.get_ip());
|
||||||
|
|
||||||
let data = Data::new();
|
let data = Data::new();
|
||||||
|
|
||||||
@ -79,8 +79,8 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.app_data(data.clone())
|
.app_data(data.clone())
|
||||||
.configure(routes::services)
|
.configure(routes::services)
|
||||||
})
|
})
|
||||||
.workers(SETTINGS.server.workers.unwrap_or_else(num_cpus::get))
|
.workers(SETTINGS.workers.unwrap_or_else(num_cpus::get))
|
||||||
.bind(SETTINGS.server.get_ip())
|
.bind(SETTINGS.get_ip())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.run()
|
.run()
|
||||||
.await
|
.await
|
||||||
|
34
src/post.rs
34
src/post.rs
@ -345,6 +345,7 @@ pub fn apply_markup(
|
|||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
let mut paragraphs: Vec<String> = Vec::with_capacity(data.content.body_model.paragraphs.len());
|
let mut paragraphs: Vec<String> = Vec::with_capacity(data.content.body_model.paragraphs.len());
|
||||||
let mut state = ListState::default();
|
let mut state = ListState::default();
|
||||||
|
let mut no_render_html = false;
|
||||||
for (pindex, p) in data.content.body_model.paragraphs.iter().enumerate() {
|
for (pindex, p) in data.content.body_model.paragraphs.iter().enumerate() {
|
||||||
let mut pos = PositionMap::default();
|
let mut pos = PositionMap::default();
|
||||||
if p.type_ == "H3" && pindex == 0 {
|
if p.type_ == "H3" && pindex == 0 {
|
||||||
@ -383,33 +384,42 @@ pub fn apply_markup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut content = String::with_capacity(p.text.len());
|
let mut content = String::with_capacity(p.text.len());
|
||||||
content += &Markup::start(p, gists, pindex, &mut state);
|
let start = &Markup::start(p, gists, pindex, &mut state);
|
||||||
|
content += start;
|
||||||
|
if start == "<pre>" {
|
||||||
|
no_render_html = true;
|
||||||
|
}
|
||||||
pos.arr.sort();
|
pos.arr.sort();
|
||||||
|
let mut page = String::default();
|
||||||
if let Some(first) = pos.arr.first() {
|
if let Some(first) = pos.arr.first() {
|
||||||
//content += p.text.substring(cur, *first as usize);
|
page += p.text.slice(cur..*first as usize);
|
||||||
content += p.text.slice(cur..*first as usize);
|
|
||||||
cur = incr_cur(cur, *first);
|
cur = incr_cur(cur, *first);
|
||||||
for point in pos.arr.iter() {
|
for point in pos.arr.iter() {
|
||||||
//content.push(p.text.substring(start, start + point);
|
|
||||||
// if *point != 0 {
|
|
||||||
|
|
||||||
if cur != *point as usize {
|
if cur != *point as usize {
|
||||||
// content += p.text.substring(cur, *point as usize);
|
page += p.text.slice(cur..*point as usize);
|
||||||
content += p.text.slice(cur..*point as usize);
|
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
let pos_markups = pos.map.get(point).unwrap();
|
let pos_markups = pos.map.get(point).unwrap();
|
||||||
for m in pos_markups.iter() {
|
for m in pos_markups.iter() {
|
||||||
content += &m.apply_markup(pindex);
|
page += &m.apply_markup(pindex);
|
||||||
}
|
}
|
||||||
cur = incr_cur(cur, *point);
|
cur = incr_cur(cur, *point);
|
||||||
}
|
}
|
||||||
log::debug!("LAST");
|
log::debug!("LAST");
|
||||||
content += p.text.slice(cur..);
|
page += p.text.slice(cur..);
|
||||||
content += &Markup::end(p, pindex, &mut state);
|
let end = &Markup::end(p, pindex, &mut state);
|
||||||
|
if end == "</pre>" {
|
||||||
|
no_render_html = false;
|
||||||
|
}
|
||||||
|
content += &page;
|
||||||
|
content += end;
|
||||||
} else {
|
} else {
|
||||||
log::debug!("LAST WITH NO MARKUP");
|
log::debug!("LAST WITH NO MARKUP");
|
||||||
content += p.text.slice(cur..);
|
page += p.text.slice(cur..);
|
||||||
|
if no_render_html {
|
||||||
|
page = page.replace("<", "<").replace(">", ">");
|
||||||
|
}
|
||||||
|
content += &page;
|
||||||
content += &Markup::end(p, pindex, &mut state);
|
content += &Markup::end(p, pindex, &mut state);
|
||||||
}
|
}
|
||||||
paragraphs.push(content);
|
paragraphs.push(content);
|
||||||
|
@ -133,7 +133,7 @@ const INDEX: &str = include_str!("../templates/index.html");
|
|||||||
async fn index() -> impl Responder {
|
async fn index() -> impl Responder {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.content_type("text/html; charset=utf-8")
|
.content_type("text/html; charset=utf-8")
|
||||||
.body(INDEX.replace("SOURCE_CODE_REPLACE", &crate::SETTINGS.source_code))
|
.body(INDEX)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web_codegen_const_routes::get(path = "crate::V1_API_ROUTES.proxy.asset")]
|
#[actix_web_codegen_const_routes::get(path = "crate::V1_API_ROUTES.proxy.asset")]
|
||||||
|
@ -24,7 +24,9 @@ use serde::Deserialize;
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct Server {
|
pub struct Settings {
|
||||||
|
pub debug: bool,
|
||||||
|
pub cache: Option<String>,
|
||||||
pub port: u32,
|
pub port: u32,
|
||||||
pub domain: String,
|
pub domain: String,
|
||||||
pub ip: String,
|
pub ip: String,
|
||||||
@ -32,28 +34,13 @@ pub struct Server {
|
|||||||
pub workers: Option<usize>,
|
pub workers: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
|
||||||
pub fn get_ip(&self) -> String {
|
|
||||||
format!("{}:{}", self.ip, self.port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
|
||||||
pub struct Settings {
|
|
||||||
pub debug: bool,
|
|
||||||
pub cache: Option<String>,
|
|
||||||
pub server: Server,
|
|
||||||
pub source_code: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
impl Settings {
|
impl Settings {
|
||||||
pub fn new() -> Result<Self, ConfigError> {
|
pub fn new() -> Result<Self, ConfigError> {
|
||||||
let mut s = Config::builder();
|
let mut s = Config::builder();
|
||||||
|
|
||||||
// setting default values
|
// setting default values
|
||||||
const CURRENT_DIR: &str = "./config/default.toml";
|
const CURRENT_DIR: &str = "./config.toml";
|
||||||
const ETC: &str = "/etc/libmedium/config.toml";
|
const ETC: &str = "/etc/libmedium/config.toml";
|
||||||
|
|
||||||
if let Ok(path) = env::var("LIBMEDIUM") {
|
if let Ok(path) = env::var("LIBMEDIUM") {
|
||||||
@ -105,4 +92,9 @@ impl Settings {
|
|||||||
fn check_url(&self) {
|
fn check_url(&self) {
|
||||||
Url::parse(&self.source_code).expect("Please enter a URL for source_code in settings");
|
Url::parse(&self.source_code).expect("Please enter a URL for source_code in settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
pub fn get_ip(&self) -> String {
|
||||||
|
format!("{}:{}", self.ip, self.port)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,59 +6,31 @@
|
|||||||
<title>LibMedium</title>
|
<title>LibMedium</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main class="index">
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<h1>LibMedium</h1>
|
<h1>LibMedium</h1>
|
||||||
<p>A free and privacy-respecting medium proxy</p>
|
<p>A free and privacy-respecting medium proxy</p>
|
||||||
<p>
|
<div>
|
||||||
<a
|
<a href="/@tylerneely/fear-and-loathing-in-lock-free-programming-7158b1cdd50c">
|
||||||
href="/@tylerneely/fear-and-loathing-in-lock-free-programming-7158b1cdd50c"
|
Demo
|
||||||
>Demo Article</a
|
</a>
|
||||||
>
|
<span> | </span>
|
||||||
| <a href="SOURCE_CODE_REPLACE">Source Code</a>
|
<a href="https://github.com/realaravinth/libmedium">
|
||||||
</p>
|
Source
|
||||||
|
</a>
|
||||||
|
<span> | </span>
|
||||||
|
<a href="https://git.ngn.tf/ngn/libmedium">
|
||||||
|
Modified Source
|
||||||
|
</a>
|
||||||
|
<span> | </span>
|
||||||
|
<a href="https://liberapay.com/realaravinth">
|
||||||
|
Donate
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
<style>
|
<style>
|
||||||
* {
|
<. include!("./main.css"); .>
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
width: 100%;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
width: 80%;
|
|
||||||
height: 100vh;
|
|
||||||
margin: auto;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center {
|
|
||||||
margin: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1200px) {
|
|
||||||
main {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</html>
|
</html>
|
||||||
|
@ -3,22 +3,48 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
min-height: 100vh;
|
||||||
flex-direction: column;
|
display: block;
|
||||||
|
background: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
.index {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
width: 80%;
|
||||||
|
height: 100vh;
|
||||||
|
margin: auto;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index .center {
|
||||||
|
margin: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index .center h1 {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1200px) {
|
||||||
|
.index {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post {
|
||||||
width: 35em;
|
width: 35em;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
@ -26,27 +52,25 @@ h4,
|
|||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif !important;
|
||||||
|
font-weight: 900;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: rgb(0, 86, 179);
|
color: #02eded;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: rgb(0, 86, 179);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
color: #333;
|
color: #fff;
|
||||||
font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif;
|
font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
line-height: 1.55rem;
|
line-height: 1.55rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
@ -84,11 +108,10 @@ pre {
|
|||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background-color: rgba(175, 184, 193, 0.2);
|
background: #101010;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
post.code-block {
|
||||||
.code-block {
|
|
||||||
display: block;
|
display: block;
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@ -106,7 +129,8 @@ iframe {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
}
|
}
|
||||||
main {
|
|
||||||
|
.post {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<. let mut open_list = false ; .>
|
<. let mut open_list = false ; .>
|
||||||
<main class="container">
|
<main class="post">
|
||||||
<h1><.= data.title .></h1>
|
<h1><.= data.title .></h1>
|
||||||
<p class="meta">
|
<p class="meta">
|
||||||
<a class="author" href="https://medium.com/u/<.= data.creator.id .>" rel="noreferrer">
|
<a class="author" href="https://medium.com/u/<.= data.creator.id .>" rel="noreferrer">
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<meta property="twitter:description" content="<.= data.get_subtitle() .>" />
|
<meta property="twitter:description" content="<.= data.get_subtitle() .>" />
|
||||||
<meta
|
<meta
|
||||||
property="og:url"
|
property="og:url"
|
||||||
content="http://<.= &*crate::SETTINGS.server.domain .>/<.= data.creator.name .>/<.= data.unique_slug .>"
|
content="http://<.= &*crate::SETTINGS.domain .>/<.= data.creator.name .>/<.= data.unique_slug .>"
|
||||||
/>
|
/>
|
||||||
<meta property="og:image" content="<.= preview_img .>" />
|
<meta property="og:image" content="<.= preview_img .>" />
|
||||||
<meta name="twitter:image:src" content="<.= preview_img .>" />
|
<meta name="twitter:image:src" content="<.= preview_img .>" />
|
||||||
@ -72,5 +72,5 @@
|
|||||||
<link rel="author" href="https://medium.com/<.= data.creator.name .>" />
|
<link rel="author" href="https://medium.com/<.= data.creator.name .>" />
|
||||||
<link
|
<link
|
||||||
rel="canonical"
|
rel="canonical"
|
||||||
href="http://<.= &*crate::SETTINGS.server.domain .>/<.= data.creator.name .>/<.= data.unique_slug .>"
|
href="http://<.= &*crate::SETTINGS.domain .>/<.= data.creator.name .>/<.= data.unique_slug .>"
|
||||||
/>
|
/>
|
||||||
|
@ -317,7 +317,6 @@ padding: 0;
|
|||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
width: 35em;
|
width: 35em;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user