blogsync

repository·master·Indexed 41 days ago

https://github.com/x-motemen/blogsync

A CLI client for Hatena Blog that enables a Git-like workflow by managing blog entries as local Markdown files. It allows users to pull, edit, push, and post entries via the AtomPub API, supporting YAML-based configuration and integration with GitHub Actions.

Tokens
7.3K
Snippets
36
Records
45
Agent score
47%

What's inside blogsync

  1. Understand content file path mapping

    master

    Content files are stored in a local directory structure that mirrors the blog's public URL paths.

    URL Path Types

    1. Custom Path (Slug): Explicitly defined by the author (referred to as CustomPath in blogsync).
    2. Auto-generated Path: Automatically assigned by the blog platform (e.g., Hatena Blog) upon publication. The format (e.g., timestamp-based 2001/02/03/150405 or title-based) is determined by the blog's settings.

    Draft File Location

    Because auto-generated URLs are only assigned upon publication, drafts (which do not have a permanent URL) are stored in a special location:

    entry/_draft/$entryID.md

    Where $entryID is the numeric ID found in the entry's EditURL.

    Note: Static pages (fixed pages) require a custom path and will never be stored in the _draft directory.

  2. Understand AtomPub date field mappings for Hatena Blog

    master

    When working with Hatena Blog via AtomPub, it is important to distinguish between different timestamp fields, as they map differently to public-facing metadata.

    Key mappings:

    • updated (AtomPub): This is the field you can control. It maps to published in Atom Feeds, datePublished in HTML, and pubDate in RSS. This is effectively the "Post Date" that users see on the blog.
    • published (AtomPub): The actual publication timestamp. This is immutable by the user and is not exposed in public feeds or HTML.
    • app:edited (AtomPub): The actual last modification timestamp. It maps to updated in Atom Feeds and dateModified in HTML.

    Crucial Note for Developers: To set the visible publication date of a post, you must manipulate the updated field in your AtomPub request.

  3. How to control the visible post date using the `updated` field

    master

    The updated field in AtomPub is the primary mechanism for controlling the "Post Date" displayed on a Hatena Blog.

    Behavioral Rules:

    • Manual Setting: You can explicitly set the updated field to any desired date/time. This is how you implement scheduled posts or backdated entries.
    • Default Behavior (No value provided): If you do not specify updated (or leave it blank in the web editor), the current time at the moment of publication is used.
    • Draft State: If updated is not specified while in a draft state, the internal database value may be NULL, though the AtomPub response will still populate app:edited with the current time.
    • Irreversibility: Once you explicitly set a value for updated, you cannot revert it to an empty/null state via the AtomPub API or the web editor.
    • Scheduled Posts: Setting updated to a future date creates a draft that behaves like a scheduled post. Note that from a data perspective, a future-dated draft is indistinguishable from a scheduled post until the time arrives.
  4. Understand the entry file format

    master

    Entries are stored as Markdown files starting with a YAML Frontmatter block containing metadata.

    Supported Metadata Fields

    • Title: The entry title.
    • Date: The publication timestamp (expected format: 2006-01-02T15:04:05-07:00).
    • URL: The entry URL (automatically generated; manual changes are ignored).
    • EditURL: The unique AtomPub edit URL used to identify the entry.
    • Category: An array of categories.
    • Draft: If set to "yes", the entry is treated as a draft.
    ---
    Title:   Example Title
    Category:
    - scraping
    Date:    2014-10-01T08:30:00+09:00
    URL:     http://motemen.hatenablog.com/entry/2014/10/01/example
    EditURL: https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450066634133
    ---
    
    Content starts here...
  5. Understand Blog ID vs. Delivery Domain

    master

    In blogsync, the domain-like string used as a key in the configuration file is the Blog ID.

    • The Blog ID is the immutable domain set when the blog was created.
    • The Delivery Domain is the domain used to access the blog (e.g., a custom domain).

    Note: If you use a custom domain, the Blog ID and the Delivery Domain will not match. You must use the original Blog ID in your configuration, not your custom domain.

    Example: If your blog is accessed via https://blog.song.mu but was originally created as songmu.hateblo.jp, your Blog ID is songmu.hateblo.jp.

  6. Configure the local root directory

    master

    By default, blogsync organizes content files in a directory structure following the pattern: $local_root/$blogID.

    To control where files are stored, use the local_root key within your blog's configuration block.

    If you want to avoid the extra subdirectory created by the Blog ID and have files placed directly inside the local_root, set omit_domain: true.

    # Default behavior: files go to /Users/Songmu/Blog/songmu.hateblo.jp
    songmu.hateblo.jp:
      local_root: /Users/Songmu/Blog
    
    # Flattened behavior: files go directly to /Users/Songmu/Blog
    songmu.hateblo.jp:
      local_root: /Users/Songmu/Blog
      omit_domain: true
  7. The entry data format

    master

    An entry in blogsync consists of a YAML header followed by the entry content. The header is defined by the entryHeader struct and contains metadata such as title, categories, date, and URLs. This format allows for local storage of blog posts with rich metadata that can be synchronized with remote providers like Hatena Blog.

    File Structure:

    ---
    Title: My Post
    Category:
      - Tech
    Date: 2023-10-27T10:00:00+09:00
    URL: https://example.com/post
    EditURL: https://blog.hatena.ne.jp/user/blog/atom/entry/123
    ---
    
    Actual content starts here...
  8. Understand how blog configuration is merged

    master

    blogsync uses a merging strategy to resolve the final configuration for a specific blog.

    1. File Merging: Settings from the local blogsync.yaml are merged with the global ~/.config/blogsync/config.yaml. Local settings take precedence.
    2. Blog-Specific Merging: When you request a configuration for a specific BlogID (via Get(blogID)), the system takes the specific blogConfig for that ID and merges it with the Default configuration.

    Precedence Order (Highest to Lowest):

    1. Specific blog settings in the local blogsync.yaml.
    2. default settings in the local blogsync.yaml.
    3. Specific blog settings in the global ~/.config/blogsync/config.yaml.
    4. default settings in the global ~/.config/blogsync/config.yaml.
    5. Environment variables (BLOGSYNC_USERNAME, BLOGSYNC_PASSWORD) applied to the Default config.
  9. Configure blogsync

    master

    Configuration is handled via YAML files. You can use a local configuration file (./blogsync.yaml) or a global configuration file (~/.config/blogsync/config.yaml). If both exist, the local configuration takes precedence.

    Configuration Keys

    KeyDescription
    <blogID>The blog ID (e.g., motemen.hatenablog.com). This is the string found in the URL of your Hatena Blog dashboard.
    defaultA special key used to set default values for all blogs.
    <blog>.usernameThe Hatena user ID for that blog.
    <blog>.passwordThe API Key for that blog (found in the blog's detailed settings). This is not your Hatena password.
    <blog>.local_rootThe root directory where entries are stored. Entries are placed in $local_root/$blogID/.
    <blog>.omit_domainIf set, the $blogID is omitted from the storage path, placing entries directly under local_root.
    <blog>.ownerThe user ID of the blog owner (if different from the editor).
    <blog>.entry_directoryThe directory name for blog entries. Defaults to /entry/. Use this if you have changed your Hatena Blog delivery directory.

    Environment Variables

    You can set default credentials using these environment variables (these are ignored if a specific blog has its own username or password configured):

    • BLOGSYNC_USERNAME
    • BLOGSYNC_PASSWORD
    motemen.hatenablog.com:
      username: motemen
      password: <API KEY>
    default:
      local_root: /Users/motemen/Dropbox/Blog