Liking cljdoc? Tell your friends :D

dk.simongray.podcast.app.library

The subscriptions, feeds, queue and play progress of an app, in one map.

The parts of a library are:

{:profile       {…}              ; the profile, a CRDT that syncs
 :feeds         {feed-guid {…}}  ; the feeds, as app.feeds keeps them
 :fetched-lists {url {…}}        ; the followed OPML lists, as fetched
 :index         {…}              ; the search index, with :search?
 :sync          {:cursors {…} …} ; what the next sync starts from
 :sleep         {:episodes 1}    ; the sleep timer of this device, if set
 :files         {id {…}}         ; the downloaded files of this device
 :config        {…}}             ; the options below

The profile is a CRDT, so never change it with assoc or dissoc. Its :device is the id of this device. A feed keeps the episodes that a fetch no longer brings back, as app.feeds says, and the views and listings mark each with its :retained fact. With :max-items, the oldest of them go once a feed has more items, but never one that the profile holds anything for, e.g. progress, a played mark that isn't archived, a star or a place in the queue.

A function that changes the library returns the new library. One that also tells what it did returns a map of the :library and what it tells, e.g. the :effects of step, or the new episodes and the :report of refresh!.

The config holds the options that the functions take, given once, and only data, so that a library is a value that prints and compares:

{:index          {…}            ; the credentials of the Podcast Index
 :languages      ["da" "en"]    ; of the listener, for transcripts
 :search?        true           ; whether to keep the search index
 :cadence        {…}            ; as app.feeds takes it
 :concurrency    8              ; how many feeds are fetched at once
 :max-pages      5              ; of a paged feed, at its first fetch
 :max-items      500            ; the most items of a feed, all by default
 :archive-after  31536000000    ; when played episodes are archived, in ms
 :only-newer?    false          ; older episodes that appear are new too
 :new-episodes   :inbox         ; where every show's new episodes go
 :extension      ".transit"     ; of the documents, as make takes it
 :timeout-seconds 15 :max-bytes … :user-agent …}

Each function also takes the same keys as options, for one call, and :at, an instant to stamp each change with in place of the time of the clock. These options are functions or hold them, so they stay out of the config, which make refuses with any of them, and you give them to each call, e.g. from a map of your own:

{:fetch          f              ; in place of podcast/fetch!
 :send           f              ; in place of client/send!
 :allow-pred     url/public?    ; which URLs a request may go to
 :credentials-of f              ; credentials of a private feed by URL
 :keep-fn        app.feeds/slim ; what to keep of a feed, all by default
 :local-file-fn  f              ; the downloaded file of an episode id
 :cache          store          ; for companion files, see read-files!
 :codec          transit/codec  ; of the documents, EDN by default
 :lenient-parser f              ; for feeds the repairs can't fix
 :now-fn         f}             ; the clock, util.time/now by default

The codec has to be of the :extension that make took, since the documents are named by it, and a call with another throws.

The subscriptions, feeds, queue and play progress of an app, in one map.

The parts of a library are:

    {:profile       {…}              ; the profile, a CRDT that syncs
     :feeds         {feed-guid {…}}  ; the feeds, as app.feeds keeps them
     :fetched-lists {url {…}}        ; the followed OPML lists, as fetched
     :index         {…}              ; the search index, with :search?
     :sync          {:cursors {…} …} ; what the next sync starts from
     :sleep         {:episodes 1}    ; the sleep timer of this device, if set
     :files         {id {…}}         ; the downloaded files of this device
     :config        {…}}             ; the options below

The profile is a CRDT, so never change it with assoc or dissoc. Its
:device is the id of this device. A feed keeps the episodes that a fetch
no longer brings back, as app.feeds says, and the views and listings
mark each with its :retained fact. With :max-items, the oldest of them
go once a feed has more items, but never one that the profile holds
anything for, e.g. progress, a played mark that isn't archived, a star
or a place in the queue.

A function that changes the library returns the new library. One that
also tells what it did returns a map of the :library and what it tells,
e.g. the :effects of step, or the new episodes and the :report of
refresh!.

The config holds the options that the functions take, given once, and
only data, so that a library is a value that prints and compares:

    {:index          {…}            ; the credentials of the Podcast Index
     :languages      ["da" "en"]    ; of the listener, for transcripts
     :search?        true           ; whether to keep the search index
     :cadence        {…}            ; as app.feeds takes it
     :concurrency    8              ; how many feeds are fetched at once
     :max-pages      5              ; of a paged feed, at its first fetch
     :max-items      500            ; the most items of a feed, all by default
     :archive-after  31536000000    ; when played episodes are archived, in ms
     :only-newer?    false          ; older episodes that appear are new too
     :new-episodes   :inbox         ; where every show's new episodes go
     :extension      ".transit"     ; of the documents, as make takes it
     :timeout-seconds 15 :max-bytes … :user-agent …}

Each function also takes the same keys as options, for one call, and
:at, an instant to stamp each change with in place of the time of the
clock. These options are functions or hold them, so they stay out of
the config, which make refuses with any of them, and you give them to
each call, e.g. from a map of your own:

    {:fetch          f              ; in place of podcast/fetch!
     :send           f              ; in place of client/send!
     :allow-pred     url/public?    ; which URLs a request may go to
     :credentials-of f              ; credentials of a private feed by URL
     :keep-fn        app.feeds/slim ; what to keep of a feed, all by default
     :local-file-fn  f              ; the downloaded file of an episode id
     :cache          store          ; for companion files, see read-files!
     :codec          transit/codec  ; of the documents, EDN by default
     :lenient-parser f              ; for feeds the repairs can't fix
     :now-fn         f}             ; the clock, util.time/now by default

The codec has to be of the :extension that make took, since the
documents are named by it, and a call with another throws.
raw docstring

add-episodeclj/s

(add-episode library url fetched item-guid)
(add-episode library url fetched item-guid opts)

The library with the episode item-guid of the feed at url, with what was fetched and the opts, though it isn't subscribed to the feed.

The fetched is the result of dk.simongray.podcast/fetch! or a parsed feed. The profile notes the episode as a remote item, so that every device fetches its feed, and the library lists it among its episodes. It throws when fetched has no feed, with the diagnostic of the fetch as the ex-data, and when the feed has no such episode.

The `library` with the episode `item-guid` of the feed at `url`, with
what was `fetched` and the `opts`, though it isn't subscribed to the
feed.

The `fetched` is the result of dk.simongray.podcast/fetch! or a parsed
feed. The profile notes the episode as a remote item, so that every
device fetches its feed, and the library lists it among its episodes.
It throws when `fetched` has no feed, with the diagnostic of the fetch
as the ex-data, and when the feed has no such episode.
sourceraw docstring

any-meets?clj/s

(any-meets? library ids criteria)
(any-meets? library ids criteria {:keys [feeds] :as opts})

Whether any of the episodes ids of library meets the criteria of criteria/where, with the opts below, e.g. whether one is explicit or of an explicit show:

(any-meets? library ids {:explicit? true})
(any-meets? library ids {:show-explicit? true})

The criteria read the profile of the library, and the time of its clock unless the opts give :at, with their :scale. With :feeds, as recommend takes them, ids can name the episodes of shows that the library doesn't hold whole, e.g. a show found in a search.

Whether any of the episodes `ids` of `library` meets the `criteria` of
criteria/where, with the `opts` below, e.g. whether one is explicit or
of an explicit show:

    (any-meets? library ids {:explicit? true})
    (any-meets? library ids {:show-explicit? true})

The criteria read the profile of the library, and the time of its clock
unless the `opts` give :at, with their :scale. With :feeds, as recommend
takes them, `ids` can name the episodes of shows that the library
doesn't hold whole, e.g. a show found in a search.
sourceraw docstring

backendclj/s

(backend store)
(backend store {:keys [opml?] :as opts})

A backend that syncs the profiles of libraries through store, a document store of dk.simongray.like-minded, with opts.

It's like-minded/backend with profile/sync-options under the opts, which can also have :opml?, true to write subscriptions.opml beside the documents.

A backend that syncs the profiles of libraries through `store`, a
document store of dk.simongray.like-minded, with `opts`.

It's like-minded/backend with profile/sync-options under the `opts`,
which can also have :opml?, true to write subscriptions.opml beside
the documents.
sourceraw docstring

default-configclj/s

The config of a library when none is given. The :list-seconds is how long a fetched OPML list stays current, and the :offline-seconds how long next-refresh waits after a refresh that found the device offline.

The config of a library when none is given. The :list-seconds is how
long a fetched OPML list stays current, and the :offline-seconds how
long next-refresh waits after a refresh that found the device offline.
sourceraw docstring

documentclj/s

(document library)
(document library opts)

This device's sync document in library, with the :app and :at of opts, as a map of the file's :name and :body.

A backend writes the same document to its store. Where an app can't write to the store, e.g. a sync folder in a browser without a folder picker, the listener can save this file into it by hand.

This device's sync document in `library`, with the :app and :at of
`opts`, as a map of the file's :name and :body.

A backend writes the same document to its store. Where an app can't
write to the store, e.g. a sync folder in a browser without a folder
picker, the listener can save this file into it by hand.
sourceraw docstring

document-namesclj/s

(document-names library)

The names of the documents of library, as documents gives them, and of those of the feeds that it holds in their documents alone.

The names of the documents of `library`, as documents gives them, and of
those of the feeds that it holds in their documents alone.
sourceraw docstring

documentsclj/s

(documents library)
(documents library {:keys [except] :or {except #{}} :as opts})

The documents of library as a map of their names to their bodies, in the :codec of opts, but for those that the :except of opts names, e.g. those that a store holds already.

They're the library's own document, which holds the parts that saved-keys names and the manifest of the search index, the document of each feed that it holds in memory, and the segments of the index. The library's own document is always among them, since every change of the library changes it. A feed's document and a segment are named by what they hold, so a store that holds one never needs it again.

The documents of `library` as a map of their names to their bodies, in
the :codec of `opts`, but for those that the :except of `opts` names,
e.g. those that a store holds already.

They're the library's own document, which holds the parts that
saved-keys names and the manifest of the search index, the document of
each feed that it holds in memory, and the segments of the index. The
library's own document is always among them, since every change of the
library changes it. A feed's document and a segment are named by what
they hold, so a store that holds one never needs it again.
sourceraw docstring

dueclj/s

(due library)
(due library opts)

What a refresh of library with the opts of refresh! fetches, as data for fetch-due! in another context, e.g. a web worker.

It's a map of the :at of the refresh, the :feed-guids to fetch, the earliest due first, the entries of their :feeds, and the entries of the followed :lists that are due, each by URL. The entries hold neither the feeds nor the lists, but name the document of each feed in the store. The lists of a list that the refresh follows are fetched by the next, and a feed that the library holds in its document alone isn't due until load! reads it.

What a refresh of `library` with the `opts` of refresh! fetches, as data
for fetch-due! in another context, e.g. a web worker.

It's a map of the :at of the refresh, the :feed-guids to fetch, the
earliest due first, the entries of their :feeds, and the entries of the
followed :lists that are due, each by URL. The entries hold neither the
feeds nor the lists, but name the document of each feed in the store.
The lists of a list that the refresh follows are fetched by the next,
and a feed that the library holds in its document alone isn't due until
load! reads it.
sourceraw docstring

durable-swap!clj/s

(durable-swap! store known f)
(durable-swap! store {:keys [library version] :as known} f opts)

Write f of the library that known holds to store with the opts of write!, on condition of the version that known holds, and f of the stored library again whenever another context wrote first, as swap! does with an atom. It gives the library and the version written, as a map of the :library and the :version, or a map of the :error of a write or a read that failed, in ClojureScript as a promise.

The known is a map of the :library and its :version, as read! gives it and this gives it back. Since f can run more than once, give it the time of its change, e.g. as the :at of step, so that it stamps the same time each time.

Write `f` of the library that `known` holds to `store` with the `opts`
of write!, on condition of the version that `known` holds, and `f` of
the stored library again whenever another context wrote first, as swap!
does with an atom. It gives the library and the version written, as a
map of the :library and the :version, or a map of the :error of a write
or a read that failed, in ClojureScript as a promise.

The `known` is a map of the :library and its :version, as read! gives
it and this gives it back. Since `f` can run more than once, give it
the time of its change, e.g. as the :at of step, so that it stamps the
same time each time.
sourceraw docstring

episodeclj/s

(episode library id)
(episode library id opts)

The view of the episode id, [feed-guid item-guid], of library, with the opts of app.episode/view over the config, e.g. its :languages, or nil when the library has no such episode, or doesn't hold its feed in memory, as loaded? tells. Unless the opts say, the :video? of the view is whether the listener watches the show. The view has the :retained fact of an episode that the feed no longer brings back.

The view of the episode `id`, [feed-guid item-guid], of `library`, with
the `opts` of app.episode/view over the config, e.g. its :languages, or
nil when the library has no such episode, or doesn't hold its feed in
memory, as loaded? tells. Unless the `opts` say, the
:video? of the view is whether the listener watches the show. The view
has the :retained fact of an episode that the feed no longer brings
back.
sourceraw docstring

episode-idclj/s

(episode-id library feed item)

The id of the episode item of feed in library, [feed-guid item-guid].

The id of the episode `item` of `feed` in `library`, [feed-guid
item-guid].
sourceraw docstring

episodesclj/s

(episodes library)
(episodes library {:keys [feed-guids] :as opts})

The episodes of the shows of library that the criteria opts select, as [feed item] pairs, e.g.

(episodes library {:where {:status :unplayed} :order :listening})

The criteria are those of criteria/episodes. They read the profile and the downloaded files of the library, and the time of its clock unless the opts give :at. The hidden episodes are left out unless the criteria name :hidden?. With :feed-guids, only the episodes of those shows are read, e.g. for the page of a show.

The episodes of the shows of `library` that the criteria `opts` select,
as [feed item] pairs, e.g.

    (episodes library {:where {:status :unplayed} :order :listening})

The criteria are those of criteria/episodes. They read the profile and
the downloaded files of the library, and the time of its clock unless
the `opts` give :at. The hidden episodes are left out unless the
criteria name :hidden?. With :feed-guids, only the episodes of those
shows are read, e.g. for the page of a show.
sourceraw docstring

episodes-from-opmlclj/s

(episodes-from-opml library list)
(episodes-from-opml library list opts)

The library with the progress, the played marks and the deleted episodes of the OPML subscription list, as Overcast's extended export writes them, at the :at of opts, as profile.opml/episodes-from-opml applies them.

An episode is found by the URL of its media among the feeds that the library has, so subscribe to the list and refresh first. Its feed is found by the URL in the list.

The `library` with the progress, the played marks and the deleted
episodes of the OPML subscription `list`, as Overcast's extended export
writes them, at the :at of `opts`, as profile.opml/episodes-from-opml
applies them.

An episode is found by the URL of its media among the feeds that the
library has, so subscribe to the list and refresh first. Its feed is
found by the URL in the list.
sourceraw docstring

fail-downloadclj/s

(fail-download library id details)
(fail-download library id details opts)

The library with the download of the episode id failed at the time of the call, with opts, and the details of downloads/fail-download: the bytes on the device and the headers that came with them, and the error.

The `library` with the download of the episode `id` failed at the time
of the call, with `opts`, and the `details` of downloads/fail-download:
the bytes on the device and the headers that came with them, and the
error.
sourceraw docstring

fetch-due!clj/s

(fetch-due! due store)
(fetch-due! {:keys [at feed-guids feeds lists] :as due} store opts)

Fetch what a refresh is due to fetch, as due gives it, with the documents of its feeds in store and the opts of refresh! and the config, and put the documents of the feeds that changed into store. It gives what the refresh found, for refreshed, in ClojureScript as a promise:

{:at        #inst "…"
 :from      {feed-guid {:document "…" :fetched-at #inst "…"}}
 :feeds     {feed-guid {…}}       ; the entries of the feeds fetched
 :documents {"feed-….edn" "…"}  ; of the feeds that changed
 :changed   [feed-guid …] :moved {feed-guid "https://…"}
 :lists     [[url fetched] …]
 :counts    {…} :seconds 4.2 :report [...]}

The entries name their documents rather than hold their feeds, as those of due do, and a feed that failed keeps its failures. The documents hold each feed as it was fetched, before the cuts of the library's :keep-fn, :max-items and remote items, which refreshed makes.

Fetch what a refresh is `due` to fetch, as due gives it, with the
documents of its feeds in `store` and the `opts` of refresh! and the
config, and put the documents of the feeds that changed into `store`.
It gives what the refresh found, for refreshed, in ClojureScript as a
promise:

    {:at        #inst "…"
     :from      {feed-guid {:document "…" :fetched-at #inst "…"}}
     :feeds     {feed-guid {…}}       ; the entries of the feeds fetched
     :documents {"feed-….edn" "…"}  ; of the feeds that changed
     :changed   [feed-guid …] :moved {feed-guid "https://…"}
     :lists     [[url fetched] …]
     :counts    {…} :seconds 4.2 :report [...]}

The entries name their documents rather than hold their feeds, as those
of due do, and a feed that failed keeps its failures. The documents hold
each feed as it was fetched, before the cuts of the library's
:keep-fn, :max-items and remote items, which refreshed makes.
sourceraw docstring

fetch-linked-shows!clj/s

(fetch-linked-shows! library feed-guid)
(fetch-linked-shows! library feed-guid opts)

Fetch the shows that the show feed-guid of library links to, with the opts of app.show/fetch-linked-shows! over the config. It gives a map of the :podroll and the :publisher, in ClojureScript as a promise, or nil when the library has no such feed.

Fetch the shows that the show `feed-guid` of `library` links to, with
the `opts` of app.show/fetch-linked-shows! over the config. It gives a
map of the :podroll and the :publisher, in ClojureScript as a promise,
or nil when the library has no such feed.
sourceraw docstring

fetch-remote-values!clj/s

(fetch-remote-values! library id)
(fetch-remote-values! library id opts)

Fetch the value blocks that the time splits of the episode id of library point at, with the opts of app.episode/fetch-remote-values! over the config. It gives a map of the :remote-values and the :remote-report, in ClojureScript as a promise, or nil when the library has no such episode.

Fetch the value blocks that the time splits of the episode `id` of
`library` point at, with the `opts` of app.episode/fetch-remote-values!
over the config. It gives a map of the :remote-values and the
:remote-report, in ClojureScript as a promise, or nil when the library
has no such episode.
sourceraw docstring

finish-downloadclj/s

(finish-download library id details)
(finish-download library id details opts)

The library with the download of the episode id finished at the time of the call, with opts, and the :path and :bytes of the file in details, as downloads/finish-download records it.

The `library` with the download of the episode `id` finished at the
time of the call, with `opts`, and the :path and :bytes of the file in
`details`, as downloads/finish-download records it.
sourceraw docstring

follow-listclj/s

(follow-list library url list)
(follow-list library url list opts)

The library following the OPML list at url, whose parse is list, with the opts below.

The opts give the :etag and :last-modified of the fetch, the :title of the list and the :folder for its shows. The shows of the list become subscriptions.

The `library` following the OPML list at `url`, whose parse is `list`,
with the `opts` below.

The `opts` give the :etag and :last-modified of the fetch, the :title of
the list and the :folder for its shows. The shows of the list become
subscriptions.
sourceraw docstring

from-documentsclj/s

(from-documents library docs)
(from-documents library docs opts)

The library with what the documents docs hold, a map of their names to their bodies, e.g. those that read! fetches, and the report of what didn't read, as a map of the :library and the :report. The library has the parts of its own document that saved-keys names, each feed from its document, and the search index.

It reads the documents in the :codec of opts, e.g. that of dk.simongray.like-minded.transit, of any version that restore! reads, among them those that save! wrote. A feed that library holds in memory with the same document stays as it is, and so does the index when its manifest is the same, so give it the library as it is to read only what changed. The report is as restore! has it, and a document that docs lack doesn't read. Without the library's own document, it's library as it is.

The `library` with what the documents `docs` hold, a map of their names
to their bodies, e.g. those that read! fetches, and the report of what
didn't read, as a map of the :library and the :report. The library has
the parts of its own document that saved-keys names, each feed from its
document, and the search index.

It reads the documents in the :codec of `opts`, e.g. that of
dk.simongray.like-minded.transit, of any version that restore! reads,
among them those that save! wrote. A feed that `library` holds in memory
with the same document stays as it is, and so does the index when its
manifest is the same, so give it the library as it is to read only what
changed. The report is as restore! has it, and a document that `docs`
lack doesn't read. Without the library's own document, it's `library`
as it is.
sourceraw docstring

hub-requestsclj/s

(hub-requests library subscriptions callback-fn)
(hub-requests library subscriptions callback-fn opts)

The requests to send the WebSub hubs of the feeds in library, by feed guid, given the subscriptions that websub-clj keeps by feed guid, with callback URLs from callback-fn and opts:

  • a subscription at the first hub of each show's feed, when the show has no subscription, or one that ended or is at another hub or topic
  • an unsubscription for each show that the listener left, or whose feed names no hub or is gone
  • the renewals and retries that websub/due returns

The callback-fn takes a feed guid and its subscription, which is nil for a new one, and returns a new callback URL, as in websub/due. A new subscription gets a secret from websub/token. Give each request to websub/asked before websub/call! sends it. The opts are those of websub/due, :at, and :allow-pred, which url/public? is by default, since the feeds choose the hubs.

The requests to send the WebSub hubs of the feeds in `library`, by feed
guid, given the `subscriptions` that websub-clj keeps by feed guid, with
callback URLs from `callback-fn` and `opts`:

- a subscription at the first hub of each show's feed, when the show has
  no subscription, or one that ended or is at another hub or topic
- an unsubscription for each show that the listener left, or whose feed
  names no hub or is gone
- the renewals and retries that websub/due returns

The `callback-fn` takes a feed guid and its subscription, which is nil
for a new one, and returns a new callback URL, as in websub/due. A new
subscription gets a secret from websub/token. Give each request to
websub/asked before websub/call! sends it. The `opts` are those of
websub/due, :at, and :allow-pred, which url/public? is by default, since
the feeds choose the hubs.
sourceraw docstring

identify!clj/s

(identify! library)
(identify! library opts)

Ask the directories for the ids of the shows of library that have none yet, with opts, as directory/identify! does, and keep them in the entries of their feeds. The views of a show and its episodes then link to it in the apps that know it by those ids. It gives a map of the new :library, the :at of the call and the :report of the directories that failed, in ClojureScript as a promise.

The Podcast Index is asked with the credentials of the :index of the config. The shows are asked about two at a time, since Apple limits how often it answers, and a show whose directory failed is asked again next time. A show of local files is never asked about, since no directory lists it. The opts are the config for this call, and :feed-guids, the shows to ask about, ids or not.

Ask the directories for the ids of the shows of `library` that have
none yet, with `opts`, as directory/identify! does, and keep them in
the entries of their feeds. The views of a show and its episodes then
link to it in the apps that know it by those ids. It gives a map of the
new :library, the :at of the call and the :report of the directories
that failed, in ClojureScript as a promise.

The Podcast Index is asked with the credentials of the :index of the
config. The shows are asked about two at a time, since Apple limits how
often it answers, and a show whose directory failed is asked again
next time. A show of local files is never asked about, since no
directory lists it. The `opts` are the config for this call, and
:feed-guids, the shows to ask about, ids or not.
sourceraw docstring

inboxclj/s

(inbox library)
(inbox library opts)

The inbox of library, the newest episode first, for a page of it, with the opts of episode: a map of its :episodes, each as queue gives them.

They're in the order of their dates, rather than of their arrival, so that an episode put back with undismiss takes its place again. An episode whose feed the library doesn't hold in memory is left out, as loaded? tells.

The inbox of `library`, the newest episode first, for a page of it, with
the `opts` of episode: a map of its :episodes, each as queue gives them.

They're in the order of their dates, rather than of their arrival, so
that an episode put back with undismiss takes its place again. An
episode whose feed the library doesn't hold in memory is left out, as
loaded? tells.
sourceraw docstring

keep-fileclj/s

(keep-file library id keep?)

The library with the file of the episode id kept whatever the rules say, or no longer kept when keep? is false.

The `library` with the file of the episode `id` kept whatever the rules
say, or no longer kept when `keep?` is false.
sourceraw docstring

leave!clj/s

(leave! library backends)
(leave! library backends opts)

Retire this device of library from the listener's sync through backends, with the opts of like-minded/leave! except :cursors and :failures, e.g. when the listener turns sync off.

It writes the retirement through each backend once more, so that the other devices stop waiting for this one before they compact. It returns the library with the retired profile and the :report, as sync! does, in ClojureScript as a promise. A retired device can't sync again, so to sync later, give the library a new device with with-device.

Retire this device of `library` from the listener's sync through
`backends`, with the `opts` of like-minded/leave! except :cursors and
:failures, e.g. when the listener turns sync off.

It writes the retirement through each backend once more, so that the
other devices stop waiting for this one before they compact. It returns
the library with the retired profile and the :report, as sync! does, in
ClojureScript as a promise. A retired device can't sync again, so to
sync later, give the library a new device with with-device.
sourceraw docstring

listedclj/s

(listed library id)
(listed library [feed-guid :as id] opts)

The row of the episode id of library in a list of episodes, e.g. of the results of recommend, as queue describes it, with the opts of episode, or nil when the library doesn't hold its feed in memory.

The row of the episode `id` of `library` in a list of episodes, e.g. of
the results of recommend, as queue describes it, with the `opts` of
episode, or nil when the library doesn't hold its feed in memory.
sourceraw docstring

live-itemsclj/s

(live-items library)
(live-items library opts)

The live items of the subscriptions of library, as [feed item] pairs, at the :at of opts or the time of its clock: those on air first, then those to come, the soonest first, then those over, the latest first.

A live item plays by its id, [feed-guid item-guid], as an episode does, e.g. with playback.

The live items of the subscriptions of `library`, as [feed item] pairs,
at the :at of `opts` or the time of its clock: those on air first, then
those to come, the soonest first, then those over, the latest first.

A live item plays by its id, [feed-guid item-guid], as an episode does,
e.g. with playback.
sourceraw docstring

load!clj/s

(load! library store feed-guids)
(load! library store feed-guids opts)

The library with the feeds feed-guids read back from their documents in store with the :codec of opts, those that it doesn't hold in memory, and the report of what didn't read, as a map of the :library and the :report, in ClojureScript as a promise. With :all for feed-guids, it's every feed.

A feed whose document is missing or doesn't read keeps only its URL, so that the next refresh fetches it again, with :library/unreadable-document in the report.

The `library` with the feeds `feed-guids` read back from their
documents in `store` with the :codec of `opts`, those that it doesn't
hold in memory, and the report of what didn't read, as a map of the
:library and the :report, in ClojureScript as a promise. With :all for
`feed-guids`, it's every feed.

A feed whose document is missing or doesn't read keeps only its URL, so
that the next refresh fetches it again, with
:library/unreadable-document in the report.
sourceraw docstring

loaded?clj/s

(loaded? library feed-guid)

Whether library holds the feed feed-guid in memory, rather than only in the document that a save wrote, as after restore! with :load or after unload!.

Whether `library` holds the feed `feed-guid` in memory, rather than only
in the document that a save wrote, as after restore! with :load or after
unload!.
sourceraw docstring

makeclj/s

(make device)
(make device {:keys [config codec] :as opts})

A library for the device device, made with the opts below.

The device is a stable id that tells the listener's devices apart, made once per installation. The opts describe the device for the other devices, such as its :name and :platform, and give the :config and the :codec of the documents, whose :extension the config keeps, EDN's by default. It throws for a config that holds one of the options that are functions, e.g. :send, since each call takes those instead.

A library for the device `device`, made with the `opts` below.

The `device` is a stable id that tells the listener's devices apart,
made once per installation. The `opts` describe the device for the other
devices, such as its :name and :platform, and give the :config and the
:codec of the documents, whose :extension the config keeps, EDN's by
default. It throws for a config that holds one of the options that are
functions, e.g. :send, since each call takes those instead.
sourceraw docstring

mark-show-playedclj/s

(mark-show-played library feed-guid)
(mark-show-played library feed-guid opts)

The library with every episode of the show feed-guid marked as played with one stamp, with opts, e.g. for a show that the listener heard elsewhere. The time is that of the clock unless the opts give :at.

The `library` with every episode of the show `feed-guid` marked as
played with one stamp, with `opts`, e.g. for a show that the listener
heard elsewhere. The time is that of the clock unless the `opts` give
:at.
sourceraw docstring

mergeclj/s

(merge library result)

The library with result merged in, a library that came from an earlier value of library, e.g. the :library of what a refresh or a sync gave.

The profiles merge, so nothing that the listener did meanwhile is lost. A feed or a list stays only while the merged profile subscribes to it, has a remote item of it, or follows it, so one that the listener left on another device goes. Of two entries of one feed or list, the later fetch wins. The :sync of the later sync is kept too, and the rest is that of library.

The `library` with `result` merged in, a library that came from an
earlier value of `library`, e.g. the :library of what a refresh or a
sync gave.

The profiles merge, so nothing that the listener did meanwhile is lost.
A feed or a list stays only while the merged profile subscribes to it,
has a remote item of it, or follows it, so one that the listener left
on another device goes. Of two entries of one feed or list, the later
fetch wins. The :sync of the later sync is kept too, and the rest is
that of `library`.
sourceraw docstring

next-refreshclj/s

(next-refresh library)
(next-refresh library opts)

When library should refresh again, with opts: when the first of its feeds and followed lists is due, or nil when it has none to fetch. The result is never before the time of the call.

The feed of a subscription that was never fetched is due at once, unless its fetch failed. Then it waits as its entry says, e.g. the first wait of the :after-failure of the cadence after one failure, as a feed that was fetched does. A feed that's gone, of local files or held for remote items alone is never due. After a refresh that found the device offline, the next waits the :offline-seconds of the config, when the :after of opts is what that refresh gave.

When `library` should refresh again, with `opts`: when the first of its
feeds and followed lists is due, or nil when it has none to fetch. The
result is never before the time of the call.

The feed of a subscription that was never fetched is due at once, unless
its fetch failed. Then it waits as its entry says, e.g. the first wait
of the :after-failure of the cadence after one failure, as a feed that
was fetched does. A feed that's gone, of local files or held for remote
items alone is never due. After a refresh that found the device
offline, the next waits the :offline-seconds of the config, when the
:after of `opts` is what that refresh gave.
sourceraw docstring

next-syncclj/s

(next-sync library)
(next-sync library opts)

When library should sync again, with opts: right away before the first sync, and sooner when the profile changed since the last one.

When `library` should sync again, with `opts`: right away before the
first sync, and sooner when the profile changed since the last one.
sourceraw docstring

notificationsclj/s

(notifications {:keys [library added] :as refreshed})

The new episodes that a refresh found in the shows that announce theirs, by show, the show with the newest episode first, of what the refresh gave, refreshed, a map of the :library and the :added, as refresh! gives it:

[{:feed-guid "…" :title "The Daily" :artwork "https://…"
  :episodes  [{:id [feed-guid item-guid] :title "…"
               :published #inst "…"}]}]

A show announces its new episodes when its :notify? setting says so, or else the listener's preference, as profile/notifies? says. An episode that the listener played already is left out.

The new episodes that a refresh found in the shows that announce theirs,
by show, the show with the newest episode first, of what the refresh
gave, `refreshed`, a map of the :library and the :added, as refresh!
gives it:

    [{:feed-guid "…" :title "The Daily" :artwork "https://…"
      :episodes  [{:id [feed-guid item-guid] :title "…"
                   :published #inst "…"}]}]

A show announces its new episodes when its :notify? setting says so,
or else the listener's preference, as profile/notifies? says. An
episode that the listener played already is left out.
sourceraw docstring

opml-nameclj/s

The name of the subscription list that a backend with :opml? writes beside the documents, for any podcast app to import.

The name of the subscription list that a backend with :opml? writes
beside the documents, for any podcast app to import.
sourceraw docstring

planclj/s

(plan library)
(plan library files)
(plan library files opts)

The episodes to download and the files to delete on this device with files, for the profile and feeds of library, with the opts of downloads/plan. Without files, it's the record of the files in the library.

It plans with the feeds that the library holds in memory. The files of the episodes of a feed that it doesn't hold are kept, so load! every feed first for a plan of them all. A show of local files has nothing to download.

The episodes to download and the files to delete on this device with
`files`, for the profile and feeds of `library`, with the `opts` of
downloads/plan. Without `files`, it's the record of the files in the
library.

It plans with the feeds that the library holds in memory. The files of
the episodes of a feed that it doesn't hold are kept, so load! every
feed first for a plan of them all. A show of local files has nothing to
download.
sourceraw docstring

playbackclj/s

(playback library id)
(playback library id {:keys [read] :as opts})

What a player needs for the episode id of library, with the opts of episode over the config, or nil when the library has no such episode:

{:id         [feed-guid item-guid]
 :src        "https://…/7.mp3"   ; the file to play
 :local?     false                ; whether the file is on the device
 :enclosure  {:url "…" :type "audio/mpeg" …}
 :position   754.0                ; where to start, in seconds
 :duration   3612.0               ; when it's known
 :playback-rate 1.5               ; the rate of the show
 :played?    false
 :title      "…" :show "…" :artwork "https://…"
 :poster     "https://…"         ; of a video, before it plays
 :chapters   {:source :embedded :document {…}}  ; in the feed itself
 :chapters-url "https://…"                    ; a file of chapters
 :transcript {:url "…" :type "text/vtt" …}   ; e.g. for captions
 :metadata   {…}}                 ; for the Media Session

The file to play is the downloaded one, which the :local-file-fn of the options gives for the id, e.g. an object URL, or else the record of the files in the library, and otherwise the enclosure, which is on the device for a show of local files. With :read, what read-files! gave for the episode, its chapters and measured duration go over those of the feed. The keys without a value are left out, and app.episode/metadata gives the metadata.

The :src, :position and :playback-rate are the keys that media/source! of the play-nice library loads, so it takes the map as it is.

What a player needs for the episode `id` of `library`, with the `opts`
of episode over the config, or nil when the library has no such
episode:

    {:id         [feed-guid item-guid]
     :src        "https://…/7.mp3"   ; the file to play
     :local?     false                ; whether the file is on the device
     :enclosure  {:url "…" :type "audio/mpeg" …}
     :position   754.0                ; where to start, in seconds
     :duration   3612.0               ; when it's known
     :playback-rate 1.5               ; the rate of the show
     :played?    false
     :title      "…" :show "…" :artwork "https://…"
     :poster     "https://…"         ; of a video, before it plays
     :chapters   {:source :embedded :document {…}}  ; in the feed itself
     :chapters-url "https://…"                    ; a file of chapters
     :transcript {:url "…" :type "text/vtt" …}   ; e.g. for captions
     :metadata   {…}}                 ; for the Media Session

The file to play is the downloaded one, which the :local-file-fn of the
options gives for the id, e.g. an object URL, or else the record of the
files in the library, and otherwise the enclosure, which is on the
device for a show of local files. With :read, what read-files! gave for
the episode, its chapters and measured duration go over those of the
feed. The keys without a value are left out, and app.episode/metadata
gives the metadata.

The :src, :position and :playback-rate are the keys that media/source!
of the play-nice library loads, so it takes the map as it is.
sourceraw docstring

pushedclj/s

(pushed library feed-guid delivery)
(pushed library feed-guid {:keys [body content-type] :as delivery} opts)

The library after a WebSub hub pushed the feed feed-guid in delivery, the map that :deliver! of websub/handler receives, with opts, and what the push brought, as refresh! gives them.

The body is parsed as fetch! parses a feed. The new episodes join the queue or the inbox as after a refresh. Since a hub can push only what changed, a push removes no episode (see app.feeds/pushed). When a push can't be applied, the feed is due at once, so the next refresh fetches it, and the report says why. A push of a feed that the library doesn't have changes nothing.

The `library` after a WebSub hub pushed the feed `feed-guid` in
`delivery`, the map that :deliver! of websub/handler receives, with
`opts`, and what the push brought, as refresh! gives them.

The body is parsed as fetch! parses a feed. The new episodes join the
queue or the inbox as after a refresh. Since a hub can push only what
changed, a push removes no episode (see app.feeds/pushed). When a push
can't be applied, the feed is due at once, so the next refresh fetches
it, and the report says why. A push of a feed that the library doesn't
have changes nothing.
sourceraw docstring

queueclj/s

(queue library)
(queue library opts)

The queue of library, the current episode first, for a page of it, with the opts of episode: a map of its :episodes and the seconds :remaining of all of them that it knows the duration of, e.g.

{:episodes  [{:id        [feed-guid item-guid]
              :title     "…" :show "…" :artwork "https://…"
              :published #inst "…"  ; when it gave a date
              :duration  3600       ; when it's known
              :position  754        ; where the listener left it
              :remaining 2846}      ; when the duration is known
             …]
 :remaining 10800}

An episode whose feed the library doesn't hold in memory is left out, as loaded? tells.

The queue of `library`, the current episode first, for a page of it, with
the `opts` of episode: a map of its :episodes and the seconds :remaining
of all of them that it knows the duration of, e.g.

    {:episodes  [{:id        [feed-guid item-guid]
                  :title     "…" :show "…" :artwork "https://…"
                  :published #inst "…"  ; when it gave a date
                  :duration  3600       ; when it's known
                  :position  754        ; where the listener left it
                  :remaining 2846}      ; when the duration is known
                 …]
     :remaining 10800}

An episode whose feed the library doesn't hold in memory is left out,
as loaded? tells.
sourceraw docstring

read!clj/s

(read! library store)
(read! library store opts)

The library in store, read onto library with from-documents and the opts, the version of its own document and the report of what didn't read, as a map of the :library, the :version and the :report, in ClojureScript as a promise.

It fetches the library's own document, in the :codec of opts, and then the documents that it names and library doesn't hold, so give it the library as it is to read only what changed. It takes no lock, so it starts over when a document is missing because another context wrote the store meanwhile. A store without the library's document gives library as it is, with no version. When the store fails to give the library's own document, it fails too, so that nothing writes over what it holds.

The library in `store`, read onto `library` with from-documents and the
`opts`, the version of its own document and the report of what didn't
read, as a map of the :library, the :version and the :report, in
ClojureScript as a promise.

It fetches the library's own document, in the :codec of `opts`, and then
the documents that it names and `library` doesn't hold, so give it the
library as it is to read only what changed. It takes no lock, so it
starts over when a document is missing because another context wrote the
store meanwhile. A store without the library's document gives `library`
as it is, with no version. When the store fails to give the library's
own document, it fails too, so that nothing writes over what it holds.
sourceraw docstring

read-files!clj/s

(read-files! library id)
(read-files! library id opts)

Read the files of the episode id of library, with the opts of app.episode/read-files! over the config. It gives a map of the :chapters, the :transcript and the :media, in ClojureScript as a promise, or nil when the library has no such episode. The media file is the one that the episode's view chooses.

Read the files of the episode `id` of `library`, with the `opts` of
app.episode/read-files! over the config. It gives a map of the
:chapters, the :transcript and the :media, in ClojureScript as a
promise, or nil when the library has no such episode. The media file is
the one that the episode's view chooses.
sourceraw docstring

recommendclj/s

(recommend library)
(recommend library ids)
(recommend library
           ids
           {:keys [same-show? max-per-show recent from feeds unlike weight-fn]
            :or {max-per-show 2 recent 10}
            :as opts})

The episodes of library most like the episodes ids, or like those that the listener heard last, best first, with the opts below, or nil when the library keeps no index.

Each result has its :feed and :item, as in search, and the :terms of the query that it holds, the best first, e.g. to tell the listener why it came up. The metadata of the results has the :terms of the query, as more-like-this of dk.simongray.drop-in-search gives them, pairs of a term and its weight. The opts are those of more-like-this, and these:

  • :limit, the most episodes, 10 by default
  • :where, the criteria of criteria/where that an episode meets, {:status :unplayed} by default, and the hidden ones are left out unless the criteria name :hidden?
  • :same-show?, true to take episodes of the shows of ids too
  • :same-language?, false to take the episodes of shows in any language, rather than of the shows whose feeds declare a language of the episodes of ids, when they declare one
  • :max-per-show, the most episodes of one show, 2 by default, or nil
  • :recent, the number of the episodes that the listener heard last to start from without ids, 10 by default, where the last weighs the most
  • :from, the criteria of criteria/where that the episodes to start from meet, whether ids names them or the listener heard them last, e.g. {:not {:explicit? true}}
  • :feeds, the shows that the library doesn't hold whole, whose episodes ids and :unlike can name, e.g. a show found in a search, as a map of the feed guid of each to a map of its parsed :feed and its :url
  • :unlike, ids of episodes whose words count against those of ids, e.g. the ones that the listener rated low
  • :weight-fn, a function of an id of ids or :unlike that gives how much it weighs, 1 by default

The words are those of the titles, notes, keywords and chapters, but not the shows' names and people, which every episode of a show shares, and they have two letters or more. By default:

  • a word is one that the episodes of ids use twice, or once in a title, which counts three times, or in keywords or chapters, which count twice, as :min-term-freq has it
  • a result holds two of the words at least, as :min-match has it
  • a word in more than 8% of the episodes in the languages of the episodes of ids, or of all episodes when they name none, is left out, e.g. ad text and function words, as :max-doc-freq has it, and so is one that more than 40% of the shows use, as the :group-fn of more-like-this is the show

Left out too are the words that link the episodes of ids to others by chance: their numbers, e.g. the 561 of "#561: TonIO" or a date, and the names of their shows' hosts and authors, e.g. the "Adam & Dave" of every episode's notes. The criteria read the profile of the library, and the time of its clock unless the opts give :at.

(recommend library [id] {:limit 5})
(recommend library nil {:where {:status   :unplayed
                                :duration [nil 1800]}})
The episodes of `library` most like the episodes `ids`, or like those
that the listener heard last, best first, with the `opts` below, or nil
when the library keeps no index.

Each result has its :feed and :item, as in search, and the :terms of the
query that it holds, the best first, e.g. to tell the listener why it
came up. The metadata of the results has the :terms of the query, as
more-like-this of dk.simongray.drop-in-search gives them, pairs of a
term and its weight. The `opts` are those of more-like-this, and these:

- :limit, the most episodes, 10 by default
- :where, the criteria of criteria/where that an episode meets,
  {:status :unplayed} by default, and the hidden ones are left out
  unless the criteria name :hidden?
- :same-show?, true to take episodes of the shows of `ids` too
- :same-language?, false to take the episodes of shows in any language,
  rather than of the shows whose feeds declare a language of the
  episodes of `ids`, when they declare one
- :max-per-show, the most episodes of one show, 2 by default, or nil
- :recent, the number of the episodes that the listener heard last to
  start from without `ids`, 10 by default, where the last weighs the
  most
- :from, the criteria of criteria/where that the episodes to start
  from meet, whether `ids` names them or the listener heard them last,
  e.g. {:not {:explicit? true}}
- :feeds, the shows that the library doesn't hold whole, whose episodes
  `ids` and :unlike can name, e.g. a show found in a search, as a map of
  the feed guid of each to a map of its parsed :feed and its :url
- :unlike, ids of episodes whose words count against those of `ids`,
  e.g. the ones that the listener rated low
- :weight-fn, a function of an id of `ids` or :unlike that gives how
  much it weighs, 1 by default

The words are those of the titles, notes, keywords and chapters, but
not the shows' names and people, which every episode of a show shares,
and they have two letters or more. By default:

- a word is one that the episodes of `ids` use twice, or once in a
  title, which counts three times, or in keywords or chapters, which
  count twice, as :min-term-freq has it
- a result holds two of the words at least, as :min-match has it
- a word in more than 8% of the episodes in the languages of the
  episodes of `ids`, or of all episodes when they name none, is left
  out, e.g. ad text and function words, as :max-doc-freq has it, and so
  is one that more than 40% of the shows use, as the :group-fn of
  more-like-this is the show

Left out too are the words that link the episodes of `ids` to others by
chance: their numbers, e.g. the 561 of "#561: TonIO" or a date, and the
names of their shows' hosts and authors, e.g. the "Adam & Dave" of
every episode's notes. The criteria read the profile of the library, and
the time of its clock unless the `opts` give :at.

    (recommend library [id] {:limit 5})
    (recommend library nil {:where {:status   :unplayed
                                    :duration [nil 1800]}})
sourceraw docstring

refresh!clj/s

(refresh! library)
(refresh! library opts)

Fetch and apply whatever library is due to fetch, with the opts below.

It fetches the followed lists, the feeds of new subscriptions and remote items, and the feeds of subscriptions whose next check has come. A feed held for remote items alone isn't fetched again, unless :feed-guids names it. It returns the new library and what the refresh found, in ClojureScript as a promise:

{:library    {…}
 :at         #inst "…"
 :added      [[feed-guid item-guid] …]  ; the new episodes
 :backfilled [[feed-guid item-guid] …]  ; older ones that appeared
 :renamed    [[old-id new-id] …]        ; episodes under a new guid,
                                        ; which took their state along
 :moved      {feed-guid "https://…"}   ; the feeds that moved, and so
                                        ; their subscriptions
 :counts     {:checked 120 :unchanged 104 :changed 14 :failed 2
              :left 0}
 :seconds    4.2                        ; how long it took
 :report     [...]}                     ; the fetches that failed, and why

Only the new episodes join the queue or the inbox. Nothing is thrown for what the network or a server does. The opts are the config for this call, and these:

  • :feed-guids, the feeds to fetch instead of those that are due, e.g. those that a Podping names
  • :online?, false when the device has no network, so that nothing is fetched
  • :max-feeds, :max-seconds, :on-feed-fn and :signal, to fetch fewer feeds or within a deadline, to hear of each fetch as it ends, and to stop, as app.feeds/refresh! takes them. The feeds left out stay due, and the :left of the :counts says how many there are.
  • :head-check?, true to read only the start of a feed whose server can't answer 304, and fetch it whole only when its newest episodes changed, as app.feeds/refresh! takes it
  • :store, the store that the library is saved to, from which it loads the feeds that it fetches and doesn't hold, as load! does. Without it, such a feed isn't fetched, and the report has :library/not-loaded.

A refresh in which every fetch of a feed failed before a server answered, at more than one host, counts as offline too. Offline, no feed or list counts it as a failure, each stays due for the next refresh, and the report has :refresh/offline.

Fetch and apply whatever `library` is due to fetch, with the `opts`
below.

It fetches the followed lists, the feeds of new subscriptions and remote
items, and the feeds of subscriptions whose next check has come. A feed
held for remote items alone isn't fetched again, unless :feed-guids
names it. It returns the new library and what the refresh found, in
ClojureScript as a promise:

    {:library    {…}
     :at         #inst "…"
     :added      [[feed-guid item-guid] …]  ; the new episodes
     :backfilled [[feed-guid item-guid] …]  ; older ones that appeared
     :renamed    [[old-id new-id] …]        ; episodes under a new guid,
                                            ; which took their state along
     :moved      {feed-guid "https://…"}   ; the feeds that moved, and so
                                            ; their subscriptions
     :counts     {:checked 120 :unchanged 104 :changed 14 :failed 2
                  :left 0}
     :seconds    4.2                        ; how long it took
     :report     [...]}                     ; the fetches that failed, and why

Only the new episodes join the queue or the inbox. Nothing is thrown for
what the network or a server does. The `opts` are the config for this
call, and these:

- :feed-guids, the feeds to fetch instead of those that are due, e.g.
  those that a Podping names
- :online?, false when the device has no network, so that nothing is
  fetched
- :max-feeds, :max-seconds, :on-feed-fn and :signal, to fetch fewer
  feeds or within a deadline, to hear of each fetch as it ends, and to
  stop, as app.feeds/refresh! takes them. The feeds left out stay due,
  and the :left of the :counts says how many there are.
- :head-check?, true to read only the start of a feed whose server can't
  answer 304, and fetch it whole only when its newest episodes changed,
  as app.feeds/refresh! takes it
- :store, the store that the library is saved to, from which it loads
  the feeds that it fetches and doesn't hold, as load! does. Without
  it, such a feed isn't fetched, and the report has :library/not-loaded.

A refresh in which every fetch of a feed failed before a server
answered, at more than one host, counts as offline too. Offline, no feed
or list counts it as a failure, each stays due for the next refresh,
and the report has :refresh/offline.
sourceraw docstring

refreshedclj/s

(refreshed library found)
(refreshed library
           {:keys [at from feeds documents changed moved lists counts seconds
                   report]
            :as found}
           opts)

The library with what a refresh found, as fetch-due! gives it, applied at its time with opts, and what the refresh found, as refresh! gives them.

An entry that found holds replaces the library's own only while the library still has the entry that the refresh was due with, so that a feed that changed meanwhile, e.g. by a subscription in another tab, stays as it is, and so does a list that the listener no longer follows. The feeds that changed are read from the documents that found holds, with the :codec of opts.

The `library` with what a refresh `found`, as fetch-due! gives it,
applied at its time with `opts`, and what the refresh found, as refresh!
gives them.

An entry that `found` holds replaces the library's own only while the
library still has the entry that the refresh was due with, so that a
feed that changed meanwhile, e.g. by a subscription in another tab,
stays as it is, and so does a list that the listener no longer follows.
The feeds that changed are read from the documents that `found` holds,
with the :codec of `opts`.
sourceraw docstring

remove-episodeclj/s

(remove-episode library id)
(remove-episode library [feed-guid :as id] opts)

The library without the remote item id, with the :at of opts. The feed of the episode goes too, when no subscription or other remote item needs it, and the queue and the progress stay as they are.

The `library` without the remote item `id`, with the :at of `opts`. The
feed of the episode goes too, when no subscription or other remote item
needs it, and the queue and the progress stay as they are.
sourceraw docstring

remove-fileclj/s

(remove-file library id)
(remove-file library id opts)

The library without the file of the episode id, deleted at the time of the call, with opts. The entry stays, so that no plan downloads it again.

The `library` without the file of the episode `id`, deleted at the time
of the call, with `opts`. The entry stays, so that no plan downloads it
again.
sourceraw docstring

remove-played-episodesclj/s

(remove-played-episodes library)
(remove-played-episodes library opts)

The library without the remote items that the listener played, with the :at of opts, e.g. to tidy up the episodes that the listener took from other shows.

They leave the queue and the playlists too, and their feeds go when nothing else needs them. One that the listener starred, bookmarked, clipped or rated stays.

The `library` without the remote items that the listener played, with
the :at of `opts`, e.g. to tidy up the episodes that the listener took
from other shows.

They leave the queue and the playlists too, and their feeds go when
nothing else needs them. One that the listener starred, bookmarked,
clipped or rated stays.
sourceraw docstring

restore!clj/s

(restore! library store)
(restore! library
          store
          {:keys [keys load] :or {keys saved-keys load :all} :as opts})

The library with what was saved to store, read with the opts below, and the report of what didn't read, as a map of the :library and the :report, in ClojureScript as a promise.

The parts of the library's document that :keys in opts names, saved-keys by default, replace those of library, so give it a new library, and each feed is read from its document. The documents are read with the :codec of opts, or in EDN, by their extensions, so that a library saved in EDN reads, and the next save writes it anew. A library saved by an older version is brought up to this one. When the library keeps a search index, it's read back, or built again from the feeds when its documents are missing or don't read. The report can have :library/unreadable-document, :library/index-rebuilt, :library/malformed-profile, :library/newer-format and :library/slow-format.

A store without the documents gives the library as it is, and so does a library saved by a newer version, which then has the diagnostic under :newer-format, so that save! and write! won't write over it. A library read in ClojureScript with the codec of EDN has :library/slow-format, since that reads about 30 times slower than the codec of dk.simongray.like-minded.transit.

The :load of opts says which feeds to read: :all by default, :none, or the guids of some. The others stay in their documents until load! reads them, e.g. the feeds of the shows on the screen, and the views mark them as not loaded.

The `library` with what was saved to `store`, read with the `opts`
below, and the report of what didn't read, as a map of the :library and
the :report, in ClojureScript as a promise.

The parts of the library's document that :keys in `opts` names,
saved-keys by default, replace those of `library`, so give it a new
library, and each feed is read from its document. The documents are read
with the :codec of `opts`, or in EDN, by their extensions, so that a
library saved in EDN reads, and the next save writes it anew. A library
saved by an older version is brought up to this one. When the library
keeps a search index, it's read back, or built again from the feeds
when its documents are missing or don't read. The report can have
:library/unreadable-document, :library/index-rebuilt,
:library/malformed-profile, :library/newer-format and
:library/slow-format.

A store without the documents gives the library as it is, and so does a
library saved by a newer version, which then has the diagnostic under
:newer-format, so that save! and write! won't write over it. A library
read in ClojureScript with the codec of EDN has :library/slow-format,
since that reads about 30 times slower than the codec of
dk.simongray.like-minded.transit.

The :load of `opts` says which feeds to read: :all by default, :none, or
the guids of some. The others stay in their documents until load!
reads them, e.g. the feeds of the shows on the screen, and the views
mark them as not loaded.
sourceraw docstring

save!clj/s

(save! library store)
(save! library store {:keys [keys] :or {keys saved-keys} :as opts})

Write library to store with the opts below, and give the names of the documents it put and deleted, as a map of :put and :delete, or a map of :error, in ClojureScript as a promise.

It writes the library's own document, library.edn in the :codec of opts, EDN by default, with the parts of library that :keys in opts names, saved-keys by default, and the version of their shape. Each feed goes to a document of its own, which is put when the feed changed since the last save, and the documents of the feeds that changed or went are deleted, and the library of another codec too. When the library keeps a search index, it writes the documents of the index that changed since the last save, and deletes those that the index no longer needs. One that it couldn't delete is left out of :delete for the next save to delete, and a store without :delete keeps them all. Give it a store of its own, e.g. over a folder, IndexedDB or the origin private file system, since it deletes the documents of any other library there.

It writes over what the store holds, so where several tabs or workers share the store, write the library with write! instead.

The :error is :library/save-failed when the store failed, and :library/newer-format when library was restored from a library of a newer version, which it doesn't write over.

Write `library` to `store` with the `opts` below, and give the names of
the documents it put and deleted, as a map of :put and :delete, or a
map of :error, in ClojureScript as a promise.

It writes the library's own document, library.edn in the :codec of
`opts`, EDN by default, with the parts of `library` that :keys in `opts`
names, saved-keys by default, and the version of their shape. Each feed
goes to a document of its own, which is put when the feed changed since
the last save, and the documents of the feeds that changed or went are
deleted, and the library of another codec too. When the library keeps a
search index, it writes the documents of the index that changed since
the last save, and deletes those that the index no longer needs. One
that it couldn't delete is left out of :delete for the next save to
delete, and a store without :delete keeps them all. Give it a store of
its own, e.g. over a folder, IndexedDB or the origin private file
system, since it deletes the documents of any other library there.

It writes over what the store holds, so where several tabs or workers
share the store, write the library with write! instead.

The :error is :library/save-failed when the store failed, and
:library/newer-format when `library` was restored from a library of a
newer version, which it doesn't write over.
sourceraw docstring

saved-keysclj/s

The parts of a library that are saved by default: the profile, the feeds, the followed lists, what the next sync starts from, whose cursors fit the profile, and the downloaded files.

The parts of a library that are saved by default: the profile, the
feeds, the followed lists, what the next sync starts from, whose cursors
fit the profile, and the downloaded files.
sourceraw docstring

(search library q)
(search library q opts)

The episodes and shows of library that match the query q, best first, with the opts below, or nil when the library keeps no index.

Each result has its :feed, and an episode its :item. The words that matched with typos are in the metadata. The opts are those of dk.simongray.drop-in-search/query, whose :filter-pred gets the result with them, and :where, the criteria of criteria/where that an episode must meet, which leaves the shows out. The criteria read the profile of the library, and the time of its clock unless the opts give :at.

(search library "value for va" {:where {:status :unplayed}})
The episodes and shows of `library` that match the query `q`, best
first, with the `opts` below, or nil when the library keeps no index.

Each result has its :feed, and an episode its :item. The words that
matched with typos are in the metadata. The `opts` are those of
dk.simongray.drop-in-search/query, whose :filter-pred gets the result
with them, and :where, the criteria of criteria/where that an episode
must meet, which leaves the shows out. The criteria read the profile of
the library, and the time of its clock unless the `opts` give :at.

    (search library "value for va" {:where {:status :unplayed}})
sourceraw docstring

showclj/s

(show library feed-guid)
(show library feed-guid opts)

The view of the show feed-guid of library, with the opts of app.show/view, or nil when the library has no such feed. Its episodes have their :retained facts.

The :title is the listener's :custom-title of the show, and the :episodes are in the :order that the listener chose for it, as profile/default-settings has them.

A feed that the library doesn't hold in memory gives only its :url, its :title and its :artwork, as the profile knows them, and :unloaded? true. Read it back with load!.

The view of the show `feed-guid` of `library`, with the `opts` of
app.show/view, or nil when the library has no such feed. Its episodes
have their :retained facts.

The :title is the listener's :custom-title of the show, and the
:episodes are in the :order that the listener chose for it, as
profile/default-settings has them.

A feed that the library doesn't hold in memory gives only its :url,
its :title and its :artwork, as the profile knows them, and
:unloaded? true. Read it back with load!.
sourceraw docstring

showsclj/s

(shows library)

The subscriptions of library in the listener's order, as profile/shows gives it, each as a map for a screen of shows:

{:feed-guid "…"
 :title     "…"           ; the listener's own title, or the feed's
 :artwork   "https://…"
 :newest    #inst "…"     ; when the newest episode came out
 :counts    {:episodes 40 :unplayed 12 :in-progress 1 :played 27
             :inbox 2 :queued 1}}

The counts are of the episodes that the library keeps of each show, and of those of its episodes in the inbox and the queue. A show whose feed isn't fetched yet counts only the inbox and the queue, and so does one whose feed isn't loaded, which has :unloaded? true.

The subscriptions of `library` in the listener's order, as profile/shows
gives it, each as a map for a screen of shows:

    {:feed-guid "…"
     :title     "…"           ; the listener's own title, or the feed's
     :artwork   "https://…"
     :newest    #inst "…"     ; when the newest episode came out
     :counts    {:episodes 40 :unplayed 12 :in-progress 1 :played 27
                 :inbox 2 :queued 1}}

The counts are of the episodes that the library keeps of each show, and
of those of its episodes in the inbox and the queue. A show whose feed
isn't fetched yet counts only the inbox and the queue, and so does one
whose feed isn't loaded, which has :unloaded? true.
sourceraw docstring

snippetclj/s

(snippet library result q)
(snippet library result q opts)

A window of the text of the result that search gave for the query q in library, around the words that match, with the opts of feed.search/snippet, or nil when no field of the result matches or the library keeps no index.

(snippet library result "value for va")
;; => {:field :description
;;     :parts [{:text "…on "} {:text "value" :match? true} …]}
A window of the text of the `result` that search gave for the query `q`
in `library`, around the words that match, with the `opts` of
feed.search/snippet, or nil when no field of the result matches or the
library keeps no index.

    (snippet library result "value for va")
    ;; => {:field :description
    ;;     :parts [{:text "…on "} {:text "value" :match? true} …]}
sourceraw docstring

start-downloadclj/s

(start-download library entry)
(start-download library entry opts)

The library with the download of entry, one of the :download of its plan, started at the time of the call, with opts, as downloads/start-download records it.

The `library` with the download of `entry`, one of the :download of
its plan, started at the time of the call, with `opts`, as
downloads/start-download records it.
sourceraw docstring

stepclj/s

(step library event)
(step library event opts)

The library after the player event, with opts, both as profile.player/step takes them, and the effects to apply, as a map of the :library and the :effects.

The library has the new profile, and what's left of the :sleep timer of this device. The opts go over the :sleep of the library. With the listener's :continuous?, an episode that ends with no other queued is followed by the first unplayed episode of its show in the listening order: the next of a serial show, and the newest of an episodic one. When that gives none, the effects have [:nothing-next id], e.g. for an app to play the first of recommend's episodes like it, with the event [:play id].

The `library` after the player `event`, with `opts`, both as
profile.player/step takes them, and the effects to apply, as a map of
the :library and the :effects.

The library has the new profile, and what's left of the :sleep timer of
this device. The `opts` go over the :sleep of the library. With the
listener's :continuous?, an episode that ends with no other queued is
followed by the first unplayed episode of its show in the listening
order: the next of a serial show, and the newest of an episodic one.
When that gives none, the effects have [:nothing-next id], e.g. for an
app to play the first of recommend's episodes like it, with the event
[:play id].
sourceraw docstring

subscribeclj/s

(subscribe library url)
(subscribe library url fetched)
(subscribe library url fetched opts)

The library subscribed to the feed at url, with what was fetched and the settings in opts.

The fetched is the result of dk.simongray.podcast/fetch! or a parsed feed, and the opts are as profile/configure takes them, besides :at and the options that hold functions, e.g. :keep-fn. Without fetched, or with nil, the feed is fetched at the next refresh, and the subscription has the guid of the URL until then. The start of a feed that discovery/fetch-head! gave counts as no feed, but for the title, the artwork and the guid that it declares. The key of a subscription is the guid that its feed gives itself when it's first fetched, on any device, and stays when the feed gives itself another.

It throws when fetched has no feed, e.g. after a fetch that failed, and when the feed declares the guid of another subscription, at another URL, since the feed would take that subscription over. The ex-data is the diagnostic of the fetch, or :fetch/guid-taken. To replace the other subscription, unsubscribe from it first.

The `library` subscribed to the feed at `url`, with what was `fetched`
and the settings in `opts`.

The `fetched` is the result of dk.simongray.podcast/fetch! or a parsed
feed, and the `opts` are as profile/configure takes them, besides :at
and the options that hold functions, e.g. :keep-fn.
Without `fetched`, or with nil, the feed is fetched at the next refresh,
and the subscription has the guid of the URL until then. The start of a
feed that discovery/fetch-head! gave counts as no feed, but for the
title, the artwork and the guid that it declares. The key of a
subscription is the guid that its feed gives itself when it's first
fetched, on any device, and stays when the feed gives itself another.

It throws when `fetched` has no feed, e.g. after a fetch that failed,
and when the feed declares the guid of another subscription, at another
URL, since the feed would take that subscription over. The ex-data is
the diagnostic of the fetch, or :fetch/guid-taken. To replace the other
subscription, unsubscribe from it first.
sourceraw docstring

subscribe-localclj/s

(subscribe-local library feed)
(subscribe-local library feed opts)

The library subscribed to the show of local files feed, which feed.local/feed built, with the settings in opts, besides :at and the options that hold functions.

The feed stays on this device, as its files do, and no refresh fetches it, so subscribe again with the files as they are when they change. The profile syncs the subscription and the progress of the episodes, so a device with the same files, which make the same guids, shares them, and one without them lists the show by its title. An image that's a data URL stays out of the profile.

The `library` subscribed to the show of local files `feed`, which
feed.local/feed built, with the settings in `opts`, besides :at and the
options that hold functions.

The feed stays on this device, as its files do, and no refresh fetches
it, so subscribe again with the files as they are when they change. The
profile syncs the subscription and the progress of the episodes, so a
device with the same files, which make the same guids, shares them, and
one without them lists the show by its title. An image that's a data URL
stays out of the profile.
sourceraw docstring

subscriptionsclj/s

(subscriptions library)

The live subscriptions of library by guid, each with its :settings, defaults included, and its :feed once it's fetched.

The live subscriptions of `library` by guid, each with its :settings,
defaults included, and its :feed once it's fetched.
sourceraw docstring

sync!clj/s

(sync! library backends)
(sync! library backends opts)

Sync library with the listener's other devices through backends, with the opts of like-minded/sync! except :cursors and :failures.

It compacts the profile as profile/compact does, with the :archive-after of the config, and keeps what the next sync starts from under the :sync of the library:

{:cursors  {…}         ; those of the stores, for the next sync
 :at       #inst "…"
 :clock    #inst "…"   ; the clock of the profile after the sync
 :failures 0}          ; the syncs in a row in which a backend failed

It returns a map of the new :library and the :report, with :sync/backend-failed for each backend that failed, in ClojureScript as a promise.

Sync `library` with the listener's other devices through `backends`,
with the `opts` of like-minded/sync! except :cursors and :failures.

It compacts the profile as profile/compact does, with the :archive-after
of the config, and keeps what the next sync starts from under the :sync
of the library:

    {:cursors  {…}         ; those of the stores, for the next sync
     :at       #inst "…"
     :clock    #inst "…"   ; the clock of the profile after the sync
     :failures 0}          ; the syncs in a row in which a backend failed

It returns a map of the new :library and the :report, with
:sync/backend-failed for each backend that failed, in ClojureScript as a
promise.
sourceraw docstring

to-opmlclj/s

(to-opml library)

The subscriptions of library as an OPML subscription list, as profile.opml/to-opml gives it, with the episodes that the listener played, started or hid, as Overcast's extended export writes them, by the media of the feeds that the library has.

The subscriptions of `library` as an OPML subscription list, as
profile.opml/to-opml gives it, with the episodes that the listener
played, started or hid, as Overcast's extended export writes them, by
the media of the feeds that the library has.
sourceraw docstring

unfollow-listclj/s

(unfollow-list library url)
(unfollow-list library url opts)

The library no longer following the list at url, with opts.

The `library` no longer following the list at `url`, with `opts`.
sourceraw docstring

unload!clj/s

(unload! library store feed-guids)
(unload! library store feed-guids opts)

The library without the feeds feed-guids in memory, each written to its document in store first, in ClojureScript as a promise. With :all for feed-guids, it's every feed.

The entry of each feed keeps the name of its document, and load! or a refresh with the store reads it back. The views show the feed as not loaded meanwhile, e.g. on a server, which needs no feed between its refreshes, or on a phone, which needs only those on the screen.

It gives a map of the new :library and the :report, in ClojureScript as a promise. The documents are written with the :codec of opts. When the store fails, the feeds stay in memory, and the report has :library/save-failed.

The `library` without the feeds `feed-guids` in memory, each written to
its document in `store` first, in ClojureScript as a promise. With :all
for `feed-guids`, it's every feed.

The entry of each feed keeps the name of its document, and load! or a
refresh with the store reads it back. The views show the feed as not
loaded meanwhile, e.g. on a server, which needs no feed between its
refreshes, or on a phone, which needs only those on the screen.

It gives a map of the new :library and the :report, in ClojureScript as
a promise. The documents are written with the :codec of `opts`. When
the store fails, the feeds stay in memory, and the report has
:library/save-failed.
sourceraw docstring

unloadedclj/s

(unloaded library)

The guids of the feeds that library keeps in their documents alone, for load! to read back.

The guids of the feeds that `library` keeps in their documents alone,
for load! to read back.
sourceraw docstring

unsubscribeclj/s

(unsubscribe library feed-guid)
(unsubscribe library feed-guid opts)

The library unsubscribed from the feed feed-guid, with opts. The feed and its search documents go, but for the episodes of its remote items, and the profile keeps a record of the subscription.

The `library` unsubscribed from the feed `feed-guid`, with `opts`. The
feed and its search documents go, but for the episodes of its remote
items, and the profile keeps a record of the subscription.
sourceraw docstring

unsynced?clj/s

(unsynced? library)

Whether the profile of library changed since its last sync, by the clock of the profile.

Whether the profile of `library` changed since its last sync, by the
clock of the profile.
sourceraw docstring

update-profileclj/s

(update-profile library f & args)

The library with its profile replaced by what f gives for it, the args and the time of the clock, in that order. For a series of changes at one time, give a function of the profile and the time.

The `library` with its profile replaced by what `f` gives for it, the
`args` and the time of the clock, in that order. For a series of changes
at one time, give a function of the profile and the time.
sourceraw docstring

urlsclj/s

(urls library)

A map from each feed of library, with the episodes that it lists, to its URL.

A map from each feed of `library`, with the episodes that it lists, to
its URL.
sourceraw docstring

with-deviceclj/s

(with-device library device)
(with-device library device opts)

The library as that of the new device, described for the other devices by the opts that make takes, e.g. to sync again after leave!.

The profile keeps what it holds, and the next sync starts afresh, as the first sync of a new device does.

The `library` as that of the new `device`, described for the other
devices by the `opts` that make takes, e.g. to sync again after leave!.

The profile keeps what it holds, and the next sync starts afresh, as the
first sync of a new device does.
sourceraw docstring

write!clj/s

(write! library store)
(write! library store {:keys [before] :as opts})

Write library to store with the opts below, and give the :version of its own document and the names of the documents that it put and deleted, as a map of :version, :put and :delete, in ClojureScript as a promise. It gives a map of :conflict? and :put when the library's own document isn't of the :if-version, and a map of :error otherwise, as save! does.

  • :codec, that of the documents
  • :if-version, the version of the library's own document in the store to write over, as read! gives it, or nil when there's to be none yet. Without it, the document is written whatever its version.
  • :before, the library that library comes from, as read! gave it or write! wrote it, whose documents go once library no longer has them

It puts the documents of documents that the store lacks, and the library's own document last, on condition of the :if-version. Then it deletes the documents of :before that library doesn't have, and the manifest that save! writes beside the library's own document, which now holds it. It deletes nothing else, so it never deletes what another context put for a write still under way.

It takes no lock and reads nothing but the names in the store, so on a conflict, read! the store again and change what it gives, as swap! does with an atom, which durable-swap! does.

Write `library` to `store` with the `opts` below, and give the :version
of its own document and the names of the documents that it put and
deleted, as a map of :version, :put and :delete, in ClojureScript as a
promise. It gives a map of :conflict? and :put when the library's own
document isn't of the :if-version, and a map of :error otherwise, as
save! does.

- :codec, that of the documents
- :if-version, the version of the library's own document in the store
  to write over, as read! gives it, or nil when there's to be none yet.
  Without it, the document is written whatever its version.
- :before, the library that `library` comes from, as read! gave it or
  write! wrote it, whose documents go once `library` no longer has them

It puts the documents of documents that the store lacks, and the
library's own document last, on condition of the :if-version. Then it
deletes the documents of :before that `library` doesn't have, and the
manifest that save! writes beside the library's own document, which now
holds it. It deletes nothing else, so it never deletes what another
context put for a write still under way.

It takes no lock and reads nothing but the names in the store, so on a
conflict, read! the store again and change what it gives, as swap! does
with an atom, which durable-swap! does.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close