From 98de1d24d6f3fd1b7d48f55486eedfb08e8b904d Mon Sep 17 00:00:00 2001 From: technonerd Date: Fri, 19 Aug 2022 11:04:26 -0400 Subject: [PATCH 01/18] Add new instance: scribe.rawbit.ninja --- docs/instances.json | 3 ++- docs/instances.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/instances.json b/docs/instances.json index 04d4a40..df1c2c1 100644 --- a/docs/instances.json +++ b/docs/instances.json @@ -5,5 +5,6 @@ "https://scribe.bus-hit.me", "https://scribe.froth.zone", "https://scribe.esmailelbob.xyz", - "https://scribe.privacydev.net" + "https://scribe.privacydev.net", + "https://scribe.rawbit.ninja" ] diff --git a/docs/instances.md b/docs/instances.md index 9af930f..c85a12f 100644 --- a/docs/instances.md +++ b/docs/instances.md @@ -7,7 +7,9 @@ * * * +* * (Tor) +* (Tor) ## How do I get my instance on this list? From 8240f4071991543fb6057b5accb0325d65ec2c36 Mon Sep 17 00:00:00 2001 From: Arya Kiran Date: Sat, 20 Aug 2022 19:19:16 +0530 Subject: [PATCH 02/18] Add new instance sc.vern.cc Signed-off-by: Arya Kiran --- docs/instances.json | 3 ++- docs/instances.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/instances.json b/docs/instances.json index df1c2c1..f96b2cc 100644 --- a/docs/instances.json +++ b/docs/instances.json @@ -6,5 +6,6 @@ "https://scribe.froth.zone", "https://scribe.esmailelbob.xyz", "https://scribe.privacydev.net", - "https://scribe.rawbit.ninja" + "https://scribe.rawbit.ninja", + "https://sc.vern.cc" ] diff --git a/docs/instances.md b/docs/instances.md index c85a12f..a401aad 100644 --- a/docs/instances.md +++ b/docs/instances.md @@ -10,6 +10,7 @@ * * (Tor) * (Tor) +* [sc.vern.i2p](http://vern3whzyfmjclq6snhlupma6nrmojghwp37tydfgqotj7sc6izq.b32.i2p) (I2P) ## How do I get my instance on this list? From b69fa2f2b198a71083c543c85f872f294641462c Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Thu, 15 Sep 2022 19:03:14 -0400 Subject: [PATCH 03/18] Update tor instance --- docs/instances.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/instances.md b/docs/instances.md index a401aad..7dc055c 100644 --- a/docs/instances.md +++ b/docs/instances.md @@ -8,7 +8,7 @@ * * * -* (Tor) +* (Tor) * (Tor) * [sc.vern.i2p](http://vern3whzyfmjclq6snhlupma6nrmojghwp37tydfgqotj7sc6izq.b32.i2p) (I2P) From 7e927469dc1351c76a2389e34ad884e319add16a Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 24 Sep 2022 15:08:54 -0400 Subject: [PATCH 04/18] 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/ --- CHANGELOG | 4 ++++ src/pages/faq/index_page.cr | 16 +++------------- src/version.cr | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4362880..21e4beb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2022-09-24 + +* Replace Redirector extension with LibRedirect + 2022-07-19 * Fix downloadable config file for Redirector extension diff --git a/src/pages/faq/index_page.cr b/src/pages/faq/index_page.cr index 74f25d4..8eb0681 100644 --- a/src/pages/faq/index_page.cr +++ b/src/pages/faq/index_page.cr @@ -18,19 +18,9 @@ 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." - end - para do - text "Once installed download a configuration file by " - link "clicking here", to: RedirectionConfig::Index - text "." - end - para do - text "Install it by opening the extension preferences, editing redirects, clicking " - code "Import" - text " and selecting the downloaded file. This will add a new redirection and not overwrite any existing ones. Now visiting any medium.com site (including user.medium.com subdomains) should redirect to Scribe instead!" + 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 end end diff --git a/src/version.cr b/src/version.cr index 0163f61..a569a61 100644 --- a/src/version.cr +++ b/src/version.cr @@ -1,3 +1,3 @@ module Scribe - VERSION = "2022-07-19" + VERSION = "2022-09-24" end From 48204b039bd2e7e452600611fc2461ee8c043929 Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 24 Sep 2022 15:59:37 -0400 Subject: [PATCH 05/18] Remove downloadable Redirector config --- CHANGELOG | 1 + src/actions/redirection_config/index.cr | 56 ------------------------- 2 files changed, 1 insertion(+), 56 deletions(-) delete mode 100644 src/actions/redirection_config/index.cr diff --git a/CHANGELOG b/CHANGELOG index 21e4beb..fa6ab1d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ 2022-09-24 * Replace Redirector extension with LibRedirect +* Remove downloadable Redirector config 2022-07-19 diff --git a/src/actions/redirection_config/index.cr b/src/actions/redirection_config/index.cr deleted file mode 100644 index 948e960..0000000 --- a/src/actions/redirection_config/index.cr +++ /dev/null @@ -1,56 +0,0 @@ -class RedirectionConfig::Index < Lucky::Action - include Lucky::ProtectFromForgery - include Lucky::EnforceUnderscoredRoute - include Lucky::SecureHeaders::DisableFLoC - - default_format :json - - get "/redirection_config" do - data( - data: config_json, - content_type: "application/json", - disposition: "attachment", - filename: "redirector-config.json" - ) - end - - private def config_json - double_escaped_pattern = "^https?://(?:.*\\\\.)*(? Scribe", - "exampleUrl": "https://medium.com/@user/post-123456abcdef", - "exampleResult": "https://#{app_domain}/@user/post-123456abcdef", - "error": null, - "includePattern": "#{double_escaped_pattern}", - "excludePattern": "", - "patternDesc": "", - "redirectUrl": "https://#{app_domain}$2", - "patternType": "R", - "processMatches": "noProcessing", - "disabled": false, - "grouped": false, - "appliesTo": [ - "main_frame", - "sub_frame", - "xmlhttprequest", - "history", - "other" - ] - } - ] - } - JSON - end - - private def app_domain - URI.parse(Home::Index.url).normalize - .to_s - .sub(/\/$/, "") - .sub(/^https?:\/\//, "") - end -end From eca9eb7f135e69931f29b003d03135d2b46d0f0a Mon Sep 17 00:00:00 2001 From: Pedro Lucas Porcellis Date: Tue, 11 Oct 2022 11:37:09 -0300 Subject: [PATCH 06/18] Avoid clipping gist code's content --- src/css/app.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/css/app.css b/src/css/app.css index 3799385..06f3611 100644 --- a/src/css/app.css +++ b/src/css/app.css @@ -11,6 +11,10 @@ p.meta { width: 55%; } +.gist > code { + width: 100% !important; +} + @media (max-width: 760px) { .gist { width: 100%; From d7ea1174ff3ef52ac300cd5cab51c854fea8974e Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Tue, 11 Oct 2022 20:33:18 -0400 Subject: [PATCH 07/18] Updates to pre/code config This ensures that code blocks look good at all screen sizes. --- CHANGELOG | 4 ++++ src/css/app.css | 24 +++++++++++------------- src/version.cr | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fa6ab1d..a5e99fb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2022-10-11 + +* Don't clip gist contents (CSS fix) + 2022-09-24 * Replace Redirector extension with LibRedirect diff --git a/src/css/app.css b/src/css/app.css index 06f3611..49f1b45 100644 --- a/src/css/app.css +++ b/src/css/app.css @@ -7,17 +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; } -.gist > code { - width: 100% !important; +pre > code { + margin-left: 0; + width: 100%; } @media (max-width: 760px) { - .gist { - width: 100%; + pre { + margin-right: 0; } } @@ -38,10 +43,3 @@ figure iframe { footer p span { margin-right: 1em; } - -pre { - background-color: rgba(127, 127, 127, 0.1); - padding: 1em; - overflow-x: scroll; - width: 100%; -} diff --git a/src/version.cr b/src/version.cr index a569a61..43e8bb5 100644 --- a/src/version.cr +++ b/src/version.cr @@ -1,3 +1,3 @@ module Scribe - VERSION = "2022-09-24" + VERSION = "2022-10-11" end From e1c70b9db0290bc2f5598426b28595186a0c7dcc Mon Sep 17 00:00:00 2001 From: blankie Date: Sun, 30 Oct 2022 22:12:48 +0700 Subject: [PATCH 08/18] Fix viewing articles if the URL has a trailing slash --- src/classes/article_id_parser.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/article_id_parser.cr b/src/classes/article_id_parser.cr index 8693ea6..1db19de 100644 --- a/src/classes/article_id_parser.cr +++ b/src/classes/article_id_parser.cr @@ -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) From bf31305617a3d5e30d152872fd1c104f3baaeb34 Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Fri, 4 Nov 2022 18:25:14 -0400 Subject: [PATCH 09/18] Version 2022-10-30 --- CHANGELOG | 4 ++++ src/version.cr | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a5e99fb..e63f441 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2022-10-30 + +Fix viewing articles if the URL has a trailing slash + 2022-10-11 * Don't clip gist contents (CSS fix) diff --git a/src/version.cr b/src/version.cr index 43e8bb5..ea2abf0 100644 --- a/src/version.cr +++ b/src/version.cr @@ -1,3 +1,3 @@ module Scribe - VERSION = "2022-10-11" + VERSION = "2022-10-30" end From 815f5c19f0e6f1561cb3832734aae2154cb60919 Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sun, 6 Nov 2022 17:33:20 -0500 Subject: [PATCH 10/18] Update to nodejs 16.18.0 It was pretty old, but also it wasn't installing correctly on an Apple Silicon machine. --- .tool-versions | 2 +- CHANGELOG | 6 +++++- src/version.cr | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.tool-versions b/.tool-versions index d933386..83bedd9 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -nodejs 12.14.1 +nodejs 16.18.0 crystal 1.5.0 diff --git a/CHANGELOG b/CHANGELOG index e63f441..58f6a9b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ 2022-10-30 -Fix viewing articles if the URL has a trailing slash +* Update to nodejs 16.18.0 + +2022-10-30 + +* Fix viewing articles if the URL has a trailing slash 2022-10-11 diff --git a/src/version.cr b/src/version.cr index ea2abf0..28051b8 100644 --- a/src/version.cr +++ b/src/version.cr @@ -1,3 +1,3 @@ module Scribe - VERSION = "2022-10-30" + VERSION = "2022-11-06" end From 761e4ef170da87a36160a024e1cf1a1275751b56 Mon Sep 17 00:00:00 2001 From: PrivacyDev Date: Mon, 5 Dec 2022 17:39:48 -0500 Subject: [PATCH 11/18] Add scribe.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion instance --- docs/instances.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/instances.md b/docs/instances.md index 7dc055c..ae42fe8 100644 --- a/docs/instances.md +++ b/docs/instances.md @@ -10,6 +10,7 @@ * * (Tor) * (Tor) +* (Tor) * [sc.vern.i2p](http://vern3whzyfmjclq6snhlupma6nrmojghwp37tydfgqotj7sc6izq.b32.i2p) (I2P) ## How do I get my instance on this list? From cef1bc256db9552b675b31ac3bc43234c9b52a3e Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 25 Mar 2023 11:16:00 -0400 Subject: [PATCH 12/18] 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? --- spec/classes/embedded_converter_spec.cr | 3 +++ spec/classes/gist_scanner_spec.cr | 5 ++++ spec/classes/page_converter_spec.cr | 6 +++++ spec/classes/paragraph_converter_spec.cr | 29 ++++++++++++++++++++---- spec/components/page_content_spec.cr | 12 +++++----- src/classes/paragraph_converter.cr | 6 ++--- src/clients/medium_client.cr | 1 + src/components/page_content.cr | 6 ++--- src/models/nodes.cr | 12 ++++++++++ src/models/post_response.cr | 2 ++ src/version.cr | 2 +- 11 files changed, 67 insertions(+), 17 deletions(-) diff --git a/spec/classes/embedded_converter_spec.cr b/spec/classes/embedded_converter_spec.cr index 780bc92..e59c387 100644 --- a/spec/classes/embedded_converter_spec.cr +++ b/spec/classes/embedded_converter_spec.cr @@ -8,6 +8,7 @@ describe EmbeddedConverter do store = GistStore.new paragraph = PostResponse::Paragraph.from_json <<-JSON { + "name": "ab12", "text": "", "type": "IFRAME", "href": null, @@ -44,6 +45,7 @@ describe EmbeddedConverter do store = GistStore.new paragraph = PostResponse::Paragraph.from_json <<-JSON { + "name": "ab12", "text": "", "type": "IFRAME", "href": null, @@ -73,6 +75,7 @@ describe EmbeddedConverter do store = GistStore.new paragraph = PostResponse::Paragraph.from_json <<-JSON { + "name": "ab12", "text": "", "type": "IFRAME", "href": null, diff --git a/spec/classes/gist_scanner_spec.cr b/spec/classes/gist_scanner_spec.cr index a5648e6..24aaf62 100644 --- a/spec/classes/gist_scanner_spec.cr +++ b/spec/classes/gist_scanner_spec.cr @@ -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, diff --git a/spec/classes/page_converter_spec.cr b/spec/classes/page_converter_spec.cr index ccb07db..6770af2 100644 --- a/spec/classes/page_converter_spec.cr +++ b/spec/classes/page_converter_spec.cr @@ -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": { diff --git a/spec/classes/paragraph_converter_spec.cr b/spec/classes/paragraph_converter_spec.cr index e66b824..b7f7b02 100644 --- a/spec/classes/paragraph_converter_spec.cr +++ b/spec/classes/paragraph_converter_spec.cr @@ -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 diff --git a/spec/components/page_content_spec.cr b/spec/components/page_content_spec.cr index bdcd9ed..bbdd631 100644 --- a/spec/components/page_content_spec.cr +++ b/spec/components/page_content_spec.cr @@ -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 %(

Title!

) + html.should eq %(

Title!

) 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 %(

Title!

) + html.should eq %(

Title!

) 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 %(

In Conclusion...

) + html.should eq %(

In Conclusion...

) end it "renders an image" do diff --git a/src/classes/paragraph_converter.cr b/src/classes/paragraph_converter.cr index 00a76f4..267bdb0 100644 --- a/src/classes/paragraph_converter.cr +++ b/src/classes/paragraph_converter.cr @@ -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) diff --git a/src/clients/medium_client.cr b/src/clients/medium_client.cr index 1898497..cc71a1c 100644 --- a/src/clients/medium_client.cr +++ b/src/clients/medium_client.cr @@ -27,6 +27,7 @@ class MediumClient content { bodyModel { paragraphs { + name text type href diff --git a/src/components/page_content.cr b/src/components/page_content.cr index 2849bbc..a4ea2db 100644 --- a/src/components/page_content.cr +++ b/src/components/page_content.cr @@ -93,15 +93,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) diff --git a/src/models/nodes.cr b/src/models/nodes.cr index 0ddce68..43139c1 100644 --- a/src/models/nodes.cr +++ b/src/models/nodes.cr @@ -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 diff --git a/src/models/post_response.cr b/src/models/post_response.cr index b295ffd..c707a98 100644 --- a/src/models/post_response.cr +++ b/src/models/post_response.cr @@ -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), diff --git a/src/version.cr b/src/version.cr index 28051b8..e38ca6b 100644 --- a/src/version.cr +++ b/src/version.cr @@ -1,3 +1,3 @@ module Scribe - VERSION = "2022-11-06" + VERSION = "2023-03-25" end From e86108e18f8ecc26d39d504b53cd08e46a1fe25e Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 25 Mar 2023 16:32:37 -0400 Subject: [PATCH 13/18] 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. --- spec/classes/article_id_parser_spec.cr | 8 ++++++++ src/classes/article_id_parser.cr | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/classes/article_id_parser_spec.cr b/spec/classes/article_id_parser_spec.cr index 2baef20..044aebf 100644 --- a/spec/classes/article_id_parser_spec.cr +++ b/spec/classes/article_id_parser_spec.cr @@ -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") diff --git a/src/classes/article_id_parser.cr b/src/classes/article_id_parser.cr index 1db19de..639013c 100644 --- a/src/classes/article_id_parser.cr +++ b/src/classes/article_id_parser.cr @@ -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) From d1ecb76cdccb9c7599a477b8b606b0f28869f01d Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 6 May 2023 10:53:31 -0400 Subject: [PATCH 14/18] Update to lucky 1.0.0-rc1 --- shard.lock | 42 +++++++++++++++++++----------- shard.yml | 12 ++++----- spec/setup/configure_lucky_flow.cr | 4 +-- spec/spec_helper.cr | 2 ++ src/version.cr | 2 +- tasks.cr | 1 + 6 files changed, 39 insertions(+), 24 deletions(-) diff --git a/shard.lock b/shard.lock index aff3c9c..3a214d8 100644 --- a/shard.lock +++ b/shard.lock @@ -2,31 +2,27 @@ version: 2.0 shards: authentic: git: https://github.com/luckyframework/authentic.git - version: 0.8.2 + version: 0.9.0 avram: git: https://github.com/luckyframework/avram.git - version: 0.23.0 + version: 1.0.0 backtracer: git: https://github.com/sija/backtracer.cr.git - version: 1.2.1 + version: 1.2.2 cadmium_transliterator: git: https://github.com/cadmiumcr/transliterator.git version: 0.1.0+git.commit.46c4c14594057dbcfaf27e7e7c8c164d3f0ce3f1 - carbon: - git: https://github.com/luckyframework/carbon.git - version: 0.2.1 - cry: git: https://github.com/luckyframework/cry.git version: 0.4.3 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 @@ -38,15 +34,23 @@ shards: exception_page: git: https://github.com/crystal-loot/exception_page.git - version: 0.2.2 + 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.30.1 + version: 1.0.0 lucky_cache: git: https://github.com/luckyframework/lucky_cache.git @@ -58,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 @@ -82,7 +86,7 @@ shards: 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 @@ -98,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 diff --git a/shard.yml b/shard.yml index 24bbe56..dafb21a 100644 --- a/shard.yml +++ b/shard.yml @@ -13,13 +13,13 @@ crystal: 1.5.0 dependencies: lucky: github: luckyframework/lucky - version: ~> 0.30.1 + version: ~> 1.0.0-rc1 + avram: + github: luckyframework/avram + version: ~> 1.0.0-rc1 authentic: github: luckyframework/authentic - version: ~> 0.8.2 - carbon: - github: luckyframework/carbon - version: ~> 0.2.0 + version: ~> 0.9.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 diff --git a/spec/setup/configure_lucky_flow.cr b/spec/setup/configure_lucky_flow.cr index cc9e935..d651d9d 100644 --- a/spec/setup/configure_lucky_flow.cr +++ b/spec/setup/configure_lucky_flow.cr @@ -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 \ No newline at end of file diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 1a9cc7e..f64b64a 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -2,6 +2,8 @@ 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/**" diff --git a/src/version.cr b/src/version.cr index e38ca6b..9fa3801 100644 --- a/src/version.cr +++ b/src/version.cr @@ -1,3 +1,3 @@ module Scribe - VERSION = "2023-03-25" + VERSION = "2023-05-06" end diff --git a/tasks.cr b/tasks.cr index c192d8a..176c5ae 100644 --- a/tasks.cr +++ b/tasks.cr @@ -7,5 +7,6 @@ require "lucky_task" require "./tasks/**" require "./db/migrations/**" require "lucky/tasks/**" +require "avram/lucky/tasks" LuckyTask::Runner.run From 27faf59549425888c38146f01d91355cb3fd920d Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 6 May 2023 10:56:02 -0400 Subject: [PATCH 15/18] Upgrade to Lucky 1.0.0 --- shard.lock | 2 +- shard.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shard.lock b/shard.lock index 3a214d8..77c29ce 100644 --- a/shard.lock +++ b/shard.lock @@ -2,7 +2,7 @@ version: 2.0 shards: authentic: git: https://github.com/luckyframework/authentic.git - version: 0.9.0 + version: 1.0.0 avram: git: https://github.com/luckyframework/avram.git diff --git a/shard.yml b/shard.yml index dafb21a..2435671 100644 --- a/shard.yml +++ b/shard.yml @@ -13,13 +13,13 @@ crystal: 1.5.0 dependencies: lucky: github: luckyframework/lucky - version: ~> 1.0.0-rc1 + version: ~> 1.0.0 avram: github: luckyframework/avram - version: ~> 1.0.0-rc1 + version: ~> 1.0.0 authentic: github: luckyframework/authentic - version: ~> 0.9.0 + version: ~> 1.0.0 lucky_env: github: luckyframework/lucky_env version: ~> 0.1.4 From 853e9ad50dddc8facf762c9449232e4c3aa71560 Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 6 May 2023 12:10:46 -0400 Subject: [PATCH 16/18] Add captions to embedded media --- spec/classes/embedded_converter_spec.cr | 38 +++++++++++++++++++++++++ spec/components/page_content_spec.cr | 7 +++++ src/classes/embedded_converter.cr | 10 ++++++- src/components/page_content.cr | 3 ++ src/models/nodes.cr | 13 +++++++-- 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/spec/classes/embedded_converter_spec.cr b/spec/classes/embedded_converter_spec.cr index e59c387..1887843 100644 --- a/spec/classes/embedded_converter_spec.cr +++ b/spec/classes/embedded_converter_spec.cr @@ -37,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 diff --git a/spec/components/page_content_spec.cr b/spec/components/page_content_spec.cr index bbdd631..5536dd2 100644 --- a/spec/components/page_content_spec.cr +++ b/spec/components/page_content_spec.cr @@ -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
+ + + + Caption +
HTML end diff --git a/src/classes/embedded_converter.cr b/src/classes/embedded_converter.cr index 925e54f..12271be 100644 --- a/src/classes/embedded_converter.cr +++ b/src/classes/embedded_converter.cr @@ -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) diff --git a/src/components/page_content.cr b/src/components/page_content.cr index a4ea2db..4f3d094 100644 --- a/src/components/page_content.cr +++ b/src/components/page_content.cr @@ -40,6 +40,9 @@ class PageContent < BaseComponent frameborder: "0", allowfullscreen: true, ) + if caption = child.caption + render_child(caption) + end end end diff --git a/src/models/nodes.cr b/src/models/nodes.cr index 43139c1..266ad43 100644 --- a/src/models/nodes.cr +++ b/src/models/nodes.cr @@ -147,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 @@ -168,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? From 467f3c3a6361e4ffe3e869ebaf2de14f018e47f2 Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 6 May 2023 13:05:58 -0400 Subject: [PATCH 17/18] Change crystal version to 1.8.1 --- .crystal-version | 2 +- shard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.crystal-version b/.crystal-version index bc80560..a8fdfda 100644 --- a/.crystal-version +++ b/.crystal-version @@ -1 +1 @@ -1.5.0 +1.8.1 diff --git a/shard.yml b/shard.yml index 2435671..a5cda11 100644 --- a/shard.yml +++ b/shard.yml @@ -8,7 +8,7 @@ targets: scribe: main: src/scribe.cr -crystal: 1.5.0 +crystal: 1.8.1 dependencies: lucky: From 6a38a1cebc7be6c5dc24231c01717500ab01503a Mon Sep 17 00:00:00 2001 From: Edward Loveall Date: Sat, 6 May 2023 13:18:13 -0400 Subject: [PATCH 18/18] Update CHANGELOG --- CHANGELOG | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 58f6a9b..a85912e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,19 @@ +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