{"id":15517277,"url":"https://github.com/skx/e-comments","last_synced_at":"2025-04-23T03:50:56.060Z","repository":{"id":13763363,"uuid":"16458160","full_name":"skx/e-comments","owner":"skx","description":"External comments for static HTML pages, a lightweight self-hosted disqus alternative.","archived":false,"fork":false,"pushed_at":"2018-01-23T17:30:47.000Z","size":98,"stargazers_count":101,"open_issues_count":0,"forks_count":7,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-17T19:17:00.446Z","etag":null,"topics":["disqus","external-comments","redis","ruby","self-hosted","sqlite"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-02-02T16:39:53.000Z","updated_at":"2025-02-10T08:46:17.000Z","dependencies_parsed_at":"2022-09-23T15:15:58.633Z","dependency_job_id":null,"html_url":"https://github.com/skx/e-comments","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fe-comments","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fe-comments/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fe-comments/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fe-comments/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skx","download_url":"https://codeload.github.com/skx/e-comments/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250366685,"owners_count":21418768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["disqus","external-comments","redis","ruby","self-hosted","sqlite"],"created_at":"2024-10-02T10:12:20.406Z","updated_at":"2025-04-23T03:50:56.025Z","avatar_url":"https://github.com/skx.png","language":"JavaScript","readme":"External Comments\n=================\n\nThis is an open source commenting system, allowing you to include\ncomments on your static website(s) without the privacy concerns of\nusing an external system such as disqus.\n\nEmbedding comments is as simple as including a couple of small javascript\nfiles, along with a CSS file for styling.\n\nFeatures:\n\n* Multiple backends for storage:\n   * Redis\n   * SQlite\n   * Adding new backends is simple.\n* Markdown formatting of comments.\n* Support for __threaded discussion__.\n   * You can limit the depth of discussions, to a given depth.\n   * Or leave the defaults in-place to allow arbitrarily nested replies.\n* Anti-spam plugins:\n   * Three simple plugins included as a demonstration.\n   * The sample plugins block hyperlinks in comment-author names, bodies which reference `viagra`, and any remote IPs which have been locally blacklisted.\n* Simplicity\n   * The code is small enough to easily understand and extend for your custom needs, but functional as-is.\n* Degrades gracefully when Javascript is disabled\n   * No white boxes, empty spaces, or error-messages.\n\nAnti-features:\n\n* There is no administrative panel to edit/delete comments.\n   * This requires manual intervention in the back-end.\n* Commenters do not get their details remembered.\n   * Nor can they receive emails on replies to their comments.\n\nRun-time (client-side) dependencies:\n\n* jQuery\n* mustache.js\n    * Included in this repository.\n\nThis server was originally written for a server optimization guide but since it seemed like a generally-useful piece of code it was moved into its own repository.\n\n### Contents\n\n* [The comment server](#the-comment-server)\n    * [API](#comment-server-api)\n    * [Dependencies](#comment-server-dependencies)\n    * [Deployment](#comment-server-deployment)\n* [Client-Side Setup](#client-side-setup)\n    * [Advanced Usage](#advanced-usage)\n    * [Theming](#theming)\n* [Alternative Solutions](#alternative-systems)\n* [Running Locally](#running-locally)\n\n\n## The Comment Server\n\nThe comment server exports a public API allowing the javascript on your\n(static) pages to add comments, and retrieve those comments which already\nexist.  It is written in Ruby using the [sinatra](http://www.sinatrarb.com/),\nframework.\n\nThere are two choices for storing the actual comment data:\n\n* A [Redis server](http://redis.io/).\n* An SQLite database.\n    * This is preferred.\n\nAdding new backends should be straight-forward, and pull-requests are\nwelcome for MySQL, CouchDB, etc.\n\n\n### Comment Server API\n\nThe server implements the following two API methods:\n\n* `GET /comments/ID`\n   * This retrieves the comments associated with the given ID.\n   * The return value is an array of hashes.\n   * The hashes have keys such as  `author`, `body` \u0026 `ip`.\n* `POST /comments/ID`\n   * Adds a new comment to the collection for the given ID.\n   * The submission should have the fields `author` and `body`.\n   * Optionally the submission might contain the field `email`.\n       * If an email is stored a Gravitar field will be present in the retrieval, but the actual email address will not be sent back to avoid a privacy leak.\n   * Optionally the submission might contain a `parent` field.\n       * This is used to support nested comments.\n       * There are no limits on the number of nested comments.\n\n\n### Comment Server Dependencies\n\nThese dependencies were tested on a Debian GNU/Linux stable machine,\nbut are a good starting point for other distributions:\n\n    apt-get install ruby ruby-json ruby-sinatra ruby-redcarpet ruby-uuidtools ruby-rack-test\n\nFor storage you get to choose between one of these two alternatives:\n\n    apt-get install libsqlite3-ruby\n\nOr\n\n    apt-get install ruby-redis\n\n\n### Comment Server Deployment\n\nDeploying the server involves two steps:\n\n* Actually launching the server, via systemd, runit, or similar.\n* Configuring your webserver to proxy to it.\n\nTo launch the comment server you'll run one of these two commands,\ndepending on which storage back-end you prefer to use:\n\n     $ ./server/comments.rb --storage=redis  --storage-args=127.0.0.1\n     $ ./server/comments.rb --storage=sqlite --storage-args=/tmp/foo.db\n\nThe server will bind to `127.0.0.1:9393` by default, so you'll\nneed to setup a virtual host in nginx/apache which will forward\nconnections to that instance.\n\nFor nginx this would look something like this:\n\n    server {\n      listen          80;\n      server_name     comments.example.com;\n      location / {\n        proxy_pass        http://127.0.0.1:9393;\n        proxy_redirect    off;\n        proxy_set_header  X-Forwarded-For $remote_addr;\n      }\n    }\n\n\n## Client-Side Setup\n\nTo allow comments upon your static site you must update your page(s) to\ninclude the appropriate javascript libraries, and the CSS.\n\nFor basic usage you'll be adding this to the `\u003chead\u003e` of your HTML:\n\n    \u003cscript src=\"https://code.jquery.com/jquery-1.12.4.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"/js/mustache.js\" type=\"text/javascript\"\u003e\u003c/script\u003e\n    \u003cscript src=\"/js/e-comments.js\" type=\"text/javascript\"\u003e\u003c/script\u003e\n\n    \u003cscript type=\"text/javascript\"\u003e\n      $( document ).ready(function() {\n        discussion( \"http://server.name/comments/COMMENT_ID\" );\n    });\n    \u003c/script\u003e\n\nAt the place you wish your comments to be displayed you'll add:\n\n    \u003cdiv id=\"comments\"\u003e\u003c/div\u003e\n\n\n### Advanced Usage\n\nThe example above configured the display of comments with the defaults,\nbut the `discussion()` method actually accepts two arguments:\n\n* The URL of the comment-server you've got running, including a discussion ID.\n* An optional hash of parameters, to customize behaviour.\n\nThe discussion will require a unique key, which will be specified as\nan URL.  For example your home-page might include this:\n\n        discussion( \"http://comments.example.com/comments/home\" );\n\nYour about page this:\n\n        discussion( \"http://comments.example.com/comments/about\" );\n\nThis will ensure that each page will have a distinct discussion-thread\nupon it.\n\nThe second parameter, which is optional, allows things to be customized.\nValid options for this hash include:\n\n* `comments`\n    * The ID of the `\u003cdiv\u003e` in which comments will be inserted.\n    * The default will be `comments`, as documented above.\n* `max_depth`\n    * This should be an integer holding the maximum thread-depth permitted.\n    * The default value is `0`, which allows an unlimited thread-depth.\n* `threading`\n    * A boolean to control whether threading is enabled/disabled.\n    * The default value is `true`.\n* `comment_template`\n    * The ID of a script-div which contains a template for comment-formatting.\n* `reply_template`\n    * The ID of a script-div which contains a template for the \"add comment\" form.\n\nIf you wished to disable threading, allowing only a flat discussion\nhierarchy, you'd use this:\n\n     discussion( \"http://comments.example.com/comments/about\",\n                 { threading: false });\n\nIf you wished to allow comments, but stop arbitrary nesting:\n\n     discussion( \"http://comments.example.com/comments/about\",\n                 { threading: true, max_depth: 2 });\n\n\n### Theming\n\nYou _could_ customize the formatting of comments, and the comment-submission\nform via CSS, however you might prefer to replace the presentation with\nsomething entirely different.\n\nTo allow this we use  [mustache.js](https://github.com/janl/mustache.js) templates for:\n\n* The display of the individual comments.\n* The display of the reply-form.\n\nYou can hide templates for both of these things inside your static HTML-files\nand cause them to be used by specifing their IDs like so:\n\n        discussion( \"http://localhost:9393/comments/id\",\n                    { comment_template: '#comment_template',\n                      reply_template: '#reply_form'} );\n\nThis would require your HTML-page to contain something like this:\n\n    \u003cscript id=\"comment_template\" type=\"x-tmpl-mustache\"\u003e\n     \u003cdiv class=\"comment\"\u003e\n     \u003cdiv class=\"link\"\u003e\u003ca href=\"#comment_{{ id }}\"\u003e#{{ id }}\u003c/a\u003e\u003c/div\u003e\n     ..\n    \u003c/script\u003e\n\n\u003e **NOTE**: You can find the default templates which are used inside the  `e-comments.js` file.\n\nReplacing the template entirely allows you to display different data, for example you might wish to show the thread-level of each comment.  This could be achived by adding the following to the comment-template:\n\n     Depth:{{#depth}}{{ uuid }}{{/depth}}\n\nI'm open to pull-requests adding more formatting options, if you have something you think would be useful.  (Similarly any improvements to the presentation of comments by default would be appreciated.)\n\n\n## Alternative Systems\n\n\n* [isso](https://github.com/posativ/isso/)\n    * Python-based.\n    * Seems active, and allows users to edit/delete their comments, which is nice.\n* [talkatv](https://github.com/talkatv/talkatv)\n    * Python-based.\n    * No screenshots, no online demo, seems to be a [defunct project](https://github.com/talkatv/talkatv/issues/45#issuecomment-78016274).\n* [Juvia](https://github.com/phusion/juvia)\n    * Ruby-on-rails-based.\n    * [No longer maintained](https://github.com/phusion/juvia/issues/65).\n\n## Running Locally\n\nProviding you have the dependencies installed you can run the same\ndemo locally:\n\n* Launch the comment-server in one terminal.\n     * `./server/comments.rb --storage=sqlite --storage-args=/tmp/foo.db`\n     * The file `/tmp/foo.db` will be created, and used to store your comments.\n* Start a local HTTP server in clients in another:\n     * `cd client ; python -m SimpleHTTPServer`\n* Open your browser:\n     * http://localhost:8000/demo.html\n     * Add some comments.\n\nThis local demo works because the `demo.html` file is configured to access\ncomments at `http://localhost:9393/`.  In a real deployment you'd hide\nthe comment-server behind a reverse proxy and access it via a public\nname such as `comments.example.com`.\n\n\nSteve\n--\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskx%2Fe-comments","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskx%2Fe-comments","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskx%2Fe-comments/lists"}