跳转到主要内容

存档RSS/Atom聚合源的全部内容,包括封装和资产。

项目描述

PyPI latest release version
PyPI Python versions
Python code style
REUSE license status
GitLab latest release
GitLab CI/CD pipeline status
GitLab coverage report
GitLab repo stars
GitHub release (latest SemVer)
GitHub Actions status
Codecov test coverage
GitHub repo stars
Docker Hub image version (latest semver)
Docker Hub image pulls count
Docker Hub stars
Docker Hub image size (latest semver)
KeyBase PGP key ID
GitHub followers count
LiberaPay donated per week
LiberaPay patrons count

$ feed-archiver》命令旨在尽可能全面地存档RSS/Atom聚合源,以便存档可以满足(至少)以下2个用例

  1. Feed Enclosures和资产的镜像

    存档聚合源的镜像,可以进一步提供给聚合源客户端/订阅者(例如播客抓取器)。例如,您可以通过手机上的播客抓取器应用程序订阅存档聚合源,实现自动下载和自动删除播客剧集,同时在具有足够存储空间的HTPC服务器上存档相同的剧集。存档版本的聚合源也将反映存档下载的最早形式的聚合源XML、项目XML、封装和资产,因此可以用于反映给客户端的原版,即使远程聚合源随着时间的推移发生变化。

  2. 将聚合源封装导入媒体库

    适用于导入其他媒体软件(如媒体库服务器)的替代密封项目层次结构。例如,您的播客剧集也可以在您的Jellyfin/Emby/Plex库中提供。

详细描述

Feed Enclosures和资产的镜像

为满足用例#1,feed-archiver将密封和外部资产(例如,在XML中指定为URL的密封和项目徽标)下载到存档的本地文件系统,调整密封XML中下载项的URL,并将密封XML保存到存档中。这使得本地存档文件系统适用于使用简单的静态网站服务器(如nginx)向密封客户端/订阅者提供服务。

所有URL都被转换为尽可能易读的文件系统路径,同时避免可能引起常见文件系统问题的特殊字符。具体来说,特殊字符使用Python的urllib.parse.quote函数进行%xx转义。注意,这会加倍转义远程URL中的任何%xx转义。

.../foo?bar=qux%2Fbaz#corge -> .../foo%3Fbar=qux%252Fbaz#corge

然后将URL转换为相应的文件系统路径

https://foo-username:secret@grault.example.com/feeds/garply.rss -> ./https/foo-username%3Asecret@grault.example.com/feeds/garply.rss

假设存档的密封都通过HTTPS/TLS从一个名为feeds.example.comnginx server_name的服务器提供,那么在内容聚合客户端(如播客抓取应用)中订阅存档密封,可以通过以下方式转换URL

https://foo-username:secret@grault.example.com/feeds/garply.rss -> https://feeds.example.com/https/foo-username%3Asecret@grault.example.com/feeds/garply.rss

换句话说,这几乎等同于简单地将存档主机名添加到密封URL前面。

由于密封随时间变化,feed-archiver尽可能保留密封内容的最早期形式。如果密封项在随后的密封检索中发生变化,则保留远程项XML,而不是更新到较新的XML。更具体地说,如果项目具有与已存档项目相同的guid/id,则将在相同密封的后续检索中忽略项目。

将聚合源封装导入媒体库

为满足用例#2,feed-archiver将下载的密封项目链接到一个基于密封项目元数据的替代层次结构,更好地反映大多数密封(如播客,带有媒体密封的节目)的“节目带剧集”性质。每个密封使用的元数据和如何使用这些元数据来组装媒体库路径是可配置的。例如,可以使用此功能仅让您的播客从媒体库软件中访问。在一个更复杂的例子中,它可以将电视剧播客的剧集链接为外部可选音频轨道,与相应的电视剧视频文件并列。可以配置多个链接路径,以便在媒体库的多个位置导入密封项目。

由于聚合源可能有多种对应库媒体的方式,因此这项功能需要高度可配置。为了高度可配置,将其定制到特定目标会变得更加复杂。因此,使用此功能需要使用封装插件,或者具有初级开发人员的技能水平,或者对阅读和解释技术文档感到舒适的人,或者使用其他人已知可工作的示例配置。

安装

本地/原生安装

使用pip等任何安装标准Python 3发行版的工具进行安装pip

$ pip3 install --user feed-archiver

可选的shell选项卡补全通过argcomplete提供。

Docker容器镜像安装

建议通过Docker Compose使用Docker容器镜像。请参阅示例./docker-compose.yml文件以获取示例配置。一旦您有了配置,您就可以创建并运行容器

$ docker compose up

或者,您可以直接使用该镜像。拉取Docker镜像

$ docker pull "registry.gitlab.com/rpatterson/feed-archiver"

然后使用该镜像创建并运行一个容器

$ docker run --rm -it "registry.gitlab.com/rpatterson/feed-archiver" ...

已发布具有Python版本、分支和主要/次要版本变体的图像标签,以便用户可以控制他们在一段时间内获取新图像的时间,例如registry.gitlab.com/rpatterson/feed-archiver:py310-main。标准的Python版本是3.10,这是不带py###的标签中使用的版本,例如registry.gitlab.com/rpatterson/feed-archiver:main。预发布版来自develop,最终版本来自main,也是不带分支的标签的默认版本,例如registry.gitlab.com/rpatterson/feed-archiver:py310。主要/次要版本标签仅应用于最终发布图像,并且没有相应的main分支标签,例如registry.gitlab.com/rpatterson/feed-archiver:py310-v0.8

已发布多平台Docker镜像,包含以下平台或架构的图像,在Python 3.10 py310变体中

  • linux/amd64

  • linux/arm64

  • linux/arm/v7

使用方法

在目录中创建一个./.feed-archiver.yml YAML文件,作为所有要存档的源根目录。该YAML文件必须有一个顶级defaults键,其值是一个定义默认或全局选项的对象。特别是,该部分中的base-url键,其值必须是一个字符串,它定义了客户端从该位置提供存档的外部基本URL,并用于在无法使用相对URL的位置组装绝对URL。该文件还必须有一个顶级feeds键,其值是一个定义在此目录中要存档的远程源的对象数组或列表。每个源对象必须包含一个remote-url键,其值是一个包含要存档的单独源URL的字符串。在最简单的情况下,这可以只是一个文件,如下所示

defaults:
  base-url: "https://feeds.example.com"
feeds:
  - title: "Garply Podcast Title"
    remote-url: "\
    https://foo-username:secret@grault.example.com\
    /feeds/garply.rss?bar=qux%2Fbaz#corge"
...

然后在那个目录中运行$ feed-archiver命令,以从当前版本的源更新存档,并编写一个包含指向存档源链接的HTML索引

$ cd "/var/www/html/feeds/"
$ feed-archiver
INFO:Retrieving feed URL: https://foo-username:secret@grault.example.com/feeds/garply.rss
...
INFO:Writing HTML index: /var/www/html/feeds/index.html

有关选项和参数的详细信息,请参阅命令行帮助

$ feed-archiver --help
usage: feed-archiver [-h] [--log-level {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}]
                     [--archive-dir [ARCHIVE_DIR]]
                     {update,relink} ...

Archive RSS/Atom syndication feeds and their enclosures and assets.

positional arguments:
  {update,relink}       sub-command
    update              Request the URL of each feed in the archive and update contents accordingly.
    relink              Re-link enclosures to the correct locations for the current configuration.

options:
  -h, --help            show this help message and exit
  --log-level {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}
                        Select logging verbosity. (default: INFO)
  --archive-dir [ARCHIVE_DIR], -a [ARCHIVE_DIR]
                        the archive root directory into which all feeds, their enclosures and assets
                        will be downloaded (default: .)

如果使用Docker容器镜像,也可以从命令行运行容器

$ docker compose run "feed-archiver" feed-archiver --help
usage: feed-archiver [-h]

要将投递项的附件链接到备用层次结构,例如媒体库中,请将一个名为“enclosures”的键添加到投递配置中,其值为一个对象列表/数组,每个对象定义一个链接到投递项附件的备用路径。顶级defaults键中定义的所有enclosures都将用于所有投递。跨多个enclosures配置共享的配置可以放在相应的defaults / plugins / enclosures / {plugin_name}对象中。附件的实际链接委托给插件

当使用$ feed-archiver update子命令从远程投递URL更新存档时,新项的附件将按配置进行链接。如果enclosures配置更改或任何使用的插件引用可能更改的外部资源,例如当使用sonarr插件且Sonarr已升级或重命名相应的视频文件时,请使用$ feed-archiver relink命令更新所有现有链接。

插件

如何将投递项附件链接到媒体库是由插件或附加组件负责的。具体来说,enclosures配置中的plugin键必须是一个字符串,它是注册在feedarchiver.enclosures组中的Python入口点的名称。入口点对象引用必须指向一个接受以下参数的feedarchiver.enclosures.EnclosurePlugin子类

  1. parent=dict

    如果插件在defaults中为所有投递配置,则为feedarchiver.archive.Archive;如果为特定投递定义,则为feedarchiver.feed.ArchiveFeed

  2. config=dict

    特定附件配置的序列化存档配置YAML的反序列化Python字典对象。

并且其实例必须是可调用的,并且在调用时必须接受以下参数

  1. archive_feed=feedarchiver.feed.ArchiveFeed

    内部表示存档中单个投递的对象。

  2. feed_elem=xml.etree.ElementTree.Elementitem_elem=xml.etree.ElementTree.Element

    表示整个投递的Python XML元素对象,对于RSS,这是<channel>子元素,而对于Atom,这是根<feed>元素,以及表示特定投递项的类似对象。

  3. feed_parsed=feedparser.util.FeedParserDictitem_parsed=feedparser.util.FeedParserDict

    表示整个投递和特定投递项的feedparser对象。

  4. url_result=lxml.etree._ElementUnicodeResult

    包含特定附件URL的lxml特殊字符串对象。可以用来访问特定的附件元素。

  5. enclosure_path=pathlib.Path

    归档中封套的路径,作为Python pathlib.Path对象,最佳猜测的文件基本名(包括后缀或扩展名),适用于给定的封套。此后缀考虑了封套URL的后缀、对封套URL请求的响应的Content-Type头,以及封套元素XML中任何type属性的值。

  6. match=re.Match

    如果match-patternmatch-string键中展开的Python格式字符串匹配,则为Python正则表达式匹配对象。特别有用的是在match-pattern中指定正则表达式分组,然后在template中使用匹配这些分组的match-string部分的格式。如果match-pattern不匹配,则不会链接封套。如果存在符号组名,例如模式中的(?P<foo_group_name>.*),则在格式字符串中也可以通过名称访问,例如{foo_group_name.lower()}。如果没有提供match-string,则使用默认值,该值将源标题、项目标题和封套基本名(包括扩展名)组合起来

    {utils.quote_sep(feed_parsed.feed.title).strip()}/{utils.quote_sep(item_parsed.title).strip()}{enclosure_path.suffix}

如果插件返回值,则必须是字符串列表,并将用作链接封套的目标路径。相对路径相对于归档根进行解析。这些路径没有转义,因此如果需要转义,则必须是插件配置的一部分。如果没有插件链接给定的封套,则任何具有fallback键为true的插件都将应用。以下是一个示例enclosures定义

defaults:
  base-url: "https://feeds.example.com"
  plugins:
    enclosures:
      sonarr:
        url: "http://localhost:8989"
        api-key: "????????????????????????????????"
  enclosures:
    # Link all feed item enclosures into the media library under the podcasts
    # directory.  Link items into an album directory named by series title if
    # matching.
    - template: "\
      /media/Library/Music/Podcasts\
      /{utils.quote_sep(feed_parsed.feed.title).strip()}\
      /{series_title}\
      /{utils.quote_sep(item_parsed.title).strip()}{enclosure_path.suffix}"
      match-string: "{utils.quote_sep(item_parsed.title).strip()}"
      match-pattern: "\
      (?P<item_title>.+) \\((?P<series_title>.+) \
      (?P<season_number>[0-9])(?P<episode_numbers>[0-9]+[0-9Ee& -]*)\\)"
    # Otherwise link into "self-titled" album directories of the same name as the
    # feed.
    - template: "\
      /media/Library/Music/Podcasts\
      /{utils.quote_sep(feed_parsed.feed.title).strip()}\
      /{utils.quote_sep(feed_parsed.feed.title).strip()}\
      /{utils.quote_sep(item_parsed.title).strip()}{enclosure_path.suffix}"
      fallback: true
feeds:
  - remote-url: "\
    https://foo-username:secret@grault.example.com\
    /feeds/garply.rss?bar=qux%2Fbaz#corge"
    enclosures:
      # This particular feed is a podcast about a TV series/show.  Link enclosures
      # from feed items about an individual episode next to the episode video file as
      # an external audio track using a non-default plugin.
      - plugin: "sonarr"
        match-string: "{utils.quote_sep(item_parsed.title).strip()}"
        match-pattern: "\
        (?P<item_title>.+) \\((?P<series_title>.+) \
        (?P<season_number>[0-9])(?P<episode_numbers>[0-9]+[0-9Ee& -]*)\\)"
        stem-append: "-garply"
...

默认模板插件

如果没有指定plugin键,则使用template插件。链接路径配置可能包含包含Python格式字符串template键,该字符串将被展开以确定馈送项目封套应该链接到何处。默认的template

./Feeds/{utils.quote_sep(feed_parsed.feed.title).strip()}/{utils.quote_sep(item_parsed.title).strip()}{enclosure_path.suffix}

格式字符串可以引用传递给封套插件的任何参数

Sonarr电视剧插件

sonarr插件使用封套配置的值和/或match组来查找由Sonarr管理的电视连续剧/节目,然后查找与馈送项目封套相对应的剧集视频文件,并将封套链接到该视频文件旁边。封套配置或match组必须包含

它们还可以包括

  • stem-append包含一个字符串,在封套后缀/扩展名之前附加到剧集文件基本名上

贡献

注意:[此项目托管在GitLab上]。GitHub上有[镜像],但请使用GitLab来报告问题、提交PR/MR以及任何其他开发或维护活动。

有关如何开始开发的更多详细信息,请参阅./CONTRIBUTING.rst文件

项目详情


下载文件

下载适用于您平台的文件。如果您不确定该选择哪个,请了解更多关于安装包的信息。

源代码分发

feed-archiver-2.0.6.tar.gz (468.8 kB 查看哈希值)

上传时间: 源代码

构建分发

feed_archiver-2.0.6-py3-none-any.whl (49.7 kB 查看哈希值)

上传时间: Python 3

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面