Porównaj commity

...

44 Commity

Autor SHA1 Wiadomość Data
Edward Loveall 8dda4233ac
Add scribe.privacyredirect.com 2024-02-24 09:39:31 -05:00
Edward Loveall 41d5713ca4
Add scribe.r4fo.com 2024-01-21 11:38:42 -05:00
Edward Loveall 6ccea391ed
Add a bunch of well-known, LLM scrapers to robots.txt
Unknown if this will actually stop them, but at least I can show my intent. User agents sourced from https://darkvisitors.com/
2024-01-15 14:55:14 -05:00
Edward Loveall 41b391e22c
add to changelog 2024-01-02 19:34:20 -05:00
Wibi 13f2d963a4
add new instance 2024-01-02 19:32:25 -05:00
Sashanoraa 76bc8fc18f
Update hash in nix package for new yarn.lock 2023-12-22 11:09:17 -05:00
Sashanoraa 4719c65a4d
Update deps in yarn.lock to support newer nodejs versions 2023-12-22 11:08:32 -05:00
Edward Loveall bb2519bdab
Add command to build_static
Uploading the object file and linking it on the server wasn't working. So I'm now using a statically linked binary.

I followed the instructions here: https://crystal-lang.org/reference/1.10/guides/static_linking.html#linux
2023-12-22 10:56:35 -05:00
Edward Loveall bf05a918cc
Version 2023-12-18 2023-12-18 10:46:02 -05:00
Edward Loveall 5e08f4b329
Update License to include https and package.json 2023-12-04 14:43:22 -05:00
Sashanoraa 5d33b071b0
Add Nix package and NixOS moodule
Add a Scribe Nix package and NixOS module to the flake that a user can
build and install.

Includes the following supporting changes:
- Adding a name and version to package.json to make Nix's mkYarnPackage
  happy
- Update laravel-mix to fix ERR_OSSL_EVP_UNSUPPORTED on newer nodejs
  versions
2023-12-04 14:41:05 -05:00
Sashanoraa 10af5c91c3
Remove outdated postgres check and dep from shell.nix 2023-12-04 11:44:15 -05:00
Opnxng 69b3fb570e
Fixed Dockerfile 2023-11-27 17:57:58 -05:00
Edward Loveall 20e31420ba
Update Dockerfile to use multi-arch base image 2023-11-24 17:34:17 -05:00
Edward Loveall bdf0f560f2
Add Docker.arm64 file
Request from opnxng@tuta.io via the mailing list
2023-10-13 08:01:17 -04:00
Edward Loveall 7dc577eff0
Remove Esmail EL BoB instances
Due to their harmful terms of service:

https://github.com/EsmailELBoBDev2/upptime/commit/c46b9bfd
2023-05-21 17:00:55 -04:00
Edward Loveall 30b7a56d8f
Remove unused carbon shard which should fix build failures 2023-05-21 16:09:59 -04:00
extremelyonline 95b794c12b
Added m.opnxng.com 2023-05-21 15:58:03 -04:00
Edward Loveall 6a38a1cebc
Update CHANGELOG 2023-05-06 13:18:13 -04:00
Edward Loveall 467f3c3a63
Change crystal version to 1.8.1 2023-05-06 13:05:58 -04:00
Edward Loveall 853e9ad50d
Add captions to embedded media 2023-05-06 12:10:46 -04:00
Edward Loveall 27faf59549
Upgrade to Lucky 1.0.0 2023-05-06 10:56:02 -04:00
Edward Loveall d1ecb76cdc
Update to lucky 1.0.0-rc1 2023-05-06 10:53:31 -04:00
Edward Loveall e86108e18f
Rearrange article id parsing to be more reliable
The article ID parser looks for a string at the end of a URL path with
a bunch of hex digits. But it also has to handle user, tag, and search
URLs.

* /@ba5eba11
* /tag/0ddba11
* /search?q=ba5eba11

Some URLs are encoded as params. The parser used to look at the result
of the path first, then the params. But paths that ended in
`global-identity-2` messed that up because `2` is a hex digit at the
end of the path. This changes the logic to parse params first and paths
second which gets around this.
2023-03-25 16:32:37 -04:00
Edward Loveall cef1bc256d
Add unique ID to headings
The `name` field on the `paragraph` type contains a unique ID for the
paragraph. It's not guaranteed to be there, on images for example like
in the `fd8d091ab8ef` post, but it's there for everything else I can
find.

This enables deep linking. There's no way to get to the deep link other
than opening up the web console. I wanted to link every heading, but
you can actually have links in part of a heading so that's not tenable.
Maybe a "permalink" link next to every heading?
2023-03-25 11:20:14 -04:00
PrivacyDev 761e4ef170
Add scribe.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion instance 2022-12-11 13:33:09 -05:00
Edward Loveall 815f5c19f0
Update to nodejs 16.18.0
It was pretty old, but also it wasn't installing correctly on an Apple
Silicon machine.
2022-11-06 17:33:20 -05:00
Edward Loveall bf31305617
Version 2022-10-30 2022-11-04 18:25:14 -04:00
blankie e1c70b9db0
Fix viewing articles if the URL has a trailing slash 2022-11-04 18:20:00 -04:00
Edward Loveall d7ea1174ff
Updates to pre/code config
This ensures that code blocks look good at all screen sizes.
2022-10-11 20:33:18 -04:00
Pedro Lucas Porcellis eca9eb7f13
Avoid clipping gist code's content 2022-10-11 19:57:31 -04:00
Edward Loveall 48204b039b
Remove downloadable Redirector config 2022-09-24 15:59:37 -04:00
Edward Loveall 7e927469dc
Replace Redirector extension with LibRedirect
Since Scribe launched, the Redirector extension config has needed
occasional attention. Using regular expressions to cover all edge cases
is difficult. After finding out that Scribe's current config can hang
websites, I decided that [LibRedirect] is likely a more robust
solution. It can rely on more than regular expressions, and is less
work to set up.

[LibRedirect]: https://libredirect.github.io/
2022-09-24 15:50:38 -04:00
Edward Loveall b69fa2f2b1
Update tor instance 2022-09-15 19:03:14 -04:00
Arya Kiran 8240f40719
Add new instance sc.vern.cc
Signed-off-by: Arya Kiran <aryak@vern.cc>
2022-08-20 10:25:19 -04:00
technonerd 98de1d24d6
Add new instance: scribe.rawbit.ninja 2022-08-20 10:19:35 -04:00
PrivacyDev ef8ddb9025
Add scribe.privacydev.net instance 2022-08-16 08:45:12 -04:00
Edward Loveall 931636ebea
Add Tor instance 2022-08-05 08:36:25 -04:00
Edward Loveall 3c6c4770d0
Add scribe.esmailelbob.xyz instance 2022-07-29 08:17:31 -04:00
Edward Loveall 4097aa20df
Fix Redirector config escaped strings
When printing out the configuration JSON, the Redirector extension
expects regex escapes to be escaped, themselves. So `\` becomes `\\`.
However, Crystal treats these as escaped character also, and each `\`
must additionally be escaped, so a single slash becomes `\\\\`
2022-07-19 16:28:23 -04:00
Edward Loveall 449ece843a
Provide a configuration file for the Redirector extension
Instead of providing long detailed instructions for how to configure
the Redirector extension, this provides a single json file that users
can import. I started by making a single file stored in the
`public/assets` directory, but then realized this was a regression since
the instructions were customized to each domain. Instead I can use
Lucky's [data] response to dynamically build the JSON config.

[data]:
https://luckyframework.org/guides/http-and-routing/request-and-response#
handling-responses
2022-07-17 15:00:03 -04:00
Edward Loveall 269ccc1bef
Scroll long code blocks
This sets the width of code blocks to be the width of the page, and
adds a scrollbar for long blocks. Article `c146e768bb41` has some
examples.

I could have also wrapped the codeblocks, but as pointed out by
[~kaki87] this often reduces readability. Hence: scrollbars.

[~kaki87]: https://todo.sr.ht/~edwardloveall/Scribe/6#event-188395
2022-07-17 13:23:03 -04:00
Edward Loveall 5b20d3f6d1
Upgrade to Crystal 1.5.0 2022-07-17 12:39:48 -04:00
Edward Loveall 35b72ada37
Upgrade to Lucky 0.30.1
Upgrading to 0.31.0 should be very easy. It's just running `shards
update` in the root of the project. That should be all.
2022-07-17 11:55:51 -04:00
43 zmienionych plików z 3359 dodań i 3029 usunięć

Wyświetl plik

@ -1 +1 @@
1.2.1
1.8.1

Wyświetl plik

@ -1,2 +1,2 @@
nodejs 12.14.1
crystal 1.2.1
nodejs 16.18.0
crystal 1.5.0

Wyświetl plik

@ -1,6 +1,69 @@
Unreleased
* Add a bunch of well-known, LLM scrapers to robots.txt
* Add command to tag releases
* Modernize nix config
* Added scribe.manasiwibi.com instance
2023-12-18
* Added release script
* Update License to include https and package.json
* Add Nix package and NixOS moodule
* Remove outdated postgres check and dep from shell.nix
* Fixed Dockerfile
* Update Dockerfile to use multi-arch base image
* Add Docker.arm64 file
* Remove instances that promote hate
2023-05-21
* Remove unused carbon shard which should fix build failures
2023-05-06
* Upgrade to Lucky framework 1.0.0
* Upgrade to Crystal version 1.8.1
* If embedded media has a caption, it will now be displayed
2023-03-25
* Headings now have an ID so readers can link to a part if an article
* If a URL contains `global-identity-2`, Scribe will now correctly parse the article ID.
2022-11-06
* Fix viewing articles if the URL has a trailing slash
* Update to nodejs 16.18.0
2022-10-30
* Update to nodejs 16.18.0
2022-10-30
* Fix viewing articles if the URL has a trailing slash
2022-10-11
* Don't clip gist contents (CSS fix)
2022-09-24
* Replace Redirector extension with LibRedirect
* Remove downloadable Redirector config
2022-07-19
* Fix downloadable config file for Redirector extension
2022-07-17
* Fix source code link
* Upgrade to Lucky 0.30.1
* Upgrade to Crystal 1.5.0
* Add scrollbar to long code blocks
* Add a downloadable config file for Redirector extension
2022-05-21

Wyświetl plik

@ -3,13 +3,13 @@ WORKDIR /tmp_build
COPY package.json .
COPY yarn.lock .
RUN yarn install --no-progress --frozen-lockfile
RUN yarn install --network-timeout 120000 --no-progress --frozen-lockfile
COPY webpack.mix.js .
COPY src ./src
RUN yarn prod
FROM crystallang/crystal:1.2.1-alpine as lucky_build
FROM 84codes/crystal:1.8.1-alpine as lucky_build
ENV SKIP_LUCKY_TASK_PRECOMPILATION="1"
RUN apk add yaml-static
WORKDIR /tmp_build

Wyświetl plik

@ -1,7 +1,7 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -643,7 +643,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@ -658,4 +658,4 @@ specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.

58
default.nix 100644
Wyświetl plik

@ -0,0 +1,58 @@
{ crystal
, mkYarnPackage
, fetchYarnDeps
}:
let
version = "1.0.0";
ui = mkYarnPackage {
pname = "scribe-ui";
inherit version;
src = ./.;
packageJSON = ./package.json;
offlineCache = fetchYarnDeps {
yarnLock = ./yarn.lock;
sha256 = "sha256-ixnGRTTKq20tnjOnHeibu12a+n3edV1eM5Om2iNO9fo=";
};
configurePhase = ''
runHook preConfigure
cp -r $node_modules node_modules
chmod +w node_modules
runHook postConfigure
'';
buildPhase = ''
runHook preBuild
export HOME=$(mktemp -d)
OUTPUT_DIR=$out yarn --offline prod
runHook postBuild
'';
installPhase = ''
mkdir -p "$out"
mv public "$out/public"
'';
distPhase = "true";
};
in
crystal.buildCrystalPackage rec {
pname = "scribe";
inherit version;
src = ./.;
shardsFile = ./shards.nix;
preBuild = ''
cp -a ${ui}/public/mix-manifest.json public/mix-manifest.json
'';
doCheck = false;
doInstallCheck = false;
format = "shards";
postInstall = ''
cp -r ${ui}/public "$out/public"
'';
}

Wyświetl plik

@ -3,5 +3,12 @@
"https://scribe.nixnet.services",
"https://scribe.citizen4.eu",
"https://scribe.bus-hit.me",
"https://scribe.froth.zone"
"https://scribe.froth.zone",
"https://scribe.privacydev.net",
"https://scribe.rawbit.ninja",
"https://sc.vern.cc",
"https://m.opnxng.com",
"https://scribe.manasiwibi.com",
"https://scribe.r4fo.com",
"https://scribe.privacyredirect.com"
]

Wyświetl plik

@ -5,6 +5,17 @@
* <https://scribe.citizen4.eu>
* <https://scribe.bus-hit.me>
* <https://scribe.froth.zone>
* <https://scribe.privacydev.net>
* <https://scribe.rawbit.ninja>
* <https://m.opnxng.com>
* <https://scribe.manasiwibi.com>
* <https://scribe.r4fo.com>
* <https://scribe.privacyredirect.com>
* <http://w7uhv5lxhgck72hhimdglmusc54t4m6bionlmd5mvyddq3bs53mohqid.onion> (Tor)
* <http://scribe.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion> (Tor)
* <http://umxccfmp4gyfllsdlzkrnhpd3lxlf4necjolrz22yzcrgwflbrzgtiad.onion> (Tor)
* <http://scribe.r4focoma7gu2zdwwcjjad47ysxt634lg73sxmdbkdozanwqslho5ohyd.onion> (Tor)
* [sc.vern.i2p](http://vern3whzyfmjclq6snhlupma6nrmojghwp37tydfgqotj7sc6izq.b32.i2p) (I2P)
## How do I get my instance on this list?

Wyświetl plik

@ -17,15 +17,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1634282420,
"narHash": "sha256-YOI78SSF4Q/ZFoEgfO8Xy3EnjCW/F9VgB2Qz9YljzhI=",
"lastModified": 1701253981,
"narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0a68ef410b40f49de76aecb5c8b5cc5111bac91d",
"rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable",
"type": "indirect"
}
},

Wyświetl plik

@ -1,8 +1,21 @@
{
inputs = { flake-utils.url = "github:numtide/flake-utils"; };
description = "Scribe";
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
in { devShell = import ./shell.nix { inherit pkgs; }; });
flake-utils.lib.eachDefaultSystem
(system:
let pkgs = nixpkgs.legacyPackages.${system};
in
{
devShell = import ./shell.nix { inherit pkgs; };
packages.default = pkgs.callPackage ./default.nix { };
})
// {
nixosModules.default = import ./module.nix self;
};
}

111
module.nix 100644
Wyświetl plik

@ -0,0 +1,111 @@
self: { config, lib, pkgs, ... }:
let
cfg = config.services.scribe;
in
{
options.services.scribe = {
enable = lib.mkEnableOption (lib.mdDoc "Enable or disable the Scribe service");
package = lib.mkOption {
type = lib.types.package;
default = self.packages."${pkgs.system}".default;
description = lib.mdDoc "Overridable attribute of the scribe package to use.";
};
user = lib.mkOption {
type = lib.types.str;
default = "scribe";
description = lib.mdDoc "User to run the Scribe service as.";
};
group = lib.mkOption {
type = lib.types.str;
default = "scribe";
description = lib.mdDoc "Group to run the Scribe service as.";
};
appDomain = lib.mkOption {
type = lib.types.str;
description = lib.mdDoc ''
The domain that Scribe is being run on. This will appear on the Scribe homepage.
'';
};
port = lib.mkOption {
type = lib.types.port;
description = lib.mdDoc "Port for the Scribe service to use.";
};
environmentFile = lib.mkOption {
type = lib.types.str;
description = lib.mdDoc ''
The path to a file containing environment varible to be set in Scribes environment.
This should be user to set SECRET_KEY_BASE, GITHUB_USERNAME, and GITHUB_PERSONAL_ACCESS_TOKEN.
Descriptions of these settings can be found
[in the official docs](https://sr.ht/~edwardloveall/Scribe/#configuration).
'';
};
};
config = lib.mkIf cfg.enable {
systemd.services.scribe = {
description = "Scribe";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
LUCKY_ENV = "production";
APP_DOMAIN = cfg.appDomain;
PORT = (toString cfg.port);
};
serviceConfig = {
ExecStart = "${cfg.package}/bin/scribe";
EnvironmentFile = cfg.environmentFile;
Restart = "on-failure";
User = cfg.user;
Group = cfg.group;
UMask = "0007";
ProtectSystem = "strict";
ProtectClock = true;
ProtectKernelLogs = true;
SystemCallArchitectures = "native";
ProtectHome = true;
ProtectProc = "noaccess";
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
ProtectControlGroups = true;
ProtectHostname = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
CapabilityBoundingSet = [
"~CAP_SYS_PTRACE"
"~CAP_SYS_ADMIN"
"~CAP_SETGID"
"~CAP_SETUID"
"~CAP_SETPCAP"
"~CAP_SYS_TIME"
"~CAP_KILL"
"~CAP_SYS_PACCT"
"~CAP_SYS_TTY_CONFIG "
"~CAP_SYS_CHROOT"
"~CAP_SYS_BOOT"
"~CAP_NET_ADMIN"
];
};
};
users.users = lib.optionalAttrs (cfg.user == "scribe") {
"scribe" = {
group = "scribe";
isSystemUser = true;
};
};
users.groups = lib.optionalAttrs (cfg.group == "scribe") {
"scribe" = { };
};
};
}

Wyświetl plik

@ -1,10 +1,11 @@
{
"license": "UNLICENSED",
"name": "scribe-ui",
"license": "AGPL-3.0-or-later",
"private": true,
"dependencies": {
"@rails/ujs": "^6.0.0",
"compression-webpack-plugin": "^8.0.1",
"laravel-mix": "^6.0.28",
"laravel-mix": "^6.0.49",
"modern-normalize": "^1.1.0",
"postcss": "^8.3.6",
"tufte-css": "^1.8.0",
@ -22,5 +23,6 @@
"resolve-url-loader": "^3.1.1",
"sass": "^1.26.10",
"sass-loader": "^10.0.2"
}
},
"version": "0.0.0"
}

Wyświetl plik

@ -1,4 +1,55 @@
# Learn more about robots.txt: https://www.robotstxt.org/robotstxt.html
User-agent: *
# 'Disallow' with an empty value allows all paths to be crawled
Disallow:
# ChatGPT-User
User-agent: ChatGPT-User
Disallow: /
# cohere-ai
User-agent: cohere-ai
Disallow: /
# anthropic-ai
User-agent: anthropic-ai
Disallow: /
# Bytespider
User-agent: Bytespider
Disallow: /
# CCBot
User-agent: CCBot
Disallow: /
# FacebookBot
User-agent: FacebookBot
Disallow: /
# Google-Extended
User-agent: Google-Extended
Disallow: /
# GPTBot
User-agent: GPTBot
Disallow: /
# omgili
User-agent: omgili
Disallow: /
# Amazonbot
User-agent: Amazonbot
Disallow: /
# Applebot
User-agent: Applebot
Disallow: /
# PerplexityBot
User-agent: PerplexityBot
Disallow: /
# PerplexityBot
User-agent: PerplexityBot
Disallow: /
# YouBot
User-agent: YouBot
Disallow: /

Wyświetl plik

@ -0,0 +1,20 @@
#!/usr/bin/env bash
# Exit if any subcommand fails
set -e
set -o pipefail
todays_date=$(date "+%Y-%m-%d")
if ! git show HEAD:src/version.cr | rg -q $todays_date; then
echo "Date in committed src/version.cr is not today's date ($todays_date)"
echo "Make sure that the file is both up to date and commited to git."
echo
echo "## src/version.cr"
git show HEAD:src/version.cr
# exit 1
fi
# Via: https://crystal-lang.org/reference/1.10/guides/static_linking.html#linux
~/.docker/bin/docker run --rm -it -v $(pwd):/workspace -w /workspace crystallang/crystal:latest-alpine \
crystal build src/start_server.cr -o ubuntu_server --static --release

18
script/release 100755
Wyświetl plik

@ -0,0 +1,18 @@
#!/bin/sh
set -e
todays_date=$(date "+%Y-%m-%d")
sed -i '' -E "s/[0-9]{4}-[0-9]{2}-[0-9]{2}/$todays_date/" src/version.cr
# Delete the tag if it exists. This will show an error but it's fine
git tag -d "$todays_date" || true
echo
echo "Bumped version to $todays_date"
echo "Here are the commits since the last tag"
echo "Update the Changelog"
echo
git log $(git describe --tags --abbrev=0)~..HEAD --oneline
git tag "$todays_date"

Wyświetl plik

@ -4,7 +4,7 @@ source script/helpers/text_helpers
source script/helpers/function_helpers
# Use this script to check the system for required tools and process that your app needs.
# A few helper functions are provided to make writing bash a little easier. See the
# A few helper functions are provided to make writing bash a little easier. See the
# script/helpers/function_helpers file for more examples.
#
# A few examples you might use here:
@ -17,26 +17,8 @@ if command_not_found "yarn"; then
print_error "Yarn is not installed\n See https://yarnpkg.com/lang/en/docs/install/ for install instructions."
fi
# Only if this isn't CI
if [ -z "$CI" ]; then
lucky ensure_process_runner_installed
fi
if command_not_found "createdb"; then
MSG="Please install the postgres CLI tools, then try again."
if is_mac; then
MSG="$MSG\nIf you're using Postgres.app, see https://postgresapp.com/documentation/cli-tools.html."
fi
MSG="$MSG\nSee https://www.postgresql.org/docs/current/tutorial-install.html for install instructions."
print_error "$MSG"
fi
## CUSTOM PRE-BOOT CHECKS ##
# example:
# if command_not_running "redis-cli ping"; then
# print_error "Redis is not running."
# fi

Wyświetl plik

@ -2,19 +2,19 @@ version: 2.0
shards:
authentic:
git: https://github.com/luckyframework/authentic.git
version: 0.8.1
version: 1.0.0
avram:
git: https://github.com/luckyframework/avram.git
version: 0.22.0
version: 1.0.0
backtracer:
git: https://github.com/sija/backtracer.cr.git
version: 1.2.1
version: 1.2.2
carbon:
git: https://github.com/luckyframework/carbon.git
version: 0.2.0
cadmium_transliterator:
git: https://github.com/cadmiumcr/transliterator.git
version: 0.1.0+git.commit.46c4c14594057dbcfaf27e7e7c8c164d3f0ce3f1
cry:
git: https://github.com/luckyframework/cry.git
@ -22,31 +22,39 @@ shards:
crystar:
git: https://github.com/naqvis/crystar.git
version: 0.2.0
version: 0.2.0+git.commit.56db8bb9dfbd5ed6d7908353405a5fae632a6561
db:
git: https://github.com/crystal-lang/crystal-db.git
version: 0.10.1
version: 0.11.0
dexter:
git: https://github.com/luckyframework/dexter.git
version: 0.3.3
version: 0.3.4
exception_page:
git: https://github.com/crystal-loot/exception_page.git
version: 0.2.1
version: 0.3.0
fnv:
git: https://github.com/naqvis/crystal-fnv.git
version: 0.1.3
habitat:
git: https://github.com/luckyframework/habitat.git
version: 0.4.7
html5:
git: https://github.com/naqvis/crystal-html5.git
version: 0.4.0
lucky:
git: https://github.com/luckyframework/lucky.git
version: 0.29.0
version: 1.0.0
lucky_cache:
git: https://github.com/luckyframework/lucky_cache.git
version: 0.1.0
version: 0.1.1
lucky_env:
git: https://github.com/luckyframework/lucky_env.git
@ -54,11 +62,11 @@ shards:
lucky_flow:
git: https://github.com/luckyframework/lucky_flow.git
version: 0.7.3
version: 0.9.0
lucky_router:
git: https://github.com/luckyframework/lucky_router.git
version: 0.5.1
version: 0.5.2
lucky_task:
git: https://github.com/luckyframework/lucky_task.git
@ -70,15 +78,15 @@ shards:
pg:
git: https://github.com/will/crystal-pg.git
version: 0.24.0
version: 0.26.0
pulsar:
git: https://github.com/luckyframework/pulsar.git
version: 0.2.2
version: 0.2.3
selenium:
git: https://github.com/matthewmcgarvey/selenium.cr.git
version: 0.9.1
version: 0.10.0
shell-table:
git: https://github.com/luckyframework/shell-table.cr.git
@ -94,9 +102,17 @@ shards:
webdrivers:
git: https://github.com/matthewmcgarvey/webdrivers.cr.git
version: 0.4.0
version: 0.4.1
webless:
git: https://github.com/matthewmcgarvey/webless.git
version: 0.1.0
wordsmith:
git: https://github.com/luckyframework/wordsmith.git
version: 0.3.0
version: 0.4.0
xpath2:
git: https://github.com/naqvis/crystal-xpath2.git
version: 0.1.3

Wyświetl plik

@ -8,18 +8,18 @@ targets:
scribe:
main: src/scribe.cr
crystal: 1.2.1
crystal: 1.8.1
dependencies:
lucky:
github: luckyframework/lucky
version: ~> 0.29.0
version: ~> 1.0.0
avram:
github: luckyframework/avram
version: ~> 1.0.0
authentic:
github: luckyframework/authentic
version: ~> 0.8.1
carbon:
github: luckyframework/carbon
version: ~> 0.2.0
version: ~> 1.0.0
lucky_env:
github: luckyframework/lucky_env
version: ~> 0.1.4
@ -31,4 +31,4 @@ dependencies:
development_dependencies:
lucky_flow:
github: luckyframework/lucky_flow
version: ~> 0.7.3
version: ~> 0.9.0

176
shards.nix 100644
Wyświetl plik

@ -0,0 +1,176 @@
{
authentic = {
owner = "luckyframework";
repo = "authentic";
rev = "v1.0.0";
sha256 = "0mc7xqh0zm4jg8vc1awlzr249fviiy1y40w4fvyvq959hlpd6zx4";
};
avram = {
owner = "luckyframework";
repo = "avram";
rev = "v1.0.0";
sha256 = "18w90m5iq0jy026zma05swh2am936j132fs3j730lq7x5yr8289c";
};
backtracer = {
owner = "sija";
repo = "backtracer.cr";
rev = "v1.2.2";
sha256 = "1rknyylsi14m7i77x7c3138wdw27i4f6sd78m3srw851p47bwr20";
};
cadmium_transliterator = {
owner = "cadmiumcr";
repo = "transliterator";
rev = "46c4c14594057dbcfaf27e7e7c8c164d3f0ce3f1";
sha256 = "15x9xbgybqrmqb7s5cpx3fgwysp5ld97vlvz8b196lqmyqnnp3d3";
};
cry = {
owner = "luckyframework";
repo = "cry";
rev = "v0.4.3";
sha256 = "0bcvpbi418855cq1jq911dv6r9wmg81rcvcirqrbw8fv2a093ss5";
};
crystar = {
owner = "naqvis";
repo = "crystar";
rev = "56db8bb9dfbd5ed6d7908353405a5fae632a6561";
sha256 = "0bzq7im3z3asr22wzwyj1z0m3m5aq5hh1kscp5gd8vjw192w2z2a";
};
db = {
owner = "crystal-lang";
repo = "crystal-db";
rev = "v0.11.0";
sha256 = "1ylfhpn64p72ywi39niqb179f61z08q4qd4hhjza05z18mdaghl3";
};
dexter = {
owner = "luckyframework";
repo = "dexter";
rev = "v0.3.4";
sha256 = "08fv3ns0wxkyr2rcifj3ihyaf7g4lsmfamfhdxbkdkmxa9l1z6cj";
};
exception_page = {
owner = "crystal-loot";
repo = "exception_page";
rev = "v0.3.0";
sha256 = "1w82283mgaaw1hy5xk997a1av4sxaa01ydipbxm5nb9nq7fgfydk";
};
fnv = {
owner = "naqvis";
repo = "crystal-fnv";
rev = "v0.1.3";
sha256 = "1vhy3j0ifc0rlrx5b6wbpcvjzw15k303jrz3bzvnxqvi600fvv2b";
};
habitat = {
owner = "luckyframework";
repo = "habitat";
rev = "v0.4.7";
sha256 = "0d183pnswgjwqg388zmnx7s41ai88ca96nl5cybi0z6icr5npw64";
};
html5 = {
owner = "naqvis";
repo = "crystal-html5";
rev = "v0.4.0";
sha256 = "0mr4vd4bl3a22jl8h698zrh8rz6m5lm2lcyx11055gn6fw0yq57k";
};
lucky = {
owner = "luckyframework";
repo = "lucky";
rev = "v1.0.0";
sha256 = "13by6bbgpbbbdncgj87cqy5y6z7s9zb3nr88dh3fwl5mfgygk66z";
};
lucky_cache = {
owner = "luckyframework";
repo = "lucky_cache";
rev = "v0.1.1";
sha256 = "1ic9nfmiv89q5v82ybshd9xqnwv62bv8a5n8rhmsm9cwvdhgc92x";
};
lucky_env = {
owner = "luckyframework";
repo = "lucky_env";
rev = "v0.1.4";
sha256 = "0rcz0kh9rkypgm34r7maqqmgirxblhwzycwxpp0y9ai68lq71qxk";
};
lucky_flow = {
owner = "luckyframework";
repo = "lucky_flow";
rev = "v0.9.0";
sha256 = "1gyxba7lbjhzbd7a5hcswr3i04mz6rqypihhpgx213aa2685c0mw";
};
lucky_router = {
owner = "luckyframework";
repo = "lucky_router";
rev = "v0.5.2";
sha256 = "1gl93rijnbaqybpry19rn951kbx1q1bb5w0npdp4fm0r212b3yh8";
};
lucky_task = {
owner = "luckyframework";
repo = "lucky_task";
rev = "v0.1.1";
sha256 = "0w0rnf22pvj3lp5z8c4sshzwhqgwpbjpm7nry9mf0iz3fa0v48f7";
};
monads = {
owner = "alex-lairan";
repo = "monads";
rev = "v1.0.0";
sha256 = "0wwhsmnzsmw03dn2j4n75sprp4baxg24i1hn1xhfzz9b33rmlxxf";
};
pg = {
owner = "will";
repo = "crystal-pg";
rev = "v0.26.0";
sha256 = "04fwbgrlf2nzma0p2c8ki7p8sk113jhziq2al3ivif2lpmhr39fy";
};
pulsar = {
owner = "luckyframework";
repo = "pulsar";
rev = "v0.2.3";
sha256 = "03pp0r1klqk49fkzjwg9mnxqplv6pdfjn6a1p59f2w1ha5piyy90";
};
selenium = {
owner = "matthewmcgarvey";
repo = "selenium.cr";
rev = "v0.10.0";
sha256 = "062baqafz2rn9czaj8wl2b1l7ngxdph2j8xcr088f2kd8bb0hj7v";
};
shell-table = {
owner = "luckyframework";
repo = "shell-table.cr";
rev = "v0.9.3";
sha256 = "046vymm2r37c6j5bqyjzxdgg5h62slsannzvfhbckkv2r9chwd3w";
};
splay_tree_map = {
owner = "wyhaines";
repo = "splay_tree_map.cr";
rev = "v0.2.2";
sha256 = "0196zpg0v190dv23mwnbia35znxz2j2g8dqynd2b8827qiwmz1vn";
};
teeplate = {
owner = "luckyframework";
repo = "teeplate";
rev = "v0.8.5";
sha256 = "1kr05qrp674rph1324wry57gzvgvcvlz0w27brlvdgd3gi4s8sdj";
};
webdrivers = {
owner = "matthewmcgarvey";
repo = "webdrivers.cr";
rev = "v0.4.1";
sha256 = "05q6z1rv29hrwq77wpas2ki4alwhx4fpallb94q4m9g5h5vfn6ag";
};
webless = {
owner = "matthewmcgarvey";
repo = "webless";
rev = "v0.1.0";
sha256 = "0fg79wy3fq0af77jm121pqfm43dzb7l5rlx13vrl74pgqagms0ih";
};
wordsmith = {
owner = "luckyframework";
repo = "wordsmith";
rev = "v0.4.0";
sha256 = "13fsmwdh431smbmsv869pa8p34g1hqd84za33xsymsycq5459xq2";
};
xpath2 = {
owner = "naqvis";
repo = "crystal-xpath2";
rev = "v0.1.3";
sha256 = "17jl0br2fibc22sz9qdpsqd17rsmnar0jwh4iq25y8rg64pgb1h0";
};
}

Wyświetl plik

@ -1,17 +1,16 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
shellHook = ''
export PKG_CONFIG_PATH=${pkgs.openssl.dev}/lib/pkgconfig
'';
buildInputs = with pkgs; [
crystal
lucky-cli
overmind
nodejs
openssl.dev
postgresql
openssl
pkg-config
shards
yarn
crystal2nix
pcre
];
}

Wyświetl plik

@ -78,6 +78,14 @@ describe ArticleIdParser do
result.should eq(Monads::Just.new("888888abcdef"))
end
it "parses the post id for global identity 2 redirects" do
request = resource_request("/m/global-identity-2?redirectUrl=https%3A%2F%2Fexample.com%2Fmy-post-999999abcdef")
result = ArticleIdParser.parse(request)
result.should eq(Monads::Just.new("999999abcdef"))
end
it "returns Nothing if path is a username" do
request = resource_request("/@ba5eba11")

Wyświetl plik

@ -8,6 +8,7 @@ describe EmbeddedConverter do
store = GistStore.new
paragraph = PostResponse::Paragraph.from_json <<-JSON
{
"name": "ab12",
"text": "",
"type": "IFRAME",
"href": null,
@ -36,6 +37,44 @@ describe EmbeddedConverter do
)
)
end
context "and a caption exists" do
it "returns an EmbeddedContent node with caption" do
store = GistStore.new
paragraph = PostResponse::Paragraph.from_json <<-JSON
{
"name": "ab12",
"text": "Caption",
"type": "IFRAME",
"href": null,
"layout": "INSET_CENTER",
"markups": [],
"iframe": {
"mediaResource": {
"id": "abc123",
"href": "https://twitter.com/user/status/1",
"iframeSrc": "https://cdn.embedly.com/widgets/...",
"iframeWidth": 500,
"iframeHeight": 281
}
},
"metadata": null
}
JSON
caption = FigureCaption.new(children: [Text.new("Caption")] of Child)
result = EmbeddedConverter.convert(paragraph, store)
result.should eq(
EmbeddedContent.new(
src: "https://cdn.embedly.com/widgets/...",
originalWidth: 500,
originalHeight: 281,
caption: caption,
)
)
end
end
end
context "when the mediaResource has a blank iframeSrc value" do
@ -44,6 +83,7 @@ describe EmbeddedConverter do
store = GistStore.new
paragraph = PostResponse::Paragraph.from_json <<-JSON
{
"name": "ab12",
"text": "",
"type": "IFRAME",
"href": null,
@ -73,6 +113,7 @@ describe EmbeddedConverter do
store = GistStore.new
paragraph = PostResponse::Paragraph.from_json <<-JSON
{
"name": "ab12",
"text": "",
"type": "IFRAME",
"href": null,

Wyświetl plik

@ -12,6 +12,7 @@ describe GistScanner do
)
paragraphs = [
PostResponse::Paragraph.new(
name: "ab12",
text: "Check out this gist:",
type: PostResponse::ParagraphType::P,
markups: [] of PostResponse::Markup,
@ -20,6 +21,7 @@ describe GistScanner do
metadata: nil
),
PostResponse::Paragraph.new(
name: "ab13",
text: "",
type: PostResponse::ParagraphType::IFRAME,
markups: [] of PostResponse::Markup,
@ -45,6 +47,7 @@ describe GistScanner do
)
paragraphs = [
PostResponse::Paragraph.new(
name: "ab12",
text: "",
type: PostResponse::ParagraphType::IFRAME,
markups: [] of PostResponse::Markup,
@ -78,6 +81,7 @@ describe GistScanner do
)
paragraphs = [
PostResponse::Paragraph.new(
name: "ab12",
text: "",
type: PostResponse::ParagraphType::IFRAME,
markups: [] of PostResponse::Markup,
@ -86,6 +90,7 @@ describe GistScanner do
metadata: nil
),
PostResponse::Paragraph.new(
name: "ab13",
text: "",
type: PostResponse::ParagraphType::IFRAME,
markups: [] of PostResponse::Markup,

Wyświetl plik

@ -8,6 +8,7 @@ describe PageConverter do
paragraph_json = <<-JSON
[
{
"name": "ab12",
"text": "#{title}",
"type": "H3",
"markups": [],
@ -28,6 +29,7 @@ describe PageConverter do
it "sets the author" do
post_json = <<-JSON
{
"name": "ab12",
"title": "This is a story",
"createdAt": 0,
"creator": {
@ -52,6 +54,7 @@ describe PageConverter do
it "sets the publish date/time" do
post_json = <<-JSON
{
"name": "ab12",
"title": "This is a story",
"createdAt": 1000,
"creator": {
@ -77,6 +80,7 @@ describe PageConverter do
paragraph_json = <<-JSON
[
{
"name": "ab12",
"text": "#{title}",
"type": "H3",
"markups": [],
@ -85,6 +89,7 @@ describe PageConverter do
"metadata": null
},
{
"name": "ab12",
"text": "Content",
"type": "P",
"markups": [],
@ -117,6 +122,7 @@ def default_post_json(
)
<<-JSON
{
"name": "ab12",
"title": "#{title}",
"createdAt": 1628974309758,
"creator": {

Wyświetl plik

@ -8,6 +8,7 @@ describe ParagraphConverter do
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
[
{
"name": "ab12",
"text": "Title",
"type": "H3",
"markups": [],
@ -17,7 +18,7 @@ describe ParagraphConverter do
}
]
JSON
expected = [Heading3.new(children: [Text.new(content: "Title")] of Child)]
expected = [Heading3.new(children: [Text.new(content: "Title")] of Child, identifier: "ab12")]
result = ParagraphConverter.new.convert(paragraphs, gist_store)
@ -29,6 +30,7 @@ describe ParagraphConverter do
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
[
{
"name": "ab12",
"text": "inline code",
"type": "P",
"markups": [
@ -66,6 +68,7 @@ describe ParagraphConverter do
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
[
{
"name": "ab12",
"text": "One",
"type": "ULI",
"markups": [],
@ -74,6 +77,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab13",
"text": "Two",
"type": "ULI",
"markups": [],
@ -82,6 +86,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab14",
"text": "Not a list item",
"type": "P",
"markups": [],
@ -109,6 +114,7 @@ describe ParagraphConverter do
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
[
{
"name": "ab12",
"text": "One",
"type": "OLI",
"markups": [],
@ -117,6 +123,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab13",
"text": "Two",
"type": "OLI",
"markups": [],
@ -125,6 +132,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab14",
"text": "Not a list item",
"type": "P",
"markups": [],
@ -151,6 +159,7 @@ describe ParagraphConverter do
gist_store = GistStore.new
paragraph = PostResponse::Paragraph.from_json <<-JSON
{
"name": "ab12",
"text": "Image by someuser",
"type": "IMG",
"markups": [
@ -197,6 +206,7 @@ describe ParagraphConverter do
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
[
{
"name": "ab12",
"text": "text",
"type": "H2",
"markups": [],
@ -205,6 +215,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab13",
"text": "text",
"type": "H3",
"markups": [],
@ -213,6 +224,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab14",
"text": "text",
"type": "H4",
"markups": [],
@ -221,6 +233,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab15",
"text": "text",
"type": "P",
"markups": [],
@ -229,6 +242,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab16",
"text": "text",
"type": "PRE",
"markups": [],
@ -237,6 +251,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab17",
"text": "text",
"type": "BQ",
"markups": [],
@ -245,6 +260,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab18",
"text": "text",
"type": "PQ",
"markups": [],
@ -253,6 +269,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab19",
"text": "text",
"type": "ULI",
"markups": [],
@ -261,6 +278,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab20",
"text": "text",
"type": "OLI",
"markups": [],
@ -269,6 +287,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab21",
"text": "text",
"type": "IMG",
"markups": [],
@ -281,6 +300,7 @@ describe ParagraphConverter do
}
},
{
"name": "ab22",
"text": "",
"type": "IFRAME",
"markups": [],
@ -296,6 +316,7 @@ describe ParagraphConverter do
"metadata": null
},
{
"name": "ab23",
"text": "Mixtape",
"type": "MIXTAPE_EMBED",
"href": null,
@ -317,9 +338,9 @@ describe ParagraphConverter do
]
JSON
expected = [
Heading1.new([Text.new("text")] of Child),
Heading2.new([Text.new("text")] of Child),
Heading3.new([Text.new("text")] of Child),
Heading1.new([Text.new("text")] of Child, identifier: "ab12"),
Heading2.new([Text.new("text")] of Child, identifier: "ab13"),
Heading3.new([Text.new("text")] of Child, identifier: "ab14"),
Paragraph.new([Text.new("text")] of Child),
Preformatted.new([Text.new("text")] of Child),
BlockQuote.new([Text.new("text")] of Child), # BQ

Wyświetl plik

@ -184,13 +184,13 @@ describe PageContent do
nodes: [
Heading1.new(children: [
Text.new(content: "Title!"),
] of Child),
] of Child, identifier: "ab12"),
] of Child
)
html = PageContent.new(page: page).render_to_string
html.should eq %(<h1>Title!</h1>)
html.should eq %(<h1 id="ab12">Title!</h1>)
end
it "renders an H3" do
@ -201,13 +201,13 @@ describe PageContent do
nodes: [
Heading2.new(children: [
Text.new(content: "Title!"),
] of Child),
] of Child, identifier: "ab12"),
] of Child
)
html = PageContent.new(page: page).render_to_string
html.should eq %(<h2>Title!</h2>)
html.should eq %(<h2 id="ab12">Title!</h2>)
end
it "renders an H4" do
@ -218,13 +218,13 @@ describe PageContent do
nodes: [
Heading3.new(children: [
Text.new(content: "In Conclusion..."),
] of Child),
] of Child, identifier: "ab12"),
] of Child
)
html = PageContent.new(page: page).render_to_string
html.should eq %(<h3>In Conclusion...</h3>)
html.should eq %(<h3 id="ab12">In Conclusion...</h3>)
end
it "renders an image" do
@ -249,6 +249,7 @@ describe PageContent do
end
it "renders embedded content" do
caption_children = [Text.new("Caption")] of Child
page = Page.new(
title: "Title",
author: user_anchor_factory,
@ -258,6 +259,7 @@ describe PageContent do
src: "https://example.com",
originalWidth: 1000,
originalHeight: 600,
caption: FigureCaption.new(children: caption_children)
),
] of Child
)
@ -268,6 +270,11 @@ describe PageContent do
<figure>
<iframe src="https://example.com" width="800" height="480" frameborder="0" allowfullscreen="true">
</iframe>
<label class="margin-toggle" for="#{caption_children.hash}">&#9997;&#xFE0E;</label>
<input class="margin-toggle" type="checkbox" id="#{caption_children.hash}">
<span class="marginnote">
Caption
</span>
</figure>
HTML
end

Wyświetl plik

@ -4,10 +4,10 @@
LuckyFlow.configure do |settings|
settings.stop_retrying_after = 200.milliseconds
settings.base_uri = Lucky::RouteHelper.settings.base_uri
# By default, LuckyFlow is set in "headless" mode (no browser window shown).
# Uncomment this to enable running `LuckyFlow` in a Google Chrome window instead.
# Be sure to disable for CI.
# settings.driver = LuckyFlow::Drivers::Chrome
end
Spec.before_each { LuckyFlow::Server::INSTANCE.reset }
LuckyFlow::Spec.setup

Wyświetl plik

@ -1,3 +0,0 @@
Spec.before_each do
Carbon::DevAdapter.reset
end

Wyświetl plik

@ -1,10 +0,0 @@
app_server = AppServer.new
spawn do
app_server.listen
end
Spec.after_suite do
LuckyFlow.shutdown
app_server.close
end

Wyświetl plik

@ -2,13 +2,14 @@ ENV["LUCKY_ENV"] = "test"
ENV["DEV_PORT"] = "5001"
require "spec"
require "lucky_flow"
require "lucky_flow/ext/lucky"
require "lucky_flow/ext/avram"
require "../src/app"
require "./support/flows/base_flow"
require "./support/**"
require "../db/migrations/**"
require "./setup/**"
include Carbon::Expectations
include Lucky::RequestExpectations
include LuckyFlow::Expectations

Wyświetl plik

@ -1,7 +1,7 @@
class ArticleIdParser
include Monads
ID_REGEX = /[\/\-]([0-9a-f]+)$/i
ID_REGEX = /[\/\-]([0-9a-f]+)\/?$/i
def self.parse(request : HTTP::Request)
new.parse(request)
@ -10,7 +10,7 @@ class ArticleIdParser
def parse(request : HTTP::Request) : Maybe
from_params = post_id_from_params(request.query_params)
from_path = post_id_from_path(request.path)
from_path.or(from_params)
from_params.or(from_path)
end
private def post_id_from_path(request_path : String)

Wyświetl plik

@ -34,11 +34,19 @@ class EmbeddedConverter
EmbeddedContent.new(
src: media.iframeSrc,
originalWidth: media.iframeWidth,
originalHeight: media.iframeHeight
originalHeight: media.iframeHeight,
caption: caption
)
end
end
private def caption : FigureCaption?
if !paragraph.text.blank?
children = [Text.new(paragraph.text || "")] of Child
FigureCaption.new(children: children)
end
end
private def custom_embed(media : PostResponse::MediaResource) : Embedded
if media.href.starts_with?(GIST_HOST_AND_SCHEME)
GithubGist.new(href: media.href, gist_store: gist_store)

Wyświetl plik

@ -16,15 +16,15 @@ class ParagraphConverter
when PostResponse::ParagraphType::H2
paragraph = paragraphs.shift
children = MarkupConverter.convert(paragraph.text, paragraph.markups)
node = Heading1.new(children: children)
node = Heading1.new(children: children, identifier: paragraph.name || "")
when PostResponse::ParagraphType::H3
paragraph = paragraphs.shift
children = MarkupConverter.convert(paragraph.text, paragraph.markups)
node = Heading2.new(children: children)
node = Heading2.new(children: children, identifier: paragraph.name || "")
when PostResponse::ParagraphType::H4
paragraph = paragraphs.shift
children = MarkupConverter.convert(paragraph.text, paragraph.markups)
node = Heading3.new(children: children)
node = Heading3.new(children: children, identifier: paragraph.name || "")
when PostResponse::ParagraphType::IFRAME
paragraph = paragraphs.shift
node = EmbeddedConverter.convert(paragraph, gist_store)

Wyświetl plik

@ -27,6 +27,7 @@ class MediumClient
content {
bodyModel {
paragraphs {
name
text
type
href

Wyświetl plik

@ -40,6 +40,9 @@ class PageContent < BaseComponent
frameborder: "0",
allowfullscreen: true,
)
if caption = child.caption
render_child(caption)
end
end
end
@ -93,15 +96,15 @@ class PageContent < BaseComponent
end
def render_child(node : Heading1)
h1 { render_children(node.children) }
h1(id: node.identifier) { render_children(node.children) }
end
def render_child(node : Heading2)
h2 { render_children(node.children) }
h2(id: node.identifier) { render_children(node.children) }
end
def render_child(node : Heading3)
h3 { render_children(node.children) }
h3(id: node.identifier) { render_children(node.children) }
end
def render_child(child : Image)

Wyświetl plik

@ -7,13 +7,22 @@ p.meta {
line-height: 1;
}
.gist {
width: 55%;
pre {
background-color: rgba(127, 127, 127, 0.1);
margin-right: 1em;
padding: 1em;
padding-left: 2em;
overflow-x: scroll;
}
pre > code {
margin-left: 0;
width: 100%;
}
@media (max-width: 760px) {
.gist {
width: 100%;
pre {
margin-right: 0;
}
}

Wyświetl plik

@ -41,12 +41,24 @@ module Nodes
end
class Heading1 < Container
getter identifier : String
def initialize(@children : Children, @identifier : String)
end
end
class Heading2 < Container
getter identifier : String
def initialize(@children : Children, @identifier : String)
end
end
class Heading3 < Container
getter identifier : String
def initialize(@children : Children, @identifier : String)
end
end
class ListItem < Container
@ -135,8 +147,14 @@ module Nodes
MAX_WIDTH = 800
getter src : String
getter caption : FigureCaption?
def initialize(@src : String, @originalWidth : Int32, @originalHeight : Int32)
def initialize(
@src : String,
@originalWidth : Int32,
@originalHeight : Int32,
@caption : FigureCaption? = nil
)
end
def width
@ -156,7 +174,10 @@ module Nodes
end
def ==(other : EmbeddedContent)
other.src == src && other.width == width && other.height == height
other.src == src &&
other.width == width &&
other.height == height &&
other.caption == caption
end
def empty?

Wyświetl plik

@ -32,6 +32,7 @@ class PostResponse
end
class Paragraph < Base
property name : String?
property text : String?
property type : ParagraphType
property markups : Array(Markup)
@ -40,6 +41,7 @@ class PostResponse
property metadata : Metadata?
def initialize(
@name : String,
@text : String?,
@type : ParagraphType,
@markups : Array(Markup),

Wyświetl plik

@ -18,62 +18,10 @@ class Faq::IndexPage < MainLayout
section do
h2 "How-to Automatically Redirect Medium Articles"
para do
text "If you don't want to manually change the URL every time, you can use an extension to do it for you. "
a "This extension", href: "https://einaregilsson.com/redirector/"
text " works well across most browsers."
text "If you don't want to manually change the URL every time, you can use an extension to do it for you. The "
a "LibRedirect extention", href: "https://libredirect.github.io/"
text " works well across most browsers, and will also redirect to other alternative services."
end
para "Once installed, create a new redirect with the following settings:"
ul do
li do
strong "Description: "
code "Medium -> Scribe"
end
li do
strong "Example URL: "
code "https://medium.com/@user/post-123456abcdef"
end
li do
strong "Include pattern: "
code "^https?://(?:.*\\.)*(?<!(link\\.|cdn\\-images\\-\\d+\\.))medium\\.com(/.*)?$"
end
li do
strong "Redirect to: "
code "https://"
code app_domain
code "$2"
end
li do
strong "Pattern type: "
code "( ) Wildcard (•) Regular Expression"
end
end
h3 "Advanced options"
ul do
li do
strong "Exclude pattern: "
text "(leave blank)"
end
li do
strong "Process matches: "
code "No Processing"
end
li do
strong "Apply to: "
ul do
li { code "[x] Main window (address bar)" }
li { code "[x] IFrames" }
li { code "[ ] Stylesheets" }
li { code "[ ] Scripts" }
li { code "[ ] Images" }
li { code "[ ] Responsive images" }
li { code "[ ] Objects" }
li { code "[x] XMLHttpRequests" }
li { code "[x] History State" }
li { code "[x] Other" }
end
end
end
para "Visiting any medium.com site (including user.medium.com subdomains) should now redirect to Scribe instead!"
end
end

Wyświetl plik

@ -5,6 +5,5 @@ LuckyEnv.load?(".env")
# Require your shards here
require "avram"
require "lucky"
require "carbon"
require "authentic"
require "monads"

Wyświetl plik

@ -1,3 +1,3 @@
module Scribe
VERSION = "2022-07-17"
VERSION = "2023-12-18"
end

Wyświetl plik

@ -7,5 +7,6 @@ require "lucky_task"
require "./tasks/**"
require "./db/migrations/**"
require "lucky/tasks/**"
require "avram/lucky/tasks"
LuckyTask::Runner.run

5450
yarn.lock

Plik diff jest za duży Load Diff