Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal - ⚡️ Lightning Comments #347

Closed
MerryOscar opened this issue Mar 7, 2022 · 13 comments
Closed

Proposal - ⚡️ Lightning Comments #347

MerryOscar opened this issue Mar 7, 2022 · 13 comments

Comments

@MerryOscar
Copy link

I would like to propose an alternative for cross-app comments that integrates the feature we all love - BOOSTS!⚡️

Issues with podcast:social

Whilst the current <podcast:social> tag is workable, in my view there are some fundamental issues:

  • There are too many platforms given as options - This choice leads to confusion on how the tag works and makes the implementation much more work for developers.
  • The account requirement leads to bad UX - As a podcast app user I really don't want to have to login to different social accounts just to comment.
  • There is no link to value for value - The value block is one of the most exciting features of Podcasting 2.0 and is already seeing many messages sent every day. Any spec that doesn't integrate boost messages is a huge missed opportunity.
  • There is no protection against spam or bots - One of the biggest problems with social media today is spam and bots - just look at Twitter. Podcasts have been a sanctuary where this doesn't exist. Let's keep it that way and include spam protection from the start.

⚡️ Lightning Comments

A cross-app <lightningcomments> specification that could be added to the Podcasting 2.0 namespace.

By tying comments to Lightning payments, any app can post a comment or reply without needing the user to create an account. Optional user info can be parsed from the TLV record just as we do things for the podcast:value tag.

Comments can come from any app - but the host still has full control.

There are 2 components to this proposed spec:

1. Comments Tag <lightningcomments>

Tells the app where to load the comments JSON. The JSON will contain the comments data along with instructions on how to post a comment.

<lightningcomments url="https://api.fountain.fm/v1/comments?feed=920666&episode=6788136469" />

Importantly:

  • The tag is so simple it can be easily posted into shownotes until hosts add support.
  • Fountain is currently using PodcastIndex IDs in the URL to make it easy for other apps to dynamically generate, but this may not be the case for other hosts.

2. Comments JSON (returned from url in tag)

Defines the JSON format that any lightningcomments host should conform to:

{
  // how to post a comment
  "_post": {
    "type": "lightning",
    "method": "keysend",
    "minimum": 1,
    "address": "03bc290b26637eb8f25de69fca83c85c014796aa03d90bf0d4c03c18947e12127d",
    "tlv": {
      // required comment tlv record
      333333: {
        // the host field allows each comments host to provide their own data which is passed along through the tlv, apps should not modify.
        "host": {
          "_show_id": "",
          "_feed_id": "",
          "_episode_id": "",
          "_episode_title": ""
        },
        // the comment field should be consistent between hosts, apps should set.
        "comment": {
          "payment": 1, // payment value (required)
          "message": "", // comment message (required)
          "parent": "", // id of parent comment (optional if reply)
          "sender": {
            "app": "", // name of app sending comment (optional)
            "id": "", // unique id of user sending comment (optional)
            "name": "" // name of user sending comment (optional)
          },
        }
      }
      // ...optional tlv records
    }
  },

  // the existing comments data
  "data": {
    "comments": [
      // a route comment
      {
        "id": "75X5adm5VCsnolxzPJFN",
        "message": "",
        "sender": {
          "app": "",
          "id": "",
          "name": "",
        },
        "depth": 0,
        "payment": 1,
        "created": "2022-01-20T18:18:00.000-0100",
        "parent": null,
        "children": [
          "CGGDl8Hy3DNmCSAqAUSQ"
        ]
      },
      // a reply to the route comment (75X5adm5VCsnolxzPJFN)
      {
        "id": "CGGDl8Hy3DNmCSAqAUSQ",
        "message": "",
        "sender": {
          "app": "",
          "id": "",
          "name": "",
        },
        "depth": 1,
        "payment": 1,
        "created": "2022-01-20T18:18:00.000-0100",
        "parent": "75X5adm5VCsnolxzPJFN",
        "children": [
          "u5u27ntCCYP2AulIClmB"
        ]
      },
      // a reply to the reply (CGGDl8Hy3DNmCSAqAUSQ)
      {
        "id": "u5u27ntCCYP2AulIClmB",
        "message": "",
        "sender": {
          "app": "",
          "id": "",
          "name": ""
        },
        "depth": 2,
        "payment": 1,
        "created": "2022-01-20T18:18:00.000-0100",
        "parent": "CGGDl8Hy3DNmCSAqAUSQ",
        "children": [] 
      }
    ]
}

Although the existing comments data is a list, the parent and children properties will allow apps to render nested comments.

Working Demo

You can see that:

  • Any boosts sent from the Fountain beta app will show up as comments.
  • If you send a keysend payment using the data in the Comments JSON it will also show up.
  • Fountain is honouring the value block and sending the comment payment to each split.
  • For non-value enabled shows Fountain charges 1 sat for the comment.

Questions

Should users have to pay for comments?

A payment is required to comment, but because the payment value can be very small (1 satoshi), apps can very easily cover the cost for users if they choose. The payment requirement brings an incredible benefit of spam protection and also incentivises better quality comments.

Will the Lightning TLV record have enough space for comments?

The TLV record is limited in size but will still be enough for multi-paragraph comments. No essays but limiting response length in this way is not nessessarily a bad thing.

What about the existing 7629169 TLV record?

We could definitely combine the TLV records - but I think in the short term it's easier to define a new record and let apps / hosting providers decide whether to include boosts from the 7629169 record in the comments JSON. This separates concerns until we have fully aggreed on the spec. It also leaves open the ability for apps to send private boosts.

The comments are stored on a central server - is this decentralised?

The comments are hosted on a central server yes, but the specification is still decentralised because you can switch comments hosts whenever you want - just like you can switch podcast hosts. As the JSON format is the same you can bring your comments with you to a new host or self-host them. The posting of comments is still decentralised because anyone can post a comment from any platform by sending a Lightning payment.

Next Steps

Please give a thumbs up on the issue if you think like the idea - otherwise I would love to open a discussion!

@yoshimo
Copy link

yoshimo commented Mar 7, 2022

What about user privacy in this context?
When comments are done on the podcasters wordpress page with captcha and so on i can post one comment as "max" the next as "john" and they can not be linked if i used a different ip they also can't tell if john on one podcast is the same john that posted a comment on another podcasts page.
Can we keep this non linkability up with your new system?

@MerryOscar
Copy link
Author

What about user privacy in this context?
When comments are done on the podcasters wordpress page with captcha and so on i can post one comment as "max" the next as "john" and they can not be linked if i used a different ip they also can't tell if john on one podcast is the same john that posted a comment on another podcasts page.
Can we keep this non linkability up with your new system?

It would up up to apps to set privacy policy - same as with the <podcast:value> tag. Some apps send an id / name / username - some apps are anonymous.

@johnspurlock
Copy link
Contributor

johnspurlock commented Mar 8, 2022

This is a cool idea! A common structure for how to locate and surface comments generated via lightning is needed.

One note about the idea specifically: the podcaster will not want to put a url to fountain (an app) in their podcast feed. They'd want to point to the system that can can surface the transactions received, ie it should come from something like helipad for those with umbrel wallets. Or maybe in your example you meant fountain owns/manages a podcaster's wallet? It is a question for how you would do this for a wallet without custom software like helipad though.

One suggestion about the idea from a high level - you may want to consider implementing "lightningcomments" as a new protocol on the existing socialInteract tag, since you are effectively creating another protocol here.
i.e.

<podcast:socialInteract platform="helipad" protocol="lightningcomments">
  https://helipad.example.com/v1/comments?feed=920666&amp;episode=6788136469
</podcast:socialInteract>

This way:

  • keeps lightning-specific terminology out of a tag name of the podcast namespace: a namespace about podcasting, not about lightning
  • builds on the foresight of the Castopod guys, allowing a url per-platform per episode - they can be rendered together in the app's ui, just not reply-able across platforms - which may actually be desired for apps wanting to give lightning-based comments more prominence
  • is non-exclusive, and therefore does not shut out the larger universe of podcasters/users potentially interested in comments (vs the smaller subset of podcasting interested in lightning-based micropayments)
  • would be a nice way to introduce users to lightning comments, as a layered add-on to easier to swallow twitter/fediverse-based comments, instead of making it the only way. i.e. "I see this special form of comment in this episode's comments, how can I participate", instead of the more gatekeepery "you must use a lightning-based app to comment at all"
  • And even then, podcasters excited about promoting lightning exclusively can still specify lightingcomments only for a given episode by defining a single element for that protocol as the sole socialInteract element

Oh and:

As a podcast app user I really don't want to have to login to different social accounts just to comment.

With ActivityPub at least, a good app will provide a transparent id on their domain, so no log in at all from the user's pov.

Hope that helps!

@MerryOscar
Copy link
Author

@johnspurlock thanks so much for the detailed feedback!


the podcaster will not want to put a url to fountain (an app) in their podcast feed.

Yes definitely agree. The Fountain url is just an example and I envision each podcast having a different comments url based on their choice. So you could have a Fountain url, another app url, a hosting platform url, a helipad url (if that's possible).


you may want to consider implementing "lightningcomments" as a new protocol on the existing socialInteract tag

Yes agree this could be a great way to do it. I thought about proposing it this way but wanted to leave the option of having it separate. But all your points make a lot of sense. I especially love the idea of a url per-platform per episode and gradually (but optionally) introducing users to Lightning.

@jamescridland
Copy link
Contributor

Since Oscar built the API, and since I support this idea in principle, I have implemented this specification within Podnews pages.

If you go and listen to the Podnews episode called "Google's new dubbing tool" and send a boostagram, the text of that boostagram will appear in the comments section towards the bottom of: https://podnews.net/update/google-dub

Screen Shot 2022-03-12 at 8 01 19 pm

The comments are updated every ten minutes; that's not a technical issue with this specification, but just how long the JSON will cache for at the CDN, to save Oscar's systems being hit every page load. The work I've had to do for this is minimal; I wrote a proxy for the comments API on Fountain (five lines of PHP, plus caching and CORS); a piece of JavaScript to asynchronously call this API and lay out the results (fourteen lines); and added an additional column in the database schema to store the Podcast Index episode ID. It'll take ten minutes more to add a tool to pull the episode ID out of Podcast Index.

I should note: I am very happy to give someone a value share in order for them to run an API for comments like this. There is a business model in operating comments like this and an API on the other end. (Indeed, some API operators might wish to add moderation tools.)

A suggestion to make it easier for developers and avoid a central point of failure

The current comments JSON lives at a URL like:
https://api.fountain.fm/v1/comments?feed=227573&episode=7130637071

Both the feedID and the episodeID are both proprietary pieces of data from Podcast Index, requiring API calls and relying on a central database. I believe that where alternatives exist we shouldn't back ourselves into a proprietary corner, no matter how nice Dave and Adam are.

I'd therefore suggest

https://api.fountain.fm/v1/comments?feedUrl=https%3A%2F%2Fpodnews.net%2Frss&guid=https%3A%2F%2Fpodnews.net%2Fupdate%2Fgoogle-dub

I do, though, recognise that boosts all currently rely on PodcastIndex IDs currently, so perhaps right now this isn't a concern; but just a suggestion.

@johnspurlock
Copy link
Contributor

Nice James - one step closer to making this hidden lightning comment data available for display in 3rd-party apps!

Just added two PRs to formally add fountain as a platform, and lightningcomments as a protocol to podcast:socialInteract, so we can get this into phase 5.

Can you add the following tag to the podnews rss feed, under the item with guid https://podnews.net/update/google-dub:

<podcast:socialInteract priority="1" platform="fountain" protocol="lightningcomments" accountId="033868c219bdb51a33560d854d500fe7d3898a1ad9e05dd89d0007e11313588500" pubDate="2021-04-14T10:25:42Z">https://api.fountain.fm/v1/comments?feed=227573&amp;episode=7130637071</podcast:socialInteract>

or for extra credit:

<podcast:socialInteract priority="1" platform="fountain" protocol="lightningcomments" accountId="033868c219bdb51a33560d854d500fe7d3898a1ad9e05dd89d0007e11313588500">https://api.fountain.fm/v1/comments?feed=227573&amp;episode=7130637071</podcast:socialInteract>
<podcast:socialInteract priority="2" platform="twitter" protocol="twitter" accountId="@Podnews">https://twitter.com/Podnews/status/1502242577122304005</podcast:socialInteract>

To provide the complete structured data for that episode, including your corresponding tweet. Didn't you used to provide this?

I could probably even add adapters to threadcap for Twitter and this new lightningcomments json format, so existing callers could just point it at any of the three: ActivityPub, Twitter, lightningcomments and get a normalized format for easy rendering.

@jamescridland
Copy link
Contributor

jamescridland commented Mar 14, 2022

Thanks, @johnspurlock - this is now in the RSS.

<podcast:socialInteract
 priority="1"
 platform="fountain"
 protocol="lightningcomments" 
 accountId="033868c219bdb51a33560d854d500fe7d3898a1ad9e05dd89d0007e11313588500"
>
https://api.fountain.fm/v1/comments?feed=227573&amp;episode=7130637071
</podcast:socialInteract>

I'm going to not publish a pubDate - it's programmatically difficult to get as far as I can see, and it appears optional in the spec.

Both @MerryOscar and @johnspurlock - It's sub-optimal to have to publish the RSS feed once in order to submit it to PodcastIndex, then to get the proprietary PodcastIndex episode ID from PodcastIndex once it's updated, and then publish the RSS feed again once I've found it. I need to fiddle with a lot of caching and double the notifications in order to achieve this. I would much rather use the episode GUID, which is set at publish time. Please can we consider how this is done?

The Twitter socialInteract - I need to see if I can programmatically get the ID of the tweet that's sent. At least, though, I can send the tweet as part of the publication process and get an instant response, which I can't rely on from PodcastIndex.

@johnspurlock
Copy link
Contributor

100% behind using the (trimmed) item guid content value to identify episodes across our various systems, instead of PI episode ids.

Best (what you have above): https://api.fountain.fm/v1/comments?feedUrl=https%3A%2F%2Fpodnews.net%2Frss&guid=https%3A%2F%2Fpodnews.net%2Fupdate%2Fgoogle-dub

Supported alternative (podcastId known ahead of time): https://api.fountain.fm/v1/comments?podcastId=227573&guid=https%3A%2F%2Fpodnews.net%2Fupdate%2Fgoogle-dub

Maybe we should pester @daveajones to provide a brand new episodes-by-feed-id-and-item-guid endpoint (or maybe an optional new param to the existing episodes-by-feed-id endpoint?). Right now you can kind of do this by enumerating all episodes for the feed-id, but his DB would do a more efficient job of it given an item guid

@jamescridland
Copy link
Contributor

(As an aside: you'll see a return of the SocialInteract for Twitter as of today; I've rewritten the tweet service to capture the tweetID. I've also added it to the /google-dub episode.)

@MerryOscar
Copy link
Author

MerryOscar commented Mar 14, 2022

It's sub-optimal to have to publish the RSS feed once in order to submit it to PodcastIndex, then to get the proprietary PodcastIndex episode ID from PodcastIndex once it's updated, and then publish the RSS feed again once I've found it. I need to fiddle with a lot of caching and double the notifications in order to achieve this. I would much rather use the episode GUID, which is set at publish time. Please can we consider how this is done?

@jamescridland yes I agree this is sub-optimal.

I think it's important to note that because it is only a url that is specified in the spec, any Lightning Comments host can return the url in whatever form they want. Some hosts could use a combination of the feedUrl and the GUID, some hosts could use their own internal IDs.

For this Fountain demo we're using our internal showID + the PodcastIndex episode itemID. The reason for this is PodcastIndex have the GET /episodes/byid endpoint which makes things very easy.

@jamescridland - I'll update our comments load endpoint so that it accepts a Fountain showID and episode guid so you don't have the extra step of waiting for the PodcastIndex itemID - will let you know when this is done.

Agree with @johnspurlock if @daveajones could create a GET /episodes/byguid that would be amazing!

@johnspurlock
Copy link
Contributor

Proposed the lookup by guid change in #352

@johnspurlock
Copy link
Contributor

Added experimental support for this new lightningcomments protocol (and also twitter!) to the latest threadcap library

https://podcastindex.social/web/@js/107967439891619300

@MerryOscar MerryOscar changed the title ⚡️ Lightning Comments Proposal - ⚡️ Lightning Comments Mar 21, 2022
@theDanielJLewis
Copy link

I'm not seeing how this is different from publishing "public" Boostagrams anyway.

I see Boostagrams as a "response" that can be highlighted in a "comment" stream, similar to "superchats" on Twitch and YouTube Live.

However, I don't see Boostagrams as something intended to spark conversation with other listeners like comments often are.

I think, if anything, there should be a simple toggle in a feed that gives the app permission to surface the "public" Boostagrams. If it's allowed, then only those Boostagrams where the sender opts-in to having their response published will be visible. And if the tag is set to not allow, then no boostagrams will be displayed. Maybe there could be an in-between option that can let a podcaster show off the amount(s) and number of boosters, but not the individual boostagrams or their senders.

My position is that podcaster control and audience privacy should come before anything else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants