Podcastindex-org / podcast-namespace

A wholistic rss namespace for podcasting
Creative Commons Zero v1.0 Universal
389 stars 116 forks source link

Proposal: universal in-app episode linking #422

Closed theDanielJLewis closed 1 year ago

theDanielJLewis commented 1 year ago

The problem

A podcaster has great content and references an old episode that a listener wants to hear. This is a good podcaster, so she has put a link back to that old episode in her notes that display well inside the podcast app. But when the listener taps on that link, it takes them to the website or anywhere but the episode within the app the listener is already using.

The solution

I propose we push forward the episode GUID, or some other means, that a podcaster can attach as a query or hash on a link back to an old episode. When that link is tapped, whatever webpage would load as usual in a legacy podcast app; but in a Podcasting 2.0 app, the episode GUID would be read from the URL without ever having to load the URL contents and the podcast app would jump straight to that old episode (preferably without stopping playback) so that the listener can add the episode to his queue.

Such a link might be as simple as this:

<a href="https://myawesomepodcast.com/how-to-be-awesome/#episode_guid_here>Listen to this old episode</a>

This code should be readable and trigger this action no matter where the link is included, primarily:

Some potential issues

I see a few problems we might run into.

  1. The podcaster might have no idea how to get their episode GUID.
  2. What happens if they link to an episode that's no longer in their feed (either by removal or by being pushed out of an item-limited feed)?
  3. If using the item GUIDs, we would need the extra step of encoding them so it doesn't cause special-character issues when the GUID is a URL (as WordPress feeds use).
  4. If we use a URL parameter instead, then we might be triggering unnecessarily uncached page loads.
  5. How to link to episodes from other podcasts when the podcaster won't have any sort of backend access to easily know the episode GUIDs. (For example, if I tell my audience to listen to my guest appearance on another show, I could link to that episode and it would trigger this same jump-to behavior, but for someone else's podcast.)

This is a rough idea for now, but something I would love to see as this could eliminate the unnecessary episode numbers as unnecessary references. Plus, I would think app developers might love this idea because it keeps a listener from leaving the podcast app and causes them to engage deeper with the same app.

daveajones commented 1 year ago

This is a great idea DJL. Need lots of input from app devs on this.

mitchdowney commented 1 year ago

But when the listener taps on that link, it takes them to the website or anywhere but the episode within the app the listener is already using.

I'm not sure I 100% understand this part. Is the idea that there would be a tag inside <content:encoded>,<description>, etc. that on click opens an episode by its GUID in whatever the user has set as their preferred/default podcasting 2.0 app? Or if there is no podcasting 2.0 app available, then open the web page in whatever the user's default/current web browser is?

theDanielJLewis commented 1 year ago

@mitchdowney, I'm saying a standard backlink a podcaster would put in their notes anyway could be slightly modified (like with the episode GUID). That link could be in any or all of those 4 places I mentioned. If the listener is using a legacy podcast app, tapping the link would open it as always. But on Podverse, for example, tapping that same link would take the listener to that episode inside Podverse. So if they want to listen to the other episode, they can use the app's built-in queue management to add that linked episode to their play queue—all without interrupting playback of the original episode.

Need a simulated screencast?

mitchdowney commented 1 year ago

I'm more of a visual learner so a screencast would be appreciated.

There are some details about how "deep links" work on iOS and Android that might be relevant here. A "deep link" is the ability for a user to tap a link, but have that link be opened in a corresponding app that is already installed on that users device.

For Podverse, there are two types of deep links supported. In both cases, our app needs to be configured to recognize either a custom protocol like podverse:// or an http scheme like https://podverse.fm. The app needs to be registered to recognize and intercept either the custom protocol or the http scheme.

We can't however (to my knowledge), do something like make Podverse open and handle a deep link from a 3rd party web domain, like if https://podcastindex.org/podcast/<GUID> were a link, and we wanted Podverse to intercept that click and use the GUID to open that podcast in Podverse instead of navigating the user to https://podcastindex.org/podcast/<GUID>. We might be able to register https://podcastindex.org as an http scheme, but I suspect (don't know for sure) Apple or Google might have policies against that, because if that were allowed then apps could abuse it to make apple.com or google.com links open in any random app. Even if it is permitted, then we would need to manually add each http scheme that we want our apps to be able to intercept as deep links.

The closest thing I can think of to the intended UX would be a custom default deep link protocol, like podcast://. If a podcaster shared a link in their description like "Open this episode in your default podcast app" and assigned it an href of podcast://podcast/<GUID>, then whatever app is registered in the device's settings as the default Podcast app could intercept the link click event, and be able to handle it however they want (such as by navigating to the podcast within the podcast app).

The big problem with that, as I understand it, is Apple doesn't support a default podcast:// protocol for podcast apps. I think Android might though? There is also the problem that the link would use a custom protocol, so there isn't a fallback web url if the user presses the custom protocol link.

Sorry if I'm misunderstanding and straying from the intention of this proposal. I just wanted to point out there are some strict constraints on how iOS and Android apps can intercept and handle "deep links".

theDanielJLewis commented 1 year ago

There are some details about how "deep links" work on iOS and Android that might be relevant here. A "deep link" is the ability for a user to tap a link, but have that link be opened in a corresponding app that is already installed on that users device.

Deep links certainly have their place, but it will be very difficult for a podcaster to generate all the deep links, let alone implement them somehow. Even if hosting providers build in RSS-agent-detection (as is being discussed on PodcastIndex.social), that means a new app can't get their internal links working until all hosts and publishing platforms support the new app. I doubt hosting providers will be interested in maintaining that, let alone having to build in the support for RSS agent detection.

I don't think URL schemas are the way to go for this anyway. I'm saying that Podverse would see the code on any URLs in <content:encoded>, <description> (or even <itunes:summary>), legacy-style ID3 and Podcasting 2.0 chapters, and thew rich-content chapters I've proposed. This is all within Podverse that the link is being seeing and tapped. In other words, someone is already listening to a podcast on Podverse, the podcaster mentions an old episode, the listener taps on the link (wherever that is for this podcast), and Podverse then captures that link to jump straight to that podcast and episode so the listener can look at it and add it to their queue. This is all happening in Podverse without even loading the URL. (There might be a need to a popup, or an option to force opening the URL in a browser instead of jumping within Podverse.)

What's triggering this behavior is not the link URL itself, but something inside the URL, like a URL parameter such as episodeguid or something else. The URL itself is irrelevant in this case.

nathangathright commented 1 year ago

If you need a visual, Overcast already does this behavior for Apple Podcasts links.

  1. It recognizes a specific URL pattern.
  2. It uses the identifiers in the URL to locate the same podcast in its database.
  3. It hijacks the link destination and directs the user to Overcast’s show page without the user ever leaving the app.

https://user-images.githubusercontent.com/3632071/208193305-b4a86b1c-d421-4e63-9b12-0f5f645c27ad.mp4

This proposal would work similarly but faces the additional challenges of supporting shows and episodes not coming from a single domain. I would suggest the proposed format include keywords that could be Regex’d by the app to ascertain which links should be manipulated.

jamescridland commented 1 year ago

This is the issue that fast-follow tried to fix, too - some way of producing a URL pattern that could trigger a suitably-configured app to capture the URL and do something with it.

In the case of fast-follow it was the podcast GUID that was in the URL, and the URL was then placed in a QR code. That then meant that: a) a user could scan the QR code with their podcast app, which would follow within the podcast app (using the GUID in the hash) b) a user could scan the QR code with their default camera app, which would open a webpage with more information about that podcast (using the rest of the URL)

URLs looked like http://podnews.net/i56t#2743-2-44244-24432343-2344-2234 (a non-working version). The first part would be read by the QR code scanner on your camera, and take you to the website; the GUID after the hash would be read by a scanner if you opened it in a capable app. This meant the URL always worked, irrespective of what it was being scanned in, and a user was never left with an opaque error.

The same mechanism could work for an episode GUID, though I would suspect you'd need to also put the podcast GUID in the URL somehow as well - a valid episode GUID can just be "45" and doesn't need to be a URL.

Bespoke protocols, like podcast:, have the fundamental problem that if your device doesn't have a handler for them (you don't have the app installed) it just fails, without any helpful UX telling you what to do next or what to install. So, they are unsuitable for a CTA to "subscribe to this show".

Apps can have a handler for a specific URL pattern. (Pocket Casts on Android has a handler for Apple Podcasts links, as one example). An example here is like fast-follow.net/podcast/listen/:GUID/:episodeguid - but someone would need to run that domain, and app developers are unlikely to build support for a third-party tool like that. We've had one of those before - subscribeonandroid.com as run by Blubbry - and support has been very patchy.

So we end up with the same issue we had for fast-follow, but on steroids. How can we make a method that can be given to prospective listeners that always works - that never leaves them high and dry with an opaque error?

I felt the solution for fast-follow was rather neat. It would never break anyone's call-to-action link and didn't require a central domain, but if opened by a capable podcast player would take you directly to the podcast in your app of choice. Unfortunately, it didn't gain much support here, and I remember at least one person being really very agitated against it, to the point of slinging insults around.

jamescridland commented 1 year ago

This proposal appears to be simpler than fast-follow, though, if I understand it. The mechanism is

In the episode description, a link is placed to another episode of the same podcast.

That link ends with #episode=http://thisisaguid/to/it

When the link is clicked in a compatible player, it takes you to that episode within the player.

When the link is clicked in a player that isn't compatible, it opens a browser as normal (the # part is never sent to the server anyway, so this causes no issues with caching).

Technically, this is quite nice, and this certainly works well. I guess the question is how many podcasters use links to other episodes in their show notes (the only place this will work).

theDanielJLewis commented 1 year ago

@nathangathright, thanks. But that's a show link. I mean linking to an actual episode and in a way that has a platform-agnostic fallback (the webpage).

@mitchdowney, here's an video to demonstrate (through editing) the behavior I'm describing: https://www.dropbox.com/s/ejc5t9300185n6r/Podcasting%202.0%20universal%20in-app%20episode%20links.mp4?dl=0

@jamescridland, thanks for bringing up QR Codes, because this could be handy for that, too. "Scan this QR Code to hear this episode." Scan with a Podcasting 2.0 app and it jumps straight to the episode within the same app. Scan with anything else and it follows the link.

James, you also nailed the behavior I'm describing within an app (and as I demonstrated in the video above). But I'd want to see this behavior supported from the links in the notes (<content:encoded> or <description>/<itunes:summary>) and chapters (ID3, JSON, or my #400 proposal for rich-content chapters).

mitchdowney commented 1 year ago

@theDanielJLewis thanks for putting this video together! Makes total sense to me now.

Ok given that we're only talking about making this work from within your podcast app, then mobile deep links shouldn't be an issue here, since deep links are used for clicking links outside of an app that redirect you into an app.

So, as long as links follow a consistent naming scheme, we could intercept the link/href onPress, then use the defined pattern to determine if it is a "universal in-app episode link", and if yes, then redirect to the episode from within the app...if no, then it will be handled as a standard link that opens in the device's web browser.

Here is the place in Podverse where the intercept onPress can happen: https://github.com/podverse/podverse-rn/blob/develop/src/components/HTMLScrollView.tsx#L64

It would be relatively simple for me to add the logic for this if a spec is decided and we have a sample feed to test with.

The tricky part, imo, is deciding on a scheme that both won't clash with links that should open in a browser, while also being a clean URL pattern that isn't too unsightly for podcasters (that may not be possible given the nature of GUIDs though).

This isn't a final proposal recommendation, but I imagine something like this being able to work:

https://any-domain-here.com/podcast-guid/<podcastGuid>/episode-guid/<episodeGuid>

The "podcast-guid" looks weird, so maybe it's not a great idea, but hopefully it conveys the idea. If a pattern like this is used, then we could also support links to podcasts directly with:

https://any-domain-here.com/podcast-guid/<podcastGuid>

I think for episodes that both podcast and episode guids should be provided, because there is no guarantee that episodeGuids are unique across all podcasts. Some podcasts incorrectly use guids like "1, 2, 3". If we include both a podcast and episode guid that should more reliably ensure uniqueness.

That reminds me that Podverse doesn't require podcasts to have a unique guid at this time (since they have traditionally been unreliable for us), but that issue could be resolved.

theDanielJLewis commented 1 year ago

I think a #code or ?parameter=code approach would be best, as these would not interfere with normal URL loading. However, the parameter method would probably cause an uncached version of the page to load, which is not ideal. Thus, I think a #code approach would be best.

So a URL might look like this: https://theaudacitytopodcast.com/numbersintitles#be757dcf-a989-53b6-a70f-d9c0712fbbcf&f340ac57-2d25-55e5-a82e-08f9c5d5c3d2

The first code is (maybe?) my podcast GUID, while the second code is UUID generated from my episode GUID.

(Sidenote: why are we using UUID to generate GUIDs instead of something similar like base64?)

mitchdowney commented 1 year ago

Hmm...I think there would at least need to be a query parameter so that we know that this string is intended as a universal in-app episode link, and not say, a link to a web page that has a # to navigate to a section on the page.

I'll defer to others though for decisions on this. I'm more comfortable on the implementation side than the spec defining side.

theDanielJLewis commented 1 year ago

That's a good point. Since we can put almost anything after a #, we could start the string with an indicator, like #guid or #podcastlink.